mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
Merge branch 'the-hunt-continues' into 'master'
Add bonus pickups in conditions you couldn't grab Spray Cans before See merge request kart-krew-dev/ring-racers-internal!2502
This commit is contained in:
commit
a35bbaacf7
13 changed files with 300 additions and 158 deletions
|
|
@ -1913,8 +1913,9 @@ bool CallFunc_GetGrabbedSprayCan(ACSVM::Thread *thread, const ACSVM::Word *argV,
|
|||
&& gamemap-1 < basenummapheaders)
|
||||
{
|
||||
// See also P_SprayCanInit
|
||||
UINT16 can_id = mapheaderinfo[gamemap-1]->cache_spraycan;
|
||||
UINT16 can_id = mapheaderinfo[gamemap-1]->records.spraycan;
|
||||
|
||||
// Intentionally not affected by MCAN_BONUS
|
||||
if (can_id < gamedata->numspraycans)
|
||||
{
|
||||
UINT16 col = gamedata->spraycans[can_id].col;
|
||||
|
|
|
|||
|
|
@ -156,6 +156,9 @@ struct skinreference_t
|
|||
#define MV_MYSTICMELODY (1<<4)
|
||||
#define MV_MAX (MV_VISITED|MV_BEATEN|MV_ENCORE|MV_SPBATTACK|MV_MYSTICMELODY)
|
||||
|
||||
#define MCAN_INVALID (UINT16_MAX)
|
||||
#define MCAN_BONUS (UINT16_MAX-1)
|
||||
|
||||
struct recordtimes_t
|
||||
{
|
||||
tic_t time; ///< Time in which the level was finished.
|
||||
|
|
@ -164,9 +167,10 @@ struct recordtimes_t
|
|||
|
||||
struct recorddata_t
|
||||
{
|
||||
UINT8 mapvisited;
|
||||
UINT8 mapvisited; ///< Generalised flags
|
||||
recordtimes_t timeattack; ///< Best times for Time Attack
|
||||
recordtimes_t spbattack; ///< Best times for SPB Attack
|
||||
UINT16 spraycan; ///< Associated spraycan id
|
||||
UINT32 timeplayed;
|
||||
UINT32 netgametimeplayed;
|
||||
UINT32 modetimeplayed[GDGT_MAX];
|
||||
|
|
@ -575,7 +579,6 @@ struct mapheader_t
|
|||
mobjtype_t destroyforchallenge[MAXDESTRUCTIBLES]; ///< Assistive for UCRP_MAPDESTROYOBJECTS
|
||||
UINT8 destroyforchallenge_size; ///< Number for above
|
||||
|
||||
UINT16 cache_spraycan; ///< Cached Spraycan ID
|
||||
UINT16 cache_maplock; ///< Cached Unlockable ID
|
||||
|
||||
// Lua information
|
||||
|
|
|
|||
|
|
@ -29,7 +29,9 @@
|
|||
namespace fs = std::filesystem;
|
||||
|
||||
#define GD_VERSION_MAJOR (0xBA5ED321)
|
||||
#define GD_VERSION_MINOR (1)
|
||||
#define GD_VERSION_MINOR (2)
|
||||
|
||||
#define GD_MINIMUM_SPRAYCANSV2 (2)
|
||||
|
||||
void srb2::save_ng_gamedata()
|
||||
{
|
||||
|
|
@ -146,6 +148,18 @@ void srb2::save_ng_gamedata()
|
|||
ng.skins[name] = std::move(skin);
|
||||
}
|
||||
|
||||
for (int i = 0; i < gamedata->numspraycans; i++)
|
||||
{
|
||||
uint16_t col = gamedata->spraycans[i].col;
|
||||
|
||||
if (col >= SKINCOLOR_FIRSTFREESLOT)
|
||||
{
|
||||
col = SKINCOLOR_NONE;
|
||||
}
|
||||
|
||||
ng.spraycans_v2.emplace_back(String(skincolors[col].name));
|
||||
}
|
||||
|
||||
auto maptojson = [](recorddata_t *records)
|
||||
{
|
||||
srb2::GamedataMapJson map {};
|
||||
|
|
@ -167,6 +181,7 @@ void srb2::save_ng_gamedata()
|
|||
map.stats.time.custom = records->modetimeplayed[GDGT_CUSTOM];
|
||||
map.stats.time.timeattack = records->timeattacktimeplayed;
|
||||
map.stats.time.spbattack = records->spbattacktimeplayed;
|
||||
map.spraycan = records->spraycan;
|
||||
|
||||
return map;
|
||||
};
|
||||
|
|
@ -183,38 +198,6 @@ void srb2::save_ng_gamedata()
|
|||
srb2::String lumpname { unloadedmap->lumpname };
|
||||
ng.maps[lumpname] = std::move(map);
|
||||
}
|
||||
for (int i = 0; i < gamedata->numspraycans; i++)
|
||||
{
|
||||
srb2::GamedataSprayCanJson spraycan {};
|
||||
|
||||
candata_t* can = &gamedata->spraycans[i];
|
||||
|
||||
if (can->col >= numskincolors)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
spraycan.color = String(skincolors[can->col].name);
|
||||
|
||||
if (can->map == NEXTMAP_INVALID)
|
||||
{
|
||||
spraycan.map = "";
|
||||
ng.spraycans.emplace_back(std::move(spraycan));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (can->map >= nummapheaders)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mapheader_t* mapheader = mapheaderinfo[can->map];
|
||||
if (!mapheader)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
spraycan.map = String(mapheader->lumpname);
|
||||
ng.spraycans.emplace_back(std::move(spraycan));
|
||||
}
|
||||
|
||||
auto cuptojson = [](cupwindata_t *windata)
|
||||
{
|
||||
|
|
@ -401,6 +384,7 @@ void srb2::load_ng_gamedata()
|
|||
uint32_t majorversion;
|
||||
uint8_t minorversion;
|
||||
uint8_t dirty;
|
||||
bool converted = false;
|
||||
try
|
||||
{
|
||||
majorversion = srb2::io::read_uint32(bis);
|
||||
|
|
@ -519,23 +503,11 @@ void srb2::load_ng_gamedata()
|
|||
gamedata->achieved[i] = js.conditionsets[i];
|
||||
}
|
||||
|
||||
if (M_CheckParm("-resetchallengegrid"))
|
||||
{
|
||||
gamedata->challengegridwidth = 0;
|
||||
if (gamedata->challengegrid)
|
||||
{
|
||||
Z_Free(gamedata->challengegrid);
|
||||
gamedata->challengegrid = nullptr;
|
||||
}
|
||||
}
|
||||
else
|
||||
#ifdef DEVELOP
|
||||
if (!M_CheckParm("-resetchallengegrid"))
|
||||
#endif
|
||||
{
|
||||
gamedata->challengegridwidth = std::max(js.challengegrid.width, (uint32_t)0);
|
||||
if (gamedata->challengegrid)
|
||||
{
|
||||
Z_Free(gamedata->challengegrid);
|
||||
gamedata->challengegrid = nullptr;
|
||||
}
|
||||
if (gamedata->challengegridwidth)
|
||||
{
|
||||
gamedata->challengegrid = static_cast<uint16_t*>(Z_Malloc(
|
||||
|
|
@ -549,10 +521,6 @@ void srb2::load_ng_gamedata()
|
|||
|
||||
M_SanitiseChallengeGrid();
|
||||
}
|
||||
else
|
||||
{
|
||||
gamedata->challengegrid = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
gamedata->timesBeaten = js.timesBeaten;
|
||||
|
|
@ -609,9 +577,37 @@ void srb2::load_ng_gamedata()
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<candata_t> tempcans;
|
||||
|
||||
#ifdef DEVELOP
|
||||
if (M_CheckParm("-resetspraycans"))
|
||||
;
|
||||
else
|
||||
#endif
|
||||
for (auto& cancolor : js.spraycans_v2)
|
||||
{
|
||||
// Version 2 behaviour - spraycans_v2, not spraycans!
|
||||
|
||||
candata_t tempcan;
|
||||
tempcan.col = SKINCOLOR_NONE;
|
||||
tempcan.map = NEXTMAP_INVALID;
|
||||
|
||||
// Find the skin color index for the name
|
||||
for (size_t i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++)
|
||||
{
|
||||
if (cancolor != skincolors[i].name)
|
||||
continue;
|
||||
|
||||
tempcan.col = i;
|
||||
break;
|
||||
}
|
||||
|
||||
tempcans.emplace_back(std::move(tempcan));
|
||||
}
|
||||
|
||||
for (auto& mappair : js.maps)
|
||||
{
|
||||
UINT16 mapnum = G_MapNumber(mappair.first.c_str());
|
||||
uint16_t mapnum = G_MapNumber(mappair.first.c_str());
|
||||
recorddata_t dummyrecord {};
|
||||
dummyrecord.mapvisited |= mappair.second.visited.visited ? MV_VISITED : 0;
|
||||
dummyrecord.mapvisited |= mappair.second.visited.beaten ? MV_BEATEN : 0;
|
||||
|
|
@ -632,15 +628,37 @@ void srb2::load_ng_gamedata()
|
|||
dummyrecord.timeattacktimeplayed = mappair.second.stats.time.timeattack;
|
||||
dummyrecord.spbattacktimeplayed = mappair.second.stats.time.spbattack;
|
||||
|
||||
dummyrecord.spraycan = (minorversion >= GD_MINIMUM_SPRAYCANSV2)
|
||||
? mappair.second.spraycan
|
||||
: MCAN_INVALID;
|
||||
|
||||
if (mapnum < nummapheaders && mapheaderinfo[mapnum])
|
||||
{
|
||||
// Valid mapheader, time to populate with record data.
|
||||
|
||||
// Infill Spray Can info
|
||||
if (
|
||||
dummyrecord.spraycan < tempcans.size()
|
||||
&& (mapnum < basenummapheaders)
|
||||
&& (tempcans[dummyrecord.spraycan].map >= basenummapheaders)
|
||||
)
|
||||
{
|
||||
// Assign map ID.
|
||||
tempcans[dummyrecord.spraycan].map = mapnum;
|
||||
}
|
||||
|
||||
if (dummyrecord.spraycan != MCAN_INVALID)
|
||||
{
|
||||
// Yes, even if it's valid. We reassign later.
|
||||
dummyrecord.spraycan = MCAN_BONUS;
|
||||
}
|
||||
|
||||
mapheaderinfo[mapnum]->records = dummyrecord;
|
||||
}
|
||||
else if (dummyrecord.mapvisited & MV_BEATEN
|
||||
|| dummyrecord.timeattack.time != 0 || dummyrecord.timeattack.lap != 0
|
||||
|| dummyrecord.spbattack.time != 0 || dummyrecord.spbattack.lap != 0)
|
||||
|| dummyrecord.spbattack.time != 0 || dummyrecord.spbattack.lap != 0
|
||||
|| dummyrecord.spraycan != MCAN_INVALID)
|
||||
{
|
||||
// Invalid, but we don't want to lose all the juicy statistics.
|
||||
// Instead, update a FILO linked list of "unloaded mapheaders".
|
||||
|
|
@ -659,81 +677,98 @@ void srb2::load_ng_gamedata()
|
|||
unloadedmap->next = unloadedmapheaders;
|
||||
unloadedmapheaders = unloadedmap;
|
||||
|
||||
if (dummyrecord.spraycan != MCAN_INVALID)
|
||||
{
|
||||
// Invalidate non-bonus spraycans.
|
||||
dummyrecord.spraycan = MCAN_BONUS;
|
||||
}
|
||||
|
||||
// Finally, copy into.
|
||||
unloadedmap->records = dummyrecord;
|
||||
}
|
||||
}
|
||||
|
||||
gamedata->gotspraycans = 0;
|
||||
gamedata->numspraycans = js.spraycans.size();
|
||||
if (gamedata->spraycans)
|
||||
if ((minorversion < GD_MINIMUM_SPRAYCANSV2) && (js.spraycans.size() > 1))
|
||||
{
|
||||
Z_Free(gamedata->spraycans);
|
||||
}
|
||||
if (gamedata->numspraycans)
|
||||
{
|
||||
gamedata->spraycans = static_cast<candata_t*>(Z_Malloc(
|
||||
(gamedata->numspraycans * sizeof(candata_t)),
|
||||
PU_STATIC, NULL));
|
||||
// Deprecated behaviour! Look above for spraycans_v2 handling
|
||||
|
||||
for (size_t i = 0; i < gamedata->numspraycans; i++)
|
||||
converted = true;
|
||||
|
||||
for (auto& deprecatedcan : js.spraycans)
|
||||
{
|
||||
auto& can = js.spraycans[i];
|
||||
candata_t tempcan;
|
||||
tempcan.col = SKINCOLOR_NONE;
|
||||
|
||||
// Find the skin color index for the name
|
||||
bool foundcolor = false;
|
||||
for (size_t j = 0; j < numskincolors; j++)
|
||||
for (size_t i = 0; i < SKINCOLOR_FIRSTFREESLOT; i++)
|
||||
{
|
||||
if (can.color == skincolors[j].name)
|
||||
{
|
||||
gamedata->spraycans[i].col = j;
|
||||
skincolors[j].cache_spraycan = i;
|
||||
foundcolor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundcolor)
|
||||
{
|
||||
// Invalid color name? Ignore the spraycan
|
||||
gamedata->numspraycans -= 1;
|
||||
i -= 1;
|
||||
continue;
|
||||
}
|
||||
if (deprecatedcan.color != skincolors[i].name)
|
||||
continue;
|
||||
|
||||
gamedata->spraycans[i].map = NEXTMAP_INVALID;
|
||||
tempcan.col = i;
|
||||
break;
|
||||
}
|
||||
|
||||
UINT16 mapnum = NEXTMAP_INVALID;
|
||||
if (!can.map.empty())
|
||||
if (!deprecatedcan.map.empty())
|
||||
{
|
||||
mapnum = G_MapNumber(can.map.c_str());
|
||||
}
|
||||
gamedata->spraycans[i].map = mapnum;
|
||||
if (mapnum >= nummapheaders)
|
||||
{
|
||||
// Can has not been grabbed on any map, this is intentional.
|
||||
continue;
|
||||
mapnum = G_MapNumber(deprecatedcan.map.c_str());
|
||||
}
|
||||
tempcan.map = mapnum;
|
||||
|
||||
if (gamedata->gotspraycans != i)
|
||||
{
|
||||
//CONS_Printf("LOAD - Swapping gotten can %u, color %s with prior ungotten can %u\n", i, skincolors[col].name, gamedata->gotspraycans);
|
||||
|
||||
// All grabbed cans should be at the head of the list.
|
||||
// Let's swap with the can the disjoint occoured at.
|
||||
// This will prevent a gap from occouring on reload.
|
||||
candata_t copycan = gamedata->spraycans[gamedata->gotspraycans];
|
||||
gamedata->spraycans[gamedata->gotspraycans] = gamedata->spraycans[i];
|
||||
gamedata->spraycans[i] = copycan;
|
||||
|
||||
mapheaderinfo[copycan.map]->cache_spraycan = i;
|
||||
}
|
||||
mapheaderinfo[mapnum]->cache_spraycan = gamedata->gotspraycans;
|
||||
gamedata->gotspraycans++;
|
||||
tempcans.emplace_back(std::move(tempcan));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
{
|
||||
gamedata->spraycans = nullptr;
|
||||
// Post-process of Spray Cans - a component of both v1 and v2 spraycans behaviour
|
||||
|
||||
// Determine sizes.
|
||||
for (auto& tempcan : tempcans)
|
||||
{
|
||||
if (tempcan.col == SKINCOLOR_NONE)
|
||||
continue;
|
||||
|
||||
gamedata->numspraycans++;
|
||||
|
||||
if (tempcan.map >= nummapheaders)
|
||||
continue;
|
||||
|
||||
gamedata->gotspraycans++;
|
||||
}
|
||||
|
||||
if (gamedata->numspraycans)
|
||||
{
|
||||
// Arrange with collected first
|
||||
std::stable_sort(tempcans.begin(), tempcans.end(), [ ]( auto& lhs, auto& rhs )
|
||||
{
|
||||
return (rhs.map >= basenummapheaders && lhs.map < basenummapheaders);
|
||||
});
|
||||
|
||||
gamedata->spraycans = static_cast<candata_t*>(Z_Malloc(
|
||||
(gamedata->numspraycans * sizeof(candata_t)),
|
||||
PU_STATIC, NULL));
|
||||
|
||||
// Finally, fill can data.
|
||||
size_t i = 0;
|
||||
for (auto& tempcan : tempcans)
|
||||
{
|
||||
if (tempcan.col == SKINCOLOR_NONE)
|
||||
continue;
|
||||
|
||||
skincolors[tempcan.col].cache_spraycan = i;
|
||||
|
||||
if (tempcan.map < basenummapheaders)
|
||||
mapheaderinfo[tempcan.map]->records.spraycan = i;
|
||||
|
||||
gamedata->spraycans[i] = tempcan;
|
||||
|
||||
if (++i < gamedata->numspraycans)
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& cuppair : js.cups)
|
||||
|
|
@ -838,7 +873,6 @@ void srb2::load_ng_gamedata()
|
|||
}
|
||||
}
|
||||
|
||||
bool converted = false;
|
||||
UINT32 chao_key_rounds = GDCONVERT_ROUNDSTOKEY;
|
||||
UINT32 start_keys = GDINIT_CHAOKEYS;
|
||||
|
||||
|
|
|
|||
|
|
@ -243,10 +243,12 @@ struct GamedataMapJson final
|
|||
{
|
||||
GamedataMapVisitedJson visited;
|
||||
GamedataMapStatsJson stats;
|
||||
uint16_t spraycan;
|
||||
|
||||
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapJson, visited, stats)
|
||||
SRB2_JSON_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(GamedataMapJson, visited, stats, spraycan)
|
||||
};
|
||||
|
||||
// Deprecated
|
||||
struct GamedataSprayCanJson final
|
||||
{
|
||||
String map;
|
||||
|
|
@ -296,8 +298,9 @@ struct GamedataJson final
|
|||
GamedataChallengeGridJson challengegrid;
|
||||
uint32_t timesBeaten;
|
||||
HashMap<String, GamedataSkinJson> skins;
|
||||
Vector<String> spraycans_v2;
|
||||
HashMap<String, GamedataMapJson> maps;
|
||||
Vector<GamedataSprayCanJson> spraycans;
|
||||
Vector<GamedataSprayCanJson> spraycans; // Deprecated
|
||||
HashMap<String, GamedataCupJson> cups;
|
||||
Vector<GamedataSealedSwapJson> sealedswaps;
|
||||
|
||||
|
|
@ -317,6 +320,7 @@ struct GamedataJson final
|
|||
challengegrid,
|
||||
timesBeaten,
|
||||
skins,
|
||||
spraycans_v2,
|
||||
maps,
|
||||
spraycans,
|
||||
cups,
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"BSPH", // Sphere
|
||||
"EMBM",
|
||||
"SPCN", // Spray Can
|
||||
"SBON", // Spray Can replacement bonus
|
||||
"MMSH", // Ancient Shrine
|
||||
"MORB", // One Morbillion
|
||||
"EMRC", // Chaos Emeralds
|
||||
|
|
|
|||
|
|
@ -589,6 +589,7 @@ typedef enum sprite
|
|||
SPR_BSPH, // Sphere
|
||||
SPR_EMBM,
|
||||
SPR_SPCN, // Spray Can
|
||||
SPR_SBON, // Spray Can replacement bonus
|
||||
SPR_MMSH, // Ancient Shrine
|
||||
SPR_MORB, // One Morbillion
|
||||
SPR_EMRC, // Chaos Emeralds
|
||||
|
|
|
|||
|
|
@ -1486,6 +1486,7 @@ extern struct statisticsmenu_s {
|
|||
INT32 gotmedals;
|
||||
INT32 nummedals;
|
||||
INT32 numextramedals;
|
||||
INT32 numcanbonus;
|
||||
UINT32 statgridplayed[9][9];
|
||||
INT32 maxscroll;
|
||||
UINT16 *maplist;
|
||||
|
|
|
|||
|
|
@ -3315,7 +3315,7 @@ void M_DrawCupSelect(void)
|
|||
incj = false;
|
||||
|
||||
work_array[j].medal = NULL;
|
||||
work_array[j].col = work_array[j].dotcol = UINT16_MAX;
|
||||
work_array[j].col = work_array[j].dotcol = MCAN_INVALID;
|
||||
|
||||
if (templevelsearch.timeattack)
|
||||
{
|
||||
|
|
@ -3354,13 +3354,17 @@ void M_DrawCupSelect(void)
|
|||
emblem = M_GetLevelEmblems(-1);
|
||||
}
|
||||
}
|
||||
else if ((gamedata->gotspraycans > 0) && (mapheaderinfo[map]->typeoflevel & TOL_RACE))
|
||||
else if (mapheaderinfo[map]->typeoflevel & TOL_RACE)
|
||||
{
|
||||
incj = true;
|
||||
|
||||
if (mapheaderinfo[map]->cache_spraycan < gamedata->numspraycans)
|
||||
if (mapheaderinfo[map]->records.spraycan == MCAN_BONUS)
|
||||
{
|
||||
work_array[j].col = gamedata->spraycans[mapheaderinfo[map]->cache_spraycan].col;
|
||||
work_array[j].col = MCAN_BONUS;
|
||||
}
|
||||
else if (mapheaderinfo[map]->records.spraycan < gamedata->numspraycans)
|
||||
{
|
||||
work_array[j].col = gamedata->spraycans[mapheaderinfo[map]->records.spraycan].col;
|
||||
}
|
||||
|
||||
if (mapheaderinfo[map]->records.mapvisited & MV_MYSTICMELODY)
|
||||
|
|
@ -3409,7 +3413,13 @@ void M_DrawCupSelect(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
if (work_array[i].col < numskincolors)
|
||||
if (work_array[i].col == MCAN_BONUS)
|
||||
{
|
||||
// Bonus in place of Spray Can
|
||||
|
||||
V_DrawScaledPatch(x, y, 0, W_CachePatchName("GOTBON", PU_CACHE));
|
||||
}
|
||||
else if (work_array[i].col < numskincolors)
|
||||
{
|
||||
// Spray Can
|
||||
|
||||
|
|
@ -8324,9 +8334,16 @@ static INT32 M_DrawMapMedals(INT32 mapnum, INT32 x, INT32 y, boolean allowtime,
|
|||
if (hasmedals)
|
||||
x -= 4;
|
||||
|
||||
if (mapheaderinfo[mapnum]->cache_spraycan < gamedata->numspraycans)
|
||||
if (mapheaderinfo[mapnum]->records.spraycan == MCAN_BONUS)
|
||||
{
|
||||
UINT16 col = gamedata->spraycans[mapheaderinfo[mapnum]->cache_spraycan].col;
|
||||
if (draw)
|
||||
V_DrawScaledPatch(x, y, 0, W_CachePatchName("GOTBON", PU_CACHE));
|
||||
|
||||
x -= 8;
|
||||
}
|
||||
else if (mapheaderinfo[mapnum]->records.spraycan < gamedata->numspraycans)
|
||||
{
|
||||
UINT16 col = gamedata->spraycans[mapheaderinfo[mapnum]->records.spraycan].col;
|
||||
|
||||
if (draw && col < numskincolors)
|
||||
{
|
||||
|
|
@ -8374,11 +8391,18 @@ static void M_DrawStatsMaps(void)
|
|||
if (gamedata->numspraycans)
|
||||
{
|
||||
medalspos = 30 + V_ThinStringWidth(medalcountstr, 0);
|
||||
medalcountstr = va("x %d/%d", gamedata->gotspraycans, gamedata->numspraycans);
|
||||
medalcountstr = va("x %d/%d", gamedata->gotspraycans + statisticsmenu.numcanbonus, gamedata->numspraycans);
|
||||
V_DrawThinString(20 + medalspos, 60, 0, medalcountstr);
|
||||
V_DrawMappedPatch(10 + medalspos, 60, 0, W_CachePatchName("GOTCAN", PU_CACHE),
|
||||
R_GetTranslationColormap(TC_DEFAULT, gamedata->spraycans[0].col, GTC_MENUCACHE));
|
||||
}
|
||||
else if (statisticsmenu.numcanbonus)
|
||||
{
|
||||
medalspos = 30 + V_ThinStringWidth(medalcountstr, 0);
|
||||
medalcountstr = va("x %d", statisticsmenu.numcanbonus);
|
||||
V_DrawThinString(20 + medalspos, 60, 0, medalcountstr);
|
||||
V_DrawScaledPatch(10 + medalspos, 60, 0, W_CachePatchName("GOTBON", PU_CACHE));
|
||||
}
|
||||
|
||||
medalspos = BASEVIDWIDTH - 20;
|
||||
|
||||
|
|
|
|||
48
src/m_cond.c
48
src/m_cond.c
|
|
@ -743,8 +743,7 @@ void M_ClearSecrets(void)
|
|||
continue;
|
||||
|
||||
mapheaderinfo[i]->records.mapvisited = 0;
|
||||
|
||||
mapheaderinfo[i]->cache_spraycan = UINT16_MAX;
|
||||
mapheaderinfo[i]->records.spraycan = MCAN_INVALID;
|
||||
|
||||
mapheaderinfo[i]->cache_maplock = MAXUNLOCKABLES;
|
||||
|
||||
|
|
@ -814,6 +813,30 @@ static void M_AssignSpraycans(void)
|
|||
conditionset_t *c;
|
||||
condition_t *cn;
|
||||
|
||||
UINT16 bonustocanmap = 0;
|
||||
|
||||
// First, turn outstanding bonuses into existing uncollected Spray Cans.
|
||||
while (gamedata->gotspraycans < gamedata->numspraycans)
|
||||
{
|
||||
while (bonustocanmap < basenummapheaders)
|
||||
{
|
||||
if (mapheaderinfo[bonustocanmap]->records.spraycan != MCAN_BONUS)
|
||||
{
|
||||
bonustocanmap++;
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (bonustocanmap == basenummapheaders)
|
||||
break;
|
||||
|
||||
mapheaderinfo[bonustocanmap]->records.spraycan = gamedata->gotspraycans;
|
||||
gamedata->spraycans[gamedata->gotspraycans].map = bonustocanmap;
|
||||
gamedata->gotspraycans++;
|
||||
}
|
||||
|
||||
const UINT16 prependoffset = MAXSKINCOLORS-1;
|
||||
|
||||
// None of the following accounts for cans being removed, only added...
|
||||
|
|
@ -829,7 +852,7 @@ static void M_AssignSpraycans(void)
|
|||
if (cn->type != UC_SPRAYCAN)
|
||||
continue;
|
||||
|
||||
// G_LoadGamedata, G_SaveGameData doesn't support custom skincolors right now.
|
||||
// This will likely never support custom skincolors.
|
||||
if (cn->requirement >= SKINCOLOR_FIRSTFREESLOT) //numskincolors)
|
||||
continue;
|
||||
|
||||
|
|
@ -891,7 +914,24 @@ static void M_AssignSpraycans(void)
|
|||
|
||||
for (i = 0; i < listlen; i++)
|
||||
{
|
||||
gamedata->spraycans[gamedata->numspraycans].map = NEXTMAP_INVALID;
|
||||
// Convert bonus pickups into Spray Cans if new ones have been added.
|
||||
while (bonustocanmap < basenummapheaders)
|
||||
{
|
||||
if (mapheaderinfo[bonustocanmap]->records.spraycan != MCAN_BONUS)
|
||||
{
|
||||
bonustocanmap++;
|
||||
continue;
|
||||
}
|
||||
|
||||
gamedata->gotspraycans++;
|
||||
mapheaderinfo[bonustocanmap]->records.spraycan = gamedata->numspraycans;
|
||||
break;
|
||||
}
|
||||
gamedata->spraycans[gamedata->numspraycans].map = (
|
||||
(bonustocanmap == basenummapheaders)
|
||||
? NEXTMAP_INVALID
|
||||
: bonustocanmap
|
||||
);
|
||||
gamedata->spraycans[gamedata->numspraycans].col = tempcanlist[i];
|
||||
|
||||
skincolors[tempcanlist[i]].cache_spraycan = gamedata->numspraycans;
|
||||
|
|
|
|||
|
|
@ -290,10 +290,22 @@ void M_Statistics(INT32 choice)
|
|||
{
|
||||
(void)choice;
|
||||
|
||||
UINT16 i;
|
||||
|
||||
statisticsmenu.gotmedals = M_CountMedals(false, false);
|
||||
statisticsmenu.nummedals = M_CountMedals(true, false);
|
||||
statisticsmenu.numextramedals = M_CountMedals(true, true);
|
||||
|
||||
statisticsmenu.numcanbonus = 0;
|
||||
for (i = 0; i < basenummapheaders; i++)
|
||||
{
|
||||
if (!mapheaderinfo[i])
|
||||
continue;
|
||||
if (mapheaderinfo[i]->records.spraycan != MCAN_BONUS)
|
||||
continue;
|
||||
statisticsmenu.numcanbonus++;
|
||||
}
|
||||
|
||||
M_StatisticsPageInit();
|
||||
|
||||
MISC_StatisticsDef.prevMenu = currentMenu;
|
||||
|
|
|
|||
|
|
@ -779,15 +779,27 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
}
|
||||
|
||||
// See also P_SprayCanInit
|
||||
UINT16 can_id = mapheaderinfo[gamemap-1]->cache_spraycan;
|
||||
UINT16 can_id = mapheaderinfo[gamemap-1]->records.spraycan;
|
||||
|
||||
if (can_id < gamedata->numspraycans)
|
||||
if (can_id < gamedata->numspraycans || can_id == MCAN_BONUS)
|
||||
{
|
||||
// Assigned to this level, has been grabbed
|
||||
return;
|
||||
}
|
||||
// Prevent footguns - these won't persist when custom levels are unloaded
|
||||
else if (gamemap-1 < basenummapheaders)
|
||||
|
||||
if (
|
||||
(gamemap-1 >= basenummapheaders)
|
||||
|| (gamedata->gotspraycans >= gamedata->numspraycans)
|
||||
)
|
||||
{
|
||||
// Custom course OR we ran out of assignables.
|
||||
|
||||
if (special->threshold != 0)
|
||||
return;
|
||||
|
||||
can_id = MCAN_BONUS;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unassigned, get the next grabbable colour
|
||||
can_id = gamedata->gotspraycans;
|
||||
|
|
@ -810,18 +822,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
skincolors[swapcol].cache_spraycan = can_id;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (can_id >= gamedata->numspraycans)
|
||||
{
|
||||
// We've exhausted all the spraycans to grab.
|
||||
return;
|
||||
}
|
||||
|
||||
if (gamedata->spraycans[can_id].map >= nummapheaders)
|
||||
{
|
||||
gamedata->spraycans[can_id].map = gamemap-1;
|
||||
mapheaderinfo[gamemap-1]->cache_spraycan = can_id;
|
||||
|
||||
if (gamedata->gotspraycans == 0
|
||||
&& gametype == GT_TUTORIAL
|
||||
|
|
@ -837,12 +838,14 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
|
|||
}
|
||||
|
||||
gamedata->gotspraycans++;
|
||||
|
||||
if (!M_UpdateUnlockablesAndExtraEmblems(true, true))
|
||||
S_StartSound(NULL, sfx_ncitem);
|
||||
gamedata->deferredsave = true;
|
||||
}
|
||||
|
||||
mapheaderinfo[gamemap-1]->records.spraycan = can_id;
|
||||
|
||||
if (!M_UpdateUnlockablesAndExtraEmblems(true, true))
|
||||
S_StartSound(NULL, sfx_ncitem);
|
||||
gamedata->deferredsave = true;
|
||||
|
||||
{
|
||||
mobj_t *canmo = NULL;
|
||||
mobj_t *next = NULL;
|
||||
|
|
|
|||
39
src/p_mobj.c
39
src/p_mobj.c
|
|
@ -12915,9 +12915,9 @@ static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj)
|
|||
void P_SprayCanInit(mobj_t* mobj)
|
||||
{
|
||||
// See also P_TouchSpecialThing
|
||||
UINT16 can_id = mapheaderinfo[gamemap-1]->cache_spraycan;
|
||||
UINT16 can_id = mapheaderinfo[gamemap-1]->records.spraycan;
|
||||
|
||||
if (can_id < gamedata->numspraycans)
|
||||
if (can_id < gamedata->numspraycans || can_id == MCAN_BONUS)
|
||||
{
|
||||
// Assigned to this level, has been grabbed
|
||||
mobj->renderflags = (tr_trans50 << RF_TRANSSHIFT);
|
||||
|
|
@ -12925,19 +12925,38 @@ void P_SprayCanInit(mobj_t* mobj)
|
|||
// Prevent footguns - these won't persist when custom levels are unloaded
|
||||
else if (gamemap-1 < basenummapheaders)
|
||||
{
|
||||
// Unassigned, get the next grabbable colour (offset by threshold)
|
||||
can_id = gamedata->gotspraycans;
|
||||
if (gamedata->gotspraycans >= gamedata->numspraycans)
|
||||
{
|
||||
can_id = MCAN_BONUS;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Unassigned, get the next grabbable colour (offset by threshold)
|
||||
can_id = gamedata->gotspraycans;
|
||||
|
||||
// It's ok if this goes over gamedata->numspraycans, as they're
|
||||
// capped below in this func... but NEVER let this go backwards!!
|
||||
if (mobj->threshold != 0)
|
||||
can_id += (mobj->threshold & UINT8_MAX);
|
||||
// It's ok if this goes over gamedata->numspraycans, as they're
|
||||
// capped below in this func... but NEVER let this go backwards!!
|
||||
if (mobj->threshold != 0)
|
||||
can_id += (mobj->threshold & UINT8_MAX);
|
||||
}
|
||||
|
||||
mobj->renderflags = 0;
|
||||
}
|
||||
|
||||
if (can_id < gamedata->numspraycans)
|
||||
else
|
||||
{
|
||||
// Custom course, bonus only
|
||||
can_id = MCAN_BONUS;
|
||||
}
|
||||
|
||||
if (can_id == MCAN_BONUS && mobj->threshold == 0)
|
||||
{
|
||||
// Only one bonus possible
|
||||
// We modify sprite instead of state for netsync reasons
|
||||
mobj->sprite = SPR_SBON;
|
||||
}
|
||||
else if (can_id < gamedata->numspraycans)
|
||||
{
|
||||
mobj->sprite = mobj->state->sprite;
|
||||
mobj->color = gamedata->spraycans[can_id].col;
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -498,14 +498,13 @@ static void P_ClearSingleMapHeaderInfo(INT16 num)
|
|||
#endif
|
||||
|
||||
memset(&mapheaderinfo[num]->records, 0, sizeof(recorddata_t));
|
||||
mapheaderinfo[num]->records.spraycan = MCAN_INVALID;
|
||||
|
||||
mapheaderinfo[num]->justPlayed = 0;
|
||||
mapheaderinfo[num]->anger = 0;
|
||||
|
||||
mapheaderinfo[num]->destroyforchallenge_size = 0;
|
||||
|
||||
mapheaderinfo[num]->cache_spraycan = UINT16_MAX;
|
||||
|
||||
mapheaderinfo[num]->cache_maplock = MAXUNLOCKABLES;
|
||||
|
||||
mapheaderinfo[num]->customopts = NULL;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue