diff options
author | mekolat <mekolat@users.noreply.github.com> | 2016-02-08 21:35:13 -0500 |
---|---|---|
committer | mekolat <mekolat@users.noreply.github.com> | 2016-02-08 21:35:13 -0500 |
commit | 8b0fab6ad2c3533eb054eb292a630b691502beae (patch) | |
tree | 9ccd267676b3c25493c13a4399e475334e8dc90f | |
parent | 71c9e0c06045303c5a0a9fb7c849b76583e449c0 (diff) | |
parent | f889e025cc403ceb6f6276d66fdc367f544a0e82 (diff) | |
download | tmwa-8b0fab6ad2c3533eb054eb292a630b691502beae.tar.gz tmwa-8b0fab6ad2c3533eb054eb292a630b691502beae.tar.bz2 tmwa-8b0fab6ad2c3533eb054eb292a630b691502beae.tar.xz tmwa-8b0fab6ad2c3533eb054eb292a630b691502beae.zip |
Merge pull request #177 from wushin/add-third-gender
Add third gender
-rw-r--r-- | src/admin/ladmin.cpp | 14 | ||||
-rw-r--r-- | src/ast/item_test.cpp | 2 | ||||
-rw-r--r-- | src/char/char.cpp | 76 | ||||
-rw-r--r-- | src/login/login.cpp | 57 | ||||
-rw-r--r-- | src/map/atcommand.cpp | 34 | ||||
-rw-r--r-- | src/map/chrif.cpp | 5 | ||||
-rw-r--r-- | src/map/clif.cpp | 6 | ||||
-rw-r--r-- | src/map/pc.cpp | 35 | ||||
-rw-r--r-- | src/mmo/enums.hpp | 9 | ||||
-rwxr-xr-x | tools/config.py | 6 | ||||
-rwxr-xr-x | tools/protocol.py | 7 |
11 files changed, 109 insertions, 142 deletions
diff --git a/src/admin/ladmin.cpp b/src/admin/ladmin.cpp index e0d6b06..ac9be1d 100644 --- a/src/admin/ladmin.cpp +++ b/src/admin/ladmin.cpp @@ -205,7 +205,7 @@ namespace admin // // sex <account_name> <sex> // Modify the sex of an account. -// <example> sex testname Male +// <example> sex testname M // // state <account_name> <new_state> <error_message_#7> // Change the state of an account. @@ -490,7 +490,7 @@ void display_help(ZString param) { PRINTF("sex <account_name> <sex>\n"_fmt); PRINTF(" Modify the sex of an account.\n"_fmt); - PRINTF(" <example> sex testname Male\n"_fmt); + PRINTF(" <example> sex testname M\n"_fmt); } else if (command == "state"_s) { @@ -627,7 +627,7 @@ void addaccount(ZString param, int emailflag) if (!name.is_print()) return; - if (!"MF"_s.contains(sex)) + if (!"MFN"_s.contains(sex)) { PRINTF("Illegal gender [%c]. Please input M or F.\n"_fmt, sex); LADMIN_LOG("Illegal gender [%c]. Please input M or F.\n"_fmt, sex); @@ -1291,7 +1291,7 @@ void changesex(ZString param) if (!qsplit(param, &name, &sex_)) { PRINTF("Please input an account name and a sex.\n"_fmt); - PRINTF("<example> sex testname Male\n"_fmt); + PRINTF("<example> sex testname M\n"_fmt); LADMIN_LOG("Incomplete parameters to change the sex of an account ('sex' command).\n"_fmt); return; } @@ -1303,7 +1303,7 @@ void changesex(ZString param) return; } - if (!"MF"_s.contains(sex)) + if (!"MFN"_s.contains(sex)) { PRINTF("Illegal gender [%c]. Please input M or F.\n"_fmt, sex); LADMIN_LOG("Illegal gender [%c]. Please input M or F.\n"_fmt, sex); @@ -1750,6 +1750,8 @@ void parse_fromlogin(Session *s) PRINTF("%-5s "_fmt, "Femal"_s); else if (info.sex == SEX::MALE) PRINTF("%-5s "_fmt, "Male"_s); + else if (info.sex == SEX::NEUTRAL) + PRINTF("%-5s "_fmt, "None"_s); else PRINTF("%-5s "_fmt, "Servr"_s); PRINTF("%6d "_fmt, info.login_count); @@ -2347,6 +2349,8 @@ void parse_fromlogin(Session *s) PRINTF(" Sex: Female\n"_fmt); else if (sex == SEX::MALE) PRINTF(" Sex: Male\n"_fmt); + else if (sex == SEX::NEUTRAL) + PRINTF(" Sex: None\n"_fmt); else // doesn't happen anymore PRINTF(" Sex: Server\n"_fmt); PRINTF(" E-mail: %s\n"_fmt, email); diff --git a/src/ast/item_test.cpp b/src/ast/item_test.cpp index 6e2cee7..7bb7193 100644 --- a/src/ast/item_test.cpp +++ b/src/ast/item_test.cpp @@ -127,7 +127,7 @@ namespace item EXPECT_SPAN(p->slot_unused.span, 1,31, 1,32); EXPECT_EQ(p->slot_unused.data, "xx"_s); EXPECT_SPAN(p->gender.span, 1,34, 1,34); - EXPECT_EQ(p->gender.data, SEX::NEUTRAL); + EXPECT_EQ(p->gender.data, SEX::UNSPECIFIED); EXPECT_SPAN(p->loc.span, 1,36, 1,37); EXPECT_EQ(p->loc.data, EPOS::MISC1); EXPECT_SPAN(p->wlv.span, 1,39, 1,40); diff --git a/src/char/char.cpp b/src/char/char.cpp index 0958c5e..1dc0e90 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -235,6 +235,16 @@ AString mmo_char_tostr(struct CharPair *cp) { p->last_point = char_conf.start_point; } + if (p->sex == SEX::UNSPECIFIED) + { + for (AuthFifoEntry& afi : auth_fifo) + { + if (afi.account_id == k->account_id) + { + p->sex = afi.sex; + } + } + } MString str_p; str_p += STRPRINTF( @@ -251,7 +261,8 @@ AString mmo_char_tostr(struct CharPair *cp) "%d,%d,%d\t" "%d,%d,%d,%d,%d\t" "%s,%d,%d\t" - "%s,%d,%d,%d\t"_fmt, + "%s,%d,%d,%d\t" + "%c\t"_fmt, k->char_id, k->account_id, k->char_num, k->name, @@ -265,10 +276,8 @@ AString mmo_char_tostr(struct CharPair *cp) p->hair, p->hair_color, p->clothes_color, p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, p->last_point.map_, p->last_point.x, p->last_point.y, - p->save_point.map_, p->save_point.x, p->save_point.y, p->partner_id); - - // memos were here (no longer supported) - str_p += '\t'; + p->save_point.map_, p->save_point.x, p->save_point.y, p->partner_id, + sex_to_char(p->sex)); for (IOff0 i : IOff0::iter()) { @@ -352,6 +361,7 @@ bool impl_extract(XString str, CharPair *cp) CharData *p = cp->data.get(); uint32_t unused_guild_id, unused_pet_id; + VString<1> sex; XString unused_memos; std::vector<Item> inventory; XString unused_cart; @@ -377,13 +387,17 @@ bool impl_extract(XString str, CharPair *cp) // of this, instead of adding a new \t // or putting it elsewhere, like by pet/guild record<','>(&p->save_point.map_, &p->save_point.x, &p->save_point.y, &p->partner_id), - &unused_memos, + &sex, vrec<' '>(&inventory), &unused_cart, vrec<' '>(&skills), vrec<' '>(&vars)))) return false; + if (sex.size() != 1) + p->sex = SEX::UNSPECIFIED; + else + p->sex = sex_from_char(sex.front()); // leftover corruption from Platinum if (hair_style == "-1"_s) { @@ -706,6 +720,7 @@ CharPair *make_new_char(Session *s, CharName name, const Stats6& stats, uint8_t ck.char_num = slot; ck.name = name; cd.species = Species(); + cd.sex = SEX::NEUTRAL; cd.base_level = 1; cd.job_level = 1; cd.base_exp = 0; @@ -978,7 +993,10 @@ int mmo_char_send006b(Session *s, struct char_session_data *sd) sel.stats.dex = saturate<uint8_t>(p->attrs[ATTR::DEX]); sel.stats.luk = saturate<uint8_t>(p->attrs[ATTR::LUK]); sel.char_num = k->char_num; - sel.unused = 0; + if (p->sex == SEX::UNSPECIFIED) + sel.sex = sd->sex; + else + sel.sex = p->sex; repeat_6b.push_back(info); } @@ -1257,29 +1275,6 @@ void parse_tologin(Session *ls) SEX sex = fixed.sex; if (acc) { - for (CharPair& cp : char_keys) - { - CharKey& ck = cp.key; - CharData& cd = *cp.data; - if (ck.account_id == acc) - { - cd.sex = sex; -// auth_fifo[i].sex = sex; - // to avoid any problem with equipment and invalid sex, equipment is unequiped. - for (IOff0 j : IOff0::iter()) - { - if (cd.inventory[j].nameid - && bool(cd.inventory[j].equip)) - cd.inventory[j].equip = EPOS::ZERO; - } - cd.weapon = ItemLook::NONE; - cd.shield = ItemNameId(); - cd.head_top = ItemNameId(); - cd.head_mid = ItemNameId(); - cd.head_bottom = ItemNameId(); - } - } - // disconnect player if online on char-server disconnect_player(acc); } Packet_Fixed<0x2b0d> fixed_0d; @@ -1694,7 +1689,6 @@ void parse_frommap(Session *ms) Packet_Payload<0x2afd> payload_fd; // not file descriptor payload_fd.account_id = account_id; payload_fd.login_id2 = afi.login_id2; - cd->sex = afi.sex; payload_fd.packet_client_version = afi.packet_client_version; FPRINTF(stderr, "From queue index %zd: recalling packet version %d\n"_fmt, @@ -1983,24 +1977,6 @@ void parse_frommap(Session *ms) fixed_0f.error = 2; break; } - case 5: // changesex - { - if (!acc - || isGM(acc).overwhelms(isGM(ck->account_id))) - { - if (login_session) - { // don't send request if no login-server - Packet_Fixed<0x2727> fixed_27; - fixed_27.account_id = ck->account_id; - send_fpacket<0x2727, 6>(login_session, fixed_27); - } - else - fixed_0f.error = 3; - } - else - fixed_0f.error = 2; - break; - } } } else @@ -2437,7 +2413,7 @@ void parse_char(Session *s) fixed_6d.char_select.stats.dex = saturate<uint8_t>(cd->attrs[ATTR::DEX]); fixed_6d.char_select.stats.luk = saturate<uint8_t>(cd->attrs[ATTR::LUK]); fixed_6d.char_select.char_num = ck->char_num; - fixed_6d.char_select.unused2 = 0; + fixed_6d.char_select.sex = cd->sex; send_fpacket<0x006d, 108>(s, fixed_6d); break; diff --git a/src/login/login.cpp b/src/login/login.cpp index 9310ad3..c071429 100644 --- a/src/login/login.cpp +++ b/src/login/login.cpp @@ -441,8 +441,6 @@ bool impl_extract(XString line, AuthData *ad) if (sex.size() != 1) return false; ad->sex = sex_from_char(sex.front()); - if (ad->sex == SEX::NEUTRAL) - return false; if (!e_mail_check(ad->email)) ad->email = DEFAULT_EMAIL; @@ -881,7 +879,6 @@ void parse_fromchar(Session *s) if (auth_fifo[i].account_id == acc && auth_fifo[i].login_id1 == fixed.login_id1 && auth_fifo[i].login_id2 == fixed.login_id2 && // relate to the versions higher than 18 - auth_fifo[i].sex == fixed.sex && auth_fifo[i].ip == fixed.ip && !auth_fifo[i].delflag) { @@ -1178,56 +1175,6 @@ void parse_fromchar(Session *s) break; } - case 0x2727: // Change of sex (sex is reversed) - { - Packet_Fixed<0x2727> fixed; - rv = recv_fpacket<0x2727, 6>(s, fixed); - if (rv != RecvResult::Complete) - break; - - { - AccountId acc = fixed.account_id; - for (AuthData& ad : auth_data) - { - if (ad.account_id == acc) - { - { - SEX sex; - if (ad.sex == SEX::FEMALE) - sex = SEX::MALE; - else - sex = SEX::FEMALE; - LOGIN_LOG("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n"_fmt, - server[id].name, acc, - sex_to_char(sex), - ip); - for (int j = 0; j < AUTH_FIFO_SIZE; j++) - { - if (auth_fifo[j].account_id == acc) - auth_fifo[j].login_id1++; // to avoid reconnection error when come back from map-server (char-server will ask again the authentification) - } - ad.sex = sex; - - Packet_Fixed<0x2723> fixed_23; - fixed_23.account_id = acc; - fixed_23.sex = sex; - - for (Session *ss : iter_char_sessions()) - { - send_fpacket<0x2723, 7>(ss, fixed_23); - } - } - goto x2727_out; - } - } - LOGIN_LOG("Char-server '%s': Error of sex change (account: %d not found, sex would be reversed, ip: %s).\n"_fmt, - server[id].name, acc, ip); - x2727_out: - ; - } - break; - } - case 0x2728: // We receive account_reg2 from a char-server, and we send them to other char-servers. { Packet_Head<0x2728> head; @@ -1504,7 +1451,7 @@ void parse_admin(Session *s) LOGIN_LOG("'ladmin': Attempt to create an invalid account (account or pass is too short, ip: %s)\n"_fmt, ip); } - else if (ma.sex != SEX::FEMALE && ma.sex != SEX::MALE) + else if (ma.sex != SEX::FEMALE && ma.sex != SEX::MALE && ma.sex != SEX::NEUTRAL) { LOGIN_LOG("'ladmin': Attempt to create an invalid account (account: %s, invalid sex, ip: %s)\n"_fmt, ma.userid, ip); @@ -1765,7 +1712,7 @@ void parse_admin(Session *s) { SEX sex = fixed.sex; - if (sex != SEX::FEMALE && sex != SEX::MALE) + if (sex != SEX::FEMALE && sex != SEX::MALE && sex != SEX::NEUTRAL) { LOGIN_LOG("'ladmin': Attempt to give an invalid sex (account: %s, received sex: %c, ip: %s)\n"_fmt, account_name, sex_to_char(sex), ip); diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index 123a723..f50cddf 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -2348,12 +2348,36 @@ ATCE atcommand_char_change_sex(Session *s, dumb_ptr<map_session_data> sd, ZString message) { CharName character; + VString<1> gender; + int operation; - if (!asplit(message, &character)) + if (!extract(message, record<' ', 1>(&character, &gender))) + { + clif_displaymessage(s, + "Please, enter a char name (usage: @charchangesex <char name> [Gender])."_s); return ATCE::USAGE; - + } + else { - chrif_char_ask_name(sd->status_key.account_id, character, 5, HumanTimeDiff()); + if (sex_from_char(gender.front()) == SEX::FEMALE) + { + operation = 5; + } + else if (sex_from_char(gender.front()) == SEX::MALE) + { + operation = 6; + } + else if (sex_from_char(gender.front()) == SEX::NEUTRAL) + { + operation = 7; + } + else + { + clif_displaymessage(s, + "Please, enter a char name (usage: @charchangesex <char name> [Gender])."_s); + return ATCE::USAGE; + } + chrif_char_ask_name(sd->status_key.account_id, character, operation, HumanTimeDiff()); // type: 5 - changesex clif_displaymessage(s, "Character name sends to char-server to ask it."_s); } @@ -5215,9 +5239,9 @@ Map<XString, AtCommandInfo> atcommand_info = {"allstats"_s, {"[value]"_s, 60, atcommand_all_stats, "Adjust all stats by value (or maximum)"_s}}, - {"charchangesex"_s, {"<charname>"_s, + {"charchangesex"_s, {"<charname> <sex>"_s, 60, atcommand_char_change_sex, - "Flip a characters sex and disconnect them"_s}}, + "Change a characters sex and disconnect them"_s}}, {"block"_s, {"<charname>"_s, 60, atcommand_char_block, "Permanently block a player's account from the server"_s}}, diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp index ce5669e..7421344 100644 --- a/src/map/chrif.cpp +++ b/src/map/chrif.cpp @@ -554,10 +554,7 @@ void chrif_changedsex(Session *, const Packet_Fixed<0x2b0d>& fixed) { if (sd != nullptr && sd->status.sex != sex) { - if (sd->status.sex == SEX::MALE) - sd->sex = sd->status.sex = SEX::FEMALE; - else if (sd->status.sex == SEX::FEMALE) - sd->sex = sd->status.sex = SEX::MALE; + sd->sex = sd->status.sex = sex; // to avoid any problem with equipment and invalid sex, equipment is unequiped. for (IOff0 i : IOff0::iter()) { diff --git a/src/map/clif.cpp b/src/map/clif.cpp index 64e9939..9743e49 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -659,7 +659,7 @@ void clif_set0078_main_1d8(dumb_ptr<map_session_data> sd, Buffer& buf) fixed_1d8.manner = sd->status.manner; fixed_1d8.opt3 = sd->opt3; fixed_1d8.karma = sd->status.karma; - fixed_1d8.sex = sd->sex; + fixed_1d8.sex = sd->status.sex; fixed_1d8.pos.x = sd->bl_x; fixed_1d8.pos.y = sd->bl_y; fixed_1d8.pos.dir = sd->dir; @@ -713,7 +713,7 @@ void clif_set0078_alt_1d9(dumb_ptr<map_session_data> sd, Buffer& buf) fixed_1d8.manner = sd->status.manner; fixed_1d8.opt3 = sd->opt3; fixed_1d8.karma = sd->status.karma; - fixed_1d8.sex = sd->sex; + fixed_1d8.sex = sd->status.sex; fixed_1d8.pos.x = sd->bl_x; fixed_1d8.pos.y = sd->bl_y; fixed_1d8.pos.dir = sd->dir; @@ -766,7 +766,7 @@ void clif_set007b(dumb_ptr<map_session_data> sd, Buffer& buf) fixed_1da.manner = sd->status.manner; fixed_1da.opt3 = sd->opt3; fixed_1da.karma = sd->status.karma; - fixed_1da.sex = sd->sex; + fixed_1da.sex = sd->status.sex; fixed_1da.pos2.x0 = sd->bl_x; fixed_1da.pos2.y0 = sd->bl_y; fixed_1da.pos2.x1 = sd->to_x; diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 254ecb5..cb115c3 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -627,7 +627,7 @@ int pc_isequip(dumb_ptr<map_session_data> sd, IOff0 n) return 1; P<struct item_data> item = TRY_UNWRAP(sd->inventory_data[n], return 0); - if (item->sex != SEX::NEUTRAL && sd->status.sex != item->sex) + if (item->sex != SEX::UNSPECIFIED && sd->status.sex != item->sex) return 0; if (item->elv > 0 && sd->status.base_level < item->elv) return 0; @@ -657,12 +657,6 @@ int pc_authok(AccountId id, int login_id2, sd->status_key = *st_key; sd->status = *st_data; - if (sd->status.sex != sd->sex) - { - clif_authfail_fd(sd->sess, 0); - return 1; - } - MAP_LOG_STATS(sd, "LOGIN"_fmt); MAP_LOG_XP(sd, "LOGIN"_fmt); MAP_LOG_MAGIC(sd, "LOGIN"_fmt); @@ -2129,7 +2123,7 @@ int pc_isUseitem(dumb_ptr<map_session_data> sd, IOff0 n) if (itemdb_type(nameid) != ItemType::USE) return 0; - if (item->sex != SEX::NEUTRAL && sd->status.sex != item->sex) + if (item->sex != SEX::UNSPECIFIED && sd->status.sex != item->sex) return 0; if (item->elv > 0 && sd->status.base_level < item->elv) return 0; @@ -3361,7 +3355,7 @@ int pc_readparam(dumb_ptr<map_session_data> sd, SP type) val = unwrap<Species>(sd->status.species); break; case SP::SEX: - val = static_cast<uint8_t>(sd->sex); + val = static_cast<uint8_t>(sd->status.sex); break; case SP::WEIGHT: val = sd->weight; @@ -3493,7 +3487,28 @@ int pc_setparam(dumb_ptr<map_session_data> sd, SP type, int val) } break; case SP::SEX: - chrif_char_ask_name(AccountId(), sd->status_key.name, 5, HumanTimeDiff()); + switch (val) + { + case 0: + sd->sex = sd->status.sex = SEX::FEMALE; + break; + case 1: + sd->sex = sd->status.sex = SEX::MALE; + break; + default: + sd->sex = sd->status.sex = SEX::NEUTRAL; + break; + } + for (IOff0 j : IOff0::iter()) + { + if (sd->status.inventory[j].nameid + && bool(sd->status.inventory[j].equip) + && !pc_isequip(sd, j)) + pc_unequipitem(sd, j, CalcStatus::LATER); + } + pc_calcstatus(sd, 0); + chrif_save(sd); + clif_fixpcpos(sd); break; case SP::WEIGHT: sd->weight = val; diff --git a/src/mmo/enums.hpp b/src/mmo/enums.hpp index caecc13..9a8f8ea 100644 --- a/src/mmo/enums.hpp +++ b/src/mmo/enums.hpp @@ -113,7 +113,8 @@ enum class SEX : uint8_t MALE = 1, // For items. This is also used as error, sometime. // TODO switch to Option<SEX> where appropriate. - NEUTRAL = 2, + UNSPECIFIED = 2, + NEUTRAL = 3, }; inline char sex_to_char(SEX sex) @@ -122,7 +123,8 @@ char sex_to_char(SEX sex) { case SEX::FEMALE: return 'F'; case SEX::MALE: return 'M'; - default: return '\0'; + case SEX::NEUTRAL: return 'N'; + default: return 'S'; } } inline @@ -132,7 +134,8 @@ SEX sex_from_char(char c) { case 'F': return SEX::FEMALE; case 'M': return SEX::MALE; - default: return SEX::NEUTRAL; + case 'N': return SEX::NEUTRAL; + default: return SEX::UNSPECIFIED; } } diff --git a/tools/config.py b/tools/config.py index cedaa3a..0892973 100755 --- a/tools/config.py +++ b/tools/config.py @@ -555,9 +555,9 @@ def build_config(): char_conf.opt('max_hair_style', u16, '20', min=1) char_conf.opt('max_hair_color', u16, '11', min=1) char_conf.opt('min_stat_value', u16, '1') - char_conf.opt('max_stat_value', u16, '9', min=2) - char_conf.opt('total_stat_sum', u16, '30', min=7) - char_conf.opt('min_name_length', u16, '4', min=1) + char_conf.opt('max_stat_value', u16, '9', min=1) + char_conf.opt('total_stat_sum', u16, '30', min=6) + char_conf.opt('min_name_length', u16, '4', min=4) char_conf.opt('char_slots', u16, '9', min=1) char_conf.opt('anti_freeze_enable', bool, 'false') char_conf.opt('anti_freeze_interval', seconds, '6_s', min='5_s') diff --git a/tools/protocol.py b/tools/protocol.py index f7be6e5..8c3a677 100755 --- a/tools/protocol.py +++ b/tools/protocol.py @@ -1638,7 +1638,7 @@ def build_context(): at(98, stats6, 'stats'), at(104, u8, 'char num'), - at(105, u8, 'unused2'), + at(105, sex, 'sex'), ], size=106, ) @@ -4971,8 +4971,9 @@ def build_context(): fixed=[ at(0, u16, 'packet id'), at(2, account_id, 'account id'), + at(6, sex, 'sex'), ], - fixed_size=6, + fixed_size=7, pre=[0x2b0e], post=[0x2723], desc=''' @@ -5406,7 +5407,7 @@ def build_context(): at(6, sex, 'sex'), ], fixed_size=7, - pre=[0x2723], + pre=[NOTHING], post=[0x00ac, 0x01d7, 0x2b01, 0x3011], xpost=[SCRIPT, 0x0080, 0x0081, 0x0088, 0x0091, 0x00a0, 0x00b0, 0x00b1, 0x00be, 0x00c0, 0x00e9, 0x00ee, 0x00fd, 0x0106, 0x010f, 0x0119, 0x013a, 0x0141, 0x0196, 0x01b1, 0x01d8, 0x01da, 0x2b05, 0x3022], desc=''' |