Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CrewContracts - onUpdateBB #5596

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

zonkmachine
Copy link
Member

@zonkmachine zonkmachine commented Jul 15, 2023

Introduce onUpdateBB to the CrewContracts module.

Some points:

  • It's unclear to me what happens when a character is deleted when it's busy in an interview (onChat) but I believe another character gets removed (the next in line) instead when the character is employed and taken off the list. In any case the crew ad update doesn't seem to interfere with the onChat action with a candidate and it can be employed and will show up on the payroll.

Fixes #5510

@impaktor
Copy link
Member

The speed at which the table changes depends on the number of applicants which means most time will be spent in a lower number of crew applicants.

I'm not suggesting any changes to the PR (haven't looked at the code, yet), but if you want to see how number of available ships in the market place was done, I wrote a post on that in #3243, assuming you're facing something similar here, with number of crew contracts, and how these are updated / churn

@zonkmachine
Copy link
Member Author

I wrote a post on that in #3243,

Those plots are mesmerizing...

@zonkmachine
Copy link
Member Author

zonkmachine commented Jul 16, 2023

@Gliese852 Thanks for the review! I'm currently looking into the algorithm @impaktor linked to above. May need to rewrite this. I like this one though.

@zonkmachine
Copy link
Member Author

zonkmachine commented Jul 17, 2023

Number of applicants over about two and a half months game time. There is no affinity to any mean number but just a free running capitalistic hell. System Administration Resting has max applicants of 11 and Cydonia 39. In these scenarios I have modified the chance of reseeding after hitting zero from one in ten to one in a hundred. That's maybe a bit too long of a wait but I think it should be pretty high. Sometimes things just go bad. :)

graph4

@zonkmachine zonkmachine marked this pull request as draft July 18, 2023 19:21
@zonkmachine
Copy link
Member Author

@impaktor OK, trying your way. I haven't tweaked the values to fit the human market yet.

@zonkmachine
Copy link
Member Author

zonkmachine commented Jul 19, 2023

Graph redone for 2.5 months of human galactic migration. This is with the same variables as for the ship market. Please note that the population base is different between master and this PR. Crew Ad used Game.system.population and the one from the ship market uses station.path:GetSystemBody().parent.population. There is more drama in the earlier code.

graph5

@zonkmachine
Copy link
Member Author

Rebased. When you have the 'Crew for hire" add open, the add isn't refreshed when the available crew changes.

@ollobrains
Copy link

-- CrewContracts.lua

local CrewContracts = {}

-- We'll store the applicant data in a local table:
local applicantPool = {}
local reSeedTimer = 0
local activeCandidateID = nil -- Track ID of a candidate currently in an interview.

-- Configuration
local MIN_APPLICANTS = 1
local MAX_APPLICANTS = 5
local RESEED_DELAY = 3600 -- e.g., after 1 hour of in-game time (or any timescale you use)
local UPDATE_FREQ = 60 -- call this function every 60s of in-game time, for example

-- Called once at game start or module init
function CrewContracts.Init()
-- Seed with some initial set of applicants
CrewContracts.SeedApplicants()
Event.Register("onUpdateBB", CrewContracts.onUpdateBB)
end

function CrewContracts.SeedApplicants()
local numToSeed = math.random(MIN_APPLICANTS, MAX_APPLICANTS)
for i = 1, numToSeed do
table.insert(applicantPool, CrewContracts.GenerateApplicant())
end
reSeedTimer = 0 -- reset the timer whenever we seed
end

function CrewContracts.GenerateApplicant()
-- Return a table describing the applicant: name, skill, wages, personality, etc.
return {
id = Engine.rand:Integer(1,9999999),
name = CrewContracts.RandomName(),
skill = math.random(1,5),
employed = false,
busy = false, -- or 'inDialogue' to track interview status
}
end

-- This function runs periodically (e.g., every 60 in-game seconds).
function CrewContracts.onUpdateBB(deltaTime)
-- If there's an applicant in dialogue, do not remove them.
-- We'll only remove "idle" applicants or add new ones.

-- 1) Possibly remove or add an applicant based on some conditions:
-- e.g., random chance to rotate an applicant out or in.

if #applicantPool > 0 then
local randomCandidateIndex = math.random(1, #applicantPool)
local candidate = applicantPool[randomCandidateIndex]

-- Example condition: remove an idle candidate with some probability
-- only if they are not the activeCandidateID
if not candidate.busy and (math.random() < 0.01) then
  table.remove(applicantPool, randomCandidateIndex)
end

-- Example condition: add a new candidate if we’re under MAX_APPLICANTS
if #applicantPool < MAX_APPLICANTS and (math.random() < 0.05) then
  table.insert(applicantPool, CrewContracts.GenerateApplicant())
end

else
-- If we have 0 applicants, increment the reSeedTimer
reSeedTimer = reSeedTimer + deltaTime
if reSeedTimer >= RESEED_DELAY then
-- Re-seed the applicant pool
CrewContracts.SeedApplicants()
end
end

-- Additional logic to handle population-based speeds, if desired.

end

-- Called when the player initiates or ends a chat
function CrewContracts.onChatStart(candidateId)
-- Mark candidate as busy or active
for _, c in ipairs(applicantPool) do
if c.id == candidateId then
c.busy = true
activeCandidateID = candidateId
return
end
end
end

function CrewContracts.onChatEnd(candidateId, hired)
-- If hired, remove from applicantPool or mark as 'employed'
-- If not hired, set 'busy' = false
for i, c in ipairs(applicantPool) do
if c.id == candidateId then
if hired then
c.employed = true
table.remove(applicantPool, i)
else
c.busy = false
end
break
end
end
activeCandidateID = nil
end

-- Optional: a function to ensure we don't remove or re-roll an active candidate
function CrewContracts.SafeRemoveIdleCandidates()
-- Only remove those with c.busy == false, or c.id ~= activeCandidateID
end

-- etc...

return CrewContracts

@ollobrains
Copy link

  1. Outline of the Enhancement
    Purpose of onUpdateBB()

onUpdateBB() is a periodic update function (e.g., called from Pioneer’s UpdateBB() or your own tick/event hook) that manages the rotating pool of crew applicants:
Add or remove applicants based on certain conditions (population, random chance, or time intervals).
Re-seed applicants if the pool ever drops to zero.
Avoiding Conflict with Ongoing Interviews

We’ll design the solution so that if a character is mid-interview (onChat with a player), the changes in the applicant list don’t invalidate that interview or accidentally remove the interviewee.
We can track an “active candidate” status so that an applicant currently in dialogue won’t be removed until after the chat concludes.
Adaptive Speed for Applicant Turnover

The frequency at which new crew members appear or old ones leave can be tied to population or remain uniform if you want simpler balancing:
A small station might only rotate one new applicant every few days.
A busy high-population port might see multiple new applicants appear every day.
Re-Seeding at Zero Applicants

If the applicant pool hits zero, we queue a re-seed timer so after X in-game hours or upon a certain event, a new batch of random applicants appears.
This prevents the module from getting permanently stuck with an empty list.

  1. Example Pseudocode (Lua-ish)
    Below is a pseudocode snippet illustrating how you might implement onUpdateBB() in the CrewContracts module. Adjust naming and references to match your actual codebase.
Notes on This Approach Seeding Logic CrewContracts.SeedApplicants() populates the list with a random number of new candidates between MIN_APPLICANTS and MAX_APPLICANTS. If the list ever drops to zero, we wait until the RESEED_DELAY passes and then repopulate. Timing & Frequencies You can tune the frequency of calling onUpdateBB and how quickly applicants come or go based on gameplay preference. Non-Interference with Interviews We mark any candidate in an active chat as busy. Your removal logic checks candidate.busy (or candidate.id ~= activeCandidateID) to avoid removing an active interviewee. Population-Based Variation (Optional) To mimic a big station vs. a tiny outpost, you could pass a “population factor” to onUpdateBB or store it in the station data. Then, when deciding whether to remove/add an applicant, you weigh the probability by that factor. 3. Addressing Your Specific Points Character Deletion During Interview

Solution: We track an activeCandidateID. If a candidate is mid-interview, we skip removing them. Once the interview is done (onChatEnd), we either finalize them as hired or set them as idle again.
Speed of Table Changes

Solution: Tweak the random() conditions or the time intervals in onUpdateBB(). You can tie it to population (e.g., big stations = more frequent turnover).
When Applicants Reach Zero

Solution: The code checks if #applicantPool == 0, increments reSeedTimer, and seeds new applicants once the timer hits RESEED_DELAY. This ensures the module recovers from an empty list automatically.
Minimal Interference

Because we only add/remove “idle” applicants or apply re-seeding on an empty list, we don’t disrupt any ongoing onChat or onHire process. The module continues functioning seamlessly.
4. Further Improvements
Persistent Storage: If you want the applicant pool to persist across save/load cycles, store it in a JSON or a custom data structure. On game load, re-initialize the pool from that saved state.
GUI & Feedback: Provide the player with some in-game interface or messages hinting that new applicants have arrived, or that no one is currently looking for work.
Character Depth: Expand the GenerateApplicant() logic to create more varied stats—maybe random backgrounds, skill specialties, or personality quirks that influence gameplay.
Conclusion
By adding an onUpdateBB() function that periodically adds, removes, or reseeds your applicant pool, you keep the CrewContracts system lively and dynamic. Incorporating checks for ongoing chats ensures no collisions with the candidate interview process. This modular approach ensures the game remains interesting—even if sometimes the number of applicants drops to zero—while giving you a clear hook (onUpdateBB) to balance crew availability over time.

@zonkmachine
Copy link
Member Author

Rebased on master

@zonkmachine
Copy link
Member Author

zonkmachine commented Jan 4, 2025

Rebased. When you have the 'Crew for hire" add open, the add isn't refreshed when the available crew changes.

This is the only issue I can find, otherwise the code adopted from @impaktor works well here.

To test the issue:

  • Start a game at Barnard's Star (as it frequently sees a crew of 0 which helps in assessing the issue). Make sure to have space for one crew.
  • Set game speed to max.
  • Open the 'CREW FOR HIRE' ad and select one of the applicants to open the dialog. Watch the output of the command-line and see when Info: #nonPersistentCharactersForCrew: 3 goes to 0. Now there should be no applicants available but you still have the dialog open.
  • Press "Make offer of position ..."
  • The applicant is now in the crew.

It's not super clean and not all clear what's going on but maybe it's not a problem when the debug line is removed and we're not reminded of it. Essentially the character seem to be still applicable when the crew list goes to zero. The alternative would be to see the dialog window close on that event and this to me sounds possibly messy. Maybe this is ready for review?

@zonkmachine zonkmachine marked this pull request as ready for review January 4, 2025 23:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Crew for Hire BBS ad doesn't dynamically spawn
4 participants