00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "command_func.h"
00014 #include "group.h"
00015 #include "train.h"
00016 #include "engine_base.h"
00017 #include "vehicle_gui.h"
00018 #include "window_func.h"
00019 #include "vehicle_func.h"
00020 #include "autoreplace_base.h"
00021 #include "autoreplace_func.h"
00022 #include "string_func.h"
00023 #include "company_func.h"
00024 #include "core/pool_func.hpp"
00025
00026 #include "table/strings.h"
00027
00028 GroupID _new_group_id;
00029
00030 GroupPool _group_pool("Group");
00031 INSTANTIATE_POOL_METHODS(Group)
00032
00033
00040 static inline void UpdateNumEngineGroup(EngineID i, GroupID old_g, GroupID new_g)
00041 {
00042 if (old_g != new_g) {
00043
00044 if (!IsDefaultGroupID(old_g) && Group::IsValidID(old_g)) Group::Get(old_g)->num_engines[i]--;
00045
00046
00047 if (!IsDefaultGroupID(new_g) && Group::IsValidID(new_g)) Group::Get(new_g)->num_engines[i]++;
00048 }
00049 }
00050
00051
00052
00053 Group::Group(Owner owner)
00054 {
00055 this->owner = owner;
00056
00057 if (!Company::IsValidID(owner)) return;
00058
00059 this->num_engines = CallocT<uint16>(Engine::GetPoolSize());
00060 }
00061
00062 Group::~Group()
00063 {
00064 free(this->name);
00065 free(this->num_engines);
00066 }
00067
00068 void InitializeGroup()
00069 {
00070 _group_pool.CleanPool();
00071 }
00072
00073
00083 CommandCost CmdCreateGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00084 {
00085 VehicleType vt = (VehicleType)p1;
00086 if (!IsCompanyBuildableVehicleType(vt)) return CMD_ERROR;
00087
00088 if (!Group::CanAllocateItem()) return CMD_ERROR;
00089
00090 if (flags & DC_EXEC) {
00091 Group *g = new Group(_current_company);
00092 g->replace_protection = false;
00093 g->vehicle_type = vt;
00094
00095 _new_group_id = g->index;
00096
00097 InvalidateWindowData(GetWindowClassForVehicleType(vt), (vt << 11) | VLW_GROUP_LIST | _current_company);
00098 }
00099
00100 return CommandCost();
00101 }
00102
00103
00114 CommandCost CmdDeleteGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00115 {
00116 Group *g = Group::GetIfValid(p1);
00117 if (g == NULL || g->owner != _current_company) return CMD_ERROR;
00118
00119 if (flags & DC_EXEC) {
00120 Vehicle *v;
00121
00122
00123 FOR_ALL_VEHICLES(v) {
00124 if (v->group_id == g->index && v->type == g->vehicle_type) v->group_id = DEFAULT_GROUP;
00125 }
00126
00127
00128 if (_backup_orders_data.group == g->index) _backup_orders_data.group = DEFAULT_GROUP;
00129
00130
00131 if (_current_company < MAX_COMPANIES) {
00132 Company *c;
00133 EngineRenew *er;
00134
00135 c = Company::Get(_current_company);
00136 FOR_ALL_ENGINE_RENEWS(er) {
00137 if (er->group_id == g->index) RemoveEngineReplacementForCompany(c, er->from, g->index, flags);
00138 }
00139 }
00140
00141 VehicleType vt = g->vehicle_type;
00142
00143
00144 DeleteWindowById(WC_REPLACE_VEHICLE, g->vehicle_type);
00145 delete g;
00146
00147 InvalidateWindowData(GetWindowClassForVehicleType(vt), (vt << 11) | VLW_GROUP_LIST | _current_company);
00148 }
00149
00150 return CommandCost();
00151 }
00152
00153 static bool IsUniqueGroupName(const char *name)
00154 {
00155 const Group *g;
00156
00157 FOR_ALL_GROUPS(g) {
00158 if (g->name != NULL && strcmp(g->name, name) == 0) return false;
00159 }
00160
00161 return true;
00162 }
00163
00174 CommandCost CmdRenameGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00175 {
00176 Group *g = Group::GetIfValid(p1);
00177 if (g == NULL || g->owner != _current_company) return CMD_ERROR;
00178
00179 bool reset = StrEmpty(text);
00180
00181 if (!reset) {
00182 if (strlen(text) >= MAX_LENGTH_GROUP_NAME_BYTES) return CMD_ERROR;
00183 if (!IsUniqueGroupName(text)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
00184 }
00185
00186 if (flags & DC_EXEC) {
00187
00188 free(g->name);
00189
00190 g->name = reset ? NULL : strdup(text);
00191
00192 InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), (g->vehicle_type << 11) | VLW_GROUP_LIST | _current_company);
00193 }
00194
00195 return CommandCost();
00196 }
00197
00198
00210 CommandCost CmdAddVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00211 {
00212 Vehicle *v = Vehicle::GetIfValid(p2);
00213 GroupID new_g = p1;
00214
00215 if (v == NULL || (!Group::IsValidID(new_g) && !IsDefaultGroupID(new_g))) return CMD_ERROR;
00216
00217 if (Group::IsValidID(new_g)) {
00218 Group *g = Group::Get(new_g);
00219 if (g->owner != _current_company || g->vehicle_type != v->type) return CMD_ERROR;
00220 }
00221
00222 if (v->owner != _current_company || !v->IsPrimaryVehicle()) return CMD_ERROR;
00223
00224 if (flags & DC_EXEC) {
00225 DecreaseGroupNumVehicle(v->group_id);
00226 IncreaseGroupNumVehicle(new_g);
00227
00228 switch (v->type) {
00229 default: NOT_REACHED();
00230 case VEH_TRAIN:
00231 SetTrainGroupID(Train::From(v), new_g);
00232 break;
00233 case VEH_ROAD:
00234 case VEH_SHIP:
00235 case VEH_AIRCRAFT:
00236 if (v->IsEngineCountable()) UpdateNumEngineGroup(v->engine_type, v->group_id, new_g);
00237 v->group_id = new_g;
00238 break;
00239 }
00240
00241
00242 SetWindowDirty(WC_REPLACE_VEHICLE, v->type);
00243 InvalidateWindowData(GetWindowClassForVehicleType(v->type), (v->type << 11) | VLW_GROUP_LIST | _current_company);
00244 }
00245
00246 return CommandCost();
00247 }
00248
00259 CommandCost CmdAddSharedVehicleGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
00260 {
00261 VehicleType type = (VehicleType)p2;
00262 if (!Group::IsValidID(p1) || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
00263
00264 if (flags & DC_EXEC) {
00265 Vehicle *v;
00266 VehicleType type = (VehicleType)p2;
00267 GroupID id_g = p1;
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 Group *g = Group::GetIfValid(p1);
00302 VehicleType type = (VehicleType)p2;
00303
00304 if (g == NULL || g->owner != _current_company || !IsCompanyBuildableVehicleType(type)) return CMD_ERROR;
00305
00306 if (flags & DC_EXEC) {
00307 GroupID old_g = p1;
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 }