Added some enchantments suggested by kerplamp

This commit is contained in:
Sollace 2021-02-16 13:39:39 +02:00
parent ec50aadda3
commit c61801b507
27 changed files with 880 additions and 19 deletions

View file

@ -12,6 +12,8 @@ public interface USounds {
SoundEvent BATPONY_EEEE = register("batpony_eeee"); SoundEvent BATPONY_EEEE = register("batpony_eeee");
SoundEvent CHANGELING_BUZZ = register("changeling_buzz"); SoundEvent CHANGELING_BUZZ = register("changeling_buzz");
SoundEvent AURA = register("aura");
SoundEvent RECORD_CRUSADE = register("record.crusade"); SoundEvent RECORD_CRUSADE = register("record.crusade");
SoundEvent RECORD_PET = register("record.pet"); SoundEvent RECORD_PET = register("record.pet");
SoundEvent RECORD_POPULAR = register("record.popular"); SoundEvent RECORD_POPULAR = register("record.popular");

View file

@ -7,18 +7,23 @@ import net.minecraft.tag.Tag;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
public interface UTags { public interface UTags {
Tag<Item> APPLES = register("apples"); Tag<Item> APPLES = item("apples");
Tag<Item> FESH_APPLES = register("fresh_apples"); Tag<Item> FESH_APPLES = item("fresh_apples");
Tag<Item> NON_TOXIC = register("non_toxic"); Tag<Item> NON_TOXIC = item("non_toxic");
Tag<Item> FAIRLY_TOXIC = register("fairly_toxic"); Tag<Item> FAIRLY_TOXIC = item("fairly_toxic");
Tag<Item> SEVERELY_TOXIC = register("severely_toxic"); Tag<Item> SEVERELY_TOXIC = item("severely_toxic");
Tag<Block> FRAGILE = TagRegistry.block(new Identifier("unicopia", "fragile")); Tag<Block> FRAGILE = block("fragile");
Tag<Block> INTERESTING = block("interesting");
static Tag<Item> register(String name) { static Tag<Item> item(String name) {
return TagRegistry.item(new Identifier("unicopia", name)); return TagRegistry.item(new Identifier("unicopia", name));
} }
static Tag<Block> block(String name) {
return TagRegistry.block(new Identifier("unicopia", name));
}
static void bootstrap() { } static void bootstrap() { }
} }

View file

@ -6,12 +6,15 @@ import com.minelittlepony.unicopia.BlockDestructionManager;
import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Hit;
import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.entity.player.Pony;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.util.MagicalDamageSource; import com.minelittlepony.unicopia.util.MagicalDamageSource;
import com.minelittlepony.unicopia.util.PosHelper; import com.minelittlepony.unicopia.util.PosHelper;
import com.minelittlepony.unicopia.util.WorldEvent; import com.minelittlepony.unicopia.util.WorldEvent;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.attribute.EntityAttributes; import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@ -80,19 +83,27 @@ public class EarthPonyStompAbility implements Ability<Hit> {
iplayer.waitForFall(() -> { iplayer.waitForFall(() -> {
BlockPos center = PosHelper.findSolidGroundAt(player.getEntityWorld(), player.getBlockPos()); BlockPos center = PosHelper.findSolidGroundAt(player.getEntityWorld(), player.getBlockPos());
float heavyness = 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, player);
iplayer.getWorld().getOtherEntities(player, areaOfEffect.offset(iplayer.getOriginVector())).forEach(i -> { iplayer.getWorld().getOtherEntities(player, areaOfEffect.offset(iplayer.getOriginVector())).forEach(i -> {
double dist = Math.sqrt(center.getSquaredDistance(i.getBlockPos())); double dist = Math.sqrt(center.getSquaredDistance(i.getBlockPos()));
if (dist <= rad + 3) { if (dist <= rad + 3) {
double force = dist / 5; double inertia = dist / 5;
if (i instanceof LivingEntity) {
inertia *= 1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, (LivingEntity)i);
}
inertia /= heavyness;
i.addVelocity( i.addVelocity(
-(player.getX() - i.getX()) / force, -(player.getX() - i.getX()) / inertia,
-(player.getY() - i.getY() - 2) / force + (dist < 1 ? dist : 0), -(player.getY() - i.getY() - 2) / inertia + (dist < 1 ? dist : 0),
-(player.getZ() - i.getZ()) / force); -(player.getZ() - i.getZ()) / inertia);
DamageSource damage = MagicalDamageSource.create("smash", player); DamageSource damage = MagicalDamageSource.create("smash", player);
double amount = (4 * player.getAttributeInstance(EntityAttributes.GENERIC_ATTACK_DAMAGE).getValue()) / (float)dist; double amount = (4 * player.getAttributeInstance(EntityAttributes.GENERIC_ATTACK_DAMAGE).getValue() + heavyness * 0.4) / (float)dist;
if (i instanceof PlayerEntity) { if (i instanceof PlayerEntity) {
Race race = Pony.of((PlayerEntity)i).getSpecies(); Race race = Pony.of((PlayerEntity)i).getSpecies();
@ -109,10 +120,12 @@ public class EarthPonyStompAbility implements Ability<Hit> {
} }
}); });
BlockPos.iterate(center.add(-rad, -rad, -rad), center.add(rad, rad, rad)).forEach(i -> { double radius = rad + heavyness * 0.3;
BlockPos.iterate(center.add(-radius, -radius, -radius), center.add(radius, radius, radius)).forEach(i -> {
double dist = Math.sqrt(i.getSquaredDistance(player.getX(), player.getY(), player.getZ(), true)); double dist = Math.sqrt(i.getSquaredDistance(player.getX(), player.getY(), player.getZ(), true));
if (dist <= rad) { if (dist <= radius) {
spawnEffect(player.world, i, dist); spawnEffect(player.world, i, dist);
} }
}); });

View file

@ -13,12 +13,14 @@ import com.minelittlepony.unicopia.ability.magic.Attached;
import com.minelittlepony.unicopia.ability.magic.Caster; 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.item.FriendshipBraceletItem; import com.minelittlepony.unicopia.item.FriendshipBraceletItem;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.particle.MagicParticleEffect; import com.minelittlepony.unicopia.particle.MagicParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleHandle; import com.minelittlepony.unicopia.particle.ParticleHandle;
import com.minelittlepony.unicopia.particle.SphereParticleEffect; import com.minelittlepony.unicopia.particle.SphereParticleEffect;
import com.minelittlepony.unicopia.projectile.ProjectileUtil; import com.minelittlepony.unicopia.projectile.ProjectileUtil;
import com.minelittlepony.unicopia.util.shape.Sphere; import com.minelittlepony.unicopia.util.shape.Sphere;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EyeOfEnderEntity; import net.minecraft.entity.EyeOfEnderEntity;
import net.minecraft.entity.FallingBlockEntity; import net.minecraft.entity.FallingBlockEntity;
@ -182,6 +184,10 @@ public class ShieldSpell extends AbstractRangedAreaSpell implements Attached {
protected void applyForce(Vec3d pos, Entity target, double force, double distance) { protected void applyForce(Vec3d pos, Entity target, double force, double distance) {
pos = target.getPos().subtract(pos).normalize().multiply(force); pos = target.getPos().subtract(pos).normalize().multiply(force);
if (target instanceof LivingEntity) {
pos = pos.multiply(1 / (1 + EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, (LivingEntity)target)));
}
target.addVelocity( target.addVelocity(
pos.x, pos.x,
pos.y + (distance < 1 ? distance : 0), pos.y + (distance < 1 ? distance : 0),

View file

@ -0,0 +1,73 @@
package com.minelittlepony.unicopia.client.sound;
import java.util.Optional;
import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.item.enchantment.SimpleEnchantment;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import net.minecraft.client.sound.MovingSoundInstance;
import net.minecraft.sound.SoundCategory;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class MagicAuraSoundInstance extends MovingSoundInstance {
private final Living<?> living;
private float sourceVolume;
private float targetVolume;
private float interpolate;
private boolean fadingOut;
public MagicAuraSoundInstance(SoundCategory category, Living<?> living) {
super(USounds.AURA, category);
this.looping = true;
this.repeat = true;
this.living = living;
this.volume = 0;
setTargetVolume(1);
}
@Override
public boolean shouldAlwaysPlay() {
return true;
}
@Override
public void tick() {
Optional<SimpleEnchantment.Data> data = living.getEnchants().getOrEmpty(UEnchantments.GEM_LOCATION);
Vec3d pos = living.getOriginVector();
x = pos.x;
y = pos.y;
z = pos.z;
if (!living.getEntity().removed && data.isPresent()) {
float level = data.get().level;
if (level != targetVolume) {
setTargetVolume(level);
}
} else {
fadingOut = true;
setTargetVolume(0);
}
if (interpolate < 1) {
interpolate = Math.min(interpolate + 0.4F, 1);
volume = MathHelper.lerp(interpolate, sourceVolume, targetVolume);
}
if (fadingOut && volume < 0.01F) {
setDone();
}
}
private void setTargetVolume(float target) {
sourceVolume = volume;
targetVolume = target;
interpolate = 0;
}
}

View file

@ -6,10 +6,17 @@ import com.minelittlepony.unicopia.ability.magic.Affine;
import com.minelittlepony.unicopia.ability.magic.Levelled; import com.minelittlepony.unicopia.ability.magic.Levelled;
import com.minelittlepony.unicopia.ability.magic.Spell; import com.minelittlepony.unicopia.ability.magic.Spell;
import com.minelittlepony.unicopia.ability.magic.spell.SpellRegistry; import com.minelittlepony.unicopia.ability.magic.spell.SpellRegistry;
import com.minelittlepony.unicopia.entity.ai.WantItNeedItTargetGoal;
import com.minelittlepony.unicopia.entity.ai.WantItTakeItGoal;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.goal.GoalSelector;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.data.DataTracker; import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.data.TrackedData; import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.data.TrackedDataHandlerRegistry;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
public class Creature extends Living<LivingEntity> { public class Creature extends Living<LivingEntity> {
@ -26,6 +33,16 @@ public class Creature extends Living<LivingEntity> {
super(entity, EFFECT); super(entity, EFFECT);
} }
public void initAi(GoalSelector goals, GoalSelector targets) {
targets.add(1, new WantItNeedItTargetGoal((MobEntity)entity));
goals.add(1, new WantItTakeItGoal((MobEntity)entity));
}
public static void registerAttributes(DefaultAttributeContainer.Builder builder) {
builder.add(EntityAttributes.GENERIC_ATTACK_DAMAGE);
builder.add(EntityAttributes.GENERIC_ATTACK_KNOCKBACK);
}
@Override @Override
public Race getSpecies() { public Race getSpecies() {
return Race.HUMAN; return Race.HUMAN;
@ -55,6 +72,7 @@ public class Creature extends Living<LivingEntity> {
@Override @Override
public void toNBT(CompoundTag compound) { public void toNBT(CompoundTag compound) {
super.toNBT(compound);
Spell effect = getSpell(true); Spell effect = getSpell(true);
if (effect != null) { if (effect != null) {
@ -65,6 +83,7 @@ public class Creature extends Living<LivingEntity> {
@Override @Override
public void fromNBT(CompoundTag compound) { public void fromNBT(CompoundTag compound) {
super.fromNBT(compound);
if (compound.contains("effect")) { if (compound.contains("effect")) {
setSpell(SpellRegistry.instance().createEffectFromNBT(compound.getCompound("effect"))); setSpell(SpellRegistry.instance().createEffectFromNBT(compound.getCompound("effect")));
} }

View file

@ -0,0 +1,97 @@
package com.minelittlepony.unicopia.entity;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.item.enchantment.SimpleEnchantment;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.util.NbtSerialisable;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.StringTag;
import net.minecraft.util.Identifier;
import net.minecraft.util.Tickable;
import net.minecraft.util.registry.Registry;
public class Enchantments implements NbtSerialisable, Tickable {
private final Living<?> entity;
private final Set<Enchantment> equippedEnchantments = new HashSet<>();
private final Map<Enchantment, SimpleEnchantment.Data> data = new HashMap<>();
Enchantments(Living<?> entity) {
this.entity = entity;
}
@SuppressWarnings("unchecked")
public <T extends SimpleEnchantment.Data> Optional<T> getOrEmpty(Enchantment enchantment) {
return Optional.ofNullable((T)data.get(enchantment));
}
@SuppressWarnings("unchecked")
public <T extends SimpleEnchantment.Data> T computeIfAbsent(Enchantment enchantment, Supplier<T> factory) {
return (T)data.computeIfAbsent(enchantment, e -> factory.get());
}
@Nullable
@SuppressWarnings("unchecked")
public <T extends SimpleEnchantment.Data> T remove(Enchantment enchantment) {
return (T)data.remove(enchantment);
}
@Override
public void tick() {
UEnchantments.REGISTRY.forEach(ench -> {
int level = EnchantmentHelper.getEquipmentLevel(ench, entity.getMaster());
boolean active = level > 0;
if (active != equippedEnchantments.contains(ench)) {
if (active) {
equippedEnchantments.add(ench);
ench.onEquipped(entity);
} else {
equippedEnchantments.remove(ench);
ench.onUnequipped(entity);
}
}
if (active) {
ench.onUserTick(entity, level);
}
});
}
@Override
public void toNBT(CompoundTag compound) {
ListTag list = new ListTag();
equippedEnchantments.forEach(enchant -> {
Identifier id = Registry.ENCHANTMENT.getId(enchant);
if (id != null) {
list.add(StringTag.of(id.toString()));
}
});
compound.put("enchants", list);
}
@Override
public void fromNBT(CompoundTag compound) {
equippedEnchantments.clear();
if (compound.contains("enchants")) {
compound.getList("enchants", 8).forEach(tag -> {
Registry.ENCHANTMENT.getOrEmpty(new Identifier(tag.asString())).ifPresent(equippedEnchantments::add);
});
}
}
}

View file

@ -34,6 +34,8 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
private int invinsibilityTicks; private int invinsibilityTicks;
private final Enchantments enchants = new Enchantments(this);
protected Living(T entity, TrackedData<CompoundTag> effect) { protected Living(T entity, TrackedData<CompoundTag> effect) {
this.entity = entity; this.entity = entity;
this.effectDelegate = new EffectSync(this, effect); this.effectDelegate = new EffectSync(this, effect);
@ -58,6 +60,10 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
return effectDelegate; return effectDelegate;
} }
public Enchantments getEnchants() {
return enchants;
}
@Override @Override
public void setMaster(T owner) { public void setMaster(T owner) {
} }
@ -93,6 +99,8 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
if (getPhysics().isGravityNegative() && entity.getY() > entity.world.getHeight() + 64) { if (getPhysics().isGravityNegative() && entity.getY() > entity.world.getHeight() + 64) {
entity.damage(DamageSource.OUT_OF_WORLD, 4.0F); entity.damage(DamageSource.OUT_OF_WORLD, 4.0F);
} }
enchants.tick();
} }
@Override @Override
@ -152,4 +160,14 @@ public abstract class Living<T extends LivingEntity> implements Equine<T>, Caste
spell.getDisguise().onImpact(this, distance, damageMultiplier); spell.getDisguise().onImpact(this, distance, damageMultiplier);
}); });
} }
@Override
public void toNBT(CompoundTag compound) {
enchants.toNBT(compound);
}
@Override
public void fromNBT(CompoundTag compound) {
enchants.fromNBT(compound);
}
} }

View file

@ -0,0 +1,34 @@
package com.minelittlepony.unicopia.entity.ai;
import java.util.Optional;
import java.util.Set;
import com.google.common.collect.ImmutableSet;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.brain.MemoryModuleType;
import net.minecraft.entity.ai.brain.sensor.Sensor;
import net.minecraft.server.world.ServerWorld;
public class WantItNeedItSensor extends Sensor<LivingEntity> {
@Override
public Set<MemoryModuleType<?>> getOutputMemoryModules() {
return ImmutableSet.of(MemoryModuleType.ATTACK_TARGET, MemoryModuleType.VISIBLE_MOBS);
}
@Override
protected void sense(ServerWorld world, LivingEntity entity) {
entity.getBrain().getOptionalMemory(MemoryModuleType.VISIBLE_MOBS).ifPresent(targets -> {
Optional<LivingEntity> target = targets.stream()
.filter(e -> (EnchantmentHelper.getEquipmentLevel(UEnchantments.DESIRED, e) * 10) >= entity.distanceTo(e))
.findFirst();
entity.getBrain().remember(MemoryModuleType.ATTACK_TARGET, target);
});
}
}

View file

@ -0,0 +1,59 @@
package com.minelittlepony.unicopia.entity.ai;
import java.util.Comparator;
import java.util.Optional;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.TargetPredicate;
import net.minecraft.entity.ai.goal.Goal;
import net.minecraft.entity.mob.MobEntity;
public class WantItNeedItTargetGoal extends Goal {
private final TargetPredicate predicate;
private final MobEntity mob;
private int interval;
public WantItNeedItTargetGoal(MobEntity mob) {
this.predicate = new TargetPredicate()
.setBaseMaxDistance(64)
.setPredicate(WantItNeedItTargetGoal::canTarget);
this.mob = mob;
}
@Override
public boolean canStart() {
if (interval-- <= 0) {
interval = 20;
Optional<LivingEntity> target = mob.world.getOtherEntities(mob, mob.getBoundingBox().expand(16, 16, 16),
e -> e instanceof LivingEntity && predicate.test(mob, (LivingEntity)e))
.stream()
.map(e -> (LivingEntity)e)
.sorted(Comparator.comparing((Entity e) -> mob.distanceTo(e)))
.findFirst();
if (target.isPresent()) {
mob.setTarget(target.get());
return true;
}
}
return false;
}
@Override
public boolean shouldContinue() {
LivingEntity target = mob.getTarget();
return target != null && mob.isTarget(target, TargetPredicate.DEFAULT);
}
static boolean canTarget(LivingEntity e) {
return EnchantmentHelper.getEquipmentLevel(UEnchantments.DESIRED, e) > 0;
}
}

View file

@ -0,0 +1,140 @@
package com.minelittlepony.unicopia.entity.ai;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.Optional;
import javax.annotation.Nullable;
import com.minelittlepony.unicopia.AwaitTickQueue;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles;
import com.minelittlepony.unicopia.util.VecHelper;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.ItemEntity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.goal.Goal;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.item.ItemStack;
public class WantItTakeItGoal extends Goal {
private final MobEntity mob;
@Nullable
private LivingEntity target;
@Nullable
private ItemEntity item;
private int cooldown;
public WantItTakeItGoal(MobEntity mob) {
this.mob = mob;
this.setControls(EnumSet.of(Goal.Control.MOVE, Goal.Control.LOOK));
}
@Override
public boolean canStart() {
LivingEntity target = mob.getTarget();
if (target == null || !WantItNeedItTargetGoal.canTarget(target)) {
Optional<ItemEntity> item = VecHelper.findInRange(mob, mob.world, mob.getPos(), 16,
e -> !e.removed && e instanceof ItemEntity && EnchantmentHelper.getLevel(UEnchantments.DESIRED, ((ItemEntity)e).getStack()) > 0)
.stream()
.map(e -> (ItemEntity)e)
.sorted(Comparator.comparing((Entity e) -> mob.distanceTo(e)))
.findFirst();
if (item.isPresent()) {
this.item = item.get();
return true;
}
return false;
}
this.target = target;
return true;
}
@Override
public boolean shouldContinue() {
return (target == null || (
target.isAlive()
&& WantItNeedItTargetGoal.canTarget(target)
&& mob.squaredDistanceTo(target) <= 225))
&& (item == null || item.isAlive())
&& (!mob.getNavigation().isIdle() || canStart());
}
@Override
public void stop() {
target = null;
item = null;
mob.getNavigation().stop();
}
@Override
public void tick() {
if (target == null && (item == null || item.removed)) {
return;
}
Entity targetEntity = target == null ? item : target;
mob.getLookControl().lookAt(targetEntity, 30, 30);
double reach = mob.getWidth() * 2 * mob.getWidth() * 2;
double distance = mob.squaredDistanceTo(targetEntity.getX(), targetEntity.getY(), targetEntity.getZ());
double speed = 0.8D;
if (distance > reach && distance < 16) {
speed = 1.33;
} else if (distance < 225) {
speed = 0.6;
}
speed *= 2;
ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, mob, 0.2F), mob, 1);
mob.getNavigation().startMovingTo(targetEntity, speed);
cooldown = Math.max(this.cooldown - 1, 0);
if (distance <= reach) {
if (target != null) {
if (cooldown <= 0) {
cooldown = 20;
mob.tryAttack(target);
if (mob.world.random.nextInt(20) == 0) {
for (EquipmentSlot slot : EquipmentSlot.values()) {
ItemStack stack = target.getEquippedStack(slot);
if (EnchantmentHelper.getLevel(UEnchantments.DESIRED, stack) > 0) {
target.equipStack(slot, ItemStack.EMPTY);
AwaitTickQueue.scheduleTask(mob.world, w -> {
mob.tryEquip(stack);
}, 0);
}
}
}
}
} else {
ItemStack stack = item.getStack();
AwaitTickQueue.scheduleTask(mob.world, w -> {
if (!item.removed) {
mob.tryEquip(stack);
mob.method_29499(item);
mob.sendPickup(item, stack.getCount());
item.remove();
}
}, 0);
}
}
}
}

View file

@ -6,11 +6,13 @@ import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.ability.magic.Spell; import com.minelittlepony.unicopia.ability.magic.Spell;
import com.minelittlepony.unicopia.entity.EntityPhysics; import com.minelittlepony.unicopia.entity.EntityPhysics;
import com.minelittlepony.unicopia.entity.player.MagicReserves.Bar; import com.minelittlepony.unicopia.entity.player.MagicReserves.Bar;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.util.NbtSerialisable; import com.minelittlepony.unicopia.util.NbtSerialisable;
import com.minelittlepony.unicopia.util.MutableVector; import com.minelittlepony.unicopia.util.MutableVector;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityPose; import net.minecraft.entity.EntityPose;
import net.minecraft.entity.attribute.EntityAttributeInstance; import net.minecraft.entity.attribute.EntityAttributeInstance;
@ -196,6 +198,12 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
lastPos = new Vec3d(entity.getX(), 0, entity.getZ()); lastPos = new Vec3d(entity.getX(), 0, entity.getZ());
if (!entity.isOnGround()) {
float heavyness = 1 - EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, entity) * 0.015F;
velocity.x *= heavyness;
velocity.z *= heavyness;
}
entity.setVelocity(velocity.toImmutable()); entity.setVelocity(velocity.toImmutable());
} }
@ -245,12 +253,17 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
thrustScale *= 0.1889F; thrustScale *= 0.1889F;
} }
float heavyness = EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, player) / 6F;
float thrustStrength = 0.135F * thrustScale; float thrustStrength = 0.135F * thrustScale;
if (heavyness > 0) {
thrustStrength /= heavyness;
}
Vec3d direction = player.getRotationVec(1).normalize().multiply(thrustStrength); Vec3d direction = player.getRotationVec(1).normalize().multiply(thrustStrength);
velocity.x += direction.x; velocity.x += direction.x;
velocity.z += direction.z; velocity.z += direction.z;
velocity.y += (direction.y * 2.45 + Math.abs(direction.y) * 10) * getGravitySignum(); velocity.y += (direction.y * 2.45 + Math.abs(direction.y) * 10) * getGravitySignum() - heavyness / 5F;
if (player.isSneaking()) { if (player.isSneaking()) {
if (!isGravityNegative()) { if (!isGravityNegative()) {
@ -264,7 +277,7 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
} }
} }
protected void applyTurbulance(Entity player, MutableVector velocity) { protected void applyTurbulance(PlayerEntity player, MutableVector velocity) {
float glance = 360 * player.world.random.nextFloat(); float glance = 360 * player.world.random.nextFloat();
float forward = 0.015F * player.world.random.nextFloat() * player.world.getRainGradient(1); float forward = 0.015F * player.world.random.nextFloat() * player.world.getRainGradient(1);
@ -287,6 +300,7 @@ public class PlayerPhysics extends EntityPhysics<Pony> implements Tickable, Moti
} }
forward = Math.min(forward, 7); forward = Math.min(forward, 7);
forward /= 1 + (EnchantmentHelper.getEquipmentLevel(UEnchantments.HEAVY, player) * 0.8F);
velocity.x += - forward * MathHelper.sin((player.yaw + glance) * 0.017453292F); velocity.x += - forward * MathHelper.sin((player.yaw + glance) * 0.017453292F);
velocity.z += forward * MathHelper.cos((player.yaw + glance) * 0.017453292F); velocity.z += forward * MathHelper.cos((player.yaw + glance) * 0.017453292F);

View file

@ -276,10 +276,10 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
ticksHanging = 0; ticksHanging = 0;
} }
super.tick();
tickers.forEach(Tickable::tick); tickers.forEach(Tickable::tick);
super.tick();
if (dirty) { if (dirty) {
sendCapabilities(true); sendCapabilities(true);
} }
@ -376,6 +376,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
@Override @Override
public void toNBT(CompoundTag compound) { public void toNBT(CompoundTag compound) {
super.toNBT(compound);
compound.putString("playerSpecies", getSpecies().name()); compound.putString("playerSpecies", getSpecies().name());
compound.putFloat("magicExhaustion", magicExhaustion); compound.putFloat("magicExhaustion", magicExhaustion);
@ -392,6 +393,7 @@ public class Pony extends Living<PlayerEntity> implements Transmittable, Copieab
@Override @Override
public void fromNBT(CompoundTag compound) { public void fromNBT(CompoundTag compound) {
super.fromNBT(compound);
speciesPersisted = true; speciesPersisted = true;
setSpecies(Race.fromName(compound.getString("playerSpecies"))); setSpecies(Race.fromName(compound.getString("playerSpecies")));

View file

@ -5,6 +5,7 @@ import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import com.minelittlepony.unicopia.USounds; import com.minelittlepony.unicopia.USounds;
import com.minelittlepony.unicopia.item.enchantment.UEnchantments;
import com.minelittlepony.unicopia.item.toxin.ToxicHolder; import com.minelittlepony.unicopia.item.toxin.ToxicHolder;
import com.minelittlepony.unicopia.item.toxin.Toxics; import com.minelittlepony.unicopia.item.toxin.Toxics;
import com.minelittlepony.unicopia.item.toxin.UFoodComponents; import com.minelittlepony.unicopia.item.toxin.UFoodComponents;
@ -72,6 +73,7 @@ public interface UItems {
static void bootstrap() { static void bootstrap() {
Toxics.bootstrap(); Toxics.bootstrap();
UEnchantments.bootstrap();
URecipes.bootstrap(); URecipes.bootstrap();
FabricItemGroupBuilder.create(new Identifier("unicopia", "items")).appendItems(list -> { FabricItemGroupBuilder.create(new Identifier("unicopia", "items")).appendItems(list -> {
@ -81,7 +83,7 @@ public interface UItems {
.map(Item::getDefaultStack) .map(Item::getDefaultStack)
.collect(Collectors.toList()) .collect(Collectors.toList())
); );
}).icon(ZAP_APPLE::getDefaultStack).build(); }).icon(EMPTY_JAR::getDefaultStack).build();
FabricItemGroupBuilder.create(new Identifier("unicopia", "horsefeed")).appendItems(list -> { FabricItemGroupBuilder.create(new Identifier("unicopia", "horsefeed")).appendItems(list -> {
list.addAll(Registry.ITEM.stream() list.addAll(Registry.ITEM.stream()

View file

@ -0,0 +1,62 @@
package com.minelittlepony.unicopia.item.enchantment;
import java.util.HashMap;
import java.util.Map;
import java.util.function.IntFunction;
import com.minelittlepony.unicopia.entity.Living;
import net.minecraft.enchantment.EnchantmentTarget;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.attribute.EntityAttribute;
import net.minecraft.entity.attribute.EntityAttributeInstance;
import net.minecraft.entity.attribute.EntityAttributeModifier;
public class AttributedEnchantment extends SimpleEnchantment {
private final Map<EntityAttribute, IntFunction<EntityAttributeModifier>> modifiers = new HashMap<>();
protected AttributedEnchantment(Rarity rarity, EnchantmentTarget target, boolean cursed, int maxLevel, EquipmentSlot... slots) {
super(rarity, target, cursed, maxLevel, slots);
}
protected AttributedEnchantment(Rarity rarity, boolean cursed, int maxLevel, EquipmentSlot... slots) {
super(rarity, cursed, maxLevel, slots);
}
public AttributedEnchantment addModifier(EntityAttribute attribute, IntFunction<EntityAttributeModifier> modifierSupplier) {
modifiers.put(attribute, modifierSupplier);
return this;
}
@Override
public void onUserTick(Living<?> user, int level) {
if (shouldChangeModifiers(user, level)) {
LivingEntity entity = user.getMaster();
modifiers.forEach((attr, modifierSupplier) -> {
EntityAttributeInstance instance = entity.getAttributeInstance(attr);
EntityAttributeModifier modifier = modifierSupplier.apply(level);
instance.removeModifier(modifier.getId());
instance.addPersistentModifier(modifier);
});
}
}
@Override
public void onUnequipped(Living<?> user) {
LivingEntity entity = user.getMaster();
modifiers.forEach((attr, modifierSupplier) -> {
EntityAttributeInstance instance = entity.getAttributeInstance(attr);
instance.tryRemoveModifier(modifierSupplier.apply(1).getId());
});
user.getEnchants().remove(this);
}
protected boolean shouldChangeModifiers(Living<?> user, int level) {
return user.getEnchants().computeIfAbsent(this, Data::new).update(level);
}
}

View file

@ -0,0 +1,46 @@
package com.minelittlepony.unicopia.item.enchantment;
import com.minelittlepony.unicopia.UTags;
import com.minelittlepony.unicopia.client.sound.MagicAuraSoundInstance;
import com.minelittlepony.unicopia.entity.Living;
import net.minecraft.client.MinecraftClient;
import net.minecraft.enchantment.EnchantmentTarget;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
public class GemFindingEnchantment extends SimpleEnchantment {
protected GemFindingEnchantment() {
super(Rarity.RARE, EnchantmentTarget.DIGGER, false, 3, EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND);
}
@Override
public void onUserTick(Living<?> user, int level) {
int radius = 2 + (level * 2);
BlockPos origin = user.getOrigin();
float volume = BlockPos.findClosest(origin, radius, radius, pos -> user.getWorld().getBlockState(pos).isIn(UTags.INTERESTING))
.map(p -> user.getOriginVector().squaredDistanceTo(p.getX(), p.getY(), p.getZ()))
.map(find -> (1 - (MathHelper.sqrt(find) / radius)))
.orElse(-1F);
volume = Math.max(volume, 0.04F);
user.getEnchants().computeIfAbsent(this, Data::new).level = volume * (1.3F + level * 0.3F);
}
@Override
public void onEquipped(Living<?> user) {
if (user.isClient()) {
MinecraftClient.getInstance().getSoundManager().play(new MagicAuraSoundInstance(user.getEntity().getSoundCategory(), user));
}
}
@Override
public void onUnequipped(Living<?> user) {
user.getEnchants().remove(this).level = 0;
}
}

View file

@ -0,0 +1,71 @@
package com.minelittlepony.unicopia.item.enchantment;
import com.minelittlepony.unicopia.entity.Living;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.EnchantmentTarget;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.item.ItemStack;
public class SimpleEnchantment extends Enchantment {
private final boolean cursed;
private final boolean allItems;
private final int maxLevel;
protected SimpleEnchantment(Rarity rarity, EnchantmentTarget target, boolean cursed, int maxLevel, EquipmentSlot... slots) {
super(rarity, target, slots);
this.cursed = cursed;
this.allItems = false;
this.maxLevel = maxLevel;
}
protected SimpleEnchantment(Rarity rarity, boolean cursed, int maxLevel, EquipmentSlot... slots) {
super(rarity, EnchantmentTarget.VANISHABLE, slots); // vanishable includes breakable. It's the one that accepts the widest variety of items
this.cursed = cursed;
this.allItems = true;
this.maxLevel = maxLevel;
}
public void onUserTick(Living<?> user, int level) {
}
public void onEquipped(Living<?> user) {
}
public void onUnequipped(Living<?> user) {
}
@Override
public boolean isAcceptableItem(ItemStack itemStack) {
return allItems || super.isAcceptableItem(itemStack);
}
@Override
public int getMaxLevel() {
return maxLevel;
}
@Override
public boolean isCursed() {
return cursed;
}
public static class Data {
public float level;
public boolean update(int level) {
if (level == this.level) {
return false;
}
this.level = level;
return true;
}
}
}

View file

@ -0,0 +1,25 @@
package com.minelittlepony.unicopia.item.enchantment;
import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.entity.player.MagicReserves.Bar;
import com.minelittlepony.unicopia.entity.player.Pony;
import net.minecraft.entity.EquipmentSlot;
public class StressfulEnchantment extends SimpleEnchantment {
protected StressfulEnchantment() {
super(Rarity.COMMON, true, 3, EquipmentSlot.values());
}
@Override
public void onUserTick(Living<?> user, int level) {
if (user instanceof Pony) {
Bar bar = ((Pony)user).getMagicalReserves().getEnergy();
float targetPercent = (level / (float)getMaxLevel()) * 0.5F;
if (bar.getPercentFill() < targetPercent) {
bar.add(20);
}
}
}
}

View file

@ -0,0 +1,82 @@
package com.minelittlepony.unicopia.item.enchantment;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import net.minecraft.enchantment.Enchantment;
import net.minecraft.enchantment.Enchantment.Rarity;
import net.minecraft.entity.EquipmentSlot;
import net.minecraft.entity.attribute.EntityAttributeModifier;
import net.minecraft.entity.attribute.EntityAttributes;
import net.minecraft.entity.attribute.EntityAttributeModifier.Operation;
import net.minecraft.enchantment.EnchantmentTarget;
import net.minecraft.util.Identifier;
import net.minecraft.util.registry.Registry;
public interface UEnchantments {
List<SimpleEnchantment> REGISTRY = new ArrayList<>();
/**
* Makes a sound when there are interesting blocks in your area.
*/
Enchantment GEM_LOCATION = register("gem_location", new GemFindingEnchantment());
/**
* Protects against wall collisions and earth pony attacks!
*
* TODO:
*/
Enchantment PADDED = register("padded", new SimpleEnchantment(Rarity.COMMON, EnchantmentTarget.ARMOR, false, 3, EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET));
/**
* Heavy players move more slowly but are less likely to be flung around wildly.
*
* TODO:
*/
Enchantment HEAVY = register("heavy", new AttributedEnchantment(Rarity.COMMON, EnchantmentTarget.ARMOR_FEET, false, 4, EquipmentSlot.FEET))
.addModifier(EntityAttributes.GENERIC_MOVEMENT_SPEED, level -> {
// 1 -> 0.9
// 2 -> 0.8
// 3 -> 0.7
return new EntityAttributeModifier(UUID.fromString("a3d5a94f-4c40-48f6-a343-558502a13e10"), "Heavyness", (1 - level/(float)10) - 1, Operation.MULTIPLY_TOTAL);
});
/**
* It's dangerous to go alone, take this!
*
* Weapons will become stronger the more allies you have around.
*
* TODO:
*/
Enchantment COLLABORATOR = register("collaborator", new SimpleEnchantment(Rarity.COMMON, EnchantmentTarget.WEAPON, false, 1, EquipmentSlot.MAINHAND));
/**
* I want it, I neeeed it!
*
* Mobs really want your candy. You'd better give it to them.
*/
Enchantment DESIRED = register("desired", new WantItNeedItEnchantment());
/**
* Hahaha geddit?
*
* Random things happen.
*
* TODO:
*/
Enchantment POISON_JOKE = register("poison_joke", new SimpleEnchantment(Rarity.COMMON, true, 3, EquipmentSlot.values()));
/**
* Who doesn't like a good freakout?
*/
Enchantment STRESS = register("stress", new StressfulEnchantment());
static void bootstrap() { }
static <T extends SimpleEnchantment> T register(String name, T enchantment) {
REGISTRY.add(enchantment);
return Registry.register(Registry.ENCHANTMENT, new Identifier("unicopia", name), enchantment);
}
}

View file

@ -0,0 +1,23 @@
package com.minelittlepony.unicopia.item.enchantment;
import com.minelittlepony.unicopia.entity.Creature;
import com.minelittlepony.unicopia.entity.Living;
import com.minelittlepony.unicopia.particle.FollowingParticleEffect;
import com.minelittlepony.unicopia.particle.ParticleUtils;
import com.minelittlepony.unicopia.particle.UParticles;
import net.minecraft.entity.EquipmentSlot;
public class WantItNeedItEnchantment extends SimpleEnchantment {
protected WantItNeedItEnchantment() {
super(Rarity.VERY_RARE, true, 1, EquipmentSlot.values());
}
@Override
public void onUserTick(Living<?> user, int level) {
if (user instanceof Creature && user.getWorld().random.nextInt(10) == 0) {
ParticleUtils.spawnParticles(new FollowingParticleEffect(UParticles.HEALTH_DRAIN, user.getEntity(), 0.2F), user.getEntity(), 1);
}
}
}

View file

@ -22,6 +22,7 @@ import com.minelittlepony.unicopia.entity.ItemWielder;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.attribute.DefaultAttributeContainer;
import net.minecraft.entity.damage.DamageSource; import net.minecraft.entity.damage.DamageSource;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
@ -58,6 +59,11 @@ abstract class MixinLivingEntity extends Entity implements PonyContainer<Equine<
return caster; return caster;
} }
@Inject(method = "createLivingAttributes()Lnet/minecraft/entity/attribute/DefaultAttributeContainer$Builder;", at = @At("RETURN"))
private static void onCreateAttributes(CallbackInfoReturnable<DefaultAttributeContainer.Builder> info) {
Creature.registerAttributes(info.getReturnValue());
}
@Inject(method = "isClimbing()Z", at = @At("HEAD"), cancellable = true) @Inject(method = "isClimbing()Z", at = @At("HEAD"), cancellable = true)
public void onIsClimbing(CallbackInfoReturnable<Boolean> info) { public void onIsClimbing(CallbackInfoReturnable<Boolean> info) {
if (get() instanceof Pony && horizontalCollision) { if (get() instanceof Pony && horizontalCollision) {

View file

@ -0,0 +1,29 @@
package com.minelittlepony.unicopia.mixin;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.minelittlepony.unicopia.entity.Creature;
import com.minelittlepony.unicopia.entity.PonyContainer;
import com.minelittlepony.unicopia.entity.Equine;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.ai.goal.GoalSelector;
import net.minecraft.entity.mob.MobEntity;
@Mixin(MobEntity.class)
abstract class MixinMobEntity extends LivingEntity implements PonyContainer<Equine<?>> {
private MixinMobEntity() { super(null, null); }
@Shadow
protected @Final GoalSelector goalSelector;
@Shadow
protected @Final GoalSelector targetSelector;
@Inject(method = "<init>()V", at = @At("RETURN"), remap = false)
private void init(CallbackInfo info) {
((Creature)get()).initAi(goalSelector, targetSelector);
}
}

View file

@ -164,6 +164,14 @@
"key.unicopia.hud_page_dn": "Hud Previous Page", "key.unicopia.hud_page_dn": "Hud Previous Page",
"key.unicopia.hud_page_up": "Hud Next Page", "key.unicopia.hud_page_up": "Hud Next Page",
"enchantment.unicopia.gem_location": "Gem Locator",
"enchantment.unicopia.padded": "Padded",
"enchantment.unicopia.heavy": "Heavy",
"enchantment.unicopia.collaborator": "Collaborator",
"enchantment.unicopia.desired": "Want It Need It",
"enchantment.unicopia.poison_joke": "Poisoned Joke",
"enchantment.unicopia.stress": "Stressful",
"commands.race.success.self": "Your race has been updated", "commands.race.success.self": "Your race has been updated",
"commands.race.success.otherself": "%1$s changed race to %2$s", "commands.race.success.otherself": "%1$s changed race to %2$s",
"commands.race.success.other": "Changed %1$s's race to %2$s", "commands.race.success.other": "Changed %1$s's race to %2$s",

View file

@ -9,6 +9,12 @@
"unicopia:wing/wing3" "unicopia:wing/wing3"
] ]
}, },
"aura": {
"category": "player",
"sounds": [
"unicopia:aura/aura0"
]
},
"batpony_eeee": { "batpony_eeee": {
"category": "player", "category": "player",
"subtitle": "unicopia.subtitle.batpony_eeee", "subtitle": "unicopia.subtitle.batpony_eeee",

View file

@ -0,0 +1,18 @@
{
"replace": false,
"values": [
"minecraft:coal_ore",
"minecraft:iron_ore",
"minecraft:gold_ore",
"minecraft:emerald_ore",
"minecraft:lapis_ore",
"minecraft:diamond_ore",
"minecraft:nether_gold_ore",
"minecraft:nether_quartz_ore",
"minecraft:sea_lantern",
"minecraft:ender_chest",
"minecraft:end_portal_frame",
"minecraft:jukebox",
"minecraft:spawner"
]
}

View file

@ -13,6 +13,7 @@
"MixinItems", "MixinItems",
"MixinLivingEntity", "MixinLivingEntity",
"MixinMilkBucketItem", "MixinMilkBucketItem",
"MixinMobEntity",
"MixinPersistentProjectileEntity", "MixinPersistentProjectileEntity",
"MixinPlayerEntity", "MixinPlayerEntity",
"MixinProjectileEntity", "MixinProjectileEntity",