That script looks right, though there's one change I'd recommend.
int firesfx = 40;
This is a global variable, but since it doesn't ever need to change it should probably be a constant (const int) instead. Typically those are written in all caps, so something like SFX_FIRE. Oh hey, just so happens that one's already declared in std.zh as the default fire sound. If you're using a different one, you could call it SFX_TORCHFIRE or something similar.
As for whistle animations, try this:
const int TIL_WHISTLEANIM = 0; //First tile of the whistle animation
const int FRAMES_WHISTLEANIM = 4; //Number of animation frames in the animation
const int ASPEED_WHISTLEANIM = 8; //Speed of the animation
const int WHISTLEANIM_DURATION = 128; //If >0, the above animation will loop for this many frames
//D0: The SFX to play for the whistle. (Set the item's actual SFX to 0 to prevent screen freezing)
itemdata script WhistleAnimation{
void run(int sfx){
Game->PlaySound(sfx);
if(WHISTLEANIM_DURATION){
int t;
int frame;
for(int i=0; i<WHISTLEANIM_DURATION; ++i){
Link->ScriptTile = TIL_WHISTLEANIM+frame;
++t;
if(t>=ASPEED_WHISTLEANIM){
t = 0;
frame = (frame+1)%FRAMES_WHISTLEANIM;
}
Link->Action = LA_NONE;
Link->Action = LA_ATTACKING;
Waitframe();
}
}
else{
for(int i=0; i<FRAMES_WHISTLEANIM; ++i){
Link->ScriptTile = TIL_WHISTLEANIM+i;
for(int j=0; j<ASPEED_WHISTLEANIM; ++j){
Link->Action = LA_NONE;
Link->Action = LA_ATTACKING;
Waitframe();
}
}
}
Link->Action = LA_NONE;
Link->ScriptTile = -1;
}
}
This script is a bit of a hack. You'll want to set your whistle's SFX to 0 and D0 on its item script tab to the whistle sound. This is because scripts can't actually run while the whistle sound is playing normally. It's just too powerful and had to be nerfed. You'll also need to have Item Scripts Continue To Run checked under ZScript->Quest Script Settings. This lets item scripts run for multiple frames.