# group_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: group_cmd.cpp 15434 2009-02-09 21:20:05Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "command_func.h"
    00007 #include "group.h"
    00008 #include "train.h"
    00009 #include "engine_base.h"
    00010 #include "vehicle_gui.h"
    00011 #include "window_func.h"
    00012 #include "vehicle_func.h"
    00013 #include "autoreplace_base.h"
    00014 #include "autoreplace_func.h"
    00015 #include "string_func.h"
    00016 #include "company_func.h"
    00017 #include "oldpool_func.h"
    00018 #include "core/alloc_func.hpp"
    00019
    00020 #include "table/strings.h"
    00021
    00022 GroupID _new_group_id;
    00023
    00031 static inline void UpdateNumEngineGroup(EngineID i, GroupID old_g, GroupID new_g)
    00032 {
    00033   if (old_g != new_g) {
    00034     /* Decrease the num engines of EngineID i of the old group if it's not the default one */
    00035     if (!IsDefaultGroupID(old_g) && IsValidGroupID(old_g)) GetGroup(old_g)->num_engines[i]--;
    00036
    00037     /* Increase the num engines of EngineID i of the new group if it's not the default one */
    00038     if (!IsDefaultGroupID(new_g) && IsValidGroupID(new_g)) GetGroup(new_g)->num_engines[i]++;
    00039   }
    00040 }
    00041
    00042
    00043 DEFINE_OLD_POOL_GENERIC(Group, Group)
    00044
    00045
    00046 Group::Group(Owner owner)
    00047 {
    00048   this->owner = owner;
    00049
    00050   if (this->IsValid()) this->num_engines = CallocT<uint16>(GetEnginePoolSize());
    00051 }
    00052
    00053 Group::~Group()
    00054 {
    00055   free(this->name);
    00056   this->owner = INVALID_OWNER;
    00057   free(this->num_engines);
    00058 }
    00059
    00060 bool Group::IsValid() const
    00061 {
    00062   return this->owner != INVALID_OWNER;
    00063 }
    00064
    00065 void InitializeGroup(void)
    00066 {
    00067   _Group_pool.CleanPool();
    00068   _Group_pool.AddBlockToPool();
    00069 }
    00070
    00071
    00078 CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00079 {
    00080   VehicleType vt = (VehicleType)p1;
    00081   if (!IsCompanyBuildableVehicleType(vt)) return CMD_ERROR;
    00082
    00083   if (!Group::CanAllocateItem()) return CMD_ERROR;
    00084
    00085   if (flags & DC_EXEC) {
    00086     Group *g = new Group(_current_company);
    00087     g->replace_protection = false;
    00088     g->vehicle_type = vt;
    00089
    00090     _new_group_id = g->index;
    00091
    00092     InvalidateWindowData(GetWindowClassForVehicleType(vt), (vt << 11) | VLW_GROUP_LIST | _current_company);
    00093   }
    00094
    00095   return CommandCost();
    00096 }
    00097
    00098
    00106 CommandCost CmdDeleteGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00107 {
    00108   if (!IsValidGroupID(p1)) return CMD_ERROR;
    00109
    00110   Group *g = GetGroup(p1);
    00111   if (g->owner != _current_company) return CMD_ERROR;
    00112
    00113   if (flags & DC_EXEC) {
    00114     Vehicle *v;
    00115
    00116     /* Add all vehicles belong to the group to the default group */
    00117     FOR_ALL_VEHICLES(v) {
    00118       if (v->group_id == g->index && v->type == g->vehicle_type) v->group_id = DEFAULT_GROUP;
    00119     }
    00120
    00121     /* Update backupped orders if needed */
    00122     if (_backup_orders_data.group == g->index) _backup_orders_data.group = DEFAULT_GROUP;
    00123
    00124     /* If we set an autoreplace for the group we delete, remove it. */
    00125     if (_current_company < MAX_COMPANIES) {
    00126       Company *c;
    00127       EngineRenew *er;
    00128
    00129       c = GetCompany(_current_company);
    00130       FOR_ALL_ENGINE_RENEWS(er) {
    00131         if (er->group_id == g->index) RemoveEngineReplacementForCompany(c, er->from, g->index, flags);
    00132       }
    00133     }
    00134
    00135     VehicleType vt = g->vehicle_type;
    00136
    00137     /* Delete the Replace Vehicle Windows */
    00138     DeleteWindowById(WC_REPLACE_VEHICLE, g->vehicle_type);
    00139     delete g;
    00140
    00141     InvalidateWindowData(GetWindowClassForVehicleType(vt), (vt << 11) | VLW_GROUP_LIST | _current_company);
    00142   }
    00143
    00144   return CommandCost();
    00145 }
    00146
    00147 static bool IsUniqueGroupName(const char *name)
    00148 {
    00149   const Group *g;
    00150
    00151   FOR_ALL_GROUPS(g) {
    00152     if (g->name != NULL && strcmp(g->name, name) == 0) return false;
    00153   }
    00154
    00155   return true;
    00156 }
    00157
    00165 CommandCost CmdRenameGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00166 {
    00167   if (!IsValidGroupID(p1)) return CMD_ERROR;
    00168
    00169   Group *g = GetGroup(p1);
    00170   if (g->owner != _current_company) return CMD_ERROR;
    00171
    00172   bool reset = StrEmpty(text);
    00173
    00174   if (!reset) {
    00175     if (strlen(text) >= MAX_LENGTH_GROUP_NAME_BYTES) return CMD_ERROR;
    00176     if (!IsUniqueGroupName(text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
    00177   }
    00178
    00179   if (flags & DC_EXEC) {
    00180     /* Delete the old name */
    00181     free(g->name);
    00182     /* Assign the new one */
    00183     g->name = reset ? NULL : strdup(text);
    00184
    00185     InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), (g->vehicle_type << 11) | VLW_GROUP_LIST | _current_company);
    00186   }
    00187
    00188   return CommandCost();
    00189 }
    00190
    00191
    00200 CommandCost CmdAddVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00201 {
    00202   GroupID new_g = p1;
    00203
    00204   if (!IsValidVehicleID(p2) || (!IsValidGroupID(new_g) && !IsDefaultGroupID(new_g))) return CMD_ERROR;
    00205
    00206   Vehicle *v = GetVehicle(p2);
    00207
    00208   if (IsValidGroupID(new_g)) {
    00209     Group *g = GetGroup(new_g);
    00210     if (g->owner != _current_company || g->vehicle_type != v->type) return CMD_ERROR;
    00211   }
    00212
    00213   if (v->owner != _current_company || !v->IsPrimaryVehicle()) return CMD_ERROR;
    00214
    00215   if (flags & DC_EXEC) {
    00216     DecreaseGroupNumVehicle(v->group_id);
    00217     IncreaseGroupNumVehicle(new_g);
    00218
    00219     switch (v->type) {
    00220       default: NOT_REACHED();
    00221       case VEH_TRAIN:
    00222         SetTrainGroupID(v, new_g);
    00223         break;
    00224       case VEH_ROAD:
    00225       case VEH_SHIP:
    00226       case VEH_AIRCRAFT:
    00227         if (IsEngineCountable(v)) UpdateNumEngineGroup(v->engine_type, v->group_id, new_g);
    00228         v->group_id = new_g;
    00229         break;
    00230     }
    00231
    00232     /* Update the Replace Vehicle Windows */
    00233     InvalidateWindow(WC_REPLACE_VEHICLE, v->type);
    00234     InvalidateWindowData(GetWindowClassForVehicleType(v->type), (v->type << 11) | VLW_GROUP_LIST | _current_company);
    00235   }
    00236
    00237   return CommandCost();
    00238 }
    00239
    00247 CommandCost CmdAddSharedVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00248 {
    00249   VehicleType type = (VehicleType)p2;
    00250   if (!IsValidGroupID(p1) || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
    00251
    00252   if (flags & DC_EXEC) {
    00253     Vehicle *v;
    00254     VehicleType type = (VehicleType)p2;
    00255     GroupID id_g = p1;
    00256
    00257     /* Find the first front engine which belong to the group id_g
    00258      * then add all shared vehicles of this front engine to the group id_g */
    00259     FOR_ALL_VEHICLES(v) {
    00260       if (v->type == type && v->IsPrimaryVehicle()) {
    00261         if (v->group_id != id_g) continue;
    00262
    00263         /* For each shared vehicles add it to the group */
    00264         for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
    00265           if (v2->group_id != id_g) CmdAddVehicleGroup(tile, flags, id_g, v2->index, text);
    00266         }
    00267       }
    00268     }
    00269
    00270     InvalidateWindowData(GetWindowClassForVehicleType(type), (type << 11) | VLW_GROUP_LIST | _current_company);
    00271   }
    00272
    00273   return CommandCost();
    00274 }
    00275
    00276
    00284 CommandCost CmdRemoveAllVehiclesGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00285 {
    00286   VehicleType type = (VehicleType)p2;
    00287   if (!IsValidGroupID(p1) || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
    00288
    00289   Group *g = GetGroup(p1);
    00290   if (g->owner != _current_company) return CMD_ERROR;
    00291
    00292   if (flags & DC_EXEC) {
    00293     GroupID old_g = p1;
    00294     Vehicle *v;
    00295
    00296     /* Find each Vehicle that belongs to the group old_g and add it to the default group */
    00297     FOR_ALL_VEHICLES(v) {
    00298       if (v->type == type && v->IsPrimaryVehicle()) {
    00299         if (v->group_id != old_g) continue;
    00300
    00301         /* Add The Vehicle to the default group */
    00302         CmdAddVehicleGroup(tile, flags, DEFAULT_GROUP, v->index, text);
    00303       }
    00304     }
    00305
    00306     InvalidateWindowData(GetWindowClassForVehicleType(type), (type << 11) | VLW_GROUP_LIST | _current_company);
    00307   }
    00308
    00309   return CommandCost();
    00310 }
    00311
    00312
    00321 CommandCost CmdSetGroupReplaceProtection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
    00322 {
    00323   if (!IsValidGroupID(p1)) return CMD_ERROR;
    00324
    00325   Group *g = GetGroup(p1);
    00326   if (g->owner != _current_company) return CMD_ERROR;
    00327
    00328   if (flags & DC_EXEC) {
    00329     g->replace_protection = HasBit(p2, 0);
    00330
    00331     InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), (g->vehicle_type << 11) | VLW_GROUP_LIST | _current_company);
    00332     InvalidateWindowData(WC_REPLACE_VEHICLE, g->vehicle_type);
    00333   }
    00334
    00335   return CommandCost();
    00336 }
    00337
    00343 void RemoveVehicleFromGroup(const Vehicle *v)
    00344 {
    00345   if (!v->IsValid() || !v->IsPrimaryVehicle()) return;
    00346
    00347   if (!IsDefaultGroupID(v->group_id)) DecreaseGroupNumVehicle(v->group_id);
    00348 }
    00349
    00350
    00357 void SetTrainGroupID(Vehicle *v, GroupID new_g)
    00358 {
    00359   if (!IsValidGroupID(new_g) && !IsDefaultGroupID(new_g)) return;
    00360
    00361   assert(v->IsValid() && v->type == VEH_TRAIN && IsFrontEngine(v));
    00362
    00363   for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00364     if (IsEngineCountable(u)) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g);
    00365
    00366     u->group_id = new_g;
    00367   }
    00368
    00369   /* Update the Replace Vehicle Windows */
    00370   InvalidateWindow(WC_REPLACE_VEHICLE, VEH_TRAIN);
    00371 }
    00372
    00373
    00381 void UpdateTrainGroupID(Vehicle *v)
    00382 {
    00383   assert(v->IsValid() && v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v)));
    00384
    00385   GroupID new_g = IsFrontEngine(v) ? v->group_id : (GroupID)DEFAULT_GROUP;
    00386   for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00387     if (IsEngineCountable(u)) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g);
    00388
    00389     u->group_id = new_g;
    00390   }
    00391
    00392   /* Update the Replace Vehicle Windows */
    00393   InvalidateWindow(WC_REPLACE_VEHICLE, VEH_TRAIN);
    00394 }
    00395
    00396 uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
    00397 {
    00398   if (IsValidGroupID(id_g)) return GetGroup(id_g)->num_engines[id_e];
    00399
    00400   uint num = GetCompany(company)->num_engines[id_e];
    00401   if (!IsDefaultGroupID(id_g)) return num;
    00402
    00403   const Group *g;
    00404   FOR_ALL_GROUPS(g) {
    00405     if (g->owner == company) num -= g->num_engines[id_e];
    00406   }
    00407   return num;
    00408 }
    00409
    00410 void RemoveAllGroupsForCompany(const CompanyID company)
    00411 {
    00412   Group *g;
    00413
    00414   FOR_ALL_GROUPS(g) {
    00415     if (company == g->owner) delete g;
    00416   }
    00417 }