Upload files to "client"
This commit is contained in:
parent
322a3d23e8
commit
72bf3dbec1
201
client/appearance.lua
Normal file
201
client/appearance.lua
Normal file
|
|
@ -0,0 +1,201 @@
|
|||
-- 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 <color> [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 <color> [highlight]")
|
||||
end, false)
|
||||
108
client/atm_blips.lua
Normal file
108
client/atm_blips.lua
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
-- client/atm_blips.lua
|
||||
print("^2[turfwar]^7 atm_blips.lua loaded")
|
||||
|
||||
if IsDuplicityVersion() then
|
||||
print("^1[turfwar]^7 atm_blips.lua loaded on SERVER by mistake!")
|
||||
return
|
||||
end
|
||||
|
||||
Config = Config or {}
|
||||
Config.Finance = Config.Finance or {}
|
||||
|
||||
-- =========================
|
||||
-- Config defaults (blips)
|
||||
-- =========================
|
||||
Config.Finance.ATM_BLIPS_ENABLED = (Config.Finance.ATM_BLIPS_ENABLED ~= false)
|
||||
Config.Finance.ATM_BLIP_SPRITE = Config.Finance.ATM_BLIP_SPRITE or 277
|
||||
Config.Finance.ATM_BLIP_SCALE = Config.Finance.ATM_BLIP_SCALE or 0.55
|
||||
Config.Finance.ATM_BLIP_COLOR = Config.Finance.ATM_BLIP_COLOR or 2
|
||||
Config.Finance.ATM_BLIP_SHORT_RANGE = (Config.Finance.ATM_BLIP_SHORT_RANGE ~= false)
|
||||
|
||||
-- =========================
|
||||
-- State
|
||||
-- =========================
|
||||
local ATM_BLIPS = {} -- array for easy cleanup
|
||||
local ATM_BY_KEY = {} -- coordKey -> blip
|
||||
|
||||
-- =========================
|
||||
-- Helpers
|
||||
-- =========================
|
||||
local function coordKey(x, y, z)
|
||||
-- round to 0.5m to dedupe close matches
|
||||
local rx = math.floor((x * 2.0) + 0.5) / 2.0
|
||||
local ry = math.floor((y * 2.0) + 0.5) / 2.0
|
||||
local rz = math.floor((z * 2.0) + 0.5) / 2.0
|
||||
return (("%0.1f|%0.1f|%0.1f"):format(rx, ry, rz))
|
||||
end
|
||||
|
||||
local function ClearATMBlips()
|
||||
for _, b in ipairs(ATM_BLIPS) do
|
||||
if DoesBlipExist(b) then RemoveBlip(b) end
|
||||
end
|
||||
ATM_BLIPS = {}
|
||||
ATM_BY_KEY = {}
|
||||
end
|
||||
|
||||
local function AddATMBlip(coords)
|
||||
local key = coordKey(coords.x, coords.y, coords.z)
|
||||
if ATM_BY_KEY[key] and DoesBlipExist(ATM_BY_KEY[key]) then return end
|
||||
|
||||
local blip = AddBlipForCoord(coords.x, coords.y, coords.z)
|
||||
SetBlipSprite(blip, Config.Finance.ATM_BLIP_SPRITE)
|
||||
SetBlipScale(blip, Config.Finance.ATM_BLIP_SCALE)
|
||||
SetBlipColour(blip, Config.Finance.ATM_BLIP_COLOR)
|
||||
SetBlipDisplay(blip, 4)
|
||||
SetBlipAsShortRange(blip, Config.Finance.ATM_BLIP_SHORT_RANGE)
|
||||
|
||||
BeginTextCommandSetBlipName("STRING")
|
||||
AddTextComponentString("ATM")
|
||||
EndTextCommandSetBlipName(blip)
|
||||
|
||||
ATM_BLIPS[#ATM_BLIPS + 1] = blip
|
||||
ATM_BY_KEY[key] = blip
|
||||
end
|
||||
|
||||
local function BuildATMBlips(atms)
|
||||
ClearATMBlips()
|
||||
|
||||
if not atms or #atms == 0 then
|
||||
print("^1[turfwar]^7 atm_blips.lua: Config.Finance.ATMS is empty (0) -> no ATM blips.")
|
||||
return
|
||||
end
|
||||
|
||||
for _, c in ipairs(atms) do
|
||||
if type(c) == "vector3" then
|
||||
AddATMBlip(c)
|
||||
elseif type(c) == "table" and c.x and c.y and c.z then
|
||||
AddATMBlip(vector3(c.x, c.y, c.z))
|
||||
end
|
||||
end
|
||||
|
||||
print(("^2[turfwar]^7 ATM blips created: %d"):format(#ATM_BLIPS))
|
||||
end
|
||||
|
||||
-- If you still have an atm_coords.lua that fires this:
|
||||
AddEventHandler("turfwar:atm:listReady", function(atms)
|
||||
if not Config.Finance.ATM_BLIPS_ENABLED then return end
|
||||
BuildATMBlips(atms)
|
||||
end)
|
||||
|
||||
-- Boot: Mode B static list from config.lua
|
||||
CreateThread(function()
|
||||
Wait(500)
|
||||
|
||||
if not Config.Finance.ATM_BLIPS_ENABLED then
|
||||
print("^3[turfwar]^7 ATM blips disabled in config")
|
||||
return
|
||||
end
|
||||
|
||||
local atms = Config.Finance.ATMS or {}
|
||||
print(("^3[turfwar]^7 atm_blips.lua: boot -> ATMS=%d"):format(#atms))
|
||||
|
||||
BuildATMBlips(atms)
|
||||
end)
|
||||
|
||||
AddEventHandler("onClientResourceStop", function(res)
|
||||
if res ~= GetCurrentResourceName() then return end
|
||||
ClearATMBlips()
|
||||
end)
|
||||
39
client/atm_coords.lua
Normal file
39
client/atm_coords.lua
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
-- client/atm_coords.lua
|
||||
print("^2[turfwar]^7 atm_coords.lua loaded")
|
||||
|
||||
if IsDuplicityVersion() then
|
||||
print("^1[turfwar]^7 atm_coords.lua loaded on SERVER by mistake!")
|
||||
return
|
||||
end
|
||||
|
||||
Config = Config or {}
|
||||
Config.Finance = Config.Finance or {}
|
||||
|
||||
--========================================================
|
||||
-- Static ATM coordinates (Mode B)
|
||||
--========================================================
|
||||
Config.Finance.ATMS = Config.Finance.ATMS or {
|
||||
vector3(150.266, -1040.203, 29.374),
|
||||
vector3(-1212.980, -330.841, 37.787),
|
||||
vector3(-2962.582, 482.627, 15.703),
|
||||
vector3(-112.202, 6469.295, 31.626),
|
||||
vector3(314.187, -278.621, 54.170),
|
||||
vector3(-351.534, -49.529, 49.042),
|
||||
vector3(241.727, 220.706, 106.286),
|
||||
vector3(1171.523, 2702.448, 38.175),
|
||||
vector3(-1091.887, 2708.560, 18.955),
|
||||
vector3(2683.011, 3286.536, 55.241),
|
||||
vector3(-386.733, 6045.953, 31.501),
|
||||
vector3(1703.138, 4933.593, 42.051),
|
||||
vector3(540.042, 2671.007, 42.177),
|
||||
vector3(2564.399, 2585.100, 38.016),
|
||||
vector3(1822.639, 3683.095, 34.276),
|
||||
}
|
||||
|
||||
print(("^2[turfwar]^7 atm_coords.lua: %d ATM coords ready"):format(#Config.Finance.ATMS))
|
||||
|
||||
-- Fire event so atm_blips.lua builds them
|
||||
CreateThread(function()
|
||||
Wait(250) -- give atm_blips.lua time to register handler
|
||||
TriggerEvent("turfwar:atm:listReady", Config.Finance.ATMS)
|
||||
end)
|
||||
46
client/atm_nui.lua
Normal file
46
client/atm_nui.lua
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
-- client/atm_nui.lua (recommended: put callbacks in a dedicated file)
|
||||
|
||||
local atmToken = nil
|
||||
local atmOpen = false
|
||||
|
||||
RegisterNetEvent("turfwar:atm:openGranted", function(token)
|
||||
atmToken = token
|
||||
atmOpen = true
|
||||
SetNuiFocus(true, true)
|
||||
SendNUIMessage({ type = "atm:open" })
|
||||
end)
|
||||
|
||||
local function CloseATM()
|
||||
atmOpen = false
|
||||
atmToken = nil
|
||||
SetNuiFocus(false, false)
|
||||
SendNUIMessage({ type = "atm:close" })
|
||||
end
|
||||
|
||||
RegisterNUICallback("atm:ready", function(_, cb)
|
||||
-- optional: can be used if you want to delay open until UI loaded
|
||||
cb({ ok = true })
|
||||
end)
|
||||
|
||||
RegisterNUICallback("atm:close", function(_, cb)
|
||||
CloseATM()
|
||||
cb({ ok = true })
|
||||
end)
|
||||
|
||||
RegisterNUICallback("atm:deposit", function(data, cb)
|
||||
local amount = tonumber(data.amount) or 0
|
||||
if amount <= 0 then cb({ ok = false, error = "bad_amount" }); return end
|
||||
if not atmToken then cb({ ok = false, error = "no_token" }); return end
|
||||
|
||||
TriggerServerEvent("turfwar:finance:deposit", atmToken, amount)
|
||||
cb({ ok = true })
|
||||
end)
|
||||
|
||||
RegisterNUICallback("atm:withdraw", function(data, cb)
|
||||
local amount = tonumber(data.amount) or 0
|
||||
if amount <= 0 then cb({ ok = false, error = "bad_amount" }); return end
|
||||
if not atmToken then cb({ ok = false, error = "no_token" }); return end
|
||||
|
||||
TriggerServerEvent("turfwar:finance:withdraw", atmToken, amount)
|
||||
cb({ ok = true })
|
||||
end)
|
||||
84
client/dev.lua
Normal file
84
client/dev.lua
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
-- dev.lua
|
||||
RegisterCommand("tw_coords_turf", function()
|
||||
local ped = PlayerPedId()
|
||||
local c = GetEntityCoords(ped)
|
||||
|
||||
local found, groundZ = GetGroundZFor_3dCoord(c.x, c.y, c.z + 200.0, 0)
|
||||
local z = found and groundZ or c.z
|
||||
|
||||
local msg = ("center = vector3(%.3f, %.3f, %.3f),"):format(c.x, c.y, z)
|
||||
|
||||
print("^3[turfwar]^7 " .. msg)
|
||||
|
||||
BeginTextCommandThefeedPost("STRING")
|
||||
AddTextComponentSubstringPlayerName(msg)
|
||||
EndTextCommandThefeedPostTicker(false, false)
|
||||
end, false)
|
||||
|
||||
-- =========================================================
|
||||
-- Killfeed NUI Self-Test (no PvP needed)
|
||||
-- =========================================================
|
||||
RegisterCommand("tw_kf", function(_, args)
|
||||
local killer = args[1] or "O'Neil Tester"
|
||||
local victim = args[2] or "Malita Tester"
|
||||
|
||||
-- Example: Gang 1 (yellow) kills Gang 2 (green)
|
||||
local killerGang = tonumber(args[3]) or 1
|
||||
local victimGang = tonumber(args[4]) or 2
|
||||
|
||||
local function rgbForGang(gangId)
|
||||
local g = Config and Config.GANGS and Config.GANGS[tonumber(gangId) or 0]
|
||||
if g and type(g.rgb) == "table" then
|
||||
return { tonumber(g.rgb[1]) or 255, tonumber(g.rgb[2]) or 255, tonumber(g.rgb[3]) or 255 }
|
||||
end
|
||||
return {255,255,255}
|
||||
end
|
||||
|
||||
SendNUIMessage({
|
||||
type = "killfeed:add",
|
||||
killerName= killer,
|
||||
victimName= victim,
|
||||
weapon = "Carbine Rifle",
|
||||
headshot = true,
|
||||
distance = 42,
|
||||
killerRgb = rgbForGang(killerGang),
|
||||
victimRgb = rgbForGang(victimGang),
|
||||
})
|
||||
|
||||
print(("^2[turfwar]^7 Killfeed test sent -> %s (g%d) killed %s (g%d)"):format(killer, killerGang, victim, victimGang))
|
||||
end, false)
|
||||
|
||||
RegisterCommand("tw_coords_ground", function()
|
||||
local ped = PlayerPedId()
|
||||
local c = GetEntityCoords(ped)
|
||||
local h = GetEntityHeading(ped)
|
||||
|
||||
-- Raycast straight down from slightly above the player
|
||||
local from = vector3(c.x, c.y, c.z + 1.0)
|
||||
local to = vector3(c.x, c.y, c.z - 200.0)
|
||||
|
||||
-- Flags: 1=world, 16=objects, 256=vehicles; 511 is a good "hit most things"
|
||||
local ray = StartShapeTestRay(from.x, from.y, from.z, to.x, to.y, to.z, 511, ped, 0)
|
||||
local _, hit, hitCoords = GetShapeTestResult(ray)
|
||||
|
||||
local z = c.z
|
||||
if hit == 1 and hitCoords then
|
||||
z = hitCoords.z
|
||||
end
|
||||
|
||||
local msg = ("Ground Coords (ray): vector4(%.3f, %.3f, %.3f, %.1f)"):format(c.x, c.y, z, h)
|
||||
print("^3[turfwar]^7 " .. msg)
|
||||
|
||||
BeginTextCommandThefeedPost("STRING")
|
||||
AddTextComponentSubstringPlayerName(msg)
|
||||
EndTextCommandThefeedPostTicker(false, false)
|
||||
end, false)
|
||||
|
||||
|
||||
|
||||
RegisterCommand("tw_hudtest", function()
|
||||
SendNUIMessage({ type="capture:start", turfName="HUD TEST", fill="rgba(255,0,0,0.9)", bg="rgba(255,255,255,0.14)" })
|
||||
Wait(250)
|
||||
SendNUIMessage({ type="capture:set", t=0.5 })
|
||||
end)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user