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; + }; }; };