Back to legacygamers.net
WARPGATE
WARP for 2025-07-16

Custom Hair Colours Guide

The client ships nine hair colours and will crash if you ask it for one that has no palette. This patch stops the crash, keeps the picker honest, and lets you add more colours behind a pager. For hair styles, see the Custom Hairstyles guide; styles and colours are separate jobs.

Patch Hair colour guard, and extra hair coloursClient 2025-07-16 · 175220998Author CrazyBebopUpdated 2026-10-30
Requirements
WARP 07-16, rAthena
You supply
.pal files per style, gender and colour; three swatch bitmaps per colour; max_hair_color on the server
Range
9 to 90 colours in total, stock nine included; 9 is the default and changes nothing
The patch: Window › Character Creation › "Hair colour guard, and extra hair colours". It is off by default and touches nothing outside the hair colour row in the character creation window.

What it does

1. Stops a crash

Pick a colour for a hairstyle that ships no matching .pal file and the client does not fall back. It shows an error and then dies:

CPaletteRes :: Cannot find File : palette\¸Ó¸®\¸Ó¸®47_³²_8.pal
  -> OK -> Gravity(tm) Error Handler, Exception Type 0xc0000005

The crash happens because the code that recolours the sprite uses the palette pointer without checking that it loaded. It cannot be caught after the fact: the client's palette loader has no failing return, so the only fix is to never ask for a palette that is not there. The patch checks first and discards the click, exactly as the client does for a button you did not hit.

The same check runs when you change style, because a colour you already picked can be stranded by the new style.

2. Keeps the picker honest

When that style check fires, your colour is forced back to none. The highlighted square used to stay lit on the colour you had picked, so the panel disagreed with the character. The row is now repainted to match.

3. Adds colours past nine

Tick the patch and it asks how many colours the picker should offer. Leave it at 9 and nothing about the layout changes. Above nine, the row keeps its size and gains a tenth cell that pages to the next nine and wraps at the end, the same way the hair style grid does.

Note: Why a pager and not more rows. The nine colour buttons sit in the client's memory immediately before the first gender button, so a tenth would land on it, which is why the patch relocates the whole list rather than growing it in place. The layout itself is computed rather than read from a table, five swatches to a row, so extra cells would simply add more rows under the first one; paging holds the row at ten cells however many colours you add.

Adding a colour, end to end

A colour is not one file. Four things have to agree: the palette that recolours the hair, the swatch art in the picker, the total you give the patch, and the server's own cap. Miss any one and the symptom looks like a different problem.

1 Palettes: what actually recolours the hair

A hair sprite stores no colour at all. Its pixels are numbers, and the .pal file is the lookup table that turns each number into a colour. Same sprite, different palette, different hair.

They live in the client's hair palette folder. Its name is Korean, and the client stores it as raw code page bytes, so on a Western-locale machine it reads as ¸Ó¸®. The gender part of each filename is the same kind of name: ³² for male, ¿© for female. These are the literal names on disk, not placeholders to fill in:

data\palette\¸Ó¸®\
¸Ó¸®10_³²_12.pal     hairstyle 10, male, colour 12
¸Ó¸®10_¿©_12.pal     hairstyle 10, female, colour 12

So one new colour needs one file per hairstyle, per gender. kRO's 45 styles come as 90 style-and-gender pairs, so 72 new colours would be 6,480 files. Only 77 of those pairs ship a complete set of nine stock colours; the other 13 are missing the file for colour 0, the "no colour" swatch, so anything that works from a complete set skips them and leaves those pairs on the stock nine. There is one shortcut, shared palettes, and it works alongside this patch: read the shared palette section before you generate anything, then pick a route and stay on it.

Trap: The folder name is not Korean. On a Western-locale machine the folder is stored as the raw code page bytes read as Latin-1, which looks like mojibake and is the name. Copy an existing folder name rather than typing it. Writing the proper Korean form produces files the client silently never finds.

2 Swatch art: the little square in the picker

Each colour needs three bitmaps under the client's UI texture folder. Like the palette folder, its name is Korean stored as code page bytes and reads as À¯ÀúÀÎÅÍÆäÀ̽º. WARP ships that same folder, with the hairstyle thumbnails in it, at Inputs\HairThumbnails\data\texture\À¯ÀúÀÎÅÍÆäÀ̽º\make_character_ver2\, so copy the path out of there rather than typing it:

data\texture\À¯ÀúÀÎÅÍÆäÀ̽º\make_character_ver2\
color<NN>_off.bmp    color<NN>_over.bmp    color<NN>_on.bmp

22 by 22 pixels, 24-bit, uncompressed. Colours count from 0, so the nine the client ships are 0 to 8. <NN> is the colour number plus one, written as two digits: colour 0 is color01_*.bmp, colour 9 is color10_*.bmp. A colour with no color<NN>_off.bmp falls back to the first swatch's face rather than failing. That check reads _off alone, so ship all three: a colour that has _off but no _over or _on passes the check and leaves the client with no art for that state, which is the missing bitmap the fallback exists to catch.

Note: loose files or a GRF. Palettes and swatch art both load through the client's own file system, so they can sit loose under the client's data\ folder or be packed into a GRF listed in DATA.INI. It checks both. Keep one copy of each file: a stale duplicate in the other place is the usual reason an edit appears to do nothing.
Trap: Make the square match its palette. The square and the palette are separate files with nothing tying them together. Pick their colours independently and you get a green square that produces red hair. Sample the colour out of the palette you are pairing it with.

3 The patch setting

Tick the patch and answer the Hair Colours prompt with the total the picker should offer, stock nine included, anywhere from 9 to 90. It is a total, not a count of new ones: nine stock plus 72 generated is 81.

Pick a multiple of nine. Each page holds nine colours, and a cell past your total is refused: it falls back to the first swatch's face and does nothing when clicked. That worked example, 81, fills nine pages exactly.

Build, launch, and open character creation. At 9 you should see the same nine squares in the same place as before. Above 9 you should see nine squares and a tenth cell, and clicking that cell should turn the row over to the next nine and wrap back to the first page at the end. If the row still shows nine and nothing pages, the patch is applied but still set to 9.

4 The server limit

rAthena clamps hair colour independently of the client, and it clamps by index, not by total. Colours count from 0, so the stock nine are 0 to 8 and rAthena ships the cap at 8. Set it to one below the total you gave the patch: the nine stock colours plus the 72 above make 81 in total, numbered 0 to 80. Raise it in conf/import/battle_conf.txt, never in the main conf:

conf/import/battle_conf.txt
max_hair_color: 80

Without this a character can pick the colour at creation and then revert to colour 8 the moment they log in, because the map server caps the value on load.

Restart the map server once the line is in. Battle conf is read at startup, so the old cap stays live until you do, and every character logging in keeps getting clamped.

The shortcut: shared palettes

Two patches in Data change where the client looks for a hair palette, so one file serves every hairstyle:

PatchLooks forFiles for 72 colours
none (stock)¸Ó¸®10_³²_72.pal6,480
Enable shared head palettes - Male & Femalehead_³²_72.pal144
Enable shared head palettes - Unisexhead72.pal72

The style number drops out of the filename entirely, so a new custom hairstyle inherits every colour for free. The trade-off is that it is all or nothing: with shared palettes you cannot give one hairstyle its own special colour, because every style reads the same file.

Note: They work with the colour guard. The guard checks the file the client is about to load, whichever palette patch is on: with Male & Female it looks for head_<gender>_<colour>.pal, with Unisex for head<colour>.pal, and with neither for ¸Ó¸®<style>_<gender>_<colour>.pal. So a shared file you have not made yet is refused like any other missing palette, and a colour you have made works for every style. Checked in the built client with both patches, and in game with Male & Female, 2026-10-21.

Traps worth knowing

Trap: A row of crossed boxes is ambiguous. Swatch 1 is a crossed box: it is the "no colour" option. So a picker full of crossed boxes looks identical whether your art is missing or every swatch has fallen back to swatch 1. Build at 9 first and compare, or you cannot tell the two apart.
Trap: The pager cell has no icon of its own. It borrows the first swatch's face unless you supply color99_off.bmp, color99_over.bmp and color99_on.bmp. Colour 99 is reserved for it, because its natural number would collide with the first colour on page two.
Trap: Only part of a palette is the hair. If you are editing palettes by hand rather than generating them, note that only about sixteen of the 256 entries carry hair colour, and which sixteen changes from style to style. Do not copy one style's entry positions onto another. Find them by diffing that style's colour 0 against all eight of its other colours and taking every index that differs in any of them. One pair is not enough: two colours can agree on a ramp entry, and on most of kRO's styles a single pair leaves part of the ramp behind.
Trap: Check a replaced palette in game, not in character creation. In our tests the creation preview kept drawing the stock colours even with a replacement palette loaded, loose or in a GRF, while a palette loaded the same way showed on the character in game (@haircolor). A replaced stock palette that looks unchanged in creation is not proof it failed: log in and look.

Troubleshooting

Symptom
Cause
Fix
Client crashes on a colour click
The patch is not applied. That crash is what it exists to prevent.
Apply the patch.
Clicking a colour does nothing
The palette for that style, gender and colour is missing, and the guard is discarding the click.
Build the name from what you clicked, ¸Ó¸®<style>_<gender>_<colour>.pal (or the shared name, if a shared-palette patch is on), and check that exact file is in the palette folder. Nothing is logged: the guard drops the click silently, so no error names the file for you. If you generated your palettes from kRO's complete sets, the 13 style-and-gender pairs that ship without a colour 0 file are the usual gap.
The square is the wrong colour
The swatch art does not match the palette it selects. They are separate files.
Sample the colour out of the palette you are pairing it with.
A crossed box where a colour should be
No color<NN>_off.bmp for that colour.
Add color<NN>_off/_over/_on.bmp for it, 22 by 22 pixels, 24-bit.
Colour reverts after logging in
max_hair_color on the server is lower than the colour you picked.
Raise it in conf/import/battle_conf.txt and restart the map server.
The whole picker only shows nine
The patch is applied but still set to 9.
Re-run WARP on a clean, unpatched Ragexe with your whole patch list, this one included, and answer the Hair Colours prompt with your total. A second pass over an already patched client keeps only the patches you tick that time, so patching the patched exe would drop everything else you shipped.
Nine colours after an unattended build
WARP cannot ask the question with nobody at the keyboard, so the patch keeps the client default of nine.
Build with the WARP window open and answer the Hair Colours prompt.
Every colour is refused after enabling shared palettes
The shared files are missing. With a shared-palette patch on, the client and the guard both look for the shared name, not the per-style one.
Add head_<gender>_<colour>.pal (Male & Female) or head<colour>.pal (Unisex) to the palette folder. See shared palettes.

Checklist

Check off items as you complete them. Progress is saved in your browser.

Client side

0 / 5
  • .pal files for every style, gender and colour you are adding, in the mojibake folder name
  • color<NN>_off/_over/_on.bmp for each colour, 22x22, 24-bit, matching the palette
  • color99_*.bmp if you want a proper arrow on the pager cell
  • The patch ticked, with your total in the Hair Colours prompt
  • Tested at 9 first, so you have a control to compare against

Server side

0 / 2
  • max_hair_color raised in conf/import/battle_conf.txt
  • Map server restarted