A custom outfit is a body model (.parts) and package (.fpk), with
optional camo, voice, face, head, and variant assets.
Place all calls inside this.LoadLibraries().
| Function | Description |
|---|---|
V_Player.RegisterOutfit |
Create a new uniform. |
V_Player.RegisterHeadOption |
Create a new custom head. |
V_Player.ExtendVanillaOutfit |
Add variants or heads to an existing vanilla outfit. |
V_TppMotherBaseManagement.AddToEquipDevelopTable |
R&D name, icon, grade, cost, and unlock state. |
V_Player.GetOutfitInfo |
Read back the ids assigned to an outfit you registered. |
V_Player.GetHeadOptionSlot |
Read back the vars.playerFaceEquipId value a custom head wears under. |
IDs are assigned automatically and saved under each registration key.
Most *Fpk and *Fv2 fields take a path, true for vanilla, or
false to disable the asset.
RegisterOutfitneeds anAddToEquipDevelopTablerow with the same key.
V_Player.RegisterOutfit({
key = "MyMod:MySuit",
ddFemale = {
partsPath = "/Assets/.../body.parts",
fpkPath = "/Assets/.../body.fpk",
},
})
Returns partsType, developId, flowIndex, or false.
| Field | Required | Purpose |
|---|---|---|
key |
Yes | Registration key. |
snake, avatar, ddMale, ddFemale, ocelot, quiet |
At least one | Per-character branch. |
| Field | Required | Purpose |
|---|---|---|
partsPath |
Yes | Body model. |
fpkPath |
Yes | Its package. Not installed: the vanilla suit is worn. |
camoFpk, camoFv2 |
No (none) | Camo. camoFpk not installed: no camo. |
diamondFpk, diamondFv2 |
No (none) | Diamond Dogs emblem or overlay. diamondFpk not installed: neither is used. |
voiceFpk, voiceType |
No (vanilla) | Outfit voice. |
faceFpk, skinFv2 |
No (vanilla) | Face and skin. |
iconFtexPath |
No (R&D icon) | Suit-list icon. |
displayName |
No (R&D name) | Outfit-cell label. |
enableArm |
No (true) |
Keep Snake or Avatar’s bionic arm. Always off on ddMale and ddFemale. |
enableHead |
No (true) |
Keep the character head. |
eyeFv2, eyeColor |
No (none) | Iris colour on the outfit’s body. |
headOptions |
No (none) | Selectable heads. Max 120. |
colors |
No (none) | Colours for the Sortie Prep colour palette. |
variants |
No (none) | Alternative looks you cycle through. Max 254. |
camoBonusType |
No (none) | Use a vanilla camo’s concealment. |
camoBonusValues |
No (none) | Own concealment per material. |
abilities |
No (none) | Abilities while worn. |
motionMtars |
No (vanilla) | Replacement player motion archives. |
Each headOptions entry is a raw equip ID, a custom head key, or one of
these vanilla heads:
none, bandana, infinitebandana, balaclava, spheadgear, hpheadgear
headOptions = { "balaclava", "MyMod:MyHead" },
eyeFv2 is an fv2 with an iris group (id 110, one unit per iris), packed with the outfit. DD staff then keep their
own iris colour on the outfit; eyeColor = n (0-31) shows unit n instead, for every character, and false
turns the iris off.
ddMale = {
-- partsPath, fpkPath ...
eyeFv2 = "/Assets/tpp/fova/chara/sna/sna4_plym0_def_v00.fv2",
},
eyeFv2 may hold only the iris group, plus the skin group (id 100) on DD soldiers, who get their own skin tone.
The body needs the eye material of the DD player bodies. Vanilla’s sna4_plym0_def_v00.fv2 works as eyeFv2.
In Sortie Prep, press Triangle (Y) on the uniform to open the colour
palette. The picked colour’s fv2 is applied over the outfit and saved per
outfit, character and channel. The second channel goes on top of the first,
so give the channels different materials. A variant’s colors replace the branch’s.
colors = {
primary = {
{ fv2 = "/Assets/tpp/fova/mymod/olive.fv2", icon = "/Assets/tpp/ui/texture/mymod/olive.ftex" },
},
secondary = { count = 12, fv2 = "/Assets/tpp/fova/mymod/trim_%02d.fv2" },
},
| Field | Required | Purpose |
|---|---|---|
primary, secondary |
At least one | Colour channels, one palette tab each. Max 1024 colours. |
fv2 |
Yes | Applied when picked. Must be in a loaded package: the outfit’s, camoFpk or the colour’s fpk. |
fpk |
No (none) | Package with the fv2 and its textures, loaded as the camo package. Not installed: the colour isn’t applied. |
icon |
No (empty swatch) | Swatch picture. |
count |
No (none) | Builds count colours from fields with one %d (or %02d), numbered from 0. |
Read or pick colours from Lua: outfit colours.
variants = {
{
partsPath = "/Assets/tpp/parts/chara/mymod/body_alt.parts",
fpkPath = "/Assets/tpp/pack/mymod/body_alt.fpk",
displayName = "staff_name_99_052",
default = true,
},
},
All variant fields are optional.
| Field | Default | Purpose |
|---|---|---|
partsPath, fpkPath |
base model | Variant model and package. |
camoFpk, camoFv2, diamondFpk, diamondFv2 |
none | Variant camo and emblem. An *Fpk not installed: its pair is not used. |
voiceFpk, voiceType |
branch’s | Variant voice. |
displayName |
none | Variant label on the cycle button. |
iconFtexPath |
branch’s | Suit-list icon. |
default |
false |
true makes this the initial variant. |
enableArm, enableHead |
branch’s | Override the branch values. |
eyeFv2, eyeColor |
branch’s | This variant’s iris. |
headOptions |
none | This variant’s heads. |
colors |
branch’s | This variant’s colours. |
motionMtars |
branch’s | Motion while this variant is worn. |
camoBonusType takes a vanilla camo name (playerCamoTypes in
player2_camouf_param.lua)
or a number 0-116:
camoBonusType = "TIGERSTRIPE",
camoBonusValues takes one value per material. Keys are MTR_* names
(materialTypes in
player2_camouf_param.lua)
or 1-82. Materials left out are 0:
camoBonusValues = {
MTR_LEAF = 90,
MTR_SOIL_A = 60,
MTR_CONC_A = 15,
},
Use one or the other. With both,
camoBonusTypewins.
abilities = {
quietMovement = true,
defense = 4,
rattleSuit = "snk",
},
All ability fields are optional.
| Field | Type (default) | Effect |
|---|---|---|
quietMovement |
boolean (false) |
Move like Quiet. |
silentFootsteps |
boolean (false) |
Footsteps one level quieter. |
sprintSpeed |
number (suit’s own) | Sprint speed, 0.1-10. Ninja suit 1.3, Raiden suit 1.5. |
raidenRun |
boolean (false) |
Raiden’s sprint animation. |
dashAttack |
boolean or TppDamage.ATK_* (false) |
Sprinting into an enemy knocks them down, as with the Ninja and Raiden suits. An ATK_ id hits with that attack instead. |
sprintSound |
boolean (false) |
The Ninja and Raiden sprint sound. |
sprintSpark |
string (none) | .vfx at each sprinting footstep, packed with the outfit. Raiden’s: /Assets/tpp/effect/vfx_data/chara/fx_tpp_chrfotspk01_s5.vfx. |
defense |
number 0-9 (0, off) |
Damage reduction. |
lifeRecovery |
number 0-9 (0, off) |
Health regeneration rate. |
rattleSuit |
string or number ("nom") |
Cloth-rustle sound: "nom", "bony", "snk", "amr". |
damageSe |
string (vanilla) | Sound when hit: "battledress" (Battle Dress) or "default". |
Name a player motion archive in motionMtars to replace it while the
outfit is worn. Archives you leave out stay vanilla.
motionMtars = {
cqc = "/Assets/tpp/motion/mtar/mymod/mysuit_cqc.mtar",
jump = "/Assets/tpp/motion/mtar/mymod/mysuit_jump.mtar",
},
Keys are the archive filenames in /Assets/tpp/motion/mtar/player2/,
without the player2_ prefix and .mtar:
avatar_edit, behind, camera, carry, cbox, cqc, cure, cypr,
ddf_facial, ddm_facial, elude, facial_ddf_helispace,
facial_ddm_helispace, facial_snake_helispace, gimmick, heli, horse,
jump, ladder, liquid, ocelot_facial, okb_zero, online, paz, pipe,
quiet_facial, resident, timecigarette, trashbox, vehicle,
vram_resident, TppPlayer2Facial
The replacement must hold every clip of the vanilla archive, or those
animations break. Build it from the vanilla .mtar.
voiceFpk is one package path, or a table with one package per voice
type. voiceType forces the voice the player speaks with.
ddMale = {
partsPath = "/Assets/tpp/parts/chara/mymod/body.parts",
fpkPath = "/Assets/tpp/pack/mymod/body.fpk",
voiceFpk = {
ddmsoldiera = "/Assets/tpp/pack/mymod/voice_a.fpk",
ddmsoldierb = "/Assets/tpp/pack/mymod/voice_b.fpk",
},
voiceType = "ddmsoldiera",
},
| Player type | Voice | Number |
|---|---|---|
snake/avatar |
snak |
0x3CF677C6 |
ddMale |
ddmsoldiera |
0x2EED93D9 |
ddMale |
ddmsoldierb |
0x2EED93DA |
ddMale |
ddmsoldierc |
0x2EED93DB |
ddMale |
ddmsoldierd |
0x2EED93DC |
ddFemale |
ddfsoldiera |
0x80400AFA |
ddFemale |
ddfsoldierb |
0x80400AF9 |
ddFemale |
ddfsoldierc |
0x80400AF8 |
ddFemale |
ddfsoldierd |
0x80400AFF |
ocelot |
ocelot |
0x1BF9CBC1 |
quiet |
quiet |
0x5D5262DF |
V_TppMotherBaseManagement.AddToEquipDevelopTable("MyMod:MySuit", {
const = {
equipID = TppEquip.EQP_SUIT,
equipDevelopTypeID = TppMbDev.EQP_DEV_TYPE_Suit,
langEquipName = "staff_name_99_051",
iconFtexPath = "/Assets/.../ui_suit_icon",
equipDevelopGroupID = V_TppMbDev.EQP_OUTFIT_VARIANT_NAME,
},
flow = {
grade = 5,
developGmpCost = 50000,
initialAvailable = 0,
},
})
Other fields: AddToEquipDevelopTable.
V_Player.RegisterHeadOption({
key = "MyMod:MyHead",
snake = {
fv2 = "/Assets/.../myhead.fv2",
fpk = "/Assets/.../myhead.fpk",
},
})
| Field | Required | Purpose |
|---|---|---|
key |
Yes | Registration key, shared with its R&D row. Max 63 characters; no line break, double quote or backslash. |
snake, avatar, ddMale, ddFemale |
At least one | Per-character branches. |
showInDevelopMenu |
No (false) |
true lists the head in R&D. |
abilities |
No (none) | Abilities while the head is worn. |
| Field | Branch | Required | Purpose |
|---|---|---|---|
fv2, fpk |
snake, avatar |
Yes | Head model. |
TppEnemyFaceId |
ddMale, ddFemale |
No (balaclava) | Soldier face worn as the head. |
fv2, fpk |
ddMale, ddFemale |
No (none) | Own head model. Wins over TppEnemyFaceId. |
colors |
any | No (none) | Head colours (Triangle (Y) in the HEAD list). Their fv2s and textures go in the head’s own fpk; needs the branch’s fv2 and fpk. |
ddMale = {
TppEnemyFaceId = TppEnemyFaceId.svs_balaclava,
},
ddFemale = {
fv2 = "/Assets/tpp/fova/chara/mymod/head_ddf.fv2",
fpk = "/Assets/tpp/pack/mymod/head_ddf.fpk",
},
A branch can animate the head and attach effects; play them with
PlayHeadMotion, PlayHeadEffect and PlayHeadSound.
snake = {
-- fv2, fpk ...
motion = {
mtar = "/Assets/tpp/motion/mymod/head_motion.mtar",
clips = { blink = "/Assets/tpp/motion/mymod/blink.gani" },
effects = {
sparks = { vfx = "/Assets/tpp/effect/mymod/sparks.vfx", point = "CNP_HEAD", clip = "blink" },
},
rest = "blink",
},
},
| Field | Required | Purpose |
|---|---|---|
mtar |
Yes, for clips | Head animation archive, packed in the head’s fpk. |
clips |
Yes, for clips | Clip name = clip id (path, MtarTool id or 0x id). |
effects |
No (none) | Effects by name. |
rest |
No (none) | Clip whose effects run while no other clip plays. |
Each effect:
| Field | Required | Purpose |
|---|---|---|
vfx |
Yes | Effect file. |
point |
No (none) | Connect point to attach to. |
clip |
No (none) | Starts with this clip. |
abilities goes at the top level, next to key. Inside a branch it is
ignored.
V_Player.RegisterHeadOption({
key = "MyMod:MyHead",
snake = { fv2 = "/Assets/.../myhead.fv2", fpk = "/Assets/.../myhead.fpk" },
abilities = { infiniteAmmo = true },
})
All optional.
| Field | Type (default) | Effect |
|---|---|---|
infiniteAmmo |
boolean (false) |
Infinite ammo. |
Optional, ddMale/ddFemale only. true keeps the soldier’s own
layer, false hides it under the head. Omitted: vanilla behaviour.
| Layer | Contents | Toggle |
|---|---|---|
| face | Face model. | enableFaceFova |
| face deco | Beard, stubble or face paint on the face. | enableFaceDecoFova |
| hair | Hair model. | enableHairFova |
| hair deco | Hair colour or style. | enableHairDecoFova |
ddMale = {
TppEnemyFaceId = TppEnemyFaceId.dds_balaclava2,
enableFaceFova = false,
enableFaceDecoFova = false,
},
Optional. Force specific layer assets, such as a hair, for a head:
V_Player.RegisterHeadOption({
key = "MyMod:CapWithPixieHair",
ddFemale = {
fv2 = "/Assets/tpp/fova/chara/mymod/cap_ddf.fv2",
fpk = "/Assets/tpp/pack/mymod/cap_ddf.fpk",
faceFovaPath = "",
faceFovaFpkPath = "",
faceDecoFovaPath = "",
faceDecoFovaFpkPath = "",
hairFovaPath = "/Assets/tpp/fova/common_source/chara/cm_head/hair/cm_hair_c101.fv2",
hairFovaFpkPath = "/Assets/tpp/pack/fova/common_source/chara/cm_head/hair/cm_hair_c101.fpk",
hairDecoFovaPath = "/Assets/tpp/fova/common_source/chara/cm_head/hair_deco/cm_hair_c101_c000.fv2",
hairDecoFovaFpkPath = "/Assets/tpp/pack/fova/common_source/chara/cm_head/hair_deco/cm_hair_c101_c000.fpk",
},
})
Optional. faceStages gives a Snake head its own face per Demon Point stage.
Missing stages use the branch’s fv2 and fpk.
snake = {
fv2 = "/Assets/.../myhead.fv2",
fpk = "/Assets/.../myhead.fpk",
faceStages = {
[1] = { fv2 = "/Assets/.../myhead_normal.fv2", fpk = "/Assets/.../myhead_normal.fpk" }, -- Normal
[2] = { fv2 = "/Assets/.../myhead_horn.fv2", fpk = "/Assets/.../myhead_horn.fpk" }, -- Grown horn
[3] = { fv2 = "/Assets/.../myhead_demon.fv2", fpk = "/Assets/.../myhead_demon.fpk" }, -- Demon Snake
},
}
Gives the head its name and icon.
V_TppMotherBaseManagement.AddToEquipDevelopTable("MyMod:MyHead", {
const = {
equipID = TppEquip.EQP_None,
equipDevelopTypeID = TppMbDev.EQP_DEV_TYPE_Suit,
langEquipName = "staff_name_99_050",
iconFtexPath = "/Assets/.../ui_head_icon",
},
flow = {
grade = 1,
developGmpCost = 1000,
initialAvailable = 0,
},
})
Adds to a vanilla suit; no new suit cell or R&D row.
V_Player.ExtendVanillaOutfit({
outfit = "TIGERSTRIPE",
snake = {
headOptions = { "bandana", "MyMod:MyHead" },
variants = {
{
partsPath = "/Assets/.../variant.parts",
fpkPath = "/Assets/.../variant.fpk",
},
},
},
})
Use one of these:
| Field | Required | Purpose |
|---|---|---|
outfit |
One of the two | Vanilla camo name, such as "TIGERSTRIPE", or a number 0-116. |
partsType |
One of the two | Raw parts type. variants do not work with it. |
V_Player.ExtendVanillaOutfit({
partsType = 3,
snake = { headOptions = { "bandana", "MyMod:MyHead" } },
})
All optional; only fields you set change the suit. headOptions and
the voice fields apply only to the named camo.
| Field | Required | Purpose |
|---|---|---|
variants |
No (none) | Extra looks. A vanilla parts type holds 29 in total. |
headOptions |
No (none) | Heads added to the suit. Max 120. |
voiceFpk, voiceType |
No (vanilla voice) | Voice for the suit on this player type. |
enableArm |
No (true) |
false hides the bionic arm, also in FOB. Snake and Avatar only. |
enableHead |
No (true) |
false hides the head (face and hair on DD); the vanilla head shows online. A head built into the suit stays. |
abilities |
No (none) | Suit abilities for this branch. |
These mirror the variant fields, with these differences:
| Field | Required | Purpose |
|---|---|---|
partsPath, fpkPath |
Yes | If fpkPath is not installed, the vanilla suit is used. |
camoFpk, camoFv2 |
No (vanilla camo) | If camoFpk is not installed, the vanilla camo is used. |
diamondFpk, diamondFv2 |
No (vanilla overlay) | Wet, mud or emblem overlay; false removes it. If diamondFpk is not installed, the vanilla overlay is used. |
voiceFpk, voiceType |
No (branch voice) | Not applied in FOB. |
V_Player.ExtendVanillaOutfit({
outfit = "TIGERSTRIPE",
ddFemale = {
variants = {
{
partsPath = "/Assets/tpp/parts/chara/sna/sna4_plyf0_def_v00.parts",
fpkPath = "/Assets/tpp/pack/mymod/plparts_female_6.fpk",
diamondFpk = false,
displayName = "staff_name_99_117",
},
},
},
})
local this = {}
function this.LoadLibraries()
V_Player.RegisterHeadOption({
key = "MyMod:OgreHorn",
ddFemale = {
fv2 = "/Assets/tpp/fova/chara/mymod/ogrehorn.fv2",
fpk = "/Assets/tpp/pack/mymod/ogrehorn.fpk",
},
})
V_TppMotherBaseManagement.AddToEquipDevelopTable("MyMod:OgreHorn", {
const = {
equipID = TppEquip.EQP_None,
equipDevelopTypeID = TppMbDev.EQP_DEV_TYPE_Suit,
langEquipName = "staff_name_99_050",
iconFtexPath = "/Assets/.../ui_head_ogre",
},
flow = {
grade = 1,
developGmpCost = 1000,
initialAvailable = 0,
},
})
V_Player.RegisterOutfit({
key = "MyMod:OgreSuit",
ddFemale = {
partsPath = "/Assets/tpp/parts/chara/mymod/ogre.parts",
fpkPath = "/Assets/tpp/pack/mymod/ogre.fpk",
headOptions = { "MyMod:OgreHorn", "balaclava" },
},
})
V_TppMotherBaseManagement.AddToEquipDevelopTable("MyMod:OgreSuit", {
const = {
equipID = TppEquip.EQP_SUIT,
equipDevelopTypeID = TppMbDev.EQP_DEV_TYPE_Suit,
langEquipName = "staff_name_99_051",
iconFtexPath = "/Assets/.../ui_ogre_suit",
equipDevelopGroupID = V_TppMbDev.EQP_OUTFIT_VARIANT_NAME,
},
flow = {
grade = 5,
developGmpCost = 50000,
initialAvailable = 1,
},
})
end
return this