Poison the mob a pufferfish stings

Pufferfish.touch gives the stung mob POISON for 60 * getPuffState() once the hit lands, before the sting sound. Mob::add_effect carries it, so the event now holds the duration and the game applies it.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
Ludovic MarieandClaude Opus 5.5 committed 2026-11-02 13:03:51 +01:00
1 parent fa297fc040
commit 2e1fae8f9f
4 files changed
+20 -8

No files matched your search

+10 -6
View File
@@ -2108,14 +2108,18 @@ impl Game<'_> {
target,
amount,
source,
poison_ticks,
} => {
// Pufferfish.touch: `playSound(PUFFER_FISH_STING, 1, 1)`
// sits inside the `hurtServer` branch, so only a hit that
// landed stings, at the fish's own position as
// Pufferfish.touch: the poison and
// `playSound(PUFFER_FISH_STING, 1, 1)` sit inside the
// `hurtServer` branch, so only a hit that landed poisons
// and stings, at the fish's own position as
// `Entity.playSound` puts it, and not when it is silent.
if self.mob_hits_mob(target, amount, source)
&& let Some(m) = self.mobs.iter_mut().find(|m| m.id == mob)
{
let landed = self.mob_hits_mob(target, amount, source);
if landed && let Some(t) = self.mobs.iter_mut().find(|m| m.id == target) {
t.add_effect("minecraft:poison", poison_ticks, 0);
}
if landed && let Some(m) = self.mobs.iter_mut().find(|m| m.id == mob) {
let at = [m.position.x, m.position.y, m.position.z];
if !m.silent {
self.handle_mob_events(vec![MobEvent::Sound(
+2 -1
View File
@@ -1536,12 +1536,13 @@ pub enum MobEvent {
},
/// `Pufferfish.touch` on a mob (`Pufferfish.aiStep`): the hit, then, only
/// when `hurtServer` let it land, the fish's `entity.puffer_fish.sting`
/// and the poison it gives.
/// and the poison it gives (`poison_ticks`, `60 * getPuffState()`).
PufferfishSting {
mob: u32,
target: u32,
amount: f32,
source: Damage,
poison_ticks: i32,
},
/// `LivingEntity.stabAttack`'s `target.stopRiding()`: a spear knocks the
/// target off its mount.
@@ -421,6 +421,7 @@ fn sting_touching_mobs(m: &mut Mob, w: &MobWorld, events: &mut Vec<MobEvent>) {
target,
amount: 1.0 + m.extra.size as f32,
source: Damage::mob(m.id, from),
poison_ticks: 60 * m.extra.size,
});
}
}
@@ -1182,8 +1183,14 @@ mod pufferfish_sting_tests {
target,
amount,
source,
poison_ticks,
} => {
assert_eq!(source.attacker, Some(Who::Mob(1)));
assert_eq!(
*poison_ticks,
60 * puff,
"Pufferfish.touch's POISON lasts 60 * getPuffState()"
);
Some((*target, *amount))
}
_ => None,
+1 -1
View File
@@ -129,7 +129,7 @@ AbstractSchoolingFish.addFollowers inline crates/horizon-client/src/mobs/aquatic
AbstractSchoolingFish.finalizeSpawn inline crates/horizon-client/src/mobs/finalize.rs::Ctx::finalize the group shares a leader id and variant, and FollowFlockLeader (crates/horizon-client/src/mobs/aquatic.rs) paths a follower to the leader every 10 ticks
Pufferfish.readAdditionalSaveData port crates/horizon-client/src/entity_nbt.rs::mob_from_nbt `getIntOr("PuffState", 0)` at most 2; mob_to_nbt writes it, and a reload test covers it
Pufferfish.registerGoals port crates/horizon-client/src/mobs/aquatic.rs::register the puff goal at priority 1
Pufferfish.touch inline crates/horizon-client/src/mobs/aquatic.rs::ai_step sting_touching_mobs: alive mobs outside #not_scary_for_pufferfish whose box meets the fish's inflated by 0.3, when teams allow damage, take a mobAttack hit for puff state + 1 and the sting sound once it lands; the poison has no path onto another mob (the cave spider's is the same)
Pufferfish.touch inline crates/horizon-client/src/mobs/aquatic.rs::ai_step sting_touching_mobs: alive mobs outside #not_scary_for_pufferfish whose box meets the fish's inflated by 0.3, when teams allow damage, take a mobAttack hit for puff state + 1, then, once it lands, POISON for 60 * puff state and the sting sound (game/creatures.rs PufferfishSting)
Salmon.defineSynchedData port crates/horizon-client/src/game/lan.rs::mob_meta size entry, small 0 to large 2
Salmon.readAdditionalSaveData port crates/horizon-client/src/entity_nbt.rs::read_variant the type tag, medium by default
Salmon.get inline crates/horizon-client/src/entity_nbt.rs::bucket_components the size component goes onto the bucket
Can't render this file because it contains an unexpected character in line 130 and column 104.