mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
740 lines
17 KiB
C++
740 lines
17 KiB
C++
// DR. ROBOTNIK'S RING RACERS
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 2024 by Vivian "toastergrl" Grannell.
|
|
// Copyright (C) 2024 by James Robert Roman.
|
|
// Copyright (C) 2024 by Kart Krew.
|
|
//
|
|
// This program is free software distributed under the
|
|
// terms of the GNU General Public License, version 2.
|
|
// See the 'LICENSE' file for more details.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include <algorithm>
|
|
#include <array>
|
|
#include <cctype>
|
|
#include <fstream>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
#include "modp_b64/modp_b64.h"
|
|
|
|
#include "cxxutil.hpp"
|
|
|
|
#include "command.h"
|
|
#include "d_main.h"
|
|
#include "doomdef.h"
|
|
#include "doomstat.h"
|
|
#include "doomtype.h"
|
|
#include "g_game.h"
|
|
#include "k_menu.h"
|
|
#include "m_cheat.h"
|
|
#include "m_cond.h"
|
|
#include "m_pw.h"
|
|
#include "m_pw_hash.h"
|
|
#include "s_sound.h"
|
|
#include "sounds.h"
|
|
#include "z_zone.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
constexpr const UINT8 kRRSalt[17] = "0L4rlK}{9ay6'VJS";
|
|
|
|
std::array<UINT8, M_PW_BUF_SIZE> decode_hash(std::string encoded)
|
|
{
|
|
std::array<UINT8, M_PW_BUF_SIZE> decoded;
|
|
if (modp::b64_decode(encoded).size() != decoded.size())
|
|
throw std::invalid_argument("hash is incorrectly sized");
|
|
std::copy(encoded.begin(), encoded.end(), decoded.begin());
|
|
return decoded;
|
|
}
|
|
|
|
struct Pw
|
|
{
|
|
Pw(void (*cb)(), const char *encoded_hash) : cb_(cb), hash_(decode_hash(encoded_hash)) {}
|
|
|
|
void (*cb_)();
|
|
const std::array<UINT8, M_PW_BUF_SIZE> hash_;
|
|
};
|
|
|
|
std::vector<Pw> passwords;
|
|
|
|
// m_cond.c
|
|
template <typename F>
|
|
void iter_conditions(F&& f)
|
|
{
|
|
UINT32 i, j;
|
|
conditionset_t *c;
|
|
condition_t *cn;
|
|
|
|
for (i = 0; i < MAXCONDITIONSETS; ++i)
|
|
{
|
|
c = &conditionSets[i];
|
|
|
|
if (!c->numconditions || gamedata->achieved[i])
|
|
continue;
|
|
|
|
for (j = 0; j < c->numconditions; ++j)
|
|
{
|
|
cn = &c->condition[j];
|
|
|
|
if (cn->type != UC_PASSWORD)
|
|
continue;
|
|
|
|
if (cn->stringvar == NULL)
|
|
continue;
|
|
|
|
f(cn);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// responders
|
|
//
|
|
|
|
void f_tournament()
|
|
{
|
|
UINT16 i;
|
|
boolean success = false;
|
|
|
|
/*if (modifiedgame)
|
|
return 0;*/
|
|
|
|
// Unlock EVERYTHING.
|
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
{
|
|
if (!unlockables[i].conditionset)
|
|
continue;
|
|
if (unlockables[i].conditionset == CH_FURYBIKE)
|
|
continue;
|
|
if (gamedata->unlocked[i])
|
|
continue;
|
|
|
|
gamedata->unlocked[i] = true;
|
|
success = true;
|
|
}
|
|
|
|
// Unlock all hidden levels.
|
|
#define GD_MV_SET (MV_VISITED|MV_BEATEN)
|
|
for (i = 0; i < nummapheaders; i++)
|
|
{
|
|
if ((mapheaderinfo[i]->records.mapvisited & GD_MV_SET) == GD_MV_SET)
|
|
continue;
|
|
if (mapheaderinfo[i]->typeoflevel & TOL_VERSUS)
|
|
continue;
|
|
if (!strcmp(mapheaderinfo[i]->lumpname, "RR_HIDDENPALACE"))
|
|
continue;
|
|
mapheaderinfo[i]->records.mapvisited |= GD_MV_SET;
|
|
success = true;
|
|
}
|
|
#undef GD_MV_SET
|
|
|
|
// Goofy, but this call needs to be before M_ClearMenus because that path
|
|
// calls G_LoadLevel, which will trigger a gamedata save. Garbage factory
|
|
if (success)
|
|
{
|
|
gamedata->gonerlevel = GDGONER_DONE;
|
|
gamedata->sealedswapalerted = true;
|
|
G_SetUsedCheats();
|
|
}
|
|
|
|
M_ClearMenus(true);
|
|
|
|
const char *text;
|
|
|
|
if (success)
|
|
{
|
|
S_StartSound(0, sfx_kc42);
|
|
|
|
text = M_GetText(
|
|
"Unlocked\x83 almost\x80 everything.\n"
|
|
"Saving is disabled - the game will\n"
|
|
"return to normal on next launch.\n"
|
|
);
|
|
|
|
usedTourney = true;
|
|
}
|
|
else
|
|
{
|
|
S_StartSound(0, sfx_s3k7b);
|
|
|
|
if (usedCheats)
|
|
{
|
|
text = M_GetText(
|
|
"This is the correct password,\n"
|
|
"but there's nothing to unlock\n"
|
|
"right now -- nothing has changed.\n"
|
|
);
|
|
}
|
|
else
|
|
{
|
|
text = M_GetText(
|
|
"This is the correct password, but\n"
|
|
"there's nothing to unlock right\n"
|
|
"now, so saving is still allowed!\n"
|
|
);
|
|
|
|
usedTourney = true;
|
|
}
|
|
}
|
|
|
|
M_StartMessage("Tournament Mode", text, NULL, MM_NOTHING, NULL, NULL);
|
|
}
|
|
|
|
void f_bighead()
|
|
{
|
|
CV_SetValue(&cv_bighead, !cv_bighead.value);
|
|
if (cv_bighead.value)
|
|
{
|
|
S_StartSound(NULL, sfx_gshbb);
|
|
}
|
|
else
|
|
{
|
|
S_StartSound(NULL, sfx_kc46);
|
|
}
|
|
}
|
|
|
|
void f_shittysigns()
|
|
{
|
|
CV_SetValue(&cv_shittysigns, !cv_shittysigns.value);
|
|
if (cv_shittysigns.value)
|
|
{
|
|
S_StartSound(NULL, sfx_mixup);
|
|
}
|
|
else
|
|
{
|
|
S_StartSound(NULL, sfx_nghurt);
|
|
}
|
|
}
|
|
|
|
void f_tastelesstaunts()
|
|
{
|
|
CV_SetValue(&cv_tastelesstaunts, !cv_tastelesstaunts.value);
|
|
if (cv_tastelesstaunts.value)
|
|
{
|
|
S_StartSound(NULL, sfx_d4getm);
|
|
}
|
|
else
|
|
{
|
|
S_StartSound(NULL, sfx_kc46);
|
|
}
|
|
}
|
|
|
|
void f_4thgear()
|
|
{
|
|
CV_SetValue(&cv_4thgear, !cv_4thgear.value);
|
|
if (cv_4thgear.value)
|
|
{
|
|
M_StartMessage("Restraint device compromised!", "Local play sped up to ""\x85""4th Gear!""\x80""\nLet's see what you're made of!\n\n""\x86""No effect in netplay and attack modes.", NULL, MM_NOTHING, NULL, NULL);
|
|
S_StartSound(NULL, sfx_gshc4);
|
|
}
|
|
else
|
|
{
|
|
S_StartSound(NULL, sfx_kc46);
|
|
}
|
|
}
|
|
|
|
void f_colors()
|
|
{
|
|
UINT16 i;
|
|
boolean success = false;
|
|
|
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
{
|
|
if (!unlockables[i].conditionset)
|
|
continue;
|
|
if (unlockables[i].conditionset == CH_FURYBIKE)
|
|
continue;
|
|
if (gamedata->unlocked[i])
|
|
continue;
|
|
if (unlockables[i].type != SECRET_COLOR)
|
|
continue;
|
|
|
|
gamedata->unlocked[i] = true;
|
|
success = true;
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
S_StartSound(0, sfx_kc42);
|
|
M_StartMessage("Time for a new look!", "Unlocked all colors. Try not to show off!", NULL, MM_NOTHING, NULL, NULL);
|
|
G_SaveGameData();
|
|
}
|
|
else
|
|
{
|
|
M_StartMessage("Time for a new look!", "You've already unlocked all colors.", NULL, MM_NOTHING, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
void f_followers()
|
|
{
|
|
UINT16 i;
|
|
boolean success = false;
|
|
|
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
{
|
|
if (!unlockables[i].conditionset)
|
|
continue;
|
|
if (unlockables[i].conditionset == CH_FURYBIKE)
|
|
continue;
|
|
if (gamedata->unlocked[i])
|
|
continue;
|
|
if (unlockables[i].type != SECRET_FOLLOWER)
|
|
continue;
|
|
|
|
gamedata->unlocked[i] = true;
|
|
success = true;
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
S_StartSound(0, sfx_kc42);
|
|
M_StartMessage("Creatures captured!", "Unlocked all followers. Who's your favorite?", NULL, MM_NOTHING, NULL, NULL);
|
|
G_SaveGameData();
|
|
}
|
|
else
|
|
{
|
|
M_StartMessage("Creatures captured!", "You've already unlocked all followers.", NULL, MM_NOTHING, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
void f_maps()
|
|
{
|
|
UINT16 i;
|
|
boolean success = false;
|
|
|
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
{
|
|
if (!unlockables[i].conditionset)
|
|
continue;
|
|
if (unlockables[i].conditionset == CH_FURYBIKE)
|
|
continue;
|
|
if (gamedata->unlocked[i])
|
|
continue;
|
|
if (unlockables[i].type != SECRET_MAP && unlockables[i].type != SECRET_CUP)
|
|
continue;
|
|
|
|
gamedata->unlocked[i] = true;
|
|
success = true;
|
|
}
|
|
|
|
#define GD_MV_SET (MV_VISITED|MV_BEATEN)
|
|
for (i = 0; i < nummapheaders; i++)
|
|
{
|
|
if ((mapheaderinfo[i]->records.mapvisited & GD_MV_SET) == GD_MV_SET)
|
|
continue;
|
|
if (mapheaderinfo[i]->typeoflevel & TOL_VERSUS)
|
|
continue;
|
|
if (!strcmp(mapheaderinfo[i]->lumpname, "RR_HIDDENPALACE"))
|
|
continue;
|
|
mapheaderinfo[i]->records.mapvisited |= GD_MV_SET;
|
|
success = true;
|
|
}
|
|
#undef GD_MV_SET
|
|
|
|
if (success)
|
|
{
|
|
S_StartSound(0, sfx_kc42);
|
|
M_StartMessage("// FIXME don't crash in certification test", "Unlocked most maps. Go see the world!", NULL, MM_NOTHING, NULL, NULL);
|
|
G_SaveGameData();
|
|
}
|
|
else
|
|
{
|
|
M_StartMessage("// FIXME don't crash in certification test", "There are no maps to unlock.", NULL, MM_NOTHING, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
void f_characters()
|
|
{
|
|
UINT16 i;
|
|
boolean success = false;
|
|
|
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
{
|
|
if (!unlockables[i].conditionset)
|
|
continue;
|
|
if (unlockables[i].conditionset == CH_FURYBIKE)
|
|
continue;
|
|
if (gamedata->unlocked[i])
|
|
continue;
|
|
if (unlockables[i].type != SECRET_SKIN)
|
|
continue;
|
|
|
|
gamedata->unlocked[i] = true;
|
|
success = true;
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
S_StartSound(0, sfx_kc42);
|
|
M_StartMessage("...Is that how you spell it?", "Unlocked most characters. All together now!", NULL, MM_NOTHING, NULL, NULL);
|
|
G_SaveGameData();
|
|
}
|
|
else
|
|
{
|
|
M_StartMessage("...Is that how you spell it?", "There are no characters to unlock!", NULL, MM_NOTHING, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
void f_altmusic()
|
|
{
|
|
UINT16 i;
|
|
boolean success = false;
|
|
|
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
{
|
|
if (!unlockables[i].conditionset)
|
|
continue;
|
|
if (unlockables[i].conditionset == CH_FURYBIKE)
|
|
continue;
|
|
if (gamedata->unlocked[i])
|
|
continue;
|
|
if (unlockables[i].type != SECRET_ALTMUSIC && unlockables[i].type != SECRET_SOUNDTEST)
|
|
continue;
|
|
|
|
gamedata->unlocked[i] = true;
|
|
success = true;
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
S_StartSound(0, sfx_kc42);
|
|
M_StartMessage("Wanna listen to some tunes?", "Unlocked all alternate music -- and Stereo Mode!", NULL, MM_NOTHING, NULL, NULL);
|
|
G_SaveGameData();
|
|
}
|
|
else
|
|
{
|
|
M_StartMessage("Wanna listen to some tunes?", "You've already unlocked all music!", NULL, MM_NOTHING, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
void f_timeattack()
|
|
{
|
|
UINT16 i;
|
|
boolean success = false;
|
|
boolean already_have_encore = M_SecretUnlocked(SECRET_ENCORE, true);
|
|
|
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
{
|
|
if (!unlockables[i].conditionset)
|
|
continue;
|
|
if (unlockables[i].conditionset == CH_FURYBIKE)
|
|
continue;
|
|
if (gamedata->unlocked[i])
|
|
continue;
|
|
|
|
if (unlockables[i].type == SECRET_TIMEATTACK
|
|
|| unlockables[i].type == SECRET_PRISONBREAK
|
|
|| unlockables[i].type == SECRET_SPECIALATTACK
|
|
|| (unlockables[i].type == SECRET_SPBATTACK && already_have_encore))
|
|
{
|
|
gamedata->unlocked[i] = true;
|
|
success = true;
|
|
}
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
S_StartSound(0, sfx_kc42);
|
|
if (already_have_encore)
|
|
{
|
|
M_StartMessage("Time Trial ON, OK!", "Unlocked all Time Attack modes -- including SPB Attack!", NULL, MM_NOTHING, NULL, NULL);
|
|
}
|
|
else
|
|
{
|
|
M_StartMessage("Time Trial ON, OK!", "Unlocked all Time Attack modes!", NULL, MM_NOTHING, NULL, NULL);
|
|
}
|
|
G_SaveGameData();
|
|
}
|
|
else
|
|
{
|
|
M_StartMessage("Time Trial ON, OK!", "You already have all Time Attack modes.", NULL, MM_NOTHING, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
void f_encore()
|
|
{
|
|
UINT16 i;
|
|
boolean success = false;
|
|
boolean already_have_timeattacks = (
|
|
M_SecretUnlocked(SECRET_TIMEATTACK, true)
|
|
&& M_SecretUnlocked(SECRET_PRISONBREAK, true)
|
|
&& M_SecretUnlocked(SECRET_SPECIALATTACK, true)
|
|
);
|
|
|
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
{
|
|
if (!unlockables[i].conditionset)
|
|
continue;
|
|
if (unlockables[i].conditionset == CH_FURYBIKE)
|
|
continue;
|
|
if (gamedata->unlocked[i])
|
|
continue;
|
|
|
|
if (unlockables[i].type == SECRET_ENCORE
|
|
|| (unlockables[i].type == SECRET_SPBATTACK && already_have_timeattacks))
|
|
{
|
|
gamedata->unlocked[i] = true;
|
|
success = true;
|
|
}
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
S_StartSound(0, sfx_kc42);
|
|
if (already_have_timeattacks)
|
|
{
|
|
M_StartMessage("And turn it all around!", "Unlocked Encore Mode -- and SPB Attack!", NULL, MM_NOTHING, NULL, NULL);
|
|
}
|
|
else
|
|
{
|
|
M_StartMessage("And turn it all around!", "Unlocked Encore Mode!", NULL, MM_NOTHING, NULL, NULL);
|
|
}
|
|
G_SaveGameData();
|
|
}
|
|
else
|
|
{
|
|
M_StartMessage("And turn it all around!", "You already have Encore Mode.", NULL, MM_NOTHING, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
void f_difficulty()
|
|
{
|
|
UINT16 i;
|
|
boolean success = false;
|
|
|
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
{
|
|
if (!unlockables[i].conditionset)
|
|
continue;
|
|
if (unlockables[i].conditionset == CH_FURYBIKE)
|
|
continue;
|
|
if (gamedata->unlocked[i])
|
|
continue;
|
|
|
|
if (unlockables[i].type == SECRET_HARDSPEED || unlockables[i].type == SECRET_MASTERMODE)
|
|
{
|
|
gamedata->unlocked[i] = true;
|
|
success = true;
|
|
}
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
S_StartSound(0, sfx_kc42);
|
|
M_StartMessage("TWO SPEEDS,", "All Gear speeds unlocked!", NULL, MM_NOTHING, NULL, NULL);
|
|
G_SaveGameData();
|
|
}
|
|
else
|
|
{
|
|
M_StartMessage("TWO SPEEDS,", "You already have all Gear speeds.", NULL, MM_NOTHING, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
void f_devmode()
|
|
{
|
|
INT32 i;
|
|
|
|
if (modifiedgame)
|
|
return;
|
|
|
|
// Just unlock all the things and turn on -debug and console devmode.
|
|
for (i = 0; i < MAXUNLOCKABLES; i++)
|
|
{
|
|
if (!unlockables[i].conditionset)
|
|
continue;
|
|
gamedata->unlocked[i] = true;
|
|
}
|
|
|
|
// Unlock all hidden levels.
|
|
for (i = 0; i < nummapheaders; i++)
|
|
{
|
|
mapheaderinfo[i]->records.mapvisited = MV_MAX;
|
|
}
|
|
|
|
gamedata->gonerlevel = GDGONER_DONE;
|
|
gamedata->sealedswapalerted = true;
|
|
|
|
M_ClearMenus(true);
|
|
|
|
// This is a developer feature, you know how to delete ringdata
|
|
// G_SetUsedCheats();
|
|
S_StartSound(0, sfx_kc42);
|
|
|
|
devparm = true;
|
|
cht_debug |= 0x8000;
|
|
|
|
G_SaveGameData();
|
|
}
|
|
|
|
void f_proceed()
|
|
{
|
|
gamedata->gonerlevel = GDGONER_DONE;
|
|
gamedata->finishedtutorialchallenge = true;
|
|
M_UpdateUnlockablesAndExtraEmblems(true, true);
|
|
|
|
M_ClearMenus(true);
|
|
S_StartSound(0, sfx_kc42);
|
|
|
|
G_SaveGameData();
|
|
}
|
|
|
|
}; // namespace
|
|
|
|
try_password_e M_TryPassword(const char *password, boolean conditions)
|
|
{
|
|
using var = std::variant<std::monostate, condition_t*, Pw*>;
|
|
|
|
// Normalize input casing
|
|
std::string key = password;
|
|
strlwr(key.data());
|
|
|
|
UINT8 key_hash[M_PW_HASH_SIZE];
|
|
M_HashPassword(key_hash, key.c_str(), kRRSalt);
|
|
|
|
auto worker = [key_hash](const UINT8* hash, var result)
|
|
{
|
|
if (memcmp(key_hash, hash, M_PW_HASH_SIZE))
|
|
result = std::monostate {}; // fail state
|
|
return result;
|
|
};
|
|
|
|
var result;
|
|
auto add_job = [&](auto&&... args)
|
|
{
|
|
if (var n = worker(args...); !std::holds_alternative<std::monostate>(n))
|
|
result = n;
|
|
};
|
|
|
|
for (Pw& pw : passwords)
|
|
add_job(pw.hash_.data(), &pw);
|
|
|
|
// Only consider challenges passwords as needed.
|
|
if (conditions && !usedTourney)
|
|
iter_conditions([&](condition_t* cn) { add_job((const UINT8*)cn->stringvar, cn); });
|
|
|
|
try_password_e return_code = M_PW_INVALID;
|
|
if (!std::holds_alternative<std::monostate>(result))
|
|
{
|
|
// Evaluate the password's function.
|
|
auto visitor = srb2::Overload {
|
|
[&](condition_t* cn)
|
|
{
|
|
// Remove the password for this session.
|
|
Z_Free(cn->stringvar);
|
|
cn->stringvar = NULL;
|
|
return_code = M_PW_CHALLENGES;
|
|
},
|
|
[&](Pw* pw)
|
|
{
|
|
pw->cb_();
|
|
return_code = M_PW_EXTRAS;
|
|
},
|
|
[](std::monostate) {},
|
|
};
|
|
std::visit(visitor, result);
|
|
}
|
|
|
|
return return_code;
|
|
}
|
|
|
|
boolean M_TryExactPassword(const char *password, const char *encodedhash)
|
|
{
|
|
// Normalize input casing
|
|
std::string key = password;
|
|
strlwr(key.data());
|
|
|
|
UINT8 key_hash[M_PW_HASH_SIZE];
|
|
M_HashPassword(key_hash, key.c_str(), kRRSalt);
|
|
|
|
auto hash = decode_hash(encodedhash);
|
|
|
|
return (memcmp(key_hash, hash.data(), M_PW_HASH_SIZE) == 0);
|
|
}
|
|
|
|
#ifdef DEVELOP
|
|
void Command_Crypt_f(void)
|
|
{
|
|
if (COM_Argc() == 1)
|
|
{
|
|
CONS_Printf(
|
|
"crypt <password>: generate a password hash\n"
|
|
"crypt -i <file>: generate multiple hashes by reading from file\n"
|
|
);
|
|
return;
|
|
}
|
|
|
|
auto gen = [](char *input)
|
|
{
|
|
UINT8 bin[M_PW_BUF_SIZE];
|
|
strlwr(input);
|
|
M_HashPassword(bin, input, kRRSalt);
|
|
CONS_Printf("%s %s\n", input, modp::b64_encode((const char*)bin, M_PW_BUF_SIZE).c_str());
|
|
};
|
|
|
|
if (!stricmp(COM_Argv(1), "-i"))
|
|
{
|
|
if (COM_Argc() != 3)
|
|
{
|
|
CONS_Printf("crypt: missing file argument\n");
|
|
return;
|
|
}
|
|
|
|
std::ifstream file{va(pandf, srb2home, COM_Argv(2))};
|
|
if (!file.is_open())
|
|
{
|
|
CONS_Printf("crypt: file error\n");
|
|
return;
|
|
}
|
|
|
|
for (std::string line; std::getline(file, line);)
|
|
{
|
|
// remove comments
|
|
std::size_t p = line.find("#");
|
|
if (p == line.npos)
|
|
p = line.size();
|
|
|
|
// remove trailing whitespace
|
|
while (p > 0 && std::isspace(line[p - 1]))
|
|
p--;
|
|
|
|
line.erase(p);
|
|
|
|
// ignore empty or completely filtered lines
|
|
if (!line.empty())
|
|
gen(line.data());
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
gen(COM_Args());
|
|
}
|
|
#endif
|
|
|
|
void M_PasswordInit(void)
|
|
{
|
|
passwords.emplace_back(f_tournament, "dSZpCST31Tu3rPJ4z18iR9Tcv+9Xi8/f7nQGplj2mvruy2A4CJJqZm1gzi6CQKl68pRXiNGUX0n4BI2LjaBcoA==");
|
|
// Tee hee.
|
|
passwords.emplace_back([] { M_WrongWarp(0); }, "WAJJ66pw2rSopXOuw4c4iKzIz3goKtivrv7b/THqYP8ev+E/sRn2LMXHqv8s+uzwMcVNoDxNn+AgG26xi+wgzg==");
|
|
passwords.emplace_back([] { M_GonerGDQ(true); }, "B287p2gJUgmUikAABl1ndG/3r0zqdIMvsMDzBrypwo78BR58S9Whu+Doma00oV+DySTalWYi1VyTs/5GWzgFEg==");
|
|
passwords.emplace_back([] { M_GonerGDQ(false); }, "1yO8FCDe0PhtgrQt0IQ4TPPfggSOnf4NiRaT86gnj4/PxMbyi4vXl4F4zpm/Xhf2oSStuhr+n7Qv2tcqv6lzaA==");
|
|
passwords.emplace_back(f_bighead, "V+YkwthNUePKS7zs5uB90VwN6Jeqgl+1r663U5zSGOEIxAO6BoWipzZoxa5H//LM+5Ag9GIGRnEcLbU21hjGfQ==");
|
|
passwords.emplace_back(f_4thgear, "zRMhR+s27VTYE0jgFf2l+PX51N3qJPvZ3oWuM/71oUaKY5zyQ2y7WIrIb464MFWn4IsK2P5rShsR9MotC/9ojQ==");
|
|
passwords.emplace_back(f_shittysigns, "yd02TPSLRgBydXlkZaEJABqegGjfJfn1aIMODfc2CC5ymJ4ydG7FblW20CH6vbo1IB1X9eBKJShuunPBClnWOQ==");
|
|
passwords.emplace_back(f_tastelesstaunts, "4QfCuCG0/7z5U5A1hxqlqx83uQTGmQ1aaWPBQ8pqQvw9KRGvxxiDq9UF0N24fDlu0+XYksgkPHJg4A5h5aEQiw==");
|
|
passwords.emplace_back(f_devmode, "ybYqLUlREa9TJqV0uftxqGL8jPR1U+uEgrff/jast0kCfeIdzY15VxjveSZho8GOjfRuC3Zt4aJQTvhJcPAhkw==");
|
|
passwords.emplace_back(f_proceed, "GZPKJsa++Tt134yS3eBKdP+8vdAHB1thwK2ys6VDfFxcIRtABtM9j4qt8WULFrI+KxCSYMZ6K0mwt5BVzcvvuw==");
|
|
passwords.emplace_back(f_colors, "aSk8dw6FzJtTEmovh8fVEtUBpu6lj3QlRT/B5lwiEhAw8dAhRBQLdvtYlPaQcZISWI4wneAfAo6w5d6uf5r++g==");
|
|
passwords.emplace_back(f_followers, "zYCIZw2qcnUbtF0P2ybLNHajdl8zrje0hzGex7yuMFe7fj4mvx4AegoMmvir28YvAbfAqkz/ekQRzr+RhrycHw==");
|
|
passwords.emplace_back(f_maps, "u/Svaf+DCnCpJ8xmP3AVP4CK6X6X4O3fY73cmIq88ZJEygwz+n+L66q4Vhlv13vWgld1PEyRszFErzflQt9WZw==");
|
|
passwords.emplace_back(f_characters, "MohmPqpaGSd3MEHLfQKUFl/Yg8pHE+12X1LHEP59Gs/5w1u8mPtGUXNv1GYTF+c8gQqT5hXpZ3FeZ/EfCxo34g==");
|
|
passwords.emplace_back(f_altmusic, "dZgxKNagOtB9F7wXqUUPzsuq4tfQlfK8ZqEeFXdI3Hd+k5tYfRm3ToLgbqawaNmwuLVrJ8PB+QnH4gT3ojnTMw==");
|
|
passwords.emplace_back(f_timeattack, "mFu5OB9d6jnc2kth7HE66wJ42F/GHDzSvuciK1Qw++6iGnpBccxcKjpoxgOvD3eIoqR606ruBINuXi23proXHQ==");
|
|
passwords.emplace_back(f_encore, "i5u5sIsMs5eITy+LzAXvKm6D9OzOVKhUqSy1mTTV/oUxJX6RPsk8OcyLbNaey9Vc6wXOhz+2+mTXILkIRzvXqA==");
|
|
passwords.emplace_back(f_difficulty, "MKjOtEFLkgXf21uiECdBTU6XtbkuFWaGh7i8znKo7JrXXEDrCBJmGwINvPg0T3TLn0zlscLvmC5nve7I+NTrnA==");
|
|
}
|