291 lines
11 KiB
C++
291 lines
11 KiB
C++
//===== Copyright © 1996-2009, Valve Corporation, All rights reserved. ======//
|
|
//
|
|
// Purpose:
|
|
//
|
|
//===========================================================================//
|
|
|
|
#include "mm_title.h"
|
|
#include "portal2.spa.h"
|
|
#include "matchmaking/portal2/imatchext_portal2.h"
|
|
|
|
#include "steam/isteamuserstats.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
static TitleDataFieldsDescription_t const * PrepareTitleDataStorageDescription()
|
|
{
|
|
#define TD_ENTRY( szName, nTD, eDataType, numBytesOffset ) \
|
|
{ \
|
|
TitleDataFieldsDescription_t aTDFD = { szName, TitleDataFieldsDescription_t::nTD, TitleDataFieldsDescription_t::eDataType, numBytesOffset }; \
|
|
s_tdfd.AddToTail( aTDFD ); \
|
|
}
|
|
|
|
static CUtlVector< TitleDataFieldsDescription_t > s_tdfd;
|
|
|
|
// Single player progress
|
|
TD_ENTRY( "SP.progress", DB_TD1, DT_uint32, offsetof( TitleData1, uiSinglePlayerProgressChapter ) );
|
|
|
|
// COOP MAPS
|
|
#define CFG( fieldname, ctx, idx, num ) \
|
|
TD_ENTRY( "MP.complete." #fieldname,DB_TD1, DT_BITFIELD, 8*offsetof( TitleData1, coop.mapbits ) + TitleData1::CoopData_t::fieldname )
|
|
#define CFG_DISABLED( fieldname, ctx, idx, num )
|
|
#include "xlast_portal2/inc_coop_maps.inc"
|
|
#undef CFG_DISABLED
|
|
#undef CFG
|
|
|
|
// COOP TAUNTS
|
|
TD_ENTRY( "MP.taunt.own", DB_TD1, DT_0, 8*offsetof( TitleData1, coop.tauntbitsOwned ) + 0 )
|
|
#define CFG( fieldname ) \
|
|
TD_ENTRY( "MP.taunt.own." #fieldname,DB_TD1, DT_BITFIELD, 8*offsetof( TitleData1, coop.tauntbitsOwned ) + TitleData1::CoopData_t::taunt_##fieldname ) \
|
|
TD_ENTRY( "MP.taunt.use." #fieldname,DB_TD1, DT_BITFIELD, 8*offsetof( TitleData1, coop.tauntbitsUsed ) + TitleData1::CoopData_t::taunt_##fieldname )
|
|
#define CFG_DISABLED( fieldname )
|
|
#include "xlast_portal2/inc_coop_taunts.inc"
|
|
#undef CFG_DISABLED
|
|
#undef CFG
|
|
// #define CFG( fieldname ) \
|
|
// TD_ENTRY( "MP.taunt.equipslot." #fieldname,DB_TD1, DT_uint8, offsetof( TitleData1, coop.tauntsEquipSlots[ TitleData1::CoopData_t::taunt_equipslot_##fieldname ] ) )
|
|
// #include "xlast_portal2/inc_coop_taunts_equipslots.inc"
|
|
// #undef CFG
|
|
|
|
// GAME INSTRUCTOR LESSONS
|
|
#define CFG( fieldname ) \
|
|
TD_ENTRY( "GI.lesson." #fieldname, DB_TD1, DT_uint8, offsetof( TitleData1, gameinstructor.lessoninfo[ TitleData1::GameInstructorData_t::lesson_##fieldname ] ) )
|
|
#define CFG_DISABLED( fieldname )
|
|
#include "xlast_portal2/inc_gameinstructor_lessons.inc"
|
|
#undef CFG_DISABLED
|
|
#undef CFG
|
|
|
|
// Storage for achievements components
|
|
uint32 uiAchievementComponentBitsUsed = 0;
|
|
#define CFG( name, compcount, ... ) \
|
|
{ \
|
|
COMPILE_TIME_ASSERT( (compcount == 0) || (compcount > 1) ); \
|
|
int numAchNameChars = Q_strlen( "ACH." #name ); \
|
|
for ( int iComponent = 0; iComponent < compcount; ++ iComponent ) \
|
|
{ \
|
|
char *pszComponentName = new char[ numAchNameChars + 10 ]; \
|
|
Q_snprintf( pszComponentName, numAchNameChars + 10, "%s[%d]", "ACH." #name, iComponent+1 ); \
|
|
TD_ENTRY( pszComponentName, DB_TD2, DT_BITFIELD, 8*offsetof( TitleData2, bitsAchievementsComponents ) + uiAchievementComponentBitsUsed + iComponent ) \
|
|
} \
|
|
uiAchievementComponentBitsUsed += 32 * STORAGE_COUNT_FOR_BITS( uint32, compcount ); \
|
|
}
|
|
#include "inc_achievements.inc"
|
|
#undef CFG
|
|
|
|
#ifdef _X360
|
|
// Awards bitfields
|
|
#define CFG( award, ... ) \
|
|
TD_ENTRY( "AV_TD_" #award, DB_TD2, DT_BITFIELD, 8*offsetof( TitleData2, awardbits ) + TitleData2::bitAward##award )
|
|
#include "xlast_portal2/inc_asset_awards.inc"
|
|
#undef CFG
|
|
#endif
|
|
|
|
// Custom achievements data
|
|
{
|
|
char const *szAch = "ACH.SPREAD_THE_LOVE";
|
|
int numAchNameChars = Q_strlen( szAch );
|
|
for ( int iComponent = 0; iComponent < TitleData2::kAchievement_SpreadTheLove_FriendsHuggedCount; ++ iComponent )
|
|
{
|
|
char *pszComponentName = new char[ numAchNameChars + 10 ];
|
|
Q_snprintf( pszComponentName, numAchNameChars + 10, "%s[%d]", szAch, iComponent+1 );
|
|
TD_ENTRY( pszComponentName, DB_TD2, DT_uint64, offsetof( TitleData2, ach_SpreadTheLove_FriendsHugged[iComponent] ) );
|
|
}
|
|
}
|
|
{
|
|
char const *szAch = "ACH.SPEED_RUN_COOP";
|
|
int numAchNameChars = Q_strlen( szAch );
|
|
for ( int iComponent = 0; iComponent < TitleData2::kAchievement_SpeedRunCoop_QualifiedRunsCount; ++ iComponent )
|
|
{
|
|
char *pszComponentName = new char[ numAchNameChars + 10 ];
|
|
Q_snprintf( pszComponentName, numAchNameChars + 10, "%s[%d]", szAch, iComponent+1 );
|
|
TD_ENTRY( pszComponentName, DB_TD2, DT_uint16, offsetof( TitleData2, ach_SpeedRunCoop_MapsQualified[iComponent] ) );
|
|
}
|
|
}
|
|
|
|
#ifdef _PS3
|
|
// DLC ownership bits
|
|
#define CFG( fieldname ) \
|
|
TD_ENTRY( "DLC." #fieldname,DB_TD2, DT_BITFIELD, 8*offsetof( TitleData2, dlcbits ) + fieldname )
|
|
CFG( 0x12 )
|
|
CFG( 0x13 )
|
|
CFG( 0x14 )
|
|
#undef CFG
|
|
#endif
|
|
|
|
#ifdef _GAMECONSOLE
|
|
// system convars
|
|
#define CFG( name, scfgType, cppType, ... ) \
|
|
TD_ENTRY( "CFG.sys." #name, DB_TD3, DT_##cppType, offsetof( TitleData3, cvSystem.name ) )
|
|
#include "xlast_portal2/inc_gameconsole_settings_sys.inc"
|
|
#undef CFG
|
|
#define CFG( name ) \
|
|
TD_ENTRY( "CFG.sys." #name, DB_TD3, DT_BITFIELD, 8*offsetof( TitleData3, cvSystem.bitfields ) + TitleData3::ConVarsSystem_t::name )
|
|
#include "xlast_portal2/inc_gameconsole_settings_sys_bits.inc"
|
|
#undef CFG
|
|
// profile-specific convars
|
|
#define CFG( name, scfgType, cppType ) \
|
|
TD_ENTRY( "CFG.usr." #name, DB_TD3, DT_##cppType, offsetof( TitleData3, cvUser.name ) ) \
|
|
TD_ENTRY( "CFG.usrSS." #name, DB_TD3, DT_##cppType, offsetof( TitleData3, cvUserSS.name ) )
|
|
#include "xlast_portal2/inc_gameconsole_settings_usr.inc"
|
|
#undef CFG
|
|
#define CFG( name ) \
|
|
TD_ENTRY( "CFG.usr." #name, DB_TD3, DT_BITFIELD, 8*offsetof( TitleData3, cvUser.bitfields ) + TitleData3::ConVarsUser_t::name ) \
|
|
TD_ENTRY( "CFG.usrSS." #name, DB_TD3, DT_BITFIELD, 8*offsetof( TitleData3, cvUserSS.bitfields ) + TitleData3::ConVarsUser_t::name )
|
|
#include "xlast_portal2/inc_gameconsole_settings_usr_bits.inc"
|
|
#undef CFG
|
|
#endif
|
|
|
|
// game stats
|
|
#define CFG( name, scfgType, cppType ) \
|
|
TD_ENTRY( "GAME." #name, DB_TD3, DT_##cppType, offsetof( TitleData3, gamestats.name ) )
|
|
#include "xlast_portal2/inc_gamestats.inc"
|
|
#undef CFG
|
|
|
|
// END MARKER
|
|
TD_ENTRY( NULL, DB_TD1, DT_0, 0 )
|
|
|
|
#undef TD_ENTRY
|
|
|
|
COMPILE_TIME_ASSERT( TitleData1::CoopData_t::mapbits_total >= TitleData1::CoopData_t::mapbits_last_bit_used );
|
|
COMPILE_TIME_ASSERT( TitleData1::CoopData_t::tauntbits_total >= TitleData1::CoopData_t::tauntbits_last_bit_used );
|
|
COMPILE_TIME_ASSERT( TitleData1::GameInstructorData_t::lessonbits_total >= TitleData1::GameInstructorData_t::lessonbits_last_bit_used );
|
|
|
|
return s_tdfd.Base();
|
|
}
|
|
|
|
TitleDataFieldsDescription_t const * CMatchTitle::DescribeTitleDataStorage()
|
|
{
|
|
static TitleDataFieldsDescription_t const *s_pTDFD = PrepareTitleDataStorageDescription();
|
|
return s_pTDFD;
|
|
}
|
|
|
|
TitleAchievementsDescription_t const * CMatchTitle::DescribeTitleAchievements()
|
|
{
|
|
static TitleAchievementsDescription_t tad[] =
|
|
{
|
|
#define CFG( name, compcount, ... ) \
|
|
{ "ACH." #name, ACHIEVEMENT_##name, compcount },
|
|
#include "inc_achievements.inc"
|
|
#undef CFG
|
|
// END MARKER
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
return tad;
|
|
}
|
|
|
|
TitleAvatarAwardsDescription_t const * CMatchTitle::DescribeTitleAvatarAwards()
|
|
{
|
|
static TitleAvatarAwardsDescription_t taad[] =
|
|
{
|
|
#define CFG( award, ... ) { "AV_" #award, AVATARASSETAWARD_##award, "AV_TD_" #award },
|
|
#include "inc_asset_awards.inc"
|
|
#undef CFG
|
|
// END MARKER
|
|
{ NULL, 0 }
|
|
};
|
|
|
|
return taad;
|
|
}
|
|
|
|
TitleDlcDescription_t const * CMatchTitle::DescribeTitleDlcs()
|
|
{
|
|
static TitleDlcDescription_t tdlcs[] =
|
|
{
|
|
{ PORTAL2_DLCID_RETAIL_DLC1, 0x80000001, 0x80000001, "DLC.0x01" },
|
|
{ PORTAL2_DLCID_COOP_BOT_SKINS, PORTAL2_DLC_APPID_COOP_BOT_SKINS, PORTAL2_DLC_PKGID_COOP_BOT_SKINS, "DLC.0x12" },
|
|
{ PORTAL2_DLCID_COOP_BOT_HELMETS, PORTAL2_DLC_APPID_COOP_BOT_HELMETS, PORTAL2_DLC_PKGID_COOP_BOT_HELMETS, "DLC.0x13" },
|
|
{ PORTAL2_DLCID_COOP_BOT_ANTENNA, PORTAL2_DLC_APPID_COOP_BOT_ANTENNA, PORTAL2_DLC_PKGID_COOP_BOT_ANTENNA, "DLC.0x14" },
|
|
// END MARKER
|
|
{ 0, 0, 0 }
|
|
};
|
|
|
|
return tdlcs;
|
|
}
|
|
|
|
// Title leaderboards
|
|
KeyValues * CMatchTitle::DescribeTitleLeaderboard( char const *szLeaderboardView )
|
|
{
|
|
// Check if this is a challenge leaderboard
|
|
if ( char const *szChallenge = StringAfterPrefix( szLeaderboardView, "challenge_besttime_" ) )
|
|
{
|
|
// if ( IsX360() )
|
|
// {
|
|
// // Find the corresponding record in the mission script
|
|
// KeyValues *pSettings = new KeyValues( "settings" );
|
|
// KeyValues::AutoDelete autodelete_pSettings( pSettings );
|
|
// pSettings->SetString( "game/mode", "survival" );
|
|
//
|
|
// KeyValues *pMissionInfo = NULL;
|
|
// KeyValues *pMapInfo = g_pMatchExtSwarm->GetMapInfoByBspName( pSettings, szSurvivalMap, &pMissionInfo );
|
|
// if ( !pMapInfo || !pMissionInfo )
|
|
// return NULL;
|
|
//
|
|
// // Find the leaderboard description in the map info
|
|
// KeyValues *pLbDesc = pMapInfo->FindKey( "x360leaderboard" );
|
|
// if ( !pLbDesc )
|
|
// return NULL;
|
|
//
|
|
// // Insert the required keys
|
|
// pLbDesc = pLbDesc->MakeCopy();
|
|
//
|
|
// static KeyValues *s_pRatingKey = KeyValues::FromString( ":rating", // X360 leaderboards are rated
|
|
// " name besttime " // game name of the rating field is "besttime"
|
|
// " type uint64 " // type is uint64
|
|
// " rule max" // rated field must be greater than cached value so that it can be written
|
|
// );
|
|
// pLbDesc->AddSubKey( s_pRatingKey->MakeCopy() );
|
|
// pLbDesc->SetString( "besttime/type", "uint64" );
|
|
//
|
|
// return pLbDesc;
|
|
// }
|
|
//
|
|
if ( !IsX360() )
|
|
{
|
|
KeyValues *pSettings = KeyValues::FromString( "SteamLeaderboard",
|
|
" :score besttime " // :score is the leaderboard value mapped to game name "besttime"
|
|
);
|
|
|
|
pSettings->SetInt( ":sort", k_ELeaderboardSortMethodAscending ); // Sort order when fetching and displaying leaderboard data
|
|
pSettings->SetInt( ":format", k_ELeaderboardDisplayTypeTimeMilliSeconds ); // Note: this is actually 1/100th seconds type, Steam change pending
|
|
pSettings->SetInt( ":upload", k_ELeaderboardUploadScoreMethodKeepBest ); // Upload method when writing to leaderboard
|
|
|
|
return pSettings;
|
|
}
|
|
}
|
|
if ( char const *szChallenge = StringAfterPrefix( szLeaderboardView, "challenge_distance_" ) )
|
|
{
|
|
if ( !IsX360() )
|
|
{
|
|
KeyValues *pSettings = KeyValues::FromString( "SteamLeaderboard",
|
|
" :score distance " // :score is the leaderboard value mapped to game name "distance"
|
|
);
|
|
|
|
pSettings->SetInt( ":sort", k_ELeaderboardSortMethodAscending ); // Sort order when fetching and displaying leaderboard data
|
|
pSettings->SetInt( ":format", k_ELeaderboardDisplayTypeNumeric ); // Note: this is actually 1/100th seconds type, Steam change pending
|
|
pSettings->SetInt( ":upload", k_ELeaderboardUploadScoreMethodKeepBest ); // Upload method when writing to leaderboard
|
|
|
|
return pSettings;
|
|
}
|
|
}
|
|
if ( char const *szChallenge = StringAfterPrefix( szLeaderboardView, "challenge_portals_" ) )
|
|
{
|
|
if ( !IsX360() )
|
|
{
|
|
KeyValues *pSettings = KeyValues::FromString( "SteamLeaderboard",
|
|
" :score portals " // :score is the leaderboard value mapped to game name "portals"
|
|
);
|
|
|
|
pSettings->SetInt( ":sort", k_ELeaderboardSortMethodAscending ); // Sort order when fetching and displaying leaderboard data
|
|
pSettings->SetInt( ":format", k_ELeaderboardDisplayTypeNumeric ); // Note: this is actually 1/100th seconds type, Steam change pending
|
|
pSettings->SetInt( ":upload", k_ELeaderboardUploadScoreMethodKeepBest ); // Upload method when writing to leaderboard
|
|
|
|
return pSettings;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|