summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am4
-rw-r--r--src/echar/char.c50
-rw-r--r--src/echar/char.h2
-rw-r--r--src/echar/init.c1
-rw-r--r--src/ecommon/enum/gender.h20
-rw-r--r--src/emap/chrif.c41
-rw-r--r--src/emap/chrif.h10
-rw-r--r--src/emap/clif.c18
-rw-r--r--src/emap/clif.h1
-rw-r--r--src/emap/init.c3
-rw-r--r--src/emap/pc.c47
-rw-r--r--src/emap/pc.h4
12 files changed, 198 insertions, 3 deletions
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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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);