214 lines
6.7 KiB
Lua
214 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)
|