#include "glue/CCharacterCreationScript.hpp" #include "client/ClientServices.hpp" #include "component/CCharacterComponent.hpp" #include "db/Db.hpp" #include "glue/CCharacterCreation.hpp" #include "net/Connection.hpp" #include "object/client/CGUnit_C.hpp" #include "ui/FrameScript.hpp" #include "ui/Types.hpp" #include "ui/game/CGLookingForGroup.hpp" #include "ui/simple/CSimpleModelFFX.hpp" #include "util/Lua.hpp" #include "util/Unimplemented.hpp" #include int32_t Script_SetCharCustomizeFrame(lua_State* L) { if (!lua_isstring(L, 1)) { luaL_error(L, "Usage: SetCharCustomizeFrame(\"frameName\")"); return 0; } auto type = CSimpleModel::GetObjectType(); auto frame = static_cast(CScriptObject::GetScriptObjectByName(lua_tostring(L, 1), type)); if (frame) { CCharacterCreation::s_charCustomizeFrame = frame; } return 0; } int32_t Script_SetCharCustomizeBackground(lua_State* L) { if (!lua_isstring(L, 1)) { luaL_error(L, "Usage: SetCharCustomizeBackground(\"filename\")"); return 0; } auto filename = lua_tostring(L, 1); CCharacterCreation::SetCharCustomizeModel(filename); return 0; } int32_t Script_ResetCharCustomize(lua_State* L) { CCharacterCreation::ResetCharCustomizeInfo(); return 0; } int32_t Script_GetNameForRace(lua_State* L) { auto raceRec = g_chrRacesDB.GetRecord(CCharacterCreation::s_character->m_data.raceID); auto displayName = CGUnit_C::GetDisplayRaceNameFromRecord( raceRec, static_cast(CCharacterCreation::s_character->m_data.sexID), nullptr ); if (raceRec && displayName) { lua_pushstring(L, displayName); lua_pushstring(L, raceRec->m_clientFileString); } else { lua_pushnil(L); lua_pushnil(L); } return 2; } int32_t Script_GetFactionForRace(lua_State* L) { if (!lua_isnumber(L, 1)) { luaL_error(L, "Usage: GetFactionForRace(index)"); return 0; } auto raceIndex = static_cast(lua_tonumber(L, 1)) - 1; auto raceID = raceIndex >= CCharacterCreation::s_races.Count() ? 0 : CCharacterCreation::s_races[raceIndex]; auto raceRec = g_chrRacesDB.GetRecord(raceID); if (!raceRec) { lua_pushnil(L); lua_pushnil(L); return 2; } auto factionTemplateRec = g_factionTemplateDB.GetRecord(raceRec->m_factionID); if (!factionTemplateRec) { lua_pushnil(L); lua_pushnil(L); return 2; } FactionGroupRec* matchingGroup = nullptr; for (auto 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) { matchingGroup = factionGroupRec; break; } } if (matchingGroup) { lua_pushstring(L, matchingGroup->m_name); lua_pushstring(L, matchingGroup->m_internalName); } else { lua_pushnil(L); lua_pushnil(L); } return 2; } int32_t Script_GetAvailableRaces(lua_State* L) { for (int32_t i = 0; i < CCharacterCreation::s_races.Count(); i++) { auto raceID = CCharacterCreation::s_races[i]; auto raceRec = g_chrRacesDB.GetRecord(raceID); auto displayName = CGUnit_C::GetDisplayRaceNameFromRecord( raceRec, static_cast(CCharacterCreation::s_character->m_data.sexID), nullptr ); lua_pushstring(L, displayName); auto clientFileString = raceRec ? raceRec->m_clientFileString : nullptr; lua_pushstring(L, clientFileString); if (raceRec) { int32_t accountExpansion = ClientServices::Connection()->m_accountExpansion; int32_t requiredExpansion = raceRec->m_requiredExpansion; lua_pushnumber(L, accountExpansion >= requiredExpansion); } else { lua_pushnumber(L, 0); } } return CCharacterCreation::s_races.Count() * 3; } int32_t Script_GetAvailableClasses(lua_State* L) { for (int32_t i = 0; i < g_chrClassesDB.GetNumRecords(); i++) { auto classRec = g_chrClassesDB.GetRecordByIndex(i); auto displayName = CGUnit_C::GetDisplayClassNameFromRecord( classRec, static_cast(CCharacterCreation::s_character->m_data.sexID), nullptr ); int32_t accountExpansion = ClientServices::Connection()->m_accountExpansion; int32_t requiredExpansion = classRec->m_requiredExpansion; if (displayName) { lua_pushstring(L, displayName); lua_pushstring(L, classRec->m_filename); lua_pushnumber(L, accountExpansion >= requiredExpansion); } else { lua_pushnil(L); lua_pushnil(L); lua_pushnil(L); } } return g_chrClassesDB.GetNumRecords() * 3; } int32_t Script_GetClassesForRace(lua_State* L) { WHOA_UNIMPLEMENTED(0); } int32_t Script_GetHairCustomization(lua_State* L) { auto raceIndex = CCharacterCreation::s_raceIndex; auto raceID = raceIndex >= CCharacterCreation::s_races.Count() ? 0 : CCharacterCreation::s_races[raceIndex]; auto raceRec = g_chrRacesDB.GetRecord(raceID); if (raceRec) { lua_pushstring(L, raceRec->m_hairCustomization); } else { lua_pushstring(L, "NORMAL"); } return 1; } int32_t Script_GetFacialHairCustomization(lua_State* L) { auto raceIndex = CCharacterCreation::s_raceIndex; auto raceID = raceIndex >= CCharacterCreation::s_races.Count() ? 0 : CCharacterCreation::s_races[raceIndex]; auto raceRec = g_chrRacesDB.GetRecord(raceID); if (raceRec) { lua_pushstring(L, raceRec->m_facialHairCustomization[CCharacterCreation::s_character->m_data.sexID]); } else { lua_pushstring(L, "NORMAL"); } return 1; } int32_t Script_GetSelectedRace(lua_State* L) { lua_pushnumber(L, CCharacterCreation::s_raceIndex + 1); return 1; } int32_t Script_GetSelectedSex(lua_State* L) { lua_pushnumber(L, g_glueFrameScriptGenders[CCharacterCreation::s_character->m_data.sexID]); return 1; } int32_t Script_GetSelectedClass(lua_State* L) { auto classRec = g_chrClassesDB.GetRecord(CCharacterCreation::s_selectedClassID); if (!classRec) { return 0; } auto displayName = CGUnit_C::GetDisplayClassNameFromRecord( classRec, static_cast(CCharacterCreation::s_character->m_data.sexID), nullptr ); lua_pushstring(L, displayName); lua_pushstring(L, classRec->m_filename); int32_t classIndex = 0; for (auto i = 0; i < g_chrClassesDB.GetNumRecords(); i++) { auto rec = g_chrClassesDB.GetRecordByIndex(i); if (rec->m_ID == CCharacterCreation::s_selectedClassID) { classIndex = i; } } lua_pushnumber(L, classIndex + 1); auto classRoles = CGLookingForGroup::GetClassRoles(CCharacterCreation::s_selectedClassID); lua_pushboolean(L, classRoles & CLASS_ROLE_TANK); lua_pushboolean(L, classRoles & CLASS_ROLE_HEALER); lua_pushboolean(L, classRoles & CLASS_ROLE_DAMAGE); return 6; } int32_t Script_SetSelectedRace(lua_State* L) { if (!lua_isnumber(L, 1)) { luaL_error(L, "Usage: SetSelectedRace(index)"); return 0; } auto raceIndex = lua_tonumber(L, 1) - 1; CCharacterCreation::SetSelectedRace(raceIndex); return 0; } int32_t Script_SetSelectedSex(lua_State* L) { if (!lua_isnumber(L, 1)) { luaL_error(L, "Usage: SetSelectedSex(index)"); return 0; } auto sexIndex = lua_tointeger(L, 1); for (int32_t sexID = 0; sexID < UNITSEX_LAST; sexID++) { if (sexIndex == g_glueFrameScriptGenders[sexID]) { CCharacterCreation::SetSelectedSex(sexID); } } return 0; } int32_t Script_SetSelectedClass(lua_State* L) { if (!lua_isnumber(L, 1)) { luaL_error(L, "Usage: SetSelectedClass(index)"); return 0; } int32_t classIndex = lua_tonumber(L, 1) - 1; auto classRec = g_chrClassesDB.GetRecordByIndex(classIndex); CCharacterCreation::SetSelectedClass(classRec ? classRec->GetID() : 0); return 0; } int32_t Script_UpdateCustomizationBackground(lua_State* L) { WHOA_UNIMPLEMENTED(0); } int32_t Script_UpdateCustomizationScene(lua_State* L) { CCharacterCreation::s_character->RenderPrep(0); return 0; } int32_t Script_CycleCharCustomization(lua_State* L) { WHOA_UNIMPLEMENTED(0); } int32_t Script_RandomizeCharCustomization(lua_State* L) { WHOA_UNIMPLEMENTED(0); } int32_t Script_GetCharacterCreateFacing(lua_State* L) { lua_pushnumber(L, CCharacterCreation::s_charFacing * 57.29578); return 1; } int32_t Script_SetCharacterCreateFacing(lua_State* L) { if (!lua_isnumber(L, 1)) { luaL_error(L, "Usage: SetCharacterCreateFacing(degrees)"); return 0; } auto orientation = lua_tonumber(L, 1) * 0.017453292; CCharacterCreation::SetFacing(orientation); return 1; } int32_t Script_GetRandomName(lua_State* L) { WHOA_UNIMPLEMENTED(0); } int32_t Script_CreateCharacter(lua_State* L) { WHOA_UNIMPLEMENTED(0); } int32_t Script_CustomizeExistingCharacter(lua_State* L) { WHOA_UNIMPLEMENTED(0); } int32_t Script_PaidChange_GetPreviousRaceIndex(lua_State* L) { WHOA_UNIMPLEMENTED(0); } int32_t Script_PaidChange_GetCurrentRaceIndex(lua_State* L) { WHOA_UNIMPLEMENTED(0); } int32_t Script_PaidChange_GetCurrentClassIndex(lua_State* L) { WHOA_UNIMPLEMENTED(0); } int32_t Script_PaidChange_GetName(lua_State* L) { WHOA_UNIMPLEMENTED(0); } int32_t Script_IsRaceClassValid(lua_State* L) { if (!lua_isnumber(L, 1) || !lua_isnumber(L, 2)) { luaL_error(L, "Usage: IsRaceClassValid(raceIndex, classIndex)"); return 0; } int32_t raceIndex = lua_tointeger(L, 1) - 1; int32_t classIndex = lua_tointeger(L, 2) - 1; auto classRec = g_chrClassesDB.GetRecordByIndex(classIndex); if (!classRec) { return 0; } auto raceID = raceIndex >= CCharacterCreation::s_races.Count() ? 0 : CCharacterCreation::s_races[raceIndex]; auto classID = classRec->m_ID; if (CCharacterCreation::IsRaceClassValid(raceID, classID)) { lua_pushnumber(L, 1.0); } else { lua_pushnil(L); } return 1; } int32_t Script_IsRaceClassRestricted(lua_State* L) { WHOA_UNIMPLEMENTED(0); } int32_t Script_GetCreateBackgroundModel(lua_State* L) { if (SFile::IsStreamingTrial()) { lua_pushstring(L, "CharacterSelect"); return 1; } if (CCharacterCreation::s_selectedClassID == 6) { auto classRec = g_chrClassesDB.GetRecord(6); if (classRec) { lua_pushstring(L, classRec->m_filename); return 1; } } else { auto raceID = CCharacterCreation::s_character->m_data.raceID; if (raceID == 7) { raceID = 3; } else if (raceID == 8) { raceID = 2; } auto raceRec = g_chrRacesDB.GetRecord(raceID); if (raceRec) { lua_pushstring(L, raceRec->m_clientFileString); return 1; } } // Race or class background not found lua_pushstring(L, ""); return 1; } static FrameScript_Method s_ScriptFunctions[NUM_SCRIPT_FUNCTIONS_CHAR_CREATE] = { { "SetCharCustomizeFrame", &Script_SetCharCustomizeFrame }, { "SetCharCustomizeBackground", &Script_SetCharCustomizeBackground }, { "ResetCharCustomize", &Script_ResetCharCustomize }, { "GetNameForRace", &Script_GetNameForRace }, { "GetFactionForRace", &Script_GetFactionForRace }, { "GetAvailableRaces", &Script_GetAvailableRaces }, { "GetAvailableClasses", &Script_GetAvailableClasses }, { "GetClassesForRace", &Script_GetClassesForRace }, { "GetHairCustomization", &Script_GetHairCustomization }, { "GetFacialHairCustomization", &Script_GetFacialHairCustomization }, { "GetSelectedRace", &Script_GetSelectedRace }, { "GetSelectedSex", &Script_GetSelectedSex }, { "GetSelectedClass", &Script_GetSelectedClass }, { "SetSelectedRace", &Script_SetSelectedRace }, { "SetSelectedSex", &Script_SetSelectedSex }, { "SetSelectedClass", &Script_SetSelectedClass }, { "UpdateCustomizationBackground", &Script_UpdateCustomizationBackground }, { "UpdateCustomizationScene", &Script_UpdateCustomizationScene }, { "CycleCharCustomization", &Script_CycleCharCustomization }, { "RandomizeCharCustomization", &Script_RandomizeCharCustomization }, { "GetCharacterCreateFacing", &Script_GetCharacterCreateFacing }, { "SetCharacterCreateFacing", &Script_SetCharacterCreateFacing }, { "GetRandomName", &Script_GetRandomName }, { "CreateCharacter", &Script_CreateCharacter }, { "CustomizeExistingCharacter", &Script_CustomizeExistingCharacter }, { "PaidChange_GetPreviousRaceIndex", &Script_PaidChange_GetPreviousRaceIndex }, { "PaidChange_GetCurrentRaceIndex", &Script_PaidChange_GetCurrentRaceIndex }, { "PaidChange_GetCurrentClassIndex", &Script_PaidChange_GetCurrentClassIndex }, { "PaidChange_GetName", &Script_PaidChange_GetName }, { "IsRaceClassValid", &Script_IsRaceClassValid }, { "IsRaceClassRestricted", &Script_IsRaceClassRestricted }, { "GetCreateBackgroundModel", &Script_GetCreateBackgroundModel } }; void CharacterCreateRegisterScriptFunctions() { for (int32_t i = 0; i < NUM_SCRIPT_FUNCTIONS_CHAR_CREATE; ++i) { FrameScript_RegisterFunction( s_ScriptFunctions[i].name, s_ScriptFunctions[i].method ); } }