Sample of a UDF?
Moderators: dorpond, trevor, Azhrei, giliath, jay, Mr.Ice
Sample of a UDF?
I'm looking at the wiki for define function and I must not be getting it. I don't see how, once you define it, you can then call it while passing in arguments...or getting results from it.
Does anyone have a sample of how to set this all up? Including how to "set" these at the "onCampaignLoad" call?
Also, what is the purpose of creating these? Do they improve code performance or is just a convenience thing?
Appreciate the info!
Does anyone have a sample of how to set this all up? Including how to "set" these at the "onCampaignLoad" call?
Also, what is the purpose of creating these? Do they improve code performance or is just a convenience thing?
Appreciate the info!
Re: Sample of a UDF?
well i guess you found this:
defineFunction(function, macro, ignoreOutput, newScope)
so
defineFunction("myMacro@lib:whatever", "myMacro", 1, 0)
which allows you to use
myMacro(1,"a")
instead of
macro("myMacro@lib:whatever"):json.append("",1,"A")
inside myMacro you simply call:
firstArg = arg(0)
secondArg = arg(1)
which will make firstArg==1 and secondArg=="a"
it will improve performance and it is convenient.
e.g. you can do
if(myMacro(1,2) == "someResult"):doThis() ; doThat()
which is not possible with the macro roll option.
clear?
note that the macro is defined AFTER onCampaignLoad has been run, which happens...on campaign load...go figure. You can also run it manually once.
also in case its not clear:
ignore output will ignore ANY output to chat in myMacro so
[r:"sho this"] inside myMacro will not show. The ONLY way to return a value is
[macro.return=result] which will return 'result' when you call the macro.
newScope means that the scope from within myMacro is called is NOT available so
[a=1]
[myMacro(1,"g")]
the value 'a' will NOT be available inside myMacro. set newScope to 0 and 'a' WILL be available inside!!
defineFunction(function, macro, ignoreOutput, newScope)
so
defineFunction("myMacro@lib:whatever", "myMacro", 1, 0)
which allows you to use
myMacro(1,"a")
instead of
macro("myMacro@lib:whatever"):json.append("",1,"A")
inside myMacro you simply call:
firstArg = arg(0)
secondArg = arg(1)
which will make firstArg==1 and secondArg=="a"
it will improve performance and it is convenient.
e.g. you can do
if(myMacro(1,2) == "someResult"):doThis() ; doThat()
which is not possible with the macro roll option.
clear?
note that the macro is defined AFTER onCampaignLoad has been run, which happens...on campaign load...go figure. You can also run it manually once.
also in case its not clear:
ignore output will ignore ANY output to chat in myMacro so
[r:"sho this"] inside myMacro will not show. The ONLY way to return a value is
[macro.return=result] which will return 'result' when you call the macro.
newScope means that the scope from within myMacro is called is NOT available so
[a=1]
[myMacro(1,"g")]
the value 'a' will NOT be available inside myMacro. set newScope to 0 and 'a' WILL be available inside!!
GETTING STARTED WITH MAPTOOLS - TUTORIALS, DOCS, VIDEOS, TOOLS, ETC
DISCORD (the new MT forum!)
My stuff
Excel Tools: Table and Light editors
MT Tools: Bag of Tricks: Tools for Maptool, Dungeon Builder I, Dungeon Builder II,onMouseOverEvent.
Frameworks: Dark Heresy, Rogue Trader, Deathwatch, Black Crusade, Only War, SET Card Game, RoboRally
Wiki: Debugging Tutorial, Speed Up Your Macros, Working With Two CODE Levels, Shortcut Keys, Avoiding Stack Overflow, READ THIS
DISCORD (the new MT forum!)
My stuff
Excel Tools: Table and Light editors
MT Tools: Bag of Tricks: Tools for Maptool, Dungeon Builder I, Dungeon Builder II,onMouseOverEvent.
Frameworks: Dark Heresy, Rogue Trader, Deathwatch, Black Crusade, Only War, SET Card Game, RoboRally
Wiki: Debugging Tutorial, Speed Up Your Macros, Working With Two CODE Levels, Shortcut Keys, Avoiding Stack Overflow, READ THIS
Re: Sample of a UDF?
I have a starter token you can use. It essentially makes all your macros UDF functions. All you have to do is set the prefix for the function in onCampaignLoad. Default is xx.lib., so if you make a macro named getStuff then you can call it from another macro as xx.lib.getStuff(). Or whatever you set the prefix to.
I also included some basic debug macros named label(string/number), pause(varName,...) and watch(varName,...) where label just outputs the string or number you pass it to know you made it that far. The varName is the variable you want to see, but in quotes. So, if you want to see your counter variable you would put [H: xx.lib.pause("counter")].
The onCampaignLoad UDF sets the default of all functions to no output, so I also included a generic output.basic() function. It looks like the normal MT output except the token image has alt text that shows the players name. Also, you can specify the targets of the output based on ownership of token using "owner" and "other" for non-owners. It can also subtract players from output list like -gm, -self. You can read the macro comments for more details in all the above macros.
I also included some basic debug macros named label(string/number), pause(varName,...) and watch(varName,...) where label just outputs the string or number you pass it to know you made it that far. The varName is the variable you want to see, but in quotes. So, if you want to see your counter variable you would put [H: xx.lib.pause("counter")].
The onCampaignLoad UDF sets the default of all functions to no output, so I also included a generic output.basic() function. It looks like the normal MT output except the token image has alt text that shows the players name. Also, you can specify the targets of the output based on ownership of token using "owner" and "other" for non-owners. It can also subtract players from output list like -gm, -self. You can read the macro comments for more details in all the above macros.
- Attachments
-
- starter lib token.rptok
- (83.63 KiB) Downloaded 82 times
Downloads:
- Notepad++ MapTool addon
- RPEdit details (v1.3)
- Coding Tips: Modularity and Design
- Videos: Macro Writing Tools
Re: Sample of a UDF?
Thanks guys, I'll dig into all this.
One last question on the UDF thing. Because of the "2 loop max" limitation in Maptool, I have a macro, that calls another, that calls another. Do ALL of them have to be UDFs? Or just the "top level" one?
One last question on the UDF thing. Because of the "2 loop max" limitation in Maptool, I have a macro, that calls another, that calls another. Do ALL of them have to be UDFs? Or just the "top level" one?
Re: Sample of a UDF?
There's a two {} nesting limit per macro. So, logically, you can go as deep as you want. It's the parser that limits the {}s. Also, the source of {} don't matter. Could be from any roll option or just {} in an html comment (where code is still executed). Personally, I almost never use [macro:] unless I'm forced to, like in a form submit or tweaking someone else's code.xavram wrote:Thanks guys, I'll dig into all this.
One last question on the UDF thing. Because of the "2 loop max" limitation in Maptool, I have a macro, that calls another, that calls another. Do ALL of them have to be UDFs? Or just the "top level" one?
Downloads:
- Notepad++ MapTool addon
- RPEdit details (v1.3)
- Coding Tips: Modularity and Design
- Videos: Macro Writing Tools
Re: Sample of a UDF?
Hmmm...so I put this in my "onCampaignLoad" macro...
[h : defineFunction("Orientation@lib:Math", "Orientation", 1, 0)]
...and then closed/restarted my campaign. Then I tried to call it, like so...
[h : intersectionResult = Orientation(pointP, pointQ, pointR, pointZ)]
...but in the chat window, I get back "Undefined function : Orientation".
This seems like it should be fairly straightforward, any ideas why this wouldn't be working? I know that the "onCampaignLoad" macro is being called because it creates an HTML form when the campaign is loaded.
[h : defineFunction("Orientation@lib:Math", "Orientation", 1, 0)]
...and then closed/restarted my campaign. Then I tried to call it, like so...
[h : intersectionResult = Orientation(pointP, pointQ, pointR, pointZ)]
...but in the chat window, I get back "Undefined function : Orientation".
This seems like it should be fairly straightforward, any ideas why this wouldn't be working? I know that the "onCampaignLoad" macro is being called because it creates an HTML form when the campaign is loaded.
Re: Sample of a UDF?
You example here looks right. Make sure the casing is correct in actual code for one. Also, turn off player editable on Orientation macro.
Downloads:
- Notepad++ MapTool addon
- RPEdit details (v1.3)
- Coding Tips: Modularity and Design
- Videos: Macro Writing Tools
Re: Sample of a UDF?
Ugh, what the heck...I changed the name of the macro to "ABC" (in all references), just to ensure I wasn't misnaming something but its still throwing the same "Undefined function".
Where is the "player editable" toggle for a macro? Only thing checked off on the "ABC" macro is "Auto Execute" checkbox.
Wouldn't you know that when i finally have time to implement the advice that everyone has been giving ("You should really change all these macros to UDFs"), I run into a problem on the very first one?
Where is the "player editable" toggle for a macro? Only thing checked off on the "ABC" macro is "Auto Execute" checkbox.
Wouldn't you know that when i finally have time to implement the advice that everyone has been giving ("You should really change all these macros to UDFs"), I run into a problem on the very first one?
Re: Sample of a UDF?
Well, you could look at the Wiki: getInfo() and it will tell you all the defined udfs. This does sound familiar, like something I've done and I think it was an easy fix. The Allow Players to Edit is in the properties | options of the macro.
Code: Select all
[dialog("D"):{<pre>[R: json.indent(replace(getInfo("server"),"<","<"))]</pre>}]
Downloads:
- Notepad++ MapTool addon
- RPEdit details (v1.3)
- Coding Tips: Modularity and Design
- Videos: Macro Writing Tools
Re: Sample of a UDF?
So, doesn't look like any UDFs are being created...
{
"timeInMs": 1487012281830,
"restricted impersonation": 0,
"tooltips for default roll format": 1,
"movement locked": 0,
"initiative owner permissions": 0,
"gm": ["jramirez"],
"individual views": 0,
"movement metric": "ONE_TWO_ONE",
"players can reveal": 0,
"strict token management": 0,
"players receive campaign macros": 0,
"timeDate": "2017-02-13 11:58:01"
}
The only place I could find some kind of "Allow Players to Edit Macros" was in Preferences...but I don't think that's where you're talking about when you say "is in the properties | options of the macro". When I edit the macro, I see no flag/checkbox for this...am I missing something obvious?
{
"timeInMs": 1487012281830,
"restricted impersonation": 0,
"tooltips for default roll format": 1,
"movement locked": 0,
"initiative owner permissions": 0,
"gm": ["jramirez"],
"individual views": 0,
"movement metric": "ONE_TWO_ONE",
"players can reveal": 0,
"strict token management": 0,
"players receive campaign macros": 0,
"timeDate": "2017-02-13 11:58:01"
}
The only place I could find some kind of "Allow Players to Edit Macros" was in Preferences...but I don't think that's where you're talking about when you say "is in the properties | options of the macro". When I edit the macro, I see no flag/checkbox for this...am I missing something obvious?
Re: Sample of a UDF?
Sorry, brain fart. It should be "client" not "server" info.
Code: Select all
{
"timeInMs": 1487022662329,
"client id": "b1a1fc2e-5092-457e-82dd-f95047b1a39e",
"library tokens": {
"Lib:CannedSpeech_v1": "unknown",
"Lib:inventory": "unknown",
"lib:player_Nicholas": "unknown",
"Lib:Magic": "unknown",
"lib:player_DM": "unknown",
"Lib:Play": "unknown",
"Lib:libDnD35Pathfinder": "unknown",
"lib:player_Ray": "unknown",
"lib:rpedit": "unknown",
"Lib:spells": "unknown",
"lib:healbot": "unknown",
"Lib:Spell_database": "unknown",
"Lib:debugger": "unknown",
"Lib:msg_mngr": "unknown",
"lib:players": "unknown",
"lib:dialog": "unknown",
"lib:DM": "unknown",
"lib:player_Sage": "unknown",
"Lib:UDFunctionsLGM": "unknown",
"lib:token": "unknown",
"lib:pathfinder": "unknown",
"lib:skills": "unknown",
"lib:player_Trey": "unknown",
"lib:pf_Feats": "unknown",
"lib:disguise": "unknown",
"lib:pf_Skills": "unknown",
"Lib:GlobalsSRDPF": "unknown",
"lib:player_Chris": "unknown",
"lib:player_Nick": "unknown",
"Lib:cifTemplates": "unknown",
"Lib:SpeakForMe": "unknown",
"Lib:spells3": "unknown",
"lib:player_Bryan": "unknown",
"Lib:TokenManager_v2.0": "unknown"
},
"user defined functions": [
"math.isOdd",
"am.dialog.oneClick",
"am.play.ClearSoftFog",
"am.play.updateGMs",
"SpellLibrary",
"am.play.imageHeader",
"dbxLaunch",
"Config_Library",
"am.play.popup",
"am.rpe.strComment",
"am.play.getServerName",
"json.pappend",
"am.play.initServer",
"json.psort",
"am.play.onTokenMove",
"am.rpe.getGroups",
"json.sort",
"am.play.isTokenId",
"am.rpe.reformatMacroOutput",
"am.hb.onCampaignLoad",
"am.play.watch",
"am.dialog.parseDialog",
"glp",
"getSpellIndex",
"am.getModStamp",
"am.play.updateTargets",
"am.pf.onCampaignLoad",
"am.defineTokenCoords.sub",
"am.getMonsterXp",
"framePopup",
"am.rpe.onCampaignLoad",
"distanceStatSheet",
"json.fromMacros",
"am.play.fixPath",
"am.rpe.local.loadOptions",
"am.play.output.icc",
"json.type",
"am.label",
"am.play.getGMNames",
"getSkillCheckLink",
"InfoBank",
"am.pf.editClass",
"am.play.formatChatText",
"oneClickLink",
"mil",
"json.reverse",
"am.play.gotoMap",
"am.play.multiSelectChange",
"am.rpe.slp",
"am.play.gotoMapLink",
"am.play.getServerTime",
"replaceStr",
"rspk.displaySpeech",
"am.hb.getStatusImage",
"am.hb.tokenUpdate",
"xx.lib.reload",
"am.hb.saveSettings",
"json.pRemove",
"am.dialog.rawDialog",
"reduceSpeedStep",
"refresh",
"cl",
"am.rpe.configOptions",
"am.play.runOnServer",
"am.hb.cureSpell.tab",
"am.play.getServerProperty",
"am.play.onMultipleTokensMove",
"displayDebug",
"am.play.icc",
"am.pfStatBlockImport",
"xx.lib.label",
"am.rpe.tool.editButtons.form",
"am.hb.getHealTargets",
"am.pf.initWeaponData",
"am.pause",
"am.rpe.closeOpenFrames",
"xx.lib.getPlayerGroups",
"list.difference",
"am.rpe.setMinWidths",
"rspk.speakForDialog",
"json.insert",
"getLibPlayerPref",
"am.gotoSelect",
"am.damageLink",
"json.toTooltip",
"am.rpe.openDebugger",
"am.pf.initClasses",
"am.play.label",
"json.pAppend",
"am.rpe.getStdMinWidth",
"myEval",
"am.rpe.formatAll",
"am.play.varsToJson",
"dbxOutputTo",
"am.dialog.getSkillCheckLink",
"tabSetup",
"am.dialog.oneClickLink",
"rspk.createSpeakDialog",
"am.output.basic",
"am.play.output",
"am.rpe.debug",
"get.targets",
"am.rpe.verifyId",
"am.dialog.uglySkillCheck",
"am.sk.SkillCheck",
"listDelete.trim",
"am.rpe.addDebug",
"am.rpe.processForm",
"am.play.saveChatTranscripts",
"css.main",
"json.toVars",
"skillRoll",
"am.toggleMod",
"am.play.configLibProperties",
"math.mod",
"r.currentToken",
"am.hb.output.basic",
"am.play.cleanVar",
"am.pf.createItemId",
"am.hb.lifelink.tab",
"json.pGet",
"am.hb.customCure.tab",
"am.setModStamp",
"am.play.output.room",
"am.hb.settings.tab",
"am.slopeRangeCheck",
"editSpeech",
"am.hb.lifelink.process",
"am.play.findTokenMap",
"roundPoint",
"am.play.spanBlockHtml.sub",
"am.hb.getPlayerGroups",
"am.hb.getSettings",
"getFeat",
"am.play.INSPECT",
"am.hb.healBot.defaults",
"am.play.splashScreen",
"am.play.PLAYERSWIP",
"am.play.gotoLibMap",
"am.play.clearSoftFOW",
"am.play.jsonToVars",
"am.play.multiDeselectChange",
"am.sk.setSkills",
"am.dialog.uniqueSaveCheck",
"am.play.VBLMove",
"json.fromMacros.withProps",
"am.rpe.setStandardButtons",
"am.play.isServer",
"json.pget",
"jaw.cspeech.displayPrefs",
"am.play.Impersonate",
"am.play.getPlayerProperty",
"am.play.onCampaignLoad",
"am.rpe.debugReport",
"am.play.confusionMessage",
"am.pf.cleanProp",
"am.getFlankers",
"canUseResetProperty",
"getSpellName",
"am.play.serverOnly",
"am.play.setPlayerProperty",
"am.dialog.onCampaignLoad",
"am.play.deferFunction",
"xx.lib.pause",
"mod",
"am.dialog.uglySaveCheck",
"am.toggleItem",
"uglySkillCheck",
"am.rpe.refreshGroups",
"am.lifelink",
"am.play.setTokenXY",
"am.hb.merciesTip",
"redefined_1_debug",
"am.rpe.parseMacros",
"adjustHP",
"am.watch",
"am.changeElevation",
"am.rpe.local.loadGroupsMenu",
"am.rpe.editTokenMacros",
"am.rpe.watch",
"createMacro.u",
"xx.lib.output.basic",
"setPageCache",
"am.pf.deleteClass",
"slp",
"am.hb.clericChannel.tab",
"am.tabTable",
"am.play.errorMessage",
"am.hb.reload",
"am.play.saveChat",
"am.rpe.tool.editButtons.link",
"am.play.tokenHeader",
"am.play.PFConfusion",
"am.rpe.tool.editButtons",
"CannedSpeech.ui",
"am.play.createToken",
"getSeenTokens",
"am.play.openSelectFrame",
"am.play.onSelectToken",
"am.rpe.selectMacroIndexes",
"am.rpe.glp",
"am.play.inspectToken",
"am.play.inspectAll",
"redefined_0_json.paths",
"json.ifGet",
"am.play.moveVBLToken",
"am.isFlanking",
"am.play.waitForServer",
"am.hb.layOnHands.tab",
"setLibPlayerPref",
"getBody",
"am.play.autoExecute",
"am.rpe.openFrame",
"saySpeech",
"am.dm.disguiseMacro",
"l.decode",
"am.play.setAsServer",
"outputTo",
"am.play.deferVBLMove",
"getShortDescription",
"math.div",
"libAttack.sub",
"searchSpellLink",
"math.dim",
"am.play.setServerProperty",
"am.play.getTokenInfo",
"constructMacro",
"rspk.getMyTokens",
"am.play.hasServer",
"list.unique",
"msl",
"am.hb.healBot",
"json.layout.editable",
"am.pf.addWeapon",
"am.mirrorImage",
"am.hasHighGround",
"am.play.validateTokenInfo",
"cif.t.removeTemplate",
"am.play.serverTest",
"manageSpeech",
"am.play.doVBLMove",
"am.play.execFunction",
"am.hb.channel.process",
"displaySpeech",
"am.rpe.tool.editButtons.css",
"am.dialog.description",
"am.bullRushSpellPF",
"json.layout",
"cif.t.drawTemplate",
"am.merciesTip",
"am.tokenImageLink",
"am.rpe.renameGroup",
"am.hb.oracleChannel.tab",
"pause",
"am.rpe.updateMacros",
"am.play.movementLock",
"am.sk.skillRoll",
"am.play.output.basic",
"am.getRangedDistance",
"am.dialog.skillCheck",
"am.rpe.EditToken",
"plo.specOutput",
"am.rpe.local.loadMenu",
"am.rpe.saveMacros",
"am.rpe.removeDebug",
"am.rpe.setOption",
"displayWhisperFrame",
"am.rpe.watchList",
"rspk.configStates",
"am.play.setupServer",
"spellReport",
"setSize",
"r.eval",
"am.rpe.setDefaultConfig",
"am.play.deferCondition",
"json.pSet",
"getSpellData",
"am.play.pause",
"debug",
"am.play.MoveLock",
"json.paths",
"am.pf.chooseClass",
"am.rpe.loadMacros",
"say",
"am.getPlayerGroups",
"am.play.addPlayer",
"getPageCache",
"am.dialog.uniqueSkillCheck",
"gotoLocation",
"am.hb.healbot.header",
"am.sk.onCampaignLoad",
"json.pset",
"xx.lib.watch",
"am.rpe.mtVarPixelCount",
"am.play.drawFromDeck",
"makeKeywordSpellList",
"am.dialog.getSaveLink",
"xx.lib.onCampaignLoad",
"startsWith"
],
"face edge": 1,
"isFullScreen": 0,
"portrait size": 100,
"show stat sheet": true,
"version": "1.4.1.7",
"timeDate": "2017-02-13 13:51:02",
"face vertex": 1
}
Downloads:
- Notepad++ MapTool addon
- RPEdit details (v1.3)
- Coding Tips: Modularity and Design
- Videos: Macro Writing Tools
Re: Sample of a UDF?
Gah, what the heck...there's the UDF!
So if its showing up there, why does it throw the "Undefined Function" error when I try to call it? I'm calling it like so...
That sure seems correct...right?
Code: Select all
{
"timeInMs": 1487040620196,
"client id": "cc51caf7-41fd-4ebe-b7e2-ffddc262864a",
"library tokens": {"lib:Math": "unknown"},
"user defined functions": [
"LineIntersection@Lib:Math",
"DistanceBetweenPoints@Lib:Math",
"ABC@Lib:Math"
],
"face edge": 1,
"isFullScreen": 0,
"portrait size": 175,
"show stat sheet": true,
"version": "1.4.0.5",
"timeDate": "2017-02-13 19:50:20",
"face vertex": 0
}
Code: Select all
[h : intersectionResult = ABC(pointP, pointQ, pointR, pointZ)]
Re: Sample of a UDF?
GOT IT!
Had the function name and the actual macro/tobken swapped in the "defineFunction" call! Now its working!
Had the function name and the actual macro/tobken swapped in the "defineFunction" call! Now its working!