Dolls are no longer limited in what features they can force, so your character can always look like a flaming centaur with wings if that's how you want to present yourself.
This shouldn't cause any major breakage with save games or dolls.txt files, although expect some weirdness. Sorry.
Also, fixed a bug where barding wasn't appearing on nagas or centaurs.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@10568 c06c8d41-db1a-0410-9941-cceddc491573
U7RYFXP5Z2QXHTCPTEBZ3TH6MW2DQQBBNABBEDB7AW25LUXF3IKQC
BUEC7H3QAAQM6AULHLEIIRJA7G22J2BTSPN2PNLCIECBZG2QGF5AC
IHICVTO5AR5SZKS4RI32XKDEO6VJEAB6XMZTSJHDI6AZXMB5PCQAC
ERDDGBLUEKZ5SIVBKSK3XOWIORPGQRJKWG2RDGT3XQSWOMV36V2QC
EZLGE274NEOKEADYMRFN62DFMLCKJT7ADPOA2WYLZODI34CK24NQC
MADTICUXDKQB7EKTXG7J2OIJGUM7A437FRWIBRA3BIVEKXEXHO6AC
Q3B3UVMYEVC4YJUPYVSNTR4DJH4E6J4JJDHZNT5LNOCHCPPMEMXAC
PBTLQZHBQK5TAIO7SNSCKSHOQQ65CFFI55OTTETV7FG2FCJOXKHQC
6DMSDQMAK5FWLGJIZB7HDWAWWEGYMIFLOZH3PXEOWZ2BCRQT3LHAC
OGDVYT4KKXIUOB4NCNWBX64EJWS25B54DF23UP3NMQ6QWHEW2RAAC
IP4A3VRYFYIVLRUAU4DF4KDNP6E4UISWJX3LI2F4EGSSMIJYRJXAC
25CH7HH4LKXFIZ75YNMXS3TSXO6O27DYSOPLOD45K4OCNFWLS4LQC
WRDCASRSGOBY5RLVORAMRBSYKEWLLO7VZ4V5NQG2TKBWYNU4OZKAC
HBPUTW5HDHUEPB62DMJ6GGP2D2GLZB53O5VRTWDLQ4Z53NWB3MKQC
DK76MINM4TMQKZ6HKMJZMZM7QPGQUO3YY3I226G7JDUYJJLWKWAQC
PUQVSISR5TQFRV6UKOFREN45ZM4YSCST5QSJ2J5CHIHOSYK62MOQC
BWH4C6ZVGZV37Y3ILA6Q22IBZKEYY35TJTT2YULSRIYI6SQNLPQQC
HPV2KABLOLNNUC3L2E5XQOWDOAOVLIGASQ2Z7SVS33QKON34OT4QC
MV5USMLTBKVRWBAD67UFJ2BS4Y5HEOMYASRSB44DS24BBMRP75RQC
3XRTONH32W5DNI2V2SGAHXN3EHOZQ26ZXMVYL5TRP6HLQN7P4HNAC
HBXWZNXAJ7LUX7FYUIHQYBTRMWVJC6CAQQL3NNZHK5ETLIFEZJ7QC
PHZTAI6CW7JHKFW77MKDK75UCNWBXFK7VDD3D5ORVXUFWV3C3EVQC
XKNRIFG2ULQLAAQ5GC4RBZPOERV73DLCNILEA5EP37JLIX5EP3OQC
LV5VQHTUP5OPVIV6FGDX5EJTHT6UJYU7MDPNYSEWQRK3GTDIJ6MAC
4EOIRJBTEWVOK4EXA4XAWWS5CHAWZHAYRO6BRZWZ2SU2CGKV6VQAC
EGCEFY2RR5K3DMJR7WP4KQRBXX2ENCO6YML32TWXXQO5HXJELMOQC
U6ILMKBXTQZYT62IGD2CALYNU4VQGRSTHN6QBFBU7BVUBHWYOEQQC
TXVL24IFH5SK7EJAN7JAUHAZJHJV7GB364UU65P745GUBWJS6Q6AC
QFIV4YISNBTC5QXN7JYHEL3FBFWIQ2HKJ4YBDCZYTQ3PMPFE653AC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
NS3KXJXQSN33UQSOBDK3WXXKA3KY5YOUJL67NBZKGQAJYDYZ2COQC
RQ24Y25QDO2GY65XESEVBCP6VXCB7BDTWXO42IPPI6UPRJQ5XYDAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
JYCMD6WMNHXA53K4LLKVTNX6PLRLU25F6J2TYMPQXM2ENAE66NIAC
Y3HZ5Q3MH5YLRMGJNGGTJDKB32WCV5XKP5HNNYPGXL5QV55K5IQAC
DNAZ35MX7CF3D53NHBU4YOL4UI5CT3VECTI3WRXXOAODXEXDAMWQC
MCBXXIV6GICTZB56APSXMJEI63FVQWVZR3H2DRNMMFDH2XCGK4JAC
RVST2QHYJ757ZHK4AUJ5NGPDZ44AD6RVFVXYPKQIBJXZBDNUCHXQC
m_active_layer = LAYER_TITLE;
TitleRegion* reg = new TitleRegion(m_windowsz.x, m_windowsz.y);
use_control_region(reg);
delete reg;
}
void TilesFramework::draw_doll_edit()
{
DollEditRegion* reg = new DollEditRegion(&m_image, m_fonts[m_msg_font].font);
use_control_region(reg);
delete reg;
}
void TilesFramework::use_control_region(ControlRegion *reg)
{
m_layers[LAYER_TILE_CONTROL].m_regions.push_back(reg);
m_active_layer = LAYER_TILE_CONTROL;
// Only initialize title region if we'll actually want to draw it.
if (Options.tile_title_screen)
{
m_region_title = new TitleRegion(m_windowsz.x, m_windowsz.y);
m_layers[LAYER_TITLE].m_regions.push_back(m_region_title);
}
void tilep_scan_parts(char *fbuf, int *parts);
void tilep_print_parts(char *fbuf, int *parts, bool check_halo = false);
void tilep_scan_parts(char *fbuf, dolls_data &doll);
void tilep_print_parts(char *fbuf, const dolls_data &doll);
enum tile_doll_mode
{
TILEP_MODE_EQUIP = 0, // draw doll based on equipment
TILEP_MODE_LOADING = 1, // draw doll based on dolls.txt definitions
TILEP_MODE_DEFAULT = 2, // draw doll based on job specific definitions
TILEP_MODE_MAX
};
class DollEditRegion : public ControlRegion
{
public:
DollEditRegion(ImageManager *im, FTFont *font);
virtual void render();
virtual void clear();
virtual void run();
virtual int handle_mouse(MouseEvent &event);
protected:
virtual void on_resize() {}
// Currently edited doll index.
int m_doll_idx;
// Currently edited category of parts.
int m_cat_idx;
// Current part in current category.
int m_part_idx;
// Set of loaded dolls.
dolls_data m_dolls[NUM_MAX_DOLLS];
dolls_data m_player;
dolls_data m_job_default;
dolls_data m_doll_copy;
bool m_copy_valid;
tile_doll_mode m_mode;
FTFont *m_font;
ShapeBuffer m_shape_buf;
FontBuffer m_font_buf;
TileBuffer m_tile_buf;
TileBuffer m_cur_buf;
};
TILEP_MODE_EQUIP = 0, // draw doll based on equipment
TILEP_MODE_LOADING = 1, // draw doll based on dolls.txt definitions
TILEP_MODE_DEFAULT = 2 // draw doll based on job specific definitions
};
// Save mode, num, and all dolls into dolls.txt.
std::string dollsTxtString = datafile_path("dolls.txt", false, true);
const char *dollsTxt = (dollsTxtString.c_str()[0] == 0) ?
"dolls.txt" : dollsTxtString.c_str();
FILE *fp = NULL;
if ( (fp = fopen(dollsTxt, "w+")) != NULL )
{
fprintf(fp, "MODE=%s\n",
(mode == TILEP_MODE_EQUIP) ? "EQUIP" :
(mode == TILEP_MODE_LOADING) ? "LOADING"
: "DEFAULT");
fprintf(fp, "NUM=%02d\n", num == -1 ? 0 : num);
char fbuf[80];
for (unsigned int i = 0; i < NUM_MAX_DOLLS; ++i)
{
tilep_print_parts(fbuf, dolls[i]);
fprintf(fp, "%s\n", fbuf);
}
fclose(fp);
tilep_race_default(you.species, gender, you.experience_level,
default_doll[0].parts);
for (int i = 0; i < TILEP_PART_MAX; i++)
player_doll.parts[i] = TILEP_SHOW_EQUIP;
tilep_race_default(you.species, gender, you.experience_level, player_doll.parts);
if (mode == TILEP_MODE_EQUIP)
return;
// Halo.
if (result.parts[TILEP_PART_HALO] == TILEP_SHOW_EQUIP)
{
const bool halo = inside_halo(you.pos());
result.parts[TILEP_PART_HALO] = halo ? TILEP_HALO_TSO : 0;
}
// Enchantments.
if (result.parts[TILEP_PART_ENCH] == TILEP_SHOW_EQUIP)
{
result.parts[TILEP_PART_ENCH] =
(you.duration[DUR_LIQUID_FLAMES] ? TILEP_ENCH_STICKY_FLAME : 0);
}
if (result.parts[TILEP_PART_LEG] == TILEP_SHOW_EQUIP)
result.parts[TILEP_PART_LEG] = 0;
if (result.parts[TILEP_PART_DRCWING] == TILEP_SHOW_EQUIP)
result.parts[TILEP_PART_DRCWING] = 0;
if (result.parts[TILEP_PART_DRCHEAD] == TILEP_SHOW_EQUIP)
result.parts[TILEP_PART_DRCHEAD] = 0;
for (int i = 0; i < TILEP_PART_MAX; i++)
{
if (result.parts[i] == TILEP_SHOW_EQUIP)
result.parts[i] = 0;
}
// Allow player to choose between up to 10 premade dolls, or replace them
// with the job default, using current equipment, or a random doll.
// If the player makes any changes while browsing the selections, i.e.
// overwrites a slot or changes the mode, these changes are saved back
// into dolls.txt.
// TODO: Change to proper menu.
void TilePlayerEdit()
{
// Initialize equipment setting.
dolls_data equip_doll;
for (unsigned int i = 0; i < TILEP_PART_MAX; ++i)
equip_doll.parts[i] = TILEP_SHOW_EQUIP;
tilep_race_default(you.species, gender,
you.experience_level, equip_doll.parts);
// Initialize job default.
dolls_data default_doll = equip_doll;
tilep_job_default(you.char_class, gender, default_doll.parts);
// Read predefined dolls from file.
dolls_data dolls[NUM_MAX_DOLLS];
for (unsigned int i = 0; i < NUM_MAX_DOLLS; ++i)
dolls[i] = equip_doll;
int old_mode = TILEP_MODE_LOADING;
int old_num = -1;
const bool found_file = _load_doll_data("dolls.txt", dolls, NUM_MAX_DOLLS,
&old_mode, &old_num);
int mode = old_mode;
int num = old_num;
bool display_num = (found_file && mode == TILEP_MODE_LOADING);
bool dolls_changed = false;
bool did_random = false;
while (true)
{
// Offer a list of choices.
std::vector<std::string> prompt;
prompt.push_back("Pick (d)efault doll for job, use (e)quipment settings");
prompt.push_back("roll a (r)andom doll");
if (found_file)
prompt.push_back("load doll (0-9) from file");
if (did_random || mode != TILEP_MODE_LOADING)
prompt.push_back("(s)ave current doll");
std::string current = "";
bool need_braces = false;
if (did_random || mode != TILEP_MODE_LOADING)
{
current = (did_random ? "random" :
mode == TILEP_MODE_EQUIP ? "equipment" :
mode == TILEP_MODE_DEFAULT ? "default" : "buggy");
need_braces = true;
}
if (display_num)
{
snprintf(info, INFO_SIZE, "doll %d", num);
if (need_braces)
current += " [";
current += info;
if (need_braces)
current += "]";
}
mprf(MSGCH_PROMPT, "%s? (Current: %s)",
comma_separated_line(prompt.begin(),
prompt.end(), ", or ", ", ").c_str(),
current.c_str());
char ch = (char) getchm(KMC_DEFAULT);
ch = tolower(ch);
bool finish = false;
did_random = false;
if (ch == 'd')
{
player_doll = default_doll;
mode = TILEP_MODE_DEFAULT;
}
else if (ch == 'e')
{
player_doll = equip_doll;
mode = TILEP_MODE_EQUIP;
}
else if (ch == 'r')
{
dolls_data random_doll = equip_doll;
_create_random_doll(random_doll);
player_doll = random_doll;
did_random = true;
}
else if (ch == 's')
{
mpr("Save current doll to what slot? (0-9)", MSGCH_PROMPT);
const char ch2 = (char) getchm(KMC_DEFAULT);
if (ch2 >= '0' && ch2 <= '9')
{
const int slot = ch2 - '0';
ASSERT(slot >= 0 && slot <= 9);
// Translate TILEP_SHOW_EQUIP according to equipment.
_fill_doll_equipment(player_doll);
dolls[slot] = player_doll;
num = slot;
did_random = false;
dolls_changed = true;
display_num = true;
mprf("Doll saved to slot %d.", slot);
}
else
mpr("Doll not saved.");
more();
}
else if (ch >= '0' && ch <= '9')
{
// HACK until I can find the proper function.
num = ch - '0';
ASSERT(num >= 0 && num <= 9);
ASSERT(num < NUM_MAX_DOLLS);
player_doll = dolls[num];
mode = TILEP_MODE_LOADING;
display_num = true;
}
else // All other input exits the loop.
finish = true;
gender = get_gender_from_tile(player_doll.parts);
mesclr();
if (finish)
{
// No changes, nothing to be saved.
if (!dolls_changed && mode == old_mode && num == old_num)
break;
// Save mode, num, and all dolls into dolls.txt.
std::string dollsTxtString = datafile_path("dolls.txt", false, true);
const char *dollsTxt = (dollsTxtString.c_str()[0] == 0) ?
"dolls.txt" : dollsTxtString.c_str();
FILE *fp = NULL;
if ( (fp = fopen(dollsTxt, "w+")) != NULL )
{
fprintf(fp, "MODE=%s\n",
(mode == TILEP_MODE_EQUIP) ? "EQUIP" :
(mode == TILEP_MODE_LOADING) ? "LOADING"
: "DEFAULT");
fprintf(fp, "NUM=%02d\n", num == -1 ? 0 : num);
// Print some explanatory comments. May contain no spaces!
fprintf(fp, "#Legend:\n");
fprintf(fp, "#***:equipment/123:index/000:none\n");
fprintf(fp, "#Shadow/Gender/Cloak/Boots/Legs/Body/Gloves/Weapon/Shield/Hair/Beard/Helmet\n");
fprintf(fp, "#--:Sex:Clk:Bts:Leg:Bdy:Glv:Wpn:Shd:Hai:Brd:Hlm\n");
char fbuf[80];
for (unsigned int i = 0; i < NUM_MAX_DOLLS; ++i)
{
tilep_print_parts(fbuf, dolls[i].parts);
fprintf(fp, "%s\n", fbuf);
}
fclose(fp);
}
else
mprf(MSGCH_ERROR, "Could not write into file '%s'.", dollsTxt);
break;
}
viewwindow(true, false);
}
}
}
// Special case bardings from being cut off.
bool is_naga = (doll.parts[TILEP_PART_BASE] == TILEP_BASE_NAGA
|| doll.parts[TILEP_PART_BASE] == TILEP_BASE_NAGA + 1);
if (doll.parts[TILEP_PART_BOOTS] >= TILEP_BOOTS_NAGA_BARDING
&& doll.parts[TILEP_PART_BOOTS] <= TILEP_BOOTS_NAGA_BARDING_RED)
{
flags[TILEP_PART_BOOTS] = is_naga ? TILEP_FLAG_NORMAL : TILEP_FLAG_HIDE;
}
bool is_cent = (doll.parts[TILEP_PART_BASE] == TILEP_BASE_CENTAUR
|| doll.parts[TILEP_PART_BASE] == TILEP_BASE_CENTAUR + 1);
if (doll.parts[TILEP_PART_BOOTS] >= TILEP_BOOTS_CENTAUR_BARDING
&& doll.parts[TILEP_PART_BOOTS] <= TILEP_BOOTS_CENTAUR_BARDING_RED)
{
flags[TILEP_PART_BOOTS] = is_cent ? TILEP_FLAG_NORMAL : TILEP_FLAG_HIDE;
}
void TitleRegion::run()
{
mouse_control mc(MOUSE_MODE_MORE);
getch();
}
DollEditRegion::DollEditRegion(ImageManager *im, FTFont *font) :
m_font_buf(font)
{
sx = sy = 0;
dx = dy = 32;
mx = my = 1;
m_font = font;
m_doll_idx = 0;
m_cat_idx = TILEP_PART_BASE;
m_copy_valid = false;
m_tile_buf.set_tex(&im->m_textures[TEX_PLAYER]);
m_cur_buf.set_tex(&im->m_textures[TEX_PLAYER]);
}
void DollEditRegion::clear()
{
m_shape_buf.clear();
m_tile_buf.clear();
m_cur_buf.clear();
m_font_buf.clear();
static int _get_next_part(int cat, int part, int inc)
{
// Can't increment or decrement on show equip.
if (part == TILEP_SHOW_EQUIP)
{
return part;
}
// Increment max_part by 1 to include the special value of "none".
int max_part = tile_player_part_count[cat] + 1;
int offset = tile_player_part_start[cat];
ASSERT(inc > -max_part);
// Translate the "none" value into something we can do modulo math with.
if (part == 0)
{
part = offset;
inc--;
}
// Valid part numbers are in the range [offset, offset + max_part - 1].
int ret = (part + max_part + inc - offset) % (max_part);
if (ret == max_part - 1)
{
// "none" value.
return 0;
}
else
{
// Otherwise, valid part number.
return ret + offset;
}
}
void DollEditRegion::render()
{
#ifdef DEBUG_TILES_REDRAW
cprintf("rendering DollEditRegion\n");
#endif
VColour grey(128, 128, 128, 255);
m_cur_buf.clear();
m_tile_buf.clear();
m_shape_buf.clear();
m_font_buf.clear();
// Max items to show at once.
const int max_show = 9;
// Layout options (units are in 32x32 squares)
const int left_gutter = 2;
const int item_line = 2;
const int edit_doll_line = 5;
const int doll_line = 8;
const int info_offset =
left_gutter + std::max(max_show, (int)NUM_MAX_DOLLS) + 1;
const int center_x = left_gutter + max_show / 2;
// Pack current doll separately so it can be drawn repeatedly.
{
dolls_data temp = m_dolls[m_doll_idx];
_fill_doll_equipment(temp);
pack_doll_buf(m_cur_buf, temp, 0, 0);
}
// Draw set of dolls.
for (int i = 0; i < NUM_MAX_DOLLS; i++)
{
int x = left_gutter + i;
int y = doll_line;
if (m_doll_idx == i)
m_tile_buf.add(TILEP_CURSOR, x, y);
dolls_data temp = m_dolls[i];
_fill_doll_equipment(temp);
pack_doll_buf(m_tile_buf, temp, x, y);
m_shape_buf.add(x, y, x + 1, y + 1, grey);
}
// Draw current category of parts.
int max_part = tile_player_part_count[m_cat_idx];
int show = std::min(max_show, max_part);
int half_show = show / 2;
for (int i = -half_show; i <= show - half_show; i++)
{
int x = center_x + i;
int y = item_line;
if (i == 0)
m_tile_buf.add(TILEP_CURSOR, x, y);
int part = _get_next_part(m_cat_idx, m_part_idx, i);
ASSERT(part != TILEP_SHOW_EQUIP);
if (part)
m_tile_buf.add(part, x, y);
m_shape_buf.add(x, y, x + 1, y + 1, grey);
}
m_shape_buf.add(left_gutter, edit_doll_line, left_gutter + 2, edit_doll_line + 2, grey);
m_shape_buf.add(left_gutter + 3, edit_doll_line, left_gutter + 4, edit_doll_line + 1, grey);
set_transform();
m_shape_buf.draw();
m_tile_buf.draw();
glLoadIdentity();
glTranslatef(32 * left_gutter, 32 * edit_doll_line, 0);
glScalef(64, 64, 1);
m_cur_buf.draw();
glLoadIdentity();
glTranslatef(32 * (left_gutter + 3), 32 * edit_doll_line, 0);
glScalef(32, 32, 1);
m_cur_buf.draw();
// Add text.
const char *part_name = "(none)";
if (m_part_idx == TILEP_SHOW_EQUIP)
part_name = "(show equip)";
else if (m_part_idx)
part_name = tile_player_name(m_part_idx);
glLoadIdentity();
glTranslatef(0, 0, 0);
glScalef(1, 1, 1);
std::string item_str = part_name;
float item_name_x = left_gutter * 32.0f;
float item_name_y = (item_line + 1) * 32.0f;
m_font_buf.add(item_str, VColour::white, item_name_x, item_name_y);
std::string doll_name;
doll_name = make_stringf("Doll %d / %d", m_doll_idx + 1, NUM_MAX_DOLLS);
float doll_name_x = left_gutter * 32.0f;
float doll_name_y = (doll_line + 1) * 32.0f;
m_font_buf.add(doll_name, VColour::white, doll_name_x, doll_name_y);
const char *mode_name[TILEP_MODE_MAX] =
{
"Current Equipment",
"Custom Doll",
"Job Defaults"
};
doll_name = make_stringf("Doll Mode: %s", mode_name[m_mode]);
doll_name_y += m_font->char_height() * 2.0f;
m_font_buf.add(doll_name, VColour::white, doll_name_x, doll_name_y);
// Add current doll information:
std::string info_str;
float info_x = info_offset * 32.0f;
float info_y = 0.0f;
// FIXME - this should be generated in rltiles
const char *cat_name[TILEP_PART_MAX] =
{
"Species",
"Shadow",
"Halo",
"Ench",
"Cloak",
"Boots",
"Legs",
"Body",
"Arm",
"LHand",
"RHand",
"Hair",
"Beard",
"Helm",
"DrcWing",
"DrcHead"
};
for (int i = 0 ; i < TILEP_PART_MAX; i++)
{
int part = m_dolls[m_doll_idx].parts[i];
int disp = part;
if (disp)
disp = disp - tile_player_part_start[i] + 1;
int maxp = tile_player_part_count[i];
const char *sel = (m_cat_idx == i) ? "->" : " ";
if (part == TILEP_SHOW_EQUIP)
info_str = make_stringf("%2s%9s: (show equip)", sel, cat_name[i]);
else if (!part)
info_str = make_stringf("%2s%9s: (none)", sel, cat_name[i]);
else
info_str = make_stringf("%2s%9s: %3d/%3d", sel, cat_name[i], disp, maxp);
m_font_buf.add(info_str, VColour::white, info_x, info_y);
info_y += m_font->char_height();
}
m_font_buf.draw();
}
int DollEditRegion::handle_mouse(MouseEvent &event)
{
return 0;
}
void DollEditRegion::run()
{
// Initialize equipment setting.
dolls_data equip_doll;
for (unsigned int i = 0; i < TILEP_PART_MAX; ++i)
equip_doll.parts[i] = TILEP_SHOW_EQUIP;
// Initialize job default.
m_job_default = equip_doll;
tilep_race_default(you.species, gender,
you.experience_level, m_job_default.parts);
tilep_job_default(you.char_class, gender, m_job_default.parts);
// Read predefined dolls from file.
for (unsigned int i = 0; i < NUM_MAX_DOLLS; ++i)
m_dolls[i] = equip_doll;
m_mode = TILEP_MODE_LOADING;
m_doll_idx = -1;
if (!_load_doll_data("dolls.txt", m_dolls, NUM_MAX_DOLLS, &m_mode, &m_doll_idx))
{
m_doll_idx = 0;
}
bool update_part_idx = true;
command_type cmd;
do
{
if (update_part_idx)
{
m_part_idx = m_dolls[m_doll_idx].parts[m_cat_idx];
if (m_part_idx == TILEP_SHOW_EQUIP)
m_part_idx = 0;
update_part_idx = false;
}
int key = getchm(KMC_DOLL);
cmd = key_to_command(key, KMC_DOLL);
switch (cmd)
{
case CMD_DOLL_RANDOMIZE:
_create_random_doll(m_dolls[m_doll_idx]);
break;
case CMD_DOLL_SELECT_NEXT_DOLL:
m_doll_idx = (m_doll_idx + 1) % NUM_MAX_DOLLS;
update_part_idx = true;
break;
case CMD_DOLL_SELECT_PREV_DOLL:
m_doll_idx = (m_doll_idx + NUM_MAX_DOLLS - 1) % NUM_MAX_DOLLS;
update_part_idx = true;
break;
case CMD_DOLL_SELECT_NEXT_PART:
m_cat_idx = (m_cat_idx + 1) % TILEP_PART_MAX;
update_part_idx = true;
break;
case CMD_DOLL_SELECT_PREV_PART:
m_cat_idx = (m_cat_idx + TILEP_PART_MAX - 1) % TILEP_PART_MAX;
update_part_idx = true;
break;
case CMD_DOLL_CHANGE_PART_NEXT:
m_part_idx = _get_next_part(m_cat_idx, m_part_idx, 1);
if (m_dolls[m_doll_idx].parts[m_cat_idx] != TILEP_SHOW_EQUIP)
m_dolls[m_doll_idx].parts[m_cat_idx] = m_part_idx;
break;
case CMD_DOLL_CHANGE_PART_PREV:
m_part_idx = _get_next_part(m_cat_idx, m_part_idx, -1);
if (m_dolls[m_doll_idx].parts[m_cat_idx] != TILEP_SHOW_EQUIP)
m_dolls[m_doll_idx].parts[m_cat_idx] = m_part_idx;
break;
case CMD_DOLL_COPY:
m_doll_copy = m_dolls[m_doll_idx];
m_copy_valid = true;
break;
case CMD_DOLL_PASTE:
if (m_copy_valid)
m_dolls[m_doll_idx] = m_doll_copy;
break;
case CMD_DOLL_TAKE_OFF:
m_part_idx = 0;
m_dolls[m_doll_idx].parts[m_cat_idx] = 0;
break;
case CMD_DOLL_TAKE_OFF_ALL:
for (int i = 0; i < TILEP_PART_MAX; i++)
{
switch (i)
{
case TILEP_PART_BASE:
case TILEP_PART_SHADOW:
case TILEP_PART_HALO:
case TILEP_PART_ENCH:
case TILEP_PART_DRCWING:
case TILEP_PART_DRCHEAD:
break;
default:
m_dolls[m_doll_idx].parts[i] = 0;
};
}
break;
case CMD_DOLL_TOGGLE_EQUIP:
if (m_dolls[m_doll_idx].parts[m_cat_idx] == TILEP_SHOW_EQUIP)
m_dolls[m_doll_idx].parts[m_cat_idx] = m_part_idx;
else
m_dolls[m_doll_idx].parts[m_cat_idx] = TILEP_SHOW_EQUIP;
break;
case CMD_DOLL_TOGGLE_EQUIP_ALL:
for (int i = 0; i < TILEP_PART_MAX; i++)
{
m_dolls[m_doll_idx].parts[i] = TILEP_SHOW_EQUIP;
}
break;
case CMD_DOLL_CLASS_DEFAULT:
m_dolls[m_doll_idx] = m_job_default;
break;
case CMD_DOLL_CHANGE_MODE:
m_mode = (tile_doll_mode)(((int)m_mode + 1) % TILEP_MODE_MAX);
default:
break;
}
}
while (cmd != CMD_DOLL_QUIT);
_save_doll_data(m_mode, m_doll_idx, &m_dolls[0]);
// Update player with the current doll.
switch (m_mode)
{
case TILEP_MODE_LOADING:
player_doll = m_dolls[m_doll_idx];
break;
case TILEP_MODE_DEFAULT:
player_doll = m_job_default;
break;
default:
case TILEP_MODE_EQUIP:
player_doll = equip_doll;
}
}
return ((parts[TILEP_PART_BASE]
- tile_player_part_start[TILEP_PART_BASE]) % 2);
int gender = ((parts[TILEP_PART_BASE]
- tile_player_part_start[TILEP_PART_BASE]) % 2);
if (gender == TILEP_GENDER_MALE || gender == TILEP_GENDER_FEMALE)
return gender;
return TILEP_GENDER_FEMALE;
if (beard == 0 || parts[TILEP_PART_BEARD] == TILEP_SHOW_EQUIP)
parts[TILEP_PART_BEARD] = beard;
parts[TILEP_PART_SHADOW] = TILEP_SHADOW_SHADOW;
if (parts[TILEP_PART_BEARD] == TILEP_SHOW_EQUIP)
parts[TILEP_PART_BEARD] = beard;
if (parts[TILEP_PART_SHADOW] == TILEP_SHOW_EQUIP)
parts[TILEP_PART_SHADOW] = TILEP_SHADOW_SHADOW;
if (parts[TILEP_PART_DRCHEAD] == TILEP_SHOW_EQUIP)
parts[TILEP_PART_DRCHEAD] = head;
if (parts[TILEP_PART_DRCWING] == TILEP_SHOW_EQUIP)
parts[TILEP_PART_DRCWING] = wing;
int idx = parts[p];
if (idx != 0 && idx != TILEP_SHOW_EQUIP)
{
idx = parts[p] - tile_player_part_start[p] + 1;
if (idx < 0 || idx > tile_player_part_count[p])
idx = 0;
}
tilep_part_to_str(idx, ptr);
idx = doll.parts[p] - tile_player_part_start[p] + 1;
if (idx < 0 || idx > tile_player_part_count[p])
idx = 0;
// Special case bardings from being cut off.
bool is_naga = (equip_doll.parts[TILEP_PART_BASE] == TILEP_BASE_NAGA
|| equip_doll.parts[TILEP_PART_BASE] == TILEP_BASE_NAGA + 1);
if (equip_doll.parts[TILEP_PART_BOOTS] >= TILEP_BOOTS_NAGA_BARDING
&& equip_doll.parts[TILEP_PART_BOOTS] <= TILEP_BOOTS_NAGA_BARDING_RED)
{
flags[TILEP_PART_BOOTS] = is_naga ? TILEP_FLAG_NORMAL : TILEP_FLAG_HIDE;
}
bool is_cent = (equip_doll.parts[TILEP_PART_BASE] == TILEP_BASE_CENTAUR
|| equip_doll.parts[TILEP_PART_BASE] == TILEP_BASE_CENTAUR + 1);
if (equip_doll.parts[TILEP_PART_BOOTS] >= TILEP_BOOTS_CENTAUR_BARDING
&& equip_doll.parts[TILEP_PART_BOOTS] <= TILEP_BOOTS_CENTAUR_BARDING_RED)
{
flags[TILEP_PART_BOOTS] = is_cent ? TILEP_FLAG_NORMAL : TILEP_FLAG_HIDE;
}
#ifdef USE_TILE
// Tile doll editing screen
CMD_DOLL_RANDOMIZE,
CMD_MIN_DOLL = CMD_DOLL_RANDOMIZE,
CMD_DOLL_SELECT_NEXT_DOLL,
CMD_DOLL_SELECT_PREV_DOLL,
CMD_DOLL_SELECT_NEXT_PART,
CMD_DOLL_SELECT_PREV_PART,
CMD_DOLL_CHANGE_PART_NEXT,
CMD_DOLL_CHANGE_PART_PREV,
CMD_DOLL_COPY,
CMD_DOLL_PASTE,
CMD_DOLL_TAKE_OFF,
CMD_DOLL_TAKE_OFF_ALL,
CMD_DOLL_TOGGLE_EQUIP,
CMD_DOLL_TOGGLE_EQUIP_ALL,
CMD_DOLL_CLASS_DEFAULT,
CMD_DOLL_CHANGE_MODE,
CMD_DOLL_QUIT,
CMD_MAX_DOLL = CMD_DOLL_QUIT,
#endif
#endif
#ifdef USE_TILE
{CONTROL('R'), CMD_DOLL_RANDOMIZE},
{'H', CMD_DOLL_SELECT_PREV_DOLL},
{'L', CMD_DOLL_SELECT_NEXT_DOLL},
{CK_SHIFT_LEFT, CMD_DOLL_SELECT_PREV_DOLL},
{CK_SHIFT_RIGHT, CMD_DOLL_SELECT_NEXT_DOLL},
{'k', CMD_DOLL_SELECT_PREV_PART},
{'j', CMD_DOLL_SELECT_NEXT_PART},
{'h', CMD_DOLL_CHANGE_PART_PREV},
{'l', CMD_DOLL_CHANGE_PART_NEXT},
{CK_UP, CMD_DOLL_SELECT_PREV_PART},
{CK_DOWN, CMD_DOLL_SELECT_NEXT_PART},
{CK_LEFT, CMD_DOLL_CHANGE_PART_PREV},
{CK_RIGHT, CMD_DOLL_CHANGE_PART_NEXT},
{1008, CMD_DOLL_SELECT_PREV_PART},
{1002, CMD_DOLL_SELECT_NEXT_PART},
{1004, CMD_DOLL_CHANGE_PART_PREV},
{1006, CMD_DOLL_CHANGE_PART_NEXT},
{CONTROL('C'), CMD_DOLL_COPY},
{CONTROL('V'), CMD_DOLL_PASTE},
{'t', CMD_DOLL_TAKE_OFF},
{CONTROL('T'), CMD_DOLL_TAKE_OFF_ALL},
{'*', CMD_DOLL_TOGGLE_EQUIP},
{CONTROL('E'), CMD_DOLL_TOGGLE_EQUIP_ALL},
{CONTROL('D'), CMD_DOLL_CLASS_DEFAULT},
{'m', CMD_DOLL_CHANGE_MODE},
{ESCAPE, CMD_DOLL_QUIT},
{'q', CMD_DOLL_QUIT},
#Legend:
#***:equipment/123:index/000:none
#Shadow/Gender/Cloak/Boots/Legs/Body/Gloves/Weapon/Shield/Hair/Beard/Helmet
#--:Sex:Clk:Bts:Leg:Bdy:Glv:Wpn:Shd:Hai:Brd:Hlm
001:001:***:011:034:092:***:023:034:017:000:063
001:001:***:009:002:040:016:077:***:023:009:040
001:000:***:014:017:046:020:048:***:010:000:041
001:001:001:018:000:017:***:190:066:000:009:043
001:001:005:003:016:137:***:117:005:000:000:***
001:000:001:021:000:033:***:136:058:007:000:012
001:001:003:014:000:005:***:194:041:017:000:028
001:000:***:017:027:068:***:197:050:011:000:068
001:000:008:011:033:091:007:055:027:008:000:054
001:001:007:***:026:015:020:170:057:011:000:032
***:***:***:011:034:092:***:023:034:017:000:063:***:***:***:***
***:***:***:009:002:040:016:077:***:023:009:040:***:***:***:***
***:020:***:014:017:046:020:048:***:010:000:041:***:***:***:***
***:***:001:018:000:017:***:190:066:000:009:043:***:***:006:***
***:***:005:003:016:137:***:117:005:000:000:***:***:***:***:***
***:***:001:021:000:033:***:136:058:007:000:012:***:***:***:***
***:***:003:014:000:005:***:194:041:017:000:028:***:***:***:***
***:***:***:017:027:068:***:197:050:011:000:068:***:***:***:***
***:018:008:022:033:091:007:055:027:008:000:054:***:***:***:***
***:***:007:***:026:015:020:170:057:011:000:032:001:***:***:***
Shift + left/right keys Switch current doll.
Ctrl + R Randomize current doll.
left/right keys Change current part.
m Change current doll usage mode.
up/down keys Change current part category.
Ctrl + C Copy current doll.
Ctrl + V Paste current doll.
t Remove current equipped part.
T Remove all equipped parts
* Toggle "show equipment".
Ctrl + E Set all to show "show equipment".
Ctrl + D Set current doll to job defaults.
Escape Quit doll editing screen.