PDA

View Full Version : Question for Trenloe or damned...



Zhern
January 13th, 2017, 04:54
Okay, so, I'm having a moment again, so please forgive me if this was answered somewhere because my search hasn't turned up what I'm trying to do and maybe I'm having a serious moment and didn't find what I'm looking to do reading through the info in the scripting guide or other info on the dev guides and wiki. I always run into these types of quandaries while I'm exhausted (up since 0430) and should have just gone to bed but head to wall seems to be my thing...

I'm working on turning a lot of the ability bonuses into templates and am hoping to avoid having to create a separate template for each ability bonus (such as open doors, resurrection survival %, strength to hit mod, strength damage mod, etc). For instance, with open doors, I have it setup like this:



<number_abilitycheck name="stropendoors" source="abilities.strength.opendoors">
<anchored to="abilityframe" position="insidetopleft" offset="95,25" width="55" height="20" />
<target>strength</target>
<modifierfield>abilities.strength.bonusmodifier</modifierfield>
<tooltip textres="char_tooltip_stropendoors"></tooltip>
<frame name="fieldlight" offset="7,5,7,5" />
</number_abilitycheck>


corresponding to this template:



<template name="number_abilitycheck">
<number_abilitybonus>
<anchored position="righthigh" offset="15,0" width="36" height="20" />
<hideonvalue value="0" />
<rollable />
<modifiersize>mini</modifiersize>
<script>
function onSourceUpdate()
local nodeWin = window.getDatabaseNode();
local nCurrentScore = DB.getValue(nodeWin, "abilities." .. target[1] .. ".score",10);

nAbilityCheck = GameSystem.getAbilityCheckBonuses(target[1], nCurrentScore) + calculateSources();

setValue(nodeWin, "abilities." .. target[1] .. ".opendoors", nAbilityCheck);
end

function onInit()
local nodeWin = window.getDatabaseNode();
DB.addHandler(DB.getPath(nodeWin, "abilities." .. target[1] .. ".score"), "onUpdate", onSourceUpdate);
end

function action(draginfo)
local rActor = ActorManager.getActor("pc", window.getDatabaseNode());
ActionAbilityCheck.performRoll(draginfo, rActor, self.target[1]);

return true;
end

function onDragStart(button, x, y, draginfo)
return action(draginfo);
end

function onDoubleClick(x,y)
return action();
end
</script>
</number_abilitybonus>
</template>


That is all well and good and works fine, including double clicking on the field to roll the open doors check so on and so forth...

What I am wanting to do is be able to pass the ability as the target along with the specific database node (sorry, words are hard right now) -> for abilities.strength.opendoors, I want to pass strength and opendoors. Can I pass open doors (or whatever I'm looking to pass so I can make the template generic enough that I don't have to hard code .opendoors in the script? So for each ability bonus, I want to pass the ability and the bonus. Does that make sense? Reason being, when I call ActionAbilityCheck.performRoll(), I want to be able to also pass that last value (opendoors, etc) to the script and execute the right section based on what is passed, but I'll need both the ability and bonus.

For strength, it would be strength and then opendoors, carrycap, damagemod, tohitbonus, then for dexterity it would be missiletohitbonus, effectonac, on through the rest of the ability scores.

Thanks for taking the time to read my rambling brain fart.

Patrick/Zhern

vodokar
January 13th, 2017, 05:29
I'm not Trenloe or Damned, so maybe they know some tricks I don't. However, I'm reasonably certain that there is not a way to use that method to point to two things at once i.e. strength and strength bonus or strength and open doors.

I made a template for each individual item which needed to use a different script, which in my case, was almost everything; take a look at the AD&D template files, you'll see what I mean. But AD&D is much more complex than C&C in its structure.

In the original C&C code, all of the attributes used one table lookup, thus, they were able to get away with having one generic template they could use for all attribute checks; for ex. strength bonus pointing to strength and the script used "abilities." .. target[1] .. ".score" and "abilities." .. target[1] .. ".bonus", then for dex, the same, but passed dexterity. Still only passing one variable.

But, C&C basically did everything with ability checks based off of your attribute bonus and all the attribute bonuses were the same i.e. based off of one table. Then saving throws worked the same, one generic template, because only one table to lookup value from.

Zhern
January 13th, 2017, 05:47
Thanks, vodokar. The 3.5E ruleset is similar to what you describe for the C&C ruleset. I'll take a look at what you did with AD&D. I appreciate your insight!

vodokar
January 13th, 2017, 06:16
I think I know a technique that will work.

Let's say, for example, that you need your ability bonus to be set by your ability score, and then the ability bonus to roll for a check. We will assume that all ability bonus checks use the same lua script, say, ActionAbility.

In the ability bonus template, set up a db handler watching the ability score on init.
In the ability bonus template, set the value of the ability bonus on update.
In the ability bonus control, target itself.
In the ability bonus template, in the code for drag, doubleclick etc. is where you put the ActionAbility.performroll. Pass the target(1) here. This passes the ability bonus that you are doing the roll for, ie. strength, dexterity, whatever.

The rest is done in your lua action script. You can do database calls from there using that stat.

You can even direct it thru different code in the script.

Here is the getRoll function from my saving throws script, as example of what you can do with that one piece of information:


function getRoll(rActor, sAbilityStat, bSecretRoll)
local rRoll = {};
rRoll.sType = "save";
rRoll.aDice = { "d20" };

local sActorType, nodeActor = ActorManager.getTypeAndNode(rActor);
if nodeActor then
if sActorType == "pc" then
local nBonus = DB.getValue(nodeActor, "save." .. sAbilityStat .. ".bonusmodifier", 0);
rRoll.nMod = nBonus;
else
rRoll.nMod = 0;

end
end

local nSaveScore = DB.getValue(nodeActor, "save." .. sAbilityStat .. ".score", 10);

rRoll.sDesc = "[SAVE: " .. nSaveScore .. "]";

if sAbilityStat == "paralyzation" then
sAbilityStat = "Paralyzation, Poison or Death Magic"
elseif sAbilityStat == "petrification" then
sAbilityStat = "Petrification or Polymorph"
elseif sAbilityStat == "rod" then
sAbilityStat = "Rod, Staff or Wand"
elseif sAbilityStat == "breathweapon" then
sAbilityStat = "Breath Weapon"
elseif sAbilityStat == "spell" then
sAbilityStat = "Spell"
end

rRoll.sDesc = rRoll.sDesc .."[d20]"
rRoll.sDesc = rRoll.sDesc .. " " .. StringManager.capitalize(sAbilityStat);
rRoll.sDesc = rRoll.sDesc .. " Save";

rRoll.bSecret = bSecretRoll;

return rRoll;
end

Almost everything that I did in all of my action scripts required some very clever manipulation of that one piece of information that was passed.

Zhern
January 13th, 2017, 12:40
Yeah, I think that will be the best way to do it so I can keep the database structure fundamentally the same as it is for 3.5E. I'm trying to make sure that the code is as compatible with future updates as possible. I hadn't thought of doing it the way you suggest but I think that is the answer. Thank you very much, sir! I needed to be able to bounce that off someone and I appreciate you stepping in. I also need to learn that sometimes, after a very long day at work, it is best to check out and relax. I'm really bad about that.

Anyway, very much appreciate your help, vodokar!

Patrick

vodokar
January 14th, 2017, 01:59
You quite welcome, Patrick. Feel free to use whatever ideas you can from my ruleset. While there are certainly more experienced programmers here, I had to learn tons about action scripts to make the ruleset work, because there are so many different system requirements, so you'll see a ton of examples on how flexible and powerful leveraging that technique can be.

Zhern
January 14th, 2017, 04:07
Thanks, man. Appreciate that. I'll have to pop the hood and see what is going on.

Zhern
January 17th, 2017, 03:22
Hah, I realized how to do it while I was working on something else. I feel kind of dense at the moment that I didn't think of it before. I don't need to pass two nodes at all, just the one I want do stuff with. Depending on what the target is then I can query for the attribute score and proceed accordingly. It did require me to use a different node, but no big deal, and now I can use one template for all ability modifiers. I will need to add logic to determine if it is necessary to invoke an action and double click or not still.

I felt like Wile E. Coyote when the light bulb goes off above his head (shortly before he orders something form ACME and winds up at the bottom of the canyon, mind you...).

Here is an example:


<number_abilitymodifier name="strcarrycapbonus" source="abilitycheckmod.carrycap.score">
<anchored to="stropendoors" position="right" offset="10,0" width="55" />
<target>carrycap</target>
<modifierfield>abilitycheckmod.carrycap.bonusmodifier</modifierfield>
<tooltip textres="char_tooltip_strcarrymod"></tooltip>
<frame name="fieldlight" offset="7,5,7,5" />
</number_abilitymodifier>

<number_abilitymodifier name="hpbonus" source="abilitycheckmod.hpbonus.score">
<anchored to="stropendoors" position="below" offset="0,15" width="55" height="20" />
<target>hpbonus</target>
<modifierfield>abilitycheckmod.hpbonus.bonusmodifier</modifierfield>
<!-- <tooltip textres="char_tooltip_strcarrymod"></tooltip> -->
<frame name="fieldlight" offset="7,5,7,5" />
</number_abilitymodifier>



<template name="number_abilitymodifier">
<number_abilitybonus>
<anchored position="righthigh" offset="15,0" width="36" height="20" />
<modifiersize>mini</modifiersize>
<script>
function onSourceUpdate()
local nodeWin = window.getDatabaseNode();
local nAbilityMod = DB.getValue(nodeWin, "abilitycheckmod." .. target[1] .. ".score");

local sAttribute;

if(string.match(target[1], "carrycap")) then
sAttribute = "strength";
elseif(string.match(target[1], "hpbonus")) then
sAttribute = "constitution";
elseif(string.match(target[1], "addlanguages") or string.match(target[1],"spelllevel")) then
sAttribute = "intelligence";
elseif(string.match(target[1], "maxnumspecialhirelings")) then
sAttribute = "charisma";
end

local nCurrentAttributeScore = DB.getValue(nodeWin, "abilities." .. sAttribute .. ".score",10);
nAbilityCheckMod = GameSystem.getAbilityModifiers(target[1], sAttribute, nCurrentAttributeScore) + calculateSources();
setValue(nodeWin, "abilitycheckmod." .. target[1] .. ".score", "number", nAbilityCheckMod);
end

function onInit()
local nodeWin = window.getDatabaseNode();
DB.addHandler(DB.getPath(nodeWin, "abilities.strength.score"), "onUpdate", onSourceUpdate);
DB.addHandler(DB.getPath(nodeWin, "abilities.constitution.score"), "onUpdate", onSourceUpdate);
DB.addHandler(DB.getPath(nodeWin, "abilities.intelligence.score"), "onUpdate", onSourceUpdate);
DB.addHandler(DB.getPath(nodeWin, "abilities.charisma.score"), "onUpdate", onSourceUpdate);
end

</script>
</number_abilitybonus>
</template>

vodokar
January 17th, 2017, 04:05
That is very clever.

I can see how your obtaining the target attribute for both the score and bonus. I'd have to see the actual getabilitymodifiers script to understand exactly how those variables that are being passed are used to actually arrive at the value of nAbilityCheckMod. I presume you could use if-then statements to direct it to the proper table based on sAttribute and then feed that table nCurrentAttributeScore.

I could probably have used something like that, but it was just easier to copy and paste the template and change a few names.

Zhern
January 17th, 2017, 04:09
Here is my getAbilityModifiers function. I took a page out of your book and each modifier type is retrievable from a function that essentially is a lookup table. The getAbilityModifiers function is the cop directing traffic.



function getAbilityModifiers(modifier, attribute, score)
if(string.match(attribute, "strength")) then
if(string.match(modifier, "opendoors")) then
return getStrengthOpenDoors(score);
elseif(string.match(modifier, "carrycap")) then
return getStrengthCarryModifier(score);
elseif(string.match(modifier, "meleetohit")) then
return getStrengthToHitModifier(score);
elseif(string.match(modifier, "meleedamage")) then
return getStrengthDamageModifier(score);
end
elseif(string.match(attribute, "dexterity")) then
if(string.match(modifier, "missiletohit")) then
return getDexterityMissileToHitModifier(score);
elseif(string.match(modifier, "effectonac")) then
return getDexterityEffectAC(score);
end
elseif(string.match(attribute,"constitution")) then
if(string.match(modifier,"hpbonus")) then
return getConstitutionHPModifier(score);
elseif(string.match(modifier, "raisedeadsurvival")) then
return getConstitutionRaiseDeadSurvival(score);
end
elseif(string.match(attribute,"intelligence")) then
if(string.match(modifier, "addlanguages")) then
return getIntelligenceMaxAddLanguages(score);
elseif(string.match(modifier, "spelllevel")) then
return getIntelligenceMaxSpellLevel(score);
elseif(string.match(modifier, "learnspell")) then
return getIntelligenceChanceToUnderstandNewSpell(score);
elseif(string.match(modifier, "minspellperlevel")) then
return getIntelligenceMinNumberSpellsLevel(score);
elseif(string.match(modifier, "maxspellperlevel")) then
return getIntelligenceMaxNumberSpellsLevel(score);
end
elseif(string.match(attribute,"wisdom")) then
return getWisdomBonusSpell(score);
elseif(string.match(attribute,"charisma")) then
if(string.match(modifier,"maxnumspecialhirelings")) then
return getCharismaSpecialHirelings(score);
end
end
end

vodokar
January 17th, 2017, 04:21
Wow. That's brilliant.

Zhern
January 17th, 2017, 13:58
I wouldn't go that far. The scripting in FG is making me have to think in a different way, which is good. I'm also able to cut down on the number of lines of code that needs to be maintained, which is also good.