Jump to content
Search In
  • More options...
Find results that contain...
Find results in...

[CS:DE] Character Customization (Gender & Hair)


DJMaxus
 Share

Recommended Posts

This is a tutorial for Crystalshire Developer's Edition. It will show you how to add basic character customization into your game upon selecting a class. This tutorial will go nicely with this one: [[CS:DE] Paperdoll & Gender Based Paperdoll](http://www.touchofdeathforums.com/smf/index.php/topic,76976.0.html) This may be a long tutorial for some.

_**How It Works:**_

This will allow you to choose the Gender and Hair of your character when you are creating them. After you have selected a class, you are able to cycle between hair and gender options for your character using buttons. Hair is a separate declaration and will appear independent from the sprite, it can be changed throughout the game. This is just a simple customization you could refer to so that you can add extra customization options if you wish. Please see attachments for the buttons you'll need to use this tutorial. To fully utilize this tutorial, you should have a set of base characters for use with your project, if anything, you can just extract the gender part out of this tutorial and forget about the hair part.

_**Screenshots:**_

>! ![](http://img543.imageshack.us/img543/8045/hairone.png)
>! ![](http://img851.imageshack.us/img851/5172/hare2.png)
>! ![](http://img14.imageshack.us/img14/7545/hayaire.png)

_**The Code:**_

==============
**Server Side**
==============

First let's add the "Hair" declaration to the PlayerRec

In **modTypes**
Find : **Private Type PlayerRec**

Find:
```
Level As Byte
```
Underneath it Add:
```
Hair As Long
```
In **modConstants**

Change **MAX_BUTTONS** Value to equal 39 instead of 35

In **modPlayer**
We're going to add a function and sub that will return the value of and set the hair, could be used for other source edits in the future.

Find: **Function GetPlayerLevel**

Above that entire function, add this:
```
Function GetPlayerHair(ByVal index As Long) As Long
    If index <= 0 Or index > MAX_PLAYERS Then Exit Function
    GetPlayerHair = Player(index).Hair
End Function

Sub SetPlayerHair(ByVal index As Long, ByVal Hair As Long)
    If index <= 0 Or index > MAX_PLAYERS Then Exit Sub
    Player(index).Hair = Hair
End Sub
```
In **modDatabase**

Find the **AddChar** Sub

We're going to modify our AddChar sub so it can know which hair will be sent from the client, look for this on the same line as the name of the sub:
```
ByVal Sprite As Long
```
Directly after it on the same line, we're going to add this:
```
, ByVal Hair As Long
```
That whole line should look like this:
```
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)

```
This will set the hair for the player on the server so it can be saved, in the same sub find this:
```
Player(index).Level = 1
```
Underneath it, add this:
```
Player(index).Hair = Hair
```
The next two additions we'll make are so that the server saves the hair value.

In the **SavePlayer** sub,

Find:
```
PutVar filename, "ACCOUNT", "Level", Val(Player(index).Level)
```
Underneath it add this:
```
PutVar filename, "ACCOUNT", "Hair", Val(Player(index).Hair)
```
In the **LoadPlayer** sub,

Find:
```
Player(index).Level = Val(GetVar(filename, "ACCOUNT", "Level"))
```
Underneath it add this:
```
Player(index).Hair = Val(GetVar(filename, "ACCOUNT", "Hair"))
```
Now we handle the sub that actually receives player data from the client. We need to tell it to read the hair value.

In **modHandleData**
Find the **HandleAddChar** sub.

Find:
```
Dim Sprite As Long
```
Underneath it add this:
```
Dim Hair As Long
```
Find:
```
Sprite = Buffer.ReadLong
```
Underneath it add this:
```
Hair = Buffer.ReadLong
```
Now we tell the AddChar sub to include hair as well

Find:
```
Call AddChar(index, Name, Sex, Class, Sprite)
```
Replace it with:
```
Call AddChar(index, Name, Sex, Class, Sprite, Hair)
```
In **modServerTCP**
Find the **PlayerData** function

Here, were going to send our saved hair value back to the client so it can load it every time.

Find:
```
Buffer.WriteLong GetPlayerLevel(index)
```
Underneath it add this:
```
Buffer.WriteLong GetPlayerHair(index)
```
That's it for server side! On to the client.

==============
**Client Side**
==============

Doing the same thing as the server here…

In **modTypes**
Find : **Private Type PlayerRec**

Find:
```
Level As Byte
```
Underneath it Add:
```
Hair As Long
```
In **modClientTCP**

Here we'll modify our SendAddChar to include a hair value to send to the server.

Replace the entire **SendAddChar** sub with this:
```
Public Sub SendAddChar(ByVal name As String, ByVal Sex As Long, ByVal ClassNum As Long, ByVal Sprite As Long, ByVal Hair As Long)
Dim Buffer As clsBuffer

    ' If debug mode, handle error then exit out
    If Options.Debug = 1 Then On Error GoTo errorhandler

    Set Buffer = New clsBuffer
    Buffer.WriteLong CAddChar
    Buffer.WriteString name
    Buffer.WriteLong Sex
    Buffer.WriteLong ClassNum
    Buffer.WriteLong Sprite
    Buffer.WriteLong Hair
    SendData Buffer.ToArray()
    Set Buffer = Nothing

    ' Error handler
    Exit Sub
errorhandler:
    HandleError "SendAddChar", "modClientTCP", Err.Number, Err.Description, Err.Source, Err.HelpContext
    Err.Clear
    Exit Sub
End Sub
```
In **modDatabase**

Now we'll add two subs that return or set the hair value.

Add this to the bottom:
```
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
```
In **modGlobals**

Adding in declarations that hold our gender and hair constants, can't remember if the "newCharSex" already exists or not, if it does, ignore it and don't add it.

Find:
```
' New char
Public newCharSprite As Long
Public newCharClass As Long
```
Underneath it add this:
```
Public newCharSex As Long
Public newCharHair As Long
```
In **modGeneral**
Find the **MenuState** sub

We send our hair constant to the server with our modified SendAddChar sub. Also, we tell it to select the gender we've picked at character creation.

Find:
```
Call SendAddChar(sChar, SEX_MALE, newCharClass, newCharSprite)
```
And Replace it with:
```
Call SendAddChar(sChar, newCharSex, newCharClass, newCharSprite, newCharHair)
```
In **modHandleData**

Find the **HandlePlayerData** sub,

Here we receive the saved hair constant from the server.

Find:
```
Call SetPlayerLevel(i, Buffer.ReadLong)
```
Underneath it, add this:
```
Call SetPlayerHair(i, Buffer.ReadLong)
```
Add this to the bottom of the entire modGeneral module:
```
Public Sub ChangeGender()

    If newCharSex = SEX_MALE Then
        newCharSex = SEX_FEMALE
    Else
        newCharSex = SEX_MALE
    End If

End Sub
```
Now we add the graphical functions of hair.

In **modDirectX8**
Find:
```
Public Tex_Fader As Long
```
Underneath it add:
```
' Hair
Public Tex_Hair() As Long
```
Find:
```
Public Count_Fog As Long
```
Underneath it add this:
```
Public Count_Hair As Long
```
Find:
```
Public Const Path_Fog As String = "\data files\graphics\fog\"
```
Underneath it add:
```
Public Const Path_Hair As String = "\data files\graphics\characters\hair\"
```
Find:
```
' Surfaces
    Count_Surface = 1
    Do While FileExist(App.Path & Path_Surface & Count_Surface & ".png")
        ReDim Preserve Tex_Surface(0 To Count_Surface)
        Tex_Surface(Count_Surface).Path = App.Path & Path_Surface & Count_Surface & ".png"
        Count_Surface = Count_Surface + 1
    Loop
    Count_Surface = Count_Surface - 1
```
Underneath it add this:
```
' Hair Textures
    Count_Hair = 1
    Do While FileExist(App.Path & Path_Hair & Count_Hair & ".png")
        ReDim Preserve Tex_Hair(0 To Count_Hair)
        Tex_Hair(Count_Hair) = SetTexturePath(App.Path & Path_Hair & Count_Hair & ".png")
        Count_Hair = Count_Hair + 1
    Loop
    Count_Hair = Count_Hair - 1
```
Find your **DrawPlayer** sub

Find:
```
RenderTexture Tex_Char(Sprite), ConvertMapX(x), ConvertMapY(y), rec.left, rec.top, rec.Width, rec.height, rec.Width, rec.height
```
Underneath it add this:
```
DrawHair x, y, GetPlayerHair(index), Anim, spritetop
```
Underneath the entire **DrawPlayer** sub, add this:
```
Public Sub DrawHair(ByVal x2 As Long, ByVal y2 As Long, ByVal Hair As Long, ByVal Anim As Long, ByVal spritetop As Long)
Dim rec As GeomRec

    If Hair < 1 Or Hair > Count_Hair Then Exit Sub

        With rec
            .top = spritetop * (D3DT_TEXTURE(Tex_Hair(Hair)).height / 4)
            .height = (D3DT_TEXTURE(Tex_Hair(Hair)).height / 4)
            .left = Anim * (D3DT_TEXTURE(Tex_Hair(Hair)).Width / 4)
            .Width = (D3DT_TEXTURE(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.Width, rec.height, rec.Width, rec.height

End Sub
```
Up next, we will be moving some things around in the New Character screen, as well as adding in our buttons and defining what they do.

Find your **DrawNewChar** sub

Find:
```
' sprite preview
    sprite = Class(newCharClass).MaleSprite(newCharSprite)
    'EngineRenderRectangle Tex_Char(sprite), x + 235, y + 123, 32, 0, 32, 32, 32, 32, 32, 32
    RenderTexture Tex_Char(sprite), x + 235, y + 123, 32, 0, 32, 32, 32, 32
```
Replace it with this:
```
RenderChar

    RenderTexture Tex_Hair(newCharHair), x + 265, y + 120, 32, 0, 32, 32, 32, 32
```
This sub will render the correct sprite based on gender on character creation. Above the entire **DrawNewChar** sub, add this:
```
Public Sub RenderChar()
Dim Sprite As Long
Dim x As Long
Dim y As Long

    x = GUIWindow(GUI_MAINMENU).x
    y = GUIWindow(GUI_MAINMENU).y

        If newCharSex = SEX_MALE Then
            Sprite = Class(newCharClass).MaleSprite(newCharSprite)
        Else
            Sprite = Class(newCharClass).FemaleSprite(newCharSprite)
        End If

    RenderTexture Tex_Char(Sprite), x + 265, y + 120, 32, 0, 32, 32, 32, 32
End Sub
```
Time to draw our four buttons. Back in the **DrawNewChar** sub, were going to **add this just above the last "End If"**
```
' position
        For buttonnum = 36 To 39
        x = GUIWindow(GUI_MAINMENU).x + Buttons(buttonnum).x
        y = GUIWindow(GUI_MAINMENU).y + Buttons(buttonnum).y
        Width = Buttons(buttonnum).Width
        height = Buttons(buttonnum).height
        ' render accept button
        If Buttons(buttonnum).state = 2 Then
            ' we're clicked boyo
            'EngineRenderRectangle Tex_Buttons_c(Buttons(buttonnum).PicNum), x, y, 0, 0, width, height, width, height, width, height
            RenderTexture Tex_Buttons(Buttons(buttonnum).PicNum), x, y, 0, 0, Width, height, Width, height
        ElseIf (GlobalX >= x And GlobalX <= x + Buttons(buttonnum).Width) And (GlobalY >= y And GlobalY <= y + Buttons(buttonnum).height) Then
            ' we're hoverin'
            'EngineRenderRectangle Tex_Buttons_h(Buttons(buttonnum).PicNum), x, y, 0, 0, width, height, width, height, width, height
            RenderTexture Tex_Buttons(Buttons(buttonnum).PicNum), x, y, 0, 0, Width, height, Width, height
            ' play sound if needed
            If Not lastButtonSound = buttonnum Then
                Play_Sound Sound_ButtonHover
                lastButtonSound = buttonnum
            End If
        Else
            ' we're normal
            'EngineRenderRectangle Tex_Buttons(Buttons(buttonnum).PicNum), x, y, 0, 0, width, height, width, height, width, height
            RenderTexture Tex_Buttons(Buttons(buttonnum).PicNum), x, y, 0, 0, Width, height, Width, height
            ' reset sound if needed
            If lastButtonSound = buttonnum Then lastButtonSound = 0
        End If
        Next
```
In **modGeneral**
Find the **InitialiseGUI** sub

This is where we defined our buttons, their sizes and position. At the very bottom of the sub but above "End Sub", were going to add in our new buttons:
```
    ' main - Select Gender Left
        With Buttons(36)
            .state = 0 'normal
            .x = 175
            .y = 114
            .Width = 19
            .height = 19
            .visible = True
            .PicNum = 23
        End With

    ' main - Select Gender Right
        With Buttons(37)
            .state = 0 'normal
            .x = 211
            .y = 114
            .Width = 19
            .height = 19
            .visible = True
            .PicNum = 24
        End With

    ' main - Select Hair Left
        With Buttons(38)
            .state = 0 'normal
            .x = 175
            .y = 141
            .Width = 19
            .height = 19
            .visible = True
            .PicNum = 23
        End With

    ' main - Select Gender Right
        With Buttons(39)
            .state = 0 'normal
            .x = 211
            .y = 141
            .Width = 19
            .height = 19
            .visible = True
            .PicNum = 24
        End With
```
In **modInput**
Find the **MainMenu_MouseDown** sub

This will check if we're clicking a button.

Add this at the bottom before "End Sub"
```
For i = 36 To 39
        x = GUIWindow(GUI_MAINMENU).x + Buttons(i).x
        y = GUIWindow(GUI_MAINMENU).y + Buttons(i).y
        ' check if we're on the button
        If (GlobalX >= x And GlobalX <= x + Buttons(i).Width) And (GlobalY >= y And GlobalY <= y + Buttons(i).height) Then
            Buttons(i).state = 2 ' clicked
        End If
    Next
```
Find the **MainMenu_MouseUp** sub

This will check if we clicked a button and what the button will do once we've clicked it.

Find:
```
' reset buttons
    resetClickedButtons
```
Above it, add this:
```
    ' Character Customization Buttons
    ' find out which button we're clicking
    For i = 36 To 39
        x = GUIWindow(GUI_MAINMENU).x + Buttons(i).x
        y = GUIWindow(GUI_MAINMENU).y + Buttons(i).y
        ' check if we're on the button
        If (GlobalX >= x And GlobalX <= x + Buttons(i).Width) And (GlobalY >= y And GlobalY <= y + Buttons(i).height) Then
            If Buttons(i).state = 2 Then
                ' do stuffs
                Select Case i
                    Case 36
                        If curMenu = MENU_NEWCHAR Then
                            ' do eet
                            ChangeGender
                            RenderChar
                        End If
                    Case 37
                        If curMenu = MENU_NEWCHAR Then
                            ' do eet
                            ChangeGender
                            RenderChar
                        End If
                    Case 38
                        If curMenu = MENU_NEWCHAR Then
                            ' Select Hair
                            newCharHair = newCharHair - 1
                            If newCharHair < 0 Then
                                newCharHair = Count_Hair
                            End If
                        End If
                    Case 39
                        If curMenu = MENU_NEWCHAR Then
                            ' Cycle Hair
                            newCharHair = newCharHair + 1
                            If newCharHair > Count_Hair Then
                                newCharHair = 1
                            End If
                        End If
                End Select
                ' play sound
                Play_Sound Sound_ButtonClick
            End If
        End If
    Next
```
_**Non-Code Work:**_

1\. In your graphics folder, create a new folder in your "characters" folder called "hair"
2\. Add 26.png to your /graphics/gui/ folder and replace the old one
3\. Add 23.png and 24.png to your graphics/gui/buttons/ folder.

I think that's it but I'm not sure. I have a bad habit of adding in things then forgetting what all I did to get it working, if you have trouble with the tutorial, have any questions, or find I left something out, let me know. Congrats, you now have a basic character customization screen. I hope this helps you further your project, and I hope its understandable enough for you to add your own customization options. I'll try to do my tutorials with a bit more explanation in the future.
Link to comment
Share on other sites

  • Replies 83
  • Created
  • Last Reply

Top Posters In This Topic

In modConstants(client)
I had to change the max buttons from 35:
Public Const MAX_BUTTONS As Long = 39

When I go to make the exe file, it raises an error modHandleData, Sub HandlePlayerData:
Call SetPlayerHair(i, Buffer.ReadLong)
"Sub or Function not defined"

Edit: my mistake.  I did not add all of the modDatabase changes.
Link to comment
Share on other sites

I have a question while I am at it.  I followed the tutorial exactly, + the minor change I suggested, compiles and works.  Now when I go to create a character I will select the class, I hit "Accept" then I get an error "Object variable or With block variable not set".

So I went back through VB6, caught the error: "Subscript out of range"

modDirectX8 - DrawNewChar Sub = RenderTexture Tex_Hair(newCharHair), x + 265, y + 120, 32, 0, 32, 32, 32, 32

I did not do the first tutorial that was listed for the paper dolling.  Also, I do not have any images in the folders.  I was hoping that I could get pointed to an idea of what I am doing wrong?  Thanks
Link to comment
Share on other sites

You will need some images in your hairs folder. Count_Hair, which is the number of hair graphics in the folder, needs to return a positive value. 0 and any negative value will be out of range.

In the Resources section, you will find some CS:DE paperdolling graphics packs for you to use with your project.

You do not need any prerequisite tutorial for this one to work, but it works nicely with the Paperdolling tut.
Link to comment
Share on other sites

Okay, to make sure I am getting this correct, (since I went ahead and installed the other tutorial as well), All the body party go in the paperdoll folder, and the hair goes in the male/female folders depending on what it is, and I just have to rename all the images: 1.png, 2.png, 3.png, etc?
Link to comment
Share on other sites

Alright, I am still having difficulty.  I have installed all hair and gender images from the graphics pack…they are all the same to make sure the names are the same for testing.

When I debug I keep having issues with this line:
```
RenderChar

    RenderTexture Tex_Hair(newCharHair), x + 265, y + 120, 32, 0, 32, 32, 32, 32

```
I have went back through all the tutorial and ensured that I followed the lines correctly.  Is anyone else running into this issue because I cannot seem to locate how to resolve it.
Link to comment
Share on other sites

Nevermind.  I had the "hair" folder in the "graphics" folder.  This is supposed to go into "characters"(client\data files\graphics\characters\hair).

I thought I had it in there but had overlooked which directory I was creating my files in.  Sorry for all the trouble and unnecessary posts :(
Link to comment
Share on other sites

@Recoil:

> Nevermind.  I had the "hair" folder in the "graphics" folder.  This is supposed to go into "characters"(client\data files\graphics\characters\hair).
>
> I thought I had it in there but had overlooked which directory I was creating my files in.  Sorry for all the trouble and unnecessary posts :(

Glad you got it figured out. ;)
Link to comment
Share on other sites

@Couture:

> Works like a charm, thank you!
> I got one question though, if you could help me with it. When you make a new character, it starts with no hair, how and what do I change/add so you can't make a char without hair?

You can make newCharHair = 1 when the menu is drawn.

@GoldSide:

> whether this also applies to EO 2.0  :huh:

No it does not, every tutorial I do in the future will also be for CS:DE. EO and CS:DE are very similar, so you could convert using many of the same procedures.
Link to comment
Share on other sites

@ThereIsNoDomino_:

> Ohh, great code, If only I could convert it to EO xD

It shouldn't be too hard. Really all you have to do is look how EO does the rendering with the EO paper doll system and make the scroll bars manually. I have already converted it. Nice tutorial :3\. Keep them coming!
Link to comment
Share on other sites

How would i make it so instead of the 32x32 square, it displays a bigger sprite. Would i have to use powers of 2 when i display it(obviously)? I was fooling around with this```
RenderTexture Tex_Hair(newCharHair), x + 265, y + 120, 32, 0, 32, 32, 32, 32
```

I'm not too sure what changing these values will do. Instead i would rather have it show a standing version of my sprite, as i do not know what it is showing because it cuts off at the head. ive been trying to figure this out for a while. if anyone has any solutions, or ideas, please let me know :]!

also im not sure if it was this specific tutorial, but the password confirmation doesnt work. When you need to retype your password, if you mess up it still accepts it.
Link to comment
Share on other sites

@✖:

> ```
> RenderTexture Tex_Hair(newCharHair), x + 265, y + 120, 32, 0, 32, 32, 32, 32
> ```
>
> I'm not too sure what changing these values will do.

Make a backup and fool around with them. Better yet: search for "Sub RenderTexture" in your client so you can see the names of the values used, and adjust accordingly.
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share


×
×
  • Create New...