Implement additive body states, rstl::binary_find

This commit is contained in:
Jack Andersen 2017-07-10 21:17:03 -10:00
parent 7e85ab932b
commit daef773f39
17 changed files with 371 additions and 71 deletions

View File

@ -72,18 +72,18 @@ public:
ResId TranslateOriginalToNew(ResId id) const
{
auto search = std::lower_bound(m_origToNew.cbegin(), m_origToNew.cend(), id,
[](const auto& id, ResId test) -> bool { return id.first < test; });
if (search == m_origToNew.cend() || search->first != id)
auto search = rstl::binary_find(m_origToNew.cbegin(), m_origToNew.cend(), id,
[](const auto& id) { return id.first; });
if (search == m_origToNew.cend())
return -1;
return search->second;
}
ResId TranslateNewToOriginal(ResId id) const
{
auto search = std::lower_bound(m_newToOrig.cbegin(), m_newToOrig.cend(), id,
[](const auto& id, ResId test) -> bool { return id.first < test; });
if (search == m_newToOrig.cend() || search->first != id)
auto search = rstl::binary_find(m_newToOrig.cbegin(), m_newToOrig.cend(), id,
[](const auto& id) { return id.first; });
if (search == m_newToOrig.cend())
return -1;
return search->second;
}

View File

@ -0,0 +1,231 @@
#include "CAdditiveBodyState.hpp"
#include "CBodyController.hpp"
#include "Character/CPASDatabase.hpp"
#include "CStateManager.hpp"
#include "CAnimTreeNode.hpp"
#include "CPASAnimParmData.hpp"
namespace urde
{
void CABSAim::Start(CBodyController& bc, CStateManager& mgr)
{
const CBCAdditiveAimCmd* cmd =
static_cast<const CBCAdditiveAimCmd*>(bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveAim));
const CPASAnimState* aimState = bc.GetPASDatabase().GetAnimState(22);
// Left, Right, Up, Down
for (int i=0 ; i<4 ; ++i)
{
CPASAnimParmData parms(22, CPASAnimParm::FromEnum(i));
std::pair<float, s32> best = bc.GetPASDatabase().FindBestAnimation(parms, *mgr.GetActiveRandom(), -1);
x8_anims[i] = best.second;
x18_angles[i] = zeus::degToRad(aimState->GetAnimParmData(x8_anims[i], 1).GetReal32Value());
}
const CAnimData& animData = *bc.GetOwner().GetModelData()->GetAnimationData();
x28_hWeight = -animData.GetAdditiveAnimationWeight(x8_anims[0]);
x28_hWeight += animData.GetAdditiveAnimationWeight(x8_anims[1]);
x30_vWeight = -animData.GetAdditiveAnimationWeight(x8_anims[2]);
x30_vWeight += animData.GetAdditiveAnimationWeight(x8_anims[3]);
x4_needsIdle = false;
if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveIdle))
x4_needsIdle = true;
}
pas::EAnimationState CABSAim::GetBodyStateTransition(float dt, CBodyController& bc)
{
if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveReaction))
return pas::EAnimationState::AdditiveReaction;
if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveFlinch))
return pas::EAnimationState::AdditiveFlinch;
if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveIdle) || x4_needsIdle)
return pas::EAnimationState::AdditiveIdle;
return pas::EAnimationState::Invalid;
}
pas::EAnimationState CABSAim::UpdateBody(float dt, CBodyController& bc, CStateManager& mgr)
{
pas::EAnimationState st = GetBodyStateTransition(dt, bc);
if (st == pas::EAnimationState::Invalid)
{
const zeus::CVector3f& target = bc.GetCommandMgr().GetAdditiveTargetVector();
if (target.canBeNormalized())
{
CAnimData& animData = *bc.GetOwner().ModelData()->AnimationData();
float hAngle = zeus::clamp(-x18_angles[0], std::atan2(target.x, target.y), x18_angles[1]);
hAngle *= 0.63661975f;
hAngle = zeus::clamp(-3.f, (hAngle - x28_hWeight) * 0.25f / dt, 3.f);
x2c_hWeightVel += dt * zeus::clamp(-10.f, (hAngle - x2c_hWeightVel) / dt, 10.f);
float hypotenuse = std::sqrt(target.y * target.y + target.x * target.x);
float vAngle = zeus::clamp(-x18_angles[3], std::atan2(target.z, hypotenuse), x18_angles[2]);
vAngle *= 0.63661975f;
vAngle = zeus::clamp(-3.f, (vAngle - x30_vWeight) * 0.25f / dt, 3.f);
x34_vWeightVel += dt * zeus::clamp(-10.f, (vAngle - x34_vWeightVel) / dt, 10.f);
float newHWeight = dt * x2c_hWeightVel + x28_hWeight;
if (newHWeight != x28_hWeight)
{
if (std::fabs(x28_hWeight) > 0.f && x28_hWeight * newHWeight <= 0.f)
animData.DelAdditiveAnimation(x8_anims[x28_hWeight < 0.f ? 0 : 1]);
float absWeight = std::fabs(newHWeight);
if (absWeight > 0.f)
animData.AddAdditiveAnimation(x8_anims[newHWeight < 0.f ? 0 : 1], absWeight, false, false);
}
float newVWeight = dt * x34_vWeightVel + x30_vWeight;
if (newVWeight != x30_vWeight)
{
if (std::fabs(x30_vWeight) > 0.f && x30_vWeight * newVWeight <= 0.f)
animData.DelAdditiveAnimation(x8_anims[x30_vWeight > 0.f ? 2 : 3]);
float absWeight = std::fabs(newVWeight);
if (absWeight > 0.f)
animData.AddAdditiveAnimation(x8_anims[newVWeight > 0.f ? 2 : 3], absWeight, false, false);
}
x28_hWeight = newHWeight;
x30_vWeight = newVWeight;
}
}
return st;
}
void CABSAim::Shutdown(CBodyController& bc)
{
CAnimData& animData = *bc.GetOwner().ModelData()->AnimationData();
if (x28_hWeight != 0.f)
animData.DelAdditiveAnimation(x8_anims[x28_hWeight < 0.f ? 0 : 1]);
if (x30_vWeight != 0.f)
animData.DelAdditiveAnimation(x8_anims[x30_vWeight > 0.f ? 2 : 3]);
}
void CABSFlinch::Start(CBodyController& bc, CStateManager& mgr)
{
const CBCAdditiveFlinchCmd* cmd =
static_cast<const CBCAdditiveFlinchCmd*>(bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveFlinch));
x4_weight = cmd->GetWeight();
CPASAnimParmData parms(23);
std::pair<float, s32> best = bc.GetPASDatabase().FindBestAnimation(parms, *mgr.GetActiveRandom(), -1);
x8_anim = best.second;
CAnimData& animData = *bc.GetOwner().ModelData()->AnimationData();
animData.AddAdditiveAnimation(x8_anim, x4_weight, false, true);
}
pas::EAnimationState CABSFlinch::GetBodyStateTransition(float dt, CBodyController& bc)
{
if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveReaction))
return pas::EAnimationState::AdditiveReaction;
return pas::EAnimationState::Invalid;
}
pas::EAnimationState CABSFlinch::UpdateBody(float dt, CBodyController& bc, CStateManager& mgr)
{
pas::EAnimationState st = GetBodyStateTransition(dt, bc);
if (st == pas::EAnimationState::Invalid)
{
CAnimData& animData = *bc.GetOwner().ModelData()->AnimationData();
CCharAnimTime rem = animData.GetAdditiveAnimationTree(x8_anim)->VGetTimeRemaining();
if (std::fabs(rem.GetSeconds()) < 0.00001f)
return pas::EAnimationState::AdditiveIdle;
}
return st;
}
pas::EAnimationState CABSIdle::GetBodyStateTransition(float dt, CBodyController& bc)
{
if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveReaction))
return pas::EAnimationState::AdditiveReaction;
if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveFlinch))
return pas::EAnimationState::AdditiveFlinch;
if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveAim))
return pas::EAnimationState::AdditiveAim;
return pas::EAnimationState::Invalid;
}
pas::EAnimationState CABSIdle::UpdateBody(float dt, CBodyController& bc, CStateManager& mgr)
{
return GetBodyStateTransition(dt, bc);
}
void CABSReaction::Start(CBodyController& bc, CStateManager& mgr)
{
const CBCAdditiveReactionCmd* cmd =
static_cast<const CBCAdditiveReactionCmd*>(bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveReaction));
x4_weight = cmd->GetWeight();
xc_type = cmd->GetType();
x10_active = cmd->GetIsActive();
CPASAnimParmData parms(24, CPASAnimParm::FromEnum(s32(xc_type)));
std::pair<float, s32> best = bc.GetPASDatabase().FindBestAnimation(parms, *mgr.GetActiveRandom(), -1);
x8_anim = best.second;
if (x8_anim != -1)
{
CAnimData& animData = *bc.GetOwner().ModelData()->AnimationData();
animData.AddAdditiveAnimation(x8_anim, x4_weight, x10_active, false);
}
}
pas::EAnimationState CABSReaction::GetBodyStateTransition(float dt, CBodyController& bc)
{
if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::AdditiveReaction) &&
xc_type == pas::EReactionType::Three)
return pas::EAnimationState::AdditiveReaction;
return pas::EAnimationState::Invalid;
}
pas::EAnimationState CABSReaction::UpdateBody(float dt, CBodyController& bc, CStateManager& mgr)
{
pas::EAnimationState st = GetBodyStateTransition(dt, bc);
if (st == pas::EAnimationState::Invalid)
{
if (x8_anim == -1)
return pas::EAnimationState::AdditiveIdle;
CAnimData& animData = *bc.GetOwner().ModelData()->AnimationData();
if (x10_active)
{
if (bc.GetCommandMgr().GetCmd(EBodyStateCmd::TwentySeven))
{
StopAnimation(bc);
bc.GetOwner().RemoveEmitter();
return pas::EAnimationState::AdditiveIdle;
}
}
else
{
if (animData.IsAdditiveAnimationAdded(x8_anim))
{
CCharAnimTime rem = animData.GetAdditiveAnimationTree(x8_anim)->VGetTimeRemaining();
if (std::fabs(rem.GetSeconds()) < 0.00001f)
{
StopAnimation(bc);
return pas::EAnimationState::AdditiveIdle;
}
}
else
{
return pas::EAnimationState::AdditiveIdle;
}
}
}
return st;
}
void CABSReaction::StopAnimation(CBodyController& bc)
{
if (x8_anim != -1)
{
CAnimData& animData = *bc.GetOwner().ModelData()->AnimationData();
animData.DelAdditiveAnimation(x8_anim);
x8_anim = -1;
}
}
}

View File

@ -7,30 +7,68 @@
namespace urde
{
class CBodyController;
class CStateManager;
class CActor;
class CAdditiveBodyState
{
public:
virtual ~CAdditiveBodyState() = default;
virtual bool ApplyHeadTracking() const { return true; }
virtual bool CanShoot() const { return true; }
virtual void Start(CBodyController& bc, CStateManager& mgr) = 0;
virtual pas::EAnimationState UpdateBody(float dt, CBodyController& bc, CStateManager& mgr) = 0;
virtual void Shutdown(CBodyController& bc) = 0;
};
class CABSAim : public CAdditiveBodyState
{
bool x4_needsIdle = false;
s32 x8_anims[4];
float x18_angles[4];
float x28_hWeight = 0.f;
float x2c_hWeightVel = 0.f;
float x30_vWeight = 0.f;
float x34_vWeightVel = 0.f;
pas::EAnimationState GetBodyStateTransition(float dt, CBodyController& bc);
public:
void Start(CBodyController& bc, CStateManager& mgr);
pas::EAnimationState UpdateBody(float dt, CBodyController& bc, CStateManager& mgr);
void Shutdown(CBodyController& bc);
};
class CABSFlinch : public CAdditiveBodyState
{
float x4_weight = 1.f;
u32 x8_anim = 0;
pas::EAnimationState GetBodyStateTransition(float dt, CBodyController& bc);
public:
void Start(CBodyController& bc, CStateManager& mgr);
pas::EAnimationState UpdateBody(float dt, CBodyController& bc, CStateManager& mgr);
void Shutdown(CBodyController& bc) {}
};
class CABSIdle : public CAdditiveBodyState
{
pas::EAnimationState GetBodyStateTransition(float dt, CBodyController& bc);
public:
void Start(CBodyController& bc, CStateManager& mgr) {}
pas::EAnimationState UpdateBody(float dt, CBodyController& bc, CStateManager& mgr);
void Shutdown(CBodyController& bc) {}
};
class CABSReaction : public CAdditiveBodyState
{
float x4_weight = 1.f;
s32 x8_anim = -1;
pas::EReactionType xc_type = pas::EReactionType::Invalid;
bool x10_active = false;
pas::EAnimationState GetBodyStateTransition(float dt, CBodyController& bc);
void StopAnimation(CBodyController& bc);
public:
void Start(CBodyController& bc, CStateManager& mgr);
pas::EAnimationState UpdateBody(float dt, CBodyController& bc, CStateManager& mgr);
void Shutdown(CBodyController& bc) { StopAnimation(bc); }
};
}

View File

@ -187,6 +187,12 @@ SAdvancementDeltas CAnimData::UpdateAdditiveAnims(float dt)
}
bool CAnimData::IsAdditiveAnimation(u32 idx) const
{
u32 animIdx = xc_charInfo.GetAnimationIndex(idx);
return x0_charFactory->HasAdditiveInfo(animIdx);
}
bool CAnimData::IsAdditiveAnimationAdded(u32 idx) const
{
auto search = std::find_if(x434_additiveAnims.cbegin(), x434_additiveAnims.cend(),
[&](const std::pair<u32, CAdditiveAnimPlayback>& pair) -> bool {
@ -197,14 +203,12 @@ bool CAnimData::IsAdditiveAnimation(u32 idx) const
return true;
}
std::shared_ptr<CAnimTreeNode> CAnimData::GetAdditiveAnimationTree(u32 idx) const
const std::shared_ptr<CAnimTreeNode>& CAnimData::GetAdditiveAnimationTree(u32 idx) const
{
auto search = std::find_if(x434_additiveAnims.cbegin(), x434_additiveAnims.cend(),
[&](const std::pair<u32, CAdditiveAnimPlayback>& pair) -> bool {
return pair.first == idx;
});
if (search == x434_additiveAnims.cend())
return {};
return search->second.GetAnim();
}
@ -215,7 +219,7 @@ bool CAnimData::IsAdditiveAnimationActive(u32 idx) const
return pair.first == idx;
});
if (search == x434_additiveAnims.cend())
return {};
return false;
return search->second.IsActive();
}
@ -257,6 +261,17 @@ void CAnimData::AddAdditiveAnimation(u32 idx, float weight, bool active, bool b)
x434_additiveAnims.emplace_back(std::make_pair(idx, CAdditiveAnimPlayback(node, weight, active, info, b)));
}
float CAnimData::GetAdditiveAnimationWeight(u32 idx) const
{
u32 animIdx = xc_charInfo.GetAnimationIndex(idx);
for (const std::pair<u32, CAdditiveAnimPlayback>& anim : x434_additiveAnims)
{
if (anim.first == animIdx)
return anim.second.GetTargetWeight();
}
return 0.f;
}
std::shared_ptr<CAnimationManager> CAnimData::GetAnimationManager()
{
return x100_animMgr;

View File

@ -162,10 +162,12 @@ public:
SAdvancementDeltas AdvanceAdditiveAnims(float);
SAdvancementDeltas UpdateAdditiveAnims(float);
bool IsAdditiveAnimation(u32) const;
std::shared_ptr<CAnimTreeNode> GetAdditiveAnimationTree(u32) const;
bool IsAdditiveAnimationAdded(u32) const;
const std::shared_ptr<CAnimTreeNode>& GetAdditiveAnimationTree(u32) const;
bool IsAdditiveAnimationActive(u32) const;
void DelAdditiveAnimation(u32);
void AddAdditiveAnimation(u32, float, bool, bool);
float GetAdditiveAnimationWeight(u32 idx) const;
std::shared_ptr<CAnimationManager> GetAnimationManager();
const CCharacterInfo& GetCharacterInfo() const { return xc_charInfo; }
const CCharLayoutInfo& GetCharLayoutInfo() const { return *xcc_layoutData.GetObj(); }

View File

@ -233,21 +233,25 @@ public:
class CBCAdditiveFlinchCmd : public CBodyStateCmd
{
float x8_ = 1.f;
float x8_weight = 1.f;
public:
CBCAdditiveFlinchCmd() : CBodyStateCmd(EBodyStateCmd::AdditiveFlinch) {}
CBCAdditiveFlinchCmd(float f) : CBodyStateCmd(EBodyStateCmd::AdditiveFlinch), x8_(f) {}
CBCAdditiveFlinchCmd(float f) : CBodyStateCmd(EBodyStateCmd::AdditiveFlinch), x8_weight(f) {}
float GetWeight() const { return x8_weight; }
};
class CBCAdditiveReactionCmd : public CBodyStateCmd
{
float x8_ = 1.f;
float x8_weight = 1.f;
pas::EReactionType xc_type = pas::EReactionType::Invalid;
bool x10_ = false;
bool x10_active = false;
public:
CBCAdditiveReactionCmd() : CBodyStateCmd(EBodyStateCmd::AdditiveReaction) {}
CBCAdditiveReactionCmd(pas::EReactionType type, float f)
: CBodyStateCmd(EBodyStateCmd::AdditiveReaction), x8_(f), xc_type(type) {}
: CBodyStateCmd(EBodyStateCmd::AdditiveReaction), x8_weight(f), xc_type(type) {}
pas::EReactionType GetType() const { return xc_type; }
float GetWeight() const { return x8_weight; }
bool GetIsActive() const { return x10_active; }
};
class CBCLoopAttackCmd : public CBodyStateCmd
@ -327,7 +331,7 @@ class CBodyStateCmdMgr
CBCCoverCmd x230_cover;
CBCWallHangCmd x254_wallHang;
CBodyStateCmd x260_ = {EBodyStateCmd::Locomotion};
CBodyStateCmd x268_ = {EBodyStateCmd::TwentyThree};
CBodyStateCmd x268_ = {EBodyStateCmd::AdditiveIdle};
CBCAdditiveAimCmd x270_additiveAim;
CBCAdditiveFlinchCmd x278_additiveFlinch;
CBCAdditiveReactionCmd x284_additiveReaction;

View File

@ -150,14 +150,24 @@ ResId CCharacterFactory::GetEventResourceIdForAnimResourceId(ResId id) const
const CAdditiveAnimationInfo& CCharacterFactory::FindAdditiveInfo(u32 idx) const
{
auto search = std::lower_bound(x40_additiveInfo.cbegin(), x40_additiveInfo.cend(), idx,
[](const auto& anim, u32 test) -> bool { return anim.first < test; });
auto search = rstl::binary_find(x40_additiveInfo.cbegin(), x40_additiveInfo.cend(), idx,
[](const auto& anim) { return anim.first; });
if (search == x40_additiveInfo.cend() || idx != search->first)
if (search == x40_additiveInfo.cend())
return x50_defaultAdditiveInfo;
return search->second;
}
bool CCharacterFactory::HasAdditiveInfo(u32 idx) const
{
auto search = rstl::binary_find(x40_additiveInfo.cbegin(), x40_additiveInfo.cend(), idx,
[](const auto& anim) { return anim.first; });
if (search == x40_additiveInfo.cend())
return false;
return true;
}
std::vector<CCharacterInfo>
CCharacterFactory::GetCharacterInfoDB(const CAnimCharacterSet& ancs)
{

View File

@ -72,6 +72,7 @@ public:
const CCharacterInfo& GetCharInfo(int charIdx) const { return x4_charInfoDB[charIdx]; }
const CAdditiveAnimationInfo& FindAdditiveInfo(u32 idx) const;
bool HasAdditiveInfo(u32 idx) const;
};
}

View File

@ -62,11 +62,9 @@ CPASAnimState::CPASAnimState(int stateId)
CPASAnimParm CPASAnimState::GetAnimParmData(s32 animId, u32 parmIdx) const
{
CPASAnimInfo key(animId);
auto search = std::lower_bound(x14_anims.begin(), x14_anims.end(), key,
[](const CPASAnimInfo& item, const CPASAnimInfo& testId) ->
bool {return item.GetAnimId() < testId.GetAnimId();});
if (search == x14_anims.end() || search->GetAnimId() > animId)
auto search = rstl::binary_find(x14_anims.begin(), x14_anims.end(), animId,
[](const CPASAnimInfo& item) {return item.GetAnimId();});
if (search == x14_anims.end())
return CPASAnimParm::NoParameter();
CPASParmInfo parm = x4_parms.at(parmIdx);

View File

@ -37,11 +37,10 @@ std::pair<float, s32> CPASDatabase::FindBestAnimation(const CPASAnimParmData& da
std::pair<float, s32> CPASDatabase::FindBestAnimation(const CPASAnimParmData& data, CRandom16& rand, s32 ignoreAnim) const
{
CPASAnimState key(data.GetStateId());
auto it = std::lower_bound(x0_states.cbegin(), x0_states.cend(), key,
[](const CPASAnimState& item, const CPASAnimState& test) -> bool {return item.GetStateId() < test.GetStateId();});
auto it = rstl::binary_find(x0_states.cbegin(), x0_states.cend(), data.GetStateId(),
[](const CPASAnimState& item) {return item.GetStateId();});
if (it == x0_states.cend() || it->GetStateId() > key.GetStateId())
if (it == x0_states.cend())
return {0.f, -1};
return (*it).FindBestAnimation(data.GetAnimParmData(), rand, ignoreAnim);

View File

@ -61,7 +61,11 @@ enum class EAnimationState
Scripted,
ProjectileAttack,
Cover,
WallHang
WallHang,
AdditiveIdle,
AdditiveAim,
AdditiveFlinch,
AdditiveReaction
};
enum class EHurledState
@ -85,7 +89,11 @@ enum class EFallState
enum class EReactionType
{
Invalid = -1
Invalid = -1,
Zero,
One,
Two,
Three
};
enum class EAdditiveReactionType
@ -242,7 +250,7 @@ enum class EBodyStateCmd
Cover,
WallHang,
Locomotion,
TwentyThree,
AdditiveIdle,
AdditiveAim,
AdditiveFlinch,
AdditiveReaction,

View File

@ -317,9 +317,9 @@ ResId CTextParser::GetAssetIdFromString(const char16_t* str, int len,
if (txtrMap)
{
auto search = std::lower_bound(txtrMap->begin(), txtrMap->end(), id,
[](const std::pair<ResId, ResId>& a, ResId test) { return a.first < test; });
if (search != txtrMap->end() && search->first == id)
auto search = rstl::binary_find(txtrMap->begin(), txtrMap->end(), id,
[](const std::pair<ResId, ResId>& a) { return a.first; });
if (search != txtrMap->end())
id = search->second;
}

View File

@ -169,8 +169,8 @@ static const CCharacterIdentifier gCantEndChars[] =
int CWordBreakTables::GetBeginRank(wchar_t ch)
{
auto search = std::lower_bound(std::cbegin(gCantBeginChars), std::cend(gCantBeginChars), ch,
[](const CCharacterIdentifier& item, const wchar_t& test) -> bool {return item.chr < test;});
auto search = rstl::binary_find(std::cbegin(gCantBeginChars), std::cend(gCantBeginChars), ch,
[](const CCharacterIdentifier& item) {return item.chr;});
if (search == std::cend(gCantBeginChars))
return 5;
return search->rank;
@ -178,8 +178,8 @@ int CWordBreakTables::GetBeginRank(wchar_t ch)
int CWordBreakTables::GetEndRank(wchar_t ch)
{
auto search = std::lower_bound(std::cbegin(gCantEndChars), std::cend(gCantEndChars), ch,
[](const CCharacterIdentifier& item, const wchar_t& test) -> bool {return item.chr < test;});
auto search = rstl::binary_find(std::cbegin(gCantEndChars), std::cend(gCantEndChars), ch,
[](const CCharacterIdentifier& item) {return item.chr;});
if (search == std::cend(gCantEndChars))
return 5;
return search->rank;

View File

@ -9,24 +9,4 @@ CEnergyDrainSource::CEnergyDrainSource(TUniqueId src, float intensity)
{
}
TUniqueId CEnergyDrainSource::GetEnergyDrainSourceId() const
{
return x0_source;
}
void CEnergyDrainSource::SetEnergyDrainIntensity(float in)
{
x4_intensity = in;
}
float CEnergyDrainSource::GetEnergyDrainIntensity() const
{
return x4_intensity;
}
bool CEnergyDrainSource::operator<(const CEnergyDrainSource& other) const
{
return x0_source < other.x0_source;
}
}

View File

@ -11,11 +11,9 @@ class CEnergyDrainSource
float x4_intensity;
public:
CEnergyDrainSource(TUniqueId src, float intensity);
TUniqueId GetEnergyDrainSourceId() const;
void SetEnergyDrainIntensity(float);
float GetEnergyDrainIntensity() const;
bool operator<(const CEnergyDrainSource& other) const;
TUniqueId GetEnergyDrainSourceId() const { return x0_source; }
void SetEnergyDrainIntensity(float in) { x4_intensity = in; }
float GetEnergyDrainIntensity() const { return x4_intensity; }
};
}
#endif // __URDE_CENERGYDRAINSOURCE_HPP__

View File

@ -10,7 +10,8 @@ void CPlayerEnergyDrain::AddEnergyDrainSource(TUniqueId id, float intensity) { x
void CPlayerEnergyDrain::RemoveEnergyDrainSource(TUniqueId id)
{
auto it = std::lower_bound(x0_sources.begin(), x0_sources.end(), CEnergyDrainSource(id, 0.f));
auto it = rstl::binary_find(x0_sources.begin(), x0_sources.end(), id,
[](const CEnergyDrainSource& item) {return item.GetEnergyDrainSourceId();});
if (it != x0_sources.end())
x0_sources.erase(it);
}

View File

@ -44,6 +44,21 @@ public:
T& operator[](size_t idx) { return x4_data[idx]; }
const T& operator[](size_t idx) const { return x4_data[idx]; }
};
template<class ForwardIt, class T>
ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value)
{
first = std::lower_bound(first, last, value);
return (!(first == last) && !(value < *first)) ? first : last;
}
template<class ForwardIt, class T, class GetKey>
ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, GetKey getkey)
{
auto comp = [&](const auto& left, const T& right) { return getkey(left) < right; };
first = std::lower_bound(first, last, value, comp);
return (!(first == last) && !(value < getkey(*first))) ? first : last;
}
}
#endif // __RSTL_HPP__