Fixed issues with ability triggering

This commit is contained in:
Sollace 2019-02-03 11:45:45 +02:00
parent eb92e7f92e
commit 42ad67dd52
14 changed files with 178 additions and 124 deletions

View file

@ -21,7 +21,6 @@ import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiOptions;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.resources.I18n;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;

View file

@ -40,7 +40,6 @@ class UKeyHandler implements IKeyHandler {
if (!pressed.contains(i)) {
pressed.add(i);
}
if (!PowersRegistry.instance().hasRegisteredPower(i.getKeyCodeDefault())) {
removed.add(i);
@ -50,6 +49,7 @@ class UKeyHandler implements IKeyHandler {
.getCapablePowerFromKey(i.getKeyCodeDefault(), iplayer.getPlayerSpecies())
.ifPresent(iplayer.getAbilities()::tryUseAbility);
}
}
} else {
if (pressed.contains(i)) {
pressed.remove(i);

View file

@ -9,6 +9,7 @@ import com.minelittlepony.jumpingcastle.api.IChannel;
import com.minelittlepony.jumpingcastle.api.IMessage;
import com.minelittlepony.jumpingcastle.api.IMessageHandler;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import com.minelittlepony.unicopia.power.IData;
import com.minelittlepony.unicopia.power.IPower;
import com.minelittlepony.unicopia.power.PowersRegistry;
@ -38,7 +39,7 @@ public class MsgPlayerAbility implements IMessage, IMessageHandler<MsgPlayerAbil
}
private <T extends IData> void apply(IPower<T> power) {
EntityPlayer player = IPlayer.getPlayerFromServer(senderId);
IPlayer player = PlayerSpeciesList.instance().getPlayer(senderId);
if (player == null) {
return;
}

View file

@ -1,5 +1,6 @@
package com.minelittlepony.unicopia.player;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.minelittlepony.jumpingcastle.api.Target;
@ -17,9 +18,20 @@ class PlayerAbilityDelegate implements IAbilityReceiver, IUpdatable<EntityPlayer
private final IPlayer player;
private int warmup = 0;
/**
* Ticks of warmup before an ability is triggered.
*/
private int warmup;
private int cooldown = 0;
/**
* Ticks of cooldown after an ability has been triggered.
*/
private int cooldown;
/**
* True once the current ability has been triggered.
*/
private boolean triggered;
@Nullable
private IPower<?> activeAbility = null;
@ -28,86 +40,123 @@ class PlayerAbilityDelegate implements IAbilityReceiver, IUpdatable<EntityPlayer
this.player = player;
}
/**
* Returns true if the currrent ability can we swapped out.
*/
boolean canSwitchStates() {
return (warmup == 0 && cooldown == 0) || activeAbility == null;
return activeAbility == null || (warmup != 0) || (triggered && cooldown == 0);
}
@Override
public synchronized void tryUseAbility(IPower<?> power) {
if (canSwitchStates() || activeAbility != power) {
activeAbility = power;
warmup = power.getWarmupTime(player);
cooldown = 0;
}
}
@Override
public synchronized void tryClearAbility() {
public void tryUseAbility(IPower<?> power) {
if (canSwitchStates()) {
activeAbility = null;
warmup = 0;
setAbility(power);
}
}
@Override
public void tryClearAbility() {
if (canSwitchStates()) {
setAbility(null);
}
}
protected synchronized void setAbility(@Nullable IPower<?> power) {
if (activeAbility != power) {
activeAbility = power;
warmup = power == null ? 0 : power.getWarmupTime(player);
cooldown = 0;
}
}
@Nullable
protected synchronized IPower<?> getUsableAbility() {
if (!(activeAbility == null || (triggered && warmup == 0 && cooldown == 0)) && activeAbility.canUse(player.getPlayerSpecies())) {
return activeAbility;
}
return null;
}
@Override
public int getRemainingCooldown() {
return cooldown;
}
@Override
public synchronized void onUpdate(EntityPlayer entity) {
if (activeAbility != null && activeAbility.canUse(player.getPlayerSpecies())) {
public void onUpdate(EntityPlayer entity) {
IPower<?> ability = getUsableAbility();
if (ability == null) {
return;
}
if (warmup > 0) {
warmup--;
activeAbility.preApply(player);
} else if (player.isClientPlayer()) {
if (activateAbility()) {
cooldown = activeAbility.getCooldownTime(player);
} else {
cooldown = 0;
ability.preApply(player);
return;
}
if (cooldown > 0) {
cooldown--;
ability.postApply(player);
return;
}
if (triggered) {
return;
}
if (ability.canActivate(player.getWorld(), player)) {
triggered = true;
cooldown = ability.getCooldownTime(player);
if (player.isClientPlayer()) {
activateAbility(ability);
}
}
if (cooldown > 0 && activeAbility != null) {
cooldown--;
activeAbility.postApply(player);
}
if (cooldown <= 0) {
setAbility(null);
}
}
@Override
public void writeToNBT(NBTTagCompound compound) {
compound.setBoolean("triggered", triggered);
compound.setInteger("warmup", warmup);
compound.setInteger("cooldown", cooldown);
if (activeAbility != null) {
compound.setString("activeAbility", activeAbility.getKeyName());
IPower<?> ability = getUsableAbility();
if (ability != null) {
compound.setString("activeAbility", ability.getKeyName());
}
}
@Override
public void readFromNBT(NBTTagCompound compound) {
warmup = compound.getInteger("warmup");
cooldown = compound.getInteger("cooldown");
activeAbility = null;
triggered = 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;
});
PowersRegistry.instance()
.getPowerFromName(compound.getString("activeAbility"))
.ifPresent(p -> activeAbility = p);
}
}
protected boolean activateAbility() {
if (activeAbility == null || !activeAbility.canActivate(player.getWorld(), player)) {
return false;
}
IData data = activeAbility.tryActivate(player.getOwner(), player.getWorld());
/**
* Attempts to activate the current stored ability.
* Returns true if the ability suceeded, otherwise false.
*/
protected boolean activateAbility(@Nonnull IPower<?> ability) {
IData data = ability.tryActivate(player);
if (data != null) {
Unicopia.channel.send(new MsgPlayerAbility(player.getOwner(), activeAbility, data), Target.SERVER);
Unicopia.channel.send(new MsgPlayerAbility(player.getOwner(), ability, data), Target.SERVER);
}
return data != null;

View file

@ -55,6 +55,10 @@ public class PlayerSpeciesList {
}
public IPlayer getPlayer(EntityPlayer player) {
if (player == null) {
return null;
}
return FBS.of(player).getPlayer();
}

View file

@ -98,11 +98,10 @@ public interface IPower<T extends IData> extends IKeyBind {
* 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
*/
@Nullable
T tryActivate(EntityPlayer player, World w);
T tryActivate(IPlayer player);
Class<T> getPackageType();
@ -113,10 +112,10 @@ public interface IPower<T extends IData> extends IKeyBind {
* @param player The player that triggered the ability
* @param data Data previously sent from the client
*/
void apply(EntityPlayer player, T data);
void apply(IPlayer player, T data);
/**
* Called just before the ability is activated.
* Called every tick until the warmup timer runs out.
* @param player The current player
*/
void preApply(IPlayer player);

View file

@ -43,7 +43,7 @@ public class PowerCarry implements IPower<Hit> {
}
@Override
public Hit tryActivate(EntityPlayer player, World w) {
public Hit tryActivate(IPlayer player) {
return new Hit();
}
@ -65,8 +65,9 @@ public class PowerCarry implements IPower<Hit> {
}
@Override
public void apply(EntityPlayer player, Hit data) {
EntityLivingBase rider = findRider(player, player.world);
public void apply(IPlayer iplayer, Hit data) {
EntityPlayer player = iplayer.getOwner();
EntityLivingBase rider = findRider(player, iplayer.getWorld());
if (rider != null) {
rider.startRiding(player, true);

View file

@ -6,7 +6,6 @@ import org.lwjgl.input.Keyboard;
import com.minelittlepony.unicopia.UParticles;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import com.minelittlepony.unicopia.power.data.Hit;
import com.minelittlepony.unicopia.spell.IMagicEffect;
import com.minelittlepony.unicopia.spell.SpellDisguise;
@ -16,7 +15,6 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.SoundEvents;
import net.minecraft.util.SoundCategory;
import net.minecraft.world.World;
public class PowerDisguise extends PowerFeed {
@ -32,16 +30,15 @@ public class PowerDisguise extends PowerFeed {
@Nullable
@Override
public Hit tryActivate(EntityPlayer player, World w) {
public Hit tryActivate(IPlayer player) {
return new Hit();
}
@Override
public void apply(EntityPlayer player, Hit data) {
public void apply(IPlayer iplayer, Hit data) {
EntityPlayer player = iplayer.getOwner();
Entity looked = VecHelper.getLookedAtEntity(player, 17);
IPlayer iplayer = PlayerSpeciesList.instance().getPlayer(player);
player.world.playSound(null, player.getPosition(), SoundEvents.E_PARROT_IM_POLAR_BEAR, SoundCategory.PLAYERS, 1.4F, 0.4F);
IMagicEffect effect = iplayer.getEffect();

View file

@ -24,7 +24,6 @@ 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> {
@ -55,9 +54,9 @@ public class PowerFeed implements IPower<Hit> {
@Nullable
@Override
public Hit tryActivate(EntityPlayer player, World w) {
if (player.getHealth() < player.getMaxHealth() || player.canEat(false)) {
Entity i = VecHelper.getLookedAtEntity(player, 15);
public Hit tryActivate(IPlayer player) {
if (player.getOwner().getHealth() < player.getOwner().getMaxHealth() || player.getOwner().canEat(false)) {
Entity i = VecHelper.getLookedAtEntity(player.getOwner(), 15);
if (i != null && canDrain(i)) {
return new Hit();
}
@ -81,7 +80,8 @@ public class PowerFeed implements IPower<Hit> {
}
@Override
public void apply(EntityPlayer player, Hit data) {
public void apply(IPlayer iplayer, Hit data) {
EntityPlayer player = iplayer.getOwner();
List<Entity> list = VecHelper.getWithinRange(player, 3, this::canDrain);
Entity looked = VecHelper.getLookedAtEntity(player, 17);
@ -98,7 +98,7 @@ public class PowerFeed implements IPower<Hit> {
for (Entity i : list) {
DamageSource d = MagicalDamageSource.causePlayerDamage("feed", player);
if (player.world.rand.nextFloat() > 0.95f) {
if (iplayer.getWorld().rand.nextFloat() > 0.95f) {
i.attackEntityFrom(d, Integer.MAX_VALUE);
} else {
i.attackEntityFrom(d, drained);
@ -112,7 +112,7 @@ public class PowerFeed implements IPower<Hit> {
player.getFoodStats().addStats(3, 0.25f);
}
if (player.world.rand.nextFloat() > 0.9f) {
if (iplayer.getWorld().rand.nextFloat() > 0.9f) {
player.addPotionEffect(new PotionEffect(MobEffects.WITHER, 20, 1));
}

View file

@ -12,7 +12,6 @@ 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;
@ -48,8 +47,8 @@ public class PowerGrow implements IPower<Location> {
}
@Override
public Location tryActivate(EntityPlayer player, World w) {
RayTraceResult ray = VecHelper.getObjectMouseOver(player, 3, 1);
public Location tryActivate(IPlayer player) {
RayTraceResult ray = VecHelper.getObjectMouseOver(player.getOwner(), 3, 1);
if (ray != null && ray.typeOfHit == RayTraceResult.Type.BLOCK) {
return new Location(ray.getBlockPos());
@ -64,17 +63,17 @@ public class PowerGrow implements IPower<Location> {
}
@Override
public void apply(EntityPlayer player, Location data) {
public void apply(IPlayer 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);
count += applySingle(player.getWorld(), player.getWorld().getBlockState(pos), pos);
}
if (count > 0) {
IPower.takeFromPlayer(player, count * 5);
IPower.takeFromPlayer(player.getOwner(), count * 5);
}
}

View file

@ -5,13 +5,9 @@ import org.lwjgl.input.Keyboard;
import com.minelittlepony.unicopia.Race;
import com.minelittlepony.unicopia.UParticles;
import com.minelittlepony.unicopia.player.IPlayer;
import com.minelittlepony.unicopia.player.PlayerSpeciesList;
import com.minelittlepony.unicopia.power.data.Hit;
import com.minelittlepony.unicopia.spell.SpellShield;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.world.World;
public class PowerMagic implements IPower<Hit> {
@Override
@ -40,7 +36,7 @@ public class PowerMagic implements IPower<Hit> {
}
@Override
public Hit tryActivate(EntityPlayer player, World w) {
public Hit tryActivate(IPlayer player) {
return new Hit();
}
@ -50,13 +46,11 @@ public class PowerMagic implements IPower<Hit> {
}
@Override
public void apply(EntityPlayer player, Hit data) {
IPlayer prop = PlayerSpeciesList.instance().getPlayer(player);
if (prop.getEffect() instanceof SpellShield) {
prop.setEffect(null);
public void apply(IPlayer player, Hit data) {
if (player.getEffect() instanceof SpellShield) {
player.setEffect(null);
} else {
prop.setEffect(new SpellShield());
player.setEffect(new SpellShield());
}
}

View file

@ -25,7 +25,6 @@ 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.SharedMonsterAttributes;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
@ -44,6 +43,13 @@ import static net.minecraft.util.EnumFacing.*;
public class PowerStomp implements IPower<PowerStomp.Data> {
private final double rad = 4;
private final AxisAlignedBB areaOfEffect = new AxisAlignedBB(
-rad, -rad, -rad,
rad, rad, rad
);
@Override
public String getKeyName() {
return "unicopia.power.earth";
@ -70,21 +76,21 @@ public class PowerStomp implements IPower<PowerStomp.Data> {
}
@Override
public PowerStomp.Data tryActivate(EntityPlayer player, World w) {
RayTraceResult mop = VecHelper.getObjectMouseOver(player, 2, 1);
public PowerStomp.Data tryActivate(IPlayer player) {
RayTraceResult mop = VecHelper.getObjectMouseOver(player.getOwner(), 2, 1);
if (mop != null && mop.typeOfHit == RayTraceResult.Type.BLOCK) {
BlockPos pos = mop.getBlockPos();
IBlockState state = w.getBlockState(pos);
IBlockState state = player.getWorld().getBlockState(pos);
if (state.getBlock() instanceof BlockLog) {
pos = getBaseOfTree(w, state, pos);
if (measureTree(w, state, pos) > 0) {
pos = getBaseOfTree(player.getWorld(), state, pos);
if (measureTree(player.getWorld(), state, pos) > 0) {
return new Data(pos.getX(), pos.getY(), pos.getZ(), 1);
}
}
}
if (!player.onGround && !player.capabilities.isFlying) {
player.addVelocity(0, -6, 0);
if (!player.getOwner().onGround && !player.getOwner().capabilities.isFlying) {
player.getOwner().addVelocity(0, -6, 0);
return new Data(0, 0, 0, 0);
}
return null;
@ -107,9 +113,9 @@ public class PowerStomp implements IPower<PowerStomp.Data> {
}
@Override
public void apply(EntityPlayer player, Data data) {
public void apply(IPlayer iplayer, Data data) {
double rad = 4;
EntityPlayer player = iplayer.getOwner();
if (data.hitType == 0) {
BlockPos ppos = player.getPosition();
@ -117,13 +123,7 @@ public class PowerStomp implements IPower<PowerStomp.Data> {
player.addVelocity(0, -(ppos.distanceSq(pos)), 0);
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) {
iplayer.getWorld().getEntitiesWithinAABBExcludingEntity(player, areaOfEffect.offset(iplayer.getOriginVector())).forEach(i -> {
double dist = Math.sqrt(i.getDistanceSq(pos));
if (dist <= rad + 3) {
@ -137,7 +137,6 @@ public class PowerStomp implements IPower<PowerStomp.Data> {
double amount = (4 * player.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getAttributeValue()) / (float)dist;
if (i instanceof EntityPlayer) {
Race race = PlayerSpeciesList.instance().getPlayer((EntityPlayer)i).getPlayerSpecies();
if (race.canUseEarth()) {
@ -151,27 +150,25 @@ public class PowerStomp implements IPower<PowerStomp.Data> {
i.attackEntityFrom(damage, (float)amount);
}
}
});
Iterable<BlockPos> area = BlockPos.getAllInBox(pos.add(-rad, -rad, -rad), pos.add(rad, rad, rad));
for (BlockPos i : area) {
BlockPos.getAllInBoxMutable(pos.add(-rad, -rad, -rad), pos.add(rad, rad, rad)).forEach(i -> {
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);
IPower.takeFromPlayer(player, rad);
} else if (data.hitType == 1) {
if (player.world.rand.nextInt(30) == 0) {
removeTree(player.world, new BlockPos(data.x, data.y, data.z));
removeTree(player.world, data.pos());
} else {
dropApples(player.world, new BlockPos(data.x, data.y, data.z));
dropApples(player.world, data.pos());
}
IPower.takeFromPlayer(player, 1);
@ -311,15 +308,16 @@ public class PowerStomp implements IPower<PowerStomp.Data> {
}
}
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(getApple(w, log));
@ -340,7 +338,9 @@ public class PowerStomp implements IPower<PowerStomp.Data> {
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;
}
@ -427,6 +427,10 @@ public class PowerStomp implements IPower<PowerStomp.Data> {
}
private Object getVariant(IBlockState state) {
if (state.getBlock() instanceof BlockLeaves) {
return ((BlockLeaves)state.getBlock()).getWoodType(state.getBlock().getMetaFromState(state));
}
for (Entry<IProperty<?>, ?> i : state.getProperties().entrySet()) {
if (i.getKey().getName().contentEquals("variant")) {
return i.getValue();

View file

@ -52,8 +52,10 @@ public class PowerTeleport implements IPower<Location> {
}
@Override
public Location tryActivate(EntityPlayer player, World w) {
RayTraceResult ray = VecHelper.getObjectMouseOver(player, 100, 1);
public Location tryActivate(IPlayer player) {
RayTraceResult ray = VecHelper.getObjectMouseOver(player.getOwner(), 100, 1);
World w = player.getWorld();
if (ray != null && ray.typeOfHit != RayTraceResult.Type.MISS) {
BlockPos pos;
@ -68,7 +70,7 @@ public class PowerTeleport implements IPower<Location> {
if (exception(w, pos)) {
EnumFacing sideHit = ray.sideHit;
if (player.isSneaking()) {
if (player.getOwner().isSneaking()) {
sideHit = sideHit.getOpposite();
}
@ -109,9 +111,10 @@ public class PowerTeleport implements IPower<Location> {
}
@Override
public void apply(EntityPlayer player, Location data) {
player.world.playSound(null, player.posX, player.posY, player.posZ, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 1, 1);
public void apply(IPlayer iplayer, Location data) {
iplayer.getWorld().playSound(null, iplayer.getOrigin(), SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 1, 1);
EntityPlayer player = iplayer.getOwner();
double distance = player.getDistance(data.x, data.y, data.z) / 10;
if (player.isRiding()) {
@ -129,7 +132,7 @@ public class PowerTeleport implements IPower<Location> {
player.fallDistance /= distance;
player.world.playSound(null, data.x, data.y, data.z, SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 1, 1);
player.world.playSound(null, data.pos(), SoundEvents.ENTITY_ITEM_PICKUP, SoundCategory.PLAYERS, 1, 1);
}
private boolean enterable(World w, BlockPos pos) {

View file

@ -27,4 +27,8 @@ public class Location implements IData {
y = pos.getY();
z = pos.getZ();
}
public BlockPos pos() {
return new BlockPos(x, y, z);
}
}