Starfinder Playlist
Page 1 of 3 123 Last
  1. #1
    Insanity's Avatar
    Join Date
    Mar 2007
    Location
    Terra, Sol system
    Posts
    198

    xml/script math questions

    I've completed my character sheets for my ruleset for the most part, the only challenge I've had is some math with ability bonuses and such. The d20 default uses the following script, which is in the charsheet_templates.xml, for calculating ability bonuses.
    Code:
    			<script>
    				function onSourceUpdate()
    					setValue(math.floor((sources[scorefield[1]].getValue() - sources[damagefield[1]].getValue() - 10) / 2) + getModifier());
    				end
    
    				function onInit()
    					addSource(scorefield[1]);
    					addSource(damagefield[1]);
    
    					super.onInit();
    				end
    			</script>
    d20 D&D ability bonus is easy, Ability Score - 10 divide by 2.

    With my ruleset it is not that simple. A vital statistic (ability) can have several bonuses or related values.
    Here is a screenshot of the main charsheet to illustrate what I mean...


    i.e. Strength has three encumbrance scores, damage bonus, skill bonus; IQ has Power Points, Max Lang, skill bonus. The skill bonus from Strength will not necessarily equal the skill bonus from IQ of the same score. A Strength of 100 will not give the same skill bonus as a IQ score of 100. Vital stats can range from 1 to 150.

    I thought the best way to handle this is with a lot of if x=>1, but <=20, y=5 type functions, but do not know enough about the math scripting to describe this.

    Any assistance is appreciated...

  2. #2

    Join Date
    Feb 2006
    Location
    Fairfax County, Virginia
    Posts
    499
    Did you arrive at your ruleset by modifying the d20 ruleset, or did you start from scratch? If you're using the d20 ruleset as a basis, you can define the fields to the right of the base scores using the "linkednumber" template. You can then specify the source field as
    Code:
    <source><name>name of source field</name></source>
    You would then need to define a custom update function for each:
    Code:
    <script>
      function update()
        -- put the guts of the function here
        -- To reference a source field, use sources["name of source field"].getValue()
        setValue(answer);
      end
    </script>
    As for the specifics of using the scripting system, it works just like Lua. There are links to a Lua tutorial in the library (go to the scripting subsection in the ruleset modification guide).

  3. #3
    Quote Originally Posted by Insanity
    I thought the best way to handle this is with a lot of if x=>1, but <=20, y=5 type functions, but do not know enough about the math scripting to describe this.
    As Dachannien said using "linkednumber"'s for your derived fields will help keep the calculations separate.
    In regards to the calculations if/elseif would work but could get very messy. As an alternative you might be able to make use of a static table

    Here's a very simple example that should calculate a strength skill bonus of:
    0 for a strength score less than 10
    2 for strength 10-59
    3 for strength 60-99
    4 for strength >= 130
    (note: the code may not be perfect as my lua skills aren't that great and I'm not able to test it right now)

    Code:
     
     
    local strengthSkillTable = { [10]=1, [60]=2, [100]=3, [130]=4};
     
    function calculateStrengthSkillBonus(strengthvalue)
      local skillBonus;
     
      skillBonus= 0;
     
      for each k, v in strengthSkillTable
        if strengthvalue >= k then
            skillBonus = v;
        end
      end
     
      return skillBonus;
    end
    Work Less, Game More!

  4. #4
    Quote Originally Posted by Toadwart
    Code:
     
     
    local strengthSkillTable = { [10]=1, [60]=2, [100]=3, [130]=4};
     
    function calculateStrengthSkillBonus(strengthvalue)
      local skillBonus;
     
      skillBonus= 0;
     
      for each k, v in pairs(strengthSkillTable) do
        if strengthvalue >= k then
            skillBonus = v;
        end
      end
     
      return skillBonus;
    end
    You always want to enclose a table in pairs() (or ipairs, but that wouldn't work in this instance) if you're iterating over it with a for loop. And there's also the necessity for a "do" statement.

    Now to hope that I didn't miss anything...
    "He is everything I have ever aspired to be."
    "Your aspiration is to be impaled on a halberd? Your parents must be proud."

  5. #5
    Ah, now that I can test it there were a few more flaws...
    However, this code works:

    Code:
     
    function calculateStrengthSkillBonus(strengthvalue)
      local strengthSkillTable = { {10,1}, {60,2}, {100,3}, {130,4} };
     
      local skillBonus; 
     
     
      skillBonus= 0;
     
     
      for k, v in pairs(strengthSkillTable) do
        if strengthvalue >= v[1] then
          skillBonus = v[2];
        end
      end
     
     
      return skillBonus;
    end
    Last edited by Toadwart; June 6th, 2007 at 08:15.
    Work Less, Game More!

  6. #6
    Insanity's Avatar
    Join Date
    Mar 2007
    Location
    Terra, Sol system
    Posts
    198
    bear with me please...

    what i've done with my ruleset so far, using the d20 default as a guide, I have a template prepared for vital stats as follows:

    Code:
    	<template name="vitalstat">
    		<numberfield>
    			<anchored>
    				<position>belowleft</position>
    				<offset>0,7</offset>
    				<size>
    					<width>32</width>
    					<height>20</height>
    				</size>
    			</anchored>
    			<frame>
    				<name>bonus</name>
    				<offset>5,5,5,5</offset>
    			</frame>
    			<keyeditframe>
    				<name>sheetfocus</name>
    				<offset>5,5,5,5</offset>
    			</keyeditframe>
    			<font>sheetnumber</font>
    			<script>
    				function onInit()
    					if getValue() == 0 then
    						setValue(50);
    					end
    				end
    			</script>
    		</numberfield>
    	</template>
    and then for each vital stat I have assigned a source name, I won't show the full code, but looks like this:

    Code:
    <vitalstat name="strength" source="vital.strength.score">
    
    <vitalstat name="manualdexterity" source="vital.manualdexterity.score">
    Much the same for all 10 stats, and done the same for the bonuses as well, again using a template:

    Code:
    <vitalbonus name="strengthskillbonus" source="vital.strength.skillbonus">
    
    <vitalbonus name="rangedbonus" source="vital.manualdexterity.rangedbonus">
    Strength score ranges from 0 to 150, with values 40-60 having a skill bonus of 0, and in this example, lets then assume scores 40-60 have +0, 61-70 have +1, 71-80 +2, 81-90 +3, 91-100, +4, 101-110 +5, 111-120 +6, 121-130 +7, 131-140 +8, 141-150 +9...

    My code would look like this?

    Code:
     
    function calculatevital.strength.skillbonus(vital.strength.score)
      local strengthSkillTable = { {61,1}, {71,2}, {81,3}, {91,4}, {101,5}, {111,6}, {121,7}, {131,8}, {141,9} };
     
      local skillBonus; 
     
     
      skillBonus= 0;
     
     
      for k, v in pairs(strengthSkillTable) do
        if strengthvalue >= v[1] then
          skillBonus = v[2];
        end
      end
     
     
      return skillBonus;
    end

  7. #7
    I'm still a bit of an lua noob and am having trouble getting my head around how the linkednumberfield works. So heres a simpler bit of code that will work for a single field.

    Code:
    <template name="vitalstat">
      <numberfield>
        <anchored>
          <position mergerule="replace">insidetopleft</position>
          <offset mergerule="replace">32,20</offset>
          <size mergerule="replace">
            <width>32</width>
            <height>20</height>
          </size>
        </anchored>
        <frame mergerule="replace">
          <name>bonus</name>
          <offset>5,5,5,5</offset>
        </frame>
        <keyeditframe mergerule="replace">
          <name>sheetfocus</name>
          <offset>5,5,5,5</offset>
        </keyeditframe>
        <font mergerule="replace">sheetnumber</font>
        <script>
          local strengthSkillTable = { {61,1}, {71,2}, {81,3}, {91,4}, {101,5}, {111,6} };
          function recalculate(source)
            local sourceValue = source.getValue();
            local skillBonus = 0;
            for k, v in pairs(strengthSkillTable) do
                if sourceValue >= v[1] then
                  skillBonus = v[2];
                end
              end
              setValue(skillBonus);
          end
          function onInit()
          if source then
           sourcenode = window.getDatabaseNode().getChild(source[1]);
           if sourcenode then
            sourcenode.onUpdate = recalculate;
              end
            end
          end
        </script>
      </numberfield>
    </template>
    An example of the template being used on the charsheet
    Code:
     
          <vitalstat name="strength_vitalstat">
            <source>abilities.strength.score</source>
            <anchored>
              <to>strength</to>
              <position>left</position>
            </anchored>
          </vitalstat>
    Also, you might want to remove the anchored node from the template and just define it when you use the template. The "anchored" behaviour is based on the control it is anchored to. If no "to" anchor is specified it would try to anchor itself to it's container (which may well be the charactersheet itself - in which case it would resize itself to be as tall as the whole sheet).
    Work Less, Game More!

  8. #8
    Psst... merge rules default to replace, so you don't need to add in all of the mergerule="replace".

    What I would suggest is changing the template a bit to make it more generic:

    First, add the following in the template's body:
    Code:
    	<table>
    		<entry mergerule="resetandadd" />
    	</table>
    Next, we put change the script a bit:
    Code:
    	local strengthSkillTable = { {61,1}, {71,2}, {81,3}, {91,4}, {101,5}, {111,6} };
    
    
    	local sourcetable = {};
    
    
    	function recalculate(source)
    		local sourceValue = source.getValue();
    		local skillBonus = 0;
    		for k, v in pairs(sourcetable) do
    			if sourceValue >= v[1] then
    				skillBonus = v[2];
    			end
    		end
    		setValue(skillBonus);
    	end
    
    	function buildTable()
    		if table and type(table) == "table" then
    			for _, v in pairs(table) do
    				if v.value and v.score then
    					table.insert(sourcetable,{v.source[1],v.score[1]})
    				end
    			end
    		end
    	end
    
    	function onInit()
    		buildTable()
    
    		if source then
    			sourcenode = window.getDatabaseNode().getChild(source[1]);
    			if sourcenode then
    				sourcenode.onUpdate = recalculate;
    			end
    		end
    	end

    Now... what that should do... you can build a table in the xml side without having to deal with modifying the script, as such:

    Code:
    <vitalstat>
    	<table>
    		<entry>
    			<value>61</value>
    			<score>1</score>
    		</entry>
    
    		<entry>
    			<value>71</value>
    			<score>2</score>
    		</entry>
    
    		<entry>
    			<value>81</value>
    			<score>3</score>
    		</entry>
    	</table>
    </vitalstat>
    Hopefully, I think that works... but it's been a 15 hour work day so far, so... I'm sleepy... >.<

    Edit: As an example of my sleepiness, I forgot to include that, in the above code: blue means remove and red means add... I know, I'm backwards...
    "He is everything I have ever aspired to be."
    "Your aspiration is to be impaled on a halberd? Your parents must be proud."

  9. #9
    Nicely done Taryn. We like code that is generic. Just hard to figure it out sometimes


    Quote Originally Posted by TarynWinterblade
    Psst... merge rules default to replace, so you don't need to add in all of the mergerule="replace".
    You sure bout this? The documentation says that 'merge' is the default behaviour.
    Work Less, Game More!

  10. #10
    Quote Originally Posted by Toadwart
    You sure bout this? The documentation says that 'merge' is the default behaviour.
    Hmm... that it does. I wonder what the difference between "merge" and "replace" is then...?

    Aha... the difference is that with merge, if you have a template with tags named table with child elements chair and lamp, and an instance of that with only table and lamp, you'd still get a chair in there. On the other hand, with replace, you'd end up only with table and lamp.

    I learn something new every day... (now if only I'd remember half of it... )
    "He is everything I have ever aspired to be."
    "Your aspiration is to be impaled on a halberd? Your parents must be proud."

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
5E Product Walkthrough Playlist

Log in

Log in