2
0
mirror of https://github.com/FWGS/hlsdk-xash3d synced 2024-11-29 05:21:01 +01:00
hlsdk-xash3d/dlls/animation.cpp

528 lines
13 KiB
C++
Raw Normal View History

2016-06-04 15:24:23 +02:00
/***
*
* Copyright (c) 1996-2002, Valve LLC. All rights reserved.
*
* This product contains software technology licensed from Id
* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc.
* All Rights Reserved.
*
* Use, distribution, and modification of this source code and/or resulting
* object code is restricted to non-commercial enhancements to products from
* Valve LLC. All other use, distribution, or modification is prohibited
* without written permission from Valve LLC.
*
****/
2016-07-31 15:48:50 +02:00
/* all this mess was here to use quake mathlib instead of hlsdk vectors
* it may break debug info or even build because global symbols types differ
* it's better to define VectorCopy macro for Vector class */
#if 0
2016-06-04 15:24:23 +02:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int BOOL;
2016-07-31 15:48:50 +02:00
#define TRUE 1
2016-06-04 15:24:23 +02:00
#define FALSE 0
// hack into header files that we can ship
typedef int qboolean;
typedef unsigned char byte;
#include "mathlib.h"
#include "const.h"
#include "progdefs.h"
#include "edict.h"
#include "eiface.h"
#include "studio.h"
2021-06-20 00:53:07 +02:00
#if !defined(ACTIVITY_H)
2016-06-04 15:24:23 +02:00
#include "activity.h"
#endif
#include "activitymap.h"
2021-06-20 00:53:07 +02:00
#if !defined(ANIMATION_H)
2016-06-04 15:24:23 +02:00
#include "animation.h"
#endif
2021-06-20 00:53:07 +02:00
#if !defined(SCRIPTEVENT_H)
2016-06-04 15:24:23 +02:00
#include "scriptevent.h"
#endif
2021-06-20 00:53:07 +02:00
#if !defined(ENGINECALLBACK_H)
2016-06-04 15:24:23 +02:00
#include "enginecallback.h"
#endif
//extern globalvars_t *gpGlobals;
#else
#include "extdll.h"
#include "util.h"
#include "activity.h"
#include "activitymap.h"
#include "animation.h"
#include "scriptevent.h"
#include "studio.h"
#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];}
#endif
2016-06-04 15:24:23 +02:00
#pragma warning( disable : 4244 )
int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs )
{
studiohdr_t *pstudiohdr;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
2016-07-31 15:48:50 +02:00
if( !pstudiohdr )
2016-06-04 15:24:23 +02:00
return 0;
2016-07-31 15:48:50 +02:00
mstudioseqdesc_t *pseqdesc;
pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex );
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
mins[0] = pseqdesc[sequence].bbmin[0];
mins[1] = pseqdesc[sequence].bbmin[1];
mins[2] = pseqdesc[sequence].bbmin[2];
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
maxs[0] = pseqdesc[sequence].bbmax[0];
maxs[1] = pseqdesc[sequence].bbmax[1];
maxs[2] = pseqdesc[sequence].bbmax[2];
2016-06-04 15:24:23 +02:00
return 1;
}
int LookupActivity( void *pmodel, entvars_t *pev, int activity )
{
studiohdr_t *pstudiohdr;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
2016-07-31 15:48:50 +02:00
if( !pstudiohdr )
2016-06-04 15:24:23 +02:00
return 0;
2016-07-31 15:48:50 +02:00
mstudioseqdesc_t *pseqdesc;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex );
2016-06-04 15:24:23 +02:00
int weighttotal = 0;
int seq = ACTIVITY_NOT_AVAILABLE;
2016-07-31 15:48:50 +02:00
for( int i = 0; i < pstudiohdr->numseq; i++ )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if( pseqdesc[i].activity == activity )
2016-06-04 15:24:23 +02:00
{
weighttotal += pseqdesc[i].actweight;
2016-07-31 15:48:50 +02:00
if( !weighttotal || RANDOM_LONG( 0, weighttotal - 1 ) < pseqdesc[i].actweight )
2016-06-04 15:24:23 +02:00
seq = i;
}
}
return seq;
}
int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity )
{
studiohdr_t *pstudiohdr;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
2016-07-31 15:48:50 +02:00
if( !pstudiohdr )
2016-06-04 15:24:23 +02:00
return 0;
2016-07-31 15:48:50 +02:00
mstudioseqdesc_t *pseqdesc;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex );
2016-06-04 15:24:23 +02:00
int weight = 0;
int seq = ACTIVITY_NOT_AVAILABLE;
2016-07-31 15:48:50 +02:00
for( int i = 0; i < pstudiohdr->numseq; i++ )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if( pseqdesc[i].activity == activity )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if( pseqdesc[i].actweight > weight )
2016-06-04 15:24:23 +02:00
{
weight = pseqdesc[i].actweight;
seq = i;
}
}
}
return seq;
}
2016-07-31 15:48:50 +02:00
void GetEyePosition( void *pmodel, float *vecEyePosition )
2016-06-04 15:24:23 +02:00
{
studiohdr_t *pstudiohdr;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
2016-07-31 15:48:50 +02:00
if( !pstudiohdr )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
ALERT( at_console, "GetEyePosition() Can't get pstudiohdr ptr!\n" );
2016-06-04 15:24:23 +02:00
return;
}
2016-07-31 15:48:50 +02:00
VectorCopy( pstudiohdr->eyeposition, vecEyePosition );
2016-06-04 15:24:23 +02:00
}
int LookupSequence( void *pmodel, const char *label )
{
studiohdr_t *pstudiohdr;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
2016-07-31 15:48:50 +02:00
if( !pstudiohdr )
2016-06-04 15:24:23 +02:00
return 0;
2016-07-31 15:48:50 +02:00
mstudioseqdesc_t *pseqdesc;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex );
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
for( int i = 0; i < pstudiohdr->numseq; i++ )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if( stricmp( pseqdesc[i].label, label ) == 0 )
2016-06-04 15:24:23 +02:00
return i;
}
return -1;
}
int IsSoundEvent( int eventNumber )
{
2016-07-31 15:48:50 +02:00
if( eventNumber == SCRIPT_EVENT_SOUND || eventNumber == SCRIPT_EVENT_SOUND_VOICE )
2016-06-04 15:24:23 +02:00
return 1;
return 0;
}
void SequencePrecache( void *pmodel, const char *pSequenceName )
{
int index = LookupSequence( pmodel, pSequenceName );
2016-07-31 15:48:50 +02:00
if( index >= 0 )
2016-06-04 15:24:23 +02:00
{
studiohdr_t *pstudiohdr;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
2016-07-31 15:48:50 +02:00
if( !pstudiohdr || index >= pstudiohdr->numseq )
2016-06-04 15:24:23 +02:00
return;
2016-07-31 15:48:50 +02:00
mstudioseqdesc_t *pseqdesc;
mstudioevent_t *pevent;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ) + index;
pevent = (mstudioevent_t *)( (byte *)pstudiohdr + pseqdesc->eventindex );
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
for( int i = 0; i < pseqdesc->numevents; i++ )
2016-06-04 15:24:23 +02:00
{
// Don't send client-side events to the server AI
2016-07-31 15:48:50 +02:00
if( pevent[i].event >= EVENT_CLIENT )
2016-06-04 15:24:23 +02:00
continue;
// UNDONE: Add a callback to check to see if a sound is precached yet and don't allocate a copy
// of it's name if it is.
2016-07-31 15:48:50 +02:00
if( IsSoundEvent( pevent[i].event ) )
2016-06-04 15:24:23 +02:00
{
2019-09-24 00:00:37 +02:00
if( pevent[i].options[0] == '\0' )
2016-06-04 15:24:23 +02:00
{
ALERT( at_error, "Bad sound event %d in sequence %s :: %s (sound is \"%s\")\n", pevent[i].event, pstudiohdr->name, pSequenceName, pevent[i].options );
}
2017-07-23 23:24:55 +02:00
PRECACHE_SOUND( gpGlobals->pStringBase + ALLOC_STRING( pevent[i].options ) );
2016-06-04 15:24:23 +02:00
}
}
}
}
void GetSequenceInfo( void *pmodel, entvars_t *pev, float *pflFrameRate, float *pflGroundSpeed )
{
studiohdr_t *pstudiohdr;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
2016-07-31 15:48:50 +02:00
if( !pstudiohdr )
2016-06-04 15:24:23 +02:00
return;
2016-07-31 15:48:50 +02:00
mstudioseqdesc_t *pseqdesc;
2016-06-04 15:24:23 +02:00
if( pev->sequence < 0 || pev->sequence >= pstudiohdr->numseq )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
*pflFrameRate = 0.0f;
*pflGroundSpeed = 0.0f;
2016-06-04 15:24:23 +02:00
return;
}
2016-07-31 15:48:50 +02:00
pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ) + (int)pev->sequence;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if( pseqdesc->numframes > 1 )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
*pflFrameRate = 256.0f * pseqdesc->fps / ( pseqdesc->numframes - 1 );
2016-07-31 15:48:50 +02:00
*pflGroundSpeed = sqrt( pseqdesc->linearmovement[0] * pseqdesc->linearmovement[0] + pseqdesc->linearmovement[1] * pseqdesc->linearmovement[1] + pseqdesc->linearmovement[2] * pseqdesc->linearmovement[2] );
*pflGroundSpeed = *pflGroundSpeed * pseqdesc->fps / ( pseqdesc->numframes - 1 );
2016-06-04 15:24:23 +02:00
}
else
{
2019-10-13 13:49:25 +02:00
*pflFrameRate = 256.0f;
*pflGroundSpeed = 0.0f;
2016-06-04 15:24:23 +02:00
}
}
int GetSequenceFlags( void *pmodel, entvars_t *pev )
{
studiohdr_t *pstudiohdr;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
if( !pstudiohdr || pev->sequence < 0 || pev->sequence >= pstudiohdr->numseq )
2016-06-04 15:24:23 +02:00
return 0;
2016-07-31 15:48:50 +02:00
mstudioseqdesc_t *pseqdesc;
pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ) + (int)pev->sequence;
2016-06-04 15:24:23 +02:00
return pseqdesc->flags;
}
int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index )
{
studiohdr_t *pstudiohdr;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
if( !pstudiohdr || pev->sequence < 0 || pev->sequence >= pstudiohdr->numseq || !pMonsterEvent )
2016-06-04 15:24:23 +02:00
return 0;
2016-07-31 15:48:50 +02:00
mstudioseqdesc_t *pseqdesc;
mstudioevent_t *pevent;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ) + (int)pev->sequence;
pevent = (mstudioevent_t *)( (byte *)pstudiohdr + pseqdesc->eventindex );
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if( pseqdesc->numevents == 0 || index > pseqdesc->numevents )
2016-06-04 15:24:23 +02:00
return 0;
2016-07-31 15:48:50 +02:00
if( pseqdesc->numframes > 1 )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
flStart *= ( pseqdesc->numframes - 1 ) / 256.0f;
flEnd *= (pseqdesc->numframes - 1) / 256.0f;
2016-06-04 15:24:23 +02:00
}
else
{
2019-10-13 13:49:25 +02:00
flStart = 0.0f;
flEnd = 1.0f;
2016-06-04 15:24:23 +02:00
}
2016-07-31 15:48:50 +02:00
for( ; index < pseqdesc->numevents; index++ )
2016-06-04 15:24:23 +02:00
{
// Don't send client-side events to the server AI
2016-07-31 15:48:50 +02:00
if( pevent[index].event >= EVENT_CLIENT )
2016-06-04 15:24:23 +02:00
continue;
2016-07-31 15:48:50 +02:00
if( ( pevent[index].frame >= flStart && pevent[index].frame < flEnd ) ||
( ( pseqdesc->flags & STUDIO_LOOPING ) && flEnd >= pseqdesc->numframes - 1 && pevent[index].frame < flEnd - pseqdesc->numframes + 1 ) )
2016-06-04 15:24:23 +02:00
{
pMonsterEvent->event = pevent[index].event;
pMonsterEvent->options = pevent[index].options;
return index + 1;
}
}
return 0;
}
float SetController( void *pmodel, entvars_t *pev, int iController, float flValue )
{
studiohdr_t *pstudiohdr;
2016-02-29 21:04:01 +01:00
int i;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
2016-07-31 15:48:50 +02:00
if( !pstudiohdr )
2016-06-04 15:24:23 +02:00
return flValue;
2016-07-31 15:48:50 +02:00
mstudiobonecontroller_t *pbonecontroller = (mstudiobonecontroller_t *)( (byte *)pstudiohdr + pstudiohdr->bonecontrollerindex );
2016-06-04 15:24:23 +02:00
// find first controller that matches the index
2016-07-31 15:48:50 +02:00
for( i = 0; i < pstudiohdr->numbonecontrollers; i++, pbonecontroller++ )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if( pbonecontroller->index == iController )
2016-06-04 15:24:23 +02:00
break;
}
2016-07-31 15:48:50 +02:00
if( i >= pstudiohdr->numbonecontrollers )
2016-06-04 15:24:23 +02:00
return flValue;
// wrap 0..360 if it's a rotational controller
2016-07-31 15:48:50 +02:00
if( pbonecontroller->type & ( STUDIO_XR | STUDIO_YR | STUDIO_ZR ) )
2016-06-04 15:24:23 +02:00
{
// ugly hack, invert value if end < start
2016-07-31 15:48:50 +02:00
if( pbonecontroller->end < pbonecontroller->start )
2016-06-04 15:24:23 +02:00
flValue = -flValue;
// does the controller not wrap?
2019-10-13 13:49:25 +02:00
if( pbonecontroller->start + 359.0f >= pbonecontroller->end )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
if( flValue > ( ( pbonecontroller->start + pbonecontroller->end ) * 0.5f ) + 180.0f )
flValue = flValue - 360.0f;
if( flValue < ( ( pbonecontroller->start + pbonecontroller->end ) * 0.5f ) - 180.0f )
flValue = flValue + 360.0f;
2016-06-04 15:24:23 +02:00
}
else
{
2019-10-13 13:49:25 +02:00
if( flValue > 360.0f )
flValue = flValue - (int)( flValue / 360.0f ) * 360.0f;
else if( flValue < 0.0f )
flValue = flValue + (int)( ( flValue / -360.0f ) + 1.0f ) * 360.0f;
2016-06-04 15:24:23 +02:00
}
}
2017-06-29 15:56:03 +02:00
int setting = (int)( 255 * ( flValue - pbonecontroller->start ) / ( pbonecontroller->end - pbonecontroller->start ) );
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if( setting < 0 )
setting = 0;
if( setting > 255 )
setting = 255;
2016-06-04 15:24:23 +02:00
pev->controller[iController] = setting;
2019-10-13 13:49:25 +02:00
return setting * ( 1.0f / 255.0f ) * (pbonecontroller->end - pbonecontroller->start ) + pbonecontroller->start;
2016-06-04 15:24:23 +02:00
}
float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue )
{
studiohdr_t *pstudiohdr;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
if( !pstudiohdr || pev->sequence < 0 || pev->sequence >= pstudiohdr->numseq )
2016-06-04 15:24:23 +02:00
return flValue;
2016-07-31 15:48:50 +02:00
mstudioseqdesc_t *pseqdesc;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex ) + (int)pev->sequence;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if( pseqdesc->blendtype[iBlender] == 0 )
2016-06-04 15:24:23 +02:00
return flValue;
2016-07-31 15:48:50 +02:00
if( pseqdesc->blendtype[iBlender] & ( STUDIO_XR | STUDIO_YR | STUDIO_ZR ) )
2016-06-04 15:24:23 +02:00
{
// ugly hack, invert value if end < start
2016-07-31 15:48:50 +02:00
if( pseqdesc->blendend[iBlender] < pseqdesc->blendstart[iBlender] )
2016-06-04 15:24:23 +02:00
flValue = -flValue;
// does the controller not wrap?
2019-10-13 13:49:25 +02:00
if( pseqdesc->blendstart[iBlender] + 359.0f >= pseqdesc->blendend[iBlender] )
2016-06-04 15:24:23 +02:00
{
2019-10-13 13:49:25 +02:00
if( flValue > ( ( pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender] ) * 0.5f ) + 180.0f )
flValue = flValue - 360.0f;
if( flValue < ( ( pseqdesc->blendstart[iBlender] + pseqdesc->blendend[iBlender] ) * 0.5f ) - 180.0f )
flValue = flValue + 360.0f;
2016-06-04 15:24:23 +02:00
}
}
2017-06-29 15:56:03 +02:00
int setting = (int)( 255 * ( flValue - pseqdesc->blendstart[iBlender] ) / ( pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender] ) );
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if( setting < 0 )
setting = 0;
if(setting > 255)
setting = 255;
2016-06-04 15:24:23 +02:00
pev->blending[iBlender] = setting;
2019-10-13 13:49:25 +02:00
return setting * ( 1.0f / 255.0f ) * ( pseqdesc->blendend[iBlender] - pseqdesc->blendstart[iBlender] ) + pseqdesc->blendstart[iBlender];
2016-06-04 15:24:23 +02:00
}
int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir )
{
studiohdr_t *pstudiohdr;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
2016-07-31 15:48:50 +02:00
if( !pstudiohdr )
2016-06-04 15:24:23 +02:00
return iGoalAnim;
2016-07-31 15:48:50 +02:00
mstudioseqdesc_t *pseqdesc;
pseqdesc = (mstudioseqdesc_t *)( (byte *)pstudiohdr + pstudiohdr->seqindex );
2016-06-04 15:24:23 +02:00
// bail if we're going to or from a node 0
2016-07-31 15:48:50 +02:00
if( pseqdesc[iEndingAnim].entrynode == 0 || pseqdesc[iGoalAnim].entrynode == 0 )
2016-06-04 15:24:23 +02:00
{
return iGoalAnim;
}
2016-07-31 15:48:50 +02:00
int iEndNode;
2016-06-04 15:24:23 +02:00
// ALERT( at_console, "from %d to %d: ", pEndNode->iEndNode, pGoalNode->iStartNode );
2016-07-31 15:48:50 +02:00
if( *piDir > 0 )
2016-06-04 15:24:23 +02:00
{
iEndNode = pseqdesc[iEndingAnim].exitnode;
}
else
{
iEndNode = pseqdesc[iEndingAnim].entrynode;
}
2016-07-31 15:48:50 +02:00
if( iEndNode == pseqdesc[iGoalAnim].entrynode )
2016-06-04 15:24:23 +02:00
{
*piDir = 1;
return iGoalAnim;
}
2016-07-31 15:48:50 +02:00
byte *pTransition = ( (byte *)pstudiohdr + pstudiohdr->transitionindex );
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
int iInternNode = pTransition[( iEndNode - 1 ) * pstudiohdr->numtransitions + ( pseqdesc[iGoalAnim].entrynode - 1 )];
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if( iInternNode == 0 )
2016-06-04 15:24:23 +02:00
return iGoalAnim;
int i;
// look for someone going
2016-07-31 15:48:50 +02:00
for( i = 0; i < pstudiohdr->numseq; i++ )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if( pseqdesc[i].entrynode == iEndNode && pseqdesc[i].exitnode == iInternNode )
2016-06-04 15:24:23 +02:00
{
*piDir = 1;
return i;
}
2016-07-31 15:48:50 +02:00
if( pseqdesc[i].nodeflags )
2016-06-04 15:24:23 +02:00
{
2016-07-31 15:48:50 +02:00
if( pseqdesc[i].exitnode == iEndNode && pseqdesc[i].entrynode == iInternNode )
2016-06-04 15:24:23 +02:00
{
*piDir = -1;
return i;
}
}
}
ALERT( at_console, "error in transition graph" );
return iGoalAnim;
}
void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue )
{
studiohdr_t *pstudiohdr;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
2016-07-31 15:48:50 +02:00
if( !pstudiohdr )
2016-06-04 15:24:23 +02:00
return;
2016-07-31 15:48:50 +02:00
if( iGroup > pstudiohdr->numbodyparts )
2016-06-04 15:24:23 +02:00
return;
2016-07-31 15:48:50 +02:00
mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)( (byte *)pstudiohdr + pstudiohdr->bodypartindex ) + iGroup;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if( iValue >= pbodypart->nummodels )
2016-06-04 15:24:23 +02:00
return;
2016-07-31 15:48:50 +02:00
int iCurrent = ( pev->body / pbodypart->base ) % pbodypart->nummodels;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
pev->body = ( pev->body - ( iCurrent * pbodypart->base ) + ( iValue * pbodypart->base ) );
2016-06-04 15:24:23 +02:00
}
int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup )
{
studiohdr_t *pstudiohdr;
2016-07-31 15:48:50 +02:00
2016-06-04 15:24:23 +02:00
pstudiohdr = (studiohdr_t *)pmodel;
2016-07-31 15:48:50 +02:00
if( !pstudiohdr )
2016-06-04 15:24:23 +02:00
return 0;
2016-07-31 15:48:50 +02:00
if( iGroup > pstudiohdr->numbodyparts )
2016-06-04 15:24:23 +02:00
return 0;
2016-07-31 15:48:50 +02:00
mstudiobodyparts_t *pbodypart = (mstudiobodyparts_t *)( (byte *)pstudiohdr + pstudiohdr->bodypartindex ) + iGroup;
2016-06-04 15:24:23 +02:00
2016-07-31 15:48:50 +02:00
if( pbodypart->nummodels <= 1 )
2016-06-04 15:24:23 +02:00
return 0;
2016-07-31 15:48:50 +02:00
int iCurrent = ( pev->body / pbodypart->base ) % pbodypart->nummodels;
2016-06-04 15:24:23 +02:00
return iCurrent;
}