src/server/game/Entities/Player/Player.cpp | 119 +++++++++++++++++++++++++ src/server/game/Entities/Player/Player.h | 1 + src/server/game/Handlers/CharacterHandler.cpp | 11 +++ src/server/game/World/World.cpp | 4 + src/server/game/World/World.h | 2 + src/server/worldserver/worldserver.conf.dist | 21 +++++ 6 files changed, 158 insertions(+) diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 1d04af6..5db0aa3 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -2044,6 +2044,125 @@ bool Player::BuildEnumData(PreparedQueryResult result, WorldPacket* data) return true; } +bool Player::CreateFakeCharacter(WorldPacket* data) +{ + uint32 guid = 0; // GUID + std::string charName; + uint32 charRace; + uint32 charClass; + uint32 charGender; + uint32 charLevel; + uint32 playerBytes1; + uint32 playerBytes2; + + *data << uint64(MAKE_NEW_GUID(guid, 0, HIGHGUID_PLAYER)); // don't touch it + switch(sWorld->getIntConfig(CONFIG_RECOMMENDED_FACTION_SIDE)) + { + case 1: // alliance + { + charName = "Alliance Recommended"; + charRace = 4; // race : night elf + charClass = 1; // class : warrior + charGender = 1; // gender : female + charLevel = 1; // level : 1 + playerBytes1 = 33556231; // used to create display column 1 + playerBytes2 = 33554437; // used to create display column 2 + } + break; + case 2: + { + charName = "Horde Recommended"; + charRace = 10; // race : blood elf + charClass = 4; // class : rogue + charGender = 1; // gender : female + charLevel = 1; // level : 1 + playerBytes1 = 17106692; // used to create display column 1 + playerBytes2 = 33554436; // used to create display column 2 + } + break; + default: + { + charName = "Horde Recommended"; + charRace = 10; // race : blood elf + charClass = 4; // class : rogue + charGender = 1; // gender : female + charLevel = 1; // level : 1 + playerBytes1 = 17106692; // used to create display column 1 + playerBytes2 = 33554436; // used to create display column 2 + } + break; + } + + *data << charName.c_str(); // name + *data << uint8(charRace); // race + *data << uint8(charClass); // class + *data << uint8(charGender); // gender + + *data << uint8(playerBytes1); // skin + *data << uint8(playerBytes1 >> 8); // face + *data << uint8(playerBytes1 >> 16); // hair style + *data << uint8(playerBytes1 >> 24); // hair color + + *data << uint8(playerBytes2 & 0xFF); // facial hair + + *data << uint8(charLevel); // level + *data << uint32(876); // zone + *data << uint32(1); // map + + *data << 0; // x + *data << 0; // y + *data << 0; // z + + *data << uint32(0); // guild id + + *data << uint32(CHARACTER_FLAG_LOCKED_BY_BILLING); // character flags + + *data << uint32(CHAR_CUSTOMIZE_FLAG_NONE); // customize flags + + *data << uint8(0 & AT_LOGIN_FIRST ? 1 : 0); // First login + + *data << uint32(0); // pet display id + *data << uint32(0); // pet level + *data << uint32(0); // pet family + + std::string equipmentTemplate = "0 0 0 0 0 0 0 0 60000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60001 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 "; + + Tokenizer equipment(equipmentTemplate.c_str(), ' '); + for (uint8 slot = 0; slot < INVENTORY_SLOT_BAG_END; ++slot) + { + uint32 visualBase = slot * 2; + uint32 itemId = GetUInt32ValueFromArray(equipment, visualBase); + ItemTemplate const* proto = sObjectMgr->GetItemTemplate(itemId); + if (!proto) + { + *data << uint32(0); + *data << uint8(0); + *data << uint32(0); + continue; + } + + SpellItemEnchantmentEntry const* enchant = NULL; + + uint32 enchants = GetUInt32ValueFromArray(equipment, visualBase + 1); + for (uint8 enchantSlot = PERM_ENCHANTMENT_SLOT; enchantSlot <= TEMP_ENCHANTMENT_SLOT; ++enchantSlot) + { + uint32 enchantId = 0x0000FFFF & (enchants >> enchantSlot*16); + if (!enchantId) + continue; + + enchant = sSpellItemEnchantmentStore.LookupEntry(enchantId); + if (enchant) + break; + } + + *data << uint32(proto->DisplayInfoID); + *data << uint8(proto->InventoryType); + *data << uint32(enchant ? enchant->aura_id : 0); + } + + return true; +} + void Player::ToggleAFK() { ToggleFlag(PLAYER_FLAGS, PLAYER_FLAGS_AFK); diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 1c0fa4e..6f09c04 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1083,6 +1083,7 @@ class Player : public Unit, public GridObject void Update(uint32 time); static bool BuildEnumData(PreparedQueryResult result, WorldPacket* data); + static bool CreateFakeCharacter(WorldPacket* data); void SetInWater(bool apply); diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index 3ba2b32..722f127 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -233,6 +233,17 @@ void WorldSession::HandleCharEnum(PreparedQueryResult result) } while (result->NextRow()); } + else + { + if (sWorld->getBoolConfig(CONFIG_RECOMMENDED_FACTION_ENABLE) && sWorld->getIntConfig(CONFIG_RECOMMENDED_FACTION_SIDE)) + { + if (Player::CreateFakeCharacter(&data)) + { + _legitCharacters.insert(0); + ++num; + } + } + } data.put(0, num); diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 645c14b..a7ac243 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1229,6 +1229,10 @@ void World::LoadConfigSettings(bool reload) m_float_configs[CONFIG_STATS_LIMITS_BLOCK] = ConfigMgr::GetFloatDefault("Stats.Limits.Block", 95.0f); m_float_configs[CONFIG_STATS_LIMITS_CRIT] = ConfigMgr::GetFloatDefault("Stats.Limits.Crit", 95.0f); + // Custom Recommended faction + m_bool_configs[CONFIG_RECOMMENDED_FACTION_ENABLE] = ConfigMgr::GetBoolDefault("Recommended.Faction.Enable", true); // 1 true | 0 false + m_int_configs[CONFIG_RECOMMENDED_FACTION_SIDE] = ConfigMgr::GetIntDefault("Recommended.Faction.Side", 1); // 1 alliance | 2 horde + // call ScriptMgr if we're reloading the configuration if (reload) sScriptMgr->OnConfigLoad(reload); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 12586ed..32c9515 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -160,6 +160,7 @@ enum WorldBoolConfigs CONFIG_UI_QUESTLEVELS_IN_DIALOGS, // Should we add quest levels to the title in the NPC dialogs? CONFIG_EVENT_ANNOUNCE, CONFIG_STATS_LIMITS_ENABLE, + CONFIG_RECOMMENDED_FACTION_ENABLE, BOOL_CONFIG_VALUE_COUNT }; @@ -326,6 +327,7 @@ enum WorldIntConfigs CONFIG_WINTERGRASP_BATTLETIME, CONFIG_WINTERGRASP_NOBATTLETIME, CONFIG_WINTERGRASP_RESTART_AFTER_CRASH, + CONFIG_RECOMMENDED_FACTION_SIDE, INT_CONFIG_VALUE_COUNT }; diff --git a/src/server/worldserver/worldserver.conf.dist b/src/server/worldserver/worldserver.conf.dist index 9577b3d..2ee411f 100644 --- a/src/server/worldserver/worldserver.conf.dist +++ b/src/server/worldserver/worldserver.conf.dist @@ -2791,3 +2791,24 @@ Log.Async.Enable = 0 # ################################################################################################### + +################################################################################################### +# CUSTOM CHARACTER LOGIN SCREEN OPTIONS +# +# Recommended.Faction.Enable +# Description: On first account login, adds a fake character representing a faction side +# Default: 0 - (disable) +# 1 - (Enable) + +Recommended.Faction.Enable = 1 + +# +# Recommended.Faction.Side +# Description: Recommended faction to represent +# Default: 1 - (alliance) +# 2 - (horde) + +Recommended.Faction.Side = 1 + +# +###################################################################################################