OpenTTD Source 20260731-master-g77ba2b244a
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
9
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 "goal_gui.h"
23#include "network/network.h"
26#include "goal_cmd.h"
27#include "script/api/script_event_types.hpp"
28
29#include "safeguards.h"
30
31
32GoalPool _goal_pool("Goal");
34
35/* static */ bool Goal::IsValidGoalDestination(CompanyID company, GoalType type, GoalTypeID dest)
36{
37 switch (type) {
38 case GoalType::None:
39 if (dest != 0) return false;
40 break;
41
42 case GoalType::Tile:
43 if (!IsValidTile(dest)) return false;
44 break;
45
47 if (!Industry::IsValidID(dest)) return false;
48 break;
49
50 case GoalType::Town:
51 if (!Town::IsValidID(dest)) return false;
52 break;
53
55 if (!Company::IsValidID(dest)) return false;
56 break;
57
59 if (!StoryPage::IsValidID(dest)) return false;
60 CompanyID story_company = StoryPage::Get(dest)->company;
61 if (company == CompanyID::Invalid() ? story_company != CompanyID::Invalid() : story_company != CompanyID::Invalid() && story_company != company) return false;
62 break;
63 }
64
65 default: return false;
66 }
67 return true;
68}
69
79std::tuple<CommandCost, GoalID> CmdCreateGoal(DoCommandFlags flags, CompanyID company, GoalType type, GoalTypeID dest, const EncodedString &text)
80{
81 if (!Goal::CanAllocateItem()) return { CMD_ERROR, GoalID::Invalid() };
82
83 if (_current_company != OWNER_DEITY) return { CMD_ERROR, GoalID::Invalid() };
84 if (text.empty()) return { CMD_ERROR, GoalID::Invalid() };
85 if (company != CompanyID::Invalid() && !Company::IsValidID(company)) return { CMD_ERROR, GoalID::Invalid() };
86 if (!Goal::IsValidGoalDestination(company, type, dest)) return { CMD_ERROR, GoalID::Invalid() };
87
88 if (flags.Test(DoCommandFlag::Execute)) {
89 Goal *g = Goal::Create(type, dest, company, text);
90
91 if (g->company == CompanyID::Invalid()) {
92 InvalidateWindowClassesData(WindowClass::GoalList);
93 } else {
94 InvalidateWindowData(WindowClass::GoalList, g->company);
95 }
96 if (Goal::GetNumItems() == 1) InvalidateWindowData(WindowClass::MainToolbar, 0);
97
98 return { CommandCost(), g->index };
99 }
100
101 return { CommandCost(), GoalID::Invalid() };
102}
103
111{
113 if (!Goal::IsValidID(goal)) return CMD_ERROR;
114
115 if (flags.Test(DoCommandFlag::Execute)) {
116 Goal *g = Goal::Get(goal);
117 CompanyID c = g->company;
118 delete g;
119
120 if (c == CompanyID::Invalid()) {
121 InvalidateWindowClassesData(WindowClass::GoalList);
122 } else {
123 InvalidateWindowData(WindowClass::GoalList, c);
124 }
125 if (Goal::GetNumItems() == 0) InvalidateWindowData(WindowClass::MainToolbar, 0);
126 }
127
128 return CommandCost();
129}
130
140{
142 if (!Goal::IsValidID(goal)) return CMD_ERROR;
143 Goal *g = Goal::Get(goal);
144 if (!Goal::IsValidGoalDestination(g->company, type, dest)) return CMD_ERROR;
145
146 if (flags.Test(DoCommandFlag::Execute)) {
147 g->type = type;
148 g->dst = dest;
149 }
150
151 return CommandCost();
152}
153
162{
164 if (!Goal::IsValidID(goal)) return CMD_ERROR;
165 if (text.empty()) return CMD_ERROR;
166
167 if (flags.Test(DoCommandFlag::Execute)) {
168 Goal *g = Goal::Get(goal);
169 g->text = text;
170
171 if (g->company == CompanyID::Invalid()) {
172 InvalidateWindowClassesData(WindowClass::GoalList);
173 } else {
174 InvalidateWindowData(WindowClass::GoalList, g->company);
175 }
176 }
177
178 return CommandCost();
179}
180
189{
191 if (!Goal::IsValidID(goal)) return CMD_ERROR;
192
193 if (flags.Test(DoCommandFlag::Execute)) {
194 Goal *g = Goal::Get(goal);
195 g->progress = text;
196
197 if (g->company == CompanyID::Invalid()) {
198 InvalidateWindowClassesData(WindowClass::GoalList);
199 } else {
200 InvalidateWindowData(WindowClass::GoalList, g->company);
201 }
202 }
203
204 return CommandCost();
205}
206
215{
217 if (!Goal::IsValidID(goal)) return CMD_ERROR;
218
219 if (flags.Test(DoCommandFlag::Execute)) {
220 Goal *g = Goal::Get(goal);
221 g->completed = completed;
222
223 if (g->company == CompanyID::Invalid()) {
224 InvalidateWindowClassesData(WindowClass::GoalList);
225 } else {
226 InvalidateWindowData(WindowClass::GoalList, g->company);
227 }
228 }
229
230 return CommandCost();
231}
232
244CommandCost CmdGoalQuestion(DoCommandFlags flags, uint16_t uniqueid, uint32_t target, bool is_client, GoalQuestionButtons buttons, GoalQuestionType type, const EncodedString &text)
245{
246 static_assert(sizeof(uint32_t) >= sizeof(CompanyID));
247 CompanyID company = (CompanyID)target;
248 static_assert(sizeof(uint32_t) >= sizeof(ClientID));
249 ClientID client = (ClientID)target;
250
252 if (text.empty()) return CMD_ERROR;
253 if (is_client) {
254 /* Only check during pre-flight; the client might have left between
255 * testing and executing. In that case it is fine to just ignore the
256 * fact the client is no longer here. */
257 if (!flags.Test(DoCommandFlag::Execute) && _network_server && NetworkClientInfo::GetByClientID(client) == nullptr) return CMD_ERROR;
258 } else {
259 if (company != CompanyID::Invalid() && !Company::IsValidID(company)) return CMD_ERROR;
260 }
261 uint min_buttons = (type == GoalQuestionType::Question ? 1 : 0);
262 if (!buttons.IsValid()) return CMD_ERROR;
263 if (buttons.Count() < min_buttons || buttons.Count() > 3) return CMD_ERROR;
264 if (type >= GoalQuestionType::End) return CMD_ERROR;
265
266 if (flags.Test(DoCommandFlag::Execute)) {
267 if (is_client) {
268 if (client != _network_own_client_id) return CommandCost();
269 } else {
270 if (company == CompanyID::Invalid() && !Company::IsValidID(_local_company)) return CommandCost();
271 if (company != CompanyID::Invalid() && company != _local_company) return CommandCost();
272 }
273 ShowGoalQuestion(uniqueid, type, buttons, text);
274 }
275
276 return CommandCost();
277}
278
287{
288 if (button >= GoalQuestionButton::End) return CMD_ERROR;
289
291 /* It has been requested to close this specific question on all clients */
292 if (flags.Test(DoCommandFlag::Execute)) CloseWindowById(WindowClass::GoalQuestion, uniqueid);
293 return CommandCost();
294 }
295
297 /* Somebody in the same company answered the question. Close the window */
298 if (flags.Test(DoCommandFlag::Execute)) CloseWindowById(WindowClass::GoalQuestion, uniqueid);
299 if (!_network_server) return CommandCost();
300 }
301
302 if (flags.Test(DoCommandFlag::Execute)) {
303 Game::NewEvent(new ScriptEventGoalQuestionAnswer(uniqueid, _current_company, static_cast<ScriptGoal::QuestionButton>(GoalQuestionButtons{button}.base())));
304 }
305
306 return CommandCost();
307}
uint Count() const
Count the number of set bits.
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
constexpr bool IsValid() const
Test that the raw value of this bit set is valid.
Common return value for all commands.
Container for an encoded string, created by GetEncodedString.
static void NewEvent(class ScriptEvent *event)
Queue a new event for the game script.
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
EnumBitSet< DoCommandFlag, uint16_t > DoCommandFlags
Bitset of DoCommandFlag elements.
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.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
static constexpr Owner OWNER_DEITY
The object is owned by a superuser / goal script.
Base functions for all Games.
CommandCost CmdGoalQuestionAnswer(DoCommandFlags flags, uint16_t uniqueid, GoalQuestionButton button)
Reply to a goal question.
Definition goal.cpp:286
CommandCost CmdGoalQuestion(DoCommandFlags flags, uint16_t uniqueid, uint32_t target, bool is_client, GoalQuestionButtons buttons, GoalQuestionType type, const EncodedString &text)
Ask a goal related question.
Definition goal.cpp:244
CommandCost CmdSetGoalProgress(DoCommandFlags flags, GoalID goal, const EncodedString &text)
Update progress text of a goal.
Definition goal.cpp:188
CommandCost CmdRemoveGoal(DoCommandFlags flags, GoalID goal)
Remove a goal.
Definition goal.cpp:110
std::tuple< CommandCost, GoalID > CmdCreateGoal(DoCommandFlags flags, CompanyID company, GoalType type, GoalTypeID dest, const EncodedString &text)
Create a new goal.
Definition goal.cpp:79
CommandCost CmdSetGoalText(DoCommandFlags flags, GoalID goal, const EncodedString &text)
Update goal text of a goal.
Definition goal.cpp:161
CommandCost CmdSetGoalDestination(DoCommandFlags flags, GoalID goal, GoalType type, GoalTypeID dest)
Update goal destination of a goal.
Definition goal.cpp:139
CommandCost CmdSetGoalCompleted(DoCommandFlags flags, GoalID goal, bool completed)
Update completed state of a goal.
Definition goal.cpp:214
Goal base class.
Command definitions related to goals.
void ShowGoalQuestion(uint16_t id, GoalQuestionType type, GoalQuestionButtons buttons, const EncodedString &question)
Display a goal question.
Definition goal_gui.cpp:466
Goal GUI functions.
GoalType
Types of goal destinations.
Definition goal_type.h:51
@ Company
Destination is a company.
Definition goal_type.h:56
@ Industry
Destination is an industry.
Definition goal_type.h:54
@ None
Destination is not linked.
Definition goal_type.h:52
@ StoryPage
Destination is a story page.
Definition goal_type.h:57
@ Town
Destination is a town.
Definition goal_type.h:55
@ Tile
Destination is a tile.
Definition goal_type.h:53
uint32_t GoalTypeID
Contains either tile, industry ID, town ID, company ID, or story page ID.
Definition goal_type.h:60
GoalQuestionType
Types of goal questions.
Definition goal_type.h:16
@ End
End marker.
Definition goal_type.h:21
@ Question
Asking a simple question; title: Question.
Definition goal_type.h:17
EnumBitSet< GoalQuestionButton, uint32_t, GoalQuestionButton::End > GoalQuestionButtons
Bitset of GoalQuestionButton elements.
Definition goal_type.h:48
GoalQuestionButton
Types of buttons that can be in the question window.
Definition goal_type.h:25
@ End
End marker.
Definition goal_type.h:44
PoolID< uint16_t, struct GoalIDTag, 64000, 0xFFFF > GoalID
ID of a goal.
Definition goal_type.h:63
Base of all industries.
bool _networking
are we in networking mode?
Definition network.cpp:67
bool _network_server
network-server is active
Definition network.cpp:68
ClientID _network_own_client_id
Our client identifier.
Definition network.cpp:72
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
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.
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:22
EncodedString progress
Progress text of the goal.
Definition goal_base.h:27
EncodedString text
Text of the goal.
Definition goal_base.h:26
bool completed
Is the goal completed or not?
Definition goal_base.h:28
GoalType type
Type of the goal.
Definition goal_base.h:24
GoalTypeID dst
Index of type.
Definition goal_base.h:25
CompanyID company
Goal is for a specific company; CompanyID::Invalid() if it is global.
Definition goal_base.h:23
static NetworkClientInfo * GetByClientID(ClientID client_id)
Return the CI given it's client-identifier.
Definition network.cpp:118
static T * Create(Targs &&... args)
static StoryPage * Get(auto index)
static bool CanAllocateItem(size_t n=1)
CompanyID company
StoryPage is for a specific company; CompanyID::Invalid() if it is global.
Definition story_base.h:165
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:1204
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:3318
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:3336
Window functions not directly related to making/drawing windows.