Skip to content

Commit 2de2b81

Browse files
committed
feat: improve ferocity
1 parent c774729 commit 2de2b81

4 files changed

Lines changed: 91 additions & 55 deletions

File tree

commons/src/main/java/net/swofty/commons/skyblock/statistics/ItemStatistic.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public enum ItemStatistic {
2525
BONUS_ATTACK_SPEED("Bonus Attack Speed", NamedTextColor.RED, NamedTextColor.YELLOW, true, PackSprite.STAT_ATTACK_SPEED, 100D),
2626
ABILITY_DAMAGE("Ability Damage", NamedTextColor.RED, NamedTextColor.RED, true, PackSprite.STAT_ABILITY_DAMAGE, 0D, 1D, null, false),
2727
TRUE_DEFENSE("True Defense", NamedTextColor.GREEN, NamedTextColor.WHITE, false, PackSprite.STAT_TRUE_DEFENSE),
28-
FEROCITY("Ferocity", NamedTextColor.GREEN, NamedTextColor.RED, false, PackSprite.STAT_FEROCITY),
28+
FEROCITY("Ferocity", NamedTextColor.GREEN, NamedTextColor.RED, false, PackSprite.STAT_FEROCITY, 500D),
2929
HEALTH_REGENERATION("Health Regen", NamedTextColor.GREEN, NamedTextColor.RED,
3030
false, PackSprite.STAT_HEALTH_REGEN, 100D, 1D),
3131
VITALITY("Vitality", NamedTextColor.GREEN, NamedTextColor.DARK_RED,

type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionArrowDamageMob.java

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package net.swofty.type.skyblockgeneric.event.actions.player.mobdamage;
22

3-
import net.minestom.server.entity.damage.Damage;
4-
import net.minestom.server.entity.damage.DamageType;
53
import net.minestom.server.event.entity.projectile.ProjectileCollideWithEntityEvent;
64
import net.swofty.commons.skyblock.statistics.ItemStatistic;
75
import net.swofty.commons.skyblock.statistics.ItemStatistics;
@@ -15,7 +13,7 @@
1513
import net.swofty.type.skyblockgeneric.item.SkyBlockItem;
1614
import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer;
1715
import net.swofty.type.skyblockgeneric.user.statistics.PlayerStatistics;
18-
import net.swofty.type.skyblockgeneric.utility.DamageIndicator;
16+
import net.swofty.type.skyblockgeneric.utility.AttackService;
1917

2018
import java.util.Map;
2119

@@ -43,33 +41,16 @@ public void run(ProjectileCollideWithEntityEvent event) {
4341
ItemStatistics playerStats = shooter.getStatistics().allStatistics();
4442

4543
// Add the arrow's statistics to the player's statistics
46-
ItemStatistics.add(playerStats, arrowItem.getAttributeHandler().getStatistics());
44+
playerStats = ItemStatistics.add(playerStats, arrowItem.getAttributeHandler().getStatistics());
4745

4846
Map.Entry<Double, Boolean> hit = PlayerStatistics.runPrimaryDamageFormula(playerStats, entityStats);
4947
double damage = hit.getKey() * AttributeEffectService.outgoingDamageMultiplier(shooter.getHuntingData(), collidedWith, true);
5048
boolean critical = hit.getValue();
5149

52-
new DamageIndicator()
53-
.damage((float) damage)
54-
.pos(collidedWith.getPosition())
55-
.critical(critical)
56-
.display(collidedWith.getInstance());
50+
float damageAmount = (float) damage;
51+
if (!AttackService.applyHit(shooter, collidedWith, damageAmount, critical)) return;
5752

58-
collidedWith.damage(new Damage(DamageType.PLAYER_ATTACK, player, player, player.getPosition(), (float) damage));
59-
60-
double ferocity = shooter.getStatistics().allStatistics().getOverall(ItemStatistic.FEROCITY);
61-
62-
int extraAttacks = (int) (ferocity / 100);
63-
double extraAttackChance = (ferocity % 100) / 100.0;
64-
65-
// Extra attacks that are guaranteed because ferocity overflowed 100
66-
for (int i = 0; i < extraAttacks; i++) {
67-
collidedWith.damage(new Damage(DamageType.PLAYER_ATTACK, player, player, player.getPosition(), (float) damage));
68-
}
69-
70-
// Extra attacks that have a chance to occur based on the remaining ferocity
71-
if (Math.random() < extraAttackChance) {
72-
collidedWith.damage(new Damage(DamageType.PLAYER_ATTACK, player, player, player.getPosition(), (float) damage));
73-
}
53+
double ferocity = playerStats.getOverall(ItemStatistic.FEROCITY);
54+
AttackService.scheduleExtraHits(shooter, collidedWith, damageAmount, critical, ferocity);
7455
}
7556
}

type.skyblockgeneric/src/main/java/net/swofty/type/skyblockgeneric/event/actions/player/mobdamage/PlayerActionDamageMob.java

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
package net.swofty.type.skyblockgeneric.event.actions.player.mobdamage;
22

3-
import net.kyori.adventure.key.Key;
4-
import net.kyori.adventure.sound.Sound;
53
import net.minestom.server.entity.Entity;
64
import net.minestom.server.entity.EntityType;
75
import net.minestom.server.entity.LivingEntity;
8-
import net.minestom.server.entity.damage.Damage;
9-
import net.minestom.server.entity.damage.DamageType;
106
import net.minestom.server.event.entity.EntityAttackEvent;
117
import net.swofty.commons.skyblock.statistics.ItemStatistic;
128
import net.swofty.commons.skyblock.statistics.ItemStatistics;
@@ -25,15 +21,13 @@
2521
import net.swofty.type.skyblockgeneric.item.components.ItemRequirementsComponent;
2622
import net.swofty.type.skyblockgeneric.item.updater.PlayerItemOrigin;
2723
import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer;
28-
import net.swofty.type.skyblockgeneric.utility.DamageIndicator;
24+
import net.swofty.type.skyblockgeneric.utility.AttackService;
2925

3026
import java.util.HashMap;
3127
import java.util.Map;
32-
import java.util.Random;
3328
import java.util.UUID;
3429

3530
public class PlayerActionDamageMob implements HypixelEventClass {
36-
private static final Random random = new Random();
3731
private static final Map<UUID, Long> COOLDOWN = new HashMap<>();
3832

3933
@PhasedEvent(node = EventNodes.ALL, requireDataLoaded = false, phase = EventPhase.GAMEPLAY)
@@ -52,8 +46,6 @@ public void run(EntityAttackEvent event) {
5246
else return;
5347
LivingEntity targetLivingEntity = (LivingEntity) targetEntity;
5448

55-
player.playSound(Sound.sound(Key.key("entity." + mob.getEntityType().name().toLowerCase().replace("minecraft:", "") + ".hurt"), Sound.Source.PLAYER, 1f, 1f), Sound.Emitter.self());
56-
5749
ItemStatistics entityStats = mob.getStatistics();
5850
Map.Entry<Double, Boolean> hit = player.getStatistics().runPrimaryDamageFormula(entityStats, player, targetLivingEntity);
5951

@@ -69,31 +61,16 @@ public void run(EntityAttackEvent event) {
6961
COOLDOWN.put(player.getUuid(), System.currentTimeMillis() +
7062
MathUtility.ticksToMilliseconds(player.getStatistics().getInvulnerabilityTime()));
7163

72-
new DamageIndicator()
73-
.damage((float) valueEvent.getValue())
74-
.pos(targetEntity.getPosition())
75-
.critical(critical)
76-
.display(targetEntity.getInstance());
77-
78-
targetLivingEntity.damage(new Damage(DamageType.PLAYER_ATTACK, player, player, player.getPosition(), (float) valueEvent.getValue()));
64+
float damageAmount = ((Number) valueEvent.getValue()).floatValue();
65+
if (!AttackService.applyHit(player, mob, damageAmount, critical)) return;
7966

8067
double ferocity = player.getStatistics().allStatistics().getOverall(ItemStatistic.FEROCITY);
81-
int extraAttacks = (int) (ferocity / 100);
82-
double extraAttackChance = (ferocity % 100) / 100.0;
83-
84-
// Extra attacks that are guaranteed because ferocity overflowed 100
85-
for (int i = 0; i < extraAttacks; i++) {
86-
targetLivingEntity.damage(new Damage(DamageType.PLAYER_ATTACK, player, player, player.getPosition(), (float) valueEvent.getValue()));
87-
}
88-
89-
// Extra attacks that have a chance to occur based on the remaining ferocity
90-
if (random.nextDouble() < extraAttackChance) {
91-
targetLivingEntity.damage(new Damage(DamageType.PLAYER_ATTACK, player, player, player.getPosition(), (float) valueEvent.getValue()));
92-
}
68+
if (player.getPosition().distance(mob.getPosition()) <= AttackService.MAX_MELEE_FEROCITY_DISTANCE)
69+
AttackService.scheduleExtraHits(player, mob, damageAmount, critical, ferocity);
9370

9471
// Handle damage event enchantments
9572
SkyBlockItem mainHandItem = PlayerItemOrigin.getFromCache(player.getUuid()).get(PlayerItemOrigin.MAIN_HAND);
96-
double damageValue = ((Number) valueEvent.getValue()).doubleValue();
73+
double damageValue = damageAmount;
9774

9875
for (SkyBlockEnchantment enchantment : mainHandItem.getAttributeHandler().getEnchantments().toList()) {
9976
if (enchantment.type().getEnch() instanceof DamageEventEnchant damageEventEnchant) {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package net.swofty.type.skyblockgeneric.utility;
2+
3+
import net.kyori.adventure.key.Key;
4+
import net.kyori.adventure.sound.Sound;
5+
import net.minestom.server.MinecraftServer;
6+
import net.minestom.server.coordinate.Pos;
7+
import net.minestom.server.entity.damage.Damage;
8+
import net.minestom.server.entity.damage.DamageType;
9+
import net.minestom.server.instance.Instance;
10+
import net.minestom.server.timer.TaskSchedule;
11+
import net.swofty.type.skyblockgeneric.entity.mob.SkyBlockMob;
12+
import net.swofty.type.skyblockgeneric.user.SkyBlockPlayer;
13+
14+
import java.util.Locale;
15+
import java.util.concurrent.ThreadLocalRandom;
16+
17+
public final class AttackService {
18+
public static final int EXTRA_HIT_DELAY_TICKS = 5;
19+
public static final double MAX_MELEE_FEROCITY_DISTANCE = 6D;
20+
public static final double MAX_FEROCITY = 500D;
21+
22+
private AttackService() {
23+
}
24+
25+
public static boolean applyHit(SkyBlockPlayer attacker, SkyBlockMob target, float damage, boolean critical) {
26+
if (target.isRemoved() || target.isDead()) return false;
27+
28+
Instance instance = target.getInstance();
29+
Pos position = target.getPosition();
30+
boolean applied = target.damage(new Damage(
31+
DamageType.PLAYER_ATTACK,
32+
attacker,
33+
attacker,
34+
attacker.getPosition(),
35+
damage
36+
));
37+
if (!applied) return false;
38+
39+
String entityName = target.getEntityType().name().toLowerCase(Locale.ROOT).replace("minecraft:", "");
40+
attacker.playSound(
41+
Sound.sound(Key.key("entity." + entityName + ".hurt"), Sound.Source.PLAYER, 1f, 1f),
42+
Sound.Emitter.self()
43+
);
44+
if (instance != null) {
45+
new DamageIndicator()
46+
.damage(damage)
47+
.pos(position)
48+
.critical(critical)
49+
.display(instance);
50+
}
51+
return true;
52+
}
53+
54+
public static void scheduleExtraHits(SkyBlockPlayer attacker, SkyBlockMob target,
55+
float damage, boolean critical, double ferocity) {
56+
double effectiveFerocity = Math.max(0D, Math.min(MAX_FEROCITY, ferocity));
57+
int extraHits = calculateExtraHits(effectiveFerocity, ThreadLocalRandom.current().nextDouble(100D));
58+
59+
for (int hit = 0; hit < extraHits; hit++) {
60+
int delay = EXTRA_HIT_DELAY_TICKS * (hit + 1);
61+
MinecraftServer.getSchedulerManager().scheduleTask(
62+
() -> applyHit(attacker, target, damage, critical),
63+
TaskSchedule.tick(delay),
64+
TaskSchedule.stop()
65+
);
66+
}
67+
}
68+
69+
static int calculateExtraHits(double ferocity, double chanceRoll) {
70+
double effectiveFerocity = Math.max(0D, Math.min(MAX_FEROCITY, ferocity));
71+
int extraHits = (int) (effectiveFerocity / 100D);
72+
double remainingChance = effectiveFerocity % 100D;
73+
if (remainingChance > 0D && chanceRoll < remainingChance) {
74+
extraHits++;
75+
}
76+
return extraHits;
77+
}
78+
}

0 commit comments

Comments
 (0)