summaryrefslogtreecommitdiff
path: root/game/shared/econ/econ_holidays.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/shared/econ/econ_holidays.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/shared/econ/econ_holidays.cpp')
-rw-r--r--game/shared/econ/econ_holidays.cpp415
1 files changed, 415 insertions, 0 deletions
diff --git a/game/shared/econ/econ_holidays.cpp b/game/shared/econ/econ_holidays.cpp
new file mode 100644
index 0000000..afe1278
--- /dev/null
+++ b/game/shared/econ/econ_holidays.cpp
@@ -0,0 +1,415 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+
+#include "cbase.h"
+
+#include "rtime.h"
+#include "econ_holidays.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Interface that answers the simple question "on the passed-in time,
+// would this holiday be active?". Any caching of calculations is left
+// up to subclasses.
+//-----------------------------------------------------------------------------
+class IIsHolidayActive
+{
+public:
+ IIsHolidayActive( const char *pszHolidayName ) : m_pszHolidayName( pszHolidayName ) { }
+ virtual ~IIsHolidayActive ( ) { }
+ virtual bool IsActive( const CRTime& timeCurrent ) = 0;
+
+ const char *GetHolidayName() const { return m_pszHolidayName; }
+
+private:
+ const char *m_pszHolidayName;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Always-disabled. Dummy event needed to map to slot zero for "disabled
+// holiday".
+//-----------------------------------------------------------------------------
+class CNoHoliday : public IIsHolidayActive
+{
+public:
+ CNoHoliday() : IIsHolidayActive( "none" ) { }
+
+ virtual bool IsActive( const CRTime& timeCurrent )
+ {
+ return false;
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: A holiday that lasts exactly one and only one day.
+//-----------------------------------------------------------------------------
+class CSingleDayHoliday : public IIsHolidayActive
+{
+public:
+ CSingleDayHoliday( const char *pszName, int iMonth, int iDay )
+ : IIsHolidayActive( pszName )
+ , m_iMonth( iMonth )
+ , m_iDay( iDay )
+ {
+ //
+ }
+
+ virtual bool IsActive( const CRTime& timeCurrent )
+ {
+ return m_iMonth == timeCurrent.GetMonth()
+ && m_iDay == timeCurrent.GetDayOfMonth();
+ }
+
+private:
+ int m_iMonth;
+ int m_iDay;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: We want "week long" holidays to encompass at least two weekends,
+// so that players get plenty of time interacting with the holiday
+// features.
+//-----------------------------------------------------------------------------
+class CWeeksBasedHoliday : public IIsHolidayActive
+{
+public:
+ CWeeksBasedHoliday( const char *pszName, int iMonth, int iDay, int iExtraWeeks )
+ : IIsHolidayActive( pszName )
+ , m_iMonth( iMonth )
+ , m_iDay( iDay )
+ , m_iExtraWeeks( iExtraWeeks )
+ , m_iCachedCalculatedYear( 0 )
+ {
+ // We'll calculate the interval the first time we call IsActive().
+ }
+
+ void RecalculateTimeActiveInterval( int iYear )
+ {
+ // Get the date of the holiday.
+ tm holiday_tm = { };
+ holiday_tm.tm_mday = m_iDay;
+ holiday_tm.tm_mon = m_iMonth - 1;
+ holiday_tm.tm_year = iYear - 1900; // convert to years since 1900
+ mktime( &holiday_tm );
+
+ // The event starts on the first Friday at least four days prior to the holiday.
+ tm start_time_tm( holiday_tm );
+ start_time_tm.tm_mday -= 4; // Move back four days.
+ mktime( &start_time_tm );
+ int days_offset = start_time_tm.tm_wday - kFriday; // Find the nearest prior Friday.
+ if ( days_offset < 0 )
+ days_offset += 7;
+ start_time_tm.tm_mday -= days_offset;
+ time_t start_time = mktime( &start_time_tm );
+
+ // The event ends on the first Monday after the holiday, maybe plus some additional fudge
+ // time.
+ tm end_time_tm( holiday_tm );
+ days_offset = 7 - (end_time_tm.tm_wday - kMonday);
+ if ( days_offset >= 7 )
+ days_offset -= 7;
+ end_time_tm.tm_mday += days_offset + 7 * m_iExtraWeeks;
+ time_t end_time = mktime( &end_time_tm );
+
+#ifdef GC_DLL
+ char rgchDateStartBuf[ 128 ];
+ BGetLocalFormattedDate( start_time, rgchDateStartBuf, sizeof( rgchDateStartBuf) );
+
+ char rgchDateEndBuf[ 128 ];
+ BGetLocalFormattedDate( end_time, rgchDateEndBuf, sizeof( rgchDateEndBuf ) );
+
+ EmitInfo( GCSDK::SPEW_GC, 4, LOG_ALWAYS, "Holiday - '%s' event starts on '%s' and ends on '%s'.\n", GetHolidayName(), rgchDateStartBuf, rgchDateEndBuf );
+#endif // GC_DLL
+
+ m_timeStart = start_time;
+ m_timeEnd = end_time;
+
+ // We're done and our interval data is cached.
+ m_iCachedCalculatedYear = iYear;
+ }
+
+ virtual bool IsActive( const CRTime& timeCurrent )
+ {
+ const int iCurrentYear = timeCurrent.GetYear();
+ if ( m_iCachedCalculatedYear != iCurrentYear )
+ RecalculateTimeActiveInterval( iCurrentYear );
+
+ return timeCurrent.GetRTime32() > m_timeStart
+ && timeCurrent.GetRTime32() < m_timeEnd;
+ }
+
+private:
+ static const int kMonday = 1;
+ static const int kFriday = 5;
+
+ int m_iMonth;
+ int m_iDay;
+ int m_iExtraWeeks;
+
+ // Filled out from RecalculateTimeActiveInterval().
+ int m_iCachedCalculatedYear;
+
+ RTime32 m_timeStart;
+ RTime32 m_timeEnd;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: A holiday that repeats on a certain time interval, like "every N days"
+// or "once every two months" or, uh, "any time there's a full moon".
+//-----------------------------------------------------------------------------
+class CCyclicalHoliday : public IIsHolidayActive
+{
+public:
+ CCyclicalHoliday( const char *pszName, int iMonth, int iDay, int iYear, float fCycleLengthInDays, float fBonusTimeInDays )
+ : IIsHolidayActive( pszName )
+ , m_fCycleLengthInDays( fCycleLengthInDays )
+ , m_fBonusTimeInDays( fBonusTimeInDays )
+ {
+ // When is our initial interval?
+ tm holiday_tm = { };
+ holiday_tm.tm_mday = iDay;
+ holiday_tm.tm_mon = iMonth - 1;
+ holiday_tm.tm_year = iYear - 1900; // convert to years since 1900
+ m_timeInitial = mktime( &holiday_tm );
+ }
+
+ virtual bool IsActive( const CRTime& timeCurrent )
+ {
+ // Days-to-seconds conversion.
+ const int iSecondsPerDay = 24 * 60 * 60;
+
+ // Convert our cycle/buffer times to seconds.
+ const int iCycleLengthInSeconds = (int)(m_fCycleLengthInDays * iSecondsPerDay);
+ const int iBufferTimeInSeconds = (int)(m_fBonusTimeInDays * iSecondsPerDay);
+
+ // How long has it been since we started this cycle?
+ int iSecondsIntoCycle = (timeCurrent.GetRTime32() - m_timeInitial) % iCycleLengthInSeconds;
+
+ // If we're within the buffer period right after the start of a cycle, we're active.
+ if ( iSecondsIntoCycle < iBufferTimeInSeconds )
+ return true;
+
+ // If we're within the buffer period towards the end of a cycle, we're active.
+ if ( iSecondsIntoCycle > iCycleLengthInSeconds - iBufferTimeInSeconds )
+ return true;
+
+ // Alas, normal mode for us.
+ return false;
+ }
+
+private:
+ time_t m_timeInitial ;
+
+ float m_fCycleLengthInDays;
+ float m_fBonusTimeInDays;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: A pseudo-holiday that is active when either of its child holidays
+// is active. Works through pointers but does not manage memory.
+//-----------------------------------------------------------------------------
+class COrHoliday : public IIsHolidayActive
+{
+public:
+ COrHoliday( const char *pszName, IIsHolidayActive *pA, IIsHolidayActive *pB )
+ : IIsHolidayActive( pszName )
+ , m_pA( pA )
+ , m_pB( pB )
+ {
+ Assert( pA );
+ Assert( pB );
+ Assert( pA != pB );
+ }
+
+ virtual bool IsActive( const CRTime& timeCurrent )
+ {
+ return m_pA->IsActive( timeCurrent )
+ || m_pB->IsActive( timeCurrent );
+ }
+
+private:
+ IIsHolidayActive *m_pA;
+ IIsHolidayActive *m_pB;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Holiday that is defined by a start and end date
+//-----------------------------------------------------------------------------
+class CDateBasedHoliday : public IIsHolidayActive
+{
+public:
+ CDateBasedHoliday( const char *pszName, const char *pszStartTime, const char *pszEndTime )
+ : IIsHolidayActive( pszName )
+ {
+ m_rtStartTime = CRTime::RTime32FromString( pszStartTime );
+ m_rtEndTime = CRTime::RTime32FromString( pszEndTime );
+ }
+
+ virtual bool IsActive( const CRTime& timeCurrent )
+ {
+ return ( ( timeCurrent >= m_rtStartTime ) && ( timeCurrent <= m_rtEndTime ) );
+ }
+
+ RTime32 GetEndRTime() const
+ {
+ return m_rtEndTime.GetRTime32();
+ }
+
+
+private:
+ CRTime m_rtStartTime;
+ CRTime m_rtEndTime;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Holiday that is defined by a start and end date with no year specified
+//-----------------------------------------------------------------------------
+class CDateBasedHolidayNoSpecificYear : public IIsHolidayActive
+{
+public:
+ CDateBasedHolidayNoSpecificYear( const char *pszName, const char *pszStartTime, const char *pszEndTime )
+ : IIsHolidayActive( pszName )
+ , m_pszStartTime( pszStartTime )
+ , m_pszEndTime( pszEndTime )
+ , m_iCachedYear( -1 )
+ {
+ }
+
+ virtual bool IsActive( const CRTime& timeCurrent )
+ {
+ const int iYear = timeCurrent.GetYear();
+
+ if ( iYear != m_iCachedYear )
+ {
+ char m_szStartTime[k_RTimeRenderBufferSize];
+ char m_szEndTime[k_RTimeRenderBufferSize];
+
+ V_sprintf_safe( m_szStartTime, "%d-%s", iYear, m_pszStartTime );
+ V_sprintf_safe( m_szEndTime, "%d-%s", iYear, m_pszEndTime );
+
+ m_iCachedYear = iYear;
+ m_rtCachedStartTime = CRTime::RTime32FromString( m_szStartTime );
+ m_rtCachedEndTime = CRTime::RTime32FromString( m_szEndTime );
+ }
+
+ return ( ( timeCurrent >= m_rtCachedStartTime ) && ( timeCurrent <= m_rtCachedEndTime ) );
+ }
+
+private:
+ const char *m_pszStartTime;
+ const char *m_pszEndTime;
+
+ int m_iCachedYear;
+ CRTime m_rtCachedStartTime;
+ CRTime m_rtCachedEndTime;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Actual holiday implementation objects.
+//-----------------------------------------------------------------------------
+
+static CNoHoliday g_Holiday_NoHoliday;
+
+static CDateBasedHolidayNoSpecificYear g_Holiday_TF2Birthday ( "birthday", "08-23", "08-25" );
+
+static CDateBasedHoliday g_Holiday_Halloween ( "halloween", "2016-10-19", "2016-11-18" );
+
+static CDateBasedHoliday g_Holiday_Christmas ( "christmas", "2016-11-28", "2017-01-12" );
+
+static CDateBasedHolidayNoSpecificYear g_Holiday_ValentinesDay ( "valentines", "02-13", "02-15" );
+
+static CDateBasedHoliday g_Holiday_MeetThePyro ( "meet_the_pyro", "2012-06-26", "2012-07-05" );
+ /* starting date cycle length in days bonus time in days on both sides */
+static CCyclicalHoliday g_Holiday_FullMoon ( "fullmoon", 5, 21, 2016, 29.53f, 1.0f );
+ // note: the cycle length is 29.5 instead of 29.53 so that the time calculations always start at noon based on the way CCyclicalHoliday works
+static COrHoliday g_Holiday_HalloweenOrFullMoon ( "halloween_or_fullmoon", &g_Holiday_Halloween, &g_Holiday_FullMoon );
+
+static COrHoliday g_Holiday_HalloweenOrFullMoonOrValentines ( "halloween_or_fullmoon_or_valentines", &g_Holiday_HalloweenOrFullMoon, &g_Holiday_ValentinesDay );
+
+static CDateBasedHolidayNoSpecificYear g_Holiday_AprilFools ( "april_fools", "03-31", "04-02" );
+
+static CDateBasedHoliday g_Holiday_EndOfTheLine ( "eotl_launch", "2014-12-03", "2015-01-05" );
+
+static CDateBasedHoliday g_Holiday_CommunityUpdate ( "community_update", "2015-09-01", "2015-11-05" );
+
+// ORDER NEEDS TO MATCH enum EHoliday
+static IIsHolidayActive *s_HolidayChecks[] =
+{
+ &g_Holiday_NoHoliday, // kHoliday_None
+ &g_Holiday_TF2Birthday, // kHoliday_TFBirthday
+ &g_Holiday_Halloween, // kHoliday_Halloween
+ &g_Holiday_Christmas, // kHoliday_Christmas
+ &g_Holiday_CommunityUpdate, // kHoliday_CommunityUpdate
+ &g_Holiday_EndOfTheLine, // kHoliday_EOTL
+ &g_Holiday_ValentinesDay, // kHoliday_Valentines
+ &g_Holiday_MeetThePyro, // kHoliday_MeetThePyro
+ &g_Holiday_FullMoon, // kHoliday_FullMoon
+ &g_Holiday_HalloweenOrFullMoon, // kHoliday_HalloweenOrFullMoon
+ &g_Holiday_HalloweenOrFullMoonOrValentines, // kHoliday_HalloweenOrFullMoonOrValentines
+ &g_Holiday_AprilFools, // kHoliday_AprilFools
+};
+
+COMPILE_TIME_ASSERT( ARRAYSIZE( s_HolidayChecks ) == kHolidayCount );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool EconHolidays_IsHolidayActive( int iHolidayIndex, const CRTime& timeCurrent )
+{
+ if ( iHolidayIndex < 0 || iHolidayIndex >= kHolidayCount )
+ return false;
+
+ Assert( s_HolidayChecks[iHolidayIndex] );
+ if ( !s_HolidayChecks[iHolidayIndex] )
+ return false;
+
+ return s_HolidayChecks[iHolidayIndex]->IsActive( timeCurrent );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int EconHolidays_GetHolidayForString( const char* pszHolidayName )
+{
+ for ( int iHoliday = 0; iHoliday < kHolidayCount; ++iHoliday )
+ {
+ Assert( s_HolidayChecks[iHoliday] );
+ if ( s_HolidayChecks[iHoliday] &&
+ 0 == Q_stricmp( pszHolidayName, s_HolidayChecks[iHoliday]->GetHolidayName() ) )
+ {
+ return iHoliday;
+ }
+ }
+
+ return kHoliday_None;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+const char *EconHolidays_GetActiveHolidayString()
+{
+ CRTime timeNow;
+ timeNow.SetToCurrentTime();
+ timeNow.SetToGMT( true );
+
+ for ( int iHoliday = 0; iHoliday < kHolidayCount; iHoliday++ )
+ {
+ if ( EconHolidays_IsHolidayActive( iHoliday, timeNow ) )
+ {
+ Assert( s_HolidayChecks[iHoliday] );
+ return s_HolidayChecks[iHoliday]->GetHolidayName();
+ }
+ }
+
+ // No holidays currently active.
+ return NULL;
+}
+
+#if defined(TF_CLIENT_DLL) || defined(TF_DLL) || defined(TF_GC_DLL)
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+RTime32 EconHolidays_TerribleHack_GetHalloweenEndData()
+{
+ return g_Holiday_Halloween.GetEndRTime();
+}
+#endif // defined(TF_CLIENT_DLL) || defined(TF_DLL) || defined(TF_GC_DLL)