#include "glue/CCharacterCreation.hpp" #include "component/CCharacterComponent.hpp" #include "component/Types.hpp" #include "db/Db.hpp" #include "glue/CGlueLoading.hpp" #include "model/CM2Shared.hpp" #include "object/client/Player_C.hpp" #include "ui/simple/CSimpleModelFFX.hpp" CCharacterComponent* CCharacterCreation::s_character; CSimpleModelFFX* CCharacterCreation::s_charCustomizeFrame; float CCharacterCreation::s_charFacing; TSFixedArray CCharacterCreation::s_classes; int32_t CCharacterCreation::s_existingCharacterIndex; int32_t CCharacterCreation::s_raceIndex; TSGrowableArray CCharacterCreation::s_races; int32_t CCharacterCreation::s_selectedClassID; void CCharacterCreation::CalcClasses(int32_t raceID) { uint32_t classCount = 0; for (int32_t i = 0; i < g_charBaseInfoDB.GetNumRecords(); i++) { auto infoRec = g_charBaseInfoDB.GetRecordByIndex(i); if (infoRec->m_raceID == raceID) { classCount++; } } CCharacterCreation::s_classes.SetCount(classCount); uint32_t classIndex = 0; for (int32_t i = 0; i < g_charBaseInfoDB.GetNumRecords(); i++) { auto infoRec = g_charBaseInfoDB.GetRecordByIndex(i); if (infoRec->m_raceID != raceID) { continue; } auto classRec = g_chrClassesDB.GetRecord(infoRec->m_classID); CCharacterCreation::s_classes[classIndex++] = classRec; } } void CCharacterCreation::CreateComponent(ComponentData* data, bool randomize) { auto modelData = Player_C_GetModelName(data->raceID, data->sexID); if (!modelData || !modelData->m_modelName) { return; } auto existingComponent = CCharacterCreation::s_character; if (existingComponent) { auto model = existingComponent->m_data.model; if (model->m_attachParent) { model->DetachFromParent(); } // TODO CCharacterComponent::FreeComponent(existingComponent); } CCharacterCreation::s_character = CCharacterComponent::AllocComponent(); auto scene = CCharacterCreation::s_charCustomizeFrame->GetScene(); auto model = scene->CreateModel(modelData->m_modelName, 0); data->model = model; if (!model) { return; } // TODO lighting data->model->SetBoneSequence(-1, 0, 0, 0, 1.0f, 1, 1); data->flags |= 0x2; CCharacterCreation::s_character->Init(data, nullptr); if (randomize) { // TODO select random variations } // TODO track previous variations // TODO set facing CCharacterCreation::Dress(); CCharacterCreation::s_character->RenderPrep(0); if (CCharacterCreation::s_charCustomizeFrame->m_model) { model->AttachToParent(CCharacterCreation::s_charCustomizeFrame->m_model, 0, nullptr, 0); } } void CCharacterCreation::Dress() { // TODO } int32_t CCharacterCreation::GetRandomClassID() { // TODO return 1; } void CCharacterCreation::GetRandomRaceAndSex(ComponentData* data) { // TODO data->raceID = 1; data->sexID = UNITSEX_MALE; } void CCharacterCreation::Initialize() { CCharacterCreation::s_charFacing = 0.0f; CCharacterCreation::s_charCustomizeFrame = nullptr; CCharacterCreation::s_existingCharacterIndex = -1; CCharacterCreation::s_races.SetCount(0); // TODO enum or define for faction sides for (int32_t side = 0; side < 2; side++) { for (int32_t race = 0; race < g_chrRacesDB.GetNumRecords(); race++) { auto raceRec = g_chrRacesDB.GetRecordByIndex(race); // TODO NPCOnly? if (raceRec->m_flags & 0x1) { continue; } auto factionTemplateRec = g_factionTemplateDB.GetRecord(raceRec->m_factionID); for (int32_t group = 0; group < g_factionGroupDB.GetNumRecords(); group++) { auto factionGroupRec = g_factionGroupDB.GetRecordByIndex(group); if (!factionGroupRec || !factionGroupRec->m_maskID) { continue; } bool templateMatch = (1 << factionGroupRec->m_maskID) & factionTemplateRec->m_factionGroup; if (!templateMatch) { continue; } bool sideMatch = (side == 0 && !SStrCmpI(factionGroupRec->m_internalName, "Alliance")) || (side == 1 && !SStrCmpI(factionGroupRec->m_internalName, "Horde")); if (!sideMatch) { continue; } // Race is playable and part of a faction aligned to either Alliance or Horde *CCharacterCreation::s_races.New() = raceRec->m_ID; } } } } bool CCharacterCreation::IsClassValid(int32_t classID) { for (int32_t i = 0; i < CCharacterCreation::s_classes.Count(); i++) { auto classRec = CCharacterCreation::s_classes[i]; if (classRec->m_ID == classID) { return true; } } return false; } void CCharacterCreation::ResetCharCustomizeInfo() { if (!CCharacterCreation::s_charCustomizeFrame) { return; } CCharacterCreation::s_existingCharacterIndex = -1; auto model = CCharacterCreation::s_charCustomizeFrame->m_model; if (model) { model->DetachAllChildrenById(0); } ComponentData data = {}; CCharacterCreation::GetRandomRaceAndSex(&data); CCharacterCreation::CalcClasses(data.raceID); CCharacterCreation::CreateComponent(&data, true); CCharacterCreation::SetSelectedClass(CCharacterCreation::GetRandomClassID()); data.classID = CCharacterCreation::s_selectedClassID; CCharacterCreation::s_raceIndex = -1; for (int32_t i = 0; i < CCharacterCreation::s_races.Count(); i++) { auto raceID = CCharacterCreation::s_races[i]; if (CCharacterCreation::s_character->m_data.raceID == raceID) { CCharacterCreation::s_raceIndex = i; break; } } // TODO name gen stuff CGlueLoading::StartLoad(CCharacterCreation::s_character, true); } void CCharacterCreation::SetCharCustomizeModel(const char* filename) { if (!CCharacterCreation::s_charCustomizeFrame || !filename || !*filename) { return; } auto existingModel = CCharacterCreation::s_charCustomizeFrame->m_model; if (existingModel && !SStrCmpI(existingModel->m_shared->m_filePath, filename)) { return; } CCharacterCreation::s_charCustomizeFrame->SetModel(filename); auto customizeModel = CCharacterCreation::s_charCustomizeFrame->m_model; // TODO inlined? if (customizeModel) { // TODO lighting stuff customizeModel->IsDrawable(1, 1); } // TODO inlined? if (customizeModel) { auto characterModel = CCharacterCreation::s_character->m_data.model; if (characterModel) { characterModel->AttachToParent(customizeModel, 0, nullptr, 0); } } } void CCharacterCreation::SetSelectedClass(int32_t classID) { if (!CCharacterCreation::IsClassValid(classID)) { return; } CCharacterCreation::s_selectedClassID = classID; ComponentData data = {}; data.raceID = CCharacterCreation::s_character->m_data.raceID; data.sexID = CCharacterCreation::s_character->m_data.sexID; data.classID = classID; data.skinColorID = CCharacterCreation::s_character->m_data.skinColorID; data.hairStyleID = CCharacterCreation::s_character->m_data.hairStyleID; data.hairColorID = CCharacterCreation::s_character->m_data.hairColorID; data.facialHairStyleID = CCharacterCreation::s_character->m_data.facialHairStyleID; data.faceID = CCharacterCreation::s_character->m_data.faceID; // TODO CCharacterComponent::ValidateComponentData(&data, 0); CCharacterCreation::CreateComponent(&data, false); CCharacterCreation::Dress(); CGlueLoading::StartLoad(CCharacterCreation::s_character, true); }