void changeAnimation(Entity * entity, size_t layer, ANIM_HANDLE * animation,
                          AnimUseType flags, bool startAtBeginning) {
	AnimLayer  & animlayer = entity->animlayer[layer];
	AcquireLastAnim(entity);
	FinishAnim(entity, animlayer.cur_anim);
	ANIM_Set(animlayer, animation);
	animlayer.flags |= flags;
	if(startAtBeginning) {
		animlayer.altidx_cur = 0;
	}
}
Beispiel #2
0
static void ARX_SPEECH_Release(long i) {
	
	if(aspeech[i].exist) {
		
		ARX_SOUND_Stop(aspeech[i].sample);
		
		if(ValidIOAddress(aspeech[i].io) && aspeech[i].io->animlayer[2].cur_anim) {
			AcquireLastAnim(aspeech[i].io);
			aspeech[i].io->animlayer[2].cur_anim = NULL;
		}
		
		aspeech[i].clear();
	}
}
Beispiel #3
0
void ManageCombatModeAnimationsEND() {
	
	Entity * io = entities.player();
	
	AnimLayer & layer1 = io->animlayer[1];
	AnimLayer & layer3 = io->animlayer[3];
	
	ANIM_HANDLE ** alist = io->anims;

	if(layer1.cur_anim
		&&(		(layer1.cur_anim == alist[ANIM_BARE_READY])
			||	(layer1.cur_anim == alist[ANIM_DAGGER_READY_PART_2])
			||	(layer1.cur_anim == alist[ANIM_DAGGER_READY_PART_1])
			||	(layer1.cur_anim == alist[ANIM_1H_READY_PART_2])
			||	(layer1.cur_anim == alist[ANIM_1H_READY_PART_1])
			||	(layer1.cur_anim == alist[ANIM_2H_READY_PART_2])
			||	(layer1.cur_anim == alist[ANIM_2H_READY_PART_1])
			||	(layer1.cur_anim == alist[ANIM_MISSILE_READY_PART_1])
			||	(layer1.cur_anim == alist[ANIM_MISSILE_READY_PART_2])	)
	) {
		AimTime = (unsigned long)(arxtime);
	}

	if(layer1.flags & EA_ANIMEND) {
		WeaponType weapontype = ARX_EQUIPMENT_GetPlayerWeaponType();

		if(layer1.cur_anim &&
			(	(layer1.cur_anim == io->anims[ANIM_BARE_UNREADY])
			||	(layer1.cur_anim == io->anims[ANIM_DAGGER_UNREADY_PART_2])
			||	(layer1.cur_anim == io->anims[ANIM_1H_UNREADY_PART_2])
			||	(layer1.cur_anim == io->anims[ANIM_2H_UNREADY_PART_2])
			||	(layer1.cur_anim == io->anims[ANIM_MISSILE_UNREADY_PART_2])	)
		) {
			AcquireLastAnim(io);
			layer1.cur_anim = NULL;
		}

		switch(weapontype) {
			case WEAPON_BARE: {
				// Is Weapon Ready ? In this case go to Fight Wait anim
				if(layer1.cur_anim == alist[ANIM_BARE_READY]) {
					if(player.Interface & INTER_NO_STRIKE) {
						player.Interface &= ~INTER_NO_STRIKE;
						changeAnimation(io, 1, alist[ANIM_BARE_WAIT], EA_LOOP);
					} else {
						changeAnimation(io, 1, alist[ANIM_BARE_STRIKE_LEFT_START + CurrFightPos * 3]);
					}
					AimTime = (unsigned long)(arxtime);
					io->isHit = false;
				}
				break;
			}
			case WEAPON_DAGGER: // DAGGER ANIMS end

				if(alist[ANIM_DAGGER_READY_PART_1]) {
					if(layer1.cur_anim == alist[ANIM_DAGGER_READY_PART_1]) {
						ARX_EQUIPMENT_AttachPlayerWeaponToHand();
						changeAnimation(io, 1, alist[ANIM_DAGGER_READY_PART_2]);
					} else if(layer1.cur_anim == alist[ANIM_DAGGER_READY_PART_2]) {
						if(player.Interface & INTER_NO_STRIKE) {
							player.Interface &= ~INTER_NO_STRIKE;
							changeAnimation(io, 1, alist[ANIM_DAGGER_WAIT], EA_LOOP);
						} else {
							changeAnimation(io, 1, alist[ANIM_DAGGER_STRIKE_LEFT_START + CurrFightPos * 3]);
						}
						AimTime = (unsigned long)(arxtime);
						io->isHit = false;
					} else if(layer1.cur_anim == alist[ANIM_DAGGER_UNREADY_PART_1]) {
						ARX_EQUIPMENT_AttachPlayerWeaponToBack();
						changeAnimation(io, 1, alist[ANIM_DAGGER_UNREADY_PART_2]);
					}
				}

			break;
			case WEAPON_1H:	// 1H ANIMS end

				if(alist[ANIM_1H_READY_PART_1]) {
					if(layer1.cur_anim == alist[ANIM_1H_READY_PART_1]) {
						ARX_EQUIPMENT_AttachPlayerWeaponToHand();
						changeAnimation(io, 1, alist[ANIM_1H_READY_PART_2]);
					} else if(layer1.cur_anim == alist[ANIM_1H_READY_PART_2]) {
						if(player.Interface & INTER_NO_STRIKE) {
							player.Interface &= ~INTER_NO_STRIKE;
							changeAnimation(io, 1, alist[ANIM_1H_WAIT], EA_LOOP);
						} else {
							changeAnimation(io, 1, alist[ANIM_1H_STRIKE_LEFT_START + CurrFightPos * 3]);
						}
						AimTime = (unsigned long)(arxtime);
						io->isHit = false;
					} else if (layer1.cur_anim == alist[ANIM_1H_UNREADY_PART_1]) {
						ARX_EQUIPMENT_AttachPlayerWeaponToBack();
						changeAnimation(io, 1, alist[ANIM_1H_UNREADY_PART_2]);
					}
				}

			break;
			case WEAPON_2H:	// 2H ANIMS end

				if(alist[ANIM_2H_READY_PART_1]) {
					if(layer1.cur_anim == alist[ANIM_2H_READY_PART_1]) {
						ARX_EQUIPMENT_AttachPlayerWeaponToHand();
						changeAnimation(io, 1, alist[ANIM_2H_READY_PART_2]);
					} else if(layer1.cur_anim == alist[ANIM_2H_READY_PART_2]) {
						if(player.Interface & INTER_NO_STRIKE) {
							player.Interface &= ~INTER_NO_STRIKE;
							changeAnimation(io, 1, alist[ANIM_2H_WAIT], EA_LOOP);
						} else {
							changeAnimation(io, 1, alist[ANIM_2H_STRIKE_LEFT_START + CurrFightPos * 3]);
						}
						AimTime = (unsigned long)(arxtime);
						io->isHit = false;
					} else if(layer1.cur_anim == alist[ANIM_2H_UNREADY_PART_1]) {
						ARX_EQUIPMENT_AttachPlayerWeaponToBack();
						changeAnimation(io, 1, alist[ANIM_2H_UNREADY_PART_2]);
					}
				}

			break;
			case WEAPON_BOW:// MISSILE Weapon ANIMS end

				if(alist[ANIM_MISSILE_READY_PART_1]) {
					if(layer1.cur_anim == alist[ANIM_MISSILE_READY_PART_1]) {
						ARX_EQUIPMENT_AttachPlayerWeaponToHand();
						changeAnimation(io, 1, alist[ANIM_MISSILE_READY_PART_2]);
					} else if(layer1.cur_anim == alist[ANIM_MISSILE_READY_PART_2]) {
						if(Player_Arrow_Count() > 0) {
							if(player.Interface & INTER_NO_STRIKE) {
								player.Interface &= ~INTER_NO_STRIKE;
								changeAnimation(io, 1, alist[ANIM_MISSILE_WAIT], EA_LOOP);
							} else {
								changeAnimation(io, 1, alist[ANIM_MISSILE_STRIKE_PART_1]);
							}
							io->isHit = false;
						} else {
							changeAnimation(io, 1, alist[ANIM_MISSILE_WAIT]);
						}
						EERIE_LINKEDOBJ_UnLinkObjectFromObject(io->obj, arrowobj);
					} else if(layer1.cur_anim == alist[ANIM_MISSILE_STRIKE_PART_1]) {
						// TODO why no AcquireLastAnim()?
						ANIM_Set(layer1, alist[ANIM_MISSILE_STRIKE_PART_2]);
					} else if(layer1.cur_anim == alist[ANIM_MISSILE_STRIKE_PART_2]) {
						// TODO why no AcquireLastAnim()?
						ANIM_Set(layer1, alist[ANIM_MISSILE_STRIKE_CYCLE]);
					} else if(layer1.cur_anim == alist[ANIM_MISSILE_UNREADY_PART_1]) {
						ARX_EQUIPMENT_AttachPlayerWeaponToBack();
						changeAnimation(io, 1, alist[ANIM_MISSILE_UNREADY_PART_2]);
					}
				}

			break;
		}

		// Spell casting anims
		if(alist[ANIM_CAST] && layer1.cur_anim == alist[ANIM_CAST]) {
			if(alist[ANIM_CAST_END]) {
				changeAnimation(io, 1, alist[ANIM_CAST_END]);
			}
		} else if(alist[ANIM_CAST_END] && layer1.cur_anim == alist[ANIM_CAST_END]) {
			AcquireLastAnim(io);
			layer1.cur_anim = NULL;
			player.doingmagic = 0;

			if(WILLRETURNTOCOMBATMODE) {
				player.Interface |= INTER_COMBATMODE;
				player.Interface |= INTER_NO_STRIKE;

				ARX_EQUIPMENT_LaunchPlayerReadyWeapon();
				WILLRETURNTOCOMBATMODE = false;
			}
		}
	}

	// Is the shield off ?
	if(layer3.flags & EA_ANIMEND) {
		if(io->anims[ANIM_SHIELD_END] && layer3.cur_anim == io->anims[ANIM_SHIELD_END]) {
			AcquireLastAnim(io);
			layer3.cur_anim = NULL;
		}
	}
}
/*!
 * \brief Main Procedure to draw an animated object
 *
 * \param eobj main object data
 * \param eanim Animation data
 * \param time Time increment to current animation in Ms
 * \param io Referrence to Interactive Object (NULL if no IO)
 */
void PrepareAnim(AnimLayer & layer, AnimationDuration time, Entity *io) {

	if(layer.flags & EA_PAUSED)
		time = AnimationDuration_ZERO;

	if(io && (io->ioflags & IO_FREEZESCRIPT))
		time = AnimationDuration_ZERO;

	if(layer.altidx_cur >= layer.cur_anim->alt_nb)
		layer.altidx_cur = 0;

	if(!(layer.flags & EA_EXCONTROL))
		layer.ctime += time;

	layer.flags &= ~EA_ANIMEND;

	AnimationDuration animTime = layer.cur_anim->anims[layer.altidx_cur]->anim_time;
	
	if(layer.ctime > animTime) {
	
		if(layer.flags & EA_STOPEND) {
			layer.ctime = animTime;
		}
		
		AnimationDuration lost = layer.ctime - animTime;
		
		if((layer.flags & EA_LOOP)
		   || (io && ((layer.cur_anim == io->anims[ANIM_WALK])
					  || (layer.cur_anim == io->anims[ANIM_WALK2])
					  || (layer.cur_anim == io->anims[ANIM_WALK3])
					  || (layer.cur_anim == io->anims[ANIM_RUN])
					  || (layer.cur_anim == io->anims[ANIM_RUN2])
					  || (layer.cur_anim == io->anims[ANIM_RUN3])))
		) {
				if(!layer.next_anim) {
					layer.ctime = AnimationDuration(layer.ctime.t % animTime.t);
	
					if(io)
						FinishAnim(io, layer.cur_anim);
				} else {
					if(io) {
						FinishAnim(io, layer.cur_anim);
						
						if(io->animBlend.lastanimtime != ArxInstant_ZERO)
							AcquireLastAnim(io);
						else
							io->animBlend.lastanimtime = ArxInstantMs(1);
					}
					
					layer.cur_anim = layer.next_anim;
					layer.altidx_cur = ANIM_GetAltIdx(layer.next_anim, layer.altidx_cur);
					layer.next_anim = NULL;
					ResetAnim(layer);
					layer.ctime = lost;
					layer.flags = layer.nextflags;
					layer.flags &= ~EA_ANIMEND;
				}
		} else {
			if(io && layer.next_anim) {
					FinishAnim(io, layer.cur_anim);
					
					if (io->animBlend.lastanimtime != ArxInstant_ZERO)
						AcquireLastAnim(io);
					else
						io->animBlend.lastanimtime = ArxInstant(1);
					
					layer.cur_anim = layer.next_anim;
					layer.altidx_cur = ANIM_GetAltIdx(layer.next_anim, layer.altidx_cur);
					layer.next_anim = NULL;
					ResetAnim(layer);
					layer.ctime = lost;
					layer.flags = layer.nextflags;
					layer.flags &= ~EA_ANIMEND;
			} else {
				layer.flags |= EA_ANIMEND;
				layer.ctime = layer.cur_anim->anims[layer.altidx_cur]->anim_time;
			}
		}
	
	}
	
	if (!layer.cur_anim)
		return;

	AnimationDuration tim;
	if(layer.flags & EA_REVERSE)
		tim = animTime - layer.ctime;
	else
		tim = layer.ctime;
	
	EERIE_ANIM * anim = layer.cur_anim->anims[layer.altidx_cur];
	
	layer.currentFrame = anim->nb_key_frames - 2;
	layer.currentInterpolation = 1.f;
	
	for(long i = 1; i < anim->nb_key_frames; i++) {
		AnimationDuration tcf = anim->frames[i - 1].time;
		AnimationDuration tnf = anim->frames[i].time;

		if(tcf == tnf)
			return;

		if((tim < tnf && tim >= tcf) || (i == anim->nb_key_frames - 1 && tim == tnf)) {
			long fr = i - 1;
			tim -= tcf;
			float pour = toMsf(tim) / toMsf(tnf - tcf);
			
			// Frame Sound Management
			if(!(layer.flags & EA_ANIMEND)
			   && time != AnimationDuration_ZERO
			   && (anim->frames[fr].sample != -1)
			   && (layer.lastframe != fr)) {

				Vec3f * position = io ? &io->pos : NULL;
				
				if(layer.lastframe < fr && layer.lastframe != -1) {
					for(long n = layer.lastframe + 1; n <= fr; n++)
						ARX_SOUND_PlayAnim(anim->frames[n].sample, position);
				} else {
					ARX_SOUND_PlayAnim(anim->frames[fr].sample, position);
				}
			}

			// Frame Flags Management
			if(!(layer.flags & EA_ANIMEND)
			   && time != AnimationDuration_ZERO
			   && (anim->frames[fr].stepSound)
			   && (layer.lastframe != fr)) {
				
				if(io && io != entities.player()) {
					if(layer.lastframe < fr && layer.lastframe != -1) {
						for(long n = layer.lastframe + 1; n <= fr; n++) {
							if(anim->frames[n].stepSound)
								ARX_NPC_NeedStepSound(io, io->pos);
						}
					}
					else if(anim->frames[fr].stepSound)
						ARX_NPC_NeedStepSound(io, io->pos);
				}
			}
			
			// Memorize this frame as lastframe.
			layer.lastframe = fr;
			layer.currentFrame = fr;
			layer.currentInterpolation = pour;
			break;
		}
	}
}
void stopAnimation(Entity * entity, size_t layer) {
	AnimLayer  & animlayer = entity->animlayer[layer];
	AcquireLastAnim(entity);
	FinishAnim(entity, animlayer.cur_anim);
	animlayer.cur_anim = NULL;
}
Beispiel #6
0
/*!
 * \brief Main Procedure to draw an animated object
 *
 * \param eobj main object data
 * \param eanim Animation data
 * \param time Time increment to current animation in Ms
 * \param io Referrence to Interactive Object (NULL if no IO)
 */
void PrepareAnim(AnimLayer & layer, unsigned long time, Entity *io) {

	if(layer.flags & EA_PAUSED)
		time = 0;

	if(io && (io->ioflags & IO_FREEZESCRIPT))
		time = 0;

	if(layer.altidx_cur >= layer.cur_anim->alt_nb)
		layer.altidx_cur = 0;

	if(!(layer.flags & EA_EXCONTROL))
		layer.ctime += time;

	layer.flags &= ~EA_ANIMEND;

	const long animTime = layer.cur_anim->anims[layer.altidx_cur]->anim_time;
	
	if(layer.ctime > animTime) {
	
		if(layer.flags & EA_STOPEND) {
			layer.ctime = animTime;
		}
		
		long lost = layer.ctime - animTime;
		
		if((layer.flags & EA_LOOP)
		   || (io && ((layer.cur_anim == io->anims[ANIM_WALK])
					  || (layer.cur_anim == io->anims[ANIM_WALK2])
					  || (layer.cur_anim == io->anims[ANIM_WALK3])
					  || (layer.cur_anim == io->anims[ANIM_RUN])
					  || (layer.cur_anim == io->anims[ANIM_RUN2])
					  || (layer.cur_anim == io->anims[ANIM_RUN3])))
		) {
				if(!layer.next_anim) {
					long t = animTime;
					layer.ctime= layer.ctime % t;
	
					if(io)
						FinishAnim(io,layer.cur_anim);
				} else {
					if(io) {
						FinishAnim(io,layer.cur_anim);
						
						if(io->animBlend.lastanimtime != 0)
							AcquireLastAnim(io);
						else
							io->animBlend.lastanimtime = 1;
					}
					
					layer.cur_anim=layer.next_anim;
					layer.altidx_cur=ANIM_GetAltIdx(layer.next_anim,layer.altidx_cur);
					layer.next_anim=NULL;
					ResetAnim(layer);
					layer.ctime = lost;
					layer.flags=layer.nextflags;
					layer.flags&=~EA_ANIMEND;
				}
		} else {
			if(io && layer.next_anim) {
					FinishAnim(io,layer.cur_anim);
					
					if (io->animBlend.lastanimtime!=0)
						AcquireLastAnim(io);
					else
						io->animBlend.lastanimtime=1;
					
					layer.cur_anim=layer.next_anim;
					layer.altidx_cur=ANIM_GetAltIdx(layer.next_anim,layer.altidx_cur);
					layer.next_anim=NULL;
					ResetAnim(layer);
					layer.ctime = lost;
					layer.flags=layer.nextflags;
					layer.flags&=~EA_ANIMEND;
			} else {
				layer.flags |= EA_ANIMEND;
				layer.ctime = layer.cur_anim->anims[layer.altidx_cur]->anim_time;
			}
		}
	
	}
	
	if (!layer.cur_anim)
		return;

	long tim;
	if(layer.flags & EA_REVERSE)
		tim = animTime - layer.ctime;
	else
		tim = layer.ctime;
	
	EERIE_ANIM * anim = layer.cur_anim->anims[layer.altidx_cur];
	
	layer.fr = anim->nb_key_frames - 2;
	layer.pour = 1.f;
	
	for(long i = 1; i < anim->nb_key_frames; i++) {
		long tcf = (long)anim->frames[i - 1].time;
		long tnf = (long)anim->frames[i].time;

		if(tcf == tnf)
			return;

		if((tim < tnf && tim >= tcf) || (i == anim->nb_key_frames - 1 && tim == tnf)) {
			long fr = i - 1;
			tim -= tcf;
			float pour = (float)((float)tim/((float)tnf-(float)tcf));
			
			// Frame Sound Management
			if(!(layer.flags & EA_ANIMEND) && time
			   && (anim->frames[fr].sample != -1)
			   && (layer.lastframe != fr)) {

				Vec3f * position = io ? &io->pos : NULL;
				
				if(layer.lastframe < fr && layer.lastframe != -1) {
					for(long n = layer.lastframe + 1; n <= fr; n++)
						ARX_SOUND_PlayAnim(anim->frames[n].sample, position);
				} else {
					ARX_SOUND_PlayAnim(anim->frames[fr].sample, position);
				}
			}

			// Frame Flags Management
			if(!(layer.flags & EA_ANIMEND) && time
			   && (anim->frames[fr].flag > 0)
			   && (layer.lastframe != fr)) {
				
				if(io && io != entities.player()) {
					if(layer.lastframe < fr && layer.lastframe != -1) {
						for(long n = layer.lastframe + 1; n <= fr; n++) {
							if(anim->frames[n].flag == 9)
								ARX_NPC_NeedStepSound(io, io->pos);
						}
					}
					else if(anim->frames[fr].flag == 9)
						ARX_NPC_NeedStepSound(io, io->pos);
				}
			}
			
			// Memorize this frame as lastframe.
			layer.lastframe = fr;
			layer.fr = fr;
			layer.pour = pour;
			break;
		}
	}
}
/*!
 * \brief Main Procedure to draw an animated object
 *
 * \param eobj main object data
 * \param eanim Animation data
 * \param time Time increment to current animation in Ms
 * \param io Referrence to Interactive Object (NULL if no IO)
 */
void PrepareAnim(ANIM_USE *eanim, unsigned long time, Entity *io) {
	
	if(!eanim)
		return;

	if(eanim->flags & EA_PAUSED)
		time = 0;

	if(io && (io->ioflags & IO_FREEZESCRIPT))
		time = 0;

	if(eanim->altidx_cur >= eanim->cur_anim->alt_nb)
		eanim->altidx_cur = 0;

	if(!(eanim->flags & EA_EXCONTROL))
		eanim->ctime += time;

	eanim->flags &= ~EA_ANIMEND;

	if((eanim->flags & EA_STOPEND) && eanim->ctime > eanim->cur_anim->anims[eanim->altidx_cur]->anim_time)
	{
		eanim->ctime = eanim->cur_anim->anims[eanim->altidx_cur]->anim_time;
	}

	if((eanim->flags & EA_LOOP)
	   || (io && ((eanim->cur_anim == io->anims[ANIM_WALK])
	              || (eanim->cur_anim == io->anims[ANIM_WALK2])
	              || (eanim->cur_anim == io->anims[ANIM_WALK3])
				  || (eanim->cur_anim == io->anims[ANIM_RUN])
				  || (eanim->cur_anim == io->anims[ANIM_RUN2])
				  || (eanim->cur_anim == io->anims[ANIM_RUN3])))) {
		
		if(eanim->ctime > eanim->cur_anim->anims[eanim->altidx_cur]->anim_time) {
			
			long lost = eanim->ctime - long(eanim->cur_anim->anims[eanim->altidx_cur]->anim_time);

			if(!eanim->next_anim) {
				long t = eanim->cur_anim->anims[eanim->altidx_cur]->anim_time;
				eanim->ctime= eanim->ctime % t;

				if(io)
					FinishAnim(io,eanim->cur_anim);
			} else {
				if(io) {
					FinishAnim(io,eanim->cur_anim);

					if(io->animBlend.lastanimtime != 0)
						AcquireLastAnim(io);
					else
						io->animBlend.lastanimtime = 1;
				}

				eanim->cur_anim=eanim->next_anim;
				eanim->altidx_cur=ANIM_GetAltIdx(eanim->next_anim,eanim->altidx_cur);
				eanim->next_anim=NULL;
				ResetAnim(eanim);
				eanim->ctime = lost;
				eanim->flags=eanim->nextflags;
				eanim->flags&=~EA_ANIMEND;
			}
		}
	} else if (eanim->ctime > eanim->cur_anim->anims[eanim->altidx_cur]->anim_time) {
		if(io) {
			long lost = eanim->ctime - eanim->cur_anim->anims[eanim->altidx_cur]->anim_time;

			if(eanim->next_anim) {
				FinishAnim(io,eanim->cur_anim);

				if (io->animBlend.lastanimtime!=0)
					AcquireLastAnim(io);
				else
					io->animBlend.lastanimtime=1;

				eanim->cur_anim=eanim->next_anim;
				eanim->altidx_cur=ANIM_GetAltIdx(eanim->next_anim,eanim->altidx_cur);
				eanim->next_anim=NULL;
				ResetAnim(eanim);
				eanim->ctime = lost;
				eanim->flags=eanim->nextflags;
				eanim->flags&=~EA_ANIMEND;
				goto suite;
			}
		}

		eanim->flags |= EA_ANIMEND;
		eanim->ctime = eanim->cur_anim->anims[eanim->altidx_cur]->anim_time;
	}

suite:

	if (!eanim->cur_anim)
		return;

	long tim;
	if(eanim->flags & EA_REVERSE)
		tim = eanim->cur_anim->anims[eanim->altidx_cur]->anim_time - eanim->ctime;
	else
		tim = eanim->ctime;

	eanim->fr = eanim->cur_anim->anims[eanim->altidx_cur]->nb_key_frames - 2;
	eanim->pour = 1.f;

	long fr;
	for(long i = 1; i < eanim->cur_anim->anims[eanim->altidx_cur]->nb_key_frames; i++) {
		long tcf = (long)eanim->cur_anim->anims[eanim->altidx_cur]->frames[i - 1].time;
		long tnf = (long)eanim->cur_anim->anims[eanim->altidx_cur]->frames[i].time;

		if(tcf == tnf)
			return;

		if((tim < tnf && tim >= tcf) || (i == eanim->cur_anim->anims[eanim->altidx_cur]->nb_key_frames - 1 && tim == tnf)) {
			fr = i - 1;
			tim -= tcf;
			float pour = (float)((float)tim/((float)tnf-(float)tcf));
			
			// Frame Sound Management
			if(!(eanim->flags & EA_ANIMEND) && time
			   && (eanim->cur_anim->anims[eanim->altidx_cur]->frames[fr].sample != -1)
			   && (eanim->lastframe != fr)) {

				Vec3f * position = io ? &io->pos : NULL;
				
				if(eanim->lastframe < fr && eanim->lastframe != -1) {
					for(long n = eanim->lastframe + 1; n <= fr; n++)
						ARX_SOUND_PlayAnim(eanim->cur_anim->anims[eanim->altidx_cur]->frames[n].sample, position);
				} else {
					ARX_SOUND_PlayAnim(eanim->cur_anim->anims[eanim->altidx_cur]->frames[fr].sample, position);
				}
			}

			// Frame Flags Management
			if(!(eanim->flags & EA_ANIMEND) && time
			   && (eanim->cur_anim->anims[eanim->altidx_cur]->frames[fr].flag > 0)
			   && (eanim->lastframe != fr)) {
				
				if(io != entities.player()) {
					if(eanim->lastframe < fr && eanim->lastframe != -1) {
						for(long n = eanim->lastframe + 1; n <= fr; n++) {
							if(eanim->cur_anim->anims[eanim->altidx_cur]->frames[n].flag == 9)
								ARX_NPC_NeedStepSound(io, &io->pos);
						}
					}
					else if(eanim->cur_anim->anims[eanim->altidx_cur]->frames[fr].flag == 9)
						ARX_NPC_NeedStepSound(io, &io->pos);
				}
			}
			
			// Memorize this frame as lastframe.
			eanim->lastframe = fr;
			eanim->fr = fr;
			eanim->pour = pour;
			break;
		}
	}
}