# group_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id$ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
    00006  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    00007  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "cmd_helper.h"
    00014 #include "command_func.h"
    00015 #include "group.h"
    00016 #include "train.h"
    00017 #include "vehicle_gui.h"
    00018 #include "vehiclelist.h"
    00019 #include "window_func.h"
    00020 #include "vehicle_func.h"
    00021 #include "autoreplace_base.h"
    00022 #include "autoreplace_func.h"
    00023 #include "string_func.h"
    00024 #include "company_func.h"
    00025 #include "core/pool_func.hpp"
    00026 #include "order_backup.h"
    00027
    00028 #include "table/strings.h"
    00029
    00030 GroupID _new_group_id;
    00031
    00032 GroupPool _group_pool("Group");
    00033 INSTANTIATE_POOL_METHODS(Group)
    00034
    00035
    00042 static inline void UpdateNumEngineGroup(EngineID i, GroupID old_g, GroupID new_g)
    00043 {
    00044   if (old_g != new_g) {
    00045     /* Decrease the num engines of EngineID i of the old group if it's not the default one */
    00046     if (!IsDefaultGroupID(old_g) && Group::IsValidID(old_g)) Group::Get(old_g)->num_engines[i]--;
    00047
    00048     /* Increase the num engines of EngineID i of the new group if it's not the default one */
    00049     if (!IsDefaultGroupID(new_g) && Group::IsValidID(new_g)) Group::Get(new_g)->num_engines[i]++;
    00050   }
    00051 }
    00052
    00053
    00054
    00055 Group::Group(Owner owner)
    00056 {
    00057   this->owner = owner;
    00058
    00059   if (!Company::IsValidID(owner)) return;
    00060
    00061   this->num_engines = CallocT<uint16>(Engine::GetPoolSize());
    00062 }
    00063
    00064 Group::~Group()
    00065 {
    00066   free(this->name);
    00067   free(this->num_engines);
    00068 }
    00069
    00070 void InitializeGroup()
    00071 {
    00072   _group_pool.CleanPool();
    00073 }
    00074
    00075
    00085 CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00086 {
    00087   VehicleType vt = Extract<VehicleType, 0, 3>(p1);
    00088   if (!IsCompanyBuildableVehicleType(vt)) return CMD_ERROR;
    00089
    00090   if (!Group::CanAllocateItem()) return CMD_ERROR;
    00091
    00092   if (flags & DC_EXEC) {
    00093     Group *g = new Group(_current_company);
    00094     g->replace_protection = false;
    00095     g->vehicle_type = vt;
    00096
    00097     _new_group_id = g->index;
    00098
    00099     InvalidateWindowData(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).Pack());
    00100   }
    00101
    00102   return CommandCost();
    00103 }
    00104
    00105
    00116 CommandCost CmdDeleteGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00117 {
    00118   Group *g = Group::GetIfValid(p1);
    00119   if (g == NULL || g->owner != _current_company) return CMD_ERROR;
    00120
    00121   if (flags & DC_EXEC) {
    00122     Vehicle *v;
    00123
    00124     /* Add all vehicles belong to the group to the default group */
    00125     FOR_ALL_VEHICLES(v) {
    00126       if (v->group_id == g->index && v->type == g->vehicle_type) v->group_id = DEFAULT_GROUP;
    00127     }
    00128
    00129     /* Update backupped orders if needed */
    00130     OrderBackup::ClearGroup(g->index);
    00131
    00132     /* If we set an autoreplace for the group we delete, remove it. */
    00133     if (_current_company < MAX_COMPANIES) {
    00134       Company *c;
    00135       EngineRenew *er;
    00136
    00137       c = Company::Get(_current_company);
    00138       FOR_ALL_ENGINE_RENEWS(er) {
    00139         if (er->group_id == g->index) RemoveEngineReplacementForCompany(c, er->from, g->index, flags);
    00140       }
    00141     }
    00142
    00143     VehicleType vt = g->vehicle_type;
    00144
    00145     /* Delete the Replace Vehicle Windows */
    00146     DeleteWindowById(WC_REPLACE_VEHICLE, g->vehicle_type);
    00147     delete g;
    00148
    00149     InvalidateWindowData(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).Pack());
    00150   }
    00151
    00152   return CommandCost();
    00153 }
    00154
    00155 static bool IsUniqueGroupName(const char *name)
    00156 {
    00157   const Group *g;
    00158
    00159   FOR_ALL_GROUPS(g) {
    00160     if (g->name != NULL && strcmp(g->name, name) == 0) return false;
    00161   }
    00162
    00163   return true;
    00164 }
    00165
    00176 CommandCost CmdRenameGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00177 {
    00178   Group *g = Group::GetIfValid(p1);
    00179   if (g == NULL || g->owner != _current_company) return CMD_ERROR;
    00180
    00181   bool reset = StrEmpty(text);
    00182
    00183   if (!reset) {
    00184     if (Utf8StringLength(text) >= MAX_LENGTH_GROUP_NAME_CHARS) return CMD_ERROR;
    00185     if (!IsUniqueGroupName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
    00186   }
    00187
    00188   if (flags & DC_EXEC) {
    00189     /* Delete the old name */
    00190     free(g->name);
    00191     /* Assign the new one */
    00192     g->name = reset ? NULL : strdup(text);
    00193
    00194     InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
    00195   }
    00196
    00197   return CommandCost();
    00198 }
    00199
    00200
    00212 CommandCost CmdAddVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00213 {
    00214   Vehicle *v = Vehicle::GetIfValid(p2);
    00215   GroupID new_g = p1;
    00216
    00217   if (v == NULL || (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g))) return CMD_ERROR;
    00218
    00219   if (Group::IsValidID(new_g)) {
    00220     Group *g = Group::Get(new_g);
    00221     if (g->owner != _current_company || g->vehicle_type != v->type) return CMD_ERROR;
    00222   }
    00223
    00224   if (v->owner != _current_company || !v->IsPrimaryVehicle()) return CMD_ERROR;
    00225
    00226   if (flags & DC_EXEC) {
    00227     DecreaseGroupNumVehicle(v->group_id);
    00228     IncreaseGroupNumVehicle(new_g);
    00229
    00230     switch (v->type) {
    00231       default: NOT_REACHED();
    00232       case VEH_TRAIN:
    00233         SetTrainGroupID(Train::From(v), new_g);
    00234         break;
    00235       case VEH_ROAD:
    00236       case VEH_SHIP:
    00237       case VEH_AIRCRAFT:
    00238         if (v->IsEngineCountable()) UpdateNumEngineGroup(v->engine_type, v->group_id, new_g);
    00239         v->group_id = new_g;
    00240         break;
    00241     }
    00242
    00243     /* Update the Replace Vehicle Windows */
    00244     SetWindowDirty(WC_REPLACE_VEHICLE, v->type);
    00245     InvalidateWindowData(GetWindowClassForVehicleType(v->type), VehicleListIdentifier(VL_GROUP_LIST, v->type, _current_company).Pack());
    00246   }
    00247
    00248   return CommandCost();
    00249 }
    00250
    00261 CommandCost CmdAddSharedVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00262 {
    00263   VehicleType type = Extract<VehicleType, 0, 3>(p2);
    00264   GroupID id_g = p1;
    00265   if (!Group::IsValidID(id_g) || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
    00266
    00267   if (flags & DC_EXEC) {
    00268     Vehicle *v;
    00269
    00270     /* Find the first front engine which belong to the group id_g
    00271      * then add all shared vehicles of this front engine to the group id_g */
    00272     FOR_ALL_VEHICLES(v) {
    00273       if (v->type == type && v->IsPrimaryVehicle()) {
    00274         if (v->group_id != id_g) continue;
    00275
    00276         /* For each shared vehicles add it to the group */
    00277         for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
    00278           if (v2->group_id != id_g) DoCommand(tile, id_g, v2->index, flags, CMD_ADD_VEHICLE_GROUP, text);
    00279         }
    00280       }
    00281     }
    00282
    00283     InvalidateWindowData(GetWindowClassForVehicleType(type), VehicleListIdentifier(VL_GROUP_LIST, type, _current_company).Pack());
    00284   }
    00285
    00286   return CommandCost();
    00287 }
    00288
    00289
    00300 CommandCost CmdRemoveAllVehiclesGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00301 {
    00302   GroupID old_g = p1;
    00303   Group *g = Group::GetIfValid(old_g);
    00304   VehicleType type = Extract<VehicleType, 0, 3>(p2);
    00305
    00306   if (g == NULL || g->owner != _current_company || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
    00307
    00308   if (flags & DC_EXEC) {
    00309     Vehicle *v;
    00310
    00311     /* Find each Vehicle that belongs to the group old_g and add it to the default group */
    00312     FOR_ALL_VEHICLES(v) {
    00313       if (v->type == type && v->IsPrimaryVehicle()) {
    00314         if (v->group_id != old_g) continue;
    00315
    00316         /* Add The Vehicle to the default group */
    00317         DoCommand(tile, DEFAULT_GROUP, v->index, flags, CMD_ADD_VEHICLE_GROUP, text);
    00318       }
    00319     }
    00320
    00321     InvalidateWindowData(GetWindowClassForVehicleType(type), VehicleListIdentifier(VL_GROUP_LIST, type, _current_company).Pack());
    00322   }
    00323
    00324   return CommandCost();
    00325 }
    00326
    00327
    00339 CommandCost CmdSetGroupReplaceProtection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00340 {
    00341   Group *g = Group::GetIfValid(p1);
    00342   if (g == NULL || g->owner != _current_company) return CMD_ERROR;
    00343
    00344   if (flags & DC_EXEC) {
    00345     g->replace_protection = HasBit(p2, 0);
    00346
    00347     InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
    00348     InvalidateWindowData(WC_REPLACE_VEHICLE, g->vehicle_type);
    00349   }
    00350
    00351   return CommandCost();
    00352 }
    00353
    00359 void RemoveVehicleFromGroup(const Vehicle *v)
    00360 {
    00361   if (!v->IsPrimaryVehicle()) return;
    00362
    00363   if (!IsDefaultGroupID(v->group_id)) DecreaseGroupNumVehicle(v->group_id);
    00364 }
    00365
    00366
    00373 void SetTrainGroupID(Train *v, GroupID new_g)
    00374 {
    00375   if (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g)) return;
    00376
    00377   assert(v->IsFrontEngine() || IsDefaultGroupID(new_g));
    00378
    00379   for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00380     if (u->IsEngineCountable()) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g);
    00381
    00382     u->group_id = new_g;
    00383   }
    00384
    00385   /* Update the Replace Vehicle Windows */
    00386   SetWindowDirty(WC_REPLACE_VEHICLE, VEH_TRAIN);
    00387 }
    00388
    00389
    00397 void UpdateTrainGroupID(Train *v)
    00398 {
    00399   assert(v->IsFrontEngine() || v->IsFreeWagon());
    00400
    00401   GroupID new_g = v->IsFrontEngine() ? v->group_id : (GroupID)DEFAULT_GROUP;
    00402   for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00403     if (u->IsEngineCountable()) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g);
    00404
    00405     u->group_id = new_g;
    00406   }
    00407
    00408   /* Update the Replace Vehicle Windows */
    00409   SetWindowDirty(WC_REPLACE_VEHICLE, VEH_TRAIN);
    00410 }
    00411
    00420 uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
    00421 {
    00422   if (Group::IsValidID(id_g)) return Group::Get(id_g)->num_engines[id_e];
    00423
    00424   uint num = Company::Get(company)->num_engines[id_e];
    00425   if (!IsDefaultGroupID(id_g)) return num;
    00426
    00427   const Group *g;
    00428   FOR_ALL_GROUPS(g) {
    00429     if (g->owner == company) num -= g->num_engines[id_e];
    00430   }
    00431   return num;
    00432 }
    00433
    00434 void RemoveAllGroupsForCompany(const CompanyID company)
    00435 {
    00436   Group *g;
    00437
    00438   FOR_ALL_GROUPS(g) {
    00439     if (company == g->owner) delete g;
    00440   }
    00441 }