From 0fb625f544355b25f653d398ad3837d4127af306 Mon Sep 17 00:00:00 2001 From: Logg-y <49533518+Logg-y@users.noreply.github.com> Date: Sun, 23 Jul 2023 17:00:50 +0100 Subject: [PATCH 1/6] Stop khadala development script from applying multiplier to tier odds because it never did that --- src/nss/dev_khadala.nss | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/nss/dev_khadala.nss b/src/nss/dev_khadala.nss index e50ac280..c7be02cb 100644 --- a/src/nss/dev_khadala.nss +++ b/src/nss/dev_khadala.nss @@ -90,14 +90,14 @@ int GetMultiplierForBaseItemType(int nBaseItem) else if (nBaseItem == BASE_ITEM_SPELLSCROLL) { nMultiplier = 0; } else if (nBaseItem == BASE_ITEM_GLOVES) { nMultiplier = 3; } else if (nBaseItem == BASE_ITEM_BRACER) { nMultiplier = 3; } - else if (nBaseItem == BASE_ITEM_RING) { nMultiplier = 5; } - else if (nBaseItem == BASE_ITEM_AMULET) { nMultiplier = 6; } + else if (nBaseItem == BASE_ITEM_RING) { nMultiplier = 3; } + else if (nBaseItem == BASE_ITEM_AMULET) { nMultiplier = 3; } else if (nBaseItem == BASE_ITEM_CLOAK) { nMultiplier = 3; } else if (nBaseItem == BASE_ITEM_BELT) { nMultiplier = 3; } else if (nBaseItem == BASE_ITEM_HELMET) { nMultiplier = 3; } else if (nBaseItem == BASE_ITEM_LARGESHIELD) { nMultiplier = 3; } else if (nBaseItem == BASE_ITEM_TOWERSHIELD) { nMultiplier = 4; } - else if (nBaseItem == BASE_ITEM_MAGICWAND) { nMultiplier = 8; } + else if (nBaseItem == BASE_ITEM_MAGICWAND) { nMultiplier = 3; } return nMultiplier; } @@ -191,15 +191,13 @@ float _GetExpectedCostForItemOfTier(float fChance, float fExpectedItemValue, int } float GetAverageCostForBaseItem(int nBaseItem, int nCost) -{ - int nMultiplier = GetMultiplierForBaseItemType(nBaseItem); - +{ int nRandom = d100(); - float fT5Chance = IntToFloat(1*nMultiplier)/100.0; - float fT4Chance = IntToFloat(3*nMultiplier)/100.0; - float fT3Chance = IntToFloat(7*nMultiplier)/100.0; + float fT5Chance = 3.0/100.0; + float fT4Chance = 7.0/100.0; + float fT3Chance = 20.0/100.0; float fT2Chance = 1.0 - (fT3Chance + fT4Chance + fT5Chance); @@ -231,13 +229,12 @@ float GetAverageCostForBaseItem(int nBaseItem, int nCost) float GetAverageCostForBaseAC(int nAC, int nCost) { - int nMultiplier = GetMultiplierForBaseAC(nAC); int nRandom = d100(); - float fT5Chance = IntToFloat(1*nMultiplier)/100.0; - float fT4Chance = IntToFloat(3*nMultiplier)/100.0; - float fT3Chance = IntToFloat(7*nMultiplier)/100.0; + float fT5Chance = 3.0/100.0; + float fT4Chance = 7.0/100.0; + float fT3Chance = 20.0/100.0; float fT2Chance = 1.0 - (fT3Chance + fT4Chance + fT5Chance); From 751849db7ba060985d21cd2e9b01d2516d9c36e9 Mon Sep 17 00:00:00 2001 From: Logg-y <49533518+Logg-y@users.noreply.github.com> Date: Sun, 23 Jul 2023 22:32:45 +0100 Subject: [PATCH 2/6] Initial pass of adding the rest of the player statistic ideas --- config/common.env | 2 +- src/nss/70_inc_nwnx.nss | 5 +-- src/nss/ai_ondeath.nss | 40 +++++++++++---------- src/nss/bash_lock.nss | 2 +- src/nss/dlg_andriel_act.nss | 4 +-- src/nss/dlg_andriel_cond.nss | 3 ++ src/nss/dlg_avista_pers.nss | 3 ++ src/nss/dlg_bluf_chk.nss | 3 ++ src/nss/dlg_chk_bluf.nss | 4 ++- src/nss/dlg_chk_pers.nss | 4 ++- src/nss/dlg_divine_pers.nss | 3 ++ src/nss/dlg_ferry_pers.nss | 7 ++-- src/nss/dlg_ferry_tele.nss | 4 +-- src/nss/dlg_house_buy.nss | 2 +- src/nss/dlg_house_sell.nss | 2 +- src/nss/dlg_q_chk_advb.nss | 2 ++ src/nss/dlg_q_chk_advb1.nss | 2 ++ src/nss/dlg_q_chk_advb2.nss | 2 ++ src/nss/dlg_q_chk_advb3.nss | 2 ++ src/nss/dlg_q_chk_advb4.nss | 2 ++ src/nss/dlg_q_chk_advb5.nss | 2 ++ src/nss/dlg_q_chk_advb6.nss | 2 ++ src/nss/dlg_q_chk_advb7.nss | 2 ++ src/nss/dlg_q_chk_advb8.nss | 2 ++ src/nss/dlg_q_chk_advb9.nss | 2 ++ src/nss/dlg_relevel_pers.nss | 3 ++ src/nss/dlg_ship_pers1.nss | 10 ++++-- src/nss/dlg_ship_pers2.nss | 9 +++-- src/nss/door_failopen.nss | 2 ++ src/nss/fol_hirepe.nss | 3 ++ src/nss/fol_hirepem.nss | 3 ++ src/nss/hen_hire.nss | 2 +- src/nss/hen_hirepe.nss | 5 ++- src/nss/hen_none_hire.nss | 2 +- src/nss/hen_ondeath.nss | 7 ++-- src/nss/inc_adv_assassin.nss | 2 +- src/nss/inc_follower.nss | 2 +- src/nss/inc_general.nss | 69 +++++++++++++++++++++++++++++++++--- src/nss/inc_horse.nss | 2 ++ src/nss/inc_housing.nss | 2 +- src/nss/inc_loot.nss | 4 +-- src/nss/inc_quest.nss | 6 +++- src/nss/inc_restxp.nss | 7 ++++ src/nss/inc_ship.nss | 4 +-- src/nss/inc_trap.nss | 2 +- src/nss/nw_i0_spells.nss | 20 ++++++++++- src/nss/nw_s0_animdead.nss | 5 +++ src/nss/nw_s0_crgrund.nss | 5 +++ src/nss/nw_s0_crundead.nss | 5 +++ src/nss/nw_s0_gate.nss | 5 +++ src/nss/nw_s0_grplanar.nss | 5 +++ src/nss/nw_s0_knock.nss | 2 +- src/nss/nw_s0_lsplanar.nss | 5 +++ src/nss/nw_s0_mordswrd.nss | 5 +++ src/nss/nw_s0_planar.nss | 5 +++ src/nss/nw_s0_summon.nss | 6 +++- src/nss/nw_s0_summshad.nss | 5 +++ src/nss/nw_s0_summshad02.nss | 5 +++ src/nss/on_attack.nss | 66 ++++++++++++++++++++++++++++++++++ src/nss/on_damage.nss | 49 +++++++++++++++++++++++++ src/nss/on_inv_addgolda.nss | 13 +++++++ src/nss/on_mod_heartb.nss | 4 +-- src/nss/on_mod_load.nss | 6 ++++ src/nss/on_pc_buya.nss | 4 +-- src/nss/on_pc_death.nss | 12 +++---- src/nss/on_pc_rest.nss | 4 +-- src/nss/on_pc_skilla.nss | 12 +++++++ src/nss/on_spellinta.nss | 10 ++++++ src/nss/on_storesella.nss | 4 +-- src/nss/on_trap_disarm.nss | 7 +++- src/nss/party_credit.nss | 28 ++++++++++++++- src/nss/pc_respawn.nss | 2 +- src/nss/tmap_complete.nss | 2 +- src/nss/treas_unlock.nss | 2 +- src/nss/x0_s0_planar.nss | 5 +++ src/nss/x0_s2_blkdead.nss | 6 ++++ src/nss/x0_s2_fiend.nss | 6 +++- src/nss/x0_s2_shadsum.nss | 6 +++- src/nss/x0_s3_summonelem.nss | 6 +++- src/nss/x2_inc_spellhook.nss | 23 ++++++++++++ src/nss/x2_s0_blckblde.nss | 5 +++ src/nss/x2_s0_crshadow.nss | 5 +++ src/nss/x2_s0_persblde.nss | 5 +++ src/nss/x2_s2_dragknght.nss | 5 +++ src/nss/x2_s2_mumdust.nss | 5 +++ src/nss/x2_s2_sumgrund.nss | 6 ++++ src/nss/x2_s2_sumundead.nss | 6 ++++ win_nasher_install.bat | 3 +- 88 files changed, 567 insertions(+), 82 deletions(-) create mode 100644 src/nss/on_attack.nss create mode 100644 src/nss/on_damage.nss create mode 100644 src/nss/on_inv_addgolda.nss diff --git a/config/common.env b/config/common.env index e828c765..de4b8491 100644 --- a/config/common.env +++ b/config/common.env @@ -26,7 +26,7 @@ export NWNX_AREA_SKIP=n export NWNX_CHAT_SKIP=n export NWNX_COMBATMODES_SKIP=n export NWNX_CREATURE_SKIP=n -export NWNX_DAMAGE_SKIP=y +export NWNX_DAMAGE_SKIP=n export NWNX_DATA_SKIP=y export NWNX_DIALOG_SKIP=y export NWNX_ELC_SKIP=n diff --git a/src/nss/70_inc_nwnx.nss b/src/nss/70_inc_nwnx.nss index 7eead10e..cab66dd1 100644 --- a/src/nss/70_inc_nwnx.nss +++ b/src/nss/70_inc_nwnx.nss @@ -13,8 +13,9 @@ const int REST_EVENTTYPE_REST_FORCEREST = 4; -const int DURATION_TYPE_EQUIPPED = 3; -const int DURATION_TYPE_INNATE = 4; +// These conflict with real nwnx stuff +//const int DURATION_TYPE_EQUIPPED = 3; +//const int DURATION_TYPE_INNATE = 4; const int AREA_DAYTIME_RESET_DEFAULT = -1; const int AREA_DAYTIME_DAY = 0; diff --git a/src/nss/ai_ondeath.nss b/src/nss/ai_ondeath.nss index cdedf5e1..20e97b5f 100644 --- a/src/nss/ai_ondeath.nss +++ b/src/nss/ai_ondeath.nss @@ -31,34 +31,38 @@ void main() if (GetLocalString(OBJECT_SELF, "heartbeat_script") == "fol_heartb") { - IncrementStat(GetMaster(OBJECT_SELF), "followers_died"); + IncrementPlayerStatistic(GetMaster(OBJECT_SELF), "followers_died"); } // not counting associates. we should count summons though - - if (GetIsPC(oKiller)) + object oPCToIncrementOn = oKiller; + + if (GetIsPC(GetMaster(oKiller))) { - IncrementStat(oKiller, "enemies_killed"); + int nAssociateType = GetAssociateType(oKiller); - if (GetLocalInt(OBJECT_SELF, "boss") == 1) + if (nAssociateType == ASSOCIATE_TYPE_FAMILIAR || nAssociateType == ASSOCIATE_TYPE_ANIMALCOMPANION || nAssociateType == ASSOCIATE_TYPE_DOMINATED || nAssociateType == ASSOCIATE_TYPE_SUMMONED) { - IncrementStat(oKiller, "bosses_killed"); + oPCToIncrementOn = GetMaster(oKiller); } } - else if (GetIsPC(GetMaster(oKiller))) + + if (GetIsPC(oPCToIncrementOn)) { - int nAssociateType = GetAssociateType(oKiller); + int nCR = GetLocalInt(OBJECT_SELF, "cr"); + IncrementPlayerStatistic(oPCToIncrementOn, "enemies_killed"); - if (nAssociateType == ASSOCIATE_TYPE_FAMILIAR || nAssociateType == ASSOCIATE_TYPE_ANIMALCOMPANION || nAssociateType == ASSOCIATE_TYPE_DOMINATED || nAssociateType == ASSOCIATE_TYPE_SUMMONED) + if (GetLocalInt(OBJECT_SELF, "boss") == 1) { - object oPC = GetMaster(oKiller); - - IncrementStat(oPC, "enemies_killed"); - - if (GetLocalInt(OBJECT_SELF, "boss") == 1) - { - IncrementStat(oPC, "bosses_killed"); - } + nCR++; + IncrementPlayerStatistic(oPCToIncrementOn, "bosses_killed"); + } + + int nOldMaxCR = GetPlayerStatistic(oPCToIncrementOn, "most_powerful_cr"); + if (nCR > nOldMaxCR) + { + SetPlayerStatistic(oPCToIncrementOn, "most_powerful_cr", nCR); + SetPlayerStatisticString(oPCToIncrementOn, "most_powerful_killed", GetName(OBJECT_SELF)); } } @@ -79,7 +83,7 @@ void main() oMurderer = oKiller; } - IncrementStat(oMurderer, "innocents_killed"); + IncrementPlayerStatistic(oMurderer, "innocents_killed"); if (GetIsPC(oMurderer)) AdjustAlignment(oMurderer, ALIGNMENT_EVIL, 5, FALSE); diff --git a/src/nss/bash_lock.nss b/src/nss/bash_lock.nss index 8a4c0649..4ec13762 100644 --- a/src/nss/bash_lock.nss +++ b/src/nss/bash_lock.nss @@ -78,7 +78,7 @@ void BashLock(object oAttacker) nEffect = VFX_COM_BLOOD_SPARK_LARGE; AssignCommand(oAttacker, ClearAllActions(TRUE)); - IncrementStat(oAttacker, "locks_bashed"); + IncrementPlayerStatistic(oAttacker, "locks_bashed"); PlaySound("cb_bu_metallrg"); diff --git a/src/nss/dlg_andriel_act.nss b/src/nss/dlg_andriel_act.nss index 5749a13e..1a5a0be2 100644 --- a/src/nss/dlg_andriel_act.nss +++ b/src/nss/dlg_andriel_act.nss @@ -29,8 +29,8 @@ void main() TakeGoldFromCreature(nRealCost, oPC, TRUE); - IncrementStat(oPC, "gold_spent_from_buying", nRealCost); - IncrementStat(oPC, "items_bought"); + IncrementPlayerStatistic(oPC, "gold_spent_from_buying", nRealCost); + IncrementPlayerStatistic(oPC, "items_bought"); int nACR = GetHitDice(oPC); int nVariability = GetHitDice(oPC) / 4; diff --git a/src/nss/dlg_andriel_cond.nss b/src/nss/dlg_andriel_cond.nss index 31ae4572..8624894a 100644 --- a/src/nss/dlg_andriel_cond.nss +++ b/src/nss/dlg_andriel_cond.nss @@ -1,6 +1,7 @@ #include "inc_gold" #include "inc_treasuremap" #include "inc_persist" +#include "inc_general" #include "inc_sqlite_time" // See also: dlg_andriel_act @@ -45,9 +46,11 @@ int StartingConditional() if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) { + IncrementPlayerStatistic(oPC, "persuade_failed"); SetTemporaryInt(GetPCPublicCDKey(oPC, TRUE)+GetName(oPC)+"_"+GetTag(OBJECT_SELF)+"_pers", 1, 900.0); return FALSE; } + IncrementPlayerStatistic(oPC, "persuade_succeeded"); } string sHasMap = GetScriptParam("hasmap"); diff --git a/src/nss/dlg_avista_pers.nss b/src/nss/dlg_avista_pers.nss index 4e681487..198cd012 100644 --- a/src/nss/dlg_avista_pers.nss +++ b/src/nss/dlg_avista_pers.nss @@ -1,5 +1,6 @@ #include "inc_gold" #include "inc_persist" +#include "inc_general" int StartingConditional() { @@ -13,11 +14,13 @@ int StartingConditional() if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) { + IncrementPlayerStatistic(oPC, "persuade_failed"); SetTemporaryInt(GetPCPublicCDKey(oPC, TRUE)+GetName(oPC)+GetTag(OBJECT_SELF), 1, 900.0); return FALSE; } else { + IncrementPlayerStatistic(oPC, "persuade_succeeded"); TakeGoldFromCreature(nCost, oPC, TRUE); return TRUE; } diff --git a/src/nss/dlg_bluf_chk.nss b/src/nss/dlg_bluf_chk.nss index 99f7f200..1cae29d2 100644 --- a/src/nss/dlg_bluf_chk.nss +++ b/src/nss/dlg_bluf_chk.nss @@ -1,4 +1,5 @@ #include "inc_persist" +#include "inc_general" int StartingConditional() { @@ -8,11 +9,13 @@ int StartingConditional() if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) { + IncrementPlayerStatistic(oPC, "bluff_failed"); SetTemporaryInt(GetPCPublicCDKey(oPC, TRUE)+GetName(oPC)+GetTag(OBJECT_SELF)+"_bluf", 1, 900.0); return FALSE; } else { + IncrementPlayerStatistic(oPC, "bluff_succeeded"); return TRUE; } } diff --git a/src/nss/dlg_chk_bluf.nss b/src/nss/dlg_chk_bluf.nss index 28d20a72..cdcbc8d7 100644 --- a/src/nss/dlg_chk_bluf.nss +++ b/src/nss/dlg_chk_bluf.nss @@ -1,4 +1,5 @@ #include "inc_persist" +#include "inc_general" // Bluff against bluff_dc local variable, offer 1 attempt per 15min // set script param "dc" to use that instead @@ -21,9 +22,10 @@ int StartingConditional() if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) { + IncrementPlayerStatistic(oPC, "bluff_failed"); SetTemporaryInt(GetPCPublicCDKey(oPC, TRUE)+GetName(oPC)+"_"+GetTag(OBJECT_SELF)+"_bluf", 1, 900.0); return FALSE; } - + IncrementPlayerStatistic(oPC, "bluff_succeeded"); return TRUE; } diff --git a/src/nss/dlg_chk_pers.nss b/src/nss/dlg_chk_pers.nss index 49fc3e6d..2445c98b 100644 --- a/src/nss/dlg_chk_pers.nss +++ b/src/nss/dlg_chk_pers.nss @@ -1,4 +1,5 @@ #include "inc_persist" +#include "inc_general" // Persuade against persuade_dc local variable, offer 1 attempt per 15min // set script param "dc" to use that instead @@ -17,9 +18,10 @@ int StartingConditional() if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) { + IncrementPlayerStatistic(oPC, "persuade_failed"); SetTemporaryInt(GetPCPublicCDKey(oPC, TRUE)+GetName(oPC)+"_"+GetTag(OBJECT_SELF)+"_pers", 1, 900.0); return FALSE; } - + IncrementPlayerStatistic(oPC, "persuade_succeeded"); return TRUE; } diff --git a/src/nss/dlg_divine_pers.nss b/src/nss/dlg_divine_pers.nss index 482e61c0..cbda1619 100644 --- a/src/nss/dlg_divine_pers.nss +++ b/src/nss/dlg_divine_pers.nss @@ -1,5 +1,6 @@ #include "inc_gold" #include "inc_persist" +#include "inc_general" int StartingConditional() { @@ -15,10 +16,12 @@ int StartingConditional() if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) { + IncrementPlayerStatistic(oPC, "persuade_failed"); return FALSE; } else { + IncrementPlayerStatistic(oPC, "persuade_succeeded"); TakeGoldFromCreature(nCost, oPC, TRUE); location lLocation = GetLocation(GetObjectByTag(GetLocalString(OBJECT_SELF, "warden_tele_wp"))); AssignCommand(oPC, JumpToLocation(lLocation)); diff --git a/src/nss/dlg_ferry_pers.nss b/src/nss/dlg_ferry_pers.nss index 3733ba9b..37dcc895 100644 --- a/src/nss/dlg_ferry_pers.nss +++ b/src/nss/dlg_ferry_pers.nss @@ -16,14 +16,15 @@ int StartingConditional() if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) { + IncrementPlayerStatistic(oPC, "persuade_failed"); return FALSE; } else { TakeGoldFromCreature(nCost, oPC, TRUE); - - IncrementStat(oPC, "gold_spent_on_ferries", nCost); - IncrementStat(oPC, "ferries_used"); + IncrementPlayerStatistic(oPC, "persuade_succeeded"); + IncrementPlayerStatistic(oPC, "gold_spent_on_ferries", nCost); + IncrementPlayerStatistic(oPC, "ferries_used"); location lLocation = GetLocation(GetObjectByTag(GetScriptParam("target"))); FadeToBlack(oPC); diff --git a/src/nss/dlg_ferry_tele.nss b/src/nss/dlg_ferry_tele.nss index 27f4ca1a..12a67fd2 100644 --- a/src/nss/dlg_ferry_tele.nss +++ b/src/nss/dlg_ferry_tele.nss @@ -12,8 +12,8 @@ void main() { TakeGoldFromCreature(nCost, oPC, TRUE); - IncrementStat(oPC, "gold_spent_on_ferries", nCost); - IncrementStat(oPC, "ferries_used"); + IncrementPlayerStatistic(oPC, "gold_spent_on_ferries", nCost); + IncrementPlayerStatistic(oPC, "ferries_used"); location lLocation = GetLocation(GetObjectByTag(GetScriptParam("target"))); FadeToBlack(oPC); diff --git a/src/nss/dlg_house_buy.nss b/src/nss/dlg_house_buy.nss index b559f308..2e2ade01 100644 --- a/src/nss/dlg_house_buy.nss +++ b/src/nss/dlg_house_buy.nss @@ -11,7 +11,7 @@ void main() ActionOpenDoor(OBJECT_SELF); TakeGoldFromCreature(nGold, oPC, TRUE); SetCampaignInt(GetPCPublicCDKey(oPC), "house_cost", nGold); - IncrementStat(oPC, "gold_spent_from_buying", nGold); + IncrementPlayerStatistic(oPC, "gold_spent_from_buying", nGold); InitializeHouseMapPin(oPC); HouseBuyWebhook(oPC, nGold, GetArea(OBJECT_SELF)); } diff --git a/src/nss/dlg_house_sell.nss b/src/nss/dlg_house_sell.nss index 3d3b936d..320192ad 100644 --- a/src/nss/dlg_house_sell.nss +++ b/src/nss/dlg_house_sell.nss @@ -19,7 +19,7 @@ void main() // TODO: Handle placeable decorations - IncrementStat(oPC, "gold_earned_from_selling", nGold); + IncrementPlayerStatistic(oPC, "gold_earned_from_selling", nGold); // So if we blow up the database timestamp, that can't happen any more. string sKey = GetPCPublicCDKey(oPC, TRUE); diff --git a/src/nss/dlg_q_chk_advb.nss b/src/nss/dlg_q_chk_advb.nss index 7a61d482..169cdfd1 100644 --- a/src/nss/dlg_q_chk_advb.nss +++ b/src/nss/dlg_q_chk_advb.nss @@ -10,11 +10,13 @@ int StartingConditional() AdjustAlignment(oPC, ALIGNMENT_CHAOTIC, BLUFF_CHAOS_SHIFT, FALSE); if(GetIsSkillSuccessful(oPC, nSkill, nDC)) { + IncrementPlayerStatistic(oPC, "bluff_succeeded"); AdvanceQuest(OBJECT_SELF, oPC, nTarget, TRUE); return TRUE; } else { + IncrementPlayerStatistic(oPC, "bluff_failed"); return FALSE; } } diff --git a/src/nss/dlg_q_chk_advb1.nss b/src/nss/dlg_q_chk_advb1.nss index 8032e4ff..eeeb0879 100644 --- a/src/nss/dlg_q_chk_advb1.nss +++ b/src/nss/dlg_q_chk_advb1.nss @@ -9,11 +9,13 @@ int StartingConditional() AdjustAlignment(oPC, ALIGNMENT_CHAOTIC, BLUFF_CHAOS_SHIFT, FALSE); if(GetIsSkillSuccessful(oPC, nSkill, nDC)) { + IncrementPlayerStatistic(oPC, "bluff_succeeded"); AdvanceQuest(OBJECT_SELF, oPC, 1, TRUE); return TRUE; } else { + IncrementPlayerStatistic(oPC, "bluff_failed"); return FALSE; } } diff --git a/src/nss/dlg_q_chk_advb2.nss b/src/nss/dlg_q_chk_advb2.nss index 6cf7c2c2..1ba237f5 100644 --- a/src/nss/dlg_q_chk_advb2.nss +++ b/src/nss/dlg_q_chk_advb2.nss @@ -9,11 +9,13 @@ int StartingConditional() AdjustAlignment(oPC, ALIGNMENT_CHAOTIC, BLUFF_CHAOS_SHIFT, FALSE); if(GetIsSkillSuccessful(oPC, nSkill, nDC)) { + IncrementPlayerStatistic(oPC, "bluff_succeeded"); AdvanceQuest(OBJECT_SELF, oPC, 2, TRUE); return TRUE; } else { + IncrementPlayerStatistic(oPC, "bluff_failed"); return FALSE; } } diff --git a/src/nss/dlg_q_chk_advb3.nss b/src/nss/dlg_q_chk_advb3.nss index ad336053..2ba58572 100644 --- a/src/nss/dlg_q_chk_advb3.nss +++ b/src/nss/dlg_q_chk_advb3.nss @@ -9,11 +9,13 @@ int StartingConditional() AdjustAlignment(oPC, ALIGNMENT_CHAOTIC, BLUFF_CHAOS_SHIFT, FALSE); if(GetIsSkillSuccessful(oPC, nSkill, nDC)) { + IncrementPlayerStatistic(oPC, "bluff_succeeded"); AdvanceQuest(OBJECT_SELF, oPC, 3, TRUE); return TRUE; } else { + IncrementPlayerStatistic(oPC, "bluff_failed"); return FALSE; } } diff --git a/src/nss/dlg_q_chk_advb4.nss b/src/nss/dlg_q_chk_advb4.nss index b7a4da8b..2cbd85dd 100644 --- a/src/nss/dlg_q_chk_advb4.nss +++ b/src/nss/dlg_q_chk_advb4.nss @@ -9,11 +9,13 @@ int StartingConditional() AdjustAlignment(oPC, ALIGNMENT_CHAOTIC, BLUFF_CHAOS_SHIFT, FALSE); if(GetIsSkillSuccessful(oPC, nSkill, nDC)) { + IncrementPlayerStatistic(oPC, "bluff_succeeded"); AdvanceQuest(OBJECT_SELF, oPC, 4, TRUE); return TRUE; } else { + IncrementPlayerStatistic(oPC, "bluff_failed"); return FALSE; } } diff --git a/src/nss/dlg_q_chk_advb5.nss b/src/nss/dlg_q_chk_advb5.nss index dfb923c2..3c1e57c7 100644 --- a/src/nss/dlg_q_chk_advb5.nss +++ b/src/nss/dlg_q_chk_advb5.nss @@ -9,11 +9,13 @@ int StartingConditional() AdjustAlignment(oPC, ALIGNMENT_CHAOTIC, BLUFF_CHAOS_SHIFT, FALSE); if(GetIsSkillSuccessful(oPC, nSkill, nDC)) { + IncrementPlayerStatistic(oPC, "bluff_succeeded"); AdvanceQuest(OBJECT_SELF, oPC, 5, TRUE); return TRUE; } else { + IncrementPlayerStatistic(oPC, "bluff_failed"); return FALSE; } } diff --git a/src/nss/dlg_q_chk_advb6.nss b/src/nss/dlg_q_chk_advb6.nss index 63d72aed..48e23914 100644 --- a/src/nss/dlg_q_chk_advb6.nss +++ b/src/nss/dlg_q_chk_advb6.nss @@ -9,11 +9,13 @@ int StartingConditional() AdjustAlignment(oPC, ALIGNMENT_CHAOTIC, BLUFF_CHAOS_SHIFT, FALSE); if(GetIsSkillSuccessful(oPC, nSkill, nDC)) { + IncrementPlayerStatistic(oPC, "bluff_succeeded"); AdvanceQuest(OBJECT_SELF, oPC, 6, TRUE); return TRUE; } else { + IncrementPlayerStatistic(oPC, "bluff_failed"); return FALSE; } } diff --git a/src/nss/dlg_q_chk_advb7.nss b/src/nss/dlg_q_chk_advb7.nss index b411d918..6f671ebd 100644 --- a/src/nss/dlg_q_chk_advb7.nss +++ b/src/nss/dlg_q_chk_advb7.nss @@ -9,11 +9,13 @@ int StartingConditional() AdjustAlignment(oPC, ALIGNMENT_CHAOTIC, BLUFF_CHAOS_SHIFT, FALSE); if(GetIsSkillSuccessful(oPC, nSkill, nDC)) { + IncrementPlayerStatistic(oPC, "bluff_succeeded"); AdvanceQuest(OBJECT_SELF, oPC, 7, TRUE); return TRUE; } else { + IncrementPlayerStatistic(oPC, "bluff_failed"); return FALSE; } } diff --git a/src/nss/dlg_q_chk_advb8.nss b/src/nss/dlg_q_chk_advb8.nss index ce27eadc..64338f0b 100644 --- a/src/nss/dlg_q_chk_advb8.nss +++ b/src/nss/dlg_q_chk_advb8.nss @@ -9,11 +9,13 @@ int StartingConditional() AdjustAlignment(oPC, ALIGNMENT_CHAOTIC, BLUFF_CHAOS_SHIFT, FALSE); if(GetIsSkillSuccessful(oPC, nSkill, nDC)) { + IncrementPlayerStatistic(oPC, "bluff_succeeded"); AdvanceQuest(OBJECT_SELF, oPC, 8, TRUE); return TRUE; } else { + IncrementPlayerStatistic(oPC, "bluff_failed"); return FALSE; } } diff --git a/src/nss/dlg_q_chk_advb9.nss b/src/nss/dlg_q_chk_advb9.nss index 4f170726..2ab86067 100644 --- a/src/nss/dlg_q_chk_advb9.nss +++ b/src/nss/dlg_q_chk_advb9.nss @@ -9,11 +9,13 @@ int StartingConditional() AdjustAlignment(oPC, ALIGNMENT_CHAOTIC, BLUFF_CHAOS_SHIFT, FALSE); if(GetIsSkillSuccessful(oPC, nSkill, nDC)) { + IncrementPlayerStatistic(oPC, "bluff_succeeded"); AdvanceQuest(OBJECT_SELF, oPC, 9, TRUE); return TRUE; } else { + IncrementPlayerStatistic(oPC, "bluff_failed"); return FALSE; } } diff --git a/src/nss/dlg_relevel_pers.nss b/src/nss/dlg_relevel_pers.nss index c771d56c..503bafae 100644 --- a/src/nss/dlg_relevel_pers.nss +++ b/src/nss/dlg_relevel_pers.nss @@ -1,5 +1,6 @@ #include "inc_gold" #include "inc_persist" +#include "inc_general" int StartingConditional() { @@ -17,10 +18,12 @@ int StartingConditional() if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) { + IncrementPlayerStatistic(oPC, "persuade_failed"); return FALSE; } else { + IncrementPlayerStatistic(oPC, "persuade_succeeded"); TakeGoldFromCreature(nCost, oPC, TRUE); SetXP(oPC, 1); SetXP(oPC, nXP); diff --git a/src/nss/dlg_ship_pers1.nss b/src/nss/dlg_ship_pers1.nss index eb255cd9..b45e7800 100644 --- a/src/nss/dlg_ship_pers1.nss +++ b/src/nss/dlg_ship_pers1.nss @@ -1,5 +1,6 @@ #include "inc_persist" #include "inc_ship" +#include "inc_general" int StartingConditional() { @@ -9,8 +10,13 @@ int StartingConditional() SetTemporaryInt(GetPCPublicCDKey(oPC, TRUE)+GetName(oPC)+"_"+GetTag(OBJECT_SELF)+"_pers", 1, 900.0); - if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) return FALSE; - + if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) + { + IncrementPlayerStatistic(oPC, "persuade_failed"); + return FALSE; + } + + IncrementPlayerStatistic(oPC, "persuade_succeeded"); PayShipAndTravel(OBJECT_SELF, GetPCSpeaker(), 1, TRUE); return TRUE; diff --git a/src/nss/dlg_ship_pers2.nss b/src/nss/dlg_ship_pers2.nss index f26c01c1..6612ab5b 100644 --- a/src/nss/dlg_ship_pers2.nss +++ b/src/nss/dlg_ship_pers2.nss @@ -1,5 +1,6 @@ #include "inc_persist" #include "inc_ship" +#include "inc_general" int StartingConditional() { @@ -9,8 +10,12 @@ int StartingConditional() SetTemporaryInt(GetPCPublicCDKey(oPC, TRUE)+GetName(oPC)+"_"+GetTag(OBJECT_SELF)+"_pers", 1, 900.0); - if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) return FALSE; - + if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) + { + IncrementPlayerStatistic(oPC, "persuade_failed"); + return FALSE; + } + IncrementPlayerStatistic(oPC, "persuade_succeeded"); PayShipAndTravel(OBJECT_SELF, GetPCSpeaker(), 2, TRUE); return TRUE; diff --git a/src/nss/door_failopen.nss b/src/nss/door_failopen.nss index f032d2b3..128ac774 100644 --- a/src/nss/door_failopen.nss +++ b/src/nss/door_failopen.nss @@ -1,4 +1,5 @@ #include "inc_key" +#include "inc_general" void main() { @@ -10,6 +11,7 @@ void main() if (GetHasKey(oPC, sKeyTag)) { SendMessageToPC(oPC, "You open the lock with the " + GetKeyName(sKeyTag) + " in your key bag."); + IncrementPlayerStatistic(oPC, "key_doors_opened"); SetLocked(OBJECT_SELF, FALSE); AssignCommand(OBJECT_SELF, ActionOpenDoor(OBJECT_SELF)); diff --git a/src/nss/fol_hirepe.nss b/src/nss/fol_hirepe.nss index 227ca687..3c5270c1 100644 --- a/src/nss/fol_hirepe.nss +++ b/src/nss/fol_hirepe.nss @@ -1,5 +1,6 @@ #include "inc_follower" #include "inc_persist" +#include "inc_general" #include "nw_i0_generic" @@ -11,11 +12,13 @@ int StartingConditional() if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) { + IncrementPlayerStatistic(oPC, "persuade_failed"); SetTemporaryInt(GetObjectUUID(oPC)+"_"+GetObjectUUID(OBJECT_SELF)+"_pers", 1, 900.0); return FALSE; } else { + IncrementPlayerStatistic(oPC, "persuade_succeeded"); SetFollowerMaster(OBJECT_SELF, oPC); SetAssociateState(NW_ASC_USE_RANGED_WEAPON, FALSE); ClearAllActions(); diff --git a/src/nss/fol_hirepem.nss b/src/nss/fol_hirepem.nss index 89809e90..842bb3d6 100644 --- a/src/nss/fol_hirepem.nss +++ b/src/nss/fol_hirepem.nss @@ -1,5 +1,6 @@ #include "inc_follower" #include "inc_persist" +#include "inc_general" #include "nw_i0_generic" @@ -11,11 +12,13 @@ int StartingConditional() if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) { + IncrementPlayerStatistic(oPC, "persuade_failed"); SetTemporaryInt(GetObjectUUID(oPC)+"_"+GetObjectUUID(OBJECT_SELF)+"_pers", 1, 900.0); return FALSE; } else { + IncrementPlayerStatistic(oPC, "persuade_succeeded"); SetFollowerMaster(OBJECT_SELF, oPC); SetAssociateState(NW_ASC_USE_RANGED_WEAPON, FALSE); ClearAllActions(); diff --git a/src/nss/hen_hire.nss b/src/nss/hen_hire.nss index f67a3bbb..f886af22 100644 --- a/src/nss/hen_hire.nss +++ b/src/nss/hen_hire.nss @@ -4,7 +4,7 @@ void main() { object oPlayer = GetPCSpeaker(); - IncrementStat(oPlayer, "henchman_recruited"); + IncrementPlayerStatistic(oPlayer, "henchman_recruited"); SetMaster(OBJECT_SELF, oPlayer); ForceRest(OBJECT_SELF); diff --git a/src/nss/hen_hirepe.nss b/src/nss/hen_hirepe.nss index 61469274..d6b01d91 100644 --- a/src/nss/hen_hirepe.nss +++ b/src/nss/hen_hirepe.nss @@ -1,5 +1,6 @@ #include "inc_henchman" #include "inc_persist" +#include "inc_general" int StartingConditional() @@ -12,11 +13,13 @@ int StartingConditional() if(!(GetIsSkillSuccessful(oPC, nSkill, nDC))) { + IncrementPlayerStatistic(oPC, "persuade_failed"); return FALSE; } else { - IncrementStat(oPC, "henchman_recruited"); + IncrementPlayerStatistic(oPC, "persuade_succeeded"); + IncrementPlayerStatistic(oPC, "henchman_recruited"); SetMaster(OBJECT_SELF, oPC); ForceRest(OBJECT_SELF); return TRUE; diff --git a/src/nss/hen_none_hire.nss b/src/nss/hen_none_hire.nss index 5f71c1a4..717b5256 100644 --- a/src/nss/hen_none_hire.nss +++ b/src/nss/hen_none_hire.nss @@ -6,7 +6,7 @@ void main() object oPC = GetPCSpeaker(); if (GetHenchmanCount(oPC) == 0) { - IncrementStat(oPC, "henchman_recruited"); + IncrementPlayerStatistic(oPC, "henchman_recruited"); SetMaster(OBJECT_SELF, oPC); } } diff --git a/src/nss/hen_ondeath.nss b/src/nss/hen_ondeath.nss index 8fee883e..658853e0 100644 --- a/src/nss/hen_ondeath.nss +++ b/src/nss/hen_ondeath.nss @@ -3,12 +3,15 @@ void main() { + // ONLY henchmen use this + // followers still retain ai_ondeath + object oKiller = GetLastHostileActor(); if (GetFactionEqual(oKiller, OBJECT_SELF)) { - IncrementStat(oKiller, "allies_killed"); - IncrementStat(GetMaster(OBJECT_SELF), "henchman_died"); + IncrementPlayerStatistic(oKiller, "allies_killed"); } + IncrementPlayerStatistic(GetMaster(OBJECT_SELF), "henchman_died"); if (GetLocalInt(OBJECT_SELF, "PETRIFIED") == 1) { diff --git a/src/nss/inc_adv_assassin.nss b/src/nss/inc_adv_assassin.nss index 71ce6ce5..cbec6698 100644 --- a/src/nss/inc_adv_assassin.nss +++ b/src/nss/inc_adv_assassin.nss @@ -154,7 +154,7 @@ object MakeAssassinNote(object oAssassin, object oPC) SetDescription(oNote, "This note was carried by an assassin in " +GetName(GetArea(oAssassin)) + ". It is too bloodstained to make out what it might have once said."); } - IncrementStat(oPC, "assassination_attempts_thwarted"); + IncrementPlayerStatistic(oPC, "assassination_attempts_thwarted"); return oNote; } diff --git a/src/nss/inc_follower.nss b/src/nss/inc_follower.nss index 5a66ab92..ee7cf7d9 100644 --- a/src/nss/inc_follower.nss +++ b/src/nss/inc_follower.nss @@ -116,7 +116,7 @@ void SetFollowerMaster(object oFollower, object oPlayer) SetLocalString(oFollower, "master", GetObjectUUID(oPlayer)); SetLocalString(oFollower, "heartbeat_script", "fol_heartb"); - IncrementStat(oPlayer, "followers_recruited"); + IncrementPlayerStatistic(oPlayer, "followers_recruited"); AddHenchman(oPlayer, oFollower); AssignHenchmanScripts(oFollower); diff --git a/src/nss/inc_general.nss b/src/nss/inc_general.nss index 9d391916..750ac6bb 100644 --- a/src/nss/inc_general.nss +++ b/src/nss/inc_general.nss @@ -762,24 +762,83 @@ int GetIsControllable(object oCreature) return TRUE; } -int IncrementStat(object oPC, string sStat, int nIncrement = 1); -int IncrementStat(object oPC, string sStat, int nIncrement = 1) +int IncrementPlayerStatistic(object oPC, string sStat, int nIncrement = 1); +int IncrementPlayerStatistic(object oPC, string sStat, int nIncrement = 1) { if (!GetIsPC(oPC)) return 0; string sVarName = STAT_PREFIX+sStat; int nNewTotal = SQLocalsPlayer_GetInt(oPC, sVarName) + nIncrement; - SQLocalsPlayer_SetInt(oPC, sVarName, nNewTotal); + + string sKey = GetPCPublicCDKey(oPC, TRUE); + int nOldPlayerValue = GetCampaignInt(sKey, STAT_PREFIX+sStat); + SetCampaignInt(sKey, STAT_PREFIX+sStat, nOldPlayerValue+nIncrement); return nNewTotal; } +void SetPlayerStatisticString(object oPC, string sStat, string sValue, int bCDKeyDB=0); +void SetPlayerStatisticString(object oPC, string sStat, string sValue, int bCDKeyDB=0) +{ + if (!GetIsPC(oPC)) return; + string sVarName = STAT_PREFIX+sStat; + if (!bCDKeyDB) + { + SQLocalsPlayer_SetString(oPC, sVarName, sValue); + return; + } + string sKey = GetPCPublicCDKey(oPC, TRUE); + SetCampaignString(sKey, STAT_PREFIX+sStat, sValue); +} + +void SetPlayerStatistic(object oPC, string sStat, int nValue, int bCDKeyDB=0); +void SetPlayerStatistic(object oPC, string sStat, int nValue, int bCDKeyDB=0) +{ + if (!GetIsPC(oPC)) return; + string sVarName = STAT_PREFIX+sStat; + if (!bCDKeyDB) + { + SQLocalsPlayer_SetInt(oPC, sVarName, nValue); + return; + } + string sKey = GetPCPublicCDKey(oPC, TRUE); + SetCampaignInt(sKey, STAT_PREFIX+sStat, nValue); +} + +string GetPlayerStatisticString(object oPC, string sStat, int bCDKeyDB=0); +string GetPlayerStatisticString(object oPC, string sStat, int bCDKeyDB=0) +{ + if (!GetIsPC(oPC)) return ""; + + string sVarName = STAT_PREFIX+sStat; + if (!bCDKeyDB) + { + return SQLocalsPlayer_GetString(oPC, sVarName); + } + string sKey = GetPCPublicCDKey(oPC, TRUE); + return GetCampaignString(sKey, STAT_PREFIX+sStat); +} + +int GetPlayerStatistic(object oPC, string sStat, int bCDKeyDB=0); +int GetPlayerStatistic(object oPC, string sStat, int bCDKeyDB=0) +{ + if (!GetIsPC(oPC)) return 0; + + string sVarName = STAT_PREFIX+sStat; + if (!bCDKeyDB) + { + return SQLocalsPlayer_GetInt(oPC, sVarName); + } + string sKey = GetPCPublicCDKey(oPC, TRUE); + return GetCampaignInt(sKey, STAT_PREFIX+sStat); +} + // for delays -void VoidIncrementStat(object oPC, string sStat, int nIncrement = 1) +void VoidIncrementPlayerStatistic(object oPC, string sStat, int nIncrement = 1) { - IncrementStat(oPC, sStat, nIncrement); + IncrementPlayerStatistic(oPC, sStat, nIncrement); } void SendMessageToAllPCs(string sMessage, int nColor = MESSAGE_COLOR_SERVER); diff --git a/src/nss/inc_horse.nss b/src/nss/inc_horse.nss index ed91a317..23d15cc4 100644 --- a/src/nss/inc_horse.nss +++ b/src/nss/inc_horse.nss @@ -1,4 +1,5 @@ #include "nwnx_creature" +#include "inc_general" //#include "inc_debug" const int HENCHMAN_MOUNT = 16; @@ -241,6 +242,7 @@ void ApplyMount(object oPC, int nHorse = 0) //SendMessageToPC(oPC, "Riding Applies: Skill Riding Check: "+IntToString(GetSkillRank(SKILL_RIDE, oPC) / 5)+" Spell Failure: "+IntToString(GetRidingSpellFailure(oPC))+"%"); DetermineHorseEffects(oPC); + IncrementPlayerStatistic(oPC, "times_mounted"); } void ValidateMount(object oPC) diff --git a/src/nss/inc_housing.nss b/src/nss/inc_housing.nss index 8a6b0ccc..cc24193a 100644 --- a/src/nss/inc_housing.nss +++ b/src/nss/inc_housing.nss @@ -638,7 +638,7 @@ void BuyPlaceable(object oPlaceable, object oPC, int bCost = TRUE) { SetLocalString(oItem, "uuid", GetRandomUUID()); TakeGoldFromCreature(nCost, oPC, TRUE); - IncrementStat(oPC, "gold_spent_from_buying", nCost); + IncrementPlayerStatistic(oPC, "gold_spent_from_buying", nCost); } else { // otherwise, assume you are retrieving a placeable and use the stored UUID diff --git a/src/nss/inc_loot.nss b/src/nss/inc_loot.nss index b9cf02b8..63c0df2d 100644 --- a/src/nss/inc_loot.nss +++ b/src/nss/inc_loot.nss @@ -1209,8 +1209,8 @@ void OpenPersonalLoot(object oContainer, object oPC) { AssignCommand(oContainer, ActionPlayAnimation(ANIMATION_PLACEABLE_OPEN)); - IncrementStat(oPC, "gold_looted", nGold); - IncrementStat(oPC, "treasures_looted"); + IncrementPlayerStatistic(oPC, "gold_looted", nGold); + IncrementPlayerStatistic(oPC, "treasures_looted"); GiveGoldToCreature(oPC, nGold); DeleteLocalInt(oPersonalLoot, PERSONAL_LOOT_GOLD_AMOUNT); diff --git a/src/nss/inc_quest.nss b/src/nss/inc_quest.nss index c0b4dc7f..cc94f1d4 100644 --- a/src/nss/inc_quest.nss +++ b/src/nss/inc_quest.nss @@ -273,7 +273,11 @@ void AdvanceQuest(object oQuestObject, object oPC, int nTarget, int bBluff = FAL // record stat for bounties if (GetStringLeft(sQuestName, 2) == "b_" && jeQuest.nQuestCompleted) { - IncrementStat(oPC, "bounties_completed"); + IncrementPlayerStatistic(oPC, "bounties_completed"); + } + else if (jeQuest.nQuestCompleted) + { + IncrementPlayerStatistic(oPC, "quests_completed"); } UpdateQuestgiverHighlights(GetArea(oQuestObject), oPC); diff --git a/src/nss/inc_restxp.nss b/src/nss/inc_restxp.nss index 3177d28f..51544cc9 100644 --- a/src/nss/inc_restxp.nss +++ b/src/nss/inc_restxp.nss @@ -229,6 +229,12 @@ void AddRestedXPHeartbeat(object oPC) float fOldPercentage = GetRestedXPPercentage(oPC); _AddRestedXP(oPC, 6.0); float fNewPercentage = GetRestedXPPercentage(oPC); + + if (!GetIsPlayerHomeless(oPC) && GetTag(GetArea(oPC)) == GetHomeTag(oPC)) + { + IncrementPlayerStatistic(oPC, "time_spent_in_house", 6); + } + if (fmod(fOldPercentage, RESTEDXP_NOTIFICATION_PERCENTAGE) > fmod(fNewPercentage, RESTEDXP_NOTIFICATION_PERCENTAGE)) { SendRestedXPNotifierToPC(oPC); @@ -284,6 +290,7 @@ void GiveHouseRestingXP(object oPC) FloatingTextStringOnCreature("You cannot accumulate more Rested XP!", oPC, FALSE); return; } + IncrementPlayerStatistic(oPC, "times_rested_in_house"); int nNow = SQLite_GetTimeStamp(); SQLocalsPlayer_SetInt(oPC, "RestXP_LastHouseRest", nNow); int nHouseCost = GetCampaignInt(GetPCPublicCDKey(oPC), "house_cost"); diff --git a/src/nss/inc_ship.nss b/src/nss/inc_ship.nss index 2ef4200c..786d98c8 100644 --- a/src/nss/inc_ship.nss +++ b/src/nss/inc_ship.nss @@ -171,8 +171,8 @@ void PayShipAndTravel(object oSpeaker, object oPlayer, int nTarget, int bPersuad // do not proceed if the player does not have enough gold if (GetGold(oPlayer) < nCost) return; - IncrementStat(oPlayer, "gold_spent_on_long_travel", nCost); - IncrementStat(oPlayer, "long_travel_used"); + IncrementPlayerStatistic(oPlayer, "gold_spent_on_long_travel", nCost); + IncrementPlayerStatistic(oPlayer, "long_travel_used"); object oArea = GetArea(oDestination); diff --git a/src/nss/inc_trap.nss b/src/nss/inc_trap.nss index 50dd023a..82973e17 100644 --- a/src/nss/inc_trap.nss +++ b/src/nss/inc_trap.nss @@ -235,7 +235,7 @@ void SetTrapTriggeredOnCreature(object oCreature, string sTrapName = "trap") { SetLocalString(oCreature, "trap_triggered", sTrapName); - IncrementStat(oCreature, "traps_triggered"); + IncrementPlayerStatistic(oCreature, "traps_triggered"); AssignCommand(oCreature, DelayCommand(0.2, DeleteLocalString(oCreature, "trap_triggered"))); } diff --git a/src/nss/nw_i0_spells.nss b/src/nss/nw_i0_spells.nss index b16f3ca4..4128609a 100644 --- a/src/nss/nw_i0_spells.nss +++ b/src/nss/nw_i0_spells.nss @@ -9,6 +9,7 @@ //:: Updated By: 2003/20/10 Georg Zoeller //::////////////////////////////////////////////// #include "70_inc_spells" +#include "inc_general" // GZ: Number of spells in GetSpellBreachProtections const int NW_I0_SPELLS_MAX_BREACH = 32;//1.72: removed duplicated shadow shield on list @@ -523,6 +524,7 @@ itemproperty ip; return FALSE; } +// Oh my god what the heck is this indentation, it's hideous int MyResistSpell(object oCaster, object oTarget, float fDelay = 0.0) { if(spell.SR == NO) return 0;//dynamic spell resist override feature, -1 = ignore SR for this spell @@ -585,7 +587,13 @@ effect eWorkaround; } effect eMantle = EffectVisualEffect(VFX_IMP_SPELL_MANTLE_USE); DelayCommand(fDelay,ApplyEffectToObject(DURATION_TYPE_INSTANT,eMantle,oTarget)); - return ResistSpell(oCaster,oTarget); + int nResisted = ResistSpell(oCaster,oTarget); + if (nResisted == 1) + { + IncrementPlayerStatistic(oTarget, "incoming_spells_resisted"); + IncrementPlayerStatistic(oCaster, "outgoing_spells_resisted"); + } + return nResisted; } int nResisted = 0; if(SR > 0)//1.72: fixed custom spell resist calculation not counting spell penetration feats @@ -605,6 +613,11 @@ effect eWorkaround; SendMessageToPC(oTarget,sFeedback); SendMessageToPC(oCaster,sFeedback); } + if (nResisted == 1) + { + IncrementPlayerStatistic(oTarget, "incoming_spells_resisted"); + IncrementPlayerStatistic(oCaster, "outgoing_spells_resisted"); + } return nResisted; } else if((clOverride > 0 || nPenetrationModifier > 0) && SR > 0)//spell penetration correction @@ -650,6 +663,11 @@ DeleteLocalInt(oTarget,"GetSpellResistance");//cleanup effect eMantle = EffectVisualEffect(VFX_IMP_SPELL_MANTLE_USE); DelayCommand(fDelay,ApplyEffectToObject(DURATION_TYPE_INSTANT,eMantle,oTarget)); } + if (nResist == 1) + { + IncrementPlayerStatistic(oTarget, "incoming_spells_resisted"); + IncrementPlayerStatistic(oCaster, "outgoing_spells_resisted"); + } return nResist; } diff --git a/src/nss/nw_s0_animdead.nss b/src/nss/nw_s0_animdead.nss index 890e5d48..f9958f18 100644 --- a/src/nss/nw_s0_animdead.nss +++ b/src/nss/nw_s0_animdead.nss @@ -14,6 +14,7 @@ #include "70_inc_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -67,6 +68,10 @@ void main() eSummon = EffectSummonCreature("sum_skelchief",VFX_FNF_SUMMON_UNDEAD); } } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } //Apply the summon visual and summon the two undead. ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, DurationToSeconds(nDuration)); } diff --git a/src/nss/nw_s0_crgrund.nss b/src/nss/nw_s0_crgrund.nss index 59b7e657..b7b0679c 100644 --- a/src/nss/nw_s0_crgrund.nss +++ b/src/nss/nw_s0_crgrund.nss @@ -14,6 +14,7 @@ #include "70_inc_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -53,6 +54,10 @@ void main() { eSummon = EffectSummonCreature("NW_S_MUMCLERIC",VFX_FNF_SUMMON_UNDEAD); } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } //Apply summon effect and VFX impact. ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, DurationToSeconds(nDuration)); } diff --git a/src/nss/nw_s0_crundead.nss b/src/nss/nw_s0_crundead.nss index 6a6a8cae..a8b35b15 100644 --- a/src/nss/nw_s0_crundead.nss +++ b/src/nss/nw_s0_crundead.nss @@ -14,6 +14,7 @@ #include "70_inc_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -52,6 +53,10 @@ void main() { eSummon = EffectSummonCreature("NW_S_SPECTRE",VFX_FNF_SUMMON_UNDEAD); } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } //Apply VFX impact and summon effect ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, DurationToSeconds(nDuration)); diff --git a/src/nss/nw_s0_gate.nss b/src/nss/nw_s0_gate.nss index b578a543..2783557c 100644 --- a/src/nss/nw_s0_gate.nss +++ b/src/nss/nw_s0_gate.nss @@ -17,6 +17,7 @@ void CreateBalor(location lLoc); #include "70_inc_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -59,6 +60,10 @@ void main() ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVis, spell.Loc); DelayCommand(3.0, CreateBalor(spell.Loc)); } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } } void CreateBalor(location lLoc) diff --git a/src/nss/nw_s0_grplanar.nss b/src/nss/nw_s0_grplanar.nss index 5dceb710..41f2af25 100644 --- a/src/nss/nw_s0_grplanar.nss +++ b/src/nss/nw_s0_grplanar.nss @@ -21,6 +21,7 @@ Patch 1.71 #include "70_inc_spells" #include "x0_i0_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -99,6 +100,10 @@ void main() fDelay = 1.0; break; } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } //Apply the VFX impact and summon effect ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, RoundsToSeconds(nDuration)); } diff --git a/src/nss/nw_s0_knock.nss b/src/nss/nw_s0_knock.nss index a7fc34ab..de847ec2 100644 --- a/src/nss/nw_s0_knock.nss +++ b/src/nss/nw_s0_knock.nss @@ -59,7 +59,7 @@ void main() DelayCommand(fDelay, ApplyEffectToObject(DURATION_TYPE_INSTANT, eVis, oTarget)); DelayCommand(fDelay, AssignCommand(oTarget, PlaySound("gui_picklockopen"))); - IncrementStat(spell.Caster, "locks_unlocked"); + IncrementPlayerStatistic(spell.Caster, "locks_unlocked"); } } else if (nResist == 1) diff --git a/src/nss/nw_s0_lsplanar.nss b/src/nss/nw_s0_lsplanar.nss index d6af5fba..4ec33712 100644 --- a/src/nss/nw_s0_lsplanar.nss +++ b/src/nss/nw_s0_lsplanar.nss @@ -23,6 +23,7 @@ Patch 1.71 #include "70_inc_spells" #include "x0_i0_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -103,6 +104,10 @@ void main() } break; } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } //Apply the summon effect and the VFX impact ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, HoursToSeconds(nDuration)); } diff --git a/src/nss/nw_s0_mordswrd.nss b/src/nss/nw_s0_mordswrd.nss index 0a04f153..6ea3002d 100644 --- a/src/nss/nw_s0_mordswrd.nss +++ b/src/nss/nw_s0_mordswrd.nss @@ -13,6 +13,7 @@ #include "70_inc_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -35,6 +36,10 @@ void main() { nDuration = nDuration *2; //Duration is +100% } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } //Apply the VFX impact and summon effect ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, DurationToSeconds(nDuration)); } diff --git a/src/nss/nw_s0_planar.nss b/src/nss/nw_s0_planar.nss index 8fa8bc87..9eac8293 100644 --- a/src/nss/nw_s0_planar.nss +++ b/src/nss/nw_s0_planar.nss @@ -22,6 +22,7 @@ Patch 1.71 #include "70_inc_spells" #include "x0_i0_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -96,6 +97,10 @@ void main() eSummon = EffectSummonCreature("sum_slaadgreen", VFX_FNF_SUMMON_MONSTER_3, 1.0); break; } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } //Apply the summon effect and VFX impact ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, HoursToSeconds(nDuration)); } diff --git a/src/nss/nw_s0_summon.nss b/src/nss/nw_s0_summon.nss index 0b8a3c43..b3345095 100644 --- a/src/nss/nw_s0_summon.nss +++ b/src/nss/nw_s0_summon.nss @@ -22,6 +22,7 @@ effect SetSummonEffect(int nSpellID, int bAnimalDomain); #include "70_inc_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -46,7 +47,10 @@ void main() nDuration = nDuration *2; //Duration is +100% } //Apply the VFX impact and summon effect - + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, DurationToSeconds(nDuration)); } diff --git a/src/nss/nw_s0_summshad.nss b/src/nss/nw_s0_summshad.nss index 14692c78..49d19817 100644 --- a/src/nss/nw_s0_summshad.nss +++ b/src/nss/nw_s0_summshad.nss @@ -15,6 +15,7 @@ #include "70_inc_spells" #include "x0_i0_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -53,6 +54,10 @@ void main() { eSummon = EffectSummonCreature("NW_S_SHADLORD",VFX_FNF_SUMMON_UNDEAD); } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } //Apply VFX impact and summon effect ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, DurationToSeconds(nDuration)); diff --git a/src/nss/nw_s0_summshad02.nss b/src/nss/nw_s0_summshad02.nss index b0c7b1c9..e4dcbf54 100644 --- a/src/nss/nw_s0_summshad02.nss +++ b/src/nss/nw_s0_summshad02.nss @@ -15,6 +15,7 @@ #include "70_inc_spells" #include "x0_i0_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -49,6 +50,10 @@ void main() { eSummon = EffectSummonCreature("NW_S_SHADLORD",VFX_FNF_SUMMON_UNDEAD); } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } //Apply VFX impact and summon effect ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, DurationToSeconds(24)); diff --git a/src/nss/on_attack.nss b/src/nss/on_attack.nss new file mode 100644 index 00000000..2e3d49f2 --- /dev/null +++ b/src/nss/on_attack.nss @@ -0,0 +1,66 @@ +#include "nwnx_damage" +#include "util_i_math" +#include "inc_general" + +void main() +{ + object oAttacker = OBJECT_SELF; + struct NWNX_Damage_AttackEventData sAttack = NWNX_Damage_GetAttackEventData(); + if (GetIsPC(oAttacker) || GetIsPC(sAttack.oTarget)) + { + int bHit = sAttack.iAttackResult == 1 || sAttack.iAttackResult == 3 || sAttack.iAttackResult == 7 || sAttack.iAttackResult == 10; + if (sAttack.iAttackType == 65002) // attack of opportunity + { + if (GetIsPC(oAttacker)) + { + IncrementPlayerStatistic(oAttacker, "attacks_of_opportunity_made"); + if (bHit) + { + IncrementPlayerStatistic(oAttacker, "attacks_of_opportunity_hit"); + } + } + if (GetIsPC(sAttack.oTarget)) + { + IncrementPlayerStatistic(sAttack.oTarget, "attacks_of_opportunity_targeted_by"); + if (bHit) + { + IncrementPlayerStatistic(sAttack.oTarget, "attacks_of_opportunity_hit_by"); + } + } + } + if (sAttack.iSneakAttack > 0) // sneak and/or death attack + { + if (GetIsPC(oAttacker)) + { + IncrementPlayerStatistic(oAttacker, "sneak_attacks_made"); + if (bHit) + { + IncrementPlayerStatistic(oAttacker, "sneak_attacks_hit"); + } + } + if (GetIsPC(sAttack.oTarget)) + { + IncrementPlayerStatistic(sAttack.oTarget, "sneak_attacks_targeted_by"); + if (bHit) + { + IncrementPlayerStatistic(sAttack.oTarget, "sneak_attacks_hit_by"); + } + } + } + if (sAttack.iAttackResult == 3) // Critical hits + { + if (GetIsPC(oAttacker)) + { + IncrementPlayerStatistic(oAttacker, "critical_hits_landed"); + } + if (GetIsPC(sAttack.oTarget)) + { + IncrementPlayerStatistic(sAttack.oTarget, "critical_hits_taken"); + } + } + if (sAttack.iToHitRoll == 1 && GetIsPC(oAttacker)) + { + IncrementPlayerStatistic(oAttacker, "natural_one_attack_rolls"); + } + } +} \ No newline at end of file diff --git a/src/nss/on_damage.nss b/src/nss/on_damage.nss new file mode 100644 index 00000000..303af0a8 --- /dev/null +++ b/src/nss/on_damage.nss @@ -0,0 +1,49 @@ +#include "nwnx_damage" +#include "util_i_math" +#include "inc_general" + +void main() +{ + object oVictim = OBJECT_SELF; + struct NWNX_Damage_DamageEventData sDamage = NWNX_Damage_GetDamageEventData(); + if (GetIsPC(oVictim) || GetIsPC(sDamage.oDamager)) + { + int nPhys = max(0, sDamage.iBase) + max(0, sDamage.iBludgeoning) + max(0, sDamage.iSlash) + max(0, sDamage.iPierce); + int nMagic = max(0, sDamage.iMagical); + int nAcid = max(0, sDamage.iAcid); + int nCold = max(0, sDamage.iCold); + int nDivine = max(0, sDamage.iDivine); + int nElectrical = max(0, sDamage.iElectrical); + int nFire = max(0, sDamage.iFire); + int nNegative = max(0, sDamage.iNegative); + int nPositive = max(0, sDamage.iPositive); + int nSonic = max(0, sDamage.iSonic); + int nTotal = nPhys + nMagic + nAcid + nCold + nDivine + nElectrical + nFire + nNegative + nPositive + nSonic; + if (GetIsPC(oVictim)) + { + if (nTotal > 0) { IncrementPlayerStatistic(oVictim, "damage_taken", nTotal); } + if (nPhys > 0) { IncrementPlayerStatistic(oVictim, "physical_damage_taken", nPhys); } + if (nAcid > 0) { IncrementPlayerStatistic(oVictim, "acid_damage_taken", nAcid); } + if (nCold > 0) { IncrementPlayerStatistic(oVictim, "cold_damage_taken", nCold); } + if (nDivine > 0) { IncrementPlayerStatistic(oVictim, "divine_damage_taken", nDivine); } + if (nElectrical > 0) { IncrementPlayerStatistic(oVictim, "electrical_damage_taken", nElectrical); } + if (nFire > 0) { IncrementPlayerStatistic(oVictim, "fire_damage_taken", nFire); } + if (nNegative > 0) { IncrementPlayerStatistic(oVictim, "negative_damage_taken", nNegative); } + if (nPositive > 0) { IncrementPlayerStatistic(oVictim, "positive_damage_taken", nPositive); } + if (nSonic > 0) { IncrementPlayerStatistic(oVictim, "sonic_damage_taken", nSonic); } + } + if (GetIsPC(sDamage.oDamager)) + { + if (nTotal > 0) { IncrementPlayerStatistic(sDamage.oDamager, "damage_dealt", nTotal); } + if (nPhys > 0) { IncrementPlayerStatistic(sDamage.oDamager, "physical_damage_dealt", nPhys); } + if (nAcid > 0) { IncrementPlayerStatistic(sDamage.oDamager, "acid_damage_dealt", nAcid); } + if (nCold > 0) { IncrementPlayerStatistic(sDamage.oDamager, "cold_damage_dealt", nCold); } + if (nDivine > 0) { IncrementPlayerStatistic(sDamage.oDamager, "divine_damage_dealt", nDivine); } + if (nElectrical > 0) { IncrementPlayerStatistic(sDamage.oDamager, "electrical_damage_dealt", nElectrical); } + if (nFire > 0) { IncrementPlayerStatistic(sDamage.oDamager, "fire_damage_dealt", nFire); } + if (nNegative > 0) { IncrementPlayerStatistic(sDamage.oDamager, "negative_damage_dealt", nNegative); } + if (nPositive > 0) { IncrementPlayerStatistic(sDamage.oDamager, "positive_damage_dealt", nPositive); } + if (nSonic > 0) { IncrementPlayerStatistic(sDamage.oDamager, "sonic_damage_dealt", nSonic); } + } + } +} \ No newline at end of file diff --git a/src/nss/on_inv_addgolda.nss b/src/nss/on_inv_addgolda.nss new file mode 100644 index 00000000..57de40a8 --- /dev/null +++ b/src/nss/on_inv_addgolda.nss @@ -0,0 +1,13 @@ +#include "inc_general" + +void main() +{ + if (GetIsPC(OBJECT_SELF)) + { + int nOldMax = GetPlayerStatistic(OBJECT_SELF, "most_gold_carried"); + if (GetGold(OBJECT_SELF) > nOldMax) + { + SetPlayerStatistic(OBJECT_SELF, "most_gold_carried", GetGold(OBJECT_SELF)); + } + } +} \ No newline at end of file diff --git a/src/nss/on_mod_heartb.nss b/src/nss/on_mod_heartb.nss index 887ebf6a..cc788c8b 100644 --- a/src/nss/on_mod_heartb.nss +++ b/src/nss/on_mod_heartb.nss @@ -184,7 +184,7 @@ void DoRevive(object oDead) SetObjectVisualTransform(oDead, OBJECT_VISUAL_TRANSFORM_TRANSLATE_Z, 0.0); DetermineDeathEffectPenalty(oDead, 1); - IncrementStat(oDead, "revived"); + IncrementPlayerStatistic(oDead, "revived"); if (GetStringLeft(GetResRef(oDead), 3) == "hen" && bMasterFound) SetMaster(oDead, oMaster); @@ -246,7 +246,7 @@ void main() DoRevive(oPC); DetermineHorseEffects(oPC); RefreshCompletedBounties(oPC, nTime, sBounties); - IncrementStat(oPC, "time_played", 6); + IncrementPlayerStatistic(oPC, "time_played", 6); int nTickCount = GetTickRate(); if (nTickCount <= 50) diff --git a/src/nss/on_mod_load.nss b/src/nss/on_mod_load.nss index f11ef314..afa200f7 100644 --- a/src/nss/on_mod_load.nss +++ b/src/nss/on_mod_load.nss @@ -17,6 +17,7 @@ #include "util_i_csvlists" #include "inc_prettify" #include "inc_loot" +#include "nwnx_damage" const int SEED_SPAWNS = 1; const int SEED_TREASURES = 1; @@ -410,6 +411,11 @@ void main() NWNX_Events_SubscribeEvent("NWNX_ON_INPUT_WALK_TO_WAYPOINT_BEFORE", "stealth_move_fix"); NWNX_Events_SubscribeEvent("NWNX_ON_CALENDAR_DUSK", "on_calendar_dusk"); + + NWNX_Events_SubscribeEvent("NWNX_ON_INVENTORY_ADD_GOLD_AFTER", "on_inv_addgolda"); + + NWNX_Damage_SetDamageEventScript("on_damage"); + NWNX_Damage_SetAttackEventScript("on_attack"); ServerWebhook("The Frozen North is starting!", "The Frozen North server is starting up. Once the module is stable and ready for players to login, we'll let you know."); diff --git a/src/nss/on_pc_buya.nss b/src/nss/on_pc_buya.nss index ae055f71..d6cc2d20 100644 --- a/src/nss/on_pc_buya.nss +++ b/src/nss/on_pc_buya.nss @@ -11,8 +11,8 @@ void main() { object oItem = StringToObject(NWNX_Events_GetEventData("ITEM")); - IncrementStat(OBJECT_SELF, "gold_spent_from_buying", StringToInt(NWNX_Events_GetEventData("PRICE"))); - IncrementStat(OBJECT_SELF, "items_bought"); + IncrementPlayerStatistic(OBJECT_SELF, "gold_spent_from_buying", StringToInt(NWNX_Events_GetEventData("PRICE"))); + IncrementPlayerStatistic(OBJECT_SELF, "items_bought"); ValuableItemWebhook(OBJECT_SELF, oItem, TRUE); } diff --git a/src/nss/on_pc_death.nss b/src/nss/on_pc_death.nss index 8e602d26..d4fcef51 100644 --- a/src/nss/on_pc_death.nss +++ b/src/nss/on_pc_death.nss @@ -63,23 +63,23 @@ void main() if (SQLocalsPlayer_GetInt(oPlayer, "DEAD") == 0) { //SQLocalsPlayer_SetInt(oPlayer, "times_died", SQLocalsPlayer_GetInt(oPlayer, "times_died")+1); - IncrementStat(oPlayer, "deaths"); + IncrementPlayerStatistic(oPlayer, "deaths"); if (GetLocalString(oPlayer, "trap_triggered") != "") { - IncrementStat(oPlayer, "deaths_from_traps"); + IncrementPlayerStatistic(oPlayer, "deaths_from_traps"); } if (GetIsPC(oKiller)) { - IncrementStat(oPlayer, "deaths_from_players"); - IncrementStat(oKiller, "players_killed"); + IncrementPlayerStatistic(oPlayer, "deaths_from_players"); + IncrementPlayerStatistic(oKiller, "players_killed"); } if (GetFactionEqual(oKiller, oPlayer)) { - IncrementStat(oPlayer, "deaths_from_allies"); - IncrementStat(oKiller, "allies_killed"); + IncrementPlayerStatistic(oPlayer, "deaths_from_allies"); + IncrementPlayerStatistic(oKiller, "allies_killed"); } location lDeathSpot = GetLocation(oPlayer); diff --git a/src/nss/on_pc_rest.nss b/src/nss/on_pc_rest.nss index b7082e01..0c697b34 100644 --- a/src/nss/on_pc_rest.nss +++ b/src/nss/on_pc_rest.nss @@ -320,7 +320,7 @@ void main() DelayCommand(fAmbushTime, FloatingTextStringOnCreature(sSpotted, oPC, FALSE)); DelayCommand(fAmbushTime, InterruptRest(GetLocation(oCampfire))); - DelayCommand(fAmbushTime, VoidIncrementStat(oPC, "rest_ambushes")); + DelayCommand(fAmbushTime, VoidIncrementPlayerStatistic(oPC, "rest_ambushes")); } } sHideClass = GetLocalString(oCampfire, "hide_class"); @@ -370,7 +370,7 @@ void main() if (GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_FAMILIAR, oPC))) DecrementRemainingFeatUses(oPC, FEAT_SUMMON_FAMILIAR); if (GetIsObjectValid(GetAssociate(ASSOCIATE_TYPE_ANIMALCOMPANION, oPC))) DecrementRemainingFeatUses(oPC, FEAT_ANIMAL_COMPANION); - IncrementStat(oPC, "rests_completed"); + IncrementPlayerStatistic(oPC, "rests_completed"); AnnounceRemainingRevives(oPC); GiveHouseRestingXP(oPC); SendRestedXPNotifierToPC(oPC); diff --git a/src/nss/on_pc_skilla.nss b/src/nss/on_pc_skilla.nss index a8f3f61a..21b24700 100644 --- a/src/nss/on_pc_skilla.nss +++ b/src/nss/on_pc_skilla.nss @@ -1,12 +1,24 @@ #include "nwnx_events" #include "nwnx_object" #include "inc_horse" +#include "inc_general" void main() { if (StringToInt(NWNX_Events_GetEventData("SKILL_ID")) == SKILL_PICK_POCKET) { AssignCommand(OBJECT_SELF, ActionPlayAnimation(ANIMATION_FIREFORGET_STEAL)); + if (GetIsPC(OBJECT_SELF)) + { + if (StringToInt(NWNX_Events_GetEventData("ACTION_RESULT"))) + { + IncrementPlayerStatistic(OBJECT_SELF, "pickpockets_succeeded"); + } + else + { + IncrementPlayerStatistic(OBJECT_SELF, "pickpockets_failed"); + } + } } else if (StringToInt(NWNX_Events_GetEventData("SKILL_ID")) == SKILL_ANIMAL_EMPATHY) { diff --git a/src/nss/on_spellinta.nss b/src/nss/on_spellinta.nss index 90d62478..5fa5dd64 100644 --- a/src/nss/on_spellinta.nss +++ b/src/nss/on_spellinta.nss @@ -1,8 +1,18 @@ #include "x0_i0_match" +#include "inc_general" void main() { if (GetHasEffect(EFFECT_TYPE_PETRIFY, OBJECT_SELF)) { return; } if (d3() == 1) PlayVoiceChat(VOICE_CHAT_SPELLFAILED); + object oHitter = GetLastDamager(); + if (GetIsPC(OBJECT_SELF)) + { + IncrementPlayerStatistic(OBJECT_SELF, "own_spells_interrupted"); + } + if (GetIsPC(oHitter)) + { + IncrementPlayerStatistic(oHitter, "other_spells_interrupted"); + } } diff --git a/src/nss/on_storesella.nss b/src/nss/on_storesella.nss index 2e5d06ec..593f2700 100644 --- a/src/nss/on_storesella.nss +++ b/src/nss/on_storesella.nss @@ -11,8 +11,8 @@ void main() object oTargetPawnStore = GetObjectByTag(sString); if (StringToInt(NWNX_Events_GetEventData("RESULT")) == TRUE) { - IncrementStat(OBJECT_SELF, "gold_earned_from_selling", StringToInt(NWNX_Events_GetEventData("PRICE"))); - IncrementStat(OBJECT_SELF, "items_sold"); + IncrementPlayerStatistic(OBJECT_SELF, "gold_earned_from_selling", StringToInt(NWNX_Events_GetEventData("PRICE"))); + IncrementPlayerStatistic(OBJECT_SELF, "items_sold"); if (GetIsObjectValid(oTargetPawnStore)) { diff --git a/src/nss/on_trap_disarm.nss b/src/nss/on_trap_disarm.nss index e7292364..ba6423b0 100644 --- a/src/nss/on_trap_disarm.nss +++ b/src/nss/on_trap_disarm.nss @@ -1,4 +1,5 @@ #include "inc_xp" +#include "inc_general" void main() { @@ -20,5 +21,9 @@ void main() return; } - if (GetIsPC(oPC)) GiveXPToPC(oPC, IntToFloat(nXP)); + if (GetIsPC(oPC)) + { + GiveXPToPC(oPC, IntToFloat(nXP)); + IncrementPlayerStatistic(oPC, "traps_disarmed"); + } } diff --git a/src/nss/party_credit.nss b/src/nss/party_credit.nss index d30ab5a9..8cc2af8a 100644 --- a/src/nss/party_credit.nss +++ b/src/nss/party_credit.nss @@ -5,6 +5,7 @@ #include "inc_henchman" #include "inc_nwnx" #include "inc_key" +#include "inc_general" // SetScriptParam: "exclusivelooter" to ObjectToString(oPC) to make oPC get everything. @@ -490,10 +491,16 @@ int DeterminePartyMemberThatGetsItem(object oItem, int nStartWeights=1000) if (nAssignedIndex <= Party.PlayerSize) { oRecipient = GetLocalArrayObject(OBJECT_SELF, "Players", nAssignedIndex); + IncrementPlayerStatistic(oRecipient, "item_gold_value_assigned", nItemValue); } else { oRecipient = GetLocalArrayObject(OBJECT_SELF, "Henchmans", nAssignedIndex - Party.PlayerSize); + for (i=1; i<= Party.PlayerSize; i++) + { + object oPlayer = GetLocalArrayObject(OBJECT_SELF, "Players", i); + IncrementPlayerStatistic(oPlayer, "henchman_item_gold_value_assigned", nItemValue); + } } // Update gold owings // I guess the best way to do this is to just subtract (item gold value/(party size-1)) from everyone else's owing @@ -865,6 +872,18 @@ void main() // ========================= // START LOOP // ========================= + // For stat tracking, work out who really killed this + // (and if it was a summon or dominated associate, direct it back to the owner) + object oKiller = GetLastKiller(); + if (GetIsPC(GetMaster(oKiller))) + { + int nAssociateType = GetAssociateType(oKiller); + if (nAssociateType == ASSOCIATE_TYPE_ANIMALCOMPANION || nAssociateType == ASSOCIATE_TYPE_DOMINATED || nAssociateType == ASSOCIATE_TYPE_FAMILIAR || nAssociateType == ASSOCIATE_TYPE_SUMMONED) + { + oKiller = GetMaster(oKiller); + } + } + for(nNth = 1; nNth <= Party.PlayerSize; nNth++) { // Credit players in previously set array "Players" @@ -876,9 +895,16 @@ void main() if (GetObjectType(OBJECT_SELF) == OBJECT_TYPE_CREATURE) { // includes neutrals or people outside of party - IncrementStat(oPC, "enemies_killed_with_credit"); + IncrementPlayerStatistic(oPC, "enemies_killed_with_credit"); GiveXPToPC(oPC, fXP); AdvanceQuest(OBJECT_SELF, oPC, GetLocalInt(OBJECT_SELF, "quest_kill")); + + if (oKiller == oPC) + { + // Number of personal kills is in ai_ondeath already + IncrementPlayerStatistic(oPC, "kill_xp_value", FloatToInt(fXP*100.0)); + } + IncrementPlayerStatistic(oPC, "total_xp_from_partys_kills", FloatToInt(fXP*100.0)); } // only proceed with loot code if container exists diff --git a/src/nss/pc_respawn.nss b/src/nss/pc_respawn.nss index 5b4b8bab..14068080 100644 --- a/src/nss/pc_respawn.nss +++ b/src/nss/pc_respawn.nss @@ -20,7 +20,7 @@ void main() RemoveMount(oRespawner); - IncrementStat(oRespawner, "respawned"); + IncrementPlayerStatistic(oRespawner, "respawned"); location lRespawnLocation = GetLocation(GetObjectByTag("RESPAWN_NEVERWINTER")); diff --git a/src/nss/tmap_complete.nss b/src/nss/tmap_complete.nss index 7839088c..8ad58beb 100644 --- a/src/nss/tmap_complete.nss +++ b/src/nss/tmap_complete.nss @@ -26,7 +26,7 @@ void main() DestroyObject(oReward, 300.0); DestroyObject(OBJECT_SELF); - IncrementStat(oOwner, "treasure_maps_completed"); + IncrementPlayerStatistic(oOwner, "treasure_maps_completed"); // Force a PC save. That way there is no way they can keep their map // and still be able to loot the chest too diff --git a/src/nss/treas_unlock.nss b/src/nss/treas_unlock.nss index 387b4e34..e9906376 100644 --- a/src/nss/treas_unlock.nss +++ b/src/nss/treas_unlock.nss @@ -18,5 +18,5 @@ void main() // do nothing if not a PC still if (!GetIsPC(oUnlocker)) return; - IncrementStat(oUnlocker, "locks_unlocked"); + IncrementPlayerStatistic(oUnlocker, "locks_unlocked"); } diff --git a/src/nss/x0_s0_planar.nss b/src/nss/x0_s0_planar.nss index 14eb4d1d..7730d4c9 100644 --- a/src/nss/x0_s0_planar.nss +++ b/src/nss/x0_s0_planar.nss @@ -17,6 +17,7 @@ #include "70_inc_spells" #include "x0_i0_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -56,6 +57,10 @@ void main() eSummon = EffectSummonCreature("sum_slaadgreen",VFX_FNF_SUMMON_MONSTER_3, 1.0); break; } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } //Apply the summon effect and VFX impact ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, DurationToSeconds(nDuration)); } diff --git a/src/nss/x0_s2_blkdead.nss b/src/nss/x0_s2_blkdead.nss index 05242d94..1b194806 100644 --- a/src/nss/x0_s2_blkdead.nss +++ b/src/nss/x0_s2_blkdead.nss @@ -11,6 +11,8 @@ //:: Created On: //::////////////////////////////////////////////// +#include "inc_general" + void main() { @@ -26,6 +28,10 @@ void main() else eSummon = EffectSummonCreature("sum_bg_ghast",VFX_FNF_SUMMON_UNDEAD); + if (GetIsPC(OBJECT_SELF)) + { + IncrementPlayerStatistic(OBJECT_SELF, "creatures_summoned"); + } ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), HoursToSeconds(nDuration)); } diff --git a/src/nss/x0_s2_fiend.nss b/src/nss/x0_s2_fiend.nss index 192deac0..5d147c06 100644 --- a/src/nss/x0_s2_fiend.nss +++ b/src/nss/x0_s2_fiend.nss @@ -17,6 +17,7 @@ Will remain for one hour per level of blackguard //:: Created By: Brent //:: Created On: April 2003 //::////////////////////////////////////////////// +#include "inc_general" void main() { int nLevel = GetLevelByClass(CLASS_TYPE_BLACKGUARD, OBJECT_SELF); @@ -43,7 +44,10 @@ void main() eSummon = EffectSummonCreature("NW_S_VROCK", VFX_FNF_SUMMON_GATE, fDelay); } } - + if (GetIsPC(OBJECT_SELF)) + { + IncrementPlayerStatistic(OBJECT_SELF, "creatures_summoned"); + } ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), HoursToSeconds(nDuration)); } diff --git a/src/nss/x0_s2_shadsum.nss b/src/nss/x0_s2_shadsum.nss index 1732bb04..62ce84e4 100644 --- a/src/nss/x0_s2_shadsum.nss +++ b/src/nss/x0_s2_shadsum.nss @@ -12,7 +12,7 @@ //:: Created By: Preston Watamaniuk //:: Created On: Oct 26, 2001 //::////////////////////////////////////////////// - +#include "inc_general" void main() { //Declare major variables @@ -49,6 +49,10 @@ void main() } } + if (GetIsPC(OBJECT_SELF)) + { + IncrementPlayerStatistic(OBJECT_SELF, "creatures_summoned"); + } //Apply VFX impact and summon effect ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), HoursToSeconds(nDuration)); diff --git a/src/nss/x0_s3_summonelem.nss b/src/nss/x0_s3_summonelem.nss index 7c93d06a..bdc7d8c1 100644 --- a/src/nss/x0_s3_summonelem.nss +++ b/src/nss/x0_s3_summonelem.nss @@ -16,6 +16,7 @@ //:: Latest Update: Andrew Nobbs April 9, 2003 #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -45,6 +46,9 @@ void main() // 0.5 sec delay between VFX and creature creation effect eSummon = EffectSummonCreature(sResRef, VFX_FNF_SUMMON_MONSTER_3, 0.5); - + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, GetSpellTargetLocation(), fDuration); } diff --git a/src/nss/x2_inc_spellhook.nss b/src/nss/x2_inc_spellhook.nss index 416ac848..5c948228 100644 --- a/src/nss/x2_inc_spellhook.nss +++ b/src/nss/x2_inc_spellhook.nss @@ -43,6 +43,7 @@ #include "x0_i0_match" #include "x2_inc_craft" #include "inc_debug" +#include "inc_general" const int X2_EVENT_CONCENTRATION_BROKEN = 12400; @@ -582,5 +583,27 @@ int X2PreSpellCastCode() DeleteLocalInt(OBJECT_SELF,"70_SPELLHOOK_LIMIT"); DeleteLocalInt(OBJECT_SELF,"70_SPELLHOOK_SAVINGTHROW"); DeleteLocalInt(OBJECT_SELF,"70_SPELLHOOK_TARGETTYPE"); + if (!nRet && GetIsPC(OBJECT_SELF)) + { + if (GetIsObjectValid(GetSpellCastItem())) + { + if (GetBaseItemType(GetSpellCastItem()) == BASE_ITEM_POTIONS) + { + IncrementPlayerStatistic(OBJECT_SELF, "potions_drunk"); + } + else if (GetBaseItemType(GetSpellCastItem()) == BASE_ITEM_SPELLSCROLL) + { + IncrementPlayerStatistic(OBJECT_SELF, "spells_cast_from_scroll"); + } + else + { + IncrementPlayerStatistic(OBJECT_SELF, "spells_cast_from_item"); + } + } + else + { + IncrementPlayerStatistic(OBJECT_SELF, "spells_cast"); + } + } return !nRet; } diff --git a/src/nss/x2_s0_blckblde.nss b/src/nss/x2_s0_blckblde.nss index 5c50cf9d..e1e2694a 100644 --- a/src/nss/x2_s0_blckblde.nss +++ b/src/nss/x2_s0_blckblde.nss @@ -25,6 +25,7 @@ Patch 1.70 #include "70_inc_spells" #include "x2_i0_spells" +#include "inc_general" //Creates the weapon that the creature will be using. void spellsCreateItemForSummoned(object oCaster, int nStat) @@ -88,5 +89,9 @@ void main() { nStat = GetAbilityModifier(ABILITY_CHARISMA, spell.Caster); } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } DelayCommand(1.5, spellsCreateItemForSummoned(spell.Caster, nStat)); } diff --git a/src/nss/x2_s0_crshadow.nss b/src/nss/x2_s0_crshadow.nss index d02c315b..098b351e 100644 --- a/src/nss/x2_s0_crshadow.nss +++ b/src/nss/x2_s0_crshadow.nss @@ -14,6 +14,7 @@ #include "70_inc_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -45,6 +46,10 @@ void main() { eSummon = EffectSummonCreature("x2shfiendfoe",VFX_FNF_SUMMON_UNDEAD); } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } //Apply VFX impact and summon effect ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, DurationToSeconds(nDuration)); diff --git a/src/nss/x2_s0_persblde.nss b/src/nss/x2_s0_persblde.nss index 30d87b54..75a561ad 100644 --- a/src/nss/x2_s0_persblde.nss +++ b/src/nss/x2_s0_persblde.nss @@ -20,6 +20,7 @@ Patch 1.71 #include "70_inc_spells" #include "x2_i0_spells" +#include "inc_general" #include "x2_inc_spellhook" //Creates the weapon that the creature will be using. @@ -90,5 +91,9 @@ void main() { nStat = GetAbilityModifier(ABILITY_CHARISMA, spell.Caster); } + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } DelayCommand(1.0, spellsCreateItemForSummoned(spell.Caster,nStat)); } diff --git a/src/nss/x2_s2_dragknght.nss b/src/nss/x2_s2_dragknght.nss index c5942b09..db38a04b 100644 --- a/src/nss/x2_s2_dragknght.nss +++ b/src/nss/x2_s2_dragknght.nss @@ -15,6 +15,7 @@ #include "70_inc_spells" #include "x2_inc_toollib" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -38,5 +39,9 @@ void main() eSummon = ExtraordinaryEffect(eSummon); //Apply the summon visual and summon the dragon. ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, DurationToSeconds(nDuration)); + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } DelayCommand(1.0,ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eVis, spell.Loc)); } diff --git a/src/nss/x2_s2_mumdust.nss b/src/nss/x2_s2_mumdust.nss index 88a1dd95..9f3f2b55 100644 --- a/src/nss/x2_s2_mumdust.nss +++ b/src/nss/x2_s2_mumdust.nss @@ -14,6 +14,7 @@ #include "70_inc_spells" #include "x2_inc_spellhook" +#include "inc_general" void main() { @@ -33,6 +34,10 @@ void main() //Warrior Mummy effect eSummon = EffectSummonCreature("X2_S_MUMMYWARR",VFX_FNF_SUMMON_EPIC_UNDEAD,1.0); eSummon = ExtraordinaryEffect(eSummon); + if (GetIsPC(spell.Caster)) + { + IncrementPlayerStatistic(spell.Caster, "creatures_summoned"); + } //Apply the summon visual and summon the undead. ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, eSummon, spell.Loc, DurationToSeconds(nDuration)); } diff --git a/src/nss/x2_s2_sumgrund.nss b/src/nss/x2_s2_sumgrund.nss index 5b5aa70f..cae8fc46 100644 --- a/src/nss/x2_s2_sumgrund.nss +++ b/src/nss/x2_s2_sumgrund.nss @@ -28,6 +28,8 @@ //:: Created On: Feb 05, 2003 //::////////////////////////////////////////////// +#include "inc_general" + void PMUpgradeSummon(object oSelf, string sScript) { object oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED,oSelf); @@ -119,6 +121,10 @@ void main() object oSelf = OBJECT_SELF; DelayCommand(1.0,PMUpgradeSummon(oSelf,sScript)); } + if (GetIsPC(OBJECT_SELF)) + { + IncrementPlayerStatistic(OBJECT_SELF, "creatures_summoned"); + } } diff --git a/src/nss/x2_s2_sumundead.nss b/src/nss/x2_s2_sumundead.nss index 584eb0b3..76f1c28f 100644 --- a/src/nss/x2_s2_sumundead.nss +++ b/src/nss/x2_s2_sumundead.nss @@ -13,6 +13,8 @@ //:: Updated By: Georg Zoeller, Oct 2003 //::////////////////////////////////////////////// +#include "inc_general" + void PMUpgradeSummon(object oSelf, string sScript) { object oSummon = GetAssociate(ASSOCIATE_TYPE_SUMMONED,oSelf); @@ -67,6 +69,10 @@ void main() object oSelf = OBJECT_SELF; DelayCommand(1.0,PMUpgradeSummon(oSelf,sScript)); } + if (GetIsPC(OBJECT_SELF)) + { + IncrementPlayerStatistic(OBJECT_SELF, "creatures_summoned"); + } } diff --git a/win_nasher_install.bat b/win_nasher_install.bat index 54eea063..ba10ed35 100644 --- a/win_nasher_install.bat +++ b/win_nasher_install.bat @@ -15,4 +15,5 @@ del /f TFN.mod "%CD%/tools/win/nasher/nasher.exe" install --verbose --erfUtil:"%CD%/tools/win/neverwinter64/nwn_erf.exe" --gffUtil:"%CD%/tools/win/neverwinter64/nwn_gff.exe" --tlkUtil:"%CD%/tools/win/neverwinter64/nwn_tlk.exe" --nssCompiler:"%CD%/tools/win/nwnsc/nwnsc.exe" --installDir:"%CD%" --nssFlags:"-oe -i ""%CD%/nwn-base-scripts""" --no -del /f TFN.mod \ No newline at end of file +del /f TFN.mod +pause From 15f7dbd13b281ed892d54be44af37f6319a9ec23 Mon Sep 17 00:00:00 2001 From: Logg-y <49533518+Logg-y@users.noreply.github.com> Date: Mon, 24 Jul 2023 04:52:14 +0100 Subject: [PATCH 3/6] Stats UI, more testing needed Not linked up to main player UI yet either --- src/nss/dev_test.nss | 6 +- src/nss/inc_general.nss | 4 + src/nss/nui_playerstats.nss | 484 ++++++++++++++++++++++++++++++++++++ src/nss/nw_s2_animalcom.nss | 3 + src/nss/nw_s2_familiar.nss | 3 + src/nss/on_attack.nss | 42 +++- src/nss/on_damage.nss | 2 + src/nss/playerstats_evt.nss | 184 ++++++++++++++ 8 files changed, 720 insertions(+), 8 deletions(-) create mode 100644 src/nss/nui_playerstats.nss create mode 100644 src/nss/playerstats_evt.nss diff --git a/src/nss/dev_test.nss b/src/nss/dev_test.nss index 4568ef91..44cb9788 100644 --- a/src/nss/dev_test.nss +++ b/src/nss/dev_test.nss @@ -1,8 +1,6 @@ -#include "inc_nui_config" +#include "nui_playerstats" void main() { - AssignCommand(GetFirstPC(), SpeakString("dev_test")); - ExecuteScript("pc_xpbar", GetFirstPC()); - DisplayUIMasterConfigurationInterface(GetFirstPC()); + ShowPlayerStatsUI(GetFirstPC()); } \ No newline at end of file diff --git a/src/nss/inc_general.nss b/src/nss/inc_general.nss index 750ac6bb..9f4c2073 100644 --- a/src/nss/inc_general.nss +++ b/src/nss/inc_general.nss @@ -5,6 +5,7 @@ #include "nwnx_effect" #include "x0_i0_match" #include "util_i_color" +#include "nui_playerstats" const float MORALE_RADIUS = 30.0; const float REMAINS_DECAY = 120.0; @@ -775,6 +776,7 @@ int IncrementPlayerStatistic(object oPC, string sStat, int nIncrement = 1) string sKey = GetPCPublicCDKey(oPC, TRUE); int nOldPlayerValue = GetCampaignInt(sKey, STAT_PREFIX+sStat); SetCampaignInt(sKey, STAT_PREFIX+sStat, nOldPlayerValue+nIncrement); + UpdatePlayerStatsUIBindIfOpen(oPC, sStat); return nNewTotal; } @@ -784,6 +786,7 @@ void SetPlayerStatisticString(object oPC, string sStat, string sValue, int bCDKe { if (!GetIsPC(oPC)) return; string sVarName = STAT_PREFIX+sStat; + UpdatePlayerStatsUIBindIfOpen(oPC, sStat); if (!bCDKeyDB) { SQLocalsPlayer_SetString(oPC, sVarName, sValue); @@ -798,6 +801,7 @@ void SetPlayerStatistic(object oPC, string sStat, int nValue, int bCDKeyDB=0) { if (!GetIsPC(oPC)) return; string sVarName = STAT_PREFIX+sStat; + UpdatePlayerStatsUIBindIfOpen(oPC, sStat); if (!bCDKeyDB) { SQLocalsPlayer_SetInt(oPC, sVarName, nValue); diff --git a/src/nss/nui_playerstats.nss b/src/nss/nui_playerstats.nss new file mode 100644 index 00000000..8514d8b4 --- /dev/null +++ b/src/nss/nui_playerstats.nss @@ -0,0 +1,484 @@ +#include "inc_nui_config" +#include "inc_debug" +#include "inc_sqlite_time" + +// Pop up the player stats UI for oPC showing them their own stats. +void ShowPlayerStatsUI(object oPC); + +// Update a bind for oPlayer's stats UI if they have it open. +// Passing "" for sBind will update the whole thing. +void UpdatePlayerStatsUIBindIfOpen(object oPlayer, string sBind=""); + + +// Categories: + +// General +// Activities +// Gold and Treasure +// Kills and Deaths +// Magic Combat +// Martial Combat +// Damage + +// GENERAL + +// time_played +// quests_completed +// bounties_completed +// treasure_maps_completed +// henchman_recruited +// followers_recruited +// rest_ambushes + +// traps_triggered +// assassination_attempts_thwarted + +// KILLS AND DEATHS +// enemies_killed +// enemies_killed_with_credit + // derive: percentage_kills_in_party +// bosses_killed +// most_powerful_killed (s) + +// kill_xp_value +// total_xp_from_partys_kills + // derive: percentage_xp_value_kills_in_party +// respawned + +// deaths +// revived +// deaths_from_traps +// deaths_from_players +// deaths_from_allies +// followers_died +// henchman_died +// innocents_killed +// allies_killed + +// MAGIC COMBAT + +// spells_cast +// spells_cast_from_scroll +// spells_cast_from_item +// own_spells_interrupted +// other_spells_interrupted +// incoming_spells_resisted +// outgoing_spells_resisted +// creatures_summoned + +// MARTIAL COMBAT + +// attacks_hit +// attacks_missed +// attacks_hit_by +// attacks_missed_by +// attacks_of_opportunity_hit +// attacks_of_opportunity_missed +// attacks_of_opportunity_hit_by +// attacks_of_opportunity_missed_by +// sneak_attacks_hit +// sneak_attacks_missed +// sneak_attacks_hit_by +// sneak_attacks_missed_by +// critical_hits_landed +// critical_hits_taken +// natural_one_attack_rolls + +// DAMAGE + +// damage_dealt +// damage_taken + +// physical_damage_dealt +// acid_damage_dealt +// cold_damage_dealt +// divine_damage_dealt +// electrical_damage_dealt +// fire_damage_dealt +// negative_damage_dealt +// positive_damage_dealt +// magic_damage_dealt +// sonic_damage_dealt +// physical_damage_taken +// acid_damage_taken +// cold_damage_taken +// divine_damage_taken +// electrical_damage_taken +// fire_damage_taken +// negative_damage_taken +// positive_damage_taken +// magic_damage_taken +// sonic_damage_taken + + +// ACTIVITIES + +// potions_drunk +// locks_unlocked +// locks_bashed +// key_doors_opened +// ferries_used +// long_travel_used +// times_mounted +// time_spent_in_house +// times_rested_in_house + +// persuade_failed +// persuade_succeeded +// bluff_failed +// bluff_succeeded +// pickpockets_succeeded +// pickpockets_failed + +// GOLD AND TREASURE + +// gold_looted +// gold_earned_from_selling +// gold_spent_by_buying +// most_gold_carried +// treasures_looted +// items_bought +// items_sold +// item_gold_value_assigned +// henchman_item_gold_value_assigned +// gold_spent_on_ferries +// gold_spent_on_long_travel + + +const float PLAYERSTATSWINDOW_BUTTONCOLUMN_WIDTH = 180.0; + +json _PreparePlayerStatsPanelItem(string sKey, string sLabel, string sTooltip) +{ + json jRet = JsonObject(); + jRet = JsonObjectSet(jRet, "key", JsonString(sKey)); + jRet = JsonObjectSet(jRet, "label", JsonString(sLabel)); + jRet = JsonObjectSet(jRet, "tooltip", JsonString(sTooltip)); + return jRet; +} + +json _GetPlayerStatsPanelBreakdown() +{ + json jRet = GetLocalJson(GetModule(), "playerstats_panel_breakdown"); + if (jRet != JsonNull() || GetIsDevServer()) + { + jRet = JsonObject(); + json jGeneral = JsonArray(); + jGeneral = JsonArrayInsert(jGeneral, _PreparePlayerStatsPanelItem("time_played", "Time Played", "Total character logged in time.")); + jGeneral = JsonArrayInsert(jGeneral, _PreparePlayerStatsPanelItem("quests_completed", "Quests Completed", "Non-bounty quests completed.")); + jGeneral = JsonArrayInsert(jGeneral, _PreparePlayerStatsPanelItem("bounties_completed", "Bounties Completed", "Number of bounties (repeatable) completed.")); + jGeneral = JsonArrayInsert(jGeneral, _PreparePlayerStatsPanelItem("treasure_maps_completed", "Treasure Maps Completed", "Number of treasure maps completed.")); + jGeneral = JsonArrayInsert(jGeneral, _PreparePlayerStatsPanelItem("henchman_recruited", "Henchmen Recruited", "Number of henchmen recruited.")); + jGeneral = JsonArrayInsert(jGeneral, _PreparePlayerStatsPanelItem("followers_recruited", "Followers Recruited", "Number of non-henchman followers recruited.")); + jGeneral = JsonArrayInsert(jGeneral, _PreparePlayerStatsPanelItem("rest_ambushes", "Rest Ambushes", "Number of times enemies interrupted resting.")); + jGeneral = JsonArrayInsert(jGeneral, _PreparePlayerStatsPanelItem("traps_triggered", "Traps Triggered", "Number of traps triggered.")); + jGeneral = JsonArrayInsert(jGeneral, _PreparePlayerStatsPanelItem("assassination_attempts_thwarted", "Assassination Attempts Survived", "The number of assassination attempts against you that failed.")); + jRet = JsonObjectSet(jRet, "general", jGeneral); + + json jKillsDeaths = JsonArray(); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("enemies_killed", "Enemies Killed", "Enemies directly killed by you or creatures you summoned.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("bosses_killed", "Bosses Killed", "Bosses directly killed by you or creatures you summoned.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("percentage_kills_in_party", "Party Kill Percentage", "The percentage of party kills that were directly killed by you or creatures you summoned.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("most_powerful_killed", "Most Powerful Killed", "The most powerful enemy killed by you or creatures you summoned.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("enemies_killed_with_credit", "Total Credited Kills", "The number of kills that you or your party have contributed towards.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("kill_xp_value", "XP from Personal Kills", "The total XP from enemies directly killed by you or creatures you summoned .")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("total_xp_from_partys_kills", "XP from Party Kills", "The total XP from kills that you or your party have contributed towards.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("percentage_xp_value_kills_in_party", "Party XP Value Kill Percentage", "Kills by you or creatures you summoned make up this percentage of the total experience you have gained from kills.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("respawned", "Respawns", "The number of times you have respawned at a temple.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("deaths", "Deaths", "The number of times you have died.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("revived", "Revives", "The number of times you have been revived by a nearby ally when out of combat.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("deaths_from_traps", "Deaths from Traps", "The number of times you have been killed by a trap.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("deaths_from_players", "Deaths from Players", "The number of times you have been killed by another player.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("deaths_from_allies", "Deaths from Alies", "The number of times you have been killed by an ally.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("followers_died", "Follower Deaths", "The number of your followers that have died.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("henchman_died", "Henchman Deaths", "The number of times your henchmen have died.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("innocents_killed", "Innocents Killed", "The number of innocent civilians you have killed.")); + jKillsDeaths = JsonArrayInsert(jKillsDeaths, _PreparePlayerStatsPanelItem("allies_killed", "Allies Killed", "The number of non-innocent allies you have killed.")); + jRet = JsonObjectSet(jRet, "killsdeaths", jKillsDeaths); + + json jMagicCombat = JsonArray(); + jMagicCombat = JsonArrayInsert(jMagicCombat, _PreparePlayerStatsPanelItem("spells_cast", "Spells Cast", "The number of spells cast through regular spellbooks.")); + jMagicCombat = JsonArrayInsert(jMagicCombat, _PreparePlayerStatsPanelItem("spells_cast_from_scroll", "Spells Cast via Scroll", "The number of spells cast off scrolls.")); + jMagicCombat = JsonArrayInsert(jMagicCombat, _PreparePlayerStatsPanelItem("spells_cast_from_item", "Spells Cast via Item", "The number of spells cast off items that were not scrolls or potions.")); + jMagicCombat = JsonArrayInsert(jMagicCombat, _PreparePlayerStatsPanelItem("own_spells_interrupted", "Own Spells Interrupted", "The number of times your own spells have been interrupted by damage.")); + jMagicCombat = JsonArrayInsert(jMagicCombat, _PreparePlayerStatsPanelItem("other_spells_interrupted", "Other Spells Interrupted", "The number of times your damage has interrupted other creatures' spells.")); + jMagicCombat = JsonArrayInsert(jMagicCombat, _PreparePlayerStatsPanelItem("incoming_spells_resisted", "Spells Resisted", "The number of spells you have resisted with spell resistance.")); + jMagicCombat = JsonArrayInsert(jMagicCombat, _PreparePlayerStatsPanelItem("outgoing_spells_resisted", "Own Spells Resisted", "The number of times other creatures have resisted your spells.")); + jMagicCombat = JsonArrayInsert(jMagicCombat, _PreparePlayerStatsPanelItem("creatures_summoned", "Creatures Summoned", "The number of creatures you have summoned.")); + jRet = JsonObjectSet(jRet, "magiccombat", jMagicCombat); + + json jMartialCombat = JsonArray(); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("attacks_hit", "Attacks Landed", "The number of attacks you have hit with.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("attacks_missed", "Attacks Missed", "The number of attacks you have missed with.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("attacks_hit_by", "Attacks Taken", "The number of attacks you have been hit with.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("attacks_missed_by", "Attacks Avoided", "The number of attacks against you that have missed.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("critical_hits_landed", "Critical Hits Landed", "The number of critical hits you have performed.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("critical_hits_taken", "Critical Hits Suffered", "The number of critical hits that have been landed on you.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("natural_one_attack_rolls", "Natural 1 Attack Rolls", "The number of times you have rolled a 1 on an attack roll.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("attacks_of_opportunity_hit", "Attacks of Opportunity Landed", "The number of attacks of opportunity you have hit with.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("attacks_of_opportunity_missed", "Attacks of Opportunity Missed", "The number of attacks of opportunity you have missed with.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("attacks_of_opportunity_hit_by", "Attacks of Opportunity Taken", "The number of attacks of opportunity you have been hit with.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("attacks_of_opportunity_missed_by", "Attacks of Opportunity Avoided", "The number of attacks of opportunity against you that have missed.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("sneak_attacks_hit", "Sneak Attacks Landed", "The number of sneak/death attacks you have hit with.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("sneak_attacks_missed", "Sneak Attacks Missed", "The number of sneak/death attacks you have missed with.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("sneak_attacks_hit_by", "Sneak Attacks Taken", "The number of sneak/death attacks you have been hit with.")); + jMartialCombat = JsonArrayInsert(jMartialCombat, _PreparePlayerStatsPanelItem("sneak_attacks_missed_by", "Sneak Attacks Avoided", "The number of sneak/death attacks against you that have missed.")); + jRet = JsonObjectSet(jRet, "martialcombat", jMartialCombat); + + json jDamage = JsonArray(); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("damage_dealt", "Damage Dealt", "Total damage inflicted.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("damage_taken", "Damage Taken", "Total damage recieved.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("physical_damage_dealt", "Physical Damage Dealt", "Total blunt/pierce/bludgeoning damage inflicted.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("acid_damage_dealt", "Acid Damage Dealt", "Total acid damage inflicted.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("cold_damage_dealt", "Cold Damage Dealt", "Total cold damage inflicted.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("divine_damage_dealt", "Divine Damage Dealt", "Total divine damage inflicted.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("electrical_damage_dealt", "Electrical Damage Dealt", "Total electrical damage inflicted.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("fire_damage_dealt", "Fire Damage Dealt", "Total fire damage inflicted.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("negative_damage_dealt", "Negative Damage Dealt", "Total negative energy damage inflicted.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("positive_damage_dealt", "Positive Damage Dealt", "Total positive energy damage inflicted.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("magic_damage_dealt", "Magical Damage Dealt", "Total magical damage inflicted.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("sonic_damage_dealt", "Sonic Damage Dealt", "Total sonic damage inflicted.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("physical_damage_taken", "Physical Damage Taken", "Total blunt/pierce/bludgeoning damage recieved.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("acid_damage_taken", "Acid Damage Taken", "Total acid damage recieved.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("cold_damage_taken", "Cold Damage Taken", "Total cold damage recieved.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("divine_damage_taken", "Divine Damage Taken", "Total divine damage recieved.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("electrical_damage_Taken", "Electrical Damage taken", "Total electrical damage recieved.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("fire_damage_taken", "Fire Damage Taken", "Total fire damage recieved.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("negative_damage_taken", "Negative Damage Taken", "Total negative energy damage recieved.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("positive_damage_taken", "Positive Damage Taken", "Total positive energy damage recieved.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("magic_damage_taken", "Magical Damage Taken", "Total magical damage recieved.")); + jDamage = JsonArrayInsert(jDamage, _PreparePlayerStatsPanelItem("sonic_damage_taken", "Sonic Damage Taken", "Total sonic damage recieved.")); + jRet = JsonObjectSet(jRet, "damage", jDamage); + + json jActivities = JsonArray(); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("potions_drunk", "Potions Consumed", "Total number of potions drunk.")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("locks_unlocked", "Locks Picked", "Total number of locked objects picked open.")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("locks_bashed", "Locks Bashed", "Total number of locked objects bashed open.")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("key_doors_opened", "Key Doors Opened", "Number of locked doors opened with keys.")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("ferries_used", "Neverwinter Ferries Used", "Number of Neverwinter ferry trips taken.")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("long_travel_used", "Long Travels Used", "Number of long travel trips (eg: river boats) taken.")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("times_mounted", "Times Mounted Horse", "Number of long travel trips (eg: river boats) taken.")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("time_spent_in_house", "Time Spent in House", "Amount of (logged in) time spent in your own house.")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("times_rested_in_house", "Times Rested in House", "Number of times rested in your own house (that have given Rested XP).")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("persuade_succeeded", "Persuade Attempts Succeeded", "Number of successful persuade attempts.")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("persuade_failed", "Persuade Attempts Failed", "Number of failed persuade attempts.")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("bluff_succeeded", "Bluff Attempts Succeeded", "Number of successful bluff attempts.")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("bluff_failed", "Bluff Attempts Failed", "Number of failed bluff attempts.")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("pickpockets_succeeded", "Pickpocket Attempts Succeeded", "Number of successful pickpocket attempts.")); + jActivities = JsonArrayInsert(jActivities, _PreparePlayerStatsPanelItem("pickpockets_failed", "Pickpocket Attempts Failed", "Number of failed pickpocket attempts.")); + jRet = JsonObjectSet(jRet, "activities", jActivities); + + json jGoldTreasure = JsonArray(); + jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("gold_looted", "Gold Looted", "Total amount of raw gold looted.")); + jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("gold_earned_from_selling", "Gold from Selling", "Total amount of gold obtained from selling goods to shops.")); + jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("gold_spent_by_buying", "Gold Spent", "Total amount of gold spent on items and services in both shops and dialogue.")); + jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("items_bought", "Items Bought", "Total number of items bought from stores.")); + jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("items_sold", "Items Sold", "Total number of items sold to stores.")); + jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("most_gold_carried", "Most Gold Carried", "Highest amount of gold carried at any time.")); + jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("treasures_looted", "Treasures Looted", "Number of objects looted.")); + jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("item_gold_value_assigned", "Item Gold Value Assigned", "Total gold value of all items assigned to you in loot.")); + jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("henchman_item_gold_value_assigned", "Henchman Item Gold Value Assigned", "Total gold value of all items assigned to henchmen in the same party as you.")); + jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("gold_spent_on_ferries", "Gold Spent on Neverwinter Ferries", "Total gold spent on Neverwinter ferries.")); + jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("gold_spent_on_long_travel", "Gold Spent on Long Travel", "Total gold spent on longer travel (eg boat trips).")); + jRet = JsonObjectSet(jRet, "goldtreasure", jGoldTreasure); + + SetLocalJson(GetModule(), "playerstats_panel_breakdown", jRet); + } + return jRet; +} + +json _PlayerStatsCategoryToNui(json jPanel, string sCategory) +{ + json jRet = GetLocalJson(GetModule(), "playerstats_panel_nui_" + sCategory); + if (jRet != JsonNull() || GetIsDevServer()) + { + json jArray = JsonObjectGet(jPanel, sCategory); + int nLength = JsonGetLength(jArray); + json jRows = JsonArray(); + int i; + for (i=0; i 0) // sneak and/or death attack { if (GetIsPC(oAttacker)) { - IncrementPlayerStatistic(oAttacker, "sneak_attacks_made"); if (bHit) { IncrementPlayerStatistic(oAttacker, "sneak_attacks_hit"); } + else + { + IncrementPlayerStatistic(oAttacker, "sneak_attacks_missed"); + } } if (GetIsPC(sAttack.oTarget)) { - IncrementPlayerStatistic(sAttack.oTarget, "sneak_attacks_targeted_by"); if (bHit) { IncrementPlayerStatistic(sAttack.oTarget, "sneak_attacks_hit_by"); } + else + { + IncrementPlayerStatistic(sAttack.oTarget, "sneak_attacks_missed_by"); + } } } if (sAttack.iAttackResult == 3) // Critical hits @@ -62,5 +74,27 @@ void main() { IncrementPlayerStatistic(oAttacker, "natural_one_attack_rolls"); } + if (bHit) + { + if (GetIsPC(oAttacker)) + { + IncrementPlayerStatistic(oAttacker, "attacks_hit"); + } + if (GetIsPC(sAttack.oTarget)) + { + IncrementPlayerStatistic(sAttack.oTarget, "attacks_hit_by"); + } + } + else + { + if (GetIsPC(oAttacker)) + { + IncrementPlayerStatistic(oAttacker, "attacks_missed"); + } + if (GetIsPC(sAttack.oTarget)) + { + IncrementPlayerStatistic(sAttack.oTarget, "attacks_missed_by"); + } + } } } \ No newline at end of file diff --git a/src/nss/on_damage.nss b/src/nss/on_damage.nss index 303af0a8..b52a015a 100644 --- a/src/nss/on_damage.nss +++ b/src/nss/on_damage.nss @@ -30,6 +30,7 @@ void main() if (nFire > 0) { IncrementPlayerStatistic(oVictim, "fire_damage_taken", nFire); } if (nNegative > 0) { IncrementPlayerStatistic(oVictim, "negative_damage_taken", nNegative); } if (nPositive > 0) { IncrementPlayerStatistic(oVictim, "positive_damage_taken", nPositive); } + if (nMagic > 0) { IncrementPlayerStatistic(oVictim, "magic_damage_taken", nMagic); } if (nSonic > 0) { IncrementPlayerStatistic(oVictim, "sonic_damage_taken", nSonic); } } if (GetIsPC(sDamage.oDamager)) @@ -43,6 +44,7 @@ void main() if (nFire > 0) { IncrementPlayerStatistic(sDamage.oDamager, "fire_damage_dealt", nFire); } if (nNegative > 0) { IncrementPlayerStatistic(sDamage.oDamager, "negative_damage_dealt", nNegative); } if (nPositive > 0) { IncrementPlayerStatistic(sDamage.oDamager, "positive_damage_dealt", nPositive); } + if (nMagic > 0) { IncrementPlayerStatistic(sDamage.oDamager, "magic_damage_dealt", nMagic); } if (nSonic > 0) { IncrementPlayerStatistic(sDamage.oDamager, "sonic_damage_dealt", nSonic); } } } diff --git a/src/nss/playerstats_evt.nss b/src/nss/playerstats_evt.nss new file mode 100644 index 00000000..d40edf94 --- /dev/null +++ b/src/nss/playerstats_evt.nss @@ -0,0 +1,184 @@ +#include "nui_playerstats" +#include "inc_general" +#include "inc_xp" + +string FormatTime(int nSeconds) +{ + int nDays = nSeconds / 86400; + nSeconds = nSeconds - (nDays * 86400); + int nHours = nSeconds / 3600; + nSeconds = nSeconds - (nHours * 3600); + int nMinutes = nSeconds / 60; + string sOut = ""; + if (nDays > 0) + { + sOut = IntToString(nDays) + "d "; + } + if (nHours > 0) + { + sOut += IntToString(nHours) + "h "; + } + if (nMinutes > 0) + { + sOut += IntToString(nMinutes) + "m"; + } + return sOut; +} + +void _UpdateBind(object oPC, int nToken, string sBind, int bCDKeyDB=0) +{ + json jBindValue; + // These ones will get updated more times than they needed to. + // Which is unfortunate. + if (sBind == "enemies_killed" || sBind == "enemies_killed_with_credit") + { + _UpdateBind(oPC, nToken, "percentage_kills_in_party", bCDKeyDB); + } + else if (sBind == "kill_xp_value" || sBind == "total_xp_from_partys_kills") + { + _UpdateBind(oPC, nToken, "percentage_xp_value_kills_in_party", bCDKeyDB); + } + + if (sBind == "most_powerful_killed") + { + jBindValue = JsonString(GetPlayerStatisticString(oPC, sBind, bCDKeyDB)); + } + else if (sBind == "percentage_kills_in_party") + { + int nPlayerKills = GetPlayerStatistic(oPC, "enemies_killed", bCDKeyDB); + int nPartyKills = GetPlayerStatistic(oPC, "enemies_killed_with_credit", bCDKeyDB); + if (nPartyKills == 0) { nPartyKills = 1; } + string sPercent = NeatFloatToString(100.0*IntToFloat(nPlayerKills)/IntToFloat(nPartyKills)); + jBindValue = JsonString(sPercent + "%"); + } + else if (sBind == "percentage_xp_value_kills_in_party") + { + int nPlayerKills = GetPlayerStatistic(oPC, "kill_xp_value", bCDKeyDB); + int nPartyKills = GetPlayerStatistic(oPC, "total_xp_from_partys_kills", bCDKeyDB); + if (nPartyKills == 0) { nPartyKills = 1; } + string sPercent = NeatFloatToString(100.0*IntToFloat(nPlayerKills)/IntToFloat(nPartyKills)); + jBindValue = JsonString(sPercent + "%"); + } + else if (sBind == "time_played" || sBind == "time_spent_in_house") + { + int nValue = GetPlayerStatistic(oPC, sBind, bCDKeyDB); + jBindValue = JsonString(FormatTime(nValue)); + } + else if (sBind == "kill_xp_value" || sBind == "total_xp_from_partys_kills") + { + // These values are saved x100 of the real one to get decimals in properly + jBindValue = JsonInt(GetPlayerStatistic(oPC, sBind, bCDKeyDB)/100); + } + else + { + jBindValue = JsonInt(GetPlayerStatistic(oPC, sBind, bCDKeyDB)); + } + NuiSetBind(oPC, nToken, sBind, jBindValue); +} + +void main() +{ + object oPC = NuiGetEventPlayer(); + string sEvent = NuiGetEventType(); + int nToken = NuiGetEventWindow(); + string sElement = NuiGetEventElement(); + + string sWindow = "pc_xpbar"; + + // Do this first! + HandleEditModeEvents(); + + string sUpdateBind = GetScriptParam("updatebind"); + string sUpdateAllBinds = GetScriptParam("updateallbinds"); + + if (sUpdateAllBinds != "" || sUpdateBind != "") + { + oPC = StringToObject(GetScriptParam("pc")); + nToken = StringToInt(GetScriptParam("token")); + } + + int bCDKeyDB = 0; + json jUserData; + if (sUpdateAllBinds != "" || sUpdateBind != "" || (sElement == "toggleallcharacters" && sEvent == "click")) + { + jUserData = NuiGetUserData(oPC, nToken); + bCDKeyDB = JsonGetString(JsonObjectGet(jUserData, "activepanel")) == "player"; + } + + if (sEvent == "click" && sElement == "toggleallcharacters") + { + int nNow = SQLite_GetTimeStamp(); + if (JsonGetInt(JsonObjectGet(jUserData, "nextswitchtime")) <= nNow) + { + // Rate limit the switching + // it has to set a lot of binds + jUserData = JsonObjectSet(jUserData, "nextswitchtime", JsonInt(nNow+2)); + + if (bCDKeyDB) + { + jUserData = JsonObjectSet(jUserData, "activepanel", JsonString("character")); + NuiSetBind(oPC, nToken, "switchviewbuttontext", JsonString("View this Character's Stats")); + } + else + { + jUserData = JsonObjectSet(jUserData, "activepanel", JsonString("player")); + NuiSetBind(oPC, nToken, "switchviewbuttontext", JsonString("View all Character Stats")); + } + bCDKeyDB = !bCDKeyDB; + sUpdateAllBinds = "1"; + + NuiSetUserData(oPC, nToken, jUserData); + } + } + else if (sEvent == "click" && GetStringLeft(sElement, 9) == "category_") + { + jUserData = NuiGetUserData(oPC, nToken); + string sCategory = GetSubString(sElement, 9, 99); + if (sCategory != JsonGetString(JsonObjectGet(jUserData, "activecategory"))) + { + int nNow = SQLite_GetTimeStamp(); + if (JsonGetInt(JsonObjectGet(jUserData, "nextcategorytime")) <= nNow) + { + // Rate limit the switching + // it has to set a lot of binds + jUserData = JsonObjectSet(jUserData, "nextcategorytime", JsonInt(nNow+1)); + json jContent = _PlayerStatsCategoryToNui(_GetPlayerStatsPanelBreakdown(), sCategory); + NuiSetGroupLayout(oPC, nToken, "configarea", jContent); + jUserData = JsonObjectSet(jUserData, "activecategory", JsonString(sCategory)); + NuiSetUserData(oPC, nToken, jUserData); + sUpdateAllBinds = "1"; + } + } + + } + + + // do not change to else if + // toggleallcharacters and category switches should do this as well + if (sUpdateAllBinds != "") + { + json jPanel = _GetPlayerStatsPanelBreakdown(); + json jKeys = JsonObjectKeys(jPanel); + int nLength = JsonGetLength(jKeys); + int i; + for (i=0; i Date: Tue, 25 Jul 2023 18:08:42 +0100 Subject: [PATCH 4/6] Add seconds if <1m on reported statistic times, fix gold spent statistic display --- src/nss/nui_playerstats.nss | 4 ++-- src/nss/on_pc_buya.nss | 11 ++++++++--- src/nss/playerstats_evt.nss | 5 +++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/nss/nui_playerstats.nss b/src/nss/nui_playerstats.nss index 8514d8b4..f68a168e 100644 --- a/src/nss/nui_playerstats.nss +++ b/src/nss/nui_playerstats.nss @@ -134,7 +134,7 @@ void UpdatePlayerStatsUIBindIfOpen(object oPlayer, string sBind=""); // gold_looted // gold_earned_from_selling -// gold_spent_by_buying +// gold_spent_from_buying // most_gold_carried // treasures_looted // items_bought @@ -270,7 +270,7 @@ json _GetPlayerStatsPanelBreakdown() json jGoldTreasure = JsonArray(); jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("gold_looted", "Gold Looted", "Total amount of raw gold looted.")); jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("gold_earned_from_selling", "Gold from Selling", "Total amount of gold obtained from selling goods to shops.")); - jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("gold_spent_by_buying", "Gold Spent", "Total amount of gold spent on items and services in both shops and dialogue.")); + jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("gold_spent_from_buying", "Gold Spent", "Total amount of gold spent on items and services in both shops and dialogue.")); jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("items_bought", "Items Bought", "Total number of items bought from stores.")); jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("items_sold", "Items Sold", "Total number of items sold to stores.")); jGoldTreasure = JsonArrayInsert(jGoldTreasure, _PreparePlayerStatsPanelItem("most_gold_carried", "Most Gold Carried", "Highest amount of gold carried at any time.")); diff --git a/src/nss/on_pc_buya.nss b/src/nss/on_pc_buya.nss index d6cc2d20..2245f7c4 100644 --- a/src/nss/on_pc_buya.nss +++ b/src/nss/on_pc_buya.nss @@ -10,11 +10,16 @@ void main() if (GetIsPC(OBJECT_SELF)) { object oItem = StringToObject(NWNX_Events_GetEventData("ITEM")); + // According to docs, this runs even if the PC has no room for the item + if (GetBaseItemFitsInInventory(GetBaseItemType(oItem), OBJECT_SELF)) + { + - IncrementPlayerStatistic(OBJECT_SELF, "gold_spent_from_buying", StringToInt(NWNX_Events_GetEventData("PRICE"))); - IncrementPlayerStatistic(OBJECT_SELF, "items_bought"); + IncrementPlayerStatistic(OBJECT_SELF, "gold_spent_from_buying", StringToInt(NWNX_Events_GetEventData("PRICE"))); + IncrementPlayerStatistic(OBJECT_SELF, "items_bought"); - ValuableItemWebhook(OBJECT_SELF, oItem, TRUE); + ValuableItemWebhook(OBJECT_SELF, oItem, TRUE); + } } } } diff --git a/src/nss/playerstats_evt.nss b/src/nss/playerstats_evt.nss index d40edf94..0ec99088 100644 --- a/src/nss/playerstats_evt.nss +++ b/src/nss/playerstats_evt.nss @@ -9,6 +9,7 @@ string FormatTime(int nSeconds) int nHours = nSeconds / 3600; nSeconds = nSeconds - (nHours * 3600); int nMinutes = nSeconds / 60; + nSeconds = nSeconds - (nMinutes * 60); string sOut = ""; if (nDays > 0) { @@ -22,6 +23,10 @@ string FormatTime(int nSeconds) { sOut += IntToString(nMinutes) + "m"; } + if (nMinutes < 1) + { + sOut += IntToString(nSeconds) + "s"; + } return sOut; } From f9c332b8126b9e31be7759fc2a8701e17cb4c79a Mon Sep 17 00:00:00 2001 From: Logg-y <49533518+Logg-y@users.noreply.github.com> Date: Tue, 25 Jul 2023 19:06:31 +0100 Subject: [PATCH 5/6] Add to player menu, hopefully make player menu setting be cdkey driven, fix stats toggle button text --- src/nss/0e_load_menu.nss | 3 +- src/nss/0e_window.nss | 61 +++--------------------------------- src/nss/0i_win_layouts.nss | 11 +++++++ src/nss/_pc_menu_toggler.nss | 7 +++-- src/nss/nui_playerstats.nss | 3 +- src/nss/playerstats_evt.nss | 18 +++++------ 6 files changed, 32 insertions(+), 71 deletions(-) diff --git a/src/nss/0e_load_menu.nss b/src/nss/0e_load_menu.nss index 266c108c..848e536d 100644 --- a/src/nss/0e_load_menu.nss +++ b/src/nss/0e_load_menu.nss @@ -9,7 +9,8 @@ void main () { - if (SQLocalsPlayer_GetInt(OBJECT_SELF, "pc_menu_disabled") != 1) + string sKey = GetPCPublicCDKey(OBJECT_SELF, TRUE); + if (GetCampaignInt(sKey, "pc_menu_disabled") != 1) { // Sets up the player target event. // If you have a target event then you will have to adjust it for you NUI. diff --git a/src/nss/0e_window.nss b/src/nss/0e_window.nss index 1e32f5d0..c059cfd1 100644 --- a/src/nss/0e_window.nss +++ b/src/nss/0e_window.nss @@ -11,62 +11,6 @@ #include "inc_restxp" #include "inc_sqlite_time" -void SendStatistic(object oPlayer, string sLabel, string sStatKey) -{ - string sStat = IntToString(SQLocalsPlayer_GetInt(oPlayer, STAT_PREFIX+sStatKey)); - - SendColorMessageToPC(oPlayer, sLabel + ": " + sStat, MESSAGE_COLOR_INFO); -} - -// TODO: Make this into NUI -void SendStatistics(object oPlayer) -{ - SendStatistic(oPlayer, "Time played (seconds)", "time_played"); - - SendStatistic(oPlayer, "Locks unlocked", "locks_unlocked"); - SendStatistic(oPlayer, "Locks bashed", "locks_bashed"); - - SendStatistic(oPlayer, "Henchman recruited", "henchman_recruited"); - SendStatistic(oPlayer, "Henchman died", "henchman_died"); - SendStatistic(oPlayer, "Followers recruited", "followers_recruited"); - SendStatistic(oPlayer, "Followers died", "followers_died"); - - SendStatistic(oPlayer, "Bounties completed", "bounties_completed"); - - SendStatistic(oPlayer, "Gold looted", "gold_looted"); - SendStatistic(oPlayer, "Treasures looted", "treasures_looted"); - SendStatistic(oPlayer, "Gold earned from selling", "gold_earned_from_selling"); - SendStatistic(oPlayer, "Items sold", "items_sold"); - - SendStatistic(oPlayer, "Gold spent", "gold_spent_from_buying"); - SendStatistic(oPlayer, "Items bought", "items_bought"); - - SendStatistic(oPlayer, "Ferries used", "ferries_used"); - SendStatistic(oPlayer, "Gold spent on ferries", "gold_spent_on_ferries"); - - SendStatistic(oPlayer, "Boats used", "long_travel_used"); - SendStatistic(oPlayer, "Gold spent on boats", "gold_spent_on_long_travel"); - - SendStatistic(oPlayer, "Treasure maps completed", "treasure_maps_completed"); - - SendStatistic(oPlayer, "Traps triggered", "traps_triggered"); - - SendStatistic(oPlayer, "Assassination attempts thwarted", "assasination_attempts_thwarted"); - SendStatistic(oPlayer, "Times rested", "rests_completed"); - SendStatistic(oPlayer, "Times ambushed while resting", "rest_ambushes"); - - SendStatistic(oPlayer, "Enemies killed", "enemies_killed"); - SendStatistic(oPlayer, "Enemies killed by you", "enemies_killed_with_credit"); - SendStatistic(oPlayer, "Bosses killed by you", "bosses_killed"); - SendStatistic(oPlayer, "Innocents murdered by you", "innocents_killed"); - SendStatistic(oPlayer, "Allies killed by you", "allies_killed"); - - SendStatistic(oPlayer, "Deaths", "deaths"); - SendStatistic(oPlayer, "Deaths from traps", "deaths_from_traps"); - SendStatistic(oPlayer, "Respawns", "respawned"); - SendStatistic(oPlayer, "Revived", "revived"); // this can probably be deprecated, you can determine this from deaths + respawns -} - void main() { // Let the inspector handle what it wants. @@ -119,7 +63,6 @@ void main() string sRespawn = GetRespawnLocationName(oPlayer); SendColorMessageToPC(oPlayer, "You have chosen to respawn in " + sRespawn + ".", MESSAGE_COLOR_INFO); SendRestedXPNotifierToPC(oPlayer); - SendStatistics(oPlayer); // PopUpPlayerSummaryGUIPanel(oPlayer, "pcsummarywin"); } } @@ -170,6 +113,10 @@ void main() { DisplayUIMasterConfigurationInterface(oPlayer); } + else if (sEvent == "click" && sElem == "open_statistics") + { + ShowPlayerStatsUI(oPlayer); + } } // This is the bug report event. else if (sWndId == "pcbugwin") diff --git a/src/nss/0i_win_layouts.nss b/src/nss/0i_win_layouts.nss index 736fb62c..2b8f2c91 100644 --- a/src/nss/0i_win_layouts.nss +++ b/src/nss/0i_win_layouts.nss @@ -530,6 +530,17 @@ void PopUpOptionsGUIPanel (object oPC, string sWinID) // Add row to the column. jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Create row 1 (label). + jRow = JsonArray(); + jButton = NuiButton(JsonString("Gameplay Statistics")); + jButton = NuiWidth(jButton, 300.0); + jButton = NuiHeight(jButton, 40.0); + jButton = NuiTooltip(jButton, JsonString("View your gameplay statistics.")); + jButton = NuiId(jButton, "open_statistics"); + jRow = JsonArrayInsert(jRow, jButton); + // Add row to the column. + jCol = JsonArrayInsert(jCol, NuiRow(jRow)); + // Create row 1 (label). jRow = JsonArray (); json jCheckBox = NuiWidth(NuiHeight(NuiCheck(NuiBind("hide_discord_label"), NuiBind("hide_discord_value2")), 40.0), 300.0); diff --git a/src/nss/_pc_menu_toggler.nss b/src/nss/_pc_menu_toggler.nss index c71e41f4..b95e4282 100644 --- a/src/nss/_pc_menu_toggler.nss +++ b/src/nss/_pc_menu_toggler.nss @@ -5,17 +5,18 @@ void main() { object oPC = GetItemActivator(); + string sKey = GetPCPublicCDKey(oPC, TRUE); - if (SQLocalsPlayer_GetInt(oPC, "pc_menu_disabled") == 1) + if (GetCampaignInt(sKey, "pc_menu_disabled") == 1) { SendColorMessageToPC(oPC, "Player menu enabled", MESSAGE_COLOR_INFO); - SQLocalsPlayer_DeleteInt(oPC, "pc_menu_disabled"); + DeleteCampaignVariable(sKey, "pc_menu_disabled"); PopUpPlayerHorGUIPanel(oPC); } else { SendColorMessageToPC(oPC, "Player menu disabled", MESSAGE_COLOR_INFO); - SQLocalsPlayer_SetInt(oPC, "pc_menu_disabled", 1); + SetCampaignInt(sKey, "pc_menu_disabled", 1); NuiDestroy(oPC, NuiFindWindow(oPC, "pcplayerwin")); } } diff --git a/src/nss/nui_playerstats.nss b/src/nss/nui_playerstats.nss index f68a168e..e8376cb1 100644 --- a/src/nss/nui_playerstats.nss +++ b/src/nss/nui_playerstats.nss @@ -330,7 +330,7 @@ void ShowPlayerStatsUI(object oPC) } json jTop = JsonArray(); - json jThisCharacterButton = NuiId(NuiHeight(NuiWidth(NuiButton(NuiBind("switchviewbuttontext")), 220.0), 40.0), "toggleallcharacters"); + json jThisCharacterButton = NuiTooltip(NuiId(NuiHeight(NuiWidth(NuiButton(NuiBind("switchviewbuttontext")), 220.0), 40.0), "toggleallcharacters"), NuiBind("switchbuttontooltip")); jTop = JsonArrayInsert(jTop, jThisCharacterButton); json jTopRow = NuiRow(jTop); @@ -415,6 +415,7 @@ void ShowPlayerStatsUI(object oPC) jUserData = JsonObjectSet(jUserData, "activecategory", JsonString("general")); NuiSetUserData(oPC, nToken, jUserData); NuiSetBind(oPC, nToken, "switchviewbuttontext", JsonString("View all Character Stats")); + NuiSetBind(oPC, nToken, "switchbuttontooltip", JsonString("Currently displaying this character's stats.")); UpdatePlayerStatsUIBindIfOpen(oPC, ""); } diff --git a/src/nss/playerstats_evt.nss b/src/nss/playerstats_evt.nss index 0ec99088..943c26a1 100644 --- a/src/nss/playerstats_evt.nss +++ b/src/nss/playerstats_evt.nss @@ -102,13 +102,8 @@ void main() nToken = StringToInt(GetScriptParam("token")); } - int bCDKeyDB = 0; - json jUserData; - if (sUpdateAllBinds != "" || sUpdateBind != "" || (sElement == "toggleallcharacters" && sEvent == "click")) - { - jUserData = NuiGetUserData(oPC, nToken); - bCDKeyDB = JsonGetString(JsonObjectGet(jUserData, "activepanel")) == "player"; - } + json jUserData = NuiGetUserData(oPC, nToken); + int bCDKeyDB = JsonGetString(JsonObjectGet(jUserData, "activepanel")) == "player";; if (sEvent == "click" && sElement == "toggleallcharacters") { @@ -119,15 +114,20 @@ void main() // it has to set a lot of binds jUserData = JsonObjectSet(jUserData, "nextswitchtime", JsonInt(nNow+2)); + // Logically: if currently looking at the cdkeydb, if (bCDKeyDB) { + SendDebugMessage("Switch to one-character view"); jUserData = JsonObjectSet(jUserData, "activepanel", JsonString("character")); - NuiSetBind(oPC, nToken, "switchviewbuttontext", JsonString("View this Character's Stats")); + NuiSetBind(oPC, nToken, "switchviewbuttontext", JsonString("View all Character's Stats")); + NuiSetBind(oPC, nToken, "switchbuttontooltip", JsonString("Currently displaying this character's stats.")); } else { + SendDebugMessage("Switch to all-character view"); jUserData = JsonObjectSet(jUserData, "activepanel", JsonString("player")); - NuiSetBind(oPC, nToken, "switchviewbuttontext", JsonString("View all Character Stats")); + NuiSetBind(oPC, nToken, "switchviewbuttontext", JsonString("View this Character Stats")); + NuiSetBind(oPC, nToken, "switchbuttontooltip", JsonString("Currently displaying combined stats for all characters.")); } bCDKeyDB = !bCDKeyDB; sUpdateAllBinds = "1"; From 698c13b5c0b52cf618b79c14b3fa1ff0531b46bb Mon Sep 17 00:00:00 2001 From: Logg-y <49533518+Logg-y@users.noreply.github.com> Date: Wed, 26 Jul 2023 02:32:12 +0100 Subject: [PATCH 6/6] Fix cache comparisons so it doesn't do this repeatedly on live --- src/nss/nui_playerstats.nss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/nss/nui_playerstats.nss b/src/nss/nui_playerstats.nss index e8376cb1..7be4419f 100644 --- a/src/nss/nui_playerstats.nss +++ b/src/nss/nui_playerstats.nss @@ -159,7 +159,7 @@ json _PreparePlayerStatsPanelItem(string sKey, string sLabel, string sTooltip) json _GetPlayerStatsPanelBreakdown() { json jRet = GetLocalJson(GetModule(), "playerstats_panel_breakdown"); - if (jRet != JsonNull() || GetIsDevServer()) + if (jRet == JsonNull() || GetIsDevServer()) { jRet = JsonObject(); json jGeneral = JsonArray(); @@ -289,7 +289,7 @@ json _GetPlayerStatsPanelBreakdown() json _PlayerStatsCategoryToNui(json jPanel, string sCategory) { json jRet = GetLocalJson(GetModule(), "playerstats_panel_nui_" + sCategory); - if (jRet != JsonNull() || GetIsDevServer()) + if (jRet == JsonNull() || GetIsDevServer()) { json jArray = JsonObjectGet(jPanel, sCategory); int nLength = JsonGetLength(jArray);