Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_LocalPlayerPenalty.c
Go to the documentation of this file.
1[EntityEditorProps(category: "GameScripted/GameMode", description: "Takes care of player penalties, kicks, bans etc.", color: "0 0 255 255")]
3{
4}
5
6class SCR_LocalPlayerPenalty : Managed
7{
8 //[Attribute("3", desc: "Penalty score for killing a friendly player.")]
10
11 //[Attribute("1", desc: "Penalty score for killing a friendly AI.")]
13
14 //[Attribute("10", desc: "Penalty score limit for a kick from the match.")]
15 protected int m_iKickPenaltyLimit;
16
17 //[Attribute("1800", desc: "Ban duration after a kick (in seconds, -1 for a session-long ban).")]
18 protected int m_iBanDuration;
19
20 //[Attribute("900", desc: "How often penalty score subtraction happens (in seconds).")]
22
23 //[Attribute("2", desc: "How many penalty points get substracted after each subtraction period.")]
25
26 protected static SCR_LocalPlayerPenalty s_Instance;
27 protected static const int EVALUATION_PERIOD = 1000;
28
29 protected ref array<ref SCR_LocalPlayerPenaltyData> m_aPlayerPenaltyData = {};
30
31 //------------------------------------------------------------------------------------------------
33 void OnPlayerConnected(int playerId)
34 {
35 //GetPlayerPenaltyData creates the PlayerPenaltyStandaloneData for this playerId if it doesn't exist
36 GetPlayerPenaltyData(playerId);
37 }
38
39 //------------------------------------------------------------------------------------------------
44 void OnControllableDestroyed(IEntity entity, IEntity killerEntity, Instigator instigator, notnull SCR_InstigatorContextData instigatorContextData)
45 {
46 if (instigator.GetInstigatorType() != InstigatorType.INSTIGATOR_PLAYER || (m_iFriendlyAIKillPenalty == 0 && m_iFriendlyPlayerKillPenalty == 0))
47 return;
48
49 //~ Kill is not a teamkill and is not a warcrime
50 if (!instigatorContextData.DoesPlayerKillCountAsTeamKill() && !instigatorContextData.IsEnemyKillPunished(SCR_EDisguisedKillingPunishment.WARCRIME))
51 return;
52
53 SCR_ECharacterControlType victimControlType = instigatorContextData.GetVictimCharacterControlType();
54 int killerPlayerId = instigator.GetInstigatorPlayerID();
55
56 //~ Character killed by player (Unlimited editor players and admins do not get punished)
57 switch (victimControlType)
58 {
59 //~ When killed a player or player that is GM/Admin
60 case SCR_ECharacterControlType.PLAYER:
61 case SCR_ECharacterControlType.UNLIMITED_EDITOR:
62 {
63 SCR_LocalPlayerPenaltyData playerPenaltyData = GetPlayerPenaltyData(killerPlayerId);
64
65 if (playerPenaltyData)
67
68 break;
69 }
70 //~ When killing friendly AI or possessed AI (Possessed AI are treated as normal AI as they are hidden to the player)
72 case SCR_ECharacterControlType.POSSESSED_AI:
73 {
74 SCR_LocalPlayerPenaltyData playerPenaltyData = GetPlayerPenaltyData(killerPlayerId);
75
76 if (playerPenaltyData)
78
79 break;
80 }
81 }
82 }
83
84 //------------------------------------------------------------------------------------------------
86 static SCR_LocalPlayerPenalty GetInstance()
87 {
88 return s_Instance;
89 }
90
91 //------------------------------------------------------------------------------------------------
95 //IT SHOULD NOT BE STATIC. TODO: IMPROVE THIS
96 static SCR_ChimeraCharacter GetInstigatorFromVehicle(IEntity veh, bool gunner = false)
97 {
98 BaseCompartmentManagerComponent compartmentManager = BaseCompartmentManagerComponent.Cast(veh.FindComponent(BaseCompartmentManagerComponent));
99
100 if (!compartmentManager)
101 return null;
102
103 array<BaseCompartmentSlot> compartments = new array <BaseCompartmentSlot>();
104
105 for (int i = 0, cnt = compartmentManager.GetCompartments(compartments); i < cnt; i++)
106 {
107 BaseCompartmentSlot slot = compartments[i];
108
109 if (slot && (!gunner && slot.Type() == PilotCompartmentSlot) || (gunner && slot.Type() == TurretCompartmentSlot))
110 return SCR_ChimeraCharacter.Cast(slot.GetOccupant());
111 }
112
113 return null;
114 }
115
116 //------------------------------------------------------------------------------------------------
118 {
119 if (playerId == 0)
120 return null;
121
122 SCR_LocalPlayerPenaltyData playerPenaltyData;
123
124 // Check if the client is reconnecting
125 //Also if there's going to be many entries, the search might prove very expensive.
126 for (int i = 0, count = m_aPlayerPenaltyData.Count(); i < count; i++)
127 {
128 if (m_aPlayerPenaltyData[i].GetPlayerId() == playerId)
129 {
130 playerPenaltyData = m_aPlayerPenaltyData[i];
131 break;
132 }
133 }
134
135 // Client reconnected, return saved data
136 if (playerPenaltyData)
137 return playerPenaltyData;
138
139 // Check validity of playerId before registering new data
140 PlayerController pc = GetGame().GetPlayerManager().GetPlayerController(playerId);
141
142 if (!pc)
143 {
144 Print(string.Format("SCR_PlayerPenaltyComponent: No player with playerId %1 found.", playerId), LogLevel.ERROR);
145 return null;
146 }
147
148 // First connection, register new data
149 playerPenaltyData = new SCR_LocalPlayerPenaltyData();
150 playerPenaltyData.SetPlayerId(playerId);
151 m_aPlayerPenaltyData.Insert(playerPenaltyData);
152
153 return playerPenaltyData;
154 }
155
156 //------------------------------------------------------------------------------------------------
157 protected void EvaluatePlayerPenalties()
158 {
159 ChimeraWorld world = GetGame().GetWorld();
160 WorldTimestamp currentTime = world.GetServerTimestamp();
161 for (int i = 0, count = m_aPlayerPenaltyData.Count(); i < count; i++)
162 {
164
165 // Periodically forgive a portion of penalty score, don't go below zero
166 if (playerPenaltyData.GetPenaltyScore() > 0 && playerPenaltyData.GetNextPenaltySubtractionTimestamp().Less(currentTime))
167 {
168 int forgivenScore;
169
170 if (m_iPenaltySubtractionPoints > playerPenaltyData.GetPenaltyScore())
171 forgivenScore = playerPenaltyData.GetPenaltyScore();
172 else
173 forgivenScore = m_iPenaltySubtractionPoints;
174
175 playerPenaltyData.AddPenaltyScore(-forgivenScore);
176 }
177
178 int playerId = playerPenaltyData.GetPlayerId();
179
180 // Player is not connected
181 if (!GetGame().GetPlayerManager().GetPlayerController(playerId))
182 continue;
183
184 // Player is host
185 if (playerId == SCR_PlayerController.GetLocalPlayerId())
186 continue;
187
188 // Check penalty limit for kick / ban
189 if (m_iKickPenaltyLimit > 0 && playerPenaltyData.GetPenaltyScore() >= m_iKickPenaltyLimit)
190 {
191 // TODO: Use callback from backend instead
192 KickPlayer(playerId, m_iBanDuration, SCR_PlayerManagerKickReason.FRIENDLY_FIRE);
193 continue;
194 }
195 }
196 }
197
198 //------------------------------------------------------------------------------------------------
203 void KickPlayer(int playerId, int duration, SCR_PlayerManagerKickReason reason)
204 {
205 SCR_LocalPlayerPenaltyData playerPenaltyData = GetPlayerPenaltyData(playerId);
206
207 if (playerPenaltyData)
208 playerPenaltyData.AddPenaltyScore(-playerPenaltyData.GetPenaltyScore());
209
210 GetGame().GetPlayerManager().KickPlayer(playerId, reason, duration);
211 }
212
213 //------------------------------------------------------------------------------------------------
216 {
217 return m_iPenaltySubtractionPeriod * 1000; // Converting s to ms
218 }
219
220 //------------------------------------------------------------------------------------------------
221 // constructor
228 void SCR_LocalPlayerPenalty(int friendlyPlayerKillPenalty, int friendlyAIKillPenalty, int penaltyLimit, int banDuration, int penaltySubtractionPeriod, int penaltySubtractionPoints)
229 {
230 m_iFriendlyPlayerKillPenalty = friendlyPlayerKillPenalty;
231 m_iFriendlyAIKillPenalty = friendlyAIKillPenalty;
232 m_iKickPenaltyLimit = penaltyLimit;
233 m_iBanDuration = banDuration;
234 m_iPenaltySubtractionPeriod = penaltySubtractionPeriod;
235 m_iPenaltySubtractionPoints = penaltySubtractionPoints;
236
238 Print("SCR_PlayerPenaltyComponent: Ban duration is shorter than Penalty substraction period. This will cause the player to remain banned until their penalty is substracted.", LogLevel.WARNING);
239
240 s_Instance = this;
241 //Looping every EVALUATION_PERIOD seconds and don't need other EOn events
242 GetGame().GetCallqueue().CallLater(EvaluatePlayerPenalties, EVALUATION_PERIOD, true);
243 }
244}
245
247{
248 protected int m_iPlayerId;
249 protected int m_iPenaltyScore;
252
253 //------------------------------------------------------------------------------------------------
255 void SetPlayerId(int playerId)
256 {
257 m_iPlayerId = playerId;
258 }
259
260 //------------------------------------------------------------------------------------------------
263 {
264 return m_iPlayerId;
265 }
266
267 //------------------------------------------------------------------------------------------------
270 void AddPenaltyScore(int points)
271 {
272 m_iPenaltyScore += points;
273
274 // Start the timer on penalty substraction when player was penalized while the timer was stopped
275 ChimeraWorld world = GetGame().GetWorld();
276 WorldTimestamp currentTime = world.GetServerTimestamp();
277 if ((points > 0 && m_fNextPenaltySubtractionTimestamp.Less(currentTime)) || (points < 0 && m_iPenaltyScore > 0))
278 m_fNextPenaltySubtractionTimestamp = currentTime.PlusMilliseconds(SCR_LocalPlayerPenalty.GetInstance().GetPenaltySubtractionPeriod());
279 }
280
281 //------------------------------------------------------------------------------------------------
284 {
285 return m_iPenaltyScore;
286 }
287
288 //------------------------------------------------------------------------------------------------
294
295 //------------------------------------------------------------------------------------------------
301}
ArmaReforgerScripted GetGame()
Definition game.c:1398
enum SCR_ECompassType EntityEditorProps(category:"GameScripted/Gadgets", description:"Compass", color:"0 0 255 255")
Prefab data class for compass component.
SCR_ECharacterControlType
What kind of controller the character or (in some cases vehicle) has, eg: AI, Player,...
int m_iKickPenaltyLimit
void KickPlayer(int playerId, int duration, SCR_PlayerManagerKickReason reason)
int m_iFriendlyAIKillPenalty
void EvaluatePlayerPenalties()
void OnControllableDestroyed(IEntity entity, IEntity killerEntity, Instigator instigator, notnull SCR_InstigatorContextData instigatorContextData)
int m_iPenaltySubtractionPeriod
SCR_LocalPlayerPenaltyData GetPlayerPenaltyData(int playerId)
ref array< ref SCR_LocalPlayerPenaltyData > m_aPlayerPenaltyData
SCR_LocalPlayerPenaltyClass m_iFriendlyPlayerKillPenalty
int m_iPenaltySubtractionPoints
int GetPenaltySubtractionPeriod()
int m_iBanDuration
void SCR_LocalPlayerPenalty(int friendlyPlayerKillPenalty, int friendlyAIKillPenalty, int penaltyLimit, int banDuration, int penaltySubtractionPeriod, int penaltySubtractionPoints)
SCR_SpawnerSlotManagerClass s_Instance
Class used for managing changes and removals of slots present in world.
enum EVehicleType IEntity
proto external Managed FindComponent(typename typeName)
WorldTimestamp GetNextPenaltySubtractionTimestamp()
SCR_PlayerManagerKickReason m_eKickReason
void SetNextPenaltySubstractionTimestamp(WorldTimestamp timestamp)
WorldTimestamp m_fNextPenaltySubtractionTimestamp
static int GetLocalPlayerId()
Returns either a valid ID of local player or 0.
InstigatorType
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
proto external PlayerController GetPlayerController()
void OnPlayerConnected(int playerId)
proto external int GetPlayerId()