Give mission achievements at game start

This commit is contained in:
fed 2023-04-14 19:37:45 +02:00
parent e45324ad32
commit 8a56923a7d
2 changed files with 180 additions and 0 deletions

View File

@ -188,6 +188,127 @@ namespace achievements
{ {
give_achievement(game::Scr_GetString(0)); give_achievement(game::Scr_GetString(0));
} }
void give_mission_achievements()
{
game::GamerProfileData data{};
game::GamerProfile_GetDataByName(&data, 0, "missionhighestdifficulty", 0xFFFFFFFF);
if (data.type != game::TYPE_STRING)
{
return;
}
achievement_file_t file{};
achievements::get_achievements(&file);
const auto completed_mission = [&](const game::level_number level, const std::string& achievement)
{
const auto id = get_achievement_id(achievement);
if (!id.has_value())
{
return;
}
const auto id_value = id.value();
const auto highest_difficulty = data.u.stringVal[level] - '0';
if (highest_difficulty)
{
file.achievements[id_value] = true;
}
};
std::unordered_map<achievement_id, std::vector<game::level_number>> veteran_achievements;
const auto add_veteran_achievement = [&](const game::level_number level, const std::string& achievement)
{
const auto id = get_achievement_id(achievement);
if (!id.has_value())
{
return;
}
const auto id_value = static_cast<achievement_id>(id.value());
veteran_achievements[id_value].push_back(level);
};
const auto give_veteran_achievements = [&]()
{
for (const auto& achievement : veteran_achievements)
{
auto has_veteran = true;
for (const auto& mission : achievement.second)
{
if (data.u.stringVal[mission] != '3')
{
has_veteran = false;
break;
}
}
if (has_veteran)
{
file.achievements[achievement.first] = true;
}
}
};
const auto give_completed_campaign_achievement = [&](const std::string& achievement)
{
const auto id = get_achievement_id(achievement);
if (!id.has_value())
{
return;
}
const auto id_value = static_cast<achievement_id>(id.value());
for (auto i = 0; i < game::LEVEL_COUNT; i++)
{
if (data.u.stringVal[i] - '0' < 2)
{
return;
}
}
file.achievements[id_value] = true;
};
completed_mission(game::LEVEL_TRAINER, "BACK_IN_THE_SADDLE");
completed_mission(game::LEVEL_ROADKILL, "DANGER_CLOSE");
completed_mission(game::LEVEL_CLIFFHANGER, "COLD_SHOULDER");
completed_mission(game::LEVEL_FAVELA, "TAGEM_AND_BAGEM");
completed_mission(game::LEVEL_INVASION, "ROYAL_WITH_CHEESE");
completed_mission(game::LEVEL_GULAG, "SOAP_ON_A_ROPE");
completed_mission(game::LEVEL_CONTINGENCY, "DESPERATE_TIMES");
completed_mission(game::LEVEL_DC_WHITEHOUSE, "HOUSTON_WE_HAVE_A_PROBLEM");
completed_mission(game::LEVEL_ESTATE, "THE_PAWN");
completed_mission(game::LEVEL_BONEYARD, "OUT_OF_THE_FRYING_PAN");
completed_mission(game::LEVEL_ENDING, "FOR_THE_RECORD");
add_veteran_achievement(game::LEVEL_TRAINER, "FIRST_DAY_OF_SCHOOL");
add_veteran_achievement(game::LEVEL_ROADKILL, "FIRST_DAY_OF_SCHOOL");
add_veteran_achievement(game::LEVEL_CLIFFHANGER, "BLACK_DIAMOND");
add_veteran_achievement(game::LEVEL_FAVELA, "TURISTAS");
add_veteran_achievement(game::LEVEL_INVASION, "RED_DAWN");
add_veteran_achievement(game::LEVEL_FAVELA_ESCAPE, "TURISTAS");
add_veteran_achievement(game::LEVEL_ARCADIA, "RED_DAWN");
add_veteran_achievement(game::LEVEL_OILRIG, "PRISONER_627");
add_veteran_achievement(game::LEVEL_GULAG, "PRISONER_627");
add_veteran_achievement(game::LEVEL_DCBURNING, "HOME_COMING");
add_veteran_achievement(game::LEVEL_CONTINGENCY, "ENDS_JUSTIFY_THE_MEANS");
add_veteran_achievement(game::LEVEL_DCEMP, "HOME_COMING");
add_veteran_achievement(game::LEVEL_DC_WHITEHOUSE, "HOME_COMING");
add_veteran_achievement(game::LEVEL_ESTATE, "QUEEN_TAKES_ROOK");
add_veteran_achievement(game::LEVEL_BONEYARD, "QUEEN_TAKES_ROOK");
add_veteran_achievement(game::LEVEL_AF_CAVES, "OFF_THE_GRID");
add_veteran_achievement(game::LEVEL_AF_CHASE, "OFF_THE_GRID");
add_veteran_achievement(game::LEVEL_ENDING, "OFF_THE_GRID");
give_veteran_achievements();
give_completed_campaign_achievement("THE_PRICE_OF_WAR");
write_achievements(&file);
}
} }
void get_achievements(achievement_file_t* file) void get_achievements(achievement_file_t* file)
@ -252,6 +373,8 @@ namespace achievements
{ {
utils::hook::jump(0x1404B6240, scr_give_achievement_stub); utils::hook::jump(0x1404B6240, scr_give_achievement_stub);
scheduler::once(give_mission_achievements, scheduler::main);
command::add("reset_achievements", [] command::add("reset_achievements", []
{ {
achievement_file_t file{}; achievement_file_t file{};

View File

@ -1728,6 +1728,63 @@ namespace game
static_assert(sizeof(physical_memory) == 0x530); static_assert(sizeof(physical_memory) == 0x530);
union GamerProfileDataUnion
{
unsigned __int8 byteVal;
bool boolVal;
__int16 shortVal;
int intVal;
float floatVal;
const char* stringVal;
};
enum level_number
{
LEVEL_TRAINER,
LEVEL_ROADKILL,
LEVEL_CLIFFHANGER,
LEVEL_AIRPORT,
LEVEL_FAVELA,
LEVEL_INVASION,
LEVEL_FAVELA_ESCAPE,
LEVEL_ARCADIA,
LEVEL_OILRIG,
LEVEL_GULAG,
LEVEL_DCBURNING,
LEVEL_CONTINGENCY,
LEVEL_DCEMP,
LEVEL_DC_WHITEHOUSE,
LEVEL_ESTATE,
LEVEL_BONEYARD,
LEVEL_AF_CAVES,
LEVEL_AF_CHASE,
LEVEL_ENDING,
LEVEL_COUNT,
};
enum GamerProfileDataType : __int32
{
TYPE_INVALID = 0x0,
TYPE_BYTE = 0x1,
TYPE_BOOL = 0x2,
TYPE_SHORT = 0x3,
TYPE_INT = 0x4,
TYPE_FLOAT = 0x5,
TYPE_STRING = 0x6,
TYPE_BUFFER = 0x7,
TYPE_FLAG = 0x8,
};
struct GamerProfileData
{
GamerProfileDataType type;
GamerProfileDataUnion u;
};
namespace hks namespace hks
{ {
struct lua_State; struct lua_State;