1 /*
2  * This file is part of OpenTTD.
3  * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4  * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5  * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6  */
7 
8 /** @file script_group.cpp Implementation of ScriptGroup. */
9 
10 #include "../../stdafx.h"
11 #include "script_group.hpp"
12 #include "script_engine.hpp"
13 #include "../script_instance.hpp"
14 #include "../../string_func.h"
15 #include "../../strings_func.h"
16 #include "../../autoreplace_func.h"
17 #include "../../settings_func.h"
18 #include "../../vehicle_base.h"
19 #include "table/strings.h"
20 
21 #include "../../safeguards.h"
22 
IsValidGroup(GroupID group_id)23 /* static */ bool ScriptGroup::IsValidGroup(GroupID group_id)
24 {
25 	const Group *g = ::Group::GetIfValid(group_id);
26 	return g != nullptr && g->owner == ScriptObject::GetCompany();
27 }
28 
CreateGroup(ScriptVehicle::VehicleType vehicle_type,GroupID parent_group_id)29 /* static */ ScriptGroup::GroupID ScriptGroup::CreateGroup(ScriptVehicle::VehicleType vehicle_type, GroupID parent_group_id)
30 {
31 	if (!ScriptObject::DoCommand(0, (::VehicleType)vehicle_type, parent_group_id, CMD_CREATE_GROUP, nullptr, &ScriptInstance::DoCommandReturnGroupID)) return GROUP_INVALID;
32 
33 	/* In case of test-mode, we return GroupID 0 */
34 	return (ScriptGroup::GroupID)0;
35 }
36 
DeleteGroup(GroupID group_id)37 /* static */ bool ScriptGroup::DeleteGroup(GroupID group_id)
38 {
39 	EnforcePrecondition(false, IsValidGroup(group_id));
40 
41 	return ScriptObject::DoCommand(0, group_id, 0, CMD_DELETE_GROUP);
42 }
43 
GetVehicleType(GroupID group_id)44 /* static */ ScriptVehicle::VehicleType ScriptGroup::GetVehicleType(GroupID group_id)
45 {
46 	if (!IsValidGroup(group_id)) return ScriptVehicle::VT_INVALID;
47 
48 	return (ScriptVehicle::VehicleType)((::VehicleType)::Group::Get(group_id)->vehicle_type);
49 }
50 
SetName(GroupID group_id,Text * name)51 /* static */ bool ScriptGroup::SetName(GroupID group_id, Text *name)
52 {
53 	CCountedPtr<Text> counter(name);
54 
55 	EnforcePrecondition(false, IsValidGroup(group_id));
56 	EnforcePrecondition(false, name != nullptr);
57 	const char *text = name->GetDecodedText();
58 	EnforcePreconditionEncodedText(false, text);
59 	EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_GROUP_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG);
60 
61 	return ScriptObject::DoCommand(0, group_id, 0, CMD_ALTER_GROUP, text);
62 }
63 
GetName(GroupID group_id)64 /* static */ char *ScriptGroup::GetName(GroupID group_id)
65 {
66 	if (!IsValidGroup(group_id)) return nullptr;
67 
68 	::SetDParam(0, group_id);
69 	return GetString(STR_GROUP_NAME);
70 }
71 
SetParent(GroupID group_id,GroupID parent_group_id)72 /* static */ bool ScriptGroup::SetParent(GroupID group_id, GroupID parent_group_id)
73 {
74 	EnforcePrecondition(false, IsValidGroup(group_id));
75 	EnforcePrecondition(false, IsValidGroup(parent_group_id));
76 
77 	return ScriptObject::DoCommand(0, group_id | 1 << 16, parent_group_id, CMD_ALTER_GROUP);
78 }
79 
GetParent(GroupID group_id)80 /* static */ ScriptGroup::GroupID ScriptGroup::GetParent(GroupID group_id)
81 {
82 	EnforcePrecondition((ScriptGroup::GroupID)INVALID_GROUP, IsValidGroup(group_id));
83 
84 	const Group *g = ::Group::GetIfValid(group_id);
85 	return (ScriptGroup::GroupID)g->parent;
86 }
87 
EnableAutoReplaceProtection(GroupID group_id,bool enable)88 /* static */ bool ScriptGroup::EnableAutoReplaceProtection(GroupID group_id, bool enable)
89 {
90 	EnforcePrecondition(false, IsValidGroup(group_id));
91 
92 	return ScriptObject::DoCommand(0, group_id | GroupFlags::GF_REPLACE_PROTECTION, enable ? 1 : 0, CMD_SET_GROUP_FLAG);
93 }
94 
GetAutoReplaceProtection(GroupID group_id)95 /* static */ bool ScriptGroup::GetAutoReplaceProtection(GroupID group_id)
96 {
97 	if (!IsValidGroup(group_id)) return false;
98 
99 	return HasBit(::Group::Get(group_id)->flags, GroupFlags::GF_REPLACE_PROTECTION);
100 }
101 
GetNumEngines(GroupID group_id,EngineID engine_id)102 /* static */ int32 ScriptGroup::GetNumEngines(GroupID group_id, EngineID engine_id)
103 {
104 	if (!IsValidGroup(group_id) && group_id != GROUP_DEFAULT && group_id != GROUP_ALL) return -1;
105 
106 	return GetGroupNumEngines(ScriptObject::GetCompany(), group_id, engine_id);
107 }
108 
GetNumVehicles(GroupID group_id,ScriptVehicle::VehicleType vehicle_type)109 /* static */ int32 ScriptGroup::GetNumVehicles(GroupID group_id, ScriptVehicle::VehicleType vehicle_type)
110 {
111 	bool valid_group = IsValidGroup(group_id);
112 	if (!valid_group && group_id != GROUP_DEFAULT && group_id != GROUP_ALL) return -1;
113 	if (!valid_group && (vehicle_type < ScriptVehicle::VT_RAIL || vehicle_type > ScriptVehicle::VT_AIR)) return -1;
114 
115 	return GetGroupNumVehicle(ScriptObject::GetCompany(), group_id, valid_group ? ::Group::Get(group_id)->vehicle_type : (::VehicleType)vehicle_type);
116 }
117 
MoveVehicle(GroupID group_id,VehicleID vehicle_id)118 /* static */ bool ScriptGroup::MoveVehicle(GroupID group_id, VehicleID vehicle_id)
119 {
120 	EnforcePrecondition(false, IsValidGroup(group_id) || group_id == GROUP_DEFAULT);
121 	EnforcePrecondition(false, ScriptVehicle::IsValidVehicle(vehicle_id));
122 
123 	return ScriptObject::DoCommand(0, group_id, vehicle_id, CMD_ADD_VEHICLE_GROUP);
124 }
125 
EnableWagonRemoval(bool enable_removal)126 /* static */ bool ScriptGroup::EnableWagonRemoval(bool enable_removal)
127 {
128 	if (HasWagonRemoval() == enable_removal) return true;
129 
130 	return ScriptObject::DoCommand(0, 0, enable_removal ? 1 : 0, CMD_CHANGE_COMPANY_SETTING, "company.renew_keep_length");
131 }
132 
HasWagonRemoval()133 /* static */ bool ScriptGroup::HasWagonRemoval()
134 {
135 	return ::Company::Get(ScriptObject::GetCompany())->settings.renew_keep_length;
136 }
137 
SetAutoReplace(GroupID group_id,EngineID engine_id_old,EngineID engine_id_new)138 /* static */ bool ScriptGroup::SetAutoReplace(GroupID group_id, EngineID engine_id_old, EngineID engine_id_new)
139 {
140 	EnforcePrecondition(false, IsValidGroup(group_id) || group_id == GROUP_DEFAULT || group_id == GROUP_ALL);
141 	EnforcePrecondition(false, ScriptEngine::IsBuildable(engine_id_new));
142 
143 	return ScriptObject::DoCommand(0, group_id << 16, (engine_id_new << 16) | engine_id_old, CMD_SET_AUTOREPLACE);
144 }
145 
GetEngineReplacement(GroupID group_id,EngineID engine_id)146 /* static */ EngineID ScriptGroup::GetEngineReplacement(GroupID group_id, EngineID engine_id)
147 {
148 	if (!IsValidGroup(group_id) && group_id != GROUP_DEFAULT && group_id != GROUP_ALL) return ::INVALID_ENGINE;
149 
150 	return ::EngineReplacementForCompany(Company::Get(ScriptObject::GetCompany()), engine_id, group_id);
151 }
152 
StopAutoReplace(GroupID group_id,EngineID engine_id)153 /* static */ bool ScriptGroup::StopAutoReplace(GroupID group_id, EngineID engine_id)
154 {
155 	EnforcePrecondition(false, IsValidGroup(group_id) || group_id == GROUP_DEFAULT || group_id == GROUP_ALL);
156 
157 	return ScriptObject::DoCommand(0, group_id << 16, (::INVALID_ENGINE << 16) | engine_id, CMD_SET_AUTOREPLACE);
158 }
159 
GetProfitThisYear(GroupID group_id)160 /* static */ Money ScriptGroup::GetProfitThisYear(GroupID group_id)
161 {
162 	if (!IsValidGroup(group_id)) return -1;
163 
164 	Money profit = 0;
165 
166 	for (const Vehicle *v : Vehicle::Iterate()) {
167 		if (v->group_id != group_id) continue;
168 		if (!v->IsPrimaryVehicle()) continue;
169 
170 		profit += v->GetDisplayProfitThisYear();
171 	}
172 
173 	return profit;
174 }
175 
GetProfitLastYear(GroupID group_id)176 /* static */ Money ScriptGroup::GetProfitLastYear(GroupID group_id)
177 {
178 	if (!IsValidGroup(group_id)) return -1;
179 
180 	return ::Group::Get(group_id)->statistics.profit_last_year;
181 }
182 
GetCurrentUsage(GroupID group_id)183 /* static */ uint32 ScriptGroup::GetCurrentUsage(GroupID group_id)
184 {
185 	if (!IsValidGroup(group_id)) return -1;
186 
187 	uint32 occupancy = 0;
188 	uint32 vehicle_count = 0;
189 
190 	for (const Vehicle *v : Vehicle::Iterate()) {
191 		if (v->group_id != group_id) continue;
192 		if (!v->IsPrimaryVehicle()) continue;
193 
194 		occupancy += v->trip_occupancy;
195 		vehicle_count++;
196 	}
197 
198 	if (vehicle_count == 0) return -1;
199 
200 	return occupancy / vehicle_count;
201 }
202 
SetPrimaryColour(GroupID group_id,ScriptCompany::Colours colour)203 /* static */ bool ScriptGroup::SetPrimaryColour(GroupID group_id, ScriptCompany::Colours colour)
204 {
205 	EnforcePrecondition(false, IsValidGroup(group_id));
206 
207 	return ScriptObject::DoCommand(0, group_id, colour << 16, CMD_SET_GROUP_LIVERY);
208 }
209 
SetSecondaryColour(GroupID group_id,ScriptCompany::Colours colour)210 /* static */ bool ScriptGroup::SetSecondaryColour(GroupID group_id, ScriptCompany::Colours colour)
211 {
212 	EnforcePrecondition(false, IsValidGroup(group_id));
213 
214 	return ScriptObject::DoCommand(0, group_id, (1 << 8) | (colour << 16), CMD_SET_GROUP_LIVERY);
215 }
216 
GetPrimaryColour(GroupID group_id)217 /* static */ ScriptCompany::Colours ScriptGroup::GetPrimaryColour(GroupID group_id)
218 {
219 	EnforcePrecondition(ScriptCompany::Colours::COLOUR_INVALID, IsValidGroup(group_id));
220 
221 	const Group *g = ::Group::GetIfValid(group_id);
222 	if (!HasBit(g->livery.in_use, 0)) return ScriptCompany::Colours::COLOUR_INVALID;
223 	return (ScriptCompany::Colours)g->livery.colour1;
224 }
225 
GetSecondaryColour(GroupID group_id)226 /* static */ ScriptCompany::Colours ScriptGroup::GetSecondaryColour(GroupID group_id)
227 {
228 	EnforcePrecondition(ScriptCompany::Colours::COLOUR_INVALID, IsValidGroup(group_id));
229 
230 	const Group *g = ::Group::GetIfValid(group_id);
231 	if (!HasBit(g->livery.in_use, 1)) return ScriptCompany::Colours::COLOUR_INVALID;
232 	return (ScriptCompany::Colours)g->livery.colour2;
233 }
234