215 lines
6.7 KiB
Lua
215 lines
6.7 KiB
Lua
|
local packages = {
|
|||
|
{
|
|||
|
text = 'коробку',
|
|||
|
money = 1000,
|
|||
|
variants = {
|
|||
|
{ model = 'models/physrbox/cardboard_taped.mdl', mass = 15 },
|
|||
|
{ model = 'models/physrbox/taped_big.mdl', mass = 15 },
|
|||
|
{ model = 'models/physrbox/taped_medium.mdl', mass = 10 },
|
|||
|
{ model = 'models/physrbox/taped_white.mdl', mass = 10 },
|
|||
|
},
|
|||
|
}, {
|
|||
|
text = 'мешок',
|
|||
|
money = 2500,
|
|||
|
variants = {
|
|||
|
{ model = 'models/props_shops/prop_bakery_floursack_01_a.mdl', mass = 40 },
|
|||
|
{ model = 'models/props_shops/prop_bakery_floursack_02_a.mdl', mass = 40 },
|
|||
|
{ model = 'models/props_shops/prop_bakery_floursack_02_b.mdl', mass = 35 },
|
|||
|
{ model = 'models/props_shops/prop_bakery_floursack_02_c.mdl', mass = 30 },
|
|||
|
},
|
|||
|
}, {
|
|||
|
text = 'телевизор',
|
|||
|
money = 2500,
|
|||
|
variants = {
|
|||
|
{ model = 'models/gmod_tower/suitetv.mdl', mass = 50 },
|
|||
|
{ model = 'models/mark2580/gtav/mp_apa_low/lobby/tv_03.mdl', mass = 40 },
|
|||
|
{ model = 'models/sal/ammunation/tv2.mdl', mass = 40 },
|
|||
|
{ model = 'models/sal/ammunation/tv.mdl', mass = 35 },
|
|||
|
},
|
|||
|
}, {
|
|||
|
text = 'кресло',
|
|||
|
money = 3500,
|
|||
|
variants = {
|
|||
|
{ model = 'models/mark2580/gtav/mp_apa_mid/hall/v_res_mp_stripchair_high.mdl', mass = 80 },
|
|||
|
{ model = 'models/mark2580/gtav/mp_apa_06/lobby/apa_mp_h_stn_chairarm_23_high.mdl', mass = 75 },
|
|||
|
{ model = 'models/props_interiors/sofa_chair02.mdl', mass = 75 },
|
|||
|
{ model = 'models/Highrise/lobby_chair_01.mdl', mass = 100 },
|
|||
|
},
|
|||
|
}, {
|
|||
|
text = 'шкаф',
|
|||
|
money = 5000,
|
|||
|
variants = {
|
|||
|
{ model = 'models/mark2580/gtav/mp_apa_mid/bedroom/v_res_tre_storageunit_high.mdl', mass = 125 },
|
|||
|
{ model = 'models/mark2580/gtav/mp_apa_low/bedroom/brm_cabinet.mdl', mass = 120 },
|
|||
|
{ model = 'models/mark2580/gtav/mp_apa_06/lobby/apa_mpa6_sideboardm02_high.mdl', mass = 140 },
|
|||
|
{ model = 'models/props_c17/furnituredresser001a.mdl', mass = 155 },
|
|||
|
{ model = 'models/props/interior/dresser_wardrobe01.mdl', mass = 170 },
|
|||
|
},
|
|||
|
}, {
|
|||
|
text = 'диван',
|
|||
|
money = 6000,
|
|||
|
variants = {
|
|||
|
{ model = 'models/mark2580/gtav/tequilala_map/basement/club_officesofa.mdl', mass = 150 },
|
|||
|
{ model = 'models/mark2580/gtav/mp_apa_low/lobby/sofa1.mdl', mass = 160 },
|
|||
|
{ model = 'models/props_interiors/sofa01.mdl', mass = 175 },
|
|||
|
{ model = 'models/props_interiors/sofa02.mdl', mass = 170 },
|
|||
|
{ model = 'models/props_c17/furniturecouch002a.mdl', mass = 140 },
|
|||
|
{ model = 'models/sims/gm_sofa.mdl', mass = 135 },
|
|||
|
},
|
|||
|
},
|
|||
|
}
|
|||
|
|
|||
|
local job = {}
|
|||
|
|
|||
|
function job.publish()
|
|||
|
local packageData = table.Random(packages)
|
|||
|
if not packageData then return end
|
|||
|
|
|||
|
local modelData = table.Random(packageData.variants)
|
|||
|
if not modelData then return end
|
|||
|
|
|||
|
local mapConfig = dbgJobs.mapConfig and dbgJobs.mapConfig.pack
|
|||
|
if not mapConfig then return end
|
|||
|
|
|||
|
local existingPackagesPositions = octolib.table.mapSequential(ents.FindByClass('dbg_jobs_package'), function(ent)
|
|||
|
return ent:GetPos()
|
|||
|
end)
|
|||
|
|
|||
|
local spawnData, targetPos
|
|||
|
for _, place in RandomPairs(mapConfig) do
|
|||
|
if not targetPos then
|
|||
|
targetPos = place[1]
|
|||
|
continue
|
|||
|
end
|
|||
|
|
|||
|
-- we don't want any other packages near spawn
|
|||
|
local pos = unpack(place)
|
|||
|
local ok = true
|
|||
|
for _, theirPos in ipairs(existingPackagesPositions) do
|
|||
|
if theirPos:DistToSqr(pos) < 90000 then
|
|||
|
ok = false
|
|||
|
break
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
if ok then
|
|||
|
spawnData = place
|
|||
|
break
|
|||
|
end
|
|||
|
end
|
|||
|
if not spawnData then return end
|
|||
|
|
|||
|
targetPos = util.TraceLine({
|
|||
|
start = targetPos,
|
|||
|
endpos = targetPos + Vector(0, 0, -300),
|
|||
|
collisiongroup = COLLISION_GROUP_WORLD,
|
|||
|
}).HitPos or targetPos
|
|||
|
|
|||
|
local prop = ents.Create 'dbg_jobs_package'
|
|||
|
prop:SetModel(modelData.model)
|
|||
|
prop:SetSkin(modelData.skin or 0)
|
|||
|
prop:SetBodyGroups(modelData.bodygroups or '')
|
|||
|
prop:Spawn()
|
|||
|
prop:Activate()
|
|||
|
prop:SetPos(spawnData[1] + Vector(0, 0, -prop:OBBMins().z))
|
|||
|
prop:SetAngles(spawnData[2])
|
|||
|
|
|||
|
local phys = prop:GetPhysicsObject()
|
|||
|
if IsValid(phys) then
|
|||
|
phys:SetMass(modelData.mass * 3)
|
|||
|
phys:Wake()
|
|||
|
end
|
|||
|
|
|||
|
local estateFrom = dbgEstates.getNearest(spawnData[1])
|
|||
|
local addressFrom = estateFrom and estateFrom.name or '???'
|
|||
|
local estateTo = dbgEstates.getNearest(targetPos)
|
|||
|
local addressTo = estateTo and estateTo.name or '???'
|
|||
|
|
|||
|
local desc = ('Требуется доставить %s массой %d кг\n%s → %s'):format(packageData.text, modelData.mass, addressFrom, addressTo)
|
|||
|
desc = desc .. ('\nОбъем груза: %dл'):format(prop:GetVolumeLiters())
|
|||
|
if modelData.mass > 100 then
|
|||
|
desc = desc .. '\nРекомендуется использовать грузовой автомобиль'
|
|||
|
end
|
|||
|
|
|||
|
local money = packageData.money
|
|||
|
-- from -25% to +25% based on distance
|
|||
|
+ math.Round(packageData.money / 40 * (math.Clamp(spawnData[1]:Distance(targetPos), 0, 10000) / 10000 - 0.5)) * 10
|
|||
|
-- from -10% to +10% as a random bonus
|
|||
|
+ math.floor(packageData.money / 100) * math.random(-10, 10)
|
|||
|
|
|||
|
return {
|
|||
|
name = ('Перевозка груза (%s кг)'):format(modelData.mass),
|
|||
|
icon = octolib.icons.silk32('lorry_go'),
|
|||
|
desc = desc,
|
|||
|
reward = DarkRP.formatMoney(money),
|
|||
|
deposit = math.floor(money / 40) * 10,
|
|||
|
timeout = octolib.time.toSeconds(10, 'minutes'),
|
|||
|
|
|||
|
money = money,
|
|||
|
prop = prop,
|
|||
|
targetPos = targetPos,
|
|||
|
}
|
|||
|
end
|
|||
|
|
|||
|
function job.cancel(publishData)
|
|||
|
local prop = publishData.prop
|
|||
|
if IsValid(prop) then prop:Remove() end
|
|||
|
end
|
|||
|
|
|||
|
function job.start(ply, publishData)
|
|||
|
if not IsValid(publishData.prop) then
|
|||
|
ply:Notify('Что-то случилось с грузом, задание отменено')
|
|||
|
dbgJobs.removeAvailable(publishData.id, true)
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
local markerID = 'job:' .. publishData.id
|
|||
|
local prop = publishData.prop
|
|||
|
ply:AddMarker({
|
|||
|
id = markerID .. '.1',
|
|||
|
txt = 'Груз',
|
|||
|
pos = prop:WorldSpaceCenter(),
|
|||
|
col = Color(255,92,38),
|
|||
|
des = {'dist', { 100 }},
|
|||
|
icon = octolib.icons.silk16('box_closed'),
|
|||
|
})
|
|||
|
|
|||
|
local targetPos = publishData.targetPos
|
|||
|
ply:AddMarker({
|
|||
|
id = markerID .. '.2',
|
|||
|
txt = 'Получатель',
|
|||
|
pos = targetPos,
|
|||
|
col = Color(255,92,38),
|
|||
|
des = {'time', { octolib.time.toSeconds(2, 'hours') }},
|
|||
|
icon = octolib.icons.silk16('arrow_down'),
|
|||
|
})
|
|||
|
prop:SetDeliveryData(publishData.id, ply, targetPos)
|
|||
|
|
|||
|
return {}
|
|||
|
end
|
|||
|
|
|||
|
function job.finish(startData, isSuccessful)
|
|||
|
local prop = startData.publishData.prop
|
|||
|
if IsValid(prop) then prop:Remove() end
|
|||
|
|
|||
|
local ply = startData.ply
|
|||
|
if not IsValid(ply) then return end
|
|||
|
|
|||
|
ply:ClearMarkers('job:' .. startData.publishData.id .. '.1')
|
|||
|
ply:ClearMarkers('job:' .. startData.publishData.id .. '.2')
|
|||
|
|
|||
|
if isSuccessful then
|
|||
|
local totalReward = startData.publishData.money + startData.publishData.deposit
|
|||
|
|
|||
|
ply:Notify(('Задание "%s" выполнено! На твой счет перечислено %s'):format(
|
|||
|
startData.publishData.name,
|
|||
|
DarkRP.formatMoney(totalReward)
|
|||
|
))
|
|||
|
ply:BankAdd(totalReward)
|
|||
|
else
|
|||
|
ply:Notify('warning', ('Задание "%s" провалено'):format(startData.publishData.name))
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
dbgJobs.registerType('pack', job)
|