metaforce/Runtime/World/CDamageVulnerability.cpp

256 lines
9.4 KiB
C++

#include "Runtime/World/CDamageVulnerability.hpp"
namespace metaforce {
const CDamageVulnerability CDamageVulnerability::sNormalVulnerability(
EVulnerability::Normal, EVulnerability::Normal, EVulnerability::Normal, EVulnerability::Normal,
EVulnerability::Normal, EVulnerability::Normal, EVulnerability::Normal, EVulnerability::Normal,
EVulnerability::Normal, EVulnerability::Normal, EVulnerability::Normal, EVulnerability::Normal,
EVulnerability::Normal, EVulnerability::Normal, EVulnerability::Normal, EVulnerability::Normal,
EVulnerability::Normal, EVulnerability::Normal, EVulnerability::Normal, EVulnerability::Normal,
EVulnerability::Normal, EVulnerability::Normal, EVulnerability::Normal, EDeflectType::None);
const CDamageVulnerability CDamageVulnerability::sImmuneVulnerability(
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EDeflectType::None);
const CDamageVulnerability CDamageVulnerability::sReflectVulnerability(
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect,
EVulnerability::Deflect, EVulnerability::Deflect, EVulnerability::Deflect, EDeflectType::One);
const CDamageVulnerability CDamageVulnerability::sPassThroughVulnerability(
EVulnerability::PassThrough, EVulnerability::PassThrough, EVulnerability::PassThrough, EVulnerability::PassThrough,
EVulnerability::PassThrough, EVulnerability::PassThrough, EVulnerability::PassThrough, EVulnerability::PassThrough,
EVulnerability::PassThrough, EVulnerability::PassThrough, EVulnerability::PassThrough, EVulnerability::PassThrough,
EVulnerability::PassThrough, EVulnerability::PassThrough, EVulnerability::PassThrough, EVulnerability::PassThrough,
EVulnerability::PassThrough, EVulnerability::PassThrough, EVulnerability::PassThrough, EVulnerability::PassThrough,
EVulnerability::PassThrough, EVulnerability::PassThrough, EVulnerability::PassThrough, EDeflectType::None);
static constexpr bool is_deflect_direct(EVulnerability vuln) {
return vuln == EVulnerability::Deflect ||
(EVulnerability(u32(vuln) - u32(EVulnerability::DirectWeak)) < EVulnerability::Deflect) ||
vuln == EVulnerability::DirectImmune;
}
static constexpr bool is_normal_or_weak(EVulnerability vuln) {
return vuln == EVulnerability::Weak || vuln == EVulnerability::Normal;
}
static constexpr bool is_not_deflect(EVulnerability vuln) { return vuln != EVulnerability::Deflect; }
void CDamageVulnerability::ConstructNew(CInputStream& in, int propCount) {
propCount -= 3;
for (int i = 0; i < std::min(propCount, 15); ++i) {
x0_normal[i] = EVulnerability(in.ReadLong());
}
if (propCount < 15) {
for (int i = propCount; i < 15; ++i) {
x0_normal[i] = EVulnerability::Deflect;
}
}
for (int i = 15; i < propCount; ++i) {
in.ReadLong();
}
x5c_deflected = EDeflectType(in.ReadLong());
in.ReadLong();
for (int i = 0; i < 4; ++i) {
x3c_charged[i] = EVulnerability(in.ReadLong());
}
x60_chargedDeflected = EDeflectType(in.ReadLong());
in.ReadLong();
for (int i = 0; i < 4; ++i) {
x4c_combo[i] = EVulnerability(in.ReadLong());
}
x64_comboDeflected = EDeflectType(in.ReadLong());
}
CDamageVulnerability::CDamageVulnerability(CInputStream& in) {
u32 propCount = in.ReadLong();
if (propCount == 11) {
for (int i = 0; i < 15; ++i) {
x0_normal[i] = EVulnerability(in.ReadLong());
}
x5c_deflected = EDeflectType(in.ReadLong());
x3c_charged[0] = x0_normal[0];
x4c_combo[0] = x0_normal[0];
x3c_charged[1] = x0_normal[1];
x4c_combo[1] = x0_normal[1];
x3c_charged[2] = x0_normal[2];
x4c_combo[2] = x0_normal[2];
x3c_charged[3] = x0_normal[3];
x4c_combo[3] = x0_normal[3];
} else {
ConstructNew(in, propCount);
}
}
EDeflectType CDamageVulnerability::GetDeflectionType(const CWeaponMode& mode) const {
if (mode.IsCharged()) {
return x60_chargedDeflected;
}
if (mode.IsComboed()) {
return x64_comboDeflected;
}
return x5c_deflected;
}
bool CDamageVulnerability::WeaponHurts(const CWeaponMode& mode, bool ignoreDirect) const {
EWeaponType weaponType = mode.GetType();
if (weaponType < EWeaponType::Power || weaponType > EWeaponType::OrangePhazon) {
return false;
}
if (mode.IsInstantKill()) {
return true;
}
EVulnerability vuln = x0_normal[u32(weaponType)];
bool normalHurts = ignoreDirect == 0 ? (is_normal_or_weak(vuln) || vuln == EVulnerability::DirectWeak ||
vuln == EVulnerability::DirectNormal)
: is_normal_or_weak(vuln);
bool chargedHurts;
if (weaponType < EWeaponType::Bomb) {
vuln = x3c_charged[u32(weaponType)];
chargedHurts = ignoreDirect == 0 ? (is_normal_or_weak(vuln) || vuln == EVulnerability::DirectWeak ||
vuln == EVulnerability::DirectNormal)
: is_normal_or_weak(vuln);
;
} else {
chargedHurts = true;
}
bool comboedHurts;
if (weaponType < EWeaponType::Bomb) {
vuln = x3c_charged[u32(weaponType)];
comboedHurts = ignoreDirect == 0 ? (is_normal_or_weak(vuln) || vuln == EVulnerability::DirectWeak ||
vuln == EVulnerability::DirectNormal)
: is_normal_or_weak(vuln);
;
} else {
comboedHurts = true;
}
bool result = false;
if ((normalHurts && !mode.IsCharged() && !mode.IsComboed()) || (chargedHurts && mode.IsCharged()) ||
(comboedHurts && mode.IsComboed())) {
result = true;
}
return result;
}
bool CDamageVulnerability::WeaponHits(const CWeaponMode& mode, bool checkDirect) const {
const EWeaponType weaponType = mode.GetType();
if (weaponType < EWeaponType::Power || weaponType > EWeaponType::OrangePhazon) {
return false;
}
if (mode.IsInstantKill()) {
return true;
}
EVulnerability vuln = x0_normal[u32(weaponType)];
bool normalHits;
if (!checkDirect) {
normalHits = is_not_deflect(vuln);
} else if (vuln == EVulnerability::Deflect ||
(static_cast<EVulnerability>((u32)vuln - (u32)EVulnerability::DirectWeak) <= EVulnerability::Normal) ||
vuln == EVulnerability::DirectImmune) {
normalHits = false;
} else {
normalHits = true;
}
bool chargedHits;
if (weaponType < EWeaponType::Bomb) {
vuln = x3c_charged[u32(weaponType)];
if (!checkDirect) {
chargedHits = is_not_deflect(vuln);
} else if (vuln == EVulnerability::Deflect ||
(static_cast<EVulnerability>((u32)vuln - (u32)EVulnerability::DirectWeak) <= EVulnerability::Normal) ||
vuln == EVulnerability::DirectImmune) {
chargedHits = false;
} else {
chargedHits = true;
}
} else {
chargedHits = true;
}
bool comboedHits;
if (weaponType < EWeaponType::Bomb) {
vuln = x4c_combo[u32(weaponType)];
if (!checkDirect) {
comboedHits = is_not_deflect(vuln);
} else if (vuln == EVulnerability::Deflect ||
(static_cast<EVulnerability>((u32)vuln - (u32)EVulnerability::DirectWeak) <= EVulnerability::Normal ||
vuln == EVulnerability::DirectImmune)) {
comboedHits = false;
} else {
comboedHits = true;
}
} else {
comboedHits = true;
}
bool result = false;
if ((normalHits && !mode.IsCharged() && !mode.IsComboed()) || (chargedHits && mode.IsCharged()) ||
(comboedHits && mode.IsComboed())) {
result = true;
}
return result;
}
inline EVulnerability direct_to_normal(EVulnerability vuln) {
if (vuln == EVulnerability::DirectWeak) {
return EVulnerability::Weak;
}
if (vuln == EVulnerability::DirectNormal) {
return EVulnerability::Normal;
}
if (vuln == EVulnerability::DirectImmune) {
return EVulnerability::Immune;
}
return vuln;
}
EVulnerability CDamageVulnerability::GetVulnerability(const CWeaponMode& mode, bool ignoreDirect) const {
if (mode.GetType() < EWeaponType::Power || mode.GetType() > EWeaponType::OrangePhazon) {
return EVulnerability::Deflect;
}
if (mode.IsInstantKill()) {
return EVulnerability::Normal;
}
EVulnerability vuln = x0_normal[u32(mode.GetType())];
EWeaponType type = mode.GetType();
if (mode.IsCharged()) {
vuln = type < EWeaponType::Bomb ? x3c_charged[u32(type)] : EVulnerability::Normal;
}
if (mode.IsComboed()) {
vuln = type < EWeaponType::Bomb ? x4c_combo[u32(type)] : EVulnerability::Normal;
}
if (ignoreDirect == 1) {
return vuln;
}
return direct_to_normal(vuln);
}
} // namespace metaforce