Codechange: Use null pointer literal instead of the NULL macro
[openttd-github.git] / src / goal.cpp
blobb545c84d251fdd61342552ef13b5466b0ff95b12
1 /* $Id$ */
3 /*
4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
8 */
10 /** @file goal.cpp Handling of goals. */
12 #include "stdafx.h"
13 #include "company_func.h"
14 #include "industry.h"
15 #include "town.h"
16 #include "window_func.h"
17 #include "goal_base.h"
18 #include "core/pool_func.hpp"
19 #include "game/game.hpp"
20 #include "command_func.h"
21 #include "company_base.h"
22 #include "story_base.h"
23 #include "string_func.h"
24 #include "gui.h"
25 #include "network/network.h"
26 #include "network/network_base.h"
27 #include "network/network_func.h"
29 #include "safeguards.h"
32 GoalID _new_goal_id;
34 GoalPool _goal_pool("Goal");
35 INSTANTIATE_POOL_METHODS(Goal)
37 /**
38 * Create a new goal.
39 * @param tile unused.
40 * @param flags type of operation
41 * @param p1 various bitstuffed elements
42 * - p1 = (bit 0 - 7) - GoalType of destination.
43 * - p1 = (bit 8 - 15) - Company for which this goal is.
44 * @param p2 GoalTypeID of destination.
45 * @param text Text of the goal.
46 * @return the cost of this operation or an error
48 CommandCost CmdCreateGoal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
50 if (!Goal::CanAllocateItem()) return CMD_ERROR;
52 GoalType type = (GoalType)GB(p1, 0, 8);
53 CompanyID company = (CompanyID)GB(p1, 8, 8);
55 if (_current_company != OWNER_DEITY) return CMD_ERROR;
56 if (StrEmpty(text)) return CMD_ERROR;
57 if (company != INVALID_COMPANY && !Company::IsValidID(company)) return CMD_ERROR;
59 switch (type) {
60 case GT_NONE:
61 if (p2 != 0) return CMD_ERROR;
62 break;
64 case GT_TILE:
65 if (!IsValidTile(p2)) return CMD_ERROR;
66 break;
68 case GT_INDUSTRY:
69 if (!Industry::IsValidID(p2)) return CMD_ERROR;
70 break;
72 case GT_TOWN:
73 if (!Town::IsValidID(p2)) return CMD_ERROR;
74 break;
76 case GT_COMPANY:
77 if (!Company::IsValidID(p2)) return CMD_ERROR;
78 break;
80 case GT_STORY_PAGE: {
81 if (!StoryPage::IsValidID(p2)) return CMD_ERROR;
82 CompanyByte story_company = StoryPage::Get(p2)->company;
83 if (company == INVALID_COMPANY ? story_company != INVALID_COMPANY : story_company != INVALID_COMPANY && story_company != company) return CMD_ERROR;
84 break;
87 default: return CMD_ERROR;
90 if (flags & DC_EXEC) {
91 Goal *g = new Goal();
92 g->type = type;
93 g->dst = p2;
94 g->company = company;
95 g->text = stredup(text);
96 g->progress = nullptr;
97 g->completed = false;
99 if (g->company == INVALID_COMPANY) {
100 InvalidateWindowClassesData(WC_GOALS_LIST);
101 } else {
102 InvalidateWindowData(WC_GOALS_LIST, g->company);
104 if (Goal::GetNumItems() == 1) InvalidateWindowData(WC_MAIN_TOOLBAR, 0);
106 _new_goal_id = g->index;
109 return CommandCost();
113 * Remove a goal.
114 * @param tile unused.
115 * @param flags type of operation
116 * @param p1 GoalID to remove.
117 * @param p2 unused.
118 * @param text unused.
119 * @return the cost of this operation or an error
121 CommandCost CmdRemoveGoal(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
123 if (_current_company != OWNER_DEITY) return CMD_ERROR;
124 if (!Goal::IsValidID(p1)) return CMD_ERROR;
126 if (flags & DC_EXEC) {
127 Goal *g = Goal::Get(p1);
128 CompanyID c = g->company;
129 delete g;
131 if (c == INVALID_COMPANY) {
132 InvalidateWindowClassesData(WC_GOALS_LIST);
133 } else {
134 InvalidateWindowData(WC_GOALS_LIST, c);
136 if (Goal::GetNumItems() == 0) InvalidateWindowData(WC_MAIN_TOOLBAR, 0);
139 return CommandCost();
143 * Update goal text of a goal.
144 * @param tile unused.
145 * @param flags type of operation
146 * @param p1 GoalID to update.
147 * @param p2 unused
148 * @param text Text of the goal.
149 * @return the cost of this operation or an error
151 CommandCost CmdSetGoalText(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
153 if (_current_company != OWNER_DEITY) return CMD_ERROR;
154 if (!Goal::IsValidID(p1)) return CMD_ERROR;
155 if (StrEmpty(text)) return CMD_ERROR;
157 if (flags & DC_EXEC) {
158 Goal *g = Goal::Get(p1);
159 free(g->text);
160 g->text = stredup(text);
162 if (g->company == INVALID_COMPANY) {
163 InvalidateWindowClassesData(WC_GOALS_LIST);
164 } else {
165 InvalidateWindowData(WC_GOALS_LIST, g->company);
169 return CommandCost();
173 * Update progress text of a goal.
174 * @param tile unused.
175 * @param flags type of operation
176 * @param p1 GoalID to update.
177 * @param p2 unused
178 * @param text Progress text of the goal.
179 * @return the cost of this operation or an error
181 CommandCost CmdSetGoalProgress(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
183 if (_current_company != OWNER_DEITY) return CMD_ERROR;
184 if (!Goal::IsValidID(p1)) return CMD_ERROR;
186 if (flags & DC_EXEC) {
187 Goal *g = Goal::Get(p1);
188 free(g->progress);
189 if (StrEmpty(text)) {
190 g->progress = nullptr;
191 } else {
192 g->progress = stredup(text);
195 if (g->company == INVALID_COMPANY) {
196 InvalidateWindowClassesData(WC_GOALS_LIST);
197 } else {
198 InvalidateWindowData(WC_GOALS_LIST, g->company);
202 return CommandCost();
206 * Update completed state of a goal.
207 * @param tile unused.
208 * @param flags type of operation
209 * @param p1 GoalID to update.
210 * @param p2 completed state. If goal is completed, set to 1, otherwise 0.
211 * @param text unused
212 * @return the cost of this operation or an error
214 CommandCost CmdSetGoalCompleted(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
216 if (_current_company != OWNER_DEITY) return CMD_ERROR;
217 if (!Goal::IsValidID(p1)) return CMD_ERROR;
219 if (flags & DC_EXEC) {
220 Goal *g = Goal::Get(p1);
221 g->completed = p2 == 1;
223 if (g->company == INVALID_COMPANY) {
224 InvalidateWindowClassesData(WC_GOALS_LIST);
225 } else {
226 InvalidateWindowData(WC_GOALS_LIST, g->company);
230 return CommandCost();
234 * Ask a goal related question
235 * @param tile unused.
236 * @param flags type of operation
237 * @param p1 various bitstuffed elements
238 * - p1 = (bit 0 - 15) - Unique ID to use for this question.
239 * - p1 = (bit 16 - 23) - Company or client for which this question is.
240 * - p1 = (bit 24 - 25) - Question type.
241 * - p1 = (bit 31) - Question target: 0 - company, 1 - client.
242 * @param p2 Buttons of the question.
243 * @param text Text of the question.
244 * @return the cost of this operation or an error
246 CommandCost CmdGoalQuestion(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
248 uint16 uniqueid = (GoalType)GB(p1, 0, 16);
249 CompanyID company = (CompanyID)GB(p1, 16, 8);
250 ClientIndex client = (ClientIndex)GB(p1, 16, 8);
251 byte type = GB(p1, 24, 2);
252 bool is_client = HasBit(p1, 31);
254 if (_current_company != OWNER_DEITY) return CMD_ERROR;
255 if (StrEmpty(text)) return CMD_ERROR;
256 if (is_client) {
257 if (!NetworkClientInfo::IsValidID(client)) return CMD_ERROR;
258 } else {
259 if (company != INVALID_COMPANY && !Company::IsValidID(company)) return CMD_ERROR;
261 if (CountBits(p2) < 1 || CountBits(p2) > 3) return CMD_ERROR;
262 if (p2 >= (1 << GOAL_QUESTION_BUTTON_COUNT)) return CMD_ERROR;
263 if (type >= GOAL_QUESTION_TYPE_COUNT) return CMD_ERROR;
265 if (flags & DC_EXEC) {
266 if (is_client) {
267 if (NetworkClientInfo::Get(client)->client_id != _network_own_client_id) return CommandCost();
268 } else {
269 if (company == INVALID_COMPANY && !Company::IsValidID(_local_company)) return CommandCost();
270 if (company != INVALID_COMPANY && company != _local_company) return CommandCost();
272 ShowGoalQuestion(uniqueid, type, p2, text);
275 return CommandCost();
279 * Reply to a goal question.
280 * @param tile unused.
281 * @param flags type of operation
282 * @param p1 Unique ID to use for this question.
283 * @param p2 Button the company pressed
284 * @param text Text of the question.
285 * @return the cost of this operation or an error
287 CommandCost CmdGoalQuestionAnswer(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
289 if (p1 > UINT16_MAX) return CMD_ERROR;
290 if (p2 >= GOAL_QUESTION_BUTTON_COUNT) return CMD_ERROR;
292 if (_current_company == OWNER_DEITY) {
293 /* It has been requested to close this specific question on all clients */
294 if (flags & DC_EXEC) DeleteWindowById(WC_GOAL_QUESTION, p1);
295 return CommandCost();
298 if (_networking && _local_company == _current_company) {
299 /* Somebody in the same company answered the question. Close the window */
300 if (flags & DC_EXEC) DeleteWindowById(WC_GOAL_QUESTION, p1);
301 if (!_network_server) return CommandCost();
304 if (flags & DC_EXEC) {
305 Game::NewEvent(new ScriptEventGoalQuestionAnswer(p1, (ScriptCompany::CompanyID)(byte)_current_company, (ScriptGoal::QuestionButton)(1 << p2)));
308 return CommandCost();