OpenTTD Source  20241108-master-g80f628063a
goal.cpp
Go to the documentation of this file.
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 
10 #include "stdafx.h"
11 #include "company_func.h"
12 #include "industry.h"
13 #include "town.h"
14 #include "window_func.h"
15 #include "goal_base.h"
16 #include "core/pool_func.hpp"
17 #include "game/game.hpp"
18 #include "command_func.h"
19 #include "company_base.h"
20 #include "story_base.h"
21 #include "string_func.h"
22 #include "gui.h"
23 #include "network/network.h"
24 #include "network/network_base.h"
25 #include "network/network_func.h"
26 #include "goal_cmd.h"
27 
28 #include "safeguards.h"
29 
30 
31 GoalPool _goal_pool("Goal");
33 
34 /* static */ bool Goal::IsValidGoalDestination(CompanyID company, GoalType type, GoalTypeID dest)
35 {
36  switch (type) {
37  case GT_NONE:
38  if (dest != 0) return false;
39  break;
40 
41  case GT_TILE:
42  if (!IsValidTile(dest)) return false;
43  break;
44 
45  case GT_INDUSTRY:
46  if (!Industry::IsValidID(dest)) return false;
47  break;
48 
49  case GT_TOWN:
50  if (!Town::IsValidID(dest)) return false;
51  break;
52 
53  case GT_COMPANY:
54  if (!Company::IsValidID(dest)) return false;
55  break;
56 
57  case GT_STORY_PAGE: {
58  if (!StoryPage::IsValidID(dest)) return false;
59  CompanyID story_company = StoryPage::Get(dest)->company;
60  if (company == INVALID_COMPANY ? story_company != INVALID_COMPANY : story_company != INVALID_COMPANY && story_company != company) return false;
61  break;
62  }
63 
64  default: return false;
65  }
66  return true;
67 }
68 
78 std::tuple<CommandCost, GoalID> CmdCreateGoal(DoCommandFlag flags, CompanyID company, GoalType type, GoalTypeID dest, const std::string &text)
79 {
80  if (!Goal::CanAllocateItem()) return { CMD_ERROR, INVALID_GOAL };
81 
83  if (text.empty()) return { CMD_ERROR, INVALID_GOAL };
84  if (company != INVALID_COMPANY && !Company::IsValidID(company)) return { CMD_ERROR, INVALID_GOAL };
85  if (!Goal::IsValidGoalDestination(company, type, dest)) return { CMD_ERROR, INVALID_GOAL };
86 
87  if (flags & DC_EXEC) {
88  Goal *g = new Goal();
89  g->type = type;
90  g->dst = dest;
91  g->company = company;
92  g->text = text;
93  g->completed = false;
94 
95  if (g->company == INVALID_COMPANY) {
97  } else {
99  }
101 
102  return { CommandCost(), g->index };
103  }
104 
105  return { CommandCost(), INVALID_GOAL };
106 }
107 
115 {
116  if (_current_company != OWNER_DEITY) return CMD_ERROR;
117  if (!Goal::IsValidID(goal)) return CMD_ERROR;
118 
119  if (flags & DC_EXEC) {
120  Goal *g = Goal::Get(goal);
121  CompanyID c = g->company;
122  delete g;
123 
124  if (c == INVALID_COMPANY) {
126  } else {
128  }
130  }
131 
132  return CommandCost();
133 }
134 
144 {
145  if (_current_company != OWNER_DEITY) return CMD_ERROR;
146  if (!Goal::IsValidID(goal)) return CMD_ERROR;
147  Goal *g = Goal::Get(goal);
148  if (!Goal::IsValidGoalDestination(g->company, type, dest)) return CMD_ERROR;
149 
150  if (flags & DC_EXEC) {
151  g->type = type;
152  g->dst = dest;
153  }
154 
155  return CommandCost();
156 }
157 
165 CommandCost CmdSetGoalText(DoCommandFlag flags, GoalID goal, const std::string &text)
166 {
167  if (_current_company != OWNER_DEITY) return CMD_ERROR;
168  if (!Goal::IsValidID(goal)) return CMD_ERROR;
169  if (text.empty()) return CMD_ERROR;
170 
171  if (flags & DC_EXEC) {
172  Goal *g = Goal::Get(goal);
173  g->text = text;
174 
175  if (g->company == INVALID_COMPANY) {
177  } else {
179  }
180  }
181 
182  return CommandCost();
183 }
184 
192 CommandCost CmdSetGoalProgress(DoCommandFlag flags, GoalID goal, const std::string &text)
193 {
194  if (_current_company != OWNER_DEITY) return CMD_ERROR;
195  if (!Goal::IsValidID(goal)) return CMD_ERROR;
196 
197  if (flags & DC_EXEC) {
198  Goal *g = Goal::Get(goal);
199  g->progress = text;
200 
201  if (g->company == INVALID_COMPANY) {
203  } else {
205  }
206  }
207 
208  return CommandCost();
209 }
210 
219 {
220  if (_current_company != OWNER_DEITY) return CMD_ERROR;
221  if (!Goal::IsValidID(goal)) return CMD_ERROR;
222 
223  if (flags & DC_EXEC) {
224  Goal *g = Goal::Get(goal);
225  g->completed = completed;
226 
227  if (g->company == INVALID_COMPANY) {
229  } else {
231  }
232  }
233 
234  return CommandCost();
235 }
236 
248 CommandCost CmdGoalQuestion(DoCommandFlag flags, uint16_t uniqueid, uint32_t target, bool is_client, uint32_t button_mask, GoalQuestionType type, const std::string &text)
249 {
250  static_assert(sizeof(uint32_t) >= sizeof(CompanyID));
251  CompanyID company = (CompanyID)target;
252  static_assert(sizeof(uint32_t) >= sizeof(ClientID));
253  ClientID client = (ClientID)target;
254 
255  static_assert(GOAL_QUESTION_BUTTON_COUNT < 29);
256  button_mask &= (1U << GOAL_QUESTION_BUTTON_COUNT) - 1;
257 
258  if (_current_company != OWNER_DEITY) return CMD_ERROR;
259  if (text.empty()) return CMD_ERROR;
260  if (is_client) {
261  /* Only check during pre-flight; the client might have left between
262  * testing and executing. In that case it is fine to just ignore the
263  * fact the client is no longer here. */
264  if (!(flags & DC_EXEC) && _network_server && NetworkClientInfo::GetByClientID(client) == nullptr) return CMD_ERROR;
265  } else {
266  if (company != INVALID_COMPANY && !Company::IsValidID(company)) return CMD_ERROR;
267  }
268  uint min_buttons = (type == GQT_QUESTION ? 1 : 0);
269  if (CountBits(button_mask) < min_buttons || CountBits(button_mask) > 3) return CMD_ERROR;
270  if (type >= GQT_END) return CMD_ERROR;
271 
272  if (flags & DC_EXEC) {
273  if (is_client) {
274  if (client != _network_own_client_id) return CommandCost();
275  } else {
276  if (company == INVALID_COMPANY && !Company::IsValidID(_local_company)) return CommandCost();
277  if (company != INVALID_COMPANY && company != _local_company) return CommandCost();
278  }
279  ShowGoalQuestion(uniqueid, type, button_mask, text);
280  }
281 
282  return CommandCost();
283 }
284 
292 CommandCost CmdGoalQuestionAnswer(DoCommandFlag flags, uint16_t uniqueid, uint8_t button)
293 {
294  if (button >= GOAL_QUESTION_BUTTON_COUNT) return CMD_ERROR;
295 
296  if (_current_company == OWNER_DEITY) {
297  /* It has been requested to close this specific question on all clients */
298  if (flags & DC_EXEC) CloseWindowById(WC_GOAL_QUESTION, uniqueid);
299  return CommandCost();
300  }
301 
303  /* Somebody in the same company answered the question. Close the window */
304  if (flags & DC_EXEC) CloseWindowById(WC_GOAL_QUESTION, uniqueid);
305  if (!_network_server) return CommandCost();
306  }
307 
308  if (flags & DC_EXEC) {
309  Game::NewEvent(new ScriptEventGoalQuestionAnswer(uniqueid, (ScriptCompany::CompanyID)(uint8_t)_current_company, (ScriptGoal::QuestionButton)(1 << button)));
310  }
311 
312  return CommandCost();
313 }
constexpr uint CountBits(T value)
Counts the number of set bits in a variable.
Common return value for all commands.
Definition: command_type.h:23
static void NewEvent(class ScriptEvent *event)
Queue a new event for a Game Script.
Definition: game_core.cpp:146
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
Definition: command_func.h:28
DoCommandFlag
List of flags for a command.
Definition: command_type.h:374
@ DC_EXEC
execute the given command
Definition: command_type.h:376
Definition of stuff that is very close to a company, like the company struct itself.
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:53
Functions related to companies.
Owner
Enum for all companies/owners.
Definition: company_type.h:18
@ INVALID_COMPANY
An invalid company.
Definition: company_type.h:30
@ OWNER_DEITY
The object is owned by a superuser / goal script.
Definition: company_type.h:27
Base functions for all Games.
CommandCost CmdSetGoalText(DoCommandFlag flags, GoalID goal, const std::string &text)
Update goal text of a goal.
Definition: goal.cpp:165
CommandCost CmdRemoveGoal(DoCommandFlag flags, GoalID goal)
Remove a goal.
Definition: goal.cpp:114
CommandCost CmdSetGoalDestination(DoCommandFlag flags, GoalID goal, GoalType type, GoalTypeID dest)
Update goal destination of a goal.
Definition: goal.cpp:143
CommandCost CmdSetGoalProgress(DoCommandFlag flags, GoalID goal, const std::string &text)
Update progress text of a goal.
Definition: goal.cpp:192
std::tuple< CommandCost, GoalID > CmdCreateGoal(DoCommandFlag flags, CompanyID company, GoalType type, GoalTypeID dest, const std::string &text)
Create a new goal.
Definition: goal.cpp:78
CommandCost CmdSetGoalCompleted(DoCommandFlag flags, GoalID goal, bool completed)
Update completed state of a goal.
Definition: goal.cpp:218
CommandCost CmdGoalQuestionAnswer(DoCommandFlag flags, uint16_t uniqueid, uint8_t button)
Reply to a goal question.
Definition: goal.cpp:292
CommandCost CmdGoalQuestion(DoCommandFlag flags, uint16_t uniqueid, uint32_t target, bool is_client, uint32_t button_mask, GoalQuestionType type, const std::string &text)
Ask a goal related question.
Definition: goal.cpp:248
Goal base class.
Command definitions related to goals.
void ShowGoalQuestion(uint16_t id, uint8_t type, uint32_t button_mask, const std::string &question)
Display a goal question.
Definition: goal_gui.cpp:482
uint16_t GoalID
ID of a goal.
Definition: goal_type.h:37
GoalType
Types of goal destinations.
Definition: goal_type.h:26
@ GT_INDUSTRY
Destination is an industry.
Definition: goal_type.h:29
@ GT_STORY_PAGE
Destination is a story page.
Definition: goal_type.h:32
@ GT_COMPANY
Destination is a company.
Definition: goal_type.h:31
@ GT_NONE
Destination is not linked.
Definition: goal_type.h:27
@ GT_TILE
Destination is a tile.
Definition: goal_type.h:28
@ GT_TOWN
Destination is a town.
Definition: goal_type.h:30
uint32_t GoalTypeID
Contains either tile, industry ID, town ID, company ID, or story page ID.
Definition: goal_type.h:35
static const GoalID INVALID_GOAL
Constant representing a non-existing goal.
Definition: goal_type.h:39
static const uint32_t GOAL_QUESTION_BUTTON_COUNT
Amount of buttons available.
Definition: goal_type.h:15
GUI functions that shouldn't be here.
Base of all industries.
bool _networking
are we in networking mode?
Definition: network.cpp:65
bool _network_server
network-server is active
Definition: network.cpp:66
ClientID _network_own_client_id
Our client identifier.
Definition: network.cpp:70
Basic functions/variables used all over the place.
Base core network types and some helper functions to access them.
Network functions used by other parts of OpenTTD.
ClientID
'Unique' identifier to be given to clients
Definition: network_type.h:49
Some methods of Pool are placed here in order to reduce compilation time and binary size.
#define INSTANTIATE_POOL_METHODS(name)
Force instantiation of pool methods so we don't get linker errors.
Definition: pool_func.hpp:237
A number of safeguards to prevent using unsafe methods.
Definition of base types and functions in a cross-platform compatible way.
StoryPage base class.
Functions related to low-level strings.
Struct about goals, current and completed.
Definition: goal_base.h:21
bool completed
Is the goal completed or not?
Definition: goal_base.h:27
GoalType type
Type of the goal.
Definition: goal_base.h:23
GoalTypeID dst
Index of type.
Definition: goal_base.h:24
std::string text
Text of the goal.
Definition: goal_base.h:25
CompanyID company
Goal is for a specific company; INVALID_COMPANY if it is global.
Definition: goal_base.h:22
std::string progress
Progress text of the goal.
Definition: goal_base.h:26
static NetworkClientInfo * GetByClientID(ClientID client_id)
Return the CI given it's client-identifier.
Definition: network.cpp:118
Tindex index
Index of this pool item.
Definition: pool_type.hpp:238
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static size_t GetNumItems()
Returns number of valid items in the pool.
Definition: pool_type.hpp:369
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:328
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
Definition: pool_type.hpp:309
Base class for all pools.
Definition: pool_type.hpp:80
bool IsValidTile(Tile tile)
Checks if a tile is valid.
Definition: tile_map.h:161
Base of the town class.
void CloseWindowById(WindowClass cls, WindowNumber number, bool force, int data)
Close a window by its class and window number (if it is open).
Definition: window.cpp:1140
void InvalidateWindowData(WindowClass cls, WindowNumber number, int data, bool gui_scope)
Mark window data of the window of a given class and specific window number as invalid (in need of re-...
Definition: window.cpp:3211
void InvalidateWindowClassesData(WindowClass cls, int data, bool gui_scope)
Mark window data of all windows of a given class as invalid (in need of re-computing) Note that by de...
Definition: window.cpp:3228
Window functions not directly related to making/drawing windows.
@ WC_GOAL_QUESTION
Popup with a set of buttons, designed to ask the user a question from a GameScript.
Definition: window_type.h:137
@ WC_GOALS_LIST
Goals list; Window numbers:
Definition: window_type.h:290
@ WC_MAIN_TOOLBAR
Main toolbar (the long bar at the top); Window numbers:
Definition: window_type.h:58