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 "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
00045 if (!IsDefaultGroupID(old_g) && Group::IsValidID(old_g)) Group::Get(old_g)->num_engines[i]--;
00046
00047
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
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
00129 if (_backup_orders_data.group == g->index) _backup_orders_data.group = DEFAULT_GROUP;
00130
00131
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
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
00189 free(g->name);
00190
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
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
00270
00271 FOR_ALL_VEHICLES(v) {
00272 if (v->type == type && v->IsPrimaryVehicle()) {
00273 if (v->group_id != id_g) continue;
00274
00275
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
00311 FOR_ALL_VEHICLES(v) {
00312 if (v->type == type && v->IsPrimaryVehicle()) {
00313 if (v->group_id != old_g) continue;
00314
00315
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
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
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 }