-Add: Save and load of goalies. Fixes #7366.
This commit is contained in:
103
company.nut
103
company.nut
@@ -12,25 +12,33 @@ class CompanyGoal {
|
|||||||
displayed_string = null;
|
displayed_string = null;
|
||||||
displayed_count = null;
|
displayed_count = null;
|
||||||
|
|
||||||
|
// Construct a company goal.
|
||||||
|
// @param comp_id Company owning the goal. Use \c null if no OpenTTD goal should be created.
|
||||||
|
// @param cargo Cargo that should be delivered.
|
||||||
|
// @param accept Accepting resource.
|
||||||
|
// @param wanted_amount Amount of cargo that should be delivered to fulfil the goal.
|
||||||
constructor(comp_id, cargo, accept, wanted_amount) {
|
constructor(comp_id, cargo, accept, wanted_amount) {
|
||||||
this.cargo = cargo;
|
this.cargo = cargo;
|
||||||
this.accept = accept;
|
this.accept = accept;
|
||||||
this.wanted_amount = wanted_amount;
|
this.wanted_amount = wanted_amount;
|
||||||
this.timeout = 5 * 365 * 74; // About 5 years.
|
this.timeout = 5 * 365 * 74; // About 5 years.
|
||||||
|
|
||||||
// Construct goal.
|
// Construct goal if a company id was provided.
|
||||||
local destination, destination_string, goal_type;
|
if (comp_id != null) {
|
||||||
if ("town" in this.accept) {
|
local destination, destination_string, goal_type;
|
||||||
destination = accept.town;
|
if ("town" in this.accept) {
|
||||||
destination_string = GSText(GSText.STR_TOWN_NAME, destination);
|
destination = accept.town;
|
||||||
goal_type = GSGoal.GT_TOWN;
|
destination_string = GSText(GSText.STR_TOWN_NAME, destination);
|
||||||
} else {
|
goal_type = GSGoal.GT_TOWN;
|
||||||
destination = accept.ind;
|
} else {
|
||||||
destination_string = GSText(GSText.STR_INDUSTRY_NAME, destination);
|
destination = accept.ind;
|
||||||
goal_type = GSGoal.GT_INDUSTRY;
|
destination_string = GSText(GSText.STR_INDUSTRY_NAME, destination);
|
||||||
|
goal_type = GSGoal.GT_INDUSTRY;
|
||||||
|
}
|
||||||
|
local goal_text = GSText(GSText.STR_COMPANY_GOAL, cargo.cid,
|
||||||
|
this.wanted_amount, destination_string);
|
||||||
|
this.goal_id = GSGoal.New(comp_id, goal_text, goal_type, destination);
|
||||||
}
|
}
|
||||||
local goal_text = GSText(GSText.STR_COMPANY_GOAL, cargo.cid, this.wanted_amount, destination_string);
|
|
||||||
this.goal_id = GSGoal.New(comp_id, goal_text, goal_type, destination);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function AddMonitorElement(mon);
|
function AddMonitorElement(mon);
|
||||||
@@ -38,8 +46,36 @@ class CompanyGoal {
|
|||||||
function UpdateTimeout(step);
|
function UpdateTimeout(step);
|
||||||
function CheckFinished();
|
function CheckFinished();
|
||||||
function FinalizeGoal();
|
function FinalizeGoal();
|
||||||
|
|
||||||
|
function SaveGoal();
|
||||||
|
static function LoadGoal(num, loaded_data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function CompanyGoal::SaveGoal()
|
||||||
|
{
|
||||||
|
return {cid=this.cargo.cid, accept=this.accept, wanted=this.wanted_amount,
|
||||||
|
delivered=this.delivered_amount, goal=this.goal_id, timeout=this.timeout};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load an existing goal.
|
||||||
|
// @param loaded_data Data of the goal.
|
||||||
|
// @param cargoes Cargoes of the game.
|
||||||
|
// @return The loaded goal, if loading went ok.
|
||||||
|
function CompanyGoal::LoadGoal(loaded_data, cargoes)
|
||||||
|
{
|
||||||
|
local goal = null;
|
||||||
|
foreach (cargo_num, cargo in cargoes) {
|
||||||
|
if (cargo.cid == loaded_data.cid) {
|
||||||
|
goal = CompanyGoal(null, cargo, loaded_data.accept, loaded_data.wanted);
|
||||||
|
goal.delivered_amount = loaded_data.delivered;
|
||||||
|
goal.goal_id = loaded_data.goal;
|
||||||
|
goal.timeout = loaded_data.timeout;
|
||||||
|
return goal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// Add an entry to the collection of monitored things.
|
// 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'.
|
// @param [inout] mon Table with 'cargo_id' to 'town' and 'ind' tables, holding ids to 'null'.
|
||||||
function CompanyGoal::AddMonitorElement(mon)
|
function CompanyGoal::AddMonitorElement(mon)
|
||||||
@@ -216,6 +252,7 @@ class CompanyData {
|
|||||||
|
|
||||||
function FinalizeCompany();
|
function FinalizeCompany();
|
||||||
|
|
||||||
|
function GoalsPostLoadCheck();
|
||||||
function GetMissingGoalCount();
|
function GetMissingGoalCount();
|
||||||
function AddActiveGoal(cargo, accept, amount);
|
function AddActiveGoal(cargo, accept, amount);
|
||||||
function HasGoal(cargo_id, accept);
|
function HasGoal(cargo_id, accept);
|
||||||
@@ -226,8 +263,36 @@ class CompanyData {
|
|||||||
function UpdateDelivereds(cmon);
|
function UpdateDelivereds(cmon);
|
||||||
function UpdateTimeout(step);
|
function UpdateTimeout(step);
|
||||||
function CheckAndFinishGoals();
|
function CheckAndFinishGoals();
|
||||||
|
|
||||||
|
function SaveCompany();
|
||||||
|
static function LoadCompany(comp_id, loaded_data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Save company data.
|
||||||
|
function CompanyData::SaveCompany()
|
||||||
|
{
|
||||||
|
local result = {};
|
||||||
|
foreach (num, goal in this.active_goals) {
|
||||||
|
if (goal == null) continue;
|
||||||
|
result[num] <- goal.SaveGoal();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load company data from the file, constructing a new company.
|
||||||
|
// @param comp_id Company id.
|
||||||
|
// @param loaded_data Data to load for this company.
|
||||||
|
// @param cargoes Cargoes of the game.
|
||||||
|
// @return The created company.
|
||||||
|
function CompanyData::LoadCompany(comp_id, loaded_data, cargoes)
|
||||||
|
{
|
||||||
|
local cdata = CompanyData(comp_id);
|
||||||
|
foreach(num, loaded_goal_data in loaded_data) {
|
||||||
|
cdata.active_goals[num] = CompanyGoal.LoadGoal(loaded_goal_data, cargoes);
|
||||||
|
}
|
||||||
|
return cdata;
|
||||||
|
}
|
||||||
|
|
||||||
// Company is about to be deleted, last chance to clean up.
|
// Company is about to be deleted, last chance to clean up.
|
||||||
function CompanyData::FinalizeCompany()
|
function CompanyData::FinalizeCompany()
|
||||||
{
|
{
|
||||||
@@ -239,7 +304,6 @@ function CompanyData::FinalizeCompany()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Find the number of active goals that are missing for this company.
|
// Find the number of active goals that are missing for this company.
|
||||||
// @return Number of additional goals that the company needs.
|
// @return Number of additional goals that the company needs.
|
||||||
function CompanyData::GetMissingGoalCount()
|
function CompanyData::GetMissingGoalCount()
|
||||||
@@ -310,6 +374,19 @@ function CompanyData::IndustryClosed(ind_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Game data was just loaded, check whether the goals make sense.
|
||||||
|
function CompanyData::GoalsPostLoadCheck()
|
||||||
|
{
|
||||||
|
// Check whether the industries still live.
|
||||||
|
foreach (num, goal in this.active_goals) {
|
||||||
|
if (goal == null) continue;
|
||||||
|
if ("ind" in goal.accept && !GSIndustry.IsValidIndustry(goal.accept.ind)) {
|
||||||
|
goal.FinalizeGoal();
|
||||||
|
this.active_goals[num] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add monitor elements of a company, if they exist.
|
// Add monitor elements of a company, if they exist.
|
||||||
// @param [inout] cmon Monitors of all companies, updated in-place.
|
// @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'
|
// Result is 'comp_id' number to 'cargo_id' numbers to 'ind' and/or 'town' indices to 'null'
|
||||||
|
|||||||
1
info.nut
1
info.nut
@@ -27,6 +27,7 @@ class BusyBeeInfo extends GSInfo {
|
|||||||
function GetShortName() { return "BBEE"; }
|
function GetShortName() { return "BBEE"; }
|
||||||
function GetAPIVersion() { return "1.5"; }
|
function GetAPIVersion() { return "1.5"; }
|
||||||
function GetUrl() { return ""; }
|
function GetUrl() { return ""; }
|
||||||
|
function MinVersionToLoad() { return this.GetVersion(); }
|
||||||
function GetSettings();
|
function GetSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
88
main.nut
88
main.nut
@@ -26,12 +26,40 @@ class BusyBeeClass extends GSController
|
|||||||
|
|
||||||
companies = null;
|
companies = null;
|
||||||
|
|
||||||
|
loaded = false;
|
||||||
|
|
||||||
|
function Load(version, data);
|
||||||
|
function Save();
|
||||||
function Start();
|
function Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Examine and store cargo types of the game.
|
function BusyBeeClass::Load(version, data)
|
||||||
function BusyBeeClass::ExamineCargoes()
|
|
||||||
{
|
{
|
||||||
|
this.loaded = true;
|
||||||
|
this.Initialize();
|
||||||
|
|
||||||
|
foreach (comp_id, loaded_comp_data in data) {
|
||||||
|
local cdata = CompanyData.LoadCompany(comp_id, loaded_comp_data, this.cargoes);
|
||||||
|
this.companies[comp_id] = cdata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function BusyBeeClass::Save()
|
||||||
|
{
|
||||||
|
local result = {};
|
||||||
|
foreach (comp_id, cdata in this.companies) {
|
||||||
|
if (cdata == null) continue;
|
||||||
|
result[comp_id] <- cdata.SaveCompany();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize core data of the script.
|
||||||
|
function BusyBeeClass::Initialize()
|
||||||
|
{
|
||||||
|
if (this.companies != null) return; // Already initialized.
|
||||||
|
|
||||||
|
// Examine and store cargo types of the game.
|
||||||
this.cargoes = {};
|
this.cargoes = {};
|
||||||
this.num_cargoes = 0;
|
this.num_cargoes = 0;
|
||||||
|
|
||||||
@@ -42,6 +70,12 @@ function BusyBeeClass::ExamineCargoes()
|
|||||||
this.cargoes[this.num_cargoes] <- cargo;
|
this.cargoes[this.num_cargoes] <- cargo;
|
||||||
this.num_cargoes += 1;
|
this.num_cargoes += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Construct empty companies.
|
||||||
|
this.companies = {};
|
||||||
|
for (local comp_id = GSCompany.COMPANY_FIRST; comp_id <= GSCompany.COMPANY_LAST; comp_id++) {
|
||||||
|
this.companies[comp_id] <- null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find cargo sources.
|
// Find cargo sources.
|
||||||
@@ -251,7 +285,7 @@ function BusyBeeClass::ProcessEvents()
|
|||||||
|
|
||||||
} else if (event_type == GSEvent.ET_INDUSTRY_CLOSE) {
|
} else if (event_type == GSEvent.ET_INDUSTRY_CLOSE) {
|
||||||
local ind_id = GSEventIndustryClose.Convert(event).GetIndustryID();
|
local ind_id = GSEventIndustryClose.Convert(event).GetIndustryID();
|
||||||
foreach (comp_id, cdata in companies) {
|
foreach (comp_id, cdata in this.companies) {
|
||||||
if (cdata != null) cdata.IndustryClosed(ind_id);
|
if (cdata != null) cdata.IndustryClosed(ind_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -268,7 +302,7 @@ function BusyBeeClass::TryAddNewGoal()
|
|||||||
local total_missing = 0; // Total number of missing goals.
|
local total_missing = 0; // Total number of missing goals.
|
||||||
local best_comp_id = null;
|
local best_comp_id = null;
|
||||||
local comp_id_missing = 0;
|
local comp_id_missing = 0;
|
||||||
foreach (comp_id, cdata in companies) {
|
foreach (comp_id, cdata in this.companies) {
|
||||||
if (cdata == null) continue;
|
if (cdata == null) continue;
|
||||||
local missing = cdata.GetMissingGoalCount();
|
local missing = cdata.GetMissingGoalCount();
|
||||||
total_missing += missing;
|
total_missing += missing;
|
||||||
@@ -299,7 +333,7 @@ function BusyBeeClass::UpdateDeliveries(old_cmon)
|
|||||||
|
|
||||||
local cmon = {};
|
local cmon = {};
|
||||||
// Collect monitors that are of interest.
|
// Collect monitors that are of interest.
|
||||||
foreach (comp_id, cdata in companies) {
|
foreach (comp_id, cdata in this.companies) {
|
||||||
if (cdata == null) continue;
|
if (cdata == null) continue;
|
||||||
cdata.AddMonitorElements(cmon);
|
cdata.AddMonitorElements(cmon);
|
||||||
}
|
}
|
||||||
@@ -308,7 +342,7 @@ function BusyBeeClass::UpdateDeliveries(old_cmon)
|
|||||||
|
|
||||||
// Distribute the retrieved data.
|
// Distribute the retrieved data.
|
||||||
local finished = false;
|
local finished = false;
|
||||||
foreach (comp_id, cdata in companies) {
|
foreach (comp_id, cdata in this.companies) {
|
||||||
if (cdata == null) continue;
|
if (cdata == null) continue;
|
||||||
if (cdata.UpdateDelivereds(cmon)) finished = true;
|
if (cdata.UpdateDelivereds(cmon)) finished = true;
|
||||||
}
|
}
|
||||||
@@ -319,23 +353,47 @@ function BusyBeeClass::UpdateDeliveries(old_cmon)
|
|||||||
return {cmon=cmon, finished_goals=finished};
|
return {cmon=cmon, finished_goals=finished};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The script data got loaded from file, check it against the game.
|
||||||
|
function BusyBeeClass::CompaniesPostLoadCheck()
|
||||||
|
{
|
||||||
|
// Check companies.
|
||||||
|
for (local comp_id = GSCompany.COMPANY_FIRST; comp_id <= GSCompany.COMPANY_LAST; comp_id++) {
|
||||||
|
if (GSCompany.ResolveCompanyID(comp_id) == GSCompany.COMPANY_INVALID) {
|
||||||
|
if (this.companies[comp_id] != null) {
|
||||||
|
this.companies[comp_id].FinalizeCompany();
|
||||||
|
this.companies[comp_id] = null;
|
||||||
|
GSLog.Info("Deleted company " + comp_id + " (disappeared after loading).");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (this.companies[comp_id] == null) {
|
||||||
|
this.companies[comp_id] = CompanyData(comp_id);
|
||||||
|
GSLog.Info("Created company " + comp_id + " (appeared from nowhere after loading).");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check industries used for goals.
|
||||||
|
foreach (comp_id, cdata in this.companies) {
|
||||||
|
if (cdata == null) continue;
|
||||||
|
cdata.GoalsPostLoadCheck();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function BusyBeeClass::Start()
|
function BusyBeeClass::Start()
|
||||||
{
|
{
|
||||||
|
this.Initialize();
|
||||||
this.Sleep(1); // Wait for the game to start.
|
this.Sleep(1); // Wait for the game to start.
|
||||||
|
|
||||||
this.ExamineCargoes();
|
local cmonitor = null;
|
||||||
|
if (this.loaded) { // Script data was loaded.
|
||||||
// Construct empty companies.
|
this.CompaniesPostLoadCheck();
|
||||||
this.companies = {};
|
cmonitor = {}; // Don't kill existing monitors after loading.
|
||||||
for (local comp_id = GSCompany.COMPANY_FIRST; comp_id <= GSCompany.COMPANY_LAST; comp_id++) {
|
|
||||||
this.companies[comp_id] <- null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main event loop.
|
// Main event loop.
|
||||||
local new_goal_timeout = 0;
|
local new_goal_timeout = 0;
|
||||||
local finished_timeout = 0;
|
local finished_timeout = 0;
|
||||||
local monitor_timeout = 0;
|
local monitor_timeout = 0;
|
||||||
local cmonitor = null;
|
|
||||||
while (true) {
|
while (true) {
|
||||||
local result = this.ProcessEvents();
|
local result = this.ProcessEvents();
|
||||||
if (result.force_goal) new_goal_timeout = 0;
|
if (result.force_goal) new_goal_timeout = 0;
|
||||||
@@ -363,7 +421,7 @@ function BusyBeeClass::Start()
|
|||||||
|
|
||||||
// Check for finished goals, and remove them if they exist.
|
// Check for finished goals, and remove them if they exist.
|
||||||
if (finished_timeout <= 0) {
|
if (finished_timeout <= 0) {
|
||||||
foreach (comp_id, cdata in companies) {
|
foreach (comp_id, cdata in this.companies) {
|
||||||
if (cdata == null) continue;
|
if (cdata == null) continue;
|
||||||
cdata.CheckAndFinishGoals();
|
cdata.CheckAndFinishGoals();
|
||||||
}
|
}
|
||||||
@@ -389,7 +447,7 @@ function BusyBeeClass::Start()
|
|||||||
|
|
||||||
// Update timeout of the goals as well.
|
// Update timeout of the goals as well.
|
||||||
if (!GSGame.IsPaused()) {
|
if (!GSGame.IsPaused()) {
|
||||||
foreach (comp_id, cdata in companies) {
|
foreach (comp_id, cdata in this.companies) {
|
||||||
if (cdata == null) continue;
|
if (cdata == null) continue;
|
||||||
cdata.UpdateTimeout(delay_time);
|
cdata.UpdateTimeout(delay_time);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user