17 #include "aircraft.h" |
17 #include "aircraft.h" |
18 #include "string.h" |
18 #include "string.h" |
19 #include "window.h" |
19 #include "window.h" |
20 #include "vehicle_gui.h" |
20 #include "vehicle_gui.h" |
21 #include "strings.h" |
21 #include "strings.h" |
|
22 #include "misc/autoptr.hpp" |
22 |
23 |
23 /** |
24 /** |
24 * Update the num engines of a groupID. Decrease the old one and increase the new one |
25 * Update the num engines of a groupID. Decrease the old one and increase the new one |
25 * @note called in SetTrainGroupID and UpdateTrainGroupID |
26 * @note called in SetTrainGroupID and UpdateTrainGroupID |
26 * @param i EngineID we have to update |
27 * @param i EngineID we have to update |
37 if (!IsDefaultGroupID(new_g) && IsValidGroupID(new_g)) GetGroup(new_g)->num_engines[i]++; |
38 if (!IsDefaultGroupID(new_g) && IsValidGroupID(new_g)) GetGroup(new_g)->num_engines[i]++; |
38 } |
39 } |
39 } |
40 } |
40 |
41 |
41 |
42 |
42 /** |
43 DEFINE_OLD_POOL_GENERIC(Group, Group) |
43 * Called if a new block is added to the group-pool |
44 |
44 */ |
45 |
45 static void GroupPoolNewBlock(uint start_item) |
46 Group::Group(StringID str) |
46 { |
47 { |
47 /* We don't use FOR_ALL here, because FOR_ALL skips invalid items. |
48 this->string_id = str; |
48 * TODO - This is just a temporary stage, this will be removed. */ |
49 } |
49 for (Group *g = GetGroup(start_item); g != NULL; g = (g->index + 1U < GetGroupPoolSize()) ? GetGroup(g->index + 1) : NULL) g->index = start_item++; |
50 |
50 } |
51 Group::~Group() |
51 |
52 { |
52 DEFINE_OLD_POOL(Group, Group, GroupPoolNewBlock, NULL) |
53 this->QuickFree(); |
53 |
54 this->string_id = STR_NULL; |
54 static Group *AllocateGroup(void) |
55 } |
55 { |
56 |
56 /* We don't use FOR_ALL here, because FOR_ALL skips invalid items. |
57 void Group::QuickFree() |
57 * TODO - This is just a temporary stage, this will be removed. */ |
58 { |
58 for (Group *g = GetGroup(0); g != NULL; g = (g->index + 1U < GetGroupPoolSize()) ? GetGroup(g->index + 1) : NULL) { |
59 DeleteName(this->string_id); |
59 if (!IsValidGroup(g)) { |
60 } |
60 const GroupID index = g->index; |
61 |
61 |
62 bool Group::IsValid() const |
62 memset(g, 0, sizeof(*g)); |
63 { |
63 g->index = index; |
64 return this->string_id != STR_NULL; |
64 |
|
65 return g; |
|
66 } |
|
67 } |
|
68 |
|
69 /* Check if we can add a block to the pool */ |
|
70 return (AddBlockToPool(&_Group_pool)) ? AllocateGroup() : NULL; |
|
71 } |
65 } |
72 |
66 |
73 void InitializeGroup(void) |
67 void InitializeGroup(void) |
74 { |
68 { |
75 CleanPool(&_Group_pool); |
69 _Group_pool.CleanPool(); |
76 AddBlockToPool(&_Group_pool); |
70 _Group_pool.AddBlockToPool(); |
77 } |
71 } |
78 |
72 |
79 |
73 |
80 static WindowClass GetWCForVT(VehicleType vt) |
74 static WindowClass GetWCForVT(VehicleType vt) |
81 { |
75 { |
98 CommandCost CmdCreateGroup(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
92 CommandCost CmdCreateGroup(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) |
99 { |
93 { |
100 VehicleType vt = (VehicleType)p1; |
94 VehicleType vt = (VehicleType)p1; |
101 if (!IsPlayerBuildableVehicleType(vt)) return CMD_ERROR; |
95 if (!IsPlayerBuildableVehicleType(vt)) return CMD_ERROR; |
102 |
96 |
103 Group *g = AllocateGroup(); |
97 AutoPtrT<Group> g_auto_delete; |
|
98 |
|
99 Group *g = new Group(STR_EMPTY); |
104 if (g == NULL) return CMD_ERROR; |
100 if (g == NULL) return CMD_ERROR; |
105 |
101 |
|
102 g_auto_delete = g; |
|
103 |
106 if (flags & DC_EXEC) { |
104 if (flags & DC_EXEC) { |
107 g->owner = _current_player; |
105 g->owner = _current_player; |
108 g->string_id = STR_EMPTY; |
|
109 g->replace_protection = false; |
106 g->replace_protection = false; |
110 g->vehicle_type = vt; |
107 g->vehicle_type = vt; |
111 |
108 |
112 InvalidateWindowData(GetWCForVT(vt), (vt << 11) | VLW_GROUP_LIST | _current_player); |
109 InvalidateWindowData(GetWCForVT(vt), (vt << 11) | VLW_GROUP_LIST | _current_player); |
|
110 |
|
111 g_auto_delete.Detach(); |
113 } |
112 } |
114 |
113 |
115 return CommandCost(); |
114 return CommandCost(); |
116 } |
115 } |
117 |
116 |
151 |
150 |
152 VehicleType vt = g->vehicle_type; |
151 VehicleType vt = g->vehicle_type; |
153 |
152 |
154 /* Delete the Replace Vehicle Windows */ |
153 /* Delete the Replace Vehicle Windows */ |
155 DeleteWindowById(WC_REPLACE_VEHICLE, g->vehicle_type); |
154 DeleteWindowById(WC_REPLACE_VEHICLE, g->vehicle_type); |
156 DeleteGroup(g); |
155 delete g; |
157 |
156 |
158 InvalidateWindowData(GetWCForVT(vt), (vt << 11) | VLW_GROUP_LIST | _current_player); |
157 InvalidateWindowData(GetWCForVT(vt), (vt << 11) | VLW_GROUP_LIST | _current_player); |
159 } |
158 } |
160 |
159 |
161 return CommandCost(); |
160 return CommandCost(); |
357 * @note Called in CmdSellRailWagon and DeleteLasWagon, |
356 * @note Called in CmdSellRailWagon and DeleteLasWagon, |
358 * @param v FrontEngine of the train we want to remove. |
357 * @param v FrontEngine of the train we want to remove. |
359 */ |
358 */ |
360 void RemoveVehicleFromGroup(const Vehicle *v) |
359 void RemoveVehicleFromGroup(const Vehicle *v) |
361 { |
360 { |
362 if (!IsValidVehicle(v) || !(v->HasFront() && v->IsPrimaryVehicle())) return; |
361 if (!v->IsValid() || !(v->HasFront() && v->IsPrimaryVehicle())) return; |
363 |
362 |
364 if (!IsDefaultGroupID(v->group_id)) DecreaseGroupNumVehicle(v->group_id); |
363 if (!IsDefaultGroupID(v->group_id)) DecreaseGroupNumVehicle(v->group_id); |
365 } |
364 } |
366 |
365 |
367 |
366 |
373 */ |
372 */ |
374 void SetTrainGroupID(Vehicle *v, GroupID new_g) |
373 void SetTrainGroupID(Vehicle *v, GroupID new_g) |
375 { |
374 { |
376 if (!IsValidGroupID(new_g) && !IsDefaultGroupID(new_g)) return; |
375 if (!IsValidGroupID(new_g) && !IsDefaultGroupID(new_g)) return; |
377 |
376 |
378 assert(IsValidVehicle(v) && v->type == VEH_TRAIN && IsFrontEngine(v)); |
377 assert(v->IsValid() && v->type == VEH_TRAIN && IsFrontEngine(v)); |
379 |
378 |
380 for (Vehicle *u = v; u != NULL; u = u->next) { |
379 for (Vehicle *u = v; u != NULL; u = u->next) { |
381 if (IsEngineCountable(u)) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g); |
380 if (IsEngineCountable(u)) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g); |
382 |
381 |
383 u->group_id = new_g; |
382 u->group_id = new_g; |
395 * @note Called in CmdBuildRailVehicle, CmdBuildRailWagon, CmdMoveRailVehicle, CmdSellRailWagon |
394 * @note Called in CmdBuildRailVehicle, CmdBuildRailWagon, CmdMoveRailVehicle, CmdSellRailWagon |
396 * @param v First vehicle of the chain. |
395 * @param v First vehicle of the chain. |
397 */ |
396 */ |
398 void UpdateTrainGroupID(Vehicle *v) |
397 void UpdateTrainGroupID(Vehicle *v) |
399 { |
398 { |
400 assert(IsValidVehicle(v) && v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))); |
399 assert(v->IsValid() && v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))); |
401 |
400 |
402 GroupID new_g = IsFrontEngine(v) ? v->group_id : (GroupID)DEFAULT_GROUP; |
401 GroupID new_g = IsFrontEngine(v) ? v->group_id : (GroupID)DEFAULT_GROUP; |
403 for (Vehicle *u = v; u != NULL; u = u->next) { |
402 for (Vehicle *u = v; u != NULL; u = u->next) { |
404 if (IsEngineCountable(u)) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g); |
403 if (IsEngineCountable(u)) UpdateNumEngineGroup(u->engine_type, u->group_id, new_g); |
405 |
404 |
445 static void Load_GROUP(void) |
444 static void Load_GROUP(void) |
446 { |
445 { |
447 int index; |
446 int index; |
448 |
447 |
449 while ((index = SlIterateArray()) != -1) { |
448 while ((index = SlIterateArray()) != -1) { |
450 if (!AddBlockIfNeeded(&_Group_pool, index)) { |
449 Group *g = new (index) Group(); |
451 error("Groups: failed loading savegame: too many groups"); |
|
452 } |
|
453 |
|
454 Group *g = GetGroup(index); |
|
455 SlObject(g, _group_desc); |
450 SlObject(g, _group_desc); |
456 } |
451 } |
457 } |
452 } |
458 |
453 |
459 extern const ChunkHandler _group_chunk_handlers[] = { |
454 extern const ChunkHandler _group_chunk_handlers[] = { |