diff --git a/src/api/java/de/teamlapen/vampirism/api/entity/player/skills/ISkillHandler.java b/src/api/java/de/teamlapen/vampirism/api/entity/player/skills/ISkillHandler.java index 9309cf0ca..d20b0aa59 100755 --- a/src/api/java/de/teamlapen/vampirism/api/entity/player/skills/ISkillHandler.java +++ b/src/api/java/de/teamlapen/vampirism/api/entity/player/skills/ISkillHandler.java @@ -19,6 +19,10 @@ static > Optional> get(Player player) return VampirismAPI.factionPlayerHandler(player).getSkillHandler(); } + static > boolean isSkillEnabled(Player player, Holder> skill) { + return get(player).map(handler -> handler.isSkillEnabled(skill)).orElse(false); + } + /** * @return Returns false if the skill already is unlocked or the parent node is not unlocked or the skill is not found */ diff --git a/src/generated/resources/data/vampirism/vampirism/skill_node/hunter/alchemy6.json b/src/generated/resources/data/vampirism/vampirism/skill_node/hunter/alchemy6.json index 6aac465f8..373cdd5ff 100644 --- a/src/generated/resources/data/vampirism/vampirism/skill_node/hunter/alchemy6.json +++ b/src/generated/resources/data/vampirism/vampirism/skill_node/hunter/alchemy6.json @@ -1,5 +1,6 @@ { "skills": [ - "vampirism:hunter_awareness" + "vampirism:hunter_awareness", + "vampirism:crucifix_repel" ] } \ No newline at end of file diff --git a/src/main/java/de/teamlapen/vampirism/client/gui/screens/VampirismContainerScreen.java b/src/main/java/de/teamlapen/vampirism/client/gui/screens/VampirismContainerScreen.java index b65b03b97..da2c5a6e3 100644 --- a/src/main/java/de/teamlapen/vampirism/client/gui/screens/VampirismContainerScreen.java +++ b/src/main/java/de/teamlapen/vampirism/client/gui/screens/VampirismContainerScreen.java @@ -106,9 +106,10 @@ public void render(@NotNull GuiGraphics graphics, int mouseX, int mouseY, float graphics.renderItem(stack, x, y); graphics.renderItemDecorations(this.font, stack, x, y, null); } + + this.renderAccessorySlots(graphics, mouseX, mouseY, partialTicks); } - this.renderAccessorySlots(graphics, mouseX, mouseY, partialTicks); this.renderTooltip(graphics, mouseX, mouseY); if (this.menu.areRefinementsAvailable()) { diff --git a/src/main/java/de/teamlapen/vampirism/entity/player/hunter/skills/HunterSkills.java b/src/main/java/de/teamlapen/vampirism/entity/player/hunter/skills/HunterSkills.java index 608268d31..f6d6a779a 100755 --- a/src/main/java/de/teamlapen/vampirism/entity/player/hunter/skills/HunterSkills.java +++ b/src/main/java/de/teamlapen/vampirism/entity/player/hunter/skills/HunterSkills.java @@ -81,6 +81,7 @@ public class HunterSkills { public static final DeferredHolder, ISkill> DOUBLE_IT = SKILLS.register("double_it", () -> new VampirismSkill.SimpleHunterSkill(2, true)); public static final DeferredHolder, ISkill> MASTER_CRAFTSMANSHIP = SKILLS.register("master_craftsmanship", () -> new VampirismSkill.SimpleHunterSkill(3, true)); public static final DeferredHolder, ISkill> AXE2 = SKILLS.register("axe2", () -> new VampirismSkill.SimpleHunterSkill(3, true)); + public static final DeferredHolder, ISkill> CRUCIFIX_REPEL = SKILLS.register("crucifix_repel", () -> new VampirismSkill.SimpleHunterSkill(2, true)); @ApiStatus.Internal public static void register(IEventBus bus) { @@ -134,7 +135,7 @@ public static void createSkillNodes(BootstrapContext context) { context.register(ALCHEMY3, new SkillNode(GARLIC_DIFFUSER)); context.register(ALCHEMY4, new SkillNode(PURIFIED_GARLIC, GARLIC_DIFFUSER_IMPROVED)); context.register(ALCHEMY5, new SkillNode(ENHANCED_BLESSING, ULTIMATE_CRUCIFIX)); - context.register(ALCHEMY6, new SkillNode(HUNTER_AWARENESS)); + context.register(ALCHEMY6, new SkillNode(HUNTER_AWARENESS, CRUCIFIX_REPEL)); context.register(POTION1, new SkillNode(MULTITASK_BREWING)); context.register(POTION2, new SkillNode(DURABLE_BREWING, CONCENTRATED_BREWING)); diff --git a/src/main/java/de/teamlapen/vampirism/items/CrucifixItem.java b/src/main/java/de/teamlapen/vampirism/items/CrucifixItem.java index 65560493b..c06d570e5 100644 --- a/src/main/java/de/teamlapen/vampirism/items/CrucifixItem.java +++ b/src/main/java/de/teamlapen/vampirism/items/CrucifixItem.java @@ -4,6 +4,7 @@ import de.teamlapen.vampirism.api.entity.factions.IFaction; import de.teamlapen.vampirism.api.entity.player.hunter.IHunterPlayer; import de.teamlapen.vampirism.api.entity.player.skills.ISkill; +import de.teamlapen.vampirism.api.entity.player.skills.ISkillHandler; import de.teamlapen.vampirism.api.items.IFactionExclusiveItem; import de.teamlapen.vampirism.api.items.IFactionLevelItem; import de.teamlapen.vampirism.api.items.IItemWithTier; @@ -12,7 +13,9 @@ import de.teamlapen.vampirism.core.ModRefinements; import de.teamlapen.vampirism.core.tags.ModFactionTags; import de.teamlapen.vampirism.entity.player.VampirismPlayerAttributes; +import de.teamlapen.vampirism.entity.player.hunter.HunterPlayer; import de.teamlapen.vampirism.entity.player.hunter.skills.HunterSkills; +import de.teamlapen.vampirism.entity.player.skills.SkillHandler; import de.teamlapen.vampirism.entity.player.vampire.VampirePlayer; import de.teamlapen.vampirism.entity.vampire.AdvancedVampireEntity; import de.teamlapen.vampirism.entity.vampire.VampireBaronEntity; @@ -46,7 +49,6 @@ public class CrucifixItem extends Item implements IItemWithTier, IFactionExclusiveItem, IFactionLevelItem { - private final static String baseRegName = "crucifix"; private final TIER tier; /** * All crucifix items are added to this set. This is used to add cooldown for all existing crucifix items at once. @@ -91,8 +93,17 @@ public TIER getVampirismTier() { @Override public @NotNull InteractionResultHolder use(Level world, @NotNull Player player, InteractionHand hand) { ItemStack itemstack = player.getItemInHand(hand); - player.startUsingItem(hand); - return InteractionResultHolder.consume(itemstack); + if (Helper.isHunter(player)) { + SkillHandler skillHandler = HunterPlayer.get(player).getSkillHandler(); + if (skillHandler.isSkillEnabled(HunterSkills.CRUCIFIX_REPEL)) { + activePush(world, player, itemstack); + applyCooldown(player, getCooldown(itemstack) * 2); + } else { + player.startUsingItem(hand); + } + return InteractionResultHolder.consume(itemstack); + } + return InteractionResultHolder.fail(itemstack); } @Override @@ -112,6 +123,15 @@ public void inventoryTick(ItemStack stack, Level world, Entity entity, int slot, } } } + if (held && entity instanceof Player player && !player.getCooldowns().isOnCooldown(this) && Helper.isHunter(player) && ISkillHandler.isSkillEnabled(player, HunterSkills.CRUCIFIX_REPEL)) { + passivePush(world, player, stack, true); + } + } + + protected void applyCooldown(LivingEntity entity, int cooldown) { + if (entity instanceof Player player) { + all_crucifix.forEach(item -> player.getCooldowns().addCooldown(item, cooldown)); + } } protected boolean affectsEntity(@NotNull LivingEntity e) { @@ -121,9 +141,7 @@ protected boolean affectsEntity(@NotNull LivingEntity e) { @Override public void releaseUsing(ItemStack stack, Level world, LivingEntity entity, int p_77615_4_) { - if (entity instanceof Player) { - all_crucifix.forEach(item -> ((Player) entity).getCooldowns().addCooldown(item, getCooldown(stack))); - } + applyCooldown(entity, getCooldown(stack)); } protected int getCooldown(ItemStack stack) { @@ -160,12 +178,16 @@ protected static int determineEntityTier(LivingEntity e) { return 1; } - protected double determineSlowdown(int entityTier) { - return switch (tier) { + protected double determineSlowdown(int entityTier, boolean reducedStrength) { + var slowdown = switch (tier) { case NORMAL -> entityTier > 1 ? 0.1 : 0.5; case ENHANCED -> entityTier > 2 ? 0.1 : 0.5; case ULTIMATE -> entityTier > 3 ? 0.3 : 0.5; }; + if (reducedStrength) { + slowdown *= 0.25; + } + return slowdown; } protected int getRange(ItemStack stack) { @@ -178,14 +200,18 @@ protected int getRange(ItemStack stack) { @Override public void onUseTick(@NotNull Level level, @NotNull LivingEntity entity, @NotNull ItemStack stack, int count) { - for (LivingEntity nearbyEntity : entity.level().getNearbyEntities(LivingEntity.class, TargetingConditions.forCombat().selector(this::affectsEntity), entity, entity.getBoundingBox().inflate(getRange(stack)))) { + passivePush(level, entity, stack, false); + } + + protected void passivePush(@NotNull Level level, @NotNull LivingEntity entity, @NotNull ItemStack stack, boolean reducedStrength) { + for (LivingEntity nearbyEntity : level.getNearbyEntities(LivingEntity.class, TargetingConditions.forCombat().selector(this::affectsEntity), entity, entity.getBoundingBox().inflate(getRange(stack)))) { Vec3 baseVector = entity.position().subtract(nearbyEntity.position()).multiply(1, 0, 1).normalize(); //Normalized horizontal (xz) vector giving the direction towards the holder of this crucifix Vec3 oldDelta = nearbyEntity.getDeltaMovement(); Vec3 horizontalDelta = oldDelta.multiply(1, 0, 1); double parallelScale = baseVector.dot(horizontalDelta); if (parallelScale > 0) { Vec3 parallelPart = baseVector.scale(parallelScale); //Part of delta that is parallel to baseVector - double scale = determineSlowdown(determineEntityTier(nearbyEntity)); + double scale = determineSlowdown(determineEntityTier(nearbyEntity), reducedStrength); Vec3 newDelta = oldDelta.subtract(parallelPart.scale(scale)); //Substract parallel part from old Delta (scaled to still allow some movement) if (newDelta.lengthSqr() > oldDelta.lengthSqr()) { //Just to make sure we do not speed up the movement even though this should not be possible newDelta = Vec3.ZERO; @@ -202,5 +228,19 @@ public void onUseTick(@NotNull Level level, @NotNull LivingEntity entity, @NotNu } } + public void activePush(@NotNull Level level, @NotNull LivingEntity entity, @NotNull ItemStack stack) { + for (LivingEntity nearbyEntity : level.getNearbyEntities(LivingEntity.class, TargetingConditions.forCombat().selector(this::affectsEntity), entity, entity.getBoundingBox().inflate(getRange(stack)))) { + Vec3 baseVector = entity.position().subtract(nearbyEntity.position()).multiply(1, 0, 1).normalize(); //Normalized horizontal (xz) vector giving the direction towards the holder of this crucifix + Vec3 oldDelta = nearbyEntity.getDeltaMovement(); + double scale = determineSlowdown(determineEntityTier(nearbyEntity), false); + Vec3 newDelta = oldDelta.subtract(baseVector.scale(scale * 3)); + Vec3 collisionDelta = ((EntityAccessor) nearbyEntity).invoke_collide(newDelta); + if (collisionDelta.y != newDelta.y && newDelta.y < 0) { + newDelta = newDelta.multiply(1, 0, 1); + } + nearbyEntity.setDeltaMovement(newDelta); + } + } + }