mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-02-20 08:14:55 -05:00
Nonbinary characters can now choose between masculine and feminine body types in character creation, with real-time preview updates and full appearance customization. Body type preference is saved to character config and persists across sessions. Also reduces character preview drag-to-rotate sensitivity from 0.5 to 0.2 for better control.
182 lines
4.6 KiB
C++
182 lines
4.6 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
namespace wowee {
|
|
namespace game {
|
|
|
|
/**
|
|
* Race IDs (WoW 3.3.5a)
|
|
*/
|
|
enum class Race : uint8_t {
|
|
HUMAN = 1,
|
|
ORC = 2,
|
|
DWARF = 3,
|
|
NIGHT_ELF = 4,
|
|
UNDEAD = 5,
|
|
TAUREN = 6,
|
|
GNOME = 7,
|
|
TROLL = 8,
|
|
GOBLIN = 9,
|
|
BLOOD_ELF = 10,
|
|
DRAENEI = 11
|
|
};
|
|
|
|
/**
|
|
* Class IDs (WoW 3.3.5a)
|
|
*/
|
|
enum class Class : uint8_t {
|
|
WARRIOR = 1,
|
|
PALADIN = 2,
|
|
HUNTER = 3,
|
|
ROGUE = 4,
|
|
PRIEST = 5,
|
|
DEATH_KNIGHT = 6,
|
|
SHAMAN = 7,
|
|
MAGE = 8,
|
|
WARLOCK = 9,
|
|
DRUID = 11
|
|
};
|
|
|
|
/**
|
|
* Gender IDs
|
|
*/
|
|
enum class Gender : uint8_t {
|
|
MALE = 0,
|
|
FEMALE = 1,
|
|
NONBINARY = 2
|
|
};
|
|
|
|
/**
|
|
* Pronoun set for text substitution
|
|
*/
|
|
struct Pronouns {
|
|
std::string subject; // he/she/they
|
|
std::string object; // him/her/them
|
|
std::string possessive; // his/her/their
|
|
std::string possessiveP; // his/hers/theirs
|
|
|
|
static Pronouns forGender(Gender gender) {
|
|
switch (gender) {
|
|
case Gender::MALE:
|
|
return {"he", "him", "his", "his"};
|
|
case Gender::FEMALE:
|
|
return {"she", "her", "her", "hers"};
|
|
case Gender::NONBINARY:
|
|
return {"they", "them", "their", "theirs"};
|
|
default:
|
|
return {"they", "them", "their", "theirs"};
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Convert gender to server-compatible value (WoW 3.3.5a only supports binary genders)
|
|
* Nonbinary is mapped to MALE for server communication while preserving client-side identity
|
|
*/
|
|
inline Gender toServerGender(Gender gender) {
|
|
return (gender == Gender::FEMALE) ? Gender::FEMALE : Gender::MALE;
|
|
}
|
|
|
|
/**
|
|
* Equipment item data
|
|
*/
|
|
struct EquipmentItem {
|
|
uint32_t displayModel; // Display model ID
|
|
uint8_t inventoryType; // Inventory slot type
|
|
uint32_t enchantment; // Enchantment/effect ID
|
|
|
|
bool isEmpty() const { return displayModel == 0; }
|
|
};
|
|
|
|
/**
|
|
* Pet data (optional)
|
|
*/
|
|
struct PetData {
|
|
uint32_t displayModel; // Pet display model ID
|
|
uint32_t level; // Pet level
|
|
uint32_t family; // Pet family ID
|
|
|
|
bool exists() const { return displayModel != 0; }
|
|
};
|
|
|
|
/**
|
|
* Complete character data from SMSG_CHAR_ENUM
|
|
*/
|
|
struct Character {
|
|
// Identity
|
|
uint64_t guid; // Character GUID (unique identifier)
|
|
std::string name; // Character name
|
|
|
|
// Basics
|
|
Race race; // Character race
|
|
Class characterClass; // Character class (renamed from 'class' keyword)
|
|
Gender gender; // Character gender
|
|
bool useFemaleModel = false; // For nonbinary: body type preference (client-side only)
|
|
uint8_t level; // Character level (1-80)
|
|
|
|
// Appearance
|
|
uint32_t appearanceBytes; // Custom appearance (skin, hair color, hair style, face)
|
|
uint8_t facialFeatures; // Facial features
|
|
|
|
// Location
|
|
uint32_t zoneId; // Current zone ID
|
|
uint32_t mapId; // Current map ID
|
|
float x; // X coordinate
|
|
float y; // Y coordinate
|
|
float z; // Z coordinate
|
|
|
|
// Affiliations
|
|
uint32_t guildId; // Guild ID (0 if no guild)
|
|
|
|
// State
|
|
uint32_t flags; // Character flags (PvP, dead, etc.)
|
|
|
|
// Optional data
|
|
PetData pet; // Pet information (if exists)
|
|
std::vector<EquipmentItem> equipment; // Equipment (23 slots)
|
|
|
|
// Helper methods
|
|
bool hasGuild() const { return guildId != 0; }
|
|
bool hasPet() const { return pet.exists(); }
|
|
};
|
|
|
|
// Race/class combo and appearance range validation (WoW 3.3.5a)
|
|
bool isValidRaceClassCombo(Race race, Class cls);
|
|
uint8_t getMaxSkin(Race race, Gender gender);
|
|
uint8_t getMaxFace(Race race, Gender gender);
|
|
uint8_t getMaxHairStyle(Race race, Gender gender);
|
|
uint8_t getMaxHairColor(Race race, Gender gender);
|
|
uint8_t getMaxFacialFeature(Race race, Gender gender);
|
|
|
|
/**
|
|
* Get human-readable race name
|
|
*/
|
|
const char* getRaceName(Race race);
|
|
|
|
/**
|
|
* Get human-readable class name
|
|
*/
|
|
const char* getClassName(Class characterClass);
|
|
|
|
/**
|
|
* Get human-readable gender name
|
|
*/
|
|
const char* getGenderName(Gender gender);
|
|
|
|
/**
|
|
* Get M2 model path for a given race and gender
|
|
* useFemaleModel allows nonbinary characters to choose body type
|
|
*/
|
|
std::string getPlayerModelPath(Race race, Gender gender, bool useFemaleModel = false);
|
|
|
|
/**
|
|
* Get M2 model path for a character (uses character's body type preference)
|
|
*/
|
|
std::string getPlayerModelPath(const Character& character);
|
|
|
|
} // namespace game
|
|
} // namespace wowee
|