Initial how_progression baseline
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
return {
|
||||
id = 'cosmic_dave',
|
||||
displayName = 'Cosmic Dave',
|
||||
ped = {
|
||||
model = 'ig_omega',
|
||||
coords = { x = 2447.63, y = 3775.08, z = 41.43, w = 23.30 },
|
||||
spawnZOffset = -1.0,
|
||||
scenario = 'WORLD_HUMAN_PARTYING',
|
||||
missionEntity = true, invincible = true, frozen = true,
|
||||
blockNonTemporaryEvents = true,
|
||||
},
|
||||
world = { alwaysPresent = true },
|
||||
missions = {},
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
return {
|
||||
id = 'crowbar',
|
||||
displayName = 'Crowbar',
|
||||
phone = { number = '555-7384' },
|
||||
ped = {
|
||||
model = 'ig_clay',
|
||||
coords = { x = 1699.67, y = 3775.30, z = 34.74, w = 207.22 },
|
||||
spawnZOffset = -1.0,
|
||||
scenario = 'WORLD_HUMAN_SMOKING',
|
||||
invincible = true,
|
||||
frozen = true,
|
||||
blockNonTemporaryEvents = true,
|
||||
},
|
||||
world = {
|
||||
requires = { column = 'crowbar_stage', min = 1 },
|
||||
vehicles = {
|
||||
{
|
||||
id = 'crowbar_daemon', model = 'daemon',
|
||||
coords = { x = 1699.70, y = 3771.63, z = 34.53, w = 258.21 },
|
||||
localEntity = true, locked = 2, invincible = true, frozen = true,
|
||||
},
|
||||
},
|
||||
},
|
||||
blip = {
|
||||
label = 'Crowbar', sprite = 280, scale = 0.75, shortRange = false,
|
||||
requires = { column = 'crowbar_stage', min = 1 },
|
||||
},
|
||||
interaction = {
|
||||
name = 'how_progression_crowbar_talk', icon = 'fa-solid fa-comment',
|
||||
label = 'Talk to Crowbar', distance = 2.0,
|
||||
gateCallback = 'how_progression:server:isCrowbarMissionActive',
|
||||
gateAllowsWhen = false,
|
||||
stageCallback = 'how_progression:server:getCrowbarMission',
|
||||
},
|
||||
progression = { stageColumn = 'crowbar_stage', repColumn = 'crowbar_rep' },
|
||||
missions = { 'crowbar:1', 'crowbar:2', 'crowbar:3', 'crowbar:4', 'crowbar:5' },
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
return {
|
||||
id = 'deke',
|
||||
displayName = 'Deke',
|
||||
ped = {
|
||||
model = 's_m_m_autoshop_02',
|
||||
coords = { x = 2359.89, y = 3136.74, z = 48.21, w = 110.90 },
|
||||
spawnZOffset = -1.0,
|
||||
scenario = 'WORLD_HUMAN_STAND_IMPATIENT',
|
||||
invincible = true, frozen = true, blockNonTemporaryEvents = true,
|
||||
},
|
||||
world = { alwaysPresent = true, spawnedWith = 'mack' },
|
||||
interaction = {
|
||||
name = 'how_progression_deke_shop', icon = 'fa-solid fa-toolbox',
|
||||
label = 'Talk to Deke', distance = 2.0,
|
||||
inventory = { kind = 'shop', type = 'DekeTools', id = 1 },
|
||||
},
|
||||
missions = {},
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
return {
|
||||
id = 'gabe',
|
||||
displayName = 'Gabe',
|
||||
location = { x = 2340.96, y = 3126.11, z = 48.21 },
|
||||
blip = {
|
||||
label = 'Money Laundering', sprite = 500, display = 4,
|
||||
scale = 0.7, shortRange = true,
|
||||
createdDuring = 'crowbar:4',
|
||||
},
|
||||
service = { resource = 'randol_moneywash' },
|
||||
associatedMissions = { 'crowbar:4' },
|
||||
missions = {},
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
-- Passive definitions. Requiring this module does not create world entities.
|
||||
local byId = {
|
||||
unknown = require 'shared.contacts.unknown',
|
||||
crowbar = require 'shared.contacts.crowbar',
|
||||
mack = require 'shared.contacts.mack',
|
||||
gabe = require 'shared.contacts.gabe',
|
||||
deke = require 'shared.contacts.deke',
|
||||
vinny = require 'shared.contacts.vinny',
|
||||
cosmic_dave = require 'shared.contacts.cosmic_dave',
|
||||
}
|
||||
|
||||
local phoneOwners = {}
|
||||
for id, contact in pairs(byId) do
|
||||
assert(contact.id == id, 'contact ID mismatch: ' .. id)
|
||||
local number = contact.phone and contact.phone.number
|
||||
if number then
|
||||
assert(number:match('^555%-%d%d%d%d$'), 'invalid contact number: ' .. id)
|
||||
assert(not phoneOwners[number], 'duplicate contact number: ' .. number)
|
||||
phoneOwners[number] = id
|
||||
end
|
||||
end
|
||||
|
||||
return {
|
||||
byId = byId,
|
||||
get = function(id) return byId[id] end,
|
||||
phoneOwner = function(number) return phoneOwners[number] end,
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
return {
|
||||
id = 'mack',
|
||||
displayName = 'Mack',
|
||||
phone = { number = '555-6842' },
|
||||
ped = {
|
||||
model = 's_m_y_xmech_01',
|
||||
coords = { x = 2366.60, y = 3154.91, z = 48.21, w = 17.84 },
|
||||
spawnZOffset = -1.0,
|
||||
scenario = 'WORLD_HUMAN_CLIPBOARD',
|
||||
invincible = true, frozen = true, blockNonTemporaryEvents = true,
|
||||
},
|
||||
world = {
|
||||
alwaysPresent = true,
|
||||
vehicles = {
|
||||
{
|
||||
id = 'festival_bus', model = 'pbus2',
|
||||
coords = { x = 2349.54, y = 3133.84, z = 48.21, w = 77.73 },
|
||||
localEntity = true, locked = 2, missionEntity = true,
|
||||
invincible = true, frozen = true,
|
||||
},
|
||||
{
|
||||
id = 'junk_emperor', model = 'emperor',
|
||||
coords = { x = 2343.67, y = 3141.72, z = 48.21, w = 211.39 },
|
||||
localEntity = true, locked = 2, missionEntity = true,
|
||||
invincible = true, frozen = true,
|
||||
damage = {
|
||||
engineHealth = 100.0, bodyHealth = 300.0,
|
||||
smashedWindows = { 0, 1, 2, 3 }, brokenDoors = { 0 },
|
||||
burstTyres = { 0, 4 },
|
||||
},
|
||||
},
|
||||
{
|
||||
id = 'forklift', model = 'forklift',
|
||||
coords = { x = 2350.42, y = 3142.49, z = 48.21, w = 231.27 },
|
||||
localEntity = true, locked = 2, missionEntity = true,
|
||||
invincible = true, frozen = true,
|
||||
},
|
||||
},
|
||||
ambientPeds = {
|
||||
{ model = 's_m_y_xmech_02', coords = { x = 2355.0, y = 3148.0, z = 48.21, w = 180.0 }, wanderRadius = 12.0 },
|
||||
{ model = 's_m_m_autoshop_01', coords = { x = 2345.0, y = 3150.0, z = 48.21, w = 90.0 }, wanderRadius = 12.0 },
|
||||
{ model = 's_m_y_construct_01', coords = { x = 2360.0, y = 3143.0, z = 48.21, w = 270.0 }, wanderRadius = 15.0 },
|
||||
{ model = 's_m_y_construct_02', coords = { x = 2341.0, y = 3130.0, z = 48.21, w = 0.0 }, wanderRadius = 10.0 },
|
||||
{ model = 's_m_m_dockwork_01', coords = { x = 2334.0, y = 3125.0, z = 48.21, w = 180.0 }, wanderRadius = 15.0 },
|
||||
{ model = 's_m_m_gardener_01', coords = { x = 2368.0, y = 3130.0, z = 48.21, w = 90.0 }, wanderRadius = 22.0 },
|
||||
},
|
||||
ambientPedBehavior = {
|
||||
spawnZOffset = -1.0, missionEntity = true, invincible = true,
|
||||
blockNonTemporaryEvents = true, canRagdoll = false,
|
||||
fleeAttributes = 0, wanderMinLength = 2.0, wanderTimeBetweenWalks = 10.0,
|
||||
},
|
||||
},
|
||||
blip = {
|
||||
label = 'Mack', sprite = 280, scale = 0.75, shortRange = false,
|
||||
requires = { column = 'mack_stage', min = 1 },
|
||||
createdDuring = 'crowbar:4',
|
||||
},
|
||||
interaction = {
|
||||
name = 'how_progression_mack_talk', icon = 'fa-solid fa-comment',
|
||||
label = 'Talk to Mack', distance = 2.0,
|
||||
gateCallback = 'how_progression:server:canTalkToMack',
|
||||
gateAllowsWhen = true,
|
||||
missionStateCallback = 'how_progression:server:getMackMission1State',
|
||||
},
|
||||
progression = { stageColumn = 'mack_stage', repColumn = 'mack_rep' },
|
||||
missions = { 'mack:1' },
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
return {
|
||||
id = 'unknown',
|
||||
displayName = 'UNKNOWN',
|
||||
phone = { number = '555-0100' },
|
||||
progression = { introductionFlag = 'unknown_introduced' },
|
||||
missions = {},
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
return {
|
||||
id = 'vinny',
|
||||
displayName = 'Vinny',
|
||||
phone = { number = '555-3176' },
|
||||
ped = {
|
||||
model = 'a_m_m_business_01',
|
||||
coords = { x = 1362.57, y = 3602.49, z = 34.96, w = 236.75 },
|
||||
spawnZOffset = -1.0,
|
||||
scenario = 'WORLD_HUMAN_STAND_IMPATIENT',
|
||||
missionEntity = true, invincible = true, frozen = true,
|
||||
blockNonTemporaryEvents = true,
|
||||
},
|
||||
world = {
|
||||
createdDuring = 'mack:1',
|
||||
restoredWhen = { vinny_fence_unlocked = 1 },
|
||||
vehicles = {
|
||||
{ model = 'sanchez', coords = { x = 1368.39, y = 3594.54, z = 34.34, w = 237.54 } },
|
||||
{ model = 'sanchez', coords = { x = 1366.95, y = 3598.24, z = 34.37, w = 244.92 } },
|
||||
{ model = 'sanchez', coords = { x = 1368.76, y = 3592.05, z = 34.37, w = 241.99 } },
|
||||
{ model = 'sanchez', coords = { x = 1357.67, y = 3601.45, z = 34.44, w = 194.85 } },
|
||||
{ model = 'sanchez', coords = { x = 1364.94, y = 3603.77, z = 34.33, w = 195.30 } },
|
||||
},
|
||||
vehicleBehavior = {
|
||||
localEntity = true, missionEntity = true, locked = 2,
|
||||
invincible = true, frozen = true,
|
||||
purchaseEvent = 'qbx_vehicleshop:server:buyShowroomVehicle',
|
||||
},
|
||||
},
|
||||
blip = {
|
||||
label = 'Vinny', sprite = 226, scale = 0.7, shortRange = true,
|
||||
createdDuring = 'mack:1', restoredWhen = { vinny_fence_unlocked = 1 },
|
||||
},
|
||||
interaction = {
|
||||
name = 'how_progression_vinny_talk', icon = 'fa-solid fa-comment',
|
||||
label = 'Talk to Vinny', distance = 2.0,
|
||||
requiresObjective = 'talk_vinny',
|
||||
},
|
||||
fence = {
|
||||
coords = { x = 1356.79, y = 3617.37, z = 34.88, w = 105.38 },
|
||||
requires = { vinny_fence_unlocked = 1 },
|
||||
vehicleModel = 'sanchez', dailyLimit = 3,
|
||||
payoutItem = 'markedbills', payoutWorth = 200,
|
||||
},
|
||||
associatedMissions = { 'mack:1' },
|
||||
missions = {},
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
-- /testcontact's temporary NPWD fixture, not a permanent story contact.
|
||||
-- Its 555 number is intentionally generated by the legacy debug command.
|
||||
return {
|
||||
displayName = 'Michael',
|
||||
avatarUrl = 'https://fivemedia.howlerdesign.com/media/6801a2d6-659f-46e3-b0ee-028a9a4ac215.png',
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
-- Named mission locations copied from the live scripts. Legacy scripts still
|
||||
-- own gameplay until each mission is migrated.
|
||||
return {
|
||||
crowbar = {
|
||||
mission1Vehicle = { x = 911.40, y = 3589.50, z = 33.25, w = 91.36 },
|
||||
mission1Return = { x = 1705.50, y = 3771.76, z = 34.49 },
|
||||
mission2Vehicle = { x = 2684.30, y = 3292.18, z = 54.75, w = 240.63 },
|
||||
harmonyRegister = { x = 549.33, y = 2669.57, z = 42.16, storeIndex = 13 },
|
||||
mission5Package = { x = 1537.56, y = 1700.49, z = 109.68 },
|
||||
mission5CrateZ = 108.6397,
|
||||
mission5Ambush = {
|
||||
{ model = 'rebel', spawn = { x = 1464.0, y = 1760.0, z = 108.0, w = 130.0 }, destination = { x = 1521.0, y = 1715.0, z = 109.0 } },
|
||||
{ model = 'bodhi2', spawn = { x = 1448.0, y = 1774.0, z = 108.0, w = 130.0 }, destination = { x = 1513.0, y = 1723.0, z = 109.0 } },
|
||||
},
|
||||
},
|
||||
mack = {
|
||||
easyRiderBikeSpawns = {
|
||||
{ x = 2360.90, y = 3114.91, z = 48.21, w = 239.14 },
|
||||
{ x = 2360.28, y = 3113.93, z = 48.21, w = 245.54 },
|
||||
{ x = 2359.64, y = 3112.59, z = 48.21, w = 265.43 },
|
||||
{ x = 2359.45, y = 3111.15, z = 48.21, w = 246.34 },
|
||||
{ x = 2361.34, y = 3117.44, z = 48.21, w = 234.06 },
|
||||
},
|
||||
easyRiderDetour = { x = 252.87, y = 2814.15, z = 43.19 },
|
||||
easyRiderTrashCar = { x = 285.10, y = 2827.15, z = 42.89, w = 116.30 },
|
||||
easyRiderVinnyDelivery = { x = 1373.86, y = 3615.83, z = 34.89 },
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
-- Mission IDs and debug phases are strings. Existing /prog still parses its
|
||||
-- own arguments; this module is for future migration of that command.
|
||||
local definitions = {
|
||||
['crowbar:1'] = { contact = 'crowbar', number = 1, name = 'The Introduction', phases = { 'retrieve_vehicle', 'return_vehicle', 'complete' } },
|
||||
['crowbar:2'] = { contact = 'crowbar', number = 2, name = 'Get Some Wheels', phases = { 'steal_vehicle', 'complete' } },
|
||||
['crowbar:3'] = { contact = 'crowbar', number = 3, name = 'Quick Score', phases = { 'rob_register', 'lose_cops', 'complete' } },
|
||||
['crowbar:4'] = { contact = 'crowbar', number = 4, name = 'Wash the Cash', phases = { 'meet_mack', 'meet_gabe', 'wash_cash', 'complete' } },
|
||||
['crowbar:5'] = { contact = 'crowbar', number = 5, name = 'Buy In', phases = { 'get_package', 'escape_ambush', 'return_package', 'complete' } },
|
||||
['mack:1'] = { contact = 'mack', number = 1, name = 'Easy Rider', phases = {} },
|
||||
}
|
||||
|
||||
local M = { definitions = definitions }
|
||||
|
||||
function M.missionId(contact, number)
|
||||
if type(contact) ~= 'string' or not contact:match('^[a-z][a-z_]*$')
|
||||
or type(number) ~= 'number' or number % 1 ~= 0
|
||||
or number < 1 or number > 999
|
||||
then
|
||||
return nil
|
||||
end
|
||||
|
||||
return ('%s:%d'):format(contact, number)
|
||||
end
|
||||
|
||||
function M.phaseId(missionId, phaseName)
|
||||
if not definitions[missionId] or type(phaseName) ~= 'string'
|
||||
or not phaseName:match('^[a-z][a-z_]*$')
|
||||
then
|
||||
return nil
|
||||
end
|
||||
|
||||
return missionId .. ':' .. phaseName
|
||||
end
|
||||
|
||||
function M.parseProgPhase(contact, notation)
|
||||
if type(notation) ~= 'string' then return nil end
|
||||
|
||||
local missionText, phaseText = notation:match('^(%d+)%.(%d+)$')
|
||||
if not missionText then return nil end
|
||||
if #missionText > 3 or #phaseText > 3 then return nil end
|
||||
|
||||
local missionNumber, phaseNumber = tonumber(missionText), tonumber(phaseText)
|
||||
if not missionNumber or not phaseNumber or missionNumber < 1 or phaseNumber < 1 then
|
||||
return nil
|
||||
end
|
||||
|
||||
local id = M.missionId(contact, missionNumber)
|
||||
local definition = definitions[id]
|
||||
local phaseName = definition and definition.phases[phaseNumber]
|
||||
if not phaseName then return nil end
|
||||
|
||||
return {
|
||||
missionId = id,
|
||||
phaseId = M.phaseId(id, phaseName),
|
||||
missionNumber = missionNumber,
|
||||
phaseNumber = phaseNumber,
|
||||
phaseName = phaseName,
|
||||
notation = notation,
|
||||
}
|
||||
end
|
||||
|
||||
return M
|
||||
Reference in New Issue
Block a user