Difference between revisions of "KarmaSystem"
(→AlterKarmaAction) |
|||
(24 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
+ | ''This page documentation was added by Gizmo'' | ||
+ | == Karma Actions == | ||
'' | '' | ||
− | welcome this will discuss the contents of the globals\ | + | welcome this will discuss the contents of the globals\static_data\karma\main.lua |
this documentation is correct as of version 6.0 PRECB1 Release | this documentation is correct as of version 6.0 PRECB1 Release | ||
+ | '' | ||
+ | '' | ||
+ | --[[ | ||
+ | KarmaActionName = { | ||
+ | -- the amount to adjust | ||
+ | Adjust = -10, | ||
+ | -- the max amount this karma action can affect | ||
+ | UpTo = -500, | ||
+ | -- These only apply to NEGATIVE mods. (Adjust < 0) | ||
+ | -- if the action is being performed on a NPC (not a player character), it's multiplied by this amount | ||
+ | NpcModifier = 0.1 | ||
+ | }, | ||
+ | ]] | ||
+ | KarmaActions = {} | ||
+ | require 'globals.static_data.karma.negative_actions' | ||
+ | require 'globals.static_data.karma.positive_actions' | ||
+ | '' | ||
+ | === NegativeActions === | ||
+ | '' | ||
+ | welcome this will discuss the contents of the globals\static_data\karma\negative_actions.lua | ||
+ | this documentation is correct as of version 6.0 PRECB1 Release | ||
+ | '' | ||
+ | '' | ||
+ | --[[ | ||
+ | Negative actions, obviously, are only applicable to 'bad' player choices. | ||
+ | (ie LootContainer should never apply when looting something from your bank or a mob you killed for example, but should apply if the thing you're looting has positive Karma) | ||
+ | ]] | ||
+ | |||
+ | KarmaActions.Negative = { | ||
+ | Attack = { | ||
+ | Adjust = -50, | ||
+ | NpcModifier = 0.5, | ||
+ | }, | ||
+ | -- This applies to looting players bodies as well as anything with ObjVar Karma | ||
+ | LootContainer = { | ||
+ | Adjust = -10, | ||
+ | NpcModifier = 0.25, | ||
+ | }, | ||
+ | LootUnownedKill = { | ||
+ | Adjust = -25, | ||
+ | NpcModifier = 1, -- set to 1 to negate the effects of this modifer for this action since this only applies to npcs (corpses n such) | ||
+ | }, | ||
+ | Murder = { | ||
+ | Adjust = -500, | ||
+ | NpcModifier = 0.1, | ||
+ | }, | ||
+ | -- applies when a player performs a benefical act on a karma level set to punish beneficial acts | ||
+ | PunishForBeneficial = { | ||
+ | Adjust = -50, | ||
+ | NpcModifier = 0.1, | ||
+ | }, | ||
+ | } | ||
+ | '' | ||
+ | |||
+ | === PositiveActions === | ||
+ | '' | ||
+ | welcome this will discuss the contents of the globals\static_data\karma\positive_actions.lua | ||
+ | this documentation is correct as of version 6.0 PRECB1 Release | ||
+ | '' | ||
+ | '' | ||
+ | KarmaActions.Positive = { | ||
+ | DailyLogin = { | ||
+ | Adjust = 50, | ||
+ | UpTo = 5000, | ||
+ | }, | ||
+ | SlayMonster = { | ||
+ | Adjust = 1, | ||
+ | UpTo = 7500 | ||
+ | } | ||
+ | } | ||
'' | '' | ||
− | == | + | == Karma Functions == |
+ | '' | ||
+ | welcome this will discuss the contents of the globals\helpers\karma.lua | ||
+ | this documentation is correct as of version 6.0 PRECB1 Release | ||
+ | '' | ||
=== AdjustKarma === | === AdjustKarma === | ||
'' | '' | ||
Line 46: | Line 122: | ||
=== CheckKarmaBeneficialAction === | === CheckKarmaBeneficialAction === | ||
'' | '' | ||
+ | -- Check when a player performs a beneficial action on a mobile(player/npc/etc) | ||
+ | -- @param player(playerObj) DOES NOT ENFORCE IsPlayerCharacter() | ||
+ | -- @param mobile(mobileObj) Anything with a karma level | ||
+ | -- @return none | ||
+ | function CheckKarmaBeneficialAction(player, mobileB) | ||
+ | -- beneficial actions are only bad against some | ||
+ | local karmaLevelB = GetKarmaLevel(GetKarma(mobileB)) | ||
+ | local isPlayerB = IsPlayerCharacter(mobileB) | ||
+ | if ( | ||
+ | (isPlayerB and karmaLevelB.PunishBeneficialToPlayer) | ||
+ | or | ||
+ | (not isPlayerB and karmaLevelB.PunishBeneficialToNPC) | ||
+ | ) then | ||
+ | ExecuteKarmaAction(player, KarmaActions.Negative.PunishForBeneficial, mobileB) | ||
+ | end | ||
+ | if ( isPlayerB ) then | ||
+ | -- when players benefit players, they inherit their aggressive conflict relations. | ||
+ | InheritAggressivePlayerConflicts(mobileB, player) | ||
+ | end | ||
+ | end | ||
'' | '' | ||
+ | |||
=== CheckKarmaLoot === | === CheckKarmaLoot === | ||
'' | '' | ||
+ | -- Check player against a container on a loot (item removed from a container) | ||
+ | -- @param player(playerObj) Player doing the looting | ||
+ | -- @param container(Container) Container being looted from (mobileB:TopmostContainer()) | ||
+ | -- @return none (executes karma actions internally) | ||
+ | function CheckKarmaLoot(player, container) | ||
+ | if ( container == nil ) then return end | ||
+ | -- can't get in trouble doing stuff to yourself.. | ||
+ | if ( player == container ) then return end | ||
+ | -- only mobiles supported right now | ||
+ | if not( container:IsMobile() ) then return end | ||
+ | local containerOwner = nil | ||
+ | -- re-assign the container to the owner if applicable. | ||
+ | if ( container:GetCreationTemplateId() == "player_corpse" ) then | ||
+ | containerOwner = container:GetObjVar("BackpackOwner") | ||
+ | else | ||
+ | if ( IsPet(container) ) then containerOwner = container:GetObjectOwner() or container end | ||
+ | end | ||
+ | -- can't get in trouble doing stuff to yourself.. | ||
+ | if ( containerOwner ~= nil and player == containerOwner ) then return end | ||
+ | local isPlayer = false | ||
+ | if ( containerOwner ~= nil ) then | ||
+ | isPlayer = IsPlayerCharacter(containerOwner) | ||
+ | else | ||
+ | isPlayer = IsPlayerCharacter(container) | ||
+ | end | ||
+ | if ( isPlayer ) then | ||
+ | -- TODO: It's ok to loot players in your group? | ||
+ | -- if looting a player owned container that's not theirs, advance the conflict relation with no warning, no karma action | ||
+ | AdvanceConflictRelation(player, containerOwner, true, KarmaActions.Negative.LootContainer) | ||
+ | else | ||
+ | -- explicitly check for false, since nil is returned in the event the container doesn't have conflicts | ||
+ | -- and we don't care to punish anyone for looting something without conflict (like a chest) | ||
+ | if ( IsMobTaggedBy(container, player) == false ) then | ||
+ | -- the container is not tagged by the player, therefor the player doesn't have the right to loot. | ||
+ | ExecuteKarmaAction(player, KarmaActions.Negative.LootUnownedKill) | ||
+ | return | ||
+ | end | ||
+ | end | ||
+ | -- at this point we just execute a LootContainer action. Karma system should take care of the rest | ||
+ | ExecuteKarmaAction(player, KarmaActions.Negative.LootContainer, container) | ||
+ | end | ||
'' | '' | ||
+ | |||
=== ColorizeMobileName === | === ColorizeMobileName === | ||
'' | '' | ||
+ | -- Colorize a mobile name dependant on their karma | ||
+ | -- @param mobile(mobileObj) the mobile used to decide the name color | ||
+ | -- @param newName(string) The name to be colorized | ||
+ | -- @return colorized newName(string) | ||
+ | function ColorizeMobileName(mobile, newName) | ||
+ | if ( mobile == nil ) then | ||
+ | LuaDebugCallStack("[Karma] Nil mobile supplied to ColorizeMobileName") | ||
+ | return newName | ||
+ | end | ||
+ | local color = nil | ||
+ | if ( mobile:GetObjVar("ImportantNPC") ~= nil ) then | ||
+ | color = "F2F5A9" | ||
+ | else | ||
+ | color = GetKarmaLevel(GetKarma(mobile)).NameColor | ||
+ | end | ||
+ | return "[" .. color .. "]" .. newName .. "[-]" | ||
+ | end | ||
'' | '' | ||
+ | |||
=== ColorizePlayerName === | === ColorizePlayerName === | ||
'' | '' | ||
+ | -- Colorize a player's name dependant on their karma | ||
+ | -- @param player(mobileObj) the playerObj used to decide the name color | ||
+ | -- @param newName(string) The name to be colorized | ||
+ | -- @return colorized newName(string) | ||
+ | function ColorizePlayerName(player, newName) | ||
+ | if ( player == nil ) then | ||
+ | LuaDebugCallStack("[Karma] Nil player supplied to ColorizePlayerName") | ||
+ | return newName | ||
+ | end | ||
+ | local color = player:GetObjVar("NameColorOverride") | ||
+ | if ( color == nil ) then | ||
+ | if ( IsImmortal(player) and not player:GetObjVar("TestMortal") ) then color = "FFBF00" end | ||
+ | end | ||
+ | if ( color == nil ) then | ||
+ | color = GetKarmaLevel(GetKarma(player)).NameColor | ||
+ | end | ||
+ | return "[" .. color .. "]" .. newName .. "[-]" | ||
+ | end | ||
'' | '' | ||
+ | |||
=== DailyLogin === | === DailyLogin === | ||
'' | '' | ||
+ | -- Perform the positive karma action Daily Login with checks | ||
+ | -- @param player(playerObj) | ||
+ | -- @return none | ||
+ | function DailyLogin(player) | ||
+ | local lastDailyLoginReward = player:GetObjVar("KarmaDaily") | ||
+ | local now = DateTime.UtcNow | ||
+ | if ( lastDailyLoginReward == nil or lastDailyLoginReward + ServerSettings.Karma.DailyLoginInterval < now ) then | ||
+ | player:SetObjVar("KarmaDaily", now) | ||
+ | ExecuteKarmaAction(player, KarmaActions.Positive.DailyLogin) | ||
+ | end | ||
+ | end | ||
'' | '' | ||
+ | |||
=== ExectueKarmaAction === | === ExectueKarmaAction === | ||
'' | '' | ||
+ | -- Perform the actual karma handling for a karma action, will adjust mobileA's karma appropriately(if at all) for the given action. | ||
+ | -- @param mobileA the mobile that is performing the karma action | ||
+ | -- @param karmaAction(table) The KarmaActions.Positive/KarmaActions.Negative for the action. | ||
+ | -- @param mobileB(mobileObj)(optional) The mobile that the karma action is being performed on(if any) | ||
+ | -- @return none | ||
+ | function ExecuteKarmaAction(mobileA, action, mobileB) | ||
+ | if ( mobileA == nil ) then | ||
+ | LuaDebugCallStack("[Karma] Nil mobileA provided, need at least one mobile for a karma action.") | ||
+ | return | ||
+ | end | ||
+ | if ( action == nil ) then | ||
+ | LuaDebugCallStack("[Karma] Nil action supplied.") | ||
+ | return | ||
+ | end | ||
+ | if ( action.Adjust == nil ) then | ||
+ | LuaDebugCallStack("[Karma] Supplied action without 'Adjust', this karma action is invalid until resolved.") | ||
+ | return | ||
+ | end | ||
+ | -- if mobileB is passed, ensure it's in the same region. | ||
+ | if ( mobileB ~= nil and not mobileB:IsValid() ) then return end | ||
+ | -- karma adjustments can only be applied to players | ||
+ | if not( IsPlayerCharacter(mobileA) ) then return end | ||
+ | local karmaA = GetKarma(mobileA) | ||
+ | -- if they cannot be affected by this karma action any further, stop here. | ||
+ | if ( action.Adjust < 0 ) then | ||
+ | if ( action.UpTo and karmaA < action.UpTo ) then return end | ||
+ | else | ||
+ | if ( action.UpTo and karmaA > action.UpTo ) then return end | ||
+ | end | ||
+ | -- ensure they are both within the karma area. | ||
+ | if ( not WithinKarmaArea(mobileA) and (mobileB ~= nil and not WithinKarmaArea(mobileB)) ) then | ||
+ | return | ||
+ | end | ||
+ | local isPlayerB = false | ||
+ | local karmaB = | ||
+ | -- handle special karma cases | ||
+ | if ( mobileB ~= nil ) then | ||
+ | isPlayerB = IsPlayerCharacter(mobileB) | ||
+ | -- important npcs are off the charts. | ||
+ | if ( not isPlayerB and mobileB:HasObjVar("ImportantNPC") ) then karmaB = 1000000 else | ||
+ | karmaB = GetKarma(mobileB) | ||
+ | end | ||
+ | end | ||
+ | local conflictMod = 1 | ||
+ | local pvpMod = 1 | ||
+ | local negativeAdjustMod = 1 | ||
+ | local npcMod = 1 | ||
+ | -- players in same guilds/opposing factions never effect each other's karma | ||
+ | if ( isPlayerB ) then | ||
+ | local guildA = mobileA:GetObjVar("Guild") | ||
+ | if ( guildA ~= nil ) then | ||
+ | local guildB = mobileB:GetObjVar("Guild") | ||
+ | -- they share the same guild, end here | ||
+ | if ( guildA == guildB ) then return end | ||
+ | if ( guildB ~= nil and guildA ~= guildB ) then | ||
+ | -- determined the two involved are both definitely in guilds, and they are not the same guild, | ||
+ | -- let's compare their factions. | ||
+ | local guildRecordA = Guild.GetGuildRecord(guildA) | ||
+ | if ( guildRecordA ~= nil and guildRecordA.PatronGod ~= nil ) then | ||
+ | local guildRecordB = Guild.GetGuildRecord(guildB) | ||
+ | if ( guildRecordB ~= nil and guildRecordB.PatronGod ~= nil and guildRecordA.PatronGod ~= guildRecordB.PatronGod ) then | ||
+ | -- officially determined that playerA and playerB are both in factions, and their factions are not the same. | ||
+ | return | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | -- handle negative karma actions | ||
+ | if ( action.Adjust < 0 ) then | ||
+ | local karmaALevel = nil | ||
+ | if ( mobileB ~= nil ) then | ||
+ | local karmaBLevel = GetKarmaLevel(karmaB) | ||
+ | -- if guards don't protect them, they are free to perform negative actions on. | ||
+ | -- the guards are the metaphorical judge/jury/(literal)executioner | ||
+ | if ( (not isPlayerB and karmaBLevel.GuardProtectNPC ~= true) or (isPlayerB and karmaBLevel.GuardProtectPlayer ~= true) ) then return end | ||
+ | if ( isPlayerB ) then | ||
+ | --determine their player vs player modifiers | ||
+ | karmaALevel = GetKarmaLevel(karmaA) | ||
+ | karmaBLevel = karmaBLevel or GetKarmaLevel(karmaB) | ||
+ | pvpMod = karmaALevel.PvPMods[karmaBLevel.Name] | ||
+ | else | ||
+ | if ( action.NpcModifier ~= nil ) then | ||
+ | -- if mobileB is not a player, modify as such | ||
+ | npcMod = action.NpcModifier | ||
+ | end | ||
+ | end | ||
+ | -- get conflict mod | ||
+ | if ( pvpMod > 0 ) then | ||
+ | if ( ConflictEquals(GetConflictRelation(mobileB, mobileA), ConflictRelations.Aggressor) ) then | ||
+ | local aToBRelation = GetConflictRelation(mobileA, mobileB) | ||
+ | if ( | ||
+ | ConflictEquals(aToBRelation, ConflictRelations.Defender) | ||
+ | or | ||
+ | ConflictEquals(aToBRelation, ConflictRelations.Victim) | ||
+ | ) then | ||
+ | --victim/defender karma action against aggressor, this is free. | ||
+ | conflictMod = 0 | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | end | ||
+ | if ( pvpMod > 0 and conflictMod > 0 ) then | ||
+ | -- determine the negative karma adjust mod | ||
+ | karmaALevel = karmaALevel or GetKarmaLevel(karmaA) | ||
+ | negativeAdjustMod = karmaALevel.NegativeKarmaAdjustMod | ||
+ | end | ||
+ | else | ||
+ | -- handle positive karma actions | ||
+ | end | ||
+ | --[[ | ||
+ | DebugMessage("--Execute Karma Action--") | ||
+ | DebugMessage("Adjust: "..action.Adjust) | ||
+ | DebugMessage("conMod: "..conflictMod) | ||
+ | DebugMessage("pvpMod: "..pvpMod) | ||
+ | DebugMessage("negMod: "..negativeAdjustMod) | ||
+ | DebugMessage("npcMod: "..npcMod) | ||
+ | ]] | ||
+ | local adjust = action.Adjust * conflictMod * pvpMod * negativeAdjustMod * npcMod | ||
+ | -- prevent positive actions from going negative | ||
+ | if ( action.Adjust > 0 and adjust < 0 ) then return end | ||
+ | -- prevent negative actions from going positive | ||
+ | if ( action.Adjust < 0 and adjust > 0 ) then return end | ||
+ | -- finally apply all the calculated karma | ||
+ | AdjustKarma(mobileA, adjust) | ||
+ | end | ||
'' | '' | ||
+ | |||
=== GetKarma === | === GetKarma === | ||
'' | '' | ||
+ | -- Get the Karma for a mobile | ||
+ | -- @param mobile(mobileObj) | ||
+ | -- @return Amount of Karma the mobile has(number), 0 if Karma is not set | ||
+ | function GetKarma(mobile) | ||
+ | if ( mobile == nil ) then | ||
+ | LuaDebugCallStack("[Karma] Nil mobile provided to GetKarma()") | ||
+ | return | ||
+ | end | ||
+ | return mobile:GetObjVar("Karma") or 0 | ||
+ | end | ||
'' | '' | ||
+ | |||
=== GetKarmaLevel === | === GetKarmaLevel === | ||
+ | '' | ||
+ | -- Get the karma level data table for the given amount of karma. | ||
+ | -- @param karma(number) return value of GetKarma() | ||
+ | -- @return KarmaLevelData(luaTable) from ServerSettings.Karma.Levels | ||
+ | function GetKarmaLevel(karma) | ||
+ | karma = karma or 0 | ||
+ | if ( karma >= 0 ) then | ||
+ | for i,data in pairs(ServerSettings.Karma.Levels) do | ||
+ | if ( karma >= data.Amount ) then return data end | ||
+ | end | ||
+ | elseif ( karma < 0 ) then | ||
+ | --negative karma we check the list backwards | ||
+ | local ii = #ServerSettings.Karma.Levels | ||
+ | for i,data in pairs(ServerSettings.Karma.Levels) do | ||
+ | if ( ServerSettings.Karma.Levels[ii].Amount >= karma ) then | ||
+ | return ServerSettings.Karma.Levels[ii] | ||
+ | end | ||
+ | ii = ii - 1 | ||
+ | end | ||
+ | end | ||
+ | end | ||
'' | '' | ||
− | |||
=== GetKarmaStringAmount === | === GetKarmaStringAmount === | ||
'' | '' | ||
+ | -- Convert an amount of karma gained/lost to a string representation | ||
+ | -- @param amount(number) | ||
+ | -- @return string amount | ||
+ | function GetKarmaStringAmount(amount) | ||
+ | if ( amount < 10 ) then | ||
+ | return " a little " | ||
+ | elseif ( amount < 50 ) then | ||
+ | return " some " | ||
+ | elseif ( amount < 100 ) then | ||
+ | return " " | ||
+ | elseif ( amount < 1000 ) then | ||
+ | return " a lot of " | ||
+ | else | ||
+ | return " a substantial amount of " | ||
+ | end | ||
+ | end | ||
'' | '' | ||
+ | |||
=== KarmaPunishAllAggressorsForMurder === | === KarmaPunishAllAggressorsForMurder === | ||
'' | '' | ||
+ | -- Anyone that is an aggressor to the victim will have a Murder Karma action executed on them. | ||
+ | -- @param victim(mobileObj) | ||
+ | -- @return none | ||
+ | function KarmaPunishAllAggressorsForMurder(victim) | ||
+ | ForeachAggressor(victim, | ||
+ | function(aggressor) | ||
+ | if ( aggressor:IsValid() ) then | ||
+ | ExecuteKarmaAction(aggressor, KarmaActions.Negative.Murder, victim) | ||
+ | end | ||
+ | end) | ||
+ | end | ||
'' | '' | ||
+ | |||
=== SetKarma === | === SetKarma === | ||
'' | '' | ||
+ | -- Set a mobiles karma to an exact amount, does not adjust. | ||
+ | -- @param mobile(mobileObj) | ||
+ | -- @param amount(number) The exact number to set their Karma too | ||
+ | -- @return none | ||
+ | function SetKarma(mobile, amount) | ||
+ | if ( mobile == nil ) then | ||
+ | LuaDebugCallStack("[Karma] Nil mobile provided to SetKarma()") | ||
+ | return | ||
+ | end | ||
+ | mobile:SetObjVar("Karma", amount) | ||
+ | end | ||
'' | '' | ||
+ | |||
=== WithinKarmaArea === | === WithinKarmaArea === | ||
'' | '' | ||
+ | -- Determine if a mobile is in a location that karma matters | ||
+ | -- @param mobileObj | ||
+ | -- @return true/false | ||
+ | function WithinKarmaArea(mobileObj) | ||
+ | for i,j in pairs(ServerSettings.Karma.DisableKarmaZones) do | ||
+ | if ( mobileObj:IsInRegion(j) ) then return false end | ||
+ | end | ||
+ | local regionAddress = GetRegionAddress() | ||
+ | for i,disabledRegionAddress in pairs(ServerSettings.Karma.DisableKarmaRegionAddresses) do | ||
+ | if ( regionAddress == disabledRegionAddress ) then return false end | ||
+ | end | ||
+ | return true | ||
+ | end | ||
+ | '' | ||
+ | == Server Settings == | ||
+ | '' | ||
+ | welcome this will discuss the contents of the globals\server_settings\karma.lua | ||
+ | this documentation is correct as of version 6.0 PRECB1 Release | ||
+ | '' | ||
+ | '' | ||
+ | ServerSettings.Karma = { | ||
+ | -- zones in-game will be disabled from karma. | ||
+ | DisableKarmaZones = { "Arena" }, | ||
+ | -- Regions with this address will be disabled | ||
+ | DisableKarmaRegionAddresses = { "TwoTowers" }, | ||
+ | -- the minimum time between daily login bonus | ||
+ | DailyLoginInterval = TimeSpan.FromHours(20), | ||
+ | -- always keep these ordered from highest to lowest | ||
+ | Levels = { | ||
+ | { | ||
+ | Amount = 10000, | ||
+ | Name = "Trustworthy", | ||
+ | NameColor = "ffff99", | ||
+ | Title = "%s the Trustworthy", -- %s will be replaced with the mobile's name. | ||
+ | --Negative Karma Adjustment modifiers are used to compound negative acts by players of positive karma and to reduce players of negative karma from falling off a cliff. | ||
+ | NegativeKarmaAdjustMod = 5, | ||
+ | -- do guards protect this karma level for players? | ||
+ | GuardProtectPlayer = true, | ||
+ | -- do guards protect this karma level for NPCs? | ||
+ | GuardProtectNPC = true, | ||
+ | --PvPMods: Player Vs Player Modifiers; Karma rewards are not given at low levels of positive karma as people may use this to game high karma through killing red accomplices. | ||
+ | Accomplishing | ||
+ | high karma must be a grind to those not generating it organically. | ||
+ | PvPMods = { | ||
+ | Trustworthy = 2, | ||
+ | Honest = 1.5, | ||
+ | Good = 1.25, | ||
+ | Neutral = 1, | ||
+ | Rude = 0, | ||
+ | Scoundrel = -1, | ||
+ | Outcast = -1.25, | ||
+ | } | ||
+ | }, | ||
+ | { | ||
+ | Amount = 5000, | ||
+ | Name = "Honest", | ||
+ | NameColor = "355fb2", | ||
+ | Title = "%s the Honest", | ||
+ | NegativeKarmaAdjustMod = 3, | ||
+ | GuardProtectPlayer = true, | ||
+ | GuardProtectNPC = true, | ||
+ | PvPMods = { | ||
+ | Trustworthy = 2, | ||
+ | Honest = 1.5, | ||
+ | Good = 1.25, | ||
+ | Neutral = 1, | ||
+ | Rude = 0, | ||
+ | Scoundrel = -1, | ||
+ | Outcast = 1.25, | ||
+ | } | ||
+ | }, | ||
+ | { | ||
+ | Amount = 2500, | ||
+ | Name = "Good", | ||
+ | NameColor = "82abff", | ||
+ | Title = "%s the Good", | ||
+ | NegativeKarmaAdjustMod = 1.5, | ||
+ | GuardProtectPlayer = true, | ||
+ | GuardProtectNPC = true, | ||
+ | PvPMods = { | ||
+ | Trustworthy = 2, | ||
+ | Honest = 1.5, | ||
+ | Good = 1.25, | ||
+ | Neutral = 1, | ||
+ | Rude = 0, | ||
+ | Scoundrel = 0, | ||
+ | Outcast = 0, | ||
+ | } | ||
+ | }, | ||
+ | { | ||
+ | Amount = 0, | ||
+ | Name = "Neutral", | ||
+ | NameColor = "FFFFFF", | ||
+ | Title = "%s", | ||
+ | NegativeKarmaAdjustMod = 1, | ||
+ | GuardProtectPlayer = true, | ||
+ | PunishBeneficialToNPC = true, | ||
+ | PvPMods = { | ||
+ | Trustworthy = 2, | ||
+ | Honest = 1.5, | ||
+ | Good = 1.25, | ||
+ | Neutral = 1, | ||
+ | Rude = 0, | ||
+ | Scoundrel = 0, | ||
+ | Outcast = 0, | ||
+ | } | ||
+ | }, | ||
+ | { | ||
+ | Amount = -2500, | ||
+ | Name = "Rude", | ||
+ | NameColor = "A7A7A7", | ||
+ | Title = "%s the Rude", | ||
+ | NegativeKarmaAdjustMod = 1, | ||
+ | GuardProtectPlayer = true, | ||
+ | GuardHostileNPC = true, | ||
+ | PunishBeneficialToNPC = true, | ||
+ | PvPMods = { | ||
+ | Trustworthy = 2, | ||
+ | Honest = 1.5, | ||
+ | Good = 1.25, | ||
+ | Neutral = 1, | ||
+ | Rude = 0, | ||
+ | Scoundrel = 0, | ||
+ | Outcast = 0, | ||
+ | }, | ||
+ | -- Apply and modify the Positive Karma action SlayMonster ONLY when slaying an NPC of this Karma Level. | ||
+ | SlayMonsterModifier = 1, | ||
+ | }, | ||
+ | { | ||
+ | Amount = -5000, | ||
+ | Name = "Scoundrel", | ||
+ | NameColor = "ff5959", | ||
+ | Title = "%s the Scoundrel", | ||
+ | NegativeKarmaAdjustMod = 0.5, | ||
+ | GuardProtectPlayer = true, | ||
+ | GuardHostileNPC = true, | ||
+ | PunishBeneficialToNPC = true, | ||
+ | PvPMods = { | ||
+ | Trustworthy = 1, | ||
+ | Honest = 1, | ||
+ | Good = 1, | ||
+ | Neutral = 1, | ||
+ | Rude = 0, | ||
+ | Scoundrel = 0, | ||
+ | Outcast = 0, | ||
+ | }, | ||
+ | SlayMonsterModifier = 2, | ||
+ | }, | ||
+ | { | ||
+ | Amount = -10000, | ||
+ | Name = "Outcast", | ||
+ | NameColor = "FF0000", | ||
+ | Title = "%s the Outcast", | ||
+ | NegativeKarmaAdjustMod = 0.25, | ||
+ | -- guards will attack this player, don't set guard protect to true when this is true, things might get weird? | ||
+ | GuardHostilePlayer = true, | ||
+ | -- guards will attack this NPC, don't set guard protect to true when this is true, things might get weird? | ||
+ | GuardHostileNPC = true, | ||
+ | -- If any beneficial actions are performed on this karma level (as a player), the one performing will have a negative karma action executed on them | ||
+ | PunishBeneficialToPlayer = true, | ||
+ | -- If any beneficial actions are performed on this karma level (as an NPC), the one performing will have a negative karma action executed on them | ||
+ | PunishBeneficialToNPC = true, | ||
+ | -- | ||
+ | DisallowBlueResurrectShrines = true, | ||
+ | PvPMods = { | ||
+ | Trustworthy = 1, | ||
+ | Honest = 1, | ||
+ | Good = 1, | ||
+ | Neutral = 1, | ||
+ | Rude = 0, | ||
+ | Scoundrel = 0, | ||
+ | Outcast = 0, | ||
+ | }, | ||
+ | SlayMonsterModifier = 3, | ||
+ | } | ||
+ | } | ||
+ | } | ||
'' | '' |
Latest revision as of 01:19, 28 January 2018
This page documentation was added by Gizmo
Contents
- 1 Karma Actions
- 2 Karma Functions
- 2.1 AdjustKarma
- 2.2 AlterKarmaAction
- 2.3 CheckKarmaBeneficialAction
- 2.4 CheckKarmaLoot
- 2.5 ColorizeMobileName
- 2.6 ColorizePlayerName
- 2.7 DailyLogin
- 2.8 ExectueKarmaAction
- 2.9 GetKarma
- 2.10 GetKarmaLevel
- 2.11 GetKarmaStringAmount
- 2.12 KarmaPunishAllAggressorsForMurder
- 2.13 SetKarma
- 2.14 WithinKarmaArea
- 3 Server Settings
Karma Actions
welcome this will discuss the contents of the globals\static_data\karma\main.lua this documentation is correct as of version 6.0 PRECB1 Release
--[[ KarmaActionName = { -- the amount to adjust Adjust = -10, -- the max amount this karma action can affect UpTo = -500, -- These only apply to NEGATIVE mods. (Adjust < 0) -- if the action is being performed on a NPC (not a player character), it's multiplied by this amount NpcModifier = 0.1 }, ]] KarmaActions = {} require 'globals.static_data.karma.negative_actions' require 'globals.static_data.karma.positive_actions'
NegativeActions
welcome this will discuss the contents of the globals\static_data\karma\negative_actions.lua this documentation is correct as of version 6.0 PRECB1 Release
--[[ Negative actions, obviously, are only applicable to 'bad' player choices. (ie LootContainer should never apply when looting something from your bank or a mob you killed for example, but should apply if the thing you're looting has positive Karma) ]]
KarmaActions.Negative = { Attack = { Adjust = -50, NpcModifier = 0.5, }, -- This applies to looting players bodies as well as anything with ObjVar Karma LootContainer = { Adjust = -10, NpcModifier = 0.25, }, LootUnownedKill = { Adjust = -25, NpcModifier = 1, -- set to 1 to negate the effects of this modifer for this action since this only applies to npcs (corpses n such) }, Murder = { Adjust = -500, NpcModifier = 0.1, }, -- applies when a player performs a benefical act on a karma level set to punish beneficial acts PunishForBeneficial = { Adjust = -50, NpcModifier = 0.1, }, }
PositiveActions
welcome this will discuss the contents of the globals\static_data\karma\positive_actions.lua this documentation is correct as of version 6.0 PRECB1 Release
KarmaActions.Positive = { DailyLogin = { Adjust = 50, UpTo = 5000, }, SlayMonster = { Adjust = 1, UpTo = 7500 } }
Karma Functions
welcome this will discuss the contents of the globals\helpers\karma.lua this documentation is correct as of version 6.0 PRECB1 Release
AdjustKarma
-- Adjust the karma for a mobile, a system message pertaining to the change is sent. -- @param mobile(mobileObj) -- @param amount(number) The amount to adjust by. -- @return none
function AdjustKarma(mobile, amount) if ( amount == 0 or amount == nil ) then return end local karma = GetKarma(mobile) -- cache the karma level so we can check if it changed. local karmaLevel = GetKarmaLevel(karma) karma = math.floor(karma + amount + 0.5) SetKarma(mobile, karma) if ( amount > 0 ) then mobile:SystemMessage("You have gained"..GetKarmaStringAmount(amount).."karma.", "info") else mobile:SystemMessage("You have lost"..GetKarmaStringAmount(math.abs(amount)).."karma.", "info") end if ( karmaLevel.Name ~= GetKarmaLevel(karma).Name ) then -- Karma was changed, update the name and whatever else, maybe a message? mobile:SendMessage("UpdateName") end end
AlterKarmaAction
-- convenience function to alter a karma action's amount before applying it -- @param karmaAction Lua table karma action -- @param newAmount(number) -- @return the altered karma action
function AlterKarmaAction(karmaAction, newAmount) karmaAction = deepcopy(karmaAction) karmaAction.Adjust = newAmount return karmaAction end
CheckKarmaBeneficialAction
-- Check when a player performs a beneficial action on a mobile(player/npc/etc) -- @param player(playerObj) DOES NOT ENFORCE IsPlayerCharacter() -- @param mobile(mobileObj) Anything with a karma level -- @return none
function CheckKarmaBeneficialAction(player, mobileB) -- beneficial actions are only bad against some local karmaLevelB = GetKarmaLevel(GetKarma(mobileB)) local isPlayerB = IsPlayerCharacter(mobileB) if ( (isPlayerB and karmaLevelB.PunishBeneficialToPlayer) or (not isPlayerB and karmaLevelB.PunishBeneficialToNPC) ) then ExecuteKarmaAction(player, KarmaActions.Negative.PunishForBeneficial, mobileB) end if ( isPlayerB ) then -- when players benefit players, they inherit their aggressive conflict relations. InheritAggressivePlayerConflicts(mobileB, player) end end
CheckKarmaLoot
-- Check player against a container on a loot (item removed from a container) -- @param player(playerObj) Player doing the looting -- @param container(Container) Container being looted from (mobileB:TopmostContainer()) -- @return none (executes karma actions internally)
function CheckKarmaLoot(player, container) if ( container == nil ) then return end -- can't get in trouble doing stuff to yourself.. if ( player == container ) then return end -- only mobiles supported right now if not( container:IsMobile() ) then return end local containerOwner = nil -- re-assign the container to the owner if applicable. if ( container:GetCreationTemplateId() == "player_corpse" ) then containerOwner = container:GetObjVar("BackpackOwner") else if ( IsPet(container) ) then containerOwner = container:GetObjectOwner() or container end end -- can't get in trouble doing stuff to yourself.. if ( containerOwner ~= nil and player == containerOwner ) then return end local isPlayer = false if ( containerOwner ~= nil ) then isPlayer = IsPlayerCharacter(containerOwner) else isPlayer = IsPlayerCharacter(container) end if ( isPlayer ) then -- TODO: It's ok to loot players in your group? -- if looting a player owned container that's not theirs, advance the conflict relation with no warning, no karma action AdvanceConflictRelation(player, containerOwner, true, KarmaActions.Negative.LootContainer) else -- explicitly check for false, since nil is returned in the event the container doesn't have conflicts -- and we don't care to punish anyone for looting something without conflict (like a chest) if ( IsMobTaggedBy(container, player) == false ) then -- the container is not tagged by the player, therefor the player doesn't have the right to loot. ExecuteKarmaAction(player, KarmaActions.Negative.LootUnownedKill) return end end -- at this point we just execute a LootContainer action. Karma system should take care of the rest ExecuteKarmaAction(player, KarmaActions.Negative.LootContainer, container) end
ColorizeMobileName
-- Colorize a mobile name dependant on their karma -- @param mobile(mobileObj) the mobile used to decide the name color -- @param newName(string) The name to be colorized -- @return colorized newName(string)
function ColorizeMobileName(mobile, newName) if ( mobile == nil ) then LuaDebugCallStack("[Karma] Nil mobile supplied to ColorizeMobileName") return newName end local color = nil if ( mobile:GetObjVar("ImportantNPC") ~= nil ) then color = "F2F5A9" else color = GetKarmaLevel(GetKarma(mobile)).NameColor end return "[" .. color .. "]" .. newName .. "[-]" end
ColorizePlayerName
-- Colorize a player's name dependant on their karma -- @param player(mobileObj) the playerObj used to decide the name color -- @param newName(string) The name to be colorized -- @return colorized newName(string)
function ColorizePlayerName(player, newName) if ( player == nil ) then LuaDebugCallStack("[Karma] Nil player supplied to ColorizePlayerName") return newName end local color = player:GetObjVar("NameColorOverride") if ( color == nil ) then if ( IsImmortal(player) and not player:GetObjVar("TestMortal") ) then color = "FFBF00" end end if ( color == nil ) then color = GetKarmaLevel(GetKarma(player)).NameColor end return "[" .. color .. "]" .. newName .. "[-]" end
DailyLogin
-- Perform the positive karma action Daily Login with checks -- @param player(playerObj) -- @return none
function DailyLogin(player) local lastDailyLoginReward = player:GetObjVar("KarmaDaily") local now = DateTime.UtcNow if ( lastDailyLoginReward == nil or lastDailyLoginReward + ServerSettings.Karma.DailyLoginInterval < now ) then player:SetObjVar("KarmaDaily", now) ExecuteKarmaAction(player, KarmaActions.Positive.DailyLogin) end end
ExectueKarmaAction
-- Perform the actual karma handling for a karma action, will adjust mobileA's karma appropriately(if at all) for the given action. -- @param mobileA the mobile that is performing the karma action -- @param karmaAction(table) The KarmaActions.Positive/KarmaActions.Negative for the action. -- @param mobileB(mobileObj)(optional) The mobile that the karma action is being performed on(if any) -- @return none
function ExecuteKarmaAction(mobileA, action, mobileB) if ( mobileA == nil ) then LuaDebugCallStack("[Karma] Nil mobileA provided, need at least one mobile for a karma action.") return end if ( action == nil ) then LuaDebugCallStack("[Karma] Nil action supplied.") return end if ( action.Adjust == nil ) then LuaDebugCallStack("[Karma] Supplied action without 'Adjust', this karma action is invalid until resolved.") return end -- if mobileB is passed, ensure it's in the same region. if ( mobileB ~= nil and not mobileB:IsValid() ) then return end -- karma adjustments can only be applied to players if not( IsPlayerCharacter(mobileA) ) then return end local karmaA = GetKarma(mobileA) -- if they cannot be affected by this karma action any further, stop here. if ( action.Adjust < 0 ) then if ( action.UpTo and karmaA < action.UpTo ) then return end else if ( action.UpTo and karmaA > action.UpTo ) then return end end -- ensure they are both within the karma area. if ( not WithinKarmaArea(mobileA) and (mobileB ~= nil and not WithinKarmaArea(mobileB)) ) then return end local isPlayerB = false local karmaB = -- handle special karma cases if ( mobileB ~= nil ) then isPlayerB = IsPlayerCharacter(mobileB) -- important npcs are off the charts. if ( not isPlayerB and mobileB:HasObjVar("ImportantNPC") ) then karmaB = 1000000 else karmaB = GetKarma(mobileB) end end local conflictMod = 1 local pvpMod = 1 local negativeAdjustMod = 1 local npcMod = 1 -- players in same guilds/opposing factions never effect each other's karma if ( isPlayerB ) then local guildA = mobileA:GetObjVar("Guild") if ( guildA ~= nil ) then local guildB = mobileB:GetObjVar("Guild") -- they share the same guild, end here if ( guildA == guildB ) then return end if ( guildB ~= nil and guildA ~= guildB ) then -- determined the two involved are both definitely in guilds, and they are not the same guild, -- let's compare their factions. local guildRecordA = Guild.GetGuildRecord(guildA) if ( guildRecordA ~= nil and guildRecordA.PatronGod ~= nil ) then local guildRecordB = Guild.GetGuildRecord(guildB) if ( guildRecordB ~= nil and guildRecordB.PatronGod ~= nil and guildRecordA.PatronGod ~= guildRecordB.PatronGod ) then -- officially determined that playerA and playerB are both in factions, and their factions are not the same. return end end end end end -- handle negative karma actions if ( action.Adjust < 0 ) then local karmaALevel = nil if ( mobileB ~= nil ) then local karmaBLevel = GetKarmaLevel(karmaB) -- if guards don't protect them, they are free to perform negative actions on. -- the guards are the metaphorical judge/jury/(literal)executioner if ( (not isPlayerB and karmaBLevel.GuardProtectNPC ~= true) or (isPlayerB and karmaBLevel.GuardProtectPlayer ~= true) ) then return end if ( isPlayerB ) then --determine their player vs player modifiers karmaALevel = GetKarmaLevel(karmaA) karmaBLevel = karmaBLevel or GetKarmaLevel(karmaB) pvpMod = karmaALevel.PvPMods[karmaBLevel.Name] else if ( action.NpcModifier ~= nil ) then -- if mobileB is not a player, modify as such npcMod = action.NpcModifier end end -- get conflict mod if ( pvpMod > 0 ) then if ( ConflictEquals(GetConflictRelation(mobileB, mobileA), ConflictRelations.Aggressor) ) then local aToBRelation = GetConflictRelation(mobileA, mobileB) if ( ConflictEquals(aToBRelation, ConflictRelations.Defender) or ConflictEquals(aToBRelation, ConflictRelations.Victim) ) then --victim/defender karma action against aggressor, this is free. conflictMod = 0 end end end end if ( pvpMod > 0 and conflictMod > 0 ) then -- determine the negative karma adjust mod karmaALevel = karmaALevel or GetKarmaLevel(karmaA) negativeAdjustMod = karmaALevel.NegativeKarmaAdjustMod end else -- handle positive karma actions end --[[ DebugMessage("--Execute Karma Action--") DebugMessage("Adjust: "..action.Adjust) DebugMessage("conMod: "..conflictMod) DebugMessage("pvpMod: "..pvpMod) DebugMessage("negMod: "..negativeAdjustMod) DebugMessage("npcMod: "..npcMod) ]] local adjust = action.Adjust * conflictMod * pvpMod * negativeAdjustMod * npcMod -- prevent positive actions from going negative if ( action.Adjust > 0 and adjust < 0 ) then return end -- prevent negative actions from going positive if ( action.Adjust < 0 and adjust > 0 ) then return end -- finally apply all the calculated karma AdjustKarma(mobileA, adjust) end
GetKarma
-- Get the Karma for a mobile -- @param mobile(mobileObj) -- @return Amount of Karma the mobile has(number), 0 if Karma is not set
function GetKarma(mobile) if ( mobile == nil ) then LuaDebugCallStack("[Karma] Nil mobile provided to GetKarma()") return end return mobile:GetObjVar("Karma") or 0 end
GetKarmaLevel
-- Get the karma level data table for the given amount of karma. -- @param karma(number) return value of GetKarma() -- @return KarmaLevelData(luaTable) from ServerSettings.Karma.Levels function GetKarmaLevel(karma) karma = karma or 0 if ( karma >= 0 ) then for i,data in pairs(ServerSettings.Karma.Levels) do if ( karma >= data.Amount ) then return data end end elseif ( karma < 0 ) then --negative karma we check the list backwards local ii = #ServerSettings.Karma.Levels for i,data in pairs(ServerSettings.Karma.Levels) do if ( ServerSettings.Karma.Levels[ii].Amount >= karma ) then return ServerSettings.Karma.Levels[ii] end ii = ii - 1 end end end
GetKarmaStringAmount
-- Convert an amount of karma gained/lost to a string representation -- @param amount(number) -- @return string amount
function GetKarmaStringAmount(amount) if ( amount < 10 ) then return " a little " elseif ( amount < 50 ) then return " some " elseif ( amount < 100 ) then return " " elseif ( amount < 1000 ) then return " a lot of " else return " a substantial amount of " end end
KarmaPunishAllAggressorsForMurder
-- Anyone that is an aggressor to the victim will have a Murder Karma action executed on them. -- @param victim(mobileObj) -- @return none
function KarmaPunishAllAggressorsForMurder(victim) ForeachAggressor(victim, function(aggressor) if ( aggressor:IsValid() ) then ExecuteKarmaAction(aggressor, KarmaActions.Negative.Murder, victim) end end) end
SetKarma
-- Set a mobiles karma to an exact amount, does not adjust. -- @param mobile(mobileObj) -- @param amount(number) The exact number to set their Karma too -- @return none
function SetKarma(mobile, amount) if ( mobile == nil ) then LuaDebugCallStack("[Karma] Nil mobile provided to SetKarma()") return end mobile:SetObjVar("Karma", amount) end
WithinKarmaArea
-- Determine if a mobile is in a location that karma matters -- @param mobileObj -- @return true/false
function WithinKarmaArea(mobileObj) for i,j in pairs(ServerSettings.Karma.DisableKarmaZones) do if ( mobileObj:IsInRegion(j) ) then return false end end local regionAddress = GetRegionAddress() for i,disabledRegionAddress in pairs(ServerSettings.Karma.DisableKarmaRegionAddresses) do if ( regionAddress == disabledRegionAddress ) then return false end end return true end
Server Settings
welcome this will discuss the contents of the globals\server_settings\karma.lua this documentation is correct as of version 6.0 PRECB1 Release
ServerSettings.Karma = { -- zones in-game will be disabled from karma. DisableKarmaZones = { "Arena" }, -- Regions with this address will be disabled DisableKarmaRegionAddresses = { "TwoTowers" }, -- the minimum time between daily login bonus DailyLoginInterval = TimeSpan.FromHours(20), -- always keep these ordered from highest to lowest Levels = { { Amount = 10000, Name = "Trustworthy", NameColor = "ffff99", Title = "%s the Trustworthy", -- %s will be replaced with the mobile's name. --Negative Karma Adjustment modifiers are used to compound negative acts by players of positive karma and to reduce players of negative karma from falling off a cliff. NegativeKarmaAdjustMod = 5, -- do guards protect this karma level for players? GuardProtectPlayer = true, -- do guards protect this karma level for NPCs? GuardProtectNPC = true, --PvPMods: Player Vs Player Modifiers; Karma rewards are not given at low levels of positive karma as people may use this to game high karma through killing red accomplices. Accomplishing high karma must be a grind to those not generating it organically. PvPMods = { Trustworthy = 2, Honest = 1.5, Good = 1.25, Neutral = 1, Rude = 0, Scoundrel = -1, Outcast = -1.25, } }, { Amount = 5000, Name = "Honest", NameColor = "355fb2", Title = "%s the Honest", NegativeKarmaAdjustMod = 3, GuardProtectPlayer = true, GuardProtectNPC = true, PvPMods = { Trustworthy = 2, Honest = 1.5, Good = 1.25, Neutral = 1, Rude = 0, Scoundrel = -1, Outcast = 1.25, } }, { Amount = 2500, Name = "Good", NameColor = "82abff", Title = "%s the Good", NegativeKarmaAdjustMod = 1.5, GuardProtectPlayer = true, GuardProtectNPC = true, PvPMods = { Trustworthy = 2, Honest = 1.5, Good = 1.25, Neutral = 1, Rude = 0, Scoundrel = 0, Outcast = 0, } }, { Amount = 0, Name = "Neutral", NameColor = "FFFFFF", Title = "%s", NegativeKarmaAdjustMod = 1, GuardProtectPlayer = true, PunishBeneficialToNPC = true, PvPMods = { Trustworthy = 2, Honest = 1.5, Good = 1.25, Neutral = 1, Rude = 0, Scoundrel = 0, Outcast = 0, } }, { Amount = -2500, Name = "Rude", NameColor = "A7A7A7", Title = "%s the Rude", NegativeKarmaAdjustMod = 1, GuardProtectPlayer = true, GuardHostileNPC = true, PunishBeneficialToNPC = true, PvPMods = { Trustworthy = 2, Honest = 1.5, Good = 1.25, Neutral = 1, Rude = 0, Scoundrel = 0, Outcast = 0, }, -- Apply and modify the Positive Karma action SlayMonster ONLY when slaying an NPC of this Karma Level. SlayMonsterModifier = 1, }, { Amount = -5000, Name = "Scoundrel", NameColor = "ff5959", Title = "%s the Scoundrel", NegativeKarmaAdjustMod = 0.5, GuardProtectPlayer = true, GuardHostileNPC = true, PunishBeneficialToNPC = true, PvPMods = { Trustworthy = 1, Honest = 1, Good = 1, Neutral = 1, Rude = 0, Scoundrel = 0, Outcast = 0, }, SlayMonsterModifier = 2, }, { Amount = -10000, Name = "Outcast", NameColor = "FF0000", Title = "%s the Outcast", NegativeKarmaAdjustMod = 0.25, -- guards will attack this player, don't set guard protect to true when this is true, things might get weird? GuardHostilePlayer = true, -- guards will attack this NPC, don't set guard protect to true when this is true, things might get weird? GuardHostileNPC = true, -- If any beneficial actions are performed on this karma level (as a player), the one performing will have a negative karma action executed on them PunishBeneficialToPlayer = true, -- If any beneficial actions are performed on this karma level (as an NPC), the one performing will have a negative karma action executed on them PunishBeneficialToNPC = true, -- DisallowBlueResurrectShrines = true, PvPMods = { Trustworthy = 1, Honest = 1, Good = 1, Neutral = 1, Rude = 0, Scoundrel = 0, Outcast = 0, }, SlayMonsterModifier = 3, } } }