mirror of
https://github.com/Sollace/Unicopia.git
synced 2024-11-27 15:17:59 +01:00
Code
This commit is contained in:
parent
acd2ad866f
commit
69b340e640
80 changed files with 4111 additions and 0 deletions
|
@ -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;
|
||||
}
|
||||
}
|
77
src/main/java/com/minelittlepony/unicopia/Race.java
Normal file
77
src/main/java/com/minelittlepony/unicopia/Race.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
9
src/main/java/com/minelittlepony/unicopia/UClient.java
Normal file
9
src/main/java/com/minelittlepony/unicopia/UClient.java
Normal 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();
|
||||
}
|
||||
}
|
42
src/main/java/com/minelittlepony/unicopia/UItems.java
Normal file
42
src/main/java/com/minelittlepony/unicopia/UItems.java
Normal 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);
|
||||
}
|
||||
}
|
120
src/main/java/com/minelittlepony/unicopia/Unicopia.java
Normal file
120
src/main/java/com/minelittlepony/unicopia/Unicopia.java
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package com.minelittlepony.unicopia.input;
|
||||
|
||||
public interface IKeyBind {
|
||||
|
||||
String getKeyCategory();
|
||||
|
||||
String getKeyName();
|
||||
|
||||
int getKeyCode();
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.minelittlepony.unicopia.input;
|
||||
|
||||
public interface IKeyHandler {
|
||||
|
||||
void addKeybind(IKeyBind bind);
|
||||
|
||||
default void onKeyInput() {
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
156
src/main/java/com/minelittlepony/unicopia/item/ItemApple.java
Normal file
156
src/main/java/com/minelittlepony/unicopia/item/ItemApple.java
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.minelittlepony.unicopia.player;
|
||||
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
|
||||
public interface IUpdatable {
|
||||
void onUpdate(EntityPlayer entity);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package com.minelittlepony.unicopia.power;
|
||||
|
||||
public interface IData {
|
||||
|
||||
}
|
129
src/main/java/com/minelittlepony/unicopia/power/IPower.java
Normal file
129
src/main/java/com/minelittlepony/unicopia/power/IPower.java
Normal 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);
|
||||
|
||||
}
|
137
src/main/java/com/minelittlepony/unicopia/power/PowerFeed.java
Normal file
137
src/main/java/com/minelittlepony/unicopia/power/PowerFeed.java
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
115
src/main/java/com/minelittlepony/unicopia/power/PowerGrow.java
Normal file
115
src/main/java/com/minelittlepony/unicopia/power/PowerGrow.java
Normal 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) {
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
405
src/main/java/com/minelittlepony/unicopia/power/PowerStomp.java
Normal file
405
src/main/java/com/minelittlepony/unicopia/power/PowerStomp.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.minelittlepony.unicopia.power.data;
|
||||
|
||||
import com.minelittlepony.unicopia.power.IData;
|
||||
|
||||
public class Hit implements IData {
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
24
src/main/java/com/minelittlepony/unicopia/spell/ICaster.java
Normal file
24
src/main/java/com/minelittlepony/unicopia/spell/ICaster.java
Normal 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();
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
165
src/main/java/com/minelittlepony/unicopia/spell/SpellShield.java
Normal file
165
src/main/java/com/minelittlepony/unicopia/spell/SpellShield.java
Normal 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");
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
25
src/main/java/com/minelittlepony/util/PosHelper.java
Normal file
25
src/main/java/com/minelittlepony/util/PosHelper.java
Normal 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;
|
||||
}
|
||||
}
|
84
src/main/java/com/minelittlepony/util/ProjectileUtil.java
Normal file
84
src/main/java/com/minelittlepony/util/ProjectileUtil.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
61
src/main/java/com/minelittlepony/util/shape/IShape.java
Normal file
61
src/main/java/com/minelittlepony/util/shape/IShape.java
Normal 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);
|
||||
}
|
123
src/main/java/com/minelittlepony/util/shape/Sphere.java
Normal file
123
src/main/java/com/minelittlepony/util/shape/Sphere.java
Normal 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;
|
||||
}
|
||||
}
|
149
src/main/java/com/minelittlepony/util/vector/VecHelper.java
Normal file
149
src/main/java/com/minelittlepony/util/vector/VecHelper.java
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
77
src/main/resources/assets/unicopia/lang/en_US.lang
Normal file
77
src/main/resources/assets/unicopia/lang/en_US.lang
Normal 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
|
18
src/main/resources/assets/unicopia/models/item/cloud.json
Normal file
18
src/main/resources/assets/unicopia/models/item/cloud.json
Normal 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 ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
}
|
19
src/main/resources/assets/unicopia/models/item/spell.json
Normal file
19
src/main/resources/assets/unicopia/models/item/spell.json
Normal 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 ]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 ]
|
||||
}
|
||||
}
|
||||
}
|
18
src/main/resources/assets/unicopia/recipes/apple.json
Normal file
18
src/main/resources/assets/unicopia/recipes/apple.json
Normal 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
|
||||
}
|
||||
}
|
18
src/main/resources/assets/unicopia/recipes/apple_2.json
Normal file
18
src/main/resources/assets/unicopia/recipes/apple_2.json
Normal 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
|
||||
}
|
||||
}
|
18
src/main/resources/assets/unicopia/recipes/apple_3.json
Normal file
18
src/main/resources/assets/unicopia/recipes/apple_3.json
Normal 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
|
||||
}
|
||||
}
|
17
src/main/resources/assets/unicopia/recipes/apple_4.json
Normal file
17
src/main/resources/assets/unicopia/recipes/apple_4.json
Normal 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 |
BIN
src/main/resources/assets/unicopia/textures/items/apple_zap.png
Normal file
BIN
src/main/resources/assets/unicopia/textures/items/apple_zap.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
16
src/main/resources/mcmod.info
Normal file
16
src/main/resources/mcmod.info
Normal file
|
@ -0,0 +1,16 @@
|
|||
[
|
||||
{
|
||||
"modid": "unicopia",
|
||||
"name": "${name}",
|
||||
"description": "${description}",
|
||||
"version": "${version}",
|
||||
"mcversion": "${mcversion}",
|
||||
"url": "",
|
||||
"updateUrl": "",
|
||||
"authorList": ["${author}"],
|
||||
"credits": "",
|
||||
"logoFile": "",
|
||||
"screenshots": [],
|
||||
"dependencies": []
|
||||
}
|
||||
]
|
Loading…
Reference in a new issue