Difference between revisions of "ConflictSystem"

From Legends of Aria Admin and Modding Wiki
Jump to: navigation, search
(GetConflictRelation)
(ValidConflictRelationTable)
 
(45 intermediate revisions by the same user not shown)
Line 1: Line 1:
welcome this will discuss the contents of the globals\helpers\conflict.lua
+
''
 +
  welcome this will discuss the contents of the globals\helpers\conflict.lua
 +
  this documentation is correct as of version 6.0 PRECB1 Release
 +
''
 +
''this documentation was added by Gizmo''
 +
== ConflictRelations Table ==
 +
''
 +
  ConflictRelations = {
 +
    Warning = {
 +
        Name = "Warning",
 +
        Warning = true,
 +
    },
 +
    BeenWarned = {
 +
        Name = "BeenWarned",
 +
        Warning = true,
 +
    },
 +
    Aggressor = {
 +
        Name = "Aggressor",
 +
    },
 +
    Victim = {
 +
        Name = "Victim"
 +
    },
 +
    Defender = {
 +
        Name = "Defender"
 +
    }
 +
  }
 +
''
  
== ConflictRelations Table ==
 
 
== Conflict Functions ==
 
== Conflict Functions ==
=== GetConflictTable ===
+
=== AdvanceConflictRelation ===
 
''
 
''
   -- Get the conflict table for a mobile
+
   -- Advance mobileA against mobileB in conflict, will also refresh any current
   -- @param mobile(mobileObj)
+
    conflicts between the two.
   -- @return luaTable containing all conflicts for this mobile
+
  -- @param mobileA(mobileObj)
 +
   -- @param mobileB(mobileObj)
 +
   -- @param noWarning(boolean)(optional) if true, warning will be skipped and they will
 +
    go directly to aggressor
 +
  -- @param karmaAction(luaTable)(optional) KarmaAction that will be executed on mobileA
 +
    when they become an aggressor. (default: KarmaActions.Negative.Attack) Setting this  
 +
    to false will not execute any karma actions.
 +
  -- @return none
  
   function GetConflictTable(mobile)
+
   function AdvanceConflictRelation(mobileA, mobileB, noWarning, karmaAction)
     if ( mobile == nil or not mobile ) then
+
    if not( karmaAction == false ) then
         LuaDebugCallStack("[Conflict] Invalid mobile provided.")
+
        karmaAction = karmaAction or KarmaActions.Negative.Attack
         return {}
+
    end
 +
    -- when Warnings are not enabled, we force noWarning to true.
 +
     if ( ServerSettings.Conflict.WarningEnabled ~= true ) then
 +
        noWarning = true
 +
    end
 +
    -- reassign mobileA and mobileB to pet owners, if applicable
 +
    if ( IsPet(mobileA) ) then
 +
        mobileA = mobileA:GetObjectOwner() or mobileA
 +
    end
 +
    if ( mobileB ~= nil and IsPet(mobileB) ) then
 +
        mobileB = mobileB:GetObjectOwner() or mobileB
 +
    end
 +
    -- conflict don't care what you do to yourself or your pets
 +
    if ( mobileA == mobileB ) then return end
 +
    local aToBRelation = GetConflictRelation(mobileA, mobileB)
 +
    local bToARelation = GetConflictRelation(mobileB, mobileA)
 +
    local refreshA = true
 +
    local refreshB = true
 +
    -- when one side has a relation but the other side does not, we count neither side
 +
      as having a relation.
 +
    -- this is so we can clear a conflict relation on either side and not need to clear
 +
      both involved parties (the other involved could be in a different region at time
 +
      of clearing!)
 +
    if ( noWarning ~= true and (aToBRelation == nil or bToARelation == nil) ) then
 +
        UpdateConflictRelation(mobileA, mobileB, ConflictRelations.Warning)
 +
        UpdateConflictRelation(mobileB, mobileA, ConflictRelations.BeenWarned)
 +
        refreshA = false
 +
    elseif ( (noWarning == true and (aToBRelation == nil or bToARelation == nil))
 +
        or ConflictEquals(aToBRelation, ConflictRelations.Warning) ) then
 +
        -- A becomes aggressor, B becomes victim.
 +
        UpdateConflictRelation(mobileA, mobileB, ConflictRelations.Aggressor, true)
 +
        UpdateConflictRelation(mobileB, mobileA, ConflictRelations.Victim)
 +
        refreshA = false
 +
        refreshB = false
 +
        -- Karma action for becoming the aggressor
 +
        if ( karmaAction ) then
 +
            ExecuteKarmaAction(mobileA, karmaAction, mobileB)
 +
        end
 +
        if ( IsInitiate(mobileB) and IsPlayerCharacter(mobileA) ) then
 +
            EndInitiate(mobileB)
 +
        end
 +
        elseif ( ConflictEquals(aToBRelation, ConflictRelations.Victim) ) then
 +
         -- A was a victim, now A is a defender.
 +
        UpdateConflictRelation(mobileA, mobileB, ConflictRelations.Defender)
 +
        refreshA = false
 +
    end
 +
    --refresh the conflict expiration.
 +
    -- Possible optimization, only refresh every other one/every third one?
 +
    if ( aToBRelation ~= nil and refreshA ) then
 +
        if ( karmaAction and ConflictEquals(aToBRelation, ConflictRelations.Aggressor) )
 +
          then
 +
            ExecuteKarmaAction(mobileA, karmaAction, mobileB)
 +
        end
 +
        UpdateConflictRelation(mobileA, mobileB, ConflictRelations[aToBRelation], true)
 +
    end
 +
    if ( bToARelation ~= nil and refreshB ) then
 +
         UpdateConflictRelation(mobileB, mobileA, ConflictRelations[bToARelation])
 
     end
 
     end
    return mobile:GetObjVar("Conflicts") or {}
 
 
   end
 
   end
 
''
 
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| base_mobile || HandleApplyDamage(damager, damageAmount, damageType, isCrit, wasBlocked)
 +
|-
 +
| globals\helpers\karma|| CheckKarmaLoot(player, container)
 +
|}
  
 
=== ClearConflictTable ===
 
=== ClearConflictTable ===
 +
''
 
   -- Clear the conflict table of a mobile
 
   -- Clear the conflict table of a mobile
 
   -- @param mobile(mobileObj)
 
   -- @param mobile(mobileObj)
Line 35: Line 131:
 
     end
 
     end
 
   end
 
   end
 +
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| base_mobile || DoResurrect(statPct, resurrector, force)
 +
|-
 +
| base_player_death|| RegisterEventHandler(EventType.CreatedObject, "created_corpse", function (success, objRef)
 +
|}
  
=== SetConflictTable ===
+
=== ConflictEquals ===
 +
''
 +
  -- Convenience function to make checking conflicts more readable
 +
  -- @param strRelation(string) The string Name of the relation to check for
 +
  -- @param tableRelation(luaTable) The ConflictRelations entry to check against
 +
  -- @return true or false
 +
 
 +
  function ConflictEquals(strRelation, tableRelation)
 +
    return ( strRelation == tableRelation.Name )
 +
  end
 +
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| globals\helpers\conflict ||
 +
    UpdateConflictRelation(mobileA, mobileB, newRelation, guardCheck)
 +
    ConflictEquals(strRelation, tableRelation)
 +
    AdvanceConflictRelation(mobileA, mobileB, noWarning, karmaAction)
 +
    ForeachAggressor(mobile, callback)
 +
    IsAggressor(mobile, guardIgnore)
 +
    InheritAggressivePlayerConflicts(playerA, playerB)
 +
    InitializeClientConflicts(mobile)
 +
|-
 +
| globals\helpers\karma|| ExecuteKarmaAction(mobileA, action, mobileB) 
 +
|}
 +
 
 +
=== ForeachAggressor ===
 
''
 
''
   -- Set the conflict table for a mobile
+
   -- Perform a function on each aggressor of a mobile
 
   -- @param mobile(mobileObj)
 
   -- @param mobile(mobileObj)
   -- @param data(luaTable)
+
   -- @param callback(function(id))
 
   -- @return none
 
   -- @return none
  
   function SetConflictTable(mobile, data)
+
   function ForeachAggressor(mobile, callback)
     mobile:SetObjVar("Conflicts", data)
+
     local conflictTable = GetConflictTable(mobile)
 +
    for mobileB,relation in pairs(conflictTable) do
 +
        if ( mobileB:IsValid() ) then
 +
            if (( ConflictEquals(relation[1], ConflictRelations.Victim) or ConflictEquals(relation[1], ConflictRelations.Defender )) and ValidConflictRelationTable(relation)) then
 +
                if ( ConflictEquals(GetConflictRelation(mobileB, mobile), ConflictRelations.Aggressor) ) then
 +
                    callback(mobileB)
 +
                end
 +
            end
 +
        end
 +
    end
 
   end
 
   end
 
''
 
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| globals/helpers/karma|| KarmaPunishAllAggressorsForMurder(victim)
 +
|-
 +
|}
  
 
=== FreezeConflictTable ===
 
=== FreezeConflictTable ===
Line 68: Line 216:
 
   end
 
   end
 
''
 
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| base_mobile || DoMobileDeath(damager)
 +
|-
 +
| base_player_death|| RegisterEventHandler(EventType.CreatedObject, "created_corpse", function (success, objRef)
 +
|}
  
 
=== GetConflictRelation ===
 
=== GetConflictRelation ===
Line 86: Line 242:
 
   end
 
   end
 
''
 
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| globals\helpers\conflict ||
 +
  GetConflictRelation(mobileA, mobileB, mobileAConflictTable)
 +
  AdvanceConflictRelation(mobileA, mobileB, noWarning, karmaAction)
 +
  ForeachAggressor(mobile, callback)
 +
  IsAggressor(mobile, guardIgnore)
 +
  InheritAggressivePlayerConflicts(playerA, playerB)
 +
  InitializeClientConflicts(mobile)
 +
|-
 +
| globals\helpers\karma|| RegisterEventHandler(EventType.CreatedObject, "created_corpse", function (success, objRef)
 +
|}
 +
 +
=== GetConflictTable ===
 +
''
 +
  -- Get the conflict table for a mobile
 +
  -- @param mobile(mobileObj)
 +
  -- @return luaTable containing all conflicts for this mobile
 +
 +
  function GetConflictTable(mobile)
 +
    if ( mobile == nil or not mobile ) then
 +
        LuaDebugCallStack("[Conflict] Invalid mobile provided.")
 +
        return {}
 +
    end
 +
    return mobile:GetObjVar("Conflicts") or {}
 +
  end
 +
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| globals/helpers/conflict|| This is used as a tool throughout the conflict file. You will find it used in the FreezContactTable, ValidConflictRelationTable, ForeachAggressor, IsAggressor, InheritAggressivePlayerConflicts and InitializeClientConflicts functions.
 +
|}
 +
 +
=== GetNearbyTaggedMobiles ===
 +
''
 +
  -- Get all mobiles that are tagged to a mobile and are also nearby
 +
  -- @param mobile
 +
  -- @return list of nearby mobiles (luaArray)
 +
 +
  function GetNearbyTaggedMobiles(mobile)
 +
    local validMobiles = {}
 +
    if ( mobile ) then
 +
        local taggedMobiles = mobile:GetObjVar("Tag") or {}
 +
        local loc = mobile:GetLoc()
 +
        for id,val in pairs(taggedMobiles) do
 +
            local obj = GameObj(id)
 +
            if ( obj ~= nil and obj:IsValid() and obj:GetLoc():Distance(loc) <= ServerSettings.Misc.GroupAutolootRange ) then
 +
                table.insert(validMobiles, obj)
 +
            end
 +
        end
 +
    end
 +
    return validMobiles
 +
  end
 +
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| globals\mobile_extensions_misc|| HandleMobileDeathRewards(victim, karmaLevel)
 +
|}
 +
 +
=== InheritAggressivePlayerConflicts ===
 +
  ''
 +
  -- Inherit Aggressor/Defender conflict relations from playerA onto playerB, DOES NOT ENFORCE IsPlayerCharacter()
 +
  -- @param playerA(playerObj) The player whos conflicts are being inherited
 +
  -- @param playerB(playerObj) The player who is inheriting the conflicts
 +
  -- @return none
 +
 +
  function InheritAggressivePlayerConflicts(playerA, playerB)
 +
    if ( playerA == playerB ) then return end
 +
    local conflictsA = GetConflictTable(playerA)
 +
    -- loop all of playerA's conflicts
 +
    for mobileC,aToCRelationTable in pairs(conflictsA) do
 +
        if ( mobileC ~= playerB and mobileC:IsValid() ) then
 +
            -- using this variable to keep the if nesting from going too deep
 +
            local keepgoing = false
 +
            -- if A to C is aggressor
 +
            if (
 +
                ConflictEquals(aToCRelationTable[1], ConflictRelations.Aggressor)
 +
                and
 +
                ValidConflictRelationTable(aToCRelationTable)
 +
            ) then
 +
                local cToARelation = GetConflictRelation(mobileC, playerA)
 +
                -- and C to A is Victim/Defender
 +
                if (
 +
                    cToARelation ~= nil
 +
                    and
 +
                    (
 +
                        ConflictEquals(cToARelation, ConflictRelations.Victim)
 +
                        or
 +
                        ConflictEquals(cToARelation, ConflictRelations.Defender)
 +
                    )
 +
                ) then
 +
                    keepgoing = true
 +
                end
 +
            end
 +
            if ( keepgoing ) then
 +
                local alreadyAggressive = false
 +
                local bToCRelation = GetConflictRelation(playerB, mobileC)
 +
                -- if B to C is aggressor
 +
                if (
 +
                    bToCRelation ~= nil
 +
                    and
 +
                    ConflictEquals(bToCRelation, ConflictRelations.Aggressor)
 +
                ) then
 +
                    local cToBRelation = GetConflictRelation(mobileC, playerB)
 +
                    -- and C to B is Victim/Defender
 +
                    if (
 +
                        cToBRelation ~= nil
 +
                        and
 +
                        (
 +
                            ConflictEquals(cToBRelation, ConflictRelations.Victim)
 +
                            or
 +
                            ConflictEquals(cToBRelation, ConflictRelations.Defender)
 +
                        )
 +
                    ) then
 +
                        alreadyAggressive = true
 +
                    end
 +
                end
 +
                if ( alreadyAggressive ) then
 +
                    -- refresh it
 +
                    UpdateConflictRelation(playerB, mobileC, conflictsB[mobileC], true)
 +
                    UpdateConflictRelation(mobileC, playerB, cRelationTable[mobileB])
 +
                else -- otherwise
 +
                    -- inherit it.
 +
                    -- set playerB's relation: aggressor to mobileC.
 +
                    UpdateConflictRelation(playerB, mobileC, ConflictRelations.Aggressor, true)
 +
                    -- and set mobileC's relation: victim to playerB
 +
                    UpdateConflictRelation(mobileC, playerB, ConflictRelations.Victim)
 +
                end
 +
            end
 +
        end
 +
    end
 +
  end
 +
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| globals\helpers\conflict|| InheritAggressivePlayerConflicts(playerA, playerB)
 +
|-
 +
| globals\helpers\karma|| CheckKarmaBeneficialAction(player, mobileB)
 +
|}
 +
 +
=== InitializeClientConflicts ===
 +
''
 +
  -- Refresh the client with conflict status on login/region change
 +
  -- @param mobile
 +
 +
  function InitializeClientConflicts(mobile) 
 +
    local conflictTable = GetConflictTable(mobile)
 +
    for mobileB,relation in pairs(conflictTable) do
 +
        if ( mobileB:IsValid() ) then -- if the mobile is in same region currently.
 +
            local bToARelation = GetConflictRelation(mobileB, mobile) -- if they have a valid relation with us
 +
            if ( bToARelation ~= nil ) then
 +
                if ((
 +
                        ConflictEquals(relation[1], ConflictRelations.Victim)
 +
                        or
 +
                        ConflictEquals(relation[1], ConflictRelations.Defender)
 +
                    )
 +
                    and
 +
                    ConflictEquals(bToARelation, ConflictRelations.Aggressor)
 +
                    and
 +
                    ValidConflictRelationTable(relation)
 +
                ) then
 +
                    local timeRemaining = relation[2] - DateTime.UtcNow
 +
                    mobile:SendClientMessage("UpdateMobileConflictStatus",{mobileB,"Aggressed",timeRemaining.TotalSeconds})
 +
                    if ( IsPlayerCharacter(mobileB) ) then
 +
                        mobileB:SendClientMessage("UpdateMobileConflictStatus",{mobile,"Aggressor",timeRemaining.TotalSeconds})
 +
                    end
 +
                elseif(
 +
                    ConflictEquals(relation[1], ConflictRelations.Aggressor)
 +
                    and
 +
                    (
 +
                        ConflictEquals(bToARelation, ConflictRelations.Victim)
 +
                        or
 +
                        ConflictEquals(bToARelation, ConflictRelations.Defender)
 +
                    )
 +
                    and
 +
                    ValidConflictRelationTable(relation)
 +
                ) then
 +
                    local timeRemaining = relation[2] - DateTime.UtcNow
 +
                    mobile:SendClientMessage("UpdateMobileConflictStatus",{mobileB,"Aggressor",timeRemaining.TotalSeconds})
 +
                    if ( IsPlayerCharacter(mobileB) ) then
 +
                        mobileB:SendClientMessage("UpdateMobileConflictStatus",{mobile,"Aggressed",timeRemaining.TotalSeconds})
 +
                    end
 +
                elseif(
 +
                    ConflictEquals(relation[1], ConflictRelations.Warning)
 +
                    and
 +
                    ConflictEquals(bToARelation, ConflictRelations.BeenWarned)
 +
                    and
 +
                    ValidConflictRelationTable(relation)
 +
                ) then
 +
                    local timeRemaining = relation[2] - DateTime.UtcNow
 +
                    mobile:SendClientMessage("UpdateMobileConflictStatus",{mobileB,"Warning",timeRemaining.TotalSeconds})
 +
                end
 +
            end
 +
        end
 +
    end
 +
  end
 +
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| globals\helpers\conflict||
 +
  InitializeClientConflicts(mobile)
 +
  ClearConflictTable(mobile, isPlayer)
 +
|-
 +
| player|| CallFunctionDelayed(TimeSpan.FromSeconds(0.5),
 +
|}
  
=== ValidConflictRelationTable ===
 
=== UpdateConflictRelation ===
 
=== ConflictEquals ===
 
=== AdvanceConflictRelation ===
 
=== ForeachAggressor ===
 
 
=== IsAggressor ===
 
=== IsAggressor ===
 +
''
 +
  --- Determine if a mobile is an aggressor
 +
  -- @param mobile(mobileObj)
 +
  -- @param guardIgnore(boolean)(optional) if true, ignore any relation that's tagged guard ignore. (this is so guards ignore when someone is an aggressor against an outcast for example)
 +
  -- @return true if mobile is an aggressor
 +
 +
  function IsAggressor(mobile, guardIgnore)
 +
    for mobileB,conflict in pairs(GetConflictTable(mobile)) do
 +
        if (
 +
            guardIgnore ~= true or
 +
            (guardIgnore == true) and
 +
            conflict[3] ~= true and
 +
            ConflictEquals(conflict[1], ConflictRelations.Aggressor) and
 +
            ValidConflictRelationTable(conflict)
 +
          ) then
 +
            if ( mobileB:IsValid() ) then
 +
                local bToARelation = GetConflictRelation(mobileB, mobile)
 +
                if ( bToARelation ~= nil ) then
 +
                    if ( ConflictEquals(bToARelation, ConflictRelations.Victim) or ConflictEquals(bToARelation, ConflictRelations.Defender) ) then return true end
 +
                end
 +
            end
 +
        end
 +
    end
 +
    return false
 +
  end
 +
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| ai_guard|| IsEnemy(targetObj)
 +
|-
 +
| ai_super_guard|| IsEnemy(targetObj)
 +
|-
 +
| globals\helpers\conflict|| IsAggressor(mobile, guardIgnore)
 +
|-
 +
| player|| UpdateFactions() *note: the code is commented out though
 +
|-
 +
| sp_resurrect_effect|| HandleLoaded() *note: the code is commented out though
 +
|}
 +
 
=== IsMobTaggedBy ===
 
=== IsMobTaggedBy ===
 +
''
 +
  -- Check to see if a mobile(npc) is tagged by a player
 +
  -- @param mobile(mobileObj) DOES NOT force this to be an NPC ( but it should be )
 +
  -- @param player(playerObj) DOES NOT force this to be an Player ( but it should be )
 +
  -- @return true or false or nil (nil if the mobile had no conflicts)
 +
 +
  function IsMobTaggedBy(mobile, player)
 +
    local tag = mobile:GetObjVar("Tag") or {}
 +
    return ( player ~= nil and tag[player.Id] == true )
 +
  end
 +
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| globals\helpers\conflict|| IsMobTaggedBy(mobile, player)
 +
|-
 +
| globals\helpers\karma|| CheckKarmaLoot(player, container)
 +
|-
 +
|}
 +
 +
=== SetConflictTable ===
 +
''
 +
  -- Set the conflict table for a mobile
 +
  -- @param mobile(mobileObj)
 +
  -- @param data(luaTable)
 +
  -- @return none
 +
 +
  function SetConflictTable(mobile, data)
 +
    mobile:SetObjVar("Conflicts", data)
 +
  end
 +
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| globals\helpers\conflict||
 +
  SetConflictTable(mobile, data)
 +
  FreezeConflictTable(mobile, target)
 +
  UpdateConflictRelation(mobileA, mobileB, newRelation, guardCheck)
 +
|-
 +
|}
 +
 
=== TagMob ===
 
=== TagMob ===
=== InheritAggressivePlayerConflicts ===
+
''
=== GetNearbyTaggedMobiles ===
+
  -- Uses the damage list to determine what Single Player/Collective Group did the most damage and sets the ObjVar Tag with the mobiles that fit the bill
=== InitializeClientConflicts ===
+
  -- @param mobile(mobileObj) the NPC that has died
 +
 
 +
  function TagMob(mobile)
 +
    local damagers = mobile:GetObjVar("Damagers")
 +
    if ( damagers ~= nil ) then
 +
        -- get a list of all groups/solos involved in all the damage
 +
        local groups = {}
 +
        local solos = {}
 +
        for damager,data in pairs(damagers) do
 +
            if ( damager ~= nil and damager:IsValid() ) then
 +
                local gid = damager:GetObjVar("Group")
 +
                if ( gid ~= nil ) then
 +
                    if ( groups[gid] == nil ) then groups[gid] = {} end
 +
                    table.insert(groups[gid], {damager,data.Amount})
 +
                else
 +
                    -- we have to set it as damager.Id because guilds keep track of members by their Id
 +
                    table.insert(solos, {damager.Id,data.Amount})
 +
                end
 +
            end
 +
        end
 +
        -- calculate the damage for each group
 +
        local groupsDamage = {}
 +
        for gid,data in pairs(groups) do
 +
            for i,d in pairs(groups[gid]) do
 +
                if ( groupsDamage[gid] == nil ) then groupsDamage[gid] = 0 end
 +
                groupsDamage[gid] = groupsDamage[gid] + d[2]
 +
            end
 +
        end
 +
        -- finally determine who's the winner
 +
        local most = {nil,0}
 +
        -- first check solos
 +
        for mobileId,data in pairs(solos) do
 +
            if ( data[2] > most[2] ) then
 +
                most = data
 +
            end
 +
        end
 +
        local isGroup = false
 +
        -- then check collective groups
 +
        for gid,amount in pairs(groupsDamage) do
 +
            if ( amount > most[2] ) then
 +
                most = {gid,amount}
 +
                -- solos were checked first
 +
                isGroup = true
 +
            end
 +
        end
 +
        local tag = {}
 +
        if ( isGroup ) then
 +
            -- add every mobile in the group that won
 +
            local groupRecord = GetGroupRecord(most[1]) or {}
 +
            groupRecord.Members = groupRecord.Members or {}
 +
            for id,data in pairs(groupRecord.Members) do
 +
                tag[id] = true
 +
            end
 +
        else
 +
            -- add the solo mobile that won
 +
            tag[most[1]] = true
 +
        end
 +
        mobile:SetObjVar("Tag", tag)
 +
    end
 +
  end
 +
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| base_mobile|| DoMobileDeath(damager)
 +
|-
 +
| globals\helpers\conflict|| TagMob(mobile)
 +
|-
 +
|}
 +
 
 +
=== UpdateConflictRelation ===
 +
''
 +
  -- Update the conflict relation between two mobiles, also cleans mobileA's conflict
 +
    table of any expired.
 +
  -- @param mobileA(mobileObj)
 +
  -- @param mobileB(mobileObj)
 +
  -- @param newRelation(luaTable) the entry from ConflictRelations
 +
  -- @param guardCheck(boolean) If true, this update will check for guard protection,
 +
      this way you can refresh a conflict on both sides but only one will cares about
 +
      guards.
 +
  -- @return none
 +
 
 +
  function UpdateConflictRelation(mobileA, mobileB, newRelation, guardCheck)
 +
    if ( newRelation == nil ) then
 +
        LuaDebugCallStack("[Conflict] Nil conflict relation table provided")
 +
        return
 +
    end
 +
    if ( newRelation.Name == nil ) then
 +
        LuaDebugCallStack("[Conflict] Invalid conflict relation table, missing Name")
 +
        return
 +
    end
 +
    if ( mobileA == nil ) then
 +
        LuaDebugCallStack("[Conflict] Nil mobileA provided.")
 +
        return
 +
    end
 +
    if ( mobileB == nil ) then
 +
        LuaDebugCallStack("[Conflict] Nil mobileB provided.")
 +
        return
 +
    end
 +
    local tableA = GetConflictTable(mobileA)
 +
    local wasGuardIgnored = false
 +
    if ( not guardCheck and tableA[mobileB] ~= nil and tableA[mobileB][3] ) then
 +
        wasGuardIgnored = true
 +
    end
 +
    -- set/update the conflict
 +
    local now = DateTime.UtcNow
 +
    tableA[mobileB] = {newRelation.Name}
 +
    -- when the conflict should end
 +
    if ( newRelation.Warning == true ) then
 +
        tableA[mobileB][2] = now + ServerSettings.Conflict.WarningDuration
 +
    else
 +
        tableA[mobileB][2] = now + ServerSettings.Conflict.RelationDuration
 +
    end
 +
    -- cleanse table of any expired.
 +
    for k,v in pairs(tableA) do
 +
        if ( now >= v[2] ) then
 +
            -- it's expired
 +
            tableA[k] = nil
 +
        end
 +
    end
 +
    if ( ConflictEquals(newRelation.Name, ConflictRelations.Aggressor) and
 +
        IsPlayerCharacter(mobileA) and IsPlayerCharacter(mobileB)) then
 +
        -- mobileB has zero karma concequences against mobileA
 +
        -- Turn mobileA AGGRESSIVE on mobileB's client (so B is looking at an aggressive
 +
        A)
 +
        mobileA:SendClientMessage("UpdateMobileConflictStatus",
 +
        {mobileB,"Aggressor",ServerSettings.Conflict.RelationDuration.TotalSeconds})
 +
        mobileB:SendClientMessage("UpdateMobileConflictStatus",
 +
        {mobileA,"Aggressed",ServerSettings.Conflict.RelationDuration.TotalSeconds})
 +
        -- 100
 +
    elseif ( ConflictEquals(newRelation.Name, ConflictRelations.Warning) and
 +
            IsPlayerCharacter(mobileA) and IsPlayerCharacter(mobileB) ) then
 +
        -- mobileA is nearly an aggressor to mobileB
 +
        -- Turn mobileB YELLOW on mobileA's client (so A is looking at a mobile they
 +
            know if they hit again they are an aggressor)
 +
        mobileA:SendClientMessage("UpdateMobileConflictStatus",
 +
        {mobileB,"Warning",ServerSettings.Conflict.WarningDuration.TotalSeconds})
 +
    end
 +
    --[[
 +
        Handle Guard protection triggers for aggressive actions.
 +
    ]]
 +
    -- if mobileA's relation is aggressor
 +
    if ( guardCheck and ConflictEquals(newRelation.Name, ConflictRelations.Aggressor) )
 +
      then
 +
        local karmaBLevel = GetKarmaLevel(GetKarma(mobileB))
 +
        local guardIgnore = true
 +
        -- if mobileB's karma level is guard protected
 +
        if ( karmaBLevel.GuardProtectPlayer or karmaBLevel.GuardProtectNPC ) then
 +
            local isPlayerB = IsPlayerCharacter(mobileB)
 +
            if ( (isPlayerB and karmaBLevel.GuardProtectPlayer)
 +
            or (not isPlayerB and karmaBLevel.GuardProtectNPC) ) then
 +
                -- make the guards protect B from A
 +
                GuardProtect(mobileB, mobileA)
 +
                guardIgnore = false
 +
            end
 +
        end
 +
        -- if guards don't protect mobileB's karma level, add an ignore guard entry
 +
        -- (This is so, for example, players can be aggressors against an outcast, but
 +
          guards won't attack them for being aggressors against outcasts)
 +
        if ( guardIgnore == true ) then
 +
            tableA[mobileB][3] = true
 +
        end
 +
    end
 +
    -- when skipping guard protect this value would be ignored and overwritten if not
 +
      cached from previous data.
 +
    if ( wasGuardIgnored ) then
 +
        tableA[mobileB][3] = true
 +
    end
 +
    -- save the updated conflict table for the mobile
 +
    SetConflictTable(mobileA, tableA)
 +
  end
 +
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| globals\helpers\conflict||
 +
  UpdateConflictRelation(mobileA, mobileB, newRelation, guardCheck)
 +
  AdvanceConflictRelation(mobileA, mobileB, noWarning, karmaAction)
 +
  InheritAggressivePlayerConflicts(playerA, playerB)
 +
|-
 +
|}
 +
 
 +
=== ValidConflictRelationTable ===
 +
''
 +
  --- Validate a conflict relation table (make sure it's not expired)
 +
  -- @param conflictRelationTable(luaTable) A single entry from return value
 +
    GetConflictTable()
 +
  -- @return true if valid, false if not
 +
 
 +
  function ValidConflictRelationTable(conflictRelationTable)
 +
    return (
 +
        conflictRelationTable ~= nil
 +
        and
 +
        (
 +
            -- frozen
 +
            conflictRelationTable[2] == true
 +
            or
 +
            -- or non-expired
 +
            DateTime.UtcNow < conflictRelationTable[2]
 +
        )
 +
    )
 +
  end
 +
''
 +
{| class="wikitable"
 +
|-
 +
! Used In File !! Function Used In
 +
|-
 +
| globals\helpers\conflict||
 +
  ValidConflictRelationTable(conflictRelationTable)
 +
  ForeachAggressor(mobile, callback)
 +
  IsAggressor(mobile, guardIgnore)
 +
  InheritAggressivePlayerConflicts(playerA, playerB)
 +
  InitializeClientConflicts(mobile)
 +
 
 +
|-
 +
|}
 +
 
 +
== Server Settings ==
 +
''
 +
  welcome this will discuss the contents of the globals\server_settings\conflict.lua
 +
  this documentation is correct as of version 6.0 PRECB1 Release
 +
''
 +
''
 +
  ServerSettings.Conflict = {
 +
    -- Do guards attack non-guard protected karma levels who are aggressors?
 +
    GuardsKillAggressors = true,
 +
    -- The duration of the Aggressor/Victim/Defender relation.
 +
    -- These must be locked in the same timespan so we can do reverse checks.
 +
    -- For example: Determine all aggressors by checking who a mobile is a Victim/Defender to.
 +
    RelationDuration = TimeSpan.FromSeconds(100),
 +
    -- Does the first hit count as a warning?
 +
    -- If this is disabled, all hits will immediately jump to aggressor.
 +
    WarningEnabled = true,
 +
    WarningDuration = TimeSpan.FromSeconds(50),
 +
  }
 +
''
 +
=== Conflict Table ===
 +
{| class="wikitable"
 +
|-
 +
! ServerSettings.Conflict Table !! Description
 +
|-
 +
| GuardsKillAggressors || true/false
 +
    -- Do guards attack non-guard protected karma levels who are aggressors?
 +
|-
 +
| RelationDuration || Duration of 100 seconds   
 +
|-
 +
| WarningEnabled || true/false
 +
    -- Does the first hit count as a warning?
 +
    -- If this is disabled, all hits will immediately jump to aggressor.
 +
|-
 +
| WarningDuration || Duration of 50 seconds
 +
|}

Latest revision as of 07:02, 28 January 2018

 welcome this will discuss the contents of the globals\helpers\conflict.lua
 this documentation is correct as of version 6.0 PRECB1 Release 

this documentation was added by Gizmo

ConflictRelations Table

 ConflictRelations = {
   Warning = {
       Name = "Warning",
       Warning = true,
   },
   BeenWarned = {
       Name = "BeenWarned",
       Warning = true,
   },
   Aggressor = {
       Name = "Aggressor",
   },
   Victim = {
       Name = "Victim"
   },
   Defender = {
       Name = "Defender"
   }
 }

Conflict Functions

AdvanceConflictRelation

 -- Advance mobileA against mobileB in conflict, will also refresh any current 
    conflicts between the two.
 -- @param mobileA(mobileObj)
 -- @param mobileB(mobileObj)
 -- @param noWarning(boolean)(optional) if true, warning will be skipped and they will 
    go directly to aggressor
 -- @param karmaAction(luaTable)(optional) KarmaAction that will be executed on mobileA 
    when they become an aggressor. (default: KarmaActions.Negative.Attack) Setting this 
    to false will not execute any karma actions.
 -- @return none
 function AdvanceConflictRelation(mobileA, mobileB, noWarning, karmaAction)
   if not( karmaAction == false ) then
       karmaAction = karmaAction or KarmaActions.Negative.Attack
   end
   -- when Warnings are not enabled, we force noWarning to true.
   if ( ServerSettings.Conflict.WarningEnabled ~= true ) then
       noWarning = true
   end
   -- reassign mobileA and mobileB to pet owners, if applicable
   if ( IsPet(mobileA) ) then
       mobileA = mobileA:GetObjectOwner() or mobileA
   end
   if ( mobileB ~= nil and IsPet(mobileB) ) then
       mobileB = mobileB:GetObjectOwner() or mobileB
   end
   -- conflict don't care what you do to yourself or your pets
   if ( mobileA == mobileB ) then return end
   local aToBRelation = GetConflictRelation(mobileA, mobileB)
   local bToARelation = GetConflictRelation(mobileB, mobileA)
   local refreshA = true
   local refreshB = true
   -- when one side has a relation but the other side does not, we count neither side 
      as having a relation.
   -- this is so we can clear a conflict relation on either side and not need to clear 
      both involved parties (the other involved could be in a different region at time 
      of clearing!)
   if ( noWarning ~= true and (aToBRelation == nil or bToARelation == nil) ) then
       UpdateConflictRelation(mobileA, mobileB, ConflictRelations.Warning)
       UpdateConflictRelation(mobileB, mobileA, ConflictRelations.BeenWarned)
       refreshA = false
   elseif ( (noWarning == true and (aToBRelation == nil or bToARelation == nil))
       or ConflictEquals(aToBRelation, ConflictRelations.Warning) ) then
       -- A becomes aggressor, B becomes victim.
       UpdateConflictRelation(mobileA, mobileB, ConflictRelations.Aggressor, true)
       UpdateConflictRelation(mobileB, mobileA, ConflictRelations.Victim)
       refreshA = false
       refreshB = false
       -- Karma action for becoming the aggressor
       if ( karmaAction ) then
           ExecuteKarmaAction(mobileA, karmaAction, mobileB)
       end
       if ( IsInitiate(mobileB) and IsPlayerCharacter(mobileA) ) then 
           EndInitiate(mobileB) 
       end
       elseif ( ConflictEquals(aToBRelation, ConflictRelations.Victim) ) then
       -- A was a victim, now A is a defender.
       UpdateConflictRelation(mobileA, mobileB, ConflictRelations.Defender)
       refreshA = false
   end
   --refresh the conflict expiration.
   -- Possible optimization, only refresh every other one/every third one?
   if ( aToBRelation ~= nil and refreshA ) then
       if ( karmaAction and ConflictEquals(aToBRelation, ConflictRelations.Aggressor) ) 
         then
           ExecuteKarmaAction(mobileA, karmaAction, mobileB)
       end
       UpdateConflictRelation(mobileA, mobileB, ConflictRelations[aToBRelation], true)
   end
   if ( bToARelation ~= nil and refreshB ) then
       UpdateConflictRelation(mobileB, mobileA, ConflictRelations[bToARelation])
   end
 end

Used In File Function Used In
base_mobile HandleApplyDamage(damager, damageAmount, damageType, isCrit, wasBlocked)
globals\helpers\karma CheckKarmaLoot(player, container)

ClearConflictTable

 -- Clear the conflict table of a mobile
 -- @param mobile(mobileObj)
 -- @return none
 function ClearConflictTable(mobile, isPlayer)
   if ( mobile == nil or not mobile ) then
       LuaDebugCallStack("[Conflict] Invalid mobile provided.")
       return
   end
   if ( mobile:HasObjVar("Conflicts") ) then
       mobile:DelObjVar("Conflicts")
   end
   if ( isPlayer == true ) then
       InitializeClientConflicts(mobile)
   end
 end

Used In File Function Used In
base_mobile DoResurrect(statPct, resurrector, force)
base_player_death RegisterEventHandler(EventType.CreatedObject, "created_corpse", function (success, objRef)

ConflictEquals

 -- Convenience function to make checking conflicts more readable
 -- @param strRelation(string) The string Name of the relation to check for
 -- @param tableRelation(luaTable) The ConflictRelations entry to check against
 -- @return true or false
 function ConflictEquals(strRelation, tableRelation)
   return ( strRelation == tableRelation.Name )
 end

Used In File Function Used In
globals\helpers\conflict
   UpdateConflictRelation(mobileA, mobileB, newRelation, guardCheck)
   ConflictEquals(strRelation, tableRelation)
   AdvanceConflictRelation(mobileA, mobileB, noWarning, karmaAction)
   ForeachAggressor(mobile, callback)
   IsAggressor(mobile, guardIgnore)
   InheritAggressivePlayerConflicts(playerA, playerB)
   InitializeClientConflicts(mobile) 
globals\helpers\karma ExecuteKarmaAction(mobileA, action, mobileB)

ForeachAggressor

 -- Perform a function on each aggressor of a mobile
 -- @param mobile(mobileObj)
 -- @param callback(function(id))
 -- @return none
 function ForeachAggressor(mobile, callback)
   local conflictTable = GetConflictTable(mobile)
   for mobileB,relation in pairs(conflictTable) do
       if ( mobileB:IsValid() ) then
           if (( ConflictEquals(relation[1], ConflictRelations.Victim) or ConflictEquals(relation[1], ConflictRelations.Defender )) and ValidConflictRelationTable(relation)) then
               if ( ConflictEquals(GetConflictRelation(mobileB, mobile), ConflictRelations.Aggressor) ) then
                   callback(mobileB)
               end
           end
       end
   end
 end

Used In File Function Used In
globals/helpers/karma KarmaPunishAllAggressorsForMurder(victim)

FreezeConflictTable

 --- Freeze the conflict table on a mobile, optionally saving the frozen table on a 
 different object. Will clear all conflicts for the mobile if target does not equal 
 mobile.
 -- @param mobile(mobileObj)
 -- @param target(gameObj)(optional) the gameObj the conflict table will be saved to
 -- @return none
 function FreezeConflictTable(mobile, target)
   target = target or mobile
   local conflictTable = GetConflictTable(mobile)
   for mobileId,conflict in pairs(conflictTable) do
       -- set all the expires to true, meaning they never expire
       conflictTable[mobileId][2] = true
   end
   -- save the frozen table on the target
   SetConflictTable(target, conflictTable)
 end

Used In File Function Used In
base_mobile DoMobileDeath(damager)
base_player_death RegisterEventHandler(EventType.CreatedObject, "created_corpse", function (success, objRef)

GetConflictRelation

 -- Get the relation of conflict mobileA is to mobileB.
 -- @param mobileA(mobileObj)
 -- @param mobileB(mobileObj)
 -- @param mobileAConflictTable(optional) return value from GetConflictTable()
 -- @return One of ConflictRelations, nil if not-found/expired.
 function GetConflictRelation(mobileA, mobileB, mobileAConflictTable)
   mobileAConflictTable = mobileAConflictTable or GetConflictTable(mobileA) or {}
   -- only valid, frozen/non-expired, will make the cut.
   if ( ValidConflictRelationTable(mobileAConflictTable[mobileB]) ) then
       return mobileAConflictTable[mobileB][1]
   end
   return nil
 end

Used In File Function Used In
globals\helpers\conflict
 GetConflictRelation(mobileA, mobileB, mobileAConflictTable)
 AdvanceConflictRelation(mobileA, mobileB, noWarning, karmaAction)
 ForeachAggressor(mobile, callback)
 IsAggressor(mobile, guardIgnore)
 InheritAggressivePlayerConflicts(playerA, playerB)
 InitializeClientConflicts(mobile)
globals\helpers\karma RegisterEventHandler(EventType.CreatedObject, "created_corpse", function (success, objRef)

GetConflictTable

 -- Get the conflict table for a mobile
 -- @param mobile(mobileObj)
 -- @return luaTable containing all conflicts for this mobile
 function GetConflictTable(mobile)
   if ( mobile == nil or not mobile ) then
       LuaDebugCallStack("[Conflict] Invalid mobile provided.")
       return {}
   end
   return mobile:GetObjVar("Conflicts") or {}
 end

Used In File Function Used In
globals/helpers/conflict This is used as a tool throughout the conflict file. You will find it used in the FreezContactTable, ValidConflictRelationTable, ForeachAggressor, IsAggressor, InheritAggressivePlayerConflicts and InitializeClientConflicts functions.

GetNearbyTaggedMobiles

 -- Get all mobiles that are tagged to a mobile and are also nearby
 -- @param mobile
 -- @return list of nearby mobiles (luaArray)
 function GetNearbyTaggedMobiles(mobile)
   local validMobiles = {}
   if ( mobile ) then
       local taggedMobiles = mobile:GetObjVar("Tag") or {}
       local loc = mobile:GetLoc()
       for id,val in pairs(taggedMobiles) do
           local obj = GameObj(id)
           if ( obj ~= nil and obj:IsValid() and obj:GetLoc():Distance(loc) <= ServerSettings.Misc.GroupAutolootRange ) then
               table.insert(validMobiles, obj)
           end
       end
   end
   return validMobiles
 end

Used In File Function Used In
globals\mobile_extensions_misc HandleMobileDeathRewards(victim, karmaLevel)

InheritAggressivePlayerConflicts

 
 -- Inherit Aggressor/Defender conflict relations from playerA onto playerB, DOES NOT ENFORCE IsPlayerCharacter()
 -- @param playerA(playerObj) The player whos conflicts are being inherited
 -- @param playerB(playerObj) The player who is inheriting the conflicts
 -- @return none
 function InheritAggressivePlayerConflicts(playerA, playerB)
   if ( playerA == playerB ) then return end
   local conflictsA = GetConflictTable(playerA)
   -- loop all of playerA's conflicts
   for mobileC,aToCRelationTable in pairs(conflictsA) do
       if ( mobileC ~= playerB and mobileC:IsValid() ) then
           -- using this variable to keep the if nesting from going too deep
           local keepgoing = false
           -- if A to C is aggressor
           if ( 
               ConflictEquals(aToCRelationTable[1], ConflictRelations.Aggressor)
               and
               ValidConflictRelationTable(aToCRelationTable)
           ) then
               local cToARelation = GetConflictRelation(mobileC, playerA)
               -- and C to A is Victim/Defender
               if ( 
                   cToARelation ~= nil
                   and
                   (
                       ConflictEquals(cToARelation, ConflictRelations.Victim)
                       or
                       ConflictEquals(cToARelation, ConflictRelations.Defender)
                   )
               ) then
                   keepgoing = true
               end
           end
           if ( keepgoing ) then
               local alreadyAggressive = false
               local bToCRelation = GetConflictRelation(playerB, mobileC)
               -- if B to C is aggressor
               if (
                   bToCRelation ~= nil
                   and
                   ConflictEquals(bToCRelation, ConflictRelations.Aggressor)
               ) then
                   local cToBRelation = GetConflictRelation(mobileC, playerB)
                   -- and C to B is Victim/Defender
                   if ( 
                       cToBRelation ~= nil
                       and
                       (
                           ConflictEquals(cToBRelation, ConflictRelations.Victim)
                           or
                           ConflictEquals(cToBRelation, ConflictRelations.Defender)
                       )
                   ) then
                       alreadyAggressive = true
                   end
               end
               if ( alreadyAggressive ) then
                   -- refresh it
                   UpdateConflictRelation(playerB, mobileC, conflictsB[mobileC], true)
                   UpdateConflictRelation(mobileC, playerB, cRelationTable[mobileB])
               else -- otherwise
                   -- inherit it.
                   -- set playerB's relation: aggressor to mobileC.
                   UpdateConflictRelation(playerB, mobileC, ConflictRelations.Aggressor, true)
                   -- and set mobileC's relation: victim to playerB
                   UpdateConflictRelation(mobileC, playerB, ConflictRelations.Victim)
               end
           end
       end
   end
 end

Used In File Function Used In
globals\helpers\conflict InheritAggressivePlayerConflicts(playerA, playerB)
globals\helpers\karma CheckKarmaBeneficialAction(player, mobileB)

InitializeClientConflicts

 -- Refresh the client with conflict status on login/region change
 -- @param mobile
 function InitializeClientConflicts(mobile)  
   local conflictTable = GetConflictTable(mobile)
   for mobileB,relation in pairs(conflictTable) do
       if ( mobileB:IsValid() ) then -- if the mobile is in same region currently.
           local bToARelation = GetConflictRelation(mobileB, mobile) -- if they have a valid relation with us
           if ( bToARelation ~= nil ) then
               if ((
                       ConflictEquals(relation[1], ConflictRelations.Victim) 
                       or
                       ConflictEquals(relation[1], ConflictRelations.Defender)
                   )
                   and
                   ConflictEquals(bToARelation, ConflictRelations.Aggressor)
                   and
                   ValidConflictRelationTable(relation)
               ) then
                   local timeRemaining = relation[2] - DateTime.UtcNow
                   mobile:SendClientMessage("UpdateMobileConflictStatus",{mobileB,"Aggressed",timeRemaining.TotalSeconds})
                   if ( IsPlayerCharacter(mobileB) ) then
                       mobileB:SendClientMessage("UpdateMobileConflictStatus",{mobile,"Aggressor",timeRemaining.TotalSeconds})
                   end
               elseif( 
                   ConflictEquals(relation[1], ConflictRelations.Aggressor)
                   and
                   (
                       ConflictEquals(bToARelation, ConflictRelations.Victim) 
                       or
                       ConflictEquals(bToARelation, ConflictRelations.Defender)
                   )
                   and
                   ValidConflictRelationTable(relation)
               ) then 
                   local timeRemaining = relation[2] - DateTime.UtcNow
                   mobile:SendClientMessage("UpdateMobileConflictStatus",{mobileB,"Aggressor",timeRemaining.TotalSeconds})
                   if ( IsPlayerCharacter(mobileB) ) then
                       mobileB:SendClientMessage("UpdateMobileConflictStatus",{mobile,"Aggressed",timeRemaining.TotalSeconds})
                   end
               elseif( 
                   ConflictEquals(relation[1], ConflictRelations.Warning)
                   and
                   ConflictEquals(bToARelation, ConflictRelations.BeenWarned)
                   and
                   ValidConflictRelationTable(relation)
               ) then
                   local timeRemaining = relation[2] - DateTime.UtcNow
                   mobile:SendClientMessage("UpdateMobileConflictStatus",{mobileB,"Warning",timeRemaining.TotalSeconds})
               end
           end
       end
   end
 end

Used In File Function Used In
globals\helpers\conflict
 InitializeClientConflicts(mobile)
 ClearConflictTable(mobile, isPlayer)
player CallFunctionDelayed(TimeSpan.FromSeconds(0.5),

IsAggressor

 --- Determine if a mobile is an aggressor
 -- @param mobile(mobileObj)
 -- @param guardIgnore(boolean)(optional) if true, ignore any relation that's tagged guard ignore. (this is so guards ignore when someone is an aggressor against an outcast for example)
 -- @return true if mobile is an aggressor
 function IsAggressor(mobile, guardIgnore)
   for mobileB,conflict in pairs(GetConflictTable(mobile)) do
       if ( 
           guardIgnore ~= true or 
           (guardIgnore == true) and 
           conflict[3] ~= true and 
           ConflictEquals(conflict[1], ConflictRelations.Aggressor) and 
           ValidConflictRelationTable(conflict)
          ) then
           if ( mobileB:IsValid() ) then
               local bToARelation = GetConflictRelation(mobileB, mobile)
               if ( bToARelation ~= nil ) then
                   if ( ConflictEquals(bToARelation, ConflictRelations.Victim) or ConflictEquals(bToARelation, ConflictRelations.Defender) ) then return true end
               end
           end
       end
   end
   return false
 end

Used In File Function Used In
ai_guard IsEnemy(targetObj)
ai_super_guard IsEnemy(targetObj)
globals\helpers\conflict IsAggressor(mobile, guardIgnore)
player UpdateFactions() *note: the code is commented out though
sp_resurrect_effect HandleLoaded() *note: the code is commented out though

IsMobTaggedBy

 -- Check to see if a mobile(npc) is tagged by a player
 -- @param mobile(mobileObj) DOES NOT force this to be an NPC ( but it should be )
 -- @param player(playerObj) DOES NOT force this to be an Player ( but it should be )
 -- @return true or false or nil (nil if the mobile had no conflicts)
 function IsMobTaggedBy(mobile, player)
   local tag = mobile:GetObjVar("Tag") or {}
   return ( player ~= nil and tag[player.Id] == true )
 end

Used In File Function Used In
globals\helpers\conflict IsMobTaggedBy(mobile, player)
globals\helpers\karma CheckKarmaLoot(player, container)

SetConflictTable

 -- Set the conflict table for a mobile
 -- @param mobile(mobileObj)
 -- @param data(luaTable)
 -- @return none
 function SetConflictTable(mobile, data)
   mobile:SetObjVar("Conflicts", data)
 end

Used In File Function Used In
globals\helpers\conflict
 SetConflictTable(mobile, data)
 FreezeConflictTable(mobile, target)
 UpdateConflictRelation(mobileA, mobileB, newRelation, guardCheck)

TagMob

 -- Uses the damage list to determine what Single Player/Collective Group did the most damage and sets the ObjVar Tag with the mobiles that fit the bill
 -- @param mobile(mobileObj) the NPC that has died
 function TagMob(mobile)
   local damagers = mobile:GetObjVar("Damagers")
   if ( damagers ~= nil ) then
       -- get a list of all groups/solos involved in all the damage
       local groups = {}
       local solos = {}
       for damager,data in pairs(damagers) do
           if ( damager ~= nil and damager:IsValid() ) then
               local gid = damager:GetObjVar("Group")
               if ( gid ~= nil ) then
                   if ( groups[gid] == nil ) then groups[gid] = {} end
                   table.insert(groups[gid], {damager,data.Amount})
               else
                   -- we have to set it as damager.Id because guilds keep track of members by their Id
                   table.insert(solos, {damager.Id,data.Amount})
               end
           end
       end
       -- calculate the damage for each group
       local groupsDamage = {}
       for gid,data in pairs(groups) do
           for i,d in pairs(groups[gid]) do
               if ( groupsDamage[gid] == nil ) then groupsDamage[gid] = 0 end
               groupsDamage[gid] = groupsDamage[gid] + d[2]
           end
       end
       -- finally determine who's the winner
       local most = {nil,0}
       -- first check solos
       for mobileId,data in pairs(solos) do
           if ( data[2] > most[2] ) then
               most = data
           end
       end
       local isGroup = false
       -- then check collective groups
       for gid,amount in pairs(groupsDamage) do
           if ( amount > most[2] ) then
               most = {gid,amount}
               -- solos were checked first
               isGroup = true
           end
       end
       local tag = {}
       if ( isGroup ) then
           -- add every mobile in the group that won
           local groupRecord = GetGroupRecord(most[1]) or {}
           groupRecord.Members = groupRecord.Members or {}
           for id,data in pairs(groupRecord.Members) do
               tag[id] = true
           end
       else
           -- add the solo mobile that won
           tag[most[1]] = true
       end
       mobile:SetObjVar("Tag", tag)
   end
 end

Used In File Function Used In
base_mobile DoMobileDeath(damager)
globals\helpers\conflict TagMob(mobile)

UpdateConflictRelation

 -- Update the conflict relation between two mobiles, also cleans mobileA's conflict 
    table of any expired.
 -- @param mobileA(mobileObj)
 -- @param mobileB(mobileObj)
 -- @param newRelation(luaTable) the entry from ConflictRelations
 -- @param guardCheck(boolean) If true, this update will check for guard protection, 
     this way you can refresh a conflict on both sides but only one will cares about 
     guards.
 -- @return none
 function UpdateConflictRelation(mobileA, mobileB, newRelation, guardCheck)
   if ( newRelation == nil ) then
       LuaDebugCallStack("[Conflict] Nil conflict relation table provided")
       return
   end
   if ( newRelation.Name == nil ) then
       LuaDebugCallStack("[Conflict] Invalid conflict relation table, missing Name")
       return
   end
   if ( mobileA == nil ) then
       LuaDebugCallStack("[Conflict] Nil mobileA provided.")
       return
   end
   if ( mobileB == nil ) then
       LuaDebugCallStack("[Conflict] Nil mobileB provided.")
       return
   end
   local tableA = GetConflictTable(mobileA)
   local wasGuardIgnored = false
   if ( not guardCheck and tableA[mobileB] ~= nil and tableA[mobileB][3] ) then
       wasGuardIgnored = true
   end
   -- set/update the conflict
   local now = DateTime.UtcNow
   tableA[mobileB] = {newRelation.Name}
   -- when the conflict should end
   if ( newRelation.Warning == true ) then
       tableA[mobileB][2] = now + ServerSettings.Conflict.WarningDuration
   else
       tableA[mobileB][2] = now + ServerSettings.Conflict.RelationDuration
   end
   -- cleanse table of any expired.
   for k,v in pairs(tableA) do
       if ( now >= v[2] ) then
           -- it's expired
           tableA[k] = nil
       end
   end
   if ( ConflictEquals(newRelation.Name, ConflictRelations.Aggressor) and 
        IsPlayerCharacter(mobileA) and IsPlayerCharacter(mobileB)) then
       -- mobileB has zero karma concequences against mobileA
       -- Turn mobileA AGGRESSIVE on mobileB's client (so B is looking at an aggressive 
       A)
       mobileA:SendClientMessage("UpdateMobileConflictStatus",
       {mobileB,"Aggressor",ServerSettings.Conflict.RelationDuration.TotalSeconds})
       mobileB:SendClientMessage("UpdateMobileConflictStatus",
       {mobileA,"Aggressed",ServerSettings.Conflict.RelationDuration.TotalSeconds})
       -- 100
   elseif ( ConflictEquals(newRelation.Name, ConflictRelations.Warning) and 
            IsPlayerCharacter(mobileA) and IsPlayerCharacter(mobileB) ) then
       -- mobileA is nearly an aggressor to mobileB
       -- Turn mobileB YELLOW on mobileA's client (so A is looking at a mobile they 
           know if they hit again they are an aggressor)
       mobileA:SendClientMessage("UpdateMobileConflictStatus",
       {mobileB,"Warning",ServerSettings.Conflict.WarningDuration.TotalSeconds})
   end
   --[[
       Handle Guard protection triggers for aggressive actions.
   ]]
   -- if mobileA's relation is aggressor
   if ( guardCheck and ConflictEquals(newRelation.Name, ConflictRelations.Aggressor) ) 
     then
       local karmaBLevel = GetKarmaLevel(GetKarma(mobileB))
       local guardIgnore = true
       -- if mobileB's karma level is guard protected
       if ( karmaBLevel.GuardProtectPlayer or karmaBLevel.GuardProtectNPC ) then
           local isPlayerB = IsPlayerCharacter(mobileB)
           if ( (isPlayerB and karmaBLevel.GuardProtectPlayer)
           or (not isPlayerB and karmaBLevel.GuardProtectNPC) ) then
               -- make the guards protect B from A
               GuardProtect(mobileB, mobileA)
               guardIgnore = false
           end
       end
       -- if guards don't protect mobileB's karma level, add an ignore guard entry
       -- (This is so, for example, players can be aggressors against an outcast, but 
          guards won't attack them for being aggressors against outcasts)
       if ( guardIgnore == true ) then
           tableA[mobileB][3] = true
       end
   end
   -- when skipping guard protect this value would be ignored and overwritten if not 
      cached from previous data.
   if ( wasGuardIgnored ) then
       tableA[mobileB][3] = true
   end
   -- save the updated conflict table for the mobile
   SetConflictTable(mobileA, tableA)
 end

Used In File Function Used In
globals\helpers\conflict
 UpdateConflictRelation(mobileA, mobileB, newRelation, guardCheck)
 AdvanceConflictRelation(mobileA, mobileB, noWarning, karmaAction)
 InheritAggressivePlayerConflicts(playerA, playerB)

ValidConflictRelationTable

 --- Validate a conflict relation table (make sure it's not expired)
 -- @param conflictRelationTable(luaTable) A single entry from return value 
    GetConflictTable()
 -- @return true if valid, false if not
 function ValidConflictRelationTable(conflictRelationTable)
   return (
       conflictRelationTable ~= nil
       and
       (
           -- frozen
           conflictRelationTable[2] == true
           or
           -- or non-expired
           DateTime.UtcNow < conflictRelationTable[2]
       )
   )
 end

Used In File Function Used In
globals\helpers\conflict
 ValidConflictRelationTable(conflictRelationTable)
 ForeachAggressor(mobile, callback)
 IsAggressor(mobile, guardIgnore)
 InheritAggressivePlayerConflicts(playerA, playerB)
 InitializeClientConflicts(mobile)
 

Server Settings

 welcome this will discuss the contents of the globals\server_settings\conflict.lua
 this documentation is correct as of version 6.0 PRECB1 Release 

 ServerSettings.Conflict = {
   -- Do guards attack non-guard protected karma levels who are aggressors?
   GuardsKillAggressors = true,
   -- The duration of the Aggressor/Victim/Defender relation. 
   -- These must be locked in the same timespan so we can do reverse checks. 
   -- For example: Determine all aggressors by checking who a mobile is a Victim/Defender to.
   RelationDuration = TimeSpan.FromSeconds(100),
   -- Does the first hit count as a warning? 
   -- If this is disabled, all hits will immediately jump to aggressor.
   WarningEnabled = true,
   WarningDuration = TimeSpan.FromSeconds(50),
 }

Conflict Table

ServerSettings.Conflict Table Description
GuardsKillAggressors true/false
   -- Do guards attack non-guard protected karma levels who are aggressors?
RelationDuration Duration of 100 seconds
WarningEnabled true/false
   -- Does the first hit count as a warning? 
   -- If this is disabled, all hits will immediately jump to aggressor.
WarningDuration Duration of 50 seconds