# group_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: group_cmd.cpp 19665 2010-04-17 22:27:49Z rubidium $ */
    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 "engine_base.h"
    00018 #include "vehicle_gui.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
    00027 #include "table/strings.h"
    00028
    00029 GroupID _new_group_id;
    00030
    00031 GroupPool _group_pool("Group");
    00032 INSTANTIATE_POOL_METHODS(Group)
    00033
    00034
    00041 static inline void UpdateNumEngineGroup(EngineID i, GroupID old_g, GroupID new_g)
    00042 {
    00043   if (old_g != new_g) {
    00044     /* Decrease the num engines of EngineID i of the old group if it's not the default one */
    00045     if (!IsDefaultGroupID(old_g) && Group::IsValidID(old_g)) Group::Get(old_g)->num_engines[i]--;
    00046
    00047     /* Increase the num engines of EngineID i of the new group if it's not the default one */
    00048     if (!IsDefaultGroupID(new_g) && Group::IsValidID(new_g)) Group::Get(new_g)->num_engines[i]++;
    00049   }
    00050 }
    00051
    00052
    00053
    00054 Group::Group(Owner owner)
    00055 {
    00056   this->owner = owner;
    00057
    00058   if (!Company::IsValidID(owner)) return;
    00059
    00060   this->num_engines = CallocT<uint16>(Engine::GetPoolSize());
    00061 }
    00062
    00063 Group::~Group()
    00064 {
    00065   free(this->name);
    00066   free(this->num_engines);
    00067 }
    00068
    00069 void InitializeGroup()
    00070 {
    00071   _group_pool.CleanPool();
    00072 }
    00073
    00074
    00084 CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00085 {
    00086   VehicleType vt = Extract<VehicleType, 0, 3>(p1);
    00087   if (!IsCompanyBuildableVehicleType(vt)) return CMD_ERROR;
    00088
    00089   if (!Group::CanAllocateItem()) return CMD_ERROR;
    00090
    00091   if (flags & DC_EXEC) {
    00092     Group *g = new Group(_current_company);
    00093     g->replace_protection = false;
    00094     g->vehicle_type = vt;
    00095
    00096     _new_group_id = g->index;
    00097
    00098     InvalidateWindowData(GetWindowClassForVehicleType(vt), (vt << 11) | VLW_GROUP_LIST | _current_company);
    00099   }
    00100
    00101   return CommandCost();
    00102 }
    00103
    00104
    00115 CommandCost CmdDeleteGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00116 {
    00117   Group *g = Group::GetIfValid(p1);
    00118   if (g == NULL || g->owner != _current_company) return CMD_ERROR;
    00119
    00120   if (flags & DC_EXEC) {
    00121     Vehicle *v;
    00122
    00123     /* Add all vehicles belong to the group to the default group */
    00124     FOR_ALL_VEHICLES(v) {
    00125       if (v->group_id == g->index && v->type == g->vehicle_type) v->group_id = DEFAULT_GROUP;
    00126     }
    00127
    00128     /* Update backupped orders if needed */
    00129     if (_backup_orders_data.group == g->index) _backup_orders_data.group = DEFAULT_GROUP;
    00130
    00131     /* If we set an autoreplace for the group we delete, remove it. */
    00132     if (_current_company < MAX_COMPANIES) {
    00133       Company *c;
    00134       EngineRenew *er;
    00135
    00136       c = Company::Get(_current_company);
    00137       FOR_ALL_ENGINE_RENEWS(er) {
    00138         if (er->group_id == g->index) RemoveEngineReplacementForCompany(c, er->from, g->index, flags);
    00139       }
    00140     }
    00141
    00142     VehicleType vt = g->vehicle_type;
    00143
    00144     /* Delete the Replace Vehicle Windows */
    00145     DeleteWindowById(WC_REPLACE_VEHICLE, g->vehicle_type);
    00146     delete g;
    00147
    00148     InvalidateWindowData(GetWindowClassForVehicleType(vt), (vt << 11) | VLW_GROUP_LIST | _current_company);
    00149   }
    00150
    00151   return CommandCost();
    00152 }
    00153
    00154 static bool IsUniqueGroupName(const char *name)
    00155 {
    00156   const Group *g;
    00157
    00158   FOR_ALL_GROUPS(g) {
    00159     if (g->name != NULL && strcmp(g->name, name) == 0) return false;
    00160   }
    00161
    00162   return true;
    00163 }
    00164
    00175 CommandCost CmdRenameGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00176 {
    00177   Group *g = Group::GetIfValid(p1);
    00178   if (g == NULL || g->owner != _current_company) return CMD_ERROR;
    00179
    00180   bool reset = StrEmpty(text);
    00181
    00182   if (!reset) {
    00183     if (strlen(text) >= MAX_LENGTH_GROUP_NAME_BYTES) return CMD_ERROR;
    00184     if (!IsUniqueGroupName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
    00185   }
    00186
    00187   if (flags & DC_EXEC) {
    00188     /* Delete the old name */
    00189     free(g->name);
    00190     /* Assign the new one */
    00191     g->name = reset ? NULL : strdup(text);
    00192
    00193     InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), (g->vehicle_type << 11) | VLW_GROUP_LIST | _current_company);
    00194   }
    00195
    00196   return CommandCost();
    00197 }
    00198
    00199
    00211 CommandCost CmdAddVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00212 {
    00213   Vehicle *v = Vehicle::GetIfValid(p2);
    00214   GroupID new_g = p1;
    00215
    00216   if (v == NULL || (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g))) return CMD_ERROR;
    00217
    00218   if (Group::IsValidID(new_g)) {
    00219     Group *g = Group::Get(new_g);
    00220     if (g->owner != _current_company || g->vehicle_type != v->type) return CMD_ERROR;
    00221   }
    00222
    00223   if (v->owner != _current_company || !v->IsPrimaryVehicle()) return CMD_ERROR;
    00224
    00225   if (flags & DC_EXEC) {
    00226     DecreaseGroupNumVehicle(v->group_id);
    00227     IncreaseGroupNumVehicle(new_g);
    00228
    00229     switch (v->type) {
    00230       default: NOT_REACHED();
    00231       case VEH_TRAIN:
    00232         SetTrainGroupID(Train::From(v), new_g);
    00233         break;
    00234       case VEH_ROAD:
    00235       case VEH_SHIP:
    00236       case VEH_AIRCRAFT:
    00237         if (v->IsEngineCountable()) UpdateNumEngineGroup(v->engine_type, v->group_id, new_g);
    00238         v->group_id = new_g;
    00239         break;
    00240     }
    00241
    00242     /* Update the Replace Vehicle Windows */
    00243     SetWindowDirty(WC_REPLACE_VEHICLE, v->type);
    00244     InvalidateWindowData(GetWindowClassForVehicleType(v->type), (v->type << 11) | VLW_GROUP_LIST | _current_company);
    00245   }
    00246
    00247   return CommandCost();
    00248 }
    00249
    00260 CommandCost CmdAddSharedVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00261 {
    00262   VehicleType type = Extract<VehicleType, 0, 3>(p2);
    00263   GroupID id_g = p1;
    00264   if (!Group::IsValidID(id_g) || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
    00265
    00266   if (flags & DC_EXEC) {
    00267     Vehicle *v;
    00268
    00269     /* Find the first front engine which belong to the group id_g
    00270      * then add all shared vehicles of this front engine to the group id_g */
    00271     FOR_ALL_VEHICLES(v) {
    00272       if (v->type == type && v->IsPrimaryVehicle()) {
    00273         if (v->group_id != id_g) continue;
    00274
    00275         /* For each shared vehicles add it to the group */
    00276         for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
    00277           if (v2->group_id != id_g) CmdAddVehicleGroup(tile, flags, id_g, v2->index, text);
    00278         }
    00279       }
    00280     }
    00281
    00282     InvalidateWindowData(GetWindowClassForVehicleType(type), (type << 11) | VLW_GROUP_LIST | _current_company);
    00283   }
    00284
    00285   return CommandCost();
    00286 }
    00287
    00288
    00299 CommandCost CmdRemoveAllVehiclesGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00300 {
    00301   GroupID old_g = p1;
    00302   Group *g = Group::GetIfValid(old_g);
    00303   VehicleType type = Extract<VehicleType, 0, 3>(p2);
    00304
    00305   if (g == NULL || g->owner != _current_company || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
    00306
    00307   if (flags & DC_EXEC) {
    00308     Vehicle *v;
    00309
    00310     /* Find each Vehicle that belongs to the group old_g and add it to the default group */
    00311     FOR_ALL_VEHICLES(v) {
    00312       if (v->type == type && v->IsPrimaryVehicle()) {
    00313         if (v->group_id != old_g) continue;
    00314
    00315         /* Add The Vehicle to the default group */
    00316         CmdAddVehicleGroup(tile, flags, DEFAULT_GROUP, v->index, text);
    00317       }
    00318     }
    00319
    00320     InvalidateWindowData(GetWindowClassForVehicleType(type), (type << 11) | VLW_GROUP_LIST | _current_company);
    00321   }
    00322
    00323   return CommandCost();
    00324 }
    00325
    00326
    00338 CommandCost CmdSetGroupReplaceProtection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00339 {
    00340   Group *g = Group::GetIfValid(p1);
    00341   if (g == NULL || g->owner != _current_company) return CMD_ERROR;
    00342
    00343   if (flags & DC_EXEC) {
    00344     g->replace_protection = HasBit(p2, 0);
    00345
    00346     InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), (g->vehicle_type << 11) | VLW_GROUP_LIST | _current_company);
    00347     InvalidateWindowData(WC_REPLACE_VEHICLE, g->vehicle_type);
    00348   }
    00349
    00350   return CommandCost();
    00351 }
    00352
    00358 void RemoveVehicleFromGroup(const Vehicle *v)
    00359 {
    00360   if (!v->IsPrimaryVehicle()) return;
    00361
    00362   if (!IsDefaultGroupID(v->group_id)) DecreaseGroupNumVehicle(v->group_id);
    00363 }
    00364
    00365
    00372 void SetTrainGroupID(Train *v, GroupID new_g)
    00373 {
    00374   if (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g)) return;
    00375
    00376   assert(v->IsFrontEngine() || IsDefaultGroupID(new_g));
    00377
    00378   for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00379     if (u->IsEngineCountable()) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g);
    00380
    00381     u->group_id = new_g;
    00382   }
    00383
    00384   /* Update the Replace Vehicle Windows */
    00385   SetWindowDirty(WC_REPLACE_VEHICLE, VEH_TRAIN);
    00386 }
    00387
    00388
    00396 void UpdateTrainGroupID(Train *v)
    00397 {
    00398   assert(v->IsFrontEngine() || v->IsFreeWagon());
    00399
    00400   GroupID new_g = v->IsFrontEngine() ? v->group_id : (GroupID)DEFAULT_GROUP;
    00401   for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00402     if (u->IsEngineCountable()) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g);
    00403
    00404     u->group_id = new_g;
    00405   }
    00406
    00407   /* Update the Replace Vehicle Windows */
    00408   SetWindowDirty(WC_REPLACE_VEHICLE, VEH_TRAIN);
    00409 }
    00410
    00411 uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
    00412 {
    00413   if (Group::IsValidID(id_g)) return Group::Get(id_g)->num_engines[id_e];
    00414
    00415   uint num = Company::Get(company)->num_engines[id_e];
    00416   if (!IsDefaultGroupID(id_g)) return num;
    00417
    00418   const Group *g;
    00419   FOR_ALL_GROUPS(g) {
    00420     if (g->owner == company) num -= g->num_engines[id_e];
    00421   }
    00422   return num;
    00423 }
    00424
    00425 void RemoveAllGroupsForCompany(const CompanyID company)
    00426 {
    00427   Group *g;
    00428
    00429   FOR_ALL_GROUPS(g) {
    00430     if (company == g->owner) delete g;
    00431   }
    00432 }