Final Fantasy Brave Exvius Wiki

Module:Data

Template-info.png Documentation

Notice: This module is currently in limited alpha-testing. Currently this module only supports weapons, armors, and accessories. Support for ability materia, consumables, and enhancer units are pending.

This module is a work in progress. Do not convert pages which contain information that the module cannot display, however please do inform CodeHydro of the name of a such a page so that he may add support for such information.


Module:Data standardizes the output of various article pages and allows those pages to be transcluded like a Template so that updating that one page may automatically sync the information across all pages.

When using this module, the #invoke tag must be wrapped inside an onlyinclude tag, which must not contain any newline characters outside of the #invoke tag.

Good: Bad:
<onlyinclude>{{#invoke:Data|func
...
}}</onlyinclude>


<onlyinclude>
{{#invoke:Data|func
...
}}
</onlyinclude>

Usage for Equipment

Empty template

Below is an empty template with commonly used parameters for equipment. Click inside to select all.

<onlyinclude>{{#invoke:Data|item
<!--For details on how this module works, visit http://exvius.gamepedia.com/Module:Data-->
|name	= <!-- only necessary for testcases; defaults to page title if blank -->
|image	= <!-- leave blank unless image is not at File:icon-[name].png -->
|desc	= 

<!--Statistics-->
|type	=
|HP	=
|MP	=
|ATK	=
|DEF	=
|MAG	=
|SPR	=
|element=
|resist	=
|effect	=
|ability=
|warning=

<!--Notes-->
|notes	=

<!--Crafting Recipe-->
|recipe	=
|buy_rec=
|rec_gil=
|rec_mat=

<!--Usage-->
|usage	=
|quest	=

<!--How to obtain-->
|buy_gil=
|quartz	=
|shop	=
|drop	=
|steal	=
|explore=
|chest	=
|reward	=
|trust	=
|STMR   =
|obtain	=

<!--Equippable By-->
|used_by=

}}</onlyinclude>
<!--Add unique categories and unique sections below-->

Data page (#invoke page)

Intro section

Parameter Description
name Takes the name of the item
image Usually left blank. Allows the specification of an image file when the image name does not match the form File:Icon-name.png where name is replaced with the value passed to |name=.
desc Takes the description (or "story") of the item

Statistics section

Parameter Description
type Takes the type of equipment (case sensitive). For weapons and armor, enter only the value normally displayed in parenthesis. For example, type = Great Sword produces:
HP
MP
ATK
DEF
MAG
SPR
Takes either a whole number or a percentage value. For items that grant both a fixed and a percentage stat, enter both fixed and percentage parts with a + character between them.
template code produces:
|ATK = 32
  • Stats: ATK+32
|ATK = 10%
|ATK = 32+10%
element Takes whatever element the weapon bestows upon the unit's attacks.
template code produces:
|element = Fire
  • Element: Fire
resist Takes a list of resistances separated by commas. Status ailments are autolinked.
template code produces:
|resist	= Earth (+100%), Blind (+30%), Stop (Null)
  • Resistance: Earth (+100%), Blind (+30%), Stop (Null)
ability
effect

Takes a list of ability/effect values separated by commas.

Values that do not contain [[ ... ]] are treated as page names and will be autolinked. If a page name has a parenthetical, autolink will hide the parenthetical on the template page (but will show it on category pages).

For |effect=, you may list Status Ailments without links like so Blind (10%) and the ailment will be autolinked appropriately rather than being treated as a page name.


template code produces:
|effect	= Holy (FFXV)
|ability=Alterna, Death (FFXV)
|effect	=
|ability= [[Fire|<span title="Fire magic damage (1.2x) to one enemy">Fire</span>]]
|effect	= Confuse (50%)
|ability=

Note that eventually it is planned for tooltips (as shown above for Fire) to be automatically generated when autolinked once Module:Data has been extended to abilities.

Warning

Takes a value which is appended to the end of the Additional effects bullet without autolink. This value is shown in bold in categories.

template code produces:
|effect = Bird Killer
|ability=
|warning=Two-handed weapon
|warning=Females only
  • Additional effect: Females only

Example on category pages:

Icon Name Stats How to obtain
Killer Bow Killer Bow ATK+60
Element: Dark
Effect: Bird KillerBird Killer
Bird KillerBird Killer
Increase physical damage against birds (50%)
, Bug KillerBug Killer
Bug KillerBug Killer
Increase physical damage against insects (50%)
, Plant KillerPlant Killer
Plant KillerPlant Killer
Increase physical damage against plants (50%)

Two-handed weapon
Reward: (Trial) Brachiosaur

Notes section

Parameter Description
notes Enter any additional information related to the item. For example, this may include details on any unique ability it grants.

Crafting Recipe section

Parameter Description
recipe

Takes a list of locations or events (separated by commas) where the recipe can be obtained. This list will appear in the "How to Obtain" section.

template code produces:
|recipe	= Town of Mitra,
Royal Capital Grandshelt,
Port City Lodin,
([[Events|Event]]) [[Lands of Plenty]]
buy_rec Enter the cost to purchase the recipe from a shop.
rec_gil Enter the cost to use the recipe to craft the item.
rec_mat Takes a list of materials required to craft and their quantity, separated by commas.
time Enter the time it takes to craft the item. This parameter is no longer in use.
template code produces:
|buy_rec=100
|rec_gil= 600
|rec_mat=Iron Helm,Fire Cryst (5),Mythril Ore (9)

Usage section

Parameter Description
usage Separate groups with semi-colons and items with commas. First item in group should be the group title, separated from the list with a colon. Autolinked.
template code produces:
|usage	= Equipment:Altair, Wizard's Staff;Abilities:ATK +10%, Barfira;Items:Bacchus's Wine
quest Separate values with commas. Autolinked.
template code produces:
|quest	= [[Port City Lodin#Muse of the Anvil|Muse of the Anvil]], Example

Involved in Quest

How to obtain section

Parameter Description
buy_gil
quartz
Enter the purchase cost of the item. If |quartz= is given, then |buy_gil= will be ignored and the Shops subsection will be replaced by Fat Chocobo. Item/item2 modes will show start quartz as the currency automatically.
shop
drop
steal
explore
chest
reward
Enter location values separated by commas.

Location values which do not contain [[ ... ]] will be placed inside double brackets automatically.

Note that the table form of |steal= and |drop= are not currently available. This form will be added when Module:Data is extended to non-equipment types. (The only dropped equipment currently is Excalipoor which doesn't use the table form)

trust Takes the name of the unit that provides this item as a Trust Mastery Reward.
STMR Takes the name of the unit that provides this item as a Super Trust Mastery Reward.
obtain
template code produces:
|obtain	= Purchase:Premium Bundle;Other Rare Subsection:Thing1, Thing2, Thing3
Purchase

Other Rare Subsection

Equippable By section

Parameter Description
used_by

Enter Units that can use the item, separated by commas. This is usually meant for equipment that is locked to a specific unit.

template code produces:
|used_by= Charlotte

Usage for Abilities

Empty template

Below is an empty template with commonly used parameters for abilities. Click inside to select all.

<onlyinclude>{{#invoke:Data|item
<!--For details on how this module works, visit http://exvius.gamepedia.com/Module:Data-->
|name   = <!-- only necessary for testcases; defaults to page title if blank -->
|image  = <!--Ability_#.png-->

<!--Statistics-->
|type   = <!--Active, Passive, White, Black, Green, or Blue-->
|mag_lv =
|effect = <!--For unconditional passive stats, use HP/MP/ATK etc. parameters instead.-->
|chain  =
|hits   =
|atk_frm= <!--rarely given-->
|MP_cost=
|filter =
|HP     =
|MP     = <!--Do not enter MP cost here. This is for the likes of MP +10%.-->
|ATK    =
|DEF    =
|MAG    =
|SPR    =
|evade_p=
|evade_m=

<!--Abilities-->
|ability=

<!--Notes-->
|notes  =

<!--Crafting Recipe-->
|recipe =
|buy_rec=
|rec_gil=
|rec_mat=

<!--Usage-->
|usage  =
|quest  =

<!--How to obtain-->
|buy_gil=
|quartz =
|shop   =
|chest  =
|reward =
|equip  =
|materia=
|learn  = <!-- ! Name !! Min rarity !! Level -->
|esper  = <!-- ! Name !! Min rarity -->
|enable =
|trust  =
|STMR   =
|obtain =

<!--Equippable By-->
|used_by=

<!--Ability Awakening
|Unit Name+1=
 awk_mat= Power/Tech/White/etc.,t1[,t2,t3...],gil
 MP_cost= 5
 one enemy => all enemies
-->

}}</onlyinclude>
<!--Add unique categories and unique sections below-->

Data page (#invoke page)

Intro section

Parameter Description
name Takes the name of the item
image Takes the image used by the item.

Statistics section

Parameter Description
type Takes the ability's type (Case Sensitive). The valid types are Active, Passive, White, Black, Green, Blue.
mag_lv Takes a number representing the magic level.
template code produces:
|type = White|mag_lv = 1
  • Type: Magic Ability (White Magic Lv 1)
effect Takes a list of effects separated by new line characters. All effects are passed to this parameter EXCEPT:

For effects that enable other skills, you may also list special instructions called Overrides, which will be discussed in greater detail later.

template code produces:
|effect	= Physical damage (2x) with ignore DEF (50%) to one enemy
Decrease light resistance (50%) for 3 turns to one enemy
  • Effect:
Physical damage (2x) with ignore DEF (50%) to one enemy
Decrease light resistance (50%) for 3 turns to one enemy
Overrides

Override instructions may be used in two ways to:

  • provide information for enabled abilities that do not have a page (Leap)
  • display different text than is shown on the enabled ability's page (See Unlock Magic on Terra's page and hover pointer over the effect of Chaos Wave)

Usually overrides have no visible effect outside of |mode=conditional (except in the case of randomly enabled skills, which display the conditional table is shown in the Abilities section).

Unlike awakening overrides (which can override all parameters), enabled effect overrides can only override the following parameters:

  • |effect=
  • |hits=
  • |MP_cost=

You do not need to override all three. Any remaining data will be fetched from the page if available or replaced with - if unavailable. (An override for |effect= is required if no page exists to avoid an error message, even if blank.)

They can take the form [skill name]parameter = value or parameter [skill name] = value, according to personal preference (generally, the first is easier to read when there are multiple abilities being overridden, while the latter is easier to read when only one ability is being overridden).

Also unlike with awakening overrides, multi-line values must be kept on the same line, using <br> or \n to delimit each line.

chain Takes a chaining family name. Finds the corresponding chaining family and autolinks to it.
template code produces:
|chain  = Divine Ruination
hits Takes the number of hits. For randomized abilities, separate the hit count for each ability with either / or ; (interchangeable).
template code produces:
|hits = 7
  • Hits: 7
atk_frm

Takes the frame (delay in 1/60 seconds) of each hit. Frames can be separated by either , or -. If the |hits= parameter is delimited by either / or ;, this param must be delimited in the same way.

If there are fewer / or ; in |atk_frm= than |hits=, the module will assume omitted values are for non-damaging abilities (e.g. when |hits= has 4 values, |atk_frm=150;150 is equivalent to |atk_frm=150/150/-/- and |atk_frm=150;150;;)

template code produces:
|hits	= 1 / 1 / - / -
|atk_frm= 150/150
|hits	= 1;1;5;1
|atk_frm= 145;150;178,184,188,191,194;130
MP_cost Takes a number for the MP cost of the ability. For MP bonuses, use |MP=
template code produces:
|MP_cost = 20
  • MP: 20
filter Highlights specified abilities. Finds the corresponding abilities within a given page's table and is controlled by a "Filter" button that highlights the background color of the specified abilities. Used for distinguishing 2 or more abilities can be multi-cast.

Multi-cast spells are not included. Page translation currently does not work as the original name is required (e.g. use Reflection instead of Reflection (FFBE)).

template code produces:
|filter = Aurora Storm/Flash - Luster
Min rarity Level Icon Name Effect Hits MP
5-star★ 17 Flash - Luster Flash - Luster Light hybrid damage (4x) to all enemies
Add light element to physical attacks for 5 turns to caster
1Attack frame: 34 30
5-star★ 40 Purge Purge Hybrid damage (4x) to one enemy
Remove all status effects from one enemy
1Attack frame: 12 18
6-star★ 1 Double Flash Double Flash Cast 2 times: Any of Aurora Fryevia's Flash skills, or Aurora Storm - 0
Passive Stats
HP Takes a percentage value. This is for stat bonuses that have no requirements and are usable by any unit. Conditional bonuses (for example "when equipped with a Robe", should be defined in |effect=.
template code produces:
|ATK = 20%
  • Effect:
Increase ATK (20%)
|ATK=20%|HP=10%
  • Effect:
Increase HP (10%) and ATK (20%)
|ATK=20%|HP=10%|evade_p=5%
  • Effect:
Increase HP (10%) and ATK (20%)
Increase physical evasion (5%)
MP
ATK
DEF
MAG
SPR
evade_p
evade_m

Abilities section

Parameter Description
ability

Notes section

Parameter Description
notes Enter additional notes about the ability, such as how it stacks and interacts with equipment or other abilities.

Crafting Recipe section

Parameter Description
recipe Takes a list of locations or events (separated by commas) where the recipe can be obtained. This list will appear in the "How to Obtain" section.
buy_rec Takes the cost to purchase the recipe from a shop.
rec_gil Takes the cost to use the recipe to craft the item.
rec_mat Takes a list of materials required to craft and their quantity, separated by commas.

Usage section

Parameter Description
usage Takes separate groups with semi-colons and items with commas. First item in group should be the group title, separated from the list with a colon. Autolinked.
quest Takes separate values with commas. Autolinked.

How to obtain section

Parameter Description
buy_gil Enter the purchase cost of the item. If |quartz= is given, then |buy_gil= will be ignored and the Shops subsection will be replaced by Fat Chocobo. Item/item2 modes will show start quartz as the currency automatically
quartz
shop Takes location values separated by commas.

Location values which do not contain [[ ... ]] will be placed inside double brackets automatically.

Tables may be entered using alternative markup as shown below:

|learn	= ! Name !! Min rarity !! Level
[[Leah]] $ {{Rarity|1}} $ 1
[[Anastasis]] $ {{Rarity|2}} $ 1
[[Fina]] $ {{Rarity|2}} $ 1
[[Gimlee]] $ {{Rarity|2}} $ 3
[[Ovelia]] $ {{Rarity|3}} $ 1
[[Luna]] $ {{Rarity|3}} $ 25
[[Vanille]] $ {{Rarity|4}} $ 1
[[Agrias]] $ {{Rarity|4}} $ 7

Also accepts wikitable markup when | are escaped using {{!}} or Module:Wikitable, like so:

|esper	={{#invoke:wikitable|main|class="wikitable sortable" style="text-align:center;"
! Name !! Min rarity
|-
| [[Carbuncle]] || {{Rarity|1}}
|-
| [[Lakshmi]] || {{Rarity|1}}
|-
| [[Shiva]] || {{Rarity|1}}
|-
| [[Siren]] || {{Rarity|1}}
}}
Name Min rarity
Carbuncle 1-star★
Lakshmi 1-star★
Shiva 1-star★
Siren 1-star★
chest
reward
equip
materia
learn
esper
enable Takes ability values separated by commas. Autolinked.
trust Takes the name of the unit that provides this ability as a Trust Mastery Reward.
STMR Takes the name of the unit that provides this ability as a Super Trust Mastery Reward.
obtain Takes separate groups with semi-colons and items with commas for any other method of obtaining the ability, such as premium bundles.

Equippable By section

Parameter Description
used_by Takes a comma separated list of units that can use this ability. This is usually meant for Ability Materia that is locked to a specific unit.

Ability Awakening section

Parameter Description

unit name+1

unit name+2

skill name+1

Awakening parameters are the only parameters relevant to abilities which are not included the Empty Template due to the uniqueness of awakenings. To be properly handled, the name of the parameter must have the form |name+#= where # is the awakening level and name must match either a unit listed in the |learn= parameter or a skill listed in the |enable= parameter.

Awakening parameters take a series of instructions, separated by newline characters, and are read sequentially. Though a little complex at first glance, writing these instructions should be fairly easy once you've learned the syntax.

There are four basic instructions:

  • Replace (or Strikeout) - A => B
  • Override - A = B
  • Append
  • Import

For the most part, bold and strikeout are handled automatically, though you may prevent automatic text formatting by including '''text''', <b>text</b>, or <s>text</s> markup in the instruction.

Instruction Description

Replace

Strikeout


(Operator: =>)

Replace takes the form A => B where A is a substring of the output of the previous result (unbolded and strikeouts removed) and B is the new substring.

Any replacements made are cascaded to the next awakening level, so replacements should be adjusted accordingly, as shown in this example from Curaga: |Roselia+1= awk_mat= White,15,8,5,250000 1000 HP => 1200 HP |Roselia+2= awk_mat= White,23,12,8,1,250000 MP_cost= 10 1200 HP => 1600 HP

Curaga +1 Heal (1200 HP, 3.4x) to all allies - 15 White 15 8 5 - - Gil250,000
Curaga +2 Heal (1600 HP, 3.4x) to all allies - 10 White 23 12 8 1 - Gil250,000

Because replacements are based on the output, not the input, autolinked text must be manually linked in order to match. For example, based on Lovely Guard+1 for Marie:

Unit Abilities Base Effects Awakening
Marie
Marie
Lovely Guard
(Guard)
Increase resistance to blind, sleep, and silence (100%) for 3 turns to all allies Increase resistance to all status ailments (100%) for 3 turns to all allies
Increase DEF/SPR (40%) for 3 turns to all allies
Bad
|Marie+1=
 awk_mat= Support,15,10,8,2,1,500000
 blind, sleep, and silence => all status ailments
Good
|Marie+1=
 awk_mat= Support,15,10,8,2,1,500000
 [[Status Ailments#Blind|blind]], [[Status Ailments#Sleep|sleep]], and [[Status Ailments#Silence|silence]] => all status ailments
Cheese
|Marie+1=
 awk_mat= Support,15,10,8,2,1,500000
 effect = Increase resistance to '''all status ailments''' (100%) for 3 turns to all allies

If a replacement is a success on last section of the ability's page, it is usually successful on the Ability Awakening page as well, however, because bold and strikeouts are not stripped between awakening levels for the latter page, you will need to include the autobolded output when replacing text the text surrounding an autobolded substring [insert Unlimited example]]

Replace instruction from previous awakening levels do not survive recalculations, which can be triggered by override instructions (described in Override). However, those in the current awakening will be applied after any recalculation is done (and before append instructions).


Special cases

If B is omitted, this becomes a Strikeout instruction. Note that the first letter of the next word will be automatically capitalized if the striked text is from the beginning of the output.

Example from Pray (Replace instruction highlighted; blank comment is optional but helps readability): Roselia+1= awk_mat= Healing,5,2,15000 50% chance to => <!--blank-->

Pray +1 50% chance to Heal (100 HP, 1x) to all allies - 3 Healing 5 2 - - - Gil15,000

If A is omitted (=> B), the text is inserted at the end of the last line. In contrast to an Append instruction, this does not put the text on a new line, as shown in this example from Aeroga: |Hope+2= awk_mat= Black,23,12,8,1,250000 => with consecutive increase (1x, max: 5) to all enemies

Aeroga +2 Wind magic damage (40x) to all enemies
Chain=Chaos Wave Awakened
8New frame delay: 42-20-20-20-20-20-20-20
New attack frames: 42-62-82-102-122-142-162-182
20 Black 23 12 8 1 - Gil250,000

If A contains ^ only (^ => B), the text is inserted in front of the first line instead, with the first letter of the first word uncapitalized automatically.



Override


(Operator: =)

Override changes the value of any parameter (or sets the value when one is not there). This instruction takes the form A => B where A is the parameter name being overridden and B is the new value assigned to it.

Will trigger a recalculation if overridden parameter is either |effect= or |ability= (collectively referred to as recalculating overrides)[tip 1]. Due to the multi-line-nature of these parameters, this module will include all operator-less lines which follow the override in the new value up to the next line which contains either = or =>. (Lines which follow overrides of non-recalculating parameters will not be considered part of the override and will be treated as Append.) If recalculation occurs, the whole effect output may be bolded automatically.

If the original unawakened effect is contained within the recalculated effect, then the original part will be unbolded. Conversely, if the recalculated effect is found within the base effect, the new effect will remain unbolded (See Chaos Wave)

Example from Tri-beam Laser:[tip 2]

|Ace+2=
 awk_mat= Power,23,15,12,4,2,500000
 effect	= Randomly use:
(30%) Tri-beam Laser (white)
(30%) Tri-beam Laser (yellow)
(30%) Tri-beam Laser (orange)
(10%) Tri-beam Laser (red)
Decrease fire, lightning, and light resistance (75%) for 3 turns to all enemies
 ability=
{{{effect}}}
Magic damage (4.2x) with ignore SPR (25%) to all enemies
Magic damage (5.6x) with ignore SPR (25%) to all enemies
Magic damage (22.5x) with ignore SPR (25%) to all enemies
Tri-beam Laser +1 Magic damage (2.8x) with ignore SPR (25%) to all enemies 7New frame delay: 64-7-7-7-7-7-7
New attack frames: 64-71-78-85-92-99-106
45 Power 15 10 8 2 1 Gil500,000
Tri-beam Laser +2
Randomly use:
(30%) Tri-beam Laser (white) - Magic damage (2.8x) with ignore SPR (25%) to all enemies
(30%) Tri-beam Laser (yellow) - Magic damage (4.2x) with ignore SPR (25%) to all enemies
(30%) Tri-beam Laser (orange) - Magic damage (5.6x) with ignore SPR (25%) to all enemies
(10%) Tri-beam Laser (red) - Magic damage (22.5x) with ignore SPR (25%) to all enemies
Decrease fire, lightning, and light resistance (75%) for 3 turns to all enemies
7New frame delay: 64-7-7-7-7-7-7
New attack frames: 64-71-78-85-92-99-106
45 Power 23 15 12 4 2 Gil500,000

Any Replace or Append instructions from previous awakenings will be lost upon recalculation, though those listed for the current awakening will be applied after recalculation (even if listed before a recalculating override). Recalculation is always done after all overrides have been processed.

Finally, although the awakening overrides resemble enabled effect overrides from the Statistics section, you cannot use the form [skill]parameter= here. (Brackets are unnecessary for awakening overrides since they always apply only to the skill of the current page.)


Append

Append instructions are lines which do not contain any operators (= or =>) and which do not follow an override of |effect= or |ability=. These lines are appended to the end of the result as though it were a new effect line. Such is done without actually modifying the effect parameter, so no recalculation is triggered.

Example from Pray: |Roselia+2= awk_mat= Healing,8,3,1,15000 Restore MP (30) to all allies

Pray +2 Heal (100 HP, 1x) to all allies
Restore MP (30) to all allies
- 3 Healing 8 3 1 - - Gil15,000

Empty lines are ignored. If a gap is desired, you may simply enter <br> in front of the next line.

Appended effects have partial auto-linking for killers, equipment, and status ailments, but NOT for enabled abilities. They are also not pattern processed for auto-tables. (Full auto-linking and auto-table require overrides instead.)

Append instructions from previous awakening levels will not survive recalculation, however those in the current awakening will be applied after any recalculation is done (and after any Replace instructions).

Finally, do not use append instructions to add lines such as MP cost reduced to X or Hit count increased to X—override |MP_cost= or |hits= instead.


Import

Import all instructions from another awakening parameter simply by entering the target parameter name as the first line by itself. Must be the first instruction. You may include additional instructions afterwards.

Example from Curaga: |Garnet+1=Roselia+1 MP_cost= 10

Curaga +1 Heal (1200 HP, 3.4x) to all allies - 10 White 15 8 5 - - Gil250,000

Note how |Garnet+1= inherits the value of |awk_mat= and the Replace instruction from |Roselia+1=.

  1. In the past, overriding #Passive Stats triggered recalculation. This is no longer the case.
  2. Note that {{{effect}}} can be used in lieu of retyping the original effect (at least for single-line effects).

Usage for Items

Empty template

Below is an empty template with commonly used parameters for items. Click inside to select all.

<onlyinclude>{{#invoke:Data/testcases|item
<!--For details on how this module works, visit http://exvius.gamepedia.com/Module:Data-->
|name	=
|image	=  <!-- leave blank unless image is not at File:icon-[name].png -->
|desc	=

<!--Statistics-->
|type	=Item
|effect	=Revive one KO'd ally (20% HP)

<!--Notes-->
|notes	=*When used on a [[:Category:Reapers|reaper]] enemy, it kills them instantly.

<!--Crafting Recipe-->
|recipe	=
|buy_rec=
|rec_gil=
|rec_mat=

<!--Usage-->
|usage	=
|quest	=

<!--How to obtain
NOTE: Info displayed in this section will not be listed in any particular order. 
Parameter numbers do not affect the order they will appear on the page.
Module:Data does not preserve order to reduce server load.-->
|buy_gil=
|quartz	=
|shop	=
|drop	=
|steal	=
|explore=
|chest	=
|trust	=
|obtain	=

<!--Equippable By-->
|used_by=

}}</onlyinclude>
<!--Add unique categories and unique sections below-->

Tranclusion (modes)

Any supported item can be transcluded into wiki pages in the form of table rows. This allows quick creation of item tables (such as a shop table) while keeping data consistent across all pages. The following modes are supported when transcluding Module:Data item pages:

Mode Description
item Used for shop pages. This mode is the default whenever equipment pages are transcluded onto non-category pages. Non-equipment pages default to |mode=typeless instead.
code produces:
{| class=wikitable
 ! Name !! Type !! Description !! Price
 {{:Wizard's Staff|mode=item}}
 {{:Golden Blade|mode=item}}
|}
Name Type Description Price
Wizard's Staff Staff ATK+13, MAG+6, SPR+32
Ability: FireFire
FireFireBlack Magic Affinity Lvl 1 
Fire magic damage (1.2x) to one enemy
Gil800
Golden Blade Great Sword ATK+51 Gil?
item2 Similar to item mode, except an icon will be included
code produces:
{| class=wikitable
 ! Name !! Type !! Description !! Price
 {{:Wizard's Staff|mode=item2}}
 {{:Golden Blade|mode=item2}}
|}
Name Type Description Price
Icon-Wizard's Staff.pngWizard's Staff Staff ATK+13, MAG+6, SPR+32
Ability: FireFire
FireFireBlack Magic Affinity Lvl 1 
Fire magic damage (1.2x) to one enemy
Gil800
Icon-Golden Blade.pngGolden Blade Great Sword ATK+51 Gil?
recipe Used for recipes sold in shops.
code produces:
{| class=wikitable
 ! Name !! Type !! Description !! Price
 {{:Mythril_Dagger|mode=recipe}}
 {{:Buster Sword|mode=recipe}}
|}
Name Type Description Price
Recipe for Mythril Dagger - - Gil150
Recipe for Buster Sword - - Gil450
typeless Variant of |mode=item which skips the type column and sets colspan=2 on the statistics cell. This mode automatically applied for non-equipment.

[example]

category This mode is generally only explicitly declared to emulate category displays on non-category namespace. When an item page is transcluded in category namespace, Module:Data will use category mode automatically. Psuedo-category pages for abilities such as Ability Materia and Special Abilities (Passive) also default to this mode.
code produces:
{| class=wikitable
 ! Icon !! Name !! Stats !! How to obtain
 {{:Healing Staff|mode=category}}
 {{:Rune Staff|mode=category}}
|}
Icon Name Stats How to obtain
Healing Staff Healing Staff ATK+11, MAG+5, SPR+26
Element: Light
Ability: CuraCura
CuraCuraWhite Magic Affinity Lvl 3 
Heal (400 HP, 3x) to all allies
Star Quartz: Lost Village of Marlo
Rune Staff Rune Staff ATK+15, MAG+6, SPR+38
Effect: Silence (30%)
Ability: SilenceSilence
SilenceSilenceGreen Magic Affinity Lvl 2 
Inflict silence (100%) to one enemy
Recipe: (Quest) Preserving the Peace
Chest: Town of Kolts
tooltip Used to make a tooltip. This is the only mode that cannot be customized or extended.
code produces:
{{:Healing Staff|mode=tooltip}}
{{:Rune Staff|mode=tooltip}}
Healing StaffHealing Staff
Healing StaffHealing StaffStaff
Stats: ATK+11, MAG+5, SPR+26
Element: Light
Ability: CuraCura
CuraCuraWhite Magic Affinity Lvl 3 
Heal (400 HP, 3x) to all allies
Rune StaffRune Staff
Rune StaffRune StaffStaff
Stats: ATK+15, MAG+6, SPR+38
Effect: Silence (30%)
Ability: SilenceSilence
SilenceSilenceGreen Magic Affinity Lvl 2 
Inflict silence (100%) to one enemy
custom Creates a table row with no default cells. See #Extension and customization
fetch Similar to custom except that cells will not be placed on a new table row.
For abilities only
conditional [placeholder]
awaken [placeholder]

Parameters

The following parameters can also be used on {{:page|parameter=value}} tags:

Parameter Applies to Description
sep |mode=fetch

By default, each parameter is separated by \n| (where \n is a newline character), thus creating a separate table cell for each parameter. Use |sep= to set a different separator.

limit |mode=item

|mode=item2
|mode=recipe
|mode=typeless

Indicates the number of items available in the shop. This value will be displayed under the Price value of the item. Enter an integer or the ∞ symbol (using &infin;).

Setting |limit=0 is magic for declaring the item priceless... or at least it instructs Module:Data to omit the price cell completely (reducing the need for custom modes).

Name Type Description
Bronze Knife Dagger ATK+10
skill |mode=awaken See Meteor#Ability Awakening and Terra#Ability Awakening (Terra does not learn Meteor directly but can access the awakened versions via the awakening of Unlock Magic)
rowspan |mode=category

|mode=conditional

This parameter is used only for magic abilities to display |mag_lv=, which is not shown by default. This should only be set on the first ability of the magic level.

Example:

{| class=wikitable
{{:Aeroja|mode=category|rowspan=2}}
{{:Stonja|mode=category}}
|}
7 Aeroja Aeroja Wind magic damage (35x) to all enemies 28 - -
Stonja Stonja Earth magic damage (35x) to all enemies 28 - -


|mode=conditional can also use |rowspan= for abilities which have the |enable= may use |enable= parameter. Example of this is the conditional section for Randi. You can use |rowspan=0 as "magic" to omit the "Activated by" cell. Abilities which do not use |enable= will ignore this param.

page all transclusions

This parameter instructs the module to behave as though it were transcluded onto the page specified.

In this manner, you may emulate how the item appears on another page without actually placing it on that page, particularly useful for displaying innate abilities (a view that cannot be accessed via |mode= at all).

For magic words, see #Extension and customization.

Wrappers

Creating tables and their headers can be simplified by using , automatically creating the proper table headers and allows you to define any desired table headers. The wrapper takes the following parameters

Parameter Description
mode The type of table you want to create. This will determine which table headers are used for this table. The following modes are available:
  • shop
name The title of the table. If the title is Item Shop or Ability Shop, the table will adjust accordingly to only include relevant columns.
name# Use instead of name if you want multiple titles to divide your rows. Each instance should look like |name1=My first title |name2=my Second title |name3=my Third title and so on in the position you wish you see the table header.
[Transcluded Rows] The rows you want to insert into the table using the matching transclusion modes.

Example:

{{#invoke:Data|wrap|mode=shop|name1=First Title|
{{:Wizard's Staff}}
{{:Wizard's Staff|mode=recipe|limit=1}}
{{:Earrings}}
|name2=Second Title|
{{:Ring of the Lucii|mode=item2}}
{{:Gaia Gear|mode=item2}}
|name3=Ability Shop|
{{:Cure}}
{{:Miracle Step}}
}}
First Title
Name Type Description Price
Wizard's Staff Staff ATK+13, MAG+6, SPR+32
Ability: FireFire
FireFireBlack Magic Affinity Lvl 1 
Fire magic damage (1.2x) to one enemy
Gil800
Recipe for Wizard's Staff - - Gil?
(Limit: 1)
Earrings Accessory DEF+3, MAG +20% Star Quartz50
Second Title
Name Type Description Price
Icon-Ring of the Lucii.pngRing of the Lucii Accessory MAG+3, SPR+3, ATK +30%, MAG +30%
Effect: Holy (FFXV)Holy (FFXV)
Holy (FFXV)Holy
Increase physical evasion (25%)
Chance to counter physical attacks (25%) with HolyHoly
Light magic damage (1.2x) to one enemy
Restore MP (15) to caster

Ability: AlternaAlterna
AlternaAlternaBlack Magic Affinity Lvl 8 
Magic damage (5.1x) with ignore SPR (25%) to all enemies
, Death (FFXV)Death (FFXV)
Death (FFXV)DeathBlack Magic Affinity Lvl 7 
Inflict death (30%) to one enemy
Dark magic damage (0.8x) as HP drain (30%) to one enemy
Gil?
Icon-Gaia Gear.pngGaia Gear Robe DEF+20, MAG+5, SPR+5
Resistance: Wind (-50%), Earth (+50%), Petrify (+30%)
Gil3,000
Ability Shop
Name Description Price
Cure Magic Abilities Heal (150 HP, 3x) to one ally Gil?
Miracle Step Special Abilities (Passive) Increase MP (20%) and MAG/SPR (10%)
Increase physical evasion (5%)
Gil?

Extension and customization

Each table can be extended to include additional information by providing the attribute's name as parameters. If the transclusion uses mode=custom, these parameters are required in order to display a table row.

The data in the cells can be further modified using the format parameter@custom text %s. Anything after the @ will be displayed in the cell, and the parameter will be displayed in place of %s. The parameter may be omitted if the cell only contains custom text. If you want to include the @ symbol in your text, you can use \@.

Example: Simple Extension

{| class="wikitable sortable"
! colspan="8" | Weapon Shop extended
|-
! Name !! Type !! Description !! Price !! ATK !! MAG !! DEF !! SPR
{{:Wizard's Staff|mode=item|ATK|MAG|DEF|SPR}}
{{:Malboro Wand|mode=item|ATK|MAG|DEF|SPR}}
{{:Earrings|mode=item|ATK|MAG|DEF|SPR}}
|}
Weapon Shop extended
Name Type Description Price ATK MAG DEF SPR
Wizard's Staff Staff ATK+13, MAG+6, SPR+32
Ability: FireFire
FireFireBlack Magic Affinity Lvl 1 
Fire magic damage (1.2x) to one enemy
Gil800 13 6 - 32
Malboro Wand Staff ATK+15, SPR+60
Effect: Blind (10%), Poison (10%)
Ability: JinxJinx
JinxJinx
Physical damage (1.5x) to one enemy
Inflict disease (100%) to one enemy

Exclusive: Vanille
Gil? 15 - - 60
Earrings Accessory DEF+3, MAG +20% Star Quartz50 - 20% 3 -

Example: Custom Table

{| class="wikitable"
! colspan="6" | Custom
|-
! Name !! Comment !! ATK !! MAG !! DEF !! SPR
{{:Wizard's Staff|mode=custom|name|@Custom Text \@ this location|ATK|MAG|DEF|SPR}}
{{:Malboro Wand|mode=custom|name@The name of this item is %s!|@|ATK|MAG|DEF|SPR}}
{{:Earrings|mode=custom|name@[[%s]]|@The above line is blank|ATK|MAG|DEF|SPR}}
|}
Custom
Name Comment ATK MAG DEF SPR
Wizard's Staff Custom Text @ this location 13 6 - 32
The name of this item is Malboro Wand! 15 - - 60
Earrings The above line is blank - 20% 3 -

Example: Fetching Data

{{:Wizard's Staff|mode=fetch|sep=,|name|ATK|MAG|DEF|SPR}}

Wizard's Staff,13,6,-,32

Magic Words

In addition to parameter names, you may also pass magic words for more complex output:

Applies to magic word Description

|mode=custom
|mode=fetch
|mode=item
|mode=item2
|mode=recipe
|mode=typeless
|mode=category

LINK

Shows the item name with a link.

Bowie Knife
TYPE

Shows the item's type with link to category.

Dagger
STATS

Shows formatted stats and effects.

ATK+82
Effect: Dual WieldDual Wield
Dual WieldDual Wield
Enable dual wielding of one-handed weapons
ICON

Shows a linked icon.

Bowie Knife
BADGE

Shows a linked name, icon, and category.

Bowie Knife
Bowie Knife
(Dagger)

|mode=exclusiveFX rowonly

Omits the table wrap. Used when table has multiple rows.

Example:

{| class="wikitable" style="text-align:center;" width="100%"
! Icon !! Name !! Type !! Effect
{{:Crimson Saber|mode=exclusiveFX|rowonly}}
{{:Rain's Clothes|mode=exclusiveFX|rowonly}}
|}
Icon Name Type Effect
Crimson Saber Crimson Saber Great Sword ATK+90
Element: Fire
Effect: Crimson SoulCrimson Soul
Crimson SoulCrimson Soul
Increase HP/MP (30%)
(Rain, Vagrant Knight Rain, Awakened Rain, Chocobo Rain only)
Rain's Clothes Rain's Clothes Light Armor DEF+38, SPR+12, MP +10%
Effect: Push ForwardPush Forward
Push ForwardPush Forward
Increase resistance to blind, paralyze, and petrify (100%)
(Rain, Vagrant Knight Rain, Awakened Rain, Chocobo Rain only)
|mode=awaken table

Shows full table given Awakened Ability.

conditional

Shows "Conditional" header along with row. Used for abilities unlocked by other abilities.



local p = {
	disable_tooltip = {
		["Category:Trust Master Rewards"] = 1,
		["Category:Super Trust Master Rewards"] = 1,
		["Category:Armors"] = 1,
		["Category:Weapons"] = 1,
		["Category:Fire"] = 1,
		["Category:Fire/2"] = 1,
		["Category:Accessories"] = 1
	},
	stat_order = {'HP','MP','ATK','DEF','MAG','SPR'},
	equipment = {
		_class ={'Weapon', 'Armor', 'Accessory'},
		_plural = {Clothes = 'Clothes', Staff = 'Staves'},
		Dagger = 1,
		Sword = 1,
		["Great Sword"] = 1,
		Katana = 1,
		Staff = 1,
		Rod = 1,
		Bow = 1,
		Axe = 1,
		Hammer = 1,
		Spear = 1,
		Instrument = 1,
		Whip = 1,
		["Throwing Weapon"] = 1,
		Gun = 1,
		Mace = 1,
		Fist = 1,
		["Light Shield"] = 2,
		["Heavy Shield"] = 2,
		Hat = 2,
		Helm = 2,
		Clothes = 2,
		["Light Armor"] = 2,
		["Heavy Armor"] = 2,
		Robe = 2,
		Accessory = 3
	},
	ability = {
		_class = {"Special Ability", "Magic Ability"},
		Active = 1,
		Passive = 1,
		White = 2,
		Black = 2,
		Green = 2,
		Blue = 2
	},
	ailment = {
		Poison = 1,
		Blind = 1,
		Sleep = 1,
		Silence = 1,
		Paralyze = 1,
		Confuse = 1,
		Disease = 1,
		Petrify = 1
	},
	killer = {
	--Special thanks to FencerTJ for category names (except he forgot humans)
		Avians = 'bird',
		Plants = "plantoid",
		Aquatics = "aqua",
		Beasts = "brute",
		Demons = "cysidus",
		Dragons = "dra[cg]o",
		Fairies = "[sf][pa]ir",--spirit or fairy
		Insects = "bug",
		Machinas = "m[ae]ch",
		Stones = "lith",
		Reapers = "undead",
		Humans = "man-?"
	},
	patterns = {
	--Not all patterns here. Just those used more than once.
		wikilink = '%[%[[^%[%]]+%]%]',
		only = '%(%[%[([%w ]+)%]%] only%)',
		enable = '([^\n]*Enable skill[^\n]-: )([^\n]+)',
		multi_break = '[^<]?%s-/?%s*([^>]?.-[^<])%s*/%s-[^>]-',
		rng_enable = '\n%(%d+%%%) +[^\n]+: Enable? ',
		event = '%(%[?%[?Event[^,]-%)%s*%[?%[?'
	},
	template = {
		evade = 'Increase %s evasion (%s)'
	}
}

local result = {}
function result:_(v)
--simplified version of mw:en:Module:Buffer
	if v and v ~= '' then table.insert(self, v) end
	return self
end
local esc_seq = string.char(127,4,127,2)

function p.item(frame)
	local args, p_args, flags, currentTitle, namespace, invokePage = {}, frame:getParent().args, {}
	if p_args.page or args.page then
	--No worries. Scribunto is sandboxed, so overwriting mw.title.getCurrentTitle won't affect any other #invokes
		local emulate = mw.title.new(p_args.page or args.page)
		mw.title.getCurrentTitle = function() return emulate end
	end
	for k, v in pairs(frame.args) do
	--Basic cleaning of arguments and argument grouping
		v = mw.text.trim(v)
		if v and v~='' and v~='-' then args[k] = v end
	end
	local stats_sorted, stats = {}, {HP = {}, MP = {}, ATK = {}, DEF = {}, MAG = {}, SPR = {}}
	for k, v in pairs(stats) do
	--grab percents and integers in the form such that DEF+7, DEF+50% is entered as 'DEF=7+50%'
		if args[k] then
			v[2] = args[k]:match'%-?%d+%%'
			if v[2] then v[1] = args[k]:match'^%+?(%-?%d+)%+'--tolerate ATK=+10
			else table.insert(v, args[k]:match'^%+?(%-?%d+)$') end
		end
	end
	if p.equipment[args.type] then
		for i = 1, 2 do
		--show percentage stats after integer stats
			for _, v in ipairs(p.stat_order) do--this line controls order of stats
				table.insert(
					stats_sorted,
					stats[v][i] and (i==1 and '%s+%s' or '[[%s +%s]]'):format(v, stats[v][i])
				)
			end
		end
	end
	local function link(v, hide_disambiguation)
	--[[
	Autolinks if does not contain a link. If hide_disambiguation evals true, links "Page (Disambigation)" as
	"Page (Disambigation)|Page"
	]]
		return v and (v:find(p.patterns.wikilink) and v
			or hide_disambiguation and v:find'%b()' and v:gsub('([^%(]+) %(([^%)]+)%)', '[[%1 (%2)|%1]]')
			or v:gsub('^(.-) -( ?\\?%+?%d?)$', function(a, b)
					if v == invokePage then a, b = v, ''
					elseif b:sub(2, 2) ~= '+' or not tonumber(b:sub(3, 3)) then a, b = a .. b, '' end
					return ('[[%s]]%s'):format(a, b):gsub('\\%+', '+')
				end, 1))
	end
	local function chain_link(v, effect)
		if effect then
			return "{{Chain|" .. v .. "}}"
		else
			return "[[Chaining/" .. v .. "|" .. v .."]]"
		end
	end
	local function tooltip_link(v, hide_disambiguation)
	--Makes tooltip link.
		if v == currentTitle then return "'''" .. v .. "'''" end
		local fetch, only = {title = ':' .. v, args = {'effect', 'ability', mode = 'fetch'}}
		only = frame:expandTemplate(fetch):match('%[%[' .. args.name:gsub('%p', '%%%1') .. '%f[|%]][^%]]-%]%] *%((.- only)%)')
			or frame:expandTemplate(
				fetch,
				rawset(fetch.args, 2, nil),
				rawset(fetch.args, 1, 'warning')
			):match'[^,]+ only'
		only = only and ' (' .. only .. ')' or ''
		return ('{{:%s|mode=tooltip%s}}')
			:format(v, hide_disambiguation and '' or '|full_pg=1')
			.. only
	end
	local function link2tooltip(v, hide_disambiguation)
	--checks all links for Module:Data and replaces them with tooltips when possible. Only use when non-Module:Data pages may be passed
		for lookback, wikilink, page in v:gmatch'(.?)(%[%[([^:#][^|%]]+)|?[^%]]*%]%])' do
			if lookback ~= '(' and not (page:find':[^ _]' or page:find'#' or stats[page:match'(.+) %+%d'] or mw.title.new(page).redirectTarget) then
				-- disable tooltips for various pages to get around template size limit
				if currentTitle == "Category:Weapons" or currentTitle == "Category:Super Trust Master Rewards" or
				   currentTitle == "Category:Trust Master Rewards" or currentTitle == "Category:Armors" or
				   p.disable_tooltip[currentTitle]
				then
					local tooltip = ""
				else
					local tooltip = frame:preprocess('{{msgnw::' .. page .. '}}')
					if tooltip:lower():find'#invoke:data%s*&#124;%s*item' then
						v = v:gsub(wikilink:gsub('%p', '%%%1'), tooltip_link(page, hide_disambiguation):gsub('%p', '%%%1'))
					end
				end
			end
		end
		return v
	end
	local function split_link(v, hide_disambiguation, sep, alt_link_func)
	--Splits v by commas and joins with sep (or comma if omitted). Links using link() unless passed alt_link_func
		local t = {}
		for s in mw.text.gsplit(v:gsub("\\,", esc_seq), ',%s*') do
			s = mw.text.trim(s)
			if s ~= '' then table.insert(t, (alt_link_func or link)(s, hide_disambiguation)) end
		end
		return table.concat(t, sep or ', '):gsub(esc_seq, ',')
	end
	local function multi_split(v, head_format, sep, headless_sep)
	--Splits by ';' and passes each to split_link(). If first item prefixed by 'text:', treats 'text' as group name
		local result = {_=result._}
		for x in mw.text.gsplit(v, ';') do
			local group, list = x:gsub('\\:', esc_seq):match'^([^:]+): -(.+)$'
			group, list = group:gsub(esc_seq, ':'), list:gsub(esc_seq, ':')
			result
				:_(group and head_format:format(group) or headless_sep)
				:_(split_link(list or x, nil, group and sep or headless_sep, group == 'Equipment' and tooltip_link))
				:_'\n'
		end
		return table.concat(result)
	end
	local function ailment_link(v, hide_disambiguation)
	--Autolinks ailments. When hide_disambiguation is nil or true, also autolinks non-ailments.
		local status, chance  = v:match'^([^%(]-) ?%(([^%)%(]-)%)'
		if status and (p.ailment)[status] then
			return ('[[Status Ailments#%s|%s]] (%s)'):format(status, status, chance)
		elseif status and v:find' status ailments? ' then return (v:gsub(' (status ailments?) ', ' [[Status Ailments|%1]] ', 1)) end
		if hide_disambiguation == false then return v end--for args.resist
		return link(v, hide_disambiguation)
	end
	local function materia_ailment_link(v)
	--auto-links ailments for materia.
		if v then for i, pattern in ipairs{
			'Cures? [^\n<]+ to ',
			'Inflicts? [^\n<]+ %(',
			'Increase resistance to [^\n<]+ %(',
			'Increase [^\n<]+ resistance %(',
			'[Rr]emove '
		} do if v:find(pattern) then
			for ailment in pairs(p.ailment) do
				v = v:gsub(
					" ('*)" .. ailment:lower(),
					(' %s1[[Status Ailments#%s|%s]]'):format('%', ailment, ailment:lower()),
					1
				)
			end
			flags.groupStatusCure, v =
				flags.groupStatusCure or i == 1 and v:find'all allies',
				v:gsub(" ('*)(status ailments?)('*) ", ' %1[[Status Ailments|%2]]%3 ', 1)
			break
		end end end
		return v
	end
	local function icon(v)
	--Makes item image. If passed a string, links to it. If passed true, links to the #invoke page (not name param)
		return (v and '[[File:%s|%s|link=%s]]' or '[[File:%s|%s]]'):format(
			args.image or ('Icon-%s.png'):format(args.name),
			args.name or '',
			v == true and invokePage or v
		)
	end
	local function smallicon(v)
	--Makes 32x32px item image. If passed a string, links to it. If passed true, links to the #invoke page (not name param)
		return (v and '[[File:%s|%s|link=%s|32x32px]]' or '[[File:%s|%s|32x32px]]'):format(
			args.image or ('Icon-%s.png'):format(args.name),
			args.name or '',
			v == true and invokePage or v
		)
	end
	local function recipe()
		return args.rec_mat and link2tooltip(frame:preprocess(split_link(args.rec_mat, nil, '<br>', function(v)
			local item, quantity, found_img = v:match'(.-) ?%(?(%d+)%)?$'
			found_img = mw.text.decode(frame:preprocess('{{msgnw::'.. (item or v) ..'}}')):match'|%s*image%s*=%s*([^<]-%.png)'
			return ('{{Item|%s|%s%s}}'):format(item or v, quantity or 1, found_img and '|image=' .. found_img or '')
		end)), true)
	end
	local function widget_sort_stats(close)
	--provide html element attributes for Widget:Sort_Stats
		local sortdata = {}
		for k, v in pairs(stats) do if v[1] or v[2] then
			table.insert(sortdata, 'data-'..k..'="'..args[k]..'"')
		end end
		if args.evade then table.insert(sortdata, 'data-evade="'..args.evade..'"') end
		return ' style="text-align:left" class=stats_cell ' .. table.concat(sortdata, ' ') .. (close or ' | ')
	end
	local function stats_cell(mode_tooltip)
	--generates stats cell used on category/shop pages for equipment; if mode_tooltip, hide_disambiguation and return stats table without concat
		local only, lines =
			args.warning and args.warning:match"Useable by '?'?'?(%a+)'?'?'? only",
			{stats_sorted[1] and table.concat(stats_sorted, ', '), _=result._}
		lines
			:_(args.element and 'Element: ' .. args.element)
			:_(args.resist and 'Resistance: ' .. split_link(args.resist, false, nil, ailment_link))
			:_(args.effect and 'Effect: ' .. link2tooltip(split_link(args.effect, mode_tooltip, nil, ailment_link), mode_tooltip))
			:_(args.ability and 'Ability: ' .. link2tooltip(split_link(args.ability, mode_tooltip), mode_tooltip))--use tooltip_link after module used on all ability pages
			:_(args.warning and (only and
				("'''%ss only'''"):format(mw.getContentLanguage():ucfirst(only))
				or ("'''%s'''"):format(args.warning):gsub(", ?", "<br>")
			))
			:_(args.used_by and 'Exclusive: ' .. split_link(args.used_by))
		return mode_tooltip and lines or lines[1] and table.concat(lines, '<br>')
	end
	local function randomized_table(v)
	--takes a string with multiple lines (separated by <br> or \n) and appends effects to each line from each double bullet in args.ability.
		local s = v:gsub('<br ?/?>', '\n')
		--if not s:find'\n(%([^\n]+)' then return v end
		return args.ability and s:find'\n%(' and
			'<table style="margin:0"><tr><td colspan=3>'
				.. s
					:gsub('\n\n+', '\n')
					:gsub("\n%f[%w '{<]", '</td></tr></table>', 1)
					:gsub("'''", '')
					:gsub('%%', '%%%%')
					:gsub(
						"\n(%([^\n]+)",
						'</td></tr><tr style="vertical-align:top"><td style="white-space:nowrap;padding-left:3em;text-indent:-3em">%1</td><td>&nbsp;-&nbsp;</td><td>%%s'
					)
					:gsub('(%) +%w+[- ] *%w+[- ] *)(%(?[%w]+)', '%1<wbr>%2')
					:format(select(2, unpack(mw.text.split(materia_ailment_link(args.ability):gsub('\n', ''), "%*.-%*%*"))))
				.. (not v:find'</table>' and '</td></tr></table>' or '')
			or v
	end
	local function effect_auto_link(v)
	--autolink killers, equipment masteries and wields, and status ailments in materia effects
		if v:find' killer ' or v:find' against ' then
			for cat, initial in pairs(p.killer) do
				local match = v:match(" '*(" .. cat:sub(1, -1):lower() .. "%l?)")
					or v:match(" '*(" .. initial .. "%l*)")
				v = match and v:gsub(match, ('[[:Category:%s|%s]]'):format(cat, match), 1) or v
			end
		elseif v:find'Increase .- equipped with' or v:find'Enable dual wielding' then
			for cat in pairs(p.equipment) do
				local match = v:match("'*([%a,']+ +'*" .. cat:lower() .. (cat:sub(-1)=='y' and '?i?e?s?)' or 's?)'))
					or cat == 'Staff' and
						v:match("'*([%a,']+ +'*staves)")
				v = match and match:sub(1, 5) ~= 'great' and v:gsub(
					match:gsub("^.- '*", '', 1),
					('[[:Category:%s|%s]]'):format(
						(p.equipment._plural[cat]
							or cat:gsub('y$', 'ie') .. 's'
						),
						match:gsub("^.- '*", '', 1)
					),
					1
				) or v
			end
		else v = materia_ailment_link(v) end
		return v
	end
	local function passive_stat_boost(effects)
		local list, group, last_percent = {[true] = {}, [false] = {}}, {[true] = {}, [false] = {}}, {[true] = {}, [false] = {}}
		for i = 1, #p.stat_order do
			if args[p.stat_order[i]] then
				local positive = tonumber(args[p.stat_order[i]]:match"^'*(%-?%d*)%%'*$") > 0
				if group[positive][1] then
					if last_percent[positive] ~= args[p.stat_order[i]] then
						table.insert(list[positive], ('%s (%s)'):format(table.concat(group[positive], '/'), last_percent[positive]))
						group[positive], last_percent[positive] = {}, args[p.stat_order[i]]
					end
				else last_percent[positive] = args[p.stat_order[i]] end
				table.insert(group[positive], p.stat_order[i])
				effects[args[p.stat_order[i]]] = (effects[args[p.stat_order[i]]] or 0) + 1
			end
		end
		for _, positive in ipairs{false, true} do
			if group[positive][1] then
				table.insert(effects, 1, (('%screase %s%s%s (%s)')
					:format(
						positive and 'In' or 'De',
						table.concat(list[positive], ', '),
						list[positive][1] and ' and ' or '',
						table.concat(group[positive], '/'),
						last_percent[positive]
					)
					:gsub('%(%-', '(')
				))
			end
		end
		return effects
	end
	local function materia_effects(mode_tooltip, no_chain)
	--generates ability materia effects. If passed true as, returns effects as a table without concat.
		local effects, transcluded, show_table = 
			args.effect and mw.text.split(args.effect, '%s*\n%s*') or {},
			invokePage ~= currentTitle,
			args.ability and (args.type ~= 'Passive' or args.mode == 'category')
		for k, v in ipairs(effects) do
			local enable, skills = v:match(p.patterns.enable)
			if enable then
				effects[k] = args.effect:match(p.patterns.wikilink) and
					effects[k]:gsub('(\\?)\\,', '%1,')
					or enable .. split_link(skills)
				while v:find((effects[k + 1] or ''):match'%[(.+)%]%S*%s*=' or '^%$$') do table.remove(effects, k + 1) end
			elseif transcluded and args.ability and (v:find':[\n<][b%(][r%d]' or v:find'[Cc]ounter') then
				if v:gsub('<br ?/?>', '\n'):find'^[^\n]+:\n%(' then
					effects[k] = show_table and randomized_table(v) or v
				elseif args.type == 'Passive' then
					for name, effect in args.ability:gmatch'%* *([^\n]-) *\n%*%*%s*([^\n]+)' do
						effects[k] = v:gsub(
							name:gsub('%p', '%%%1'), 
							'{{tooltip|2=%1|1=%1<br>' .. effect:gsub('%%', '%%%1'):gsub('Randomly use:<br ?/?>', '') .. ' |style=white-space:nowrap}}'
						)
					end
				end
			else effects[k] = effect_auto_link(v) end
		end

		if not no_chain then
			if args.chain then table.insert(effects, chain_link(args.chain, true)) end
		end
		--Note: Below inserted in backwards order to the front of the effects table
		if args.evade_m then table.insert(effects, 1, p.template.evade:format('magic', args.evade_m)) end
		if args.evade_p then table.insert(effects, 1, p.template.evade:format('physical', args.evade_p)) end
		passive_stat_boost(effects)
		if args.used_by and not args.learn and args.mode and args.mode ~= 'exclusiveFX' then
			table.insert(effects, 'Exclusive: ' .. split_link(args.used_by))
		end
		return mode_tooltip and effects or effects[1] and table.concat(effects, '<br>'):gsub('(</table>)<br>', '%1')
	end
	local function type_link(parens)
	--makes [[:Category:Weapons]] ([[:Category:Guns]]). If parens is true, places them in parenthesis
		return p.ability[args.type] and '[['
				.. p.ability._class[p.ability[args.type]]:sub(1, -2)
				.. (p.ability[args.type] == 1 and 'ies (%s)]]' or 'ies]]')
					:format(args.type)
			or p.equipment[args.type] and (parens and ' ([[:Category:%s|%s]])' or '[[:Category:%s|%s]]'):format(
					p.equipment._plural[args.type] or args.type:gsub('y$', 'ie') .. 's',
					args.type
				)
			or args.usage and '[[:Category:Materials]]' or '[[Miscellaneous Items]]'	
	end
	local function multi_break(s)
	--takes args.hits or arg.MP_cost and splits them by backslash or semicolon, inserting same number of breaks per item as in args.ability
		if s and not tonumber(s) and s:find(p.patterns.multi_break) then
			local hits = ('/ ' .. s .. ' /'):gmatch(p.patterns.multi_break) 
			s = {}
			for v in mw.text.gsplit(
				args.ability
					or args.effect:gsub('\nIf used after[^\n]+:', '<br>'):gsub(':\n', '<br>'),
				args.ability and '\n%*%*' or '\n'
			) do
				table.insert(s, ('<br>'):rep(select(2, v:gsub('<br ?/?>', '')) + 1))
				table.insert(s, (hits()))
			end
			if not args.ability then table.remove(s, 1) end
			s = table.concat(s)
		end
		return '\n| ' .. (s or '-')
	end
	local frame_tooltip = '[[#.|{{Tooltip|style=text-align:left' .. frame:callParserFunction('#tag:nowiki', ';') .. 'white-space:nowrap|hideicon=|'
	local function attack_frames(hits, v)
	--[[
		pass args.hits as first param. Reads args.atk_frm and makes tooltip.
		Also recursively splits and tooltips args.atk_frm by / or ; characters if such are present in args.hits
	]]
		hits = hits ~= '' and hits ~= '-' and hits
		if hits and args.atk_frm then
			if not v and hits:find(p.patterns.multi_break) then
				local split = {
					hits = ('/ ' .. hits .. ' /'):gmatch(p.patterns.multi_break), 
					a_frames = ('/ ' .. args.atk_frm  .. ' /'):gmatch(p.patterns.multi_break)
				}
				for hit_count in split.hits do
					local animation = split.a_frames()
					table.insert(split, animation and tonumber(hit_count) and attack_frames(hit_count, animation) or hit_count)
				end
				hits = table.concat(split, ' / ')
			else
				local output, frames = {_=result._}, mw.text.split(v or args.atk_frm, ' ?[,%-] ?')
				output
					:_(frame_tooltip)
					:_(#frames > 1 and 'Frame delay: ' or 'Attack frame: ')
					:_(frames[1])
				if #frames > 1 then
					for i = 2, #frames do output:_(-tonumber(frames[i]) + tonumber(frames[i - 1])) end
					output
						:_'<br>Attack frames: '
						:_(table.concat(frames, '-'))
				else output:_(table.concat(frames, nil, 2, #frames)) end
				hits = table.concat(output:_'|':_(mw.text.trim(hits)):_'}}]]')
			end
		end
		return hits
	end
	local froms, hasExclusiveFX, learned = {
		--[[
		{parameter name, how-to-obtain title, flag}
		Set flag for sources that would not place an ability in Category:Items and to exclude source from how-to-obtain cell for mode=category
		1 = list parameter for equipable sources
		2 = non-equipment sources or non-list parameter
		]]
			{'drop', 'Dropped from'},
			{'steal', 'Stolen from'},
			{'explore', 'Collected from'},
			{'shop', args.quartz and 'Star Quartz' or 'Shop'},
			{'recipe', 'Recipe'},
			{'chest', 'Chest'},
			{'reward', 'Reward'},
			{'equip',  'Equipment', 1},
			{'materia', 'Ability Materia', 1},
			{'learn', 'Learned by', 2},
			{'esper', 'Esper', 2},--because not a comma-separates list
			{'enable', 'Enabled by', 2}
		},
		args.effect and--do not check used_by here
			args.effect:match(p.patterns.only)
			or args.ability and args.ability:match(p.patterns.only)--use match() not find()
	currentTitle, namespace, invokePage = 
		mw.title.getCurrentTitle().fullText,
		mw.title.getCurrentTitle().namespace,
		frame:getParent():getTitle()
	args.name = args.name or not invokePage:find':' and invokePage
	args.mode = args.mode
		or p_args.mode
		or currentTitle == 'Module:Data' and 'demo'
		or currentTitle == 'Ability Awakening' and 'awaken'
		or (namespace == 14
				or p.ability[args.type] and (
					currentTitle == 'Ability Materia'
					or currentTitle == (p.ability[args.type] == 1 and
						('Special Abilities (%s)'):format(args.type)
						or 'Magic Abilities'
					)
				)
			) and 'category'
		or invokePage ~= currentTitle and (
			(args.recipe or args.reward) and (args.recipe or args.reward):find(
				p.patterns.event
				.. currentTitle:gsub('_', ' '):gsub('%p', '%%%1')
			) and 'event'
			or (hasExclusiveFX == currentTitle or args.used_by and args.used_by:find(currentTitle)) and 'exclusiveFX'
			or p.equipment[args.type] and 'item'
			or 'typeless'
		)
	local function format_skill_args()
		--simplifies pattern matching by allowing newlines and <br> to be used interchangeably
		args.effect = args.effect and args.effect
			:gsub('(([^\n]+)\n%()', function(match, prev_line)
				if prev_line:find'=' then return match end
				return prev_line .. '<br>('
			end)
			:gsub('\n+(If used after)', '\n<br>%1')
		if args.ability and not args.ability:find('\n*', 1, 1) then
		--automatically takes names from effect param for randomized abilities and transcludes effect if line == '[data]'
			local a = mw.text.split(args.ability, '\n')
			if a[2] then
				args.ability = {}
				for name in args.effect:gmatch'<br ?/?>%([^\n<]+%) ([^\n<]+)' do
					local abil = table.remove(a, 1)
					if abil == '[data]' then
						abil = frame:expandTemplate{title = ':' .. name:match'%[%[(.-)[|%]]', args = {'STATS', mode = 'fetch'}}
					end
					table.insert(args.ability, ('*%s\n**%s'):format(name, abil or 'NO DATA'))
				end
				args.ability = table.concat(args.ability, '\n')
			end
		end
	end
	local function format_split_args(v) return v and v:gsub(' ?; ?', ' / '):gsub(' +', ' '):gsub('^ ?/', '- /'):gsub('/ /', '/ - /') end
	if p.ability[args.type] then
		learned = not p_args.mode and args.learn and invokePage ~= currentTitle and {args.learn:match('\n|? *%[%[' .. currentTitle .. '.-|?[$|]?%s*(<[^\n]+>)%s*|?[$|] ?(%d%d?%d?)')}
		args.hits, args.atk_frm, args.MP_cost =
			args.hits and (
				args.hits:find'^[dD][^/;]*$' and
					((args.mode or learned and learned[1]) and 'D' or 'Default unit attack')
					or format_split_args(args.hits)
			),
			args.atk_frm and format_split_args(args.atk_frm),
			args.MP_cost and
				format_split_args(args.MP_cost)
				or args.type == 'Active' and 0
		format_skill_args()
	end
	if learned and learned[1] then
	--Display when transcluded onto a page listed in args.learn
		local unmerge, hits = args.type ~= 'Passive' or p_args[1] == 'unmerge'
		result
			:_'|-\n|'
			:_(learned[1])
			:_'\n|'
			:_(learned[2])
			:_'\n|'
			:_(icon(true))
			:_'\n|align=left|'
			:_(link(args.name, true))
			:_'\n|align=left'
			:_(unmerge and '|' or ' colspan=3|')
		if args.filter then
			result
				:_'{{#Widget:Filter|skills='
				:_(args.filter)
				:_'}}'
		end
		result
			:_(materia_effects():gsub("(%) with [^\n:]+): ?<br ?/?> ?%([^\n]+", '%1'))--save random counter info for mode=conditional
		if unmerge then
			result
				:_(multi_break(attack_frames(args.hits)))
				:_(multi_break(args.MP_cost))
		end
	elseif args.mode and args.mode ~= 'demo' then
		local function BADGE()
			return ('<p style="text-align:center">%s<br>%s<br>(%s)</p>'):format(
				icon(true),
				link(invokePage ~= args.name and invokePage .. '|' .. args.name or invokePage),
				type_link()
			)
		end
		local function STATS(b)
			local v = (p.equipment[args.type] and stats_cell or materia_effects)()
			return not (b or p_args.sep or args.mode == 'fetch' or p_args[1] == 'STATS') and v and widget_sort_stats() .. v or v
		end
		local function extend(sep)
		--Reads customization parameters from parent frame. Def = default value, sep = separator
			local magic_words = {
				STATS = {STATS},
				ICON = {icon, true},
				TYPE = {type_link},
				LINK = {link, table.concat({invokePage, args.name}, '|')},
				RECIPE = {recipe},
				BADGE = {BADGE}
			}
			for _, v in ipairs(p_args) do
				_ = mw.text.trim(mw.text.killMarkers(v))
				if _ ~= '' then
					local a, b = v:gsub('\\@', esc_seq):match'^(.-)@(.*)'
					result:_(sep or '\n| '):_(
						a and (a~='' and 
							((args[a] or magic_words[a]) and 
								b:gsub(esc_seq, '@'):format(
									frame.args[a] ~= '' and frame.args[a]
									or args[a]
									or magic_words[a][1](unpack(a == 'STATS' and {nil, b} or magic_words[a], 2))
								)
								or '-')
							or b and b:gsub(esc_seq, '@'))
						or frame.args[_] ~= '' and frame.args[_]--return unprocessed non-empty args
						or args[_]--for auto args
						or magic_words[v] and magic_words[v][1](unpack(magic_words[v], 2))
						or p_args.default or '-'
					)
				end
			end
		end
		if args.mode == 'category' then
		--Display when on category page
			local obtain, equipped = {}, {}
			for i = 1, #froms do
				if args[froms[i][1]] and froms[i][3] ~= 2 then
					table.insert(froms[i][3] and equipped or obtain, 
						froms[i][3] and
							split_link(args[froms[i][1]]:gsub('%]%] %([^%)]+%)', ']]'), nil, froms[i][3] and '<br>')
							or ("'''%s:''' %s"):format(
								froms[i][2],
								split_link(args[froms[i][1]])
					))
				end
			end
			if args.esper then
				for esper in args.esper:gmatch'%[%[[^:]-%]%]' do table.insert(equipped, esper) end
			end
			table.insert(obtain, args.trust and ("'''TMR:''' [[%s]]"):format(args.trust))
			table.insert(obtain, args.STMR and ("'''STMR:''' [[%s]]"):format(args.STMR))
			table.insert(obtain, args.obtain and multi_split(args.obtain, "'''%s''': ", ', ', '<br ?/?>'))
			result
				:_'|-\n|'
				:_(tonumber(p_args.rowspan) and ('rowspan=%s style="text-align:center"| %s ||')
					:format(p_args.rowspan, args.mag_lv or '')
				)
				:_(args.image and p.ability[args.type] and 'data-sort-value=' .. args.image:match'_(%d+)%.')
				:_((' align=center|%s|| %s || '):format(
					icon(true),
					link(args.name, true)
				))
				:_((p.equipment[args.type] or args.type == 'Passive') and widget_sort_stats())
				:_(p.equipment[args.type] and stats_cell()
					or materia_effects())
				:_' \n| '
				:_(p.ability[args.type] and result
					:_(args.MP_cost and ('style="text-align:center"| %s ||'):format(args.MP_cost) or '')
					:_(equipped[1] and table.concat(equipped, '<br>') or '-')
					:_' || '
					and nil
				)
				:_(obtain[1] and table.concat(obtain, '<br>') or '-')
			extend()
		elseif args.mode == 'exclusiveFX' then
		--Display when current page title matches name of the unit which benefits from an exclusive effect
			result
				:_(p_args[1] ~= 'rowonly' and ("{| class=wikitable style='text-align:center;width:100%'\n!" ..
					(p.equipment[args.type] and "Icon!!Name!!Type!!Effect"
					or "style='width:50px'|Icon!!style='width:130px'|Name!!Effect!!style='width:50px'|Hits{{tooltip|style=white-space:nowrap|D {{=}} Default unit attack}}!!style='width:50px'|MP")
				))
				:_"\n|-\n|"
				:_(icon(true))
				:_'\n| '
				:_(link(args.name, true))
				:_'\n|'
				:_(p.equipment[args.type] and type_link() ..'\n|')
				:_(widget_sort_stats())
				:_(p.equipment[args.type] and
					(stats_cell() or '')--in case stats_cell() returns nil
					or table.concat{
						materia_effects(),
						multi_break(attack_frames(args.hits)),
						multi_break(args.MP_cost)
					}
				)
			if p_args[1] ~= 'rowonly' then result:_'\n|}' end
		elseif args.mode == 'conditional' then
			local function conditional_row(rowspan, activator)
				result
					:_'|-\n|colspan=3'
					:_(rowspan and result:_' rowspan=' and rowspan)
					:_'|Activated by<br>'
					:_(activator ~= '' and activator
						or args.enable and split_link(args.enable)
						or link(args.name, true)
					)
					:_'||style="text-align:left"| '
			end
			local ability_count, isPassive, randomized_counter, unmerge =
				args.ability and select(2, ('\n'..args.ability):gsub("%*'''", 0)),
				args.type == 'Passive',
				args.effect and args.effect:match"Chance to counter[^\n]+with '?'?'?(.-)'?'?'?:<br ?/?>%(%d+%%",
				p_args[1] == 'unmerge'
			if args.ability then
				conditional_row()
				if randomized_counter then
					result
						:_(randomized_counter)
						:_'\n|style="text-align:left"| '
						:_(randomized_table(materia_effects()):gsub("Chance to counter[^\n]-:", 'Randomly use:'))
						:_(multi_break(attack_frames(args.hits)))
						:_(multi_break(args.MP_cost))
				else
					if ability_count > 0 then table.insert(result, 2, ' rowspan=' .. ability_count) end
					if args.ability and not args.hits and args.ability:find'>Hits:' then
						args.hits, args.MP_cost = {}
						for line in args.ability:gmatch'\n%*%*[^\n]+' do
							local a, b, h = line:find'<br ?/?>Hits: *(.+)'
							if a then
								local offset = args.ability:find(line, 3, 1)
								args.ability = args.ability:sub(1, offset + a - 2) .. args.ability:sub(offset + b)
								table.insert(args.hits, h)
							else table.insert(args.hits, '-') end
						end
						args.hits = table.concat(args.hits, ' / '):gsub('Default unit attack', 'D')
					end
					result
						:_(args.ability and materia_ailment_link(args.ability)
							:gsub("\n%* *'''(.-)'''", '|-\n|style="text-align:left"| %1')
							:gsub("%* *'''(.-)'''", '%1')
							:gsub('%*%*', '| style="text-align:left"' 
								.. (isPassive and not (args.hits or args.MP_cost or unmerge) and
									' colspan=3| '
									or '| '
							))
						)
					if unmerge or args.hits or args.MP_cost then
						result
							:_(multi_break(attack_frames(args.hits)))
							:_(multi_break(args.MP_cost))
					end
				end
			elseif args.enable then
				if p_args.rowspan == '0' then result:_'|-\n|style="text-align:left"| '
				else conditional_row(tonumber(p_args.rowspan)) end
				result
					:_(link(args.name, true))
					:_'\n|style="text-align:left"| '
				if args.filter then
					result
						:_'{{#Widget:Filter|skills='
						:_(args.filter)
						:_'}}'
				end
				result
					:_(materia_effects())
					:_(multi_break(attack_frames(args.hits)))
					:_(multi_break(args.MP_cost))
			else for line in args.effect:gsub('<br ?/?>%s*%(', '\n('):gmatch'[^\n]*Enable[^\n]+' do if not line:find'%].*=' then
				local skills, ability_count = (select(2, line:match(p.patterns.enable)) or line:match' of (.+)')
					:gsub('([^\\]), *', '%1@$#')
				result:_(result[1] and '\n')
				conditional_row(
					ability_count > 0 and ability_count + 1,
					(line:gsub('\\:', esc_seq):match'^%(%d+%%%) *(.-):' or ''):gsub(esc_seq, ':')
				)
				for k, v in ipairs(mw.text.split(skills, '@$#')) do--no gsplit because k needed
					if k > 1 then result:_'\n|-\n|style="text-align:left"| ' end
					local title, page = (v:match'%[%[(.-)[|%]\]' or v):gsub('\\,', ',')
					page = mw.title.new(title).exists and frame:expandTemplate{title = ':' .. title, args = {page = title}}
						:gsub('Default unit attack', 'D')
					local override, page_effect =
						frame.args.effect:match('\n%s*effect%[' .. title:gsub('%p', '%%%1') .. '%]%s*=%s*([^\n]+)')
							or frame.args.effect:match('\n%s*%[' .. title:gsub('%p', '%%%1') .. '%]effect%s*=%s*([^\n]+)'),
						page and page:match("'''Effect:'''\n:([^*=]+)\n")
					args.effect = (override or page_effect or 'ERROR - No page or override found for ' .. link(title)):gsub('\\n', '\n')
					result
						:_(page and link(v, true) or v)--when all abilities use Data, replace all with:						 
						--:_('{{:'..v..'|mode=fetch|STATS|{{tooltip|{{{hits}}}|Attack frame(s): {{{atk_frm}}}}}|MP}}') 
						:_'\n|style="text-align:left"| '
						:_(page and override and '<span class="ttip">')
						:_(args.effect)
						:_(override and page_effect and 
							"<span class=tip style='width:40em'><u>Automated Warning</u><br>A page exists for ''"
							.. link(v)
							.. "'' but an override has been set on ''"
							.. link(invokePage)
							.. "''. If the effect shown is the same as the following, please remove the override:<table class=wikitable  style='margin:auto' ><tr><td>"
							.. page_effect
							.. "</td></tr></table></span></span>")
					--args.atk_frm = args.effect:match('\n%s*atk_frm%[' .. title:gsub('%p', '%%%1') .. '%]%s*=%s*([^\n]+)') or args.atk_frm
					for i, m in ipairs{{'Hits', 'hits'}, {'MP', 'MP_cost'}} do
						result:_(multi_break(
							frame.args.effect:match('\n%s*' .. m[2] .. '%[' .. title:gsub('%p', '%%%1') .. '%]%s*=%s*([^\n]+)')
								or frame.args.effect:match('\n%s*%[' .. title:gsub('%p', '%%%1') .. '%]' .. m[2] .. '%s*=%s*([^\n]+)')
								or page and page:match("'''" .. m[1] .. ":''' ([^\n]+)")
								or '-'
						))
					end
				end
			end end end
		elseif args.mode == 'awaken' then
			local function bold(v)
				return v and ((v:find"'''" or v:find'</?b>') and v or ("'''%s'''"):format(v)) or ''
			end
			local function unbold(v, manual_bold)--removes striked text and all tags except those that start with a t (table)
				if manual_bold then return v end
				return v and (v
					:gsub("'''", '')
					:gsub('<br><b><s%b></s></b><br>', '\n')
					:gsub('<s%b></s>', '')
					:gsub('%b<>', function(tag)
						if tag == '<wbr>' or tag:find'^</?t' then return tag
						elseif tag:sub(2, 3) == 'br' then return '\n' end
						return ''
					end)
					:gsub('font-weight:bold;', '')
				)
			end
			local function calculate_effects()
				return unbold(materia_effects())
			end
			local unit, o_args, passive_stats, effects, new_effects = 
				p_args[1] ~= 'table' and p_args[1] ~= 'conditional' and p_args[1] or currentTitle == 'Ability Awakening' and 'Error - unspecified unit',
				{},
				{},
				unbold(materia_effects()):gsub('\n', '<br>')
			new_effects, passive_stats.lines = effects, passive_stat_boost{}
			local function parse_awakening(input)
				local to_replace, to_append, recalc, manual_bold = {}, {}
				if input then 
					for _, v in next, {'effect', 'ability'} do
						_ = '%s+' .. v .. '%s*=%s*([^=]+%f[\n])([^=]+=?)'
						local m, m2, m3 = ('\n' .. input):match(_)
						if not m then
							_ = '%s+' .. v .. '%s*=%s*([^\n]*)'
							m3 = ('\n' .. input):match(_)
						end
						if m or m3 then
							input, args[v], o_args[v], recalc, manual_bold =
								('\n' .. input):gsub(_, m2 and m2:find'=' and '%2' or ''),
								(m3 or (m2:find'=' and m or m .. m2):gsub('\n%(', '<br>(')):gsub('\\n', '\n'),
								args[v],
								true,
								manual_bold or (m or m3):find"'''" or (m or m3):find"<b>"
						end
					end
				end
				input = input and mw.text.split(input, '%s*\n%s*') or {'awk_mat=NO DATA,0'}
				for i = 1, #input do
					if i == 1 and args[input[i]] then parse_awakening(args[input[i]])
					else
						local diff = mw.text.split(input[i], '%s*=>%s*')
						if diff[2] then
							table.insert(to_replace, {diff[1]:gsub('\\n', '\n'), diff[2]:gsub('\\n', '\n')})
						else
							diff = mw.text.split(input[i], '%s*=%s*')
							if diff[2] then
								diff[2] = diff[2]:gsub('\\n', '\n')
								if diff[2] == '' then diff[2] = nil end
								if ({hits=1,atk_frm=1,MP_cost=1})[diff[1]] then diff[2] = format_split_args(diff[2]) end
								if stats[diff[1]] then
									if diff[2] == '0' or diff[2] == '0%' then diff[2] = nil end
									if args[diff[1]] then passive_stats.lines[args[diff[1]]] = passive_stats.lines[args[diff[1]]] - 1 end
									o_args[diff[1]], args[diff[1]], passive_stats.changed, passive_stats[diff[1]] = args[diff[1]], diff[2], true, true
								elseif (diff[1] == 'chain') then
									new_effects = mw.text.split(new_effects, new_effects:find'\n' and '\n' or '<br>')
									table.insert(new_effects, chain_link(diff[2], true))
									new_effects = table.concat(new_effects, '<br>')
								elseif (diff[1] == 'evade_p' or diff[1] == 'evade_m') then
									if not recalc and args[diff[1]] ~= diff[2] then
										local physical, v, evade = diff[1] == 'evade_p' and 'physical', diff[2]--:gsub('%%', '%%%%')
										evade = physical or 'magic'
										if args[diff[1]] then
											table.insert(to_replace, {
												new_effects:match(p.template.evade:format(evade, '[^(]+'):gsub('[()]', '%%%1')),
												p.template.evade:format(evade, (#(frame.args[diff[1]] or '') > 0 or not unit and args[diff[1]]) and bold(v) or v)
											})
										else
											new_effects = mw.text.split(new_effects, new_effects:find'\n' and '\n' or '<br>')
											table.insert(
												new_effects,
												1 + #passive_stats.lines + (not physical and args.evade_p and 1 or 0),
												bold(p.template.evade:format(evade, v))
											)
											new_effects = table.concat(new_effects, '<br>')
										end
									end
									args[diff[1]] = diff[2]--no recalc
								elseif not args[diff[1]] or unbold(diff[2]) ~= unbold(args[diff[1]]) then
									o_args[diff[1]], args[diff[1]] =
										args[diff[1]] or '0',
										({awk_mat=1,name=1,atk_frm=1})[diff[1]] and diff[2] or bold(diff[2])
								end
							elseif input[i] ~= '' then table.insert(to_append, input[i]) end
						end
					end
				end
				if recalc then
					if args.ability then
						format_skill_args()
						new_effects = frame.args.ability and frame.args.ability ~= '' and bold(unbold(materia_effects(), manual_bold))
							or unbold(materia_effects(), manual_bold)
								:gsub('(<table style=")', '%1font-weight:bold;')
								:gsub('(</table>)(.+)', "%1'''%2'''" )
								:gsub('^(.+)(<table)', "'''%1'''%2")
					else new_effects = bold(unbold(materia_effects(), manual_bold)) end
					new_effects, passive_stats.changed = frame:preprocess(new_effects)
					local a, b = new_effects:find(effects, 1, 1)
					if not a then a, b = new_effects:find(frame.args.effect, 1, 1) end
					if a and (not frame.args.ability or frame.args.ability == '') then
						new_effects = new_effects:sub(1, a - 1)
							.. '<span style="font-weight:normal">' .. effects .. '</span>'
							.. new_effects:sub(b + 1)
					else
					--Unbold if override effect is found in original (assume strikethrough was undesired)
						local plain = unbold(new_effects)
						if effects:find(plain, 1, 1) or frame.args.effect:find(plain, 1, 1) then new_effects = plain end
					end
				elseif passive_stats.changed then
					new_effects = mw.text.split(new_effects, new_effects:find'\n' and '\n' or '<br>')
					local new_lines = passive_stat_boost{to_replace = unit and passive_stats.lines.to_replace or {}}
					if #new_lines > #passive_stats.lines then
						for n = 1, #new_lines do
							local a = new_lines[n]:sub(1, 3)
							if not table.concat(passive_stats.lines):find(a) then new_lines[n] = bold(new_lines[n]) end
						end
					elseif #new_lines < #passive_stats.lines then
						for n = 1, #passive_stats.lines do
							local a = passive_stats.lines[n]:match'(%u%l%l)rease '
							if not table.concat(new_lines):find(a) then
								table.insert(new_lines, select(a == 'Inc' and 1 or 2, 1, ("<b><s>%s</s></b>"):format(passive_stats.lines[n])))
							end
						end
					end
					for n = 1, #passive_stats.lines do table.remove(new_effects, 1) end
					table.insert(new_effects, 1, table.concat(new_lines, '<br>'))
					new_effects = table.concat(new_effects, '<br>')
					for _, stat in ipairs(p.stat_order) do
						if args[stat] then
							if passive_stats.lines[args[stat]] == 0 or not passive_stats.lines[args[stat]] then
								local percent = args[stat]:sub((args[stat]:find'%d'))
								table.insert(new_lines.to_replace, {percent, percent})
							end
							passive_stats.lines[args[stat]] = (passive_stats.lines[args[stat]] or 0) + 1
						end
						if passive_stats[stat] and (
							not o_args[stat]
							or args[stat] and (
								o_args[stat]:sub(1, 1) == '-' and args[stat]:sub(1, 1) ~= '-'
								or o_args[stat]:sub(1, 1) ~= '-' and args[stat]:sub(1, 1) == '-'
							)
						) then table.insert(new_lines.to_replace, {stat, stat}) end
					end
					for n = 1, #new_lines.to_replace do table.insert(to_replace, n, new_lines.to_replace[n]) end
					if unit then new_lines.to_replace = {}
					else
						for n = 1, #new_lines do new_lines[n] = unbold(new_lines[n]) end
						passive_stats = {}
					end
					passive_stats.lines, passive_stats.changed = new_lines
				end
				for _, diff in ipairs(to_replace) do
					local a, b = new_effects:find(diff[1], 1, 1)
					if not a then
						a, b = new_effects:find(diff[1]:gsub('<br>', '\n'), 1, 1)
						if not a then
							a, b = new_effects:find(diff[1]:gsub('\n', '<br>'), 1, 1)
							if not a then 
								a, b = new_effects:find(diff[1]:gsub("'''", ''), 1, 1)
								if not a then a, b = new_effects:find(unbold(diff[1]), 1, 1) end
							end
						end
					end
					if a then
						if diff[1] == '' then new_effects = new_effects .. ' ' .. bold(diff[2])
						else
							if diff[2] == '' then diff[2] = ("<b><s>%s</s></b>"):format(diff[1]:gsub('\n', '<br>'))
							else--no bold if inside bold line
								local line = new_effects:gsub('<br>', '\n'):match('[^\n]*' .. diff[1]:gsub('%p', '%%%1') .. '[^\n]*')
								if not line then line = new_effects:gsub('<br>', '\n'):match('[^\n]*' .. unbold(diff[1]):gsub('%p', '%%%1') .. '[^\n]*') end
								if line:sub(1, 3) ~= "'''" or line:sub(-3) ~= "'''" or line:match"^'?'?'?(.-)'?'?'?$":find"'''" then diff[2] = bold(diff[2]) end
							end
							new_effects = new_effects:sub(1, a - 1)
								.. diff[2]
								.. (diff[2] == '' and (a == 1 or new_effects:find('\n' .. diff[1], 1, 1)) and
									new_effects:sub(b + 1, b + 2):upper()
										.. new_effects:sub(b + 3)
									or new_effects:sub(b + 1)
								)
						end
					elseif diff[1] == '^' then new_effects = bold(diff[2]) .. ' ' .. new_effects:sub(1, 1):lower() .. new_effects:sub(2)
					else table.insert(to_append, "''Error - Unable to find: ''" .. bold(diff[1])) end
				end
				for k, v in ipairs(to_append) do to_append[k] = bold(effect_auto_link(v)) end
				table.insert(to_append, 1, to_replace[1] and effect_auto_link(new_effects) or new_effects)
				new_effects = table.concat(to_append, '<br>'):gsub('\n', '<br>'):gsub("'''/'''", '/')
				return new_effects
			end
			local function missing_plus(unit, i) return 'awk_mat=NO DATA,0\nWarning: {{param|' .. unit .. '+' .. i .. '}} undefined' end
			if unit then
				for i = 1, tonumber(args.max_plus or p_args.max_plus) or 2 do
					new_effects = parse_awakening(args[unit .. '+' .. i] or missing_plus(unit, i))
				end
				new_effects = new_effects:gsub("'+''(''%b'''')'''+"--[[looks wrong but isn't]], "%1"):gsub(("'"):rep(6),'')
				local function arg_change(i)
					return o_args[i] and ("<br>'''%s %sed to %s'''"):format(
						({hits = 'Hit count', MP_cost = 'MP cost'})[i],
						tonumber(unbold(args[i])) and
							(tonumber(unbold(o_args[i])) > tonumber(unbold(args[i])) and ' reduc' or ' increas')
							or 'chang',
						unbold(args[i])
					) or ''
				end
				result
					:_(p_args[2] and (p_args[2] == 'table' and					
						'{|class=wikitable\n!Unit!!Abilities!!class=spacer|Base Effects!!class=spacer|Awakening'
						or '|-class=subheader\n!colspan=4|'))
					:_'\n|-\n|'
					:_(p_args[2] and
						('rowspan=%s style="text-align:center"|{{Sprite|%s}}<br>[[%s]]\n|')
							:format(tonumber(p_args[2]) or tonumber(p_args[3]) or 3, unit, unit))
					:_(link(args.name, true))
					:_'<br>('
					:_(args.awk_mat and args.awk_mat:match'^[^,]+' or '<b>awk_mat</b> undefined')
					:_')\n| '
					:_(args.ability and effects:sub(1, 7) ~= '<table ' and randomized_table(effects) or effects)
					:_'\n| '
					:_(args[unit .. '+1'] and new_effects or "''No data for unit named'' " .. bold(unit))
					:_((arg_change'hits' .. arg_change'MP_cost'):sub(new_effects:sub(-8) == '</table>' and 5 or 1))
			else
				if p_args[1] == 'table' then
					result:_'{|style="text-align:center;width:100%" class=wikitable\n|-\n!Name!!class=spacer|Effect!!style="width:50px"|{{tooltip|D {{=}} Default unit attack|Hits}}!!style="width:50px"|MP!!style="width:50px"|Type'
					for i = 1, 5 do result:_'!!style="width:20px"|T':_(i) end
					result:_'!!style="width:100px"|Gil'
				elseif p_args[1] == 'conditional' then result:_'|-\n! colspan="11" | Conditional\n|-'
				else result:_'|-class=subheader\n!colspan=11|' end
				local last_atk_frm = args.atk_frm
				for i = 1, tonumber(args.max_plus or p_args.max_plus) or 2 do
					new_effects = unbold(new_effects)
					parse_awakening(args[(p_args.skill or currentTitle) .. '+' .. i] or missing_plus(p_args.skill or currentTitle, i))
					result
						:_'\n|-\n|'
						:_(link(args.name, true))
						:_' +'
						:_(i)
						:_'\n|style="text-align:left"| '
						:_(new_effects
							:gsub("'''''%b'''''''", "'''%1'''")
							:gsub(("'"):rep(6),'')
							:gsub('\n', '<br>')
						)
						:_(atk_frm ~= args.atk_frm and
							(function()
								last_atk_frm = args.atk_frm
								return multi_break(attack_frames(args.hits)):gsub('[FA]', function(m)return'New '..m:lower()end)
							end)()
							or multi_break(args.hits)
						)
						:_(multi_break(args.MP_cost))
					if args.awk_mat then 
						local mats = mw.text.split(args.awk_mat, '%s*,%s*')
						for c = 1, #mats - 1 do result:_'\n|':_(mats[c]) end
						result
							:_'\n|'
							:_((' -\n|'):rep(7 - #mats))
							:_(frame:expandTemplate{title='Gil', args = {mats[#mats]}})
					else
						result:_'\n|colspan=7|'
						if p_args.skill then 
							if currentTitle ~= invokePage then result
								:_'via '
								:_(link(p_args.skill))
								:_' +'
								:_(i)
							else result:_' -'end
						else result:_'<b>awk_mat</b> undefined' end
					end
					args.MP_cost, args.hits = unbold(args.MP_cost), unbold(args.hits)
				end
			end
		elseif args.mode == 'event' then
			result
				:_'|-\n|'
				:_(BADGE())
				:_'\n| '
				:_(p.equipment[args.type] and stats_cell()
					or materia_effects())
			if args.recipe then result:_'\n| ':_(recipe()) end
			extend()
		elseif args.mode == 'custom' then
			result:_'|-'
			extend()
		elseif args.mode == 'fetch' then
			extend(p_args.sep)
			if p_args.sep ~= '' then table.remove(result, 1) end--removes first sep
		elseif args.mode == 'tooltip' then
			local wikilink, tip, lines =
				link(args.name, not p_args.full_pg),
				mw.html.create'td',
				(p.equipment[args.type] and stats_cell or materia_effects)(true)
			lines[1] = stats_sorted[1] and p.equipment[args.type] and
				'Stats: ' .. lines[1]
					:gsub('%((%-%d+%%?)%)', '(<span style="color:#f00">%1</span>)')
					:gsub('([^ ])(%+%d+%%?)', '%1<span style="color:#0f0">%2</span>')
				 or lines[1]
			for i = 1, #lines do
				if lines[i]:find'^<table' then
					tip:node(lines[i]:gsub('(<table style=")', '%1font-size:8.5px;'))
					lines.table = true
				else tip
					:tag'div'
					:css{
						--['padding-left']='2ex',
						--['text-indent']='-2ex',
						['font-size']=lines.table and '8.5px' or nil
					}
					:wikitext(lines[i])
				end
			end
			--tip:css{background = '#014'}
			return frame:preprocess(tostring(mw.html.create'span'
				:addClass'ttip'
					:tag'span'
					:addClass'mobileonly'
					:wikitext(wikilink)
				:done()
					:tag'span'
					:addClass'nomobile'
					:wikitext(wikilink)
				:done()
				:tag'span'
					:addClass'tip module-tooltip'
					:tag'table'
						:tag'tr'
							:tag'td'
							:css{width='90px',['text-align']='center',['vertical-align']='top',padding='12px 6px 0'}
							:attr{rowspan=2}
							:wikitext(icon'')
						:done()
							:tag'td'
							:css{font='15px Lato, sans-serif',['font-weight']='700',height='30px'}
							:node(args.name:gsub(' %(%w+%)', ''))
							:node((p.equipment[args.type] or p.ability[args.type] == 2) and mw.html.create'span'
								:css{position='absolute',right='8px',top='5px'}
								:wikitext(
									frame:expandTemplate{
										title = p.equipment[args.type] and 'Equip' or 'Affinity',
										args = {args.type == 'Throwing Weapon' and
											'Throwing'
											or args.type
										}
									},
									p.ability[args.type] and '&nbsp;Lvl&nbsp;' .. args.mag_lv .. '&nbsp;'
								)
							)
						:done()
					:done()
						:tag'tr'
						:node(tip)
				:allDone()
			))
		elseif args.mode == 'imagetooltip' then
			local wikilink, tip, lines =
				link(args.name, not p_args.full_pg),
				mw.html.create'td',
				(p.equipment[args.type] and stats_cell or materia_effects)(true)
			lines[1] = stats_sorted[1] and p.equipment[args.type] and
				'Stats: ' .. lines[1]
					:gsub('%((%-%d+%%?)%)', '(<span style="color:#f00">%1</span>)')
					:gsub('([^ ])(%+%d+%%?)', '%1<span style="color:#0f0">%2</span>')
				 or lines[1]
			for i = 1, #lines do
				if lines[i]:find'^<table' then
					tip:node(lines[i]:gsub('(<table style=")', '%1font-size:8.5px;'))
					lines.table = true
				else tip
					:tag'div'
					:css{
						--['padding-left']='2ex',
						--['text-indent']='-2ex',
						['font-size']=lines.table and '8.5px' or nil
					}
					:wikitext(lines[i])
				end
			end
			--tip:css{background = '#014'}
			return frame:preprocess(tostring(mw.html.create'span'
				:addClass'ttip tooltip-hide-icon'
					:tag'span'
					:addClass'mobileonly'
					:wikitext(smallicon(true))
				:done()
					:tag'span'
					:addClass'nomobile'
					:wikitext(smallicon(true))
				:done()
				:tag'span'
					:addClass'tip module-tooltip'
					:tag'table'
						:tag'tr'
							:tag'td'
							:css{width='90px',['text-align']='center',['vertical-align']='top',padding='12px 6px 0'}
							:attr{rowspan=2}
							:wikitext(icon'')
						:done()
							:tag'td'
							:css{font='15px Lato, sans-serif',['font-weight']='700',height='30px'}
							:node(args.name:gsub(' %(%w+%)', ''))
							:node((p.equipment[args.type] or p.ability[args.type] == 2) and mw.html.create'span'
								:css{position='absolute',right='8px',top='5px'}
								:wikitext(
									frame:expandTemplate{
										title = p.equipment[args.type] and 'Equip' or 'Affinity',
										args = {args.type == 'Throwing Weapon' and
											'Throwing'
											or args.type
										}
									},
									p.ability[args.type] and '&nbsp;Lvl&nbsp;' .. args.mag_lv .. '&nbsp;'
								)
							)
						:done()
					:done()
						:tag'tr'
						:node(tip)
				:allDone()
			))
		else
		--Display when on a shop page (mode = recipe/item/item2/typeless)
			result
				:_(('|-\n| %s@\n| %s %s')--don't remove spaces
					:gsub('@', args.mode == 'item2' and '{{item|%%s}}' or '%%s')
					:format(
						args.mode == 'recipe' and 'Recipe for '
							or '',
						args.mode == 'item2' and args.name or link(args.name, true),
						(args.mode == 'typeless' or args.mode == 'recipe') and
							(p.equipment[args.type] and '-\n| ' or 'colspan=2' .. (args.mode == 'recipe' and '| ' or ''))
							or type_link() .. '\n|',
						args.mode == 'recipe' and '-'
							or widget_sort_stats() .. (
								p.equipment[args.type] and stats_cell()
								or materia_effects()
								or (args.usage or args.awk_mat) and 'Material'
								or '-'
				)))
				:_(p_args.limit ~= '0' and ('\n|{{%s|%s}}%s'):format(
					args.quartz and 'Star Quartz' or 'Gil',
					args.quartz
						or ({item=1,item2=1})[args.mode] and args.buy_gil
						or args.mode == 'recipe' and args.buy_rec
						or '?',
					p_args.limit and ('<br>(Limit: %s)'):format(p_args.limit) or ''
				))
			extend()
		end
	else
	--info displayed on item (invoke) page
		result
			:_'__NOTOC__\n__NOEDITSECTION__'
			:_((args.image or args.name) and ('<div class="frame-%s">\n%s\n</div>'):format( 
				p.equipment[args.type] and 'equip' or p.ability[args.type] and 'ability' or 'item',
				icon()
			))
			:_(args.desc and '\n\n' .. args.desc)
		if args.mode then table.remove(result, 1) end--mode = demo
		if args.type then
			if p.equipment[args.type] then
				local materia = {args.effect}
				table.insert(materia, args.ability)
				for k, v in ipairs(materia) do materia[k] = split_link(v, true, nil, ailment_link) end
				result
					:_"\n== Statistics ==\n*'''Type:''' "
					:_(args.type == 'Accessory' and '[[:Category:Accessories|Accessory]]'
						or p.equipment._class[p.equipment[args.type]] .. type_link(true))
					:_"\n*'''Stats:''' "
					:_(stats_sorted[1] and table.concat(stats_sorted, ', ') or '-')
					:_"\n*'''Element:''' "
					:_(args.element or '-')
					:_"\n*'''Resistance:''' "
					:_(args.resist and split_link(args.resist, false, nil, ailment_link) or '-')
					:_"\n*'''Additional effect:''' "
					:_(#materia > 0 and 
						link2tooltip(args.ability and (--replace link2tooltip after all abilities use Data
							args.effect and 
								"%s and enable use of %s"
								or 'Enable use of %s'
							):format(unpack(materia))
							or materia[1], true) .. (args.warning and ', ' .. args.warning or '')
						or args.warning
						or '-'
					)
			elseif p.ability[args.type] then
				flags.rng_enable = args.effect and args.effect:find'%(%d+%%%) [^\n]*Enable' and not args.ability
				result
					:_"\n== Statistics ==\n*'''Type:''' "
					:_(p.ability._class[p.ability[args.type]])
					:_' ('
					:_(args.type)
					:_(p.ability[args.type] == 2 and ' Magic Lv ' .. args.mag_lv)
					:_")\n*'''Effect:'''\n:"
					:_(materia_effects(false, true))
					:_(args.chain and "\n*'''Chaining Family:''' " .. chain_link(args.chain))
					:_(args.hits and "\n*'''Hits:''' " .. attack_frames(args.hits))
					:_(args.MP_cost and "\n*'''MP:''' " .. args.MP_cost)
					if args.ability or flags.rng_enable then
						result
							:_'\n==Abilities==\n'
							:_(args.ability and materia_ailment_link(args.ability))
						if flags.rng_enable then
							local r, fake_parent = result, {
								getTitle = function() return currentTitle end,
								args = {mode = 'conditional'},
								getParent = frame.getParent
							}
							function frame.getParent() return fake_parent end
							result = {_ = result._}
							frame.getParent, result = fake_parent.getParent, r
								:_'{|class=wikitable style="text-align:center;width:100%"\n|-\n! colspan="3" | Condition !! width="130px" | Name !! class="spacer" | Effect !! width="50px" | Hits {{Tooltip|D {{=}} Default unit attack}} !! width="50px" | MP\n'
								:_(p.item(frame))
								:_'\n|}'
						end
					end
			elseif args.type == 'Item' and args.effect then
				result
					:_'\n== Effect ==\n'
					:_(materia_effects())
			end
		end
		result
			:_(args.notes and '\n==Notes==\n')
			:_(args.notes)
			:_'\n==Crafting recipe==\n'
			:_(args.recipe and args.recipe ~= 'none' and
				('{|class=wikitable style="text-align:center"\n!Materials!!Gil\n|-\n|align=left|%s\n||{{Gil|%s}}\n|}'):format(
					recipe() or '{{param|rec_mat}} is undefined',
					args.rec_gil or '?')
				or 'None'
			)
			:_((args.usage or args.quest) and result
				:_"\n==Usage=="
				:_(args.awk_mat and "\n''Awakening Material''\n:*" .. split_link(args.quest, nil, '\n:*'))
				:_(args.usage and "\n''Crafting Material''" .. multi_split(args.usage, "\n:''%s''\n::*", '\n::*', '\n:*'))
				:_(args.quest and "\n''Involved in Quest''\n:*" .. split_link(args.quest, nil, '\n:*'))
				and nil
			)
			:_"\n==How to obtain=="
		local function simpleTable(v)
			local rows = mw.text.split(v, '\n+')
			for k, r in ipairs(rows) do
				local cells = mw.text.split(r, "%$")
				for i, c in ipairs(cells) do
					if c:find'^ *%[%[.+%]%] *$' then cells[i] = 'style="text-align:left"| ' .. c end
				end
				rows[k] = table.concat(cells, ' || ')
			end
			result
				:_'{|class="wikitable sortable" style="text-align:center"\n'
				:_(table.concat(rows, '\n|-\n| '))
				:_'\n|}'
		end
		for i = 1, #froms do
			if args[froms[i][1]] then
				flags.isItem = flags.isItem or not froms[i][3]
				result
					:_"\n''"
					:_(froms[i][2])
					:_"''\n:"
				if args[froms[i][1]]:find'^{|' then
					result:_(args[froms[i][1]])
				elseif args[froms[i][1]]:find'^!' then
					simpleTable(args[froms[i][1]])
				else result
					:_"*"
					:_(split_link(args[froms[i][1]], nil, '\n:*', froms[i][1] == 'equip' and tooltip_link))
				end
			end
		end
		result
			:_(args.trust and ("\n''Trust Master Reward''\n:*[[%s]]"):format(args.trust))
			:_(args.STMR and ("\n''Super Trust Master Reward''\n:*[[%s]]"):format(args.STMR))
			:_(args.obtain and multi_split(args.obtain, "\n''%s''\n:*", '\n:*', '\n*'))
			:_(args.used_by and "\n==Equippable By==\n:*" .. split_link(args.used_by, nil, '\n:*'))
		if args.learn then
			local awk = {}
			for name in args.learn:gmatch'\n|? *%[%[([^%]|]+)' do
				if args[name .. '+1'] then table.insert(awk, {name}) end
			end
			if args.enable then for skill in args.enable:gsub('\\,', '@$'):gmatch'%f[%w][^,]+' do
				if args[skill .. '+1'] then table.insert(awk, {skill:gsub('@$', ','), isSkill = true}) end
			end end
			if awk[1] then
				table.sort(awk, function(a, b) return a[1] < b[1] end)
				local fake_parent = {
					getTitle = function() return currentTitle end,
					args = {'table', mode = 'awaken'}
				}
				function frame.getParent() return fake_parent end
				local r, wide_tab = result:_'\n==Ability Awakening==',
					'width:200%%;margin-right:-99vh;%1"%2 mw-collapsible mw-collapsed" data-expandtext="Show table (hidden on testcase pages only due to width)"\n|+'
				for k, name in ipairs(awk) do
					result, fake_parent.args.page, fake_parent.args.skill = 
						setmetatable({}, {__index = r}),
						select(name.isSkill and 1 or 2, invokePage, name[1])
					awk, fake_parent.args[1] = k== 1 and 
						p.item(frame)
							:gsub('!Name', '!style="width:5em"|Unit/Skill!%1', 1)
							:gsub(currentTitle:find'testcases/' and 'width:100%%([^"]*" class=)(wikitable)' or '^$',
								wide_tab,
								1
							)
						or p.item(frame)
							:gsub('(colspan=)(%d+)', function(a,b)return a..b+1 end, 1)--future maintenance proof
					r:_'\n':_(awk:gsub(
						'(%|%[%[.-%]%] %+)',
						'|rowspan=' .. select(2, awk:gsub('[^|]%[%[([^%]|]+)%]%] ?%+1', '')) * 3 + 2 .. '|'
							.. (name.isSkill and
								'{{:' .. name[1] .. '|mode=fetch|ICON}}'
								or '{{sprite|' .. name[1] .. '}}' 
							) .. '<br>'.. link(name[1]) ..'|%1',
						1
					))
					for conditional in awk:gmatch'[^|]%[%[([^%]|]+)%]%] ?%+1' do
						local m = ''
						for n in awk:gmatch('%[%[' .. conditional .. '%]%] ?%+%s') do m = m < n and n or m end
						r:_'\n':_(frame
							:expandTemplate{title = ':' .. conditional, args = {
								mode = 'awaken',
								skill = args.name,
								max_plus = m
							}}
							:gsub('undefined', '%1 at ' .. link(conditional))
						)
					end
				end
				result = r:_'\n|}'
			end
		end
		local categories = {''}
		if args.type then
			if p.ability[args.type] then
				table.insert(categories, 'Module:Data Ability')
				if flags.isItem or args.trust or args.STMR or args.obtain then
					table.insert(categories, 'Items')
					table.insert(categories, 'Ability Materia')
				elseif args.esper or args.equip then table.insert(categories, 'Ability Materia') end
				if p.ability[args.type] == 1 then
					table.insert(categories, ('%s (%s)'):format(
						p.ability._class[p.ability[args.type]]:sub(1, -2) .. 'ies',
						args.type
					))
				else
					table.insert(categories, 'Magic')
					table.insert(categories, args.type .. ' Magic')
					table.insert(categories, args.type .. ' Magic Level ' .. args.mag_lv)
				end
			else 
				table.insert(categories, 'Items')
				if p.equipment[args.type] then
					table.insert(categories, 'Equipment')
					if args.type == 'Accessory' then
						table.insert(categories, 'Accessories')
					else
						table.insert(categories, p.equipment._class[p.equipment[args.type]] .. 's')
						table.insert(categories, p.equipment._plural[args.type] or args.type .. 's')
					end
				else
					if args.usage or args.awk_mat then table.insert(categories, 'Materials') end
				end
			end
		end
		for _, arg in ipairs{'recipe', 'reward', 'chest'} do
			if args[arg] and args[arg]:find(p.patterns.event) then table.insert(categories, 'Event Items') break end
		end
		for _, k in ipairs{
			--{arg key, category name}, if key is not nil, put in cat
			{'recipe', 'Crafting Recipes'},
			{'buy_gil', 'Purchasables'},
			{'trust', 'Trust Master Rewards'},
			{'STMR', 'Super Trust Master Rewards'},
			{hasExclusiveFX and 'effect' or 'used_by', 'Unit Exclusive Items'},
			{'awk_mat', 'Awakening Materials'},
			{'usage', 'Crafting Materials'},
			{'quest', 'Quest Items'},
			{'equip', 'Equipment-given Abilities'},
			{'esper', 'Esper-given Abilities'}
		} do
			if args[k[1]] then table.insert(categories, k[2]) end
		end
		result
			:_((namespace ~= 0 and --escape catagories if not on main namespace
				table.concat(categories, ']]\n[[:Category:'):gsub('%[C', '[:C')
				or table.concat(categories, ']]\n[[Category:')
			):sub(3, -1))
			:_']]'
	end
	return frame:preprocess(table.concat(result))
end

function p.wrap(frame)
	if frame.args.mode == 'shop' then
		result
			:_'{|class=wikitable'
		for k, v in ipairs(frame.args) do
			local name = k==1 and frame.args.name or frame.args['name'..k] or ''
			result
				:_'\n|-\n!colspan=4| '
				:_(name)
				:_'\n|-\n!Name!!'
				:_((name == 'Item Shop' or name == 'Ability Shop') and
					'colspan=2| '
					or 'Type!!'
				)
				:_'Description!!Price'
				:_(v)
		end
		result:_'\n|}'
	end
	return frame:preprocess(table.concat(result))
end

function p.find(frame)
	local data, bad, title, result, this = {}, {}, mw.title.getCurrentTitle().fullText
	local p_args = frame:getParent().args --warning suppress--
	this = mw.text.decode(frame:preprocess('{{msgnw::' .. (frame.args[1] or mw.title.getCurrentTitle().fullText) .. '}}'))
	if title:find'User:' or not title:find':' and not title:find'/' then
		for m, p, l in this:gmatch'|%s*%[(%b[])%] *(.)(%d?)' do 
			m = m:sub(2, -2):match'^[^|]+'
			if not (m:find':[^ _]' or m:find'#') and (p ~= '+' or l ~= '2') then
				local page = mw.text.decode(frame:preprocess('{{msgnw::' .. m .. '}}')):gsub('<!%-%b--%->', '')
				if page:lower():find'<onlyinclude>%s*{{#invoke:data|item' and (not title:find'Abilit' or page:find'Ability_%d+%.png') then
					if this:sub(1, 99):find'Unit Infobox' then
						table.insert(page:find(title) and data or bad, p == '+' and tonumber(l) and m .. '|mode=awaken' or m)
					else 
						if title == 'Ability Awakening' then
							for awk in page:gmatch'|%s*([^\n]-)%+1%s*=' do
								if not this:find(m .. '|'.. awk, 1, 1) then
									local rowspan = this:match(
										'rowspan%s*=%s*["\']?(%d+)[^\n]+'
										.. awk .. '[^\n]+\n|%s*%[%[' .. m
									)
									table.insert(data, m .. '|' .. awk
										.. (rowspan and '|' .. rowspan or ''))
								end
							end
						else
							local rowspan
							if title:find'Abilit' and page:find'mag_lv%s*=%s*%d' then
								rowspan = this:match('rowspan=["\']?(%d+)[^\n]+\n|[^\n]+|' .. m)
							end
							table.insert(data, rowspan and
								m .. '|rowspan=' .. rowspan
								or m
							)
						end
					end
				end
			end
		end
	end
	if(p_args["max-rarity"]) then
		local notNVRarity = not p_args["max-rarity"]:find "NV"
	end
	if not p_args.suppressmdwarnings then --warning suppress--
	if data[1] then
		result = '{{Unfinished Module Data|text=Please transclude these skills to this page: '
			.. '\n<pre style="margin:0 !important;padding:0 !important;box-shadow:none;background:transparent !important">{{:' 
			.. table.concat(data, '}}\n{{:')
			.. '}}</pre>}}'
	end
	if bad[1] then
		result = (result or '')
			.. '{{Unfinished Module Data|text=Please add this unit to these pages: '
			.. '[[' 
			.. table.concat(bad, ']], [[') 
			.. ']]}}'
	end
	end  --warning suppress--
	local count = #data
	if bad[1] then count = '*'
	elseif #data > 9 then count = mw.ustring.char(('A'):byte() + #data - 10) end
	return result and frame:preprocess(result) .. (not this:find'{{Unreleased}}' and '[[Category:Pages needing a Module:Data transclusion|' .. count.. ']]' or '')
	--following script can be used on pages like Special Abilities Passive in edit mode
	--javascript:for(i=0,m=document.querySelector('div>pre').innerHTML.match(/[^{}:][^{}\n]+?(?=\}\})/g);m[i];i++)wpTextbox1.value=wpTextbox1.value.replace(new RegExp('\\n\\|\\-.*?\\n?.*?\n?.*?\\[\\[('+m[i].replace(/([^\w\s])/g, "\\$1")+')(\]\]|\\|)[\\s\\S]*?(?=\\n(\\|(\\-|\\})|\\{\\{:))'), "\n{{:$1}}");
end

return p