00001
00002
00003
00004
00005
00006
00007
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
00046 if (!IsDefaultGroupID(old_g) && Group::IsValidID(old_g)) Group::Get(old_g)->num_engines[i]--;
00047
00048
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
00080 CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00081 {
00082 VehicleType vt = Extract<VehicleType, 0, 3>(p1);
00083 if (!IsCompanyBuildableVehicleType(vt)) return CMD_ERROR;
00084
00085 if (!Group::CanAllocateItem()) return CMD_ERROR;
00086
00087 if (flags & DC_EXEC) {
00088 Group *g = new Group(_current_company);
00089 g->replace_protection = false;
00090 g->vehicle_type = vt;
00091
00092 _new_group_id = g->index;
00093
00094 InvalidateWindowData(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).Pack());
00095 }
00096
00097 return CommandCost();
00098 }
00099
00100
00111 CommandCost CmdDeleteGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00112 {
00113 Group *g = Group::GetIfValid(p1);
00114 if (g == NULL || g->owner != _current_company) return CMD_ERROR;
00115
00116 if (flags & DC_EXEC) {
00117 Vehicle *v;
00118
00119
00120 FOR_ALL_VEHICLES(v) {
00121 if (v->group_id == g->index && v->type == g->vehicle_type) v->group_id = DEFAULT_GROUP;
00122 }
00123
00124
00125 OrderBackup::ClearGroup(g->index);
00126
00127
00128 if (_current_company < MAX_COMPANIES) {
00129 Company *c;
00130 EngineRenew *er;
00131
00132 c = Company::Get(_current_company);
00133 FOR_ALL_ENGINE_RENEWS(er) {
00134 if (er->group_id == g->index) RemoveEngineReplacementForCompany(c, er->from, g->index, flags);
00135 }
00136 }
00137
00138 VehicleType vt = g->vehicle_type;
00139
00140
00141 DeleteWindowById(WC_REPLACE_VEHICLE, g->vehicle_type);
00142 delete g;
00143
00144 InvalidateWindowData(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).Pack());
00145 }
00146
00147 return CommandCost();
00148 }
00149
00150 static bool IsUniqueGroupName(const char *name)
00151 {
00152 const Group *g;
00153
00154 FOR_ALL_GROUPS(g) {
00155 if (g->name != NULL && strcmp(g->name, name) == 0) return false;
00156 }
00157
00158 return true;
00159 }
00160
00171 CommandCost CmdRenameGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00172 {
00173 Group *g = Group::GetIfValid(p1);
00174 if (g == NULL || g->owner != _current_company) return CMD_ERROR;
00175
00176 bool reset = StrEmpty(text);
00177
00178 if (!reset) {
00179 if (Utf8StringLength(text) >= MAX_LENGTH_GROUP_NAME_CHARS) return CMD_ERROR;
00180 if (!IsUniqueGroupName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
00181 }
00182
00183 if (flags & DC_EXEC) {
00184
00185 free(g->name);
00186
00187 g->name = reset ? NULL : strdup(text);
00188
00189 InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
00190 }
00191
00192 return CommandCost();
00193 }
00194
00195
00207 CommandCost CmdAddVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00208 {
00209 Vehicle *v = Vehicle::GetIfValid(p2);
00210 GroupID new_g = p1;
00211
00212 if (v == NULL || (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g))) return CMD_ERROR;
00213
00214 if (Group::IsValidID(new_g)) {
00215 Group *g = Group::Get(new_g);
00216 if (g->owner != _current_company || g->vehicle_type != v->type) return CMD_ERROR;
00217 }
00218
00219 if (v->owner != _current_company || !v->IsPrimaryVehicle()) return CMD_ERROR;
00220
00221 if (flags & DC_EXEC) {
00222 DecreaseGroupNumVehicle(v->group_id);
00223 IncreaseGroupNumVehicle(new_g);
00224
00225 switch (v->type) {
00226 default: NOT_REACHED();
00227 case VEH_TRAIN:
00228 SetTrainGroupID(Train::From(v), new_g);
00229 break;
00230 case VEH_ROAD:
00231 case VEH_SHIP:
00232 case VEH_AIRCRAFT:
00233 if (v->IsEngineCountable()) UpdateNumEngineGroup(v->engine_type, v->group_id, new_g);
00234 v->group_id = new_g;
00235 break;
00236 }
00237
00238
00239 SetWindowDirty(WC_REPLACE_VEHICLE, v->type);
00240 InvalidateWindowData(GetWindowClassForVehicleType(v->type), VehicleListIdentifier(VL_GROUP_LIST, v->type, _current_company).Pack());
00241 }
00242
00243 return CommandCost();
00244 }
00245
00256 CommandCost CmdAddSharedVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00257 {
00258 VehicleType type = Extract<VehicleType, 0, 3>(p2);
00259 GroupID id_g = p1;
00260 if (!Group::IsValidID(id_g) || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
00261
00262 if (flags & DC_EXEC) {
00263 Vehicle *v;
00264
00265
00266
00267 FOR_ALL_VEHICLES(v) {
00268 if (v->type == type && v->IsPrimaryVehicle()) {
00269 if (v->group_id != id_g) continue;
00270
00271
00272 for (Vehicle *v2 = v->FirstShared(); v2 != NULL; v2 = v2->NextShared()) {
00273 if (v2->group_id != id_g) DoCommand(tile, id_g, v2->index, flags, CMD_ADD_VEHICLE_GROUP, text);
00274 }
00275 }
00276 }
00277
00278 InvalidateWindowData(GetWindowClassForVehicleType(type), VehicleListIdentifier(VL_GROUP_LIST, type, _current_company).Pack());
00279 }
00280
00281 return CommandCost();
00282 }
00283
00284
00295 CommandCost CmdRemoveAllVehiclesGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00296 {
00297 GroupID old_g = p1;
00298 Group *g = Group::GetIfValid(old_g);
00299 VehicleType type = Extract<VehicleType, 0, 3>(p2);
00300
00301 if (g == NULL || g->owner != _current_company || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
00302
00303 if (flags & DC_EXEC) {
00304 Vehicle *v;
00305
00306
00307 FOR_ALL_VEHICLES(v) {
00308 if (v->type == type && v->IsPrimaryVehicle()) {
00309 if (v->group_id != old_g) continue;
00310
00311
00312 DoCommand(tile, DEFAULT_GROUP, v->index, flags, CMD_ADD_VEHICLE_GROUP, text);
00313 }
00314 }
00315
00316 InvalidateWindowData(GetWindowClassForVehicleType(type), VehicleListIdentifier(VL_GROUP_LIST, type, _current_company).Pack());
00317 }
00318
00319 return CommandCost();
00320 }
00321
00322
00334 CommandCost CmdSetGroupReplaceProtection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00335 {
00336 Group *g = Group::GetIfValid(p1);
00337 if (g == NULL || g->owner != _current_company) return CMD_ERROR;
00338
00339 if (flags & DC_EXEC) {
00340 g->replace_protection = HasBit(p2, 0);
00341
00342 InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
00343 InvalidateWindowData(WC_REPLACE_VEHICLE, g->vehicle_type);
00344 }
00345
00346 return CommandCost();
00347 }
00348
00354 void RemoveVehicleFromGroup(const Vehicle *v)
00355 {
00356 if (!v->IsPrimaryVehicle()) return;
00357
00358 if (!IsDefaultGroupID(v->group_id)) DecreaseGroupNumVehicle(v->group_id);
00359 }
00360
00361
00368 void SetTrainGroupID(Train *v, GroupID new_g)
00369 {
00370 if (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g)) return;
00371
00372 assert(v->IsFrontEngine() || IsDefaultGroupID(new_g));
00373
00374 for (Vehicle *u = v; u != NULL; u = u->Next()) {
00375 if (u->IsEngineCountable()) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g);
00376
00377 u->group_id = new_g;
00378 }
00379
00380
00381 SetWindowDirty(WC_REPLACE_VEHICLE, VEH_TRAIN);
00382 }
00383
00384
00392 void UpdateTrainGroupID(Train *v)
00393 {
00394 assert(v->IsFrontEngine() || v->IsFreeWagon());
00395
00396 GroupID new_g = v->IsFrontEngine() ? v->group_id : (GroupID)DEFAULT_GROUP;
00397 for (Vehicle *u = v; u != NULL; u = u->Next()) {
00398 if (u->IsEngineCountable()) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g);
00399
00400 u->group_id = new_g;
00401 }
00402
00403
00404 SetWindowDirty(WC_REPLACE_VEHICLE, VEH_TRAIN);
00405 }
00406
00415 uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
00416 {
00417 if (Group::IsValidID(id_g)) return Group::Get(id_g)->num_engines[id_e];
00418
00419 uint num = Company::Get(company)->num_engines[id_e];
00420 if (!IsDefaultGroupID(id_g)) return num;
00421
00422 const Group *g;
00423 FOR_ALL_GROUPS(g) {
00424 if (g->owner == company) num -= g->num_engines[id_e];
00425 }
00426 return num;
00427 }
00428
00429 void RemoveAllGroupsForCompany(const CompanyID company)
00430 {
00431 Group *g;
00432
00433 FOR_ALL_GROUPS(g) {
00434 if (company == g->owner) delete g;
00435 }
00436 }