This guide is designed to serve as a comprehensive resource to allow
mod authors to add JC Outfits support to their mod. It details all of
the steps required in order to integrate the outfits system into your
mod as seamlessly as possible. The Outfits mod has been designed to be
as modular as possible, with almost all functionality being held within
JCOutfits.u
, with only minimal changes being required to
core game classes. This mod is designed to be integrated in a way that
makes it optional - for users with JC Outfits installed, they will see
the Outfits screen. For everyone else, this functionality will be hidden
and the outfits system will be disabled.
JCOutfits.u
is designed to be completely self-contained,
and exposes an API to DeusEx.u
. This means that it’s
possible for new versions of JCOutfits.u
to work with
existing mods, even if those mods were only updated to work with a
previous version. Because of this, it is highly recommended that
you do not include JCOutfits.u
in your own mod. Instead,
you should let players know that it is compatible, but do not include
it. This will mean that players who do not want the
functionality can easily avoid it, and will essentially future-proof
your mod in the long term against changes made to future Outfits
versions.
Copy the provided OutfitSpawner.uc
,
OutfitSpawner2.uc
and OutfitManagerBase.uc
files into your DeusEx classes folder.
The first edit should be made to DeusExPlayer.uc
First, locate the end of list of variables. It will usually be immediately followed by a list of native functions.
Here’s a snippet of what the end of the variable list looks like:
// For closing comptuers if the server quits
var Computers ActiveComputer;
// native Functions
native(1099) final function string GetDeusExVersion();
native(2100) final function ConBindEvents();
The following code needs to be inserted between the end of the variables and the start of the native functions
// OUTFIT STUFF
var travel OutfitManagerBase outfitManager;
var globalconfig string unlockedOutfits[255];
Unless other edits have been made by your mod, in most cases, the code should end up looking like this:
// For closing comptuers if the server quits
var Computers ActiveComputer;
// OUTFIT STUFF
var travel OutfitManagerBase outfitManager;
var globalconfig string unlockedOutfits[255];
// native Functions
native(1099) final function string GetDeusExVersion();
native(2100) final function ConBindEvents();
Locate the start of the functions, which usually looks like this:
var localized String ImagesButtonLabel;
var localized String LogsButtonLabel;
// ----------------------------------------------------------------------
// CreateButtons()
// ----------------------------------------------------------------------
And insert the following code after the final variables, but before the start of the functions:
//Sarge: Outfits Stuff
var PersonaNavButtonWindow btnOutfits;
var localized String ConsButtonLabelShort; //Sarge: Added
var localized String OutfitsButtonLabel;
Unless other edits have been made by your mod, in most cases, the code should end up looking like this:
var localized String ImagesButtonLabel;
var localized String LogsButtonLabel;
//Sarge: Outfits Stuff
var PersonaNavButtonWindow btnOutfits;
var localized String ConsButtonLabelShort; //Sarge: Added
var localized String OutfitsButtonLabel;
// ----------------------------------------------------------------------
// CreateButtons()
// ----------------------------------------------------------------------
Next, locate the line Super.CreateButtons()
, and add the
following line above it:
CreateOutfitsButton(); //Sarge: Added
Unless other edits have been made by your mod, in most cases, the code should end up looking like this:
btnAugs = CreateNavButton(winNavButtons, AugsButtonLabel);
btnHealth = CreateNavButton(winNavButtons, HealthButtonLabel);
btnInventory = CreateNavButton(winNavButtons, InventoryButtonLabel);
CreateOutfitsButton(); //Sarge: Added
Super.CreateButtons();
}
Add the following code anywhere in the file (it is recommended to place it right below the CreateButtons function):
// ----------------------------------------------------------------------
// CreateOutfitsButton()
// Will shorten the Conversations button to fit it in
// ----------------------------------------------------------------------
function CreateOutfitsButton()
{
local class<PersonaScreenBaseWindow> test;
test = class<PersonaScreenBaseWindow>(DynamicLoadObject("JCOutfits.PersonaScreenOutfits", class'Class'));
//Only create the Outfits button if the outfits window is actually available
if (test != None)
{
btnOutfits = CreateNavButton(winNavButtons, OutfitsButtonLabel);
btnCons.SetButtonText(ConsButtonLabelShort);
}
}
Next, locate the following lines in the ButtonActivated
function:
case btnImages:
winClass = Class'PersonaScreenImages';
break;
case btnLogs:
winClass = Class'PersonaScreenLogs';
break;
default:
bHandled = False;
break;
Add the following code between the btnLogs
case and the
default
case:
//Sarge: Add new button for Outfits
case btnOutfits:
winClass = class<PersonaScreenBaseWindow>(DynamicLoadObject("JCOutfits.PersonaScreenOutfits", class'Class'));
break;
Unless other edits have been made by your mod, in most cases, the code should end up looking like this:
case btnImages:
winClass = Class'PersonaScreenImages';
break;
case btnLogs:
winClass = Class'PersonaScreenLogs';
break;
//Sarge: Add new button for Outfits
case btnOutfits:
winClass = class<PersonaScreenBaseWindow>(DynamicLoadObject("JCOutfits.PersonaScreenOutfits", class'Class'));
break;
default:
bHandled = False;
break;
Finally, add the following two properties to the
defaultproperties
section:
OutfitsButtonLabel="|&Outfits"
ConsButtonLabelShort="|&Conv."
Unless other edits have been made by your mod, in most cases, the code should end up looking like this:
ConsButtonLabel="|&Conversations"
ImagesButtonLabel="I|&mages"
LogsButtonLabel="|&Logs"
OutfitsButtonLabel="|&Outfits"
ConsButtonLabelShort="|&Conv."
}
First, find the TravelPostAccept
function, which
typically looks like this:
event TravelPostAccept()
{
local DeusExLevelInfo info;
Super.TravelPostAccept();
switch(PlayerSkin)
{
case 0: MultiSkins[0] = Texture'JCDentonTex0'; break;
case 1: MultiSkins[0] = Texture'JCDentonTex4'; break;
case 2: MultiSkins[0] = Texture'JCDentonTex5'; break;
case 3: MultiSkins[0] = Texture'JCDentonTex6'; break;
case 4: MultiSkins[0] = Texture'JCDentonTex7'; break;
}
}
Insert the following lines at the end of the function:
//SARGE: Setup outfit manager
SetTimer(0.5,false);
Unless other edits have been made by your mod, in most cases, the code should end up looking like this:
event TravelPostAccept()
{
local DeusExLevelInfo info;
Super.TravelPostAccept();
switch(PlayerSkin)
{
case 0: MultiSkins[0] = Texture'JCDentonTex0'; break;
case 1: MultiSkins[0] = Texture'JCDentonTex4'; break;
case 2: MultiSkins[0] = Texture'JCDentonTex5'; break;
case 3: MultiSkins[0] = Texture'JCDentonTex6'; break;
case 4: MultiSkins[0] = Texture'JCDentonTex7'; break;
}
//SARGE: Setup outfit manager
SetTimer(0.5,false);
}
Finally, copy the following code below the
TravelPostAccept
function:
// ----------------------------------------------------------------------
// Timer()
// SARGE: We need to delay slightly before setting models, to allow mods like LDDP to work properly
// ----------------------------------------------------------------------
function Timer()
{
Super.Timer();
SetupOutfitManager();
}
// ----------------------------------------------------------------------
// ResetPlayerToDefaults()
// SARGE: When we start a new game, throw away our outfit manager
// ----------------------------------------------------------------------
function ResetPlayerToDefaults()
{
outfitManager = None;
Super.ResetPlayerToDefaults();
}
// ----------------------------------------------------------------------
// SetupOutfitManager()
// SARGE: Setup the outfit manager and restore current outfit
// ----------------------------------------------------------------------
function SetupOutfitManager()
{
local class<OutfitManagerBase> managerBaseClass;
// create the Outfit Manager if not found
if (outfitManager == None)
{
//ClientMessage("Outfit Manager successfully created");
//outfitManager = new(Self) class'OutfitManager';
managerBaseClass = class<OutfitManagerBase>(DynamicLoadObject("JCOutfits.OutfitManager", class'Class'));
outfitManager = new(Self) managerBaseClass;
}
if (outfitManager != None)
{
//ClientMessage("Outfit Manager successfully inited");
//Call base setup code, required each map load
outfitManager.Setup(Self);
//Add additional outfits below this line
//---------------------------------------
//See docs/mod_integration.pdf for more info
//---------------------------------------
//Re-assign current outfit
outfitManager.ApplyCurrentOutfit();
}
}
New outfits can be added quite easily, using the following code:
outfitManager.AddOutfit("chef","Chefs Outfit","This outfit is usually worn by chefs","previewTex",true,false,"GM_Suit","PantsTex10","skin","ChefTex1","ChefTex1","GrayMaskTex","BlackMaskTex","ChefTex3",6);
The function arguments are as follows: 1. The ID of the outfit. This is used by outfit pickups to associate a specific outfit with a pickup. This should be a simple name like “myMod_outfit1”. Multiple outfits can have the same id if they are assigned to different genders. 2. The name of the outfit. This will appear in the Outfits list. 3. The long description of the outfit. This will eventually appear in the Outfits list but is currently unused. 4. The preview image of the outfit. This will appear in the main display when selecting the outfit in the menu. 5. Whether or not this outfit can be worn by males. 6. Whether or not this outfit can be worn by females (if LDDP is installed). 7. The mesh used by the outfit. This is typically “GM_Suit”, “GM_Trench”, etc. 8. A list of 7 textures used by the outfit. Typically textures 1-5 are used normally by the model, and textures 6-7 are used for glasses/hats/etc. - The string “skin” can be used to use the characters current skin texture in any texture slot. - The string “default” can be used to use the texture from the characters default outfit (JC Denton’s trenchcoat). This is useful for making outfits that are minor edits to the original trenchcoat - The string “none” can be used to denote no texture (or the argument can be left blank) 9. Optionally a number can be specified to determine which textures should be set to “none” when the user has the “Use Accessories” checkbox disabled. If no value is set, this uses slots 6 and 7, which are mostly used in vanilla for glasses frames and lenses. The number determines which slot is considered the first slot for disabling, and 2 slots will always be disabled.
It is recommended to add any additional outfits at the end of the
SetupOutfitManager
function, before the
ApplyCurrentOutfit();
line. For example:
// ----------------------------------------------------------------------
// SetupOutfitManager()
// SARGE: Setup the outfit manager and restore current outfit
// ----------------------------------------------------------------------
function SetupOutfitManager()
{
local class<OutfitManagerBase> managerBaseClass;
// create the Outfit Manager if not found
if (outfitManager == None)
{
//ClientMessage("Outfit Manager successfully created");
//outfitManager = new(Self) class'OutfitManager';
managerBaseClass = class<OutfitManagerBase>(DynamicLoadObject("JCOutfits.OutfitManager", class'Class'));
outfitManager = new(Self) managerBaseClass;
}
if (outfitManager != None)
{
//ClientMessage("Outfit Manager successfully inited");
//Call base setup code, required each map load
outfitManager.Setup(Self);
//Add additional outfits below this line
//---------------------------------------
outfitManager.AddOutfit("chef","Chefs Outfit","Some Desc","hudImg1",true,false,"GM_Suit","PantsTex10","skin","ChefTex1","ChefTex1","GrayMaskTex","BlackMaskTex","ChefTex3",6);
outfitManager.AddOutfit("chef2","Chefs Outfit","Some Desc","hudImg2",true,false,"GM_Suit","PantsTex10","skin","ChefTex1","ChefTex1","GrayMaskTex","BlackMaskTex","ChefTex3",6);
outfitManager.AddOutfit("chef3","Chefs Outfit","Some Desc","hudImg3",true,false,"GM_Suit","PantsTex10","skin","ChefTex1","ChefTex1","GrayMaskTex","BlackMaskTex","ChefTex3",6);
//---------------------------------------
//Re-assign current outfit
outfitManager.ApplyCurrentOutfit();
}
}
It is possible to create outfits which reflect the players chosen skin colour.
The mod automatically looks for textures named
<texture>_S[0-4]
, where the numbers 0-4 represent the
available skin colours (white, black, hispanic, ginger, albino), when
given a base texture name.
So for instance, you might add a new outfit with the texture
MyShirtTex01
. Your mod can additionally contain a texture
MyShirtTex01_S1
for a version containing dark skin,
MyShirtTex_S2
for hispanic, etc.
You can then simply add the default texture in the AddOutfit call, like so:
outfitManager.AddOutfit("myOutfit","My Cool Outfit","previewTex",true,false,"GM_Suit","PantsTex10","skin","MyShirtTex01","MyShirtTex02","GrayMaskTex","BlackMaskTex","MyShirtTex03",6);
Note: It is recommended to include a default version of
MyShirtTex01
, and not ship a special white skin version
MyShirtTex01_S0
to provide a fallback in case someone is
using a mod that provides additional skin colours. This way, any request
for an invalid variant texture will default to the basic white version.
This can be done for other skin colours instead, if desired. As long as
one skin colour is the “default” texture, it should always work in some
capacity.
Don’t forget to include these textures in your mod, via the usual
#exec
statements, for example:
//Goth GF Outfit
#exec TEXTURE IMPORT FILE="Textures\Female\Goth GF Outfit\Tex1.bmp" NAME="Outfit3F_Tex1" GROUP="Outfits"
#exec TEXTURE IMPORT FILE="Textures\Female\Goth GF Outfit\Tex1_S1.bmp" NAME="Outfit3F_Tex1_S1" GROUP="Outfits"
#exec TEXTURE IMPORT FILE="Textures\Female\Goth GF Outfit\Tex1_S2.bmp" NAME="Outfit3F_Tex1_S2" GROUP="Outfits"
#exec TEXTURE IMPORT FILE="Textures\Female\Goth GF Outfit\Tex1_S3.bmp" NAME="Outfit3F_Tex1_S3" GROUP="Outfits"
#exec TEXTURE IMPORT FILE="Textures\Female\Goth GF Outfit\Tex1_S4.bmp" NAME="Outfit3F_Tex1_S4" GROUP="Outfits"
#exec TEXTURE IMPORT FILE="Textures\Female\Goth GF Outfit\Tex2.pcx" NAME="Outfit3F_Tex2" GROUP="Outfits"
#exec TEXTURE IMPORT FILE="Textures\Female\Goth GF Outfit\Tex3.bmp" NAME="Outfit3F_Tex3" GROUP="Outfits"