diff --git a/src/k_battle.c b/src/k_battle.c index 4c5c01b54..a49883f6f 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -781,7 +781,6 @@ void K_BattleInit(boolean singleplayercontext) P_SpawnMapThing(mt); } - g_gpRank.totalCapsules += maptargets; battlecapsules = true; } diff --git a/src/k_rank.c b/src/k_rank.c index 369b940e1..09651015a 100644 --- a/src/k_rank.c +++ b/src/k_rank.c @@ -20,9 +20,240 @@ #include "k_kart.h" #include "m_random.h" #include "r_things.h" +#include "fastcmp.h" +#include "byteptr.h" gpRank_t g_gpRank = {0}; +// I was ALMOST tempted to start tearing apart all +// of the map loading code and turning it into C++ +// and making it properly split between read-only +// and true level loading and clean up all of the +// global variable garbage it uses ... but I stopped +// myself. So here's code duplication hell instead. +static UINT32 g_rankCapsules_mapthingsPos[UINT16_MAX]; +static size_t g_rankCapsules_nummapthings = 0; +static boolean g_rankCapsules_udmf = false; +static UINT32 g_rankCapsules_count = 0; + +/*-------------------------------------------------- + static void RankCapsules_TextmapCount(size_t size) + + Counts the number of map things and records + the structure positions, for the result of + RankCapsules_CountFromMap. + + Input Arguments:- + size - Length of the TEXTMAP lump. + + Return:- + N/A +--------------------------------------------------*/ +static UINT32 RankCapsules_TextmapCount(size_t size) +{ + const char *tkn = M_TokenizerRead(0); + UINT8 brackets = 0; + + g_rankCapsules_nummapthings = 0; + + // Look for namespace at the beginning. + if (!fastcmp(tkn, "namespace")) + { + return false; + } + + // Check if namespace is valid. + tkn = M_TokenizerRead(0); + + while ((tkn = M_TokenizerRead(0)) && M_TokenizerGetEndPos() < size) + { + // Avoid anything inside bracketed stuff, only look for external keywords. + if (brackets) + { + if (fastcmp(tkn, "}")) + brackets--; + } + else if (fastcmp(tkn, "{")) + brackets++; + // Check for valid fields. + else if (fastcmp(tkn, "thing")) + g_rankCapsules_mapthingsPos[g_rankCapsules_nummapthings++] = M_TokenizerGetEndPos(); + } + + if (brackets) + { + return false; + } + + return true; +} + +/*-------------------------------------------------- + static void RankCapsules_LoadTextmap(void) + + Loads UDMF map data for the result of + RankCapsules_CountFromMap. +--------------------------------------------------*/ +static void RankCapsules_LoadTextmap(void) +{ + size_t i; + + for (i = 0; i < g_rankCapsules_nummapthings; i++) + { + const char *param, *val; + + M_TokenizerSetEndPos(g_rankCapsules_mapthingsPos[i]); + param = M_TokenizerRead(0); + + if (!fastcmp(param, "{")) + { + continue; + } + + while (true) + { + param = M_TokenizerRead(0); + + if (fastcmp(param, "}")) + { + break; + } + + val = M_TokenizerRead(1); + + if (fastcmp(param, "type")) + { + UINT16 type = atol(val); + + if (type == mobjinfo[MT_BATTLECAPSULE].doomednum) + { + g_rankCapsules_count++; + } + + break; + } + } + } +} + +/*-------------------------------------------------- + static void RankCapsules_LoadThingsLump(UINT8 *data) + + Loads binary map data for the result of + RankCapsules_CountFromMap. + + Input Arguments:- + data - Pointer to a THINGS lump. + + Return:- + N/A +--------------------------------------------------*/ +static void RankCapsules_LoadThingsLump(UINT8 *data) +{ + size_t i; + + for (i = 0; i < g_rankCapsules_nummapthings; i++) + { + UINT16 type = 0; + + data += 2; // x + data += 2; // y + + data += 2; // angle + type = READUINT16(data); // type + type &= 4095; + + data += 2; // options + + if (type == mobjinfo[MT_BATTLECAPSULE].doomednum) + { + g_rankCapsules_count++; + } + } +} + +/*-------------------------------------------------- + static boolean RankCapsules_LoadMapData(const virtres_t *virt) + + Loads either UDMF or binary map data, for the + result of RankCapsules_CountFromMap. + + Input Arguments:- + virt - Pointer to the map's virtual resource. + + Return:- + true if we could successfully load the map data, + otherwise false. +--------------------------------------------------*/ +static boolean RankCapsules_LoadMapData(const virtres_t *virt) +{ + virtlump_t *virtthings = NULL; + + // Count map data. + if (g_rankCapsules_udmf) // Count how many entries for each type we got in textmap. + { + virtlump_t *textmap = vres_Find(virt, "TEXTMAP"); + M_TokenizerOpen((char *)textmap->data); + if (!RankCapsules_TextmapCount(textmap->size)) + { + M_TokenizerClose(); + return false; + } + } + else + { + virtthings = vres_Find(virt, "THINGS"); + + if (!virtthings) + { + return false; + } + + // Traditional doom map format just assumes the number of elements from the lump sizes. + g_rankCapsules_nummapthings = virtthings->size / (5 * sizeof (INT16)); + } + + // Load map data. + if (g_rankCapsules_udmf) + { + RankCapsules_LoadTextmap(); + M_TokenizerClose(); + } + else + { + RankCapsules_LoadThingsLump(virtthings->data); + } + + return true; +} + +/*-------------------------------------------------- + static UINT32 RankCapsules_CountFromMap(const virtres_t *virt) + + Counts the number of capsules in a map, without + needing to fully load it. + + Input Arguments:- + virt - Pointer to the map's virtual resource. + + Return:- + Number of MT_BATTLECAPSULE instances found. +--------------------------------------------------*/ +static UINT32 RankCapsules_CountFromMap(const virtres_t *virt) +{ + virtlump_t *textmap = vres_Find(virt, "TEXTMAP"); + + g_rankCapsules_udmf = (textmap != NULL); + g_rankCapsules_count = 0; + + if (RankCapsules_LoadMapData(virt) == true) + { + return g_rankCapsules_count; + } + + return 0; +} + /*-------------------------------------------------- void K_InitGrandPrixRank(gpRank_t *rankData) @@ -83,7 +314,30 @@ void K_InitGrandPrixRank(gpRank_t *rankData) rankData->totalLaps += laps; } - // Total capsules will need to be calculated as you enter the bonus stages... + // Search through all of the cup's bonus levels + // for an accurate count of how many capsules they have. + for (i = 0; i < grandprixinfo.cup->numbonus; i++) + { + const INT32 cupLevelNum = grandprixinfo.cup->cachedlevels[CUPCACHE_BONUS + i]; + if (cupLevelNum < nummapheaders && mapheaderinfo[cupLevelNum] != NULL) + { + lumpnum_t lp = mapheaderinfo[cupLevelNum]->lumpnum; + virtres_t *virt = NULL; + + if (lp == LUMPERROR) + { + continue; + } + + virt = vres_GetMap(lp); + if (virt == NULL) + { + continue; + } + + rankData->totalCapsules += RankCapsules_CountFromMap(virt); + } + } } /*--------------------------------------------------