# company_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: company_cmd.cpp 15584 2009-02-25 21:45:14Z yexo $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "engine_base.h"
    00008 #include "company_func.h"
    00009 #include "company_gui.h"
    00010 #include "town.h"
    00011 #include "news_func.h"
    00012 #include "command_func.h"
    00013 #include "network/network.h"
    00014 #include "network/network_func.h"
    00015 #include "network/network_base.h"
    00016 #include "variables.h"
    00017 #include "ai/ai.hpp"
    00018 #include "company_manager_face.h"
    00019 #include "group.h"
    00020 #include "window_func.h"
    00021 #include "tile_map.h"
    00022 #include "strings_func.h"
    00023 #include "gfx_func.h"
    00024 #include "date_func.h"
    00025 #include "sound_func.h"
    00026 #include "core/alloc_func.hpp"
    00027 #include "autoreplace_func.h"
    00028 #include "autoreplace_gui.h"
    00029 #include "string_func.h"
    00030 #include "road_func.h"
    00031 #include "rail.h"
    00032 #include "sprite.h"
    00033 #include "oldpool_func.h"
    00034
    00035 #include "table/strings.h"
    00036
    00037 CompanyByte _local_company;
    00038 CompanyByte _current_company;
    00039 /* NOSAVE: can be determined from company structs */
    00040 Colours _company_colours[MAX_COMPANIES];
    00041 CompanyManagerFace _company_manager_face;
    00042 uint _next_competitor_start;
    00043 uint _cur_company_tick_index;
    00044
    00045 DEFINE_OLD_POOL_GENERIC(Company, Company)
    00046
    00047 Company::Company(uint16 name_1, bool is_ai) :
    00048   name_1(name_1),
    00049   location_of_HQ(INVALID_TILE),
    00050   is_ai(is_ai)
    00051 {
    00052   for (uint j = 0; j < 4; j++) this->share_owners[j] = COMPANY_SPECTATOR;
    00053 }
    00054
    00055 Company::~Company()
    00056 {
    00057   free(this->name);
    00058   free(this->president_name);
    00059   free(this->num_engines);
    00060
    00061   if (CleaningPool()) return;
    00062
    00063   DeleteCompanyWindows(this->index);
    00064   this->name_1 = 0;
    00065 }
    00066
    00073 void SetLocalCompany(CompanyID new_company)
    00074 {
    00075   /* company could also be COMPANY_SPECTATOR or OWNER_NONE */
    00076   assert(IsValidCompanyID(new_company) || new_company == COMPANY_SPECTATOR || new_company == OWNER_NONE);
    00077
    00078   _local_company = new_company;
    00079
    00080   /* Do not update the settings if we are in the intro GUI */
    00081   if (IsValidCompanyID(new_company) && _game_mode != GM_MENU) {
    00082     const Company *c = GetCompany(new_company);
    00083     _settings_client.gui.autorenew        = c->engine_renew;
    00084     _settings_client.gui.autorenew_months = c->engine_renew_months;
    00085     _settings_client.gui.autorenew_money  = c->engine_renew_money;
    00086     InvalidateWindow(WC_GAME_OPTIONS, 0);
    00087   }
    00088
    00089   /* Delete any construction windows... */
    00090   DeleteConstructionWindows();
    00091
    00092   /* ... and redraw the whole screen. */
    00093   MarkWholeScreenDirty();
    00094 }
    00095
    00096 bool IsHumanCompany(CompanyID company)
    00097 {
    00098   return !GetCompany(company)->is_ai;
    00099 }
    00100
    00101
    00102 uint16 GetDrawStringCompanyColour(CompanyID company)
    00103 {
    00104   /* Get the colour for DrawString-subroutines which matches the colour
    00105    * of the company */
    00106   if (!IsValidCompanyID(company)) return _colour_gradient[COLOUR_WHITE][4] | IS_PALETTE_COLOUR;
    00107   return (_colour_gradient[_company_colours[company]][4]) | IS_PALETTE_COLOUR;
    00108 }
    00109
    00110 void DrawCompanyIcon(CompanyID c, int x, int y)
    00111 {
    00112   DrawSprite(SPR_PLAYER_ICON, COMPANY_SPRITE_COLOUR(c), x, y);
    00113 }
    00114
    00121 bool IsValidCompanyManagerFace(CompanyManagerFace cmf)
    00122 {
    00123   if (!AreCompanyManagerFaceBitsValid(cmf, CMFV_GEN_ETHN, GE_WM)) return false;
    00124
    00125   GenderEthnicity ge   = (GenderEthnicity)GetCompanyManagerFaceBits(cmf, CMFV_GEN_ETHN, GE_WM);
    00126   bool has_moustache   = !HasBit(ge, GENDER_FEMALE) && GetCompanyManagerFaceBits(cmf, CMFV_HAS_MOUSTACHE,   ge) != 0;
    00127   bool has_tie_earring = !HasBit(ge, GENDER_FEMALE) || GetCompanyManagerFaceBits(cmf, CMFV_HAS_TIE_EARRING, ge) != 0;
    00128   bool has_glasses     = GetCompanyManagerFaceBits(cmf, CMFV_HAS_GLASSES, ge) != 0;
    00129
    00130   if (!AreCompanyManagerFaceBitsValid(cmf, CMFV_EYE_COLOUR, ge)) return false;
    00131   for (CompanyManagerFaceVariable cmfv = CMFV_CHEEKS; cmfv < CMFV_END; cmfv++) {
    00132     switch (cmfv) {
    00133       case CMFV_MOUSTACHE:   if (!has_moustache)   continue; break;
    00134       case CMFV_LIPS:        /* FALL THROUGH */
    00135       case CMFV_NOSE:        if (has_moustache)    continue; break;
    00136       case CMFV_TIE_EARRING: if (!has_tie_earring) continue; break;
    00137       case CMFV_GLASSES:     if (!has_glasses)     continue; break;
    00138       default: break;
    00139     }
    00140     if (!AreCompanyManagerFaceBitsValid(cmf, cmfv, ge)) return false;
    00141   }
    00142
    00143   return true;
    00144 }
    00145
    00146 void InvalidateCompanyWindows(const Company *company)
    00147 {
    00148   CompanyID cid = company->index;
    00149
    00150   if (cid == _local_company) InvalidateWindow(WC_STATUS_BAR, 0);
    00151   InvalidateWindow(WC_FINANCES, cid);
    00152 }
    00153
    00154 bool CheckCompanyHasMoney(CommandCost cost)
    00155 {
    00156   if (cost.GetCost() > 0) {
    00157     CompanyID company = _current_company;
    00158     if (IsValidCompanyID(company) && cost.GetCost() > GetCompany(company)->money) {
    00159       SetDParam(0, cost.GetCost());
    00160       _error_message = STR_0003_NOT_ENOUGH_CASH_REQUIRES;
    00161       return false;
    00162     }
    00163   }
    00164   return true;
    00165 }
    00166
    00167 static void SubtractMoneyFromAnyCompany(Company *c, CommandCost cost)
    00168 {
    00169   if (cost.GetCost() == 0) return;
    00170   assert(cost.GetExpensesType() != INVALID_EXPENSES);
    00171
    00172   c->money -= cost.GetCost();
    00173   c->yearly_expenses[0][cost.GetExpensesType()] += cost.GetCost();
    00174
    00175   if (HasBit(1 << EXPENSES_TRAIN_INC    |
    00176              1 << EXPENSES_ROADVEH_INC  |
    00177              1 << EXPENSES_AIRCRAFT_INC |
    00178              1 << EXPENSES_SHIP_INC, cost.GetExpensesType())) {
    00179     c->cur_economy.income -= cost.GetCost();
    00180   } else if (HasBit(1 << EXPENSES_TRAIN_RUN    |
    00181                     1 << EXPENSES_ROADVEH_RUN  |
    00182                     1 << EXPENSES_AIRCRAFT_RUN |
    00183                     1 << EXPENSES_SHIP_RUN     |
    00184                     1 << EXPENSES_PROPERTY     |
    00185                     1 << EXPENSES_LOAN_INT, cost.GetExpensesType())) {
    00186     c->cur_economy.expenses -= cost.GetCost();
    00187   }
    00188
    00189   InvalidateCompanyWindows(c);
    00190 }
    00191
    00192 void SubtractMoneyFromCompany(CommandCost cost)
    00193 {
    00194   CompanyID cid = _current_company;
    00195
    00196   if (IsValidCompanyID(cid)) SubtractMoneyFromAnyCompany(GetCompany(cid), cost);
    00197 }
    00198
    00199 void SubtractMoneyFromCompanyFract(CompanyID company, CommandCost cst)
    00200 {
    00201   Company *c = GetCompany(company);
    00202   byte m = c->money_fraction;
    00203   Money cost = cst.GetCost();
    00204
    00205   c->money_fraction = m - (byte)cost;
    00206   cost >>= 8;
    00207   if (c->money_fraction > m) cost++;
    00208   if (cost != 0) SubtractMoneyFromAnyCompany(c, CommandCost(cst.GetExpensesType(), cost));
    00209 }
    00210
    00211 void GetNameOfOwner(Owner owner, TileIndex tile)
    00212 {
    00213   SetDParam(2, owner);
    00214
    00215   if (owner != OWNER_TOWN) {
    00216     if (!IsValidCompanyID(owner)) {
    00217       SetDParam(0, STR_0150_SOMEONE);
    00218     } else {
    00219       SetDParam(0, STR_COMPANY_NAME);
    00220       SetDParam(1, owner);
    00221     }
    00222   } else {
    00223     const Town *t = ClosestTownFromTile(tile, UINT_MAX);
    00224
    00225     SetDParam(0, STR_TOWN);
    00226     SetDParam(1, t->index);
    00227   }
    00228 }
    00229
    00230
    00231 bool CheckOwnership(Owner owner)
    00232 {
    00233   assert(owner < OWNER_END);
    00234
    00235   if (owner == _current_company) return true;
    00236   _error_message = STR_013B_OWNED_BY;
    00237   GetNameOfOwner(owner, 0);
    00238   return false;
    00239 }
    00240
    00241 bool CheckTileOwnership(TileIndex tile)
    00242 {
    00243   Owner owner = GetTileOwner(tile);
    00244
    00245   assert(owner < OWNER_END);
    00246
    00247   if (owner == _current_company) return true;
    00248   _error_message = STR_013B_OWNED_BY;
    00249
    00250   /* no need to get the name of the owner unless we're the local company (saves some time) */
    00251   if (IsLocalCompany()) GetNameOfOwner(owner, tile);
    00252   return false;
    00253 }
    00254
    00255 static void GenerateCompanyName(Company *c)
    00256 {
    00257   TileIndex tile;
    00258   Town *t;
    00259   StringID str;
    00260   Company *cc;
    00261   uint32 strp;
    00262   char buffer[100];
    00263
    00264   if (c->name_1 != STR_SV_UNNAMED) return;
    00265
    00266   tile = c->last_build_coordinate;
    00267   if (tile == 0) return;
    00268
    00269   t = ClosestTownFromTile(tile, UINT_MAX);
    00270
    00271   if (t->name == NULL && IsInsideMM(t->townnametype, SPECSTR_TOWNNAME_START, SPECSTR_TOWNNAME_LAST + 1)) {
    00272     str = t->townnametype - SPECSTR_TOWNNAME_START + SPECSTR_PLAYERNAME_START;
    00273     strp = t->townnameparts;
    00274
    00275 verify_name:;
    00276     /* No companies must have this name already */
    00277     FOR_ALL_COMPANIES(cc) {
    00278       if (cc->name_1 == str && cc->name_2 == strp) goto bad_town_name;
    00279     }
    00280
    00281     GetString(buffer, str, lastof(buffer));
    00282     if (strlen(buffer) >= MAX_LENGTH_COMPANY_NAME_BYTES) goto bad_town_name;
    00283
    00284 set_name:;
    00285     c->name_1 = str;
    00286     c->name_2 = strp;
    00287
    00288     MarkWholeScreenDirty();
    00289
    00290     if (!IsHumanCompany(c->index)) {
    00291       CompanyNewsInformation *cni = MallocT<CompanyNewsInformation>(1);
    00292       cni->FillData(c);
    00293       SetDParam(0, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED);
    00294       SetDParam(1, STR_705F_STARTS_CONSTRUCTION_NEAR);
    00295       SetDParamStr(2, cni->company_name);
    00296       SetDParam(3, t->index);
    00297       AddNewsItem(STR_02B6, NS_COMPANY_NEW, c->last_build_coordinate, 0, cni);
    00298     }
    00299     AI::BroadcastNewEvent(new AIEventCompanyNew(c->index), c->index);
    00300     return;
    00301   }
    00302 bad_town_name:;
    00303
    00304   if (c->president_name_1 == SPECSTR_PRESIDENT_NAME) {
    00305     str = SPECSTR_ANDCO_NAME;
    00306     strp = c->president_name_2;
    00307     goto set_name;
    00308   } else {
    00309     str = SPECSTR_ANDCO_NAME;
    00310     strp = Random();
    00311     goto verify_name;
    00312   }
    00313 }
    00314
    00315 static const byte _colour_sort[COLOUR_END] = {2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 2, 2, 3, 1, 1, 1};
    00316 static const Colours _similar_colour[COLOUR_END][2] = {
    00317   { COLOUR_BLUE,       COLOUR_LIGHT_BLUE }, // COLOUR_DARK_BLUE
    00318   { COLOUR_GREEN,      COLOUR_DARK_GREEN }, // COLOUR_PALE_GREEN
    00319   { INVALID_COLOUR,    INVALID_COLOUR    }, // COLOUR_PINK
    00320   { COLOUR_ORANGE,     INVALID_COLOUR    }, // COLOUR_YELLOW
    00321   { INVALID_COLOUR,    INVALID_COLOUR    }, // COLOUR_RED
    00322   { COLOUR_DARK_BLUE,  COLOUR_BLUE       }, // COLOUR_LIGHT_BLUE
    00323   { COLOUR_PALE_GREEN, COLOUR_DARK_GREEN }, // COLOUR_GREEN
    00324   { COLOUR_PALE_GREEN, COLOUR_GREEN      }, // COLOUR_DARK_GREEN
    00325   { COLOUR_DARK_BLUE,  COLOUR_LIGHT_BLUE }, // COLOUR_BLUE
    00326   { COLOUR_BROWN,      COLOUR_ORANGE     }, // COLOUR_CREAM
    00327   { COLOUR_PURPLE,     INVALID_COLOUR    }, // COLOUR_MAUVE
    00328   { COLOUR_MAUVE,      INVALID_COLOUR    }, // COLOUR_PURPLE
    00329   { COLOUR_YELLOW,     COLOUR_CREAM      }, // COLOUR_ORANGE
    00330   { COLOUR_CREAM,      INVALID_COLOUR    }, // COLOUR_BROWN
    00331   { COLOUR_WHITE,      INVALID_COLOUR    }, // COLOUR_GREY
    00332   { COLOUR_GREY,       INVALID_COLOUR    }, // COLOUR_WHITE
    00333 };
    00334
    00335 static Colours GenerateCompanyColour()
    00336 {
    00337   Colours colours[COLOUR_END];
    00338
    00339   /* Initialize array */
    00340   for (uint i = 0; i < COLOUR_END; i++) colours[i] = (Colours)i;
    00341
    00342   /* And randomize it */
    00343   for (uint i = 0; i < 100; i++) {
    00344     uint r = Random();
    00345     Swap(colours[GB(r, 0, 4)], colours[GB(r, 4, 4)]);
    00346   }
    00347
    00348   /* Bubble sort it according to the values in table 1 */
    00349   for (uint i = 0; i < COLOUR_END; i++) {
    00350     for (uint j = 1; j < COLOUR_END; j++) {
    00351       if (_colour_sort[colours[j - 1]] < _colour_sort[colours[j]]) {
    00352         Swap(colours[j - 1], colours[j]);
    00353       }
    00354     }
    00355   };
    00356
    00357   /* Move the colours that look similar to each company's colour to the side */
    00358   Company *c;
    00359   FOR_ALL_COMPANIES(c) {
    00360     Colours pcolour = (Colours)c->colour;
    00361
    00362     for (uint i = 0; i < COLOUR_END; i++) {
    00363       if (colours[i] == pcolour) {
    00364         colours[i] = INVALID_COLOUR;
    00365         break;
    00366       }
    00367     }
    00368
    00369     for (uint j = 0; j < 2; j++) {
    00370       Colours similar = _similar_colour[pcolour][j];
    00371       if (similar == INVALID_COLOUR) break;
    00372
    00373       for (uint i = 1; i < COLOUR_END; i++) {
    00374         if (colours[i - 1] == similar) Swap(colours[i - 1], colours[i]);
    00375       }
    00376     }
    00377   }
    00378
    00379   /* Return the first available colour */
    00380   for (uint i = 0; i < COLOUR_END; i++) {
    00381     if (colours[i] != INVALID_COLOUR) return colours[i];
    00382   }
    00383
    00384   NOT_REACHED();
    00385 }
    00386
    00387 static void GeneratePresidentName(Company *c)
    00388 {
    00389   for (;;) {
    00390 restart:;
    00391     c->president_name_2 = Random();
    00392     c->president_name_1 = SPECSTR_PRESIDENT_NAME;
    00393
    00394     char buffer[MAX_LENGTH_PRESIDENT_NAME_BYTES + 1];
    00395     SetDParam(0, c->index);
    00396     GetString(buffer, STR_PRESIDENT_NAME, lastof(buffer));
    00397     if (strlen(buffer) >= MAX_LENGTH_PRESIDENT_NAME_BYTES) continue;
    00398
    00399     Company *cc;
    00400     FOR_ALL_COMPANIES(cc) {
    00401       if (c != cc) {
    00402         char buffer2[MAX_LENGTH_PRESIDENT_NAME_BYTES + 2];
    00403         SetDParam(0, cc->index);
    00404         GetString(buffer2, STR_PRESIDENT_NAME, lastof(buffer2));
    00405         if (strcmp(buffer2, buffer) == 0) goto restart;
    00406       }
    00407     }
    00408     return;
    00409   }
    00410 }
    00411
    00412 void ResetCompanyLivery(Company *c)
    00413 {
    00414   for (LiveryScheme scheme = LS_BEGIN; scheme < LS_END; scheme++) {
    00415     c->livery[scheme].in_use  = false;
    00416     c->livery[scheme].colour1 = c->colour;
    00417     c->livery[scheme].colour2 = c->colour;
    00418   }
    00419 }
    00420
    00427 Company *DoStartupNewCompany(bool is_ai)
    00428 {
    00429   if (ActiveCompanyCount() == MAX_COMPANIES || !Company::CanAllocateItem()) return NULL;
    00430
    00431   /* we have to generate colour before this company is valid */
    00432   Colours colour = GenerateCompanyColour();
    00433
    00434   Company *c = new Company(STR_SV_UNNAMED, is_ai);
    00435
    00436   c->colour = colour;
    00437
    00438   ResetCompanyLivery(c);
    00439   _company_colours[c->index] = (Colours)c->colour;
    00440
    00441   c->money = c->current_loan = 100000;
    00442
    00443   c->share_owners[0] = c->share_owners[1] = c->share_owners[2] = c->share_owners[3] = INVALID_OWNER;
    00444
    00445   c->avail_railtypes = GetCompanyRailtypes(c->index);
    00446   c->avail_roadtypes = GetCompanyRoadtypes(c->index);
    00447   c->inaugurated_year = _cur_year;
    00448   RandomCompanyManagerFaceBits(c->face, (GenderEthnicity)Random(), false); // create a random company manager face
    00449
    00450   /* Engine renewal settings */
    00451   c->engine_renew_list = NULL;
    00452   c->renew_keep_length = false;
    00453   c->engine_renew = _settings_client.gui.autorenew;
    00454   c->engine_renew_months = _settings_client.gui.autorenew_months;
    00455   c->engine_renew_money = _settings_client.gui.autorenew_money;
    00456
    00457   GeneratePresidentName(c);
    00458
    00459   InvalidateWindow(WC_GRAPH_LEGEND, 0);
    00460   InvalidateWindow(WC_TOOLBAR_MENU, 0);
    00461   InvalidateWindow(WC_CLIENT_LIST, 0);
    00462
    00463   if (is_ai && (!_networking || _network_server)) AI::StartNew(c->index);
    00464
    00465   c->num_engines = CallocT<uint16>(GetEnginePoolSize());
    00466
    00467   return c;
    00468 }
    00469
    00470 void StartupCompanies()
    00471 {
    00472   _next_competitor_start = 0;
    00473 }
    00474
    00475 static void MaybeStartNewCompany()
    00476 {
    00477 #ifdef ENABLE_NETWORK
    00478   if (_networking && ActiveCompanyCount() >= _settings_client.network.max_companies) return;
    00479 #endif /* ENABLE_NETWORK */
    00480
    00481   Company *c;
    00482
    00483   /* count number of competitors */
    00484   uint n = 0;
    00485   FOR_ALL_COMPANIES(c) {
    00486     if (c->is_ai) n++;
    00487   }
    00488
    00489   if (n < (uint)_settings_game.difficulty.max_no_competitors) {
    00490     /* Send a command to all clients to start up a new AI.
    00491      * Works fine for Multiplayer and Singleplayer */
    00492     DoCommandP(0, 1, 0, CMD_COMPANY_CTRL);
    00493   }
    00494 }
    00495
    00496 void InitializeCompanies()
    00497 {
    00498   _Company_pool.CleanPool();
    00499   _Company_pool.AddBlockToPool();
    00500   _cur_company_tick_index = 0;
    00501 }
    00502
    00503 void OnTick_Companies()
    00504 {
    00505   if (_game_mode == GM_EDITOR) return;
    00506
    00507   if (IsValidCompanyID((CompanyID)_cur_company_tick_index)) {
    00508     Company *c = GetCompany((CompanyID)_cur_company_tick_index);
    00509     if (c->name_1 != 0) GenerateCompanyName(c);
    00510   }
    00511
    00512   if (_next_competitor_start == 0) {
    00513     _next_competitor_start = AI::GetStartNextTime() * DAY_TICKS;
    00514   }
    00515
    00516   if (AI::CanStartNew() && _game_mode != GM_MENU && --_next_competitor_start == 0) {
    00517     MaybeStartNewCompany();
    00518   }
    00519
    00520   _cur_company_tick_index = (_cur_company_tick_index + 1) % MAX_COMPANIES;
    00521 }
    00522
    00523 void CompaniesYearlyLoop()
    00524 {
    00525   Company *c;
    00526
    00527   /* Copy statistics */
    00528   FOR_ALL_COMPANIES(c) {
    00529     memmove(&c->yearly_expenses[1], &c->yearly_expenses[0], sizeof(c->yearly_expenses) - sizeof(c->yearly_expenses[0]));
    00530     memset(&c->yearly_expenses[0], 0, sizeof(c->yearly_expenses[0]));
    00531     InvalidateWindow(WC_FINANCES, c->index);
    00532   }
    00533
    00534   if (_settings_client.gui.show_finances && _local_company != COMPANY_SPECTATOR) {
    00535     ShowCompanyFinances(_local_company);
    00536     c = GetCompany(_local_company);
    00537     if (c->num_valid_stat_ent > 5 && c->old_economy[0].performance_history < c->old_economy[4].performance_history) {
    00538       SndPlayFx(SND_01_BAD_YEAR);
    00539     } else {
    00540       SndPlayFx(SND_00_GOOD_YEAR);
    00541     }
    00542   }
    00543 }
    00544
    00573 CommandCost CmdSetAutoReplace(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00574 {
    00575   if (!IsValidCompanyID(_current_company)) return CMD_ERROR;
    00576
    00577   Company *c = GetCompany(_current_company);
    00578   switch (GB(p1, 0, 3)) {
    00579     case 0:
    00580       if (c->engine_renew == HasBit(p2, 0)) return CMD_ERROR;
    00581
    00582       if (flags & DC_EXEC) {
    00583         c->engine_renew = HasBit(p2, 0);
    00584         if (IsLocalCompany()) {
    00585           _settings_client.gui.autorenew = c->engine_renew;
    00586           InvalidateWindow(WC_GAME_OPTIONS, 0);
    00587         }
    00588       }
    00589       break;
    00590
    00591     case 1:
    00592       if (Clamp((int16)p2, -12, 12) != (int16)p2) return CMD_ERROR;
    00593       if (c->engine_renew_months == (int16)p2) return CMD_ERROR;
    00594
    00595       if (flags & DC_EXEC) {
    00596         c->engine_renew_months = (int16)p2;
    00597         if (IsLocalCompany()) {
    00598           _settings_client.gui.autorenew_months = c->engine_renew_months;
    00599           InvalidateWindow(WC_GAME_OPTIONS, 0);
    00600         }
    00601       }
    00602       break;
    00603
    00604     case 2:
    00605       if (ClampU(p2, 0, 2000000) != p2) return CMD_ERROR;
    00606       if (c->engine_renew_money == p2) return CMD_ERROR;
    00607
    00608       if (flags & DC_EXEC) {
    00609         c->engine_renew_money = p2;
    00610         if (IsLocalCompany()) {
    00611           _settings_client.gui.autorenew_money = c->engine_renew_money;
    00612           InvalidateWindow(WC_GAME_OPTIONS, 0);
    00613         }
    00614       }
    00615       break;
    00616
    00617     case 3: {
    00618       EngineID old_engine_type = GB(p2, 0, 16);
    00619       EngineID new_engine_type = GB(p2, 16, 16);
    00620       GroupID id_g = GB(p1, 16, 16);
    00621       CommandCost cost;
    00622
    00623       if (!IsValidGroupID(id_g) && !IsAllGroupID(id_g) && !IsDefaultGroupID(id_g)) return CMD_ERROR;
    00624       if (new_engine_type != INVALID_ENGINE) {
    00625         if (!CheckAutoreplaceValidity(old_engine_type, new_engine_type, _current_company)) return CMD_ERROR;
    00626
    00627         cost = AddEngineReplacementForCompany(c, old_engine_type, new_engine_type, id_g, flags);
    00628       } else {
    00629         cost = RemoveEngineReplacementForCompany(c, old_engine_type, id_g, flags);
    00630       }
    00631
    00632       if (IsLocalCompany()) InvalidateAutoreplaceWindow(old_engine_type, id_g);
    00633
    00634       return cost;
    00635     }
    00636
    00637     case 4:
    00638       if (Clamp((int16)GB(p1, 16, 16), -12, 12) != (int16)GB(p1, 16, 16)) return CMD_ERROR;
    00639       if (ClampU(p2, 0, 2000000) != p2) return CMD_ERROR;
    00640
    00641       if (flags & DC_EXEC) {
    00642         c->engine_renew = HasBit(p1, 15);
    00643         c->engine_renew_months = (int16)GB(p1, 16, 16);
    00644         c->engine_renew_money = p2;
    00645
    00646         if (IsLocalCompany()) {
    00647           _settings_client.gui.autorenew = c->engine_renew;
    00648           _settings_client.gui.autorenew_months = c->engine_renew_months;
    00649           _settings_client.gui.autorenew_money = c->engine_renew_money;
    00650           InvalidateWindow(WC_GAME_OPTIONS, 0);
    00651         }
    00652       }
    00653       break;
    00654
    00655     case 5:
    00656       if (c->renew_keep_length == HasBit(p2, 0)) return CMD_ERROR;
    00657
    00658       if (flags & DC_EXEC) {
    00659         c->renew_keep_length = HasBit(p2, 0);
    00660         if (IsLocalCompany()) {
    00661           InvalidateWindow(WC_REPLACE_VEHICLE, VEH_TRAIN);
    00662         }
    00663       }
    00664     break;
    00665   }
    00666
    00667   return CommandCost();
    00668 }
    00669
    00675 void CompanyNewsInformation::FillData(const Company *c, const Company *other)
    00676 {
    00677   SetDParam(0, c->index);
    00678   GetString(this->company_name, STR_COMPANY_NAME, lastof(this->company_name));
    00679
    00680   if (other == NULL) {
    00681     *this->other_company_name = '\0';
    00682   } else {
    00683     SetDParam(0, other->index);
    00684     GetString(this->other_company_name, STR_COMPANY_NAME, lastof(this->other_company_name));
    00685     c = other;
    00686   }
    00687
    00688   SetDParam(0, c->index);
    00689   GetString(this->president_name, STR_7058_PRESIDENT, lastof(this->president_name));
    00690
    00691   this->colour = c->colour;
    00692   this->face = c->face;
    00693
    00694 }
    00695
    00716 CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00717 {
    00718   if (flags & DC_EXEC) _current_company = OWNER_NONE;
    00719
    00720   InvalidateWindowData(WC_COMPANY_LEAGUE, 0, 0);
    00721
    00722   switch (p1) {
    00723     case 0: { /* Create a new company */
    00724       /* This command is only executed in a multiplayer game */
    00725       if (!_networking) return CMD_ERROR;
    00726
    00727 #ifdef ENABLE_NETWORK
    00728
    00729       /* Joining Client:
    00730       * _local_company: COMPANY_SPECTATOR
    00731       * _network_playas/cid = requested company/clientid
    00732       *
    00733       * Other client(s)/server:
    00734       * _local_company/_network_playas: what they play as
    00735       * cid = requested company/company of joining client */
    00736       ClientID cid = (ClientID)p2;
    00737
    00738       /* Has the network client a correct ClientIndex? */
    00739       if (!(flags & DC_EXEC)) return CommandCost();
    00740       NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(cid);
    00741       if (ci == NULL) return CommandCost();
    00742
    00743       /* Delete multiplayer progress bar */
    00744       DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
    00745
    00746       Company *c = DoStartupNewCompany(false);
    00747
    00748       /* A new company could not be created, revert to being a spectator */
    00749       if (c == NULL) {
    00750         if (_network_server) {
    00751           ci->client_playas = COMPANY_SPECTATOR;
    00752           NetworkUpdateClientInfo(ci->client_id);
    00753         } else if (_local_company == COMPANY_SPECTATOR) {
    00754           _network_playas = COMPANY_SPECTATOR;
    00755         }
    00756         break;
    00757       }
    00758
    00759       /* This is the client (or non-dedicated server) who wants a new company */
    00760       if (cid == _network_own_client_id) {
    00761         assert(_local_company == COMPANY_SPECTATOR);
    00762         SetLocalCompany(c->index);
    00763         if (!StrEmpty(_settings_client.network.default_company_pass)) {
    00764           char *password = _settings_client.network.default_company_pass;
    00765           NetworkChangeCompanyPassword(1, &password);
    00766         }
    00767
    00768         _current_company = _local_company;
    00769
    00770         /* Now that we have a new company, broadcast our autorenew settings to
    00771         * all clients so everything is in sync */
    00772         NetworkSend_Command(0,
    00773           (_settings_client.gui.autorenew << 15 ) | (_settings_client.gui.autorenew_months << 16) | 4,
    00774           _settings_client.gui.autorenew_money,
    00775           CMD_SET_AUTOREPLACE,
    00776           NULL,
    00777           NULL
    00778         );
    00779
    00780         MarkWholeScreenDirty();
    00781       }
    00782
    00783       if (_network_server) {
    00784         /* XXX - UGLY! p2 (pid) is mis-used to fetch the client-id, done at
    00785         * server-side in network_server.c:838, function
    00786         * DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) */
    00787         CompanyID old_playas = ci->client_playas;
    00788         ci->client_playas = c->index;
    00789         NetworkUpdateClientInfo(ci->client_id);
    00790
    00791         if (IsValidCompanyID(ci->client_playas)) {
    00792           CompanyID company_backup = _local_company;
    00793           _network_company_states[c->index].months_empty = 0;
    00794           _network_company_states[c->index].password[0] = '\0';
    00795           NetworkServerUpdateCompanyPassworded(ci->client_playas, false);
    00796
    00797           /* XXX - When a client joins, we automatically set its name to the
    00798           * client's name (for some reason). As it stands now only the server
    00799           * knows the client's name, so it needs to send out a "broadcast" to
    00800           * do this. To achieve this we send a network command. However, it
    00801           * uses _local_company to execute the command as.  To prevent abuse
    00802           * (eg. only yourself can change your name/company), we 'cheat' by
    00803           * impersonation _local_company as the server. Not the best solution;
    00804           * but it works.
    00805           * TODO: Perhaps this could be improved by when the client is ready
    00806           * with joining to let it send itself the command, and not the server?
    00807           * For example in network_client.c:534? */
    00808           _local_company = ci->client_playas;
    00809           NetworkSend_Command(0, 0, 0, CMD_RENAME_PRESIDENT, NULL, ci->client_name);
    00810           _local_company = company_backup;
    00811         }
    00812
    00813         /* Announce new company on network, if the client was a SPECTATOR before */
    00814         if (old_playas == COMPANY_SPECTATOR) {
    00815           NetworkServerSendChat(NETWORK_ACTION_COMPANY_NEW, DESTTYPE_BROADCAST, 0, "", ci->client_id, ci->client_playas + 1);
    00816         }
    00817       }
    00818 #endif /* ENABLE_NETWORK */
    00819     } break;
    00820
    00821     case 1: /* Make a new AI company */
    00822       if (!(flags & DC_EXEC)) return CommandCost();
    00823
    00824       DoStartupNewCompany(true);
    00825       break;
    00826
    00827     case 2: { /* Delete a company */
    00828       Company *c;
    00829
    00830       if (!IsValidCompanyID((CompanyID)p2)) return CMD_ERROR;
    00831
    00832       if (!(flags & DC_EXEC)) return CommandCost();
    00833
    00834       c = GetCompany((CompanyID)p2);
    00835
    00836       /* Delete any open window of the company */
    00837       DeleteCompanyWindows(c->index);
    00838       CompanyNewsInformation *cni = MallocT<CompanyNewsInformation>(1);
    00839       cni->FillData(c);
    00840
    00841       /* Show the bankrupt news */
    00842       SetDParam(0, STR_705C_BANKRUPT);
    00843       SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
    00844       SetDParamStr(2, cni->company_name);
    00845       AddNewsItem(STR_02B6, NS_COMPANY_BANKRUPT, 0, 0, cni);
    00846
    00847       /* Remove the company */
    00848       ChangeOwnershipOfCompanyItems(c->index, INVALID_OWNER);
    00849       if (!IsHumanCompany(c->index)) AI::Stop(c->index);
    00850
    00851       CompanyID c_index = c->index;
    00852       delete c;
    00853       AI::BroadcastNewEvent(new AIEventCompanyBankrupt(c_index));
    00854     } break;
    00855
    00856     case 3: { /* Merge a company (#1) into another company (#2), elimination company #1 */
    00857       CompanyID cid_old = (CompanyID)GB(p2,  0, 16);
    00858       CompanyID cid_new = (CompanyID)GB(p2, 16, 16);
    00859
    00860       if (!IsValidCompanyID(cid_old) || !IsValidCompanyID(cid_new)) return CMD_ERROR;
    00861
    00862       if (!(flags & DC_EXEC)) return CMD_ERROR;
    00863
    00864       ChangeOwnershipOfCompanyItems(cid_old, cid_new);
    00865       delete GetCompany(cid_old);
    00866     } break;
    00867
    00868     default: return CMD_ERROR;
    00869   }
    00870
    00871   return CommandCost();
    00872 }