From db2fa04439ded43b55ca2e7fdc3509ac2041c9fd Mon Sep 17 00:00:00 2001 From: gumi Date: Sat, 17 Aug 2019 21:34:34 -0400 Subject: add full support for non-binary gender --- src/Makefile.am | 4 ++++ src/echar/char.c | 50 ++++++++++++++++++++++++++++++++++++++++++++--- src/echar/char.h | 2 ++ src/echar/init.c | 1 + src/ecommon/enum/gender.h | 20 +++++++++++++++++++ src/emap/chrif.c | 41 ++++++++++++++++++++++++++++++++++++++ src/emap/chrif.h | 10 ++++++++++ src/emap/clif.c | 18 +++++++++++++++++ src/emap/clif.h | 1 + src/emap/init.c | 3 +++ src/emap/pc.c | 47 ++++++++++++++++++++++++++++++++++++++++++++ src/emap/pc.h | 4 ++++ 12 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 src/ecommon/enum/gender.h create mode 100644 src/emap/chrif.c create mode 100644 src/emap/chrif.h diff --git a/src/Makefile.am b/src/Makefile.am index d3ffbd3..1727ae9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,6 +7,7 @@ CHAR_SRC = echar/char.c \ echar/init.c \ ecommon/config.c \ ecommon/config.h \ + ecommon/enum/gender.h \ ecommon/init.c \ ecommon/init.h \ ecommon/serverversion.h @@ -36,6 +37,8 @@ MAP_SRC = emap/atcommand.c \ emap/battle.h \ emap/battleground.c \ emap/battleground.h \ + emap/chrif.c \ + emap/chrif.h \ emap/clan.c \ emap/clan.h \ emap/clif.c \ @@ -128,6 +131,7 @@ MAP_SRC = emap/atcommand.c \ emap/utils/formatutils.h \ ecommon/config.c \ ecommon/config.h \ + ecommon/enum/gender.h \ ecommon/init.c \ ecommon/init.h \ ecommon/serverversion.h \ diff --git a/src/echar/char.c b/src/echar/char.c index cac3daf..cbaa884 100644 --- a/src/echar/char.c +++ b/src/echar/char.c @@ -21,6 +21,8 @@ #include "plugins/HPMHooking.h" +#include "ecommon/enum/gender.h" + #include "echar/char.h" #include "echar/config.h" @@ -355,10 +357,52 @@ int echar_mmo_gender(const struct char_session_data **sd __attribute__ ((unused) switch (*sex) { case 'M': - return SEX_MALE; + return GENDER_MALE; case 'F': - return SEX_FEMALE; + return GENDER_FEMALE; default: - return 3; // FIXME: this enum has no SEX_OTHER + return GENDER_NONBINARY; + } +} + +// update sql from map to char with the new gender +// XXX: this whole hook is only to change one line; we might want to change it +// upstream in hercules +int echar_changecharsex(int *char_idPtr, int *sexPtr) +{ + int char_id = *char_idPtr; + int sex = *sexPtr; + + int account_id = 0; + char *data; + + // get character data + if (SQL_ERROR == SQL->Query(inter->sql_handle, "SELECT `account_id` FROM `char` WHERE `char_id` = '%d'", char_id)) { + Sql_ShowDebug(inter->sql_handle); + hookStop(); + return 1; + } + + if (SQL->NumRows(inter->sql_handle) != 1 || SQL_ERROR == SQL->NextRow(inter->sql_handle)) { + SQL->FreeResult(inter->sql_handle); + hookStop(); + return 1; } + + SQL->GetData(inter->sql_handle, 0, &data, NULL); account_id = atoi(data); + SQL->FreeResult(inter->sql_handle); + + if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `char` SET `sex` = '%c' WHERE `char_id` = '%d'", sex == SEX_MALE ? 'M' : (sex == SEX_FEMALE ? 'F' : 'U'), char_id)) { + Sql_ShowDebug(inter->sql_handle); + hookStop(); + return 1; + } + + // disconnect player if online on char-server + chr->disconnect_player(account_id); + + // notify all mapservers about this change + chr->changesex(account_id, sex); + hookStop(); + return 0; } diff --git a/src/echar/char.h b/src/echar/char.h index 9a59a44..534b075 100644 --- a/src/echar/char.h +++ b/src/echar/char.h @@ -31,4 +31,6 @@ void echat_send_login_serverexit(const int code); int echar_mmo_gender(const struct char_session_data **, const struct mmo_charstatus **, char *sex); +int echar_changecharsex(int *char_idPtr, int *sexPtr); + #endif // EVOL_CHAR_CHAR diff --git a/src/echar/init.c b/src/echar/init.c index 1c0ba48..f58802c 100644 --- a/src/echar/init.c +++ b/src/echar/init.c @@ -68,6 +68,7 @@ HPExport void plugin_init (void) // non-binary gender stuff: addHookPre(chr, mmo_gender, echar_mmo_gender); + addHookPre(chr, changecharsex, echar_changecharsex); addHookPost(chr, send_HC_ACK_CHARINFO_PER_PAGE, echar_send_HC_ACK_CHARINFO_PER_PAGE_post); addHookPost(chr, mmo_char_send_characters, echar_mmo_char_send_characters_post); diff --git a/src/ecommon/enum/gender.h b/src/ecommon/enum/gender.h new file mode 100644 index 0000000..039ca04 --- /dev/null +++ b/src/ecommon/enum/gender.h @@ -0,0 +1,20 @@ +// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// Copyright (c) 2014 - 2020 Evol developers + +#ifndef EVOL_ENUM_GENDER +#define EVOL_ENUM_GENDER + +#include "common/mmo.h" + +/** + * identical to SEX_ but also includes nonbinary + */ +typedef enum Gender +{ + GENDER_FEMALE = SEX_FEMALE, + GENDER_MALE = SEX_MALE, + __UNUSED_GENDER_SERVER = SEX_SERVER, + GENDER_NONBINARY, +} Gender; + +#endif // EVOL_ENUM_GENDER diff --git a/src/emap/chrif.c b/src/emap/chrif.c new file mode 100644 index 0000000..91f4aa7 --- /dev/null +++ b/src/emap/chrif.c @@ -0,0 +1,41 @@ +// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// Copyright (c) 2014 - 2019 Evol developers + +#include "common/hercules.h" + +#include +#include +#include + +#include "common/HPMi.h" +#include "common/nullpo.h" +#include "common/socket.h" +#include "map/chrif.h" +#include "map/pc.h" + +#include "emap/chrif.h" + +#include "plugins/HPMHooking.h" + +/** + * save sex change + */ +bool echrif_changesex(TBL_PC **sdPtr, bool *change_account __attribute__ ((unused))) +{ + const TBL_PC *sd = *sdPtr; + nullpo_retr(false, sd); + + if (!chrif->isconnected()) + return false; + + WFIFOHEAD(chrif->fd, 44); + WFIFOW(chrif->fd, 0) = 0x2b0e; + WFIFOL(chrif->fd, 2) = sd->status.account_id; + safestrncpy(WFIFOP(chrif->fd, 6), sd->status.name, NAME_LENGTH); + WFIFOW(chrif->fd, 30) = CHAR_ASK_NAME_CHANGECHARSEX; + WFIFOB(chrif->fd, 32) = sd->status.sex; + WFIFOSET(chrif->fd, 44); + + hookStop(); + return true; +} diff --git a/src/emap/chrif.h b/src/emap/chrif.h new file mode 100644 index 0000000..f0a9790 --- /dev/null +++ b/src/emap/chrif.h @@ -0,0 +1,10 @@ +// Copyright (c) Copyright (c) Hercules Dev Team, licensed under GNU GPL. +// Copyright (c) 2014 - 2019 Evol developers + +#ifndef EVOL_MAP_CHRIF +#define EVOL_MAP_CHRIF + +bool echrif_changesex(TBL_PC **sdPtr, + bool *change_account); + +#endif // EVOL_MAP_CHRIF diff --git a/src/emap/clif.c b/src/emap/clif.c index 9bdb6b8..25cbd31 100644 --- a/src/emap/clif.c +++ b/src/emap/clif.c @@ -17,6 +17,7 @@ #include "common/random.h" #include "common/timer.h" #include "map/battle.h" +#include "map/chrif.h" #include "map/elemental.h" #include "map/homunculus.h" #include "map/guild.h" @@ -1541,3 +1542,20 @@ void eclif_rodex_icon_pre(int *fdPtr, return; } } + +void eclif_force_charselect(struct map_session_data *sd) +{ + int fd = sd->fd; + + /* Rovert's Prevent logout option - Fixed [Valaris] */ + if (!sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] + && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC__INVISIBILITY] && !sd->sc.data[SC_SUHIDE] + && (!battle->bc->prevent_logout || DIFF_TICK(timer->gettick(), sd->canlog_tick) > battle->bc->prevent_logout) + ) { + //Send to char-server for character selection. + chrif->charselectreq(sd, sockt->session[fd]->client_addr); + } else { + // GM-kick the player + clif->GM_kick(NULL, sd); + } +} diff --git a/src/emap/clif.h b/src/emap/clif.h index b4f384d..13ce09e 100644 --- a/src/emap/clif.h +++ b/src/emap/clif.h @@ -94,4 +94,5 @@ void eclif_parse_NpcStringInput(int fd, struct map_session_data* sd) __attribute__((nonnull (2))); void eclif_rodex_icon_pre(int *fdPtr, bool *showPtr); +void eclif_force_charselect(struct map_session_data *sd); #endif // EVOL_MAP_CLIF diff --git a/src/emap/init.c b/src/emap/init.c index 6bfdfa7..c2699dd 100644 --- a/src/emap/init.c +++ b/src/emap/init.c @@ -53,6 +53,7 @@ #include "emap/atcommand.h" #include "emap/battle.h" #include "emap/battleground.h" +#include "emap/chrif.h" #include "emap/clan.h" #include "emap/clif.h" #include "emap/config.h" @@ -266,6 +267,7 @@ HPExport void plugin_init (void) addHookPre(pc, can_Adopt, epc_can_Adopt_pre); addHookPre(pc, adoption, epc_adoption_pre); addHookPre(pc, readparam, epc_readparam_pre); + addHookPre(pc, setparam, epc_setparam_pre); addHookPre(pc, setregistry, epc_setregistry_pre); addHookPre(pc, equipitem_pos, epc_equipitem_pos_pre); addHookPre(pc, unequipitem_pos, epc_unequipitem_pos_pre); @@ -344,6 +346,7 @@ HPExport void plugin_init (void) addHookPre(status, calc_pc_additional, estatus_calc_pc_additional_pre); addHookPre(status, calc_pc_recover_hp, estatus_calc_pc_recover_hp_pre); addHookPre(homun, gainexp, ehomunculus_gainexp_pre); + addHookPre(chrif, changesex, echrif_changesex); addHookPost(battle, calc_weapon_attack, ebattle_calc_weapon_attack_post); addHookPost(battle, calc_magic_attack, ebattle_calc_weapon_attack_post); diff --git a/src/emap/pc.c b/src/emap/pc.c index 011743e..5a8b527 100644 --- a/src/emap/pc.c +++ b/src/emap/pc.c @@ -25,6 +25,8 @@ #include "plugins/HPMHooking.h" +#include "ecommon/enum/gender.h" + #include "emap/clif.h" #include "emap/pc.h" #include "emap/send.h" @@ -53,6 +55,51 @@ int64 epc_readparam_pre(const TBL_PC **sdPtr, return 0; } +/** + * change sex without the complicated RO stuff + * @return 1 on success +**/ +static int epc_changesex(TBL_PC *sd, unsigned char sex) +{ + // because this is evol we do not any of the bulky sex change stuff + // since every gender can use every job and every item + switch (sex) { + case GENDER_FEMALE: + case GENDER_MALE: + case GENDER_NONBINARY: + sd->status.sex = sex; + break; + default: + return 0; + } + + // FIXME: there's no way to tell manaplus we changed gender! + //clif->updatestatus(sd, SP_SEX); + + // FIXME: show gender change to other players: + //pc->stop_following(sd); // fixpos + + // TODO: add a packet to manaplus that calls dstBeing->setGender() in ea/beingrecv or modify an existing packet and bump the protocol version + + // tell char server we changed sex + chrif->changesex(sd, 0); + + // XXX: we kick to the char server because we currently can't update in manaplus + eclif_force_charselect(sd); + return 1; +} + +int epc_setparam_pre(TBL_PC **sd, int *type, int64 *val) +{ + if (*type == SP_SEX) + { + int ret = epc_changesex(*sd, *val); + hookStop(); + return ret; + } + return 1; +} + int epc_setregistry_pre(TBL_PC **sdPtr, int64 *reg, int *val) diff --git a/src/emap/pc.h b/src/emap/pc.h index d5c59bf..db1a912 100644 --- a/src/emap/pc.h +++ b/src/emap/pc.h @@ -12,6 +12,10 @@ enum VarConst int64 epc_readparam_pre(const TBL_PC **sdPtr, int *type); +int epc_setparam_pre(TBL_PC **sdPtr, + int *type, + int64 *val); + int epc_setregistry_pre(TBL_PC **sdPtr, int64 *reg, int *val); -- cgit v1.2.3-60-g2f50