From 5770b51c9cd4a834bc84902e82917f97a0ecc3e1 Mon Sep 17 00:00:00 2001 From: Oskar Wallgren Date: Sat, 15 Jul 2023 15:59:52 +0200 Subject: [PATCH 1/6] CrewContracts - onUpdateBB --- data/modules/CrewContracts/CrewContracts.lua | 62 +++++++++++++++----- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/data/modules/CrewContracts/CrewContracts.lua b/data/modules/CrewContracts/CrewContracts.lua index 344c7973e8e..d725df9faf7 100644 --- a/data/modules/CrewContracts/CrewContracts.lua +++ b/data/modules/CrewContracts/CrewContracts.lua @@ -379,6 +379,24 @@ local isEnabled = function (ref) return numCrewmenAvailable > 0 end +local newCrew = function() + local hopefulCrew = Character.New() + -- Roll new stats, with a 1/3 chance that they're utterly inexperienced + hopefulCrew:RollNew(Engine.rand:Integer(0, 2) > 0) + -- Make them a title if they're good at anything + local maxScore = math.max(hopefulCrew.engineering, + hopefulCrew.piloting, + hopefulCrew.navigation, + hopefulCrew.sensors) + if maxScore > 45 then + if hopefulCrew.engineering == maxScore then hopefulCrew.title = lui.SHIPS_ENGINEER end + if hopefulCrew.piloting == maxScore then hopefulCrew.title = lui.PILOT end + if hopefulCrew.navigation == maxScore then hopefulCrew.title = lui.NAVIGATOR end + if hopefulCrew.sensors == maxScore then hopefulCrew.title = lui.SENSORS_AND_DEFENCE end + end + return hopefulCrew +end + local onCreateBB = function (station) -- Create non-persistent Characters as available crew nonPersistentCharactersForCrew[station] = {} @@ -393,26 +411,38 @@ local onCreateBB = function (station) -- Number is based on population, nicked from Assassinations.lua and tweaked for i = 1, Engine.rand:Integer(0, math.ceil(Game.system.population) * 2 + 1) do - local hopefulCrew = Character.New() - -- Roll new stats, with a 1/3 chance that they're utterly inexperienced - hopefulCrew:RollNew(Engine.rand:Integer(0, 2) > 0) - -- Make them a title if they're good at anything - local maxScore = math.max(hopefulCrew.engineering, - hopefulCrew.piloting, - hopefulCrew.navigation, - hopefulCrew.sensors) - if maxScore > 45 then - if hopefulCrew.engineering == maxScore then hopefulCrew.title = lui.SHIPS_ENGINEER end - if hopefulCrew.piloting == maxScore then hopefulCrew.title = lui.PILOT end - if hopefulCrew.navigation == maxScore then hopefulCrew.title = lui.NAVIGATOR end - if hopefulCrew.sensors == maxScore then hopefulCrew.title = lui.SENSORS_AND_DEFENCE end - end - table.insert(nonPersistentCharactersForCrew[station],hopefulCrew) + table.insert(nonPersistentCharactersForCrew[station],newCrew()) end end - Event.Register("onCreateBB", onCreateBB) +local onUpdateBB = function (station) + -- If no crew available (ad is greyed out), reseed the table after a while + if #nonPersistentCharactersForCrew[station] < 1 and Engine.rand:Integer(0, 10) == 0 then -- Not much crew around + table.insert(nonPersistentCharactersForCrew[station],newCrew()) + print("Reseeding crew candidates") + else + -- 1 in 30 to be removed and then maybe someone new inserted + for k,v in pairs(nonPersistentCharactersForCrew[station]) do + if #nonPersistentCharactersForCrew[station] > 0 then + if Engine.rand:Integer(0, 100) == 0 then + table.remove(nonPersistentCharactersForCrew[station],k) + print("Removing crew candidate. #nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) + end + end + end + for k,v in pairs(nonPersistentCharactersForCrew[station]) do + if #nonPersistentCharactersForCrew[station] < math.ceil(Game.system.population) * 2 + 1 then + if Engine.rand:Integer(0, 100) == 0 then + table.insert(nonPersistentCharactersForCrew[station],k,newCrew()) + print("Adding crew candidate. #nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) + end + end + end + end +end +Event.Register("onUpdateBB", onUpdateBB) + -- Wipe temporary crew out when hyperspacing Event.Register("onEnterSystem", function(ship) if ship:IsPlayer() then From ed5ee818b159f0b8d337399165ff99d92d5597ce Mon Sep 17 00:00:00 2001 From: Oskar Wallgren Date: Sun, 16 Jul 2023 17:08:16 +0200 Subject: [PATCH 2/6] fix issues from review --- data/modules/CrewContracts/CrewContracts.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/data/modules/CrewContracts/CrewContracts.lua b/data/modules/CrewContracts/CrewContracts.lua index d725df9faf7..07aefa548d3 100644 --- a/data/modules/CrewContracts/CrewContracts.lua +++ b/data/modules/CrewContracts/CrewContracts.lua @@ -418,14 +418,14 @@ Event.Register("onCreateBB", onCreateBB) local onUpdateBB = function (station) -- If no crew available (ad is greyed out), reseed the table after a while - if #nonPersistentCharactersForCrew[station] < 1 and Engine.rand:Integer(0, 10) == 0 then -- Not much crew around + if #nonPersistentCharactersForCrew[station] < 1 and Engine.rand:Integer(0, 99) == 0 then -- Not much crew around table.insert(nonPersistentCharactersForCrew[station],newCrew()) print("Reseeding crew candidates") else - -- 1 in 30 to be removed and then maybe someone new inserted + -- 1 in 100 to be removed and then maybe someone new inserted for k,v in pairs(nonPersistentCharactersForCrew[station]) do if #nonPersistentCharactersForCrew[station] > 0 then - if Engine.rand:Integer(0, 100) == 0 then + if Engine.rand:Integer(0, 99) == 0 then table.remove(nonPersistentCharactersForCrew[station],k) print("Removing crew candidate. #nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) end @@ -433,7 +433,7 @@ local onUpdateBB = function (station) end for k,v in pairs(nonPersistentCharactersForCrew[station]) do if #nonPersistentCharactersForCrew[station] < math.ceil(Game.system.population) * 2 + 1 then - if Engine.rand:Integer(0, 100) == 0 then + if Engine.rand:Integer(0, 99) == 0 then table.insert(nonPersistentCharactersForCrew[station],k,newCrew()) print("Adding crew candidate. #nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) end From 9bcfafd82d241e53b9a107c768c4eb52fdda1888 Mon Sep 17 00:00:00 2001 From: Oskar Wallgren Date: Mon, 17 Jul 2023 15:38:01 +0200 Subject: [PATCH 3/6] fixup --- data/modules/CrewContracts/CrewContracts.lua | 22 +++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/data/modules/CrewContracts/CrewContracts.lua b/data/modules/CrewContracts/CrewContracts.lua index 07aefa548d3..469763df0fe 100644 --- a/data/modules/CrewContracts/CrewContracts.lua +++ b/data/modules/CrewContracts/CrewContracts.lua @@ -397,6 +397,11 @@ local newCrew = function() return hopefulCrew end +-- Returns a suitable max number of applicants depending on system population +local maxCrewForStation = function () + return math.ceil(Game.system.population) * 2 + 1 +end + local onCreateBB = function (station) -- Create non-persistent Characters as available crew nonPersistentCharactersForCrew[station] = {} @@ -410,7 +415,7 @@ local onCreateBB = function (station) isEnabled = isEnabled})] = station -- Number is based on population, nicked from Assassinations.lua and tweaked - for i = 1, Engine.rand:Integer(0, math.ceil(Game.system.population) * 2 + 1) do + for i = 1, Engine.rand:Integer(0, maxCrewForStation()) do table.insert(nonPersistentCharactersForCrew[station],newCrew()) end end @@ -418,28 +423,31 @@ Event.Register("onCreateBB", onCreateBB) local onUpdateBB = function (station) -- If no crew available (ad is greyed out), reseed the table after a while - if #nonPersistentCharactersForCrew[station] < 1 and Engine.rand:Integer(0, 99) == 0 then -- Not much crew around - table.insert(nonPersistentCharactersForCrew[station],newCrew()) - print("Reseeding crew candidates") + if #nonPersistentCharactersForCrew[station] < 1 then + if Engine.rand:Integer(0, 99) == 0 then -- Not much crew around + table.insert(nonPersistentCharactersForCrew[station],newCrew()) + print("Reseeding crew candidates") + end else -- 1 in 100 to be removed and then maybe someone new inserted for k,v in pairs(nonPersistentCharactersForCrew[station]) do if #nonPersistentCharactersForCrew[station] > 0 then if Engine.rand:Integer(0, 99) == 0 then table.remove(nonPersistentCharactersForCrew[station],k) - print("Removing crew candidate. #nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) + --print("Removing crew candidate. #nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) end end end for k,v in pairs(nonPersistentCharactersForCrew[station]) do - if #nonPersistentCharactersForCrew[station] < math.ceil(Game.system.population) * 2 + 1 then + if #nonPersistentCharactersForCrew[station] < maxCrewForStation() then if Engine.rand:Integer(0, 99) == 0 then table.insert(nonPersistentCharactersForCrew[station],k,newCrew()) - print("Adding crew candidate. #nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) + --print("Adding crew candidate. #nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) end end end end + print("#nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) end Event.Register("onUpdateBB", onUpdateBB) From ca35fdf8d366d75030b393341f4f8b3363d10efa Mon Sep 17 00:00:00 2001 From: Oskar Wallgren Date: Mon, 17 Jul 2023 23:23:28 +0200 Subject: [PATCH 4/6] fixup --- data/modules/CrewContracts/CrewContracts.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/modules/CrewContracts/CrewContracts.lua b/data/modules/CrewContracts/CrewContracts.lua index 469763df0fe..c3c53553646 100644 --- a/data/modules/CrewContracts/CrewContracts.lua +++ b/data/modules/CrewContracts/CrewContracts.lua @@ -424,7 +424,7 @@ Event.Register("onCreateBB", onCreateBB) local onUpdateBB = function (station) -- If no crew available (ad is greyed out), reseed the table after a while if #nonPersistentCharactersForCrew[station] < 1 then - if Engine.rand:Integer(0, 99) == 0 then -- Not much crew around + if Engine.rand:Integer(0, 29) == 0 then -- Not much crew around table.insert(nonPersistentCharactersForCrew[station],newCrew()) print("Reseeding crew candidates") end From 4d7e39f34ccc27bca6018f396f66565606c07aad Mon Sep 17 00:00:00 2001 From: Oskar Wallgren Date: Tue, 18 Jul 2023 19:07:35 +0200 Subject: [PATCH 5/6] stash --- data/modules/CrewContracts/CrewContracts.lua | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/data/modules/CrewContracts/CrewContracts.lua b/data/modules/CrewContracts/CrewContracts.lua index c3c53553646..ce1423ee58e 100644 --- a/data/modules/CrewContracts/CrewContracts.lua +++ b/data/modules/CrewContracts/CrewContracts.lua @@ -424,9 +424,13 @@ Event.Register("onCreateBB", onCreateBB) local onUpdateBB = function (station) -- If no crew available (ad is greyed out), reseed the table after a while if #nonPersistentCharactersForCrew[station] < 1 then - if Engine.rand:Integer(0, 29) == 0 then -- Not much crew around + if Engine.rand:Integer(0, 29) == 0 then -- One in thirty to reseed with one candidate. We're a bit off season. table.insert(nonPersistentCharactersForCrew[station],newCrew()) - print("Reseeding crew candidates") + print("Reseeding. One candidate added.") + return + else + print("#nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) + return end else -- 1 in 100 to be removed and then maybe someone new inserted From 29a9830a118e0f529636ad15b1f28ea2d7a82487 Mon Sep 17 00:00:00 2001 From: Oskar Wallgren Date: Tue, 18 Jul 2023 23:27:16 +0200 Subject: [PATCH 6/6] Switch to algorithm from ship market --- data/modules/CrewContracts/CrewContracts.lua | 61 ++++++++++---------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/data/modules/CrewContracts/CrewContracts.lua b/data/modules/CrewContracts/CrewContracts.lua index ce1423ee58e..4564e74eb33 100644 --- a/data/modules/CrewContracts/CrewContracts.lua +++ b/data/modules/CrewContracts/CrewContracts.lua @@ -379,6 +379,16 @@ local isEnabled = function (ref) return numCrewmenAvailable > 0 end +local function N_equilibrium(station) + local pop = station.path:GetSystemBody().parent.population -- E.g. Earth=7, Mars=0.3 + local pop_bonus = 9 * math.log(pop * 0.45 + 1) -- something that gives resonable result + if station.type == "STARPORT_SURFACE" then + pop_bonus = pop_bonus * 1.5 + end + + return 2 + pop_bonus +end + local newCrew = function() local hopefulCrew = Character.New() -- Roll new stats, with a 1/3 chance that they're utterly inexperienced @@ -397,9 +407,11 @@ local newCrew = function() return hopefulCrew end --- Returns a suitable max number of applicants depending on system population -local maxCrewForStation = function () - return math.ceil(Game.system.population) * 2 + 1 +local function removeAd (station, num) + if not nonPersistentCharactersForCrew[station] then + nonPersistentCharactersForCrew[station] = {} + end + table.remove(nonPersistentCharactersForCrew[station], num) end local onCreateBB = function (station) @@ -415,43 +427,30 @@ local onCreateBB = function (station) isEnabled = isEnabled})] = station -- Number is based on population, nicked from Assassinations.lua and tweaked - for i = 1, Engine.rand:Integer(0, maxCrewForStation()) do + for i = 1, Engine.rand:Poisson(N_equilibrium(station)) do table.insert(nonPersistentCharactersForCrew[station],newCrew()) end end Event.Register("onCreateBB", onCreateBB) local onUpdateBB = function (station) - -- If no crew available (ad is greyed out), reseed the table after a while - if #nonPersistentCharactersForCrew[station] < 1 then - if Engine.rand:Integer(0, 29) == 0 then -- One in thirty to reseed with one candidate. We're a bit off season. - table.insert(nonPersistentCharactersForCrew[station],newCrew()) - print("Reseeding. One candidate added.") - return - else - print("#nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) - return - end - else - -- 1 in 100 to be removed and then maybe someone new inserted - for k,v in pairs(nonPersistentCharactersForCrew[station]) do - if #nonPersistentCharactersForCrew[station] > 0 then - if Engine.rand:Integer(0, 99) == 0 then - table.remove(nonPersistentCharactersForCrew[station],k) - --print("Removing crew candidate. #nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) - end - end - end - for k,v in pairs(nonPersistentCharactersForCrew[station]) do - if #nonPersistentCharactersForCrew[station] < maxCrewForStation() then - if Engine.rand:Integer(0, 99) == 0 then - table.insert(nonPersistentCharactersForCrew[station],k,newCrew()) - --print("Adding crew candidate. #nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) - end - end + local tau = 7*24 -- half life of a ship advert in hours + local lambda = 0.693147 / tau -- removal probability= ln(2) / tau + local prod = N_equilibrium(station) * lambda -- creation probability + + -- remove with decay rate lambda. Call ONCE/hour for each ship advert in station + for k,v in pairs(nonPersistentCharactersForCrew[station]) do + if Engine.rand:Number(0,1) < lambda then -- remove one random ship (sold) + table.remove(nonPersistentCharactersForCrew[station],k) end end + + -- spawn a new ship adverts, call for each station + if Engine.rand:Number(0,1) <= prod then + table.insert(nonPersistentCharactersForCrew[station], 1, newCrew()) + end print("#nonPersistentCharactersForCrew: " .. #nonPersistentCharactersForCrew[station]) + if prod > 1 then print("Warning: crew market not in equilibrium") end end Event.Register("onUpdateBB", onUpdateBB)