PDA

View Full Version : LUA Help



statik37
August 26th, 2019, 18:00
Hi,

I am working on trying to add code to have my weapons window autofill some things for me. The code I have so far is:



function onDrop(x,y,draginfo)
if draginfo.isType("shortcut") then
local nodeWin = window.getDatabaseNode();
Debug.chat("nodeWin: ");
Debug.chat(nodeWin);
local nodeItem = nodeWin.getChild("....");
Debug.chat("nodeItem: ");
Debug.chat(nodeItem);
local nDamage = DB.getValue(nodeItem, "damagerating", 0);
Debug.chat("nDamage");
Debug.chat(nDamage);
local nDisc = DB.getValue(nodeWin, "discipline.security", 0);
Debug.chat("nDisc");
Debug.chat(nDisc);
nDamage = nDamage + nDisc;
Debug.chat("nDamage");
Debug.chat(nDamage);
local class, datasource = draginfo.getShortcutData();
Debug.chat("class");
Debug.chat(class);
if class == "referencetext" or class == "item" then
local newentry = createWindow()
Debug.chat("newentry");
Debug.chat(newentry);
newentry.name.setValue(draginfo.getDatabaseNode(). getChild("name").getValue());
newentry.size.setValue(draginfo.getDatabaseNode(). getChild("size").getValue());
newentry.damage.setValue(draginfo.getDatabaseNode( ).getChild("damagerating").getValue());
end
return true;
end
end


Everything seems to work, except nodeItem generates nil. What I want to do is have it point to the items field in the database instead of the character field. Because this isn't working, my nDamage is coming back as 0. I took what I have from 5e and a little kit bashing, but I can not figure out how to fix this. I don't know enough about LUA, and I feel this may be an easy fix.

Thanks.

Moon Wizard
August 26th, 2019, 22:28
What's the output from your debug statements? If nodeItem is nil, that probably means that the relative path "...." isn't valid.

Regards,
JPG

statik37
August 26th, 2019, 23:37
The output is nil. Basically, as it is, when I access the database, I am accessing the charsheet info. I want to use that statement to transfer and grab from the Items section of the database. How do i do that?

Moon Wizard
August 26th, 2019, 23:48
I meant the output from all of your debug statements. For example, nodeItem depends on nodeWin, so there’s no way to tell if “....” is valid relative path without knowing what nodeWin is.

If you use Debug.console instead of Debug.chat; you can just hit the Copy To Clipboard menu to quickly copy all the output.

Regards,
JPG

statik37
August 26th, 2019, 23:52
28664

Moon Wizard
August 27th, 2019, 03:11
It looks like nodeWin is essentially the root character node that is only two levels deep; so “....” is not a valid relative path (which means to go up the data tree three levels). That explains why it’s returning nil.

Try looking at getShortcutData, instead of getDatabaseNode. Dragging an item stores quite a bit of data in different places in the drag object; but each drag slot can contain a link.

If that doesn’t work, you might want to go back and look at some of the CoreRPG code that handles onDrop with links to see examples. Make sure to use a good text editor with multiple file search capability. (I use Notepad++)

Regards,
JPG

statik37
August 27th, 2019, 15:26
Thank you, that was a great help.

Instead of having:

local nodeItem = nodeWin.getChild("....");

I did:


local nodeItem = draginfo.getDatabaseNode();

And that seems to have fixed my issue. Thank you for your insight.

statik37
August 27th, 2019, 19:50
OK, I have another question.

I have a row of Attributes and a row of Disciplines. I have it set now, that when I click one attribute, it updates a DB field:



function attribSelect(winFrame, nAttrib)
local nodeWin = winFrame.getDatabaseNode();
Debug.chat("nodeWin:");
Debug.chat(nodeWin);
local nAttribute = nodeWin.createChild("attrib");
Debug.chat("nAttribute:");
Debug.chat(nAttribute);
local attrib = DB.getValue(nodeWin, nAttrib, 0);
Debug.chat("attrib:");
Debug.chat(attrib);
return true;
end


And the same thing for the disciplines.



function discipSelect(winFrame, nDiscip)
local nodeWin = winFrame.getDatabaseNode();
Debug.chat("nodeWin:");
Debug.chat(nodeWin);
local nDiscipline = nodeWin.createChild("discip");
Debug.chat("nDiscipline:");
Debug.chat(nDiscipline);
local discip = DB.getValue(nodeWin, nDiscip, 0);
Debug.chat("discip:");
Debug.chat(discip);
return true;
end


What I would like to do now is whenever either function value changes, I want to add the two of them together together and pass them into a third field. For that I wrote this:



function targetNumber(winFrame, attrib, discip)
local nodeWin = winFrame.getDatabaseNode();
Debug.chat("nodeWin:");
Debug.chat(nodeWin);
local att = nodeWin.getValue(nodeWin, attrib, 0);
local dis = nodeWin.getValue(nodeWin, discip, 0);
local TN = att + dis;
Debug.chat("TN:");
Debug.chat(TN);
DB.setValue(nodeWin, "rollable.targetroll", "number", TN);
end


Now, I don't know if I am even close to doing that right. Or how to then get the values from the two other functions into this function. I don't know if I need the second winNode command, or if it's just redundant.

statik37
August 27th, 2019, 19:57
I just realized now looking at that, it is actually not doing what I was hoping. The createChild makes a new DB category, but doesn't pass the number. And I was just passing the value, without loading it into the database.

Is there any insight on how to create a DB entry since createChild didn't work?

basically I want to create a field that says something like

<attrib type="number">12</attrib>

Moon Wizard
August 27th, 2019, 20:19
Look at DB.setValue as a better way to do that.

You can also pass additional parameters into createChild to set a data type for the node.

Regards,
JPG

statik37
August 27th, 2019, 20:55
I feel like I am so close.



function attribSelect(winFrame, nAttrib)
local nodeWin = winFrame.getDatabaseNode();
Debug.chat("nodeWin:");
Debug.chat(nodeWin);
nodeWin.createChild("attrib", "number");
local test = DB.setValue(nodeWin, "attrib", "number", nAttrib);
Debug.chat("test:");
Debug.chat(test);
return true;
end


I get setValue: Database node type mismatch.

I think it's trying to pass the source name for nAttrib, instead of the number.

Moon Wizard
August 27th, 2019, 21:36
You don't need to use both databasenode.createChild and DB.setValue. The DB.setValue call will create the child, if it doesn't exist already.

Most likely, the database mismatch is because of your previous code that created the "attrib" database node with no value type. You'll need to either delete that old character and create a new one for testing; or edit the campaign database to remove the offending node. If it still happens, then check your code for other places where "attrib" child might be created with no value type, or a different value type.

Regards,
JPG

statik37
August 27th, 2019, 23:01
Removed cause I'm dumb.

statik37
August 27th, 2019, 23:09
Removed cause I'm dumb.

Moon Wizard
August 28th, 2019, 04:57
That's all part of learning. :)

Cheers,
JPG

statik37
August 28th, 2019, 14:02
OK, another issue.

Her is my code:



function taskcheck(winFrame)
local nodeWin = winFrame.getDatabaseNode();
Debug.chat("nodeWin: ", nodeWin);

local rRoll = {sType = "dice", aDice = {}, nMod = nodeWin.getChild("rollable.comprange").getValue()};
for i = 1, nodeWin.getChild("rollable.dicetoroll").getValue(), 1 do
table.insert(rRoll.aDice, "d20");
end

Debug.chat("rRoll:",rRoll);
local rActor = ActorManager.getActor("pc", nodeWin);
Debug.chat("rActor: ", rActor);

local TN = nodeWin.getChild("rollable.targetroll").getValue();
Debug.chat("TN: ", TN);

local FC = nodeWin.getChild("rollable.focusused").getValue();
Debug.chat("FC: ", FC);

local comp = nodeWin.getChild("rollable.comprange").getValue();
Debug.chat("comp", comp);

local rolling20 = nodeWin.getChild("rollable.dicetoroll").getValue();
Debug.chat("rolling20: ", rolling20);


local msg = {font = "sheetlabel"};
msg.text = rActor.sName .. " rolls a task"
Comm.deliverChatMessage(msg);

local msg = {font = "sheetlabel"};
msg.text= "TN.." .. TN.." / FC.."..FC.."\nRolling "..rolling20.. "d20\n"
Comm.deliverChatMessage(msg);

for i = 1, rolling20, 1 do
table.insert(rRoll, "d20");
end

Debug.chat("rRoll", rRoll);


resetdice(winFrame);
ActionsManager.roll(nil, nil, rRoll);
-- SkillDieHandler.handleDiceLanded(nodeWin, TN, rRoll);
return true;
end


I am getting a Script Error: invalid key to 'next'

When I comment out the ActionsManager line, the error goes away. I am using the ActionsManager from the CoreRPG set with no edits to it. My debug outputs are in the image below. I don't know what this error means. Usually it at least gives me a line to look at, this gives me nothing.

I even tried to throw some debug statement into the ActionsManager file, and it doesn't seem to get past the first if statement.

28683

damned
August 28th, 2019, 14:10
I am getting a Script Error: invalid key to 'next'

When I comment out the ActionsManager line, the error goes away. I am using the ActionsManager from the CoreRPG set with no edits to it. My debug outputs are in the image below. I don't know what this error means. Usually it at least gives me a line to look at, this gives me nothing.

I even tried to throw some debug statement into the ActionsManager file, and it doesn't seem to get past the first if statement.

28683

If you are layered on CoreRPG and you probably want to make changes to ActionManager you would generally make a new ActionManager2 and leave the original intact.
I cant see an if statement in your code?

damned
August 28th, 2019, 14:14
Without going thru all of your code the only example in CoreRPG of ActionsManager.roll has 2 values + nil being passed to it and you are only passing 1 + 2 nil.
Its possible the first value cant be nil.

Bidmaron
August 28th, 2019, 17:07
I am away from computer so I cannot speak to the actionmanager problem until after work but I noticed the next problem you will have.
The roll call is not synchronous. When you call roll, (unless you are using non standard dice that cannot do 3d roll, in which case I still believe it dispatches to the landed handler) when it returns to your code, the dice will be rolling and you cannot handle the dice result as the next or any subsequent instruction in your code. You must register a handler that will take the results and deal with them. You should be able to find all kinds of examples of registering this handler and handling the results in Core RPG.

statik37
August 30th, 2019, 03:42
I fixed this. I did not realize that MoreCore had a ton of custom dice codes. I found those yesterday, and with a little adjustment, they had exactly what I needed. I wish I found it earlier, and saved myself a lot of trouble. The more I work with the code, the easier it is getting for me to look at code and figure it out.

damned
August 30th, 2019, 13:29
Mooooaaaarrrr MoreCore!

statik37
September 6th, 2019, 19:31
I have another question. I am trying to set up certain windows on my items screen to lock when I hit the lock icon. This is the code I have so far:



function onInit()
update();
end

function VisDataCleared()
update();
end

function InvisDataAdded()
update();
end

function updateControl(sControl, bReadOnly)
if not self[sControl] then
return false;
end

return self[sControl].update(bReadOnly);
end

function update()
local nodeRecord = getDatabaseNode();
local bReadOnly = WindowManager.getReadOnlyState(nodeRecord);

local bWeapon = ItemManager2.isWeapon(nodeRecord);
local bArmor = ItemManager2.isArmor(nodeRecord);

local bSection1 = false;
if updateControl("type", bReadOnly) then bSection1 = true; end
if updateControl("range", bReadOnly) then bSection1 = true; end

local bSection2 = false;
-- if updateControl("damagerating", bReadOnly) then bSection2 = true; end
-- if updateControl("resistance", bReadOnly) then bSection2 = true; end
if updateControl("effect", bReadOnly) then bSection2 = true; end

local bSection3 = false;
if updateControl("size", bReadOnly) then bSection3 = true; end
if updateControl("qualities", bReadOnly) then bSection3 = true; end
if updateControl("cost", bReadOnly) then bSection3 = true; end

local bSection4 = true
notes.setReadOnly(bReadOnly);

divider.setVisible(bSection1 and bSection2);
divider2.setVisible((bSection1 or bSection2) and bSection3);
divider3.setVisible((bSection1 or bSection2 or bSection3) and bSection4);
end


I took it from 5E and made some adjustments. As it sits now, it works with no problem, but the two commented out fields do not lock. If I uncomments then, I get the error:


attempt to call field 'update' (a nil value)

The difference between those fields and the others are those two are number fields and everything else is a string field. However, when I look at the code in 5E, they have this on numbers and strings, and it works fine. The only big difference was I got rid of the bID bit, because I don't want to have non-ID settings.

Moon Wizard
September 6th, 2019, 20:34
What template are you using to implement those fields?

The scripts associated with those templates must have an update function, which is the error reporting when you uncomment.

There are some templates in CoreRPG that implement those functions for strings and numbers already that you can reuse. If you’re making a custom field, you’ll need to implement your own script for those fields.

Make sure to use a multi-file text search with a good text editor to track back the templates to see what is being inherited.

Regards,
JPG

statik37
September 6th, 2019, 20:53
I was able to fix it. Upon looking back at the code I borrowed from, I realized I was using the wrong template for the number fields. I was off by one letter. Once I fixed that, it was all set.

statik37
September 16th, 2019, 16:45
You all have been so helpful.


function rankchange(draginfo, winFrame)

local nodeWin = winFrame.getDatabaseNode();
local curRank = DB.getValue(nodeWin, "rank");
DB.setValue(nodeWin, "reputation.rank", "string", curRank);
DB.setValue(nodeWin, "reputation.reputation", "number", 10);

if DB.getValue(nodeWin, "reputation.rank") == "Ensign" then
nodeWin.getChild("reputation.privilege").setValue(1);
nodeWin.getChild("reputation.responsibility").setValue(20);
elseif DB.getValue(nodeWin, "reputation.rank") == "Lieutenant JG" then
nodeWin.getChild("reputation.privilege").setValue(1);
nodeWin.getChild("reputation.responsibility").setValue(20);
elseif DB.getValue(nodeWin, "reputation.rank") == "Lieutenant" then
nodeWin.getChild("reputation.privilege").setValue(2);
nodeWin.getChild("reputation.responsibility").setValue(19);
elseif DB.getValue(nodeWin, "reputation.rank") == "Lieutenant Commander" then
nodeWin.getChild("reputation.privilege").setValue(2);
nodeWin.getChild("reputation.responsibility").setValue(19);
elseif DB.getValue(nodeWin, "reputation.rank") == "Commander" then
nodeWin.getChild("reputation.privilege").setValue(3);
nodeWin.getChild("reputation.responsibility").setValue(18);
elseif DB.getValue(nodeWin, "reputation.rank") == "Captain" then
nodeWin.getChild("reputation.privilege").setValue(4);
nodeWin.getChild("reputation.responsibility").setValue(17);
else
nodeWin.getChild("reputation.privilege").setValue(1);
nodeWin.getChild("reputation.responsibility").setValue(20);

end


end


This is in the LUA file. As it stands, when I open the character sheet and I go to Attributes I have a number default for these fields. After visiting the Attributes, when I run through the cycler to activate this code, it works perfectly fine. However, if I create a new character, and do not go to the Attributes page, once I start cycling, I get an error saying setChild is a nul value. I assume it's because the field has yet to be created in the DB. How can I change the code to have it create the DB fields if it's not been created yet?

Trenloe
September 16th, 2019, 17:09
How can I change the code to have it create the DB fields if it's not been created yet?
Use <dbnode>.createChild - https://www.fantasygrounds.com/refdoc/databasenode.xcp#createChild