Fantasy Grounds Fridays Pre
View RSS Feed

Minty23185Fresh

A Neophyte Tackles the FG Extension - Lua Behind the Visibility Options

Rate this Entry
In a previous post I detailed how I added additional effect visibility button options to the Combat TrackerĎs GUI. This time Iíll step through the process of adding the Lua to make those button options functional.

Detour: This is post 18 in this series. I hope that by now, as a neo-developer, you have the confidence to do many things without the detailed instruction I have provided in the past. Iíll explain concept and intent but I wonít detail some of the more mundane code.

Setup: I started with a fresh, unzipped copy of the 5E ruleset. I created a new campaign. In the host I imported a couple PCs: Krystryd and a Paladin (in that order). I joined the game as Client1 and selected the Paladin as the clientís PC. I joined the game again as Client2 and picked Krystryd. I opened the Combat Tracker in the GMís instance and added actors in the following order: an Orc, Krystryd, a Kobold, Paladin, and a Goblin. I made all actors visible. I opened the Effects Manager (EM) then used it or the PCís Actions to apply the following effects: the Orc frightened (EM) the Paladin, Krystryd poisoned (EM) the Goblin and paralyzed (EM) the Orc, the Paladin applied (client Action) Aura of Courage to Krystryd and Aura of Warding to self. Finally I set the effect visibility options as shown here:
15a - All CTs Initial.png
Note the following in the Combat Trackers: (1) The GMís (left panel) displays all effects as desired. (2) The Goblinís poisoned effect, does not show up in either the Paladinís (upper right) nor Krystrydís (lower right). (3) All other effects show up in both clients.

There are four button options, two of which behave appropriately, but Iíll have to address the Self option and the Target option in the clientís Combat Tracker.

Recall from previous work, the ct_host.xml file in the 5E\ct subfolder. There is also a ct_client.xml file. I started there. There are two windowclasses, one for the whole Combat Tracker and one for each list entry. I perused the <sheetdata> of the list entry, it was easy to reconcile the one-to-one correspondence to what is seen on screen. ďstring_ctentry_effectsĒ must be the control that displays the effects. I searched for a template and found it in the Coreís template_ct.xml file. Which led me to the ct_effect_summary.lua file also in the Core. One of its functions points to the familiar EffectManager.getEffectsString(). Recall that I used a ďforwardingĒ function for it. I put Debug statements in getEffectsString() in both the 5E and the extension manager_effect.lua files. I closed all instances of FG and restarted the host. Sure enough getEffectsString() in the 5E ruleset was called multiple times, but surprisingly, the one in the extension was never called.

A dilemma: should I chase down why the extension code is not being utilized, or work on modifying when the effects are displayed? The latter is the point of the current exercise, so Iíll do the development in the ruleset for now then move it to the extension and deal with the other issue later. After all, I might not even be in the right code yet!

Now to cursorily ascertain what the getEffectsString() function does: The first five or so lines create a ďtableĒ of nodes from the DB and sort it. Each table item is then operated on in a for loop that takes up the rest of the function. Within the for loop, some variables are set that are used in decision making further along. Then depending on the value of the variable bAddEffect, some string construction occurs.

I tried to change the display of the effects strings by changing the value of bAddEffect. I forced it to be false, just before it was tested (~line102, FG v3.1.7):
Code:
      bAddEffect = false;
      if bAddEffect then
I saved, restarted, brought up the host and clients; the effects strings were gone! But in the host, when I clicked the Effects button, I saw the effects were still present, the summary strings just werenít displayed.

I was in the right place! (I removed my negation statement.)

The following code took hours to develop. I constantly referred to the DB page of the XML and Scripting Reference. Numerous times I viewed the campaignĎs db.xml file and inserted Debug statements to confirm variable values.

A word about getEffectsString(): This function is called for every running instance of FG, and for every actor in the Combat Tracker. I had a console up for each instance, I observed the function being called 5 times in each instance, processing each of the 5 effects.

The decision tree: (1) Depending on certain criteria, e.g. what FG instance is being operated on, what the visibility buttonís value is, etc., the code will need to force bAddEffectís value to be false. (2) The effects strings in the host instance are always displayed, so further decisions need only be processed if the current instance is not the host. (3) Visibility button values of 0 (All), or 1 (GM), do not need to be processed. Only values of 2 (Self) or 3 (Target) need to be addressed. This leads to a base decision tree of:
Code:
  if User.isHost() == false then
    local nVisibility = DB.getValue(v, "isgmonly", 0);
    if nVisibility == 2 then

    elseif nVisibility == 3 then

    end
  end
The decision process for Self: Only display the effects string if the current instance is the same as the actor possessing the effect. Within the DB, the effect has a property that lists the character sheet id (i.e. which PC is afflicted). The decision specific to case 2 becomes:
Code:
    if nVisibility == 2 then
      local sUser = User.getCurrentIdentity();
      local sCharSheetID = DB.getValue(DB.getValue(nodeCTEntry, "link"));
      if sCharSheetID ~= "charsheet." .. sUser then
        bAddEffect = false;
      end
    else Ö
The decision process for Target: Display the effects string as above for Self or display it if the inflictor of the effect is the same as the instance. Again within the DB, there is a property that lists the source or inflictor. Note that Iíve stated when to display the string, not when not to. Fortunately there is a ďmathĒ that will help me write the code.

Detour: Boolean Algebra is the ďmathĒ of true and false. For example, if one ORs something true with something false the result is always true. If one ANDs something true with something false the result is always false. What I have above is, if Self is true OR inflictor is true then display is true. A Boolean Algebra axiom states that if one negates each of the arguments and changes the operation (e.g. OR becomes AND) then the result is negated. In my case, if Self is false AND inflictor is false then donít display.

Code:
    elseif nVisibility == 3 then
      local sUser = User.getCurrentIdentity();
      local sCharSheetID = DB.getValue(DB.getValue(nodeCTEntry, "link"));
      local nodeCTSource = DB.findNode(sSource);
      local sInflictorID = DB.getValue(DB.getValue(nodeCTSource, "link"));
      if (sCharSheetID ~= "charsheet." .. sUser) and (sInflictorID ~= "charsheet." .. sUser) then
          bAddEffect = false;
        end
      end
    end
Note that within the whole tree, there are duplicated statements for sUser and sCharSheetID, so I refactored the code. I also split the if statement, containing the and operation, into two statements and nested the nodeCTSource and sInflictorID evaluations between them. These variable resolutions donít need to be done if the first part of the if statement fails. (This blog post is running long so I am not displaying the code here. Iíll put the refactored code in a comment attached to the blog.)

Bad News & Good News: As mentioned earlier in this post the getEffectsString() function in the extension was not being called. I tried to determine why and how to fix it. I copied quite a bit of code into the extension from both the Core and 5E rulesets without success. It appears as though it is some sort of interplay as code is loaded, parsed and executed from the various sources. As a last resort I posted a question in the FG Forums. To say the answer by Moon Wizard was inspiring, does not do him justice.

I employed the methodology brought to light in the forum thread. I discarded the manager_effect.lua and manager_effect_maker.lua files and replaced them with a manager_effect_boss.lua file. I copied the two functions, getEffectsString() and addEffect() from the 5E manager_effect.lua file to my ďbossĒ file, renamed them, and added my functionality into them. Here is what the ďbossĒ file contains (abbreviated):
Code:
function onInit()
  -- supplant the getEffectsString() functionality 
  EffectManager.getEffectsString = Ext_getEffectsString;
  -- supplant the addEffect() functionality
  EffectManager.addEffect = Ext_addEffect;
end

function Ext_getEffectsString(nodeCTEntry, bPublicOnly)
  -- override the functionality of the EffectManager's
  -- getEffectsString() function with that of this function
  . . . . .
end

function Ext_addEffect(sUser, sIdentity, nodeCT, rNewEffect, bShowMsg, sEffectTargetNode)
  -- override the functionality of the EffectManager's
  -- addEffect() function with that of this function
  . . . . .
end
Obviously the <base> in my extension.xml file changed too:
Code:
  <base>
    <includefile source="strings/strings_5e.xml" />
    <includefile source="ct/ct_host.xml" /> 

    <script name="SuperviseEffectManager" file="scripts/manager_effect_boss.lua" />
  </base>
Thatís it! Done. Note the effects in this screenshot:
15b -All CTs Final.png

(PLEASE VIEW COMMENTS BELOW.)

Until next time keep on role playing.

Submit "A Neophyte Tackles the FG Extension - Lua Behind the Visibility Options" to Digg Submit "A Neophyte Tackles the FG Extension - Lua Behind the Visibility Options" to del.icio.us Submit "A Neophyte Tackles the FG Extension - Lua Behind the Visibility Options" to StumbleUpon Submit "A Neophyte Tackles the FG Extension - Lua Behind the Visibility Options" to Google Submit "A Neophyte Tackles the FG Extension - Lua Behind the Visibility Options" to Facebook Submit "A Neophyte Tackles the FG Extension - Lua Behind the Visibility Options" to Twitter

Updated July 9th, 2016 at 04:52 by Minty23185Fresh

Categories
Uncategorized

Comments

  1. Minty23185Fresh's Avatar
    Here is the complete refactored code of the decision tree in the getEffectsString() function, as mentioned in the main body of the blog.

    Code:
          -- GM (or Host) sees all effects, so if the User is not Host then
          -- as needed negate the bAddEffect value so the effect doesn't show up
          if User.isHost() == false then
            -- possible values of the visibility button are: 0-All, 1-GM, 2-Self, 3-Target
            local nVisibility = DB.getValue(v, "isgmonly", 0);
            -- user is the FG user or instance ID, and the same as the character sheet id
            local sUser = User.getCurrentIdentity();
            -- combat tracker ids are not equivalent to character sheet ids,
            -- this id, is the character sheet id, for this combat tracker id (or actor)
            local sCharSheetID = DB.getValue(DB.getValue(nodeCTEntry, "link"));
            if nVisibility == 2 then
              -- effects visible to self link back to themselves in charsheet
              if sCharSheetID ~= "charsheet." .. sUser then
                bAddEffect = false;
              end
            elseif nVisibility == 3 then
              -- effects with target visibility should not be displayed
              -- if the entry is not me and if the entry is not the inflictor (e.g. source)
              if sCharSheetID ~= "charsheet." .. sUser then
                -- source_names are effect inflictors, the combat tracker id's (empty for Self)
                local nodeCTSource = DB.findNode(DB.getValue(v, "source_name", ""));
                local sInflictorID = DB.getValue(DB.getValue(nodeCTSource, "link"));
                if sInflictorID ~= "charsheet." .. sUser then
                  bAddEffect = false;
                end
              end
            end
          end
    Updated July 9th, 2016 at 04:41 by Minty23185Fresh
  2. Minty23185Fresh's Avatar
    The extension has been play tested for about 3-1/2 hours. I released it in the Fantasy Grounds forums. Should you want to view the final renditions of all the extension’s files, download the extension, and unpack it, same as with rulesets, as I’ve explained in previous blog posts.

    This has been a truly delightful, albeit time-consuming, learning process. I cannot shower enough praise upon the Smiteworks developers and the FG Forums moderators, responders and lurkers . When I started this I would have never believed I could add so much functionality with so little code (four tiny files, in all). A real tribute to the overall design of FG!

    I do plan on continuing to blog, though I suppose, not as a neophyte. Acolyte maybe?

    To the followers of this lengthy blog series, Thanks for staying with me.
    Updated July 9th, 2016 at 04:47 by Minty23185Fresh
Joshua Stream Pre

Log in

Log in