mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-01-07 23:42:40 +00:00
Merge branch 'auto-medal-times' into 'master'
Add automedal time configs and calculation Closes #790 See merge request KartKrew/Kart!1777
This commit is contained in:
commit
0f468c4634
11 changed files with 202 additions and 37 deletions
|
|
@ -4920,6 +4920,72 @@ static void Command_cxdiag_f(void)
|
|||
}
|
||||
}
|
||||
|
||||
{
|
||||
CONS_Printf("\x82""Evaluating Time Medals...\n");
|
||||
|
||||
for (i = 0; i < numemblems; i++)
|
||||
{
|
||||
if (emblemlocations[i].type != ET_TIME)
|
||||
continue;
|
||||
|
||||
INT32 checkLevel = M_EmblemMapNum(&emblemlocations[i]);
|
||||
|
||||
if (checkLevel >= nummapheaders || !mapheaderinfo[checkLevel])
|
||||
continue;
|
||||
|
||||
if (emblemlocations[i].tag > 0)
|
||||
{
|
||||
if (emblemlocations[i].tag > mapheaderinfo[checkLevel]->ghostCount)
|
||||
{
|
||||
CONS_Printf("\x87"" Time Medal %u (level %s) has tag %d, which is greater than the number of associated Staff Ghosts (%u)\n", i+1, mapheaderinfo[checkLevel]->lumpname, emblemlocations[i].tag, mapheaderinfo[checkLevel]->ghostCount);
|
||||
errors++;
|
||||
}
|
||||
}
|
||||
else switch (emblemlocations[i].tag)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (emblemlocations[i].var < TICRATE)
|
||||
{
|
||||
CONS_Printf("\x87"" Time Medal %u (level %s) is set to %d (less than a second??)\n", i+1, mapheaderinfo[checkLevel]->lumpname, emblemlocations[i].var);
|
||||
errors++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AUTOMEDAL_PLATINUM:
|
||||
{
|
||||
if (mapheaderinfo[checkLevel]->ghostCount == 0)
|
||||
{
|
||||
CONS_Printf("\x87"" Time Medal %u (level %s) is AUTOMEDAL_PLATINUM, but there are no associated Staff Ghosts\n", i+1, mapheaderinfo[checkLevel]->lumpname);
|
||||
errors++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case AUTOMEDAL_GOLD:
|
||||
case AUTOMEDAL_SILVER:
|
||||
case AUTOMEDAL_BRONZE:
|
||||
{
|
||||
if (mapheaderinfo[checkLevel]->ghostCount < 2)
|
||||
{
|
||||
CONS_Printf("\x87"" Time Medal %u (level %s) is an Auto Medal, but there are %u associated Staff Ghosts, which is less than the 2 recommended minimum\n", i+1, mapheaderinfo[checkLevel]->lumpname, mapheaderinfo[checkLevel]->ghostCount);
|
||||
errors++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
CONS_Printf("\x87"" Time Medal %u (level %s) has invalid tag (%d)\n", i+1, mapheaderinfo[checkLevel]->lumpname, emblemlocations[i].tag);
|
||||
errors++;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errors)
|
||||
CONS_Printf("\x85""%u errors detected.\n", errors);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -2279,7 +2279,7 @@ void reademblemdata(MYFILE *f, INT32 num)
|
|||
emblemlocations[num-1].type = (UINT8)value;
|
||||
}
|
||||
else if (fastcmp(word, "TAG"))
|
||||
emblemlocations[num-1].tag = (INT16)value;
|
||||
emblemlocations[num-1].tag = get_number(word2);
|
||||
else if (fastcmp(word, "MAPNAME"))
|
||||
{
|
||||
emblemlocations[num-1].level = Z_StrDup(word2);
|
||||
|
|
|
|||
|
|
@ -6916,6 +6916,12 @@ struct int_const_s const INT_CONST[] = {
|
|||
{"ME_ENCORE",ME_ENCORE},
|
||||
{"ME_SPBATTACK",ME_SPBATTACK},
|
||||
|
||||
// Automedal SOC tags
|
||||
{"AUTOMEDAL_BRONZE",AUTOMEDAL_BRONZE},
|
||||
{"AUTOMEDAL_SILVER",AUTOMEDAL_SILVER},
|
||||
{"AUTOMEDAL_GOLD",AUTOMEDAL_GOLD},
|
||||
{"AUTOMEDAL_PLATINUM",AUTOMEDAL_PLATINUM},
|
||||
|
||||
// p_local.h constants
|
||||
{"FLOATSPEED",FLOATSPEED},
|
||||
{"MAXSTEPMOVE",MAXSTEPMOVE},
|
||||
|
|
|
|||
|
|
@ -252,32 +252,6 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
|
|||
else
|
||||
i = 0;
|
||||
|
||||
if (fastcmp(word, "EMBLEM"))
|
||||
{
|
||||
if (!mainfile && !gamedataadded)
|
||||
{
|
||||
deh_warning("You must define a custom gamedata to use \"%s\"", word);
|
||||
ignorelines(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!word2)
|
||||
i = numemblems + 1;
|
||||
|
||||
if (i > 0 && i <= MAXEMBLEMS)
|
||||
{
|
||||
if (numemblems < i)
|
||||
numemblems = i;
|
||||
reademblemdata(f, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
deh_warning("Emblem number %d out of range (1 - %d)", i, MAXEMBLEMS);
|
||||
ignorelines(f);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (word2)
|
||||
{
|
||||
if (fastcmp(word, "THING") || fastcmp(word, "MOBJ") || fastcmp(word, "OBJECT"))
|
||||
|
|
@ -430,6 +404,28 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
|
|||
ignorelines(f);
|
||||
}
|
||||
}
|
||||
else if (fastcmp(word, "EMBLEM"))
|
||||
{
|
||||
if (!mainfile && !gamedataadded)
|
||||
{
|
||||
deh_warning("You must define a custom gamedata to use \"%s\"", word);
|
||||
ignorelines(f);
|
||||
}
|
||||
else if (i > 0 && i <= MAXEMBLEMS)
|
||||
{
|
||||
if (numemblems < i)
|
||||
{
|
||||
// This is no longer strictly necessary... but I've left it in as an optimisation, because the datatype is now immensohuge, heh.
|
||||
numemblems = i;
|
||||
}
|
||||
reademblemdata(f, i);
|
||||
}
|
||||
else
|
||||
{
|
||||
deh_warning("Emblem number %d out of range (1 - %d)", i, MAXEMBLEMS);
|
||||
ignorelines(f);
|
||||
}
|
||||
}
|
||||
else if (fastcmp(word, "UNLOCKABLE"))
|
||||
{
|
||||
if (!mainfile && !gamedataadded)
|
||||
|
|
|
|||
|
|
@ -483,6 +483,7 @@ struct mapheader_t
|
|||
UINT8 ghostCount; ///< Count of valid staff ghosts
|
||||
UINT32 ghostBriefSize; ///< Size of ghostBrief vector allocation
|
||||
staffbrief_t **ghostBrief; ///< Valid staff ghosts, pointers are owned
|
||||
tic_t automedaltime[4]; ///< Auto Medal times derived from ghost times, best to worst
|
||||
|
||||
recorddata_t records; ///< Stores completion/record attack data
|
||||
|
||||
|
|
|
|||
14
src/g_game.c
14
src/g_game.c
|
|
@ -482,8 +482,16 @@ bademblem:
|
|||
else
|
||||
stickermedalinfo.timetoreach = mapheaderinfo[map]->ghostBrief[emblem->tag-1]->time;
|
||||
}
|
||||
else if (emblem->tag < 0 && emblem->tag > AUTOMEDAL_MAX)
|
||||
{
|
||||
// Use auto medal times for emblem tags, see AUTOMEDAL_ in m_cond.h
|
||||
int index = -emblem->tag - 1; // 0 is Platinum, 3 is Bronze
|
||||
stickermedalinfo.timetoreach = mapheaderinfo[map]->automedaltime[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
stickermedalinfo.timetoreach = emblem->var;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4559,7 +4567,7 @@ void G_LoadGameSettings(void)
|
|||
}
|
||||
|
||||
#define GD_VERSIONCHECK 0xBA5ED123 // Change every major version, as usual
|
||||
#define GD_VERSIONMINOR 9 // Change every format update
|
||||
#define GD_VERSIONMINOR 10 // Change every format update
|
||||
|
||||
// You can't rearrange these without a special format update
|
||||
typedef enum
|
||||
|
|
@ -4765,6 +4773,10 @@ void G_LoadGameData(void)
|
|||
unlockreadcount = conditionreadcount = UINT8_MAX;
|
||||
unlockreadsize = sizeof(UINT8);
|
||||
}
|
||||
else if (versionMinor < 10)
|
||||
{
|
||||
emblemreadcount = 1024*2;
|
||||
}
|
||||
|
||||
// To save space, use one bit per collected/achieved/unlocked flag
|
||||
for (i = 0; i < emblemreadcount;)
|
||||
|
|
|
|||
|
|
@ -212,7 +212,7 @@ void G_UseContinue(void);
|
|||
void G_AfterIntermission(void);
|
||||
void G_EndGame(void); // moved from y_inter.c/h and renamed
|
||||
|
||||
#define MAXMEDALVISIBLECOUNT 3
|
||||
#define MAXMEDALVISIBLECOUNT 4
|
||||
extern struct stickermedalinfo
|
||||
{
|
||||
UINT8 visiblecount;
|
||||
|
|
|
|||
19
src/m_cond.c
19
src/m_cond.c
|
|
@ -45,7 +45,7 @@ emblem_t emblemlocations[MAXEMBLEMS];
|
|||
// Unlockables
|
||||
unlockable_t unlockables[MAXUNLOCKABLES];
|
||||
|
||||
// Number of emblems
|
||||
// Highest used emblem ID
|
||||
INT32 numemblems = 0;
|
||||
|
||||
// The challenge that will truly let the games begin.
|
||||
|
|
@ -2271,7 +2271,7 @@ static const char *M_GetConditionString(condition_t *cn)
|
|||
i = cn->requirement-1;
|
||||
checkLevel = M_EmblemMapNum(&emblemlocations[i]);
|
||||
|
||||
if (checkLevel >= nummapheaders || !mapheaderinfo[checkLevel])
|
||||
if (checkLevel >= nummapheaders || !mapheaderinfo[checkLevel] || emblemlocations[i].type == ET_NONE)
|
||||
return va("INVALID MEDAL MAP \"%d:%d\"", cn->requirement, checkLevel);
|
||||
|
||||
title = M_BuildConditionTitle(checkLevel);
|
||||
|
|
@ -3160,6 +3160,14 @@ UINT16 M_CheckLevelEmblems(void)
|
|||
|
||||
res = (G_GetBestTime(levelnum) <= mapheaderinfo[checkLevel]->ghostBrief[tag-1]->time);
|
||||
}
|
||||
else if (tag < 0 && tag > AUTOMEDAL_MAX)
|
||||
{
|
||||
// Use auto medal times for emblem tags, see AUTOMEDAL_ in m_cond.h
|
||||
int index = -tag - 1; // 0 is Platinum, 3 is Bronze
|
||||
tic_t time = mapheaderinfo[checkLevel]->automedaltime[index];
|
||||
|
||||
res = (G_GetBestTime(levelnum) <= time);
|
||||
}
|
||||
else
|
||||
{
|
||||
res = (G_GetBestTime(levelnum) <= (unsigned)valToReach);
|
||||
|
|
@ -3394,6 +3402,8 @@ INT32 M_CountMedals(boolean all, boolean extraonly)
|
|||
{
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
{
|
||||
if (emblemlocations[i].type == ET_NONE)
|
||||
continue;
|
||||
if ((emblemlocations[i].type == ET_GLOBAL)
|
||||
&& (emblemlocations[i].flags & GE_NOTMEDAL))
|
||||
continue;
|
||||
|
|
@ -3424,6 +3434,8 @@ boolean M_GotEnoughMedals(INT32 number)
|
|||
INT32 i, gottenmedals = 0;
|
||||
for (i = 0; i < numemblems; ++i)
|
||||
{
|
||||
if (emblemlocations[i].type == ET_NONE)
|
||||
continue;
|
||||
if (!gamedata->collected[i])
|
||||
continue;
|
||||
if (++gottenmedals < number)
|
||||
|
|
@ -3693,6 +3705,9 @@ emblem_t *M_GetLevelEmblems(INT32 mapnum)
|
|||
|
||||
while (--i >= 0)
|
||||
{
|
||||
if (emblemlocations[i].type == ET_NONE)
|
||||
continue;
|
||||
|
||||
INT32 checkLevel = M_EmblemMapNum(&emblemlocations[i]);
|
||||
|
||||
if (checkLevel >= nummapheaders || !mapheaderinfo[checkLevel])
|
||||
|
|
|
|||
17
src/m_cond.h
17
src/m_cond.h
|
|
@ -171,10 +171,10 @@ struct conditionset_t
|
|||
};
|
||||
|
||||
// Emblem information
|
||||
#define ET_GLOBAL 0 // Emblem with a position in space
|
||||
#define ET_MAP 1 // Beat the map
|
||||
#define ET_TIME 2 // Get the time
|
||||
//#define ET_DEVTIME 3 // Time, but the value is tied to a Time Trial demo, not pre-defined
|
||||
#define ET_NONE 0 // Empty slot
|
||||
#define ET_GLOBAL 1 // Emblem with a position in space
|
||||
#define ET_MAP 2 // Beat the map
|
||||
#define ET_TIME 3 // Get the time
|
||||
|
||||
// Global emblem flags
|
||||
#define GE_NOTMEDAL 1 // Doesn't count towards number of medals
|
||||
|
|
@ -185,6 +185,13 @@ struct conditionset_t
|
|||
#define ME_ENCORE 1 // Achieve in Encore
|
||||
#define ME_SPBATTACK 2 // Achieve in SPB Attack
|
||||
|
||||
// Automedal SOC tags
|
||||
#define AUTOMEDAL_MAX -5 // just in case any more are ever added
|
||||
#define AUTOMEDAL_BRONZE -4
|
||||
#define AUTOMEDAL_SILVER -3
|
||||
#define AUTOMEDAL_GOLD -2
|
||||
#define AUTOMEDAL_PLATINUM -1
|
||||
|
||||
struct emblem_t
|
||||
{
|
||||
UINT8 type; ///< Emblem type
|
||||
|
|
@ -260,7 +267,7 @@ typedef enum
|
|||
// If you have more secrets than these variables allow in your game,
|
||||
// you seriously need to get a life.
|
||||
#define MAXCONDITIONSETS 1024
|
||||
#define MAXEMBLEMS (MAXCONDITIONSETS*2)
|
||||
#define MAXEMBLEMS (MAXCONDITIONSETS*4)
|
||||
#define MAXUNLOCKABLES MAXCONDITIONSETS
|
||||
|
||||
#define CHALLENGEGRIDHEIGHT 5
|
||||
|
|
|
|||
|
|
@ -229,7 +229,8 @@ boolean P_CanPickupEmblem(player_t *player, INT32 emblemID)
|
|||
|
||||
boolean P_EmblemWasCollected(INT32 emblemID)
|
||||
{
|
||||
if (emblemID < 0 || emblemID >= numemblems)
|
||||
if (emblemID < 0 || emblemID >= numemblems
|
||||
|| emblemlocations[emblemID].type == ET_NONE)
|
||||
{
|
||||
// Invalid emblem ID, can't pickup.
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
|
|
@ -492,6 +493,10 @@ static void P_ClearSingleMapHeaderInfo(INT16 num)
|
|||
mapheaderinfo[num]->ghostBrief = NULL;
|
||||
mapheaderinfo[num]->ghostCount = 0;
|
||||
mapheaderinfo[num]->ghostBriefSize = 0;
|
||||
mapheaderinfo[num]->automedaltime[0] = 1;
|
||||
mapheaderinfo[num]->automedaltime[1] = 2;
|
||||
mapheaderinfo[num]->automedaltime[2] = 3;
|
||||
mapheaderinfo[num]->automedaltime[3] = 4;
|
||||
}
|
||||
|
||||
/** Allocates a new map-header structure.
|
||||
|
|
@ -8848,6 +8853,60 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l
|
|||
return lumpinfo;
|
||||
}
|
||||
|
||||
static void P_DeriveAutoMedalTimes(mapheader_t& map)
|
||||
{
|
||||
// Gather staff ghost times
|
||||
std::vector<tic_t> stafftimes;
|
||||
for (int i = 0; i < map.ghostCount; i++)
|
||||
{
|
||||
tic_t time = map.ghostBrief[i]->time;
|
||||
if (time <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
stafftimes.push_back(map.ghostBrief[i]->time);
|
||||
}
|
||||
|
||||
if (stafftimes.empty())
|
||||
{
|
||||
// Use fallback times
|
||||
map.automedaltime[0] = 1;
|
||||
map.automedaltime[1] = 2;
|
||||
map.automedaltime[2] = 3;
|
||||
map.automedaltime[3] = 4;
|
||||
return;
|
||||
}
|
||||
|
||||
std::sort(stafftimes.begin(), stafftimes.end());
|
||||
|
||||
// Auto Platinum is the best staff ghost time
|
||||
// Auto Gold is the median staff ghost time
|
||||
// Silver and Bronze are 10% longer successively
|
||||
|
||||
tic_t best = stafftimes.at(0);
|
||||
tic_t gold = stafftimes.at(stafftimes.size() / 2);
|
||||
if (gold == best)
|
||||
{
|
||||
gold += 1;
|
||||
}
|
||||
tic_t silver = static_cast<tic_t>(std::ceil(gold * 1.1f));
|
||||
if (silver == gold)
|
||||
{
|
||||
silver += 1;
|
||||
}
|
||||
tic_t bronze = static_cast<tic_t>(std::ceil(silver * 1.1f));
|
||||
if (bronze == silver)
|
||||
{
|
||||
bronze += 1;
|
||||
}
|
||||
|
||||
map.automedaltime[0] = best;
|
||||
map.automedaltime[1] = gold;
|
||||
map.automedaltime[2] = silver;
|
||||
map.automedaltime[3] = bronze;
|
||||
}
|
||||
|
||||
lumpnum_t wadnamelump = LUMPERROR;
|
||||
INT16 wadnamemap = 0; // gamemap based
|
||||
|
||||
|
|
@ -9024,6 +9083,8 @@ UINT8 P_InitMapData(void)
|
|||
}
|
||||
}
|
||||
|
||||
P_DeriveAutoMedalTimes(*mapheaderinfo[i]);
|
||||
|
||||
vres_Free(virtmap);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue