-- --------------------------------------------------------------------------- -- Building a freemode ped from an appearance table. -- -- The same code paints the creator preview and the live player, so what you -- saw while editing is exactly what walks into the world. -- --------------------------------------------------------------------------- PedBuild = {} local NO_OVERLAY = 255 -- the native's "none" value; our model stores -1 local function loadModel(name) local hash = joaat(name) if not IsModelInCdimage(hash) or not IsModelValid(hash) then return nil end RequestModel(hash) local waited = 0 while not HasModelLoaded(hash) and waited < 10000 do Wait(10) waited = waited + 10 end if not HasModelLoaded(hash) then return nil end return hash end PedBuild.LoadModel = loadModel --- Apply an appearance table to an existing freemode ped. function PedBuild.Apply(ped, a) if not ped or not DoesEntityExist(ped) or type(a) ~= 'table' then return end SetPedHeadBlendData( ped, a.parents.father, a.parents.mother, 0, a.parents.father, a.parents.mother, 0, a.parents.shapeMix + 0.0, a.parents.skinMix + 0.0, 0.0, false ) for _, f in ipairs(Appearance.FEATURES) do local v = a.features[tostring(f.id)] if v then SetPedFaceFeature(ped, f.id, v + 0.0) end end for _, o in ipairs(Appearance.OVERLAYS) do local ov = a.overlays[o.key] if ov then local index = (ov.index == nil or ov.index < 0) and NO_OVERLAY or ov.index SetPedHeadOverlay(ped, o.id, index, ov.opacity + 0.0) if o.tint and index ~= NO_OVERLAY then -- tint type 1 = hair palette, 2 = make-up palette SetPedHeadOverlayColor(ped, o.id, o.tint == 'hair' and 1 or 2, ov.colour, ov.colour) end end end SetPedComponentVariation(ped, 2, a.hair.style, 0, 0) SetPedHairColor(ped, a.hair.colour, a.hair.highlight) SetPedEyeColor(ped, a.eyeColour) for _, c in ipairs(Appearance.COMPONENTS) do local cc = a.components[c.key] if cc then SetPedComponentVariation(ped, c.id, cc.drawable, cc.texture, 0) end end for _, p in ipairs(Appearance.PROPS) do local pp = a.props[p.key] if pp then if not pp.drawable or pp.drawable < 0 then ClearPedProp(ped, p.id) else SetPedPropIndex(ped, p.id, pp.drawable, pp.texture, true) end end end end --- How many variations this particular model actually has, so the creator's --- sliders stop at real values instead of guessed ones. function PedBuild.Limits(ped) local limits = { components = {}, props = {}, overlays = {}, hair = 0 } if not ped or not DoesEntityExist(ped) then return limits end limits.hair = math.max(0, GetNumberOfPedDrawableVariations(ped, 2) - 1) for _, c in ipairs(Appearance.COMPONENTS) do local drawables = math.max(0, GetNumberOfPedDrawableVariations(ped, c.id) - 1) local current = GetPedDrawableVariation(ped, c.id) limits.components[c.key] = { drawable = drawables, texture = math.max(0, GetNumberOfPedTextureVariations(ped, c.id, current) - 1), } end for _, p in ipairs(Appearance.PROPS) do local drawables = math.max(-1, GetNumberOfPedPropDrawableVariations(ped, p.id) - 1) local current = GetPedPropIndex(ped, p.id) limits.props[p.key] = { drawable = drawables, texture = math.max(0, GetNumberOfPedPropTextureVariations(ped, p.id, current) - 1), } end for _, o in ipairs(Appearance.OVERLAYS) do limits.overlays[o.key] = o.max end return limits end --- Create a standalone preview ped (never networked). function PedBuild.CreatePreview(appearance, coords, heading) local modelName = Appearance.MODELS[appearance.model] or Appearance.MODELS.m local hash = loadModel(modelName) if not hash then return nil end local ped = CreatePed(2, hash, coords.x, coords.y, coords.z, heading + 0.0, false, false) SetModelAsNoLongerNeeded(hash) SetEntityInvincible(ped, true) FreezeEntityPosition(ped, true) SetBlockingOfNonTemporaryEvents(ped, true) SetPedDefaultComponentVariation(ped) SetPedCanRagdoll(ped, false) SetEntityCollision(ped, false, false) PedBuild.Apply(ped, appearance) return ped end --- Turn the local player into this character. function PedBuild.ApplyToPlayer(appearance) local modelName = Appearance.MODELS[appearance.model] or Appearance.MODELS.m local hash = loadModel(modelName) if not hash then return false end SetPlayerModel(PlayerId(), hash) SetModelAsNoLongerNeeded(hash) local ped = PlayerPedId() SetPedDefaultComponentVariation(ped) PedBuild.Apply(ped, appearance) -- freemode peds start with no head blend applied until this settles a frame Wait(50) PedBuild.Apply(ped, appearance) return true end --- A calm idle so the preview does not stand like a mannequin. function PedBuild.Idle(ped) local dict = 'anim@heists@heist_corona@team_idles@female_a' RequestAnimDict(dict) local waited = 0 while not HasAnimDictLoaded(dict) and waited < 3000 do Wait(10) waited = waited + 10 end if HasAnimDictLoaded(dict) then TaskPlayAnim(ped, dict, 'idle', 2.0, 2.0, -1, 1, 0, false, false, false) end end