Also move species<->string translation from player.cc to species.cc.
SNH6UWOYVWP4A6B4NC6YZ6KRYPYCGGNYCW5TILTALPH552H2EUFQC
ZIR3QTZNQ4JHRPSCFXKBY6Q7F4S4QLMYH26HTECBBTAZ7Y62GW2AC
Y2FUMSP563WQWVM66N46HHBGAQ6TD5DV3K3CZQ64DRAFPVLWYCAQC
JTXU5QU5KSRO2OPW7D7PXHSR4WHZDXYHDCJSFAEAR6RDMIVWNP5QC
MQBPIR2ALV2KSE3YLXPBFEGYJBXFOTMGCRYBOEVNPHYGZD5OHAZQC
UIIGQWA5DET6T62DCYRAFTQF35NZJ2TVULR3SR2VXV2AMKGOGHMAC
JDM5R3HYGXKQKZWY35QZ2KOB24TFZ3FW2PCNXCRCMWG72AZC5ZXQC
UJHVY3MHU23VJMYKIXCDSAIXF6HH6MWKT5H2KHSJTHJVU4DYWTFAC
K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC
7NDXS36TE7QVXTXJWMYSVG5UHCCLPIO4VL6NXFGTDK3ZNKE3A2IAC
77H4BWWPPGLM3PLZH4QTAJRXIZTSDVNCOKZE223I437FN2UJ34RQC
ESWIM76FGJL4QFLSHU6AC4D74PT7OPLQ7ZCJYWLZS5UCBAJDXYHAC
Z6XF4AIERIW4U4AR3HU2ILYFZ54IK4K4ORQ6JKCEWRO5LZODWDDAC
IIN7AVA6JYRBXH6ZYRR7BY7TV6PW7ANAQ2A3PD55FKBKKQFEEF2AC
UL7XFKMUX3WIU4O2LZANK4ECJ654UZPDBFGNXUEYZYOLKBYBCG6AC
2YL37AGHLFOMIF3GCTVQGGV2RNNWETWM6ZMUHO3QEWDVBFFSFAKQC
QG7MKYZECIRDJJZKVRFI6XTCH42GTKA55BFIWPJBQZ27CZVLUJDQC
M5ZDZJBTOJ7SWQPZZQPC24JYZKP26MWSRDHXBWQE2MPPL6WCXOIQC
RISMOCQM6BKK4XSIRKYLOBB2UPDYJNDAL6OGIIR5GGNZQAK5YSZAC
ZBPZZ5A7AB2VFZKQ2UJXVDGUK22OCZJCEN2RWTGDGK3VXFCCDKVAC
QDTVLBRGHDTRUVT7I3O72K6TMOYAUSAJBZUHGOEFU2RKJNUPWZSQC
N6SBZYHPKCHUZ5UQJLYYIEK62TTEV7YWZXHPTPNVHWPHR6XZRF4AC
RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC
EO4FXWNFJRHPOSDHWH2Y6QNUP7KB5ANLX43GA3TJLXR3QOOJZ7VQC
AVEOSLDREJHWFZE6ULAWGQPDT24YX4OAOGL7YAUCFVRGHCS22UCAC
VXSORUQOM2VZA4CAZDC6KPAY373NQIN3UT7CXQXTRCYXO2WM62DAC
VJZ4D26E4L4E22SO6UYB44DNUTLG72LA4GTAEZ2DKKEMAICHOXBQC
RPI3C7RPSAS4E76BMEDHEPOFX2UU2LUEIQNSRDO65HJ7CRPKNDSQC
S6ADNAPM545WP3FRHCU6UWKX5VEMY5TPSIZYSZ3XE76VCBTVIN5QC
6O5667Y65C5GTP4V3NBKWUN22IRGCAXEELJ6MCANMYPBOKDUO75QC
WN3ZHNL4T7QMQC6JF5DJR6NHLZVOGQVO4OJNEKEM5FZKQ7AVOP4AC
UKYGZDI6PYZPXDACCQGVPHANUP5ADCSNROOZIE7LYIZQWSNFHJZAC
M5FC232XYPYMLL4WYYD4WHCDS36NZD762CFHRHGNK7TNXGZGZNZAC
33MBISZXMRGZMQ37PVINHKNWAXHYPHURMRG6ST7O2SKIRGGBHI2AC
RKBFYX6A3ORSXOVFPBGZFHL25AMX754YAT6M23FNGYXBXZ4DSFAAC
SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC
CPUDHKEC3NYEKINBNTRDSKH4NLRQHDLGX432SIYLK5YASCE4O3RQC
JJULXW764V5C2HJKZNWQAEWB6QM5YZADD7ZCE35LYTBFEM6PMYCAC
BTO5WE4OEK64DZQVNYLOESM74KKQNE7KSNMQVF5UDB26OBKP7ORQC
BVVC3O42KD4PA2QTD2NUBHPDZXYE2SFPSCDMW4F5FNA4QDTU7F4AC
QEEJFAETO6B2J4IWDIDCJ5UNIFNNHHG22IWF2CUJRTJJBNE47CWQC
C2PRXJYHDRF2642VDAUY76HJKCPQFGWDI6AM3SMCMYCHGWYDQXQQC
WMFU65IAJ3LX2YSFXXRS7ZFNDCZYQC3ZQ3QDHHK3DU3UMLJMAP4QC
YVXBG7RWH64BDT6WPAPIEINOXRXLF2ROXK6HZVKBQHK2TOBAFK5QC
FS732HH3GBQCSQRKU5ZYBYVLDBGOAGBWDNKHQV5HETPT634CFLDAC
SOCA7SXH3OXTPFBVXHWXPLMIYXCQQBDT72KVCDM4445PIKTU3GZQC
KKNUX66ORZWWQH4ARKCHPHNDOYCI65STE3A27LKA3FWUKIX7MAXQC
PNRMCHHEBCAUD2XBSSH6JOEQ6A6CFEZBCIX436DVD26DA52OCYTQC
DE2BXPJDLWN7F3LAYKUSWI5CFEYZMV2ZN4K2Y356NWIX4AIGD73QC
VDMADGWYGYZJWAEWU3WE7UCPVDS2O6HOHCXLOML64U5UCH4FER3AC
LCDAVMTTCXQW6AOXG4IHXGRGVNMA47ZKHXW3NDYK2YFJFBMCFFQAC
BTDIRPAGSX5DWEEV62VGTYALWM6G5LKFKHT7HYJXVH7XBA4BPHLQC
LABXKXWWQY2V4FUDLGVTDYHXINAP6KRHZDHBQ2FE22FFOEIZPL6QC
MQ62OAMLGJVRW2QIL4PAZRAU6PC52ZVGY2FCOBIY6IWGQIHMU5CAC
WNC5SY6P2PBCU62Q2DB5J2M4HPDS5EJY76ZEPHRGGCLJ4BSLBSSQC
LPTP6ZL7U4OVXLZ56TJKJ6HENDHE7ITFMFBXC5BKEBVXEGXPW44AC
YATODO2EN3AW7IXW5PL25HHK34YHF6Y32QBMOUZXEATZZ4YQQWZQC
SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC
FMBJCM5LJKCG326YRJGOOJU6QNWONXAHK2AB4CP4SAOHKJ5CORXQC
EJKHYV2Z6UPRVYUAL4WRW33GBNHYBFPMPA57HMBX2LQKXHIUO5VQC
#ifndef SPECIES_H
#define SPECIES_H
// from newgame.cc
species_type get_species(const int index);
species_type random_draconian_player_species();
int ng_num_species();
int get_species_by_abbrev(const char *abbrev);
const char *get_species_abbrev(int which_species);
int get_species_index_by_abbrev(const char *abbrev);
int get_species_index_by_name(const char *name);
// from player.cc
std::string species_name( species_type speci, int level, bool genus = false,
bool adj = false );
int str_to_species(const std::string &species);
#endif
#include "AppHdr.h"
#include "species.h"
#include "stuff.h"
// March 2008: change order of species and jobs on character selection
// screen as suggested by Markus Maier. Summarizing comments below are
// copied directly from Markus' SourceForge comments. (jpeg)
//
// These are listed in two columns to match the selection screen output.
// Take care to list all valid species here, or they cannot be directly
// chosen.
//
// The red draconian is later replaced by a random variant.
// The old and new lists are expected to have the same length.
static species_type old_species_order[] = {
SP_HUMAN, SP_HIGH_ELF,
SP_DEEP_ELF, SP_SLUDGE_ELF,
SP_MOUNTAIN_DWARF, SP_HALFLING,
SP_HILL_ORC, SP_KOBOLD,
SP_MUMMY, SP_NAGA,
SP_OGRE, SP_TROLL,
SP_RED_DRACONIAN, SP_CENTAUR,
SP_DEMIGOD, SP_SPRIGGAN,
SP_MINOTAUR, SP_DEMONSPAWN,
SP_GHOUL, SP_KENKU,
SP_MERFOLK, SP_VAMPIRE,
SP_DEEP_DWARF
};
// Fantasy staples and humanoid creatures come first, then diminutive and
// stealthy creatures, then monstrous creatures, then planetouched and after
// all living creatures finally the undead. (MM)
static species_type new_species_order[] = {
// comparatively human-like looks
SP_HUMAN, SP_HIGH_ELF,
SP_DEEP_ELF, SP_SLUDGE_ELF,
SP_MOUNTAIN_DWARF, SP_DEEP_DWARF,
SP_HILL_ORC, SP_MERFOLK,
// small species
SP_HALFLING, SP_KOBOLD,
SP_SPRIGGAN,
// significantly different body type from human
SP_NAGA, SP_CENTAUR,
SP_OGRE, SP_TROLL,
SP_MINOTAUR, SP_KENKU,
SP_RED_DRACONIAN,
// celestial species
SP_DEMIGOD, SP_DEMONSPAWN,
// undead species
SP_MUMMY, SP_GHOUL,
SP_VAMPIRE
};
species_type random_draconian_player_species()
{
const int num_drac = SP_PALE_DRACONIAN - SP_RED_DRACONIAN + 1;
return static_cast<species_type>(SP_RED_DRACONIAN + random2(num_drac));
}
species_type get_species(const int index)
{
if (index < 0 || (unsigned int) index >= ARRAYSZ(old_species_order))
return (SP_UNKNOWN);
return (Options.use_old_selection_order ? old_species_order[index]
: new_species_order[index]);
}
static const char * Species_Abbrev_List[NUM_SPECIES] =
{ "XX", "Hu", "HE", "DE", "SE", "MD", "Ha",
"HO", "Ko", "Mu", "Na", "Og", "Tr",
// the draconians
"Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr",
"Ce", "DG", "Sp", "Mi", "DS", "Gh", "Ke", "Mf", "Vp", "DD",
// placeholders
"El", "HD", "OM", "GE", "Gn" };
int get_species_index_by_abbrev(const char *abbrev)
{
COMPILE_CHECK(ARRAYSZ(Species_Abbrev_List) == NUM_SPECIES, c1);
for (unsigned i = 0; i < ARRAYSZ(old_species_order); i++)
{
const int sp = (Options.use_old_selection_order ? old_species_order[i]
: new_species_order[i]);
if (tolower( abbrev[0] ) == tolower( Species_Abbrev_List[sp][0] )
&& tolower( abbrev[1] ) == tolower( Species_Abbrev_List[sp][1] ))
{
return (i);
}
}
return (-1);
}
int get_species_index_by_name( const char *name )
{
unsigned int i;
int sp = -1;
std::string::size_type pos = std::string::npos;
char lowered_buff[80];
strncpy(lowered_buff, name, sizeof(lowered_buff));
strlwr(lowered_buff);
for (i = 0; i < ARRAYSZ(old_species_order); i++)
{
const species_type real_sp
= (Options.use_old_selection_order ? old_species_order[i]
: new_species_order[i]);
const std::string lowered_species =
lowercase_string(species_name(real_sp,1));
pos = lowered_species.find( lowered_buff );
if (pos != std::string::npos)
{
sp = i;
if (pos == 0) // prefix takes preference
break;
}
}
return (sp);
}
const char *get_species_abbrev( int which_species )
{
ASSERT( which_species > 0 && which_species < NUM_SPECIES );
return (Species_Abbrev_List[ which_species ]);
}
// Needed for debug.cc and hiscores.cc.
int get_species_by_abbrev( const char *abbrev )
{
int i;
COMPILE_CHECK(ARRAYSZ(Species_Abbrev_List) == NUM_SPECIES, c1);
for (i = SP_HUMAN; i < NUM_SPECIES; i++)
{
if (tolower( abbrev[0] ) == tolower( Species_Abbrev_List[i][0] )
&& tolower( abbrev[1] ) == tolower( Species_Abbrev_List[i][1] ))
{
break;
}
}
return ((i < NUM_SPECIES) ? i : -1);
}
int ng_num_species()
{
// The list musn't be longer than the number of actual species.
COMPILE_CHECK(ARRAYSZ(old_species_order) <= NUM_SPECIES, c1);
// Check whether the two lists have the same size.
COMPILE_CHECK(ARRAYSZ(old_species_order) == ARRAYSZ(new_species_order), c2);
return (ARRAYSZ(old_species_order));
}
// Does a case-sensitive lookup of the species name supplied.
int str_to_species(const std::string &species)
{
if (species.empty())
return SP_HUMAN;
// first look for full name (e.g. Green Draconian)
for (int i = SP_HUMAN; i < NUM_SPECIES; ++i)
{
if (species == species_name(static_cast<species_type>(i), 10))
return (i);
}
// nothing found, try again with plain name
for (int i = SP_HUMAN; i < NUM_SPECIES; ++i)
{
if (species == species_name(static_cast<species_type>(i), 1))
return (i);
}
return (SP_HUMAN);
}
std::string species_name(species_type speci, int level, bool genus, bool adj)
// defaults: false false
{
std::string res;
if (player_genus( GENPC_DRACONIAN, speci ))
{
if (adj || genus) // adj doesn't care about exact species
res = "Draconian";
else
{
if (level < 7)
res = "Draconian";
else
{
switch (speci)
{
case SP_RED_DRACONIAN: res = "Red Draconian"; break;
case SP_WHITE_DRACONIAN: res = "White Draconian"; break;
case SP_GREEN_DRACONIAN: res = "Green Draconian"; break;
case SP_YELLOW_DRACONIAN: res = "Yellow Draconian"; break;
case SP_GREY_DRACONIAN: res = "Grey Draconian"; break;
case SP_BLACK_DRACONIAN: res = "Black Draconian"; break;
case SP_PURPLE_DRACONIAN: res = "Purple Draconian"; break;
case SP_MOTTLED_DRACONIAN: res = "Mottled Draconian"; break;
case SP_PALE_DRACONIAN: res = "Pale Draconian"; break;
case SP_BASE_DRACONIAN:
default:
res = "Draconian";
break;
}
}
}
}
else if (player_genus( GENPC_ELVEN, speci ))
{
if (adj) // doesn't care about species/genus
res = "Elven";
else if (genus)
res = "Elf";
else
{
switch (speci)
{
case SP_HIGH_ELF: res = "High Elf"; break;
case SP_DEEP_ELF: res = "Deep Elf"; break;
case SP_SLUDGE_ELF: res = "Sludge Elf"; break;
default: res = "Elf"; break;
}
}
}
else if (player_genus(GENPC_DWARVEN, speci))
{
if (adj) // doesn't care about species/genus
res = "Dwarven";
else if (genus)
res = "Dwarf";
else
{
switch (speci)
{
case SP_MOUNTAIN_DWARF: res = "Mountain Dwarf"; break;
case SP_DEEP_DWARF: res = "Deep Dwarf"; break;
default: res = "Dwarf"; break;
}
}
}
else
{
switch (speci)
{
case SP_HUMAN: res = "Human"; break;
case SP_HALFLING: res = "Halfling"; break;
case SP_KOBOLD: res = "Kobold"; break;
case SP_MUMMY: res = "Mummy"; break;
case SP_NAGA: res = "Naga"; break;
case SP_CENTAUR: res = "Centaur"; break;
case SP_SPRIGGAN: res = "Spriggan"; break;
case SP_MINOTAUR: res = "Minotaur"; break;
case SP_KENKU: res = "Kenku"; break;
case SP_HILL_ORC:
res = (adj ? "Orcish" : genus ? "Orc" : "Hill Orc");
break;
case SP_OGRE: res = (adj ? "Ogreish" : "Ogre"); break;
case SP_TROLL: res = (adj ? "Trollish" : "Troll"); break;
case SP_DEMIGOD: res = (adj ? "Divine" : "Demigod"); break;
case SP_DEMONSPAWN: res = (adj ? "Demonic" : "Demonspawn"); break;
case SP_GHOUL: res = (adj ? "Ghoulish" : "Ghoul"); break;
case SP_MERFOLK: res = (adj ? "Merfolkian" : "Merfolk"); break;
case SP_VAMPIRE: res = (adj ? "Vampiric" : "Vampire"); break;
default: res = (adj ? "Yakish" : "Yak"); break;
}
}
return res;
}
* called from: acr - chardump - describe - newgame - view
* *********************************************************************** */
std::string species_name( species_type speci, int level, bool genus = false,
bool adj = false );
int str_to_species(const std::string &species);
/* ***********************************************************************
// Does a case-sensitive lookup of the species name supplied.
int str_to_species(const std::string &species)
{
if (species.empty())
return SP_HUMAN;
// first look for full name (e.g. Green Draconian)
for (int i = SP_HUMAN; i < NUM_SPECIES; ++i)
{
if (species == species_name(static_cast<species_type>(i), 10))
return (i);
}
// nothing found, try again with plain name
for (int i = SP_HUMAN; i < NUM_SPECIES; ++i)
{
if (species == species_name(static_cast<species_type>(i), 1))
return (i);
}
return (SP_HUMAN);
}
std::string species_name(species_type speci, int level, bool genus, bool adj)
// defaults: false false
{
std::string res;
if (player_genus( GENPC_DRACONIAN, speci ))
{
if (adj || genus) // adj doesn't care about exact species
res = "Draconian";
else
{
if (level < 7)
res = "Draconian";
else
{
switch (speci)
{
case SP_RED_DRACONIAN: res = "Red Draconian"; break;
case SP_WHITE_DRACONIAN: res = "White Draconian"; break;
case SP_GREEN_DRACONIAN: res = "Green Draconian"; break;
case SP_YELLOW_DRACONIAN: res = "Yellow Draconian"; break;
case SP_GREY_DRACONIAN: res = "Grey Draconian"; break;
case SP_BLACK_DRACONIAN: res = "Black Draconian"; break;
case SP_PURPLE_DRACONIAN: res = "Purple Draconian"; break;
case SP_MOTTLED_DRACONIAN: res = "Mottled Draconian"; break;
case SP_PALE_DRACONIAN: res = "Pale Draconian"; break;
case SP_BASE_DRACONIAN:
default:
res = "Draconian";
break;
}
}
}
}
else if (player_genus( GENPC_ELVEN, speci ))
{
if (adj) // doesn't care about species/genus
res = "Elven";
else if (genus)
res = "Elf";
else
{
switch (speci)
{
case SP_HIGH_ELF: res = "High Elf"; break;
case SP_DEEP_ELF: res = "Deep Elf"; break;
case SP_SLUDGE_ELF: res = "Sludge Elf"; break;
default: res = "Elf"; break;
}
}
}
else if (player_genus(GENPC_DWARVEN, speci))
{
if (adj) // doesn't care about species/genus
res = "Dwarven";
else if (genus)
res = "Dwarf";
else
{
switch (speci)
{
case SP_MOUNTAIN_DWARF: res = "Mountain Dwarf"; break;
case SP_DEEP_DWARF: res = "Deep Dwarf"; break;
default: res = "Dwarf"; break;
}
}
}
else
{
switch (speci)
{
case SP_HUMAN: res = "Human"; break;
case SP_HALFLING: res = "Halfling"; break;
case SP_KOBOLD: res = "Kobold"; break;
case SP_MUMMY: res = "Mummy"; break;
case SP_NAGA: res = "Naga"; break;
case SP_CENTAUR: res = "Centaur"; break;
case SP_SPRIGGAN: res = "Spriggan"; break;
case SP_MINOTAUR: res = "Minotaur"; break;
case SP_KENKU: res = "Kenku"; break;
case SP_HILL_ORC:
res = (adj ? "Orcish" : genus ? "Orc" : "Hill Orc");
break;
case SP_OGRE: res = (adj ? "Ogreish" : "Ogre"); break;
case SP_TROLL: res = (adj ? "Trollish" : "Troll"); break;
case SP_DEMIGOD: res = (adj ? "Divine" : "Demigod"); break;
case SP_DEMONSPAWN: res = (adj ? "Demonic" : "Demonspawn"); break;
case SP_GHOUL: res = (adj ? "Ghoulish" : "Ghoul"); break;
case SP_MERFOLK: res = (adj ? "Merfolkian" : "Merfolk"); break;
case SP_VAMPIRE: res = (adj ? "Vampiric" : "Vampire"); break;
default: res = (adj ? "Yakish" : "Yak"); break;
}
}
return res;
}
/* ***********************************************************************
* called from: initfile
* *********************************************************************** */
int get_species_index_by_abbrev(const char *abbrev);
int get_species_index_by_name(const char *name);
const char *get_species_abbrev(int which_species);
int get_class_index_by_abbrev(const char *abbrev);
int get_class_index_by_name(const char *name);
const char *get_class_abbrev(int which_job);
const char *get_class_name(int which_job);
/* ***********************************************************************
* called from: debug and hiscores
* *********************************************************************** */
int get_species_by_abbrev( const char *abbrev );
int get_species_by_name( const char *name );
int get_class_by_abbrev( const char *abbrev );
int get_class_by_name( const char *name );
// March 2008: change order of species and jobs on character selection
// screen as suggested by Markus Maier. Summarizing comments below are
// copied directly from Markus' SourceForge comments. (jpeg)
//
// These are listed in two columns to match the selection screen output.
// Take care to list all valid species here, or they cannot be directly
// chosen.
//
// The red draconian is later replaced by a random variant.
// The old and new lists are expected to have the same length.
static species_type old_species_order[] = {
SP_HUMAN, SP_HIGH_ELF,
SP_DEEP_ELF, SP_SLUDGE_ELF,
SP_MOUNTAIN_DWARF, SP_HALFLING,
SP_HILL_ORC, SP_KOBOLD,
SP_MUMMY, SP_NAGA,
SP_OGRE, SP_TROLL,
SP_RED_DRACONIAN, SP_CENTAUR,
SP_DEMIGOD, SP_SPRIGGAN,
SP_MINOTAUR, SP_DEMONSPAWN,
SP_GHOUL, SP_KENKU,
SP_MERFOLK, SP_VAMPIRE,
SP_DEEP_DWARF
};
// Fantasy staples and humanoid creatures come first, then diminutive and
// stealthy creatures, then monstrous creatures, then planetouched and after
// all living creatures finally the undead. (MM)
static species_type new_species_order[] = {
// comparatively human-like looks
SP_HUMAN, SP_HIGH_ELF,
SP_DEEP_ELF, SP_SLUDGE_ELF,
SP_MOUNTAIN_DWARF, SP_DEEP_DWARF,
SP_HILL_ORC, SP_MERFOLK,
// small species
SP_HALFLING, SP_KOBOLD,
SP_SPRIGGAN,
// significantly different body type from human
SP_NAGA, SP_CENTAUR,
SP_OGRE, SP_TROLL,
SP_MINOTAUR, SP_KENKU,
SP_RED_DRACONIAN,
// celestial species
SP_DEMIGOD, SP_DEMONSPAWN,
// undead species
SP_MUMMY, SP_GHOUL,
SP_VAMPIRE
};
static species_type _random_draconian_player_species()
{
const int num_drac = SP_PALE_DRACONIAN - SP_RED_DRACONIAN + 1;
return static_cast<species_type>(SP_RED_DRACONIAN + random2(num_drac));
}
static species_type _get_species(const int index)
{
if (index < 0 || (unsigned int) index >= ARRAYSZ(old_species_order))
return (SP_UNKNOWN);
return (Options.use_old_selection_order ? old_species_order[index]
: new_species_order[index]);
}
// Listed in two columns to match the selection screen output.
// Take care to list all valid classes here, or they cannot be directly chosen.
// The old and new lists are expected to have the same length.
static job_type old_jobs_order[] = {
JOB_FIGHTER, JOB_WIZARD,
JOB_PRIEST, JOB_THIEF,
JOB_GLADIATOR, JOB_NECROMANCER,
JOB_PALADIN, JOB_ASSASSIN,
JOB_BERSERKER, JOB_HUNTER,
JOB_CONJURER, JOB_ENCHANTER,
JOB_FIRE_ELEMENTALIST, JOB_ICE_ELEMENTALIST,
JOB_SUMMONER, JOB_AIR_ELEMENTALIST,
JOB_EARTH_ELEMENTALIST, JOB_CRUSADER,
JOB_DEATH_KNIGHT, JOB_VENOM_MAGE,
JOB_CHAOS_KNIGHT, JOB_TRANSMUTER,
JOB_HEALER, JOB_REAVER,
JOB_STALKER, JOB_MONK,
JOB_WARPER, JOB_WANDERER,
JOB_ARTIFICER
};
// First plain fighters, then religious fighters, then spell-casting
// fighters, then primary spell-casters, then stabbers and shooters. (MM)
static job_type new_jobs_order[] = {
// fighters
JOB_FIGHTER, JOB_GLADIATOR,
JOB_MONK, JOB_BERSERKER,
// religious professions (incl. Berserker above)
JOB_PALADIN, JOB_PRIEST,
JOB_HEALER, JOB_CHAOS_KNIGHT,
JOB_DEATH_KNIGHT, JOB_CRUSADER,
// general and niche spellcasters (incl. Crusader above)
JOB_REAVER, JOB_WARPER,
JOB_WIZARD, JOB_CONJURER,
JOB_ENCHANTER, JOB_SUMMONER,
JOB_NECROMANCER, JOB_TRANSMUTER,
JOB_FIRE_ELEMENTALIST, JOB_ICE_ELEMENTALIST,
JOB_AIR_ELEMENTALIST, JOB_EARTH_ELEMENTALIST,
// poison specialists and stabbers
JOB_VENOM_MAGE, JOB_STALKER,
JOB_THIEF, JOB_ASSASSIN,
JOB_HUNTER, JOB_ARTIFICER,
JOB_WANDERER
};
static job_type _get_class(const int index)
{
if (index < 0 || (unsigned int) index >= ARRAYSZ(old_jobs_order))
return (JOB_UNKNOWN);
return (Options.use_old_selection_order? old_jobs_order[index]
: new_jobs_order[index]);
}
static const char * Species_Abbrev_List[ NUM_SPECIES ] =
{ "XX", "Hu", "HE", "DE", "SE", "MD", "Ha",
"HO", "Ko", "Mu", "Na", "Og", "Tr",
// the draconians
"Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr", "Dr",
"Ce", "DG", "Sp", "Mi", "DS", "Gh", "Ke", "Mf", "Vp", "DD",
// placeholders
"El", "HD", "OM", "GE", "Gn" };
int get_species_index_by_abbrev( const char *abbrev )
{
COMPILE_CHECK(ARRAYSZ(Species_Abbrev_List) == NUM_SPECIES, c1);
for (unsigned i = 0; i < ARRAYSZ(old_species_order); i++)
{
const int sp = (Options.use_old_selection_order ? old_species_order[i]
: new_species_order[i]);
if (tolower( abbrev[0] ) == tolower( Species_Abbrev_List[sp][0] )
&& tolower( abbrev[1] ) == tolower( Species_Abbrev_List[sp][1] ))
{
return (i);
}
}
return (-1);
}
int get_species_index_by_name( const char *name )
{
unsigned int i;
int sp = -1;
std::string::size_type pos = std::string::npos;
char lowered_buff[80];
strncpy( lowered_buff, name, sizeof( lowered_buff ) );
strlwr( lowered_buff );
for (i = 0; i < ARRAYSZ(old_species_order); i++)
{
const species_type real_sp
= (Options.use_old_selection_order ? old_species_order[i]
: new_species_order[i]);
const std::string lowered_species =
lowercase_string(species_name(real_sp,1));
pos = lowered_species.find( lowered_buff );
if (pos != std::string::npos)
{
sp = i;
if (pos == 0) // prefix takes preference
break;
}
}
return (sp);
}
const char *get_species_abbrev( int which_species )
{
ASSERT( which_species > 0 && which_species < NUM_SPECIES );
return (Species_Abbrev_List[ which_species ]);
}
// Needed for debug.cc and hiscores.cc.
int get_species_by_abbrev( const char *abbrev )
{
int i;
COMPILE_CHECK(ARRAYSZ(Species_Abbrev_List) == NUM_SPECIES, c1);
for (i = SP_HUMAN; i < NUM_SPECIES; i++)
{
if (tolower( abbrev[0] ) == tolower( Species_Abbrev_List[i][0] )
&& tolower( abbrev[1] ) == tolower( Species_Abbrev_List[i][1] ))
{
break;
}
}
return ((i < NUM_SPECIES) ? i : -1);
}
static const char * Class_Abbrev_List[ NUM_JOBS ] =
{ "Fi", "Wz", "Pr", "Th", "Gl", "Ne", "Pa", "As", "Be", "Hu",
"Cj", "En", "FE", "IE", "Su", "AE", "EE", "Cr", "DK", "VM",
"CK", "Tm", "He", "Re", "St", "Mo", "Wr", "Wn", "Ar" };
static const char * Class_Name_List[ NUM_JOBS ] =
{ "Fighter", "Wizard", "Priest", "Thief", "Gladiator", "Necromancer",
"Paladin", "Assassin", "Berserker", "Hunter", "Conjurer", "Enchanter",
"Fire Elementalist", "Ice Elementalist", "Summoner", "Air Elementalist",
"Earth Elementalist", "Crusader", "Death Knight", "Venom Mage",
"Chaos Knight", "Transmuter", "Healer", "Reaver", "Stalker",
"Monk", "Warper", "Wanderer", "Artificer" };
int get_class_index_by_abbrev( const char *abbrev )
{
COMPILE_CHECK(ARRAYSZ(Class_Abbrev_List) == NUM_JOBS, c1);
unsigned int job;
for (unsigned int i = 0; i < ARRAYSZ(old_jobs_order); i++)
{
job = (Options.use_old_selection_order ? old_jobs_order[i]
: new_jobs_order[i]);
if (tolower( abbrev[0] ) == tolower( Class_Abbrev_List[job][0] )
&& tolower( abbrev[1] ) == tolower( Class_Abbrev_List[job][1] ))
{
return i;
}
}
return (-1);
}
const char *get_class_abbrev( int which_job )
{
ASSERT( which_job < NUM_JOBS );
return (Class_Abbrev_List[ which_job ]);
}
int get_class_by_abbrev( const char *abbrev )
{
int i;
for (i = 0; i < NUM_JOBS; i++)
{
if (tolower( abbrev[0] ) == tolower( Class_Abbrev_List[i][0] )
&& tolower( abbrev[1] ) == tolower( Class_Abbrev_List[i][1] ))
{
break;
}
}
return ((i < NUM_JOBS) ? i : -1);
}
int get_class_index_by_name( const char *name )
{
COMPILE_CHECK(ARRAYSZ(Class_Name_List) == NUM_JOBS, c1);
char *ptr;
char lowered_buff[80];
char lowered_class[80];
strncpy( lowered_buff, name, sizeof( lowered_buff ) );
strlwr( lowered_buff );
int cl = -1;
unsigned int job;
for (unsigned int i = 0; i < ARRAYSZ(old_jobs_order); i++)
{
job = (Options.use_old_selection_order ? old_jobs_order[i]
: new_jobs_order[i]);
strncpy( lowered_class, Class_Name_List[job], sizeof( lowered_class ) );
strlwr( lowered_class );
ptr = strstr( lowered_class, lowered_buff );
if (ptr != NULL)
{
cl = i;
if (ptr == lowered_class) // prefix takes preference
break;
}
}
return (cl);
}
const char *get_class_name( int which_job )
{
ASSERT( which_job < NUM_JOBS );
return (Class_Name_List[ which_job ]);
}
int get_class_by_name( const char *name )
{
int i;
int cl = -1;
char *ptr;
char lowered_buff[80];
char lowered_class[80];
strncpy( lowered_buff, name, sizeof( lowered_buff ) );
strlwr( lowered_buff );
for (i = 0; i < NUM_JOBS; i++)
{
strncpy( lowered_class, Class_Name_List[i], sizeof( lowered_class ) );
strlwr( lowered_class );
ptr = strstr( lowered_class, lowered_buff );
if (ptr != NULL)
{
cl = i;
if (ptr == lowered_class) // prefix takes preference
break;
}
}
return (cl);
}
// The list musn't be longer than the number of actual species.
COMPILE_CHECK(ARRAYSZ(old_species_order) <= NUM_SPECIES, c1);
// Check whether the two lists have the same size.
COMPILE_CHECK(ARRAYSZ(old_species_order) == ARRAYSZ(new_species_order), c2);
const int num_species = ARRAYSZ(old_species_order);
// The list musn't be longer than the number of actual classes.
COMPILE_CHECK(ARRAYSZ(old_jobs_order) <= NUM_JOBS, c1);
// Check whether the two lists have the same size.
COMPILE_CHECK(ARRAYSZ(old_jobs_order) == ARRAYSZ(new_jobs_order), c2);
const int num_classes = ARRAYSZ(old_jobs_order);
#ifndef JOBS_H
#define JOBS_H
int ng_num_classes();
job_type get_class(const int index);
int get_class_index_by_abbrev(const char *abbrev);
const char *get_class_abbrev(int which_job);
int get_class_by_abbrev(const char *abbrev);
int get_class_index_by_name(const char *name);
const char *get_class_name(int which_job);
int get_class_by_name(const char *name);
#endif
#include "AppHdr.h"
#include "jobs.h"
// Listed in two columns to match the selection screen output.
// Take care to list all valid classes here, or they cannot be directly chosen.
// The old and new lists are expected to have the same length.
static job_type old_jobs_order[] = {
JOB_FIGHTER, JOB_WIZARD,
JOB_PRIEST, JOB_THIEF,
JOB_GLADIATOR, JOB_NECROMANCER,
JOB_PALADIN, JOB_ASSASSIN,
JOB_BERSERKER, JOB_HUNTER,
JOB_CONJURER, JOB_ENCHANTER,
JOB_FIRE_ELEMENTALIST, JOB_ICE_ELEMENTALIST,
JOB_SUMMONER, JOB_AIR_ELEMENTALIST,
JOB_EARTH_ELEMENTALIST, JOB_CRUSADER,
JOB_DEATH_KNIGHT, JOB_VENOM_MAGE,
JOB_CHAOS_KNIGHT, JOB_TRANSMUTER,
JOB_HEALER, JOB_REAVER,
JOB_STALKER, JOB_MONK,
JOB_WARPER, JOB_WANDERER,
JOB_ARTIFICER
};
// First plain fighters, then religious fighters, then spell-casting
// fighters, then primary spell-casters, then stabbers and shooters. (MM)
static job_type new_jobs_order[] = {
// fighters
JOB_FIGHTER, JOB_GLADIATOR,
JOB_MONK, JOB_BERSERKER,
// religious professions (incl. Berserker above)
JOB_PALADIN, JOB_PRIEST,
JOB_HEALER, JOB_CHAOS_KNIGHT,
JOB_DEATH_KNIGHT, JOB_CRUSADER,
// general and niche spellcasters (incl. Crusader above)
JOB_REAVER, JOB_WARPER,
JOB_WIZARD, JOB_CONJURER,
JOB_ENCHANTER, JOB_SUMMONER,
JOB_NECROMANCER, JOB_TRANSMUTER,
JOB_FIRE_ELEMENTALIST, JOB_ICE_ELEMENTALIST,
JOB_AIR_ELEMENTALIST, JOB_EARTH_ELEMENTALIST,
// poison specialists and stabbers
JOB_VENOM_MAGE, JOB_STALKER,
JOB_THIEF, JOB_ASSASSIN,
JOB_HUNTER, JOB_ARTIFICER,
JOB_WANDERER
};
job_type get_class(const int index)
{
if (index < 0 || (unsigned int) index >= ARRAYSZ(old_jobs_order))
return (JOB_UNKNOWN);
return (Options.use_old_selection_order? old_jobs_order[index]
: new_jobs_order[index]);
}
static const char * Class_Abbrev_List[ NUM_JOBS ] =
{ "Fi", "Wz", "Pr", "Th", "Gl", "Ne", "Pa", "As", "Be", "Hu",
"Cj", "En", "FE", "IE", "Su", "AE", "EE", "Cr", "DK", "VM",
"CK", "Tm", "He", "Re", "St", "Mo", "Wr", "Wn", "Ar" };
static const char * Class_Name_List[ NUM_JOBS ] =
{ "Fighter", "Wizard", "Priest", "Thief", "Gladiator", "Necromancer",
"Paladin", "Assassin", "Berserker", "Hunter", "Conjurer", "Enchanter",
"Fire Elementalist", "Ice Elementalist", "Summoner", "Air Elementalist",
"Earth Elementalist", "Crusader", "Death Knight", "Venom Mage",
"Chaos Knight", "Transmuter", "Healer", "Reaver", "Stalker",
"Monk", "Warper", "Wanderer", "Artificer" };
int get_class_index_by_abbrev( const char *abbrev )
{
COMPILE_CHECK(ARRAYSZ(Class_Abbrev_List) == NUM_JOBS, c1);
unsigned int job;
for (unsigned int i = 0; i < ARRAYSZ(old_jobs_order); i++)
{
job = (Options.use_old_selection_order ? old_jobs_order[i]
: new_jobs_order[i]);
if (tolower( abbrev[0] ) == tolower( Class_Abbrev_List[job][0] )
&& tolower( abbrev[1] ) == tolower( Class_Abbrev_List[job][1] ))
{
return i;
}
}
return (-1);
}
const char *get_class_abbrev( int which_job )
{
ASSERT( which_job < NUM_JOBS );
return (Class_Abbrev_List[ which_job ]);
}
int get_class_by_abbrev( const char *abbrev )
{
int i;
for (i = 0; i < NUM_JOBS; i++)
{
if (tolower( abbrev[0] ) == tolower( Class_Abbrev_List[i][0] )
&& tolower( abbrev[1] ) == tolower( Class_Abbrev_List[i][1] ))
{
break;
}
}
return ((i < NUM_JOBS) ? i : -1);
}
int get_class_index_by_name( const char *name )
{
COMPILE_CHECK(ARRAYSZ(Class_Name_List) == NUM_JOBS, c1);
char *ptr;
char lowered_buff[80];
char lowered_class[80];
strncpy( lowered_buff, name, sizeof( lowered_buff ) );
strlwr( lowered_buff );
int cl = -1;
unsigned int job;
for (unsigned int i = 0; i < ARRAYSZ(old_jobs_order); i++)
{
job = (Options.use_old_selection_order ? old_jobs_order[i]
: new_jobs_order[i]);
strncpy( lowered_class, Class_Name_List[job], sizeof( lowered_class ) );
strlwr( lowered_class );
ptr = strstr( lowered_class, lowered_buff );
if (ptr != NULL)
{
cl = i;
if (ptr == lowered_class) // prefix takes preference
break;
}
}
return (cl);
}
const char *get_class_name( int which_job )
{
ASSERT( which_job < NUM_JOBS );
return (Class_Name_List[ which_job ]);
}
int get_class_by_name( const char *name )
{
int i;
int cl = -1;
char *ptr;
char lowered_buff[80];
char lowered_class[80];
strncpy( lowered_buff, name, sizeof( lowered_buff ) );
strlwr( lowered_buff );
for (i = 0; i < NUM_JOBS; i++)
{
strncpy( lowered_class, Class_Name_List[i], sizeof( lowered_class ) );
strlwr( lowered_class );
ptr = strstr( lowered_class, lowered_buff );
if (ptr != NULL)
{
cl = i;
if (ptr == lowered_class) // prefix takes preference
break;
}
}
return (cl);
}
int ng_num_classes()
{
// The list musn't be longer than the number of actual classes.
COMPILE_CHECK(ARRAYSZ(old_jobs_order) <= NUM_JOBS, c1);
// Check whether the two lists have the same size.
COMPILE_CHECK(ARRAYSZ(old_jobs_order) == ARRAYSZ(new_jobs_order), c2);
return ARRAYSZ(old_jobs_order);
}