Files
bee-reward/company.nut

270 lines
8.5 KiB
Plaintext

// Company related data.
// A goal for a company.
class CompanyGoal {
cargo_id = null; // Cargo id
accept = null; // Accepting resource.
wanted_amount = null; // Amount to deliver for achieving the goal.
delivered_amount = 0; // Amount delivered so far.
goal_id = null; // Number of the goal in OpenTTD goal window.
timeout = null; // Timeout in ticks before the goal becomes obsolete.
constructor(comp_id, cargo_id, accept, wanted_amount, cargoes) {
this.cargo_id = cargo_id;
this.accept = accept;
this.wanted_amount = wanted_amount;
this.timeout = 60 * 30 * 74; // 60 months timeout (30 days, 74 ticks).
// Construct goal.
local destination, destination_string, goal_type;
if ("town" in this.accept) {
destination = accept.town;
destination_string = GSText(GSText.STR_TOWN_NAME, destination);
goal_type = GSGoal.GT_TOWN;
} else {
destination = accept.ind;
destination_string = GSText(GSText.STR_INDUSTRY_NAME, destination);
goal_type = GSGoal.GT_INDUSTRY;
}
local goal_text = GSText(GSText.STR_COMPANY_GOAL, cargoes[this.cargo_id].cid, this.wanted_amount, destination_string);
this.goal_id = GSGoal.New(comp_id, goal_text, goal_type, destination);
}
function AddMonitorElement(mon);
function UpdateDelivered(mon);
function UpdateTimeout(step);
function CheckFinished();
function FinalizeGoal();
};
// Add an entry to the collection of monitored things.
// @param [inout] mon Table with 'cargo_id' to 'town' and 'ind' tables, holding ids to 'null'.
function CompanyGoal::AddMonitorElement(mon)
{
if (!(this.cargo_id in mon)) mon[this.cargo_id] <- {};
mon = mon[this.cargo_id];
if ("ind" in this.accept) {
if (!("ind" in mon)) mon.ind <- {};
mon.ind[this.accept.ind] <- null;
} else {
if (!("town" in mon)) mon.town <- {};
mon.town[this.accept.town] <- null;
}
}
// Update the delivered amount from the monitored amounts.
function CompanyGoal::UpdateDelivered(mon)
{
local delivered;
if ("ind" in this.accept) {
delivered = mon[this.cargo_id].ind[this.accept.ind];
} else {
delivered = mon[this.cargo_id].town[this.accept.town];
}
if (delivered > 0) {
this.delivered_amount += delivered;
if (this.goal_id != null) {
local perc;
if (this.delivered_amount >= this.wanted_amount) {
perc = 100;
GSGoal.SetCompleted(this.goal_id, true);
} else {
perc = 100 * this.delivered_amount / this.wanted_amount;
if (perc > 100) perc = 100;
}
local progress_text = GSText(GSText.STR_PROGRESS, perc);
GSGoal.SetProgress(this.goal_id, progress_text);
}
}
}
// Update the timeout of the goal
// @param step Number of passed ticks.
function CompanyGoal::UpdateTimeout(step)
{
this.timeout -= step;
if (this.goal_id != null) {
local remaining = this.timeout;
if (remaining < 0) remaining = 0;
if (this.delivered_amount > 0) return; // Don't print remaining ticks when there is cargo delivered.
local progress_text = GSText(GSText.STR_TIMEOUT, remaining);
GSGoal.SetProgress(this.goal_id, progress_text);
}
}
// Test whether the goal can be considered 'done' (or obsolete).
// @return Whether the goal is considered done.
function CompanyGoal::CheckFinished()
{
return this.timeout < 0 || this.delivered_amount >= this.wanted_amount;
}
// Goal is considered 'done', last chance to clean up before the goal is dropped
// (to make room for a new goal).
function CompanyGoal::FinalizeGoal()
{
if (this.goal_id != null) GSGoal.Remove(this.goal_id);
}
class CompanyData {
comp_id = null;
active_goals = null;
constructor(comp_id) {
this.active_goals = {};
this.comp_id = comp_id;
for (local num = 0; num < 5; num += 1) this.active_goals[num] <- null;
}
function GetMissingGoalCount();
function AddActiveGoal(cargo_id, accept, amount, cargoes);
function HasGoal(cargo_id, accept);
function GetNumberOfGoalsForCargo(cargo_id);
function IndustryClosed(ind_id);
function AddMonitorElement(mon);
function UpdateDelivered(mon);
function UpdateTimeout(step);
function CheckAndFinishGoals();
function FinalizeCompany();
};
// Company is about to be deleted, last chance to clean up.
function CompanyData::FinalizeCompany()
{
foreach (num, goal in this.active_goals) {
if (goal != null) {
goal.FinalizeGoal();
this.active_goals[num] = null;
}
}
}
// Find the number of active goals that are missing for this company.
// @return Number of additional goals that the company needs.
function CompanyData::GetMissingGoalCount()
{
local missing = 0;
foreach (num, goal in this.active_goals) {
if (goal == null) missing += 1;
}
return missing;
}
// Add a goal to the list of the company.
// @param cargo_id Cargo of the goal.
// @param accept Accepting resource of the goal.
// @param amount Amount of cargo to deliver.
function CompanyData::AddActiveGoal(cargo_id, accept, amount, cargoes)
{
foreach (num, goal in this.active_goals) {
if (goal == null) {
this.active_goals[num] = CompanyGoal(this.comp_id, cargo_id, accept, amount, cargoes);
break;
}
}
}
// Does the company have an active goal for the given cargo and accepting resource?
// @param cargo_id Cargo to check for.
// @param accept Accepting resource to check.
// @return Whether the company has a goal for the cargo and resource.
function CompanyData::HasGoal(cargo_id, accept)
{
foreach (num, goal in this.active_goals) {
if (goal == null) continue;
if (goal.cargo_id != cargo_id) continue;
if ("town" in accept) {
if ("ind" in goal.accept || accept.town != goal.accept.town) continue;
} else {
if ("town" in goal.accept || accept.ind != goal.accept.ind) continue;
}
return true;
}
return false;
}
// Count the number of goals that ask for the given cargo type.
// @param cargo_id Cargo to check for.
// @return Number of active goals with the given cargo type.
function CompanyData::GetNumberOfGoalsForCargo(cargo_id)
{
local count = 0;
foreach (num, goal in this.active_goals) {
if (goal == null) continue;
if (goal.cargo_id == cargo_id) count += 1;
}
return count;
}
// The given industry closed, delete any goal with it.
// @param ind_id Industry that closed.
function CompanyData::IndustryClosed(ind_id)
{
foreach (num, goal in this.active_goals) {
if (goal == null) continue;
if ("ind" in goal.accept && goal.accept.ind == ind_id) {
goal.FinalizeGoal();
this.active_goals[num] = null;
}
}
}
// Add monitor elements of a company, if they exist.
// @param [inout] cmon Monitors of all companies, updated in-place.
// Result is 'comp_id' number to 'cargo_id' numbers to 'ind' and/or 'town' indices to 'null'
function CompanyData::AddMonitorElements(cmon)
{
local mon = {};
foreach (num, goal in this.active_goals) {
if (goal == null) continue;
goal.AddMonitorElement(mon);
}
if (mon.len() == 0) return;
cmon[this.comp_id] <- mon;
return;
}
// Distribute the delivered amounts to the goals.
// @param cmon Monitor results of all companies, 'comp_id' numbers to 'cargo_id' number to
// 'ind' and/or 'town' to resource indices to amount.
// @return Whether a goal is considered to be 'done'.
function CompanyData::UpdateDelivereds(cmon)
{
local finished = false;
if (this.comp_id in cmon) {
foreach (num, goal in this.active_goals) {
if (goal == null) continue;
goal.UpdateDelivered(cmon[this.comp_id]);
if (goal.CheckFinished()) finished = true;
}
}
return finished; // One or more goals was considered 'done'
}
function CompanyData::UpdateTimeout(step)
{
foreach (num, goal in this.active_goals) {
if (goal == null) continue;
goal.UpdateTimeout(step);
}
}
// Test whether goals of the company are 'done', and if so, drop them.
function CompanyData::CheckAndFinishGoals()
{
foreach (num, goal in this.active_goals) {
if (goal == null) continue;
if (goal.CheckFinished()) {
goal.FinalizeGoal();
this.active_goals[num] = null;
}
}
}