use of jackiecrazy.wardance.event.ParryEvent in project WarDance by Jackiecrazy.
the class Afterimage method parry.
@Override
protected void parry(LivingEntity caster, ParryEvent procPoint, SkillData stats, LivingEntity target, STATE state) {
if (!caster.isShiftKeyDown() || state == STATE.COOLING)
return;
final float cost = ((ParryEvent) procPoint).getPostureConsumption();
SkillUtils.createCloud(caster.level, caster, caster.getX(), caster.getY(), caster.getZ(), cost, ParticleTypes.LARGE_SMOKE);
for (LivingEntity e : caster.level.getLoadedEntitiesOfClass(LivingEntity.class, caster.getBoundingBox().inflate(cost))) {
if (e.distanceToSqr(caster) > cost * cost) {
e.addEffect(new EffectInstance(Effects.BLINDNESS, 100));
}
}
caster.addEffect(new EffectInstance(Effects.INVISIBILITY, 20));
markUsed(caster);
((ParryEvent) procPoint).setPostureConsumption(0);
}
use of jackiecrazy.wardance.event.ParryEvent in project WarDance by Jackiecrazy.
the class CombatHandler method parry.
// because compat with BHT...
@SubscribeEvent(priority = EventPriority.LOWEST)
public static void parry(final LivingAttackEvent e) {
if (!e.getEntityLiving().level.isClientSide && e.getSource() != null && CombatUtils.isPhysicalAttack(e.getSource())) {
LivingEntity uke = e.getEntityLiving();
if (MovementUtils.hasInvFrames(uke)) {
e.setCanceled(true);
}
ICombatCapability ukeCap = CombatData.getCap(uke);
ItemStack attack = CombatUtils.getAttackingItemStack(e.getSource());
if (CombatUtils.isMeleeAttack(e.getSource()) && e.getSource().getEntity() instanceof LivingEntity && attack != null && e.getAmount() > 0) {
LivingEntity seme = (LivingEntity) e.getSource().getEntity();
if (StealthConfig.inv)
seme.removeEffect(Effects.INVISIBILITY);
ICombatCapability semeCap = CombatData.getCap(seme);
Hand attackingHand = semeCap.isOffhandAttack() ? Hand.OFF_HAND : Hand.MAIN_HAND;
// hand bound or staggered, no attack
if (semeCap.getStaggerTime() > 0 || semeCap.getHandBind(attackingHand) > 0) {
e.setCanceled(true);
return;
}
boolean sweeping = false;
// capability handler
seme.getMainHandItem().getCapability(CombatManipulator.CAP).ifPresent((i) -> i.attackStart(e.getSource(), seme, uke, seme.getMainHandItem(), e.getAmount()));
// add stats if it's the first attack this tick and cooldown is sufficient
if (semeCap.getSweepTick() != seme.tickCount) {
// first hit of a potential sweep attack
semeCap.addRank(0.1f);
float might = CombatUtils.getAttackMight(seme, uke);
semeCap.addMight(might);
semeCap.setSweepTick(seme.tickCount);
} else {
// hitting twice in a sweep attack, disqualified from parry refund
sweeping = true;
}
// blocking, reset posture cooldown without resetting combo cooldown, bypass parry
if (uke.isBlocking()) {
ukeCap.consumePosture(0);
return;
}
// manual parry toggle
// why does everyone want this feature...
boolean failManualParry = CombatConfig.sneakParry > 0 && (ukeCap.getParryingTick() > uke.tickCount || ukeCap.getParryingTick() < uke.tickCount - CombatConfig.sneakParry);
failManualParry |= CombatConfig.sneakParry < 0 && ukeCap.getParryingTick() == -1;
failManualParry &= uke instanceof PlayerEntity;
boolean canParry = GeneralUtils.isFacingEntity(uke, seme, 120);
boolean useDeflect = (uke instanceof PlayerEntity || WarDance.rand.nextFloat() < CombatConfig.mobDeflectChance) && GeneralUtils.isFacingEntity(uke, seme, 120 + 2 * (int) GeneralUtils.getAttributeValueSafe(uke, WarAttributes.DEFLECTION.get())) && !GeneralUtils.isFacingEntity(uke, seme, 120) && !canParry;
// staggered, no parry
if (ukeCap.getStaggerTime() > 0) {
downingHit = false;
return;
}
// parry code start, grab attack multiplier
float atkMult = CombatUtils.getPostureAtk(seme, seme, attackingHand, e.getAmount(), attack);
// store atkMult at this stage for event
float original = atkMult;
downingHit = true;
// stabby bonus
StealthUtils.Awareness awareness = StealthUtils.getAwareness(seme, uke);
atkMult *= CombatUtils.getDamageMultiplier(awareness, attack);
// crit bonus
if (e.getSource() instanceof CombatDamageSource && ((CombatDamageSource) e.getSource()).isCrit())
atkMult *= ((CombatDamageSource) e.getSource()).getCritDamage();
// grab defending stack
ItemStack defend = null;
Hand parryHand = null;
if (canParry) {
float posMod = 1337;
boolean isShield = false;
if (CombatUtils.canParry(uke, seme, uke.getOffhandItem(), atkMult)) {
defend = uke.getOffhandItem();
posMod = CombatUtils.getPostureDef(seme, uke, uke.getOffhandItem(), e.getAmount());
isShield = CombatUtils.isShield(uke, uke.getOffhandItem());
parryHand = Hand.OFF_HAND;
}
if (!isShield && CombatUtils.canParry(uke, seme, uke.getMainHandItem(), atkMult) && CombatUtils.getPostureDef(seme, uke, uke.getMainHandItem(), e.getAmount()) < posMod) {
defend = uke.getMainHandItem();
parryHand = Hand.MAIN_HAND;
}
}
float defMult = CombatUtils.getPostureDef(seme, uke, defend, e.getAmount());
// special mob parry overrides
if (atkMult >= 0 && awareness != StealthUtils.Awareness.UNAWARE && CombatUtils.parryMap.containsKey(GeneralUtils.getResourceLocationFromEntity(uke))) {
CombatUtils.MobInfo stats = CombatUtils.parryMap.get(GeneralUtils.getResourceLocationFromEntity(uke));
if (WarDance.rand.nextFloat() < stats.chance) {
if (stats.mult < 0) {
// cannot parry
defend = null;
canParry = false;
defMult = (float) -stats.mult;
} else if (stats.omnidirectional || canParry) {
if (defMult > stats.mult) {
if (!canParry) {
parryHand = CombatUtils.getCooledAttackStrength(uke, Hand.MAIN_HAND, 0.5f) > CombatUtils.getCooledAttackStrength(uke, Hand.OFF_HAND, 0.5f) ? Hand.MAIN_HAND : Hand.OFF_HAND;
}
defend = ItemStack.EMPTY;
defMult = (float) Math.min(stats.mult, defMult);
canParry = true;
}
}
}
}
// accounting for negative posture damage, used to mark an item as ignoring parries
float finalPostureConsumption = Math.abs(atkMult * defMult);
// updating this quickly, it's basically the above without crit and stab multipliers, which were necessary for calculating canParry so they couldn't be eliminated cleanly...
float originalPostureConsumption = Math.abs(original * defMult);
ParryEvent pe = new ParryEvent(uke, seme, ((canParry && defend != null) || useDeflect), attackingHand, attack, parryHand, defend, finalPostureConsumption, originalPostureConsumption, e.getAmount());
if (failManualParry)
pe.setResult(Event.Result.DENY);
MinecraftForge.EVENT_BUS.post(pe);
if (pe.isCanceled()) {
e.setCanceled(true);
return;
}
if (ukeCap.getStaggerTime() == 0) {
// overflow posture
float consumption = pe.getPostureConsumption();
/*
barrier reduction if appropriate
this is so ugly oh my god
*/
if (pe.canParry() && !useDeflect && CombatUtils.isShield(uke, defend)) {
consumption -= ukeCap.consumeBarrier(consumption);
}
/*
end ugliness
*/
float knockback = ukeCap.consumePosture(seme, consumption);
// no parries if stabby
if (StealthConfig.ignore && awareness == StealthUtils.Awareness.UNAWARE)
return;
if (pe.canParry()) {
e.setCanceled(true);
downingHit = false;
ukeCap.addRank(0);
if (useDeflect) {
// deflect
uke.level.playSound(null, uke.getX(), uke.getY(), uke.getZ(), SoundEvents.IRON_TRAPDOOR_OPEN, SoundCategory.PLAYERS, 0.75f + WarDance.rand.nextFloat() * 0.5f, (1 - (ukeCap.getPosture() / ukeCap.getMaxPosture())) + WarDance.rand.nextFloat() * 0.5f);
return;
}
// shield disabling
boolean disshield = false;
parryHand = uke.getOffhandItem() == defend ? Hand.OFF_HAND : Hand.MAIN_HAND;
// barrier has already been handled. Subsequent binding and cooldown are handled by the capability.
if (CombatUtils.isShield(uke, defend)) {
Tuple<Integer, Float> stat = CombatUtils.getShieldStats(defend);
if (attack.canDisableShield(defend, uke, seme)) {
// shield is disabled
if (uke instanceof PlayerEntity) {
((PlayerEntity) uke).getCooldowns().addCooldown(defend.getItem(), stat.getA());
} else
ukeCap.setHandBind(parryHand, stat.getA());
disshield = true;
}
}
// knockback based on posture consumed
// this will return negative if the defmult is greater, and positive if the atkmult is greater. Larger abs val=larger difference
double kb = Math.sqrt(atkMult) - 0.18 - (1 / Math.max(defMult, 0.1));
// sigmoid curve again!
// this is the knockback to be applied to the defender
kb = 1d / (1d + Math.exp(-kb));
CombatUtils.knockBack(uke, seme, Math.min(uke instanceof PlayerEntity ? 1.6f : 1.3f, 0.2f + (pe.getPostureConsumption() + knockback) * (float) kb * (uke instanceof PlayerEntity ? 6 : 4) / ukeCap.getMaxPosture()), true, false);
kb = 1 - kb;
CombatUtils.knockBack(seme, uke, Math.min(uke instanceof PlayerEntity ? 1.6f : 1.3f, 0.1f + pe.getPostureConsumption() * (float) kb * (seme instanceof PlayerEntity ? 3 : 2) / semeCap.getMaxPosture()), true, false);
uke.level.playSound(null, uke.getX(), uke.getY(), uke.getZ(), disshield ? SoundEvents.SHIELD_BLOCK : SoundEvents.ANVIL_PLACE, SoundCategory.PLAYERS, 0.25f + WarDance.rand.nextFloat() * 0.5f, (1 - (ukeCap.getPosture() / ukeCap.getMaxPosture())) + WarDance.rand.nextFloat() * 0.5f);
// reset cooldown
if (defMult != 0) {
// shield time
// (posture consumption+1)*5 ticks of cooldown
int ticks = (int) ((consumption + 1) * 5);
// attack cooldown ticks
float cd = CombatUtils.getCooldownPeriod(uke, parryHand);
if (// if attack speed is lower, refund partial cooldown
cd > ticks)
CombatUtils.setHandCooldownDirect(uke, parryHand, ticks, true);
else
// otherwise bind hand
ukeCap.setHandBind(parryHand, (ticks - (int) cd));
}
if (sweeping) {
CombatUtils.setHandCooldown(seme, attackingHand, 0, true);
} else
CombatUtils.setHandCooldown(seme, attackingHand, (float) (1 - kb), true);
// sword on sword is 1.4, sword on shield is 1.12
if (defend != null) {
ItemStack finalDefend = defend;
defend.getCapability(CombatManipulator.CAP).ifPresent((i) -> i.onParry(seme, uke, finalDefend, e.getAmount()));
Hand other = uke.getMainHandItem() == defend ? Hand.OFF_HAND : Hand.MAIN_HAND;
ItemStack finalDefend1 = uke.getItemInHand(other);
finalDefend1.getCapability(CombatManipulator.CAP).ifPresent((i) -> i.onOtherHandParry(seme, uke, finalDefend1, e.getAmount()));
}
}
}
if (!(seme instanceof PlayerEntity)) {
semeCap.setHandBind(attackingHand, CombatUtils.getCooldownPeriod(seme, attackingHand) + 7);
}
}
// shatter, at the rock bottom of the attack event, saving your protected butt.
if (!uke.isBlocking() && !e.isCanceled()) {
if (CombatUtils.isPhysicalAttack(e.getSource()) && StealthUtils.getAwareness(e.getSource().getDirectEntity() instanceof LivingEntity ? (LivingEntity) e.getSource().getDirectEntity() : null, uke) != StealthUtils.Awareness.UNAWARE) {
if (CombatData.getCap(uke).consumeShatter(e.getAmount())) {
e.setCanceled(true);
uke.level.playSound(null, uke.getX(), uke.getY(), uke.getZ(), SoundEvents.GLASS_BREAK, SoundCategory.PLAYERS, 0.25f + WarDance.rand.nextFloat() * 0.5f, 0.75f + WarDance.rand.nextFloat() * 0.5f);
}
// otherwise the rest of the damage goes through and is handled later down the line anyway
}
}
}
}
Aggregations