This tutorial is based on a personal adaptation of DJMaxus' [[CS:DE] Character Customization (Gender & Hair)](http://www.touchofdeathforums.com/community/index.php?/topic/123485-csde-character-customization-gender-hair/), moved to EO 3.0 What it does: It lets you have a separate graphic file for character hair, and to color it at render time. Screenshots of what you should end up with (just the important bits, it's in Spanish, sorry about that): >! ![](http://i.imgur.com/sW2DErM.png)![](http://i.imgur.com/TAShk8I.png) >! Both of those hairs are the same hair file. Neat, isn't it? This might sound hard, but don't worry, it's just me, being bad at explaining. **REMEMBER! Always make a backup of your working source!** **SERVER SIDE:** First go to **modTypes**, and in **PlayerRec** add``` Hair As Long HairTint As Long ```at the bottom. Add it to **TempPlayerRec** too. (I'm not sure it's needed, but I did it just in case.) At the bottom of **modPlayer**, add``` Function GetPlayerHair(ByVal Index As Long) As Long If Index MAX_PLAYERS Then Exit Function GetPlayerHair = Player(Index).Hair End Function Sub SetPlayerHair(ByVal Index As Long, ByVal Hair As Long) If Index MAX_PLAYERS Then Exit Sub Player(Index).Hair = Hair End Sub Function GetPlayerHairTint(ByVal Index As Long) As Long If Index MAX_PLAYERS Then Exit Function GetPlayerHairTint = Player(Index).HairTint End Function Sub SetPlayerHairTintTint(ByVal Index As Long, ByVal HairTint As Long) If Index MAX_PLAYERS Then Exit Sub Player(Index).HairTint = HairTint End Sub ``` in **modDatabase** find``` Sub AddChar(ByVal Index As Long, ByVal Name As String, ByVal Sex As Byte, ByVal ClassNum As Long, ByVal Sprite As Long) ```and replace it with``` Sub AddChar(ByVal Index As Long, ByVal Name As String, ByVal Sex As Byte, ByVal ClassNum As Long, ByVal Sprite As Long, ByVal Hair As Long, ByVal HairTint As Long) ```then, inside the sub, under``` Player(Index).Level = Level ```add``` Player(Index).Hair = Hair Player(Index).HairTint = HairTint ``` Now, in **modHandleData**, find``` HandleAddChar ```and under``` Dim n As Long ```add``` Dim Hair As Long Dim HairTint As Long ```, under``` Sprite = Buffer.ReadLong ```add``` Hair = Buffer.ReadLong HairTint = Buffer.ReadLong ```(if you place it somewhere else, remember where!), then find``` Call AddChar(Index, Name, Sex, Class, Sprite) ```and replace with``` Call AddChar(Index, Name, Sex, Class, Sprite, Hair, HairTint) ``` Next, in **modServerTCP**, find``` Function PlayerData ```and under``` Buffer.WriteLong GetPlayerLevel(Index) ```add``` Buffer.WriteLong GetPlayerHair(Index) Buffer.WriteLong GetPlayerHairTint(Index) ``` And that's the server work. Now comes the client work. **CLIENT SIDE:** Like with the server, first go to **modTypes**, and in **PlayerRec** add``` Hair As Long HairTint As Long ```at the bottom. Then in **modClientTCP** find``` Public Sub SendAddChar(ByVal Name As String, ByVal Sex As Long, ByVal ClassNum As Long, ByVal Sprite As Long) ```and replace with``` Public Sub SendAddChar(ByVal Name As String, ByVal Sex As Long, ByVal ClassNum As Long, ByVal Sprite As Long, ByVal Hair As Long, ByVal HairTint As Long) ``` and under``` Buffer.WriteLong Sprite ```add``` Buffer.WriteLong Hair Buffer.WriteLong HairTint ```(If in the server **modHandleData HandleAddChar** you placed the lines somewhere else, place them in the same point of order) In **modDatabase** add, at the bottom or somewhere:``` ' Hairs Public Sub CheckHairs() Dim i As Long ' If debug mode, handle error then exit out If Options.Debug = 1 Then On Error GoTo errorhandler i = 1 NumHairs = 1 ReDim Tex_Hair(1) While FileExist(GFX_PATH & "hair\" & i & GFX_EXT) ReDim Preserve Tex_Hair(NumHairs) NumTextures = NumTextures + 1 ReDim Preserve gTexture(NumTextures) Tex_Hair(NumHairs).filepath = App.Path & GFX_PATH & "hair\" & i & GFX_EXT Tex_Hair(NumHairs).Texture = NumTextures NumHairs = NumHairs + 1 i = i + 1 Wend NumHairs = NumHairs - 1 If NumHairs = 0 Then Exit Sub For i = 1 To NumHairs LoadTexture Tex_Hair(i) Next ' Error handler Exit Sub errorhandler: HandleError "CheckHairs", "modDatabase", Err.Number, Err.Description, Err.Source, Err.HelpContext Err.Clear Exit Sub End Sub Function GetPlayerHair(ByVal Index As Long) As Long ' If debug mode, handle error then exit out If Options.Debug = 1 Then On Error GoTo errorhandler If Index > MAX_PLAYERS Then Exit Function GetPlayerHair = Player(Index).Hair ' Error handler Exit Function errorhandler: HandleError "GetPlayerSprite", "modDatabase", Err.Number, Err.Description, Err.Source, Err.HelpContext Err.Clear Exit Function End Function Sub SetPlayerHair(ByVal Index As Long, ByVal Hair As Long) ' If debug mode, handle error then exit out If Options.Debug = 1 Then On Error GoTo errorhandler If Index > MAX_PLAYERS Then Exit Sub Player(Index).Hair = Hair ' Error handler Exit Sub errorhandler: HandleError "SetPlayerSprite", "modDatabase", Err.Number, Err.Description, Err.Source, Err.HelpContext Err.Clear Exit Sub End Sub Function GetPlayerHairTint(ByVal Index As Long) As Long ' If debug mode, handle error then exit out If Options.Debug = 1 Then On Error GoTo errorhandler If Index > MAX_PLAYERS Then Exit Function GetPlayerHairTint = Player(Index).HairTint ' Error handler Exit Function errorhandler: HandleError "GetPlayerSprite", "modDatabase", Err.Number, Err.Description, Err.Source, Err.HelpContext Err.Clear Exit Function End Function Sub SetPlayerHairTint(ByVal Index As Long, ByVal HairTint As Long) ' If debug mode, handle error then exit out If Options.Debug = 1 Then On Error GoTo errorhandler If Index > MAX_PLAYERS Then Exit Sub Player(Index).HairTint = HairTint ' Error handler Exit Sub errorhandler: HandleError "SetPlayerSprite", "modDatabase", Err.Number, Err.Description, Err.Source, Err.HelpContext Err.Clear Exit Sub End Sub ``` in **modGlobals**, under``` Public newCharClass As Long ```add``` Public newCharHair As Long Public newCharHairTint As Long ``` now, in **modGeneral** you have to find``` Call SendAddChar ```it will look somewhat like this:``` If frmMenu.optMale.Value Then Call SendAddChar(frmMenu.txtCName, SEX_MALE, frmMenu.cmbClass.ListIndex + 1, newCharSprite) Else Call SendAddChar(frmMenu.txtCName, SEX_FEMALE, frmMenu.cmbClass.ListIndex + 1, newCharSprite) End If ```replace it with this:``` If frmMenu.optMale.Value Then Call SendAddChar(frmMenu.txtCName, SEX_MALE, frmMenu.cmbClass.ListIndex + 1, newCharSprite, newCharHair, newCharHairTint) Else Call SendAddChar(frmMenu.txtCName, SEX_FEMALE, frmMenu.cmbClass.ListIndex + 1, newCharSprite, newCharHair, newCharHairTint) End If ``` go to **modHandleData** and find``` Call SetPlayerLevel(i, Buffer.ReadLong) ```and add under it``` Call SetPlayerHair(i, Buffer.ReadLong) Call SetPlayerHairTint(i, Buffer.ReadLong) ``` in **modGraphics**, somewhere along or under``` Public Tex_Fog() As DX8TextureRec ```add``` Public Tex_Hair() As DX8TextureRec ```, under``` Public NumFogs As Long ```add``` Public NumHairs As Long ```, under``` Call CheckFogs ```(in Sub LoadTextures) add``` Call CheckHairs ```find DrawPlayer and under``` Call DrawSprite(Sprite, x, y, rec) ```add``` Call DrawHair(x, y, GetPlayerHair(Index), Anim, spritetop, GetPlayerHairTint(Index)) ```and at the bottom or somewhere in the module add``` Public Sub DrawHair(ByVal x2 As Long, ByVal y2 As Long, ByVal Hair As Long, ByVal Anim As Long, ByVal spritetop As Long, ByVal tint As Long) Dim rec As RECT If Hair < 1 Or Hair > NumHairs Then Exit Sub With rec .Top = spritetop * (Tex_Hair(Hair).Height / 4) .Bottom = .Top + (Tex_Hair(Hair).Height / 4) .Left = Anim * (Tex_Hair(Hair).Width / 4) .Right = .Left + (Tex_Hair(Hair).Width / 4) End With ' Clip to screen If y2 < 0 Then With rec .Top = .Top - y2 End With y2 = 0 End If If x2 < 0 Then With rec .Left = .Left - x2 End With x2 = 0 End If 'RenderTexture Tex_Hair(Hair), ConvertMapX(x2), ConvertMapY(y2), rec.Left, rec.Top, rec.Right - rec.Left, rec.Bottom - rec.Top, rec.Width, rec.Height RenderTexture Tex_Hair(Hair), ConvertMapX(x2), ConvertMapY(y2), rec.Left, rec.Top, rec.Right - rec.Left, rec.Bottom - rec.Top, rec.Right - rec.Left, rec.Bottom - rec.Top, tint End Sub ``` still in **modGraphics**, find``` Public Sub NewCharacterDrawSprite() ```and under``` RenderTextureByRects Tex_Character(Sprite), sRect, dRect ```add``` RenderTexture Tex_Hair(newCharHair), 0, 0, 0, 0, Width, Height, Width, Height, newCharHairTint ``` Alright. Now open up **frmMenu** and make sure you've got **picCharacter** in front (make sure you can see the "new character" menu box), then add: > A label that will act as a button to change the hairstyle, named **lblHair** (preferably with a relevant caption) > A label to show what hair is selected out of them all, named **lblHairNum** (caption unnecesary) > Three scrollbars, named **scrlCRed** , **scrlCGreen** and **scrlCBlue** (preferably with labels alongside to show which is which) with a **Min** of 0 and a **Max** of 255 (You can change them if you prefer, but always within those bounds) and a **Value** of 128, or somewhere around the middle. Now, inside **frmMenu**'s code, add… (Choice time!) >If all your hairs fit both male and female characters:``` Private Sub lblHair_Click() ' If debug mode, handle error then exit out If Options.Debug = 1 Then On Error GoTo errorhandler If newCharHair >= NumHairs Then newCharHair = 0 Else newCharHair = newCharHair + 1 End If lblHairNum.Caption = newCharHair & " / " & NumHairs ' Error handler Exit Sub errorhandler: HandleError "lblHair_Click", "frmMenu", Err.Number, Err.Description, Err.Source, Err.HelpContext Err.Clear Exit Sub End Sub ```>On the other hand, if your males and females need different hairs…``` Private Sub lblHair_Click() ' If debug mode, handle error then exit out If Options.Debug = 1 Then On Error GoTo errorhandler Dim haircount As Long If optMale.Value Then haircount = Round((NumHairs + 1) / 2) Else haircount = Round((NumHairs) / 2) End If If optMale.Value And newCharHair >= NumHairs Then newCharHair = 0 ElseIf newCharHair >= NumHairs - 1 Then newCharHair = 0 Else If optMale.Value And newCharHair = 0 Then newCharHair = 1 ElseIf newCharHair = 0 Then newCharHair = 2 Else newCharHair = newCharHair + 2 End If End If If optMale.Value Then lblHairNum.Caption = Round((newCharHair + 1) / 2) & " / " & haircount Else lblHairNum.Caption = Round(newCharHair / 2) & " / " & haircount End If ' Error handler Exit Sub errorhandler: HandleError "lblHair_Click", "frmMenu", Err.Number, Err.Description, Err.Source, Err.HelpContext Err.Clear Exit Sub End Sub ```Note that with "Males get different hairs than Females", odd numbered hairs (1,3,5…) are used for males and even numbered hairs (2,4,6...) are used for females. Now, somewhere within the form's code add``` Private Sub scrlCRed_Change() newCharHairTint = D3DColorRGBA(frmMenu.scrlCRed.Value, frmMenu.scrlCGreen.Value, frmMenu.scrlCBlue.Value, 255) End Sub Private Sub scrlCGreen_Change() newCharHairTint = D3DColorRGBA(frmMenu.scrlCRed.Value, frmMenu.scrlCGreen.Value, frmMenu.scrlCBlue.Value, 255) End Sub Private Sub scrlCBlue_Change() newCharHairTint = D3DColorRGBA(frmMenu.scrlCRed.Value, frmMenu.scrlCGreen.Value, frmMenu.scrlCBlue.Value, 255) End Sub ``` Now, inside``` Private Sub Form_Load() ```, under``` If Options.Debug = 1 Then On Error GoTo errorhandler ```add``` If optMale.Value Then newCharHair = 1 Else newCharHair = 2 End If newCharHairTint = D3DColorRGBA(frmMenu.scrlCRed.Value, frmMenu.scrlCGreen.Value, frmMenu.scrlCBlue.Value, 255) ```to make sure the default hair isn't "no hair" (though "no hair" can still be chosen by going around all the hairs and all the way back to 0) If you went the "different hairs for males and females" way, find``` Private Sub optFemale_Click() ```and under``` newCharSprite = 0 ```add``` newCharHair = 2 Dim haircount As Long haircount = Round(NumHairs / 2) frmMenu.lblHairNum.Caption = Round(newCharHair / 2) & " / " & haircount ```, then in``` Private Sub optMale_Click() ```under``` newCharSprite = 0 ```add``` newCharHair = 1 Dim haircount As Long haircount = Round((NumHairs + 1) / 2) frmMenu.lblHairNum.Caption = Round(newCharHair / 2) & " / " & haircount ``` Whelp, that's all the code! Now, for the non-code stuff. Inside the client folder, in "**data files\graphics**", create a new folder called **hair** Add your numbered hair files, making sure to previously desaturate them so they look grayscale and can be properly colored at runtime. Examples: >! ![](http://i.imgur.com/tHcUG5x.png)![](http://i.imgur.com/7cTd4j7.png) >! These are a male and a female hair, respectively, the male hair being 1.png and the female hair being 2.png >! This is using "male and female hairs are different", so odd numbers are male hairs and even numbers are female hairs. >! Make sure the initial picture is as bright as it needs to be, because you can use the sliders to get darker colors, but not brighter. You will also have to replace the classes sprites with hairless/bald sprites so the hair isn't drawn over more hair. Existing characters will have no hair, and there is no way given in this tutorial on how to change a player's hair, but it's as easy as making the server do a SetPlayerHair or a SetPlayerHairTint, so probably with a custom event, or command… I'll leave that for you to find a way on how do you want to do it. Original tutorial on which this one is based on: [[CS:DE] Character Customization (Gender & Hair)](http://www.touchofdeathforums.com/community/index.php?/topic/123485-csde-character-customization-gender-hair/), by DJMaxus