-
Notifications
You must be signed in to change notification settings - Fork 2
/
ShieldParry.java
105 lines (87 loc) · 4.84 KB
/
ShieldParry.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
package us.drullk.parry;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.entity.projectile.AbstractHurtingProjectile;
import net.minecraft.world.entity.projectile.FishingHook;
import net.minecraft.world.entity.projectile.Projectile;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.EnchantmentHelper;
import net.minecraft.world.phys.EntityHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.ForgeConfigSpec;
import net.minecraftforge.event.entity.ProjectileImpactEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import org.apache.commons.lang3.tuple.Pair;
@Mod(ShieldParry.MODID)
@Mod.EventBusSubscriber(modid = ShieldParry.MODID)
public class ShieldParry {
public static final String MODID = "parry";
public static final TagKey<EntityType<?>> PROJECTILES_DISABLED_FOR_PARRYING = TagKey.create(Registries.ENTITY_TYPE, ShieldParry.modId("projectiles_parrying_disabled"));
public static final TagKey<Item> EXCLUDED_SHIELDS = TagKey.create(Registries.ITEM, ShieldParry.modId("excluded_shields"));
public ShieldParry() {
Pair<ParryConfig, ForgeConfigSpec> pairConfigSpec = new ForgeConfigSpec.Builder().configure(ParryConfig::new);
ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, pairConfigSpec.getRight());
ParryConfig.INSTANCE = pairConfigSpec.getLeft();
}
private static <T extends Projectile> boolean tryParry(T projectile, LivingEntity entityBlocking, boolean takeOwnership) {
if (!projectile.getType().is(PROJECTILES_DISABLED_FOR_PARRYING) && entityBlocking.isBlocking() && projectile.getOwner() != entityBlocking) {
ItemStack itemUsed = entityBlocking.getUseItem();
if (!itemUsed.is(EXCLUDED_SHIELDS) && itemUsed.getUseDuration() - entityBlocking.getUseItemRemainingTicks() <= applyTimerBonus(ParryConfig.INSTANCE.shieldParryTicks.get(), itemUsed, ParryConfig.INSTANCE.shieldEnchantmentMultiplier.get())) {
return parryProjectile(projectile, entityBlocking, takeOwnership);
}
}
return false;
}
private static <T extends Projectile> boolean parryProjectile(T projectile, LivingEntity entityBlocking, boolean takeOwnership) {
if (takeOwnership) transferOwnership(projectile, entityBlocking);
Vec3 reboundAngle = entityBlocking.getLookAngle();
projectile.shoot(reboundAngle.x, reboundAngle.y, reboundAngle.z, 1.1F, 0.1F); // reflect faster and more accurately
if (projectile instanceof AbstractHurtingProjectile damagingProjectile) {
damagingProjectile.xPower = reboundAngle.x * 0.1D;
damagingProjectile.yPower = reboundAngle.y * 0.1D;
damagingProjectile.zPower = reboundAngle.z * 0.1D;
}
// Also used in parrying Ghast Fireball
projectile.hurtMarked = true;
return true;
}
private static <T extends Projectile> void transferOwnership(T projectile, LivingEntity entityBlocking) {
if (projectile instanceof AbstractArrow arrow) {
// AbstractArrow overrides setOwner, override changes state for its pickup based on owner
AbstractArrow.Pickup priorPickupState = arrow.pickup;
arrow.setOwner(entityBlocking);
arrow.leftOwner = true;
// Re-set the pre-fetched value
arrow.pickup = priorPickupState;
} else {
projectile.setOwner(entityBlocking);
projectile.leftOwner = true;
}
}
@SubscribeEvent
public static void parryThisCasual(ProjectileImpactEvent event) {
if (!event.getEntity().getLevel().isClientSide()
&& event.getEntity() instanceof Projectile projectile
&& event.getRayTraceResult() instanceof EntityHitResult entityHitResult
&& entityHitResult.getEntity() instanceof LivingEntity livingEntity
&& tryParry(projectile, livingEntity, !(projectile instanceof FishingHook))
) {
event.setCanceled(true);
}
}
private static int applyTimerBonus(int base, ItemStack stack, double multiplier) {
//LOGGER.info(base + base * getEnchantedLevel(stack) * multiplier);
return (int) (base + base * EnchantmentHelper.getItemEnchantmentLevel(ParryEnchantment.reboundEnchantment, stack) * multiplier);
}
public static ResourceLocation modId(String name) {
return new ResourceLocation(MODID, name);
}
}