summaryrefslogtreecommitdiff
path: root/game/server/tf/tf_achievementdata.h
blob: 7c596e4fadaaaaaf3211a3714de1d978e9d0be64 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//========= Copyright Valve Corporation, All rights reserved. ============//
//
//=============================================================================
#ifndef TF_ACHIEVEMENT_DATA_H
#define TF_ACHIEVEMENT_DATA_H
#pragma once

#include "UtlSortVector.h"

#define MAX_ACHIEVEMENT_HISTORY_SLOTS	4
#define MAX_ACHIEVEMENT_DAMAGE_HISTORY_SLOTS	128

//=============================================================================
// Custom class to manage lists of history events. Maintains a prioritized list of 
// events, but includes two extra features: 
//		- Maximum size of the number of entries in the queue.
//		- Ensures each associated-entity in the entries appears only once in the queue.
template <class T, class LessFunc, int maxSize>
class CHistoryVector : public CUtlSortVector<T, LessFunc>
{
public:
	CHistoryVector()
	{
	}

	void InsertHistory( T const &element )
	{
		LessFunc less;

		// Make sure it's not in the list already
		for ( int i = 0; i < this->Count(); i++ )
		{
			if ( less.HistoryMatch( this->Element(i), element ) )
			{
				this->Remove( i );
				break;
			}
		}

		CUtlSortVector<T, LessFunc>::Insert( element );

		// Remove the oldest entry if we're over max size
		if ( this->Count() > maxSize )
		{
			this->Remove( this->Count()-1 );
		}
	}
};

//=============================================================================
// Data stored in players for achievement handling
struct EntityHistory_t
{
	EHANDLE hEntity;
	EHANDLE hObject;
	float	flTimeDamage;
};

struct EntityDamageHistory_t : public EntityHistory_t
{
	int	nDamageAmount;
};


class CEntityHistoryLess
{
public:
	bool Less( const EntityHistory_t &dmg1, const EntityHistory_t &dmg2, void *pCtx )
	{
		return (dmg1.flTimeDamage > dmg2.flTimeDamage);
	}
	bool HistoryMatch( const EntityHistory_t &dmg1, const EntityHistory_t &dmg2 )
	{
		return (dmg1.hEntity == dmg2.hEntity);
	}
};

// Allow duplicate (source) entries with this type; HistoryMatch always returns false
class CEntityDamageHistoryLess
{
public:
	bool Less( const EntityDamageHistory_t &dmg1, const EntityDamageHistory_t &dmg2, void *pCtx )
	{
		return ( dmg2.flTimeDamage < dmg1.flTimeDamage );
	}
	bool HistoryMatch( const EntityDamageHistory_t &dmg1, const EntityDamageHistory_t &dmg2 )
	{
		return false;
	}
};

// Achievement Tracking container
class CAchievementData
{
public:
	void ClearHistories( void )
	{
		aDamagers.RemoveAll();
		aDamageEvents.RemoveAll();
		aTargets.RemoveAll();
		aSentryDamagers.RemoveAll();
		aPushers.RemoveAll();
	}

	void				AddDamagerToHistory( EHANDLE hDamager );
	EntityHistory_t		*GetDamagerHistory( int i ) { if (i >= aDamagers.Count()) return NULL; return &aDamagers[i]; }
	int					CountDamagersWithinTime( float flTime );
	bool				IsDamagerInHistory( CBaseEntity *pTarget, float flTimeWindow );
	void				DumpDamagers( void );

	// Capture the last 64 damage events - duplicates allowed
	void				AddDamageEventToHistory( EHANDLE hAttacker, float flDmgAmount = 0.f );
	EntityDamageHistory_t *GetDamageEventHistory( int i ) { if ( i >= aDamageEvents.Count() ) return NULL; return &aDamageEvents[i]; }
	int					GetDamageEventHistoryCount( void ) { return aDamageEvents.Count(); }
	bool				IsEntityInDamageEventHistory( CBaseEntity *pEntity, float flTimeWindow );
	int					GetAmountForDamagerInEventHistory( CBaseEntity *pEntity, float flTimeWindow );

	void				AddTargetToHistory( EHANDLE hTarget );
	bool				IsTargetInHistory( CBaseEntity *pTarget, float flTimeWindow );
	EntityHistory_t		*GetTargetHistory( int i ) { if (i >= aTargets.Count()) return NULL; return &aTargets[i]; }
	int					CountTargetsWithinTime( float flTime );

	void                AddSentryDamager( EHANDLE hDamager, EHANDLE hObject );
	EntityHistory_t     *IsSentryDamagerInHistory( CBaseEntity *pDamager, float flTimeWindow );

	void				AddPusherToHistory( EHANDLE hPlayer );
	bool				IsPusherInHistory( CBaseEntity *pPlayer, float flTimeWindow );

private:
	CHistoryVector< EntityHistory_t, CEntityHistoryLess, MAX_ACHIEVEMENT_HISTORY_SLOTS > aDamagers;
	CHistoryVector< EntityDamageHistory_t, CEntityDamageHistoryLess, MAX_ACHIEVEMENT_DAMAGE_HISTORY_SLOTS > aDamageEvents;	// Duplicates allowed
	CHistoryVector< EntityHistory_t, CEntityHistoryLess, MAX_ACHIEVEMENT_HISTORY_SLOTS > aTargets;
	CHistoryVector< EntityHistory_t, CEntityHistoryLess, MAX_ACHIEVEMENT_HISTORY_SLOTS > aSentryDamagers;
	CHistoryVector< EntityHistory_t, CEntityHistoryLess, MAX_ACHIEVEMENT_HISTORY_SLOTS > aPushers;
};

#endif