Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minimal support for some Echoes changes #412

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ if(APPLE AND NOT CMAKE_OSX_SYSROOT)
OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()

set(METAFORCE_TARGET_GAME "PRIME1" CACHE STRING "The game Metaforce will replicate")
set_property(CACHE METAFORCE_TARGET_GAME PROPERTY STRINGS PRIME1 PRIME2)

option(METAFORCE_CROSSCOMPILING "Don't build tools; attempt package import" OFF)
if (METAFORCE_CROSSCOMPILING)
set(CMAKE_CROSSCOMPILING On)
Expand Down Expand Up @@ -361,6 +364,12 @@ if (NOT WIN32)
set(ZLIB_LIBRARIES ZLIB::ZLIB CACHE STRING "zlib libraries" FORCE)
endif()

if("${METAFORCE_TARGET_GAME}" STREQUAL "PRIME1")
add_definitions(-DPRIME1)
elseif("${METAFORCE_TARGET_GAME}" STREQUAL "PRIME2")
add_definitions(-DPRIME2)
endif()

add_subdirectory(extern/nod)

set(DATA_SPEC_LIBS RetroDataSpec AssetNameMap)
Expand Down
33 changes: 33 additions & 0 deletions CMakeSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,39 @@
"type": "STRING"
}
]
},
{
"name": "Prime2-x64-MSVC-Release",
"generator": "Ninja",
"configurationType": "RelWithDebInfo",
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x64_x64" ],
"variables": [
{
"name": "CMAKE_MSVC_RUNTIME_LIBRARY",
"value": "MultiThreadedDLL",
"type": "STRING"
},
{
"name": "CMAKE_CXX_FLAGS",
"value": "",
"type": "STRING"
},
{
"name": "CMAKE_C_FLAGS",
"value": "",
"type": "STRING"
},
{
"name": "METAFORCE_TARGET_GAME",
"value": "PRIME2",
"type": "STRING"
}
]
}
]
}
102 changes: 99 additions & 3 deletions Runtime/CPlayerState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ u32 CPlayerState::GetItemCapacity(CPlayerState::EItemType type) const {
return 0;
}

#ifdef PRIME1
u32 CPlayerState::GetItemAmount(CPlayerState::EItemType type) const {
if (type == EItemType::SpaceJumpBoots || type == EItemType::PowerBombs || type == EItemType::Flamethrower ||
type == EItemType::EnergyTanks || type == EItemType::Missiles ||
Expand All @@ -297,20 +298,59 @@ u32 CPlayerState::GetItemAmount(CPlayerState::EItemType type) const {

return 0;
}
#else
u32 CPlayerState::GetItemAmount(EItemType type, bool respectFieldToQuery = true) const {
if (int(type) < 0 || type >= EItemType::Max) {
return 0;
}
auto query = EPowerUpFieldToQuery::Actual;
if (respectFieldToQuery) {
query = GetPowerUpFieldToQuery(type);
}
switch (query) {
case EPowerUpFieldToQuery::Actual:
return x24_powerups[int(type)].x0_amount;
case EPowerUpFieldToQuery::Maximum:
return GetPowerUpMaxValue(type);
case EPowerUpFieldToQuery::Minimum:
return 0;
}
}
#endif


void CPlayerState::DecrPickup(CPlayerState::EItemType type, u32 amount) {
#ifdef PRIME1
if (type >= EItemType::Max)
return;

if ((type == EItemType::Missiles || type >= EItemType::PowerBombs) && type < EItemType::ThermalVisor)
x24_powerups[u32(type)].x0_amount -= amount;

#else
if (int(type) < 0 || type >= EItemType::Max || GetPowerUpFieldToQuery(type) == EPowerUpFieldToQuery::Maximum) {
return;
}
auto& powerup = x24_powerups[u32(type)];
if (powerup.x0_amount > amount) {
powerup.x0_amount -= amount;
} else {
powerup.x0_amount = 0;
}
if (type == EItemType::EnergyTanks) {
IncrementHealth(0.0f);
}
#endif
}

void CPlayerState::IncrPickup(EItemType type, u32 amount) {
if (type >= EItemType::Max)
return;

switch (type) {
#ifdef PRIME1
default:
break;
case EItemType::Missiles:
case EItemType::PowerBombs:
case EItemType::ChargeBeam:
Expand All @@ -327,7 +367,11 @@ void CPlayerState::IncrPickup(EItemType type, u32 amount) {
case EItemType::Sun:
case EItemType::World:
case EItemType::Spirit:
case EItemType::Newborn: {
case EItemType::Newborn:
#else
default:
#endif
{
CPowerUp& pup = x24_powerups[u32(type)];
pup.x0_amount = std::min(pup.x0_amount + u32(amount), pup.x4_capacity);

Expand All @@ -338,8 +382,6 @@ void CPlayerState::IncrPickup(EItemType type, u32 amount) {
case EItemType::HealthRefill:
xc_health.SetHP(std::min(amount + xc_health.GetHP(), CalculateHealth()));
break;
default:
break;
}
}

Expand Down Expand Up @@ -535,4 +577,58 @@ std::string_view CPlayerState::ItemTypeToName(CPlayerState::EItemType type) {
}
}


#ifdef PRIME2

void CPlayerState::IncrementHealth(float delta) {
xc_health.SetHP(zeus::clamp(0.0f, xc_health.GetHP() + delta, CalculateHealth()));
}

CPlayerState::EPowerUpFieldToQuery CPlayerState::GetPowerUpFieldToQuery(EItemType type) const {
switch (type) {
case EItemType::MorphBall:
if (x24_powerups[int(EItemType::DeathBall)].x0_amount != 0) {
return EPowerUpFieldToQuery::Minimum;
}
if (x24_powerups[int(EItemType::DisableBall)].x0_amount != 0) {
return EPowerUpFieldToQuery::Minimum;
}
if (x24_powerups[int(EItemType::Unknown_91)].x0_amount != 0) {
return EPowerUpFieldToQuery::Minimum;
}
break;
case EItemType::BoostBall:
case EItemType::SpiderBall:
case EItemType::MorphBallBombs:
case EItemType::PowerBombs:
if (x24_powerups[int(EItemType::DeathBall)].x0_amount != 0) {
return EPowerUpFieldToQuery::Minimum;
}
break;
case EItemType::SpaceJumpBoots:
if (x24_powerups[int(EItemType::DisableSpaceJump)].x0_amount != 0) {
return EPowerUpFieldToQuery::Minimum;
}
break;
case EItemType::Missiles:
if (x24_powerups[int(EItemType::DisableMissiles)].x0_amount != 0) {
return EPowerUpFieldToQuery::Minimum;
}
if (x24_powerups[int(EItemType::UnlimitedMissiles)].x0_amount != 0) {
return EPowerUpFieldToQuery::Maximum;
}
break;
case EItemType::DarkAmmo:
case EItemType::LightAmmo:
if (x24_powerups[int(EItemType::DisableBeamAmmo)].x0_amount != 0) {
return EPowerUpFieldToQuery::Minimum;
}
if (x24_powerups[int(EItemType::UnlimitedBeamAmmo)].x0_amount != 0) {
return EPowerUpFieldToQuery::Maximum;
}
}
return EPowerUpFieldToQuery::Actual;
}
#endif

} // namespace metaforce
129 changes: 129 additions & 0 deletions Runtime/CPlayerState.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,118 @@ class CPlayerState {
Spirit = 39,
Newborn = 40,

#ifdef PRIME2
//PowerBeam,
DarkBeam,
LightBeam,
AnnihilatorBeam,
//SuperMissile,
Darkburst,
Sunburst,
SonicBoom,
//CombatVisor,
//ScanVisor,
DarkVisor,
EchoVisor,
//VariaSuit,
DarkSuit,
LightSuit,
//MorphBall,
//BoostBall,
//SpiderBall,
//MorphBallBombs,
Unknown01,
Unknown02,
Unknown03,
//ChargeBeam,
//GrappleBeam,
//SpaceJumpBoots,
GravityBoost,
SeekerLauncher,
ScrewAttack,
Unknown04,
TempleKey1,
TempleKey2,
TempleKey3,
AgonKey1,
AgonKey2,
AgonKey3,
TorvusKey1,
TorvusKey2,
TorvusKey3,
HiveKey1,
HiveKey2,
HiveKey3,
//HealthRefill,
//EnergyTank,
//Powerbomb,
//Missile,
DarkAmmo,
LightAmmo,
ItemPercentage,
Unknown_48,
Unknown_49,
Unknown_50,
Unknown_51,
Unknown_52,
Unknown_53,
Unknown_54,
Unknown_55,
Unknown_56,
Invisibility,
DoubleDamage,
Invincibility,
Unknown_60,
Unknown_61,
Unknown_62,
Unknown_63,
Unknown_64,
Unknown_65,
Unknown_66,
Unknown_67,
Unknown_68,
Unknown_69,
Unknown_70,
Unused1,
Unused2,
Unused3,
Unused4,
Unknown_76,
Unknown_77,
Unknown_78,
Unknown_79,
Unknown_80,
Unknown_81,
UnlimitedMissiles,
UnlimitedBeamAmmo,
DarkShield,
LightShield,
AbsorbAttack,
DeathBall,
ScanVirus,
Unknown_88,
DisableBeamAmmo,
DisableMissiles,
Unknown_91,
DisableBall,
DisableSpaceJump,
Unknown_94,
HackedEffect,
CannonBall,
VioletTranslator,
AmberTranslator,
EmeraldTranslator,
CobaltTranslator,
TempleKey4,
TempleKey5,
TempleKey6,
TempleKey7,
TempleKey8,
TempleKey9,
EnergyTransferModule,
ChargeCombo,
#endif

/* This must remain at the end of the list */
Max
};
Expand Down Expand Up @@ -87,6 +199,14 @@ class CPlayerState {

enum class EBeamId : s32 { Invalid = -1, Power, Ice, Wave, Plasma, Phazon, Phazon2 = 27 };

#ifdef PRIME2
enum class EPowerUpFieldToQuery : u32 {
Actual,
Minimum,
Maximum
};
#endif

private:
struct CPowerUp {
u32 x0_amount = 0;
Expand Down Expand Up @@ -144,7 +264,11 @@ class CPlayerState {
void EnableItem(EItemType type);
bool HasPowerUp(EItemType type) const;
u32 GetItemCapacity(EItemType type) const;
#ifdef PRIME1
u32 GetItemAmount(EItemType type) const;
#else
u32 GetItemAmount(EItemType type, bool respectFieldToQuery = true) const;
#endif
void DecrPickup(EItemType type, u32 amount);
void IncrPickup(EItemType type, u32 amount);
void ResetAndIncrPickUp(EItemType type, u32 amount);
Expand All @@ -171,5 +295,10 @@ class CPlayerState {
static std::string_view ItemTypeToName(EItemType type);
bool CanTakeDamage() const { return m_canTakeDamage; }
void SetCanTakeDamage(bool c) { m_canTakeDamage = c; }

#ifdef PRIME2
void IncrementHealth(float delta);
EPowerUpFieldToQuery GetPowerUpFieldToQuery(EItemType type) const;
#endif
};
} // namespace metaforce
15 changes: 15 additions & 0 deletions Runtime/CStateManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2907,4 +2907,19 @@ const CGameArea* CStateManager::GetCurrentArea() const {
}
return nullptr;
};

#ifdef PRIME2

int CStateManager::MaskUIdNumPlayers(TUniqueId uid) const {
// Give a TUniqueId of a CPlayer object, returns the player index
u16 uVar1 = uid.Value();
if (uVar1 < numPlayers) {
return uVar1;
} else {
return 0;
}
}

#endif

} // namespace metaforce
Loading