mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-04-17 09:33:51 +00:00
Add nonbinary gender support with pronoun system and server compatibility
Extends gender system beyond WoW's binary male/female to support nonbinary characters with proper they/them pronouns. Implements client-side gender mapping (nonbinary→male) for 3.3.5a server compatibility while preserving player identity through local config persistence. Adds pronoun placeholders ($p/$o/$s/$S) and three-option gender text parsing ($g<male>:<female>:<nonbinary>;) for inclusive quest and dialog text.
This commit is contained in:
parent
28aa88608f
commit
0071c24713
10 changed files with 421 additions and 32 deletions
|
|
@ -88,50 +88,54 @@ const char* getGenderName(Gender gender) {
|
|||
switch (gender) {
|
||||
case Gender::MALE: return "Male";
|
||||
case Gender::FEMALE: return "Female";
|
||||
case Gender::NONBINARY: return "Nonbinary";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
std::string getPlayerModelPath(Race race, Gender gender) {
|
||||
// For nonbinary, default to male model (can be extended later for model selection)
|
||||
bool useFemale = (gender == Gender::FEMALE);
|
||||
|
||||
switch (race) {
|
||||
case Race::HUMAN:
|
||||
return gender == Gender::FEMALE
|
||||
return useFemale
|
||||
? "Character\\Human\\Female\\HumanFemale.m2"
|
||||
: "Character\\Human\\Male\\HumanMale.m2";
|
||||
case Race::ORC:
|
||||
return gender == Gender::FEMALE
|
||||
return useFemale
|
||||
? "Character\\Orc\\Female\\OrcFemale.m2"
|
||||
: "Character\\Orc\\Male\\OrcMale.m2";
|
||||
case Race::DWARF:
|
||||
return gender == Gender::FEMALE
|
||||
return useFemale
|
||||
? "Character\\Dwarf\\Female\\DwarfFemale.m2"
|
||||
: "Character\\Dwarf\\Male\\DwarfMale.m2";
|
||||
case Race::NIGHT_ELF:
|
||||
return gender == Gender::FEMALE
|
||||
return useFemale
|
||||
? "Character\\NightElf\\Female\\NightElfFemale.m2"
|
||||
: "Character\\NightElf\\Male\\NightElfMale.m2";
|
||||
case Race::UNDEAD:
|
||||
return gender == Gender::FEMALE
|
||||
return useFemale
|
||||
? "Character\\Scourge\\Female\\ScourgeFemale.m2"
|
||||
: "Character\\Scourge\\Male\\ScourgeMale.m2";
|
||||
case Race::TAUREN:
|
||||
return gender == Gender::FEMALE
|
||||
return useFemale
|
||||
? "Character\\Tauren\\Female\\TaurenFemale.m2"
|
||||
: "Character\\Tauren\\Male\\TaurenMale.m2";
|
||||
case Race::GNOME:
|
||||
return gender == Gender::FEMALE
|
||||
return useFemale
|
||||
? "Character\\Gnome\\Female\\GnomeFemale.m2"
|
||||
: "Character\\Gnome\\Male\\GnomeMale.m2";
|
||||
case Race::TROLL:
|
||||
return gender == Gender::FEMALE
|
||||
return useFemale
|
||||
? "Character\\Troll\\Female\\TrollFemale.m2"
|
||||
: "Character\\Troll\\Male\\TrollMale.m2";
|
||||
case Race::BLOOD_ELF:
|
||||
return gender == Gender::FEMALE
|
||||
return useFemale
|
||||
? "Character\\BloodElf\\Female\\BloodElfFemale.m2"
|
||||
: "Character\\BloodElf\\Male\\BloodElfMale.m2";
|
||||
case Race::DRAENEI:
|
||||
return gender == Gender::FEMALE
|
||||
return useFemale
|
||||
? "Character\\Draenei\\Female\\DraeneiFemale.m2"
|
||||
: "Character\\Draenei\\Male\\DraeneiMale.m2";
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -5924,6 +5924,7 @@ void GameHandler::saveCharacterConfig() {
|
|||
}
|
||||
|
||||
out << "character_guid=" << playerGuid << "\n";
|
||||
out << "gender=" << static_cast<int>(ch->gender) << "\n";
|
||||
for (int i = 0; i < ACTION_BAR_SLOTS; i++) {
|
||||
out << "action_bar_" << i << "_type=" << static_cast<int>(actionBar[i].type) << "\n";
|
||||
out << "action_bar_" << i << "_id=" << actionBar[i].id << "\n";
|
||||
|
|
@ -5943,6 +5944,7 @@ void GameHandler::loadCharacterConfig() {
|
|||
std::array<int, ACTION_BAR_SLOTS> types{};
|
||||
std::array<uint32_t, ACTION_BAR_SLOTS> ids{};
|
||||
bool hasSlots = false;
|
||||
int savedGender = -1;
|
||||
|
||||
std::string line;
|
||||
while (std::getline(in, line)) {
|
||||
|
|
@ -5953,6 +5955,8 @@ void GameHandler::loadCharacterConfig() {
|
|||
|
||||
if (key == "character_guid") {
|
||||
try { savedGuid = std::stoull(val); } catch (...) {}
|
||||
} else if (key == "gender") {
|
||||
try { savedGender = std::stoi(val); } catch (...) {}
|
||||
} else if (key.rfind("action_bar_", 0) == 0) {
|
||||
// Parse action_bar_N_type or action_bar_N_id
|
||||
size_t firstUnderscore = 11; // length of "action_bar_"
|
||||
|
|
@ -5980,6 +5984,17 @@ void GameHandler::loadCharacterConfig() {
|
|||
return;
|
||||
}
|
||||
|
||||
// Apply saved gender (allows nonbinary to persist even though server only stores male/female)
|
||||
if (savedGender >= 0 && savedGender <= 2) {
|
||||
for (auto& character : characters) {
|
||||
if (character.guid == playerGuid) {
|
||||
character.gender = static_cast<Gender>(savedGender);
|
||||
LOG_INFO("Applied saved gender: ", getGenderName(character.gender));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasSlots) {
|
||||
for (int i = 0; i < ACTION_BAR_SLOTS; i++) {
|
||||
actionBar[i].type = static_cast<ActionBarSlot::Type>(types[i]);
|
||||
|
|
|
|||
|
|
@ -257,10 +257,13 @@ const char* getAuthResultString(AuthResult result) {
|
|||
network::Packet CharCreatePacket::build(const CharCreateData& data) {
|
||||
network::Packet packet(static_cast<uint16_t>(Opcode::CMSG_CHAR_CREATE));
|
||||
|
||||
// Convert nonbinary gender to server-compatible value (servers only support male/female)
|
||||
Gender serverGender = toServerGender(data.gender);
|
||||
|
||||
packet.writeString(data.name); // null-terminated name
|
||||
packet.writeUInt8(static_cast<uint8_t>(data.race));
|
||||
packet.writeUInt8(static_cast<uint8_t>(data.characterClass));
|
||||
packet.writeUInt8(static_cast<uint8_t>(data.gender));
|
||||
packet.writeUInt8(static_cast<uint8_t>(serverGender));
|
||||
packet.writeUInt8(data.skin);
|
||||
packet.writeUInt8(data.face);
|
||||
packet.writeUInt8(data.hairStyle);
|
||||
|
|
@ -272,6 +275,7 @@ network::Packet CharCreatePacket::build(const CharCreateData& data) {
|
|||
" race=", static_cast<int>(data.race),
|
||||
" class=", static_cast<int>(data.characterClass),
|
||||
" gender=", static_cast<int>(data.gender),
|
||||
" (server gender=", static_cast<int>(serverGender), ")",
|
||||
" skin=", static_cast<int>(data.skin),
|
||||
" face=", static_cast<int>(data.face),
|
||||
" hair=", static_cast<int>(data.hairStyle),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue