summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwushin <pasekei@gmail.com>2015-11-09 13:46:56 -0600
committerwushin <pasekei@gmail.com>2016-02-08 18:53:15 -0600
commitf593049cd8286f48497782d8bc0afe787724ad5d (patch)
tree371402a86444ce9104227d638192fa4a305dd48f
parentf81bcc78fb1aa5475bbe54907ff82199fc031521 (diff)
downloadtmwa-f593049cd8286f48497782d8bc0afe787724ad5d.tar.gz
tmwa-f593049cd8286f48497782d8bc0afe787724ad5d.tar.bz2
tmwa-f593049cd8286f48497782d8bc0afe787724ad5d.tar.xz
tmwa-f593049cd8286f48497782d8bc0afe787724ad5d.zip
Add third gender to account
Add Gender to char Make gear work proper with new gender Enable legacy clients to use account gender
-rw-r--r--src/admin/ladmin.cpp14
-rw-r--r--src/ast/item_test.cpp2
-rw-r--r--src/char/char.cpp73
-rw-r--r--src/login/login.cpp14
-rw-r--r--src/map/atcommand.cpp34
-rw-r--r--src/map/chrif.cpp5
-rw-r--r--src/map/pc.cpp32
-rw-r--r--src/mmo/enums.hpp9
-rwxr-xr-xtools/protocol.py7
9 files changed, 124 insertions, 66 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..bc759d0 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;
@@ -1984,6 +1979,8 @@ void parse_frommap(Session *ms)
break;
}
case 5: // changesex
+ case 6: // changesex
+ case 7: // changesex
{
if (!acc
|| isGM(acc).overwhelms(isGM(ck->account_id)))
@@ -1992,7 +1989,19 @@ void parse_frommap(Session *ms)
{ // 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);
+ switch (operation)
+ {
+ case 5:
+ fixed_27.sex = SEX::FEMALE;
+ break;
+ case 6:
+ fixed_27.sex = SEX::MALE;
+ break;
+ case 7:
+ fixed_27.sex = SEX::NEUTRAL;
+ break;
+ }
+ send_fpacket<0x2727, 7>(login_session, fixed_27);
}
else
fixed_0f.error = 3;
@@ -2437,7 +2446,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..4ab0773 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;
@@ -1181,7 +1179,7 @@ void parse_fromchar(Session *s)
case 0x2727: // Change of sex (sex is reversed)
{
Packet_Fixed<0x2727> fixed;
- rv = recv_fpacket<0x2727, 6>(s, fixed);
+ rv = recv_fpacket<0x2727, 7>(s, fixed);
if (rv != RecvResult::Complete)
break;
@@ -1192,11 +1190,7 @@ void parse_fromchar(Session *s)
if (ad.account_id == acc)
{
{
- SEX sex;
- if (ad.sex == SEX::FEMALE)
- sex = SEX::MALE;
- else
- sex = SEX::FEMALE;
+ SEX sex = fixed.sex;
LOGIN_LOG("Char-server '%s': Sex change (account: %d, new sex %c, ip: %s).\n"_fmt,
server[id].name, acc,
sex_to_char(sex),
@@ -1504,7 +1498,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 +1759,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 4dd80bb..11ca1a3 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/pc.cpp b/src/map/pc.cpp
index 254ecb5..8a5127d 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;
@@ -2129,7 +2129,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;
@@ -3493,7 +3493,33 @@ 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());
+ int operation;
+ switch (val)
+ {
+ case 0:
+ sd->sex = sd->status.sex = SEX::FEMALE;
+ operation = 5;
+ break;
+ case 1:
+ sd->sex = sd->status.sex = SEX::MALE;
+ operation = 6;
+ break;
+ default:
+ sd->sex = sd->status.sex = SEX::NEUTRAL;
+ operation = 7;
+ break;
+ }
+ for (IOff0 j : IOff0::iter())
+ {
+ if (sd->status.inventory[j].nameid
+ && bool(sd->status.inventory[j].equip))
+ pc_unequipitem(sd, j, CalcStatus::LATER);
+ }
+ pc_calcstatus(sd, 0);
+ chrif_save(sd);
+ sd->login_id1++;
+ clif_fixpcpos(sd);
+ chrif_char_ask_name(AccountId(), sd->status_key.name, operation, HumanTimeDiff());
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/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='''