00001
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
00035 if (!IsDefaultGroupID(old_g) && IsValidGroupID(old_g)) GetGroup(old_g)->num_engines[i]--;
00036
00037
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
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
00122 if (_backup_orders_data.group == g->index) _backup_orders_data.group = DEFAULT_GROUP;
00123
00124
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
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
00181 free(g->name);
00182
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
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
00258
00259 FOR_ALL_VEHICLES(v) {
00260 if (v->type == type && v->IsPrimaryVehicle()) {
00261 if (v->group_id != id_g) continue;
00262
00263
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
00297 FOR_ALL_VEHICLES(v) {
00298 if (v->type == type && v->IsPrimaryVehicle()) {
00299 if (v->group_id != old_g) continue;
00300
00301
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
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
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 }