diff --git a/Server_Install_Pack/sc/battleye/scripts.txt b/Server_Install_Pack/sc/battleye/scripts.txt
index eb06f35f..14ad9b24 100644
--- a/Server_Install_Pack/sc/battleye/scripts.txt
+++ b/Server_Install_Pack/sc/battleye/scripts.txt
@@ -23,7 +23,7 @@
5 createVehicleLocal !="\"Sign_Arrow_Direction_Yellow_F\" createVehicleLocal" !="\"#particlesource\" createVehicleLocal" !="\"#lightpoint\" createVehicleLocal" !="\"BloodSplat\" createVehicleLocal" !="[\"lightning1_F\", \"lightning2_F\"] call BIS_fnc_selectRandom;\n_lighting = _class createVehicleLocal" !="SLX_XEH_DUMMY createVehicleLocal [0, 0, 0];" !="CBA_eventHandlers = \"Logic\" createVehicleLocal [0, 0];"
5 createUnit !="_driver = _grp createUnit[\"I_UAV_AI\", position _unit, [], 0, \"CAN_COLLIDE\"];" !="axeGeneral = grpVIPGeneral createUnit [\"I_officer_F\", axeGeneralPos, [], 1, \"CAN_COLLIDE\"];" !="bis_functions_mainscope = _grpLogic createunit [\"Logic\",[9,9,9],[],0,\"none\"];" !="_unit = _grp createUnit[selectRandom _arrUnits, _pos, [], 0, \"FORM\"];" !="_driver = (group player) createUnit[\"I_UAV_AI\", position axeUAV, [], 0, \"CAN_COLLIDE\"];"
5 createAgent !="bis_revive_ratioLethal = createAgent [\"Logic\", [10,10,0], [], 0, \"CAN_COLLIDE\"];" !="_unit = createAgent[_unitClass, _targetPos, [], 256, \"FORM\"];" !="_unit = createAgent [_unitClass, _targetPos, [], 120, \"FORM\"];" !="_animal = createAgent[_randomAIClass, _animalPos, [], 5, \"NONE\"];" !="_unit = createAgent [\"Epoch_Cloak_F\", _pos, [], 0, \"CAN_COLLIDE\"];" !="_unit = createAgent [\"Epoch_Sapper_F\", _targetPos, [], 180, \"FORM\"];" !="_sapper = createAgent [\"Epoch_Sapper_F\", getPos _cage2, [], 0, \"FORM\"];" !="_unit = createAgent[_unitClass, position player, [], _zRange, \"FORM\"];" !="_animal = createAgent[_randomAIClass, _animalPos, [], 0, \"CAN_COLLIDE\"];" !="_axeSapper = createAgent [\"Epoch_Sapper_F\", _pos, [], 12, \"FORM\"];" !="_nestMate = createAgent [\"Epoch_Sapper_F\", _garrPos, [], 0, \"FORM\"];"
-5 createDialog !="createDialog 'server_info_picture'" !="createdialog 'epoch_tablet_gui'" !="createdialog 'Epoch_CamDialog'" !="createDialog \"rmx_dynamenu\";" !="createDialog \"rmx_craftingUI\";" !="createDialog \"QuickUpgrade\";" !="createDialog \"QuickTake\";" !="createDialog \"InteractBank\";" !="createdialog \"SelectGender\";" !="_handled = createdialog _dialog;" !="if !(createdialog \"InteractItem\") exitWith {};" !="createDialog _tapDiag;" !="if !(createdialog \"Trade\") exitWith {};" !="_ok = createdialog \"Interact\";" !="_ok = createdialog \"TradeNPCMenu\";" !="createDialog \"Epoch_myGroup\";" !="createDialog (if ((Epoch_my_GroupUID == \"\") && (Epoch_my_Group isEqualTo [])) then {\"EPOCH_createGrp\"} else {\"Epoch_myGroup\"});" !="createDialog \"GroupRequests\";" !="_ok = createdialog \"MissionSelect\";" !="createDialog 'Skaronator_AdminMenu';" !="createDialog \"Epoch_myTempGroup\";" !="createDialog (if ((Epoch_my_tempGroupUID == \"\") && (Epoch_my_tempGroup isEqualTo [])) then {\"EPOCH_createTempGrp\"} else {\"Epoch_myTempGroup\"});" !="createDialog \"tempGroupRequests\";" !="createdialog 'EPOCH_SimpleInput';"
+5 createDialog !="createDialog 'server_info_picture'" !="createdialog 'epoch_tablet_gui'" !="createdialog 'Epoch_CamDialog'" !="createDialog \"rmx_dynamenu\";" !="createDialog \"rmx_craftingUI\";" !="createDialog \"QuickUpgrade\";" !="createDialog \"QuickTake\";" !="createDialog \"InteractBank\";" !="createdialog \"SelectGender\";" !="_handled = createdialog _dialog;" !="if !(createdialog \"InteractItem\") exitWith {};" !="createDialog _tapDiag;" !="if !(createdialog \"Trade\") exitWith {};" !="_ok = createdialog \"Interact\";" !="_ok = createdialog \"TradeNPCMenu\";" !="createDialog \"Epoch_myGroup\";" !="createDialog (if ((Epoch_my_GroupUID == \"\") && (Epoch_my_Group isEqualTo [])) then {\"EPOCH_createGrp\"} else {\"Epoch_myGroup\"});" !="createDialog \"GroupRequests\";" !="_ok = createdialog \"MissionSelect\";" !="createDialog 'Skaronator_AdminMenu';" !="createDialog \"Epoch_myTempGroup\";" !="createDialog (if ((Epoch_my_tempGroupUID == \"\") && (Epoch_my_tempGroup isEqualTo [])) then {\"EPOCH_createTempGrp\"} else {\"Epoch_myTempGroup\"});" !="createDialog \"tempGroupRequests\";" !="createdialog 'EPOCH_SimpleInput';" !="createdialog 'PlayerStatsDialog'"
5 createDisplay !="createDisplay \"rmx_dynamenu\";" !="createDisplay \"rmx_moveDynamicHUD\";" !="_parent createdisplay _displayClass;" !="finddisplay 151 createdisplay 'RscDisplayOptionsLayout'" !="_display createdisplay \"RscDisplayDLCPreview\";"
5 deleteMarker !="deleteMarkerLocal _mName;"
5 setMarker !="CBA_fnc_setMarkerPersistent\"" !="\\fnc_setMarkerPersistent" !="\"setMarkerPersistent" !="_mName setMarkerShapeLocal _mShape;" !="_mName setMarkerTypeLocal _mType;" !="(_x select 0) setMarkerPosLocal (position player);" !="_zoomMarker setMarkerSizeLocal"
diff --git a/Sources/epoch_code/compile/EPOCH_PlayerStatsDialog.sqf b/Sources/epoch_code/compile/EPOCH_PlayerStatsDialog.sqf
new file mode 100644
index 00000000..e967c676
--- /dev/null
+++ b/Sources/epoch_code/compile/EPOCH_PlayerStatsDialog.sqf
@@ -0,0 +1,17 @@
+disableSerialization;
+_display = findDisplay -1200;
+_UsedStats = ["CfgEpochClient", "PlayerStatsDialogEntries", []] call EPOCH_fnc_returnConfigEntryV2;
+_ctrlNo = 1100;
+{
+ _ctrl = _display displayCtrl _ctrlNo;
+ _txt = '';
+ {
+ _x params ["_stattype","_entrytext",["_calc","%1"]];
+ _value = missionNamespace getVariable [format ['EPOCH_total%1',_stattype],0];
+ _value = format [_calc,_value];
+ _value = call compile _value;
+ _txt = _txt + format [' %1: %2
',_entrytext,_value];
+ } foreach _x;
+ _ctrl ctrlSetStructuredText parseText _txt;
+ _ctrlNo = _ctrlNo + 1;
+} foreach _UsedStats;
\ No newline at end of file
diff --git a/Sources/epoch_code/compile/functions/EPOCH_client_updatePlayerStat.sqf b/Sources/epoch_code/compile/functions/EPOCH_client_updatePlayerStat.sqf
index 81fec9ab..0c888631 100644
--- a/Sources/epoch_code/compile/functions/EPOCH_client_updatePlayerStat.sqf
+++ b/Sources/epoch_code/compile/functions/EPOCH_client_updatePlayerStat.sqf
@@ -26,7 +26,7 @@
_toServer - BOOLEAN: (OPTIONAL): false by default
*/
-params [ ["_statType",""], ["_adjust",0], ["_toServer",false] ];
+params [ ["_statType",""], ["_adjust",0], ["_toServer",false], ["_isTotal",false]];
if(_statType isEqualTo "")exitWith{
diag_log "EPOCHDebug: updatePlayerStats -2- stat type not defined";
@@ -38,8 +38,11 @@ if(_adjust isEqualTo 0)exitWith{
private _statVarName = format["EPOCH_total%1",_statType];
private _currentStat = missionNameSpace getVariable[_statVarName,0];
private _newStat = _currentStat + _adjust;
+if (_isTotal) then {
+ _newStat = _adjust;
+};
missionNameSpace setVariable[_statVarName,_newStat];
if(_toServer)then{
- [player, objNull, _statType, _adjust, false, Epoch_personalToken] remoteExec ["EPOCH_fnc_updatePlayerStats",2];
+ [player, ObjNull, _statType, _adjust, false, Epoch_personalToken, _isTotal] remoteExec ["EPOCH_fnc_updatePlayerStats",2];
};
diff --git a/Sources/epoch_code/compile/setup/masterLoop/Event2.sqf b/Sources/epoch_code/compile/setup/masterLoop/Event2.sqf
index 3cb9355f..40e866c9 100644
--- a/Sources/epoch_code/compile/setup/masterLoop/Event2.sqf
+++ b/Sources/epoch_code/compile/setup/masterLoop/Event2.sqf
@@ -202,3 +202,18 @@ _playerNuisance = [_playerNuisanceKey,-1,_playerNuisanceMax,_playerNuisanceMin]
// calculate max stamina
EPOCH_playerStaminaMax = (100 * (round(_playerAliveTime/360)/10)) min 2500;
+if (_isOnFoot) then {
+ _Walkdist = _lastPlayerPos2 distance (getposATL player);
+ if (_Walkdist < 150) then {
+ _TotalWalkDist = _TotalWalkDist + _Walkdist;
+ ["WalkDist",_TotalWalkDist,false,true] call EPOCH_client_updatePlayerStat;
+ };
+};
+_lastPlayerPos2 = getposATL player;
+if (_playerAliveTime > _MaxAliveTime) then {
+ _MaxAliveTime = _playerAliveTime;
+ ["MaxAliveTime",_MaxAliveTime,false,true] call EPOCH_client_updatePlayerStat;
+};
+_PlayTime = _PlayTime + diag_ticktime - _PlayTimeTimer;
+["PlayTime",_PlayTime,false,true] call EPOCH_client_updatePlayerStat;
+_PlayTimeTimer = diag_ticktime;
diff --git a/Sources/epoch_code/compile/setup/masterLoop/init.sqf b/Sources/epoch_code/compile/setup/masterLoop/init.sqf
index dc4783a5..b73926f6 100644
--- a/Sources/epoch_code/compile/setup/masterLoop/init.sqf
+++ b/Sources/epoch_code/compile/setup/masterLoop/init.sqf
@@ -95,7 +95,13 @@ _fnc_forceUpdate = {
if !(isNil "_varNameTmp") then {_varName = _varNameTmp};
_customVars pushBack (missionNamespace getVariable [_varName,_defaultVarValues select _foreachindex]);
} forEach _customVarNames;
- [player,_customVars,Epoch_personalToken] remoteExec ["EPOCH_fnc_savePlayer",2];
+ _stats = [
+ ["WalkDist",round _TotalWalkDist,true],
+ ["MaxAliveTime",_MaxAliveTime,true],
+ ["PlayTime", round _PlayTime, true],
+ ["LootedObjs",missionnamespace getvariable ["EPOCH_totalLootedObjs",0], true]
+ ];
+ [player,_customVars,Epoch_personalToken,_stats] remoteExec ["EPOCH_fnc_savePlayer",2];
};
// disable fuel sources client side.
@@ -222,6 +228,12 @@ _lootClassesIgnore = ['Default'];
'_cN = configName _x;if !(_cN in _lootClassesIgnore)then{_lootClasses pushBackUnique (toLower _cN)}; true' configClasses _masterConfig;
_lastPlayerPos = getPosATL player;
+_lastPlayerPos2 = getPosATL player;
+_TotalWalkDist = missionnamespace getvariable ["EPOCH_totalWalkDist",0];
+_MaxAliveTime = missionnamespace getvariable ["EPOCH_totalMaxAliveTime",0];
+_PlayTime = missionnamespace getvariable ["EPOCH_totalPlayTime",0];
+_PlayTimeTimer = diag_ticktime;
+
_pushbacklootedbld = {
private ["_lootCheckBufferLimit"];
_lootCheckBufferLimit = 333;
diff --git a/Sources/epoch_code/gui/scripts/craftingv2/EPOCH_crafting_craft.sqf b/Sources/epoch_code/gui/scripts/craftingv2/EPOCH_crafting_craft.sqf
index dd96e529..3576641b 100644
--- a/Sources/epoch_code/gui/scripts/craftingv2/EPOCH_crafting_craft.sqf
+++ b/Sources/epoch_code/gui/scripts/craftingv2/EPOCH_crafting_craft.sqf
@@ -28,7 +28,7 @@ if !(false call EPOCH_crafting_checkResources) exitWith {};
//craft button
[] spawn {
- private ["_GiveBackRounds","_TotalroundsIn","_TotalMaxRoundsIn","_roundsCheck","_maxMagrnd","_maxMagRndTmp","_roundsCheckTmp","_magsammosearched","_craftReturn","_needBench","_craftCount","_fnc_UILock","_itemCraftTime","_selection","_craftItem","_item","_itemName","_itemCraftTime","_itemRecipeItems","_itemType","_nearbyReq","_hasNearby","_canCraft","_wH","_nearByHolder","_wHPos"];
+ private ["_GiveBackRounds","_TotalroundsIn","_TotalMaxRoundsIn","_roundsCheck","_maxMagrnd","_maxMagRndTmp","_roundsCheckTmp","_magsammosearched","_craftReturn","_needBench","_craftCount","_fnc_UILock","_itemCraftTime","_selection","_craftItem","_item","_itemName","_itemCraftTime","_itemRecipeItems","_itemType","_nearbyReq","_hasNearby","_canCraft","_wH","_nearByHolder","_wHPos","_craftedcount"];
disableSerialization;
_fnc_UILock = {
@@ -55,6 +55,8 @@ if !(false call EPOCH_crafting_checkResources) exitWith {};
_craftReturn = _craftItem param [16,[]];
_BulletCalculateOnCraft = ["CfgEpochClient", "BulletCalculateOnCraft", false] call EPOCH_fnc_returnConfigEntryV2;
+
+ _craftedcount = 0;
for "_c" from 1 to rmx_var_craftQTYOut do {
false call _fnc_UILock;
@@ -131,6 +133,10 @@ if !(false call EPOCH_crafting_checkResources) exitWith {};
} forEach _craftReturn;
call EPOCH_crafting_LB_click;
+ _craftedcount = _craftedcount + 1;
+ };
+ if (_craftedcount > 0) then {
+ ["CraftedItems",_craftedcount,true] call EPOCH_client_updatePlayerStat;
};
call EPOCH_crafting_LB_defaults;
true call _fnc_UILock;
diff --git a/Sources/epoch_config/Configs/CfgClientFunctions.hpp b/Sources/epoch_config/Configs/CfgClientFunctions.hpp
index 65c1b4e2..48a1b089 100644
--- a/Sources/epoch_config/Configs/CfgClientFunctions.hpp
+++ b/Sources/epoch_config/Configs/CfgClientFunctions.hpp
@@ -54,6 +54,7 @@ class CfgClientFunctions
class DefibrillatorUse {};
class CamUse {};
class DefuseBomb {};
+ class PlayerStatsDialog {};
};
class building
{
diff --git a/Sources/epoch_config/Configs/CfgEPad.hpp b/Sources/epoch_config/Configs/CfgEPad.hpp
index 19fe44b8..f5e85bd7 100644
--- a/Sources/epoch_config/Configs/CfgEPad.hpp
+++ b/Sources/epoch_config/Configs/CfgEPad.hpp
@@ -285,5 +285,17 @@ class e_pad_config
ToggleVar = "";
ToggleAble = "false";
};
+ class PlayerStats
+ {
+ ButtonText = "";
+ Description = "Player Statistic";
+ icon = "x\addons\a3_epoch_code\Data\UI\epad\PlayerStats.paa";
+ color[] = {1,1,1,1};
+ colortoggled[] = {0,1,0,1};
+ action = "if (isnull (finddisplay -1200)) then {createdialog 'PlayerStatsDialog'};";
+ Tooltip = "Player Statistic";
+ ToggleVar = "";
+ ToggleAble = "false";
+ };
};
};
\ No newline at end of file
diff --git a/Sources/epoch_config/Configs/CfgEpochClient.hpp b/Sources/epoch_config/Configs/CfgEpochClient.hpp
index 30e95dc3..fe6e69b6 100644
--- a/Sources/epoch_config/Configs/CfgEpochClient.hpp
+++ b/Sources/epoch_config/Configs/CfgEpochClient.hpp
@@ -194,8 +194,51 @@ class CfgEpochClient
{"TraderMissions",0,{}},
{"AIKills",0,{}},
{"AntagonistKills",0,{}},
- {"ZombieKills",0,{}}
+ {"ZombieKills",0,{}},
+ {"WalkDist",0,{}},
+ {"MaxAliveTime",0,{}},
+ {"NPCTrades",0,{}},
+ {"PlayTime",0,{}},
+ {"LootedObjs",0,{}},
+ {"CraftedItems",0,{}},
+ {"ConnectCount",0,{}},
+ {"BuildingsSet",0,{}},
+ {"AIDeaths",0,{}},
};
+ PlayerStatsDialogEntries[] = {
+ {
+ {"ConnectCount","Times connected"},
+ {"PlayTime","Playtime (hours)","%1/3600 toFixed 2"},
+ {"MaxAliveTime","Max Alivetime (hours)","%1/3600 toFixed 2"},
+ {"Walkdist","Distance Walked (Km)","%1/1000 toFixed 2"}
+ },
+ {
+ {"LootedObjs","Objects Looted"},
+ {"NPCTrades","Trades at Trader"},
+ {"BuildingsSet","Placed Buildings"},
+ {"CraftedItems","Crafted Items"}
+ },
+ {
+ {"Karma","Karma"},
+ {"Revives","Player Revived"},
+ {"TraderMissions","Tradermissions"}
+ },
+ {
+ {"Murders","Player Kills"},
+ {"AIKills","AI Kills"},
+ {"AntagonistKills","Antagonist Kills"},
+ {"ZombieKills","Zombie Kills"}
+ },
+ {
+ {"Deaths","Deaths by Player"},
+ {"AIDeaths","Deaths by AI"},
+ {"Suicides","Suicides"}
+ },
+ {
+ {"","K/D PvP","(Epoch_totalMurders/(Epoch_totalDeaths max 1)) toFixed 1"},
+ {"","K/D PvE","(Epoch_totalAIKills/(Epoch_totalAIDeaths max 1)) toFixed 1"}
+ }
+ };
group_upgrade_lvl[] = {4,"1000",6,"1500",8,"2000",10,"2500",12,"3000",14,"3500",16,"4000",32,"8000",64,"16000"}; // controls max group limit and cost
// Event handler code
displayAddEventHandler[] = {"keyDown","keyUp"};
diff --git a/Sources/epoch_server/compile/epoch_bases/EPOCH_server_saveBuilding.sqf b/Sources/epoch_server/compile/epoch_bases/EPOCH_server_saveBuilding.sqf
index bd47c6d4..c8d92ccd 100644
--- a/Sources/epoch_server/compile/epoch_bases/EPOCH_server_saveBuilding.sqf
+++ b/Sources/epoch_server/compile/epoch_bases/EPOCH_server_saveBuilding.sqf
@@ -68,6 +68,7 @@ if (isText _staticClassConfig) then {
if (isDamageAllowed _storageObj) then { // Only needed, if damage is allowed
_storageObj call EPOCH_server_storageInit;
};
+ [_player,"BuildingsSet",1,true] call EPOCH_server_updatePlayerStats;
diag_log format["Epoch: STORAGE: %1 created storage %2 at %3 with slot %4", _playerUID, _staticClass, _vehiclePos, _slot];
};
@@ -111,6 +112,7 @@ if (isText _staticClassConfig) then {
publicvariable "EPOCH_Plotpoles";
};
_newVehicle call EPOCH_saveBuilding;
+ [_player,"BuildingsSet",1,true] call EPOCH_server_updatePlayerStats;
};
} else {
diff --git a/Sources/epoch_server/compile/epoch_looting/EPOCH_server_destroyTrash.sqf b/Sources/epoch_server/compile/epoch_looting/EPOCH_server_destroyTrash.sqf
index b115f80a..58471bda 100644
--- a/Sources/epoch_server/compile/epoch_looting/EPOCH_server_destroyTrash.sqf
+++ b/Sources/epoch_server/compile/epoch_looting/EPOCH_server_destroyTrash.sqf
@@ -39,6 +39,7 @@ if (alive _object) then {
_config = (configFile >> "CfgMainTable" >> _payout);
if (isClass _config) then {
+ [_player,"LootedObjs",1,true] call EPOCH_server_updatePlayerStats;
if (random 1 < getNumber(_config >> "chance")) then {
[_item, _payout] call EPOCH_serverLootObject;
// force player to open gear on this object.
diff --git a/Sources/epoch_server/compile/epoch_looting/EPOCH_server_lootContainer.sqf b/Sources/epoch_server/compile/epoch_looting/EPOCH_server_lootContainer.sqf
index 9713d50e..996f52e7 100644
--- a/Sources/epoch_server/compile/epoch_looting/EPOCH_server_lootContainer.sqf
+++ b/Sources/epoch_server/compile/epoch_looting/EPOCH_server_lootContainer.sqf
@@ -24,6 +24,8 @@ if (_player distance _object > 20) exitWith{};
if !(_object in EPOCH_cleanupQueue) then {
+ [_player,"LootedObjs",1,true] call EPOCH_server_updatePlayerStats;
+
EPOCH_cleanupQueue pushBack _object;
_type = typeOf _object;
diff --git a/Sources/epoch_server/compile/epoch_player/EPOCH_fnc_savePlayer.sqf b/Sources/epoch_server/compile/epoch_player/EPOCH_fnc_savePlayer.sqf
index 18ff043e..952ed234 100644
--- a/Sources/epoch_server/compile/epoch_player/EPOCH_fnc_savePlayer.sqf
+++ b/Sources/epoch_server/compile/epoch_player/EPOCH_fnc_savePlayer.sqf
@@ -12,7 +12,11 @@
Github:
https://github.com/EpochModTeam/Epoch/tree/release/Sources/epoch_server/compile/epoch_player/EPOCH_fnc_savePlayer.sqf
*/
-params ["_player","",["_token","",[""]]];
+params ["_player","",["_token","",[""]],["_stats",[]]];
if([_player,_token] call EPOCH_server_getPToken)then{
+ {
+ _x params ["_statType","_adjust","_isTotal"];
+ [_player, _statType, _adjust, false,_isTotal] call Epoch_server_updatePlayerStats;
+ } foreach _stats;
_this call EPOCH_server_savePlayer;
};
diff --git a/Sources/epoch_server/compile/epoch_player/EPOCH_fnc_updatePlayerStats.sqf b/Sources/epoch_server/compile/epoch_player/EPOCH_fnc_updatePlayerStats.sqf
index 44e56b92..edc683d4 100644
--- a/Sources/epoch_server/compile/epoch_player/EPOCH_fnc_updatePlayerStats.sqf
+++ b/Sources/epoch_server/compile/epoch_player/EPOCH_fnc_updatePlayerStats.sqf
@@ -12,15 +12,18 @@
Github:
https://github.com/EpochModTeam/Epoch/tree/release/Sources/epoch_server/compile/epoch_player/EPOCH_fnc_updatePlayerStats.sqf
*/
-params ["_player","_killer","_statType","_adjust","_toClient",["_token","",[""]]];
+params ["_player",["_killer",ObjNull],["_statType",""],["_adjust",0],["_toClient",false],["_token","",[""]],["_isTotal",false]];
if(isNull _player)exitWith{
diag_log "EPOCHDebug: fnc_updatePlayerStats -1a- player is Null";
};
-if(isNull _killer)exitWith{
- diag_log "EPOCHDebug: fnc_updatePlayerStats -1b- non local killer is Null";
+if(!isplayer _player)exitWith{
+ diag_log "EPOCHDebug: fnc_updatePlayerStats -1b- is not a player";
};
if([_player,_token] call EPOCH_server_getPToken)then{
- [_killer, _statType, _adjust, _toClient] call EPOCH_server_updatePlayerStats;
+ if (!isnull _killer) then {
+ _player = _killer;
+ };
+ [_player, _statType, _adjust, _toClient, _isTotal] call EPOCH_server_updatePlayerStats;
};
\ No newline at end of file
diff --git a/Sources/epoch_server/compile/epoch_player/EPOCH_server_checkPlayer.sqf b/Sources/epoch_server/compile/epoch_player/EPOCH_server_checkPlayer.sqf
index 89ecde47..028c09a5 100644
--- a/Sources/epoch_server/compile/epoch_player/EPOCH_server_checkPlayer.sqf
+++ b/Sources/epoch_server/compile/epoch_player/EPOCH_server_checkPlayer.sqf
@@ -13,7 +13,7 @@
https://github.com/EpochModTeam/Epoch/tree/release/Sources/epoch_server/compile/epoch_player/EPOCH_server_checkPlayer.sqf
*/
//[[[cog import generate_private_arrays ]]]
-private ["_apperance","_arr","_class","_communityStatsArray","_dead","_deadPlayer","_defaultData","_instanceID","_isMale","_medical","_playerUID","_response","_return","_vars"];
+private ["_apperance","_arr","_class","_dead","_deadPlayer","_defaultData","_instanceID","_isMale","_medical","_playerUID","_response","_return","_vars"];
//[[[end]]]
params [["_playerObj",objNull],["_fsmHandle",0]];
if (_playerObj isEqualType objNull) then {
@@ -50,12 +50,6 @@ if (_playerObj isEqualType objNull) then {
};
};
- // check status of community stats to prevent load / save issues
- _communityStatsArray = ["CommunityStats", _playerUID] call EPOCH_fnc_server_hiveGETRANGE;
- if((_communityStatsArray select 1) isEqualTo []) then{
- _return = ["CommunityStats", _playerUID, EPOCH_expiresCommunityStats, [EPOCH_defaultStatVars]] call EPOCH_fnc_server_hiveSETEX;
- };
-
/* true => New Char
false => load old Char */
[_fsmHandle,['_checkPlayer_PVC', _dead]] remoteExecCall ['setFSMVariable', _playerObj];
diff --git a/Sources/epoch_server/compile/epoch_player/EPOCH_server_deadPlayer.sqf b/Sources/epoch_server/compile/epoch_player/EPOCH_server_deadPlayer.sqf
index f567d6c4..060d71ab 100644
--- a/Sources/epoch_server/compile/epoch_player/EPOCH_server_deadPlayer.sqf
+++ b/Sources/epoch_server/compile/epoch_player/EPOCH_server_deadPlayer.sqf
@@ -63,7 +63,7 @@ if (_playerObj != _killer) then {
if(_playerIsNeutral)then{_playerKarmaAdj = abs((-_playerKarma) * 0.03)};
if(_playerIsBandit)then{_playerKarmaAdj = abs((-_playerKarma) * 0.055)};
if(_playerIsHero)then{_playerKarmaAdj = abs((-_playerKarma) * 0.025)};
-
+ _deathType = 0;
if!(_killerUID isEqualTo "")then{
[_killer, "Murders", 1, true] call EPOCH_server_updatePlayerStats;
@@ -89,18 +89,21 @@ if (_playerObj != _killer) then {
if(_playerIsHero)then{_killerKarmaAdj = abs((-_killerKarma) * 0.25) + _playerKarmaAdj};
};
[_killer, "Karma", _killerKarmaAdj, true] call EPOCH_server_updatePlayerStats;
+ _deathType = 1;
};
- _deathType = 1;
};
switch(_deathType)do{
case 666: {
- [_playerObj, "Suicides", 1] call EPOCH_server_updatePlayerStats;
- [_playerObj, "Karma", _playerKarmaAdj] call EPOCH_server_updatePlayerStats;
+ [_playerObj, "Suicides", 1, true] call EPOCH_server_updatePlayerStats;
+ [_playerObj, "Karma", _playerKarmaAdj, true] call EPOCH_server_updatePlayerStats;
};
case 1: {
- [_playerObj, "Deaths", 1] call EPOCH_server_updatePlayerStats;
- [_playerObj, "Karma", _playerKarmaAdj] call EPOCH_server_updatePlayerStats;
+ [_playerObj, "Deaths", 1, true] call EPOCH_server_updatePlayerStats;
+ [_playerObj, "Karma", _playerKarmaAdj, true] call EPOCH_server_updatePlayerStats;
+ };
+ case 0: {
+ [_playerObj, "AIDeaths", 1, true] call EPOCH_server_updatePlayerStats;
};
};
_defaultVars = call EPOCH_defaultVars_SEPXVar;
@@ -114,6 +117,9 @@ if (_current_crypto > 0) then{
diag_log format["Epoch: ADMIN: Crypto added to dead body for %1 with %2 at %3", getPlayerUID _playerObj, _current_crypto, _pos];
};
+// save community stats (skipped in EPOCH_server_savePlayer for dead Players)
+["CommunityStats", _playerUID, EPOCH_expiresCommunityStats, [_playerObj getVariable["COMMUNITY_STATS", EPOCH_defaultStatVars]]] call EPOCH_fnc_server_hiveSETEX;
+
[_playerObj, _defaultVars] call EPOCH_server_savePlayer;
// death cost
diff --git a/Sources/epoch_server/compile/epoch_player/EPOCH_server_loadPlayer.sqf b/Sources/epoch_server/compile/epoch_player/EPOCH_server_loadPlayer.sqf
index b850da0f..1292d31e 100644
--- a/Sources/epoch_server/compile/epoch_player/EPOCH_server_loadPlayer.sqf
+++ b/Sources/epoch_server/compile/epoch_player/EPOCH_server_loadPlayer.sqf
@@ -243,6 +243,23 @@ if (!isNull _player) then {
// load community stats
_communityStatsArray = ["CommunityStats", _playerUID] call EPOCH_fnc_server_hiveGETRANGE;
_communityStats = (_communityStatsArray param [1,[]]) param [0,[]];
+ if (_communityStats isEqualTo []) then {
+ _communityStats = EPOCH_defaultStatVars;
+ };
+ if (count _communityStats < EPOCH_communityStatsCount) then {
+ {
+ private _check = _communityStats select _foreachindex;
+ if (isnil '_check') then {
+ _communityStats pushback _x;
+ };
+ } foreach EPOCH_defaultStatVars;
+ };
+ _Index = EPOCH_communityStats find "ConnectCount";
+ if (_Index > -1) then {
+ _currentStat = _communityStats select _Index;
+ _communityStats set[_Index, _currentStat + 1];
+ };
+
_newPlyr setVariable["COMMUNITY_STATS", _communityStats];
// Flag new body as ready for use.
diff --git a/Sources/epoch_server/compile/epoch_player/EPOCH_server_revivePlayer.sqf b/Sources/epoch_server/compile/epoch_player/EPOCH_server_revivePlayer.sqf
index 9f6fa2d9..35b0367b 100644
--- a/Sources/epoch_server/compile/epoch_player/EPOCH_server_revivePlayer.sqf
+++ b/Sources/epoch_server/compile/epoch_player/EPOCH_server_revivePlayer.sqf
@@ -157,6 +157,7 @@ if (!local _player) then {
_vars set[_cIndex, _PlayerCrypto];
_newPlyr setVariable['VARS', _vars];
};
+ _newPlyr setvariable ["COMMUNITY_STATS",_player getVariable["COMMUNITY_STATS", EPOCH_defaultStatVars]];
// send to player
[_newPlyr, _token, _loadabs] remoteExec ['EPOCH_clientRevive',_player];
diff --git a/Sources/epoch_server/compile/epoch_player/EPOCH_server_updatePlayerStats.sqf b/Sources/epoch_server/compile/epoch_player/EPOCH_server_updatePlayerStats.sqf
index 000211ca..475d7839 100644
--- a/Sources/epoch_server/compile/epoch_player/EPOCH_server_updatePlayerStats.sqf
+++ b/Sources/epoch_server/compile/epoch_player/EPOCH_server_updatePlayerStats.sqf
@@ -31,7 +31,7 @@
by setting this true the client will receive the stat update.
Use true when the stat change originates from the server and not the client.
*/
-params [ ["_playerObj",objNull], ["_statType",""], ["_adjust",0], ["_toClient",false] ];
+params [ ["_playerObj",objNull], ["_statType",""], ["_adjust",0], ["_toClient",false], ["_isTotal",false]];
if(isNull _playerObj)exitWith{
diag_log "EPOCHDebug: playerUpdateStats -1- player is null object";
@@ -46,22 +46,33 @@ _playerUID = getplayerUID _playerObj;
if(_playerUID isEqualTo "")exitWith{
diag_log "EPOCHDebug: playerUpdateStats -4- player UID is empty";
};
+if(!isplayer _playerObj)exitWith{
+ diag_log "EPOCHDebug: playerUpdateStats -5- is not a player";
+};
//get this playerObj stats
_playerStats = _playerObj getVariable["COMMUNITY_STATS", EPOCH_defaultStatVars];
//get this stats index #
_sIndex = EPOCH_communityStats find _statType;
-//get this stat value
-_currentStat = _playerStats select _sIndex;
-//set the new stat value
-_playerStats set[_sIndex, _currentStat + _adjust];
-//set the new stats array back onto this playerObj
-_playerObj setVariable["COMMUNITY_STATS", _playerStats];
+if (_sIndex > -1) then {
+ //get this stat value
+ _currentStat = _playerStats select _sIndex;
+ //set the new stat value
+ if (_isTotal) then {
+ _playerStats set[_sIndex, _adjust];
+ }
+ else {
+ _playerStats set[_sIndex, _currentStat + _adjust];
+ };
+ //set the new stats array back onto this playerObj
+ _playerObj setVariable["COMMUNITY_STATS", _playerStats];
-//send to hive
-["CommunityStats", _playerUID, EPOCH_expiresCommunityStats, [_playerStats]] call EPOCH_fnc_server_hiveSETEX;
+ //send to hive
+// ["CommunityStats", _playerUID, EPOCH_expiresCommunityStats, [_playerStats]] call EPOCH_fnc_server_hiveSETEX;
+ // Prevent saving to DB too much often, as it is already saved on Player Save Loop / Disconnect / Kill
-//send to player
-if(_toClient)then{
- [_statType,_adjust] remoteExecCall ["EPOCH_client_updatePlayerStat",(owner _playerObj)];
+ //send to player
+ if(_toClient)then{
+ [_statType,_adjust,false,_isTotal] remoteExecCall ["EPOCH_client_updatePlayerStat",(owner _playerObj)];
+ };
};
\ No newline at end of file
diff --git a/Sources/epoch_server/compile/epoch_trading/EPOCH_server_makeNPCTrade.sqf b/Sources/epoch_server/compile/epoch_trading/EPOCH_server_makeNPCTrade.sqf
index ea0150de..6cbe5b68 100644
--- a/Sources/epoch_server/compile/epoch_trading/EPOCH_server_makeNPCTrade.sqf
+++ b/Sources/epoch_server/compile/epoch_trading/EPOCH_server_makeNPCTrade.sqf
@@ -334,6 +334,12 @@ if (_slot != -1) then {
_current_crypto remoteExec ['EPOCH_effectCrypto',_player];
_vars set[_cIndex, _current_crypto];
_player setVariable["VARS", _vars];
+
+ // Update Player Stats
+ _kIndex = EPOCH_communityStats find "NPCTrades";
+ if (_kIndex > -1) then {
+ [_player, "NPCTrades", 1, true] call EPOCH_server_updatePlayerStats;
+ };
};
};