# group_cmd.cpp

Go to the documentation of this file.

    00001 /* $Id: group_cmd.cpp 12864 2008-04-24 11:48:09Z rubidium $ */
    00002
    00005 #include "stdafx.h"
    00006 #include "openttd.h"
    00007 #include "variables.h"
    00008 #include "command_func.h"
    00009 #include "saveload.h"
    00010 #include "debug.h"
    00011 #include "group.h"
    00012 #include "train.h"
    00013 #include "aircraft.h"
    00014 #include "vehicle_gui.h"
    00015 #include "strings_func.h"
    00016 #include "functions.h"
    00017 #include "window_func.h"
    00018 #include "vehicle_func.h"
    00019 #include "autoreplace_base.h"
    00020 #include "autoreplace_func.h"
    00021 #include "string_func.h"
    00022 #include "player_func.h"
    00023
    00024 #include "table/strings.h"
    00025
    00033 static inline void UpdateNumEngineGroup(EngineID i, GroupID old_g, GroupID new_g)
    00034 {
    00035   if (old_g != new_g) {
    00036     /* Decrease the num engines of EngineID i of the old group if it's not the default one */
    00037     if (!IsDefaultGroupID(old_g) && IsValidGroupID(old_g)) GetGroup(old_g)->num_engines[i]--;
    00038
    00039     /* Increase the num engines of EngineID i of the new group if it's not the new one */
    00040     if (!IsDefaultGroupID(new_g) && IsValidGroupID(new_g)) GetGroup(new_g)->num_engines[i]++;
    00041   }
    00042 }
    00043
    00044
    00045 DEFINE_OLD_POOL_GENERIC(Group, Group)
    00046
    00047
    00048 Group::Group(PlayerID owner)
    00049 {
    00050   this->owner = owner;
    00051 }
    00052
    00053 Group::~Group()
    00054 {
    00055   free(this->name);
    00056   this->owner = INVALID_PLAYER;
    00057 }
    00058
    00059 bool Group::IsValid() const
    00060 {
    00061   return this->owner != INVALID_PLAYER;
    00062 }
    00063
    00064 void InitializeGroup(void)
    00065 {
    00066   _Group_pool.CleanPool();
    00067   _Group_pool.AddBlockToPool();
    00068 }
    00069
    00070
    00071 static WindowClass GetWCForVT(VehicleType vt)
    00072 {
    00073   switch (vt) {
    00074     default:
    00075     case VEH_TRAIN:    return WC_TRAINS_LIST;
    00076     case VEH_ROAD:     return WC_ROADVEH_LIST;
    00077     case VEH_SHIP:     return WC_SHIPS_LIST;
    00078     case VEH_AIRCRAFT: return WC_AIRCRAFT_LIST;
    00079   }
    00080 }
    00081
    00082
    00089 CommandCost CmdCreateGroup(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    00090 {
    00091   VehicleType vt = (VehicleType)p1;
    00092   if (!IsPlayerBuildableVehicleType(vt)) return CMD_ERROR;
    00093
    00094   if (!Group::CanAllocateItem()) return CMD_ERROR;
    00095
    00096   if (flags & DC_EXEC) {
    00097     Group *g = new Group(_current_player);
    00098     g->replace_protection = false;
    00099     g->vehicle_type = vt;
    00100
    00101     InvalidateWindowData(GetWCForVT(vt), (vt << 11) | VLW_GROUP_LIST | _current_player);
    00102   }
    00103
    00104   return CommandCost();
    00105 }
    00106
    00107
    00115 CommandCost CmdDeleteGroup(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    00116 {
    00117   if (!IsValidGroupID(p1)) return CMD_ERROR;
    00118
    00119   Group *g = GetGroup(p1);
    00120   if (g->owner != _current_player) return CMD_ERROR;
    00121
    00122   if (flags & DC_EXEC) {
    00123     Vehicle *v;
    00124
    00125     /* Add all vehicles belong to the group to the default group */
    00126     FOR_ALL_VEHICLES(v) {
    00127       if (v->group_id == g->index && v->type == g->vehicle_type) v->group_id = DEFAULT_GROUP;
    00128     }
    00129
    00130     /* Update backupped orders if needed */
    00131     if (_backup_orders_data.group == g->index) _backup_orders_data.group = DEFAULT_GROUP;
    00132
    00133     /* If we set an autoreplace for the group we delete, remove it. */
    00134     if (_current_player < MAX_PLAYERS) {
    00135       Player *p;
    00136       EngineRenew *er;
    00137
    00138       p = GetPlayer(_current_player);
    00139       FOR_ALL_ENGINE_RENEWS(er) {
    00140         if (er->group_id == g->index) RemoveEngineReplacementForPlayer(p, er->from, g->index, flags);
    00141       }
    00142     }
    00143
    00144     VehicleType vt = g->vehicle_type;
    00145
    00146     /* Delete the Replace Vehicle Windows */
    00147     DeleteWindowById(WC_REPLACE_VEHICLE, g->vehicle_type);
    00148     delete g;
    00149
    00150     InvalidateWindowData(GetWCForVT(vt), (vt << 11) | VLW_GROUP_LIST | _current_player);
    00151   }
    00152
    00153   return CommandCost();
    00154 }
    00155
    00156 static bool IsUniqueGroupName(const char *name)
    00157 {
    00158   const Group *g;
    00159   char buf[512];
    00160
    00161   FOR_ALL_GROUPS(g) {
    00162     SetDParam(0, g->index);
    00163     GetString(buf, STR_GROUP_NAME, lastof(buf));
    00164     if (strcmp(buf, name) == 0) return false;
    00165   }
    00166
    00167   return true;
    00168 }
    00169
    00177 CommandCost CmdRenameGroup(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    00178 {
    00179   if (!IsValidGroupID(p1) || StrEmpty(_cmd_text)) return CMD_ERROR;
    00180
    00181   Group *g = GetGroup(p1);
    00182   if (g->owner != _current_player) return CMD_ERROR;
    00183
    00184   if (!IsUniqueGroupName(_cmd_text)) return_cmd_error(STR_NAME_MUST_BE_UNIQUE);
    00185
    00186   if (flags & DC_EXEC) {
    00187     /* Delete the old name */
    00188     free(g->name);
    00189     /* Assign the new one */
    00190     g->name = strdup(_cmd_text);
    00191
    00192     InvalidateWindowData(GetWCForVT(g->vehicle_type), (g->vehicle_type << 11) | VLW_GROUP_LIST | _current_player);
    00193   }
    00194
    00195   return CommandCost();
    00196 }
    00197
    00198
    00207 CommandCost CmdAddVehicleGroup(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    00208 {
    00209   GroupID new_g = p1;
    00210
    00211   if (!IsValidVehicleID(p2) || (!IsValidGroupID(new_g) && !IsDefaultGroupID(new_g))) return CMD_ERROR;
    00212
    00213   Vehicle *v = GetVehicle(p2);
    00214
    00215   if (IsValidGroupID(new_g)) {
    00216     Group *g = GetGroup(new_g);
    00217     if (g->owner != _current_player || g->vehicle_type != v->type) return CMD_ERROR;
    00218   }
    00219
    00220   if (v->owner != _current_player || !v->IsPrimaryVehicle()) return CMD_ERROR;
    00221
    00222   if (flags & DC_EXEC) {
    00223     DecreaseGroupNumVehicle(v->group_id);
    00224     IncreaseGroupNumVehicle(new_g);
    00225
    00226     switch (v->type) {
    00227       default: NOT_REACHED();
    00228       case VEH_TRAIN:
    00229         SetTrainGroupID(v, new_g);
    00230         break;
    00231       case VEH_ROAD:
    00232       case VEH_SHIP:
    00233       case VEH_AIRCRAFT:
    00234         if (IsEngineCountable(v)) UpdateNumEngineGroup(v->engine_type, v->group_id, new_g);
    00235         v->group_id = new_g;
    00236         break;
    00237     }
    00238
    00239     /* Update the Replace Vehicle Windows */
    00240     InvalidateWindow(WC_REPLACE_VEHICLE, v->type);
    00241     InvalidateWindowData(GetWCForVT(v->type), (v->type << 11) | VLW_GROUP_LIST | _current_player);
    00242   }
    00243
    00244   return CommandCost();
    00245 }
    00246
    00254 CommandCost CmdAddSharedVehicleGroup(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    00255 {
    00256   VehicleType type = (VehicleType)p2;
    00257   if (!IsValidGroupID(p1) || !IsPlayerBuildableVehicleType(type)) return CMD_ERROR;
    00258
    00259   if (flags & DC_EXEC) {
    00260     Vehicle *v;
    00261     VehicleType type = (VehicleType)p2;
    00262     GroupID id_g = p1;
    00263
    00264     /* Find the first front engine which belong to the group id_g
    00265      * then add all shared vehicles of this front engine to the group id_g */
    00266     FOR_ALL_VEHICLES(v) {
    00267       if (v->type == type && v->IsPrimaryVehicle()) {
    00268         if (v->group_id != id_g) continue;
    00269
    00270         /* For each shared vehicles add it to the group */
    00271         for (Vehicle *v2 = GetFirstVehicleFromSharedList(v); v2 != NULL; v2 = v2->next_shared) {
    00272           if (v2->group_id != id_g) CmdAddVehicleGroup(tile, flags, id_g, v2->index);
    00273         }
    00274       }
    00275     }
    00276
    00277     InvalidateWindowData(GetWCForVT(type), (type << 11) | VLW_GROUP_LIST | _current_player);
    00278   }
    00279
    00280   return CommandCost();
    00281 }
    00282
    00283
    00291 CommandCost CmdRemoveAllVehiclesGroup(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    00292 {
    00293   VehicleType type = (VehicleType)p2;
    00294   if (!IsValidGroupID(p1) || !IsPlayerBuildableVehicleType(type)) return CMD_ERROR;
    00295
    00296   Group *g = GetGroup(p1);
    00297   if (g->owner != _current_player) return CMD_ERROR;
    00298
    00299   if (flags & DC_EXEC) {
    00300     GroupID old_g = p1;
    00301     Vehicle *v;
    00302
    00303     /* Find each Vehicle that belongs to the group old_g and add it to the default group */
    00304     FOR_ALL_VEHICLES(v) {
    00305       if (v->type == type && v->IsPrimaryVehicle()) {
    00306         if (v->group_id != old_g) continue;
    00307
    00308         /* Add The Vehicle to the default group */
    00309         CmdAddVehicleGroup(tile, flags, DEFAULT_GROUP, v->index);
    00310       }
    00311     }
    00312
    00313     InvalidateWindowData(GetWCForVT(type), (type << 11) | VLW_GROUP_LIST | _current_player);
    00314   }
    00315
    00316   return CommandCost();
    00317 }
    00318
    00319
    00328 CommandCost CmdSetGroupReplaceProtection(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
    00329 {
    00330   if (!IsValidGroupID(p1)) return CMD_ERROR;
    00331
    00332   Group *g = GetGroup(p1);
    00333   if (g->owner != _current_player) return CMD_ERROR;
    00334
    00335   if (flags & DC_EXEC) {
    00336     g->replace_protection = HasBit(p2, 0);
    00337
    00338     InvalidateWindowData(GetWCForVT(g->vehicle_type), (g->vehicle_type << 11) | VLW_GROUP_LIST | _current_player);
    00339   }
    00340
    00341   return CommandCost();
    00342 }
    00343
    00349 void RemoveVehicleFromGroup(const Vehicle *v)
    00350 {
    00351   if (!v->IsValid() || !v->IsPrimaryVehicle()) return;
    00352
    00353   if (!IsDefaultGroupID(v->group_id)) DecreaseGroupNumVehicle(v->group_id);
    00354 }
    00355
    00356
    00363 void SetTrainGroupID(Vehicle *v, GroupID new_g)
    00364 {
    00365   if (!IsValidGroupID(new_g) && !IsDefaultGroupID(new_g)) return;
    00366
    00367   assert(v->IsValid() && v->type == VEH_TRAIN && IsFrontEngine(v));
    00368
    00369   for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00370     if (IsEngineCountable(u)) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g);
    00371
    00372     u->group_id = new_g;
    00373   }
    00374
    00375   /* Update the Replace Vehicle Windows */
    00376   InvalidateWindow(WC_REPLACE_VEHICLE, VEH_TRAIN);
    00377 }
    00378
    00379
    00387 void UpdateTrainGroupID(Vehicle *v)
    00388 {
    00389   assert(v->IsValid() && v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v)));
    00390
    00391   GroupID new_g = IsFrontEngine(v) ? v->group_id : (GroupID)DEFAULT_GROUP;
    00392   for (Vehicle *u = v; u != NULL; u = u->Next()) {
    00393     if (IsEngineCountable(u)) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g);
    00394
    00395     u->group_id = new_g;
    00396   }
    00397
    00398   /* Update the Replace Vehicle Windows */
    00399   InvalidateWindow(WC_REPLACE_VEHICLE, VEH_TRAIN);
    00400 }
    00401
    00402 uint GetGroupNumEngines(PlayerID p, GroupID id_g, EngineID id_e)
    00403 {
    00404   if (IsValidGroupID(id_g)) return GetGroup(id_g)->num_engines[id_e];
    00405
    00406   uint num = GetPlayer(p)->num_engines[id_e];
    00407   if (!IsDefaultGroupID(id_g)) return num;
    00408
    00409   const Group *g;
    00410   FOR_ALL_GROUPS(g) {
    00411     if (g->owner == p) num -= g->num_engines[id_e];
    00412   }
    00413   return num;
    00414 }
    00415
    00416 void RemoveAllGroupsForPlayer(const PlayerID p)
    00417 {
    00418   Group *g;
    00419
    00420   FOR_ALL_GROUPS(g) {
    00421     if (p == g->owner) delete g;
    00422   }
    00423 }
    00424
    00425
    00426 static const SaveLoad _group_desc[] = {
    00427   SLE_CONDVAR(Group, name,           SLE_NAME,    0, 83),
    00428   SLE_CONDSTR(Group, name,           SLE_STR, 0, 84, SL_MAX_VERSION),
    00429   SLE_VAR(Group, num_vehicle,        SLE_UINT16),
    00430   SLE_VAR(Group, owner,              SLE_UINT8),
    00431   SLE_VAR(Group, vehicle_type,       SLE_UINT8),
    00432   SLE_VAR(Group, replace_protection, SLE_BOOL),
    00433   SLE_END()
    00434 };
    00435
    00436
    00437 static void Save_GROUP(void)
    00438 {
    00439   Group *g;
    00440
    00441   FOR_ALL_GROUPS(g) {
    00442     SlSetArrayIndex(g->index);
    00443     SlObject(g, _group_desc);
    00444   }
    00445 }
    00446
    00447
    00448 static void Load_GROUP(void)
    00449 {
    00450   int index;
    00451
    00452   while ((index = SlIterateArray()) != -1) {
    00453     Group *g = new (index) Group();
    00454     SlObject(g, _group_desc);
    00455   }
    00456 }
    00457
    00458 extern const ChunkHandler _group_chunk_handlers[] = {
    00459   { 'GRPS', Save_GROUP, Load_GROUP, CH_ARRAY | CH_LAST},
    00460 };