-- client/appearance.lua print("^2[turfwar]^7 appearance.lua loaded (client)") local appearance = nil local function IsFreemodeModel(hash) return hash == GetHashKey("mp_m_freemode_01") or hash == GetHashKey("mp_f_freemode_01") end local function ForcePlayerModel(modelName) local model = GetHashKey(modelName) if not IsModelInCdimage(model) or not IsModelValid(model) then print(("^1[turfwar]^7 INVALID model: %s"):format(modelName)) return false end RequestModel(model) local timeout = GetGameTimer() + 8000 while not HasModelLoaded(model) do Wait(0) if GetGameTimer() > timeout then print(("^1[turfwar]^7 TIMEOUT loading model: %s"):format(modelName)) return false end end SetPlayerModel(PlayerId(), model) SetModelAsNoLongerNeeded(model) Wait(200) return (GetEntityModel(PlayerPedId()) == model) end local function ApplyAppearanceNow() if not appearance then return end local ped = PlayerPedId() if not ped or ped == 0 then return end -- 1) Force model local desired = (appearance.gender == "f") and "mp_f_freemode_01" or "mp_m_freemode_01" if GetEntityModel(ped) ~= GetHashKey(desired) then ForcePlayerModel(desired) ped = PlayerPedId() if not ped or ped == 0 then return end end local function ApplyDefaultHeadBlend(ped, gender) if gender == "f" then -- softer defaults for female SetPedHeadBlendData(ped, 21, 0, 0, -- shape (mother-ish) 21, 0, 0, -- skin 0.55, 0.0, 0.0, false ) else SetPedHeadBlendData(ped, 0, 0, 0, 0, 0, 0, 0.5, 0.5, 0.0, false ) end -- neutralize extreme face features (optional) for i = 0, 19 do SetPedFaceFeature(ped, i, 0.0) end end ApplyDefaultHeadBlend(ped, appearance.gender) -- 2) Ensure freemode if not IsFreemodeModel(GetEntityModel(ped)) then print("^1[turfwar]^7 ApplyAppearanceNow: not freemode even after force (something else is overriding model).") return end -- 3) Hair style validation (component 2) local hairDrawable = tonumber(appearance.hair_drawable) or 0 local hairTexture = tonumber(appearance.hair_texture) or 0 local maxHair = GetNumberOfPedDrawableVariations(ped, 2) if maxHair > 0 then if hairDrawable < 0 then hairDrawable = 0 end if hairDrawable >= maxHair then hairDrawable = maxHair - 1 end local maxTex = GetNumberOfPedTextureVariations(ped, 2, hairDrawable) if maxTex <= 0 then maxTex = 1 end if hairTexture < 0 then hairTexture = 0 end if hairTexture >= maxTex then hairTexture = maxTex - 1 end SetPedComponentVariation(ped, 2, hairDrawable, hairTexture, 0) end -- 4) Hair color local c = tonumber(appearance.hair_color) or 0 local h = tonumber(appearance.hair_highlight) if h == nil then h = c end local numColors = GetNumHairColors() if numColors and numColors > 0 then c = math.max(0, math.min(c, numColors - 1)) h = math.max(0, math.min(h, numColors - 1)) else -- fallback clamp c = math.max(0, math.min(c, 63)) h = math.max(0, math.min(h, 63)) end SetPedHairColor(ped, c, h) print(("[turfwar] appearance applied: gender=%s hair=%d/%d color=%d/%d") :format(tostring(appearance.gender), hairDrawable, hairTexture, c, h)) -- Tell main.lua (optional) that appearance has been applied TriggerEvent("turfwar:appearance:applied") end RegisterNetEvent("turfwar:appearance:update", function(row) appearance = row ApplyAppearanceNow() end) -- Request on resource start & spawn AddEventHandler("onClientResourceStart", function(res) if res ~= GetCurrentResourceName() then return end CreateThread(function() Wait(500) TriggerServerEvent("turfwar:appearance:request") end) end) AddEventHandler("playerSpawned", function() CreateThread(function() Wait(700) TriggerServerEvent("turfwar:appearance:request") end) end) -- Commands RegisterCommand("tw_gender", function(_, args) local g = args[1] and args[1]:lower() or "" if g ~= "m" and g ~= "f" then print("^3[turfwar]^7 Usage: /tw_gender m OR /tw_gender f") return end TriggerServerEvent("turfwar:appearance:setGender", g) end, false) RegisterCommand("tw_hair_next", function() if not appearance then return end local ped = PlayerPedId() if ped == 0 then return end local maxHair = GetNumberOfPedDrawableVariations(ped, 2) if maxHair <= 0 then print("^1[turfwar]^7 No hair variations on this model.") return end local cur = GetPedDrawableVariation(ped, 2) local nxt = (cur + 1) % maxHair local maxTex = GetNumberOfPedTextureVariations(ped, 2, nxt) if maxTex <= 0 then maxTex = 1 end local tex = 0 TriggerServerEvent("turfwar:appearance:setHair", nxt, tex, appearance.hair_color, appearance.hair_highlight) end, false) RegisterCommand("tw_hair_prev", function() if not appearance then return end local ped = PlayerPedId() if ped == 0 then return end local maxHair = GetNumberOfPedDrawableVariations(ped, 2) if maxHair <= 0 then return end local cur = GetPedDrawableVariation(ped, 2) local prv = (cur - 1) if prv < 0 then prv = maxHair - 1 end TriggerServerEvent("turfwar:appearance:setHair", prv, 0, appearance.hair_color, appearance.hair_highlight) end, false) RegisterCommand("tw_haircolor", function(_, args) if not appearance then return end local c = tonumber(args[1]) local h = tonumber(args[2]) if c == nil then print("^3[turfwar]^7 Usage: /tw_haircolor [highlight]") return end if h == nil then h = c end TriggerServerEvent("turfwar:appearance:setHair", appearance.hair_drawable, appearance.hair_texture, c, h) end, false) RegisterCommand("tw_appearance", function() print("^3[turfwar]^7 Commands:") print("^3[turfwar]^7 /tw_gender m|f") print("^3[turfwar]^7 /tw_hair_next (cycle)") print("^3[turfwar]^7 /tw_hair_prev (cycle)") print("^3[turfwar]^7 /tw_haircolor [highlight]") end, false)