PDA

View Full Version : Extend_CoC



GMBazUK
June 29th, 2012, 10:40
Okay, so much to my own surprise I've been able to add various features to CoC, and whilst it has one or two interesting quirks (that may or may not be inherent in the functionality of FG) I have one remaining console error that I cant fathom.


Script Error: [string "scripts/export_list.lua"]:36: attempt to call global 'getNextWindow' (a nil value)

I have added Encounters to the ruleset, and have two files added to my extension:
utility_export.xml and export_list.lua

This is the lua outlined in the error (in bold). You can see my newly inserted Encounters category right above the function in question. I think... its to do with the order in which things are loaded in to FG, and because this function is in the extension and not in the main ruleset folder...


entrymap = {};

function addCategories()
local w;

w = createWindow();
w.setExportName("encounter");
w.setExportClass("encounter");
w.label.setValue("Story");

w = createWindow();
w.setExportName("image");
w.setExportClass("imagewindow");
w.label.setValue("Images & Maps");

w = createWindow();
w.setExportName("npc");
w.setExportClass("npc");
w.label.setValue("Personalities");

w = createWindow();
w.setExportName("item");
w.setExportClass("item");
w.label.setValue("Items");

w = createWindow();
w.setExportName("battle");
w.setExportClass("battle");
w.label.setValue("Encounters");
end

function onInit()
getNextWindow(nil).close();

addCategories();
end

function onDrop(x, y, draginfo)
if draginfo.isType("shortcut") then
for k,v in ipairs(getWindows()) do
local class, recordname = draginfo.getShortcutData();

-- Find matching export category
if string.find(recordname, v.exportsource) == 1 then
-- Check duplicates
for l,c in ipairs(v.entries.getWindows()) do
if c.getDatabaseNode().getNodeName() == recordname then
return true;
end
end


One of you clever people will know what to do I'm sure.:)
Thanks in advance.
Baz.

Trenloe
June 29th, 2012, 16:35
I don't know why you'd need "getNextWindow(nil).close();" in the onInit function. The onInit function is the function that gets call first when the lua file is loaded (when it is first defined - usually in an xml file) - so not sure what window would need to be closed.

Also, getNextWindow(nil) wil not be valid - as nil is probably not defined (unless it is a global variable). But, I'm hoping that "nil" is not a global variable somewhere as the naming suggests it isn't anything - but you never know... Did you add this or was it there already?

Zeus
June 29th, 2012, 17:23
Hmm, you may have issues overriding the /export functionality unless you ask the ruleset developer to add node registration functionality allowing you to then register your additional nodes for /export. Check out some of my previous 4E 2.8 extensions and the latest 4E ruleset for examples of how to do this.

For reference, calling getNextWindow(nil) is another way of saying get the first entry of a window list. Nil being a global constant for Null or nothing.

I believe, in this case, the intent is to remove the first window list entry that is auto created in an empty window list. This is strictly not necessary; if the <skipempty /> tag is applied in the windowclass xml containing the definition of the window list, when the window list is initialised, if the list is empty, the empty entry will not be auto-created.

Check to see if the tag is already added, if not, add and then amend your onInit() handler to:

function onInit()
addCategories();
end

That should fix your problem. BTW: This assumes that the export_list.lua file is called within the window list definition and not the parent window.

GMBazUK
June 29th, 2012, 20:04
Thanks guys for your advice.
Please find attached three images for comparison:
Export function with script intact and console error as previously posted
2667

(Incidentally even with the error I can export modules)

Export function with just the getWindows line removed
2668

Export function with whole function removed
2669

The following windowlist is part of the "Export" windowclass which defines the parent window for the export function



<!-- Node list -->
<windowlist name="categories">
<class>export_categoryentry</class>
<bounds>23,219,-27,-151</bounds>
<frame>
<name>sheetgroup</name>
<offset>9,27,9,20</offset>
</frame>
<script file="scripts/export_list.lua" />
</windowlist>
<scrollercontrol>
<anchored>
<to>categories</to>
<position>insidebottomright</position>
<size>
<width>45</width>
<height>27</height>
</size>
</anchored>
<target>categories</target>
<button>
<normal>button_scroller</normal>
<pressed>button_scroller_down</pressed>
</button>
</scrollercontrol>...

Before this there is another windowlist called entries which forms part of a windowclass called export_categoryentry, but I think this just creates the list.


<windowlist name="entries">
<class>export_entry</class>
<bounds>0,19,-1,-1</bounds>
<skipempty />
<script>
function onSortCompare(w1, w2)
return w1.name.getValue() &gt; w2.name.getValue();
end
</script>
</windowlist>
</sheetdata>
</windowclass>

If I add <skipempty /> to the windowlist "categories" and edit the function to remove getWindow(nil) I get another error to do with createwindow, which appears in the export_list.lua (see previous post, export_list.lua, line 6)

Hope this isn't too confusing.
Baz.

Dakadin
June 29th, 2012, 21:46
Script Error: [string "scripts/export_list.lua"]:36: attempt to call global 'getNextWindow' (a nil value)

I don't think this error is referring to the nil value in this line:


getNextWindow(nil).close();

I think the error is saying that it doesn't recognize getNextWindow as a valid function so it is saying it is a nil value. I just wanted to point that out since I think the focus was on the function parameter.

Try putting a Debug.console statement before each of the createWindow function calls in addCategories so you can validate that it is being caused by the encounters. Then I would compare the classes for the encounters with one of the other categories (like story). You will likely see that the encounters is using a class that doesn't exist in the CoC ruleset. At least that would be my guess.

Zeus
June 29th, 2012, 21:48
What do you get if you try replacing onInit() as follows:


function onInit()
if User.isHost() then
if self.getNextWindow(nil) then
self.getNextWindow(nil).getDatabaseNode().delete() ;
end

addCategories();
end
end

GMBazUK
June 29th, 2012, 22:52
Hi Dakadin,
Yes, I was of the same thinking that the nil value in the function was nothing to do with the nil value in the error message. I also had checked and confirmed that the getWindow parameter was existent elsewhere in the ruleset.
I will look at your Debug suggestion though. Thanks.

Hi Doc,
By changing the function onInit to your suggestion I get only the following error

Script Error: [string "scripts/export_list.lua"]:38: attempt to index global 'self' (a nil value)

...which refers to the first instance of self in the substituted function.

Its getting a little late here in the UK, so please forgive my lack of a response to any further advice until tomorrow.
Thank you guys,
Baz.

Dakadin
June 30th, 2012, 06:31
Try removing the 2 instances of self from DrZeuss' code sample and see if that fixes it.

Here is the modified version:

function onInit()
if User.isHost() then
if getNextWindow(nil) then
getNextWindow(nil).getDatabaseNode().delete();
end

addCategories();
end
end

GMBazUK
June 30th, 2012, 10:29
Hi Dakadin,

No dice I'm afraid. Removing the two instances of "self" just results in the same original error?

I'm determined to get to the bottom of it, as when I put the script (the one throwing the original getWindow error) in the ruleset folder it does not produce an error.


Baz.

GMBazUK
June 30th, 2012, 10:52
OMG! I did it.
Firstly a big thank you to everyone that provided advice to spur me on to a solution.:)
particulary you Doc, for writing those lua functions.

I had inadvertently (I say inadvertently, I'm flying by the seat of my pants most of the time:) ) listed the script (export_list.lua) in the extension.xml. I have no idea why, but it occurred to me that it shouldnt be listed, as it was being called by the included file utility_export.xml, so I removed it, and... bam! Problemo no moreo. Simple, elegant, and pretty darn stupid on my part:)

Now on to my next problem...

As of this point everything seems hunky-dory, except I did notice one or two strange behaviours that seem to have ironed themselves out.

Firstly: When I placed tokens on an image, they appeared really small, regardless of the grid size I had set. This has magically (as far as I'm concerned) stopped happening.

Secondly: (And this is still an issue) If I create a new campaign, and select my Gaslight skin extension during campaign creation, I get multiple sets of desktop icons (story, image...etc) If I create a new campaign using the default skin, and then apply the Gaslight skin later, I dont?

Baz.

Zeus
June 30th, 2012, 11:58
GMBazUK - I did mention overriding ruleset code can be tricky ;) Glad you have a working solution though.

Moving forward you may want to consider discussing getting better extension support for the ruleset by asking the ruleset developer to consider extensions when updating the ruleset base code. Its very straightforward for the ruleset to expose methods for extensions to exploit which can then extend the functionality of the ruleset without the need for extensions to override existing objects. Take a look at 4E (and now 3.5E) which are littered with such examples.

e.g. for export the rulesets expose ExportManager.registerExportNodes() and ExportManager.unregisterExportNodes() methods

As for the token sizing, if you are using v2.9, note token and image functionality (including pointers, token sizing, token orientation etc. etc.) have been overhauled, some has even been ingested directly into the host/client and is no longer managed at the ruleset level. May explain the 'as if by magic' changes you have seen. :)

As for the multiple book icons, this sounds like another override issue. See first part of this post for solution.

Dakadin
June 30th, 2012, 19:08
Secondly: (And this is still an issue) If I create a new campaign, and select my Gaslight skin extension during campaign creation, I get multiple sets of desktop icons (story, image...etc) If I create a new campaign using the default skin, and then apply the Gaslight skin later, I dont?


I used a work around for this issue in the RolemasterClassic ruleset. I added code to check if the control already exists before allowing it to create another one. I changed the createStackShortcut function of the desktopmanager.lua file to this:

function createStackShortcut(iconNormal, iconPressed, tooltipText, className, recordName)
local control = window.createControl("desktop_stackitem", tooltipText);

-- Check if the shortcut has already been registered
for k, v in pairs(stackcontrols) do
if v.getName() == tooltipText then
return;
end
end

table.insert(stackcontrols, control);

control.setIcons(iconNormal, iconPressed);
control.setValue(className, recordName or "");
control.setTooltipText(tooltipText);

updateControls();
end

And changed the createDockShortcut function to this:

function createDockShortcut(iconNormal, iconPressed, tooltipText, className, recordName, useSubdock)
local control = window.createControl("desktop_dockitem", tooltipText);

-- Check if it is a registered subdockcontrol
for k, v in pairs(subdockcontrols) do
if v.getName() == tooltipText then
return;
end
end
-- Check if it is a registered dockcontrols
for k, v in pairs(dockcontrols) do
if v.getName() == tooltipText then
return;
end
end

if useSubdock then
table.insert(subdockcontrols, control);
else
table.insert(dockcontrols, control);
end

control.setIcons(iconNormal, iconPressed);
control.setValue(className, recordName or "");
control.setTooltipText(tooltipText);

updateControls();
end

I just added the for loops to the functions. You might have to make a few modifications to get it to work in the CoC ruleset.

GMBazUK
July 1st, 2012, 05:19
Once again, Dakadin, I am greatly appreciative of your assistance. In a way I'm relived you had this issue, as I was beginning to think the basis of CoC and FG v2.9 might be to blame, and if that were so, and in terms of my degree of understanding, I might as well get to work on a solution to the world's debt crisis whilst I'm at it.:)
Baz.

Dakadin
July 2nd, 2012, 07:49
Once again, Dakadin, I am greatly appreciative of your assistance. In a way I'm relived you had this issue, as I was beginning to think the basis of CoC and FG v2.9 might be to blame, and if that were so, and in terms of my degree of understanding, I might as well get to work on a solution to the world's debt crisis whilst I'm at it.:)
Baz.

I am glad to hear you got it working. I felt the same way you do about 8 months ago. It is overwhelming at first but it gets easier the more you do it. Just keep working on the little stuff at first and you will do fine. :)

GMBazUK
July 2nd, 2012, 10:51
The code you supplied Dakadin, slotted right in without any changes. Another, "hey presto" moment for me (ignorance is bliss). I was rather relieved, as the XML I'm fine with, but the LUA!!!!!!!!!!!!
Back in the day, I hated Computer Studies at school. I just didn't have the aptitude for it. Maths, Science... no problem, but writing programs in Spectrum basic, and whatever it was the Zenith used... and the BBC basic, ugh!:)
I still don't have the aptitude, but fortunately I don't have to worry about it these days.
Baz.

GMBazUK
July 2nd, 2012, 19:45
I've introduced a list of modifiers to CoC but they don't quite work how I'd like, and I'm looking for some advice.

2682


<windowlist name="list">
<bounds>25,30,-25,-40</bounds>
<datasource>modifiers</datasource>
<class>modifiersmall</class>
<useallmodules />
<frame>
<name>sheetgroup</name>
<offset>9,10,9,6</offset>
</frame>
<script>
function onInit()
if User.isHost() then
registerMenuItem("Create Item", "insert", 5);
end
end

function createItem()
local wnd = self;
if not wnd then
return nil;
end

wnd.createWindow();
if wnd then
if wnd.label then
wnd.label.setFocus();
end
end
return wnd;
end

function onMenuSelection(selection)
if selection == 5 then
createItem();
end
end

function onClickDown(button, x, y)
return true;
end

function onClickRelease(button, x, y)
if User.isHost() then
if not getNextWindow(nil) then
createItem();
end
end
return true;
end

function onSortCompare(w1, w2)
if w1.label and w2.label then
return w1.label.getValue() &gt; w2.label.getValue();
else
return false;
end
end

function onDrop(x, y, draginfo)
if User.isHost() then
if draginfo.getType() == "number" then
local wnd = createWindow();
if wnd then
wnd.label.setValue(draginfo.getDescription());
wnd.bonus.setValue(draginfo.getNumberData());
end
return true;
end
end
end

function onFilter(w)
local f = string.lower(window.filter.getValue());
if f == "" then
return true;
end

if string.find(string.lower(w.label.getValue()), f, 0, true) then
return true;
end

return false;
end
</script>
</windowlist>

At the moment, only the GM can modify the rolls, which he makes. I would like either:
A. the players rolls to also be modified by the GMs modifier stack, and the results that the GM sees, sent to the player.
or (which may be simpler)...
B. the player to have access to the GMs modifier list (but not editing rights) so they can drag them to their own modifier stack prior to rolling.

I could create a library item with a list of drag enabled modifiers, but I like the idea of having a list that can be edited on the fly.


Thanks in advance.
Baz.