Macro Best Practices

Discuss macro implementations, ask for macro help (to share your creations, see User Creations, probably either Campaign Frameworks or Drop-in Resources).

Moderators: Azhrei, dorpond, trevor, giliath, jay, Mr.Ice

Post Reply
User avatar
toyrobots
Dragon
Posts: 278
Joined: Sat Apr 12, 2008 4:17 pm

Macro Best Practices

Post by toyrobots »

Has anyone established "best practices" for macro code?

For example, the case conventions of property names, string property names, local variables, etc?

I'm about to start a big campaign file project in a few weeks and I'd like to adopt some standards of someone who knows better than I do... but furthermore, some standards would enable better communication on the forums.

Any thoughts?

User avatar
zEal
Dragon
Posts: 944
Joined: Sun Mar 22, 2009 2:25 am

Re: Macro Best Practices

Post by zEal »

Ask 5 different programmers this question, and you'll probably get 8 different answers.

My Recommendations:
  • It doesn't matter how many spaces you use to indent, just be consistent. Everyone will like you better for it if you have to ask for help with a particular piece of code.
  • dontBeAfriadToMakeVariablesWithLongNames (okay, that's an extreme example) it may take you a little longer to type it all out, but it makes understanding your code so much easier.
  • If the difference between [t:] and [e:] is going to break your layout, don't rely on the default.
Beyond that, pick something you're comfortable with, and stick with it.

User avatar
RPTroll
TheBard
Posts: 3148
Joined: Tue Mar 21, 2006 7:26 pm
Location: Austin, Tx
Contact:

Re: Macro Best Practices

Post by RPTroll »

Answer 2:

Create property names with an upper case first letter and local vars with a lower case first letter then uppercase a word change

Strength = token property
strVar = local variable

Use getLibProperty and setLibProperty ALWAYS when dealing with Lib: token properties. If you don't you're going to be frustrated that your macro can't find the property when the Lib: token is on another map

Use encode()/decode() for every darn string a user might enter

The init panel sucks. Expect problems. Write a function for everything you want to do with it then never touch the controls on the init panel itself.

A two space indent works for me. Others prefer tabs.

JSON=good, Lists=Ok but why not use JSON, StrProps= why not use a JSON'?
ImageImage ImageImageImageImage
Support RPTools by shopping
Image
Image

User avatar
toyrobots
Dragon
Posts: 278
Joined: Sat Apr 12, 2008 4:17 pm

Re: Macro Best Practices

Post by toyrobots »

zEal wrote:Ask 5 different programmers this question, and you'll probably get 8 different answers.


Eight ideas to steal? I'm down with that, consider the question asked.

RPTroll wrote:Answer 2:

Create property names with an upper case first letter and local vars with a lower case first letter then uppercase a word change

Strength = token property
strVar = local variable


Yay, I do this too!

I want more! Prolific macro-smiths, post your conventions!

User avatar
zEal
Dragon
Posts: 944
Joined: Sun Mar 22, 2009 2:25 am

Re: Macro Best Practices

Post by zEal »

I prefer the practice of putting branch brackets on their own line.

Code: Select all

[if(something), code:
{
  [dosomething]
};{
  [dosomethingelse]
}]


Since variables are not case sensitive (>.<) I don't rely on case conventions to tell me what is a property and what is a variable; I always use get/setProperty() (I actually always use custom get/set() functions, but that's a different story)

If it's something you're going to do more than once with little variation, create a user defined function.

Putting as much code as possible on library tokens should help with transfer speeds, since IIRC the entire token is transfered when properties are updated. Since pc/npc tokens are changed the most, try to keep them lean. Plus, redundant code sucks.

Make your framework(if that's what you intend to create) i18n ready. This is easier than it sounds.

Don't use 'magic numbers', if need be create a series of variables at the beginning of your macro that will function as 'constants'.

Don't rely on line-wrapping; try to find ways to break your lines into manageable lengths on your own.

User avatar
jfrazierjr
Deity
Posts: 5175
Joined: Tue Sep 11, 2007 7:31 pm

Re: Macro Best Practices

Post by jfrazierjr »

zEal wrote:My Recommendations:
[list]
[*]dontBeAfriadToMakeVariablesWithLongNames (okay, that's an extreme example) it may take you a little longer to type it all out, but it makes understanding your code so much easier.
.


Along with this, when asking for help, put in all your variables instead of letting people guess whats in your properties that you did not show.

This

Code: Select all

      [h: enemyList="Orcs, Goblins, Ogres, Trolls"]
      [FOREACH(enemy, enemyList, "<br>"): "You really hate " + enemy]


is INFINITELY more likely to get me to response to your post that this:

Code: Select all

      
      [FOREACH(enemy, enemyList, "<br>"): "You really hate " + enemy]


because now I know exactly what enemyList will contain. Of course, this is a simple example, but as you can see, it is 100% self contained. If anyone posts up macro code that is not self contained (or with an attached campaign file), I will likely not respond because it takes to much set up work just to begin looking at the issue.
Last edited by jfrazierjr on Thu Apr 16, 2009 2:15 pm, edited 1 time in total.
I save all my Campaign Files to DropBox. Not only can I access a campaign file from pretty much any OS that will run Maptool(Win,OSX, linux), but each file is versioned, so if something goes crazy wild, I can always roll back to a previous version of the same file.

Get your Dropbox 2GB via my referral link, and as a bonus, I get an extra 250 MB of space. Even if you don't don't use my link, I still enthusiastically recommend Dropbox..

User avatar
Veggiesama
Dragon
Posts: 619
Joined: Wed Aug 29, 2007 1:18 am

Re: Macro Best Practices

Post by Veggiesama »

Write extremely modular code and avoid the monolithic macros. I made this mistake way too many times, and it bites you in the donkey later with stack size and unreadability issues.

Write separate macros for input, execution, and display (there are obviously other ways you want to categorize, too). Box up necessary variables in JSON objects, so if you decide down the road you no longer want to use the input() function for player inputted data, you can make a separate input macro that uses frame(), dialog(), whatever comes out in the future, etc. The underlying execution will remain the same, but you'll have multiple ways of giving it the needed data, along with multiple ways to display it.

For example, I'm working on a very simple Shadowrun 4th Ed framework now. Since I want to customize how dice are rolled, I have these three macros: inputDice, rollDice, displayDice.

Later on, I wrote an initiative macro. Initiative is handled a little strangely, but it still involves rolling dice. So I wrote inputInit and setupInit. It still involves rolling dice (along with all the special options that rollDice can do for me), but there is an extra step involved: adding the tokens to the initiative panel. So here's what the execution looks like:

Rolling dice:

Code: Select all

inputDice --> rollDice
          --> displayDice


Rolling initiative:

Code: Select all

inputInit --> rollDice
          --> displayDice
          --> setupInit


Even though inits are done a little differently from regular dice rolls, I can still re-use previous code. Yes, there is a lot of boxing/unboxing of variables that goes on, but it helps to make things explicit.
My D&D 4e Campaign FrameworkMy Shadowrun 4e Campaign Framework
RPGA#: 5223846427 — Skype: Veggiesama — Fear the ferret.

User avatar
Veggiesama
Dragon
Posts: 619
Joined: Wed Aug 29, 2007 1:18 am

Re: Macro Best Practices

Post by Veggiesama »

Oh, and I agree with the capitalizing token properties. I've done that forever, and I don't even know why I started. I'm surprised a lot of others do it too.

Even though MapTool is case-insensitive, treat it like it's sensitive for consistency's sake.

Also, I use capital letters and underscores for Library properties. That's because I generally treat Library props as constants, so if you don't, I guess using the Token naming convention is fine too.

Local: myVar
Token: MyVar
Library: MY_VAR

And... USE HTML COMMENTS on anything even remotely strange, and don't slack on the description. You'll thank yourself later when you put down the project for a month and try to jump back into it.
Last edited by Veggiesama on Thu Apr 16, 2009 2:26 pm, edited 3 times in total.
My D&D 4e Campaign FrameworkMy Shadowrun 4e Campaign Framework
RPGA#: 5223846427 — Skype: Veggiesama — Fear the ferret.

User avatar
zEal
Dragon
Posts: 944
Joined: Sun Mar 22, 2009 2:25 am

Re: Macro Best Practices

Post by zEal »

Veggiesama wrote:...I have these three macros: inputDice, rollDice, displayDice...So I wrote inputInit and setupInit.
^- This

User defined functions(and the the macros that they run), should always be named starting with a strong verb... because they do something.

User avatar
toyrobots
Dragon
Posts: 278
Joined: Sat Apr 12, 2008 4:17 pm

Re: Macro Best Practices

Post by toyrobots »

zEal wrote:Since variables are not case sensitive (>.<)

Wait, what? They aren't?

Make your framework(if that's what you intend to create) i18n ready. This is easier than it sounds.

I'll bite. Why and how?

Don't use 'magic numbers', if need be create a series of variables at the beginning of your macro that will function as 'constants'.

That sounds like a delicious piece of jargon, but as a novice I'd like you to elaborate.

Thanks!

User avatar
toyrobots
Dragon
Posts: 278
Joined: Sat Apr 12, 2008 4:17 pm

Re: Macro Best Practices

Post by toyrobots »

Veggiesama wrote:Also, I use capital letters and underscores for Library properties. That's because I generally treat Library props as constants, so if you don't, I guess using the Token naming convention is fine too.

Local: myVar
Token: MyVar
Library: MY_VAR



Steal!

User avatar
zEal
Dragon
Posts: 944
Joined: Sun Mar 22, 2009 2:25 am

Re: Macro Best Practices

Post by zEal »

toyrobots wrote:
zEal wrote:Since variables are not case sensitive (>.<)

Wait, what? They aren't?
Afraid not.

toyrobots wrote:
Make your framework(if that's what you intend to create) i18n ready. This is easier than it sounds.

I'll bite. Why and how?
So people that don't speak your language can easily translate it to the language they prefer to speak. Granted, if you never plan to give out your framework, this isn't really necessary. There are many ways you could go about it, I personally use a custom function called lang() that accepts an English string and returns a language specific string based on library token property(the same library token that has all the macros and strings) that contains a ISO 3166-1 alpha-2 country code. This allows me to have all of the 'words' in one place in case someone needs to translate it in the future.

toyrobots wrote:
Don't use 'magic numbers', if need be create a series of variables at the beginning of your macro that will function as 'constants'.

That sounds like a delicious piece of jargon, but as a novice I'd like you to elaborate.
Magic numbers are when you use a literal number in your code where its meaning isn't immediately obvious by adjacent code. Let's say for example that you're creating a framework for a particularly pessimistic game system that likes to subtract 5 from a lot of different things, this hypothetical game system refers to it as Bad Luck. Even though Bad Luck never changes in this system, you don't want to sprinkle a lot of -5's throughout your code, so you create a variable called BadLuck and use that every time you'd use a -5. This is a very basic example, and you might occasionally find yourself accidentally using magic numbers in various situations without realizing it.

User avatar
Rumble
Deity
Posts: 6235
Joined: Tue Jul 01, 2008 7:48 pm

Re: Macro Best Practices

Post by Rumble »

zEal wrote:If it's something you're going to do more than once with little variation, create a user defined function.



This is something I rarely do, and should probably do more, but I never saw a substantial need.

User avatar
Veggiesama
Dragon
Posts: 619
Joined: Wed Aug 29, 2007 1:18 am

Re: Macro Best Practices

Post by Veggiesama »

I know some people like to jump in and start writing, but it often pays to do some thinking beforehand.

Think about the flow of the code. Think about the data structures you'll need. Think about how you want your macros to be accessed and displayed.

Heck, I still write things on paper first: a Weapon object has a damage value (int), a damage type (string: "physical" or "stun"), a concealability modifier (int), etc. Little pictures with arrows work. It's just an aide, though: there's no need to keep this updated as you're writing, since that'll just slow you down.

If I'm going to build a non-simple GUI, I even like to pull out a straight-edge and draw it myself. I like to get it right the first time and not have to constantly re-execute until it looks juuust right.

I'm also kind of a perfectionist.
My D&D 4e Campaign FrameworkMy Shadowrun 4e Campaign Framework
RPGA#: 5223846427 — Skype: Veggiesama — Fear the ferret.

User avatar
toyrobots
Dragon
Posts: 278
Joined: Sat Apr 12, 2008 4:17 pm

Re: Macro Best Practices

Post by toyrobots »

Rumble wrote:
zEal wrote:If it's something you're going to do more than once with little variation, create a user defined function.



This is something I rarely do, and should probably do more, but I never saw a substantial need.


Point me to an explanation of User-Defined Functions in Macros?

Post Reply

Return to “Macros”