Difference between revisions of "ConflictSystem"

From Legends of Aria Admin and Modding Wiki
Jump to: navigation, search
(IsAggressor)
(AdvanceConflictRelation)
Line 245: Line 245:
 
   function ConflictEquals(strRelation, tableRelation)
 
   function ConflictEquals(strRelation, tableRelation)
 
     return ( strRelation == tableRelation.Name )
 
     return ( strRelation == tableRelation.Name )
  end
 
''
 
 
=== 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
 
   end
 
''
 
''

Revision as of 08:31, 27 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 

ConflictRelations Table

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

Conflict Functions

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

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

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

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

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

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

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

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

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

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

IsMobTaggedBy

TagMob

InheritAggressivePlayerConflicts

GetNearbyTaggedMobiles

InitializeClientConflicts