Simple VBL Macro

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

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

MandyRae
Cave Troll
Posts: 53
Joined: Sat Mar 12, 2016 11:39 am

Re: Simple VBL Macro

Post by MandyRae »

The tokenVBL can work, I'd just have to change the script to swap tokens instead of images. But I'd have to create "blanks" to generate the VBL with, and swap the image over (and repeat for each wall tile I have, since there's no way to get a single px wide VBL on the token and the rest of my VBL is drawn with the line tool). Anything thicker than that would cause some funky vision issues with the door tiles.

However, the issue with tokenVBL not drawing the bottom px or two prevents me from doing this, at least until that issue gets resolved.
Attachments
05.png
05.png (14.8 KiB) Viewed 676 times
04.png
04.png (11.85 KiB) Viewed 676 times

User avatar
JamzTheMan
Great Wyrm
Posts: 1872
Joined: Mon May 10, 2010 12:59 pm
Location: Chicagoland
Contact:

Re: Simple VBL Macro

Post by JamzTheMan »

Can I make a suggestion?

Create a "Door jamb" image (if needed) and create that door as it's own image. Then for the door token, set it's token VBL and click "always visible". It doesn't need a 1 pixel VBL as the door will show 100% of itself and it can overlap with your door jamb/walls a bit.

Then, your macro (instead of swamping tokens/images) will "move" and "rotate" the door. The VBL will just move with it.

Here is a set of (simple?) macros I use for creating doors:
Set Door to Closed Position

Code: Select all

<!-- MACRO: Set Door to Closed Position -->
[g, if(getPropertyType() == "Pathfinder"): assert(0, "Token already set as a Pathfinder Token...", 0)]

Setting Property Type, Token Shape, isDoor state, isClosed state for current door in Closed position.<br>

[h: getPropertyType()]
[h, if(getPropertyType() != "Nerps.Door"): setPropertyType("Nerps.Door")]

[h: setTokenShape("TOP DOWN")]
[h: setState("isDoor", 1)]
[h: setState("isClosed", 1)]

[h: xClose = getTokenX()]
[h: yClose = getTokenY()]
[h: closedAngle = getTokenFacing()]
Set Door to Open Position

Code: Select all

<!-- MACRO: Set Door to Open Position -->
[g, if(getPropertyType() == "Pathfinder"): assert(0, "Token already set as a Pathfinder Token...", 0)]

Setting Property Type, Token Shape, isDoor state, isClosed state for current door in Open position.<br>

[h: getPropertyType()]
[h, if(getPropertyType() != "Nerps.Door"): setPropertyType("Nerps.Door")]

[h: setTokenShape("TOP DOWN")]
[h: setState("isDoor", 1)]
[h: setState("isClosed", 0)]

[h: xOpen = getTokenX()]
[h: yOpen = getTokenY()]
[h: openAngle = getTokenFacing()]

To use them, you place the door as closed, click the closed door macro. Then Rotate and move the door to how you want it to look as opened, click the open door macro. Then to open/close them, I use:
Open Nearest Door to Token

Code: Select all

<!-- MACRO: Open Nearest Door to Token -->

[h: tokenSelected = getSelected("json")]
[h, if(! json.isEmpty(tokenSelected)), code: {
   [h: tokenB = json.get(tokenSelected, 0)]
   [h, if(getState("isDoor", tokenB)): isDoor = 1; isDoor = 0]
};{
   [h: assert(0, "No tokens selected. Either select a door to open, or select a PC/NPC to open the nearest door to them.", 0)]
}]
   
[h: cond = '{ "range": {"upto":3, "distancePerCell":0, metric:"NO_GRID", "token":"' + tokenB + '"}, "setStates":["isDoor", "isClosed"], "layer":["TOKEN", "OBJECT", "BACKGROUND"] }']
[h, if(isDoor == 0): tokenList = getTokenNames("json", cond); tokenList=tokenSelected]
[h, if(! json.isEmpty(tokenList)): tokenB = json.get(tokenList, 0); assert(0, "No closed doors within 10 feet.", 0)]

[h: distance = 25]
[h: tokenA = getSelected()]

[h, foreach(tempToken, tokenList), code: {
    [h: canSee = 0]
    [h, if(isDoor == 0), code: {
        [h: canSee = !json.isEmpty(canSeeToken(tempToken))]
    };{}]

    [h: this.distance = getDistance(tempToken, 1, tokenA, "NO_GRID")]
    [h, if(this.distance < distance && canSee), code: {
      [h: distance = this.distance]
      [h: tokenB = tempToken]
    };{}]
}]

[h, if(isDoor == 0), code: {
   [h: cantSee = json.isEmpty(canSeeToken(tokenB))]
   [g, if(cantSee): assert(0, "The door, " + getName(tokenB) + ", is out of sight...", 0)]
};{}]

[h, if(getState("Locked", tokenB)): assert(0, "The door appears to be locked.", 0)]

[h, macro("openNearestDoor@Lib:NerpsForPathfinder"): "doorToken=" + tokenB]
[h: selectTokens(tokenSelected, 0, "json")]

[h: exposeAllOwnedArea()]
Close Nearest Door to Token

Code: Select all

<!-- MACRO: Close Nearest Door to Token -->

[h: tokenSelected = getSelected("json")][h, if(! json.isEmpty(tokenSelected)), code: {
   [h: tokenB = json.get(tokenSelected, 0)]
   [h, if(getState("isDoor", tokenB)): isDoor = 1; isDoor = 0]
};{
   [h: assert(0, "No tokens selected.", 0)]
}]

[h: cond = '{ "range": {"upto":3, "distancePerCell":0, metric:"NO_GRID", "token":"' + tokenB + '"}, "setStates":["isDoor"], "unsetStates":["isClosed"], "layer":["TOKEN", "OBJECT", "BACKGROUND"] }']
[h, if(isDoor == 0): tokenList = getTokenNames("json", cond); tokenList=tokenSelected]
[h, if(! json.isEmpty(tokenList)): tokenB = json.get(tokenList, 0); assert(0, "No open doors within 10 feet.", 0)]

[h: distance = 25]
[h: tokenA = getSelected()]

[h, foreach(tempToken, tokenList), code: {
    [h: canSee = 0]
    [h, if(isDoor == 0), code: {
        [h: canSee = !json.isEmpty(canSeeToken(tempToken))]
    };{}]

    [h: this.distance = getDistance(tempToken, 1, tokenA, "NO_GRID")]
    [h, if(this.distance < distance && canSee), code: {
      [h: distance = this.distance]
      [h: tokenB = tempToken]
    };{}]
}]

[h, if(isDoor == 0), code: {
   [h: cantSee = json.isEmpty(canSeeToken(tokenB))]
   [g, if(cantSee): assert(0, "The door, " + getName(tokenB) + ", is out of sight...", 0)]
};{}]

[h, macro("closeNearestDoor@Lib:NerpsForPathfinder"): "doorToken=" + tokenB]
[h: selectTokens(tokenSelected, 0, "json")]

[r: exposeAllOwnedArea()]

You can simplify these macros but as they are, if you click the door and click the macro, it open/closes that door. If you click a PC token, it open/closes the nearest door to them that they can see (prevents you from having to switch layers) and can even be used by players. As a bonus: Lock your doors and create secret doors!
Lock the door!

Code: Select all

<!-- MACRO: Toggle Door Lock -->
[H: assert( isGM(), "<b>" + getMacroName() + "</b> is a GM only macro.", 0 )]

[h: tokenSelected = getSelected("json")]
[h, if(! json.isEmpty(tokenSelected)): tokenB = json.get(tokenSelected, 0)]
[h, if(getState("isDoor", tokenB)): isDoor = 1; isDoor = 0]

[h: cond = '{ "range": {"upto":2, "distancePerCell":0, metric:"NO_GRID", "token":"' + tokenB + '"}, "setStates":["isDoor"], "layer":["TOKEN", "HIDDEN", "OBJECT", "BACKGROUND"] }']
[h, if(isDoor == 0): tokenList = getTokenNames("json", cond); tokenList=tokenSelected]
[h, if(! json.isEmpty(tokenList)): tokenB = json.get(tokenList, 0); assert(0, "No open doors within 10 feet.", 0)]

[h: distance = 25]
[h: tokenA = getSelected()]

[h, foreach(tempToken, tokenList), code: {
   [h: this.distance = getDistance(tempToken, 1, tokenA, "NO_GRID")]
   [h, if( this.distance < distance), code: {
      [h: distance = this.distance]
      [h: tokenB = tempToken]
   };{}]
}]


<!-- TokenList= list of token IDs ; State= statename like Dazed ; Action= 0-clear, 1-set, 2-toggle -->
[H: state = "Locked" ]
[H: action = 2 ]

<!-- DO NOT EDIT BELOW HERE -->

[H: passedVars = json.set( "{}", "TokenList", tokenB, "State", state, "Action", action)]
[MACRO( "changeState@Lib:NerpsForPathfinder" ): passedVars]
[R, S, G: macro.return]

[h: lockNotes = trim(getGMNotes(tokenB))]
[h, IF(getState("Locked", tokenB) && lockNotes == "" ), CODE:{
	[H: cancel = input("notes|Disable Device DC |Notes for door when locked, eg Disable DC, hardness, etc:| TEXT | WIDTH=25")]
    [h, IF(cancel), CODE:{
        [h: notes = "<FONT size=4>" + notes + "</FONT>"]
        [h: notes = replace(notes, "(DC [0-9]+)", "<FONT COLOR=RED><b>\$1</b></FONT>")]
        [H: setGMNotes(notes, tokenB)]
    }]
}]

Make it secret!

Code: Select all

<!-- MACRO: Toggle Secret Door -->
[h: assert( isGM(), "<b>" + getMacroName() + "</b> is a GM only macro.", 0 )]

[h: tokenSelected = getSelected("json")]
[h, if(!json.isEmpty(tokenSelected)): tokenB = json.get(tokenSelected, 0)]
[h, if(getState("isDoor", tokenB)): isDoor = 1; isDoor = 0]

[h: cond = '{ "range": {"upto":2, "distancePerCell":0, metric:"NO_GRID", "token":"' + tokenB + '"}, "setStates":["isDoor"], "layer":["TOKEN", "HIDDEN", "OBJECT", "BACKGROUND"] }']
[h, if(isDoor == 0): tokenList = getTokenNames("json", cond); tokenList=tokenSelected]
[h, if(!json.isEmpty(tokenList)): tokenB = json.get(tokenList, 0); assert(0, "No open doors within 10 feet.", 0)]

[h: distance = 25]
[h: tokenA = getSelected()]

[h, foreach(tempToken, tokenList), CODE: {
	 [h: this.distance = getDistance(tempToken, 1, tokenA, "NO_GRID")]
	 [h, if( this.distance < distance), CODE: {
			[h: distance = this.distance]
			[h: tokenB = tempToken]
	 };{}]
}]

[h, if(isDoor == 0), CODE: {
	[h, if(getProperty("Type", tokenB) != "Secret" || getState("Locked", tokenB) == 1), CODE: {
		[h: assert(0, "No secret doors within 10 feet.", 0)]
	}]
};{
	[h, if(getProperty("Type", tokenB) != "Secret"), CODE: {
		[h: setProperty("Type", "Secret", tokenB)]
		[h: setState("isSecret", 0, tokenB)]
	}]
}]

[h, if(getState("isSecret", tokenB)), CODE: {
	[h: setLayer("OBJECT", tokenB)]
};{
	[h: setLayer("HIDDEN", tokenB)]
}]

<!-- TokenList = list of token IDs ; State= statename like Dazed ; Action= 0-clear, 1-set, 2-toggle -->
[H: state = "isSecret" ]
[H: action = 2 ]

<!-- DO NOT EDIT BELOW HERE -->

[H: passedVars = json.set( "{}", "TokenList", tokenB, "State", state, "Action", action)]
[MACRO( "changeState@Lib:NerpsForPathfinder" ): passedVars]
[R, S, G: macro.return]
-Jamz
____________________
Custom MapTool 1.4.x.x Fork: maptool.nerps.net
Custom TokenTool 2.0 Fork: tokentool.nerps.net
More information here: MapTool Nerps! Fork

MandyRae
Cave Troll
Posts: 53
Joined: Sat Mar 12, 2016 11:39 am

Re: Simple VBL Macro

Post by MandyRae »

Many thanks Jamz!! I think I can work with your code and a few modifications to my images and be totally happy! However, looking at your code, something tells me that it requires a little more set up beyond simply copying the code over . . . it references property types and states, which leaves me to believe that I would either need to change those to match what I'm using, or create them to make the code work properly, correct?

MandyRae
Cave Troll
Posts: 53
Joined: Sat Mar 12, 2016 11:39 am

Re: Simple VBL Macro

Post by MandyRae »

Okay, so I decided to try the copyToken route . . . and I am able to copy the token over from another map. But when I try to define the X and Y coordinate location to copy the new token to I get an error message:

Argument number 4 to function "copyToken" must be a JSON Object.

This is the code I'm running:

Code: Select all

[h: X = getTokenX()]
[h: Y = getTokenY()]

[h: updates = "{
                 x: X,
                 y: Y,
               }"
]

[h: copyToken("Reinforced_Door_Closed",1,"Images", updates)]


MandyRae
Cave Troll
Posts: 53
Joined: Sat Mar 12, 2016 11:39 am

Re: Simple VBL Macro

Post by MandyRae »

Made the changes to the code, now getting error message saying jsonobject["x"] is not a number

MandyRae
Cave Troll
Posts: 53
Joined: Sat Mar 12, 2016 11:39 am

Re: Simple VBL Macro

Post by MandyRae »

Finally got the code to function properly:

Code: Select all

[r: Door = getProperty("Closed")]

[h: updates = '{
	x: "[r: X = getTokenX(0)]",
	y: "[r: Y = getTokenY(0)]",
	facing: "[r:  Facing = getTokenFacing()]",
	}'
]

[h: copyToken(Door,1,"Doors", updates)]

[r: ids = getSelected()]

[h: removeToken(ids)]
All that is missing is a way to reveal the newly opened area automatically as well . . . any suggestions?

User avatar
wolph42
Winter Wolph
Posts: 9999
Joined: Fri Mar 20, 2009 5:40 am
Location: Netherlands
Contact:

Re: Simple VBL Macro

Post by wolph42 »

Wiki: exposeFOW() and you'll probly also need Wiki: selectTokens()

alternatively you could use: Wiki: exposePCOnlyArea() but that resets all FOW where the players were (but currently can't see). In terms of performance this is always good to use as it does not overload the tokens with FOW data, but some GM prefer to have cleared area to stay cleared.

User avatar
JamzTheMan
Great Wyrm
Posts: 1872
Joined: Mon May 10, 2010 12:59 pm
Location: Chicagoland
Contact:

Re: Simple VBL Macro

Post by JamzTheMan »

MandyRae wrote:Many thanks Jamz!! I think I can work with your code and a few modifications to my images and be totally happy! However, looking at your code, something tells me that it requires a little more set up beyond simply copying the code over . . . it references property types and states, which leaves me to believe that I would either need to change those to match what I'm using, or create them to make the code work properly, correct?

Sorry, yes, I have a custom propertyType called Nerps.Door, you can rename it if you want, and it only has these properties:
Nerps.Door

Code: Select all

*#closedAngle
*#openAngle
*#_currentFacing:{getTokenFacing()}
*#originalFacing
*#xOriginal
*#yOriginal
*#xClose
*#yClose
*#xOpen
*#yOpen
*#Type:Normal
-Jamz
____________________
Custom MapTool 1.4.x.x Fork: maptool.nerps.net
Custom TokenTool 2.0 Fork: tokentool.nerps.net
More information here: MapTool Nerps! Fork

Post Reply

Return to “Macros”