This commit is contained in:
Sollace 2018-09-12 01:29:49 +02:00
parent acd2ad866f
commit 69b340e640
80 changed files with 4111 additions and 0 deletions

View file

@ -0,0 +1,29 @@
package com.minelittlepony.unicopia;
import net.minecraft.nbt.NBTTagCompound;
public interface InbtSerialisable {
/**
* Called to save this to nbt to persist state on file or to transmit over the network
*
* @param compound Compound tag to write to.
*/
default void writeToNBT(NBTTagCompound compound) {
}
/**
* Called to load this state from nbt
*
* @param compound Compound tag to read from.
*/
default void readFromNBT(NBTTagCompound compound) {
}
default NBTTagCompound toNBT() {
NBTTagCompound compound = new NBTTagCompound();
writeToNBT(compound);
return compound;
}
}

View file

@ -0,0 +1,77 @@
package com.minelittlepony.unicopia;
import com.google.common.base.Strings;
import net.minecraft.client.resources.I18n;
public enum Race {
HUMAN(false, false, false),
EARTH(false, false, true),
UNICORN(true, false, false),
PEGASUS(false, true, false),
ALICORN(true, true, true),
CHANGELING(false, true, false);
private final boolean magic;
private final boolean flight;
private final boolean earth;
Race(boolean magic, boolean flight, boolean earth) {
this.magic = magic;
this.flight = flight;
this.earth = earth;
}
public boolean isDefault() {
return this == HUMAN;
}
public boolean canFly() {
return flight;
}
public boolean canCast() {
return magic;
}
public boolean canUseEarth() {
return earth;
}
public String getDisplayString() {
return I18n.format(getTranslationString());
}
public String getTranslationString() {
return String.format("unicopia.race.%s", name());
}
public boolean isSameAs(String s) {
return name().equalsIgnoreCase(s)
|| getTranslationString().equalsIgnoreCase(s)
|| getDisplayString().equalsIgnoreCase(s);
}
public static Race fromName(String s) {
if (!Strings.isNullOrEmpty(s)) {
for (Race i : values()) {
if (i.isSameAs(s)) return i;
}
}
return fromId(s);
}
public static Race fromId(String s) {
try {
int id = Integer.parseInt(s);
Race[] values = values();
if (id >= 0 || id < values.length) {
return values[id];
}
} catch (NumberFormatException e) { }
return HUMAN;
}
}

View file

@ -0,0 +1,9 @@
package com.minelittlepony.unicopia;
import net.minecraftforge.fml.common.FMLCommonHandler;
public interface UClient {
static boolean isClientSide() {
return FMLCommonHandler.instance().getSide().isServer();
}
}

View file

@ -0,0 +1,42 @@
package com.minelittlepony.unicopia;
import com.minelittlepony.unicopia.item.ItemApple;
import come.minelittlepony.unicopia.forgebullshit.RegistryLockSpinner;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.FurnaceRecipes;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.ModelLoader;
public class UItems {
public static final ItemApple apple = new ItemApple()
.setSubTypes("apple", "green", "sweet", "rotten", "zap", "zap_cooked")
.setTypeRarities(10, 20, 10, 30);
static void registerItems() {
RegistryLockSpinner.unlock(Item.REGISTRY);
Item.REGISTRY.register(260, new ResourceLocation("minecraft", "apple"), apple);
if (UClient.isClientSide()) {
String[] variants = apple.getVariants();
ResourceLocation app = new ResourceLocation("minecraft", "apple");
for (int i = 0; i < variants.length; i++) {
ModelLoader.setCustomModelResourceLocation(apple, i, new ModelResourceLocation(app, variants[i]));
}
}
RegistryLockSpinner.lock(Item.REGISTRY);
}
static void registerFuels() {
int zap = apple.getZapAppleMetadata();
FurnaceRecipes.instance().addSmeltingRecipe(
new ItemStack(UItems.apple, 1, zap),
new ItemStack(UItems.apple, 1, zap + 1), 0.1F);
}
}

View file

@ -0,0 +1,120 @@
package com.minelittlepony.unicopia;
import net.minecraft.entity.Entity;
import net.minecraft.item.EnumAction;
import net.minecraft.item.Item;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventBusSubscriber;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.ClientTickEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent.Phase;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import com.minelittlepony.jumpingcastle.api.IChannel;
import com.minelittlepony.jumpingcastle.api.JumpingCastle;
import com.minelittlepony.unicopia.client.particle.EntityMagicFX;
import com.minelittlepony.unicopia.client.particle.Particles;
import com.minelittlepony.unicopia.command.Commands;
import com.minelittlepony.unicopia.input.Keyboard;
import com.minelittlepony.unicopia.network.MsgPlayerAbility;
import com.minelittlepony.unicopia.network.MsgPlayerCapabilities;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import com.minelittlepony.unicopia.power.PowersRegistry;
import come.minelittlepony.unicopia.forgebullshit.FBS;
@Mod(modid = Unicopia.MODID, name = Unicopia.NAME, version = Unicopia.VERSION)
@EventBusSubscriber
public class Unicopia {
public static final String MODID = "unicopia";
public static final String NAME = "@NAME@";
public static final String VERSION = "@VERSION@";
public static IChannel channel;
public static int MAGIC_PARTICLE;
@EventHandler
public void preInit(FMLPreInitializationEvent event) {
}
@EventHandler
public void init(FMLInitializationEvent event) {
channel = JumpingCastle.listen(MODID)
.consume(MsgPlayerCapabilities.class, (msg, channel) -> {
PlayerSpeciesList.instance().handleSpeciesChange(msg.senderId, msg.newRace);
})
.consume(MsgPlayerAbility.class, (msg, channel) -> {
msg.applyServerAbility();
});
MAGIC_PARTICLE = Particles.instance().registerParticle(new EntityMagicFX.Factory());
PowersRegistry.instance().init();
FBS.init();
}
@SubscribeEvent
public static void registerItemsStatic(RegistryEvent.Register<Item> event) {
// Why won't you run!?
UItems.registerItems();
}
@SubscribeEvent
public static void onPlayerJoin(PlayerLoggedInEvent event) {
PlayerSpeciesList.instance().sendCapabilities(event.player.getGameProfile().getId());
}
@SideOnly(Side.CLIENT)
@SubscribeEvent
public static void onGameTick(TickEvent.ClientTickEvent event) {
if (event.phase == Phase.END) {
Keyboard.getKeyHandler().onKeyInput();
}
}
@SubscribeEvent
public static void onPlyerTick(TickEvent.PlayerTickEvent event) {
if (event.phase == Phase.END) {
PlayerSpeciesList.instance().getPlayer(event.player).onEntityUpdate();
}
}
@EventHandler
public void onServerStarted(FMLServerStartingEvent event) {
Commands.init(event);
}
@EventHandler
public void onPlayerRightClick(PlayerInteractEvent.RightClickItem event) {
// Why won't you run!?
if (!event.isCanceled()
&& event.getItemStack().getItemUseAction() == EnumAction.EAT) {
PlayerSpeciesList.instance().getPlayer(event.getEntityPlayer()).onEntityEat();
}
}
@SubscribeEvent
public static void attachCapabilities(AttachCapabilitiesEvent<Entity> event) {
// Why won't you run!?
FBS.attach(event);
}
@SubscribeEvent
public static void clonePlayer(PlayerEvent.Clone event) {
FBS.clone(event);
}
}

View file

@ -0,0 +1,80 @@
package com.minelittlepony.unicopia.client.particle;
import net.minecraft.client.particle.Particle;
import net.minecraft.client.particle.IParticleFactory;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.entity.Entity;
import net.minecraft.world.World;
public class EntityMagicFX extends Particle {
private float portalParticleScale;
private double portalPosX;
private double portalPosY;
private double portalPosZ;
public EntityMagicFX(World w, double x, double y, double z, double vX, double vY, double vZ) {
super(w, x, y, z, vX, vY, vZ);
motionX = vX;
motionY = vY;
motionZ = vZ;
portalPosX = posX = x;
portalPosY = posY = y;
portalPosZ = posZ = z;
portalParticleScale = particleScale = rand.nextFloat() * 0.2F + 0.5F;
particleMaxAge = (int)(Math.random() * 10) + 40;
setParticleTextureIndex((int)(Math.random() * 8));
particleRed = particleGreen = particleBlue = 1;
particleGreen *= 0.3F;
if (rand.nextBoolean()) particleBlue *= 0.4F;
if (rand.nextBoolean()) particleRed *= 0.9F;
if (rand.nextBoolean()) particleGreen += 0.5F;
if (rand.nextBoolean()) {
particleGreen *= 2F;
} else if (rand.nextBoolean()) {
particleRed *= 3.9F;
}
}
public void renderParticle(BufferBuilder renderer, Entity e, float p_70539_2_, float p_70539_3_, float p_70539_4_, float p_70539_5_, float p_70539_6_, float p_70539_7_) {
float f6 = 1 - ((particleAge + p_70539_2_) / particleMaxAge);
f6 = 1 - f6 * f6;
particleScale = portalParticleScale * f6;
super.renderParticle(renderer, e, p_70539_2_, p_70539_3_, p_70539_4_, p_70539_5_, p_70539_6_, p_70539_7_);
}
public int getBrightnessForRender(float p_70070_1_) {
int i = super.getBrightnessForRender(p_70070_1_);
float f1 = (float)particleAge / (float)particleMaxAge;
f1 *= f1;
f1 *= f1;
int j = i & 255;
int k = i >> 16 & 255;
k += f1 * 15 * 16;
if (k > 240) k = 240;
return j | k << 16;
}
public void onUpdate() {
prevPosX = posX;
prevPosY = posY;
prevPosZ = posZ;
float var1 = (float)particleAge / (float)particleMaxAge;
var1 = 1 + var1 - var1 * var1 * 2;
posX = portalPosX + motionX * var1;
posY = portalPosY + motionY;
posZ = portalPosZ + motionZ * var1;
if (particleAge++ >= particleMaxAge) setExpired();
}
public static class Factory implements IParticleFactory {
@Override
public Particle createParticle(int id, World w, double x, double y, double z, double vX, double vY, double vZ, int... args) {
return new EntityMagicFX(w, x, y, z, vX, vY, vZ);
}
}
}

View file

@ -0,0 +1,84 @@
package com.minelittlepony.unicopia.client.particle;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.particle.IParticleFactory;
import net.minecraft.client.particle.Particle;
import net.minecraft.entity.Entity;
public class Particles {
private static final Particles instance = new Particles();
public static Particles instance() {
return instance;
}
private final Minecraft mc = Minecraft.getMinecraft();
private final List<IParticleFactory> registeredParticles = new ArrayList<>();
public int registerParticle(IParticleFactory factory) {
int id = registeredParticles.size();
registeredParticles.add(factory);
return -id;
}
public Particle spawnParticle(int particleId, boolean ignoreDistance, double posX, double posY, double posZ, double speedX, double speedY, double speedZ, int ...pars) {
Entity entity = mc.getRenderViewEntity();
if (entity == null && mc.effectRenderer == null) {
return null;
}
double dX = entity.posX - posX;
double dY = entity.posY - posY;
double dZ = entity.posZ - posZ;
double distance = dX * dX + dY * dY + dZ * dZ;
if (ignoreDistance || (distance <= 1024 && calculateParticleLevel(false) < 2)) {
return spawnEffectParticle(particleId, posX, posY, posZ, speedX, speedY, speedZ, pars);
}
return null;
}
private Particle spawnEffectParticle(int particleId, double posX, double posY, double posZ, double speedX, double speedY, double speedZ, int ...pars) {
if (particleId >= 0) {
// Not ours, delegate to mojang
return mc.effectRenderer.spawnEffectParticle(particleId, posX, posY, posZ, speedX, speedY, speedZ, pars);
}
IParticleFactory iparticlefactory = registeredParticles.get(-particleId);
if (iparticlefactory == null) {
return null;
}
Particle particle = iparticlefactory.createParticle(particleId, mc.world, posX, posY, posZ, speedX, speedY, speedZ, pars);
if (particle == null) {
return null;
}
mc.effectRenderer.addEffect(particle);
return particle;
}
private int calculateParticleLevel(boolean minimiseLevel) {
int level = mc.gameSettings.particleSetting;
if (minimiseLevel && level == 2 && mc.world.rand.nextInt(10) == 0) {
level = 1;
}
if (level == 1 && mc.world.rand.nextInt(3) == 0) {
level = 2;
}
return level;
}
}

View file

@ -0,0 +1,48 @@
package com.minelittlepony.unicopia.command;
import com.minelittlepony.unicopia.player.IPlayer;
import net.minecraft.command.CommandException;
import net.minecraft.command.CommandGameMode;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.WrongUsageException;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.world.GameType;
class CommandOverrideGameMode extends CommandGameMode {
public void execute(MinecraftServer server, ICommandSender sender, String[] params) throws CommandException {
if (params.length <= 0) {
throw new WrongUsageException("commands.gamemode.usage");
}
GameType gametype = getGameModeFromCommand(sender, params[0]);
EntityPlayerMP entityplayermp = params.length >= 2 ? getPlayer(server, sender, params[1]) : getCommandSenderAsPlayer(sender);
updateGameMode(entityplayermp, gametype);
ITextComponent chatcomponenttranslation = new TextComponentTranslation("gameMode." + gametype.getName(), new Object[0]);
if (entityplayermp != sender) {
notifyCommandListener(sender, this, 1, "commands.gamemode.success.other", entityplayermp.getName(), chatcomponenttranslation);
} else {
notifyCommandListener(sender, this, 1, "commands.gamemode.success.self", chatcomponenttranslation);
}
}
private void updateGameMode(EntityPlayerMP player, GameType m) {
boolean flying = player.capabilities.isFlying;
player.setGameType(m);
player.capabilities.isFlying = ((IPlayer)player).getPlayerSpecies().canFly();
if (flying != player.capabilities.isFlying) {
player.sendPlayerAbilities();
}
player.fallDistance = 0;
}
}

View file

@ -0,0 +1,148 @@
package com.minelittlepony.unicopia.command;
import java.util.ArrayList;
import java.util.List;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.WrongUsageException;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.TextFormatting;
class CommandSpecies extends CommandBase {
public String getName() {
return "race";
}
public int getRequiredPermissionLevel() {
return 0;
}
public boolean checkPermission(MinecraftServer server, ICommandSender sender) {
return sender.canUseCommand(getRequiredPermissionLevel(), "help");
}
private String getRacesString() {
String values = "";
for (Race i : Race.values()) {
if (PlayerSpeciesList.instance().speciesPermitted(i)) {
if (values != "") values += ", ";
values += i.toString();
}
}
return values;
}
public String getUsage(ICommandSender sender) {
return "commands.race.usage";
}
public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException {
if (args.length < 1) {
throw new WrongUsageException(getUsage(sender));
}
EntityPlayerMP player;
int playerIndex = 1;
if (args[0].contentEquals("set")) playerIndex++;
if (args.length > playerIndex) {
player = getPlayer(server, sender, args[playerIndex]);
} else {
player = getCommandSenderAsPlayer(sender);
}
if (args[0].contentEquals("set")) {
if (args.length >= 2) {
Race species = Race.fromName(args[1]);
if (species == null) {
player.sendMessage(new TextComponentTranslation("commands.race.fail", args[1].toUpperCase()));
} else {
if (PlayerSpeciesList.instance().speciesPermitted(species)) {
IPlayer iplayer = PlayerSpeciesList.instance().getPlayer(player);
iplayer.setPlayerSpecies(species);
iplayer.sendCapabilities();
TextComponentTranslation formattedName = new TextComponentTranslation(species.name().toLowerCase());
if (player != sender) {
notifyCommandListener(sender, this, 1, "commands.race.success.other", player.getName(), formattedName);
} else {
player.sendMessage(new TextComponentTranslation("commands.race.success.self"));
notifyCommandListener(sender, this, 1, "commands.race.success.otherself", player.getName(), formattedName);
}
} else {
player.sendMessage(new TextComponentTranslation("commands.race.permission"));
}
}
}
} else if (args[0].contentEquals("get")) {
Race spec = PlayerSpeciesList.instance().getPlayer(player).getPlayerSpecies();
String name = "commands.race.tell.";
name += player == sender ? "self" : "other";
ITextComponent race = new TextComponentString(spec.getTranslationString());
TextComponentTranslation message = new TextComponentTranslation(name);
race.getStyle().setColor(TextFormatting.GOLD);
message.appendSibling(race);
player.sendMessage(message);
} else if (args[0].contentEquals("list")) {
player.sendMessage(new TextComponentTranslation("commands.race.list"));
ITextComponent message = new TextComponentString(" " + getRacesString());
message.getStyle().setColor(TextFormatting.GOLD);
player.sendMessage(message);
}
}
/**
* Adds the strings available in this command to the given list of tab completion options.
*/
public List<String> getTabCompletions(MinecraftServer server, ICommandSender par1ICommandSender, String[] args, BlockPos pos) {
if (args.length == 1) {
return getListOfStringsMatchingLastWord(args, new String[] { "get", "set", "list" });
} else if (args.length == 2 && args[0].contentEquals("set")) {
ArrayList<String> names = new ArrayList<String>();
for (Race i : Race.values()) {
if (PlayerSpeciesList.instance().speciesPermitted(i)) {
names.add(i.toString());
}
}
return getListOfStringsMatchingLastWord(args, names.toArray(new String[names.size()]));
} else if ((args.length == 3 && args[0].contentEquals("set")) || (args[0].contentEquals("get") && args.length == 2)) {
return getListOfStringsMatchingLastWord(args, server.getOnlinePlayerNames());
}
return null;
}
public boolean isUsernameIndex(String[] args, int index) {
if (args[0].contentEquals("get")) {
return index == 1;
} else if (args[0].contentEquals("set")) {
return index == 2;
}
return false;
}
}

View file

@ -0,0 +1,11 @@
package com.minelittlepony.unicopia.command;
import net.minecraftforge.fml.common.event.FMLServerStartingEvent;
public class Commands {
public static void init(FMLServerStartingEvent event) {
event.registerServerCommand(new CommandOverrideGameMode());
event.registerServerCommand(new CommandSpecies());
}
}

View file

@ -0,0 +1,11 @@
package com.minelittlepony.unicopia.input;
public interface IKeyBind {
String getKeyCategory();
String getKeyName();
int getKeyCode();
}

View file

@ -0,0 +1,10 @@
package com.minelittlepony.unicopia.input;
public interface IKeyHandler {
void addKeybind(IKeyBind bind);
default void onKeyInput() {
}
}

View file

@ -0,0 +1,20 @@
package com.minelittlepony.unicopia.input;
import com.minelittlepony.unicopia.UClient;
public final class Keyboard {
private static IKeyHandler keyHandler;
public static IKeyHandler getKeyHandler() {
if (keyHandler == null) {
if (UClient.isClientSide()) {
keyHandler = bind -> {};
}
keyHandler = new UKeyHandler();
}
return keyHandler;
}
}

View file

@ -0,0 +1,68 @@
package com.minelittlepony.unicopia.input;
import java.util.ArrayList;
import org.lwjgl.input.Keyboard;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import com.minelittlepony.unicopia.power.PowersRegistry;
import net.minecraft.client.Minecraft;
import net.minecraft.client.settings.KeyBinding;
import net.minecraftforge.fml.client.registry.ClientRegistry;
public class UKeyHandler implements IKeyHandler {
private static ArrayList<KeyBinding> bindings = new ArrayList<KeyBinding>();
private static ArrayList<KeyBinding> removed = new ArrayList<KeyBinding>();
private static ArrayList<KeyBinding> pressed = new ArrayList<KeyBinding>();
@Override
public void addKeybind(IKeyBind p) {
KeyBinding b = new KeyBinding(p.getKeyName(), p.getKeyCode(), p.getKeyCategory());
ClientRegistry.registerKeyBinding(b);
bindings.add(b);
}
@Override
public void onKeyInput() {
if (Minecraft.getMinecraft().currentScreen != null
|| Minecraft.getMinecraft().player == null) {
return;
}
IPlayer iplayer = PlayerSpeciesList.instance().getPlayer(Minecraft.getMinecraft().player);
for (KeyBinding i : bindings) {
if (Keyboard.isKeyDown(i.getKeyCode())) {
if (!pressed.contains(i)) {
pressed.add(i);
}
if (!PowersRegistry.instance().hasRegisteredPower(i.getKeyCodeDefault())) {
removed.add(i);
System.out.println("Error: Keybinding(" + i.getKeyDescription() + ") does not have a registered pony power. Keybinding will be removed from event.");
} else {
PowersRegistry.instance()
.getCapablePowerFromKey(i.getKeyCodeDefault(), iplayer.getPlayerSpecies())
.ifPresent(iplayer.getAbilities()::tryUseAbility);
}
} else {
if (pressed.contains(i)) {
pressed.remove(i);
iplayer.getAbilities().tryClearAbility();
}
}
}
for (KeyBinding i : removed) {
removed.remove(i);
bindings.remove(i);
pressed.remove(i);
}
}
}

View file

@ -0,0 +1,156 @@
package com.minelittlepony.unicopia.item;
import java.util.Random;
import com.minelittlepony.unicopia.UItems;
import com.minelittlepony.util.MagicalDamageSource;
import com.minelittlepony.util.vector.VecHelper;
import net.minecraft.block.BlockPlanks;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.effect.EntityLightningBolt;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.passive.EntityPig;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumRarity;
import net.minecraft.item.ItemFood;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
public class ItemApple extends ItemFood {
private int[] typeRarities = new int[0];
private String[] subTypes = new String[0];
private String[] variants = subTypes;
public int getRandomAppleMetadata(Random rand, Object variant) {
int[] rarity = typeRarities;
int result = 0;
for (int i = 0; i < rarity.length && i < subTypes.length; i++) {
if (rand.nextInt(rarity[i]) == 0) {
result++;
}
}
if (variant == BlockPlanks.EnumType.JUNGLE) {
result = result == 0 ? 1 : result == 1 ? 0 : result;
}
if (variant == BlockPlanks.EnumType.SPRUCE) {
result = result == 0 ? 3 : result == 3 ? 0 : result;
}
if (variant == BlockPlanks.EnumType.BIRCH) {
result = result == 0 ? 2 : result == 2 ? 0 : result;
}
if (variant == BlockPlanks.EnumType.DARK_OAK) {
result = result == 1 ? getZapAppleMetadata() : result == getZapAppleMetadata() ? 1 : result;
}
return result;
}
public ItemApple() {
super(4, 3, false);
setHasSubtypes(true);
setMaxDamage(0);
setTranslationKey("apple");
}
@Override
public ActionResult<ItemStack> onItemRightClick(World world, EntityPlayer player, EnumHand hand) {
RayTraceResult mop = VecHelper.getObjectMouseOver(player, 5, 0);
if (mop != null && mop.typeOfHit == RayTraceResult.Type.ENTITY) {
ItemStack stack = player.getHeldItem(hand);
if (canFeedTo(stack, mop.entityHit)) {
return onFedTo(stack, player, mop.entityHit);
}
}
return super.onItemRightClick(world, player, hand);
}
@Override
protected void onFoodEaten(ItemStack stack, World w, EntityPlayer player) {
super.onFoodEaten(stack, w, player);
if (isZapApple(stack)) {
player.attackEntityFrom(MagicalDamageSource.create("zap"), 120);
w.addWeatherEffect(new EntityLightningBolt(w, player.posX, player.posY, player.posZ, false));
}
}
public boolean canFeedTo(ItemStack stack, Entity e) {
return isZapApple(stack) && (e instanceof EntityVillager || e instanceof EntityCreeper || e instanceof EntityPig);
}
public boolean isZapApple(ItemStack stack) {
int meta = stack.getMetadata();
return meta == getZapAppleMetadata() || meta >= subTypes.length;
}
public ActionResult<ItemStack> onFedTo(ItemStack stack, EntityPlayer player, Entity e) {
e.onStruckByLightning(new EntityLightningBolt(e.world, e.posX, e.posY, e.posZ, false));
if (!player.capabilities.isCreativeMode) stack.shrink(1);
return new ActionResult<ItemStack>(EnumActionResult.SUCCESS, stack);
}
public int getZapAppleMetadata() {
return 4;
}
public ItemApple setSubTypes(String... types) {
subTypes = types;
variants = new String[subTypes.length * 2];
setTranslationKey(variants[0] = types[0]);
for (int i = 1; i < variants.length; i++) {
variants[i] = variants[0] + (i % subTypes.length != 0 ? "_" + subTypes[i % subTypes.length] : "");
}
return this;
}
public ItemApple setTypeRarities(int ... rarity) {
typeRarities = rarity;
return this;
}
public String[] getVariants() {
return variants;
}
@Override
public void getSubItems(CreativeTabs tab, NonNullList<ItemStack> items) {
for (int i = 0; i < subTypes.length; i++) {
items.add(new ItemStack(UItems.apple, 1, i));
}
}
@Override
public EnumRarity getRarity(ItemStack stack) {
int meta = stack.getMetadata();
if (meta == getZapAppleMetadata()) return EnumRarity.EPIC;
if (meta >= subTypes.length) return EnumRarity.RARE;
return EnumRarity.COMMON;
}
/*public String getItemStackDisplayName(ItemStack stack) {
String result = super.getItemStackDisplayName(stack);
if (stack.getMetadata() >= subTypes.length) {
return ChatColor.ITALIC + result;
}
return result;
}*/
@Override
public String getTranslationKey(ItemStack stack) {
int meta = stack.getMetadata() % subTypes.length;
if (meta < 0) meta = 0;
return super.getTranslationKey(stack) + (meta > 0 ? "." + subTypes[meta] : "");
}
@Override
public int getItemBurnTime(ItemStack stack) {
return stack.getMetadata() == 2 ? 150 : 0;
}
}

View file

@ -0,0 +1,51 @@
package com.minelittlepony.unicopia.network;
import java.util.UUID;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import com.minelittlepony.jumpingcastle.api.IMessage;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.power.IData;
import com.minelittlepony.unicopia.power.IPower;
import com.minelittlepony.unicopia.power.PowersRegistry;
import net.minecraft.entity.player.EntityPlayer;
@IMessage.Id(2)
public class MsgPlayerAbility implements IMessage {
private static final Gson gson = new GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create();
@Expose
private UUID senderId;
@Expose
private String powerIdentifier;
@Expose
private String abilityJson;
public MsgPlayerAbility(IPower<?> power, IData data) {
powerIdentifier = power.getKeyName();
abilityJson = gson.toJson(data, power.getPackageType());
}
public void applyServerAbility() {
PowersRegistry.instance().getPowerFromName(powerIdentifier).ifPresent(this::apply);
}
private <T extends IData> void apply(IPower<T> power) {
EntityPlayer player = IPlayer.getPlayerEntity(senderId);
if (player == null) {
return;
}
T data = gson.fromJson(abilityJson, power.getPackageType());
power.apply(player, data);
}
}

View file

@ -0,0 +1,28 @@
package com.minelittlepony.unicopia.network;
import java.util.UUID;
import com.google.gson.annotations.Expose;
import com.minelittlepony.jumpingcastle.api.IMessage;
import com.minelittlepony.unicopia.Race;
import net.minecraft.entity.player.EntityPlayer;
@IMessage.Id(1)
public class MsgPlayerCapabilities implements IMessage {
@Expose
public Race newRace;
@Expose
public UUID senderId;
public MsgPlayerCapabilities(Race race, EntityPlayer player) {
newRace = race;
senderId = player.getGameProfile().getId();
}
public MsgPlayerCapabilities(Race race, UUID playerId) {
newRace = race;
senderId = playerId;
}
}

View file

@ -0,0 +1,74 @@
package com.minelittlepony.unicopia.player;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.power.IPower;
import com.minelittlepony.unicopia.spell.IMagicEffect;
import net.minecraft.entity.player.EntityPlayer;
final class DefaultPlayerSpecies implements IPlayer, IAbilityReceiver {
public static final IPlayer INSTANCE = new DefaultPlayerSpecies();
private DefaultPlayerSpecies() {
}
@Override
public Race getPlayerSpecies() {
return Race.EARTH;
}
@Override
public void setPlayerSpecies(Race race) {
}
@Override
public void sendCapabilities() {
}
@Override
public void tryUseAbility(IPower<?> power) {
}
@Override
public void tryClearAbility() {
}
@Override
public int getRemainingCooldown() {
return 0;
}
@Override
public IAbilityReceiver getAbilities() {
return this;
}
@Override
public boolean isClientPlayer() {
return false;
}
@Override
public void onEntityUpdate() {
}
@Override
public void setEffect(IMagicEffect effect) {
}
@Override
public IMagicEffect getEffect() {
return null;
}
@Override
public EntityPlayer getOwner() {
return null;
}
}

View file

@ -0,0 +1,12 @@
package com.minelittlepony.unicopia.player;
import com.minelittlepony.unicopia.power.IPower;
public interface IAbilityReceiver {
void tryUseAbility(IPower<?> power);
void tryClearAbility();
int getRemainingCooldown();
}

View file

@ -0,0 +1,32 @@
package com.minelittlepony.unicopia.player;
import java.util.UUID;
import com.minelittlepony.unicopia.InbtSerialisable;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.spell.ICaster;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.fml.common.FMLCommonHandler;
public interface IPlayer extends ICaster<EntityPlayer>, InbtSerialisable {
Race getPlayerSpecies();
void setPlayerSpecies(Race race);
void sendCapabilities();
IAbilityReceiver getAbilities();
boolean isClientPlayer();
void onEntityUpdate();
default void onEntityEat() {
}
static EntityPlayer getPlayerEntity(UUID playerId) {
return FMLCommonHandler.instance().getMinecraftServerInstance().getPlayerList().getPlayerByUUID(playerId);
}
}

View file

@ -0,0 +1,7 @@
package com.minelittlepony.unicopia.player;
import net.minecraft.entity.player.EntityPlayer;
public interface IUpdatable {
void onUpdate(EntityPlayer entity);
}

View file

@ -0,0 +1,119 @@
package com.minelittlepony.unicopia.player;
import com.minelittlepony.jumpingcastle.api.Target;
import com.minelittlepony.unicopia.InbtSerialisable;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.network.MsgPlayerAbility;
import com.minelittlepony.unicopia.power.IData;
import com.minelittlepony.unicopia.power.IPower;
import com.minelittlepony.unicopia.power.PowersRegistry;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
class PlayerAbilityDelegate implements IAbilityReceiver, IUpdatable, InbtSerialisable {
private final IPlayer player;
private boolean abilityTriggered = false;
private int warmup = 0;
private int cooldown = 0;
private IPower<?> activeAbility = null;
public PlayerAbilityDelegate(IPlayer player) {
this.player = player;
}
boolean canSwitchStates() {
return abilityTriggered && cooldown <= 0;
}
@Override
public void tryUseAbility(IPower<?> power) {
if (canSwitchStates() || activeAbility != power) {
abilityTriggered = false;
activeAbility = power;
warmup = 0;
cooldown = power.getCooldownTime(player);
}
}
@Override
public void tryClearAbility() {
if (canSwitchStates() || activeAbility != null) {
abilityTriggered = false;
activeAbility = null;
warmup = 0;
cooldown = 0;
}
}
@Override
public int getRemainingCooldown() {
return cooldown;
}
@Override
public void onUpdate(EntityPlayer entity) {
if (activeAbility != null && activeAbility.canUse(player.getPlayerSpecies())) {
if (!abilityTriggered) {
if (warmup < activeAbility.getWarmupTime(player)) {
activeAbility.preApply(entity);
warmup++;
} else if (player.isClientPlayer()) {
if (activeAbility.canActivate(entity.getEntityWorld(), player)) {
abilityTriggered = activateAbility(entity);
if (!abilityTriggered) {
activeAbility = null;
cooldown = 0;
}
} else {
activeAbility = null;
cooldown = 0;
}
}
} else if (cooldown > 0) {
activeAbility.postApply(entity);
cooldown--;
}
}
}
@Override
public void writeToNBT(NBTTagCompound compound) {
compound.setBoolean("triggered", abilityTriggered);
compound.setInteger("warmup", warmup);
compound.setInteger("cooldown", cooldown);
if (activeAbility != null) {
compound.setString("activeAbility", activeAbility.getKeyName());
}
}
@Override
public void readFromNBT(NBTTagCompound compound) {
activeAbility = null;
abilityTriggered = compound.getBoolean("triggered");
warmup = compound.getInteger("warmup");
cooldown = compound.getInteger("cooldown");
if (compound.hasKey("activeAbility")) {
PowersRegistry.instance().getPowerFromName(compound.getString("activeAbility")).ifPresent(p -> {
activeAbility = p;
});
}
}
protected boolean activateAbility(EntityPlayer entity) {
IData data = activeAbility.tryActivate(entity, entity.getEntityWorld());
if (data != null) {
Unicopia.channel.send(new MsgPlayerAbility(activeAbility, data), Target.SERVER);
}
return data != null;
}
}

View file

@ -0,0 +1,144 @@
package com.minelittlepony.unicopia.player;
import java.util.UUID;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UClient;
import com.minelittlepony.unicopia.spell.ICaster;
import com.minelittlepony.unicopia.spell.IMagicEffect;
import com.minelittlepony.unicopia.spell.SpellRegistry;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.MobEffects;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.potion.PotionEffect;
class PlayerCapabilities implements IPlayer, ICaster<EntityPlayer> {
private Race playerSpecies = Race.HUMAN;
private UUID playerId;
private final PlayerAbilityDelegate powers = new PlayerAbilityDelegate(this);
private final PlayerGravityDelegate gravity = new PlayerGravityDelegate(this);
private IMagicEffect effect;
PlayerCapabilities(UUID playerId) {
this.playerId = playerId;
}
@Override
public Race getPlayerSpecies() {
return playerSpecies;
}
@Override
public void setPlayerSpecies(Race race) {
if (race == playerSpecies) {
return;
}
playerSpecies = race;
EntityPlayer self = getOwner();
self.capabilities.allowFlying = race.canFly();
gravity.updateFlightStat(self, self.capabilities.isFlying);
self.sendPlayerAbilities();
}
@Override
public void sendCapabilities() {
PlayerSpeciesList.instance().sendCapabilities(playerId);
}
@Override
public IAbilityReceiver getAbilities() {
return powers;
}
@Override
public boolean isClientPlayer() {
return UClient.isClientSide() &&
Minecraft.getMinecraft().player.getGameProfile().getId().equals(playerId);
}
@Override
public void onEntityUpdate() {
EntityPlayer player = getOwner();
powers.onUpdate(player);
gravity.onUpdate(player);
if (!getPlayerSpecies().canCast()) {
effect = null;
}
if (effect != null) {
if (player.getEntityWorld().isRemote && player.getEntityWorld().getWorldTime() % 10 == 0) {
effect.render(player);
}
if (!effect.update(player)) {
effect = null;
}
}
}
public void onEntityEat() {
if (getPlayerSpecies() == Race.CHANGELING) {
EntityPlayer player = getOwner();
player.addPotionEffect(new PotionEffect(MobEffects.WEAKNESS, 2000, 2));
player.addPotionEffect(new PotionEffect(MobEffects.NAUSEA, 2000, 2));
}
}
@Override
public void writeToNBT(NBTTagCompound compound) {
compound.setUniqueId("playerId", playerId);
compound.setString("playerSpecies", playerSpecies.name());
compound.setTag("powers", powers.toNBT());
compound.setTag("gravity", gravity.toNBT());
if (effect != null) {
compound.setString("effect_id", effect.getName());
compound.setTag("effect", effect.toNBT());
}
}
@Override
public void readFromNBT(NBTTagCompound compound) {
playerId = compound.getUniqueId("playerId");
playerSpecies = Race.fromName(compound.getString("playerSpecies"));
powers.readFromNBT(compound.getCompoundTag("powers"));
gravity.readFromNBT(compound.getCompoundTag("gravity"));
if (compound.hasKey("effect_id") && compound.hasKey("effect")) {
effect = null;
SpellRegistry.instance().getSpellFromName(compound.getString("effect_id")).ifPresent(f -> {
effect = f;
effect.readFromNBT(compound.getCompoundTag("effect"));
});
}
}
@Override
public void setEffect(IMagicEffect effect) {
this.effect = effect;
}
@Override
public IMagicEffect getEffect() {
return effect;
}
@Override
public EntityPlayer getOwner() {
return IPlayer.getPlayerEntity(playerId);
}
}

View file

@ -0,0 +1,68 @@
package com.minelittlepony.unicopia.player;
import com.minelittlepony.unicopia.InbtSerialisable;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
class PlayerGravityDelegate implements IUpdatable, InbtSerialisable {
private final IPlayer player;
private int ticksSinceLanding = 0;
public boolean isFlying = false;
public PlayerGravityDelegate(IPlayer player) {
this.player = player;
}
@Override
public void onUpdate(EntityPlayer entity) {
if (!entity.capabilities.isCreativeMode) {
if (player.getPlayerSpecies().canFly()) {
if (ticksSinceLanding < 2) {
ticksSinceLanding++;
}
entity.capabilities.allowFlying = entity.capabilities.isFlying = false;
}
}
if (entity.capabilities.isFlying) {
entity.fallDistance = 0;
}
}
public void updateFlightStat(EntityPlayer entity, boolean flying) {
if (!entity.capabilities.isCreativeMode) {
entity.capabilities.allowFlying = player.getPlayerSpecies().canFly();
if (entity.capabilities.allowFlying) {
entity.capabilities.isFlying |= flying;
isFlying = entity.capabilities.isFlying;
if (isFlying) {
ticksSinceLanding = 0;
}
} else {
entity.capabilities.isFlying = false;
isFlying = false;
}
}
}
@Override
public void writeToNBT(NBTTagCompound compound) {
compound.setInteger("ticksOnGround", ticksSinceLanding);
compound.setBoolean("isFlying", isFlying);
}
@Override
public void readFromNBT(NBTTagCompound compound) {
ticksSinceLanding = compound.getInteger("ticksOnGround");
isFlying = compound.getBoolean("isFlying");
}
}

View file

@ -0,0 +1,62 @@
package com.minelittlepony.unicopia.player;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import com.minelittlepony.jumpingcastle.api.Target;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.network.MsgPlayerCapabilities;
import come.minelittlepony.unicopia.forgebullshit.FBS;
import come.minelittlepony.unicopia.forgebullshit.IPlayerCapabilitiesProxyContainer;
import net.minecraft.entity.player.EntityPlayer;
public class PlayerSpeciesList {
private static final PlayerSpeciesList instance = new PlayerSpeciesList();
public static PlayerSpeciesList instance() {
return instance;
}
private List<Race> serverPermittedRaces = new ArrayList<>();
public boolean speciesPermitted(Race race) {
return race.isDefault() || serverPermittedRaces.isEmpty() || serverPermittedRaces.contains(race);
}
public void sendCapabilities(UUID playerId) {
Unicopia.channel.send(new MsgPlayerCapabilities(getPlayer(playerId).getPlayerSpecies(), playerId), Target.SERVER_AND_CLIENTS);
}
public void handleSpeciesChange(UUID playerId, Race race) {
getPlayer(playerId).setPlayerSpecies(race);
}
public IPlayer emptyPlayer(UUID playerId) {
return new PlayerCapabilities(playerId);
}
public IPlayer getPlayer(EntityPlayer player) {
if (player == null) {
return DefaultPlayerSpecies.INSTANCE;
}
IPlayerCapabilitiesProxyContainer container = FBS.of(player);
IPlayer ply = container.getPlayer();
if (ply == null) {
ply = emptyPlayer(player.getGameProfile().getId());
container.setPlayer(ply);
}
return ply;
}
public IPlayer getPlayer(UUID playerId) {
return getPlayer(IPlayer.getPlayerEntity(playerId));
}
}

View file

@ -0,0 +1,5 @@
package com.minelittlepony.unicopia.power;
public interface IData {
}

View file

@ -0,0 +1,129 @@
package com.minelittlepony.unicopia.power;
import java.util.Random;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.client.particle.Particles;
import com.minelittlepony.unicopia.input.IKeyBind;
import com.minelittlepony.unicopia.player.IPlayer;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.DamageSource;
import net.minecraft.world.World;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public interface IPower<T extends IData> extends IKeyBind {
/**
* Subtracts a given food amount from the player.
* Harms the player if there is not enough enough hunger available.
*/
static boolean takeFromPlayer(EntityPlayer player, double foodSubtract) {
if (!player.capabilities.isCreativeMode) {
int food = (int)(player.getFoodStats().getFoodLevel() - foodSubtract);
if (food < 0) {
player.getFoodStats().addStats(-player.getFoodStats().getFoodLevel(), 0);
player.attackEntityFrom(DamageSource.MAGIC, -food);
} else {
player.getFoodStats().addStats((int)-foodSubtract, 0);
}
}
return player.getHealth() > 0;
}
static double getPlayerEyeYPos(EntityPlayer player) {
if (player.getEntityWorld().isRemote) {
return player.posY + player.getEyeHeight() - player.getYOffset();
}
return player.posY + player.getEyeHeight() - 1;
}
static void spawnParticles(int particleId, EntityPlayer player, int count) {
double halfDist = player.getEyeHeight() / 1.5;
double middle = player.getEntityBoundingBox().minY + halfDist;
Random rand = player.getEntityWorld().rand;
for (int i = 0; i < count; i++) {
double x = (rand.nextFloat() * halfDist) - halfDist;
double y = (rand.nextFloat() * halfDist) - halfDist;
double z = (rand.nextFloat() * halfDist) - halfDist;
Particles.instance().spawnParticle(particleId, false,
player.posX + x,
middle + y,
player.posZ + z,
0, 0, 0);
}
}
@Override
default String getKeyCategory() {
return "unicopia.category.name";
}
/**
* Returns the number of ticks the player must hold the ability key to trigger this ability.
*/
int getWarmupTime(IPlayer player);
/**
* Returns the number of ticks allowed for cooldown
*/
int getCooldownTime(IPlayer player);
/**
* Called to check preconditions for activating the ability.
*
* @param w The world
* @param player The player
* @return True to allow activation
*/
default boolean canActivate(World w, IPlayer player) {
return true;
}
/**
* Checks if the given race is permitted to use this ability
* @param playerSpecies The player's species
*/
boolean canUse(Race playerSpecies);
/**
* Called on the client to activate the ability.
*
* @param player The player activating the ability
* @param w The player's world
* @return Data to be sent, or null if activation failed
*/
T tryActivate(EntityPlayer player, World w);
Class<T> getPackageType();
/**
* Called to actually apply the ability.
* Only called on the server side.
*
* @param player The player that triggered the ability
* @param data Data previously sent from the client
*/
@SideOnly(Side.SERVER)
void apply(EntityPlayer player, T data);
/**
* Called just before the ability is activated.
* @param player The current player
*/
@SideOnly(Side.CLIENT)
void preApply(EntityPlayer player);
/**
* Called every tick until the cooldown timer runs out.
* @param player The current player
*/
@SideOnly(Side.CLIENT)
void postApply(EntityPlayer player);
}

View file

@ -0,0 +1,137 @@
package com.minelittlepony.unicopia.power;
import java.util.ArrayList;
import java.util.List;
import org.lwjgl.input.Keyboard;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.client.particle.Particles;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.power.data.Hit;
import com.minelittlepony.util.MagicalDamageSource;
import com.minelittlepony.util.vector.VecHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EnumCreatureType;
import net.minecraft.entity.passive.EntityCow;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.MobEffects;
import net.minecraft.potion.PotionEffect;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.world.World;
public class PowerFeed implements IPower<Hit> {
@Override
public String getKeyName() {
return "unicopia.power.feed";
}
@Override
public int getKeyCode() {
return Keyboard.KEY_N;
}
@Override
public int getWarmupTime(IPlayer player) {
return 20;
}
@Override
public int getCooldownTime(IPlayer player) {
return 50;
}
@Override
public boolean canUse(Race playerSpecies) {
return playerSpecies == Race.CHANGELING;
}
@Override
public Hit tryActivate(EntityPlayer player, World w) {
if (player.getHealth() < player.getMaxHealth() || player.canEat(false)) {
Entity i = VecHelper.getLookedAtEntity(player, 10);
if (i != null && canDrain(i)) {
return new Hit();
}
}
return null;
}
private boolean canDrain(Entity e) {
return e instanceof EntityCow
|| e instanceof EntityVillager
|| e instanceof EntityPlayer
|| EnumCreatureType.MONSTER.getCreatureClass().isAssignableFrom(e.getClass());
}
@Override
public Class<Hit> getPackageType() {
return Hit.class;
}
@Override
public void apply(EntityPlayer player, Hit data) {
List<Entity> list = new ArrayList<Entity>();
for (Entity i : VecHelper.getWithinRange(player, 3)) {
if (canDrain(i)) list.add(i);
}
Entity looked = VecHelper.getLookedAtEntity(player, 10);
if (looked != null && !list.contains(looked)) {
list.add(looked);
}
float lostHealth = player.getMaxHealth() - player.getHealth();
if (lostHealth > 0 || player.canEat(false)) {
float totalDrained = (lostHealth < 2 ? lostHealth : 2);
float drained = totalDrained / list.size();
for (Entity i : list) {
DamageSource d = MagicalDamageSource.causePlayerDamage("feed", player);
if (EnumCreatureType.CREATURE.getCreatureClass().isAssignableFrom(i.getClass())
|| player.world.rand.nextFloat() > 0.95f) {
i.attackEntityFrom(d, Integer.MAX_VALUE);
} else {
i.attackEntityFrom(d, drained);
}
}
if (lostHealth > 0) {
player.getFoodStats().addStats(3, 0.125f);
player.heal(totalDrained);
} else {
player.getFoodStats().addStats(3, 0.25f);
}
if (player.world.rand.nextFloat() > 0.9f) {
player.addPotionEffect(new PotionEffect(MobEffects.WITHER, 20, 1));
}
if (player.world.rand.nextFloat() > 0.4f) {
player.removePotionEffect(MobEffects.NAUSEA);
}
}
}
@Override
public void preApply(EntityPlayer player) { }
@Override
public void postApply(EntityPlayer player) {
for (int i = 0; i < 10; i++) {
Particles.instance().spawnParticle(EnumParticleTypes.HEART.getParticleID(), false,
player.posX + player.world.rand.nextFloat() * 2 - 1,
player.posY + player.world.rand.nextFloat() * 2 - 1,
player.posZ + player.world.rand.nextFloat() * 2 - 1,
0, 0.25, 0);
}
}
}

View file

@ -0,0 +1,115 @@
package com.minelittlepony.unicopia.power;
import org.lwjgl.input.Keyboard;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.power.data.Location;
import com.minelittlepony.util.vector.VecHelper;
import net.minecraft.block.BlockDoublePlant;
import net.minecraft.block.BlockGrass;
import net.minecraft.block.IGrowable;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemDye;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
public class PowerGrow implements IPower<Location> {
@Override
public String getKeyName() {
return "unicopia.power.grow";
}
@Override
public int getKeyCode() {
return Keyboard.KEY_N;
}
@Override
public int getWarmupTime(IPlayer player) {
return 10;
}
@Override
public int getCooldownTime(IPlayer player) {
return 50;
}
@Override
public boolean canUse(Race playerSpecies) {
return playerSpecies == Race.EARTH;
}
@Override
public Location tryActivate(EntityPlayer player, World w) {
RayTraceResult ray = VecHelper.getObjectMouseOver(player, 3, 1);
if (ray != null && ray.typeOfHit == RayTraceResult.Type.BLOCK) {
return new Location(ray.getBlockPos());
}
return null;
}
@Override
public Class<Location> getPackageType() {
return Location.class;
}
@Override
public void apply(EntityPlayer player, Location data) {
int count = 0;
for (BlockPos pos : BlockPos.getAllInBox(
new BlockPos(data.x - 2, data.y - 2, data.z - 2),
new BlockPos(data.x + 2, data.y + 2, data.z + 2))) {
count += applySingle(player.world, player.world.getBlockState(pos), pos);
}
if (count > 0) {
IPower.takeFromPlayer(player, count * 5);
}
}
protected int applySingle(World w, IBlockState state, BlockPos pos) {
if (state.getBlock() instanceof IGrowable
&& !(state.getBlock() instanceof BlockGrass)) {
IGrowable g = ((IGrowable)state.getBlock());
if (g.canGrow(w, pos, state, w.isRemote) && g.canUseBonemeal(w, w.rand, pos, state)) {
do {
if (ItemDye.applyBonemeal(new ItemStack(Items.DYE, 1), w, pos)) {
w.playEvent(2005, pos, 0);
if (g instanceof BlockDoublePlant) {
w.playEvent(2005, pos.up(), 0);
}
}
state = w.getBlockState(pos);
g = ((IGrowable)state.getBlock());
} while (g.canGrow(w, pos, state, w.isRemote));
return 1;
}
}
return 0;
}
@Override
public void preApply(EntityPlayer player) {
IPower.spawnParticles(com.minelittlepony.unicopia.Unicopia.MAGIC_PARTICLE, player, 1);
}
@Override
public void postApply(EntityPlayer player) {
}
}

View file

@ -0,0 +1,81 @@
package com.minelittlepony.unicopia.power;
import org.lwjgl.input.Keyboard;
import com.google.gson.annotations.Expose;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import com.minelittlepony.unicopia.spell.SpellShield;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.World;
public class PowerMagic implements IPower<PowerMagic.Magic> {
@Override
public String getKeyName() {
return "unicopia.power.magic";
}
@Override
public int getKeyCode() {
return Keyboard.KEY_P;
}
@Override
public int getWarmupTime(IPlayer player) {
if (player.hasEffect() && "shield".contentEquals(player.getEffect().getName())) {
return 0;
}
return 20;
}
@Override
public int getCooldownTime(IPlayer player) {
return 0;
}
@Override
public boolean canUse(Race playerSpecies) {
return playerSpecies.canCast();
}
@Override
public Magic tryActivate(EntityPlayer player, World w) {
return new Magic(0);
}
@Override
public Class<Magic> getPackageType() {
return Magic.class;
}
@Override
public void apply(EntityPlayer player, Magic data) {
IPlayer prop = PlayerSpeciesList.instance().getPlayer(player);
if (prop.getEffect() instanceof SpellShield) {
prop.setEffect(null);
} else {
prop.setEffect(new SpellShield(data.type));
}
}
@Override
public void preApply(EntityPlayer player) { }
@Override
public void postApply(EntityPlayer player) { }
class Magic implements IData {
@Expose
public int type;
public Magic(int strength) {
type = strength;
}
}
}

View file

@ -0,0 +1,405 @@
package com.minelittlepony.unicopia.power;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import org.lwjgl.input.Keyboard;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UItems;
import com.minelittlepony.unicopia.client.particle.Particles;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import com.minelittlepony.unicopia.power.data.Location;
import com.minelittlepony.util.MagicalDamageSource;
import com.minelittlepony.util.PosHelper;
import com.minelittlepony.util.shape.IShape;
import com.minelittlepony.util.shape.Sphere;
import com.minelittlepony.util.vector.VecHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLeaves;
import net.minecraft.block.BlockLog;
import net.minecraft.block.material.Material;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import static net.minecraft.util.EnumFacing.*;
public class PowerStomp implements IPower<PowerStomp.Data> {
@Override
public String getKeyName() {
return "unicopia.power.earth";
}
@Override
public int getKeyCode() {
return Keyboard.KEY_M;
}
@Override
public int getWarmupTime(IPlayer player) {
return 0;
}
@Override
public int getCooldownTime(IPlayer player) {
return 500;
}
@Override
public boolean canUse(Race playerSpecies) {
return playerSpecies.canUseEarth();
}
@Override
public PowerStomp.Data tryActivate(EntityPlayer player, World w) {
RayTraceResult mop = VecHelper.getObjectMouseOver(player, 2, 1);
if (mop != null && mop.typeOfHit == RayTraceResult.Type.BLOCK) {
BlockPos pos = mop.getBlockPos();
IBlockState state = w.getBlockState(pos);
if (state.getBlock() instanceof BlockLog) {
pos = getBaseOfTree(w, state, pos);
if (measureTree(w, state, pos) > 0) {
return new Data(pos.getX(), pos.getY(), pos.getZ(), 1);
}
}
}
if (!player.onGround && !player.capabilities.isFlying) {
player.addVelocity(0, -6, 0);
return new Data(0, 0, 0, 0);
}
return null;
}
@Override
public Class<PowerStomp.Data> getPackageType() {
return PowerStomp.Data.class;
}
@Override
public void apply(EntityPlayer player, Data data) {
double rad = 4;
if (data.hitType == 0) {
player.addVelocity(0, -6, 0);
BlockPos pos = player.getPosition();
AxisAlignedBB box = new AxisAlignedBB(player.posX - rad, player.posY - rad, player.posZ - rad, player.posX + rad, player.posY + rad, player.posZ + rad);
List<Entity> entities = player.world.getEntitiesWithinAABBExcludingEntity(player, box);
for (Entity i : entities) {
double dist = Math.sqrt(i.getDistanceSq(pos));
if (dist <= rad + 3) {
i.addVelocity(i.posX - player.posX, i.posY - player.posY, i.posZ - player.posZ);
DamageSource damage = MagicalDamageSource.causePlayerDamage("smash", player);
float amount = 4 / (float)dist;
if (i instanceof EntityPlayer) {
Race race = PlayerSpeciesList.instance().getPlayer((EntityPlayer)i).getPlayerSpecies();
if (race.canUseEarth()) amount /= 3;
if (race.canFly()) amount *= 4;
}
i.attackEntityFrom(damage, amount);
}
}
Iterable<BlockPos> area = BlockPos.getAllInBox(pos.add(-rad, -rad, -rad), pos.add(rad, rad, rad));
for (BlockPos i : area) {
if (i.distanceSqToCenter(player.posX, player.posY, player.posZ) <= rad*rad) {
spawnEffect(player.world, i);
}
}
for (int i = 1; i < 202; i+= 2) {
spawnParticleRing(player, i);
}
IPower.takeFromPlayer(player, 4);
} else if (data.hitType == 1) {
if (player.world.rand.nextInt(30) == 0) {
removeTree(player.world, new BlockPos(data.x, data.y, data.z));
} else {
dropApples(player.world, new BlockPos(data.x, data.y, data.z));
}
IPower.takeFromPlayer(player, 1);
}
}
private void spawnEffect(World w, BlockPos pos) {
IBlockState state = w.getBlockState(pos);
if (state.getBlock() != Blocks.AIR) {
if (w.getBlockState(pos.up()).getBlock() == Blocks.AIR) {
w.playEvent(2001, pos, Block.getStateId(state));
}
}
}
@Override
public void preApply(EntityPlayer player) {
player.spawnRunningParticles();
}
@Override
public void postApply(EntityPlayer player) {
IPlayer prop = PlayerSpeciesList.instance().getPlayer(player);
int timeDiff = getCooldownTime(prop) - prop.getAbilities().getRemainingCooldown();
if (player.world.getWorldTime() % 1 == 0 || timeDiff == 0) {
spawnParticleRing(player, timeDiff, 1);
}
}
private void spawnParticleRing(EntityPlayer player, int timeDiff) {
spawnParticleRing(player, timeDiff, 0);
}
private void spawnParticleRing(EntityPlayer player, int timeDiff, double yVel) {
int animationTicks = (int)(timeDiff / 10);
if (animationTicks < 6) {
IShape shape = new Sphere(true, animationTicks, 1, 0, 1);
double y = 0.5 + (Math.sin(animationTicks) * 1.5);
yVel *= y * 5;
for (int i = 0; i < shape.getVolumeOfSpawnableSpace(); i++) {
Vec3d point = shape.computePoint(player.getEntityWorld().rand);
Particles.instance().spawnParticle(EnumParticleTypes.BLOCK_CRACK.getParticleID(), false,
player.posX + point.x,
player.posY + y + point.y,
player.posZ + point.z,
0, yVel, 0,
Block.getStateId(Blocks.DIRT.getDefaultState()));
}
}
}
private void removeTree(World w, BlockPos pos) {
IBlockState log = w.getBlockState(pos);
int size = measureTree(w, log, pos);
if (size > 0) {
pos = ascendTrunk(new ArrayList<BlockPos>(), w, pos, log, 0);
removeTreePart(w, log, pos, 0);
}
}
private BlockPos ascendTrunk(List<BlockPos> done, World w, BlockPos pos, IBlockState log, int level) {
if (level < 3 && !done.contains(pos)) {
done.add(pos);
BlockPos result = ascendTree(w, log, pos, true);
if (variantAndBlockEquals(w.getBlockState(pos.east()), log)) {
result = ascendTrunk(done, w, pos.east(), log, level + 1);
}
if (variantAndBlockEquals(w.getBlockState(pos.west()), log)) {
result = ascendTrunk(done, w, pos.west(), log, level + 1);
}
if (variantAndBlockEquals(w.getBlockState(pos.north()), log)) {
result = ascendTrunk(done, w, pos.north(), log, level + 1);
}
if (variantAndBlockEquals(w.getBlockState(pos.south()), log)) {
result = ascendTrunk(done, w, pos.south(), log, level + 1);
}
return result;
}
return pos;
}
private void removeTreePart(World w, IBlockState log, BlockPos pos, int level) {
if (level < 10 && isWoodOrLeaf(w, log, pos)) {
if (level < 5) {
w.destroyBlock(pos, true);
} else {
IBlockState state = w.getBlockState(pos);
state.getBlock().dropBlockAsItem(w, pos, state, 0);
w.setBlockState(pos, Blocks.AIR.getDefaultState(), 3);
}
PosHelper.all(pos, p -> {
removeTreePart(w, log, p, level + 1);
}, UP, NORTH, SOUTH, EAST, WEST);
}
}
private BlockPos ascendTree(World w, IBlockState log, BlockPos pos, boolean remove) {
int breaks = 0;
IBlockState state;
while (variantAndBlockEquals(w.getBlockState(pos.up()), log)) {
if (PosHelper.some(pos, p -> isLeaves(w.getBlockState(p), log), HORIZONTALS)) {
break;
}
if (remove) {
if (breaks < 10) {
w.destroyBlock(pos, true);
} else {
state = w.getBlockState(pos);
state.getBlock().dropBlockAsItem(w, pos, state, 0);
w.setBlockState(pos, Blocks.AIR.getDefaultState(), 3);
}
breaks++;
}
pos = pos.up();
}
return pos;
}
private void dropApples(World w, BlockPos pos) {
IBlockState log = w.getBlockState(pos);
int size = measureTree(w, log, pos);
if (size > 0) {
dropApplesPart(new ArrayList<BlockPos>(), w, log, pos, 0);
}
}
private void dropApplesPart(List<BlockPos> done, World w, IBlockState log, BlockPos pos, int level) {
if (!done.contains(pos)) {
done.add(pos);
pos = ascendTree(w, log, pos, false);
if (level < 10 && isWoodOrLeaf(w, log, pos)) {
IBlockState state = w.getBlockState(pos);
if (state.getBlock() instanceof BlockLeaves && w.getBlockState(pos.down()).getMaterial() == Material.AIR) {
w.playEvent(2001, pos, Block.getStateId(state));
EntityItem item = new EntityItem(w);
item.setPosition(pos.getX() + 0.5, pos.getY() - 0.5, pos.getZ() + 0.5);
item.setItem(new ItemStack(Items.APPLE, 1, getAppleMeta(w, log)));
w.spawnEntity(item);
}
PosHelper.all(pos, p -> {
dropApplesPart(done, w, log, p, level + 1);
}, UP, NORTH, SOUTH, EAST, WEST);
}
}
}
private int getAppleMeta(World w, IBlockState log) {
return UItems.apple.getRandomAppleMetadata(w.rand, getVariant(log));
}
private int measureTree(World w, IBlockState log, BlockPos pos) {
List<BlockPos> logs = new ArrayList<BlockPos>();
List<BlockPos> leaves = new ArrayList<BlockPos>();
countParts(logs, leaves, w, log, pos);
return logs.size() <= (leaves.size() / 2) ? logs.size() + leaves.size() : 0;
}
private BlockPos getBaseOfTree(World w, IBlockState log, BlockPos pos) {
return getBaseOfTreePart(new ArrayList<BlockPos>(), w, log, pos);
}
private BlockPos getBaseOfTreePart(List<BlockPos> done, World w, IBlockState log, BlockPos pos) {
if (done.contains(pos) || !variantAndBlockEquals(w.getBlockState(pos), log)) {
return null;
}
done.add(pos);
while (variantAndBlockEquals(w.getBlockState(pos.down()), log)) {
pos = pos.down();
done.add(pos);
}
BlockPos adjacent = getBaseOfTreePart(done, w, log, pos.north());
if (adjacent != null && adjacent.getY() < pos.getY()) {
pos = adjacent;
}
adjacent = getBaseOfTreePart(done, w, log, pos.south());
if (adjacent != null && adjacent.getY() < pos.getY()) {
pos = adjacent;
}
adjacent = getBaseOfTreePart(done, w, log, pos.east());
if (adjacent != null && adjacent.getY() < pos.getY()) {
pos = adjacent;
}
adjacent = getBaseOfTreePart(done, w, log, pos.west());
if (adjacent != null && adjacent.getY() < pos.getY()) {
pos = adjacent;
}
if (!done.contains(pos)) {
done.add(pos);
}
return pos;
}
private boolean isWoodOrLeaf(World w, IBlockState log, BlockPos pos) {
IBlockState state = w.getBlockState(pos);
return variantAndBlockEquals(state, log) || (isLeaves(state, log) && ((Boolean)state.getValue(BlockLeaves.DECAYABLE)).booleanValue());
}
private void countParts(List<BlockPos> logs, List<BlockPos> leaves, World w, IBlockState log, BlockPos pos) {
if (logs.contains(pos) || leaves.contains(pos)) {
return;
}
IBlockState state = w.getBlockState(pos);
boolean yay = false;
if (state.getBlock() instanceof BlockLeaves && ((Boolean)state.getValue(BlockLeaves.DECAYABLE)).booleanValue() && variantEquals(state, log)) {
leaves.add(pos);
yay = true;
} else if (variantAndBlockEquals(state, log)) {
logs.add(pos);
yay = true;
}
if (yay) {
PosHelper.all(pos, p -> {
countParts(logs, leaves, w, log, p);
}, UP, NORTH, SOUTH, EAST, WEST);
}
}
private boolean isLeaves(IBlockState state, IBlockState log) {
return state.getBlock() instanceof BlockLeaves && variantEquals(state, log);
}
private boolean variantAndBlockEquals(IBlockState one, IBlockState two) {
return (one.getBlock() == two.getBlock()) && variantEquals(one, two);
}
private boolean variantEquals(IBlockState one, IBlockState two) {
return getVariant(one) == getVariant(two);
}
private Object getVariant(IBlockState state) {
for (Entry<IProperty<?>, ?> i : state.getProperties().entrySet()) {
if (i.getKey().getName().contentEquals("variant")) {
return i.getValue();
}
}
return null;
}
protected static class Data extends Location {
public int hitType;
public Data(int x, int y, int z, int hit) {
super(x, y, z);
hitType = hit;
}
}
}

View file

@ -0,0 +1,152 @@
package com.minelittlepony.unicopia.power;
import org.lwjgl.input.Keyboard;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.power.data.Location;
import com.minelittlepony.util.vector.VecHelper;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFence;
import net.minecraft.block.BlockLeaves;
import net.minecraft.block.BlockWall;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.SoundCategory;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.World;
public class PowerTeleport implements IPower<Location> {
@Override
public String getKeyName() {
return "unicopia.power.teleport";
}
@Override
public int getKeyCode() {
return Keyboard.KEY_O;
}
@Override
public int getWarmupTime(IPlayer player) {
return 20;
}
@Override
public int getCooldownTime(IPlayer player) {
return 50;
}
@Override
public boolean canUse(Race playerSpecies) {
return playerSpecies.canCast();
}
@Override
public Location tryActivate(EntityPlayer player, World w) {
RayTraceResult ray = VecHelper.getObjectMouseOver(player, 100, 1);
if (ray != null && ray.typeOfHit != RayTraceResult.Type.MISS) {
BlockPos pos;
if (ray.typeOfHit == RayTraceResult.Type.ENTITY) {
pos = new BlockPos(ray.entityHit);
} else {
pos = ray.getBlockPos();
}
boolean airAbove = enterable(w, pos.up()) && enterable(w, pos.up(2));
if (exception(w, pos)) {
EnumFacing sideHit = ray.sideHit;
if (player.isSneaking()) {
sideHit = sideHit.getOpposite();
}
pos = pos.offset(sideHit);
}
if (enterable(w, pos.down())) {
pos = pos.down();
if (enterable(w, pos.down())) {
if (airAbove) {
pos = new BlockPos(
ray.getBlockPos().getX(),
pos.getY() + 2,
ray.getBlockPos().getZ());
} else {
return null;
}
}
}
if ((!enterable(w, pos) && exception(w, pos))
|| (!enterable(w, pos.up()) && exception(w, pos.up()))) {
return null;
}
return new Location(pos.getX(), pos.getY(), pos.getZ());
}
return null;
}
@Override
public Class<Location> getPackageType() {
return Location.class;
}
@Override
public void apply(EntityPlayer player, Location data) {
player.world.playSound(player.posX, player.posY, player.posZ, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 1, 1, true);
double distance = player.getDistance(data.x, data.y, data.z) / 10;
player.dismountRidingEntity();
player.setPositionAndUpdate(data.x + (player.posX - Math.floor(player.posX)), data.y, data.z + (player.posZ - Math.floor(player.posZ)));
IPower.takeFromPlayer(player, distance);
player.fallDistance /= distance;
player.world.playSound(data.x, data.y, data.z, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 1, 1, true);
}
private boolean enterable(World w, BlockPos pos) {
IBlockState state = w.getBlockState(pos);
Block block = state.getBlock();
return w.isAirBlock(pos)
|| block.isReplaceable(w, pos)
|| (block instanceof BlockLeaves);
}
private boolean exception(World w, BlockPos pos) {
IBlockState state = w.getBlockState(pos);
Block c = state.getBlock();
return state.isSideSolid(w, pos, EnumFacing.UP)
|| state.getMaterial().isLiquid()
|| (c instanceof BlockWall)
|| (c instanceof BlockFence)
|| (c instanceof BlockLeaves);
}
@Override
public void preApply(EntityPlayer player) {
postApply(player);
}
@Override
public void postApply(EntityPlayer player) {
IPower.spawnParticles(Unicopia.MAGIC_PARTICLE, player, 1);
}
}

View file

@ -0,0 +1,58 @@
package com.minelittlepony.unicopia.power;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.input.Keyboard;
public class PowersRegistry {
private static PowersRegistry instance = new PowersRegistry();
public static PowersRegistry instance() {
return instance;
}
private final Map<Integer, List<IPower<? extends IData>>> keyToPowerMap = new HashMap<>();
private final Map<String, IPower<? extends IData>> powerNamesMap = new HashMap<>();
private PowersRegistry() {
}
public void init() {
registerPower(new PowerTeleport());
registerPower(new PowerMagic());
registerPower(new PowerStomp());
registerPower(new PowerGrow());
registerPower(new PowerFeed());
}
public boolean hasRegisteredPower(int keyCode) {
return keyToPowerMap.containsKey(keyCode);
}
public Optional<IPower<? extends IData>> getCapablePowerFromKey(int keyCode, Race race) {
return getKeyCodePool(keyCode).stream()
.filter(power -> power.canUse(race))
.findFirst();
}
public Optional<IPower<? extends IData>> getPowerFromName(String name) {
return Optional.ofNullable(powerNamesMap.get(name));
}
private List<IPower<? extends IData>> getKeyCodePool(int keyCode) {
return keyToPowerMap.computeIfAbsent(keyCode, ArrayList::new);
}
public void registerPower(IPower<? extends IData> power) {
getKeyCodePool(power.getKeyCode()).add(power);
powerNamesMap.put(power.getKeyName(), power);
Keyboard.getKeyHandler().addKeybind(power);
}
}

View file

@ -0,0 +1,7 @@
package com.minelittlepony.unicopia.power.data;
import com.minelittlepony.unicopia.power.IData;
public class Hit implements IData {
}

View file

@ -0,0 +1,30 @@
package com.minelittlepony.unicopia.power.data;
import com.google.gson.annotations.Expose;
import com.minelittlepony.unicopia.power.IData;
import net.minecraft.util.math.BlockPos;
public class Location implements IData {
@Expose
public int x;
@Expose
public int y;
@Expose
public int z;
public Location(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public Location(BlockPos pos) {
x = pos.getX();
y = pos.getY();
z = pos.getZ();
}
}

View file

@ -0,0 +1,29 @@
package com.minelittlepony.unicopia.spell;
import net.minecraft.entity.Entity;
import net.minecraft.world.World;
public abstract class AbstractSpell implements IMagicEffect {
protected boolean isDead = false;
@Override
public void setDead() {
isDead = true;
}
@Override
public boolean getDead() {
return isDead;
}
@Override
public boolean update(Entity source) {
return false;
}
@Override
public boolean updateAt(ICaster<?> source, World w, double x, double y, double z, int level) {
return false;
}
}

View file

@ -0,0 +1,21 @@
package com.minelittlepony.unicopia.spell;
/**
* A type of action to perform after a spell has completed its handling.
*/
public enum ActionResult {
/**
* No action.
*/
NONE,
/**
* Place block/gem into the world.
*/
PLACE,
/**
* Vanilla behaviour.
* In the case of dispensers the item will be ejected into the world.
* When right clicking a block the itemstack will be decremented.
*/
DEFAULT;
}

View file

@ -0,0 +1,24 @@
package com.minelittlepony.unicopia.spell;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
public interface ICaster<E extends EntityLivingBase> {
void setEffect(IMagicEffect effect);
IMagicEffect getEffect();
default boolean hasEffect() {
return getEffect() != null;
}
default void setOwner(EntityLivingBase owner) {
}
E getOwner();
default Entity getEntity() {
return getOwner();
}
}

View file

@ -0,0 +1,22 @@
package com.minelittlepony.unicopia.spell;
import net.minecraft.dispenser.IBlockSource;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.EnumFacing;
/**
* Represents an object with an action to perform when dispensed from a dispenser.
*
*/
public interface IDispenceable {
/**
* Called when dispensed.
*
* @param pos Block position in front of the dispenser
* @param facing Direction of the dispenser
* @param source The dispenser currently dispensing
* @return an ActionResult for the type of action to perform.
*/
public ActionResult onDispenced(BlockPos pos, EnumFacing facing, IBlockSource source);
}

View file

@ -0,0 +1,87 @@
package com.minelittlepony.unicopia.spell;
import com.minelittlepony.unicopia.InbtSerialisable;
import net.minecraft.entity.Entity;
import net.minecraft.world.World;
/**
*
* Interface for a magic spell
*
*/
public interface IMagicEffect extends InbtSerialisable {
/**
* Maximum level this spell can reach or -1 for unlimited.
* <br>
* If a gem goes past this level it is more likely to explode.
*/
default int getMaxLevel() {
return 0;
}
String getName();
/**
* Sets this effect as dead.
*/
void setDead();
/**
* Returns true if this spell is dead, and must be cleaned up.
*/
boolean getDead();
/**
* Called every tick when attached to a player.
*
* @param source The entity we are currently attached to.
* @return true to keep alive
*/
boolean update(Entity source);
/**
* Called every tick when attached to a player. Used to apply particle effects.
* Is only called on the client side.
*
* @param source The entity we are currently attached to.
*/
default void render(Entity source) {
}
/**
* Called every tick when attached to a gem.
*
* @param source The entity we are attached to.
* @param w The world
* @param x Entity position x
* @param y Entity position y
* @param z Entity position z
* @param level Current spell level
*/
boolean updateAt(ICaster<?> source, World w, double x, double y, double z, int level);
/**
* Called every tick when attached to an entity to produce particle effects.
* Is only called on the client side.
*
* @param source The entity we are attached to.
* @param w The world
* @param x Entity position x
* @param y Entity position y
* @param z Entity position z
* @param level Current spell level
*/
default void renderAt(ICaster<?> source, World w, double x, double y, double z, int level) {
}
/**
* Return true to allow the gem update and move.
*/
default boolean allowAI() {
return false;
}
}

View file

@ -0,0 +1,43 @@
package com.minelittlepony.unicopia.spell;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.world.World;
/**
* Interface for right-click actions.
*
*/
public interface IUseAction {
/**
* Triggered when the player right clicks a block
*
* @param stack The current itemstack
* @param player The player
* @param world The player's world
* @param pos The location clicked
* @param side The side of the block clicked
* @param hitX X offset inside the block
* @param hitY Y offset inside the block
* @param hitZ Z offset inside the block
*
* @return ActionResult for the type of action to perform
*/
public ActionResult onUse(ItemStack stack, EntityPlayer player, World world, BlockPos pos, EnumFacing side, float hitX, float hitY, float hitZ);
/**
* Triggered when the player right clicks
*
* @param stack The current itemstack
* @param player The player
* @param world The player's world
* @param hitEntity The entity in focus, if any
*
* @return ActionResult for the type of action to perform
*/
public ActionResult onUse(ItemStack stack, EntityPlayer player, World world, Entity hitEntity);
}

View file

@ -0,0 +1,40 @@
package com.minelittlepony.unicopia.spell;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
public class SpellRegistry {
private static final SpellRegistry instance = new SpellRegistry();
public static SpellRegistry instance() {
return instance;
}
private final Map<String, Callable<IMagicEffect>> factories = new HashMap<>();
private SpellRegistry() {
}
public void init() {
registerSpell("shield", SpellShield::new);
}
public Optional<IMagicEffect> getSpellFromName(String name) {
try {
if (factories.containsKey(name)) {
return Optional.ofNullable(factories.get(name).call());
}
} catch (Exception e) {
e.printStackTrace();
}
return Optional.empty();
}
public void registerSpell(String key, Callable<IMagicEffect> factory) {
factories.put(key, factory);
}
}

View file

@ -0,0 +1,165 @@
package com.minelittlepony.unicopia.spell;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UClient;
import com.minelittlepony.unicopia.Unicopia;
import com.minelittlepony.unicopia.client.particle.Particles;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import com.minelittlepony.unicopia.power.IPower;
import com.minelittlepony.util.ProjectileUtil;
import com.minelittlepony.util.shape.IShape;
import com.minelittlepony.util.shape.Sphere;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class SpellShield extends AbstractSpell {
private int strength = 0;
public SpellShield() {
}
public SpellShield(int type) {
setStrength(type);
}
public void setStrength(int level) {
strength = level;
}
@Override
public String getName() {
return "shield";
}
@Override
public int getMaxLevel() {
return -1;
}
@Override
public void render(Entity source) {
if (UClient.isClientSide()) {
spawnParticles(source.getEntityWorld(), source.posX, source.posY, source.posZ, 4 + (strength * 2));
}
}
public void renderAt(ICaster<?> source, World w, double x, double y, double z, int level) {
if (UClient.isClientSide()) {
if (w.rand.nextInt(4 + level * 4) == 0) {
spawnParticles(w, x, y, z, 4 + (level * 2));
}
}
}
protected void spawnParticles(World w, double x, double y, double z, int strength) {
IShape sphere = new Sphere(true, strength);
Vec3d pos = sphere.computePoint(w.rand);
Particles.instance().spawnParticle(Unicopia.MAGIC_PARTICLE, false,
pos.x + x, pos.y + y, pos.z + z,
0, 0, 0);
}
@Override
public boolean update(Entity source) {
applyEntities(null, source, source.getEntityWorld(), source.posX, source.posY, source.posZ, strength);
if (source.getEntityWorld().getWorldTime() % 50 == 0) {
double radius = 4 + (strength * 2);
if (!IPower.takeFromPlayer((EntityPlayer)source, radius/4)) {
setDead();
}
}
return !isDead;
}
@Override
public boolean updateAt(ICaster<?> source, World w, double x, double y, double z, int level) {
return applyEntities(source, source.getOwner(), w, x, y, z, level);
}
private boolean applyEntities(ICaster<?> source, Entity owner, World w, double x, double y, double z, int level) {
double radius = 4 + (level * 2);
AxisAlignedBB bb = new AxisAlignedBB(x - radius, y - radius, z - radius, x + radius, y + radius, z + radius);
for (Entity i : w.getEntitiesWithinAABBExcludingEntity(source.getEntity(), bb)) {
if ((!i.equals(owner)
|| (owner instanceof EntityPlayer
&& !PlayerSpeciesList.instance().getPlayer((EntityPlayer)owner).getPlayerSpecies().canCast()))) {
double dist = i.getDistance(x, y, z);
double dist2 = i.getDistance(x, y - i.getEyeHeight(), z);
boolean projectile = ProjectileUtil.isProjectile(i);
if (dist <= radius || dist2 <= radius) {
if (projectile) {
if (!ProjectileUtil.isProjectileThrownBy(i, owner)) {
if (dist < radius/2) {
i.playSound(SoundEvents.ENTITY_ZOMBIE_VILLAGER_CURE, 0.1f, 1);
i.setDead();
} else {
ricochet(i, x, y, z);
}
}
} else if (i instanceof EntityLivingBase) {
double force = dist;
if (i instanceof EntityPlayer) {
force = calculateForce((EntityPlayer)i);
}
i.addVelocity(
-(x - i.posX) / force,
-(y - i.posY) / force + (dist < 1 ? dist : 0),
-(z - i.posZ) / force);
}
}
}
}
return true;
}
protected double calculateForce(EntityPlayer player) {
Race race = PlayerSpeciesList.instance().getPlayer(player).getPlayerSpecies();
double force = 4 * 8;
if (race.canUseEarth()) {
if (player.isSneaking()) {
force *= 16;
}
} else if (race.canFly()) {
force /= 2;
}
return force;
}
private void ricochet(Entity projectile, double x, double y, double z) {
Vec3d position = new Vec3d(projectile.posX, projectile.posY, projectile.posZ);
Vec3d motion = new Vec3d(projectile.motionX, projectile.motionY, projectile.motionZ);
Vec3d normal = position.subtract(x, y, z).normalize();
Vec3d approach = motion.subtract(normal);
if (approach.length() >= motion.length()) {
ProjectileUtil.setThrowableHeading(projectile, normal.x, normal.y, normal.z, (float)motion.length(), 0);
}
}
public void writeToNBT(NBTTagCompound compound) {
compound.setInteger("spell_strength", strength);
}
public void readFromNBT(NBTTagCompound compound) {
strength = compound.getInteger("spell_strength");
}
}

View file

@ -0,0 +1,57 @@
package com.minelittlepony.util;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.DamageSource;
import net.minecraft.util.EntityDamageSource;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.translation.I18n;
@SuppressWarnings("deprecation")
public class MagicalDamageSource extends EntityDamageSource {
public static DamageSource create(String type) {
return new MagicalDamageSource(type);
}
public static DamageSource causePlayerDamage(String type, EntityPlayer player) {
return new MagicalDamageSource(type, player);
}
public static DamageSource causeMobDamage(String type, EntityLivingBase source) {
return new MagicalDamageSource(type, source);
}
protected MagicalDamageSource(String type) {
this(type, null);
}
protected MagicalDamageSource(String type, Entity source) {
super(type, source);
setMagicDamage();
}
public ITextComponent getDeathMessage(EntityLivingBase target) {
Entity attacker = damageSourceEntity instanceof EntityLivingBase ? (EntityLivingBase)damageSourceEntity : target.getRidingEntity();
String basic = "death.attack." + this.damageType;
if (attacker != null && attacker instanceof EntityLivingBase) {
String withAttecker = basic + ".player";
ItemStack held = attacker instanceof EntityLivingBase ? ((EntityLivingBase)attacker).getHeldItemMainhand() : ItemStack.EMPTY;
String withItem = withAttecker + ".item";
if (held != null && held.hasDisplayName() && I18n.canTranslate(withItem)) {
return new TextComponentTranslation(withItem, target.getDisplayName(), attacker.getDisplayName(), held.getTextComponent());
}
if (I18n.canTranslate(withAttecker)) {
return new TextComponentTranslation(withAttecker, target.getDisplayName(), attacker.getDisplayName());
}
}
return new TextComponentTranslation(basic, target.getDisplayName());
}
}

View file

@ -0,0 +1,25 @@
package com.minelittlepony.util;
import java.util.function.Consumer;
import java.util.function.Function;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
public class PosHelper {
public static void all(BlockPos origin, Consumer<BlockPos> consumer, EnumFacing... directions) {
for (EnumFacing facing : directions) {
consumer.accept(origin.offset(facing));
}
}
public static boolean some(BlockPos origin, Function<BlockPos, Boolean> consumer, EnumFacing... directions) {
for (EnumFacing facing : directions) {
if (consumer.apply(origin.offset(facing))) {
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,84 @@
package com.minelittlepony.util;
import net.minecraft.entity.Entity;
import net.minecraft.entity.IProjectile;
import net.minecraft.entity.projectile.EntityArrow;
import net.minecraft.entity.projectile.EntityFireball;
import net.minecraft.entity.projectile.EntityLlamaSpit;
import net.minecraft.entity.projectile.EntityThrowable;
public class ProjectileUtil {
/**
* Checks if the given entity is a projectile.
*/
public static boolean isProjectile(Entity e) {
return e instanceof IProjectile
|| e instanceof EntityFireball;
}
/**
* Checks if an entity is a thrown projectile.
*/
public static boolean isThrowable(Entity e) {
return e instanceof EntityThrowable ||
e instanceof EntityArrow ||
e instanceof EntityFireball;
}
/**
* Checks if the given projectile was thrown by the given entity
*/
@SuppressWarnings("unchecked")
public static <T extends Entity> boolean isProjectileThrownBy(Entity throwable, T e) {
if (e == null || !isProjectile(throwable)) {
return false;
}
return e.equals(getThrowingEntity(throwable));
}
/**
* Gets the thrower for a projectile or null
*/
@SuppressWarnings("unchecked")
public static <T extends Entity> T getThrowingEntity(Entity throwable) {
if (throwable instanceof EntityArrow) {
return (T)((EntityArrow) throwable).shootingEntity;
}
if (throwable instanceof EntityFireball) {
return (T)((EntityFireball) throwable).shootingEntity;
}
if (throwable instanceof EntityLlamaSpit) {
return (T)((EntityLlamaSpit) throwable).owner;
}
if (throwable instanceof EntityThrowable) {
return (T)((EntityThrowable) throwable).getThrower();
}
return null;
}
/**
* Sets the velocity and heading for a projectile.
*
* @param throwable The projectile
* @param x X Direction component
* @param y Y Direction component
* @param z Z Direction component
* @param velocity Velocity
* @param inaccuracy Inaccuracy
* @return True the projectile's heading was set, false otherwise
*/
public static void setThrowableHeading(Entity throwable, double x, double y, double z, float velocity, float inaccuracy) {
if (throwable instanceof IProjectile) {
((IProjectile)throwable).shoot(x, y, z, velocity, inaccuracy);
} else {
((Entity)throwable).setVelocity(x, y, z);
}
}
}

View file

@ -0,0 +1,61 @@
package com.minelittlepony.util.shape;
import java.util.Random;
import net.minecraft.util.math.Vec3d;
/**
*
*Interface for a 3d shape, used for spawning particles in a designated area (or anything else you need shapes for).
*/
public interface IShape {
/**
* Rotates this shape around it's center.
*
* @param u Rotate yaw
* @param v Rotate pitch
*
* @return This Shape
*/
public IShape setRotation(float u, float v);
/**
* Get the volume of space filled by this shape, or the surface area if hollow.
*
* @return double volume
*/
public double getVolumeOfSpawnableSpace();
/**
* X offset from the shape's origin.
*
* @return X
*/
public double getXOffset();
/**
* Y offset from the shape's origin.
*
* @return Y
*/
public double getYOffset();
/**
* Z offset from the shape's origin.
*
* @return Z
*/
public double getZOffset();
/**
* Computes a random coordinate that falls within this shape's designated area.
*/
public Vec3d computePoint(Random rand);
/**
* Checks if the given point is on the edge, or if not hollow the inside, of this shape.
* @return
*/
public boolean isPointInside(Vec3d point);
}

View file

@ -0,0 +1,123 @@
package com.minelittlepony.util.shape;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import java.util.Random;
/**
* A sphere, or 2d circle of you so desire.
*
*/
public class Sphere implements IShape {
protected final Vec3d stretch;
private final boolean hollow;
private final double rad;
private float yaw = 0;
private float pitch = 0;
private final double volume;
/**
* Creates a uniform sphere.
*
* @param hollow True if this shape must be hollow.
* @param radius Sphere radius
*/
public Sphere(boolean hollow, double radius) {
this(hollow, radius, 1, 1, 1);
}
/**
* Creates a sphere of arbitrary dimensions.
* <p>
* Can be used to create a flat circle by setting one of the stretch parameters to 0.
* If you set two of them to 0 it will probably produce a line.
*
* @param hollow True if this shape must be hollow.
* @param radius Sphere radius
* @param stretchX Warp this shape's X-axis
* @param stretchY Warp this shape's Y-axis
* @param stretchZ Warp this shape's Z-axis
*
*/
public Sphere(boolean hollow, double radius, float stretchX, float stretchY, float stretchZ) {
this.hollow = hollow;
stretch = new Vec3d(stretchX, stretchY, stretchZ);
rad = radius;
volume = computeSpawnableSpace();
}
public double getVolumeOfSpawnableSpace() {
return volume;
}
private double computeSpawnableSpace() {
if (hollow) {
if (stretch.x == stretch.x && stretch.y == stretch.z) {
double radius = rad * stretch.x;
return 4 * Math.PI * radius * radius;
}
return computeEllipsoidArea(rad, stretch);
}
return computeEllipsoidVolume(rad, stretch);
}
public static double computeEllipsoidArea(double rad, Vec3d stretch) {
double p = 1.6075;
double result = Math.pow(rad * stretch.x, p) * Math.pow(rad * stretch.y, p);
result += Math.pow(rad * stretch.x, p) * Math.pow(rad * stretch.z, p);
result += Math.pow(rad * stretch.y, p) * Math.pow(rad * stretch.y, p);
result /= 3;
return 2 * Math.PI * Math.pow(result, 1/p);
}
public static double computeEllipsoidVolume(double rad, Vec3d stretch) {
double result = (4/3) * Math.PI;
result *= (rad * stretch.x);
result *= (rad * stretch.y);
result *= (rad * stretch.z);
return result;
}
public double getXOffset() {
return 0;
}
public double getYOffset() {
return 0;
}
public double getZOffset() {
return 0;
}
public Vec3d computePoint(Random rand) {
double rad = this.rad;
if (!hollow) {
rad = MathHelper.nextDouble(rand, 0, rad);
}
double z = MathHelper.nextDouble(rand, -rad, rad);
double phi = MathHelper.nextDouble(rand, 0, Math.PI * 2);
double theta = Math.asin(z / rad);
return new Vec3d(rad * Math.cos(theta) * Math.cos(phi) * stretch.x, rad * Math.cos(theta) * Math.sin(phi) * stretch.y, z * stretch.z).rotateYaw(yaw).rotatePitch(pitch);
}
public Sphere setRotation(float u, float v) {
yaw = u;
pitch = v;
return this;
}
public boolean isPointInside(Vec3d point) {
point = point.rotateYaw(-yaw).rotatePitch(-pitch);
point = new Vec3d(point.x / stretch.x, point.y / stretch.y, point.z / stretch.z);
double dist = point.length();
return hollow ? dist == rad : dist <= rad;
}
}

View file

@ -0,0 +1,149 @@
package com.minelittlepony.util.vector;
import java.util.List;
import com.google.common.base.Predicate;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EntitySelectors;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
public class VecHelper {
/**
* Performs a ray cast from the given entity and returns a result for the first block that ray intercepts.
*
* @param e Entity to start from
* @param distance Maximum distance
* @param partialTick Client partial ticks
*
* @return RayTraceResult result or null
*/
public static RayTraceResult rayTrace(Entity e, double distance, float partialTick) {
Vec3d pos = geteEyePosition(e, partialTick);
Vec3d look = e.getLook(partialTick);
Vec3d ray = pos.add(look.x * distance, look.y * distance, look.z * distance);
return e.world.rayTraceBlocks(pos, ray, false, false, true);
}
/**
* Gets the entity the player is currently looking at, or null.
*/
public static Entity getLookedAtEntity(EntityLivingBase e, int reach) {
RayTraceResult objectMouseOver = getObjectMouseOver(e, reach, 1);
if (objectMouseOver != null && objectMouseOver.typeOfHit == RayTraceResult.Type.ENTITY) {
return objectMouseOver.entityHit;
}
return null;
}
/**
* Gets all entities within a given range from the player.
*/
public static List<Entity> getWithinRange(EntityPlayer player, double reach) {
Vec3d look = player.getLook(0);
float var9 = 1.0F;
return player.world.getEntitiesWithinAABBExcludingEntity(player, player.getEntityBoundingBox().expand(look.x * reach, look.y * reach, look.z * reach).expand((double)var9, (double)var9, (double)var9));
}
/**
* Gets the position vector of an entity's eyes for ray tracing.
*
* @param e Entity
* @param partialTick Client partial ticks
*
* @return A vector of the entity's eye position
*/
public static Vec3d geteEyePosition(Entity e, float partialTick) {
double eyeHeight = e.getEyeHeight();
if (partialTick == 1) return new Vec3d(e.posX, e.posY + eyeHeight, e.posZ);
double x = e.prevPosX + (e.posX - e.prevPosX) * partialTick;
double y = e.prevPosY + (e.posY - e.prevPosY) * partialTick + eyeHeight;
double z = e.prevPosZ + (e.posZ - e.prevPosZ) * partialTick;
return new Vec3d(x, y, z);
}
/**
* Performs a ray trace from the given entity and returns a result for the first Entity or block that the ray intercepts.
*
* @param e Entity to start from
* @param distance Maximum distance
* @param partialTick Client partial ticks
*
* @return RayTraceResult result or null
*/
public static RayTraceResult getObjectMouseOver(Entity e, double distance, float partialTick) {
return getObjectMouseOverExcept(e, distance, partialTick, EntitySelectors.NOT_SPECTATING);
}
/**
* Performs a ray trace from the given entity and returns a result for the first Entity that passing the given predicate or block that the ray intercepts.
* <p>
*
*
* @param e Entity to start from
* @param distance Maximum distance
* @param partialTick Client partial ticks
* @param predicate Predicate test to filter entities
*
* @return RayTraceResult result or null
*/
public static RayTraceResult getObjectMouseOverExcept(Entity e, double distance, float partialTick, Predicate<Entity> predicate) {
RayTraceResult tracedBlock = rayTrace(e, distance, partialTick);
double totalTraceDistance = distance;
Vec3d pos = geteEyePosition(e, partialTick);
if (tracedBlock != null) totalTraceDistance = tracedBlock.hitVec.distanceTo(pos);
Vec3d look = e.getLook(partialTick);
Vec3d ray = pos.add(look.x * distance, look.y * distance, look.z * distance);
Vec3d hit = null;
Entity pointedEntity = null;
List<Entity> entitiesWithinRange = e.world.getEntitiesInAABBexcluding(e, e.getEntityBoundingBox().grow(look.x * distance, look.y * distance, look.z * distance).expand(1, 1, 1), predicate);
double traceDistance = totalTraceDistance;
for (Entity entity : entitiesWithinRange) {
if (entity.canBeCollidedWith()) {
double size = entity.getCollisionBorderSize();
AxisAlignedBB entityAABB = entity.getEntityBoundingBox().expand(size, size, size);
RayTraceResult intercept = entityAABB.calculateIntercept(pos, ray);
if (entityAABB.contains(pos)) {
if (0 < traceDistance || traceDistance == 0) {
pointedEntity = entity;
hit = intercept == null ? pos : intercept.hitVec;
traceDistance = 0;
}
} else if (intercept != null) {
double distanceToHit = pos.distanceTo(intercept.hitVec);
if (distanceToHit < traceDistance || traceDistance == 0) {
if (entity == e.getRidingEntity()) {
if (traceDistance == 0) {
pointedEntity = entity;
hit = intercept.hitVec;
}
} else {
pointedEntity = entity;
hit = intercept.hitVec;
traceDistance = distanceToHit;
}
}
}
}
}
if (pointedEntity != null && (traceDistance < totalTraceDistance || tracedBlock == null)) {
return new RayTraceResult(pointedEntity, hit);
}
return tracedBlock;
}
}

View file

@ -0,0 +1,42 @@
package come.minelittlepony.unicopia.forgebullshit;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.CapabilityInject;
class DefaultPlayerCapabilitiesProxyContainer implements IPlayerCapabilitiesProxyContainer {
@CapabilityInject(IPlayerCapabilitiesProxyContainer.class)
public static final Capability<IPlayerCapabilitiesProxyContainer> CAPABILITY = null;
private IPlayer player;
@Override
public IPlayer getPlayer() {
return player;
}
@Override
public void setPlayer(IPlayer player) {
this.player = player;
}
public void writeToNBT(NBTTagCompound compound) {
if (player == null) {
return;
}
player.writeToNBT(compound);
}
public void readFromNBT(NBTTagCompound compound) {
if (player == null) {
player = PlayerSpeciesList.instance().emptyPlayer(null);
}
player.readFromNBT(compound);
}
}

View file

@ -0,0 +1,43 @@
package come.minelittlepony.unicopia.forgebullshit;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.common.capabilities.CapabilityManager;
import net.minecraftforge.event.AttachCapabilitiesEvent;
import net.minecraftforge.event.entity.player.PlayerEvent;
public class FBS {
public static void init() {
CapabilityManager.INSTANCE.register(IPlayerCapabilitiesProxyContainer.class,
new Storage(), DefaultPlayerCapabilitiesProxyContainer::new);
}
public static void attach(AttachCapabilitiesEvent<Entity> event) {
if (event.getObject() instanceof EntityPlayer) {
event.addCapability(new ResourceLocation("unicopia", "race"), new Provider());
}
}
public static void clone(PlayerEvent.Clone event) {
final IPlayerCapabilitiesProxyContainer original = of(event.getOriginal());
if (original == null) {
return;
}
final IPlayerCapabilitiesProxyContainer clone = of(event.getEntity());
clone.setPlayer(original.getPlayer());
}
public static IPlayerCapabilitiesProxyContainer of(Entity entity) {
if (entity.hasCapability(DefaultPlayerCapabilitiesProxyContainer.CAPABILITY, EnumFacing.DOWN)) {
return entity.getCapability(DefaultPlayerCapabilitiesProxyContainer.CAPABILITY, EnumFacing.DOWN);
}
return null;
}
}

View file

@ -0,0 +1,10 @@
package come.minelittlepony.unicopia.forgebullshit;
import com.minelittlepony.unicopia.InbtSerialisable;
import com.minelittlepony.unicopia.player.IPlayer;
public interface IPlayerCapabilitiesProxyContainer extends InbtSerialisable {
IPlayer getPlayer();
void setPlayer(IPlayer player);
}

View file

@ -0,0 +1,36 @@
package come.minelittlepony.unicopia.forgebullshit;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.ICapabilitySerializable;
class Provider implements ICapabilitySerializable<NBTTagCompound> {
DefaultPlayerCapabilitiesProxyContainer instance = (DefaultPlayerCapabilitiesProxyContainer) DefaultPlayerCapabilitiesProxyContainer.CAPABILITY.getDefaultInstance();
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing facing) {
return capability == DefaultPlayerCapabilitiesProxyContainer.CAPABILITY;
}
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing facing) {
if (hasCapability(capability, facing)) {
return DefaultPlayerCapabilitiesProxyContainer.CAPABILITY.<T>cast(instance);
}
return null;
}
@Override
public NBTTagCompound serializeNBT() {
return (NBTTagCompound) DefaultPlayerCapabilitiesProxyContainer.CAPABILITY.getStorage()
.writeNBT(DefaultPlayerCapabilitiesProxyContainer.CAPABILITY, instance, null);
}
@Override
public void deserializeNBT(NBTTagCompound nbt) {
DefaultPlayerCapabilitiesProxyContainer.CAPABILITY.getStorage()
.readNBT(DefaultPlayerCapabilitiesProxyContainer.CAPABILITY, instance, null, nbt);
}
}

View file

@ -0,0 +1,28 @@
package come.minelittlepony.unicopia.forgebullshit;
import java.lang.reflect.Field;
import net.minecraft.util.registry.RegistryNamespaced;
import net.minecraftforge.registries.ILockableRegistry;
public class RegistryLockSpinner {
public static void unlock(RegistryNamespaced<?, ?> registry) {
if (registry instanceof ILockableRegistry) {
try {
Field f = registry.getClass().getDeclaredField("locked");
f.setAccessible(true);
f.setBoolean(registry, false);
} catch (IllegalArgumentException | IllegalAccessException | NoSuchFieldException | SecurityException e) {
e.printStackTrace();
}
}
}
public static void lock(RegistryNamespaced<?, ?> registry) {
if (registry instanceof ILockableRegistry) {
((ILockableRegistry) registry).lock();
}
}
}

View file

@ -0,0 +1,24 @@
package come.minelittlepony.unicopia.forgebullshit;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.capabilities.Capability.IStorage;
class Storage implements IStorage<IPlayerCapabilitiesProxyContainer> {
@Override
public NBTBase writeNBT(Capability<IPlayerCapabilitiesProxyContainer> capability, IPlayerCapabilitiesProxyContainer instance, EnumFacing side) {
NBTTagCompound compound = new NBTTagCompound();
instance.writeToNBT(compound);
return compound;
}
@Override
public void readNBT(Capability<IPlayerCapabilitiesProxyContainer> capability, IPlayerCapabilitiesProxyContainer instance, EnumFacing side, NBTBase nbt) {
instance.readFromNBT((NBTTagCompound)nbt);
}
}

View file

@ -0,0 +1,77 @@
tile.cloudBlock.normal.name=Block of Cloud
tile.cloudBlock.packed.name=Dense Cloud
tile.cloudBlock.enchanted.name=Enchanted Cloud
tile.cloudSlab.normal.name=Cloud Slab
tile.cloudSlab.packed.name=Dense Cloud Slab
tile.cloudSlab.enchanted.name=Enchanted Cloud Slab
tile.stairsCloud.name=Cloud Stairs
item.cloud_matter.name=Cloud Matter
item.cloud.small.name=Small Cloud
item.cloud.medium.name=Medium Cloud
item.cloud.large.name=Large Cloud
item.spell.name=Gem
item.spell.shield.name=Gem of Repulsion
item.spell.fire.name=Gem of Flame
item.spell.inferno.name=Gem of Inferno
item.spell.ice.name=Gem of Freezing
item.spell.portal.name=Gem of Teleportation
item.spell.attract.name=Gem of Retention
item.spell.minion.name=Gem of Obedience
item.spellbook.name=Spellbook
item.apple.green.name=Granny Smith Apple
item.apple.sweet.name=Sweet Apple Acres Apple
item.apple.rotten.name=Rotten Apple
item.apple.zap.name=Zap Apple
item.apple.zap_cooked.name=Cooked Zap Apple
entity.cloud.name=Cloud
entity.cloud_natural.name=Cloud
entity.spell.name=Magic
commands.race.success.self=Your race has been updated
commands.race.success.otherself=%s changed race to %s
commands.race.success.other=Changed %s's race to %s
commands.race.usage=/race <get|set|list> [player] <species>
commands.race.list=The available races are:
commands.race.permission=Selected Race is not permitted
commands.race.fail="%s" is not a recognised Race
commands.race.tell.self=You are a
commands.race.tell.self.alt=You are an
commands.race.tell.other=%s is a
commands.race.tell.other.alt=%s is an
commands.decloud.success=%s clouds removed
commands.decloud.usage=/decloud <all>
unicopia.category.name=Pony Abilities
unicopia.power.grow=Earth Pony (Primary)
unicopia.power.earth=Earth Pony (Secondary)
unicopia.power.teleport=Unicorn (Primary)
unicopia.power.magic=Unicorn (Secondary)
unicopia.power.rain=Pegasus (Primary)
unicopia.power.thunder=Pegasus (Secondary)
unicopia.power.feed=Changeling (Primary)
unicopia.power.disguise=Changeling (Secondary)
death.attack.feed=%1$s was drained of all life
death.attack.feed.player=%1$s died to feed %2$s
death.attack.cold=%1$s died of frost bite
death.attack.cold.player=%1$s was frozen to death by %2$s
death.attack.cold.player.item=%1$s was frozen to death by %2$s using %3$s
death.attack.smash=%1$s was crushed under hoof
death.attack.smash.player=%1$s was crushed by %2$s
death.attack.fire=%1$s was burnt to a crisp by magic
death.attack.fire.player=%1$s was burnt to a crisp by %2$s
death.attack.fire.own=%1$s was burnt to a crisp by their own spell
death.attack.zap=%1$s ate a Zap Apple

View file

@ -0,0 +1,18 @@
{
"parent": "builtin/generated",
"textures": {
"layer0": "unicopia:items/cloud"
},
"display": {
"thirdperson": {
"rotation": [ -90, 0, 0 ],
"translation": [ 0, 1, -3 ],
"scale": [ 0.55, 0.55, 0.55 ]
},
"firstperson": {
"rotation": [ 0, -135, 25 ],
"translation": [ 0, 4, 2 ],
"scale": [ 1.7, 1.7, 1.7 ]
}
}
}

View file

@ -0,0 +1,27 @@
{
"textures": {
"top": "unicopia:blocks/cloud_normal",
"bottom": "unicopia:blocks/cloud_normal",
"side": "unicopia:blocks/cloud_normal"
},
"elements": [
{ "from": [ 0, 0, 0 ],
"to": [ 16, 8, 16 ],
"faces": {
"down": { "uv": [ 1, 1, 15, 15 ], "texture": "#bottom", "cullface": "down" },
"up": { "uv": [ 1, 1, 15, 15 ], "texture": "#top" },
"north": { "uv": [ 0, 4, 16, 12 ], "texture": "#side", "cullface": "north" },
"south": { "uv": [ 0, 4, 16, 12 ], "texture": "#side", "cullface": "south" },
"west": { "uv": [ 0, 4, 16, 12 ], "texture": "#side", "cullface": "west" },
"east": { "uv": [ 0, 4, 16, 12 ], "texture": "#side", "cullface": "east" }
}
}
],
"display": {
"thirdperson": {
"rotation": [ 10, -45, 170 ],
"translation": [ 0, 1.5, -2.75 ],
"scale": [ 0.375, 0.375, 0.375 ]
}
}
}

View file

@ -0,0 +1,18 @@
{
"parent": "builtin/generated",
"textures": {
"layer0": "unicopia:items/cloud_matter"
},
"display": {
"thirdperson": {
"rotation": [ -90, 0, 0 ],
"translation": [ 0, 1, -3 ],
"scale": [ 0.55, 0.55, 0.55 ]
},
"firstperson": {
"rotation": [ 0, -135, 25 ],
"translation": [ 0, 4, 2 ],
"scale": [ 1.7, 1.7, 1.7 ]
}
}
}

View file

@ -0,0 +1,16 @@
{
"parent": "unicopia:item/cloud_large",
"display": {
"thirdperson": {
"rotation": [ 10, -45, 170 ],
"translation": [ 0, 1.5, -2.75 ],
"scale": [ 0.25, 0.25, 0.25 ]
},
"firstperson": {
"scale": [ 0.7, 0.7, 0.7 ]
},
"gui": {
"scale": [ 0.7, 0.7, 0.7 ]
}
}
}

View file

@ -0,0 +1,16 @@
{
"parent": "unicopia:item/cloud_large",
"display": {
"thirdperson": {
"rotation": [ 10, -45, 170 ],
"translation": [ 0, 1.5, -2.75 ],
"scale": [ 0.15, 0.15, 0.15 ]
},
"firstperson": {
"scale": [ 0.5, 0.5, 0.5 ]
},
"gui": {
"scale": [ 0.5, 0.5, 0.5 ]
}
}
}

View file

@ -0,0 +1,13 @@
{
"parent": "unicopia:block/cloud_stairs",
"display": {
"thirdperson": {
"rotation": [ 10, -45, 170 ],
"translation": [ 0, 1.5, -2.75 ],
"scale": [ 0.375, 0.375, 0.375 ]
},
"gui": {
"rotation": [ 0, 180, 0 ]
}
}
}

View file

@ -0,0 +1,10 @@
{
"parent": "unicopia:block/enchanted_cloud",
"display": {
"thirdperson": {
"rotation": [ 10, -45, 170 ],
"translation": [ 0, 1.5, -2.75 ],
"scale": [ 0.375, 0.375, 0.375 ]
}
}
}

View file

@ -0,0 +1,10 @@
{
"parent": "unicopia:block/half_slab_enchanted_cloud",
"display": {
"thirdperson": {
"rotation": [ 10, -45, 170 ],
"translation": [ 0, 1.5, -2.75 ],
"scale": [ 0.375, 0.375, 0.375 ]
}
}
}

View file

@ -0,0 +1,10 @@
{
"parent": "unicopia:block/normal_cloud",
"display": {
"thirdperson": {
"rotation": [ 10, -45, 170 ],
"translation": [ 0, 1.5, -2.75 ],
"scale": [ 0.375, 0.375, 0.375 ]
}
}
}

View file

@ -0,0 +1,10 @@
{
"parent": "unicopia:block/half_slab_normal_cloud",
"display": {
"thirdperson": {
"rotation": [ 10, -45, 170 ],
"translation": [ 0, 1.5, -2.75 ],
"scale": [ 0.375, 0.375, 0.375 ]
}
}
}

View file

@ -0,0 +1,10 @@
{
"parent": "unicopia:block/packed_cloud",
"display": {
"thirdperson": {
"rotation": [ 10, -45, 170 ],
"translation": [ 0, 1.5, -2.75 ],
"scale": [ 0.375, 0.375, 0.375 ]
}
}
}

View file

@ -0,0 +1,10 @@
{
"parent": "unicopia:block/half_slab_packed_cloud",
"display": {
"thirdperson": {
"rotation": [ 10, -45, 170 ],
"translation": [ 0, 1.5, -2.75 ],
"scale": [ 0.375, 0.375, 0.375 ]
}
}
}

View file

@ -0,0 +1,19 @@
{
"parent": "builtin/generated",
"textures": {
"layer0": "unicopia:items/gem",
"layer1": "unicopia:items/gem_overlay"
},
"display": {
"thirdperson": {
"rotation": [ -90, 0, 0 ],
"translation": [ 0, 1, -3 ],
"scale": [ 0.55, 0.55, 0.55 ]
},
"firstperson": {
"rotation": [ 0, -135, 25 ],
"translation": [ 0, 4, 2 ],
"scale": [ 1.7, 1.7, 1.7 ]
}
}
}

View file

@ -0,0 +1,18 @@
{
"parent": "builtin/generated",
"textures": {
"layer0": "unicopia:items/spellbook"
},
"display": {
"thirdperson": {
"rotation": [ -90, 0, 0 ],
"translation": [ 0, 1, -3 ],
"scale": [ 0.55, 0.55, 0.55 ]
},
"firstperson": {
"rotation": [ 0, -135, 25 ],
"translation": [ 0, 4, 2 ],
"scale": [ 1.7, 1.7, 1.7 ]
}
}
}

View file

@ -0,0 +1,18 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{
"item": "minecraft:apple",
"data": 4
},
{
"item": "minecraft:dye",
"data": 1
}
],
"result": {
"item": "minecraft:apple",
"count": 1,
"data": 6
}
}

View file

@ -0,0 +1,18 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{
"item": "minecraft:apple",
"data": 4
},
{
"item": "minecraft:dye",
"data": 2
}
],
"result": {
"item": "minecraft:apple",
"count": 1,
"data": 7
}
}

View file

@ -0,0 +1,18 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{
"item": "minecraft:apple",
"data": 4
},
{
"item": "minecraft:dye",
"data": 14
}
],
"result": {
"item": "minecraft:apple",
"count": 1,
"data": 8
}
}

View file

@ -0,0 +1,17 @@
{
"type": "minecraft:crafting_shapeless",
"ingredients": [
{
"item": "minecraft:apple",
"data": 4
},
{
"item": "minecraft:rotten_flesh"
}
],
"result": {
"item": "minecraft:apple",
"count": 1,
"data": 9
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View file

@ -0,0 +1,16 @@
[
{
"modid": "unicopia",
"name": "${name}",
"description": "${description}",
"version": "${version}",
"mcversion": "${mcversion}",
"url": "",
"updateUrl": "",
"authorList": ["${author}"],
"credits": "",
"logoFile": "",
"screenshots": [],
"dependencies": []
}
]