From 28d71ad2df40678ce57052a0e74bebb9c97448ea Mon Sep 17 00:00:00 2001 From: Alberth Date: Mon, 29 Dec 2014 12:22:27 +0100 Subject: [PATCH] Add: Cargo delivery monitoring and updating. --- company.nut | 83 +++++++++++++++++++++++++++---- main.nut | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 208 insertions(+), 12 deletions(-) diff --git a/company.nut b/company.nut index 7ca492b..4896dd2 100644 --- a/company.nut +++ b/company.nut @@ -2,24 +2,57 @@ // A goal for a company. class CompanyGoal { - cid = null; - accept = null; - wanted_amount = null; + 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. - constructor(cid, accept, wanted_amount) { - this.cid = cid; + constructor(cargo_id, accept, wanted_amount) { + this.cargo_id = cargo_id; this.accept = accept; this.wanted_amount = wanted_amount; } + + function AddMonitorElement(mon); + function UpdateDelivered(mon); }; +// 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]; + } + + this.delivered_amount += delivered; +} + + class CompanyData { - cid = null; + comp_id = null; active_goals = {}; - constructor(cid) { - this.cid = cid; + constructor(comp_id) { + this.comp_id = comp_id; for (local num = 0; num < 5; num += 1) this.active_goals[num] <- null; } @@ -27,6 +60,9 @@ class CompanyData { function GetMissingGoalCount(); function AddActiveGoal(cargo_id, accept, amount); function HasGoal(cargo_id, accept); + + function AddMonitorElement(mon); + function UpdateDelivered(mon); }; // Find the number of active goals that are missing for this company. @@ -62,7 +98,7 @@ function CompanyData::HasGoal(cargo_id, accept) { foreach (num, goal in this.active_goals) { if (goal == null) continue; - if (goal.cid != cargo_id) continue; + if (goal.cargo_id != cargo_id) continue; if ("town" in accept) { if ("ind" in goal.accept || accept.town != goal.accept.town) continue; } else { @@ -72,3 +108,32 @@ function CompanyData::HasGoal(cargo_id, accept) } return false; } + +// 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. +function CompanyData::UpdateDelivereds(cmon) +{ + if (this.comp_id in cmon) { + foreach (num, goal in this.active_goals) { + if (goal == null) continue; + goal.UpdateDelivered(cmon[this.comp_id]); + } + } +} diff --git a/main.nut b/main.nut index 079d686..8f2d1cf 100644 --- a/main.nut +++ b/main.nut @@ -220,6 +220,8 @@ function FMainClass::Start() // Main event loop. local companies_timeout = 0; local goal_timeout = 0; + local monitor_timeout = 0; + local old_cmonitor = null; while (true) { // Check for new or disappeared companies. if (companies_timeout <= 0) { @@ -227,6 +229,7 @@ function FMainClass::Start() if (GSCompany.ResolveCompanyID(cid) == GSCompany.COMPANY_INVALID) { if (this.companies[cid] != null) { // XXX Handle company disappearing + monitor_timeout = 0; // Force updating of the goals. GSLog.Info("Deleted company " + cid); } this.companies[cid] = null; @@ -256,7 +259,10 @@ function FMainClass::Start() cid_missing = missing; } } - if (best_cid != null) this.CreateChallenge(best_cid); + if (best_cid != null) { + this.CreateChallenge(best_cid); + monitor_timeout = 0; // Force updating of the monitor. + } if (total_missing > 1) { goal_timeout = 1 * 74; // If more missing goals, wait only a short while. @@ -265,6 +271,34 @@ function FMainClass::Start() } } + // Monitoring and updating of company goals. Note that code above may force an update. + if (monitor_timeout <= 0) { + local cmon = {}; + // Collect monitors that are of interest. + foreach (cid, cdata in companies) { + if (cdata == null) continue; + cdata.AddMonitorElements(cmon); + } + + if (old_cmonitor == null) { // First run, clear any old monitoring. + GSCargoMonitor.StopAllMonitoring(); + old_cmonitor = {}; + } + this.FillMonitors(cmon); // Query the monitors. + + // Distribute the retrieved data. + foreach (cid, cdata in companies) { + if (cdata == null) continue; + cdata.UpdateDelivereds(cmon); + } + + // Drop obsolete monitors. + this.UpdateCompanyMonitors(old_cmonitor, cmon); + old_cmonitor = cmon; + + monitor_timeout = 15 * 74; // By default, check monitors every 15 days (other processes may force a check earlier). + } + // local lake_news = GSText(GSText.STR_LAKE_NEWS); // GSNews.Create(GSNews.NT_GENERAL, lake_news, GSCompany.COMPANY_INVALID); // GSGoal.Question(1, GSCompany.COMPANY_INVALID, lake_news, GSGoal.QT_INFORMATION, GSGoal.BUTTON_GO); @@ -272,12 +306,109 @@ function FMainClass::Start() // Sleep until the next event. local delay_time = 5000; if (delay_time > companies_timeout) delay_time = companies_timeout; - if (delay_time > goal_timeout) delay_time = goal_timeout; + if (delay_time > goal_timeout) delay_time = goal_timeout; + if (delay_time > monitor_timeout) delay_time = monitor_timeout; // XXX Perhaps check for company events? if (delay_time > 0) this.Sleep(delay_time); companies_timeout -= delay_time; - goal_timeout -= delay_time; + goal_timeout -= delay_time; + monitor_timeout -= delay_time; + } +} + +// Fill company monitors with monitored amounts. +// @param [inout] cmon Table of 'comp_id' number to 'cargo_id' number to +// 'ind' and/or 'town' to resource indices to 'null'. +function FMainClass::FillMonitors(cmon) +{ + foreach (comp_id, mon in cmon) { + foreach (cargo_id, rmon in mon) { + if ("ind" in rmon) { + foreach (ind_id, _ in rmon.ind) { + local amount = GSCargoMonitor.GetIndustryDeliveryAmount(comp_id, cargo_id, ind_id, true); + rmon.ind[ind_id] = amount; + local text = "Industry " + GSIndustry.GetName(ind_id) + " received " + amount + + " units for company " + comp_id + + ", cargo " + GSCargo.GetCargoLabel(cargo_id); + GSLog.Info(text); + } + } + if ("town" in rmon) { + foreach (town_id, _ in rmon.town) { + local amount = GSCargoMonitor.GetTownDeliveryAmount(comp_id, cargo_id, town_id, true); + rmon.town[town_id] = amount; + local text = "Town " + GSTown.GetName(town_id) + " received " + amount + + " units for company " + comp_id + + ", cargo " + GSCargo.GetCargoLabel(cargo_id); + GSLog.Info(text); + } + } + } + } +} + +function FMainClass::UpdateCompanyMonitors(old_cmon, cmon) +{ + foreach (comp_id, old_mon in old_cmon) { + if (comp_id in cmon) { + this.UpdateCargoMonitors(comp_id, old_mon, cmon[comp_id]); + } else { + this.UpdateCargoMonitors(comp_id, old_mon, {}); + } + } +} + +function FMainClass::UpdateCargoMonitors(comp_id, old_mon, mon) +{ + foreach (cargo_id, old_rmon in old_mon) { + if (cargo_id in mon) { + this.UpdateResourceMonitors(comp_id, cargo_id, old_rmon, mon[cargo_id]); + } else { + this.UpdateResourceMonitors(comp_id, cargo_id, old_rmon, {}); + } + } +} + +function FMainClass::UpdateResourceMonitors(comp_id, cargo_id, old_rmon, rmon) +{ + if ("town" in old_rmon) { + if ("town" in rmon) { + this.UpdateTownMonitors(comp_id, cargo_id, old_rmon.town, rmon.town); + } else { + this.UpdateTownMonitors(comp_id, cargo_id, old_rmon.town, {}); + } + } + if ("ind" in old_rmon) { + if ("ind" in rmon) { + this.UpdateIndMonitors(comp_id, cargo_id, old_rmon.ind, rmon.ind); + } else { + this.UpdateIndMonitors(comp_id, cargo_id, old_rmon.ind, {}); + } + } +} + +function FMainClass::UpdateTownMonitors(comp_id, cargo_id, old_tmon, tmon) +{ + foreach (town_id, _ in old_tmon) { + if (!(town_id in tmon)) { + GSCargoMonitor.GetTownDeliveryAmount(comp_id, cargo_id, town_id, false); + local text = "Stop monitoring town " + GSTown.GetName(town_id) + + "for company " + comp_id + ", cargo " + GSCargo.GetCargoLabel(cargo_id); + GSLog.Info(text); + } + } +} + +function FMainClass::UpdateIndMonitors(comp_id, cargo_id, old_imon, imon) +{ + foreach (ind_id, _ in old_imon) { + if (!(ind_id in imon)) { + GSCargoMonitor.GetIndustryDeliveryAmount(comp_id, cargo_id, ind_id, false); + local text = "Stop monitoring industry " + GSIndustry.GetName(ind_id) + + "for company " + comp_id + ", cargo " + GSCargo.GetCargoLabel(cargo_id); + GSLog.Info(text); + } } }