summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrubidium <rubidium@openttd.org>2009-09-01 12:57:04 +0000
committerrubidium <rubidium@openttd.org>2009-09-01 12:57:04 +0000
commit4c84db16361c17e6c3def857b400b9a974f90d44 (patch)
tree57d6185c490b3a04178e78f6bbcca714ac1b3824
parent4abf4602e7a0b624de9836b5a58d3d606612c2fa (diff)
downloadopenttd-4c84db16361c17e6c3def857b400b9a974f90d44.tar.xz
(svn r17345) -Fix [FS#2769]: one wasn't offered to take over bankrupt companies anymore; caused by the introduction NoAI, although NewAI had the same problem too.
-rw-r--r--src/ai/ai_instance.cpp1
-rw-r--r--src/ai/api/ai_changelog.hpp1
-rw-r--r--src/ai/api/ai_event.hpp1
-rw-r--r--src/ai/api/ai_event.hpp.sq1
-rw-r--r--src/ai/api/ai_event_types.cpp5
-rw-r--r--src/ai/api/ai_event_types.hpp48
-rw-r--r--src/ai/api/ai_event_types.hpp.sq22
-rw-r--r--src/company_cmd.cpp69
-rw-r--r--src/company_func.h1
-rw-r--r--src/economy.cpp20
10 files changed, 153 insertions, 16 deletions
diff --git a/src/ai/ai_instance.cpp b/src/ai/ai_instance.cpp
index 2d5a01251..6d29aec95 100644
--- a/src/ai/ai_instance.cpp
+++ b/src/ai/ai_instance.cpp
@@ -186,6 +186,7 @@ void AIInstance::RegisterAPI()
SQAIEngineList_Register(this->engine);
SQAIError_Register(this->engine);
SQAIEvent_Register(this->engine);
+ SQAIEventCompanyAskMerger_Register(this->engine);
SQAIEventCompanyBankrupt_Register(this->engine);
SQAIEventCompanyInTrouble_Register(this->engine);
SQAIEventCompanyMerger_Register(this->engine);
diff --git a/src/ai/api/ai_changelog.hpp b/src/ai/api/ai_changelog.hpp
index c1c9e44be..6c14b7a2e 100644
--- a/src/ai/api/ai_changelog.hpp
+++ b/src/ai/api/ai_changelog.hpp
@@ -19,6 +19,7 @@
* API additions:
* \li AIBaseStation
* \li AIBuoyList
+ * \li AIEventCompanyAskMerger
* \li AIRail::RemoveRailWaypointTileRect
* \li AISubsidy::SubsidyParticipantType
* \li AISubsidy::GetSourceType
diff --git a/src/ai/api/ai_event.hpp b/src/ai/api/ai_event.hpp
index 25330a4cf..dd12dfbca 100644
--- a/src/ai/api/ai_event.hpp
+++ b/src/ai/api/ai_event.hpp
@@ -36,6 +36,7 @@ public:
AI_ET_ENGINE_PREVIEW,
AI_ET_COMPANY_NEW,
AI_ET_COMPANY_IN_TROUBLE,
+ AI_ET_COMPANY_ASK_MERGER,
AI_ET_COMPANY_MERGER,
AI_ET_COMPANY_BANKRUPT,
AI_ET_VEHICLE_CRASHED,
diff --git a/src/ai/api/ai_event.hpp.sq b/src/ai/api/ai_event.hpp.sq
index dd365c4bc..cc250961f 100644
--- a/src/ai/api/ai_event.hpp.sq
+++ b/src/ai/api/ai_event.hpp.sq
@@ -38,6 +38,7 @@ void SQAIEvent_Register(Squirrel *engine) {
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_ENGINE_PREVIEW, "AI_ET_ENGINE_PREVIEW");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_COMPANY_NEW, "AI_ET_COMPANY_NEW");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_COMPANY_IN_TROUBLE, "AI_ET_COMPANY_IN_TROUBLE");
+ SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_COMPANY_ASK_MERGER, "AI_ET_COMPANY_ASK_MERGER");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_COMPANY_MERGER, "AI_ET_COMPANY_MERGER");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_COMPANY_BANKRUPT, "AI_ET_COMPANY_BANKRUPT");
SQAIEvent.DefSQConst(engine, AIEvent::AI_ET_VEHICLE_CRASHED, "AI_ET_VEHICLE_CRASHED");
diff --git a/src/ai/api/ai_event_types.cpp b/src/ai/api/ai_event_types.cpp
index 554112f87..5500d15cb 100644
--- a/src/ai/api/ai_event_types.cpp
+++ b/src/ai/api/ai_event_types.cpp
@@ -92,3 +92,8 @@ bool AIEventEnginePreview::AcceptPreview()
{
return AIObject::DoCommand(0, this->engine, 0, CMD_WANT_ENGINE_PREVIEW);
}
+
+bool AIEventCompanyAskMerger::AcceptMerger()
+{
+ return AIObject::DoCommand(0, this->owner, 0, CMD_BUY_COMPANY);
+}
diff --git a/src/ai/api/ai_event_types.hpp b/src/ai/api/ai_event_types.hpp
index 7c5112949..774df7c44 100644
--- a/src/ai/api/ai_event_types.hpp
+++ b/src/ai/api/ai_event_types.hpp
@@ -359,6 +359,54 @@ private:
};
/**
+ * Event Company Ask Merger, indicating a company can be bought (cheaply) by you.
+ */
+class AIEventCompanyAskMerger : public AIEvent {
+public:
+ static const char *GetClassName() { return "AIEventCompanyAskMerger"; }
+
+ /**
+ * @param owner The company that can be bough.
+ * @param value The value/costs of buying the company.
+ */
+ AIEventCompanyAskMerger(Owner owner, int32 value) :
+ AIEvent(AI_ET_COMPANY_MERGER),
+ owner((AICompany::CompanyID)owner),
+ value(value)
+ {}
+
+ /**
+ * Convert an AIEvent to the real instance.
+ * @param instance The instance to convert.
+ * @return The converted instance.
+ */
+ static AIEventCompanyAskMerger *Convert(AIEvent *instance) { return (AIEventCompanyAskMerger *)instance; }
+
+ /**
+ * Get the CompanyID of the company that can be bought.
+ * @return The CompanyID of the company that can be bought.
+ * @note If the company is bought this will become invalid.
+ */
+ AICompany::CompanyID GetCompanyID() { return this->owner; }
+
+ /**
+ * Get the value of the new company.
+ * @return The value of the new company.
+ */
+ int32 GetValue() { return this->value; }
+
+ /**
+ * Take over the company for this merger.
+ * @return true if the merger was a success.
+ */
+ bool AcceptMerger();
+
+private:
+ AICompany::CompanyID owner;
+ int32 value;
+};
+
+/**
* Event Company Merger, indicating a company has been bought by another
* company.
*/
diff --git a/src/ai/api/ai_event_types.hpp.sq b/src/ai/api/ai_event_types.hpp.sq
index f10bb9621..a0842231a 100644
--- a/src/ai/api/ai_event_types.hpp.sq
+++ b/src/ai/api/ai_event_types.hpp.sq
@@ -192,6 +192,28 @@ void SQAIEventCompanyInTrouble_Register(Squirrel *engine) {
}
namespace SQConvert {
+ /* Allow AIEventCompanyAskMerger to be used as Squirrel parameter */
+ template <> AIEventCompanyAskMerger *GetParam(ForceType<AIEventCompanyAskMerger *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEventCompanyAskMerger *)instance; }
+ template <> AIEventCompanyAskMerger &GetParam(ForceType<AIEventCompanyAskMerger &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEventCompanyAskMerger *)instance; }
+ template <> const AIEventCompanyAskMerger *GetParam(ForceType<const AIEventCompanyAskMerger *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEventCompanyAskMerger *)instance; }
+ template <> const AIEventCompanyAskMerger &GetParam(ForceType<const AIEventCompanyAskMerger &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEventCompanyAskMerger *)instance; }
+ template <> int Return<AIEventCompanyAskMerger *>(HSQUIRRELVM vm, AIEventCompanyAskMerger *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "AIEventCompanyAskMerger", res, NULL, DefSQDestructorCallback<AIEventCompanyAskMerger>); return 1; }
+}; // namespace SQConvert
+
+void SQAIEventCompanyAskMerger_Register(Squirrel *engine) {
+ DefSQClass <AIEventCompanyAskMerger> SQAIEventCompanyAskMerger("AIEventCompanyAskMerger");
+ SQAIEventCompanyAskMerger.PreRegister(engine, "AIEvent");
+
+ SQAIEventCompanyAskMerger.DefSQStaticMethod(engine, &AIEventCompanyAskMerger::Convert, "Convert", 2, ".x");
+
+ SQAIEventCompanyAskMerger.DefSQMethod(engine, &AIEventCompanyAskMerger::GetCompanyID, "GetCompanyID", 1, "x");
+ SQAIEventCompanyAskMerger.DefSQMethod(engine, &AIEventCompanyAskMerger::GetValue, "GetValue", 1, "x");
+ SQAIEventCompanyAskMerger.DefSQMethod(engine, &AIEventCompanyAskMerger::AcceptMerger, "AcceptMerger", 1, "x");
+
+ SQAIEventCompanyAskMerger.PostRegister(engine);
+}
+
+namespace SQConvert {
/* Allow AIEventCompanyMerger to be used as Squirrel parameter */
template <> AIEventCompanyMerger *GetParam(ForceType<AIEventCompanyMerger *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (AIEventCompanyMerger *)instance; }
template <> AIEventCompanyMerger &GetParam(ForceType<AIEventCompanyMerger &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(AIEventCompanyMerger *)instance; }
diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp
index f1ae42c70..f47072562 100644
--- a/src/company_cmd.cpp
+++ b/src/company_cmd.cpp
@@ -492,13 +492,78 @@ void InitializeCompanies()
_cur_company_tick_index = 0;
}
+/**
+ * Handle the bankruptcy take over of a company.
+ * Companies going bankrupt will ask the other companies in order of their
+ * performance rating, so better performing companies get the 'do you want to
+ * merge with Y' question earlier. The question will then stay till either the
+ * company has gone bankrupt or got merged with a company.
+ *
+ * @param c the company that is going bankrupt.
+ */
+static void HandleBankruptcyTakeover(Company *c)
+{
+ /* Amount of time out for each company to take over a company;
+ * Timeout is a quarter (3 months of 30 days) divided over the
+ * number of companies. The minimum number of days in a quarter
+ * is 90: 31 in January, 28 in February and 31 in March.
+ * Note that the company going bankrupt can't buy itself. */
+ static const int TAKE_OVER_TIMEOUT = 3 * 30 * DAY_TICKS / (MAX_COMPANIES - 1);
+
+ assert(c->bankrupt_asked != 0);
+
+ /* We're currently asking some company to buy 'us' */
+ if (c->bankrupt_timeout != 0) {
+ c->bankrupt_timeout -= MAX_COMPANIES;
+ if (c->bankrupt_timeout > 0) return;
+ c->bankrupt_timeout = 0;
+
+ return;
+ }
+
+ /* Did we ask everyone for bankruptcy? If so, bail out. */
+ if (c->bankrupt_asked == MAX_UVALUE(CompanyMask)) return;
+
+ Company *c2, *best = NULL;
+ int32 best_performance = -1;
+
+ /* Ask the company with the highest performance history first */
+ FOR_ALL_COMPANIES(c2) {
+ if (c2->bankrupt_asked == 0 && // Don't ask companies going bankrupt themselves
+ !HasBit(c->bankrupt_asked, c2->index) &&
+ best_performance < c2->old_economy[1].performance_history) {
+ best_performance = c2->old_economy[1].performance_history;
+ best = c2;
+ }
+ }
+
+ /* Asked all companies? */
+ if (best_performance == -1) {
+ c->bankrupt_asked = MAX_UVALUE(CompanyMask);
+ return;
+ }
+
+ SetBit(c->bankrupt_asked, best->index);
+
+ if (IsInteractiveCompany(best->index)) {
+ c->bankrupt_timeout = TAKE_OVER_TIMEOUT;
+ ShowBuyCompanyDialog(c->index);
+ return;
+ }
+
+ if (best->is_ai) {
+ AI::NewEvent(best->index, new AIEventCompanyAskMerger(c->index, ClampToI32(c->bankrupt_value)));
+ }
+}
+
void OnTick_Companies()
{
if (_game_mode == GM_EDITOR) return;
Company *c = Company::GetIfValid(_cur_company_tick_index);
- if (c != NULL && c->name_1 != 0) {
- GenerateCompanyName(c);
+ if (c != NULL) {
+ if (c->name_1 != 0) GenerateCompanyName(c);
+ if (c->bankrupt_asked != 0) HandleBankruptcyTakeover(c);
}
if (_next_competitor_start == 0) {
diff --git a/src/company_func.h b/src/company_func.h
index 2f398747a..c458048ec 100644
--- a/src/company_func.h
+++ b/src/company_func.h
@@ -21,6 +21,7 @@
void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner);
void GetNameOfOwner(Owner owner, TileIndex tile);
void SetLocalCompany(CompanyID new_company);
+void ShowBuyCompanyDialog(CompanyID company);
extern CompanyByte _local_company;
extern CompanyByte _current_company;
diff --git a/src/economy.cpp b/src/economy.cpp
index 997c882d8..335889d83 100644
--- a/src/economy.cpp
+++ b/src/economy.cpp
@@ -506,16 +506,6 @@ static void CompanyCheckBankrupt(Company *c)
AI::BroadcastNewEvent(new AIEventCompanyInTrouble(c->index));
break;
case 3: {
- /* XXX - In multiplayer, should we ask other companies if it wants to take
- over when it is a human company? -- TrueLight */
- if (!c->is_ai) {
- SetDParam(0, STR_NEWS_COMPANY_IN_TROUBLE_TITLE);
- SetDParam(1, STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION);
- SetDParamStr(2, cni->company_name);
- AddCompanyNewsItem(STR_MESSAGE_NEWS_FORMAT, NS_COMPANY_TROUBLE, cni);
- break;
- }
-
/* Check if the company has any value.. if not, declare it bankrupt
* right now */
Money val = CalculateCompanyValue(c);
@@ -1560,15 +1550,17 @@ CommandCost CmdSellShareInCompany(TileIndex tile, DoCommandFlag flags, uint32 p1
CommandCost CmdBuyCompany(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
{
Company *c = Company::GetIfValid(p1);
+ if (c == NULL) return CMD_ERROR;
- /* Disable takeovers in multiplayer games */
- if (c == NULL || _networking) return CMD_ERROR;
+ /* Disable takeovers when not asked */
+ if (!HasBit(c->bankrupt_asked, _current_company)) return CMD_ERROR;
+
+ /* Disable taking over the local company in single player */
+ if (!_networking && _local_company == c->index) return CMD_ERROR;
/* Do not allow companies to take over themselves */
if ((CompanyID)p1 == _current_company) return CMD_ERROR;
- if (!c->is_ai) return CMD_ERROR;
-
if (flags & DC_EXEC) {
DoAcquireCompany(c);
}