<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.fetishquest.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=JasX</id>
	<title>FetishQuest Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.fetishquest.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=JasX"/>
	<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php/Special:Contributions/JasX"/>
	<updated>2026-07-25T18:55:57Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.0</generator>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Wrapper_(Asset)&amp;diff=343</id>
		<title>Wrapper (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Wrapper_(Asset)&amp;diff=343"/>
		<updated>2026-06-06T11:19:10Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A wrapper is a collection of effects to run immediately, ticking, on events, or passively. Wrappers with no duration are called instant effects. Wrappers with an infinite duration are called passives. And wrappers with a limited duration are called buffs or debuffs depending on what they do.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique label for your wrapper. &#039;&#039;&#039;Do not change after finishing creating your wrapper!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Editor Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Adds a short description of your wrapper to help you locate it when searching. This field is only used in the editor, and not shown in game.&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Name of your wrapper. Doesn&#039;t have to be unique. Only needed in buffs/debuffs.&lt;br /&gt;
|-&lt;br /&gt;
|Icon&lt;br /&gt;
|[[Icon]]&lt;br /&gt;
|&lt;br /&gt;
|Icon of your wrapper. Only needed in buffs/debuffs.&lt;br /&gt;
|-&lt;br /&gt;
|Target&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Target of your wrapper. Auto, Caster and AoE are the most commonly used one.&lt;br /&gt;
|-&lt;br /&gt;
|Duration&lt;br /&gt;
|String&lt;br /&gt;
|0&lt;br /&gt;
|How long the effect should last. Using -1 on a wrapper applied in combat will last until combat ends. Can be a formula.&lt;br /&gt;
|-&lt;br /&gt;
|Stacks&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Amount of stacks to add. Leave at 1 for instant effects.&lt;br /&gt;
|-&lt;br /&gt;
|Max Stacks&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Max stacks a player can have. Leave at 1 for instant effects.&lt;br /&gt;
|-&lt;br /&gt;
|Rarity&lt;br /&gt;
|String&lt;br /&gt;
|COMMON&lt;br /&gt;
|Only used for wrappers attached to armor. Used to set the color of the tooltip.&lt;br /&gt;
|-&lt;br /&gt;
|Unique&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When unique, players can only have one wrapper of this type, regardless of caster. Otherwise you may have one instance of each wrapper per caster.&lt;br /&gt;
|-&lt;br /&gt;
|Hidden&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Don&#039;t show the icon on the player.&lt;br /&gt;
|-&lt;br /&gt;
|Trigger Immediate&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Doesn&#039;t affect instant effects. When checked, trigger all valid effects immediately when the wrapper is applied, otherwise it triggers the first time on their turn.&lt;br /&gt;
|-&lt;br /&gt;
|Tick on turn start&lt;br /&gt;
|Boolean&lt;br /&gt;
|True&lt;br /&gt;
|Triggers effects when the player&#039;s turn starts.&lt;br /&gt;
|-&lt;br /&gt;
|Stack time&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When true, duration is added to any existing wrappers, otherwise duration resets to what the duration was set to in the incoming wrapper.&lt;br /&gt;
|-&lt;br /&gt;
|Tick on team turn end&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Triggers effects when the player&#039;s team members have all ended their turns.&lt;br /&gt;
|-&lt;br /&gt;
|Tick on personal turn end&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Triggers effects when the player hits the end turn button (or similar), regardless of if their team members have ended their turn or not.&lt;br /&gt;
|-&lt;br /&gt;
|Global&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When checked, all players will receive this wrapper as a passive when they&#039;re placed in world. Use sparingly!&lt;br /&gt;
|-&lt;br /&gt;
|Use game timer&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|By default, duration is in turns. If you check use game timer, the duration becomes in-game seconds. Mainly used by buffs and debuffs related to items and random events, and talents. When linked to a talent, use game timer is automatically enforced since it puts the icon at the bottom of your portrait.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Describe the wrapper. You can use special vars here such as modifying a value by damage taken/done etc. See [[Action (Asset)|Action]] for a list of valid variables. In addition to the Action variables, there&#039;s a few special ones for wrappers.&lt;br /&gt;
|-&lt;br /&gt;
|Tags&lt;br /&gt;
|[[Tag]]&lt;br /&gt;
|&lt;br /&gt;
|Tags applied to the target. Use wr_ tags.&lt;br /&gt;
|-&lt;br /&gt;
|Effects&lt;br /&gt;
|[[Effect (Asset)|Effect]]&lt;br /&gt;
|interrupt&lt;br /&gt;
|Effects to trigger as long as their conditions match.&lt;br /&gt;
|-&lt;br /&gt;
|Add Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions required to apply this to a target. If you&#039;re using a multi-target target, then each target will be checked before applying it to them individually.&lt;br /&gt;
|-&lt;br /&gt;
|Stay Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions required for this wrapper to stay on its target.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Description vars ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Var&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|%knockdown&lt;br /&gt;
|Can be used if the wrapper has a knockdown effect. Returns stomach or back.&lt;br /&gt;
|-&lt;br /&gt;
|%caster / %S&lt;br /&gt;
|Colored name of caster (sender).&lt;br /&gt;
|-&lt;br /&gt;
|%target / %T&lt;br /&gt;
|Colored name of target.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Description condition lines ==&lt;br /&gt;
A line may start with |AC:&amp;lt;condition&amp;gt;,&amp;lt;condition&amp;gt;...|. If conditions between |AC: and the closing pipe are not met, the whole line is removed. This takes place on wrapper ADD and is never checked after that. Use sparingly. Currently it&#039;s only used for overWhelmingOrgasm because the label is hardcoded.&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=FQCrop_Batch&amp;diff=342</id>
		<title>FQCrop Batch</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=FQCrop_Batch&amp;diff=342"/>
		<updated>2026-06-05T14:30:02Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following is a script you can use along with the [[Creating Advanced Art Layers|Creating Advanced Art Layers Guide]] to speed up connecting your advanced art layers to your FQ mod.&lt;br /&gt;
&lt;br /&gt;
To use it, simply copy the content into a new text file and name it fqcrop_batch.jsx&lt;br /&gt;
&lt;br /&gt;
You can either put this in your Phothoshop/Presets/Scripts folder and restart photoshop to use it from file &amp;gt; scripts. Or you can go to file &amp;gt; scripts &amp;gt; browse.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
	Note: This is similar to the fqcrop.jsx file except it exports all layers one at a time.&lt;br /&gt;
	Usage: See fqcrop.jsx for more info. Things you need to keep in mind in this implementation:&lt;br /&gt;
	- Each art layer can only consist of ONE photoshop layer&lt;br /&gt;
	- All layers must begin with &amp;lt;layerNr&amp;gt;_ ex 30_bikini_light_ub to use layer 30 (upper body base)&lt;br /&gt;
	- A JSON metadata file named the same as the original file will be created or updated. It&#039;s going to need a bit of editing, but you can use it to quickly upload a full character.&lt;br /&gt;
	- Layers and groups starting with # are ignored.&lt;br /&gt;
	- If a JSON file exists, it&#039;s loaded and updated. Missing layers aren&#039;t deleted from it. So if you remove layers you have to remove them from the JSON file or delete the JSON file to generate a new one.&lt;br /&gt;
	- The following values are overwritten into the JSON file, using the photoshop settings:&lt;br /&gt;
		- icon&lt;br /&gt;
		- x&lt;br /&gt;
		- y&lt;br /&gt;
		- blendMode (only normal, multiply, overlay are supported)&lt;br /&gt;
		- opacity&lt;br /&gt;
*/&lt;br /&gt;
var startRulesUnits = preferences.rulerUnits;&lt;br /&gt;
var doc = activeDocument;&lt;br /&gt;
var docW = doc.width;&lt;br /&gt;
var docH = doc.height;&lt;br /&gt;
var allLayers = [];&lt;br /&gt;
var dirJson = decodeURI(doc.path.fsName)+&amp;quot;/&amp;quot;;&lt;br /&gt;
var jsonName = doc.name.split(&amp;quot;.&amp;quot;);&lt;br /&gt;
jsonName.pop();&lt;br /&gt;
var fName = jsonName.join(&#039;_&#039;)&lt;br /&gt;
var dir = dirJson+fName+&amp;quot;/&amp;quot;;&lt;br /&gt;
jsonName = jsonName.join(&amp;quot;.&amp;quot;)+&amp;quot;.json&amp;quot;;&lt;br /&gt;
var pics = [];&lt;br /&gt;
var url = &#039;&#039;;&lt;br /&gt;
var bgName = &amp;quot;&amp;quot;;&lt;br /&gt;
var bgLayer;&lt;br /&gt;
Array.prototype.indexOf = function ( item ) {&lt;br /&gt;
&lt;br /&gt;
	  var index = 0, length = this.length;&lt;br /&gt;
&lt;br /&gt;
	  for ( ; index &amp;lt; length; index++ ) {&lt;br /&gt;
&lt;br /&gt;
				if ( this[index] === item )&lt;br /&gt;
&lt;br /&gt;
						  return index;&lt;br /&gt;
&lt;br /&gt;
	  }&lt;br /&gt;
&lt;br /&gt;
	  return -1;&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
var jiggleMasks = {&lt;br /&gt;
	&#039;jm_breasts&#039; : {&lt;br /&gt;
		slot : &amp;quot;Breasts&amp;quot;,&lt;br /&gt;
		points : []&lt;br /&gt;
	},&lt;br /&gt;
	&#039;jm_groin&#039; : {&lt;br /&gt;
		slot : &amp;quot;Groin&amp;quot;,&lt;br /&gt;
		points : []&lt;br /&gt;
	},&lt;br /&gt;
	&#039;jm_butt&#039; : {&lt;br /&gt;
		slot : &amp;quot;Butt&amp;quot;,&lt;br /&gt;
		points : []&lt;br /&gt;
	}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var condMap = {&lt;br /&gt;
	&#039;55_stains&#039; : {&lt;br /&gt;
        conds : [&#039;targetStains&#039;],&lt;br /&gt;
    },&lt;br /&gt;
	&#039;51_gloves&#039; : {&lt;br /&gt;
		conds : [&#039;targetGloves&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;50_gloves&#039; : {&lt;br /&gt;
		conds : [&#039;targetGloves&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;19_gloves&#039; : {&lt;br /&gt;
		conds : [&#039;targetGloves&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;18_gloves&#039; : {&lt;br /&gt;
		conds : [&#039;targetGloves&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;41_boots&#039; : {&lt;br /&gt;
		conds : [&#039;targetBoots&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;40_boots&#039; : {&lt;br /&gt;
		conds : [&#039;targetBoots&#039;]&lt;br /&gt;
	},&lt;br /&gt;
    &#039;26_sling_heavy&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;,&#039;targetLowerBodyHard&#039;] &lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_sling_heavy&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;,&#039;targetLowerBodyHard&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_sling_med&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;,&#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_sling_med&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;,&#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_sling_light&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_sling_light&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_bodysuit_med&#039; : {&lt;br /&gt;
        conds: [&#039;targetBodysuit&#039;, &#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_bodysuit_med&#039; : {&lt;br /&gt;
        conds: [&#039;targetBodysuit&#039;, &#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_bodysuit_light&#039; : {&lt;br /&gt;
        conds: [&#039;targetBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_bodysuit_light&#039; : {&lt;br /&gt;
        conds: [&#039;targetBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
    &#039;36_heavy_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyHard&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;35_heavy_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyHard&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
    &#039;26_heavy_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetLowerBodyHard&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_heavy_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetLowerBodyHard&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&lt;br /&gt;
	&#039;36_bikini_med_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyBikini&#039;, &#039;targetUpperBodyLeather&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;35_bikini_med_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyBikini&#039;, &#039;targetUpperBodyLeather&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;26_bikini_med_lb&#039; : {&lt;br /&gt;
		conds: [&#039;targetWearsThong&#039;, &#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;25_bikini_med_lb&#039; : {&lt;br /&gt;
		conds: [&#039;targetWearsThong&#039;, &#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&lt;br /&gt;
	&#039;36_bikini_light_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyBikini&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;35_bikini_light_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyBikini&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;26_bikini_light_lb&#039; : {&lt;br /&gt;
		conds: [&#039;targetWearsThong&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;25_bikini_light_lb&#039; : {&lt;br /&gt;
		conds: [&#039;targetWearsThong&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&lt;br /&gt;
    &lt;br /&gt;
    &#039;36_med_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyLeather&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;35_med_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyLeather&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_med_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_med_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
	&lt;br /&gt;
    &#039;36_light_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsUpperBody&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;35_light_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsUpperBody&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_light_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsLowerBody&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_light_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsLowerBody&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
	// Collar can be either above or below armor&lt;br /&gt;
    &#039;3_collar&#039; : {&lt;br /&gt;
        conds: [&#039;targetCollar&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;23_collar&#039; : {&lt;br /&gt;
        conds: [&#039;targetCollar&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;43_collar&#039; : {&lt;br /&gt;
        conds: [&#039;targetCollar&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&lt;br /&gt;
	&#039;22_nipple_studs&#039; : {&lt;br /&gt;
        conds: [&#039;targetCollar&#039;]&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    &#039;15_aroused_heavy&#039; : {&lt;br /&gt;
        conds: [&#039;metaVeryArousing&#039;],&lt;br /&gt;
        stdtag: &#039;ex_aroused_heavy&#039;&lt;br /&gt;
    },&lt;br /&gt;
    &#039;15_pain_heavy&#039; : {&lt;br /&gt;
        conds: [&#039;metaVeryPainful&#039;],&lt;br /&gt;
        stdtag : &#039;ex_pained_heavy&#039;&lt;br /&gt;
    },&lt;br /&gt;
    &#039;10_aroused&#039; : {&lt;br /&gt;
        conds: [&#039;metaArousing&#039;],&lt;br /&gt;
        stdtag: &#039;ex_aroused&#039;&lt;br /&gt;
    },&lt;br /&gt;
    &#039;10_pain&#039; : {&lt;br /&gt;
        conds: [&#039;metaPainful&#039;],&lt;br /&gt;
        stdtag : &#039;ex_pained&#039;&lt;br /&gt;
    },&lt;br /&gt;
    &#039;5_orgasm&#039; : {&lt;br /&gt;
        conds: [&#039;targetHasOrgasm&#039;]&lt;br /&gt;
    }, &lt;br /&gt;
    &lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function round(input){&lt;br /&gt;
	return Math.round(input*100)/100;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function exec(){&lt;br /&gt;
	&lt;br /&gt;
	preferences.rulerUnits = Units.PIXELS;&lt;br /&gt;
	&lt;br /&gt;
	fetchLayers(doc);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	// Fetch JSON if possible&lt;br /&gt;
	var jsonFile = new File(dir+jsonName);&lt;br /&gt;
	jsonFile.encoding = &#039;UTF8&#039;;&lt;br /&gt;
	if( jsonFile.exists ){&lt;br /&gt;
		&lt;br /&gt;
		jsonFile.open(&amp;quot;r&amp;quot;);&lt;br /&gt;
        var parsed = JSON.parse(jsonFile.read());&lt;br /&gt;
        url = parsed.url || &#039;&#039;;&lt;br /&gt;
		bgName = parsed.base || &amp;quot;&amp;quot;;&lt;br /&gt;
		pics = parsed.layers;&lt;br /&gt;
		jsonFile.close();&lt;br /&gt;
		&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	var pngOpts = new PNGSaveOptions();&lt;br /&gt;
	pngOpts.method = stringIDToTypeID(&amp;quot;thorough&amp;quot;);&lt;br /&gt;
	pngOpts.compression = 1;&lt;br /&gt;
	&lt;br /&gt;
	var missingFromMap = [];&lt;br /&gt;
	for( var i = 0; i &amp;lt; allLayers.length; ++i ){&lt;br /&gt;
		&lt;br /&gt;
		var l = allLayers[i];&lt;br /&gt;
		l.visible = true;&lt;br /&gt;
		if( i &amp;amp;&amp;amp; allLayers[i-1].name.substring(0,1) != &amp;quot;#&amp;quot; )&lt;br /&gt;
			allLayers[i-1].visible = false;&lt;br /&gt;
		&lt;br /&gt;
		var baseOpacity = l.opacity;&lt;br /&gt;
		&lt;br /&gt;
		var bounds = l.bounds;&lt;br /&gt;
		var left = bounds[0];&lt;br /&gt;
		var right = docW-bounds[2];&lt;br /&gt;
		var top = bounds[1];&lt;br /&gt;
		var bottom = docH - bounds[3];&lt;br /&gt;
		var width = bounds[2]-bounds[0];&lt;br /&gt;
		var height = bounds[3]-bounds[1];&lt;br /&gt;
		&lt;br /&gt;
		var layerName = l.name;&lt;br /&gt;
		var layerNr = parseInt(layerName);&lt;br /&gt;
		var blendMode = &#039;source-over&#039;;&lt;br /&gt;
		if( l.blendMode == BlendMode.MULTIPLY )&lt;br /&gt;
			blendMode = &#039;multiply&#039;;&lt;br /&gt;
		else if( l.blendMode == BlendMode.OVERLAY )&lt;br /&gt;
			blendMode = &#039;overlay&#039;;&lt;br /&gt;
		var opacity = baseOpacity/100;&lt;br /&gt;
		var jiggleMask = jiggleMasks[layerName];&lt;br /&gt;
		&lt;br /&gt;
		if( layerName.substring(0,3) === &#039;jp_&#039; ){&lt;br /&gt;
			var layer = layerName.substring(3);&lt;br /&gt;
			var targ = jiggleMasks[&#039;jm_&#039;+layer];&lt;br /&gt;
			if( targ ){&lt;br /&gt;
				// Create a jiggle point&lt;br /&gt;
				var point = {&lt;br /&gt;
					r : round(width/docW),&lt;br /&gt;
					x : round((width/2+left)/docW),&lt;br /&gt;
					y : round((height/2+top)/docH),&lt;br /&gt;
				};&lt;br /&gt;
				targ.points.push(point);&lt;br /&gt;
				&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		else if( isNaN(layerNr) &amp;amp;&amp;amp; !jiggleMask )&lt;br /&gt;
			alert(&amp;quot;Layer &amp;quot;+layerName+&amp;quot; needs to start with the FQ art layer number. Use # if you don&#039;t want to save this layer.&amp;quot;);&lt;br /&gt;
		else{&lt;br /&gt;
			&lt;br /&gt;
			var file = layerName+&amp;quot;.png&amp;quot;;&lt;br /&gt;
			&lt;br /&gt;
			var folder = Folder(dir);&lt;br /&gt;
			if( !folder.exists )&lt;br /&gt;
				folder.create();&lt;br /&gt;
			&lt;br /&gt;
			l.opacity = 100;&lt;br /&gt;
						&lt;br /&gt;
			//alert(&amp;quot;Image cropped x:&amp;quot;+left+&amp;quot; y:&amp;quot;+top)&lt;br /&gt;
			var workLayer = doc.duplicate();&lt;br /&gt;
&lt;br /&gt;
			workLayer.crop(bounds);&lt;br /&gt;
			&lt;br /&gt;
			&lt;br /&gt;
			var fileOut = new File(dir+file)&lt;br /&gt;
			workLayer.saveAs(fileOut, pngOpts, true);	&lt;br /&gt;
			workLayer.close(SaveOptions.DONOTSAVECHANGES);&lt;br /&gt;
			&lt;br /&gt;
			l.opacity = baseOpacity;&lt;br /&gt;
			var baseData = {&lt;br /&gt;
				x : parseInt(left),&lt;br /&gt;
				y : parseInt(top),&lt;br /&gt;
			};&lt;br /&gt;
			&lt;br /&gt;
			if( jiggleMask ){&lt;br /&gt;
				&lt;br /&gt;
				baseData.slot = layerName.substring(3);&lt;br /&gt;
				baseData.mask = file;&lt;br /&gt;
				baseData = makeJiggleMask(baseData);&lt;br /&gt;
				baseData.p = jiggleMask.points;&lt;br /&gt;
				&lt;br /&gt;
			}else{&lt;br /&gt;
				&lt;br /&gt;
				var duration = 0;&lt;br /&gt;
				if( layerNr &amp;lt; 18 &amp;amp;&amp;amp; layerNr &amp;gt;= 10 )&lt;br /&gt;
					duration = 3000; // Facial expressions generally.&lt;br /&gt;
				var slots = {&lt;br /&gt;
					s26 : &#039;lowerBody&#039;,&lt;br /&gt;
					s31 : &#039;hands&#039;,&lt;br /&gt;
					s36 : &#039;upperBody&#039;,&lt;br /&gt;
					s41 : &#039;jewelleryCosmetic&#039;,&lt;br /&gt;
					s46 : &#039;lowerBodyCosmetic&#039;,&lt;br /&gt;
					s51 : &#039;upperBodyCosmetic&#039;,&lt;br /&gt;
				};&lt;br /&gt;
				&lt;br /&gt;
				var cmap = condMap[layerName], cm = [], stdtag = &#039;&#039;;&lt;br /&gt;
				if( cmap ){&lt;br /&gt;
					cm = cmap.conds;&lt;br /&gt;
					stdtag = cmap.stdtag;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				if( !cm.length )&lt;br /&gt;
					missingFromMap.push(layerName);&lt;br /&gt;
				&lt;br /&gt;
				baseData.layer = layerNr;&lt;br /&gt;
				baseData.icon = file;&lt;br /&gt;
				baseData.duration = duration;&lt;br /&gt;
				baseData.slot = slots[&#039;s&#039;+layerNr] || &#039;&#039;;&lt;br /&gt;
				baseData.blendMode = blendMode;&lt;br /&gt;
				baseData.opacity = opacity;&lt;br /&gt;
                baseData.conditions = cm;&lt;br /&gt;
                baseData.stdtag = stdtag;&lt;br /&gt;
				&lt;br /&gt;
				baseData = makePic(baseData);&lt;br /&gt;
				&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			&lt;br /&gt;
			updatePic(baseData);&lt;br /&gt;
			&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
	}&lt;br /&gt;
	if( missingFromMap.length )&lt;br /&gt;
		alert(&amp;quot;The following layers are missing auto condition definitions, check your spelling etc: &amp;quot;+missingFromMap.join(&amp;quot;, &amp;quot;));&lt;br /&gt;
		&lt;br /&gt;
	// Save BG as nude layer&lt;br /&gt;
	if( bgLayer ){&lt;br /&gt;
		&lt;br /&gt;
		if( allLayers.length )&lt;br /&gt;
			allLayers[i-1].visible = false;&lt;br /&gt;
		bgLayer.visible = true;&lt;br /&gt;
		var jpegOpts = new JPEGSaveOptions();&lt;br /&gt;
		jpegOpts.quality = 9;&lt;br /&gt;
		var fn = fName+&amp;quot;_n.jpg&amp;quot;;&lt;br /&gt;
		doc.saveAs(new File(dir+fn), jpegOpts, true);&lt;br /&gt;
		bgName = fn;&lt;br /&gt;
		&lt;br /&gt;
	&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	var keys = [];&lt;br /&gt;
	for( var i in condMap ){&lt;br /&gt;
		keys.push(i);&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	pics.sort(function(a, b){&lt;br /&gt;
				&lt;br /&gt;
		var aln = (a.icon || a.mask).split(&amp;quot;.&amp;quot;)[0];&lt;br /&gt;
		var bln = (b.icon || b.mask).split(&amp;quot;.&amp;quot;)[0];&lt;br /&gt;
		var aPos = keys.indexOf(aln);&lt;br /&gt;
		var bPos = keys.indexOf(bln);&lt;br /&gt;
		if( aPos == bPos )&lt;br /&gt;
			return 0;&lt;br /&gt;
		if( aPos == -1 )&lt;br /&gt;
			return 1;&lt;br /&gt;
		if( bPos == -1 )&lt;br /&gt;
			return -1;&lt;br /&gt;
		return aPos &amp;lt; bPos ? -1 : 1;&lt;br /&gt;
		&lt;br /&gt;
	});&lt;br /&gt;
	&lt;br /&gt;
	var dump = JSON.stringify({&lt;br /&gt;
		base : bgName,&lt;br /&gt;
        url : url,&lt;br /&gt;
        layers : pics&lt;br /&gt;
    }, null, 4);&lt;br /&gt;
	jsonFile.open(&amp;quot;w&amp;quot;);&lt;br /&gt;
	jsonFile.write(dump);&lt;br /&gt;
	jsonFile.close();&lt;br /&gt;
&lt;br /&gt;
	preferences.rulerUnits = startRulesUnits;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Accept data from makePic&lt;br /&gt;
function updatePic( picData ){&lt;br /&gt;
	for( var i = 0; i &amp;lt; pics.length; ++i ){&lt;br /&gt;
		&lt;br /&gt;
		var p = pics[i];&lt;br /&gt;
		if( (p.icon &amp;amp;&amp;amp; p.icon == picData.icon) || (p.mask &amp;amp;&amp;amp; picData.mask === p.mask)  ){&lt;br /&gt;
			&lt;br /&gt;
			if( picData.layer !== undefined )&lt;br /&gt;
				p.layer = picData.layer;&lt;br /&gt;
			p.x = picData.x;&lt;br /&gt;
			p.y = picData.y;&lt;br /&gt;
			if( picData.blendMode !== undefined )&lt;br /&gt;
				p.blendMode = picData.blendMode;&lt;br /&gt;
			if( picData.opacity !== undefined )&lt;br /&gt;
				p.opacity = picData.opacity;&lt;br /&gt;
			if( picData.slot !== undefined )&lt;br /&gt;
				p.slot = picData.slot;&lt;br /&gt;
			if( picData.p )&lt;br /&gt;
				p.p = picData.p;&lt;br /&gt;
			&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	pics.push(picData);&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Fetches all viable art layers&lt;br /&gt;
function fetchLayers( parentLayer, ignore ){&lt;br /&gt;
	&lt;br /&gt;
	for( var i = 0; i &amp;lt; parentLayer.layers.length; ++i ){&lt;br /&gt;
		&lt;br /&gt;
		var l = parentLayer.layers[i];&lt;br /&gt;
		&lt;br /&gt;
		var ign = ignore;&lt;br /&gt;
		var isBg = l.name == &amp;quot;Background&amp;quot;;&lt;br /&gt;
		&lt;br /&gt;
		if( !ignore )&lt;br /&gt;
			ign = isBg;&lt;br /&gt;
		if( l.name.substring(0,1) == &amp;quot;#&amp;quot; )&lt;br /&gt;
			continue;&lt;br /&gt;
		&lt;br /&gt;
		if( isBg )&lt;br /&gt;
			bgLayer = l;&lt;br /&gt;
&lt;br /&gt;
		l.visible = (l.typename == &amp;quot;LayerSet&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
		if( l.typename == &amp;quot;LayerSet&amp;quot; ){&lt;br /&gt;
			fetchLayers(l, ign);&lt;br /&gt;
			continue;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if( !ign )&lt;br /&gt;
			allLayers.push(l);&lt;br /&gt;
		&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeJiggleMask( data ){&lt;br /&gt;
	if( typeof data != &amp;quot;object&amp;quot; )&lt;br /&gt;
		data = {};&lt;br /&gt;
	var out = {};&lt;br /&gt;
	out.x = data.x || 0;&lt;br /&gt;
	out.y = data.y || 0;&lt;br /&gt;
	out.mask = data.mask;&lt;br /&gt;
	out.slot = data.slot;&lt;br /&gt;
	return out;&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makePic( data ){&lt;br /&gt;
	&lt;br /&gt;
	if( typeof data != &amp;quot;object&amp;quot; )&lt;br /&gt;
		data = {};&lt;br /&gt;
	&lt;br /&gt;
	var out = {};&lt;br /&gt;
	out.icon = data.icon;&lt;br /&gt;
	out.conditions = data.conditions || [];&lt;br /&gt;
	out.layer = data.layer || 0;&lt;br /&gt;
	out.duration = parseInt(data.duration) || 0;&lt;br /&gt;
	out.x = data.x || 0;&lt;br /&gt;
	out.y = data.y || 0;&lt;br /&gt;
	out.slot = data.slot || &#039;&#039;;&lt;br /&gt;
	out.blendMode = data.blendMode || &#039;source-over&#039;;&lt;br /&gt;
	out.opacity = 1.0;&lt;br /&gt;
	if( !isNaN(data.opacity) )&lt;br /&gt;
		out.opacity = data.opacity;&lt;br /&gt;
    out.conditions = data.conditions;&lt;br /&gt;
    out.stdtag = data.stdtag;&lt;br /&gt;
	return out;&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function save_as_png(doc, file, copy, comp, filter, none){&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
&lt;br /&gt;
        if (copy == undefined) copy = true;&lt;br /&gt;
&lt;br /&gt;
        if (comp == undefined) comp = 9;&lt;br /&gt;
&lt;br /&gt;
        if (none == undefined) none = true;&lt;br /&gt;
&lt;br /&gt;
        if (filter == undefined) filter = &amp;quot;PNGFilterAdaptive&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        var doc0 = app.activeDocument;&lt;br /&gt;
&lt;br /&gt;
        app.activeDocument = doc;&lt;br /&gt;
&lt;br /&gt;
        var d = new ActionDescriptor();&lt;br /&gt;
&lt;br /&gt;
        var d1 = new ActionDescriptor();&lt;br /&gt;
&lt;br /&gt;
        d1.putEnumerated(stringIDToTypeID(&amp;quot;method&amp;quot;), stringIDToTypeID(&amp;quot;PNGMethod&amp;quot;), stringIDToTypeID(&amp;quot;quick&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
        if (none)&lt;br /&gt;
&lt;br /&gt;
            d1.putEnumerated(stringIDToTypeID(&amp;quot;PNGInterlaceType&amp;quot;), stringIDToTypeID(&amp;quot;PNGInterlaceType&amp;quot;), stringIDToTypeID(&amp;quot;PNGInterlaceNone&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
        else&lt;br /&gt;
&lt;br /&gt;
            d1.putEnumerated(stringIDToTypeID(&amp;quot;PNGInterlaceType&amp;quot;), stringIDToTypeID(&amp;quot;PNGInterlaceType&amp;quot;), stringIDToTypeID(&amp;quot;PNGInterlaceAdam7&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
        d1.putEnumerated(stringIDToTypeID(&amp;quot;PNGFilter&amp;quot;), stringIDToTypeID(&amp;quot;PNGFilter&amp;quot;), stringIDToTypeID(filter));&lt;br /&gt;
&lt;br /&gt;
        d1.putInteger(stringIDToTypeID(&amp;quot;compression&amp;quot;), comp);&lt;br /&gt;
&lt;br /&gt;
        d.putObject(stringIDToTypeID(&amp;quot;as&amp;quot;), stringIDToTypeID(&amp;quot;PNGFormat&amp;quot;), d1);&lt;br /&gt;
&lt;br /&gt;
        d.putPath(stringIDToTypeID(&amp;quot;in&amp;quot;), file);&lt;br /&gt;
&lt;br /&gt;
        d.putBoolean(stringIDToTypeID(&amp;quot;copy&amp;quot;), copy);&lt;br /&gt;
&lt;br /&gt;
        executeAction(stringIDToTypeID(&amp;quot;save&amp;quot;), d, DialogModes.NO);&lt;br /&gt;
&lt;br /&gt;
        app.activeDocument = doc0;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    catch (e) { alert(e); return false; }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//  json2.js&lt;br /&gt;
//  2023-05-10&lt;br /&gt;
//  Public Domain.&lt;br /&gt;
//  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.&lt;br /&gt;
&lt;br /&gt;
//  USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO&lt;br /&gt;
//  NOT CONTROL.&lt;br /&gt;
&lt;br /&gt;
//  This file creates a global JSON object containing two methods: stringify&lt;br /&gt;
//  and parse. This file provides the ES5 JSON capability to ES3 systems.&lt;br /&gt;
//  If a project might run on IE8 or earlier, then this file should be included.&lt;br /&gt;
//  This file does nothing on ES5 systems.&lt;br /&gt;
&lt;br /&gt;
//      JSON.stringify(value, replacer, space)&lt;br /&gt;
//          value       any JavaScript value, usually an object or array.&lt;br /&gt;
//          replacer    an optional parameter that determines how object&lt;br /&gt;
//                      values are stringified for objects. It can be a&lt;br /&gt;
//                      function or an array of strings.&lt;br /&gt;
//          space       an optional parameter that specifies the indentation&lt;br /&gt;
//                      of nested structures. If it is omitted, the text will&lt;br /&gt;
//                      be packed without extra whitespace. If it is a number,&lt;br /&gt;
//                      it will specify the number of spaces to indent at each&lt;br /&gt;
//                      level. If it is a string (such as &amp;quot;\t&amp;quot; or &amp;quot;&amp;amp;nbsp;&amp;quot;),&lt;br /&gt;
//                      it contains the characters used to indent at each level.&lt;br /&gt;
//          This method produces a JSON text from a JavaScript value.&lt;br /&gt;
//          When an object value is found, if the object contains a toJSON&lt;br /&gt;
//          method, its toJSON method will be called and the result will be&lt;br /&gt;
//          stringified. A toJSON method does not serialize: it returns the&lt;br /&gt;
//          value represented by the name/value pair that should be serialized,&lt;br /&gt;
//          or undefined if nothing should be serialized. The toJSON method&lt;br /&gt;
//          will be passed the key associated with the value, and this will be&lt;br /&gt;
//          bound to the value.&lt;br /&gt;
&lt;br /&gt;
//          For example, this would serialize Dates as ISO strings.&lt;br /&gt;
&lt;br /&gt;
//              Date.prototype.toJSON = function (key) {&lt;br /&gt;
//                  function f(n) {&lt;br /&gt;
//                      // Format integers to have at least two digits.&lt;br /&gt;
//                      return (n &amp;lt; 10)&lt;br /&gt;
//                          ? &amp;quot;0&amp;quot; + n&lt;br /&gt;
//                          : n;&lt;br /&gt;
//                  }&lt;br /&gt;
//                  return this.getUTCFullYear()   + &amp;quot;-&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCMonth() + 1) + &amp;quot;-&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCDate())      + &amp;quot;T&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCHours())     + &amp;quot;:&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCMinutes())   + &amp;quot;:&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCSeconds())   + &amp;quot;Z&amp;quot;;&lt;br /&gt;
//              };&lt;br /&gt;
&lt;br /&gt;
//          You can provide an optional replacer method. It will be passed the&lt;br /&gt;
//          key and value of each member, with this bound to the containing&lt;br /&gt;
//          object. The value that is returned from your method will be&lt;br /&gt;
//          serialized. If your method returns undefined, then the member will&lt;br /&gt;
//          be excluded from the serialization.&lt;br /&gt;
&lt;br /&gt;
//          If the replacer parameter is an array of strings, then it will be&lt;br /&gt;
//          used to select the members to be serialized. It filters the results&lt;br /&gt;
//          such that only members with keys listed in the replacer array are&lt;br /&gt;
//          stringified.&lt;br /&gt;
&lt;br /&gt;
//          Values that do not have JSON representations, such as undefined or&lt;br /&gt;
//          functions, will not be serialized. Such values in objects will be&lt;br /&gt;
//          dropped; in arrays they will be replaced with null. You can use&lt;br /&gt;
//          a replacer function to replace those with JSON values.&lt;br /&gt;
&lt;br /&gt;
//          JSON.stringify(undefined) returns undefined.&lt;br /&gt;
&lt;br /&gt;
//          The optional space parameter produces a stringification of the&lt;br /&gt;
//          value that is filled with line breaks and indentation to make it&lt;br /&gt;
//          easier to read.&lt;br /&gt;
&lt;br /&gt;
//          If the space parameter is a non-empty string, then that string will&lt;br /&gt;
//          be used for indentation. If the space parameter is a number, then&lt;br /&gt;
//          the indentation will be that many spaces.&lt;br /&gt;
&lt;br /&gt;
//          Example:&lt;br /&gt;
&lt;br /&gt;
//          text = JSON.stringify([&amp;quot;e&amp;quot;, {pluribus: &amp;quot;unum&amp;quot;}]);&lt;br /&gt;
//          // text is &#039;[&amp;quot;e&amp;quot;,{&amp;quot;pluribus&amp;quot;:&amp;quot;unum&amp;quot;}]&#039;&lt;br /&gt;
&lt;br /&gt;
//          text = JSON.stringify([&amp;quot;e&amp;quot;, {pluribus: &amp;quot;unum&amp;quot;}], null, &amp;quot;\t&amp;quot;);&lt;br /&gt;
//          // text is &#039;[\n\t&amp;quot;e&amp;quot;,\n\t{\n\t\t&amp;quot;pluribus&amp;quot;: &amp;quot;unum&amp;quot;\n\t}\n]&#039;&lt;br /&gt;
&lt;br /&gt;
//          text = JSON.stringify([new Date()], function (key, value) {&lt;br /&gt;
//              return this[key] instanceof Date&lt;br /&gt;
//                  ? &amp;quot;Date(&amp;quot; + this[key] + &amp;quot;)&amp;quot;&lt;br /&gt;
//                  : value;&lt;br /&gt;
//          });&lt;br /&gt;
//          // text is &#039;[&amp;quot;Date(---current time---)&amp;quot;]&#039;&lt;br /&gt;
&lt;br /&gt;
//      JSON.parse(text, reviver)&lt;br /&gt;
//          This method parses a JSON text to produce an object or array.&lt;br /&gt;
//          It can throw a SyntaxError exception.&lt;br /&gt;
&lt;br /&gt;
//          The optional reviver parameter is a function that can filter and&lt;br /&gt;
//          transform the results. It receives each of the keys and values,&lt;br /&gt;
//          and its return value is used instead of the original value.&lt;br /&gt;
//          If it returns what it received, then the structure is not modified.&lt;br /&gt;
//          If it returns undefined then the member is deleted.&lt;br /&gt;
&lt;br /&gt;
//          Example:&lt;br /&gt;
&lt;br /&gt;
//          // Parse the text. Values that look like ISO date strings will&lt;br /&gt;
//          // be converted to Date objects.&lt;br /&gt;
&lt;br /&gt;
//          myData = JSON.parse(text, function (key, value) {&lt;br /&gt;
//              var a;&lt;br /&gt;
//              if (typeof value === &amp;quot;string&amp;quot;) {&lt;br /&gt;
//                  a =&lt;br /&gt;
//   /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);&lt;br /&gt;
//                  if (a) {&lt;br /&gt;
//                      return new Date(Date.UTC(&lt;br /&gt;
//                         +a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]&lt;br /&gt;
//                      ));&lt;br /&gt;
//                  }&lt;br /&gt;
//                  return value;&lt;br /&gt;
//              }&lt;br /&gt;
//          });&lt;br /&gt;
&lt;br /&gt;
//          myData = JSON.parse(&lt;br /&gt;
//              &amp;quot;[\&amp;quot;Date(09/09/2001)\&amp;quot;]&amp;quot;,&lt;br /&gt;
//              function (key, value) {&lt;br /&gt;
//                  var d;&lt;br /&gt;
//                  if (&lt;br /&gt;
//                      typeof value === &amp;quot;string&amp;quot;&lt;br /&gt;
//                      &amp;amp;&amp;amp; value.slice(0, 5) === &amp;quot;Date(&amp;quot;&lt;br /&gt;
//                      &amp;amp;&amp;amp; value.slice(-1) === &amp;quot;)&amp;quot;&lt;br /&gt;
//                  ) {&lt;br /&gt;
//                      d = new Date(value.slice(5, -1));&lt;br /&gt;
//                      if (d) {&lt;br /&gt;
//                          return d;&lt;br /&gt;
//                      }&lt;br /&gt;
//                  }&lt;br /&gt;
//                  return value;&lt;br /&gt;
//              }&lt;br /&gt;
//          );&lt;br /&gt;
&lt;br /&gt;
//  This is a reference implementation. You are free to copy, modify, or&lt;br /&gt;
//  redistribute.&lt;br /&gt;
&lt;br /&gt;
/*jslint&lt;br /&gt;
    eval, for, this&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/*property&lt;br /&gt;
    JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,&lt;br /&gt;
    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,&lt;br /&gt;
    lastIndex, length, parse, prototype, push, replace, slice, stringify,&lt;br /&gt;
    test, toJSON, toString, valueOf&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Create a JSON object only if one does not already exist. We create the&lt;br /&gt;
// methods in a closure to avoid creating global variables.&lt;br /&gt;
&lt;br /&gt;
var JSON = {};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &amp;quot;use strict&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    var rx_one = /^[\],:{}\s]*$/;&lt;br /&gt;
    var rx_two = /\\(?:[&amp;quot;\\\/bfnrt]|u[0-9a-fA-F]{4})/g;&lt;br /&gt;
    var rx_three = /&amp;quot;[^&amp;quot;\\\n\r]*&amp;quot;|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;&lt;br /&gt;
    var rx_four = /(?:^|:|,)(?:\s*\[)+/g;&lt;br /&gt;
    var rx_escapable = /[\\&amp;quot;\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;&lt;br /&gt;
    var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;&lt;br /&gt;
&lt;br /&gt;
    function f(n) {&lt;br /&gt;
        // Format integers to have at least two digits.&lt;br /&gt;
        return (n &amp;lt; 10)&lt;br /&gt;
            ? &amp;quot;0&amp;quot; + n&lt;br /&gt;
            : n;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function this_value() {&lt;br /&gt;
        return this.valueOf();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (typeof Date.prototype.toJSON !== &amp;quot;function&amp;quot;) {&lt;br /&gt;
&lt;br /&gt;
        Date.prototype.toJSON = function () {&lt;br /&gt;
&lt;br /&gt;
            return isFinite(this.valueOf())&lt;br /&gt;
                ? (&lt;br /&gt;
                    this.getUTCFullYear()&lt;br /&gt;
                    + &amp;quot;-&amp;quot;&lt;br /&gt;
                    + f(this.getUTCMonth() + 1)&lt;br /&gt;
                    + &amp;quot;-&amp;quot;&lt;br /&gt;
                    + f(this.getUTCDate())&lt;br /&gt;
                    + &amp;quot;T&amp;quot;&lt;br /&gt;
                    + f(this.getUTCHours())&lt;br /&gt;
                    + &amp;quot;:&amp;quot;&lt;br /&gt;
                    + f(this.getUTCMinutes())&lt;br /&gt;
                    + &amp;quot;:&amp;quot;&lt;br /&gt;
                    + f(this.getUTCSeconds())&lt;br /&gt;
                    + &amp;quot;Z&amp;quot;&lt;br /&gt;
                )&lt;br /&gt;
                : null;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        Boolean.prototype.toJSON = this_value;&lt;br /&gt;
        Number.prototype.toJSON = this_value;&lt;br /&gt;
        String.prototype.toJSON = this_value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gap;&lt;br /&gt;
    var indent;&lt;br /&gt;
    var meta;&lt;br /&gt;
    var rep;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    function quote(string) {&lt;br /&gt;
&lt;br /&gt;
// If the string contains no control characters, no quote characters, and no&lt;br /&gt;
// backslash characters, then we can safely slap some quotes around it.&lt;br /&gt;
// Otherwise we must also replace the offending characters with safe escape&lt;br /&gt;
// sequences.&lt;br /&gt;
&lt;br /&gt;
        rx_escapable.lastIndex = 0;&lt;br /&gt;
        return rx_escapable.test(string)&lt;br /&gt;
            ? &amp;quot;\&amp;quot;&amp;quot; + string.replace(rx_escapable, function (a) {&lt;br /&gt;
                var c = meta[a];&lt;br /&gt;
                return typeof c === &amp;quot;string&amp;quot;&lt;br /&gt;
                    ? c&lt;br /&gt;
                    : &amp;quot;\\u&amp;quot; + (&amp;quot;0000&amp;quot; + a.charCodeAt(0).toString(16)).slice(-4);&lt;br /&gt;
            }) + &amp;quot;\&amp;quot;&amp;quot;&lt;br /&gt;
            : &amp;quot;\&amp;quot;&amp;quot; + string + &amp;quot;\&amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    function str(key, holder) {&lt;br /&gt;
&lt;br /&gt;
// Produce a string from holder[key].&lt;br /&gt;
&lt;br /&gt;
        var i;          // The loop counter.&lt;br /&gt;
        var k;          // The member key.&lt;br /&gt;
        var v;          // The member value.&lt;br /&gt;
        var length;&lt;br /&gt;
        var mind = gap;&lt;br /&gt;
        var partial;&lt;br /&gt;
        var value = holder[key];&lt;br /&gt;
&lt;br /&gt;
// If the value has a toJSON method, call it to obtain a replacement value.&lt;br /&gt;
&lt;br /&gt;
        if (&lt;br /&gt;
            value&lt;br /&gt;
            &amp;amp;&amp;amp; typeof value === &amp;quot;object&amp;quot;&lt;br /&gt;
            &amp;amp;&amp;amp; typeof value.toJSON === &amp;quot;function&amp;quot;&lt;br /&gt;
        ) {&lt;br /&gt;
            value = value.toJSON(key);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
// If we were called with a replacer function, then call the replacer to&lt;br /&gt;
// obtain a replacement value.&lt;br /&gt;
&lt;br /&gt;
        if (typeof rep === &amp;quot;function&amp;quot;) {&lt;br /&gt;
            value = rep.call(holder, key, value);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
// What happens next depends on the value&#039;s type.&lt;br /&gt;
&lt;br /&gt;
        switch (typeof value) {&lt;br /&gt;
        case &amp;quot;string&amp;quot;:&lt;br /&gt;
            return quote(value);&lt;br /&gt;
&lt;br /&gt;
        case &amp;quot;number&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
// JSON numbers must be finite. Encode non-finite numbers as null.&lt;br /&gt;
&lt;br /&gt;
            return (isFinite(value))&lt;br /&gt;
                ? String(value)&lt;br /&gt;
                : &amp;quot;null&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        case &amp;quot;boolean&amp;quot;:&lt;br /&gt;
        case &amp;quot;null&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
// If the value is a boolean or null, convert it to a string. Note:&lt;br /&gt;
// typeof null does not produce &amp;quot;null&amp;quot;. The case is included here in&lt;br /&gt;
// the remote chance that this gets fixed someday.&lt;br /&gt;
&lt;br /&gt;
            return String(value);&lt;br /&gt;
&lt;br /&gt;
// If the type is &amp;quot;object&amp;quot;, we might be dealing with an object or an array or&lt;br /&gt;
// null.&lt;br /&gt;
&lt;br /&gt;
        case &amp;quot;object&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
// Due to a specification blunder in ECMAScript, typeof null is &amp;quot;object&amp;quot;,&lt;br /&gt;
// so watch out for that case.&lt;br /&gt;
&lt;br /&gt;
            if (!value) {&lt;br /&gt;
                return &amp;quot;null&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// Make an array to hold the partial results of stringifying this object value.&lt;br /&gt;
&lt;br /&gt;
            gap += indent;&lt;br /&gt;
            partial = [];&lt;br /&gt;
&lt;br /&gt;
// Is the value an array?&lt;br /&gt;
&lt;br /&gt;
            if (Object.prototype.toString.apply(value) === &amp;quot;[object Array]&amp;quot;) {&lt;br /&gt;
&lt;br /&gt;
// The value is an array. Stringify every element. Use null as a placeholder&lt;br /&gt;
// for non-JSON values.&lt;br /&gt;
&lt;br /&gt;
                length = value.length;&lt;br /&gt;
                for (i = 0; i &amp;lt; length; i += 1) {&lt;br /&gt;
                    partial[i] = str(i, value) || &amp;quot;null&amp;quot;;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
// Join all of the elements together, separated with commas, and wrap them in&lt;br /&gt;
// brackets.&lt;br /&gt;
&lt;br /&gt;
                v = partial.length === 0&lt;br /&gt;
                    ? &amp;quot;[]&amp;quot;&lt;br /&gt;
                    : gap&lt;br /&gt;
                        ? (&lt;br /&gt;
                            &amp;quot;[\n&amp;quot;&lt;br /&gt;
                            + gap&lt;br /&gt;
                            + partial.join(&amp;quot;,\n&amp;quot; + gap)&lt;br /&gt;
                            + &amp;quot;\n&amp;quot;&lt;br /&gt;
                            + mind&lt;br /&gt;
                            + &amp;quot;]&amp;quot;&lt;br /&gt;
                        )&lt;br /&gt;
                        : &amp;quot;[&amp;quot; + partial.join(&amp;quot;,&amp;quot;) + &amp;quot;]&amp;quot;;&lt;br /&gt;
                gap = mind;&lt;br /&gt;
                return v;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// If the replacer is an array, use it to select the members to be stringified.&lt;br /&gt;
&lt;br /&gt;
            if (rep &amp;amp;&amp;amp; typeof rep === &amp;quot;object&amp;quot;) {&lt;br /&gt;
                length = rep.length;&lt;br /&gt;
                for (i = 0; i &amp;lt; length; i += 1) {&lt;br /&gt;
                    if (typeof rep[i] === &amp;quot;string&amp;quot;) {&lt;br /&gt;
                        k = rep[i];&lt;br /&gt;
                        v = str(k, value);&lt;br /&gt;
                        if (v) {&lt;br /&gt;
                            partial.push(quote(k) + (&lt;br /&gt;
                                (gap)&lt;br /&gt;
                                    ? &amp;quot;: &amp;quot;&lt;br /&gt;
                                    : &amp;quot;:&amp;quot;&lt;br /&gt;
                            ) + v);&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            } else {&lt;br /&gt;
&lt;br /&gt;
// Otherwise, iterate through all of the keys in the object.&lt;br /&gt;
&lt;br /&gt;
                for (k in value) {&lt;br /&gt;
                    if (Object.prototype.hasOwnProperty.call(value, k)) {&lt;br /&gt;
                        v = str(k, value);&lt;br /&gt;
                        if (v) {&lt;br /&gt;
                            partial.push(quote(k) + (&lt;br /&gt;
                                (gap)&lt;br /&gt;
                                    ? &amp;quot;: &amp;quot;&lt;br /&gt;
                                    : &amp;quot;:&amp;quot;&lt;br /&gt;
                            ) + v);&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// Join all of the member texts together, separated with commas,&lt;br /&gt;
// and wrap them in braces.&lt;br /&gt;
&lt;br /&gt;
            v = partial.length === 0&lt;br /&gt;
                ? &amp;quot;{}&amp;quot;&lt;br /&gt;
                : gap&lt;br /&gt;
                    ? &amp;quot;{\n&amp;quot; + gap + partial.join(&amp;quot;,\n&amp;quot; + gap) + &amp;quot;\n&amp;quot; + mind + &amp;quot;}&amp;quot;&lt;br /&gt;
                    : &amp;quot;{&amp;quot; + partial.join(&amp;quot;,&amp;quot;) + &amp;quot;}&amp;quot;;&lt;br /&gt;
            gap = mind;&lt;br /&gt;
            return v;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// If the JSON object does not yet have a stringify method, give it one.&lt;br /&gt;
&lt;br /&gt;
    if (typeof JSON.stringify !== &amp;quot;function&amp;quot;) {&lt;br /&gt;
        meta = {    // table of character substitutions&lt;br /&gt;
            &amp;quot;\b&amp;quot;: &amp;quot;\\b&amp;quot;,&lt;br /&gt;
            &amp;quot;\t&amp;quot;: &amp;quot;\\t&amp;quot;,&lt;br /&gt;
            &amp;quot;\n&amp;quot;: &amp;quot;\\n&amp;quot;,&lt;br /&gt;
            &amp;quot;\f&amp;quot;: &amp;quot;\\f&amp;quot;,&lt;br /&gt;
            &amp;quot;\r&amp;quot;: &amp;quot;\\r&amp;quot;,&lt;br /&gt;
            &amp;quot;\&amp;quot;&amp;quot;: &amp;quot;\\\&amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;\\&amp;quot;: &amp;quot;\\\\&amp;quot;&lt;br /&gt;
        };&lt;br /&gt;
        JSON.stringify = function (value, replacer, space) {&lt;br /&gt;
&lt;br /&gt;
// The stringify method takes a value and an optional replacer, and an optional&lt;br /&gt;
// space parameter, and returns a JSON text. The replacer can be a function&lt;br /&gt;
// that can replace values, or an array of strings that will select the keys.&lt;br /&gt;
// A default replacer method can be provided. Use of the space parameter can&lt;br /&gt;
// produce text that is more easily readable.&lt;br /&gt;
&lt;br /&gt;
            var i;&lt;br /&gt;
            gap = &amp;quot;&amp;quot;;&lt;br /&gt;
            indent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// If the space parameter is a number, make an indent string containing that&lt;br /&gt;
// many spaces.&lt;br /&gt;
&lt;br /&gt;
            if (typeof space === &amp;quot;number&amp;quot;) {&lt;br /&gt;
                for (i = 0; i &amp;lt; space; i += 1) {&lt;br /&gt;
                    indent += &amp;quot; &amp;quot;;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
// If the space parameter is a string, it will be used as the indent string.&lt;br /&gt;
&lt;br /&gt;
            } else if (typeof space === &amp;quot;string&amp;quot;) {&lt;br /&gt;
                indent = space;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// If there is a replacer, it must be a function or an array.&lt;br /&gt;
// Otherwise, throw an error.&lt;br /&gt;
&lt;br /&gt;
            rep = replacer;&lt;br /&gt;
            if (replacer &amp;amp;&amp;amp; typeof replacer !== &amp;quot;function&amp;quot; &amp;amp;&amp;amp; (&lt;br /&gt;
                typeof replacer !== &amp;quot;object&amp;quot;&lt;br /&gt;
                || typeof replacer.length !== &amp;quot;number&amp;quot;&lt;br /&gt;
            )) {&lt;br /&gt;
                throw new Error(&amp;quot;JSON.stringify&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// Make a fake root object containing our value under the key of &amp;quot;&amp;quot;.&lt;br /&gt;
// Return the result of stringifying the value.&lt;br /&gt;
&lt;br /&gt;
            return str(&amp;quot;&amp;quot;, {&amp;quot;&amp;quot;: value});&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// If the JSON object does not yet have a parse method, give it one.&lt;br /&gt;
&lt;br /&gt;
    if (typeof JSON.parse !== &amp;quot;function&amp;quot;) {&lt;br /&gt;
        JSON.parse = function (text, reviver) {&lt;br /&gt;
&lt;br /&gt;
// The parse method takes a text and an optional reviver function, and returns&lt;br /&gt;
// a JavaScript value if the text is a valid JSON text.&lt;br /&gt;
&lt;br /&gt;
            var j;&lt;br /&gt;
&lt;br /&gt;
            function walk(holder, key) {&lt;br /&gt;
&lt;br /&gt;
// The walk method is used to recursively walk the resulting structure so&lt;br /&gt;
// that modifications can be made.&lt;br /&gt;
&lt;br /&gt;
                var k;&lt;br /&gt;
                var v;&lt;br /&gt;
                var value = holder[key];&lt;br /&gt;
                if (value &amp;amp;&amp;amp; typeof value === &amp;quot;object&amp;quot;) {&lt;br /&gt;
                    for (k in value) {&lt;br /&gt;
                        if (Object.prototype.hasOwnProperty.call(value, k)) {&lt;br /&gt;
                            v = walk(value, k);&lt;br /&gt;
                            if (v !== undefined) {&lt;br /&gt;
                                value[k] = v;&lt;br /&gt;
                            } else {&lt;br /&gt;
                                delete value[k];&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
                return reviver.call(holder, key, value);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Parsing happens in four stages. In the first stage, we replace certain&lt;br /&gt;
// Unicode characters with escape sequences. JavaScript handles many characters&lt;br /&gt;
// incorrectly, either silently deleting them, or treating them as line endings.&lt;br /&gt;
&lt;br /&gt;
            text = String(text);&lt;br /&gt;
            rx_dangerous.lastIndex = 0;&lt;br /&gt;
            if (rx_dangerous.test(text)) {&lt;br /&gt;
                text = text.replace(rx_dangerous, function (a) {&lt;br /&gt;
                    return (&lt;br /&gt;
                        &amp;quot;\\u&amp;quot;&lt;br /&gt;
                        + (&amp;quot;0000&amp;quot; + a.charCodeAt(0).toString(16)).slice(-4)&lt;br /&gt;
                    );&lt;br /&gt;
                });&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// In the second stage, we run the text against regular expressions that look&lt;br /&gt;
// for non-JSON patterns. We are especially concerned with &amp;quot;()&amp;quot; and &amp;quot;new&amp;quot;&lt;br /&gt;
// because they can cause invocation, and &amp;quot;=&amp;quot; because it can cause mutation.&lt;br /&gt;
// But just to be safe, we want to reject all unexpected forms.&lt;br /&gt;
&lt;br /&gt;
// We split the second stage into 4 regexp operations in order to work around&lt;br /&gt;
// crippling inefficiencies in IE&#039;s and Safari&#039;s regexp engines. First we&lt;br /&gt;
// replace the JSON backslash pairs with &amp;quot;@&amp;quot; (a non-JSON character). Second, we&lt;br /&gt;
// replace all simple value tokens with &amp;quot;]&amp;quot; characters. Third, we delete all&lt;br /&gt;
// open brackets that follow a colon or comma or that begin the text. Finally,&lt;br /&gt;
// we look to see that the remaining characters are only whitespace or &amp;quot;]&amp;quot; or&lt;br /&gt;
// &amp;quot;,&amp;quot; or &amp;quot;:&amp;quot; or &amp;quot;{&amp;quot; or &amp;quot;}&amp;quot;. If that is so, then the text is safe for eval.&lt;br /&gt;
&lt;br /&gt;
            if (&lt;br /&gt;
                rx_one.test(&lt;br /&gt;
                    text&lt;br /&gt;
                        .replace(rx_two, &amp;quot;@&amp;quot;)&lt;br /&gt;
                        .replace(rx_three, &amp;quot;]&amp;quot;)&lt;br /&gt;
                        .replace(rx_four, &amp;quot;&amp;quot;)&lt;br /&gt;
                )&lt;br /&gt;
            ) {&lt;br /&gt;
&lt;br /&gt;
// In the third stage we use the eval function to compile the text into a&lt;br /&gt;
// JavaScript structure. The &amp;quot;{&amp;quot; operator is subject to a syntactic ambiguity&lt;br /&gt;
// in JavaScript: it can begin a block or an object literal. We wrap the text&lt;br /&gt;
// in parens to eliminate the ambiguity.&lt;br /&gt;
&lt;br /&gt;
                j = eval(&amp;quot;(&amp;quot; + text + &amp;quot;)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// In the optional fourth stage, we recursively walk the new structure, passing&lt;br /&gt;
// each name/value pair to a reviver function for possible transformation.&lt;br /&gt;
&lt;br /&gt;
                return (typeof reviver === &amp;quot;function&amp;quot;)&lt;br /&gt;
                    ? walk({&amp;quot;&amp;quot;: j}, &amp;quot;&amp;quot;)&lt;br /&gt;
                    : j;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// If the text is not JSON parseable, then a SyntaxError is thrown.&lt;br /&gt;
&lt;br /&gt;
            throw new SyntaxError(&amp;quot;JSON.parse&amp;quot;);&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
exec();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Modding]]&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Player_(Asset)&amp;diff=341</id>
		<title>Player (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Player_(Asset)&amp;diff=341"/>
		<updated>2026-06-05T14:06:57Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A player is an NPC or player character with fixed settings. Useful for NPCs or playable characters linked in [[Gallery (Asset)|Gallery]]. If you want to create random NPCs for random encounters, use a [[Player Template (Asset)|Player Template]] instead. &lt;br /&gt;
&lt;br /&gt;
If you want an NPC to offer a service, check out the [[Creating a Service NPC|Creating a Service]] tutorial.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique ID for your player. &#039;&#039;&#039;Do not edit after creation!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Name of your character. Not unique.&lt;br /&gt;
|-&lt;br /&gt;
|Species Article&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A/An. Automatically inferred unless your species doesn&#039;t follow the &amp;quot;an&amp;quot; before a vowel, such as unicorn.&lt;br /&gt;
|-&lt;br /&gt;
|Species&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Species of your character.&lt;br /&gt;
|-&lt;br /&gt;
|Voice&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you bind combat grunts. Not currently used in the official game.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun he&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|he/she/it pronoun. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun him&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|him/her/it pronoun. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun his&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|his/her/its. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Image dressed&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to fully dressed state. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image upper body armor&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing only upper body armor. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image lower body armor&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing only lower body armor. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image nude&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing no clothes, or to art if character has only one art layer. Should always be used.&lt;br /&gt;
|-&lt;br /&gt;
|Icon Y Offset&lt;br /&gt;
|Int&lt;br /&gt;
|&lt;br /&gt;
|Offset from top to put portrait in percent. 0 uses default (5%).&lt;br /&gt;
|-&lt;br /&gt;
|Image base path&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Gets prepended to all images (even advanced art layers). Saves some typing. You can use the domain here, such as https://imagehost.com/&lt;br /&gt;
|-&lt;br /&gt;
|No Proxy&lt;br /&gt;
|Boolean&lt;br /&gt;
|false&lt;br /&gt;
|In order for CORS to work, images hosted at an external domain will use the FQ proxy service. However, if you know for sure that your image is hosted at a place with proper CORS headers, checking no proxy will make the image load faster.&lt;br /&gt;
|-&lt;br /&gt;
|Portrait XYWH&lt;br /&gt;
|Vector&lt;br /&gt;
|0,0,0&lt;br /&gt;
|Sets the portrait icon. Click select, then drag a box over the character&#039;s face. Right click when done.&lt;br /&gt;
|-&lt;br /&gt;
|Team&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Team of player, decides how the NPC behaves in combat. Use 0 for players. Use 1 for enemies and NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Size&lt;br /&gt;
|Float&lt;br /&gt;
|5&lt;br /&gt;
|Used mainly in texts. Where 5 = average human, 0 = insect, 10 = dragon. Use a range between 4-6 for most humanoids.&lt;br /&gt;
|-&lt;br /&gt;
|Level&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Default level. Note that level is set to 1 for all player characters on game start.&lt;br /&gt;
|-&lt;br /&gt;
|Level is offset from party&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Check this for combat NPCs. When checked, the level field becomes an offset from the average player level. Setting the level field to 0 will then equal to same as player average level, and setting it to 1 means average player level plus 1.&lt;br /&gt;
|-&lt;br /&gt;
|Power&lt;br /&gt;
|Float&lt;br /&gt;
|1&lt;br /&gt;
|Sets how powerful an NPC is compared to other NPCs in the encounter. Note that this value is normalized. If you want a harder fight, set difficulty on the encounter instead.&lt;br /&gt;
|-&lt;br /&gt;
|HP Multiplier&lt;br /&gt;
|Float&lt;br /&gt;
|1&lt;br /&gt;
|Lets you increase or decrease the character&#039;s max HP by this.&lt;br /&gt;
|-&lt;br /&gt;
|Armor&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Used mainly for beasts. Percentage damage reduction from all attacks unless they bypass armor. 0 = no damage reduction, 100 = full.&lt;br /&gt;
|-&lt;br /&gt;
|Talkative&lt;br /&gt;
|Float&lt;br /&gt;
|0.3&lt;br /&gt;
|Multiplier used to check if an NPC should use Chat type texts in response to an event. Higher value = more talkative.&lt;br /&gt;
|-&lt;br /&gt;
|Sadistic&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Used mainly for flavor in roleplays.&lt;br /&gt;
|-&lt;br /&gt;
|Dominant&lt;br /&gt;
|Float&lt;br /&gt;
|0.8&lt;br /&gt;
|Used mainly for flavor in roleplays.&lt;br /&gt;
|-&lt;br /&gt;
|Hetero&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Determines sexual preference. Where 0.5 = bisexual. Used in NPCs to slightly modify who they are more likely to attack.&lt;br /&gt;
|-&lt;br /&gt;
|Emotive&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Chance to use audio triggers. Not used in the main game.&lt;br /&gt;
|-&lt;br /&gt;
|Intelligence&lt;br /&gt;
|Float&lt;br /&gt;
|0.6&lt;br /&gt;
|Slightly affects AI decisions and used for flavor in RP. 0.6 is average human intelligence. 0.4-0.5 a dumb human. 0.1-0.2 for most beasts.&lt;br /&gt;
|-&lt;br /&gt;
|Ignore spell slots&lt;br /&gt;
|Boolean&lt;br /&gt;
|True&lt;br /&gt;
|When used on NPCs they can use ALL abilities available to them, rather than just slotted ones. Uncheck for players, and leave checked for NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|PC Chat Reactions&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|By default, only players not controlled by a human are allowed to use chat type texts. Checking this allows the player to use these texts regardless of if it&#039;s controlled or not.&lt;br /&gt;
|-&lt;br /&gt;
|Remove on death&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When dying, immediately remove this player from the game. Useful for summoned NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Placement Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you change the player label when they are placed in world.&lt;br /&gt;
|-&lt;br /&gt;
|Play Order&lt;br /&gt;
|Int&lt;br /&gt;
|10&lt;br /&gt;
|Sets the order that NPCs will play in. Lower value goes first. If multiple NPCs have the same order, their order will be shuffled after each action.&lt;br /&gt;
|-&lt;br /&gt;
|Stats&lt;br /&gt;
|Integers&lt;br /&gt;
|&lt;br /&gt;
|Hard codes player stats. Only recommended for NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Describes your player in the gallery selector, and when inspecting them.&lt;br /&gt;
|-&lt;br /&gt;
|Secret information&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Secret information to show when using clairvoyance on the player.&lt;br /&gt;
|-&lt;br /&gt;
|Jiggles&lt;br /&gt;
|[[Player Jiggle (Asset)|Player Jiggle]]&lt;br /&gt;
|&lt;br /&gt;
|Player jiggle assets.&lt;br /&gt;
|-&lt;br /&gt;
|Advanced Icon States&lt;br /&gt;
|[[Player Icon State (Asset)|Player Icon State]]&lt;br /&gt;
|&lt;br /&gt;
|See [[Creating Advanced Art Layers|creating advanced art layers]]. You can shift click these to toggle them in the preview. Also works in the jiggle previews, but you will have to manually refresh them by clicking the refresh button at the top of the window.&lt;br /&gt;
|-&lt;br /&gt;
|Player Class&lt;br /&gt;
|[[Player Class (Asset)|Player Class]]&lt;br /&gt;
|&lt;br /&gt;
|Sets player class.&lt;br /&gt;
|-&lt;br /&gt;
|Tags&lt;br /&gt;
|Tags&lt;br /&gt;
|&lt;br /&gt;
|Sets player tags. Unlike editing tags within the game itself, you must prefix these with the pl_ prefix.&lt;br /&gt;
|-&lt;br /&gt;
|Actions&lt;br /&gt;
|[[Action (Asset)|Action]]&lt;br /&gt;
|&lt;br /&gt;
|Adds actions to the player.&lt;br /&gt;
|-&lt;br /&gt;
|Passives&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Adds passive wrappers to the player.&lt;br /&gt;
|-&lt;br /&gt;
|Follower RP&lt;br /&gt;
|[[Roleplay (Asset)|Roleplay]]&lt;br /&gt;
|&lt;br /&gt;
|Marks the player as a follower, and adds a roleplay when talking to the follower.&lt;br /&gt;
|-&lt;br /&gt;
|Preview&lt;br /&gt;
|N/A&lt;br /&gt;
|&lt;br /&gt;
|Preview of what the player will look like.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Player_(Asset)&amp;diff=340</id>
		<title>Player (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Player_(Asset)&amp;diff=340"/>
		<updated>2026-06-05T13:06:52Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A player is an NPC or player character with fixed settings. Useful for NPCs or playable characters linked in [[Gallery (Asset)|Gallery]]. If you want to create random NPCs for random encounters, use a [[Player Template (Asset)|Player Template]] instead. &lt;br /&gt;
&lt;br /&gt;
If you want an NPC to offer a service, check out the [[Creating a Service NPC|Creating a Service]] tutorial.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique ID for your player. &#039;&#039;&#039;Do not edit after creation!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Name of your character. Not unique.&lt;br /&gt;
|-&lt;br /&gt;
|Species Article&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A/An. Automatically inferred unless your species doesn&#039;t follow the &amp;quot;an&amp;quot; before a vowel, such as unicorn.&lt;br /&gt;
|-&lt;br /&gt;
|Species&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Species of your character.&lt;br /&gt;
|-&lt;br /&gt;
|Voice&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you bind combat grunts. Not currently used in the official game.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun he&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|he/she/it pronoun. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun him&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|him/her/it pronoun. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun his&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|his/her/its. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Image dressed&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to fully dressed state. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image upper body armor&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing only upper body armor. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image lower body armor&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing only lower body armor. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image nude&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing no clothes, or to art if character has only one art layer. Should always be used.&lt;br /&gt;
|-&lt;br /&gt;
|Icon Y Offset&lt;br /&gt;
|Int&lt;br /&gt;
|&lt;br /&gt;
|Offset from top to put portrait in percent. 0 uses default (5%).&lt;br /&gt;
|-&lt;br /&gt;
|Image base path&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Gets prepended to all images (even advanced art layers). Saves some typing. You can use the domain here, such as https://imagehost.com/&lt;br /&gt;
|-&lt;br /&gt;
|No Proxy&lt;br /&gt;
|Boolean&lt;br /&gt;
|false&lt;br /&gt;
|In order for CORS to work, images hosted at an external domain will use the FQ proxy service. However, if you know for sure that your image is hosted at a place with proper CORS headers, checking no proxy will make the image load faster.&lt;br /&gt;
|-&lt;br /&gt;
|Portrait XYWH&lt;br /&gt;
|Vector&lt;br /&gt;
|0,0,0&lt;br /&gt;
|Sets the portrait icon. Click select, then drag a box over the character&#039;s face. Right click when done.&lt;br /&gt;
|-&lt;br /&gt;
|Team&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Team of player, decides how the NPC behaves in combat. Use 0 for players. Use 1 for enemies and NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Size&lt;br /&gt;
|Float&lt;br /&gt;
|5&lt;br /&gt;
|Used mainly in texts. Where 5 = average human, 0 = insect, 10 = dragon. Use a range between 4-6 for most humanoids.&lt;br /&gt;
|-&lt;br /&gt;
|Level&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Default level. Note that level is set to 1 for all player characters on game start.&lt;br /&gt;
|-&lt;br /&gt;
|Level is offset from party&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Check this for combat NPCs. When checked, the level field becomes an offset from the average player level. Setting the level field to 0 will then equal to same as player average level, and setting it to 1 means average player level plus 1.&lt;br /&gt;
|-&lt;br /&gt;
|Power&lt;br /&gt;
|Float&lt;br /&gt;
|1&lt;br /&gt;
|Lets you make a player more or less powerful. Multiplying their stats.&lt;br /&gt;
|-&lt;br /&gt;
|HP Multiplier&lt;br /&gt;
|Float&lt;br /&gt;
|1&lt;br /&gt;
|Lets you increase or decrease the character&#039;s max HP by this.&lt;br /&gt;
|-&lt;br /&gt;
|Armor&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Used mainly for beasts. Percentage damage reduction from all attacks unless they bypass armor. 0 = no damage reduction, 100 = full.&lt;br /&gt;
|-&lt;br /&gt;
|Talkative&lt;br /&gt;
|Float&lt;br /&gt;
|0.3&lt;br /&gt;
|Multiplier used to check if an NPC should use Chat type texts in response to an event. Higher value = more talkative.&lt;br /&gt;
|-&lt;br /&gt;
|Sadistic&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Used mainly for flavor in roleplays.&lt;br /&gt;
|-&lt;br /&gt;
|Dominant&lt;br /&gt;
|Float&lt;br /&gt;
|0.8&lt;br /&gt;
|Used mainly for flavor in roleplays.&lt;br /&gt;
|-&lt;br /&gt;
|Hetero&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Determines sexual preference. Where 0.5 = bisexual. Used in NPCs to slightly modify who they are more likely to attack.&lt;br /&gt;
|-&lt;br /&gt;
|Emotive&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Chance to use audio triggers. Not used in the main game.&lt;br /&gt;
|-&lt;br /&gt;
|Intelligence&lt;br /&gt;
|Float&lt;br /&gt;
|0.6&lt;br /&gt;
|Slightly affects AI decisions and used for flavor in RP. 0.6 is average human intelligence. 0.4-0.5 a dumb human. 0.1-0.2 for most beasts.&lt;br /&gt;
|-&lt;br /&gt;
|Ignore spell slots&lt;br /&gt;
|Boolean&lt;br /&gt;
|True&lt;br /&gt;
|When used on NPCs they can use ALL abilities available to them, rather than just slotted ones. Uncheck for players, and leave checked for NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|PC Chat Reactions&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|By default, only players not controlled by a human are allowed to use chat type texts. Checking this allows the player to use these texts regardless of if it&#039;s controlled or not.&lt;br /&gt;
|-&lt;br /&gt;
|Remove on death&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When dying, immediately remove this player from the game. Useful for summoned NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Placement Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you change the player label when they are placed in world.&lt;br /&gt;
|-&lt;br /&gt;
|Play Order&lt;br /&gt;
|Int&lt;br /&gt;
|10&lt;br /&gt;
|Sets the order that NPCs will play in. Lower value goes first. If multiple NPCs have the same order, their order will be shuffled after each action.&lt;br /&gt;
|-&lt;br /&gt;
|Stats&lt;br /&gt;
|Integers&lt;br /&gt;
|&lt;br /&gt;
|Hard codes player stats. Only recommended for NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Describes your player in the gallery selector, and when inspecting them.&lt;br /&gt;
|-&lt;br /&gt;
|Secret information&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Secret information to show when using clairvoyance on the player.&lt;br /&gt;
|-&lt;br /&gt;
|Jiggles&lt;br /&gt;
|[[Player Jiggle (Asset)|Player Jiggle]]&lt;br /&gt;
|&lt;br /&gt;
|Player jiggle assets.&lt;br /&gt;
|-&lt;br /&gt;
|Advanced Icon States&lt;br /&gt;
|[[Player Icon State (Asset)|Player Icon State]]&lt;br /&gt;
|&lt;br /&gt;
|See [[Creating Advanced Art Layers|creating advanced art layers]]. You can shift click these to toggle them in the preview. Also works in the jiggle previews, but you will have to manually refresh them by clicking the refresh button at the top of the window.&lt;br /&gt;
|-&lt;br /&gt;
|Player Class&lt;br /&gt;
|[[Player Class (Asset)|Player Class]]&lt;br /&gt;
|&lt;br /&gt;
|Sets player class.&lt;br /&gt;
|-&lt;br /&gt;
|Tags&lt;br /&gt;
|Tags&lt;br /&gt;
|&lt;br /&gt;
|Sets player tags. Unlike editing tags within the game itself, you must prefix these with the pl_ prefix.&lt;br /&gt;
|-&lt;br /&gt;
|Actions&lt;br /&gt;
|[[Action (Asset)|Action]]&lt;br /&gt;
|&lt;br /&gt;
|Adds actions to the player.&lt;br /&gt;
|-&lt;br /&gt;
|Passives&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Adds passive wrappers to the player.&lt;br /&gt;
|-&lt;br /&gt;
|Follower RP&lt;br /&gt;
|[[Roleplay (Asset)|Roleplay]]&lt;br /&gt;
|&lt;br /&gt;
|Marks the player as a follower, and adds a roleplay when talking to the follower.&lt;br /&gt;
|-&lt;br /&gt;
|Preview&lt;br /&gt;
|N/A&lt;br /&gt;
|&lt;br /&gt;
|Preview of what the player will look like.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=FqAutoLayers&amp;diff=339</id>
		<title>FqAutoLayers</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=FqAutoLayers&amp;diff=339"/>
		<updated>2026-06-05T11:54:34Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This script will automatically try to remove unchanged pixels. Save it as fqAutoLayers.jsx and import into photoshop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
var startRulesUnits = preferences.rulerUnits;&lt;br /&gt;
var doc = activeDocument;&lt;br /&gt;
var bgLayer;&lt;br /&gt;
var allLayers = [];&lt;br /&gt;
&lt;br /&gt;
var layerNames = {&lt;br /&gt;
	stains : 55,&lt;br /&gt;
	gloves : 50,&lt;br /&gt;
	boots : 40,&lt;br /&gt;
	&lt;br /&gt;
	sling_heavy: 25,&lt;br /&gt;
	sling_med : 25,&lt;br /&gt;
	sling_leather : {alias:&amp;quot;sling_med&amp;quot;, num:25},&lt;br /&gt;
	sling_medium : {alias:&amp;quot;sling_med&amp;quot;, num:25},&lt;br /&gt;
	sling_light : 25,&lt;br /&gt;
	sling_cloth : {alias:&amp;quot;sling_light&amp;quot;, num:25},&lt;br /&gt;
	&lt;br /&gt;
	bodysuit_med : 25,&lt;br /&gt;
	bodysuit_medium : {alias:&amp;quot;bodysuit_med&amp;quot;, num:25},&lt;br /&gt;
	bodysuit_leather : {alias:&amp;quot;bodysuit_med&amp;quot;, num:25},	&lt;br /&gt;
	&lt;br /&gt;
	bodysuit_light : 25,&lt;br /&gt;
	bodysuit_cloth : {alias:&amp;quot;bodysuit_light&amp;quot;, num:25},&lt;br /&gt;
	&lt;br /&gt;
	bikini_med : 35,&lt;br /&gt;
	bikini_light : 35,&lt;br /&gt;
	&lt;br /&gt;
	heavy : {alias:&amp;quot;heavy_ub&amp;quot;,num:35},&lt;br /&gt;
	&lt;br /&gt;
	leather : {alias:&amp;quot;med_ub&amp;quot;, num:35},&lt;br /&gt;
	med : {alias:&amp;quot;med_ub&amp;quot;, num:35},&lt;br /&gt;
	medium : {alias:&amp;quot;med_ub&amp;quot;, num:35},&lt;br /&gt;
	&lt;br /&gt;
	&lt;br /&gt;
	armor : {alias:&amp;quot;light_ub&amp;quot;,num:35}, // Used for NPCs with only one armor set&lt;br /&gt;
	cloth : {alias:&amp;quot;light_ub&amp;quot;, num:35},&lt;br /&gt;
	light : {alias:&amp;quot;light_ub&amp;quot;, num:35},&lt;br /&gt;
	&lt;br /&gt;
	collar : 23,&lt;br /&gt;
	nipple_studs : 22,&lt;br /&gt;
	stocks_aroused : {alias:&amp;quot;aroused&amp;quot;, num:10},&lt;br /&gt;
	aroused : 10,&lt;br /&gt;
	stocks_pain : {alias:&amp;quot;pain&amp;quot;, num:10},&lt;br /&gt;
	pain : 10,&lt;br /&gt;
	stocks_orgasm : {alias:&amp;quot;orgasm&amp;quot;, num:5},&lt;br /&gt;
	orgasm : 5,&lt;br /&gt;
	stocks_pain_heavy : {alias:&amp;quot;pain_heavy&amp;quot;, num:15},&lt;br /&gt;
	pain_heavy: 15,&lt;br /&gt;
	stocks_aroused_heavy : {alias:&amp;quot;aroused_heavy&amp;quot;, num:15},&lt;br /&gt;
	aroused_heavy: 15&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function exec(){&lt;br /&gt;
&lt;br /&gt;
	fetchLayers(doc);&lt;br /&gt;
&lt;br /&gt;
	for( var i = 0; i &amp;lt; allLayers.length; ++i ){&lt;br /&gt;
		&lt;br /&gt;
		hideAllLayers();&lt;br /&gt;
&lt;br /&gt;
		var l = allLayers[i];&lt;br /&gt;
		activeDocument.activeLayer = l;&lt;br /&gt;
		l.visible = true;&lt;br /&gt;
		&lt;br /&gt;
		l.blendMode = BlendMode.DIFFERENCE;&lt;br /&gt;
		&lt;br /&gt;
		quickSel(0,0,1);&lt;br /&gt;
		doc.selection.clear();&lt;br /&gt;
		doc.selection.deselect();&lt;br /&gt;
		&lt;br /&gt;
		l.blendMode = BlendMode.NORMAL;&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function quickSel (x, y, tol){&lt;br /&gt;
&lt;br /&gt;
	var idsetd = charIDToTypeID( &amp;quot;setd&amp;quot; );&lt;br /&gt;
	var desc2 = new ActionDescriptor();&lt;br /&gt;
	var idnull = charIDToTypeID( &amp;quot;null&amp;quot; );&lt;br /&gt;
		var ref1 = new ActionReference();&lt;br /&gt;
		var idChnl = charIDToTypeID( &amp;quot;Chnl&amp;quot; );&lt;br /&gt;
		var idfsel = charIDToTypeID( &amp;quot;fsel&amp;quot; );&lt;br /&gt;
		ref1.putProperty( idChnl, idfsel );&lt;br /&gt;
	desc2.putReference( idnull, ref1 );&lt;br /&gt;
	var idT = charIDToTypeID( &amp;quot;T   &amp;quot; );&lt;br /&gt;
		var desc3 = new ActionDescriptor();&lt;br /&gt;
		var idHrzn = charIDToTypeID( &amp;quot;Hrzn&amp;quot; );&lt;br /&gt;
		var idPxl = charIDToTypeID( &amp;quot;#Pxl&amp;quot; );&lt;br /&gt;
		desc3.putUnitDouble( idHrzn, idPxl, x );&lt;br /&gt;
		var idVrtc = charIDToTypeID( &amp;quot;Vrtc&amp;quot; );&lt;br /&gt;
		var idPxl = charIDToTypeID( &amp;quot;#Pxl&amp;quot; );&lt;br /&gt;
		desc3.putUnitDouble( idVrtc, idPxl, y);&lt;br /&gt;
	var idPnt = charIDToTypeID( &amp;quot;Pnt &amp;quot; );&lt;br /&gt;
	desc2.putObject( idT, idPnt, desc3 );&lt;br /&gt;
	var idTlrn = charIDToTypeID( &amp;quot;Tlrn&amp;quot; );&lt;br /&gt;
	desc2.putInteger( idTlrn, tol);&lt;br /&gt;
	var idAntA = charIDToTypeID( &amp;quot;AntA&amp;quot; );&lt;br /&gt;
	desc2.putBoolean( idAntA, true );&lt;br /&gt;
	var idCntg = charIDToTypeID( &amp;quot;Cntg&amp;quot; );&lt;br /&gt;
	desc2.putBoolean( idCntg, true );&lt;br /&gt;
	var idMrgd = charIDToTypeID( &amp;quot;Mrgd&amp;quot; );&lt;br /&gt;
	desc2.putBoolean( idMrgd, true );&lt;br /&gt;
	executeAction( idsetd, desc2, DialogModes.NO );&lt;br /&gt;
&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function hideAllLayers(){&lt;br /&gt;
	for( var i = 0; i &amp;lt; allLayers.length; ++i )&lt;br /&gt;
		allLayers[i].visible = false;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Fetches all viable art layers&lt;br /&gt;
function fetchLayers( parentLayer, ignore ){&lt;br /&gt;
	&lt;br /&gt;
	for( var i = 0; i &amp;lt; parentLayer.layers.length; ++i ){&lt;br /&gt;
		&lt;br /&gt;
		var l = parentLayer.layers[i];&lt;br /&gt;
		&lt;br /&gt;
		var ign = ignore;&lt;br /&gt;
		var isBg = l.name == &amp;quot;Background&amp;quot;;&lt;br /&gt;
		if( !ignore )&lt;br /&gt;
			ign = ( l.name.substring(0,1) == &amp;quot;#&amp;quot; || isBg || l.name.substring(0,1) == &amp;quot;.&amp;quot; );&lt;br /&gt;
		if( isBg )&lt;br /&gt;
			bgLayer = l;&lt;br /&gt;
&lt;br /&gt;
		if( l.typename == &amp;quot;LayerSet&amp;quot; ){&lt;br /&gt;
			fetchLayers(l, ign);&lt;br /&gt;
			continue;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if( !isBg ){&lt;br /&gt;
			&lt;br /&gt;
			var subname = l.name.split(&#039;.&#039;);&lt;br /&gt;
			subname.pop();&lt;br /&gt;
			subname = subname.join(&amp;quot;.&amp;quot;).toLowerCase();&lt;br /&gt;
			var itm = layerNames[subname];			&lt;br /&gt;
			if( itm !== undefined ){&lt;br /&gt;
				if( typeof itm === &amp;quot;object&amp;quot; ){&lt;br /&gt;
					subname = itm.alias;&lt;br /&gt;
					itm = itm.num;&lt;br /&gt;
				}&lt;br /&gt;
				l.name = itm+&amp;quot;_&amp;quot;+subname;&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if( !ign ){&lt;br /&gt;
			allLayers.push(l);&lt;br /&gt;
		}&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
exec();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=FQCrop_Batch&amp;diff=338</id>
		<title>FQCrop Batch</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=FQCrop_Batch&amp;diff=338"/>
		<updated>2026-06-05T11:53:55Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The following is a script you can use along with the [[Creating Advanced Art Layers|Creating Advanced Art Layers Guide]] to speed up connecting your advanced art layers to your FQ mod.&lt;br /&gt;
&lt;br /&gt;
To use it, simply copy the content into a new text file and name it fqcrop_batch.jsx&lt;br /&gt;
&lt;br /&gt;
You can either put this in your Phothoshop/Presets/Scripts folder and restart photoshop to use it from file &amp;gt; scripts. Or you can go to file &amp;gt; scripts &amp;gt; browse.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
	Note: This is similar to the fqcrop.jsx file except it exports all layers one at a time.&lt;br /&gt;
	Usage: See fqcrop.jsx for more info. Things you need to keep in mind in this implementation:&lt;br /&gt;
	- Each art layer can only consist of ONE photoshop layer&lt;br /&gt;
	- All layers must begin with &amp;lt;layerNr&amp;gt;_ ex 30_bikini_light_ub to use layer 30 (upper body base)&lt;br /&gt;
	- A JSON metadata file named the same as the original file will be created or updated. It&#039;s going to need a bit of editing, but you can use it to quickly upload a full character.&lt;br /&gt;
	- Layers and groups starting with # are ignored.&lt;br /&gt;
	- If a JSON file exists, it&#039;s loaded and updated. Missing layers aren&#039;t deleted from it. So if you remove layers you have to remove them from the JSON file or delete the JSON file to generate a new one.&lt;br /&gt;
	- The following values are overwritten into the JSON file, using the photoshop settings:&lt;br /&gt;
		- icon&lt;br /&gt;
		- x&lt;br /&gt;
		- y&lt;br /&gt;
		- blendMode (only normal, multiply, overlay are supported)&lt;br /&gt;
		- opacity&lt;br /&gt;
*/&lt;br /&gt;
var startRulesUnits = preferences.rulerUnits;&lt;br /&gt;
var doc = activeDocument;&lt;br /&gt;
var docW = doc.width;&lt;br /&gt;
var docH = doc.height;&lt;br /&gt;
var allLayers = [];&lt;br /&gt;
var dirJson = decodeURI(doc.path.fsName)+&amp;quot;/&amp;quot;;&lt;br /&gt;
var jsonName = doc.name.split(&amp;quot;.&amp;quot;);&lt;br /&gt;
jsonName.pop();&lt;br /&gt;
var fName = jsonName.join(&#039;_&#039;)&lt;br /&gt;
var dir = dirJson+fName+&amp;quot;/&amp;quot;;&lt;br /&gt;
jsonName = jsonName.join(&amp;quot;.&amp;quot;)+&amp;quot;.json&amp;quot;;&lt;br /&gt;
var pics = [];&lt;br /&gt;
var url = &#039;&#039;;&lt;br /&gt;
var bgName = &amp;quot;&amp;quot;;&lt;br /&gt;
var bgLayer;&lt;br /&gt;
Array.prototype.indexOf = function ( item ) {&lt;br /&gt;
&lt;br /&gt;
	  var index = 0, length = this.length;&lt;br /&gt;
&lt;br /&gt;
	  for ( ; index &amp;lt; length; index++ ) {&lt;br /&gt;
&lt;br /&gt;
				if ( this[index] === item )&lt;br /&gt;
&lt;br /&gt;
						  return index;&lt;br /&gt;
&lt;br /&gt;
	  }&lt;br /&gt;
&lt;br /&gt;
	  return -1;&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
var jiggleMasks = {&lt;br /&gt;
	&#039;jm_breasts&#039; : {&lt;br /&gt;
		slot : &amp;quot;Breasts&amp;quot;,&lt;br /&gt;
		points : []&lt;br /&gt;
	},&lt;br /&gt;
	&#039;jm_groin&#039; : {&lt;br /&gt;
		slot : &amp;quot;Groin&amp;quot;,&lt;br /&gt;
		points : []&lt;br /&gt;
	},&lt;br /&gt;
	&#039;jm_butt&#039; : {&lt;br /&gt;
		slot : &amp;quot;Butt&amp;quot;,&lt;br /&gt;
		points : []&lt;br /&gt;
	}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var condMap = {&lt;br /&gt;
	&#039;55_stains&#039; : {&lt;br /&gt;
        conds : [&#039;targetStains&#039;],&lt;br /&gt;
    },&lt;br /&gt;
	&#039;51_gloves&#039; : {&lt;br /&gt;
		conds : [&#039;targetGloves&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;50_gloves&#039; : {&lt;br /&gt;
		conds : [&#039;targetGloves&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;19_gloves&#039; : {&lt;br /&gt;
		conds : [&#039;targetGloves&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;18_gloves&#039; : {&lt;br /&gt;
		conds : [&#039;targetGloves&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;41_boots&#039; : {&lt;br /&gt;
		conds : [&#039;targetBoots&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;40_boots&#039; : {&lt;br /&gt;
		conds : [&#039;targetBoots&#039;]&lt;br /&gt;
	},&lt;br /&gt;
    &#039;26_sling_heavy&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;,&#039;targetLowerBodyHard&#039;] &lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_sling_heavy&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;,&#039;targetLowerBodyHard&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_sling_med&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;,&#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_sling_med&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;,&#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_sling_light&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_sling_light&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_bodysuit_med&#039; : {&lt;br /&gt;
        conds: [&#039;targetBodysuit&#039;, &#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_bodysuit_med&#039; : {&lt;br /&gt;
        conds: [&#039;targetBodysuit&#039;, &#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_bodysuit_light&#039; : {&lt;br /&gt;
        conds: [&#039;targetBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_bodysuit_light&#039; : {&lt;br /&gt;
        conds: [&#039;targetBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
    &#039;36_heavy_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyHard&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;35_heavy_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyHard&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
    &#039;26_heavy_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetLowerBodyHard&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_heavy_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetLowerBodyHard&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&lt;br /&gt;
	&#039;36_bikini_med_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyBikini&#039;, &#039;targetUpperBodyLeather&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;35_bikini_med_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyBikini&#039;, &#039;targetUpperBodyLeather&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;26_bikini_med_lb&#039; : {&lt;br /&gt;
		conds: [&#039;targetWearsThong&#039;, &#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;25_bikini_med_lb&#039; : {&lt;br /&gt;
		conds: [&#039;targetWearsThong&#039;, &#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&lt;br /&gt;
	&#039;36_bikini_light_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyBikini&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;35_bikini_light_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyBikini&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;26_bikini_light_lb&#039; : {&lt;br /&gt;
		conds: [&#039;targetWearsThong&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;25_bikini_light_lb&#039; : {&lt;br /&gt;
		conds: [&#039;targetWearsThong&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&lt;br /&gt;
    &lt;br /&gt;
    &#039;36_med_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyLeather&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;35_med_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyLeather&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_med_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_med_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
	&lt;br /&gt;
    &#039;36_light_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsUpperBody&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;35_light_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsUpperBody&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_light_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsLowerBody&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_light_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsLowerBody&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
	// Collar can be either above or below armor&lt;br /&gt;
    &#039;3_collar&#039; : {&lt;br /&gt;
        conds: [&#039;targetCollar&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;23_collar&#039; : {&lt;br /&gt;
        conds: [&#039;targetCollar&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;43_collar&#039; : {&lt;br /&gt;
        conds: [&#039;targetCollar&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&lt;br /&gt;
	&#039;22_nipple_studs&#039; : {&lt;br /&gt;
        conds: [&#039;targetCollar&#039;]&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    &#039;15_aroused_heavy&#039; : {&lt;br /&gt;
        conds: [&#039;metaVeryArousing&#039;],&lt;br /&gt;
        stdtag: &#039;ex_aroused_heavy&#039;&lt;br /&gt;
    },&lt;br /&gt;
    &#039;15_pain_heavy&#039; : {&lt;br /&gt;
        conds: [&#039;metaVeryPainful&#039;],&lt;br /&gt;
        stdtag : &#039;ex_pained_heavy&#039;&lt;br /&gt;
    },&lt;br /&gt;
    &#039;10_aroused&#039; : {&lt;br /&gt;
        conds: [&#039;metaArousing&#039;],&lt;br /&gt;
        stdtag: &#039;ex_aroused&#039;&lt;br /&gt;
    },&lt;br /&gt;
    &#039;10_pain&#039; : {&lt;br /&gt;
        conds: [&#039;metaPainful&#039;],&lt;br /&gt;
        stdtag : &#039;ex_pained&#039;&lt;br /&gt;
    },&lt;br /&gt;
    &#039;5_orgasm&#039; : {&lt;br /&gt;
        conds: [&#039;targetHasOrgasm&#039;]&lt;br /&gt;
    }, &lt;br /&gt;
    &lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function round(input){&lt;br /&gt;
	return Math.round(input*100)/100;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function exec(){&lt;br /&gt;
	&lt;br /&gt;
	preferences.rulerUnits = Units.PIXELS;&lt;br /&gt;
	&lt;br /&gt;
	fetchLayers(doc);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	// Fetch JSON if possible&lt;br /&gt;
	var jsonFile = new File(dir+jsonName);&lt;br /&gt;
	jsonFile.encoding = &#039;UTF8&#039;;&lt;br /&gt;
	if( jsonFile.exists ){&lt;br /&gt;
		&lt;br /&gt;
		jsonFile.open(&amp;quot;r&amp;quot;);&lt;br /&gt;
        var parsed = JSON.parse(jsonFile.read());&lt;br /&gt;
        url = parsed.url || &#039;&#039;;&lt;br /&gt;
		bgName = parsed.base || &amp;quot;&amp;quot;;&lt;br /&gt;
		pics = parsed.layers;&lt;br /&gt;
		jsonFile.close();&lt;br /&gt;
		&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	var pngOpts = new PNGSaveOptions();&lt;br /&gt;
	pngOpts.method = stringIDToTypeID(&amp;quot;thorough&amp;quot;);&lt;br /&gt;
	pngOpts.compression = 1;&lt;br /&gt;
	&lt;br /&gt;
	var missingFromMap = [];&lt;br /&gt;
	for( var i = 0; i &amp;lt; allLayers.length; ++i ){&lt;br /&gt;
		&lt;br /&gt;
		var l = allLayers[i];&lt;br /&gt;
		l.visible = true;&lt;br /&gt;
		if( i &amp;amp;&amp;amp; allLayers[i-1].name.substring(0,1) != &amp;quot;#&amp;quot; )&lt;br /&gt;
			allLayers[i-1].visible = false;&lt;br /&gt;
		&lt;br /&gt;
		var baseOpacity = l.opacity;&lt;br /&gt;
		&lt;br /&gt;
		var bounds = l.bounds;&lt;br /&gt;
		var left = bounds[0];&lt;br /&gt;
		var right = docW-bounds[2];&lt;br /&gt;
		var top = bounds[1];&lt;br /&gt;
		var bottom = docH - bounds[3];&lt;br /&gt;
		var width = bounds[2]-bounds[0];&lt;br /&gt;
		var height = bounds[3]-bounds[1];&lt;br /&gt;
		&lt;br /&gt;
		var layerName = l.name;&lt;br /&gt;
		var layerNr = parseInt(layerName);&lt;br /&gt;
		var blendMode = &#039;source-over&#039;;&lt;br /&gt;
		if( l.blendMode == BlendMode.MULTIPLY )&lt;br /&gt;
			blendMode = &#039;multiply&#039;;&lt;br /&gt;
		else if( l.blendMode == BlendMode.OVERLAY )&lt;br /&gt;
			blendMode = &#039;overlay&#039;;&lt;br /&gt;
		var opacity = baseOpacity/100;&lt;br /&gt;
		var jiggleMask = jiggleMasks[layerName];&lt;br /&gt;
		&lt;br /&gt;
		if( layerName.substring(0,3) === &#039;jp_&#039; ){&lt;br /&gt;
			var layer = layerName.substring(3);&lt;br /&gt;
			var targ = jiggleMasks[&#039;jm_&#039;+layer];&lt;br /&gt;
			if( targ ){&lt;br /&gt;
				// Create a jiggle point&lt;br /&gt;
				var point = {&lt;br /&gt;
					r : round(width/docW),&lt;br /&gt;
					x : round((width/2+left)/docW),&lt;br /&gt;
					y : round((height/2+top)/docH),&lt;br /&gt;
				};&lt;br /&gt;
				targ.points.push(point);&lt;br /&gt;
				&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		else if( isNaN(layerNr) &amp;amp;&amp;amp; !jiggleMask )&lt;br /&gt;
			alert(&amp;quot;Layer &amp;quot;+layerName+&amp;quot; needs to start with the FQ art layer number. Use # if you don&#039;t want to save this layer.&amp;quot;);&lt;br /&gt;
		else{&lt;br /&gt;
			&lt;br /&gt;
			var file = layerName+&amp;quot;.png&amp;quot;;&lt;br /&gt;
			&lt;br /&gt;
			var folder = Folder(dir);&lt;br /&gt;
			if( !folder.exists )&lt;br /&gt;
				folder.create();&lt;br /&gt;
			&lt;br /&gt;
			l.opacity = 100;&lt;br /&gt;
						&lt;br /&gt;
			//alert(&amp;quot;Image cropped x:&amp;quot;+left+&amp;quot; y:&amp;quot;+top)&lt;br /&gt;
			var workLayer = doc.duplicate();&lt;br /&gt;
&lt;br /&gt;
			workLayer.crop(bounds);&lt;br /&gt;
			&lt;br /&gt;
			&lt;br /&gt;
			var fileOut = new File(dir+file)&lt;br /&gt;
			workLayer.saveAs(fileOut, pngOpts, true);	&lt;br /&gt;
			workLayer.close(SaveOptions.DONOTSAVECHANGES);&lt;br /&gt;
			&lt;br /&gt;
			l.opacity = baseOpacity;&lt;br /&gt;
			var baseData = {&lt;br /&gt;
				x : parseInt(left),&lt;br /&gt;
				y : parseInt(top),&lt;br /&gt;
			};&lt;br /&gt;
			&lt;br /&gt;
			if( jiggleMask ){&lt;br /&gt;
				&lt;br /&gt;
				baseData.slot = layerName.substring(3);&lt;br /&gt;
				baseData.mask = file;&lt;br /&gt;
				baseData = makeJiggleMask(baseData);&lt;br /&gt;
				baseData.p = jiggleMask.points;&lt;br /&gt;
				&lt;br /&gt;
			}else{&lt;br /&gt;
				&lt;br /&gt;
				var duration = 0;&lt;br /&gt;
				if( layerNr &amp;lt; 20 &amp;amp;&amp;amp; layerNr &amp;gt;= 10 )&lt;br /&gt;
					duration = 3000; // Facial expressions generally.&lt;br /&gt;
				var slots = {&lt;br /&gt;
					s26 : &#039;lowerBody&#039;,&lt;br /&gt;
					s31 : &#039;hands&#039;,&lt;br /&gt;
					s36 : &#039;upperBody&#039;,&lt;br /&gt;
					s41 : &#039;jewelleryCosmetic&#039;,&lt;br /&gt;
					s46 : &#039;lowerBodyCosmetic&#039;,&lt;br /&gt;
					s51 : &#039;upperBodyCosmetic&#039;,&lt;br /&gt;
				};&lt;br /&gt;
				&lt;br /&gt;
				var cmap = condMap[layerName], cm = [], stdtag = &#039;&#039;;&lt;br /&gt;
				if( cmap ){&lt;br /&gt;
					cm = cmap.conds;&lt;br /&gt;
					stdtag = cmap.stdtag;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				if( !cm.length )&lt;br /&gt;
					missingFromMap.push(layerName);&lt;br /&gt;
				&lt;br /&gt;
				baseData.layer = layerNr;&lt;br /&gt;
				baseData.icon = file;&lt;br /&gt;
				baseData.duration = duration;&lt;br /&gt;
				baseData.slot = slots[&#039;s&#039;+layerNr] || &#039;&#039;;&lt;br /&gt;
				baseData.blendMode = blendMode;&lt;br /&gt;
				baseData.opacity = opacity;&lt;br /&gt;
                baseData.conditions = cm;&lt;br /&gt;
                baseData.stdtag = stdtag;&lt;br /&gt;
				&lt;br /&gt;
				baseData = makePic(baseData);&lt;br /&gt;
				&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			&lt;br /&gt;
			updatePic(baseData);&lt;br /&gt;
			&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
	}&lt;br /&gt;
	if( missingFromMap.length )&lt;br /&gt;
		alert(&amp;quot;The following layers are missing auto condition definitions, check your spelling etc: &amp;quot;+missingFromMap.join(&amp;quot;, &amp;quot;));&lt;br /&gt;
		&lt;br /&gt;
	// Save BG as nude layer&lt;br /&gt;
	if( bgLayer ){&lt;br /&gt;
		&lt;br /&gt;
		if( allLayers.length )&lt;br /&gt;
			allLayers[i-1].visible = false;&lt;br /&gt;
		bgLayer.visible = true;&lt;br /&gt;
		var jpegOpts = new JPEGSaveOptions();&lt;br /&gt;
		jpegOpts.quality = 9;&lt;br /&gt;
		var fn = fName+&amp;quot;_n.jpg&amp;quot;;&lt;br /&gt;
		doc.saveAs(new File(dir+fn), jpegOpts, true);&lt;br /&gt;
		bgName = fn;&lt;br /&gt;
		&lt;br /&gt;
	&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	var keys = [];&lt;br /&gt;
	for( var i in condMap ){&lt;br /&gt;
		keys.push(i);&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	pics.sort(function(a, b){&lt;br /&gt;
				&lt;br /&gt;
		var aln = (a.icon || a.mask).split(&amp;quot;.&amp;quot;)[0];&lt;br /&gt;
		var bln = (b.icon || b.mask).split(&amp;quot;.&amp;quot;)[0];&lt;br /&gt;
		var aPos = keys.indexOf(aln);&lt;br /&gt;
		var bPos = keys.indexOf(bln);&lt;br /&gt;
		if( aPos == bPos )&lt;br /&gt;
			return 0;&lt;br /&gt;
		if( aPos == -1 )&lt;br /&gt;
			return 1;&lt;br /&gt;
		if( bPos == -1 )&lt;br /&gt;
			return -1;&lt;br /&gt;
		return aPos &amp;lt; bPos ? -1 : 1;&lt;br /&gt;
		&lt;br /&gt;
	});&lt;br /&gt;
	&lt;br /&gt;
	var dump = JSON.stringify({&lt;br /&gt;
		base : bgName,&lt;br /&gt;
        url : url,&lt;br /&gt;
        layers : pics&lt;br /&gt;
    }, null, 4);&lt;br /&gt;
	jsonFile.open(&amp;quot;w&amp;quot;);&lt;br /&gt;
	jsonFile.write(dump);&lt;br /&gt;
	jsonFile.close();&lt;br /&gt;
&lt;br /&gt;
	preferences.rulerUnits = startRulesUnits;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Accept data from makePic&lt;br /&gt;
function updatePic( picData ){&lt;br /&gt;
	for( var i = 0; i &amp;lt; pics.length; ++i ){&lt;br /&gt;
		&lt;br /&gt;
		var p = pics[i];&lt;br /&gt;
		if( (p.icon &amp;amp;&amp;amp; p.icon == picData.icon) || (p.mask &amp;amp;&amp;amp; picData.mask === p.mask)  ){&lt;br /&gt;
			&lt;br /&gt;
			if( picData.layer !== undefined )&lt;br /&gt;
				p.layer = picData.layer;&lt;br /&gt;
			p.x = picData.x;&lt;br /&gt;
			p.y = picData.y;&lt;br /&gt;
			if( picData.blendMode !== undefined )&lt;br /&gt;
				p.blendMode = picData.blendMode;&lt;br /&gt;
			if( picData.opacity !== undefined )&lt;br /&gt;
				p.opacity = picData.opacity;&lt;br /&gt;
			if( picData.slot !== undefined )&lt;br /&gt;
				p.slot = picData.slot;&lt;br /&gt;
			if( picData.p )&lt;br /&gt;
				p.p = picData.p;&lt;br /&gt;
			&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	pics.push(picData);&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Fetches all viable art layers&lt;br /&gt;
function fetchLayers( parentLayer, ignore ){&lt;br /&gt;
	&lt;br /&gt;
	for( var i = 0; i &amp;lt; parentLayer.layers.length; ++i ){&lt;br /&gt;
		&lt;br /&gt;
		var l = parentLayer.layers[i];&lt;br /&gt;
		&lt;br /&gt;
		var ign = ignore;&lt;br /&gt;
		var isBg = l.name == &amp;quot;Background&amp;quot;;&lt;br /&gt;
		&lt;br /&gt;
		if( !ignore )&lt;br /&gt;
			ign = isBg;&lt;br /&gt;
		if( l.name.substring(0,1) == &amp;quot;#&amp;quot; )&lt;br /&gt;
			continue;&lt;br /&gt;
		&lt;br /&gt;
		if( isBg )&lt;br /&gt;
			bgLayer = l;&lt;br /&gt;
&lt;br /&gt;
		l.visible = (l.typename == &amp;quot;LayerSet&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
		if( l.typename == &amp;quot;LayerSet&amp;quot; ){&lt;br /&gt;
			fetchLayers(l, ign);&lt;br /&gt;
			continue;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if( !ign )&lt;br /&gt;
			allLayers.push(l);&lt;br /&gt;
		&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeJiggleMask( data ){&lt;br /&gt;
	if( typeof data != &amp;quot;object&amp;quot; )&lt;br /&gt;
		data = {};&lt;br /&gt;
	var out = {};&lt;br /&gt;
	out.x = data.x || 0;&lt;br /&gt;
	out.y = data.y || 0;&lt;br /&gt;
	out.mask = data.mask;&lt;br /&gt;
	out.slot = data.slot;&lt;br /&gt;
	return out;&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makePic( data ){&lt;br /&gt;
	&lt;br /&gt;
	if( typeof data != &amp;quot;object&amp;quot; )&lt;br /&gt;
		data = {};&lt;br /&gt;
	&lt;br /&gt;
	var out = {};&lt;br /&gt;
	out.icon = data.icon;&lt;br /&gt;
	out.conditions = data.conditions || [];&lt;br /&gt;
	out.layer = data.layer || 0;&lt;br /&gt;
	out.duration = parseInt(data.duration) || 0;&lt;br /&gt;
	out.x = data.x || 0;&lt;br /&gt;
	out.y = data.y || 0;&lt;br /&gt;
	out.slot = data.slot || &#039;&#039;;&lt;br /&gt;
	out.blendMode = data.blendMode || &#039;source-over&#039;;&lt;br /&gt;
	out.opacity = 1.0;&lt;br /&gt;
	if( !isNaN(data.opacity) )&lt;br /&gt;
		out.opacity = data.opacity;&lt;br /&gt;
    out.conditions = data.conditions;&lt;br /&gt;
    out.stdtag = data.stdtag;&lt;br /&gt;
	return out;&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function save_as_png(doc, file, copy, comp, filter, none){&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
&lt;br /&gt;
        if (copy == undefined) copy = true;&lt;br /&gt;
&lt;br /&gt;
        if (comp == undefined) comp = 9;&lt;br /&gt;
&lt;br /&gt;
        if (none == undefined) none = true;&lt;br /&gt;
&lt;br /&gt;
        if (filter == undefined) filter = &amp;quot;PNGFilterAdaptive&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        var doc0 = app.activeDocument;&lt;br /&gt;
&lt;br /&gt;
        app.activeDocument = doc;&lt;br /&gt;
&lt;br /&gt;
        var d = new ActionDescriptor();&lt;br /&gt;
&lt;br /&gt;
        var d1 = new ActionDescriptor();&lt;br /&gt;
&lt;br /&gt;
        d1.putEnumerated(stringIDToTypeID(&amp;quot;method&amp;quot;), stringIDToTypeID(&amp;quot;PNGMethod&amp;quot;), stringIDToTypeID(&amp;quot;quick&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
        if (none)&lt;br /&gt;
&lt;br /&gt;
            d1.putEnumerated(stringIDToTypeID(&amp;quot;PNGInterlaceType&amp;quot;), stringIDToTypeID(&amp;quot;PNGInterlaceType&amp;quot;), stringIDToTypeID(&amp;quot;PNGInterlaceNone&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
        else&lt;br /&gt;
&lt;br /&gt;
            d1.putEnumerated(stringIDToTypeID(&amp;quot;PNGInterlaceType&amp;quot;), stringIDToTypeID(&amp;quot;PNGInterlaceType&amp;quot;), stringIDToTypeID(&amp;quot;PNGInterlaceAdam7&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
        d1.putEnumerated(stringIDToTypeID(&amp;quot;PNGFilter&amp;quot;), stringIDToTypeID(&amp;quot;PNGFilter&amp;quot;), stringIDToTypeID(filter));&lt;br /&gt;
&lt;br /&gt;
        d1.putInteger(stringIDToTypeID(&amp;quot;compression&amp;quot;), comp);&lt;br /&gt;
&lt;br /&gt;
        d.putObject(stringIDToTypeID(&amp;quot;as&amp;quot;), stringIDToTypeID(&amp;quot;PNGFormat&amp;quot;), d1);&lt;br /&gt;
&lt;br /&gt;
        d.putPath(stringIDToTypeID(&amp;quot;in&amp;quot;), file);&lt;br /&gt;
&lt;br /&gt;
        d.putBoolean(stringIDToTypeID(&amp;quot;copy&amp;quot;), copy);&lt;br /&gt;
&lt;br /&gt;
        executeAction(stringIDToTypeID(&amp;quot;save&amp;quot;), d, DialogModes.NO);&lt;br /&gt;
&lt;br /&gt;
        app.activeDocument = doc0;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    catch (e) { alert(e); return false; }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//  json2.js&lt;br /&gt;
//  2023-05-10&lt;br /&gt;
//  Public Domain.&lt;br /&gt;
//  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.&lt;br /&gt;
&lt;br /&gt;
//  USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO&lt;br /&gt;
//  NOT CONTROL.&lt;br /&gt;
&lt;br /&gt;
//  This file creates a global JSON object containing two methods: stringify&lt;br /&gt;
//  and parse. This file provides the ES5 JSON capability to ES3 systems.&lt;br /&gt;
//  If a project might run on IE8 or earlier, then this file should be included.&lt;br /&gt;
//  This file does nothing on ES5 systems.&lt;br /&gt;
&lt;br /&gt;
//      JSON.stringify(value, replacer, space)&lt;br /&gt;
//          value       any JavaScript value, usually an object or array.&lt;br /&gt;
//          replacer    an optional parameter that determines how object&lt;br /&gt;
//                      values are stringified for objects. It can be a&lt;br /&gt;
//                      function or an array of strings.&lt;br /&gt;
//          space       an optional parameter that specifies the indentation&lt;br /&gt;
//                      of nested structures. If it is omitted, the text will&lt;br /&gt;
//                      be packed without extra whitespace. If it is a number,&lt;br /&gt;
//                      it will specify the number of spaces to indent at each&lt;br /&gt;
//                      level. If it is a string (such as &amp;quot;\t&amp;quot; or &amp;quot;&amp;amp;nbsp;&amp;quot;),&lt;br /&gt;
//                      it contains the characters used to indent at each level.&lt;br /&gt;
//          This method produces a JSON text from a JavaScript value.&lt;br /&gt;
//          When an object value is found, if the object contains a toJSON&lt;br /&gt;
//          method, its toJSON method will be called and the result will be&lt;br /&gt;
//          stringified. A toJSON method does not serialize: it returns the&lt;br /&gt;
//          value represented by the name/value pair that should be serialized,&lt;br /&gt;
//          or undefined if nothing should be serialized. The toJSON method&lt;br /&gt;
//          will be passed the key associated with the value, and this will be&lt;br /&gt;
//          bound to the value.&lt;br /&gt;
&lt;br /&gt;
//          For example, this would serialize Dates as ISO strings.&lt;br /&gt;
&lt;br /&gt;
//              Date.prototype.toJSON = function (key) {&lt;br /&gt;
//                  function f(n) {&lt;br /&gt;
//                      // Format integers to have at least two digits.&lt;br /&gt;
//                      return (n &amp;lt; 10)&lt;br /&gt;
//                          ? &amp;quot;0&amp;quot; + n&lt;br /&gt;
//                          : n;&lt;br /&gt;
//                  }&lt;br /&gt;
//                  return this.getUTCFullYear()   + &amp;quot;-&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCMonth() + 1) + &amp;quot;-&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCDate())      + &amp;quot;T&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCHours())     + &amp;quot;:&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCMinutes())   + &amp;quot;:&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCSeconds())   + &amp;quot;Z&amp;quot;;&lt;br /&gt;
//              };&lt;br /&gt;
&lt;br /&gt;
//          You can provide an optional replacer method. It will be passed the&lt;br /&gt;
//          key and value of each member, with this bound to the containing&lt;br /&gt;
//          object. The value that is returned from your method will be&lt;br /&gt;
//          serialized. If your method returns undefined, then the member will&lt;br /&gt;
//          be excluded from the serialization.&lt;br /&gt;
&lt;br /&gt;
//          If the replacer parameter is an array of strings, then it will be&lt;br /&gt;
//          used to select the members to be serialized. It filters the results&lt;br /&gt;
//          such that only members with keys listed in the replacer array are&lt;br /&gt;
//          stringified.&lt;br /&gt;
&lt;br /&gt;
//          Values that do not have JSON representations, such as undefined or&lt;br /&gt;
//          functions, will not be serialized. Such values in objects will be&lt;br /&gt;
//          dropped; in arrays they will be replaced with null. You can use&lt;br /&gt;
//          a replacer function to replace those with JSON values.&lt;br /&gt;
&lt;br /&gt;
//          JSON.stringify(undefined) returns undefined.&lt;br /&gt;
&lt;br /&gt;
//          The optional space parameter produces a stringification of the&lt;br /&gt;
//          value that is filled with line breaks and indentation to make it&lt;br /&gt;
//          easier to read.&lt;br /&gt;
&lt;br /&gt;
//          If the space parameter is a non-empty string, then that string will&lt;br /&gt;
//          be used for indentation. If the space parameter is a number, then&lt;br /&gt;
//          the indentation will be that many spaces.&lt;br /&gt;
&lt;br /&gt;
//          Example:&lt;br /&gt;
&lt;br /&gt;
//          text = JSON.stringify([&amp;quot;e&amp;quot;, {pluribus: &amp;quot;unum&amp;quot;}]);&lt;br /&gt;
//          // text is &#039;[&amp;quot;e&amp;quot;,{&amp;quot;pluribus&amp;quot;:&amp;quot;unum&amp;quot;}]&#039;&lt;br /&gt;
&lt;br /&gt;
//          text = JSON.stringify([&amp;quot;e&amp;quot;, {pluribus: &amp;quot;unum&amp;quot;}], null, &amp;quot;\t&amp;quot;);&lt;br /&gt;
//          // text is &#039;[\n\t&amp;quot;e&amp;quot;,\n\t{\n\t\t&amp;quot;pluribus&amp;quot;: &amp;quot;unum&amp;quot;\n\t}\n]&#039;&lt;br /&gt;
&lt;br /&gt;
//          text = JSON.stringify([new Date()], function (key, value) {&lt;br /&gt;
//              return this[key] instanceof Date&lt;br /&gt;
//                  ? &amp;quot;Date(&amp;quot; + this[key] + &amp;quot;)&amp;quot;&lt;br /&gt;
//                  : value;&lt;br /&gt;
//          });&lt;br /&gt;
//          // text is &#039;[&amp;quot;Date(---current time---)&amp;quot;]&#039;&lt;br /&gt;
&lt;br /&gt;
//      JSON.parse(text, reviver)&lt;br /&gt;
//          This method parses a JSON text to produce an object or array.&lt;br /&gt;
//          It can throw a SyntaxError exception.&lt;br /&gt;
&lt;br /&gt;
//          The optional reviver parameter is a function that can filter and&lt;br /&gt;
//          transform the results. It receives each of the keys and values,&lt;br /&gt;
//          and its return value is used instead of the original value.&lt;br /&gt;
//          If it returns what it received, then the structure is not modified.&lt;br /&gt;
//          If it returns undefined then the member is deleted.&lt;br /&gt;
&lt;br /&gt;
//          Example:&lt;br /&gt;
&lt;br /&gt;
//          // Parse the text. Values that look like ISO date strings will&lt;br /&gt;
//          // be converted to Date objects.&lt;br /&gt;
&lt;br /&gt;
//          myData = JSON.parse(text, function (key, value) {&lt;br /&gt;
//              var a;&lt;br /&gt;
//              if (typeof value === &amp;quot;string&amp;quot;) {&lt;br /&gt;
//                  a =&lt;br /&gt;
//   /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);&lt;br /&gt;
//                  if (a) {&lt;br /&gt;
//                      return new Date(Date.UTC(&lt;br /&gt;
//                         +a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]&lt;br /&gt;
//                      ));&lt;br /&gt;
//                  }&lt;br /&gt;
//                  return value;&lt;br /&gt;
//              }&lt;br /&gt;
//          });&lt;br /&gt;
&lt;br /&gt;
//          myData = JSON.parse(&lt;br /&gt;
//              &amp;quot;[\&amp;quot;Date(09/09/2001)\&amp;quot;]&amp;quot;,&lt;br /&gt;
//              function (key, value) {&lt;br /&gt;
//                  var d;&lt;br /&gt;
//                  if (&lt;br /&gt;
//                      typeof value === &amp;quot;string&amp;quot;&lt;br /&gt;
//                      &amp;amp;&amp;amp; value.slice(0, 5) === &amp;quot;Date(&amp;quot;&lt;br /&gt;
//                      &amp;amp;&amp;amp; value.slice(-1) === &amp;quot;)&amp;quot;&lt;br /&gt;
//                  ) {&lt;br /&gt;
//                      d = new Date(value.slice(5, -1));&lt;br /&gt;
//                      if (d) {&lt;br /&gt;
//                          return d;&lt;br /&gt;
//                      }&lt;br /&gt;
//                  }&lt;br /&gt;
//                  return value;&lt;br /&gt;
//              }&lt;br /&gt;
//          );&lt;br /&gt;
&lt;br /&gt;
//  This is a reference implementation. You are free to copy, modify, or&lt;br /&gt;
//  redistribute.&lt;br /&gt;
&lt;br /&gt;
/*jslint&lt;br /&gt;
    eval, for, this&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/*property&lt;br /&gt;
    JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,&lt;br /&gt;
    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,&lt;br /&gt;
    lastIndex, length, parse, prototype, push, replace, slice, stringify,&lt;br /&gt;
    test, toJSON, toString, valueOf&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Create a JSON object only if one does not already exist. We create the&lt;br /&gt;
// methods in a closure to avoid creating global variables.&lt;br /&gt;
&lt;br /&gt;
var JSON = {};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &amp;quot;use strict&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    var rx_one = /^[\],:{}\s]*$/;&lt;br /&gt;
    var rx_two = /\\(?:[&amp;quot;\\\/bfnrt]|u[0-9a-fA-F]{4})/g;&lt;br /&gt;
    var rx_three = /&amp;quot;[^&amp;quot;\\\n\r]*&amp;quot;|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;&lt;br /&gt;
    var rx_four = /(?:^|:|,)(?:\s*\[)+/g;&lt;br /&gt;
    var rx_escapable = /[\\&amp;quot;\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;&lt;br /&gt;
    var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;&lt;br /&gt;
&lt;br /&gt;
    function f(n) {&lt;br /&gt;
        // Format integers to have at least two digits.&lt;br /&gt;
        return (n &amp;lt; 10)&lt;br /&gt;
            ? &amp;quot;0&amp;quot; + n&lt;br /&gt;
            : n;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function this_value() {&lt;br /&gt;
        return this.valueOf();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (typeof Date.prototype.toJSON !== &amp;quot;function&amp;quot;) {&lt;br /&gt;
&lt;br /&gt;
        Date.prototype.toJSON = function () {&lt;br /&gt;
&lt;br /&gt;
            return isFinite(this.valueOf())&lt;br /&gt;
                ? (&lt;br /&gt;
                    this.getUTCFullYear()&lt;br /&gt;
                    + &amp;quot;-&amp;quot;&lt;br /&gt;
                    + f(this.getUTCMonth() + 1)&lt;br /&gt;
                    + &amp;quot;-&amp;quot;&lt;br /&gt;
                    + f(this.getUTCDate())&lt;br /&gt;
                    + &amp;quot;T&amp;quot;&lt;br /&gt;
                    + f(this.getUTCHours())&lt;br /&gt;
                    + &amp;quot;:&amp;quot;&lt;br /&gt;
                    + f(this.getUTCMinutes())&lt;br /&gt;
                    + &amp;quot;:&amp;quot;&lt;br /&gt;
                    + f(this.getUTCSeconds())&lt;br /&gt;
                    + &amp;quot;Z&amp;quot;&lt;br /&gt;
                )&lt;br /&gt;
                : null;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        Boolean.prototype.toJSON = this_value;&lt;br /&gt;
        Number.prototype.toJSON = this_value;&lt;br /&gt;
        String.prototype.toJSON = this_value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gap;&lt;br /&gt;
    var indent;&lt;br /&gt;
    var meta;&lt;br /&gt;
    var rep;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    function quote(string) {&lt;br /&gt;
&lt;br /&gt;
// If the string contains no control characters, no quote characters, and no&lt;br /&gt;
// backslash characters, then we can safely slap some quotes around it.&lt;br /&gt;
// Otherwise we must also replace the offending characters with safe escape&lt;br /&gt;
// sequences.&lt;br /&gt;
&lt;br /&gt;
        rx_escapable.lastIndex = 0;&lt;br /&gt;
        return rx_escapable.test(string)&lt;br /&gt;
            ? &amp;quot;\&amp;quot;&amp;quot; + string.replace(rx_escapable, function (a) {&lt;br /&gt;
                var c = meta[a];&lt;br /&gt;
                return typeof c === &amp;quot;string&amp;quot;&lt;br /&gt;
                    ? c&lt;br /&gt;
                    : &amp;quot;\\u&amp;quot; + (&amp;quot;0000&amp;quot; + a.charCodeAt(0).toString(16)).slice(-4);&lt;br /&gt;
            }) + &amp;quot;\&amp;quot;&amp;quot;&lt;br /&gt;
            : &amp;quot;\&amp;quot;&amp;quot; + string + &amp;quot;\&amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    function str(key, holder) {&lt;br /&gt;
&lt;br /&gt;
// Produce a string from holder[key].&lt;br /&gt;
&lt;br /&gt;
        var i;          // The loop counter.&lt;br /&gt;
        var k;          // The member key.&lt;br /&gt;
        var v;          // The member value.&lt;br /&gt;
        var length;&lt;br /&gt;
        var mind = gap;&lt;br /&gt;
        var partial;&lt;br /&gt;
        var value = holder[key];&lt;br /&gt;
&lt;br /&gt;
// If the value has a toJSON method, call it to obtain a replacement value.&lt;br /&gt;
&lt;br /&gt;
        if (&lt;br /&gt;
            value&lt;br /&gt;
            &amp;amp;&amp;amp; typeof value === &amp;quot;object&amp;quot;&lt;br /&gt;
            &amp;amp;&amp;amp; typeof value.toJSON === &amp;quot;function&amp;quot;&lt;br /&gt;
        ) {&lt;br /&gt;
            value = value.toJSON(key);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
// If we were called with a replacer function, then call the replacer to&lt;br /&gt;
// obtain a replacement value.&lt;br /&gt;
&lt;br /&gt;
        if (typeof rep === &amp;quot;function&amp;quot;) {&lt;br /&gt;
            value = rep.call(holder, key, value);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
// What happens next depends on the value&#039;s type.&lt;br /&gt;
&lt;br /&gt;
        switch (typeof value) {&lt;br /&gt;
        case &amp;quot;string&amp;quot;:&lt;br /&gt;
            return quote(value);&lt;br /&gt;
&lt;br /&gt;
        case &amp;quot;number&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
// JSON numbers must be finite. Encode non-finite numbers as null.&lt;br /&gt;
&lt;br /&gt;
            return (isFinite(value))&lt;br /&gt;
                ? String(value)&lt;br /&gt;
                : &amp;quot;null&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        case &amp;quot;boolean&amp;quot;:&lt;br /&gt;
        case &amp;quot;null&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
// If the value is a boolean or null, convert it to a string. Note:&lt;br /&gt;
// typeof null does not produce &amp;quot;null&amp;quot;. The case is included here in&lt;br /&gt;
// the remote chance that this gets fixed someday.&lt;br /&gt;
&lt;br /&gt;
            return String(value);&lt;br /&gt;
&lt;br /&gt;
// If the type is &amp;quot;object&amp;quot;, we might be dealing with an object or an array or&lt;br /&gt;
// null.&lt;br /&gt;
&lt;br /&gt;
        case &amp;quot;object&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
// Due to a specification blunder in ECMAScript, typeof null is &amp;quot;object&amp;quot;,&lt;br /&gt;
// so watch out for that case.&lt;br /&gt;
&lt;br /&gt;
            if (!value) {&lt;br /&gt;
                return &amp;quot;null&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// Make an array to hold the partial results of stringifying this object value.&lt;br /&gt;
&lt;br /&gt;
            gap += indent;&lt;br /&gt;
            partial = [];&lt;br /&gt;
&lt;br /&gt;
// Is the value an array?&lt;br /&gt;
&lt;br /&gt;
            if (Object.prototype.toString.apply(value) === &amp;quot;[object Array]&amp;quot;) {&lt;br /&gt;
&lt;br /&gt;
// The value is an array. Stringify every element. Use null as a placeholder&lt;br /&gt;
// for non-JSON values.&lt;br /&gt;
&lt;br /&gt;
                length = value.length;&lt;br /&gt;
                for (i = 0; i &amp;lt; length; i += 1) {&lt;br /&gt;
                    partial[i] = str(i, value) || &amp;quot;null&amp;quot;;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
// Join all of the elements together, separated with commas, and wrap them in&lt;br /&gt;
// brackets.&lt;br /&gt;
&lt;br /&gt;
                v = partial.length === 0&lt;br /&gt;
                    ? &amp;quot;[]&amp;quot;&lt;br /&gt;
                    : gap&lt;br /&gt;
                        ? (&lt;br /&gt;
                            &amp;quot;[\n&amp;quot;&lt;br /&gt;
                            + gap&lt;br /&gt;
                            + partial.join(&amp;quot;,\n&amp;quot; + gap)&lt;br /&gt;
                            + &amp;quot;\n&amp;quot;&lt;br /&gt;
                            + mind&lt;br /&gt;
                            + &amp;quot;]&amp;quot;&lt;br /&gt;
                        )&lt;br /&gt;
                        : &amp;quot;[&amp;quot; + partial.join(&amp;quot;,&amp;quot;) + &amp;quot;]&amp;quot;;&lt;br /&gt;
                gap = mind;&lt;br /&gt;
                return v;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// If the replacer is an array, use it to select the members to be stringified.&lt;br /&gt;
&lt;br /&gt;
            if (rep &amp;amp;&amp;amp; typeof rep === &amp;quot;object&amp;quot;) {&lt;br /&gt;
                length = rep.length;&lt;br /&gt;
                for (i = 0; i &amp;lt; length; i += 1) {&lt;br /&gt;
                    if (typeof rep[i] === &amp;quot;string&amp;quot;) {&lt;br /&gt;
                        k = rep[i];&lt;br /&gt;
                        v = str(k, value);&lt;br /&gt;
                        if (v) {&lt;br /&gt;
                            partial.push(quote(k) + (&lt;br /&gt;
                                (gap)&lt;br /&gt;
                                    ? &amp;quot;: &amp;quot;&lt;br /&gt;
                                    : &amp;quot;:&amp;quot;&lt;br /&gt;
                            ) + v);&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            } else {&lt;br /&gt;
&lt;br /&gt;
// Otherwise, iterate through all of the keys in the object.&lt;br /&gt;
&lt;br /&gt;
                for (k in value) {&lt;br /&gt;
                    if (Object.prototype.hasOwnProperty.call(value, k)) {&lt;br /&gt;
                        v = str(k, value);&lt;br /&gt;
                        if (v) {&lt;br /&gt;
                            partial.push(quote(k) + (&lt;br /&gt;
                                (gap)&lt;br /&gt;
                                    ? &amp;quot;: &amp;quot;&lt;br /&gt;
                                    : &amp;quot;:&amp;quot;&lt;br /&gt;
                            ) + v);&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// Join all of the member texts together, separated with commas,&lt;br /&gt;
// and wrap them in braces.&lt;br /&gt;
&lt;br /&gt;
            v = partial.length === 0&lt;br /&gt;
                ? &amp;quot;{}&amp;quot;&lt;br /&gt;
                : gap&lt;br /&gt;
                    ? &amp;quot;{\n&amp;quot; + gap + partial.join(&amp;quot;,\n&amp;quot; + gap) + &amp;quot;\n&amp;quot; + mind + &amp;quot;}&amp;quot;&lt;br /&gt;
                    : &amp;quot;{&amp;quot; + partial.join(&amp;quot;,&amp;quot;) + &amp;quot;}&amp;quot;;&lt;br /&gt;
            gap = mind;&lt;br /&gt;
            return v;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// If the JSON object does not yet have a stringify method, give it one.&lt;br /&gt;
&lt;br /&gt;
    if (typeof JSON.stringify !== &amp;quot;function&amp;quot;) {&lt;br /&gt;
        meta = {    // table of character substitutions&lt;br /&gt;
            &amp;quot;\b&amp;quot;: &amp;quot;\\b&amp;quot;,&lt;br /&gt;
            &amp;quot;\t&amp;quot;: &amp;quot;\\t&amp;quot;,&lt;br /&gt;
            &amp;quot;\n&amp;quot;: &amp;quot;\\n&amp;quot;,&lt;br /&gt;
            &amp;quot;\f&amp;quot;: &amp;quot;\\f&amp;quot;,&lt;br /&gt;
            &amp;quot;\r&amp;quot;: &amp;quot;\\r&amp;quot;,&lt;br /&gt;
            &amp;quot;\&amp;quot;&amp;quot;: &amp;quot;\\\&amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;\\&amp;quot;: &amp;quot;\\\\&amp;quot;&lt;br /&gt;
        };&lt;br /&gt;
        JSON.stringify = function (value, replacer, space) {&lt;br /&gt;
&lt;br /&gt;
// The stringify method takes a value and an optional replacer, and an optional&lt;br /&gt;
// space parameter, and returns a JSON text. The replacer can be a function&lt;br /&gt;
// that can replace values, or an array of strings that will select the keys.&lt;br /&gt;
// A default replacer method can be provided. Use of the space parameter can&lt;br /&gt;
// produce text that is more easily readable.&lt;br /&gt;
&lt;br /&gt;
            var i;&lt;br /&gt;
            gap = &amp;quot;&amp;quot;;&lt;br /&gt;
            indent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// If the space parameter is a number, make an indent string containing that&lt;br /&gt;
// many spaces.&lt;br /&gt;
&lt;br /&gt;
            if (typeof space === &amp;quot;number&amp;quot;) {&lt;br /&gt;
                for (i = 0; i &amp;lt; space; i += 1) {&lt;br /&gt;
                    indent += &amp;quot; &amp;quot;;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
// If the space parameter is a string, it will be used as the indent string.&lt;br /&gt;
&lt;br /&gt;
            } else if (typeof space === &amp;quot;string&amp;quot;) {&lt;br /&gt;
                indent = space;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// If there is a replacer, it must be a function or an array.&lt;br /&gt;
// Otherwise, throw an error.&lt;br /&gt;
&lt;br /&gt;
            rep = replacer;&lt;br /&gt;
            if (replacer &amp;amp;&amp;amp; typeof replacer !== &amp;quot;function&amp;quot; &amp;amp;&amp;amp; (&lt;br /&gt;
                typeof replacer !== &amp;quot;object&amp;quot;&lt;br /&gt;
                || typeof replacer.length !== &amp;quot;number&amp;quot;&lt;br /&gt;
            )) {&lt;br /&gt;
                throw new Error(&amp;quot;JSON.stringify&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// Make a fake root object containing our value under the key of &amp;quot;&amp;quot;.&lt;br /&gt;
// Return the result of stringifying the value.&lt;br /&gt;
&lt;br /&gt;
            return str(&amp;quot;&amp;quot;, {&amp;quot;&amp;quot;: value});&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// If the JSON object does not yet have a parse method, give it one.&lt;br /&gt;
&lt;br /&gt;
    if (typeof JSON.parse !== &amp;quot;function&amp;quot;) {&lt;br /&gt;
        JSON.parse = function (text, reviver) {&lt;br /&gt;
&lt;br /&gt;
// The parse method takes a text and an optional reviver function, and returns&lt;br /&gt;
// a JavaScript value if the text is a valid JSON text.&lt;br /&gt;
&lt;br /&gt;
            var j;&lt;br /&gt;
&lt;br /&gt;
            function walk(holder, key) {&lt;br /&gt;
&lt;br /&gt;
// The walk method is used to recursively walk the resulting structure so&lt;br /&gt;
// that modifications can be made.&lt;br /&gt;
&lt;br /&gt;
                var k;&lt;br /&gt;
                var v;&lt;br /&gt;
                var value = holder[key];&lt;br /&gt;
                if (value &amp;amp;&amp;amp; typeof value === &amp;quot;object&amp;quot;) {&lt;br /&gt;
                    for (k in value) {&lt;br /&gt;
                        if (Object.prototype.hasOwnProperty.call(value, k)) {&lt;br /&gt;
                            v = walk(value, k);&lt;br /&gt;
                            if (v !== undefined) {&lt;br /&gt;
                                value[k] = v;&lt;br /&gt;
                            } else {&lt;br /&gt;
                                delete value[k];&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
                return reviver.call(holder, key, value);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Parsing happens in four stages. In the first stage, we replace certain&lt;br /&gt;
// Unicode characters with escape sequences. JavaScript handles many characters&lt;br /&gt;
// incorrectly, either silently deleting them, or treating them as line endings.&lt;br /&gt;
&lt;br /&gt;
            text = String(text);&lt;br /&gt;
            rx_dangerous.lastIndex = 0;&lt;br /&gt;
            if (rx_dangerous.test(text)) {&lt;br /&gt;
                text = text.replace(rx_dangerous, function (a) {&lt;br /&gt;
                    return (&lt;br /&gt;
                        &amp;quot;\\u&amp;quot;&lt;br /&gt;
                        + (&amp;quot;0000&amp;quot; + a.charCodeAt(0).toString(16)).slice(-4)&lt;br /&gt;
                    );&lt;br /&gt;
                });&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// In the second stage, we run the text against regular expressions that look&lt;br /&gt;
// for non-JSON patterns. We are especially concerned with &amp;quot;()&amp;quot; and &amp;quot;new&amp;quot;&lt;br /&gt;
// because they can cause invocation, and &amp;quot;=&amp;quot; because it can cause mutation.&lt;br /&gt;
// But just to be safe, we want to reject all unexpected forms.&lt;br /&gt;
&lt;br /&gt;
// We split the second stage into 4 regexp operations in order to work around&lt;br /&gt;
// crippling inefficiencies in IE&#039;s and Safari&#039;s regexp engines. First we&lt;br /&gt;
// replace the JSON backslash pairs with &amp;quot;@&amp;quot; (a non-JSON character). Second, we&lt;br /&gt;
// replace all simple value tokens with &amp;quot;]&amp;quot; characters. Third, we delete all&lt;br /&gt;
// open brackets that follow a colon or comma or that begin the text. Finally,&lt;br /&gt;
// we look to see that the remaining characters are only whitespace or &amp;quot;]&amp;quot; or&lt;br /&gt;
// &amp;quot;,&amp;quot; or &amp;quot;:&amp;quot; or &amp;quot;{&amp;quot; or &amp;quot;}&amp;quot;. If that is so, then the text is safe for eval.&lt;br /&gt;
&lt;br /&gt;
            if (&lt;br /&gt;
                rx_one.test(&lt;br /&gt;
                    text&lt;br /&gt;
                        .replace(rx_two, &amp;quot;@&amp;quot;)&lt;br /&gt;
                        .replace(rx_three, &amp;quot;]&amp;quot;)&lt;br /&gt;
                        .replace(rx_four, &amp;quot;&amp;quot;)&lt;br /&gt;
                )&lt;br /&gt;
            ) {&lt;br /&gt;
&lt;br /&gt;
// In the third stage we use the eval function to compile the text into a&lt;br /&gt;
// JavaScript structure. The &amp;quot;{&amp;quot; operator is subject to a syntactic ambiguity&lt;br /&gt;
// in JavaScript: it can begin a block or an object literal. We wrap the text&lt;br /&gt;
// in parens to eliminate the ambiguity.&lt;br /&gt;
&lt;br /&gt;
                j = eval(&amp;quot;(&amp;quot; + text + &amp;quot;)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// In the optional fourth stage, we recursively walk the new structure, passing&lt;br /&gt;
// each name/value pair to a reviver function for possible transformation.&lt;br /&gt;
&lt;br /&gt;
                return (typeof reviver === &amp;quot;function&amp;quot;)&lt;br /&gt;
                    ? walk({&amp;quot;&amp;quot;: j}, &amp;quot;&amp;quot;)&lt;br /&gt;
                    : j;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// If the text is not JSON parseable, then a SyntaxError is thrown.&lt;br /&gt;
&lt;br /&gt;
            throw new SyntaxError(&amp;quot;JSON.parse&amp;quot;);&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
exec();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:Modding]]&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=FqAutoLayers&amp;diff=337</id>
		<title>FqAutoLayers</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=FqAutoLayers&amp;diff=337"/>
		<updated>2026-06-05T11:53:39Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This script will automatically try to remove unchanged pixels. Save it as fqAutoLayers.jsx and import into photoshop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/*&lt;br /&gt;
	Note: This is similar to the fqcrop.jsx file except it exports all layers one at a time.&lt;br /&gt;
	Usage: See fqcrop.jsx for more info. Things you need to keep in mind in this implementation:&lt;br /&gt;
	- Each art layer can only consist of ONE photoshop layer&lt;br /&gt;
	- All layers must begin with &amp;lt;layerNr&amp;gt;_ ex 30_bikini_light_ub to use layer 30 (upper body base)&lt;br /&gt;
	- A JSON metadata file named the same as the original file will be created or updated. It&#039;s going to need a bit of editing, but you can use it to quickly upload a full character.&lt;br /&gt;
	- Layers and groups starting with # are ignored.&lt;br /&gt;
	- If a JSON file exists, it&#039;s loaded and updated. Missing layers aren&#039;t deleted from it. So if you remove layers you have to remove them from the JSON file or delete the JSON file to generate a new one.&lt;br /&gt;
	- The following values are overwritten into the JSON file, using the photoshop settings:&lt;br /&gt;
		- icon&lt;br /&gt;
		- x&lt;br /&gt;
		- y&lt;br /&gt;
		- blendMode (only normal, multiply, overlay are supported)&lt;br /&gt;
		- opacity&lt;br /&gt;
*/&lt;br /&gt;
var startRulesUnits = preferences.rulerUnits;&lt;br /&gt;
var doc = activeDocument;&lt;br /&gt;
var docW = doc.width;&lt;br /&gt;
var docH = doc.height;&lt;br /&gt;
var allLayers = [];&lt;br /&gt;
var dirJson = decodeURI(doc.path.fsName)+&amp;quot;/&amp;quot;;&lt;br /&gt;
var jsonName = doc.name.split(&amp;quot;.&amp;quot;);&lt;br /&gt;
jsonName.pop();&lt;br /&gt;
var fName = jsonName.join(&#039;_&#039;)&lt;br /&gt;
var dir = dirJson+fName+&amp;quot;/&amp;quot;;&lt;br /&gt;
jsonName = jsonName.join(&amp;quot;.&amp;quot;)+&amp;quot;.json&amp;quot;;&lt;br /&gt;
var pics = [];&lt;br /&gt;
var url = &#039;&#039;;&lt;br /&gt;
var bgName = &amp;quot;&amp;quot;;&lt;br /&gt;
var bgLayer;&lt;br /&gt;
Array.prototype.indexOf = function ( item ) {&lt;br /&gt;
&lt;br /&gt;
	  var index = 0, length = this.length;&lt;br /&gt;
&lt;br /&gt;
	  for ( ; index &amp;lt; length; index++ ) {&lt;br /&gt;
&lt;br /&gt;
				if ( this[index] === item )&lt;br /&gt;
&lt;br /&gt;
						  return index;&lt;br /&gt;
&lt;br /&gt;
	  }&lt;br /&gt;
&lt;br /&gt;
	  return -1;&lt;br /&gt;
&lt;br /&gt;
  };&lt;br /&gt;
var jiggleMasks = {&lt;br /&gt;
	&#039;jm_breasts&#039; : {&lt;br /&gt;
		slot : &amp;quot;Breasts&amp;quot;,&lt;br /&gt;
		points : []&lt;br /&gt;
	},&lt;br /&gt;
	&#039;jm_groin&#039; : {&lt;br /&gt;
		slot : &amp;quot;Groin&amp;quot;,&lt;br /&gt;
		points : []&lt;br /&gt;
	},&lt;br /&gt;
	&#039;jm_butt&#039; : {&lt;br /&gt;
		slot : &amp;quot;Butt&amp;quot;,&lt;br /&gt;
		points : []&lt;br /&gt;
	}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
var condMap = {&lt;br /&gt;
	&#039;55_stains&#039; : {&lt;br /&gt;
        conds : [&#039;targetStains&#039;],&lt;br /&gt;
    },&lt;br /&gt;
	&#039;51_gloves&#039; : {&lt;br /&gt;
		conds : [&#039;targetGloves&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;50_gloves&#039; : {&lt;br /&gt;
		conds : [&#039;targetGloves&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;19_gloves&#039; : {&lt;br /&gt;
		conds : [&#039;targetGloves&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;18_gloves&#039; : {&lt;br /&gt;
		conds : [&#039;targetGloves&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;41_boots&#039; : {&lt;br /&gt;
		conds : [&#039;targetBoots&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;40_boots&#039; : {&lt;br /&gt;
		conds : [&#039;targetBoots&#039;]&lt;br /&gt;
	},&lt;br /&gt;
    &#039;26_sling_heavy&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;,&#039;targetLowerBodyHard&#039;] &lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_sling_heavy&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;,&#039;targetLowerBodyHard&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_sling_med&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;,&#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_sling_med&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;,&#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_sling_light&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_sling_light&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsSlingBikini&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_bodysuit_med&#039; : {&lt;br /&gt;
        conds: [&#039;targetBodysuit&#039;, &#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_bodysuit_med&#039; : {&lt;br /&gt;
        conds: [&#039;targetBodysuit&#039;, &#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_bodysuit_light&#039; : {&lt;br /&gt;
        conds: [&#039;targetBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_bodysuit_light&#039; : {&lt;br /&gt;
        conds: [&#039;targetBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
    &#039;36_heavy_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyHard&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;35_heavy_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyHard&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
    &#039;26_heavy_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetLowerBodyHard&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_heavy_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetLowerBodyHard&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&lt;br /&gt;
	&#039;36_bikini_med_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyBikini&#039;, &#039;targetUpperBodyLeather&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;35_bikini_med_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyBikini&#039;, &#039;targetUpperBodyLeather&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;26_bikini_med_lb&#039; : {&lt;br /&gt;
		conds: [&#039;targetWearsThong&#039;, &#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;25_bikini_med_lb&#039; : {&lt;br /&gt;
		conds: [&#039;targetWearsThong&#039;, &#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&lt;br /&gt;
	&#039;36_bikini_light_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyBikini&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;35_bikini_light_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyBikini&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;26_bikini_light_lb&#039; : {&lt;br /&gt;
		conds: [&#039;targetWearsThong&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&#039;25_bikini_light_lb&#039; : {&lt;br /&gt;
		conds: [&#039;targetWearsThong&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
	},&lt;br /&gt;
	&lt;br /&gt;
    &lt;br /&gt;
    &#039;36_med_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyLeather&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;35_med_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetUpperBodyLeather&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_med_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_med_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetLowerBodyLeather&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
	&lt;br /&gt;
    &#039;36_light_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsUpperBody&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;35_light_ub&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsUpperBody&#039;, &#039;targetNoBodysuit&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;26_light_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsLowerBody&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &#039;25_light_lb&#039; : {&lt;br /&gt;
        conds: [&#039;targetWearsLowerBody&#039;]&lt;br /&gt;
    },&lt;br /&gt;
    &lt;br /&gt;
	// Collar can be either above or below armor&lt;br /&gt;
    &#039;3_collar&#039; : {&lt;br /&gt;
        conds: [&#039;targetCollar&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;23_collar&#039; : {&lt;br /&gt;
        conds: [&#039;targetCollar&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&#039;43_collar&#039; : {&lt;br /&gt;
        conds: [&#039;targetCollar&#039;]&lt;br /&gt;
    },&lt;br /&gt;
	&lt;br /&gt;
	&#039;22_nipple_studs&#039; : {&lt;br /&gt;
        conds: [&#039;targetCollar&#039;]&lt;br /&gt;
    },&lt;br /&gt;
&lt;br /&gt;
    &#039;15_aroused_heavy&#039; : {&lt;br /&gt;
        conds: [&#039;metaVeryArousing&#039;],&lt;br /&gt;
        stdtag: &#039;ex_aroused_heavy&#039;&lt;br /&gt;
    },&lt;br /&gt;
    &#039;15_pain_heavy&#039; : {&lt;br /&gt;
        conds: [&#039;metaVeryPainful&#039;],&lt;br /&gt;
        stdtag : &#039;ex_pained_heavy&#039;&lt;br /&gt;
    },&lt;br /&gt;
    &#039;10_aroused&#039; : {&lt;br /&gt;
        conds: [&#039;metaArousing&#039;],&lt;br /&gt;
        stdtag: &#039;ex_aroused&#039;&lt;br /&gt;
    },&lt;br /&gt;
    &#039;10_pain&#039; : {&lt;br /&gt;
        conds: [&#039;metaPainful&#039;],&lt;br /&gt;
        stdtag : &#039;ex_pained&#039;&lt;br /&gt;
    },&lt;br /&gt;
    &#039;5_orgasm&#039; : {&lt;br /&gt;
        conds: [&#039;targetHasOrgasm&#039;]&lt;br /&gt;
    }, &lt;br /&gt;
    &lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function round(input){&lt;br /&gt;
	return Math.round(input*100)/100;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function exec(){&lt;br /&gt;
	&lt;br /&gt;
	preferences.rulerUnits = Units.PIXELS;&lt;br /&gt;
	&lt;br /&gt;
	fetchLayers(doc);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
	// Fetch JSON if possible&lt;br /&gt;
	var jsonFile = new File(dir+jsonName);&lt;br /&gt;
	jsonFile.encoding = &#039;UTF8&#039;;&lt;br /&gt;
	if( jsonFile.exists ){&lt;br /&gt;
		&lt;br /&gt;
		jsonFile.open(&amp;quot;r&amp;quot;);&lt;br /&gt;
        var parsed = JSON.parse(jsonFile.read());&lt;br /&gt;
        url = parsed.url || &#039;&#039;;&lt;br /&gt;
		bgName = parsed.base || &amp;quot;&amp;quot;;&lt;br /&gt;
		pics = parsed.layers;&lt;br /&gt;
		jsonFile.close();&lt;br /&gt;
		&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	var pngOpts = new PNGSaveOptions();&lt;br /&gt;
	pngOpts.method = stringIDToTypeID(&amp;quot;thorough&amp;quot;);&lt;br /&gt;
	pngOpts.compression = 1;&lt;br /&gt;
	&lt;br /&gt;
	var missingFromMap = [];&lt;br /&gt;
	for( var i = 0; i &amp;lt; allLayers.length; ++i ){&lt;br /&gt;
		&lt;br /&gt;
		var l = allLayers[i];&lt;br /&gt;
		l.visible = true;&lt;br /&gt;
		if( i &amp;amp;&amp;amp; allLayers[i-1].name.substring(0,1) != &amp;quot;#&amp;quot; )&lt;br /&gt;
			allLayers[i-1].visible = false;&lt;br /&gt;
		&lt;br /&gt;
		var baseOpacity = l.opacity;&lt;br /&gt;
		&lt;br /&gt;
		var bounds = l.bounds;&lt;br /&gt;
		var left = bounds[0];&lt;br /&gt;
		var right = docW-bounds[2];&lt;br /&gt;
		var top = bounds[1];&lt;br /&gt;
		var bottom = docH - bounds[3];&lt;br /&gt;
		var width = bounds[2]-bounds[0];&lt;br /&gt;
		var height = bounds[3]-bounds[1];&lt;br /&gt;
		&lt;br /&gt;
		var layerName = l.name;&lt;br /&gt;
		var layerNr = parseInt(layerName);&lt;br /&gt;
		var blendMode = &#039;source-over&#039;;&lt;br /&gt;
		if( l.blendMode == BlendMode.MULTIPLY )&lt;br /&gt;
			blendMode = &#039;multiply&#039;;&lt;br /&gt;
		else if( l.blendMode == BlendMode.OVERLAY )&lt;br /&gt;
			blendMode = &#039;overlay&#039;;&lt;br /&gt;
		var opacity = baseOpacity/100;&lt;br /&gt;
		var jiggleMask = jiggleMasks[layerName];&lt;br /&gt;
		&lt;br /&gt;
		if( layerName.substring(0,3) === &#039;jp_&#039; ){&lt;br /&gt;
			var layer = layerName.substring(3);&lt;br /&gt;
			var targ = jiggleMasks[&#039;jm_&#039;+layer];&lt;br /&gt;
			if( targ ){&lt;br /&gt;
				// Create a jiggle point&lt;br /&gt;
				var point = {&lt;br /&gt;
					r : round(width/docW),&lt;br /&gt;
					x : round((width/2+left)/docW),&lt;br /&gt;
					y : round((height/2+top)/docH),&lt;br /&gt;
				};&lt;br /&gt;
				targ.points.push(point);&lt;br /&gt;
				&lt;br /&gt;
			}&lt;br /&gt;
		}&lt;br /&gt;
		else if( isNaN(layerNr) &amp;amp;&amp;amp; !jiggleMask )&lt;br /&gt;
			alert(&amp;quot;Layer &amp;quot;+layerName+&amp;quot; needs to start with the FQ art layer number. Use # if you don&#039;t want to save this layer.&amp;quot;);&lt;br /&gt;
		else{&lt;br /&gt;
			&lt;br /&gt;
			var file = layerName+&amp;quot;.png&amp;quot;;&lt;br /&gt;
			&lt;br /&gt;
			var folder = Folder(dir);&lt;br /&gt;
			if( !folder.exists )&lt;br /&gt;
				folder.create();&lt;br /&gt;
			&lt;br /&gt;
			l.opacity = 100;&lt;br /&gt;
						&lt;br /&gt;
			//alert(&amp;quot;Image cropped x:&amp;quot;+left+&amp;quot; y:&amp;quot;+top)&lt;br /&gt;
			var workLayer = doc.duplicate();&lt;br /&gt;
&lt;br /&gt;
			workLayer.crop(bounds);&lt;br /&gt;
			&lt;br /&gt;
			&lt;br /&gt;
			var fileOut = new File(dir+file)&lt;br /&gt;
			workLayer.saveAs(fileOut, pngOpts, true);	&lt;br /&gt;
			workLayer.close(SaveOptions.DONOTSAVECHANGES);&lt;br /&gt;
			&lt;br /&gt;
			l.opacity = baseOpacity;&lt;br /&gt;
			var baseData = {&lt;br /&gt;
				x : parseInt(left),&lt;br /&gt;
				y : parseInt(top),&lt;br /&gt;
			};&lt;br /&gt;
			&lt;br /&gt;
			if( jiggleMask ){&lt;br /&gt;
				&lt;br /&gt;
				baseData.slot = layerName.substring(3);&lt;br /&gt;
				baseData.mask = file;&lt;br /&gt;
				baseData = makeJiggleMask(baseData);&lt;br /&gt;
				baseData.p = jiggleMask.points;&lt;br /&gt;
				&lt;br /&gt;
			}else{&lt;br /&gt;
				&lt;br /&gt;
				var duration = 0;&lt;br /&gt;
				if( layerNr &amp;lt; 20 &amp;amp;&amp;amp; layerNr &amp;gt;= 10 )&lt;br /&gt;
					duration = 3000; // Facial expressions generally.&lt;br /&gt;
				var slots = {&lt;br /&gt;
					s26 : &#039;lowerBody&#039;,&lt;br /&gt;
					s31 : &#039;hands&#039;,&lt;br /&gt;
					s36 : &#039;upperBody&#039;,&lt;br /&gt;
					s41 : &#039;jewelleryCosmetic&#039;,&lt;br /&gt;
					s46 : &#039;lowerBodyCosmetic&#039;,&lt;br /&gt;
					s51 : &#039;upperBodyCosmetic&#039;,&lt;br /&gt;
				};&lt;br /&gt;
				&lt;br /&gt;
				var cmap = condMap[layerName], cm = [], stdtag = &#039;&#039;;&lt;br /&gt;
				if( cmap ){&lt;br /&gt;
					cm = cmap.conds;&lt;br /&gt;
					stdtag = cmap.stdtag;&lt;br /&gt;
				}&lt;br /&gt;
				&lt;br /&gt;
				if( !cm.length )&lt;br /&gt;
					missingFromMap.push(layerName);&lt;br /&gt;
				&lt;br /&gt;
				baseData.layer = layerNr;&lt;br /&gt;
				baseData.icon = file;&lt;br /&gt;
				baseData.duration = duration;&lt;br /&gt;
				baseData.slot = slots[&#039;s&#039;+layerNr] || &#039;&#039;;&lt;br /&gt;
				baseData.blendMode = blendMode;&lt;br /&gt;
				baseData.opacity = opacity;&lt;br /&gt;
                baseData.conditions = cm;&lt;br /&gt;
                baseData.stdtag = stdtag;&lt;br /&gt;
				&lt;br /&gt;
				baseData = makePic(baseData);&lt;br /&gt;
				&lt;br /&gt;
			}&lt;br /&gt;
			&lt;br /&gt;
			&lt;br /&gt;
			updatePic(baseData);&lt;br /&gt;
			&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
		&lt;br /&gt;
	}&lt;br /&gt;
	if( missingFromMap.length )&lt;br /&gt;
		alert(&amp;quot;The following layers are missing auto condition definitions, check your spelling etc: &amp;quot;+missingFromMap.join(&amp;quot;, &amp;quot;));&lt;br /&gt;
		&lt;br /&gt;
	// Save BG as nude layer&lt;br /&gt;
	if( bgLayer ){&lt;br /&gt;
		&lt;br /&gt;
		if( allLayers.length )&lt;br /&gt;
			allLayers[i-1].visible = false;&lt;br /&gt;
		bgLayer.visible = true;&lt;br /&gt;
		var jpegOpts = new JPEGSaveOptions();&lt;br /&gt;
		jpegOpts.quality = 9;&lt;br /&gt;
		var fn = fName+&amp;quot;_n.jpg&amp;quot;;&lt;br /&gt;
		doc.saveAs(new File(dir+fn), jpegOpts, true);&lt;br /&gt;
		bgName = fn;&lt;br /&gt;
		&lt;br /&gt;
	&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	var keys = [];&lt;br /&gt;
	for( var i in condMap ){&lt;br /&gt;
		keys.push(i);&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	pics.sort(function(a, b){&lt;br /&gt;
				&lt;br /&gt;
		var aln = (a.icon || a.mask).split(&amp;quot;.&amp;quot;)[0];&lt;br /&gt;
		var bln = (b.icon || b.mask).split(&amp;quot;.&amp;quot;)[0];&lt;br /&gt;
		var aPos = keys.indexOf(aln);&lt;br /&gt;
		var bPos = keys.indexOf(bln);&lt;br /&gt;
		if( aPos == bPos )&lt;br /&gt;
			return 0;&lt;br /&gt;
		if( aPos == -1 )&lt;br /&gt;
			return 1;&lt;br /&gt;
		if( bPos == -1 )&lt;br /&gt;
			return -1;&lt;br /&gt;
		return aPos &amp;lt; bPos ? -1 : 1;&lt;br /&gt;
		&lt;br /&gt;
	});&lt;br /&gt;
	&lt;br /&gt;
	var dump = JSON.stringify({&lt;br /&gt;
		base : bgName,&lt;br /&gt;
        url : url,&lt;br /&gt;
        layers : pics&lt;br /&gt;
    }, null, 4);&lt;br /&gt;
	jsonFile.open(&amp;quot;w&amp;quot;);&lt;br /&gt;
	jsonFile.write(dump);&lt;br /&gt;
	jsonFile.close();&lt;br /&gt;
&lt;br /&gt;
	preferences.rulerUnits = startRulesUnits;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Accept data from makePic&lt;br /&gt;
function updatePic( picData ){&lt;br /&gt;
	for( var i = 0; i &amp;lt; pics.length; ++i ){&lt;br /&gt;
		&lt;br /&gt;
		var p = pics[i];&lt;br /&gt;
		if( (p.icon &amp;amp;&amp;amp; p.icon == picData.icon) || (p.mask &amp;amp;&amp;amp; picData.mask === p.mask)  ){&lt;br /&gt;
			&lt;br /&gt;
			if( picData.layer !== undefined )&lt;br /&gt;
				p.layer = picData.layer;&lt;br /&gt;
			p.x = picData.x;&lt;br /&gt;
			p.y = picData.y;&lt;br /&gt;
			if( picData.blendMode !== undefined )&lt;br /&gt;
				p.blendMode = picData.blendMode;&lt;br /&gt;
			if( picData.opacity !== undefined )&lt;br /&gt;
				p.opacity = picData.opacity;&lt;br /&gt;
			if( picData.slot !== undefined )&lt;br /&gt;
				p.slot = picData.slot;&lt;br /&gt;
			if( picData.p )&lt;br /&gt;
				p.p = picData.p;&lt;br /&gt;
			&lt;br /&gt;
			return;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
	pics.push(picData);&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Fetches all viable art layers&lt;br /&gt;
function fetchLayers( parentLayer, ignore ){&lt;br /&gt;
	&lt;br /&gt;
	for( var i = 0; i &amp;lt; parentLayer.layers.length; ++i ){&lt;br /&gt;
		&lt;br /&gt;
		var l = parentLayer.layers[i];&lt;br /&gt;
		&lt;br /&gt;
		var ign = ignore;&lt;br /&gt;
		var isBg = l.name == &amp;quot;Background&amp;quot;;&lt;br /&gt;
		&lt;br /&gt;
		if( !ignore )&lt;br /&gt;
			ign = isBg;&lt;br /&gt;
		if( l.name.substring(0,1) == &amp;quot;#&amp;quot; )&lt;br /&gt;
			continue;&lt;br /&gt;
		&lt;br /&gt;
		if( isBg )&lt;br /&gt;
			bgLayer = l;&lt;br /&gt;
&lt;br /&gt;
		l.visible = (l.typename == &amp;quot;LayerSet&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
		if( l.typename == &amp;quot;LayerSet&amp;quot; ){&lt;br /&gt;
			fetchLayers(l, ign);&lt;br /&gt;
			continue;&lt;br /&gt;
		}&lt;br /&gt;
		&lt;br /&gt;
		if( !ign )&lt;br /&gt;
			allLayers.push(l);&lt;br /&gt;
		&lt;br /&gt;
	}&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makeJiggleMask( data ){&lt;br /&gt;
	if( typeof data != &amp;quot;object&amp;quot; )&lt;br /&gt;
		data = {};&lt;br /&gt;
	var out = {};&lt;br /&gt;
	out.x = data.x || 0;&lt;br /&gt;
	out.y = data.y || 0;&lt;br /&gt;
	out.mask = data.mask;&lt;br /&gt;
	out.slot = data.slot;&lt;br /&gt;
	return out;&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
function makePic( data ){&lt;br /&gt;
	&lt;br /&gt;
	if( typeof data != &amp;quot;object&amp;quot; )&lt;br /&gt;
		data = {};&lt;br /&gt;
	&lt;br /&gt;
	var out = {};&lt;br /&gt;
	out.icon = data.icon;&lt;br /&gt;
	out.conditions = data.conditions || [];&lt;br /&gt;
	out.layer = data.layer || 0;&lt;br /&gt;
	out.duration = parseInt(data.duration) || 0;&lt;br /&gt;
	out.x = data.x || 0;&lt;br /&gt;
	out.y = data.y || 0;&lt;br /&gt;
	out.slot = data.slot || &#039;&#039;;&lt;br /&gt;
	out.blendMode = data.blendMode || &#039;source-over&#039;;&lt;br /&gt;
	out.opacity = 1.0;&lt;br /&gt;
	if( !isNaN(data.opacity) )&lt;br /&gt;
		out.opacity = data.opacity;&lt;br /&gt;
    out.conditions = data.conditions;&lt;br /&gt;
    out.stdtag = data.stdtag;&lt;br /&gt;
	return out;&lt;br /&gt;
	&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
function save_as_png(doc, file, copy, comp, filter, none){&lt;br /&gt;
&lt;br /&gt;
    try {&lt;br /&gt;
&lt;br /&gt;
        if (copy == undefined) copy = true;&lt;br /&gt;
&lt;br /&gt;
        if (comp == undefined) comp = 9;&lt;br /&gt;
&lt;br /&gt;
        if (none == undefined) none = true;&lt;br /&gt;
&lt;br /&gt;
        if (filter == undefined) filter = &amp;quot;PNGFilterAdaptive&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        var doc0 = app.activeDocument;&lt;br /&gt;
&lt;br /&gt;
        app.activeDocument = doc;&lt;br /&gt;
&lt;br /&gt;
        var d = new ActionDescriptor();&lt;br /&gt;
&lt;br /&gt;
        var d1 = new ActionDescriptor();&lt;br /&gt;
&lt;br /&gt;
        d1.putEnumerated(stringIDToTypeID(&amp;quot;method&amp;quot;), stringIDToTypeID(&amp;quot;PNGMethod&amp;quot;), stringIDToTypeID(&amp;quot;quick&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
        if (none)&lt;br /&gt;
&lt;br /&gt;
            d1.putEnumerated(stringIDToTypeID(&amp;quot;PNGInterlaceType&amp;quot;), stringIDToTypeID(&amp;quot;PNGInterlaceType&amp;quot;), stringIDToTypeID(&amp;quot;PNGInterlaceNone&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
        else&lt;br /&gt;
&lt;br /&gt;
            d1.putEnumerated(stringIDToTypeID(&amp;quot;PNGInterlaceType&amp;quot;), stringIDToTypeID(&amp;quot;PNGInterlaceType&amp;quot;), stringIDToTypeID(&amp;quot;PNGInterlaceAdam7&amp;quot;));&lt;br /&gt;
&lt;br /&gt;
        d1.putEnumerated(stringIDToTypeID(&amp;quot;PNGFilter&amp;quot;), stringIDToTypeID(&amp;quot;PNGFilter&amp;quot;), stringIDToTypeID(filter));&lt;br /&gt;
&lt;br /&gt;
        d1.putInteger(stringIDToTypeID(&amp;quot;compression&amp;quot;), comp);&lt;br /&gt;
&lt;br /&gt;
        d.putObject(stringIDToTypeID(&amp;quot;as&amp;quot;), stringIDToTypeID(&amp;quot;PNGFormat&amp;quot;), d1);&lt;br /&gt;
&lt;br /&gt;
        d.putPath(stringIDToTypeID(&amp;quot;in&amp;quot;), file);&lt;br /&gt;
&lt;br /&gt;
        d.putBoolean(stringIDToTypeID(&amp;quot;copy&amp;quot;), copy);&lt;br /&gt;
&lt;br /&gt;
        executeAction(stringIDToTypeID(&amp;quot;save&amp;quot;), d, DialogModes.NO);&lt;br /&gt;
&lt;br /&gt;
        app.activeDocument = doc0;&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
    catch (e) { alert(e); return false; }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
//  json2.js&lt;br /&gt;
//  2023-05-10&lt;br /&gt;
//  Public Domain.&lt;br /&gt;
//  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.&lt;br /&gt;
&lt;br /&gt;
//  USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO&lt;br /&gt;
//  NOT CONTROL.&lt;br /&gt;
&lt;br /&gt;
//  This file creates a global JSON object containing two methods: stringify&lt;br /&gt;
//  and parse. This file provides the ES5 JSON capability to ES3 systems.&lt;br /&gt;
//  If a project might run on IE8 or earlier, then this file should be included.&lt;br /&gt;
//  This file does nothing on ES5 systems.&lt;br /&gt;
&lt;br /&gt;
//      JSON.stringify(value, replacer, space)&lt;br /&gt;
//          value       any JavaScript value, usually an object or array.&lt;br /&gt;
//          replacer    an optional parameter that determines how object&lt;br /&gt;
//                      values are stringified for objects. It can be a&lt;br /&gt;
//                      function or an array of strings.&lt;br /&gt;
//          space       an optional parameter that specifies the indentation&lt;br /&gt;
//                      of nested structures. If it is omitted, the text will&lt;br /&gt;
//                      be packed without extra whitespace. If it is a number,&lt;br /&gt;
//                      it will specify the number of spaces to indent at each&lt;br /&gt;
//                      level. If it is a string (such as &amp;quot;\t&amp;quot; or &amp;quot;&amp;amp;nbsp;&amp;quot;),&lt;br /&gt;
//                      it contains the characters used to indent at each level.&lt;br /&gt;
//          This method produces a JSON text from a JavaScript value.&lt;br /&gt;
//          When an object value is found, if the object contains a toJSON&lt;br /&gt;
//          method, its toJSON method will be called and the result will be&lt;br /&gt;
//          stringified. A toJSON method does not serialize: it returns the&lt;br /&gt;
//          value represented by the name/value pair that should be serialized,&lt;br /&gt;
//          or undefined if nothing should be serialized. The toJSON method&lt;br /&gt;
//          will be passed the key associated with the value, and this will be&lt;br /&gt;
//          bound to the value.&lt;br /&gt;
&lt;br /&gt;
//          For example, this would serialize Dates as ISO strings.&lt;br /&gt;
&lt;br /&gt;
//              Date.prototype.toJSON = function (key) {&lt;br /&gt;
//                  function f(n) {&lt;br /&gt;
//                      // Format integers to have at least two digits.&lt;br /&gt;
//                      return (n &amp;lt; 10)&lt;br /&gt;
//                          ? &amp;quot;0&amp;quot; + n&lt;br /&gt;
//                          : n;&lt;br /&gt;
//                  }&lt;br /&gt;
//                  return this.getUTCFullYear()   + &amp;quot;-&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCMonth() + 1) + &amp;quot;-&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCDate())      + &amp;quot;T&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCHours())     + &amp;quot;:&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCMinutes())   + &amp;quot;:&amp;quot; +&lt;br /&gt;
//                       f(this.getUTCSeconds())   + &amp;quot;Z&amp;quot;;&lt;br /&gt;
//              };&lt;br /&gt;
&lt;br /&gt;
//          You can provide an optional replacer method. It will be passed the&lt;br /&gt;
//          key and value of each member, with this bound to the containing&lt;br /&gt;
//          object. The value that is returned from your method will be&lt;br /&gt;
//          serialized. If your method returns undefined, then the member will&lt;br /&gt;
//          be excluded from the serialization.&lt;br /&gt;
&lt;br /&gt;
//          If the replacer parameter is an array of strings, then it will be&lt;br /&gt;
//          used to select the members to be serialized. It filters the results&lt;br /&gt;
//          such that only members with keys listed in the replacer array are&lt;br /&gt;
//          stringified.&lt;br /&gt;
&lt;br /&gt;
//          Values that do not have JSON representations, such as undefined or&lt;br /&gt;
//          functions, will not be serialized. Such values in objects will be&lt;br /&gt;
//          dropped; in arrays they will be replaced with null. You can use&lt;br /&gt;
//          a replacer function to replace those with JSON values.&lt;br /&gt;
&lt;br /&gt;
//          JSON.stringify(undefined) returns undefined.&lt;br /&gt;
&lt;br /&gt;
//          The optional space parameter produces a stringification of the&lt;br /&gt;
//          value that is filled with line breaks and indentation to make it&lt;br /&gt;
//          easier to read.&lt;br /&gt;
&lt;br /&gt;
//          If the space parameter is a non-empty string, then that string will&lt;br /&gt;
//          be used for indentation. If the space parameter is a number, then&lt;br /&gt;
//          the indentation will be that many spaces.&lt;br /&gt;
&lt;br /&gt;
//          Example:&lt;br /&gt;
&lt;br /&gt;
//          text = JSON.stringify([&amp;quot;e&amp;quot;, {pluribus: &amp;quot;unum&amp;quot;}]);&lt;br /&gt;
//          // text is &#039;[&amp;quot;e&amp;quot;,{&amp;quot;pluribus&amp;quot;:&amp;quot;unum&amp;quot;}]&#039;&lt;br /&gt;
&lt;br /&gt;
//          text = JSON.stringify([&amp;quot;e&amp;quot;, {pluribus: &amp;quot;unum&amp;quot;}], null, &amp;quot;\t&amp;quot;);&lt;br /&gt;
//          // text is &#039;[\n\t&amp;quot;e&amp;quot;,\n\t{\n\t\t&amp;quot;pluribus&amp;quot;: &amp;quot;unum&amp;quot;\n\t}\n]&#039;&lt;br /&gt;
&lt;br /&gt;
//          text = JSON.stringify([new Date()], function (key, value) {&lt;br /&gt;
//              return this[key] instanceof Date&lt;br /&gt;
//                  ? &amp;quot;Date(&amp;quot; + this[key] + &amp;quot;)&amp;quot;&lt;br /&gt;
//                  : value;&lt;br /&gt;
//          });&lt;br /&gt;
//          // text is &#039;[&amp;quot;Date(---current time---)&amp;quot;]&#039;&lt;br /&gt;
&lt;br /&gt;
//      JSON.parse(text, reviver)&lt;br /&gt;
//          This method parses a JSON text to produce an object or array.&lt;br /&gt;
//          It can throw a SyntaxError exception.&lt;br /&gt;
&lt;br /&gt;
//          The optional reviver parameter is a function that can filter and&lt;br /&gt;
//          transform the results. It receives each of the keys and values,&lt;br /&gt;
//          and its return value is used instead of the original value.&lt;br /&gt;
//          If it returns what it received, then the structure is not modified.&lt;br /&gt;
//          If it returns undefined then the member is deleted.&lt;br /&gt;
&lt;br /&gt;
//          Example:&lt;br /&gt;
&lt;br /&gt;
//          // Parse the text. Values that look like ISO date strings will&lt;br /&gt;
//          // be converted to Date objects.&lt;br /&gt;
&lt;br /&gt;
//          myData = JSON.parse(text, function (key, value) {&lt;br /&gt;
//              var a;&lt;br /&gt;
//              if (typeof value === &amp;quot;string&amp;quot;) {&lt;br /&gt;
//                  a =&lt;br /&gt;
//   /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);&lt;br /&gt;
//                  if (a) {&lt;br /&gt;
//                      return new Date(Date.UTC(&lt;br /&gt;
//                         +a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]&lt;br /&gt;
//                      ));&lt;br /&gt;
//                  }&lt;br /&gt;
//                  return value;&lt;br /&gt;
//              }&lt;br /&gt;
//          });&lt;br /&gt;
&lt;br /&gt;
//          myData = JSON.parse(&lt;br /&gt;
//              &amp;quot;[\&amp;quot;Date(09/09/2001)\&amp;quot;]&amp;quot;,&lt;br /&gt;
//              function (key, value) {&lt;br /&gt;
//                  var d;&lt;br /&gt;
//                  if (&lt;br /&gt;
//                      typeof value === &amp;quot;string&amp;quot;&lt;br /&gt;
//                      &amp;amp;&amp;amp; value.slice(0, 5) === &amp;quot;Date(&amp;quot;&lt;br /&gt;
//                      &amp;amp;&amp;amp; value.slice(-1) === &amp;quot;)&amp;quot;&lt;br /&gt;
//                  ) {&lt;br /&gt;
//                      d = new Date(value.slice(5, -1));&lt;br /&gt;
//                      if (d) {&lt;br /&gt;
//                          return d;&lt;br /&gt;
//                      }&lt;br /&gt;
//                  }&lt;br /&gt;
//                  return value;&lt;br /&gt;
//              }&lt;br /&gt;
//          );&lt;br /&gt;
&lt;br /&gt;
//  This is a reference implementation. You are free to copy, modify, or&lt;br /&gt;
//  redistribute.&lt;br /&gt;
&lt;br /&gt;
/*jslint&lt;br /&gt;
    eval, for, this&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
/*property&lt;br /&gt;
    JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,&lt;br /&gt;
    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,&lt;br /&gt;
    lastIndex, length, parse, prototype, push, replace, slice, stringify,&lt;br /&gt;
    test, toJSON, toString, valueOf&lt;br /&gt;
*/&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Create a JSON object only if one does not already exist. We create the&lt;br /&gt;
// methods in a closure to avoid creating global variables.&lt;br /&gt;
&lt;br /&gt;
var JSON = {};&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
(function () {&lt;br /&gt;
    &amp;quot;use strict&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    var rx_one = /^[\],:{}\s]*$/;&lt;br /&gt;
    var rx_two = /\\(?:[&amp;quot;\\\/bfnrt]|u[0-9a-fA-F]{4})/g;&lt;br /&gt;
    var rx_three = /&amp;quot;[^&amp;quot;\\\n\r]*&amp;quot;|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;&lt;br /&gt;
    var rx_four = /(?:^|:|,)(?:\s*\[)+/g;&lt;br /&gt;
    var rx_escapable = /[\\&amp;quot;\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;&lt;br /&gt;
    var rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;&lt;br /&gt;
&lt;br /&gt;
    function f(n) {&lt;br /&gt;
        // Format integers to have at least two digits.&lt;br /&gt;
        return (n &amp;lt; 10)&lt;br /&gt;
            ? &amp;quot;0&amp;quot; + n&lt;br /&gt;
            : n;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function this_value() {&lt;br /&gt;
        return this.valueOf();&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if (typeof Date.prototype.toJSON !== &amp;quot;function&amp;quot;) {&lt;br /&gt;
&lt;br /&gt;
        Date.prototype.toJSON = function () {&lt;br /&gt;
&lt;br /&gt;
            return isFinite(this.valueOf())&lt;br /&gt;
                ? (&lt;br /&gt;
                    this.getUTCFullYear()&lt;br /&gt;
                    + &amp;quot;-&amp;quot;&lt;br /&gt;
                    + f(this.getUTCMonth() + 1)&lt;br /&gt;
                    + &amp;quot;-&amp;quot;&lt;br /&gt;
                    + f(this.getUTCDate())&lt;br /&gt;
                    + &amp;quot;T&amp;quot;&lt;br /&gt;
                    + f(this.getUTCHours())&lt;br /&gt;
                    + &amp;quot;:&amp;quot;&lt;br /&gt;
                    + f(this.getUTCMinutes())&lt;br /&gt;
                    + &amp;quot;:&amp;quot;&lt;br /&gt;
                    + f(this.getUTCSeconds())&lt;br /&gt;
                    + &amp;quot;Z&amp;quot;&lt;br /&gt;
                )&lt;br /&gt;
                : null;&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
        Boolean.prototype.toJSON = this_value;&lt;br /&gt;
        Number.prototype.toJSON = this_value;&lt;br /&gt;
        String.prototype.toJSON = this_value;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    var gap;&lt;br /&gt;
    var indent;&lt;br /&gt;
    var meta;&lt;br /&gt;
    var rep;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    function quote(string) {&lt;br /&gt;
&lt;br /&gt;
// If the string contains no control characters, no quote characters, and no&lt;br /&gt;
// backslash characters, then we can safely slap some quotes around it.&lt;br /&gt;
// Otherwise we must also replace the offending characters with safe escape&lt;br /&gt;
// sequences.&lt;br /&gt;
&lt;br /&gt;
        rx_escapable.lastIndex = 0;&lt;br /&gt;
        return rx_escapable.test(string)&lt;br /&gt;
            ? &amp;quot;\&amp;quot;&amp;quot; + string.replace(rx_escapable, function (a) {&lt;br /&gt;
                var c = meta[a];&lt;br /&gt;
                return typeof c === &amp;quot;string&amp;quot;&lt;br /&gt;
                    ? c&lt;br /&gt;
                    : &amp;quot;\\u&amp;quot; + (&amp;quot;0000&amp;quot; + a.charCodeAt(0).toString(16)).slice(-4);&lt;br /&gt;
            }) + &amp;quot;\&amp;quot;&amp;quot;&lt;br /&gt;
            : &amp;quot;\&amp;quot;&amp;quot; + string + &amp;quot;\&amp;quot;&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    function str(key, holder) {&lt;br /&gt;
&lt;br /&gt;
// Produce a string from holder[key].&lt;br /&gt;
&lt;br /&gt;
        var i;          // The loop counter.&lt;br /&gt;
        var k;          // The member key.&lt;br /&gt;
        var v;          // The member value.&lt;br /&gt;
        var length;&lt;br /&gt;
        var mind = gap;&lt;br /&gt;
        var partial;&lt;br /&gt;
        var value = holder[key];&lt;br /&gt;
&lt;br /&gt;
// If the value has a toJSON method, call it to obtain a replacement value.&lt;br /&gt;
&lt;br /&gt;
        if (&lt;br /&gt;
            value&lt;br /&gt;
            &amp;amp;&amp;amp; typeof value === &amp;quot;object&amp;quot;&lt;br /&gt;
            &amp;amp;&amp;amp; typeof value.toJSON === &amp;quot;function&amp;quot;&lt;br /&gt;
        ) {&lt;br /&gt;
            value = value.toJSON(key);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
// If we were called with a replacer function, then call the replacer to&lt;br /&gt;
// obtain a replacement value.&lt;br /&gt;
&lt;br /&gt;
        if (typeof rep === &amp;quot;function&amp;quot;) {&lt;br /&gt;
            value = rep.call(holder, key, value);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
// What happens next depends on the value&#039;s type.&lt;br /&gt;
&lt;br /&gt;
        switch (typeof value) {&lt;br /&gt;
        case &amp;quot;string&amp;quot;:&lt;br /&gt;
            return quote(value);&lt;br /&gt;
&lt;br /&gt;
        case &amp;quot;number&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
// JSON numbers must be finite. Encode non-finite numbers as null.&lt;br /&gt;
&lt;br /&gt;
            return (isFinite(value))&lt;br /&gt;
                ? String(value)&lt;br /&gt;
                : &amp;quot;null&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        case &amp;quot;boolean&amp;quot;:&lt;br /&gt;
        case &amp;quot;null&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
// If the value is a boolean or null, convert it to a string. Note:&lt;br /&gt;
// typeof null does not produce &amp;quot;null&amp;quot;. The case is included here in&lt;br /&gt;
// the remote chance that this gets fixed someday.&lt;br /&gt;
&lt;br /&gt;
            return String(value);&lt;br /&gt;
&lt;br /&gt;
// If the type is &amp;quot;object&amp;quot;, we might be dealing with an object or an array or&lt;br /&gt;
// null.&lt;br /&gt;
&lt;br /&gt;
        case &amp;quot;object&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
// Due to a specification blunder in ECMAScript, typeof null is &amp;quot;object&amp;quot;,&lt;br /&gt;
// so watch out for that case.&lt;br /&gt;
&lt;br /&gt;
            if (!value) {&lt;br /&gt;
                return &amp;quot;null&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// Make an array to hold the partial results of stringifying this object value.&lt;br /&gt;
&lt;br /&gt;
            gap += indent;&lt;br /&gt;
            partial = [];&lt;br /&gt;
&lt;br /&gt;
// Is the value an array?&lt;br /&gt;
&lt;br /&gt;
            if (Object.prototype.toString.apply(value) === &amp;quot;[object Array]&amp;quot;) {&lt;br /&gt;
&lt;br /&gt;
// The value is an array. Stringify every element. Use null as a placeholder&lt;br /&gt;
// for non-JSON values.&lt;br /&gt;
&lt;br /&gt;
                length = value.length;&lt;br /&gt;
                for (i = 0; i &amp;lt; length; i += 1) {&lt;br /&gt;
                    partial[i] = str(i, value) || &amp;quot;null&amp;quot;;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
// Join all of the elements together, separated with commas, and wrap them in&lt;br /&gt;
// brackets.&lt;br /&gt;
&lt;br /&gt;
                v = partial.length === 0&lt;br /&gt;
                    ? &amp;quot;[]&amp;quot;&lt;br /&gt;
                    : gap&lt;br /&gt;
                        ? (&lt;br /&gt;
                            &amp;quot;[\n&amp;quot;&lt;br /&gt;
                            + gap&lt;br /&gt;
                            + partial.join(&amp;quot;,\n&amp;quot; + gap)&lt;br /&gt;
                            + &amp;quot;\n&amp;quot;&lt;br /&gt;
                            + mind&lt;br /&gt;
                            + &amp;quot;]&amp;quot;&lt;br /&gt;
                        )&lt;br /&gt;
                        : &amp;quot;[&amp;quot; + partial.join(&amp;quot;,&amp;quot;) + &amp;quot;]&amp;quot;;&lt;br /&gt;
                gap = mind;&lt;br /&gt;
                return v;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// If the replacer is an array, use it to select the members to be stringified.&lt;br /&gt;
&lt;br /&gt;
            if (rep &amp;amp;&amp;amp; typeof rep === &amp;quot;object&amp;quot;) {&lt;br /&gt;
                length = rep.length;&lt;br /&gt;
                for (i = 0; i &amp;lt; length; i += 1) {&lt;br /&gt;
                    if (typeof rep[i] === &amp;quot;string&amp;quot;) {&lt;br /&gt;
                        k = rep[i];&lt;br /&gt;
                        v = str(k, value);&lt;br /&gt;
                        if (v) {&lt;br /&gt;
                            partial.push(quote(k) + (&lt;br /&gt;
                                (gap)&lt;br /&gt;
                                    ? &amp;quot;: &amp;quot;&lt;br /&gt;
                                    : &amp;quot;:&amp;quot;&lt;br /&gt;
                            ) + v);&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            } else {&lt;br /&gt;
&lt;br /&gt;
// Otherwise, iterate through all of the keys in the object.&lt;br /&gt;
&lt;br /&gt;
                for (k in value) {&lt;br /&gt;
                    if (Object.prototype.hasOwnProperty.call(value, k)) {&lt;br /&gt;
                        v = str(k, value);&lt;br /&gt;
                        if (v) {&lt;br /&gt;
                            partial.push(quote(k) + (&lt;br /&gt;
                                (gap)&lt;br /&gt;
                                    ? &amp;quot;: &amp;quot;&lt;br /&gt;
                                    : &amp;quot;:&amp;quot;&lt;br /&gt;
                            ) + v);&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// Join all of the member texts together, separated with commas,&lt;br /&gt;
// and wrap them in braces.&lt;br /&gt;
&lt;br /&gt;
            v = partial.length === 0&lt;br /&gt;
                ? &amp;quot;{}&amp;quot;&lt;br /&gt;
                : gap&lt;br /&gt;
                    ? &amp;quot;{\n&amp;quot; + gap + partial.join(&amp;quot;,\n&amp;quot; + gap) + &amp;quot;\n&amp;quot; + mind + &amp;quot;}&amp;quot;&lt;br /&gt;
                    : &amp;quot;{&amp;quot; + partial.join(&amp;quot;,&amp;quot;) + &amp;quot;}&amp;quot;;&lt;br /&gt;
            gap = mind;&lt;br /&gt;
            return v;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
// If the JSON object does not yet have a stringify method, give it one.&lt;br /&gt;
&lt;br /&gt;
    if (typeof JSON.stringify !== &amp;quot;function&amp;quot;) {&lt;br /&gt;
        meta = {    // table of character substitutions&lt;br /&gt;
            &amp;quot;\b&amp;quot;: &amp;quot;\\b&amp;quot;,&lt;br /&gt;
            &amp;quot;\t&amp;quot;: &amp;quot;\\t&amp;quot;,&lt;br /&gt;
            &amp;quot;\n&amp;quot;: &amp;quot;\\n&amp;quot;,&lt;br /&gt;
            &amp;quot;\f&amp;quot;: &amp;quot;\\f&amp;quot;,&lt;br /&gt;
            &amp;quot;\r&amp;quot;: &amp;quot;\\r&amp;quot;,&lt;br /&gt;
            &amp;quot;\&amp;quot;&amp;quot;: &amp;quot;\\\&amp;quot;&amp;quot;,&lt;br /&gt;
            &amp;quot;\\&amp;quot;: &amp;quot;\\\\&amp;quot;&lt;br /&gt;
        };&lt;br /&gt;
        JSON.stringify = function (value, replacer, space) {&lt;br /&gt;
&lt;br /&gt;
// The stringify method takes a value and an optional replacer, and an optional&lt;br /&gt;
// space parameter, and returns a JSON text. The replacer can be a function&lt;br /&gt;
// that can replace values, or an array of strings that will select the keys.&lt;br /&gt;
// A default replacer method can be provided. Use of the space parameter can&lt;br /&gt;
// produce text that is more easily readable.&lt;br /&gt;
&lt;br /&gt;
            var i;&lt;br /&gt;
            gap = &amp;quot;&amp;quot;;&lt;br /&gt;
            indent = &amp;quot;&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// If the space parameter is a number, make an indent string containing that&lt;br /&gt;
// many spaces.&lt;br /&gt;
&lt;br /&gt;
            if (typeof space === &amp;quot;number&amp;quot;) {&lt;br /&gt;
                for (i = 0; i &amp;lt; space; i += 1) {&lt;br /&gt;
                    indent += &amp;quot; &amp;quot;;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
// If the space parameter is a string, it will be used as the indent string.&lt;br /&gt;
&lt;br /&gt;
            } else if (typeof space === &amp;quot;string&amp;quot;) {&lt;br /&gt;
                indent = space;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// If there is a replacer, it must be a function or an array.&lt;br /&gt;
// Otherwise, throw an error.&lt;br /&gt;
&lt;br /&gt;
            rep = replacer;&lt;br /&gt;
            if (replacer &amp;amp;&amp;amp; typeof replacer !== &amp;quot;function&amp;quot; &amp;amp;&amp;amp; (&lt;br /&gt;
                typeof replacer !== &amp;quot;object&amp;quot;&lt;br /&gt;
                || typeof replacer.length !== &amp;quot;number&amp;quot;&lt;br /&gt;
            )) {&lt;br /&gt;
                throw new Error(&amp;quot;JSON.stringify&amp;quot;);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// Make a fake root object containing our value under the key of &amp;quot;&amp;quot;.&lt;br /&gt;
// Return the result of stringifying the value.&lt;br /&gt;
&lt;br /&gt;
            return str(&amp;quot;&amp;quot;, {&amp;quot;&amp;quot;: value});&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// If the JSON object does not yet have a parse method, give it one.&lt;br /&gt;
&lt;br /&gt;
    if (typeof JSON.parse !== &amp;quot;function&amp;quot;) {&lt;br /&gt;
        JSON.parse = function (text, reviver) {&lt;br /&gt;
&lt;br /&gt;
// The parse method takes a text and an optional reviver function, and returns&lt;br /&gt;
// a JavaScript value if the text is a valid JSON text.&lt;br /&gt;
&lt;br /&gt;
            var j;&lt;br /&gt;
&lt;br /&gt;
            function walk(holder, key) {&lt;br /&gt;
&lt;br /&gt;
// The walk method is used to recursively walk the resulting structure so&lt;br /&gt;
// that modifications can be made.&lt;br /&gt;
&lt;br /&gt;
                var k;&lt;br /&gt;
                var v;&lt;br /&gt;
                var value = holder[key];&lt;br /&gt;
                if (value &amp;amp;&amp;amp; typeof value === &amp;quot;object&amp;quot;) {&lt;br /&gt;
                    for (k in value) {&lt;br /&gt;
                        if (Object.prototype.hasOwnProperty.call(value, k)) {&lt;br /&gt;
                            v = walk(value, k);&lt;br /&gt;
                            if (v !== undefined) {&lt;br /&gt;
                                value[k] = v;&lt;br /&gt;
                            } else {&lt;br /&gt;
                                delete value[k];&lt;br /&gt;
                            }&lt;br /&gt;
                        }&lt;br /&gt;
                    }&lt;br /&gt;
                }&lt;br /&gt;
                return reviver.call(holder, key, value);&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Parsing happens in four stages. In the first stage, we replace certain&lt;br /&gt;
// Unicode characters with escape sequences. JavaScript handles many characters&lt;br /&gt;
// incorrectly, either silently deleting them, or treating them as line endings.&lt;br /&gt;
&lt;br /&gt;
            text = String(text);&lt;br /&gt;
            rx_dangerous.lastIndex = 0;&lt;br /&gt;
            if (rx_dangerous.test(text)) {&lt;br /&gt;
                text = text.replace(rx_dangerous, function (a) {&lt;br /&gt;
                    return (&lt;br /&gt;
                        &amp;quot;\\u&amp;quot;&lt;br /&gt;
                        + (&amp;quot;0000&amp;quot; + a.charCodeAt(0).toString(16)).slice(-4)&lt;br /&gt;
                    );&lt;br /&gt;
                });&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// In the second stage, we run the text against regular expressions that look&lt;br /&gt;
// for non-JSON patterns. We are especially concerned with &amp;quot;()&amp;quot; and &amp;quot;new&amp;quot;&lt;br /&gt;
// because they can cause invocation, and &amp;quot;=&amp;quot; because it can cause mutation.&lt;br /&gt;
// But just to be safe, we want to reject all unexpected forms.&lt;br /&gt;
&lt;br /&gt;
// We split the second stage into 4 regexp operations in order to work around&lt;br /&gt;
// crippling inefficiencies in IE&#039;s and Safari&#039;s regexp engines. First we&lt;br /&gt;
// replace the JSON backslash pairs with &amp;quot;@&amp;quot; (a non-JSON character). Second, we&lt;br /&gt;
// replace all simple value tokens with &amp;quot;]&amp;quot; characters. Third, we delete all&lt;br /&gt;
// open brackets that follow a colon or comma or that begin the text. Finally,&lt;br /&gt;
// we look to see that the remaining characters are only whitespace or &amp;quot;]&amp;quot; or&lt;br /&gt;
// &amp;quot;,&amp;quot; or &amp;quot;:&amp;quot; or &amp;quot;{&amp;quot; or &amp;quot;}&amp;quot;. If that is so, then the text is safe for eval.&lt;br /&gt;
&lt;br /&gt;
            if (&lt;br /&gt;
                rx_one.test(&lt;br /&gt;
                    text&lt;br /&gt;
                        .replace(rx_two, &amp;quot;@&amp;quot;)&lt;br /&gt;
                        .replace(rx_three, &amp;quot;]&amp;quot;)&lt;br /&gt;
                        .replace(rx_four, &amp;quot;&amp;quot;)&lt;br /&gt;
                )&lt;br /&gt;
            ) {&lt;br /&gt;
&lt;br /&gt;
// In the third stage we use the eval function to compile the text into a&lt;br /&gt;
// JavaScript structure. The &amp;quot;{&amp;quot; operator is subject to a syntactic ambiguity&lt;br /&gt;
// in JavaScript: it can begin a block or an object literal. We wrap the text&lt;br /&gt;
// in parens to eliminate the ambiguity.&lt;br /&gt;
&lt;br /&gt;
                j = eval(&amp;quot;(&amp;quot; + text + &amp;quot;)&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
// In the optional fourth stage, we recursively walk the new structure, passing&lt;br /&gt;
// each name/value pair to a reviver function for possible transformation.&lt;br /&gt;
&lt;br /&gt;
                return (typeof reviver === &amp;quot;function&amp;quot;)&lt;br /&gt;
                    ? walk({&amp;quot;&amp;quot;: j}, &amp;quot;&amp;quot;)&lt;br /&gt;
                    : j;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
// If the text is not JSON parseable, then a SyntaxError is thrown.&lt;br /&gt;
&lt;br /&gt;
            throw new SyntaxError(&amp;quot;JSON.parse&amp;quot;);&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
}());&lt;br /&gt;
&lt;br /&gt;
exec();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Creating_Advanced_Art_Layers&amp;diff=336</id>
		<title>Creating Advanced Art Layers</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Creating_Advanced_Art_Layers&amp;diff=336"/>
		<updated>2026-06-05T11:52:49Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Inpaint Tits.png|thumb|Inpainting nipple-studs/clothes: Only inpaint the clothes to make it easier later.]]&lt;br /&gt;
Advanced art layers can be used to give a character multiple/colorable outfits. Note: This tutorial was written for photoshop. You can use gimp, but you&#039;ll have to either rewrite my script, or add the art in game manually.&lt;br /&gt;
&lt;br /&gt;
== Creating the Art ==&lt;br /&gt;
&lt;br /&gt;
The first thing you&#039;ll want to do is to create the actual art. If you&#039;re creating AI art, you&#039;ll want to draw some clothes over the character and only generate the parts you&#039;ve drawn. Otherwise you may end up with clashing layers. If you know how to draw yourself, it&#039;s going to be significantly easier, since you can just draw the clothes on separate layers directly.&lt;br /&gt;
&lt;br /&gt;
Since I can&#039;t draw, this tutorial will be from the perspective of using AI tools.&lt;br /&gt;
&lt;br /&gt;
You can add as many or as few layers as you want, but these are the layers that are used by default and the photoshop script is setup to auto handle these layers:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Description&lt;br /&gt;
!Base Layer&lt;br /&gt;
!UB Layer&lt;br /&gt;
!File name for PS script&lt;br /&gt;
|-&lt;br /&gt;
|Gloves&lt;br /&gt;
|50 or 18&lt;br /&gt;
|N/A&lt;br /&gt;
|gloves.png&lt;br /&gt;
|-&lt;br /&gt;
|Boots&lt;br /&gt;
|40&lt;br /&gt;
|N/A&lt;br /&gt;
|boots.png&lt;br /&gt;
|-&lt;br /&gt;
|Sling Bikini Heavy Armor&lt;br /&gt;
|25&lt;br /&gt;
|N/A&lt;br /&gt;
|sling_heavy.png&lt;br /&gt;
|-&lt;br /&gt;
|Sling Bikini Medium Armor&lt;br /&gt;
|25&lt;br /&gt;
|N/A&lt;br /&gt;
|sling_med.png&lt;br /&gt;
|-&lt;br /&gt;
|Sling Bikini Light Armor&lt;br /&gt;
|25&lt;br /&gt;
|N/A&lt;br /&gt;
|sling_light.png&lt;br /&gt;
|-&lt;br /&gt;
|Bodysuit medium armor&lt;br /&gt;
|25&lt;br /&gt;
|N/A&lt;br /&gt;
|bodysuit_med.png&lt;br /&gt;
|-&lt;br /&gt;
|Bodysuit light armor&lt;br /&gt;
|25&lt;br /&gt;
|N/A&lt;br /&gt;
|bodysuit_light.png&lt;br /&gt;
|-&lt;br /&gt;
|Heavy 2-part armor&lt;br /&gt;
|25&lt;br /&gt;
|35&lt;br /&gt;
|heavy.png&lt;br /&gt;
|-&lt;br /&gt;
|Medium 2-part armor&lt;br /&gt;
|25&lt;br /&gt;
|35&lt;br /&gt;
|med.png&lt;br /&gt;
|-&lt;br /&gt;
|Light 2-part armor&lt;br /&gt;
|25&lt;br /&gt;
|35&lt;br /&gt;
|light.png&lt;br /&gt;
|-&lt;br /&gt;
|Collar&lt;br /&gt;
|23, 3 or 43&lt;br /&gt;
|N/A&lt;br /&gt;
|collar.png&lt;br /&gt;
|-&lt;br /&gt;
|Nipple studs (optional)&lt;br /&gt;
|22&lt;br /&gt;
|N/A&lt;br /&gt;
|nipple_studs.png&lt;br /&gt;
|-&lt;br /&gt;
|Aroused heavy state&lt;br /&gt;
|15&lt;br /&gt;
|N/A&lt;br /&gt;
|aroused_heavy.png&lt;br /&gt;
|-&lt;br /&gt;
|Pain heavy state&lt;br /&gt;
|15&lt;br /&gt;
|N/A&lt;br /&gt;
|pain_heavy.png&lt;br /&gt;
|-&lt;br /&gt;
|Aroused state&lt;br /&gt;
|10&lt;br /&gt;
|N/A&lt;br /&gt;
|aroused.png&lt;br /&gt;
|-&lt;br /&gt;
|Pain state&lt;br /&gt;
|10&lt;br /&gt;
|N/A&lt;br /&gt;
|pain.png&lt;br /&gt;
|-&lt;br /&gt;
|Orgasm state&lt;br /&gt;
|5&lt;br /&gt;
|N/A&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
== Preparing the File ==&lt;br /&gt;
&lt;br /&gt;
We&#039;ll need to create a photoshop file. In this tutorial I&#039;ll be creating a jaguar character. I&#039;ll drag the naked layer into photoshop and save it as a new file called &amp;quot;jaguar.psd&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The layer order, names, and settings will be used by the exporter to generate a file you can use in the FetishQuest devtools to make it easier to setup your character art. We&#039;ll start with the lower nr layers and go up.&lt;br /&gt;
&lt;br /&gt;
FQ supports the following layers (tho see public/classes/PlayerIconState.js in the source for something more up to date:&lt;br /&gt;
&lt;br /&gt;
* FaceResting : 5 - Resting face reaction. I use it for orgasm faces.&lt;br /&gt;
* FaceMild : 10 - Facial expression for mild reactions. I use it for pain/arousal.&lt;br /&gt;
* FaceHeavy : 15 - Facial expression for heavy reactions, I use it for heavy pain/arousal such as critical hits.&lt;br /&gt;
* CosmeticLower : 20 - Allows you to put cosmetics under armor. Nipple clamps and collars are good examples. I won&#039;t be using this in the tutorial.&lt;br /&gt;
* ArmorLower : 25 - Lower body armor&lt;br /&gt;
* Handheld : 30 - Handheld items. Not used in this tutorial because there&#039;s way too many items.&lt;br /&gt;
* ArmorUpper : 35 - Upper body armor.&lt;br /&gt;
* ArmorCosmeticJewellery : 40 - Jewelry layer. Not used in this tutorial.&lt;br /&gt;
* ArmorCosmeticLower : 45 - Lower body cosmetic. Not used in this tutorial.&lt;br /&gt;
* ArmorCosmeticUpper : 50 - Upper body cosmetic. Not used in this tutorial.&lt;br /&gt;
* Stains : 55 - Stain/slime layers etc. Not used in this tutorial.&lt;br /&gt;
&lt;br /&gt;
When the image is drawn, layers are drawn from lowest to highest, drawing active higher value layers on top of lower value layers. Only one image per layer is ever drawn. The higher the layer is in the FQ editor/photoshop file, the higher priority it gains. There&#039;s an exception for temporary layers, such as FaceMild and FaceHeavy, which are triggered from events and the last triggered one gets priority.&lt;br /&gt;
&lt;br /&gt;
== Preparing the Orgasm Face ==&lt;br /&gt;
[[File:Layers1.png|thumb|The layer order and name matters. 5_orgasm means draw on layer 5 (FaceResting) and label the layer &amp;quot;orgasm&amp;quot;.]]&lt;br /&gt;
[[File:Difference.png|thumb|Use difference and magic wand to select and delete all pixels that are the same as the background.]]&lt;br /&gt;
&#039;&#039;Note: In all these examples, if you draw your own art you can skip the erasing parts of these steps, and go directly to naming your layers. Just keep in mind that you can only have one photoshop layer per art layer. So if for instance your orgasm face is drawn on multiple layers, you&#039;ll have to merge those. But don&#039;t merge them to the background!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Copy your orgasm face art over the background in the jaguar.psd file and rename the layer to 5_orgasm. &#039;&#039;&#039;The number followed by _ is required&#039;&#039;&#039; and tells the script what FQ art layer you want the photoshop layer to go on. Layer 5 is the FaceResting layer, which we&#039;ll use for orgasm. To make things easier, I&#039;ll create a Faces folder and put it in there. But you don&#039;t have to.&lt;br /&gt;
# If you want to prevent a layer from being exported, start the name with # and it will be invisible in the exporter script.&lt;br /&gt;
# Next we&#039;ll need to erase everything but the face (changed pixels). The easiest way I&#039;ve found to do this is to change the blend mode of 5_orgasm to &amp;quot;difference&amp;quot;. This makes pixels that are the same as the background pure black. While in this mode, use the magic wand with a tolerance of 1 and Sample All Layers checked on any of the black parts of the picture. Then delete the black pixels. Set the blend mode back to normal.&lt;br /&gt;
# You may want to do some touch-ups with the eraser tool.&lt;br /&gt;
&lt;br /&gt;
== Preparing the Reaction Faces ==&lt;br /&gt;
Reactions are layers that should show up for a specified amount of time. They&#039;re all bound to text events, meaning you probably want to use the meta tags conditions. Reaction layers are also special in that you can bind multiple ones to the same layer, and only the most recently triggered one will be made visible. This makes them good for facial reactions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;When using photoshop, you can use the [[fqAutoLayers]] script to automate removing the unchanged pixels.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
# Copy your aroused face art into the photoshop file.&lt;br /&gt;
# Name the layer 10_aroused to use layer 10 (FaceMild). And put it in the Faces folder, on top of 5_orgasm.&lt;br /&gt;
# Do the same difference trick. Remember to hide any layers except 10_aroused and the background.&lt;br /&gt;
# If you plan to add a collar, you probably want to use a soft eraser brush to remove everything below the chin.&lt;br /&gt;
# Do the same with the pain expression, but name it 10_pain&lt;br /&gt;
# Do the same thing with your heavy aroused/pained layers, but use layer 15 by naming them 15_aroused_heavy and 15_pain_heavy&lt;br /&gt;
# If you did it right, you should now have your layers setup as such:[[File:Facelayers.png|none|thumb|Example of facial reaction layers in photoshop. Ignore the #Background copy layer. I&#039;m only using it to help erase needless pixels.]]&lt;br /&gt;
&lt;br /&gt;
== Preparing Clothing Layers ==&lt;br /&gt;
[[File:Clothes Difference.png|thumb|Using the difference trick to remove pixels that are the same on the clothing layer and background.]]&lt;br /&gt;
[[File:Panty Selection.png|thumb|Selecting only the colorable part of the outfit.]]&lt;br /&gt;
[[File:MaskingLayer Panties.png|thumb|Masking layer set to multiply and 68% opacity]]&lt;br /&gt;
[[File:Masked outfit.png|thumb|Outfit with 70% opacity multiply layers on top.]]&lt;br /&gt;
Remember that the order of photoshop layers matter. Each layer number (this is the number the layer name starts with) is unique in FQ, and only the first valid layer nr matching a set of conditions will be drawn. Basically, put the most unique outfits on top, and use the lower ones as a fallback. &lt;br /&gt;
&lt;br /&gt;
# The first outfit we&#039;ll prepare is the fallback outfit: An outfit that you can fall back on if none of the layers above it are valid. You can pick what you want, but for this I&#039;m going to pick the cloth outfit (shirt and panties).&lt;br /&gt;
# Create a new group and name it something descriptive such as &amp;quot;cloth&amp;quot;&lt;br /&gt;
# Paste the cloth art into the file and put it in said group.&lt;br /&gt;
# Use the difference trick again to remove unchanged pixels. I also recommend using a soft eraser to make the visible parts as small as possible.&lt;br /&gt;
# Next select only the top part of the outfit, using a selection tool of your choosing.&lt;br /&gt;
# Hit ctrl+shift+J to split it into a new layer.&lt;br /&gt;
# Name the layer containing the top half of the armor something like 35_cloth_ub and the lower half layer 25_cloth_lb&lt;br /&gt;
# If you did it correct, you should have something like this:[[File:Cloth Layers.png|none|thumb|Ignore the #Background copy layer.]]&lt;br /&gt;
# To allow players to recolor the layer, we&#039;ll need to create a mask layer. Start by selecting the 25_cloth_lb layer.&lt;br /&gt;
# This is the time consuming part. Use a selection tool of your choosing and select only parts of the panties you want to recolor.&lt;br /&gt;
# Hit ctrl+j to copy it to a new layer. Name it 26_cloth_lb&lt;br /&gt;
# Hit ctrl+u to enter hue/saturation. Drag the lightness all the way up to make it pure white, and accept.&lt;br /&gt;
# Hit ctrl+u again and check colorize. Drag saturation all the way to max and color to -50.&lt;br /&gt;
# In the layer browser, change the blending mode to multiply or overlay, depending on what you think looks better.&lt;br /&gt;
# Alter the opacity until it looks good. Keep in mind this is what it&#039;s going to look like if the player dyes their armor pure red.&lt;br /&gt;
# Set your brush to pure red and use a small brush / eraser to patch up any sections you missed.&lt;br /&gt;
# You can use hue/saturation on this layer to preview what it&#039;s going to look like in different brightness and colors.&lt;br /&gt;
# Repeat for the top part of the outfit.&lt;br /&gt;
# Your layers should now look like this:[[File:Mask Layers.png|none|thumb]]&lt;br /&gt;
# Adding a bodysuit is basically the same, except you&#039;ll only be using layer 25 and layer 26, since it only affects one layer.&lt;br /&gt;
# From this point on it&#039;s just rinse and repeat for your art layers. But remember the order of your photoshop layers matter. The following is how I ended up laying it out. I went with the strategy of &amp;quot;most specific outfit&amp;quot; first, meaning bodysuits on top:[[File:Finished Layers.png|none|thumb|Advanced armor setup with faces and armor types.]]&lt;br /&gt;
&lt;br /&gt;
== Using the script ==&lt;br /&gt;
[[File:Compiled Output.png|thumb|5 faces and 9 outfits sliced using the FQCrop batch script.]]&lt;br /&gt;
Time to bake the different layers! If you wanna do this by hand, you&#039;d crop, make a note of the top left corner, and manually add the layers in the FQ layer editor. But if you have photoshop you can run a script to bake all the layers into a folder and generate a JSON file you can use for uploading.&lt;br /&gt;
You can grab the script here: [[FQCrop Batch]]&lt;br /&gt;
&lt;br /&gt;
If everything goes according to plan, you&#039;ll see a bunch of images pop up as it crops them for you. A new folder with the same name as the PSD file will be put in the PSD directory. This includes all the sliced images. The background image will also be saved in said folder as a PNG with _n appended to it. This is the nude layer.&lt;br /&gt;
&lt;br /&gt;
The script also outputs (in the same folder as the PSD file) a JSON document named the same as the PSD file. This is pre-filled with some basic values. But we&#039;ll need to add conditions to it.&lt;br /&gt;
&lt;br /&gt;
Note: If you make changes in the photoshop file and re-run the script, it&#039;ll load and update the JSON file, maintaining your conditions. But if you change the name (including the number) of a photoshop layer, you&#039;ll have to modify it in the JSON file to match first. This is because the script will NEVER DELETE anything from the JSON file, only update and add. So make sure you have the order of photoshop layers correct before you start adding conditions to the JSON file.&lt;br /&gt;
&lt;br /&gt;
Also note: The coordinates in the JSON file are based off of the largest image in the set, which is usually the background.&lt;br /&gt;
&lt;br /&gt;
== Modifying the JSON file ==&lt;br /&gt;
My preferred way to map conditions is to modify the JSON file. But you can also skip editing the JSON file and import it into the FQ mod tool. Then use the mod tool to setup the conditions. If you do, I recommend you export it back to JSON in case you want to rerun the script to update images and positions.&lt;br /&gt;
The JSON file just contains an array objects for each layer. Each object may look something like:&lt;br /&gt;
 {&lt;br /&gt;
     &amp;quot;icon&amp;quot;: &amp;quot;25_sling_heavy.png&amp;quot;,&lt;br /&gt;
     &amp;quot;conditions&amp;quot;: [&lt;br /&gt;
             &lt;br /&gt;
     ],&lt;br /&gt;
     &amp;quot;layer&amp;quot;: 25,&lt;br /&gt;
     &amp;quot;duration&amp;quot;: 0,&lt;br /&gt;
     &amp;quot;x&amp;quot;: 363,&lt;br /&gt;
     &amp;quot;y&amp;quot;: 133,&lt;br /&gt;
     &amp;quot;slot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
     &amp;quot;blendMode&amp;quot;: &amp;quot;source-over&amp;quot;,&lt;br /&gt;
     &amp;quot;opacity&amp;quot;: 1&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
* Icon is the image file name.&lt;br /&gt;
* Conditions is an array of FQ conditions that must be matched (see below). If you follow the naming convention in the [[JaguarArtFile|jaguar demo file]], it will try to auto fill conditions.&lt;br /&gt;
* Layer is the FQ art layer.&lt;br /&gt;
* Duration is used in reaction faces, and specifies how long it should show in milliseconds.&lt;br /&gt;
* X/Y are pixel coordinates relative to the largest image (should be the background).&lt;br /&gt;
* Slot is the armor slot for the mask layer. It specifies what armor slot it should grab the color from.&lt;br /&gt;
* Blend mode is the blend mode. source-over is the same as normal in photoshop.&lt;br /&gt;
* Opacity is the opacity between 0-1&lt;br /&gt;
On top of the file is a URL field, you can set that to the base path where you&#039;re hosting your files.&lt;br /&gt;
&lt;br /&gt;
The script will setup most of these for you, except the conditions, which we&#039;ll have to add manually.&lt;br /&gt;
&lt;br /&gt;
# Open the JSON file in one window and the FQ mod tools in another. Load up your mod and go to the conditions listing.&lt;br /&gt;
# Search for conditions here and add them to the condition arrays. Example for heavy sling bikini with sling bikini and lowerBodyHard (hard armor) conditions. Note that layer 26 is the masking layer for layer 25. Both of them need the same conditions to work.&lt;br /&gt;
&lt;br /&gt;
     {&lt;br /&gt;
         &amp;quot;icon&amp;quot;: &amp;quot;26_sling_heavy.png&amp;quot;,&lt;br /&gt;
         &amp;quot;conditions&amp;quot;: [&lt;br /&gt;
             &amp;quot;targetWearsSlingBikini&amp;quot;, &amp;quot;targetLowerBodyHard&amp;quot;&lt;br /&gt;
         ],&lt;br /&gt;
         &amp;quot;layer&amp;quot;: 26,&lt;br /&gt;
         &amp;quot;duration&amp;quot;: 0,&lt;br /&gt;
         &amp;quot;x&amp;quot;: 383,&lt;br /&gt;
         &amp;quot;y&amp;quot;: 159,&lt;br /&gt;
         &amp;quot;slot&amp;quot;: &amp;quot;lowerBody&amp;quot;,&lt;br /&gt;
         &amp;quot;blendMode&amp;quot;: &amp;quot;multiply&amp;quot;,&lt;br /&gt;
         &amp;quot;opacity&amp;quot;: 0.70196078431373&lt;br /&gt;
     },&lt;br /&gt;
     {&lt;br /&gt;
         &amp;quot;icon&amp;quot;: &amp;quot;25_sling_heavy.png&amp;quot;,&lt;br /&gt;
         &amp;quot;conditions&amp;quot;: [&lt;br /&gt;
             &amp;quot;targetWearsSlingBikini&amp;quot;, &amp;quot;targetLowerBodyHard&amp;quot;&lt;br /&gt;
         ],&lt;br /&gt;
         &amp;quot;layer&amp;quot;: 25,&lt;br /&gt;
         &amp;quot;duration&amp;quot;: 0,&lt;br /&gt;
         &amp;quot;x&amp;quot;: 363,&lt;br /&gt;
         &amp;quot;y&amp;quot;: 133,&lt;br /&gt;
         &amp;quot;slot&amp;quot;: &amp;quot;&amp;quot;,&lt;br /&gt;
         &amp;quot;blendMode&amp;quot;: &amp;quot;source-over&amp;quot;,&lt;br /&gt;
         &amp;quot;opacity&amp;quot;: 1&lt;br /&gt;
     },&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Table of the layer order and conditions I used for the jaguar (clothing layers only). Remember that these conditions have to be applied to both cloth and mask layers for each outfit.   &lt;br /&gt;
!Outfit&lt;br /&gt;
!Upper Body (If any)&lt;br /&gt;
!Lower Body&lt;br /&gt;
!Notes&lt;br /&gt;
|-&lt;br /&gt;
|Sling Heavy&lt;br /&gt;
|&lt;br /&gt;
|&amp;quot;targetWearsSlingBikini&amp;quot;, &amp;quot;targetLowerBodyHard&amp;quot;&lt;br /&gt;
|Sling bikinis are also tagged as bodysuits. So they need to go above bodysuits. You can think of the bodysuit tag as any one-piece.&lt;br /&gt;
|-&lt;br /&gt;
|Sling Leather&lt;br /&gt;
|&lt;br /&gt;
|&amp;quot;targetWearsSlingBikini&amp;quot;, &amp;quot;targetLowerBodyLeather&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Sling Cloth&lt;br /&gt;
|&lt;br /&gt;
|&amp;quot;targetWearsSlingBikini&amp;quot;&lt;br /&gt;
|Since the other two sling bikinis are above, they will get priority. So we use this as a catchall for sling that don&#039;t match above conditions.&lt;br /&gt;
|-&lt;br /&gt;
|Bodysuit Leather&lt;br /&gt;
|&lt;br /&gt;
|&amp;quot;targetBodysuit&amp;quot;, &amp;quot;targetLowerBodyLeather&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Bodysuit Cloth&lt;br /&gt;
|&lt;br /&gt;
|&amp;quot;targetBodysuit&amp;quot;&lt;br /&gt;
|Same thing with this, if the body suit isn&#039;t leather and we&#039;re wearing a bodysuit. We fall back to this one.&lt;br /&gt;
|-&lt;br /&gt;
|Heavy Armor&lt;br /&gt;
|&amp;quot;targetUpperBodyHard&amp;quot;, &amp;quot;targetNoBodysuit&amp;quot;&lt;br /&gt;
|&amp;quot;targetLowerBodyHard&amp;quot;&lt;br /&gt;
|This is the last heavy armor, so we use this as a fallback for hard. Bodysuits only use the bottom layer, so we need to add the targetNoBodysuit condition to prevent upper body from overriding bodysuits.&lt;br /&gt;
|-&lt;br /&gt;
|Bikini Leather&lt;br /&gt;
|&amp;quot;targetUpperBodyBikini&amp;quot;, &amp;quot;targetUpperBodyLeather&amp;quot;, &amp;quot;targetNoBodysuit&amp;quot;&lt;br /&gt;
|&amp;quot;targetWearsThong&amp;quot;, &amp;quot;targetLowerBodyLeather&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Bikini Cloth&lt;br /&gt;
|&amp;quot;targetUpperBodyBikini&amp;quot;, &amp;quot;targetNoBodysuit&amp;quot;&lt;br /&gt;
|&amp;quot;targetWearsThong&amp;quot;&lt;br /&gt;
|Last bikini check, so we fallback for all materials other than leather. Last thong also.&lt;br /&gt;
|-&lt;br /&gt;
|Cloth&lt;br /&gt;
|&amp;quot;targetWearsUpperBody&amp;quot;, &amp;quot;targetNoBodysuit&amp;quot;&lt;br /&gt;
|&amp;quot;targetWearsLowerBody&amp;quot;&lt;br /&gt;
|Last call for clothes. Only check if they&#039;re wearing anything on the relevant slots (and upper body isn&#039;t bodysuit since we have a fallback for that above). This is used as the final fallback if nothing above matches.&lt;br /&gt;
|-&lt;br /&gt;
|Orgasm&lt;br /&gt;
|&amp;quot;targetHasOrgasm&amp;quot;&lt;br /&gt;
|&lt;br /&gt;
|Technically not clothes. But it&#039;s a passive art layer just like the clothing. It will be visible when the player has the orgasm wrapper.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Finally we need to add conditions to the facial expressions. These are ACTIVE art layers and conditions are checked against texts whenever the player is a target of one. You can use sender/target conditions where sender is who caused the text and target is ALWAYS the player the art is attached to. This is pretty straight forward since you can use the existing meta tag conditions&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Layer&lt;br /&gt;
!Conditions&lt;br /&gt;
|-&lt;br /&gt;
|aroused_heavy&lt;br /&gt;
|&amp;quot;metaVeryArousing&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|pain_heavy&lt;br /&gt;
|&amp;quot;metaVeryPainful&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|aroused&lt;br /&gt;
|&amp;quot;metaArousing&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|pain&lt;br /&gt;
|&amp;quot;metaPainful&amp;quot;&lt;br /&gt;
|}&lt;br /&gt;
You can find the full JSON file I used for the jaguar [[JaguarArtFile|here]].&lt;br /&gt;
&lt;br /&gt;
You should now have a JSON file all setup and ready to go! Let&#039;s import it into the FQ editor!&lt;br /&gt;
&lt;br /&gt;
== Importing into the FQ editor ==&lt;br /&gt;
[[File:Player Layers Example.png|thumb|Example of the player editor after importing a JSON file of advanced art layers.]]&lt;br /&gt;
[[File:New Game Jaguar.png|thumb|Jaguar in the new game menu.]]&lt;br /&gt;
[[File:Messed up art layer.png|thumb|Forgot to add the &amp;quot;targetNoBodysuit&amp;quot; to cloth_ub. After fixing it in the player editor, I refresh my game and use game.players[0].replaceIconsByPlayer(&#039;pc_jaguar&#039;)]]&lt;br /&gt;
&lt;br /&gt;
# First off, create a player in the editor. Click the question mark on the player window for help with filling out the fields. But if you&#039;re using advanced art layers, you can skip filling out the art fields for now.&lt;br /&gt;
# Next you need to upload the sliced images you generated. If you have your own webserver, you can just upload them there and make a note of the path. If you upload them to an image service they&#039;ll probably get renamed. In that case you&#039;ll need to edit each of the created layers in the FQ mod tools. This is a bit tedious, but needs to be done. &#039;&#039;Note: You don&#039;t need to specify the full URL anymore! Say I upload 5_orgasm to &amp;quot;&amp;lt;nowiki&amp;gt;https://i.ibb.co/fx8FNvG/5-orgasm.png&amp;lt;/nowiki&amp;gt;&amp;quot;. I then put &amp;lt;nowiki&amp;gt;https://i.ibb.co/&amp;lt;/nowiki&amp;gt; into the &amp;quot;image base path&amp;quot; in the player editor. ALL image URLs used in the player should no longer the first part of the URL. So if I have said base path, then the icon file would just be &amp;quot;fx8FNvG/5-orgasm.png&amp;quot; instead of the full URL.&#039;&#039;&lt;br /&gt;
# Put the file name of the _n file in the image_nude field. In my case &amp;quot;jaguar_n.png&amp;quot;. Unless you follow the note above, you&#039;ll have to paste the full URL.&lt;br /&gt;
# Click the import JSON button and select the JSON file you generated. It then auto populates the layers. If you uploaded the files to an image service, you can click the layer items and edit the URLs. You can also export your JSON file from here, should you break something while testing. Note: If you&#039;re re-importing the JSON file you can check &amp;quot;Replace ALL&amp;quot; and it will delete all the existing layers before adding from the JSON file. &lt;br /&gt;
# If you&#039;re not happy with the order of the layers, you can reorder them from the player editor.&lt;br /&gt;
# Finally go to the Gallery listing and create a new entry.&lt;br /&gt;
# You can change the tags here to select what outfit the character should be wearing in the new game listing.&lt;br /&gt;
&lt;br /&gt;
== Modifying ==&lt;br /&gt;
&lt;br /&gt;
* Large changes such as modifying the layer order or layer names in photoshop will require you to delete the JSON file and restart from the exporting step.&lt;br /&gt;
* Minor changes such as erasing or recoloring a layer without renaming it can be handled by simply exporting it again. But note that you will have to rename the files again in the editor if you used a service that renamed your uploaded files, which may be tedious.&lt;br /&gt;
* When you start playing, the art layers are snapshotted and won&#039;t update automatically when you refresh the game. But there&#039;s a function to copy your layers from a library player. If your player is the first player in the game (as is usual when you start a new game), you can open the console (chrome: ctrl+shift+j) and run: game.players[0].replaceIconsByPlayer(&#039;pc_jaguar&#039;) - It&#039;ll copy the art layers from a player by label. This is especially handy when changing things around in the player editor.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Modding]]&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Wrapper_(Asset)&amp;diff=335</id>
		<title>Wrapper (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Wrapper_(Asset)&amp;diff=335"/>
		<updated>2026-05-30T21:50:51Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A wrapper is a collection of effects to run immediately, ticking, on events, or passively. Wrappers with no duration are called instant effects. Wrappers with an infinite duration are called passives. And wrappers with a limited duration are called buffs or debuffs depending on what they do.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique label for your wrapper. &#039;&#039;&#039;Do not change after finishing creating your wrapper!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Editor Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Adds a short description of your wrapper to help you locate it when searching. This field is only used in the editor, and not shown in game.&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Name of your wrapper. Doesn&#039;t have to be unique. Only needed in buffs/debuffs.&lt;br /&gt;
|-&lt;br /&gt;
|Icon&lt;br /&gt;
|[[Icon]]&lt;br /&gt;
|&lt;br /&gt;
|Icon of your wrapper. Only needed in buffs/debuffs.&lt;br /&gt;
|-&lt;br /&gt;
|Target&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Target of your wrapper. Auto, Caster and AoE are the most commonly used one.&lt;br /&gt;
|-&lt;br /&gt;
|Duration&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|How long the effect should last. Using -1 on a wrapper applied in combat will last until combat ends.&lt;br /&gt;
|-&lt;br /&gt;
|Stacks&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Amount of stacks to add. Leave at 1 for instant effects.&lt;br /&gt;
|-&lt;br /&gt;
|Max Stacks&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Max stacks a player can have. Leave at 1 for instant effects.&lt;br /&gt;
|-&lt;br /&gt;
|Rarity&lt;br /&gt;
|String&lt;br /&gt;
|COMMON&lt;br /&gt;
|Only used for wrappers attached to armor. Used to set the color of the tooltip.&lt;br /&gt;
|-&lt;br /&gt;
|Unique&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When unique, players can only have one wrapper of this type, regardless of caster. Otherwise you may have one instance of each wrapper per caster.&lt;br /&gt;
|-&lt;br /&gt;
|Hidden&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Don&#039;t show the icon on the player.&lt;br /&gt;
|-&lt;br /&gt;
|Trigger Immediate&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Doesn&#039;t affect instant effects. When checked, trigger all valid effects immediately when the wrapper is applied, otherwise it triggers the first time on their turn.&lt;br /&gt;
|-&lt;br /&gt;
|Tick on turn start&lt;br /&gt;
|Boolean&lt;br /&gt;
|True&lt;br /&gt;
|Triggers effects when the player&#039;s turn starts.&lt;br /&gt;
|-&lt;br /&gt;
|Stack time&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When true, duration is added to any existing wrappers, otherwise duration resets to what the duration was set to in the incoming wrapper.&lt;br /&gt;
|-&lt;br /&gt;
|Tick on team turn end&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Triggers effects when the player&#039;s team members have all ended their turns.&lt;br /&gt;
|-&lt;br /&gt;
|Tick on personal turn end&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Triggers effects when the player hits the end turn button (or similar), regardless of if their team members have ended their turn or not.&lt;br /&gt;
|-&lt;br /&gt;
|Global&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When checked, all players will receive this wrapper as a passive when they&#039;re placed in world. Use sparingly!&lt;br /&gt;
|-&lt;br /&gt;
|Use game timer&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|By default, duration is in turns. If you check use game timer, the duration becomes in-game seconds. Mainly used by buffs and debuffs related to items and random events, and talents. When linked to a talent, use game timer is automatically enforced since it puts the icon at the bottom of your portrait.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Describe the wrapper. You can use special vars here such as modifying a value by damage taken/done etc. See [[Action (Asset)|Action]] for a list of valid variables. In addition to the Action variables, there&#039;s a few special ones for wrappers.&lt;br /&gt;
|-&lt;br /&gt;
|Tags&lt;br /&gt;
|[[Tag]]&lt;br /&gt;
|&lt;br /&gt;
|Tags applied to the target. Use wr_ tags.&lt;br /&gt;
|-&lt;br /&gt;
|Effects&lt;br /&gt;
|[[Effect (Asset)|Effect]]&lt;br /&gt;
|interrupt&lt;br /&gt;
|Effects to trigger as long as their conditions match.&lt;br /&gt;
|-&lt;br /&gt;
|Add Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions required to apply this to a target. If you&#039;re using a multi-target target, then each target will be checked before applying it to them individually.&lt;br /&gt;
|-&lt;br /&gt;
|Stay Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions required for this wrapper to stay on its target.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Description vars ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Var&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|%knockdown&lt;br /&gt;
|Can be used if the wrapper has a knockdown effect. Returns stomach or back.&lt;br /&gt;
|-&lt;br /&gt;
|%caster / %S&lt;br /&gt;
|Colored name of caster (sender).&lt;br /&gt;
|-&lt;br /&gt;
|%target / %T&lt;br /&gt;
|Colored name of target.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Description condition lines ==&lt;br /&gt;
A line may start with |AC:&amp;lt;condition&amp;gt;,&amp;lt;condition&amp;gt;...|. If conditions between |AC: and the closing pipe are not met, the whole line is removed. This takes place on wrapper ADD and is never checked after that. Use sparingly. Currently it&#039;s only used for overWhelmingOrgasm because the label is hardcoded.&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Dungeon_Sub_Template_(Asset)&amp;diff=334</id>
		<title>Dungeon Sub Template (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Dungeon_Sub_Template_(Asset)&amp;diff=334"/>
		<updated>2026-05-18T17:43:03Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Used to set conditions for rooms and encounters attached to a procedural dungeon.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Asset Type&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Room/Encounter&lt;br /&gt;
|Any&lt;br /&gt;
|[[Room (Asset)|Room]] / [[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|Asset to add conditions to.&lt;br /&gt;
|-&lt;br /&gt;
|Conditions&lt;br /&gt;
|Any&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions needed to validate to add the room. Often Z position conditions.&lt;br /&gt;
|-&lt;br /&gt;
|Min Z / Max Z&lt;br /&gt;
|Room&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Only available in room templates. Sets the min and max z coordinates where these rooms can be placed. &#039;&#039;&#039;Do not use Z level conditions in Room type subtemplates, it will fail to generate! Use Min Z / Max Z instead!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|No Rot&lt;br /&gt;
|Room&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Prevents the room from being rotated.&lt;br /&gt;
|-&lt;br /&gt;
|Is House&lt;br /&gt;
|Room&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If checked, these rooms are treated as sub-dungeons instead, and added to the pool of flow node dungeons. Note. When this is checked, the conditions check against the parent room, not this one.&lt;br /&gt;
|-&lt;br /&gt;
|Required door tags&lt;br /&gt;
|Room&lt;br /&gt;
|[[Tag]]&amp;lt;nowiki/&amp;gt;s&lt;br /&gt;
|&lt;br /&gt;
|Requires parent room doors to have all these tags. Tags here support regex.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Dungeon_Sub_Template_(Asset)&amp;diff=333</id>
		<title>Dungeon Sub Template (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Dungeon_Sub_Template_(Asset)&amp;diff=333"/>
		<updated>2026-05-18T17:25:36Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Used to set conditions for rooms and encounters attached to a procedural dungeon.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Asset Type&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Room/Encounter&lt;br /&gt;
|Any&lt;br /&gt;
|[[Room (Asset)|Room]] / [[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|Asset to add conditions to.&lt;br /&gt;
|-&lt;br /&gt;
|Conditions&lt;br /&gt;
|Any&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions needed to validate to add the room. Often Z position conditions.&lt;br /&gt;
|-&lt;br /&gt;
|Min Z / Max Z&lt;br /&gt;
|Room&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Only available in room templates. Sets the min and max z coordinates where these rooms can be placed. &#039;&#039;&#039;Do not use Z level conditions in Room type subtemplates, it will fail to generate! Use Min Z / Max Z instead!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|No Rot&lt;br /&gt;
|Room&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Prevents the room from being rotated.&lt;br /&gt;
|-&lt;br /&gt;
|Is House&lt;br /&gt;
|Room&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If checked, these rooms are treated as sub-dungeons instead, and added to the pool of flow node dungeons.&lt;br /&gt;
|-&lt;br /&gt;
|Required door tags&lt;br /&gt;
|Room&lt;br /&gt;
|[[Tag]]&amp;lt;nowiki/&amp;gt;s&lt;br /&gt;
|&lt;br /&gt;
|Requires parent room doors to have all these tags. Tags here support regex.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Connecting_an_LLM_Assistant&amp;diff=332</id>
		<title>Connecting an LLM Assistant</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Connecting_an_LLM_Assistant&amp;diff=332"/>
		<updated>2026-04-17T19:41:29Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The devtools allow you to utilize a local or remote LLM (large language model) that follows the OpenAI API spec. For an example, [https://github.com/oobabooga/textgen Oobabooga text-generation webUI]. Please note that running your own LLM needs a ton of VRAM. I&#039;d strongly suggest using at least an RTX3090 or better. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;In this tutorial, I will assume that you have an LLM up and running already!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Configuring ==&lt;br /&gt;
&lt;br /&gt;
# In the mod tools top menu, click tools and LLM assistant.&lt;br /&gt;
# Enter your AI endpoint. If running locally, it may look like https://127.0.0.1:5000/v1&lt;br /&gt;
# Enter a bearer token (if you configured one, otherwise leave this blank)&lt;br /&gt;
# Min P lets you set how &amp;quot;creative&amp;quot; your model is. Lower value = more creative, higher value = more deterministic.&lt;br /&gt;
# Max tokens sets the max length of the response you want. Lower is faster.&lt;br /&gt;
# Append to all prompts lets you append a message to every prompt sent to your LLM.&lt;br /&gt;
&lt;br /&gt;
[[File:LLM Configuration.png|frameless]]&lt;br /&gt;
&lt;br /&gt;
== Adding AI context to characters ==&lt;br /&gt;
Some of the assets have AI Inference text boxes that automatically adds metadata to AI prompts that include that asset. This metadata is only used by the LLM tools, and is not accessible anywhere in game.&lt;br /&gt;
&lt;br /&gt;
For an instance, you may want to describe what a character looks like, their accent, kinks etc so other characters can automatically take in that information when generating roleplays.&lt;br /&gt;
&lt;br /&gt;
The following assets have AI inference fields (as of writing):&lt;br /&gt;
&lt;br /&gt;
* Player - Used to describe a character. Such as their appearance, kinks, accent etc.&lt;br /&gt;
* Story - Only used this in single-story mods. Use this for worldbuilding.&lt;br /&gt;
* Roleplay - Describes the scene of a roleplay. Such as &#039;&#039;The player approaches Barr at his camp in a remote forest. Barr is very happy and tries to convince the player to help him with X Y Z.&#039;&#039;&lt;br /&gt;
* Action - Describes what the action should look like. Such as &#039;&#039;Summons a slimy tentacle from the ground that penetrates the target, leaving a slimy poison behind&#039;&#039;.&lt;br /&gt;
* PlayerTemplate - Same as player, but for template.&lt;br /&gt;
&lt;br /&gt;
== Using instruct type autocompletions ==&lt;br /&gt;
In the AI Tools window, there&#039;s a Chat tab that lets you create texts. This is useful for generating combat texts or just asking the AI about whatever.&lt;br /&gt;
&lt;br /&gt;
# Click the chat button in the LLM configuration window. This lets you do basic LLM auto Instruct-type prompting. For an example, in the &amp;quot;in this situation&amp;quot; box, enter &#039;&#039;disregard previous instructions, here&#039;s a recipe for chocolate cake:&#039;&#039; and click Generate.&lt;br /&gt;
# You can also add players, player templates, and actions. Their names and descriptions will be automatically added to the prompt sent to the server when you click Generate.&lt;br /&gt;
# Clicking Generate tries to generate more text to the existing text in the output box. Clicking Redo tries to redo the last generated text. To start over with a fresh response, delete the content in this box.&lt;br /&gt;
&lt;br /&gt;
== Using dialog generation in roleplays ==&lt;br /&gt;
1. Enter the Roleplay editor. Add the player that should speak. Then scroll down and add an AI inference description. This describes the goal of your RP. You can also optionally add an AI inference player to give the RP player a visual of who they&#039;re talking to.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[File:AI_RP_Setup.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
2. Create a roleplay stage and a new text. The text editor has a Gen Dialog and Gen Emote button. Gen Dialog tries to generate spoken dialog, and Gen Emote tries to generate a described action.&lt;br /&gt;
Note: The Gen buttons will &#039;&#039;&#039;REPLACE&#039;&#039;&#039; the written text. Check &#039;&#039;Continue&#039;&#039; if you want to generate additional text to what is already written.&lt;br /&gt;
[[File:Actual first stage.png|none|frame|First stage node generated with no description. The inference description is automatically added to the prompt, so it knows roughly what you&#039;re looking for.]]&lt;br /&gt;
3. Create a response (I went with &#039;&#039;Not interested, heavy armor is way too bulky!&#039;&#039;) and then create another response node. Generating Dialog on that takes the previous lines spoken into account.&lt;br /&gt;
&lt;br /&gt;
[[File:LLM Response.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
4. If you&#039;re going for a more particular response, you can add AI Instruction.&lt;br /&gt;
[[File:First stage.png|none|frame|Here I wanted a more particular response. &#039;&#039;So I went with Rönn teases Lo, assuring him that a plate thong would still let him show off his goods&#039;&#039;.]]&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Connecting_an_LLM_Assistant&amp;diff=331</id>
		<title>Connecting an LLM Assistant</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Connecting_an_LLM_Assistant&amp;diff=331"/>
		<updated>2026-04-17T19:40:21Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The devtools allow you to utilize a local or remote LLM (large language model) that follows the OpenAI API spec. For an example, [https://github.com/oobabooga/textgen Oobabooga text-generation webUI]. Please note that running your own LLM needs a ton of VRAM. I&#039;d strongly suggest using at least an RTX3090 or better. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;In this tutorial, I will assume that you have an LLM up and running already!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Configuring ==&lt;br /&gt;
&lt;br /&gt;
# In the mod tools top menu, click tools and LLM assistant.&lt;br /&gt;
# Enter your AI endpoint. If running locally, it may look like https://127.0.0.1:5000/v1&lt;br /&gt;
# Enter a bearer token (if you configured one, otherwise leave this blank)&lt;br /&gt;
# Min P lets you set how &amp;quot;creative&amp;quot; your model is. Lower value = more creative, higher value = more deterministic.&lt;br /&gt;
# Max tokens sets the max length of the response you want. Lower is faster.&lt;br /&gt;
# Append to all prompts lets you append a message to every prompt sent to your LLM.&lt;br /&gt;
&lt;br /&gt;
[[File:LLM Configuration.png|frameless]]&lt;br /&gt;
&lt;br /&gt;
== Adding AI context to characters ==&lt;br /&gt;
Some of the assets have AI Inference text boxes that automatically adds metadata to AI prompts that include that asset. This metadata is only used by the LLM tools, and is not accessible anywhere in game.&lt;br /&gt;
&lt;br /&gt;
For an instance, you may want to describe what a character looks like, their accent, kinks etc so other characters can automatically take in that information when generating roleplays.&lt;br /&gt;
&lt;br /&gt;
The following assets have AI inference fields (as of writing):&lt;br /&gt;
&lt;br /&gt;
* Player - Used to describe a character. Such as their appearance, kinks, accent etc.&lt;br /&gt;
* Story - Only used this in single-story mods. Use this for worldbuilding.&lt;br /&gt;
* Roleplay - Describes the scene of a roleplay. Such as &#039;&#039;The player approaches Barr at his camp in a remote forest. Barr is very happy and tries to convince the player to help him with X Y Z.&#039;&#039;&lt;br /&gt;
* Action - Describes what the action should look like. Such as &#039;&#039;Summons a slimy tentacle from the ground that penetrates the target, leaving a slimy poison behind&#039;&#039;.&lt;br /&gt;
* PlayerTemplate - Same as player, but for template.&lt;br /&gt;
&lt;br /&gt;
== Using instruct type autocompletions ==&lt;br /&gt;
In the AI Tools window, there&#039;s a Chat tab that lets you create texts. This is useful for generating combat texts or just asking the AI about whatever.&lt;br /&gt;
&lt;br /&gt;
# Click the chat button in the LLM configuration window. This lets you do basic LLM auto Instruct-type prompting. For an example, in the &amp;quot;in this situation&amp;quot; box, enter &#039;&#039;disregard previous instructions, here&#039;s a recipe for chocolate cake:&#039;&#039; and click Generate.&lt;br /&gt;
# You can also add players, player templates, and actions. Their names and descriptions will be automatically added to the prompt sent to the server when you click Generate.&lt;br /&gt;
# Clicking Generate tries to generate more text to the existing text in the output box. Clicking Redo tries to redo the last generated text. To start over with a fresh response, delete the content in this box.&lt;br /&gt;
&lt;br /&gt;
== Using dialog generation in roleplays ==&lt;br /&gt;
1. Enter the Roleplay editor. Add the player that should speak. Then scroll down and add an AI inference description. This describes the goal of your RP. You can also optionally add an AI inference player to give the RP player a visual of who they&#039;re talking to.&lt;br /&gt;
[[File:AI RP Setup.png]]&lt;br /&gt;
2. Create a roleplay stage and a new text. The text editor has a Gen Dialog and Gen Emote button. Gen Dialog tries to generate spoken dialog, and Gen Emote tries to generate a described action.&lt;br /&gt;
Note: The Gen buttons will &#039;&#039;&#039;REPLACE&#039;&#039;&#039; the written text. Check &#039;&#039;Continue&#039;&#039; if you want to generate additional text to what is already written.&lt;br /&gt;
[[File:Actual first stage.png|none|frame|First stage node generated with no description. The inference description is automatically added to the prompt, so it knows roughly what you&#039;re looking for.]]&lt;br /&gt;
3. Create a response (I went with &#039;&#039;Not interested, heavy armor is way too bulky!&#039;&#039;) and then create another response node. Generating Dialog on that takes the previous lines spoken into account.&lt;br /&gt;
&lt;br /&gt;
[[File:LLM Response.png]]&lt;br /&gt;
4. If you&#039;re going for a more particular response, you can add AI Instruction.&lt;br /&gt;
[[File:First stage.png|none|frame|Here I wanted a more particular response. &#039;&#039;So I went with Rönn teases Lo, assuring him that a plate thong would still let him show off his goods&#039;&#039;.]]&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=File:Actual_first_stage.png&amp;diff=330</id>
		<title>File:Actual first stage.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=File:Actual_first_stage.png&amp;diff=330"/>
		<updated>2026-04-17T19:39:01Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Generated text&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=File:LLM_Response.png&amp;diff=329</id>
		<title>File:LLM Response.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=File:LLM_Response.png&amp;diff=329"/>
		<updated>2026-04-17T19:36:08Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Response to reply option with no instruction.&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=File:First_stage.png&amp;diff=328</id>
		<title>File:First stage.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=File:First_stage.png&amp;diff=328"/>
		<updated>2026-04-17T19:33:34Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;AI generated an introduction&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=File:AI_RP_Setup.png&amp;diff=327</id>
		<title>File:AI RP Setup.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=File:AI_RP_Setup.png&amp;diff=327"/>
		<updated>2026-04-17T19:31:23Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;AI RP Setup&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Connecting_an_LLM_Assistant&amp;diff=326</id>
		<title>Connecting an LLM Assistant</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Connecting_an_LLM_Assistant&amp;diff=326"/>
		<updated>2026-04-17T19:29:12Z</updated>

		<summary type="html">&lt;p&gt;JasX: Created page with &amp;quot;The devtools allow you to utilize a local or remote LLM (large language model) that follows the OpenAI API spec. For an example, [https://github.com/oobabooga/textgen Oobabooga text-generation webUI]. Please note that running your own LLM needs a ton of VRAM. I&amp;#039;d strongly suggest using at least an RTX3090 or better.   &amp;#039;&amp;#039;&amp;#039;In this tutorial, I will assume that you have an LLM up and running already!&amp;#039;&amp;#039;&amp;#039;  == Configuring ==  # In the mod tools top menu, click tools and LLM ass...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The devtools allow you to utilize a local or remote LLM (large language model) that follows the OpenAI API spec. For an example, [https://github.com/oobabooga/textgen Oobabooga text-generation webUI]. Please note that running your own LLM needs a ton of VRAM. I&#039;d strongly suggest using at least an RTX3090 or better. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;In this tutorial, I will assume that you have an LLM up and running already!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
== Configuring ==&lt;br /&gt;
&lt;br /&gt;
# In the mod tools top menu, click tools and LLM assistant.&lt;br /&gt;
# Enter your AI endpoint. If running locally, it may look like https://127.0.0.1:5000/v1&lt;br /&gt;
# Enter a bearer token (if you configured one, otherwise leave this blank)&lt;br /&gt;
# Min P lets you set how &amp;quot;creative&amp;quot; your model is. Lower value = more creative, higher value = more deterministic.&lt;br /&gt;
# Max tokens sets the max length of the response you want. Lower is faster.&lt;br /&gt;
# Append to all prompts lets you append a message to every prompt sent to your LLM.&lt;br /&gt;
&lt;br /&gt;
[[File:LLM Configuration.png|frameless]]&lt;br /&gt;
&lt;br /&gt;
== Adding AI context to characters ==&lt;br /&gt;
Some of the assets have AI Inference text boxes that automatically adds metadata to AI prompts that include that asset. This metadata is only used by the LLM tools, and is not accessible anywhere in game.&lt;br /&gt;
&lt;br /&gt;
For an instance, you may want to describe what a character looks like, their accent, kinks etc so other characters can automatically take in that information when generating roleplays.&lt;br /&gt;
&lt;br /&gt;
The following assets have AI inference fields (as of writing):&lt;br /&gt;
&lt;br /&gt;
* Player - Used to describe a character. Such as their appearance, kinks, accent etc.&lt;br /&gt;
* Story - Only used this in single-story mods. Use this for worldbuilding.&lt;br /&gt;
* Roleplay - Describes the scene of a roleplay. Such as &#039;&#039;The player approaches Barr at his camp in a remote forest. Barr is very happy and tries to convince the player to help him with X Y Z.&#039;&#039;&lt;br /&gt;
* Action - Describes what the action should look like. Such as &#039;&#039;Summons a slimy tentacle from the ground that penetrates the target, leaving a slimy poison behind&#039;&#039;.&lt;br /&gt;
* PlayerTemplate - Same as player, but for template.&lt;br /&gt;
&lt;br /&gt;
== Using instruct type autocompletions ==&lt;br /&gt;
In the AI Tools window, there&#039;s a Chat tab that lets you create texts. This is useful for generating combat texts or just asking the AI about whatever.&lt;br /&gt;
&lt;br /&gt;
# Click the chat button in the LLM configuration window. This lets you do basic LLM auto Instruct-type prompting. For an example, in the &amp;quot;in this situation&amp;quot; box, enter &#039;&#039;disregard previous instructions, here&#039;s a recipe for chocolate cake:&#039;&#039; and click Generate.&lt;br /&gt;
# You can also add players, player templates, and actions. Their names and descriptions will be automatically added to the prompt sent to the server when you click Generate.&lt;br /&gt;
# Clicking Generate tries to generate more text to the existing text in the output box. Clicking Redo tries to redo the last generated text. To start over with a fresh response, delete the content in this box.&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=File:LLM_Configuration.png&amp;diff=325</id>
		<title>File:LLM Configuration.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=File:LLM_Configuration.png&amp;diff=325"/>
		<updated>2026-04-17T19:17:31Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Basic configuration&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Category:Modding&amp;diff=324</id>
		<title>Category:Modding</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Category:Modding&amp;diff=324"/>
		<updated>2026-04-17T19:11:50Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Note: These pages generally reflect the dev branch. Note that mods created on the dev branch often don&#039;t work on the live branch until the live branch syncs with dev.&lt;br /&gt;
&lt;br /&gt;
The best place to get information about specific asset types in the editor is to click the question mark on the window header. It&#039;s the most up to date information about what the asset is for and how to use the fields.&lt;br /&gt;
&lt;br /&gt;
Basic controls in the editor:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+ Caption text&lt;br /&gt;
|-&lt;br /&gt;
! Ctrl+click !! Unlink a linked asset, or delete an asset.&lt;br /&gt;
|-&lt;br /&gt;
! Alt+click !! Clone an asset.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Suggested tutorials:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| [[Creating a Mod|Creating a mod]]|| How to create a new mod, and devtool basics. &#039;&#039;&#039;Start here!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| [[Creating a Text]]|| Teaches you how to add a combat text for an existing action. &#039;&#039;&#039;Good for beginners!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| [[Creating a Monster]]|| Goes through the process of making a monster, abilities for it, and attaching it to an encounter.&lt;br /&gt;
|-&lt;br /&gt;
| [[Creating a Dungeon]]|| How to create a dungeon and link it to the main mod.&lt;br /&gt;
|-&lt;br /&gt;
| [[Creating a Service NPC]]|| How to create an NPC that you can talk to, or offer services, and adding it to the world.&lt;br /&gt;
|-&lt;br /&gt;
| [[Creating an Action]]|| Creating an action and linking it to a player or NPC.&lt;br /&gt;
|-&lt;br /&gt;
| [[Creating an Armor Type]]|| Creating an armor/material that can be used in randomly generated equipment.&lt;br /&gt;
|-&lt;br /&gt;
| [[Creating a Roleplay]]|| How to create a dialog with an NPC.&lt;br /&gt;
|-&lt;br /&gt;
| [[Creating an Exploration Event]]|| How to create a random event that players may stumble upon in a dungeon (mainly exploration dungeons).&lt;br /&gt;
|-&lt;br /&gt;
| [[Creating an Enchant]]|| How to create an enchant and link it to the pool of random enchants available to generated equipment.&lt;br /&gt;
|-&lt;br /&gt;
| [[Creating an Exploration Dungeon]]|| How to create a procedurally generated dungeon template, and link it to the world.&lt;br /&gt;
|-&lt;br /&gt;
| [[Creating Advanced Art Layers]]|| How to create conditional art layers.&lt;br /&gt;
|-&lt;br /&gt;
| [[Sharing Your Mod]]|| Share your mod with others!&lt;br /&gt;
|-&lt;br /&gt;
|[[Connecting an LLM Assistant]]&lt;br /&gt;
|How to use a local AI model to add additional capabilities to the dev tools.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Common pitfalls ==&lt;br /&gt;
&lt;br /&gt;
* Dungeon vars and RP vars may not have labels that end with _Set&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=323</id>
		<title>Dungeon Flow Node (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=323"/>
		<updated>2026-03-23T22:37:17Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
A flow node is used to create a general layout for an advanced procedural dungeon. Each node can have multiple condition groups, but only one is ever picked. These condition groups decide which room templates should be available in that group. Such as cave tiles that also support forest tiles etc. These tiles must be specified in Room Templates, and the conditions of the room templates still apply.&lt;br /&gt;
&lt;br /&gt;
===== Caveats: =====&lt;br /&gt;
&lt;br /&gt;
* The first flow node used in a dungeon template MUST be able to start at coordinates 0,0,0. Because that&#039;s where the entrance room is placed.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Optional, just used in the editor to remind you of the purpose of the flow node, such as &amp;quot;forest&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
|Optional&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When checked, this flow node may be ignored at random.&lt;br /&gt;
|-&lt;br /&gt;
|Friendly&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|You can use the flowNodeFriendly condition type in the various conditions fields in your dungeon template.&lt;br /&gt;
|-&lt;br /&gt;
|Offer Quest&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Can offer a quest in any of these rooms. You must setup quests in the [[Procedural Dungeon (Asset)|DungeonTemplate]] to use this.&lt;br /&gt;
|-&lt;br /&gt;
|Min Rooms&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Minimum nr of rooms to generate. A minimum of 1 is enforced.&lt;br /&gt;
|-&lt;br /&gt;
|Max Rooms&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Maximum nr of rooms to generate. Anything below Min Rooms is clamped at Min Rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Shape&lt;br /&gt;
|Constant&lt;br /&gt;
|Random&lt;br /&gt;
|Sets the dungeon shape. Random will place rooms at random. Linear will generate all rooms in a sequence. SemiLinear will generate a few side rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Min Z&lt;br /&gt;
|Int&lt;br /&gt;
| -3&lt;br /&gt;
|Sets how far below the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|Max Z&lt;br /&gt;
|Int&lt;br /&gt;
|3&lt;br /&gt;
|Sets how far above the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|No Mimics&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Disables mimics.&lt;br /&gt;
|-&lt;br /&gt;
|Random Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Enables random encounters (exploration events).&lt;br /&gt;
|-&lt;br /&gt;
|Levers&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Place levers.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Items&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has items to collect, you can place them in this room&#039;s cells. Recommended to only not do it on a flownode before the one that offers the quest.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has specific encounters, you can place them here.&lt;br /&gt;
|-&lt;br /&gt;
|Max Treasures&lt;br /&gt;
|Boolean&lt;br /&gt;
| -1&lt;br /&gt;
|Sets how many treasures can be placed in this flowNode. Note that this value will never override the grand total set in the [[Procedural Dungeon (Asset)|DungeonTemplate]].&lt;br /&gt;
|-&lt;br /&gt;
|Condition Groups&lt;br /&gt;
|[[Dungeon Sub Template (Asset)|Dungeon Sub Template]]&lt;br /&gt;
|&lt;br /&gt;
|When generated, these are shuffled, and only one of these are picked. At least one room must pass conditions and be valid to be used with the dungeon template quest. If none are supplied, a condition-free group is used.&lt;br /&gt;
|-&lt;br /&gt;
|Vaible Templates&lt;br /&gt;
|[[Dungeon (Asset)|Dungeon]]&lt;br /&gt;
|&lt;br /&gt;
|Allows the generator to link template dungeons in this node.&lt;br /&gt;
|-&lt;br /&gt;
|Entry Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions that need to be met for the door linking to this flow node to be treated as &amp;quot;unlocked&amp;quot;. Do not use this on the first flowNode of your dungeon. To prevent the player from entering a quest objective area before accepting the quest, consider adding a questAccepted condition that isn&#039;t pointing to a quest. &lt;br /&gt;
|-&lt;br /&gt;
|Force Start Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the first room will get these encounters as its encounters.&lt;br /&gt;
|-&lt;br /&gt;
|Shuffle Start Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When true, shuffles the order of encounters.&lt;br /&gt;
|-&lt;br /&gt;
|Force End Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the last room generated will have its encounters set to this one. And one is picked at random.&lt;br /&gt;
|-&lt;br /&gt;
|Shuffle End Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When true, shuffles the order of encounters.&lt;br /&gt;
|-&lt;br /&gt;
|Force End Chest GameAction&lt;br /&gt;
|[[Game Action (Asset)|GameAction]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the dungeon generator will try to force the end room with a chest placeholder, and add one of the game actions as the chest game action. Useful for boss loot etc.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=322</id>
		<title>Dungeon Flow Node (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=322"/>
		<updated>2026-03-23T22:36:12Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
A flow node is used to create a general layout for an advanced procedural dungeon. Each node can have multiple condition groups, but only one is ever picked. These condition groups decide which room templates should be available in that group. Such as cave tiles that also support forest tiles etc. These tiles must be specified in Room Templates, and the conditions of the room templates still apply.&lt;br /&gt;
&lt;br /&gt;
===== Caveats: =====&lt;br /&gt;
&lt;br /&gt;
* The first flow node used in a dungeon template MUST be able to start at coordinates 0,0,0. Because that&#039;s where the entrance room is placed.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Optional, just used in the editor to remind you of the purpose of the flow node, such as &amp;quot;forest&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
|Optional&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When checked, this flow node may be ignored at random.&lt;br /&gt;
|-&lt;br /&gt;
|Friendly&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|You can use the flowNodeFriendly condition type in the various conditions fields in your dungeon template.&lt;br /&gt;
|-&lt;br /&gt;
|Offer Quest&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Can offer a quest in any of these rooms. You must setup quests in the [[Procedural Dungeon (Asset)|DungeonTemplate]] to use this.&lt;br /&gt;
|-&lt;br /&gt;
|Min Rooms&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Minimum nr of rooms to generate. A minimum of 1 is enforced.&lt;br /&gt;
|-&lt;br /&gt;
|Max Rooms&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Maximum nr of rooms to generate. Anything below Min Rooms is clamped at Min Rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Shape&lt;br /&gt;
|Constant&lt;br /&gt;
|Random&lt;br /&gt;
|Sets the dungeon shape. Random will place rooms at random. Linear will generate all rooms in a sequence. SemiLinear will generate a few side rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Min Z&lt;br /&gt;
|Int&lt;br /&gt;
| -3&lt;br /&gt;
|Sets how far below the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|Max Z&lt;br /&gt;
|Int&lt;br /&gt;
|3&lt;br /&gt;
|Sets how far above the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|No Mimics&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Disables mimics.&lt;br /&gt;
|-&lt;br /&gt;
|Random Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Enables random encounters (exploration events).&lt;br /&gt;
|-&lt;br /&gt;
|Levers&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Place levers.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Items&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has items to collect, you can place them in this room&#039;s cells. Recommended to only not do it on a flownode before the one that offers the quest.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has specific encounters, you can place them here.&lt;br /&gt;
|-&lt;br /&gt;
|Max Treasures&lt;br /&gt;
|Boolean&lt;br /&gt;
| -1&lt;br /&gt;
|Sets how many treasures can be placed in this flowNode. Note that this value will never override the grand total set in the [[Procedural Dungeon (Asset)|DungeonTemplate]].&lt;br /&gt;
|-&lt;br /&gt;
|Condition Groups&lt;br /&gt;
|[[Dungeon Sub Template (Asset)|Dungeon Sub Template]]&lt;br /&gt;
|&lt;br /&gt;
|When generated, these are shuffled, and only one of these are picked. At least one room must pass conditions and be valid to be used with the dungeon template quest. If none are supplied, a condition-free group is used.&lt;br /&gt;
|-&lt;br /&gt;
|Vaible Templates&lt;br /&gt;
|[[Dungeon (Asset)|Dungeon]]&lt;br /&gt;
|&lt;br /&gt;
|Allows the generator to link template dungeons in this node.&lt;br /&gt;
|-&lt;br /&gt;
|Entry Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions that need to be met for the door linking to this flow node to be treated as &amp;quot;unlocked&amp;quot;. Do not use this on the first flowNode of your dungeon. To prevent the player from entering a quest objective area before accepting the quest, consider adding a questAccepted condition that isn&#039;t pointing to a quest. &lt;br /&gt;
|-&lt;br /&gt;
|Force Start Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the first room will get these encounters as its encounters.&lt;br /&gt;
|-&lt;br /&gt;
|Shuffle Start Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When true, shuffles the order of encounters.&lt;br /&gt;
|-&lt;br /&gt;
|Force End Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the last room generated will have its encounters set to this one. And one is picked at random.&lt;br /&gt;
|-&lt;br /&gt;
|Shuffle End Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When true, shuffles the order of encounters.&lt;br /&gt;
|-&lt;br /&gt;
|Force End Chest GameAction&lt;br /&gt;
|[[Game Action (Asset)|GameAction]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the dungeon generator will try to force the end room with a chest placeholder, and add one of the game actions as the chest game action. Useful for boss loot etc. Note: This is ignored unless you also set Force End Encounter.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=321</id>
		<title>Dungeon Flow Node (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=321"/>
		<updated>2026-03-23T22:34:48Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
A flow node is used to create a general layout for an advanced procedural dungeon. Each node can have multiple condition groups, but only one is ever picked. These condition groups decide which room templates should be available in that group. Such as cave tiles that also support forest tiles etc. These tiles must be specified in Room Templates, and the conditions of the room templates still apply.&lt;br /&gt;
&lt;br /&gt;
===== Caveats: =====&lt;br /&gt;
&lt;br /&gt;
* The first flow node used in a dungeon template MUST be able to start at coordinates 0,0,0. Because that&#039;s where the entrance room is placed.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Optional, just used in the editor to remind you of the purpose of the flow node, such as &amp;quot;forest&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
|Optional&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When checked, this flow node may be ignored at random.&lt;br /&gt;
|-&lt;br /&gt;
|Friendly&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|You can use the flowNodeFriendly condition type in the various conditions fields in your dungeon template.&lt;br /&gt;
|-&lt;br /&gt;
|Offer Quest&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Can offer a quest in any of these rooms. You must setup quests in the [[Procedural Dungeon (Asset)|DungeonTemplate]] to use this.&lt;br /&gt;
|-&lt;br /&gt;
|Min Rooms&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Minimum nr of rooms to generate. A minimum of 1 is enforced.&lt;br /&gt;
|-&lt;br /&gt;
|Max Rooms&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Maximum nr of rooms to generate. Anything below Min Rooms is clamped at Min Rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Shape&lt;br /&gt;
|Constant&lt;br /&gt;
|Random&lt;br /&gt;
|Sets the dungeon shape. Random will place rooms at random. Linear will generate all rooms in a sequence. SemiLinear will generate a few side rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Min Z&lt;br /&gt;
|Int&lt;br /&gt;
| -3&lt;br /&gt;
|Sets how far below the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|Max Z&lt;br /&gt;
|Int&lt;br /&gt;
|3&lt;br /&gt;
|Sets how far above the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|No Mimics&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Disables mimics.&lt;br /&gt;
|-&lt;br /&gt;
|Random Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Enables random encounters (exploration events).&lt;br /&gt;
|-&lt;br /&gt;
|Levers&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Place levers.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Items&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has items to collect, you can place them in this room&#039;s cells. Recommended to only not do it on a flownode before the one that offers the quest.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has specific encounters, you can place them here.&lt;br /&gt;
|-&lt;br /&gt;
|Max Treasures&lt;br /&gt;
|Boolean&lt;br /&gt;
| -1&lt;br /&gt;
|Sets how many treasures can be placed in this flowNode. Note that this value will never override the grand total set in the [[Procedural Dungeon (Asset)|DungeonTemplate]].&lt;br /&gt;
|-&lt;br /&gt;
|Condition Groups&lt;br /&gt;
|[[Dungeon Sub Template (Asset)|Dungeon Sub Template]]&lt;br /&gt;
|&lt;br /&gt;
|When generated, these are shuffled, and only one of these are picked. At least one room must pass conditions and be valid to be used with the dungeon template quest. If none are supplied, a condition-free group is used.&lt;br /&gt;
|-&lt;br /&gt;
|Vaible Templates&lt;br /&gt;
|[[Dungeon (Asset)|Dungeon]]&lt;br /&gt;
|&lt;br /&gt;
|Allows the generator to link template dungeons in this node.&lt;br /&gt;
|-&lt;br /&gt;
|Entry Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions that need to be met for the door linking to this flow node to be treated as &amp;quot;unlocked&amp;quot;. Do not use this on the first flowNode of your dungeon. To prevent the player from entering a quest objective area before accepting the quest, consider adding a questAccepted condition that isn&#039;t pointing to a quest. &lt;br /&gt;
|-&lt;br /&gt;
|Force Start Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the first room will get these encounters as its encounters.&lt;br /&gt;
|-&lt;br /&gt;
|Shuffle Start Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When true, shuffles the order of encounters.&lt;br /&gt;
|-&lt;br /&gt;
|Force End Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the last room generated will have its encounters set to this one. And one is picked at random.&lt;br /&gt;
|-&lt;br /&gt;
|Shuffle End Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When true, shuffles the order of encounters.&lt;br /&gt;
|-&lt;br /&gt;
|Force End Chest GameAction&lt;br /&gt;
|[[Game Action (Asset)|GameAction]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the dungeon generator will try to force the end room with a chest placeholder, and add one of the game actions as the chest game action. Useful for boss loot etc.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=320</id>
		<title>Dungeon Flow Node (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=320"/>
		<updated>2026-03-23T13:47:45Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
A flow node is used to create a general layout for an advanced procedural dungeon. Each node can have multiple condition groups, but only one is ever picked. These condition groups decide which room templates should be available in that group. Such as cave tiles that also support forest tiles etc. These tiles must be specified in Room Templates, and the conditions of the room templates still apply.&lt;br /&gt;
&lt;br /&gt;
===== Caveats: =====&lt;br /&gt;
&lt;br /&gt;
* The first flow node used in a dungeon template MUST be able to start at coordinates 0,0,0. Because that&#039;s where the entrance room is placed.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Optional, just used in the editor to remind you of the purpose of the flow node, such as &amp;quot;forest&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
|Optional&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When checked, this flow node may be ignored at random.&lt;br /&gt;
|-&lt;br /&gt;
|Friendly&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|You can use the flowNodeFriendly condition type in the various conditions fields in your dungeon template.&lt;br /&gt;
|-&lt;br /&gt;
|Offer Quest&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Can offer a quest in any of these rooms. You must setup quests in the [[Procedural Dungeon (Asset)|DungeonTemplate]] to use this.&lt;br /&gt;
|-&lt;br /&gt;
|Min Rooms&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Minimum nr of rooms to generate. A minimum of 1 is enforced.&lt;br /&gt;
|-&lt;br /&gt;
|Max Rooms&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Maximum nr of rooms to generate. Anything below Min Rooms is clamped at Min Rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Shape&lt;br /&gt;
|Constant&lt;br /&gt;
|Random&lt;br /&gt;
|Sets the dungeon shape. Random will place rooms at random. Linear will generate all rooms in a sequence. SemiLinear will generate a few side rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Min Z&lt;br /&gt;
|Int&lt;br /&gt;
| -3&lt;br /&gt;
|Sets how far below the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|Max Z&lt;br /&gt;
|Int&lt;br /&gt;
|3&lt;br /&gt;
|Sets how far above the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|No Mimics&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Disables mimics.&lt;br /&gt;
|-&lt;br /&gt;
|Random Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Enables random encounters (exploration events).&lt;br /&gt;
|-&lt;br /&gt;
|Levers&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Place levers.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Items&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has items to collect, you can place them in this room&#039;s cells. Recommended to only not do it on a flownode before the one that offers the quest.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has specific encounters, you can place them here.&lt;br /&gt;
|-&lt;br /&gt;
|Max Treasures&lt;br /&gt;
|Boolean&lt;br /&gt;
| -1&lt;br /&gt;
|Sets how many treasures can be placed in this flowNode. Note that this value will never override the grand total set in the [[Procedural Dungeon (Asset)|DungeonTemplate]].&lt;br /&gt;
|-&lt;br /&gt;
|Condition Groups&lt;br /&gt;
|[[Dungeon Sub Template (Asset)|Dungeon Sub Template]]&lt;br /&gt;
|&lt;br /&gt;
|When generated, these are shuffled, and only one of these are picked. At least one room must pass conditions and be valid to be used with the dungeon template quest. If none are supplied, a condition-free group is used.&lt;br /&gt;
|-&lt;br /&gt;
|Vaible Templates&lt;br /&gt;
|[[Dungeon (Asset)|Dungeon]]&lt;br /&gt;
|&lt;br /&gt;
|Allows the generator to link template dungeons in this node.&lt;br /&gt;
|-&lt;br /&gt;
|Entry Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions that need to be met for the door linking to this flow node to be treated as &amp;quot;unlocked&amp;quot;. Do not use this on the first flowNode of your dungeon. To prevent the player from entering a quest objective area before accepting the quest, consider adding a questAccepted condition that isn&#039;t pointing to a quest. &lt;br /&gt;
|-&lt;br /&gt;
|Force Start Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the first room will get these encounters as its encounters, and one is picked at random.&lt;br /&gt;
|-&lt;br /&gt;
|Force End Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the last room generated will have its encounters set to this one. And one is picked at random.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Roleplay_(Asset)&amp;diff=319</id>
		<title>Roleplay (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Roleplay_(Asset)&amp;diff=319"/>
		<updated>2025-11-18T12:34:53Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Roleplay is the dialog popup with multiple options you may encounter. In order to trigger a roleplay, you need to tie it to a [[Game Action (Asset)|game action]], generally a unique one inside of an [[Encounter (Asset)|encounter]].&lt;br /&gt;
&lt;br /&gt;
This is the asset reference. If you want a tutorial, you can check out [[Creating a Roleplay]].&lt;br /&gt;
&lt;br /&gt;
=== Definitely Use Outliner Mode ===&lt;br /&gt;
Click the Outliner button to enter outliner mode. This is a vastly superior mode of designing your roleplays. Right click to add a node, and then simply drag and drop to connect them. You can also right click a node or path to delete it. Some features are only availabe in the outliner.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique label for your roleplay. &#039;&#039;&#039;Do not edit after setting up your roleplay.&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A description that&#039;s only visible in the editor. Helps you organize roleplays.&lt;br /&gt;
|-&lt;br /&gt;
|Portrait&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to a portrait, or an [[Icon]]. Portrait can also be left empty to auto fetch from player. And it can be overridden in [[Roleplay Stage (Asset)|roleplay stages]].&lt;br /&gt;
|-&lt;br /&gt;
|Persistent&lt;br /&gt;
|Boolean&lt;br /&gt;
|True&lt;br /&gt;
|A persistent roleplay maintains its state. Otherwise the roleplay resets when you close it.&lt;br /&gt;
|-&lt;br /&gt;
|Once&lt;br /&gt;
|Boolean&lt;br /&gt;
|True&lt;br /&gt;
|Makes the roleplay only happen once. When closed, the roleplay cannot be reopened.&lt;br /&gt;
|-&lt;br /&gt;
|Auto Play&lt;br /&gt;
|Boolean&lt;br /&gt;
|True&lt;br /&gt;
|Automatically plays the roleplay when encountered.&lt;br /&gt;
|-&lt;br /&gt;
|Auto Play Once&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Requires auto play. Makes the roleplay only auto play once.&lt;br /&gt;
|-&lt;br /&gt;
|No Attach&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Allows the RP to auto play, but no speech interaction is added to the player, preventing them from picking it up after exiting.&lt;br /&gt;
|-&lt;br /&gt;
|rpVars Persistent&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Makes roleplay variables persistent. Otherwise they reset when the roleplay is closed. Consider using dungeon vars if the outcome of a roleplay should affect something in the game outside of the roleplay.&lt;br /&gt;
|-&lt;br /&gt;
|Music&lt;br /&gt;
|[[Music (Asset)|Music]]&lt;br /&gt;
|&lt;br /&gt;
|If set, music is overridden with this track while the roleplay is open.&lt;br /&gt;
|-&lt;br /&gt;
|Player&lt;br /&gt;
|[[Player (Asset)|Player]]&lt;br /&gt;
|&lt;br /&gt;
|When set, this player is used for the portrait and speech bubbles.&lt;br /&gt;
|-&lt;br /&gt;
|Stages&lt;br /&gt;
|[[Roleplay Stage (Asset)|Roleplay Stage]]&lt;br /&gt;
|&lt;br /&gt;
|Stages attached to this roleplay. I strongly suggest using the outliner instead of manually creating stages.&lt;br /&gt;
|-&lt;br /&gt;
|Outliner&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Opens the RP outliner.&lt;br /&gt;
|-&lt;br /&gt;
|Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions needed to start the roleplay.&lt;br /&gt;
|-&lt;br /&gt;
|Player Conditoins&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|By default, roleplays will use the player who triggered it as the roleplay player. Roleplay players can be accessed by %P, %P2 etc and the roleplay players can be modified inside of an RP. You can alternatively add player conditions, then all players who match these conditions will be added as RP players (Including NPCs, so consider using targetOnPlayerTeam). The order of this list is random.&lt;br /&gt;
|-&lt;br /&gt;
|NPC Gen Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|When set: Used in the procedural generator when linking a roleplay to an NPC. You can set it to a condition that always validates to true if you want to link it to an NPC without using any proper conditions.&lt;br /&gt;
|-&lt;br /&gt;
|Min Players&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Minimum players that need to pass player conditions in order to start the RP. Setting to -1 means all players on the player team must match.&lt;br /&gt;
|-&lt;br /&gt;
|Max Players&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Maximum players that should be stored as RP targets. The roleplay can still start if exceeded, but the RP Players will be capped to this amount.&lt;br /&gt;
|-&lt;br /&gt;
|Game Actions&lt;br /&gt;
|[[Game Action (Asset)|Game Action]]&lt;br /&gt;
|&lt;br /&gt;
|Game actions to trigger when the RP is started.&lt;br /&gt;
|-&lt;br /&gt;
|Close Actions&lt;br /&gt;
|[[Game Action (Asset)|Game Action]]&lt;br /&gt;
|&lt;br /&gt;
|Game actions to trigger when the RP ends.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Using the outliner ==&lt;br /&gt;
&lt;br /&gt;
* You can click and drag the header of all assets to move it.&lt;br /&gt;
* Clicking the middle of an asset will open an editor window for that asset.&lt;br /&gt;
* Right click the background to add a new asset. You can also use Pan To Root to go back to the root roleplay node.&lt;br /&gt;
* Be careful with purge positions as it resets all asset positions back to default.&lt;br /&gt;
* Drag the little round connectors from the right edge of one asset to the left edge of another. The colors must match.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Outliner Assets&lt;br /&gt;
!Asset&lt;br /&gt;
!Connections&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Roleplay&lt;br /&gt;
|[[Roleplay Stage (Asset)|Stage]]&lt;br /&gt;
|This is the root roleplay node. All roleplays have exactly one.&lt;br /&gt;
|-&lt;br /&gt;
|Stage&lt;br /&gt;
|[[Roleplay Option (Asset)|Reply]], [[Roleplay Stage (Asset)|Stage]]&lt;br /&gt;
|Stage is a text that the NPC will say (or may be silent). When connected directly to another stage, a [Continue] reply is automatically added pointing to said stage. If no reply or stage is connected, a [Leave] option is automatically added.&lt;br /&gt;
|-&lt;br /&gt;
|Reply&lt;br /&gt;
|[[Roleplay Goto (Asset)|Goto]], [[Roleplay Stage (Asset)|Stage]]&lt;br /&gt;
|A reply is an option that the player can click. Goto connections are checked first against their conditions. A stage connection is always last.&lt;br /&gt;
|-&lt;br /&gt;
|Goto&lt;br /&gt;
|[[Roleplay Stage (Asset)|Stage]]&lt;br /&gt;
|A goto option is an invisible flow control block. You use them to take the conversation to a different stage based on the goto conditoins.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Action_(Asset)&amp;diff=318</id>
		<title>Action (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Action_(Asset)&amp;diff=318"/>
		<updated>2025-10-18T22:20:41Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is the Action asset reference. If you want a tutorial, check out [[Creating an Action]].&lt;br /&gt;
&lt;br /&gt;
Spells and attacks are all actions. To link an action to a player, trainer, or NPC template, use the [[Player Action (Asset)|Player Action]] asset type.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Set to a unique label for your action. &#039;&#039;&#039;Do not edit after setting up your action!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Name your action, doesn&#039;t have to be unique.&lt;br /&gt;
|-&lt;br /&gt;
|Icon&lt;br /&gt;
|[[Icon]]&lt;br /&gt;
|&lt;br /&gt;
|Icon for your action.&lt;br /&gt;
|-&lt;br /&gt;
|M.Off/Def/Uti&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Momentum cost.&lt;br /&gt;
|-&lt;br /&gt;
|Cooldown&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Cooldown in turns.&lt;br /&gt;
|-&lt;br /&gt;
|Init Cooldown&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Start the battle with the ability on cooldown for this amount of turns. Usually used for boss mechanics.&lt;br /&gt;
|-&lt;br /&gt;
|Hit Chance&lt;br /&gt;
|Int&lt;br /&gt;
|90&lt;br /&gt;
|Hit chance in percent. Use 9001 for guaranteed hit. Not needed for beneficial actions.&lt;br /&gt;
|-&lt;br /&gt;
|Override disable lv&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Overrides disable effects if above the disable effect&#039;s priority.&lt;br /&gt;
|-&lt;br /&gt;
|Cast time&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Nr of turns needed to finish this action.&lt;br /&gt;
|-&lt;br /&gt;
|Allow while charging&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When checked, this action may be used while the player is readying an action with a cast time.&lt;br /&gt;
|-&lt;br /&gt;
|Taunt Override Charge&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If charged, taunt will override the cast target.&lt;br /&gt;
|-&lt;br /&gt;
|Ripostable&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Allows the action to be riposted on miss. If the action missed, the action is run in reverse against the caster with the target as the new caster.&lt;br /&gt;
|-&lt;br /&gt;
|Group&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you group spells in the action bar. Mainly used for potions.&lt;br /&gt;
|-&lt;br /&gt;
|Charges&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Max charges of the action that can be used. Each cooldown period adds 1 charge.&lt;br /&gt;
|-&lt;br /&gt;
|Start Charges&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Set to -1 to start combat with max charges. Otherwise you can edit the nr of charges you start with.&lt;br /&gt;
|-&lt;br /&gt;
|Min Targets&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Minimum targets to use this action.&lt;br /&gt;
|-&lt;br /&gt;
|Max Targets&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Maximum targets that you can use this action on.&lt;br /&gt;
|-&lt;br /&gt;
|Target&lt;br /&gt;
|String&lt;br /&gt;
|target&lt;br /&gt;
|Overrides the target of the action.&lt;br /&gt;
|-&lt;br /&gt;
|Detrimental&lt;br /&gt;
|String&lt;br /&gt;
|yes&lt;br /&gt;
|Sets if the action is detrimental. Team makes it detrimental to players not on your team, and beneficial to players on your team.&lt;br /&gt;
|-&lt;br /&gt;
|Allow detrimental self cast&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When true, it lets you use the action on yourself even if it&#039;s detrimental.&lt;br /&gt;
|-&lt;br /&gt;
|Type&lt;br /&gt;
|String&lt;br /&gt;
|physical&lt;br /&gt;
|Damage type&lt;br /&gt;
|-&lt;br /&gt;
|Range&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Melee is affected by knockdown, ranged by silence, none by neither.&lt;br /&gt;
|-&lt;br /&gt;
|Standard&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If set to standard, ALL players receive this action on game start.&lt;br /&gt;
|-&lt;br /&gt;
|Hidden&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|The only action that uses hidden is &amp;quot;end turn&amp;quot; which is technically an action.&lt;br /&gt;
|-&lt;br /&gt;
|Semi hidden&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Hides the action in player inspect. Punishments use this.&lt;br /&gt;
|-&lt;br /&gt;
|Hide from action selector&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Legacy option. Was used in repair kits.&lt;br /&gt;
|-&lt;br /&gt;
|Do not generate text&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Prevents the game from trying to find a combat log text when using the action.&lt;br /&gt;
|-&lt;br /&gt;
|No interrupt&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Prevents interrupt effects from interrupting this action (requires cast time).&lt;br /&gt;
|-&lt;br /&gt;
|Permanent Charges&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Prevents cooldown from triggering. Can be used if you want to create an action with a finite amount of charges per battle.&lt;br /&gt;
|-&lt;br /&gt;
|Reset Interrupt&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|By default, having an ability interrupted causes it to go on cooldown. Checking Reset Interrupt finishes that cooldown immediately.&lt;br /&gt;
|-&lt;br /&gt;
|Hide if no viable targets&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Hides the action from the action bar if no viable targets exist.&lt;br /&gt;
|-&lt;br /&gt;
|Cast if no viable wrapper&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|By default, actions can&#039;t be used if it doesn&#039;t have at least one wrapper that passes condition checks. This will bypass that.&lt;br /&gt;
|-&lt;br /&gt;
|Can crit&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Can critically hit.&lt;br /&gt;
|-&lt;br /&gt;
|No clairvoyance&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Doesn&#039;t show up when you use clairvoyance on the target.&lt;br /&gt;
|-&lt;br /&gt;
|Max wrappers&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Max nr of wrappers to apply to each target. Use 0 for no limit.&lt;br /&gt;
|-&lt;br /&gt;
|NPC Priority&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Priority when cast by a bot (NPC). Higher number gets cast first.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Describe your action. See below for variables that can be used here.&lt;br /&gt;
|-&lt;br /&gt;
|Target Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Allows you to have a separate description while hovering the arrow above a target.&lt;br /&gt;
|-&lt;br /&gt;
|Wrappers&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Wrappers to apply. At least one wrapper must apply to a target to consider it castable unless &#039;&#039;Cast if no viable wrapper&#039;&#039; is checked.&lt;br /&gt;
|-&lt;br /&gt;
|Wrapper Mods&lt;br /&gt;
|[[Wrapper Mod (Asset)|Wrapper Mod]]&lt;br /&gt;
|&lt;br /&gt;
|Lets you modify wrapper values and reuse the same wrapper in multiple actions.&lt;br /&gt;
|-&lt;br /&gt;
|Riposte Wrappers&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Requires Riposte checked. Wrappers to apply back to the user if successfully riposted.&lt;br /&gt;
|-&lt;br /&gt;
|Riposte Wrapper Mods&lt;br /&gt;
|[[Wrapper Mod (Asset)|Wrapper Mod]]&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Passives&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Lets you grant the user passives while the action is slotted.&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt Wrappers&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Requires a cast time. Lets you run wrappers on the caster if the action is interrupted.&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt Wrapper Mods&lt;br /&gt;
|[[Wrapper Mod (Asset)|Wrapper Mod]]&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Cast Passives&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Passives that will affect the caster while they&#039;re charging this action. Requires a cast time.&lt;br /&gt;
|-&lt;br /&gt;
|Tags&lt;br /&gt;
|[[Tag]]&lt;br /&gt;
|&lt;br /&gt;
|Tags to add to the player while the action is slotted.&lt;br /&gt;
|-&lt;br /&gt;
|Aliases&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you add aliases to other action labels to share their texts.&lt;br /&gt;
|-&lt;br /&gt;
|Alternate Crit Formula&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A [[math]] formula that overrides the default critical hit chance modifier. Should result in a number between 0 and 1. Requires Can Crit to be checked.&lt;br /&gt;
|-&lt;br /&gt;
|Hit modifier formula&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A [[math]] formula that&#039;s multiplied against the default hit chance.&lt;br /&gt;
|-&lt;br /&gt;
|Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions required to use the action. Note that wrapper conditions are also checked, and if no wrappers match any targets, then it will also be considered to be unusable. Conditions must be match on both cast start and cast end (for charged actions).&lt;br /&gt;
|-&lt;br /&gt;
|Show Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions required to show this action in the action bar. A commonly used condition is &#039;&#039;inCombat.&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Cast Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions required to start a cast (needs a cast time), but not required to complete a cast.&lt;br /&gt;
|-&lt;br /&gt;
|Finish Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions required to finish a cast (needs a cast time), but not required to start it.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Common action tags ==&lt;br /&gt;
You should tag your actions, primarily to help NPCs decide how to use them. You&#039;ll want to use tags starting with &#039;&#039;ac_.&#039;&#039;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Tag&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|ac_buff&lt;br /&gt;
|Action is a buff&lt;br /&gt;
|-&lt;br /&gt;
|ac_debuff&lt;br /&gt;
|Action is a debuff&lt;br /&gt;
|-&lt;br /&gt;
|ac_heal&lt;br /&gt;
|Action has a healing component&lt;br /&gt;
|-&lt;br /&gt;
|ac_npc_important&lt;br /&gt;
|Action will be prioritized by NPCs and always used by NPCs whenever they can&lt;br /&gt;
|-&lt;br /&gt;
|ac_npc_first&lt;br /&gt;
|Use this first unless an important action is castable. Can be combined with ac_npc important to further increase ranking.&lt;br /&gt;
|-&lt;br /&gt;
|ac_npc_important_last&lt;br /&gt;
|Only works consistently for actions that don&#039;t require momentum. If no other actions can be used, then this will be used.&lt;br /&gt;
|-&lt;br /&gt;
|ac_interrupt&lt;br /&gt;
|Action has an interrupt component.&lt;br /&gt;
|-&lt;br /&gt;
|ac_item&lt;br /&gt;
|Action is tied to an item.&lt;br /&gt;
|-&lt;br /&gt;
|ac_mana_heal&lt;br /&gt;
|Action has a momentum restore component.&lt;br /&gt;
|-&lt;br /&gt;
|ac_self_heal&lt;br /&gt;
|Action has a self heal component.&lt;br /&gt;
|-&lt;br /&gt;
|ac_taunt&lt;br /&gt;
|Action has a taunt component.&lt;br /&gt;
|-&lt;br /&gt;
|ac_mana_damage&lt;br /&gt;
|Action has a momentum damage component.&lt;br /&gt;
|-&lt;br /&gt;
|ac_npc_ignore_aggro&lt;br /&gt;
|The NPC caster should ignore the aggro system and pick targets at random.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Description variables ==&lt;br /&gt;
You can set a description and/or name to exactly: %P% when the action is tied to an [[Asset (Asset)|Asset]]. Then it will use the asset description/name.&lt;br /&gt;
&lt;br /&gt;
You can also use a special variable like below to automatically show the amount of damage/healing etc the action does based on your current stats, such as damage done effects. These variables also work in [[Wrapper (Asset)|wrapper]] descriptions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: Target Description/wrapper descriptions will also take target effects into consideration when calculating the number, such as damage taken reduction effects.&#039;&#039;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Variable&lt;br /&gt;
!Example&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|$&lt;br /&gt;
|$2&lt;br /&gt;
|2 multiplied by nr of stacks.&lt;br /&gt;
|-&lt;br /&gt;
|$D&lt;br /&gt;
|$D10&lt;br /&gt;
|10 multiplied by damage done effects.&lt;br /&gt;
|-&lt;br /&gt;
|$H&lt;br /&gt;
|$H10&lt;br /&gt;
|10 multiplied by healing done effects.&lt;br /&gt;
|-&lt;br /&gt;
|$N&lt;br /&gt;
|$DN10&lt;br /&gt;
|&#039;&#039;Wrapper effects only.&#039;&#039; Don&#039;t multiply the other variables by the stacks of the wrapper that has this variable.&lt;br /&gt;
|-&lt;br /&gt;
|$B&lt;br /&gt;
|$B10&lt;br /&gt;
|10 multiplied by block done effects.&lt;br /&gt;
|-&lt;br /&gt;
|$A&lt;br /&gt;
|$A10&lt;br /&gt;
|10 multiplied by arousal done effects.&lt;br /&gt;
|}&lt;br /&gt;
You can also freely combine the variables. Just make sure all the letters come before the number. Ex: $DH10 multiplies 10 by both healing and damage done.&lt;br /&gt;
&lt;br /&gt;
Instead of supplying a number you can also supply a [[math]] formula wrapped in {}. These also need to come after the letters.&lt;br /&gt;
&lt;br /&gt;
Ex: $D{ceil(se_Block/2)} = Damage done multiplier times half the sender&#039;s block value.&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Player_(Asset)&amp;diff=317</id>
		<title>Player (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Player_(Asset)&amp;diff=317"/>
		<updated>2025-10-18T16:42:45Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A player is an NPC or player character with fixed settings. Useful for NPCs or playable characters linked in [[Gallery (Asset)|Gallery]]. If you want to create random NPCs for random encounters, use a [[Player Template (Asset)|Player Template]] instead. &lt;br /&gt;
&lt;br /&gt;
If you want an NPC to offer a service, check out the [[Creating a Service NPC|Creating a Service]] tutorial.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique ID for your player. &#039;&#039;&#039;Do not edit after creation!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Name of your character. Not unique.&lt;br /&gt;
|-&lt;br /&gt;
|Species Article&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A/An. Automatically inferred unless your species doesn&#039;t follow the &amp;quot;an&amp;quot; before a vowel, such as unicorn.&lt;br /&gt;
|-&lt;br /&gt;
|Species&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Species of your character.&lt;br /&gt;
|-&lt;br /&gt;
|Voice&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you bind combat grunts. Not currently used in the official game.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun he&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|he/she/it pronoun. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun him&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|him/her/it pronoun. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun his&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|his/her/its. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Image dressed&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to fully dressed state. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image upper body armor&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing only upper body armor. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image lower body armor&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing only lower body armor. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image nude&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing no clothes, or to art if character has only one art layer. Should always be used.&lt;br /&gt;
|-&lt;br /&gt;
|Image base path&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Gets prepended to all images (even advanced art layers). Saves some typing. You can use the domain here, such as https://imagehost.com/&lt;br /&gt;
|-&lt;br /&gt;
|No Proxy&lt;br /&gt;
|Boolean&lt;br /&gt;
|false&lt;br /&gt;
|In order for CORS to work, images hosted at an external domain will use the FQ proxy service. However, if you know for sure that your image is hosted at a place with proper CORS headers, checking no proxy will make the image load faster.&lt;br /&gt;
|-&lt;br /&gt;
|Portrait XYWH&lt;br /&gt;
|Vector&lt;br /&gt;
|0,0,0&lt;br /&gt;
|Sets the portrait icon. Click select, then drag a box over the character&#039;s face. Right click when done.&lt;br /&gt;
|-&lt;br /&gt;
|Team&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Team of player, decides how the NPC behaves in combat. Use 0 for players. Use 1 for enemies and NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Size&lt;br /&gt;
|Float&lt;br /&gt;
|5&lt;br /&gt;
|Used mainly in texts. Where 5 = average human, 0 = insect, 10 = dragon. Use a range between 4-6 for most humanoids.&lt;br /&gt;
|-&lt;br /&gt;
|Level&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Default level. Note that level is set to 1 for all player characters on game start.&lt;br /&gt;
|-&lt;br /&gt;
|Level is offset from party&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Check this for combat NPCs. When checked, the level field becomes an offset from the average player level. Setting the level field to 0 will then equal to same as player average level, and setting it to 1 means average player level plus 1.&lt;br /&gt;
|-&lt;br /&gt;
|Power&lt;br /&gt;
|Float&lt;br /&gt;
|1&lt;br /&gt;
|Lets you make a player more or less powerful. Multiplying their stats.&lt;br /&gt;
|-&lt;br /&gt;
|HP Multiplier&lt;br /&gt;
|Float&lt;br /&gt;
|1&lt;br /&gt;
|Lets you increase or decrease the character&#039;s max HP by this.&lt;br /&gt;
|-&lt;br /&gt;
|Armor&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Used mainly for beasts. Percentage damage reduction from all attacks unless they bypass armor. 0 = no damage reduction, 100 = full.&lt;br /&gt;
|-&lt;br /&gt;
|Talkative&lt;br /&gt;
|Float&lt;br /&gt;
|0.3&lt;br /&gt;
|Multiplier used to check if an NPC should use Chat type texts in response to an event. Higher value = more talkative.&lt;br /&gt;
|-&lt;br /&gt;
|Sadistic&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Used mainly for flavor in roleplays.&lt;br /&gt;
|-&lt;br /&gt;
|Dominant&lt;br /&gt;
|Float&lt;br /&gt;
|0.8&lt;br /&gt;
|Used mainly for flavor in roleplays.&lt;br /&gt;
|-&lt;br /&gt;
|Hetero&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Determines sexual preference. Where 0.5 = bisexual. Used in NPCs to slightly modify who they are more likely to attack.&lt;br /&gt;
|-&lt;br /&gt;
|Emotive&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Chance to use audio triggers. Not used in the main game.&lt;br /&gt;
|-&lt;br /&gt;
|Intelligence&lt;br /&gt;
|Float&lt;br /&gt;
|0.6&lt;br /&gt;
|Slightly affects AI decisions and used for flavor in RP. 0.6 is average human intelligence. 0.4-0.5 a dumb human. 0.1-0.2 for most beasts.&lt;br /&gt;
|-&lt;br /&gt;
|Ignore spell slots&lt;br /&gt;
|Boolean&lt;br /&gt;
|True&lt;br /&gt;
|When used on NPCs they can use ALL abilities available to them, rather than just slotted ones. Uncheck for players, and leave checked for NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|PC Chat Reactions&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|By default, only players not controlled by a human are allowed to use chat type texts. Checking this allows the player to use these texts regardless of if it&#039;s controlled or not.&lt;br /&gt;
|-&lt;br /&gt;
|Remove on death&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When dying, immediately remove this player from the game. Useful for summoned NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Placement Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you change the player label when they are placed in world.&lt;br /&gt;
|-&lt;br /&gt;
|Play Order&lt;br /&gt;
|Int&lt;br /&gt;
|10&lt;br /&gt;
|Sets the order that NPCs will play in. Lower value goes first. If multiple NPCs have the same order, their order will be shuffled after each action.&lt;br /&gt;
|-&lt;br /&gt;
|Stats&lt;br /&gt;
|Integers&lt;br /&gt;
|&lt;br /&gt;
|Hard codes player stats. Only recommended for NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Describes your player in the gallery selector, and when inspecting them.&lt;br /&gt;
|-&lt;br /&gt;
|Secret information&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Secret information to show when using clairvoyance on the player.&lt;br /&gt;
|-&lt;br /&gt;
|Jiggles&lt;br /&gt;
|[[Player Jiggle (Asset)|Player Jiggle]]&lt;br /&gt;
|&lt;br /&gt;
|Player jiggle assets.&lt;br /&gt;
|-&lt;br /&gt;
|Advanced Icon States&lt;br /&gt;
|[[Player Icon State (Asset)|Player Icon State]]&lt;br /&gt;
|&lt;br /&gt;
|See [[Creating Advanced Art Layers|creating advanced art layers]]. You can shift click these to toggle them in the preview. Also works in the jiggle previews, but you will have to manually refresh them by clicking the refresh button at the top of the window.&lt;br /&gt;
|-&lt;br /&gt;
|Player Class&lt;br /&gt;
|[[Player Class (Asset)|Player Class]]&lt;br /&gt;
|&lt;br /&gt;
|Sets player class.&lt;br /&gt;
|-&lt;br /&gt;
|Tags&lt;br /&gt;
|Tags&lt;br /&gt;
|&lt;br /&gt;
|Sets player tags. Unlike editing tags within the game itself, you must prefix these with the pl_ prefix.&lt;br /&gt;
|-&lt;br /&gt;
|Actions&lt;br /&gt;
|[[Action (Asset)|Action]]&lt;br /&gt;
|&lt;br /&gt;
|Adds actions to the player.&lt;br /&gt;
|-&lt;br /&gt;
|Passives&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Adds passive wrappers to the player.&lt;br /&gt;
|-&lt;br /&gt;
|Follower RP&lt;br /&gt;
|[[Roleplay (Asset)|Roleplay]]&lt;br /&gt;
|&lt;br /&gt;
|Marks the player as a follower, and adds a roleplay when talking to the follower.&lt;br /&gt;
|-&lt;br /&gt;
|Preview&lt;br /&gt;
|N/A&lt;br /&gt;
|&lt;br /&gt;
|Preview of what the player will look like.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Roleplay_Goto_(Asset)&amp;diff=316</id>
		<title>Roleplay Goto (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Roleplay_Goto_(Asset)&amp;diff=316"/>
		<updated>2025-10-16T20:04:21Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Lets you select a [[Roleplay Stage (Asset)|stage]] that the [[Roleplay Option (Asset)|reply]] should go to, that way you can use [[Condition (Asset)|conditions]] to have the same response take you to different stage.&lt;br /&gt;
&lt;br /&gt;
In conditions, target is the player who selected the response, and sender is the player attached to the roleplay stage the reply is attached to. If no sender is present, it uses the same as target.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Go to&lt;br /&gt;
|[[Roleplay Stage (Asset)|Roleplay Stage]]&lt;br /&gt;
| - END RP -&lt;br /&gt;
|Sets where the option should take the player.&lt;br /&gt;
|-&lt;br /&gt;
|Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions needed for the goto to trigger.&lt;br /&gt;
|-&lt;br /&gt;
|Return to parent RP&lt;br /&gt;
|Boolean&lt;br /&gt;
|false&lt;br /&gt;
|When checked, and this is linked to from a parent RP using [[Roleplay Jump (Asset)|Jump]], it will return to where we triggered the jump&lt;br /&gt;
|-&lt;br /&gt;
|Add Roll Success&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Automatically adds conditions for a roll success (requires a roll in the parent reply object).&lt;br /&gt;
|-&lt;br /&gt;
|Add Roll Fail&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Automatically adds conditions for a roll failed (requires a roll in the parent reply object).&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Roleplay_Jump_(Asset)&amp;diff=315</id>
		<title>Roleplay Jump (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Roleplay_Jump_(Asset)&amp;diff=315"/>
		<updated>2025-10-16T20:03:39Z</updated>

		<summary type="html">&lt;p&gt;JasX: Created page with &amp;quot;Jumps are used to link smaller roleplays to a bigger one. Jumps are appended to a roleplay in game on trigger, so they save memory and make it easier to structure very large roleplays.  Caveats:  * Jumps currently won&amp;#039;t work correctly when persistent the jumps are appended when encountered, and not saved. * The roleplay stage output will be automatically linked to from any Roleplay Stage in the sub-roleplay that doesn&amp;#039;t have any options or direct links. * There is also a...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Jumps are used to link smaller roleplays to a bigger one. Jumps are appended to a roleplay in game on trigger, so they save memory and make it easier to structure very large roleplays.&lt;br /&gt;
&lt;br /&gt;
Caveats:&lt;br /&gt;
&lt;br /&gt;
* Jumps currently won&#039;t work correctly when persistent the jumps are appended when encountered, and not saved.&lt;br /&gt;
* The roleplay stage output will be automatically linked to from any Roleplay Stage in the sub-roleplay that doesn&#039;t have any options or direct links.&lt;br /&gt;
* There is also a checkbox in [[Roleplay Goto (Asset)|RoleplayGoto]] that lets you force return to the parent roleplay.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Target Roleplay&lt;br /&gt;
|[[Roleplay (Asset)|Roleplay]]&lt;br /&gt;
|&lt;br /&gt;
|Roleplay that you want to link to from this node.&lt;br /&gt;
|-&lt;br /&gt;
|Stage&lt;br /&gt;
|[[Roleplay Stage (Asset)|RoleplayStage]]&lt;br /&gt;
|1st&lt;br /&gt;
|The roleplay stage we should link to in the target roleplay.&lt;br /&gt;
|-&lt;br /&gt;
|Return&lt;br /&gt;
|[[Roleplay Stage (Asset)|RoleplayStage]]&lt;br /&gt;
|&lt;br /&gt;
|Optional. Where to go once we return from the sub roleplay.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Roleplay_Goto_(Asset)&amp;diff=314</id>
		<title>Roleplay Goto (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Roleplay_Goto_(Asset)&amp;diff=314"/>
		<updated>2025-10-16T19:58:58Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Lets you select a [[Roleplay Stage (Asset)|stage]] that the [[Roleplay Option (Asset)|reply]] should go to, that way you can use [[Condition (Asset)|conditions]] to have the same response take you to different stage.&lt;br /&gt;
&lt;br /&gt;
In conditions, target is the player who selected the response, and sender is the player attached to the roleplay stage the reply is attached to. If no sender is present, it uses the same as target.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Go to&lt;br /&gt;
|[[Roleplay Stage (Asset)|Roleplay Stage]]&lt;br /&gt;
| - END RP -&lt;br /&gt;
|Sets where the option should take the player.&lt;br /&gt;
|-&lt;br /&gt;
|Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions needed for the goto to trigger.&lt;br /&gt;
|-&lt;br /&gt;
|Return to parent RP&lt;br /&gt;
|Boolean&lt;br /&gt;
|false&lt;br /&gt;
|When checked, and this is linked to from a parent RP using Jump, it will return to where we triggered the jump&lt;br /&gt;
|-&lt;br /&gt;
|Add Roll Success&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Automatically adds conditions for a roll success (requires a roll in the parent reply object).&lt;br /&gt;
|-&lt;br /&gt;
|Add Roll Fail&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Automatically adds conditions for a roll failed (requires a roll in the parent reply object).&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Player_(Asset)&amp;diff=313</id>
		<title>Player (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Player_(Asset)&amp;diff=313"/>
		<updated>2025-10-12T20:43:46Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A player is an NPC or player character with fixed settings. Useful for NPCs or playable characters linked in [[Gallery (Asset)|Gallery]]. If you want to create random NPCs for random encounters, use a [[Player Template (Asset)|Player Template]] instead. &lt;br /&gt;
&lt;br /&gt;
If you want an NPC to offer a service, check out the [[Creating a Service NPC|Creating a Service]] tutorial.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique ID for your player. &#039;&#039;&#039;Do not edit after creation!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Name of your character. Not unique.&lt;br /&gt;
|-&lt;br /&gt;
|Species Article&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A/An. Automatically inferred unless your species doesn&#039;t follow the &amp;quot;an&amp;quot; before a vowel, such as unicorn.&lt;br /&gt;
|-&lt;br /&gt;
|Species&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Species of your character.&lt;br /&gt;
|-&lt;br /&gt;
|Voice&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you bind combat grunts. Not currently used in the official game.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun he&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|he/she/it pronoun. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun him&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|him/her/it pronoun. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun his&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|his/her/its. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Image dressed&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to fully dressed state. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image upper body armor&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing only upper body armor. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image lower body armor&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing only lower body armor. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image nude&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing no clothes, or to art if character has only one art layer. Should always be used.&lt;br /&gt;
|-&lt;br /&gt;
|Image base path&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Gets prepended to all images (even advanced art layers). Saves some typing. You can use the domain here, such as https://imagehost.com/&lt;br /&gt;
|-&lt;br /&gt;
|No Proxy&lt;br /&gt;
|Boolean&lt;br /&gt;
|false&lt;br /&gt;
|In order for CORS to work, images hosted at an external domain will use the FQ proxy service. However, if you know for sure that your image is hosted at a place with proper CORS headers, checking no proxy will make the image load faster.&lt;br /&gt;
|-&lt;br /&gt;
|Portrait XYWH&lt;br /&gt;
|Vector&lt;br /&gt;
|0,0,0&lt;br /&gt;
|Sets the portrait icon. Click select, then drag a box over the character&#039;s face. Right click when done.&lt;br /&gt;
|-&lt;br /&gt;
|Team&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Team of player, decides how the NPC behaves in combat. Use 0 for players. Use 1 for enemies and NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Size&lt;br /&gt;
|Float&lt;br /&gt;
|5&lt;br /&gt;
|Used mainly in texts. Where 5 = average human, 0 = insect, 10 = dragon. Use a range between 4-6 for most humanoids.&lt;br /&gt;
|-&lt;br /&gt;
|Level&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Default level. Note that level is set to 1 for all player characters on game start.&lt;br /&gt;
|-&lt;br /&gt;
|Level is offset from party&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Check this for combat NPCs. When checked, the level field becomes an offset from the average player level. Setting the level field to 0 will then equal to same as player average level, and setting it to 1 means average player level plus 1.&lt;br /&gt;
|-&lt;br /&gt;
|Power&lt;br /&gt;
|Float&lt;br /&gt;
|1&lt;br /&gt;
|Lets you make a player more or less powerful. Multiplying their stats.&lt;br /&gt;
|-&lt;br /&gt;
|HP Multiplier&lt;br /&gt;
|Float&lt;br /&gt;
|1&lt;br /&gt;
|Lets you increase or decrease the character&#039;s max HP by this.&lt;br /&gt;
|-&lt;br /&gt;
|Armor&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Used mainly for beasts. Percentage damage reduction from all attacks unless they bypass armor. 0 = no damage reduction, 100 = full.&lt;br /&gt;
|-&lt;br /&gt;
|Talkative&lt;br /&gt;
|Float&lt;br /&gt;
|0.3&lt;br /&gt;
|Multiplier used to check if an NPC should use Chat type texts in response to an event. Higher value = more talkative.&lt;br /&gt;
|-&lt;br /&gt;
|Sadistic&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Used mainly for flavor in roleplays.&lt;br /&gt;
|-&lt;br /&gt;
|Dominant&lt;br /&gt;
|Float&lt;br /&gt;
|0.8&lt;br /&gt;
|Used mainly for flavor in roleplays.&lt;br /&gt;
|-&lt;br /&gt;
|Hetero&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Determines sexual preference. Where 0.5 = bisexual. Used in NPCs to slightly modify who they are more likely to attack.&lt;br /&gt;
|-&lt;br /&gt;
|Emotive&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Chance to use audio triggers. Not used in the main game.&lt;br /&gt;
|-&lt;br /&gt;
|Intelligence&lt;br /&gt;
|Float&lt;br /&gt;
|0.6&lt;br /&gt;
|Slightly affects AI decisions and used for flavor in RP. 0.6 is average human intelligence. 0.4-0.5 a dumb human. 0.1-0.2 for most beasts.&lt;br /&gt;
|-&lt;br /&gt;
|Ignore spell slots&lt;br /&gt;
|Boolean&lt;br /&gt;
|True&lt;br /&gt;
|When used on NPCs they can use ALL abilities available to them, rather than just slotted ones. Uncheck for players, and leave checked for NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Remove on death&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When dying, immediately remove this player from the game. Useful for summoned NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Placement Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you change the player label when they are placed in world.&lt;br /&gt;
|-&lt;br /&gt;
|Play Order&lt;br /&gt;
|Int&lt;br /&gt;
|10&lt;br /&gt;
|Sets the order that NPCs will play in. Lower value goes first. If multiple NPCs have the same order, their order will be shuffled after each action.&lt;br /&gt;
|-&lt;br /&gt;
|Stats&lt;br /&gt;
|Integers&lt;br /&gt;
|&lt;br /&gt;
|Hard codes player stats. Only recommended for NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Describes your player in the gallery selector, and when inspecting them.&lt;br /&gt;
|-&lt;br /&gt;
|Secret information&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Secret information to show when using clairvoyance on the player.&lt;br /&gt;
|-&lt;br /&gt;
|Jiggles&lt;br /&gt;
|[[Player Jiggle (Asset)|Player Jiggle]]&lt;br /&gt;
|&lt;br /&gt;
|Player jiggle assets.&lt;br /&gt;
|-&lt;br /&gt;
|Advanced Icon States&lt;br /&gt;
|[[Player Icon State (Asset)|Player Icon State]]&lt;br /&gt;
|&lt;br /&gt;
|See [[Creating Advanced Art Layers|creating advanced art layers]]. You can shift click these to toggle them in the preview. Also works in the jiggle previews, but you will have to manually refresh them by clicking the refresh button at the top of the window.&lt;br /&gt;
|-&lt;br /&gt;
|Player Class&lt;br /&gt;
|[[Player Class (Asset)|Player Class]]&lt;br /&gt;
|&lt;br /&gt;
|Sets player class.&lt;br /&gt;
|-&lt;br /&gt;
|Tags&lt;br /&gt;
|Tags&lt;br /&gt;
|&lt;br /&gt;
|Sets player tags. Unlike editing tags within the game itself, you must prefix these with the pl_ prefix.&lt;br /&gt;
|-&lt;br /&gt;
|Actions&lt;br /&gt;
|[[Action (Asset)|Action]]&lt;br /&gt;
|&lt;br /&gt;
|Adds actions to the player.&lt;br /&gt;
|-&lt;br /&gt;
|Passives&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Adds passive wrappers to the player.&lt;br /&gt;
|-&lt;br /&gt;
|Follower RP&lt;br /&gt;
|[[Roleplay (Asset)|Roleplay]]&lt;br /&gt;
|&lt;br /&gt;
|Marks the player as a follower, and adds a roleplay when talking to the follower.&lt;br /&gt;
|-&lt;br /&gt;
|Preview&lt;br /&gt;
|N/A&lt;br /&gt;
|&lt;br /&gt;
|Preview of what the player will look like.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Player_(Asset)&amp;diff=312</id>
		<title>Player (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Player_(Asset)&amp;diff=312"/>
		<updated>2025-10-12T20:43:34Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A player is an NPC or player character with fixed settings. Useful for NPCs or playable characters linked in [[Gallery (Asset)|Gallery]]. If you want to create random NPCs for random encounters, use a [[Player Template (Asset)|Player Template]] instead. &lt;br /&gt;
&lt;br /&gt;
If you want an NPC to offer a service, check out the [[Creating a Service NPC|Creating a Service]] tutorial.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique ID for your player. &#039;&#039;&#039;Do not edit after creation!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Name of your character. Not unique.&lt;br /&gt;
|-&lt;br /&gt;
|Species Article&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A/An. Automatically inferred unless your species doesn&#039;t follow the &amp;quot;an&amp;quot; before a vowel, such as unicorn.&lt;br /&gt;
|-&lt;br /&gt;
|Species&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Species of your character.&lt;br /&gt;
|-&lt;br /&gt;
|Voice&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you bind combat grunts. Not currently used in the official game.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun he&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|he/she/it pronoun. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun him&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|him/her/it pronoun. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Pronoun his&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|his/her/its. Auto inferred for male/female.&lt;br /&gt;
|-&lt;br /&gt;
|Image dressed&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to fully dressed state. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image upper body armor&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing only upper body armor. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image lower body armor&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing only lower body armor. Leave blank if using advanced art layers.&lt;br /&gt;
|-&lt;br /&gt;
|Image nude&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to character wearing no clothes, or to art if character has only one art layer. Should always be used.&lt;br /&gt;
|-&lt;br /&gt;
|Image base path&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Gets prepended to all images (even advanced art layers). Saves some typing. You can use the domain here, such as https://imagehost.com/&lt;br /&gt;
|-&lt;br /&gt;
|No Proxy&lt;br /&gt;
|Boolean&lt;br /&gt;
|false&lt;br /&gt;
|In order for CORS to work, images hosted at an external domain will use the FQ proxy service. However, if you know for sure that your image is hosted at a place with proper CORS headers, checking no proxy will make the image load faster.&lt;br /&gt;
|-&lt;br /&gt;
|Portrait XYWH&lt;br /&gt;
|Vector&lt;br /&gt;
|0,0,0&lt;br /&gt;
|Sets the portrait icon. Click select, then drag a box over the character&#039;s face. Right click when done.&lt;br /&gt;
|-&lt;br /&gt;
|Team&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Team of player, decides how the NPC behaves in combat. Use 0 for players. Use 1 for enemies and NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Size&lt;br /&gt;
|Float&lt;br /&gt;
|5&lt;br /&gt;
|Used mainly in texts. Where 5 = average human, 0 = insect, 10 = dragon. Use a range between 4-6 for most humanoids.&lt;br /&gt;
|-&lt;br /&gt;
|Level&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Default level. Note that level is set to 1 for all player characters on game start.&lt;br /&gt;
|-&lt;br /&gt;
|Level is offset from party&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Check this for combat NPCs. When checked, the level field becomes an offset from the average player level. Setting the level field to 0 will then equal to same as player average level, and setting it to 1 means average player level plus 1.&lt;br /&gt;
|-&lt;br /&gt;
|Power&lt;br /&gt;
|Float&lt;br /&gt;
|1&lt;br /&gt;
|Lets you make a player more or less powerful. Multiplying their stats.&lt;br /&gt;
|-&lt;br /&gt;
|HP Multiplier&lt;br /&gt;
|Float&lt;br /&gt;
|1&lt;br /&gt;
|Lets you increase or decrease the character&#039;s max HP by this.&lt;br /&gt;
|-&lt;br /&gt;
|Armor&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Used mainly for beasts. Percentage damage reduction from all attacks unless they bypass armor. 0 = no damage reduction, 100 = full.&lt;br /&gt;
|-&lt;br /&gt;
|Talkative&lt;br /&gt;
|Float&lt;br /&gt;
|0.3&lt;br /&gt;
|Multiplier used to check if an NPC should use Chat type texts in response to an event. Higher value = more talkative.&lt;br /&gt;
|-&lt;br /&gt;
|Sadistic&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Used mainly for flavor in roleplays.&lt;br /&gt;
|-&lt;br /&gt;
|Dominant&lt;br /&gt;
|Float&lt;br /&gt;
|0.8&lt;br /&gt;
|Used mainly for flavor in roleplays.&lt;br /&gt;
|-&lt;br /&gt;
|Hetero&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Determines sexual preference. Where 0.5 = bisexual. Used in NPCs to slightly modify who they are more likely to attack.&lt;br /&gt;
|-&lt;br /&gt;
|Emotive&lt;br /&gt;
|Float&lt;br /&gt;
|0.5&lt;br /&gt;
|Chance to use audio triggers. Not used in the main game.&lt;br /&gt;
|-&lt;br /&gt;
|Intelligence&lt;br /&gt;
|Float&lt;br /&gt;
|0.6&lt;br /&gt;
|Slightly affects AI decisions and used for flavor in RP. 0.6 is average human intelligence. 0.4-0.5 a dumb human. 0.1-0.2 for most beasts.&lt;br /&gt;
|-&lt;br /&gt;
|Ignore spell slots&lt;br /&gt;
|Boolean&lt;br /&gt;
|True&lt;br /&gt;
|When used on NPCs they can use ALL abilities available to them, rather than just slotted ones. Uncheck for players, and leave checked for NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Remove on death&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When dying, immediately remove this player from the game. Useful for summoned NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Placement Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you change the player label when they are placed in world.&lt;br /&gt;
|-&lt;br /&gt;
|Play Order&lt;br /&gt;
|Int&lt;br /&gt;
|10&lt;br /&gt;
|Sets the order that NPCs will play in. Lower value goes first. If multiple NPCs have the same order, the order will be shuffled after each action.&lt;br /&gt;
|-&lt;br /&gt;
|Stats&lt;br /&gt;
|Integers&lt;br /&gt;
|&lt;br /&gt;
|Hard codes player stats. Only recommended for NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Describes your player in the gallery selector, and when inspecting them.&lt;br /&gt;
|-&lt;br /&gt;
|Secret information&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Secret information to show when using clairvoyance on the player.&lt;br /&gt;
|-&lt;br /&gt;
|Jiggles&lt;br /&gt;
|[[Player Jiggle (Asset)|Player Jiggle]]&lt;br /&gt;
|&lt;br /&gt;
|Player jiggle assets.&lt;br /&gt;
|-&lt;br /&gt;
|Advanced Icon States&lt;br /&gt;
|[[Player Icon State (Asset)|Player Icon State]]&lt;br /&gt;
|&lt;br /&gt;
|See [[Creating Advanced Art Layers|creating advanced art layers]]. You can shift click these to toggle them in the preview. Also works in the jiggle previews, but you will have to manually refresh them by clicking the refresh button at the top of the window.&lt;br /&gt;
|-&lt;br /&gt;
|Player Class&lt;br /&gt;
|[[Player Class (Asset)|Player Class]]&lt;br /&gt;
|&lt;br /&gt;
|Sets player class.&lt;br /&gt;
|-&lt;br /&gt;
|Tags&lt;br /&gt;
|Tags&lt;br /&gt;
|&lt;br /&gt;
|Sets player tags. Unlike editing tags within the game itself, you must prefix these with the pl_ prefix.&lt;br /&gt;
|-&lt;br /&gt;
|Actions&lt;br /&gt;
|[[Action (Asset)|Action]]&lt;br /&gt;
|&lt;br /&gt;
|Adds actions to the player.&lt;br /&gt;
|-&lt;br /&gt;
|Passives&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Adds passive wrappers to the player.&lt;br /&gt;
|-&lt;br /&gt;
|Follower RP&lt;br /&gt;
|[[Roleplay (Asset)|Roleplay]]&lt;br /&gt;
|&lt;br /&gt;
|Marks the player as a follower, and adds a roleplay when talking to the follower.&lt;br /&gt;
|-&lt;br /&gt;
|Preview&lt;br /&gt;
|N/A&lt;br /&gt;
|&lt;br /&gt;
|Preview of what the player will look like.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Encounter_(Asset)&amp;diff=311</id>
		<title>Encounter (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Encounter_(Asset)&amp;diff=311"/>
		<updated>2025-10-02T22:18:50Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Encounters are used to add enemies, NPCs, and custom rules to [[Room (Asset)|dungeon rooms]].  &lt;br /&gt;
&lt;br /&gt;
If you want help creating a random exploration event, check out [[Creating an Exploration Event]].  &lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique label for your encounter. &#039;&#039;&#039;Do not change a label after creation&#039;&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A description to help you locate your encounter later. The description is only used in the ditor.&lt;br /&gt;
|-&lt;br /&gt;
|Friendly&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If not marked as friendly, combat will start when the encounter starts.&lt;br /&gt;
|-&lt;br /&gt;
|Proc Event&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Marks the encounter as a procedural event, used when you mark a [[Room (Asset)|room]] as having a procedural event. Note that if you specify procedural events in a [[Story (Asset)|Story]], then only those will be included.&lt;br /&gt;
|-&lt;br /&gt;
|Once&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Only used in procedural events. When checked, the event will only trigger once per game.&lt;br /&gt;
|-&lt;br /&gt;
|Evt Weight&lt;br /&gt;
|Float&lt;br /&gt;
|1&lt;br /&gt;
|Only used in procedural events. Increases or decreases the event&#039;s chance of being discovered.&lt;br /&gt;
|-&lt;br /&gt;
|Override game over&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When checked, prevents the players from being send back to the start of the dungeon and regenerated if they are defeated.&lt;br /&gt;
|-&lt;br /&gt;
|Start Text&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Legacy. Outputs a string into the combat log when the encounter starts.&lt;br /&gt;
|-&lt;br /&gt;
|Respawn Time&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Used mainly for combat encounters that should respawn, such as beasts out in the field. Time is in game hours in seconds.&lt;br /&gt;
|-&lt;br /&gt;
|Difficulty Adjust&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Lets you adjust the difficulty. 1 = 100% more difficult, -0.5 = half as difficult.&lt;br /&gt;
|-&lt;br /&gt;
|Max players&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Max [[Player Template (Asset)|NPC templates]] to generate (minus [[Player (Asset)|Player NPCs]]). Use 0 for auto.&lt;br /&gt;
|-&lt;br /&gt;
|Gen Extendable&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Allow the procedural generator to add additional friendly NPCs to this encounter.&lt;br /&gt;
|-&lt;br /&gt;
|Ambient Music&lt;br /&gt;
|[[Music (Asset)|Music]]&lt;br /&gt;
|&lt;br /&gt;
|Sets ambient music. If left empty, dungeon room or dungeon music is used.&lt;br /&gt;
|-&lt;br /&gt;
|Combat Music&lt;br /&gt;
|[[Music (Asset)|Music]]&lt;br /&gt;
|&lt;br /&gt;
|Sets combat music. If left empty, dungeon room or dungeon music is used.&lt;br /&gt;
|-&lt;br /&gt;
|Players&lt;br /&gt;
|[[Player (Asset)|Player]]&lt;br /&gt;
|&lt;br /&gt;
|Adds NPCs.&lt;br /&gt;
|-&lt;br /&gt;
|Player Templates&lt;br /&gt;
|[[Player Template (Asset)|Player Template]]&lt;br /&gt;
|&lt;br /&gt;
|Adds player templates that can be generated when the encounter starts.&lt;br /&gt;
|-&lt;br /&gt;
|Wrappers&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Adds wrappers to apply to players when the encounter starts.&lt;br /&gt;
|-&lt;br /&gt;
|Wrapper Mods&lt;br /&gt;
|[[Wrapper Mod (Asset)|Wrapper Mod]]&lt;br /&gt;
|&lt;br /&gt;
|Lets you modify the wrappers you apply. Such as number of stacks.&lt;br /&gt;
|-&lt;br /&gt;
|Passives&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Wrappers that affect all players that match wrapper conditions while the encounter is active.&lt;br /&gt;
|-&lt;br /&gt;
|Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions for this encounter to start.&lt;br /&gt;
|-&lt;br /&gt;
|Start/Passive game actions&lt;br /&gt;
|[[Game Action (Asset)|Game Action]]&lt;br /&gt;
|&lt;br /&gt;
|Game actions to run when the encounter starts, and passives. Commonly used to link [[Roleplay (Asset)|roleplays]] to encounters. &lt;br /&gt;
|-&lt;br /&gt;
|Event Bindings&lt;br /&gt;
|[[Encounter Event (Asset)|Encounter Event]]&lt;br /&gt;
|&lt;br /&gt;
|Lets you trigger [[Game Action (Asset)|game actions]] based on [[Event|events]].&lt;br /&gt;
|-&lt;br /&gt;
|Finish Game Actions&lt;br /&gt;
|[[Game Action (Asset)|Game Action]]&lt;br /&gt;
|&lt;br /&gt;
|Lets you trigger a [[Game Action (Asset)|game action]] when the encounter is finished (combat is won).&lt;br /&gt;
|-&lt;br /&gt;
|Player Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Lets you add conditions for certain players to show up.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Quest_(Asset)&amp;diff=310</id>
		<title>Quest (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Quest_(Asset)&amp;diff=310"/>
		<updated>2025-09-29T21:22:40Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Quests are tasks for the players to do that show up in the quest log.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique label for your quest. &#039;&#039;&#039;Do not edit after setting up your quest!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Name of your quest. Doesn&#039;t have to be unique.&lt;br /&gt;
|-&lt;br /&gt;
|Exp Multiplier&lt;br /&gt;
|Float&lt;br /&gt;
|1&lt;br /&gt;
|Lets you raise or lower the exp reward. Raise it for longer quests and lower it for shorter ones. Use your own discretion. Exp is by default multiplied by nr of objectives.&lt;br /&gt;
|-&lt;br /&gt;
|Hide Rewards&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Hides quest rewards in the quest log.&lt;br /&gt;
|-&lt;br /&gt;
|Multiply Money&lt;br /&gt;
|Boolen&lt;br /&gt;
|True&lt;br /&gt;
|Scales any money rewards by nr of players.&lt;br /&gt;
|-&lt;br /&gt;
|Multiply Reward&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Gives every player the item reward, otherwise a random player will receive the reward.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Describe your quest. You can add additional descriptions show up in the quest log as the players complete objectives.&lt;br /&gt;
|-&lt;br /&gt;
|Rewards&lt;br /&gt;
|[[Quest Reward (Asset)|Quest Reward]]&lt;br /&gt;
|&lt;br /&gt;
|Rewards.&lt;br /&gt;
|-&lt;br /&gt;
|Objectives&lt;br /&gt;
|[[Quest Objective (Asset)|Quest Objective]]&lt;br /&gt;
|&lt;br /&gt;
|Objectives for the player to complete.&lt;br /&gt;
|-&lt;br /&gt;
|Completion Objectives&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Legacy. Do not use. Use a [[Roleplay (Asset)|Roleplay]] to finish your quest instead.&lt;br /&gt;
|-&lt;br /&gt;
|Completion Game Actions&lt;br /&gt;
|[[Game Action (Asset)|GameAction]]&lt;br /&gt;
|&lt;br /&gt;
|Actions to run. Do not rely on target, as it will be the first player on the player team. Use gameAction playerconds to target specific players.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Giver RP&lt;br /&gt;
|[[Roleplay (Asset)|Roleplay]]&lt;br /&gt;
|&lt;br /&gt;
|Note: This is only used when linking this quest to a [[Procedural Dungeon (Asset)|procedural dungeon]]. The conditions in said RP will be used to map the quest to the world.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Buttons ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Button&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Auto Create Quest Conditions&lt;br /&gt;
|Auto Creates quest/objective completed/accepted/not_completed conditions in your conditions DB.&lt;br /&gt;
|-&lt;br /&gt;
|Create and link quest conditions&lt;br /&gt;
|Automatically creates and links objective conditions, setting each objective to require the previous objective completed before showing the next.&lt;br /&gt;
|-&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Action_(Asset)&amp;diff=309</id>
		<title>Action (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Action_(Asset)&amp;diff=309"/>
		<updated>2025-09-29T18:12:35Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is the Action asset reference. If you want a tutorial, check out [[Creating an Action]].&lt;br /&gt;
&lt;br /&gt;
Spells and attacks are all actions. To link an action to a player, trainer, or NPC template, use the [[Player Action (Asset)|Player Action]] asset type.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Set to a unique label for your action. &#039;&#039;&#039;Do not edit after setting up your action!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Name your action, doesn&#039;t have to be unique.&lt;br /&gt;
|-&lt;br /&gt;
|Icon&lt;br /&gt;
|[[Icon]]&lt;br /&gt;
|&lt;br /&gt;
|Icon for your action.&lt;br /&gt;
|-&lt;br /&gt;
|M.Off/Def/Uti&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Momentum cost.&lt;br /&gt;
|-&lt;br /&gt;
|Cooldown&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Cooldown in turns.&lt;br /&gt;
|-&lt;br /&gt;
|Init Cooldown&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Start the battle with the ability on cooldown for this amount of turns. Usually used for boss mechanics.&lt;br /&gt;
|-&lt;br /&gt;
|Hit Chance&lt;br /&gt;
|Int&lt;br /&gt;
|90&lt;br /&gt;
|Hit chance in percent. Use 9001 for guaranteed hit. Not needed for beneficial actions.&lt;br /&gt;
|-&lt;br /&gt;
|Override disable lv&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Overrides disable effects if above the disable effect&#039;s priority.&lt;br /&gt;
|-&lt;br /&gt;
|Cast time&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Nr of turns needed to finish this action.&lt;br /&gt;
|-&lt;br /&gt;
|Allow while charging&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When checked, this action may be used while the player is readying an action with a cast time.&lt;br /&gt;
|-&lt;br /&gt;
|Taunt Override Charge&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If charged, taunt will override the cast target.&lt;br /&gt;
|-&lt;br /&gt;
|Ripostable&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Allows the action to be riposted on miss. If the action missed, the action is run in reverse against the caster with the target as the new caster.&lt;br /&gt;
|-&lt;br /&gt;
|Group&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you group spells in the action bar. Mainly used for potions.&lt;br /&gt;
|-&lt;br /&gt;
|Charges&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Max charges of the action that can be used. Each cooldown period adds 1 charge.&lt;br /&gt;
|-&lt;br /&gt;
|Start Charges&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Set to -1 to start combat with max charges. Otherwise you can edit the nr of charges you start with.&lt;br /&gt;
|-&lt;br /&gt;
|Min Targets&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Minimum targets to use this action.&lt;br /&gt;
|-&lt;br /&gt;
|Max Targets&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Maximum targets that you can use this action on.&lt;br /&gt;
|-&lt;br /&gt;
|Target&lt;br /&gt;
|String&lt;br /&gt;
|target&lt;br /&gt;
|Overrides the target of the action.&lt;br /&gt;
|-&lt;br /&gt;
|Detrimental&lt;br /&gt;
|String&lt;br /&gt;
|yes&lt;br /&gt;
|Sets if the action is detrimental. Team makes it detrimental to players not on your team, and beneficial to players on your team.&lt;br /&gt;
|-&lt;br /&gt;
|Allow detrimental self cast&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When true, it lets you use the action on yourself even if it&#039;s detrimental.&lt;br /&gt;
|-&lt;br /&gt;
|Type&lt;br /&gt;
|String&lt;br /&gt;
|physical&lt;br /&gt;
|Damage type&lt;br /&gt;
|-&lt;br /&gt;
|Range&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Melee is affected by knockdown, ranged by silence, none by neither.&lt;br /&gt;
|-&lt;br /&gt;
|Standard&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If set to standard, ALL players receive this action on game start.&lt;br /&gt;
|-&lt;br /&gt;
|Hidden&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|The only action that uses hidden is &amp;quot;end turn&amp;quot; which is technically an action.&lt;br /&gt;
|-&lt;br /&gt;
|Semi hidden&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Hides the action in player inspect. Punishments use this.&lt;br /&gt;
|-&lt;br /&gt;
|Hide from action selector&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Legacy option. Was used in repair kits.&lt;br /&gt;
|-&lt;br /&gt;
|Do not generate text&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Prevents the game from trying to find a combat log text when using the action.&lt;br /&gt;
|-&lt;br /&gt;
|No interrupt&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Prevents interrupt effects from interrupting this action (requires cast time).&lt;br /&gt;
|-&lt;br /&gt;
|Permanent Charges&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Prevents cooldown from triggering. Can be used if you want to create an action with a finite amount of charges per battle.&lt;br /&gt;
|-&lt;br /&gt;
|Reset Interrupt&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|By default, having an ability interrupted causes it to go on cooldown. Checking Reset Interrupt finishes that cooldown immediately.&lt;br /&gt;
|-&lt;br /&gt;
|Hide if no viable targets&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Hides the action from the action bar if no viable targets exist.&lt;br /&gt;
|-&lt;br /&gt;
|Cast if no viable wrapper&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|By default, actions can&#039;t be used if it doesn&#039;t have at least one wrapper that passes condition checks. This will bypass that.&lt;br /&gt;
|-&lt;br /&gt;
|Can crit&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Can critically hit.&lt;br /&gt;
|-&lt;br /&gt;
|No clairvoyance&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Doesn&#039;t show up when you use clairvoyance on the target.&lt;br /&gt;
|-&lt;br /&gt;
|Max wrappers&lt;br /&gt;
|Int&lt;br /&gt;
|0&lt;br /&gt;
|Max nr of wrappers to apply to each target. Use 0 for no limit.&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Describe your action. See below for variables that can be used here.&lt;br /&gt;
|-&lt;br /&gt;
|Target Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Allows you to have a separate description while hovering the arrow above a target.&lt;br /&gt;
|-&lt;br /&gt;
|Wrappers&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Wrappers to apply. At least one wrapper must apply to a target to consider it castable unless &#039;&#039;Cast if no viable wrapper&#039;&#039; is checked.&lt;br /&gt;
|-&lt;br /&gt;
|Wrapper Mods&lt;br /&gt;
|[[Wrapper Mod (Asset)|Wrapper Mod]]&lt;br /&gt;
|&lt;br /&gt;
|Lets you modify wrapper values and reuse the same wrapper in multiple actions.&lt;br /&gt;
|-&lt;br /&gt;
|Riposte Wrappers&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Requires Riposte checked. Wrappers to apply back to the user if successfully riposted.&lt;br /&gt;
|-&lt;br /&gt;
|Riposte Wrapper Mods&lt;br /&gt;
|[[Wrapper Mod (Asset)|Wrapper Mod]]&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Passives&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Lets you grant the user passives while the action is slotted.&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt Wrappers&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Requires a cast time. Lets you run wrappers on the caster if the action is interrupted.&lt;br /&gt;
|-&lt;br /&gt;
|Interrupt Wrapper Mods&lt;br /&gt;
|[[Wrapper Mod (Asset)|Wrapper Mod]]&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Cast Passives&lt;br /&gt;
|[[Wrapper (Asset)|Wrapper]]&lt;br /&gt;
|&lt;br /&gt;
|Passives that will affect the caster while they&#039;re charging this action. Requires a cast time.&lt;br /&gt;
|-&lt;br /&gt;
|Tags&lt;br /&gt;
|[[Tag]]&lt;br /&gt;
|&lt;br /&gt;
|Tags to add to the player while the action is slotted.&lt;br /&gt;
|-&lt;br /&gt;
|Aliases&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Lets you add aliases to other action labels to share their texts.&lt;br /&gt;
|-&lt;br /&gt;
|Alternate Crit Formula&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A [[math]] formula that overrides the default critical hit chance modifier. Should result in a number between 0 and 1. Requires Can Crit to be checked.&lt;br /&gt;
|-&lt;br /&gt;
|Hit modifier formula&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A [[math]] formula that&#039;s multiplied against the default hit chance.&lt;br /&gt;
|-&lt;br /&gt;
|Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions required to use the action. Note that wrapper conditions are also checked, and if no wrappers match any targets, then it will also be considered to be unusable. Conditions must be match on both cast start and cast end (for charged actions).&lt;br /&gt;
|-&lt;br /&gt;
|Show Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions required to show this action in the action bar. A commonly used condition is &#039;&#039;inCombat.&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Cast Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions required to start a cast (needs a cast time), but not required to complete a cast.&lt;br /&gt;
|-&lt;br /&gt;
|Finish Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions required to finish a cast (needs a cast time), but not required to start it.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Common action tags ==&lt;br /&gt;
You should tag your actions, primarily to help NPCs decide how to use them. You&#039;ll want to use tags starting with &#039;&#039;ac_.&#039;&#039;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Tag&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|ac_buff&lt;br /&gt;
|Action is a buff&lt;br /&gt;
|-&lt;br /&gt;
|ac_debuff&lt;br /&gt;
|Action is a debuff&lt;br /&gt;
|-&lt;br /&gt;
|ac_heal&lt;br /&gt;
|Action has a healing component&lt;br /&gt;
|-&lt;br /&gt;
|ac_npc_important&lt;br /&gt;
|Action will be prioritized by NPCs and always used by NPCs whenever they can&lt;br /&gt;
|-&lt;br /&gt;
|ac_npc_first&lt;br /&gt;
|Use this first unless an important action is castable. Can be combined with ac_npc important to further increase ranking.&lt;br /&gt;
|-&lt;br /&gt;
|ac_npc_important_last&lt;br /&gt;
|Only works consistently for actions that don&#039;t require momentum. If no other actions can be used, then this will be used.&lt;br /&gt;
|-&lt;br /&gt;
|ac_interrupt&lt;br /&gt;
|Action has an interrupt component.&lt;br /&gt;
|-&lt;br /&gt;
|ac_item&lt;br /&gt;
|Action is tied to an item.&lt;br /&gt;
|-&lt;br /&gt;
|ac_mana_heal&lt;br /&gt;
|Action has a momentum restore component.&lt;br /&gt;
|-&lt;br /&gt;
|ac_self_heal&lt;br /&gt;
|Action has a self heal component.&lt;br /&gt;
|-&lt;br /&gt;
|ac_taunt&lt;br /&gt;
|Action has a taunt component.&lt;br /&gt;
|-&lt;br /&gt;
|ac_mana_damage&lt;br /&gt;
|Action has a momentum damage component.&lt;br /&gt;
|-&lt;br /&gt;
|ac_npc_ignore_aggro&lt;br /&gt;
|The NPC caster should ignore the aggro system and pick targets at random.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Description variables ==&lt;br /&gt;
You can set a description and/or name to exactly: %P% when the action is tied to an [[Asset (Asset)|Asset]]. Then it will use the asset description/name.&lt;br /&gt;
&lt;br /&gt;
You can also use a special variable like below to automatically show the amount of damage/healing etc the action does based on your current stats, such as damage done effects. These variables also work in [[Wrapper (Asset)|wrapper]] descriptions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: Target Description/wrapper descriptions will also take target effects into consideration when calculating the number, such as damage taken reduction effects.&#039;&#039;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Variable&lt;br /&gt;
!Example&lt;br /&gt;
!Explanation&lt;br /&gt;
|-&lt;br /&gt;
|$&lt;br /&gt;
|$2&lt;br /&gt;
|2 multiplied by nr of stacks.&lt;br /&gt;
|-&lt;br /&gt;
|$D&lt;br /&gt;
|$D10&lt;br /&gt;
|10 multiplied by damage done effects.&lt;br /&gt;
|-&lt;br /&gt;
|$H&lt;br /&gt;
|$H10&lt;br /&gt;
|10 multiplied by healing done effects.&lt;br /&gt;
|-&lt;br /&gt;
|$N&lt;br /&gt;
|$DN10&lt;br /&gt;
|&#039;&#039;Wrapper effects only.&#039;&#039; Don&#039;t multiply the other variables by the stacks of the wrapper that has this variable.&lt;br /&gt;
|-&lt;br /&gt;
|$B&lt;br /&gt;
|$B10&lt;br /&gt;
|10 multiplied by block done effects.&lt;br /&gt;
|-&lt;br /&gt;
|$A&lt;br /&gt;
|$A10&lt;br /&gt;
|10 multiplied by arousal done effects.&lt;br /&gt;
|}&lt;br /&gt;
You can also freely combine the variables. Just make sure all the letters come before the number. Ex: $DH10 multiplies 10 by both healing and damage done.&lt;br /&gt;
&lt;br /&gt;
Instead of supplying a number you can also supply a [[math]] formula wrapped in {}. These also need to come after the letters.&lt;br /&gt;
&lt;br /&gt;
Ex: $D{ceil(se_Block/2)} = Damage done multiplier times half the sender&#039;s block value.&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=MathScript_Snippets&amp;diff=308</id>
		<title>MathScript Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=MathScript_Snippets&amp;diff=308"/>
		<updated>2025-09-25T17:49:00Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A collection of snippets you can use in math scripts.&lt;br /&gt;
&lt;br /&gt;
=== Update a dvar array on new day. ===&lt;br /&gt;
In this example, we use a dungeon with the label &amp;lt;code&amp;gt;sfq_town&amp;lt;/code&amp;gt; with the following dVars:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;last_trainer_reset&amp;lt;/code&amp;gt; Which we store the day when this math script was run last.&lt;br /&gt;
* &amp;lt;code&amp;gt;trainer_skills&amp;lt;/code&amp;gt; Where we store an array of 4 action labels that we&#039;ll use in conditions to decide which skills are available at a trainer.&lt;br /&gt;
The point of the script is to pick a random set of trainer skills each day to present to the player when visiting a trainer. We do this by having game actions checking if action labels are present in the trainer_skills dvar.&amp;lt;pre&amp;gt;setDvar(&amp;quot;sfq_town&amp;quot;,&amp;quot;last_trainer_reset&amp;quot;,&amp;quot;!$g_day&amp;quot;)&lt;br /&gt;
actions = getAssetLabelsRegex(&#039;Action&#039;, &#039;^sfq_pc&#039;)&lt;br /&gt;
shuffle(actions)&lt;br /&gt;
actions = arraySlice(actions, 0,4)&lt;br /&gt;
setDvar(&amp;quot;sfq_town&amp;quot;, &amp;quot;trainer_skills&amp;quot;, actions)&amp;lt;/pre&amp;gt;Explanation:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;setDvar(&amp;quot;sfq_town&amp;quot;,&amp;quot;last_trainer_reset&amp;quot;,&amp;quot;!$g_day&amp;quot;)&amp;lt;/code&amp;gt; Sets a dvar called last_trainer_reset in the dungeon labeled sfq_town to the current day. The !$ prefix in the setDvar function is used to mark that the rest of the data should be evaluated as a formula. g_day is a game mathvar (used in ALL formulas) and is an integer value specifying how many days have elapsed in the active game.&lt;br /&gt;
*&amp;lt;code&amp;gt;actions = getAssetLabelsRegex(&#039;Action&#039;, &#039;^sfq_pc&#039;)&amp;lt;/code&amp;gt; Scans through the Action library and return an array of all actions starting with sfq_pc (^sfq_pc is a regular expression).&lt;br /&gt;
*&amp;lt;code&amp;gt;shuffle(actions)&amp;lt;/code&amp;gt; Shuffles the action array.&lt;br /&gt;
*&amp;lt;code&amp;gt;actions = arraySlice(actions, 0,4)&amp;lt;/code&amp;gt; Get the first 4 actions of the array.&lt;br /&gt;
*&amp;lt;code&amp;gt;setDvar(&amp;quot;sfq_town&amp;quot;, &amp;quot;trainer_skills&amp;quot;, actions)&amp;lt;/code&amp;gt; Sets the trainer_skills dungeon var in the dungeon labeled sfq_town to the array of actions.&lt;br /&gt;
Said mathScript game action is run every time the player enters the gym.&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=MathScript_Snippets&amp;diff=307</id>
		<title>MathScript Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=MathScript_Snippets&amp;diff=307"/>
		<updated>2025-09-25T17:47:45Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A collection of snippets you can use in math scripts.&lt;br /&gt;
&lt;br /&gt;
=== Update a dvar array on new day. ===&lt;br /&gt;
In this example, we use a dungeon with the label &amp;lt;code&amp;gt;sfq_town&amp;lt;/code&amp;gt; with the following dVars:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;last_trainer_reset&amp;lt;/code&amp;gt; Which we store the day when this math script was run last.&lt;br /&gt;
* &amp;lt;code&amp;gt;trainer_skills&amp;lt;/code&amp;gt; Where we store an array of 4 action labels that we&#039;ll use in conditions to decide which skills are available at a trainer.&lt;br /&gt;
The point of the script is to pick a random set of trainer skills each day to present to the player when visiting a trainer. We do this by having game actions checking if action labels are present in the trainer_skills dvar.&amp;lt;pre&amp;gt;setDvar(&amp;quot;sfq_town&amp;quot;,&amp;quot;last_trainer_reset&amp;quot;,&amp;quot;!$g_day&amp;quot;)&lt;br /&gt;
actions = getAssetLabelsRegex(&#039;Action&#039;, &#039;^sfq_pc&#039;)&lt;br /&gt;
shuffle(actions)&lt;br /&gt;
actions = arraySlice(actions, 0,4)&lt;br /&gt;
setDvar(&amp;quot;sfq_town&amp;quot;, &amp;quot;trainer_skills&amp;quot;, actions)&amp;lt;/pre&amp;gt;Explanation:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;setDvar(&amp;quot;sfq_town&amp;quot;,&amp;quot;last_trainer_reset&amp;quot;,&amp;quot;!$g_day&amp;quot;)&amp;lt;/code&amp;gt; Sets a dvar called last_trainer_reset in the dungeon labeled sfq_town to the current day. The !$ prefix in the setDvar function is used to mark that the rest of the data should be evaluated as a formula. g_day is a game mathvar (used in ALL formulas) and is an integer value specifying how many days have elapsed in the active game.&lt;br /&gt;
*&amp;lt;code&amp;gt;actions = getAssetLabelsRegex(&#039;Action&#039;, &#039;^sfq_pc&#039;)&amp;lt;/code&amp;gt; Scans through the Action library and return an array of all actions starting with sfq_pc (^sfq_pc is a regular expression).&lt;br /&gt;
*&amp;lt;code&amp;gt;shuffle(actions)&amp;lt;/code&amp;gt; Shuffles the action array.&lt;br /&gt;
*&amp;lt;code&amp;gt;actions = arraySlice(actions, 0,4)&amp;lt;/code&amp;gt; Get the first 4 actions of the array.&lt;br /&gt;
*&amp;lt;code&amp;gt;setDvar(&amp;quot;sfq_town&amp;quot;, &amp;quot;trainer_skills&amp;quot;, actions)&amp;lt;/code&amp;gt; Sets the trainer_skills dungeon var in the dungeon labeled sfq_town to the array of actions.&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=MathScript_Snippets&amp;diff=306</id>
		<title>MathScript Snippets</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=MathScript_Snippets&amp;diff=306"/>
		<updated>2025-09-25T17:41:32Z</updated>

		<summary type="html">&lt;p&gt;JasX: Created page with &amp;quot;A collection of snippets you can use in math scripts.  === Update a dvar array on new day. === In this example, we use a dungeon with the label &amp;lt;code&amp;gt;sfq_town&amp;lt;/code&amp;gt; . We have the following dVars:  * &amp;lt;code&amp;gt;last_trainer_reset&amp;lt;/code&amp;gt; Which we store the day when this math script was run last. * &amp;lt;code&amp;gt;trainer_skills&amp;lt;/code&amp;gt; Where we store an array of 4 action labels that we&amp;#039;ll use in conditions to decide which skills are available at a trainer. &amp;lt;pre&amp;gt;setDvar(&amp;quot;sfq_town&amp;quot;,&amp;quot;last_t...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A collection of snippets you can use in math scripts.&lt;br /&gt;
&lt;br /&gt;
=== Update a dvar array on new day. ===&lt;br /&gt;
In this example, we use a dungeon with the label &amp;lt;code&amp;gt;sfq_town&amp;lt;/code&amp;gt; . We have the following dVars:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;last_trainer_reset&amp;lt;/code&amp;gt; Which we store the day when this math script was run last.&lt;br /&gt;
* &amp;lt;code&amp;gt;trainer_skills&amp;lt;/code&amp;gt; Where we store an array of 4 action labels that we&#039;ll use in conditions to decide which skills are available at a trainer.&lt;br /&gt;
&amp;lt;pre&amp;gt;setDvar(&amp;quot;sfq_town&amp;quot;,&amp;quot;last_trainer_reset&amp;quot;,&amp;quot;!$g_day&amp;quot;)&lt;br /&gt;
actions = getAssetLabelsRegex(&#039;Action&#039;, &#039;^sfq_pc&#039;)&lt;br /&gt;
shuffle(actions)&lt;br /&gt;
actions = arraySlice(actions, 0,4)&lt;br /&gt;
setDvar(&amp;quot;sfq_town&amp;quot;, &amp;quot;trainer_skills&amp;quot;, actions)&amp;lt;/pre&amp;gt;Explanation:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;setDvar(&amp;quot;sfq_town&amp;quot;,&amp;quot;last_trainer_reset&amp;quot;,&amp;quot;!$g_day&amp;quot;)&amp;lt;/code&amp;gt; Sets a dvar called last_trainer_reset in the dungeon labeled sfq_town to the current day.&lt;br /&gt;
*&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Effect_(Asset)&amp;diff=305</id>
		<title>Effect (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Effect_(Asset)&amp;diff=305"/>
		<updated>2025-09-25T10:10:09Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;An effect is a block of data that describes something that should affect a player, such as modifying HP or stats. Effects are tied to [[Wrapper (Asset)|Wrappers]] which may contain multiple effects. Effects are always triggered by events.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique label for your effect. &#039;&#039;&#039;Do not change this after setting up your effect!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Describe your effect. This is not used in game, but helps search in the editor.&lt;br /&gt;
|-&lt;br /&gt;
|Type&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Effect type. When you change this value, the description below will change.&lt;br /&gt;
|-&lt;br /&gt;
|Don&#039;t multiply by stacks&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|By default, most integer values will be multiplied by the nr of stacks in the parent wrapper. Checking this sets the stack count to a fixed 1.&lt;br /&gt;
|-&lt;br /&gt;
|Debug&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Used to output debug output. Only use if you&#039;re modifying the FQ source code.&lt;br /&gt;
|-&lt;br /&gt;
|Highlight&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Highlights the parent wrapper icon. If the effect is a non-passive type, it blinks. Otherwise it highlights while the effect conditions are matched.&lt;br /&gt;
|-&lt;br /&gt;
|Targets&lt;br /&gt;
|Array&lt;br /&gt;
|&lt;br /&gt;
|Sets what targets the effects should affect. Auto is usually the parent wrapper target.&lt;br /&gt;
|-&lt;br /&gt;
|Events&lt;br /&gt;
|Array&lt;br /&gt;
|&lt;br /&gt;
|List of events that should trigger the effect. internalWrapperTick is triggered when an instant wrapper is triggered, or a duration wrapper ticks. For most instant effects, you just want internalWrapperTick. You can use as many as you want.&lt;br /&gt;
|-&lt;br /&gt;
|Effect Data&lt;br /&gt;
|JSON&lt;br /&gt;
|&lt;br /&gt;
|A JSON object which changes based on the type of effect you&#039;re editing. Above the editor is a description of the fields you can use, and what the effect does.&lt;br /&gt;
|-&lt;br /&gt;
|Tags&lt;br /&gt;
|[[Tag]]&lt;br /&gt;
|&lt;br /&gt;
|Tags to apply to the target(s) while affected by the effect.&lt;br /&gt;
|-&lt;br /&gt;
|Conditions&lt;br /&gt;
|[[Condition (Asset)|Conditions]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions required for the effect to trigger, or in the case of modifier effects (such as stat modifiers), to apply to the target(s).&lt;br /&gt;
Example: You bind the effect to trigger on event actionMissed and attach the parent wrapper to PlayerA. PlayerB triggers an actionMissed event against PlayerC.&lt;br /&gt;
event.effect is this effect, evt.originalWrapper is the wrapper involved in the miss, and evt.wrapper this event.effect.parent. Sender is PlayerB, target is PlayerC.&lt;br /&gt;
|-&lt;br /&gt;
|Subconditions&lt;br /&gt;
|[[Condition (Asset)|Conditions]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions are always checked with sender/target being the same as the event that triggered the effect. However, if you use a target other than sender/target, and want to check conditions on the recipient, then you can use a subcondition. Sender of the subcondition is always the parent wrapper&#039;s owner.&lt;br /&gt;
Example: You bind the effect to trigger on event actionMissed with target set to aoe, and attach the parent wrapper to PlayerA. PlayerB triggers an actionMissed event against PlayerC.&lt;br /&gt;
event.effect is this effect, evt.originalWrapper is the wrapper involved in the miss, and evt.wrapper this event.effect.parent. Sender is the player affected by this effect&#039;s parent (holder). The effect then iterates through every player (because of AoE), sets that player as the target, and runs the effect on that target only if they match conditions. &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
&lt;br /&gt;
* If the target of the event that triggered the effect is the holder of the wrapper this effect is attached to, then it flips target/sender. So generally you want to flip so ta_ vars target the owner of the effect, whereas se_ will target the target of the effect. I don&#039;t remember why I made it this way, but I think it was important.&lt;br /&gt;
* By default, mathVar targets will be the target(s) set in the targets section. If you want to access the parent wrapper&#039;s sender or target, you have access to pws_ and pwt_. These stand for parentWrapperSender and parentWrapperTarget, and contain data about the effect parent wrapper\&#039;s send and target.&lt;br /&gt;
&lt;br /&gt;
   &lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Node_Editor&amp;diff=304</id>
		<title>Node Editor</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Node_Editor&amp;diff=304"/>
		<updated>2025-09-07T23:10:13Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The node editor offers a better overview over how an asset is connected. Currently this is used for [[Roleplay (Asset)|Roleplay]].&lt;br /&gt;
&lt;br /&gt;
Controls:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Input&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Click &amp;amp; Drag On Background&lt;br /&gt;
|Pans the node view.&lt;br /&gt;
|-&lt;br /&gt;
|Click &amp;amp; Drag On Block Header&lt;br /&gt;
|Moves a node.&lt;br /&gt;
|-&lt;br /&gt;
|Click &amp;amp; Drag On Block Node&lt;br /&gt;
|Draws a new node connection. Nodes can be connected right and left side of a block, and must match by color.&lt;br /&gt;
|-&lt;br /&gt;
|Ctrl + Click &amp;amp; Drag&lt;br /&gt;
|Drags a selection box, allowing you to select multiple blocks.&lt;br /&gt;
|-&lt;br /&gt;
|Right Click on Background&lt;br /&gt;
|Opens the global context menu (see below).&lt;br /&gt;
|-&lt;br /&gt;
|Right Click On Block&lt;br /&gt;
|Opens the block context menu (see below).&lt;br /&gt;
|-&lt;br /&gt;
|Right Click On Background With Multiple Selctions &lt;br /&gt;
|Opens the batch context menu (see below).&lt;br /&gt;
|-&lt;br /&gt;
|Shift + Click &amp;amp; Drag Block Header&lt;br /&gt;
|Clones the block (or all selected blocks if you have an active multi-block selection).&lt;br /&gt;
|-&lt;br /&gt;
|Mousewheel&lt;br /&gt;
|Zooms&lt;br /&gt;
|-&lt;br /&gt;
|Shift + Right Click On Block&lt;br /&gt;
|Resets block connection positions.&lt;br /&gt;
|-&lt;br /&gt;
|Right Click on Line&lt;br /&gt;
|Opens the line context menu (see below).&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Global Context Menu&lt;br /&gt;
!Option&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
| + &amp;lt;blockType&amp;gt;&lt;br /&gt;
|Inserts a new block of this type.&lt;br /&gt;
|-&lt;br /&gt;
|Pan To Root&lt;br /&gt;
|Pans to the root node.&lt;br /&gt;
|-&lt;br /&gt;
|Purge Position&lt;br /&gt;
|Resets all positions (can be useful is you&#039;ve lost the node positions).&lt;br /&gt;
|-&lt;br /&gt;
|Minimize All&lt;br /&gt;
|Minimizes all Blocks&lt;br /&gt;
|-&lt;br /&gt;
|Maximize All&lt;br /&gt;
|Maximizes all Blocks.&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Block Context Menu&lt;br /&gt;
!Option&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Align Inputs&lt;br /&gt;
|Moves connected nodes to this one.&lt;br /&gt;
|-&lt;br /&gt;
|Delete&lt;br /&gt;
|Deletes the node.&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Bath Context Menu&lt;br /&gt;
!Option&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Maximize&lt;br /&gt;
|Maximizes selected blocks.&lt;br /&gt;
|-&lt;br /&gt;
|Minimize&lt;br /&gt;
|Minimizes selected blocks.&lt;br /&gt;
|-&lt;br /&gt;
|Delete&lt;br /&gt;
|Deletes selected blocks.&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Line Context menu&lt;br /&gt;
!Option&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Delete&lt;br /&gt;
|Deletes the line&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Node_Editor&amp;diff=303</id>
		<title>Node Editor</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Node_Editor&amp;diff=303"/>
		<updated>2025-09-07T11:59:56Z</updated>

		<summary type="html">&lt;p&gt;JasX: Created page with &amp;quot;The node editor offers a better overview over how an asset is connected. Currently this is used for Roleplay.  Controls: {| class=&amp;quot;wikitable&amp;quot; |+ !Input !Description |- |Click &amp;amp; Drag On Background |Pans the node view. |- |Click &amp;amp; Drag On Block Header |Moves a node. |- |Click &amp;amp; Drag On Block Node |Draws a new node connection. Nodes can be connected right and left side of a block, and must match by color. |- |Ctrl + Click &amp;amp; Drag |Drags a selection box,...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The node editor offers a better overview over how an asset is connected. Currently this is used for [[Roleplay (Asset)|Roleplay]].&lt;br /&gt;
&lt;br /&gt;
Controls:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Input&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Click &amp;amp; Drag On Background&lt;br /&gt;
|Pans the node view.&lt;br /&gt;
|-&lt;br /&gt;
|Click &amp;amp; Drag On Block Header&lt;br /&gt;
|Moves a node.&lt;br /&gt;
|-&lt;br /&gt;
|Click &amp;amp; Drag On Block Node&lt;br /&gt;
|Draws a new node connection. Nodes can be connected right and left side of a block, and must match by color.&lt;br /&gt;
|-&lt;br /&gt;
|Ctrl + Click &amp;amp; Drag&lt;br /&gt;
|Drags a selection box, allowing you to select multiple blocks.&lt;br /&gt;
|-&lt;br /&gt;
|Right Click on Background&lt;br /&gt;
|Opens the global context menu (see below).&lt;br /&gt;
|-&lt;br /&gt;
|Right Click On Block&lt;br /&gt;
|Opens the block context menu (see below).&lt;br /&gt;
|-&lt;br /&gt;
|Right Click On Background With Multiple Selctions &lt;br /&gt;
|Opens the batch context menu (see below).&lt;br /&gt;
|-&lt;br /&gt;
|Shift + Click &amp;amp; Drag Block Header&lt;br /&gt;
|Clones the block (or all selected blocks if you have an active multi-block selection).&lt;br /&gt;
|-&lt;br /&gt;
|Mousewheel&lt;br /&gt;
|Zooms&lt;br /&gt;
|-&lt;br /&gt;
|Shift + Right Click On Block&lt;br /&gt;
|Resets block connection positions.&lt;br /&gt;
|-&lt;br /&gt;
|Right Click on Line&lt;br /&gt;
|Opens the line context menu (see below).&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Global Context Menu&lt;br /&gt;
!Option&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
| + &amp;lt;blockType&amp;gt;&lt;br /&gt;
|Inserts a new block of this type.&lt;br /&gt;
|-&lt;br /&gt;
|Pan To Root&lt;br /&gt;
|Pans to the root node.&lt;br /&gt;
|-&lt;br /&gt;
|Purge Position&lt;br /&gt;
|Resets all positions (can be useful is you&#039;ve lost the node positions, which aren&#039;t saved on export).&lt;br /&gt;
|-&lt;br /&gt;
|Minimize All&lt;br /&gt;
|Minimizes all Blocks&lt;br /&gt;
|-&lt;br /&gt;
|Maximize All&lt;br /&gt;
|Maximizes all Blocks.&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Block Context Menu&lt;br /&gt;
!Option&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Align Inputs&lt;br /&gt;
|Moves connected nodes to this one.&lt;br /&gt;
|-&lt;br /&gt;
|Delete&lt;br /&gt;
|Deletes the node.&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Bath Context Menu&lt;br /&gt;
!Option&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Maximize&lt;br /&gt;
|Maximizes selected blocks.&lt;br /&gt;
|-&lt;br /&gt;
|Minimize&lt;br /&gt;
|Minimizes selected blocks.&lt;br /&gt;
|-&lt;br /&gt;
|Delete&lt;br /&gt;
|Deletes selected blocks.&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Line Context menu&lt;br /&gt;
!Option&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Delete&lt;br /&gt;
|Deletes the line&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Roleplay_(Asset)&amp;diff=302</id>
		<title>Roleplay (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Roleplay_(Asset)&amp;diff=302"/>
		<updated>2025-09-03T21:58:29Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Roleplay is the dialog popup with multiple options you may encounter. In order to trigger a roleplay, you need to tie it to a [[Game Action (Asset)|game action]], generally a unique one inside of an [[Encounter (Asset)|encounter]].&lt;br /&gt;
&lt;br /&gt;
This is the asset reference. If you want a tutorial, you can check out [[Creating a Roleplay]].&lt;br /&gt;
&lt;br /&gt;
=== Definitely Use Outliner Mode ===&lt;br /&gt;
Click the Outliner button to enter outliner mode. This is a vastly superior mode of designing your roleplays. Right click to add a node, and then simply drag and drop to connect them. You can also right click a node or path to delete it. Some features are only availabe in the outliner.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique label for your roleplay. &#039;&#039;&#039;Do not edit after setting up your roleplay.&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Description&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A description that&#039;s only visible in the editor. Helps you organize roleplays.&lt;br /&gt;
|-&lt;br /&gt;
|Portrait&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to a portrait, or an [[Icon]]. Portrait can also be left empty to auto fetch from player. And it can be overridden in [[Roleplay Stage (Asset)|roleplay stages]].&lt;br /&gt;
|-&lt;br /&gt;
|Persistent&lt;br /&gt;
|Boolean&lt;br /&gt;
|True&lt;br /&gt;
|A persistent roleplay maintains its state. Otherwise the roleplay resets when you close it.&lt;br /&gt;
|-&lt;br /&gt;
|Once&lt;br /&gt;
|Boolean&lt;br /&gt;
|True&lt;br /&gt;
|Makes the roleplay only happen once. When closed, the roleplay cannot be reopened.&lt;br /&gt;
|-&lt;br /&gt;
|Auto Play&lt;br /&gt;
|Boolean&lt;br /&gt;
|True&lt;br /&gt;
|Automatically plays the roleplay when encountered.&lt;br /&gt;
|-&lt;br /&gt;
|Auto Play Once&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Requires auto play. Makes the roleplay only auto play once.&lt;br /&gt;
|-&lt;br /&gt;
|No Attach&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Allows the RP to auto play, but no speech interaction is added to the player, preventing them from picking it up after exiting.&lt;br /&gt;
|-&lt;br /&gt;
|rpVars Persistent&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Makes roleplay variables persistent. Otherwise they reset when the roleplay is closed. Consider using dungeon vars if the outcome of a roleplay should affect something in the game outside of the roleplay.&lt;br /&gt;
|-&lt;br /&gt;
|Music&lt;br /&gt;
|[[Music (Asset)|Music]]&lt;br /&gt;
|&lt;br /&gt;
|If set, music is overridden with this track while the roleplay is open.&lt;br /&gt;
|-&lt;br /&gt;
|Player&lt;br /&gt;
|[[Player (Asset)|Player]]&lt;br /&gt;
|&lt;br /&gt;
|When set, this player is used for the portrait and speech bubbles.&lt;br /&gt;
|-&lt;br /&gt;
|Stages&lt;br /&gt;
|[[Roleplay Stage (Asset)|Roleplay Stage]]&lt;br /&gt;
|&lt;br /&gt;
|Stages attached to this roleplay. I strongly suggest using the outliner instead of manually creating stages.&lt;br /&gt;
|-&lt;br /&gt;
|Outliner&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Opens the RP outliner.&lt;br /&gt;
|-&lt;br /&gt;
|Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions needed to start the roleplay.&lt;br /&gt;
|-&lt;br /&gt;
|Player Conditoins&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|By default, roleplays will use the player who triggered it as the roleplay player. Roleplay players can be accessed by %P, %P2 etc and the roleplay players can be modified inside of an RP. You can alternatively add player conditions, then all players who match these conditions will be added as RP players (Including NPCs, so consider using targetOnPlayerTeam). The order of this list is random.&lt;br /&gt;
|-&lt;br /&gt;
|Min Players&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Minimum players that need to pass player conditions in order to start the RP. Setting to -1 means all players on the player team must match.&lt;br /&gt;
|-&lt;br /&gt;
|Max Players&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Maximum players that should be stored as RP targets. The roleplay can still start if exceeded, but the RP Players will be capped to this amount.&lt;br /&gt;
|-&lt;br /&gt;
|Game Actions&lt;br /&gt;
|[[Game Action (Asset)|Game Action]]&lt;br /&gt;
|&lt;br /&gt;
|Game actions to trigger when the RP is started.&lt;br /&gt;
|-&lt;br /&gt;
|Close Actions&lt;br /&gt;
|[[Game Action (Asset)|Game Action]]&lt;br /&gt;
|&lt;br /&gt;
|Game actions to trigger when the RP ends.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Using the outliner ==&lt;br /&gt;
&lt;br /&gt;
* You can click and drag the header of all assets to move it.&lt;br /&gt;
* Clicking the middle of an asset will open an editor window for that asset.&lt;br /&gt;
* Right click the background to add a new asset. You can also use Pan To Root to go back to the root roleplay node.&lt;br /&gt;
* Be careful with purge positions as it resets all asset positions back to default.&lt;br /&gt;
* Drag the little round connectors from the right edge of one asset to the left edge of another. The colors must match.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+Outliner Assets&lt;br /&gt;
!Asset&lt;br /&gt;
!Connections&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Roleplay&lt;br /&gt;
|[[Roleplay Stage (Asset)|Stage]]&lt;br /&gt;
|This is the root roleplay node. All roleplays have exactly one.&lt;br /&gt;
|-&lt;br /&gt;
|Stage&lt;br /&gt;
|[[Roleplay Option (Asset)|Reply]], [[Roleplay Stage (Asset)|Stage]]&lt;br /&gt;
|Stage is a text that the NPC will say (or may be silent). When connected directly to another stage, a [Continue] reply is automatically added pointing to said stage. If no reply or stage is connected, a [Leave] option is automatically added.&lt;br /&gt;
|-&lt;br /&gt;
|Reply&lt;br /&gt;
|[[Roleplay Goto (Asset)|Goto]], [[Roleplay Stage (Asset)|Stage]]&lt;br /&gt;
|A reply is an option that the player can click. Goto connections are checked first against their conditions. A stage connection is always last.&lt;br /&gt;
|-&lt;br /&gt;
|Goto&lt;br /&gt;
|[[Roleplay Stage (Asset)|Stage]]&lt;br /&gt;
|A goto option is an invisible flow control block. You use them to take the conversation to a different stage based on the goto conditoins.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Procedural_Dungeon_(Asset)&amp;diff=301</id>
		<title>Procedural Dungeon (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Procedural_Dungeon_(Asset)&amp;diff=301"/>
		<updated>2025-08-30T21:17:34Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This lets you create procedural dungeons (exploration dungeons). In order to link a procedural dungeon to the world, create a door in the dungeon room and double click it to add a game action of type &amp;quot;proceduralDungeon&amp;quot;, set the label to a unique label for your dungeon, and then link this dungeon template to the game action.&lt;br /&gt;
&lt;br /&gt;
This is the asset reference. You can find a tutorial at [[Creating an Exploration Dungeon]].&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique label for your procedural dungeon. &#039;&#039;&#039;Do not modify after setting up!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Fog override&lt;br /&gt;
|Float&lt;br /&gt;
|0&lt;br /&gt;
|Use 0 to turn off. See [[Room (Asset)|Room]] for more information.&lt;br /&gt;
|-&lt;br /&gt;
|Ambient light &lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Overrides ambient light. See [[Room (Asset)|Room]] for more information.&lt;br /&gt;
|-&lt;br /&gt;
|Ambiance&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to an ambient OGG file to use, unless the room itself has ambient set.&lt;br /&gt;
|-&lt;br /&gt;
|Ambiance volume&lt;br /&gt;
|Float&lt;br /&gt;
|0.2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Saturation&lt;br /&gt;
|Float&lt;br /&gt;
|1.3&lt;br /&gt;
|Dungeon color saturation. Can be overridden in rooms. See [[Room (Asset)|Room]] for more info.&lt;br /&gt;
|-&lt;br /&gt;
|Max Treasures&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Sets a hard cap on nr of treasures in the dungeon. -1 defaults to 25% of rooms. The total nr generated will never exceed this value, no matter what you set in the flow nodes.&lt;br /&gt;
|-&lt;br /&gt;
|Max Exp Events&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Defaults to 20% of all rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Progress Tracker&lt;br /&gt;
|Boolean&lt;br /&gt;
|true&lt;br /&gt;
|Shows the nr of rooms you have explored in this dungeon at the top of the screen.&lt;br /&gt;
|-&lt;br /&gt;
|Reward Cartograph&lt;br /&gt;
|Boolean&lt;br /&gt;
|true&lt;br /&gt;
|If set to false, disable the dungeon exploration reward, including &amp;quot;dungeon explored&amp;quot; popup, exp, and cartograph rewards.&lt;br /&gt;
|-&lt;br /&gt;
|Reverb Type&lt;br /&gt;
|String&lt;br /&gt;
|Room Mesh&lt;br /&gt;
|Lets you set reverb type for your dungeon unless overridden by the rooms themselves. Room Mesh will use the room mesh settings.&lt;br /&gt;
|-&lt;br /&gt;
|Reverb intensity&lt;br /&gt;
|Float&lt;br /&gt;
|PASS&lt;br /&gt;
|Setting to pass automates it. Otherwise you can override the room asset reverb intensity.&lt;br /&gt;
|-&lt;br /&gt;
|Lowpass filter&lt;br /&gt;
|Float&lt;br /&gt;
|PASS&lt;br /&gt;
|Setting to pass automates it. Otherwise you can override the room asset lowpass filter. Mainly used for underwater dungeons.&lt;br /&gt;
|-&lt;br /&gt;
|Test Audio&lt;br /&gt;
|N/A&lt;br /&gt;
|&lt;br /&gt;
|Plays a random sample with your audio settings.&lt;br /&gt;
|-&lt;br /&gt;
|Unique Consumables&lt;br /&gt;
|[[Asset (Asset)|Asset]]&lt;br /&gt;
|&lt;br /&gt;
|Sets the [[Dungeon (Asset)|dungeon]] consumables field.&lt;br /&gt;
|-&lt;br /&gt;
|Ignore Global Consumables in autoLoot&lt;br /&gt;
|Boolean&lt;br /&gt;
|false&lt;br /&gt;
|Maps to the [[Dungeon (Asset)|dungeon]] l_no_auto field.&lt;br /&gt;
|-&lt;br /&gt;
|Ignore asset templates in autoLoot&lt;br /&gt;
|Boolean&lt;br /&gt;
|false&lt;br /&gt;
|Maps to the [[Dungeon (Asset)|dungeon]] l_no_cons field.&lt;br /&gt;
|-&lt;br /&gt;
|Rooms&lt;br /&gt;
|[[Dungeon Sub Template (Asset)|Sub Template]]&lt;br /&gt;
|&lt;br /&gt;
|Adds rooms to the list of rooms that can be added.&lt;br /&gt;
|-&lt;br /&gt;
|Encounters&lt;br /&gt;
|[[Dungeon Sub Template (Asset)|Sub Template]]&lt;br /&gt;
|&lt;br /&gt;
|Adds encounters that can be placed randomly in the dungeon (as long as conditions match the room).&lt;br /&gt;
|-&lt;br /&gt;
|Ambient Music&lt;br /&gt;
|[[Music (Asset)|Music]]&lt;br /&gt;
|&lt;br /&gt;
|Sets music to play in the dungeon. Note that rooms/encounters/RP may override this.&lt;br /&gt;
|-&lt;br /&gt;
|Combat Music&lt;br /&gt;
|[[Music (Asset)|Music]]&lt;br /&gt;
|&lt;br /&gt;
|Sets combat music to play in the dungeon. Note that rooms/encounters/RP may override this.&lt;br /&gt;
|-&lt;br /&gt;
|Force Start Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|One or many encounters that must be placed at start. If multiple encounters are picked, the order is randomized and the first viable encounter is played.&lt;br /&gt;
|-&lt;br /&gt;
|Force End Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|One or many encounters that must be placed in the final room. If multiple encounters are picked, the order of encounters is shuffled. Cannot be used if a template quest is used.&lt;br /&gt;
|-&lt;br /&gt;
|Flow Map&lt;br /&gt;
|[[Dungeon Flow Node (Asset)|Dungeon Flow Node]]&lt;br /&gt;
|&lt;br /&gt;
|You can use flow nodes to enforce a certain layout. Such as &amp;quot;start with a forest&amp;quot;, &amp;quot;then a settlement&amp;quot; etc. See the flow node asset type for more info. Using flow nodes will override the nr of cells setting in the procedural dungeon game action.&lt;br /&gt;
|-&lt;br /&gt;
|Procedural Quests&lt;br /&gt;
|[[Quest (Asset)|Quest]]&lt;br /&gt;
|&lt;br /&gt;
|Quests that can be offered here. Note that these quests are marked as procedural.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Dungeon_Sub_Template_(Asset)&amp;diff=300</id>
		<title>Dungeon Sub Template (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Dungeon_Sub_Template_(Asset)&amp;diff=300"/>
		<updated>2025-08-30T21:01:54Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Used to set conditions for rooms and encounters attached to a procedural dungeon.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Room/Encounter&lt;br /&gt;
|[[Room (Asset)|Room]] / [[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|Asset to add conditions to.&lt;br /&gt;
|-&lt;br /&gt;
|Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions needed to validate to add the room. Often Z position conditions.&lt;br /&gt;
|-&lt;br /&gt;
|Min Z / Max Z&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Only available in room templates. Sets the min and max z coordinates where these rooms can be placed. &#039;&#039;&#039;Do not use Z level conditions in Room type subtemplates, it will fail to generate! Use Min Z / Max Z instead!&#039;&#039;&#039;&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=299</id>
		<title>Dungeon Flow Node (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=299"/>
		<updated>2025-08-30T20:45:40Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
A flow node is used to create a general layout for an advanced procedural dungeon. Each node can have multiple condition groups, but only one is ever picked. These condition groups decide which room templates should be available in that group. Such as cave tiles that also support forest tiles etc. These tiles must be specified in Room Templates, and the conditions of the room templates still apply.&lt;br /&gt;
&lt;br /&gt;
===== Caveats: =====&lt;br /&gt;
&lt;br /&gt;
* The first flow node used in a dungeon template MUST be able to start at coordinates 0,0,0. Because that&#039;s where the entrance room is placed.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Optional, just used in the editor to remind you of the purpose of the flow node, such as &amp;quot;forest&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
|Optional&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When checked, this flow node may be ignored at random.&lt;br /&gt;
|-&lt;br /&gt;
|Friendly&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|You can use the flowNodeFriendly condition type in the various conditions fields in your dungeon template.&lt;br /&gt;
|-&lt;br /&gt;
|Offer Quest&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Can offer a quest in any of these rooms. You must setup quests in the [[Procedural Dungeon (Asset)|DungeonTemplate]] to use this.&lt;br /&gt;
|-&lt;br /&gt;
|Min Rooms&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Minimum nr of rooms to generate. A minimum of 1 is enforced.&lt;br /&gt;
|-&lt;br /&gt;
|Max Rooms&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Maximum nr of rooms to generate. Anything below Min Rooms is clamped at Min Rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Shape&lt;br /&gt;
|Constant&lt;br /&gt;
|Random&lt;br /&gt;
|Sets the dungeon shape. Random will place rooms at random. Linear will generate all rooms in a sequence. SemiLinear will generate a few side rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Min Z&lt;br /&gt;
|Int&lt;br /&gt;
| -3&lt;br /&gt;
|Sets how far below the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|Max Z&lt;br /&gt;
|Int&lt;br /&gt;
|3&lt;br /&gt;
|Sets how far above the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|No Mimics&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Disables mimics.&lt;br /&gt;
|-&lt;br /&gt;
|Random Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Enables random encounters (exploration events).&lt;br /&gt;
|-&lt;br /&gt;
|Levers&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Place levers.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Items&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has items to collect, you can place them in this room&#039;s cells. Recommended to only not do it on a flownode before the one that offers the quest.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has specific encounters, you can place them here.&lt;br /&gt;
|-&lt;br /&gt;
|Max Treasures&lt;br /&gt;
|Boolean&lt;br /&gt;
| -1&lt;br /&gt;
|Sets how many treasures can be placed in this flowNode. Note that this value will never override the grand total set in the [[Procedural Dungeon (Asset)|DungeonTemplate]].&lt;br /&gt;
|-&lt;br /&gt;
|Condition Groups&lt;br /&gt;
|[[Dungeon Sub Template (Asset)|Dungeon Sub Template]]&lt;br /&gt;
|&lt;br /&gt;
|When generated, these are shuffled, and only one of these are picked. At least one room must pass conditions and be valid to be used with the dungeon template quest. If none are supplied, a condition-free group is used.&lt;br /&gt;
|-&lt;br /&gt;
|Vaible Templates&lt;br /&gt;
|[[Dungeon (Asset)|Dungeon]]&lt;br /&gt;
|&lt;br /&gt;
|Allows the generator to link template dungeons in this node.&lt;br /&gt;
|-&lt;br /&gt;
|Entry Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions that need to be met for the door linking to this flow node to be treated as &amp;quot;unlocked&amp;quot;. Do not use this on the first flowNode of your dungeon. To prevent the player from entering a quest objective area before accepting the quest, consider adding a questAccepted condition that isn&#039;t pointing to a quest. &lt;br /&gt;
|-&lt;br /&gt;
|Force Start Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the first room will get these encounters as its encounters, and one is picked at random.&lt;br /&gt;
|-&lt;br /&gt;
|Force End Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the last room generated will have its encounters set to this one.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=298</id>
		<title>Dungeon Flow Node (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=298"/>
		<updated>2025-08-30T20:37:07Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
A flow node is used to create a general layout for an advanced procedural dungeon. Each node can have multiple condition groups, but only one is ever picked. These condition groups decide which room templates should be available in that group. Such as cave tiles that also support forest tiles etc. These tiles must be specified in Room Templates, and the conditions of the room templates still apply.&lt;br /&gt;
&lt;br /&gt;
===== Caveats: =====&lt;br /&gt;
&lt;br /&gt;
* The first flow node used in a dungeon template MUST be able to start at coordinates 0,0,0. Because that&#039;s where the entrance room is placed.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Optional, just used in the editor to remind you of the purpose of the flow node, such as &amp;quot;forest&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
|Optional&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When checked, this flow node may be ignored at random.&lt;br /&gt;
|-&lt;br /&gt;
|Friendly&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|You can use the flowNodeFriendly condition type in the various conditions fields in your dungeon template.&lt;br /&gt;
|-&lt;br /&gt;
|Offer Quest&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Can offer a quest in any of these rooms. You must setup quests in the [[Procedural Dungeon (Asset)|DungeonTemplate]] to use this.&lt;br /&gt;
|-&lt;br /&gt;
|Min Rooms&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Minimum nr of rooms to generate. A minimum of 1 is enforced.&lt;br /&gt;
|-&lt;br /&gt;
|Max Rooms&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Maximum nr of rooms to generate. Anything below Min Rooms is clamped at Min Rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Shape&lt;br /&gt;
|Constant&lt;br /&gt;
|Random&lt;br /&gt;
|Sets the dungeon shape. Random will place rooms at random. Linear will generate all rooms in a sequence. SemiLinear will generate a few side rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Min Z&lt;br /&gt;
|Int&lt;br /&gt;
| -3&lt;br /&gt;
|Sets how far below the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|Max Z&lt;br /&gt;
|Int&lt;br /&gt;
|3&lt;br /&gt;
|Sets how far above the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|No Mimics&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Disables mimics.&lt;br /&gt;
|-&lt;br /&gt;
|Random Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Enables random encounters (exploration events).&lt;br /&gt;
|-&lt;br /&gt;
|Levers&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Place levers.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Items&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has items to collect, you can place them in this room&#039;s cells. Recommended to only not do it on a flownode before the one that offers the quest.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has specific encounters, you can place them here.&lt;br /&gt;
|-&lt;br /&gt;
|Max Treasures&lt;br /&gt;
|Boolean&lt;br /&gt;
| -1&lt;br /&gt;
|Sets how many treasures can be placed in this flowNode. Note that this value will never override the grand total set in the [[Procedural Dungeon (Asset)|DungeonTemplate]].&lt;br /&gt;
|-&lt;br /&gt;
|Condition Groups&lt;br /&gt;
|[[Dungeon Sub Template (Asset)|Dungeon Sub Template]]&lt;br /&gt;
|&lt;br /&gt;
|When generated, these are shuffled, and only one of these are picked. At least one room must pass conditions and be valid to be used with the dungeon template quest.&lt;br /&gt;
|-&lt;br /&gt;
|Vaible Templates&lt;br /&gt;
|[[Dungeon (Asset)|Dungeon]]&lt;br /&gt;
|&lt;br /&gt;
|Allows the generator to link template dungeons in this node.&lt;br /&gt;
|-&lt;br /&gt;
|Entry Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions that need to be met for the door linking to this flow node to be treated as &amp;quot;unlocked&amp;quot;. Do not use this on the first flowNode of your dungeon. To prevent the player from entering a quest objective area before accepting the quest, consider adding a questAccepted condition that isn&#039;t pointing to a quest. &lt;br /&gt;
|-&lt;br /&gt;
|Force Start Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the first room will get these encounters as its encounters, and one is picked at random.&lt;br /&gt;
|-&lt;br /&gt;
|Force End Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the last room generated will have its encounters set to this one.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=297</id>
		<title>Dungeon Flow Node (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Dungeon_Flow_Node_(Asset)&amp;diff=297"/>
		<updated>2025-08-28T14:56:34Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A flow node is used to create a general layout for an advanced procedural dungeon. Each node can have multiple condition groups, but only one is ever picked. These condition groups decide which room templates should be available in that group. Such as cave tiles that also support forest tiles etc. These tiles must be specified in Room Templates, and the conditions of the room templates still apply.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Name&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Optional, just used in the editor to remind you of the purpose of the flow node, such as &amp;quot;forest&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
|Optional&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|When checked, this flow node may be ignored at random.&lt;br /&gt;
|-&lt;br /&gt;
|Friendly&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|You can use the flowNodeFriendly condition type in the various conditions fields in your dungeon template.&lt;br /&gt;
|-&lt;br /&gt;
|Offer Quest&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Can offer a quest in any of these rooms. You must setup quests in the [[Procedural Dungeon (Asset)|DungeonTemplate]] to use this.&lt;br /&gt;
|-&lt;br /&gt;
|Min Rooms&lt;br /&gt;
|Int&lt;br /&gt;
|1&lt;br /&gt;
|Minimum nr of rooms to generate. A minimum of 1 is enforced.&lt;br /&gt;
|-&lt;br /&gt;
|Max Rooms&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Maximum nr of rooms to generate. Anything below Min Rooms is clamped at Min Rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Shape&lt;br /&gt;
|Constant&lt;br /&gt;
|Random&lt;br /&gt;
|Sets the dungeon shape. Random will place rooms at random. Linear will generate all rooms in a sequence. SemiLinear will generate a few side rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Min Z&lt;br /&gt;
|Int&lt;br /&gt;
| -3&lt;br /&gt;
|Sets how far below the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|Max Z&lt;br /&gt;
|Int&lt;br /&gt;
|3&lt;br /&gt;
|Sets how far above the entrance on the Z axis we can go.&lt;br /&gt;
|-&lt;br /&gt;
|No Mimics&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Disables mimics.&lt;br /&gt;
|-&lt;br /&gt;
|Random Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Enables random encounters (exploration events).&lt;br /&gt;
|-&lt;br /&gt;
|Levers&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|Place levers.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Items&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has items to collect, you can place them in this room&#039;s cells. Recommended to only not do it on a flownode before the one that offers the quest.&lt;br /&gt;
|-&lt;br /&gt;
|Quest Encounters&lt;br /&gt;
|Boolean&lt;br /&gt;
|False&lt;br /&gt;
|If the picked quest has specific encounters, you can place them here.&lt;br /&gt;
|-&lt;br /&gt;
|Max Treasures&lt;br /&gt;
|Boolean&lt;br /&gt;
| -1&lt;br /&gt;
|Sets how many treasures can be placed in this flowNode. Note that this value will never override the grand total set in the [[Procedural Dungeon (Asset)|DungeonTemplate]].&lt;br /&gt;
|-&lt;br /&gt;
|Condition Groups&lt;br /&gt;
|[[Dungeon Sub Template (Asset)|Dungeon Sub Template]]&lt;br /&gt;
|&lt;br /&gt;
|When generated, these are shuffled, and only one of these are picked. At least one room must pass conditions and be valid to be used with the dungeon template quest.&lt;br /&gt;
|-&lt;br /&gt;
|Vaible Templates&lt;br /&gt;
|[[Dungeon (Asset)|Dungeon]]&lt;br /&gt;
|&lt;br /&gt;
|Allows the generator to link template dungeons in this node.&lt;br /&gt;
|-&lt;br /&gt;
|Entry Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions that need to be met for the door linking to this flow node to be treated as &amp;quot;unlocked&amp;quot;. Do not use this on the first flowNode of your dungeon. To prevent the player from entering a quest objective area before accepting the quest, consider adding a questAccepted condition that isn&#039;t pointing to a quest. &lt;br /&gt;
|-&lt;br /&gt;
|Force Start Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the first room will get these encounters as its encounters, and one is picked at random.&lt;br /&gt;
|-&lt;br /&gt;
|Force End Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|When set, the last room generated will have its encounters set to this one.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Dungeon_Sub_Template_(Asset)&amp;diff=296</id>
		<title>Dungeon Sub Template (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Dungeon_Sub_Template_(Asset)&amp;diff=296"/>
		<updated>2025-08-28T14:44:23Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Used to set conditions for rooms and encounters attached to a procedural dungeon.&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Room/Encounter&lt;br /&gt;
|[[Room (Asset)|Room]] / [[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|Asset to add conditions to.&lt;br /&gt;
|-&lt;br /&gt;
|Conditions&lt;br /&gt;
|[[Condition (Asset)|Condition]]&lt;br /&gt;
|&lt;br /&gt;
|Conditions needed to validate to add the room. Often Z position conditions.&lt;br /&gt;
|-&lt;br /&gt;
|Min Z / Max Z&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|Only available in room templates. Sets the min and max z coordinates where these rooms can be placed.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Procedural_Dungeon_(Asset)&amp;diff=295</id>
		<title>Procedural Dungeon (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Procedural_Dungeon_(Asset)&amp;diff=295"/>
		<updated>2025-08-28T14:43:27Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This lets you create procedural dungeons (exploration dungeons). In order to link a procedural dungeon to the world, create a door in the dungeon room and double click it to add a game action of type &amp;quot;proceduralDungeon&amp;quot;, set the label to a unique label for your dungeon, and then link this dungeon template to the game action.&lt;br /&gt;
&lt;br /&gt;
This is the asset reference. You can find a tutorial at [[Creating an Exploration Dungeon]].&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique label for your procedural dungeon. &#039;&#039;&#039;Do not modify after setting up!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Fog override&lt;br /&gt;
|Float&lt;br /&gt;
|0&lt;br /&gt;
|Use 0 to turn off. See [[Room (Asset)|Room]] for more information.&lt;br /&gt;
|-&lt;br /&gt;
|Ambient light &lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Overrides ambient light. See [[Room (Asset)|Room]] for more information.&lt;br /&gt;
|-&lt;br /&gt;
|Ambiance&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to an ambient OGG file to use, unless the room itself has ambient set.&lt;br /&gt;
|-&lt;br /&gt;
|Ambiance volume&lt;br /&gt;
|Float&lt;br /&gt;
|0.2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Saturation&lt;br /&gt;
|Float&lt;br /&gt;
|1.3&lt;br /&gt;
|Dungeon color saturation. Can be overridden in rooms. See [[Room (Asset)|Room]] for more info.&lt;br /&gt;
|-&lt;br /&gt;
|Max Treasures&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Sets a hard cap on nr of treasures in the dungeon. -1 defaults to 25% of rooms. The total nr generated will never exceed this value, no matter what you set in the flow nodes.&lt;br /&gt;
|-&lt;br /&gt;
|Max Exp Events&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Defaults to 20% of all rooms.&lt;br /&gt;
|-&lt;br /&gt;
|Progress Tracker&lt;br /&gt;
|Boolean&lt;br /&gt;
|true&lt;br /&gt;
|Shows the nr of rooms you have explored in this dungeon at the top of the screen.&lt;br /&gt;
|-&lt;br /&gt;
|Reward Cartograph&lt;br /&gt;
|Boolean&lt;br /&gt;
|true&lt;br /&gt;
|If set to false, disable the dungeon exploration reward, including &amp;quot;dungeon explored&amp;quot; popup, exp, and cartograph rewards.&lt;br /&gt;
|-&lt;br /&gt;
|Reverb Type&lt;br /&gt;
|String&lt;br /&gt;
|Room Mesh&lt;br /&gt;
|Lets you set reverb type for your dungeon unless overridden by the rooms themselves. Room Mesh will use the room mesh settings.&lt;br /&gt;
|-&lt;br /&gt;
|Reverb intensity&lt;br /&gt;
|Float&lt;br /&gt;
|PASS&lt;br /&gt;
|Setting to pass automates it. Otherwise you can override the room asset reverb intensity.&lt;br /&gt;
|-&lt;br /&gt;
|Lowpass filter&lt;br /&gt;
|Float&lt;br /&gt;
|PASS&lt;br /&gt;
|Setting to pass automates it. Otherwise you can override the room asset lowpass filter. Mainly used for underwater dungeons.&lt;br /&gt;
|-&lt;br /&gt;
|Test Audio&lt;br /&gt;
|N/A&lt;br /&gt;
|&lt;br /&gt;
|Plays a random sample with your audio settings.&lt;br /&gt;
|-&lt;br /&gt;
|Unique Consumables&lt;br /&gt;
|[[Asset (Asset)|Asset]]&lt;br /&gt;
|&lt;br /&gt;
|Sets the [[Dungeon (Asset)|dungeon]] consumables field.&lt;br /&gt;
|-&lt;br /&gt;
|Ignore Global Consumables in autoLoot&lt;br /&gt;
|Boolean&lt;br /&gt;
|false&lt;br /&gt;
|Maps to the [[Dungeon (Asset)|dungeon]] l_no_auto field.&lt;br /&gt;
|-&lt;br /&gt;
|Ignore asset templates in autoLoot&lt;br /&gt;
|Boolean&lt;br /&gt;
|false&lt;br /&gt;
|Maps to the [[Dungeon (Asset)|dungeon]] l_no_cons field.&lt;br /&gt;
|-&lt;br /&gt;
|Template Dungeons&lt;br /&gt;
|[[Dungeon (Asset)|Dungeon]]&lt;br /&gt;
|&lt;br /&gt;
|Attaches rooms from a dungeon. These can currently only be attached to DungeonRoomAssets tagged as &#039;&#039;m_house_ent&#039;&#039; and &#039;&#039;m_door_autoxy&#039;&#039;.&lt;br /&gt;
|-&lt;br /&gt;
|Room Templates&lt;br /&gt;
|[[Dungeon Sub Template (Asset)|Sub Template]]&lt;br /&gt;
|&lt;br /&gt;
|Adds rooms to the list of rooms that can be added.&lt;br /&gt;
|-&lt;br /&gt;
|Encounters&lt;br /&gt;
|[[Dungeon Sub Template (Asset)|Sub Template]]&lt;br /&gt;
|&lt;br /&gt;
|Adds encounters that can be placed randomly in the dungeon (as long as conditions match the room).&lt;br /&gt;
|-&lt;br /&gt;
|Ambient Music&lt;br /&gt;
|[[Music (Asset)|Music]]&lt;br /&gt;
|&lt;br /&gt;
|Sets music to play in the dungeon. Note that rooms/encounters/RP may override this.&lt;br /&gt;
|-&lt;br /&gt;
|Combat Music&lt;br /&gt;
|[[Music (Asset)|Music]]&lt;br /&gt;
|&lt;br /&gt;
|Sets combat music to play in the dungeon. Note that rooms/encounters/RP may override this.&lt;br /&gt;
|-&lt;br /&gt;
|Force Start Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|One or many encounters that must be placed at start. If multiple encounters are picked, the order is randomized and the first viable encounter is played.&lt;br /&gt;
|-&lt;br /&gt;
|Force End Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|One or many encounters that must be placed in the final room. If multiple encounters are picked, the order of encounters is shuffled. Cannot be used if a template quest is used.&lt;br /&gt;
|-&lt;br /&gt;
|Flow Map&lt;br /&gt;
|[[Dungeon Flow Node (Asset)|Dungeon Flow Node]]&lt;br /&gt;
|&lt;br /&gt;
|You can use flow nodes to enforce a certain layout. Such as &amp;quot;start with a forest&amp;quot;, &amp;quot;then a settlement&amp;quot; etc. See the flow node asset type for more info. Using flow nodes will override the nr of cells setting in the procedural dungeon game action.&lt;br /&gt;
|-&lt;br /&gt;
|Procedural Quests&lt;br /&gt;
|[[Quest (Asset)|Quest]]&lt;br /&gt;
|&lt;br /&gt;
|Quests that can be offered here. Note that these quests are marked as procedural.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
	<entry>
		<id>https://wiki.fetishquest.com/index.php?title=Procedural_Dungeon_(Asset)&amp;diff=294</id>
		<title>Procedural Dungeon (Asset)</title>
		<link rel="alternate" type="text/html" href="https://wiki.fetishquest.com/index.php?title=Procedural_Dungeon_(Asset)&amp;diff=294"/>
		<updated>2025-08-28T14:34:11Z</updated>

		<summary type="html">&lt;p&gt;JasX: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This lets you create procedural dungeons (exploration dungeons). In order to link a procedural dungeon to the world, create a door in the dungeon room and double click it to add a game action of type &amp;quot;proceduralDungeon&amp;quot;, set the label to a unique label for your dungeon, and then link this dungeon template to the game action.&lt;br /&gt;
&lt;br /&gt;
This is the asset reference. You can find a tutorial at [[Creating an Exploration Dungeon]].&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|+&lt;br /&gt;
!Field&lt;br /&gt;
!Type&lt;br /&gt;
!Default&lt;br /&gt;
!Description&lt;br /&gt;
|-&lt;br /&gt;
|Label&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|A unique label for your procedural dungeon. &#039;&#039;&#039;Do not modify after setting up!&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
|Fog override&lt;br /&gt;
|Float&lt;br /&gt;
|0&lt;br /&gt;
|Use 0 to turn off. See [[Room (Asset)|Room]] for more information.&lt;br /&gt;
|-&lt;br /&gt;
|Ambient light &lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|Overrides ambient light. See [[Room (Asset)|Room]] for more information.&lt;br /&gt;
|-&lt;br /&gt;
|Ambiance&lt;br /&gt;
|String&lt;br /&gt;
|&lt;br /&gt;
|URL to an ambient OGG file to use, unless the room itself has ambient set.&lt;br /&gt;
|-&lt;br /&gt;
|Ambiance volume&lt;br /&gt;
|Float&lt;br /&gt;
|0.2&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Saturation&lt;br /&gt;
|Float&lt;br /&gt;
|1.3&lt;br /&gt;
|Dungeon color saturation. Can be overridden in rooms. See [[Room (Asset)|Room]] for more info.&lt;br /&gt;
|-&lt;br /&gt;
|Max Treasures&lt;br /&gt;
|Int&lt;br /&gt;
| -1&lt;br /&gt;
|Sets a hard cap on nr of treasures in the dungeon. -1 defaults to 25% of rooms. The total nr generated will never exceed this value, no matter what you set in the flow nodes.&lt;br /&gt;
|-&lt;br /&gt;
|Max Encounters&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Reverb Type&lt;br /&gt;
|String&lt;br /&gt;
|Room Mesh&lt;br /&gt;
|Lets you set reverb type for your dungeon unless overridden by the rooms themselves. Room Mesh will use the room mesh settings.&lt;br /&gt;
|-&lt;br /&gt;
|Reverb intensity&lt;br /&gt;
|Float&lt;br /&gt;
|PASS&lt;br /&gt;
|Setting to pass automates it. Otherwise you can override the room asset reverb intensity.&lt;br /&gt;
|-&lt;br /&gt;
|Lowpass filter&lt;br /&gt;
|Float&lt;br /&gt;
|PASS&lt;br /&gt;
|Setting to pass automates it. Otherwise you can override the room asset lowpass filter. Mainly used for underwater dungeons.&lt;br /&gt;
|-&lt;br /&gt;
|Test Audio&lt;br /&gt;
|N/A&lt;br /&gt;
|&lt;br /&gt;
|Plays a random sample with your audio settings.&lt;br /&gt;
|-&lt;br /&gt;
|Room Templates&lt;br /&gt;
|[[Dungeon Sub Template (Asset)|Sub Template]]&lt;br /&gt;
|&lt;br /&gt;
|Adds rooms to the list of rooms that can be added.&lt;br /&gt;
|-&lt;br /&gt;
|Encounters&lt;br /&gt;
|[[Dungeon Sub Template (Asset)|Sub Template]]&lt;br /&gt;
|&lt;br /&gt;
|Adds encounters that can be found in the dungeon.&lt;br /&gt;
|-&lt;br /&gt;
|Ambient Music&lt;br /&gt;
|[[Music (Asset)|Music]]&lt;br /&gt;
|&lt;br /&gt;
|Sets music to play in the dungeon. Note that rooms/encounters/RP may override this.&lt;br /&gt;
|-&lt;br /&gt;
|Combat Music&lt;br /&gt;
|[[Music (Asset)|Music]]&lt;br /&gt;
|&lt;br /&gt;
|Sets combat music to play in the dungeon. Note that rooms/encounters/RP may override this.&lt;br /&gt;
|-&lt;br /&gt;
|Force Start Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|One or many encounters that must be placed at start. If multiple encounters are picked, the order is randomized and the first viable encounter is played.&lt;br /&gt;
|-&lt;br /&gt;
|Force End Encounter&lt;br /&gt;
|[[Encounter (Asset)|Encounter]]&lt;br /&gt;
|&lt;br /&gt;
|One or many encounters that must be placed in the final room. If multiple encounters are picked, the order of encounters is shuffled. Cannot be used if a template quest is used.&lt;br /&gt;
|-&lt;br /&gt;
|Flow Map&lt;br /&gt;
|[[Dungeon Flow Node (Asset)|Dungeon Flow Node]]&lt;br /&gt;
|&lt;br /&gt;
|You can use flow nodes to enforce a certain layout. Such as &amp;quot;start with a forest&amp;quot;, &amp;quot;then a settlement&amp;quot; etc. See the flow node asset type for more info. Using flow nodes will override the nr of cells setting in the procedural dungeon game action.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>JasX</name></author>
	</entry>
</feed>