Random animations.
This was SVN commit r2330.
This commit is contained in:
parent
0331883a86
commit
26b1cf5556
@ -206,16 +206,17 @@ void CModel::CalcAnimatedObjectBound(CSkeletonAnimDef* anim,CBound& result)
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BuildAnimation: load raw animation frame animation from given file, and build a
|
||||
// animation specific to this model
|
||||
CSkeletonAnim* CModel::BuildAnimation(const char* filename,float speed,double actionpos,double actionpos2)
|
||||
CSkeletonAnim* CModel::BuildAnimation(const char* filename, const char* name, float speed, double actionpos, double actionpos2)
|
||||
{
|
||||
CSkeletonAnimDef* def=g_SkelAnimMan.GetAnimation(filename);
|
||||
if (!def) return 0;
|
||||
if (!def) return NULL;
|
||||
|
||||
CSkeletonAnim* anim=new CSkeletonAnim;
|
||||
anim->m_AnimDef=def;
|
||||
anim->m_Speed=speed;
|
||||
anim->m_ActionPos=(size_t)( actionpos * anim->m_AnimDef->GetDuration() / speed );
|
||||
anim->m_ActionPos2=(size_t)( actionpos2 * anim->m_AnimDef->GetDuration() / speed );
|
||||
CSkeletonAnim* anim = new CSkeletonAnim;
|
||||
anim->m_Name = name;
|
||||
anim->m_AnimDef = def;
|
||||
anim->m_Speed = speed;
|
||||
anim->m_ActionPos = (size_t)(actionpos * anim->m_AnimDef->GetDuration() / speed);
|
||||
anim->m_ActionPos2 = (size_t)(actionpos2 * anim->m_AnimDef->GetDuration() / speed);
|
||||
anim->m_ObjectBounds.SetEmpty();
|
||||
InvalidateBounds();
|
||||
|
||||
@ -228,30 +229,30 @@ void CModel::Update(float time)
|
||||
{
|
||||
if (m_Anim && m_BoneMatrices) {
|
||||
// convert to ms and adjust for animation speed
|
||||
float animtime=time*1000*m_Anim->m_Speed;
|
||||
float animtime = time*1000*m_Anim->m_Speed;
|
||||
|
||||
// update animation time, but don't calculate bone matrices - do that (lazily) when
|
||||
// something requests them; that saves some calculation work for offscreen models,
|
||||
// and also assures the world space, inverted bone matrices (required for normal
|
||||
// skinning) are up to date with respect to m_Transform
|
||||
m_AnimTime+=animtime;
|
||||
m_AnimTime += animtime;
|
||||
|
||||
float duration=m_Anim->m_AnimDef->GetDuration();
|
||||
if (m_AnimTime>duration) {
|
||||
if( m_Flags & MODELFLAG_NOLOOPANIMATION )
|
||||
SetAnimation( NULL );
|
||||
m_AnimTime=(float) fmod(m_AnimTime,duration);
|
||||
float duration = m_Anim->m_AnimDef->GetDuration();
|
||||
if (m_AnimTime > duration) {
|
||||
if (m_Flags & MODELFLAG_NOLOOPANIMATION)
|
||||
SetAnimation(NULL);
|
||||
m_AnimTime = fmod(m_AnimTime, duration);
|
||||
}
|
||||
|
||||
// mark vertices as dirty
|
||||
SetDirty(RENDERDATA_UPDATE_VERTICES);
|
||||
|
||||
// mark matrices as dirty
|
||||
m_BoneMatricesValid=false;
|
||||
m_BoneMatricesValid = false;
|
||||
}
|
||||
|
||||
// update props
|
||||
for (uint i=0;i<m_Props.size();i++) {
|
||||
for (uint i=0; i<m_Props.size(); i++) {
|
||||
m_Props[i].m_Model->Update(time);
|
||||
}
|
||||
}
|
||||
@ -303,7 +304,7 @@ bool CModel::SetAnimation(CSkeletonAnim* anim, bool once)
|
||||
|
||||
if (anim) {
|
||||
m_Flags &= ~MODELFLAG_NOLOOPANIMATION;
|
||||
if( once )
|
||||
if (once)
|
||||
m_Flags |= MODELFLAG_NOLOOPANIMATION;
|
||||
|
||||
if (!m_BoneMatrices) {
|
||||
@ -311,7 +312,7 @@ bool CModel::SetAnimation(CSkeletonAnim* anim, bool once)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (anim->m_AnimDef->GetNumKeys()!=m_pModelDef->GetNumBones()) {
|
||||
if (anim->m_AnimDef->GetNumKeys() != m_pModelDef->GetNumBones()) {
|
||||
// mismatch between model's skeleton and animation's skeleton
|
||||
LOG(ERROR, LOG_CATEGORY, "Mismatch between model's skeleton and animation's skeleton (%d model bones != %d animation keys)",
|
||||
m_pModelDef->GetNumBones(), anim->m_AnimDef->GetNumKeys());
|
||||
@ -333,7 +334,7 @@ bool CModel::SetAnimation(CSkeletonAnim* anim, bool once)
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AddProp: add a prop to the model on the given point
|
||||
void CModel::AddProp(SPropPoint* point,CModel* model)
|
||||
void CModel::AddProp(SPropPoint* point, CModel* model)
|
||||
{
|
||||
// position model according to prop point position
|
||||
model->SetTransform(point->m_Transform);
|
||||
@ -375,11 +376,12 @@ void CModel::RemoveProp(SPropPoint* point)
|
||||
// Clone: return a clone of this model
|
||||
CModel* CModel::Clone() const
|
||||
{
|
||||
CModel* clone=new CModel;
|
||||
clone->m_ObjectBounds=m_ObjectBounds;
|
||||
CModel* clone = new CModel;
|
||||
clone->m_ObjectBounds = m_ObjectBounds;
|
||||
clone->InitModel(m_pModelDef);
|
||||
clone->SetTexture(m_Texture);
|
||||
if (m_Texture.GetHandle()) h_add_ref(m_Texture.GetHandle());
|
||||
if (m_Texture.GetHandle())
|
||||
h_add_ref(m_Texture.GetHandle());
|
||||
clone->SetMaterial(m_Material);
|
||||
clone->SetAnimation(m_Anim);
|
||||
clone->SetFlags(m_Flags);
|
||||
|
@ -102,7 +102,7 @@ public:
|
||||
|
||||
// load raw animation frame animation from given file, and build a
|
||||
// animation specific to this model
|
||||
CSkeletonAnim* BuildAnimation(const char* filename,float speed,double actionpos,double actionpos2);
|
||||
CSkeletonAnim* BuildAnimation(const char* filename, const char* name, float speed, double actionpos, double actionpos2);
|
||||
|
||||
// add a prop to the model on the given point
|
||||
void AddProp(SPropPoint* point,CModel* model);
|
||||
|
@ -14,7 +14,7 @@ public:
|
||||
|
||||
struct Anim {
|
||||
// constructor
|
||||
Anim() : m_Speed(1), m_ActionPos( 0.0 ), m_ActionPos2( 0.0 ), m_AnimData(0) {}
|
||||
Anim() : m_Speed(1), m_ActionPos(0.0), m_ActionPos2(0.0) {}
|
||||
|
||||
// name of the animation - "Idle", "Run", etc
|
||||
CStr m_AnimName;
|
||||
@ -27,8 +27,6 @@ public:
|
||||
// data is loaded)
|
||||
double m_ActionPos;
|
||||
double m_ActionPos2;
|
||||
// the animation data, specific to the this model
|
||||
CSkeletonAnim* m_AnimData;
|
||||
};
|
||||
|
||||
struct Prop {
|
||||
|
@ -22,25 +22,16 @@
|
||||
#define LOG_CATEGORY "graphics"
|
||||
|
||||
CObjectEntry::CObjectEntry(int type, CObjectBase* base)
|
||||
: m_Model(0), m_Type(type), m_Base(base), m_Color(1.0f, 1.0f, 1.0f, 1.0f)
|
||||
: m_Model(NULL), m_Type(type), m_Base(base), m_Color(1.0f, 1.0f, 1.0f, 1.0f),
|
||||
m_ProjectileModel(NULL), m_AmmunitionPoint(NULL), m_AmmunitionModel(NULL)
|
||||
{
|
||||
m_IdleAnim=0;
|
||||
m_WalkAnim=0;
|
||||
m_DeathAnim=0;
|
||||
m_CorpseAnim=0;
|
||||
m_MeleeAnim=0;
|
||||
m_GatherAnim=0;
|
||||
m_RangedAnim=0;
|
||||
m_ProjectileModel=0;
|
||||
m_AmmunitionPoint=0;
|
||||
m_AmmunitionModel=0;
|
||||
}
|
||||
|
||||
template<typename T, typename S> static void delete_pair_2nd(std::pair<T,S> v) { delete v.second; }
|
||||
|
||||
CObjectEntry::~CObjectEntry()
|
||||
{
|
||||
for (size_t i=0;i<m_Animations.size();i++) {
|
||||
delete m_Animations[i].m_AnimData;
|
||||
}
|
||||
std::for_each(m_Animations.begin(), m_Animations.end(), delete_pair_2nd<CStr, CSkeletonAnim*>);
|
||||
|
||||
delete m_Model;
|
||||
}
|
||||
@ -51,7 +42,7 @@ bool CObjectEntry::BuildRandomVariant(CObjectBase::variation_key& vars, CObjectB
|
||||
CStr chosenModel;
|
||||
CStr chosenColor;
|
||||
std::map<CStr, CObjectBase::Prop> chosenProps;
|
||||
std::map<CStr, CObjectBase::Anim> chosenAnims;
|
||||
std::multimap<CStr, CObjectBase::Anim> chosenAnims;
|
||||
|
||||
// For each group in m_Base->m_Variants, take whichever variant is specified
|
||||
// by 'vars', and then store its data into the 'chosen' variables. If data
|
||||
@ -90,8 +81,16 @@ bool CObjectEntry::BuildRandomVariant(CObjectBase::variation_key& vars, CObjectB
|
||||
for (std::vector<CObjectBase::Prop>::iterator it = var.m_Props.begin(); it != var.m_Props.end(); ++it)
|
||||
chosenProps[it->m_PropPointName] = *it;
|
||||
|
||||
// If one variant defines one animation called e.g. "attack", and this
|
||||
// variant defines two different animations with the same name, the one
|
||||
// original should be erased, and replaced by the two new ones.
|
||||
//
|
||||
// So, erase all existing animations which are overridden by this variant:
|
||||
for (std::vector<CObjectBase::Anim>::iterator it = var.m_Anims.begin(); it != var.m_Anims.end(); ++it)
|
||||
chosenAnims[it->m_AnimName] = *it;
|
||||
chosenAnims.erase(chosenAnims.lower_bound(it->m_AnimName), chosenAnims.upper_bound(it->m_AnimName));
|
||||
// and this insert the new ones:
|
||||
for (std::vector<CObjectBase::Anim>::iterator it = var.m_Anims.begin(); it != var.m_Anims.end(); ++it)
|
||||
chosenAnims.insert(make_pair(it->m_AnimName, *it));
|
||||
}
|
||||
|
||||
// Copy the chosen data onto this model:
|
||||
@ -110,12 +109,10 @@ bool CObjectEntry::BuildRandomVariant(CObjectBase::variation_key& vars, CObjectB
|
||||
m_Color = CColor(r/255.0f, g/255.0f, b/255.0f, 1.0f);
|
||||
}
|
||||
|
||||
std::vector<CObjectBase::Prop> props;
|
||||
|
||||
for (std::map<CStr, CObjectBase::Prop>::iterator it = chosenProps.begin(); it != chosenProps.end(); ++it)
|
||||
m_Props.push_back(it->second);
|
||||
|
||||
for (std::map<CStr, CObjectBase::Anim>::iterator it = chosenAnims.begin(); it != chosenAnims.end(); ++it)
|
||||
m_Animations.push_back(it->second);
|
||||
|
||||
props.push_back(it->second);
|
||||
|
||||
|
||||
// Build the model:
|
||||
@ -148,51 +145,31 @@ bool CObjectEntry::BuildRandomVariant(CObjectBase::variation_key& vars, CObjectB
|
||||
// calculate initial object space bounds, based on vertex positions
|
||||
m_Model->CalcObjectBounds();
|
||||
|
||||
// load animations
|
||||
for (size_t t = 0; t < m_Animations.size(); t++)
|
||||
// load the animations
|
||||
for (std::multimap<CStr, CObjectBase::Anim>::iterator it = chosenAnims.begin(); it != chosenAnims.end(); ++it)
|
||||
{
|
||||
if (m_Animations[t].m_FileName.Length() > 0)
|
||||
{
|
||||
const char* animfilename = m_Animations[t].m_FileName;
|
||||
m_Animations[t].m_AnimData = m_Model->BuildAnimation(animfilename, m_Animations[t].m_Speed, m_Animations[t].m_ActionPos, m_Animations[t].m_ActionPos2);
|
||||
CStr name = it->first.LowerCase();
|
||||
|
||||
CStr AnimNameLC = m_Animations[t].m_AnimName.LowerCase();
|
||||
// TODO: Use consistent names everywhere, then remove this translation section.
|
||||
// (It's just mapping the names used in actors onto the names used by code.)
|
||||
if (name == "attack") name = "melee";
|
||||
else if (name == "chop") name = "gather";
|
||||
else if (name == "decay") name = "corpse";
|
||||
|
||||
if (AnimNameLC == "idle")
|
||||
m_IdleAnim = m_Animations[t].m_AnimData;
|
||||
else
|
||||
if (AnimNameLC == "walk")
|
||||
m_WalkAnim = m_Animations[t].m_AnimData;
|
||||
else
|
||||
if (AnimNameLC == "attack")
|
||||
m_MeleeAnim = m_Animations[t].m_AnimData;
|
||||
else
|
||||
if (AnimNameLC == "chop")
|
||||
m_GatherAnim = m_Animations[t].m_AnimData;
|
||||
else
|
||||
if (AnimNameLC == "death")
|
||||
m_DeathAnim = m_Animations[t].m_AnimData;
|
||||
else
|
||||
if (AnimNameLC == "decay")
|
||||
m_CorpseAnim = m_Animations[t].m_AnimData;
|
||||
//else
|
||||
// debug_printf("Invalid animation name '%s'\n", (const char*)AnimNameLC);
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME, RC - don't store invalid animations (possible?)
|
||||
m_Animations[t].m_AnimData = NULL;
|
||||
}
|
||||
CSkeletonAnim* anim = m_Model->BuildAnimation(it->second.m_FileName, name, it->second.m_Speed, it->second.m_ActionPos, it->second.m_ActionPos2);
|
||||
if (anim)
|
||||
m_Animations.insert(std::make_pair(name, anim));
|
||||
}
|
||||
|
||||
// start up idling
|
||||
if (! m_Model->SetAnimation(m_IdleAnim))
|
||||
if (! m_Model->SetAnimation(GetRandomAnimation("idle")))
|
||||
LOG(ERROR, LOG_CATEGORY, "Failed to set idle animation in model \"%s\"", modelfilename);
|
||||
|
||||
// build props - TODO, RC - need to fix up bounds here
|
||||
// TODO: Make sure random variations get handled correctly when a prop fails
|
||||
for (size_t p = 0; p < m_Props.size(); p++)
|
||||
for (size_t p = 0; p < props.size(); p++)
|
||||
{
|
||||
const CObjectBase::Prop& prop = m_Props[p];
|
||||
const CObjectBase::Prop& prop = props[p];
|
||||
|
||||
CObjectEntry* oe = g_ObjMan.FindObjectVariation(prop.m_ModelName, vars, vars_it);
|
||||
if (!oe)
|
||||
@ -222,8 +199,7 @@ bool CObjectEntry::BuildRandomVariant(CObjectBase::variation_key& vars, CObjectB
|
||||
{
|
||||
CModel* propmodel = oe->m_Model->Clone();
|
||||
m_Model->AddProp(proppoint, propmodel);
|
||||
if (oe->m_IdleAnim)
|
||||
propmodel->SetAnimation(oe->m_IdleAnim);
|
||||
propmodel->SetAnimation(oe->GetRandomAnimation("idle"));
|
||||
}
|
||||
else
|
||||
LOG(ERROR, LOG_CATEGORY, "Failed to find matching prop point called \"%s\" in model \"%s\" on actor \"%s\"", (const char*)prop.m_PropPointName, modelfilename, (const char*)prop.m_ModelName);
|
||||
@ -275,21 +251,21 @@ bool CObjectEntry::BuildRandomVariant(CObjectBase::variation_key& vars, CObjectB
|
||||
}
|
||||
|
||||
|
||||
CSkeletonAnim* CObjectEntry::GetNamedAnimation(CStr animationName)
|
||||
CSkeletonAnim* CObjectEntry::GetRandomAnimation(const CStr& animationName)
|
||||
{
|
||||
for (size_t t = 0; t < m_Animations.size(); t++)
|
||||
if (m_Animations[t].m_AnimName == animationName)
|
||||
return m_Animations[t].m_AnimData;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
CObjectBase::Prop* CObjectEntry::FindProp(const char* proppointname)
|
||||
{
|
||||
for (size_t i = 0; i < m_Props.size(); i++)
|
||||
if (strcmp(proppointname, m_Props[i].m_PropPointName) == 0)
|
||||
return &m_Props[i];
|
||||
|
||||
return NULL;
|
||||
SkeletonAnimMap::iterator lower = m_Animations.lower_bound(animationName);
|
||||
SkeletonAnimMap::iterator upper = m_Animations.upper_bound(animationName);
|
||||
size_t count = std::distance(lower, upper);
|
||||
if (count == 0)
|
||||
{
|
||||
// LOG(WARNING, LOG_CATEGORY, "Failed to find animation '%s' for actor '%s'", animationName.c_str(), m_ModelName.c_str());
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Do we care about network synchronisation of random animations?
|
||||
int id = rand() % (int)count;
|
||||
std::advance(lower, id);
|
||||
return lower->second;
|
||||
}
|
||||
}
|
||||
|
@ -22,35 +22,33 @@ public:
|
||||
// different variations of the actor.
|
||||
CObjectBase* m_Base;
|
||||
|
||||
CObjectBase::Prop* FindProp(const char* proppointname);
|
||||
|
||||
// texture name
|
||||
CStr m_TextureName;
|
||||
// model name
|
||||
CStr m_ModelName;
|
||||
// colour (used when doing alpha-channel colouring, but not doing player-colour)
|
||||
CColor m_Color;
|
||||
// list of valid animations for this object
|
||||
std::vector<CObjectBase::Anim> m_Animations;
|
||||
CSkeletonAnim* m_IdleAnim;
|
||||
CSkeletonAnim* m_WalkAnim;
|
||||
CSkeletonAnim* m_DeathAnim;
|
||||
CSkeletonAnim* m_MeleeAnim;
|
||||
CSkeletonAnim* m_GatherAnim;
|
||||
CSkeletonAnim* m_RangedAnim;
|
||||
CSkeletonAnim* m_CorpseAnim;
|
||||
// (probable TODO: make colour a per-model thing, rather than per-objectEntry,
|
||||
// so we can have lots of colour variations without wasting memory on
|
||||
// lots of objectEntries)
|
||||
|
||||
CModel* m_ProjectileModel;
|
||||
CModel* m_AmmunitionModel;
|
||||
SPropPoint* m_AmmunitionPoint;
|
||||
|
||||
CSkeletonAnim* GetNamedAnimation( CStr animationName );
|
||||
// list of props attached to object
|
||||
std::vector<CObjectBase::Prop> m_Props;
|
||||
// Returns a randomly-chosen animation matching the given name.
|
||||
// If none is found, returns NULL.
|
||||
CSkeletonAnim* GetRandomAnimation(const CStr& animationName);
|
||||
|
||||
// corresponding model
|
||||
CModel* m_Model;
|
||||
// type of object; index into object managers types array
|
||||
int m_Type;
|
||||
|
||||
private:
|
||||
typedef std::multimap<CStr, CSkeletonAnim*> SkeletonAnimMap;
|
||||
SkeletonAnimMap m_Animations;
|
||||
// TODO: something more memory-efficient than storing loads of similar strings for each unit?
|
||||
};
|
||||
|
||||
|
||||
|
@ -33,7 +33,7 @@ CObjectManager::CObjectManager() : m_SelectedThing(NULL)
|
||||
m_ObjectTypes.reserve(32);
|
||||
}
|
||||
|
||||
template<typename T, typename S> void delete_pair_2nd(std::pair<T,S> v) { delete v.second; }
|
||||
template<typename T, typename S> static void delete_pair_2nd(std::pair<T,S> v) { delete v.second; }
|
||||
|
||||
CObjectManager::~CObjectManager()
|
||||
{
|
||||
|
@ -19,6 +19,8 @@ class CSkeletonAnimDef;
|
||||
class CSkeletonAnim
|
||||
{
|
||||
public:
|
||||
// the name of the action which uses this animation (e.g. "idle")
|
||||
CStr m_Name;
|
||||
// the raw animation frame data
|
||||
CSkeletonAnimDef* m_AnimDef;
|
||||
// speed at which this animation runs
|
||||
|
@ -50,8 +50,8 @@ public:
|
||||
u32 GetNumKeys() const { return m_NumKeys; }
|
||||
|
||||
// accessors: get a key for given bone at given time
|
||||
Key& GetKey(u32 frame,u32 bone) { return m_Keys[frame*m_NumKeys+bone]; }
|
||||
const Key& GetKey(u32 frame,u32 bone) const { return m_Keys[frame*m_NumKeys+bone]; }
|
||||
Key& GetKey(u32 frame, u32 bone) { return m_Keys[frame*m_NumKeys+bone]; }
|
||||
const Key& GetKey(u32 frame, u32 bone) const { return m_Keys[frame*m_NumKeys+bone]; }
|
||||
|
||||
// get duration of this anim, in ms
|
||||
float GetDuration() const { return m_NumFrames*m_FrameTime; }
|
||||
@ -62,15 +62,15 @@ public:
|
||||
u32 GetNumFrames() const { return m_NumFrames; }
|
||||
|
||||
// build matrices for all bones at the given time (in MS) in this animation
|
||||
void BuildBoneMatrices(float time,CMatrix3D* matrices) const;
|
||||
void BuildBoneMatrices(float time, CMatrix3D* matrices) const;
|
||||
|
||||
// anim I/O functions
|
||||
static CSkeletonAnimDef* Load(const char* filename);
|
||||
static void Save(const char* filename,const CSkeletonAnimDef* anim);
|
||||
static void Save(const char* filename, const CSkeletonAnimDef* anim);
|
||||
|
||||
public:
|
||||
// name of the animation
|
||||
CStr m_Name;
|
||||
CStr m_Name; // TODO: this doesn't seem to be used, so it's just a waste of memory...
|
||||
// frame time - time between successive frames, in ms
|
||||
float m_FrameTime;
|
||||
// number of keys in each frame - should match number of bones in the skeleton
|
||||
|
@ -30,4 +30,34 @@ void CUnit::HideAmmunition()
|
||||
}
|
||||
// No usual prop.
|
||||
m_Model->RemoveProp( m_Object->m_AmmunitionPoint );
|
||||
}
|
||||
}
|
||||
|
||||
bool CUnit::SetRandomAnimation(const CStr& name, bool once)
|
||||
{
|
||||
CSkeletonAnim* anim = GetRandomAnimation(name);
|
||||
if (anim)
|
||||
{
|
||||
m_Model->SetAnimation(anim, once);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO - report an error?
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CSkeletonAnim* CUnit::GetRandomAnimation(const CStr& name)
|
||||
{
|
||||
CSkeletonAnim* anim = m_Object->GetRandomAnimation(name);
|
||||
// Fall back to 'idle', if no matching animation is found
|
||||
if (anim == NULL && name != "idle")
|
||||
anim = m_Object->GetRandomAnimation("idle");
|
||||
|
||||
return anim;
|
||||
}
|
||||
|
||||
bool CUnit::IsPlayingAnimation(const CStr& name)
|
||||
{
|
||||
return (m_Model->GetAnimation()->m_Name == name);
|
||||
}
|
||||
|
@ -6,6 +6,8 @@
|
||||
class CModel;
|
||||
class CObjectEntry;
|
||||
class CEntity;
|
||||
class CSkeletonAnim;
|
||||
class CStr8;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CUnit: simple "actor" definition - defines a sole object within the world
|
||||
@ -13,10 +15,10 @@ class CUnit
|
||||
{
|
||||
public:
|
||||
// constructor - unit invalid without a model and object
|
||||
CUnit(CObjectEntry* object,CModel* model) : m_Object(object), m_Model(model), m_Entity(NULL) {
|
||||
CUnit(CObjectEntry* object, CModel* model) : m_Object(object), m_Model(model), m_Entity(NULL) {
|
||||
assert(object && model);
|
||||
}
|
||||
CUnit(CObjectEntry* object,CModel* model, CEntity* entity) : m_Object(object), m_Model(model), m_Entity(entity) {
|
||||
CUnit(CObjectEntry* object, CModel* model, CEntity* entity) : m_Object(object), m_Model(model), m_Entity(entity) {
|
||||
assert(object && model);
|
||||
}
|
||||
|
||||
@ -35,6 +37,18 @@ public:
|
||||
void ShowAmmunition();
|
||||
void HideAmmunition();
|
||||
|
||||
// Sets the animation a random one matching 'name'. If none is found,
|
||||
// sets to idle instead.
|
||||
bool SetRandomAnimation(const CStr8& name, bool once = false);
|
||||
|
||||
// Returns the animation a random one matching 'name'. If none is found,
|
||||
// returns idle instead.
|
||||
CSkeletonAnim* GetRandomAnimation(const CStr8& name);
|
||||
|
||||
// Returns whether the currently active animation is one of the ones
|
||||
// matchin 'name'.
|
||||
bool IsPlayingAnimation(const CStr8& name);
|
||||
|
||||
private:
|
||||
// object from which unit was created
|
||||
CObjectEntry* m_Object;
|
||||
|
@ -331,10 +331,11 @@ void CEntity::update( size_t timestep )
|
||||
if( m_extant )
|
||||
{
|
||||
if( ( m_lastState != -1 ) || !m_actor->GetModel()->GetAnimation() )
|
||||
m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_IdleAnim );
|
||||
m_actor->SetRandomAnimation( "idle" );
|
||||
|
||||
}
|
||||
else if( !m_actor->GetModel()->GetAnimation() )
|
||||
m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_CorpseAnim );
|
||||
m_actor->SetRandomAnimation( "corpse" );
|
||||
}
|
||||
|
||||
if( m_lastState != -1 )
|
||||
@ -860,7 +861,7 @@ bool CEntity::Kill( JSContext* cx, uintN argc, jsval* argv )
|
||||
clearOrders();
|
||||
|
||||
if( m_actor )
|
||||
m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_DeathAnim, true );
|
||||
m_actor->SetRandomAnimation( "death", true );
|
||||
|
||||
return( true );
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ private:
|
||||
uint processGotoHelper( CEntityOrder* current, size_t timestep_milli, HEntity& collide );
|
||||
|
||||
bool processContactAction( CEntityOrder* current, size_t timestep_millis, int transition, SEntityAction* action );
|
||||
bool processContactActionNoPathing( CEntityOrder* current, size_t timestep_millis, CSkeletonAnim* animation, CScriptEvent* contactEvent, SEntityAction* action );
|
||||
bool processContactActionNoPathing( CEntityOrder* current, size_t timestep_millis, const CStr& animation, CScriptEvent* contactEvent, SEntityAction* action );
|
||||
|
||||
bool processAttackMelee( CEntityOrder* current, size_t timestep_milli );
|
||||
bool processAttackMeleeNoPathing( CEntityOrder* current, size_t timestep_milli );
|
||||
|
@ -287,7 +287,7 @@ bool CEntity::processContactAction( CEntityOrder* current, size_t timestep_milli
|
||||
|
||||
if( m_transition && m_actor )
|
||||
{
|
||||
m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_WalkAnim );
|
||||
m_actor->SetRandomAnimation( "walk" );
|
||||
// Animation desync
|
||||
m_actor->GetModel()->Update( ( rand() * 1000.0f ) / 1000.0f );
|
||||
}
|
||||
@ -298,7 +298,7 @@ bool CEntity::processContactAction( CEntityOrder* current, size_t timestep_milli
|
||||
|
||||
return( true );
|
||||
}
|
||||
bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t timestep_millis, CSkeletonAnim* animation, CScriptEvent* contactEvent, SEntityAction* action )
|
||||
bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t timestep_millis, const CStr& animation, CScriptEvent* contactEvent, SEntityAction* action )
|
||||
{
|
||||
if( m_fsm_cyclepos != NOT_IN_CYCLE )
|
||||
{
|
||||
@ -373,9 +373,9 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times
|
||||
// (is this good enough?)
|
||||
|
||||
// Play walk for a bit.
|
||||
if( m_actor && ( m_actor->GetModel()->GetAnimation() != m_actor->GetObject()->m_WalkAnim ) )
|
||||
if( m_actor && ! m_actor->IsPlayingAnimation( "walk" ) )
|
||||
{
|
||||
m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_WalkAnim );
|
||||
m_actor->SetRandomAnimation( "walk" );
|
||||
// Animation desync
|
||||
m_actor->GetModel()->Update( ( rand() * 1000.0f ) / 1000.0f );
|
||||
}
|
||||
@ -440,8 +440,8 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times
|
||||
}
|
||||
|
||||
// Pick our animation, calculate the time to play it, and start the timer.
|
||||
m_fsm_animation = animation; // <- Replace with a call that gets one randomly, probably pass in a CSkeletonAnim* (void) fn for this purpose
|
||||
|
||||
m_fsm_animation = m_actor->GetRandomAnimation( animation );
|
||||
|
||||
// Here's the idea - we want to be at that animation's event point
|
||||
// when the timer reaches action->m_Speed. The timer increments by 2 every millisecond.
|
||||
// animation->m_actionpos is the time offset into that animation that event
|
||||
@ -461,7 +461,7 @@ bool CEntity::processContactActionNoPathing( CEntityOrder* current, size_t times
|
||||
// If we've just transitioned, play idle. Otherwise, let the previous animation complete, if it
|
||||
// hasn't already.
|
||||
if( m_transition )
|
||||
m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_IdleAnim );
|
||||
m_actor->SetRandomAnimation( "idle" );
|
||||
}
|
||||
|
||||
// Load time needs to be animation->m_ActionPos2 ms after the start of the animation.
|
||||
@ -486,14 +486,7 @@ bool CEntity::processAttackMeleeNoPathing( CEntityOrder* current, size_t timeste
|
||||
{
|
||||
CEventAttack evt( current->m_data[0].entity );
|
||||
if( !m_actor ) return( false );
|
||||
CSkeletonAnim* animation = m_actor->GetObject()->m_MeleeAnim;
|
||||
if( !animation ) animation = m_actor->GetObject()->m_IdleAnim;
|
||||
if( !animation ) return( false ); // Should probably tell people why this is failing
|
||||
// (didn't specify an actor or animation) but that
|
||||
// would probably involve including CLogger.h, which
|
||||
// conflicts.
|
||||
|
||||
return( processContactActionNoPathing( current, timestep_milli, animation, &evt, &m_melee ) );
|
||||
return( processContactActionNoPathing( current, timestep_milli, "melee", &evt, &m_melee ) );
|
||||
}
|
||||
bool CEntity::processGather( CEntityOrder* current, size_t timestep_millis )
|
||||
{
|
||||
@ -504,13 +497,7 @@ bool CEntity::processGatherNoPathing( CEntityOrder* current, size_t timestep_mil
|
||||
{
|
||||
CEventGather evt( current->m_data[0].entity );
|
||||
if( !m_actor ) return( false );
|
||||
CSkeletonAnim* animation = m_actor->GetObject()->m_GatherAnim;
|
||||
if( !animation ) animation = m_actor->GetObject()->m_IdleAnim;
|
||||
if( !animation ) return( false ); // Should probably tell people why this is failing
|
||||
// (didn't specify an actor or animation) but that
|
||||
// would probably involve including CLogger.h, which
|
||||
// conflicts.
|
||||
return( processContactActionNoPathing( current, timestep_millis, animation, &evt, &m_gather ) );
|
||||
return( processContactActionNoPathing( current, timestep_millis, "gather", &evt, &m_gather ) );
|
||||
}
|
||||
|
||||
bool CEntity::processGoto( CEntityOrder* current, size_t timestep_millis )
|
||||
@ -527,7 +514,7 @@ bool CEntity::processGoto( CEntityOrder* current, size_t timestep_millis )
|
||||
|
||||
if( m_transition && m_actor )
|
||||
{
|
||||
m_actor->GetModel()->SetAnimation( m_actor->GetObject()->m_WalkAnim );
|
||||
m_actor->SetRandomAnimation( "walk" );
|
||||
// Animation desync
|
||||
m_actor->GetModel()->Update( ( rand() * 1000.0f ) / 1000.0f );
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user