reskin wolf as hyena — visual + lean-in flavor

Replaces the procedural brown-rectangle "wolf" with the CraftPix Free
Desert Enemy Sprite Sheets hyena. 48×48, side-view, 2-direction via
horizontal flip. AnimatedSprite2D mounted in Wolf.setup() and
Wolf.from_dict() (same pattern as pawn reskin Slice 1). Anims: idle
(4f @ 5fps) + walk (6f @ 10fps). Attack/hurt/death anims skipped for
MVP scope.

Player-facing copy renamed wolf→hyena in strings.gd (6 entries) and
event_catalog.gd (3 EventDef title/body fields). Internal identifiers
(class Wolf, World.wolves, EventBus.wolf_spawned, save class_id
&"wolf", event IDs like &"lone_wolf") stay the same for save compat
— see header comment in wolf.gd.

MCP runtime verified: hyena AnimatedSprite2D mounted on spawn, idle
anim plays, storyteller modal renders "Lone Hyena — A starving hyena
circles your livestock."

Sprites: CraftPix Free Desert Enemy Sprite Sheets.
License: CraftPix Free (commercial OK, attribution appreciated).
https://free-game-assets.itch.io/free-enemy-sprite-sheets-pixel-art

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
megaproxy 2026-05-16 21:03:46 +01:00
parent 8a7584e411
commit f30c7a858b
9 changed files with 179 additions and 31 deletions

View file

@ -0,0 +1,34 @@
class_name HyenaSpriteFrames extends RefCounted
## Builds a SpriteFrames resource for the Hyena (player-facing "hyena") entity.
##
## Atlas layout (single horizontal strip, 48×48 cells):
## Hyena_idle.png — 192×48 = 4 frames
## Hyena_walk.png — 288×48 = 6 frames
##
## Sprites: CraftPix Free Desert Enemy Sprite Sheets.
## License: CraftPix Free (commercial OK, attribution appreciated).
## https://free-game-assets.itch.io/free-enemy-sprite-sheets-pixel-art
const FRAME_SIZE: int = 48
## Build and return a SpriteFrames with "idle" (4f, 5 fps) and "walk" (6f, 10 fps).
static func build() -> SpriteFrames:
var sf := SpriteFrames.new()
var idle_tex: Texture2D = preload("res://art/sprites/Hyena_idle.png")
var walk_tex: Texture2D = preload("res://art/sprites/Hyena_walk.png")
if sf.has_animation(&"default"):
sf.remove_animation(&"default")
_add_anim(sf, &"idle", idle_tex, 4, 5.0)
_add_anim(sf, &"walk", walk_tex, 6, 10.0)
return sf
static func _add_anim(sf: SpriteFrames, anim_name: StringName, tex: Texture2D, count: int, fps: float) -> void:
sf.add_animation(anim_name)
sf.set_animation_loop(anim_name, true)
sf.set_animation_speed(anim_name, fps)
for i in count:
var at := AtlasTexture.new()
at.atlas = tex
at.region = Rect2(i * FRAME_SIZE, 0, FRAME_SIZE, FRAME_SIZE)
sf.add_frame(anim_name, at)