changeset 20344:70f3ab64660a draft

(svn r25296) -Feature: Goals can now have a progress text and/or be marked as completed.
author zuu <zuu@openttd.org>
date Sun, 26 May 2013 19:54:43 +0000
parents 2a706e82e463
children a5b426ec42c6
files src/command.cpp src/command_type.h src/goal.cpp src/goal_base.h src/goal_gui.cpp src/lang/english.txt src/saveload/goal_sl.cpp src/saveload/saveload.cpp src/script/api/game/game_goal.hpp.sq src/script/api/game/game_window.hpp.sq src/script/api/game_changelog.hpp src/script/api/script_goal.cpp src/script/api/script_goal.hpp src/script/api/script_window.hpp src/widgets/goal_widget.h
diffstat 15 files changed, 256 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -150,6 +150,9 @@
 CommandProc CmdCustomNewsItem;
 CommandProc CmdCreateGoal;
 CommandProc CmdRemoveGoal;
+CommandProc CmdSetGoalText;
+CommandProc CmdSetGoalProgress;
+CommandProc CmdSetGoalCompleted;
 CommandProc CmdGoalQuestion;
 CommandProc CmdGoalQuestionAnswer;
 
@@ -292,6 +295,9 @@
 	DEF_CMD(CmdCustomNewsItem,          CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT      ), // CMD_CUSTOM_NEWS_ITEM
 	DEF_CMD(CmdCreateGoal,              CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT      ), // CMD_CREATE_GOAL
 	DEF_CMD(CmdRemoveGoal,                             CMD_DEITY, CMDT_OTHER_MANAGEMENT      ), // CMD_REMOVE_GOAL
+	DEF_CMD(CmdSetGoalText,             CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT      ), // CMD_SET_GOAL_TEXT
+	DEF_CMD(CmdSetGoalProgress,         CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT      ), // CMD_SET_GOAL_PROGRESS
+	DEF_CMD(CmdSetGoalCompleted,        CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT      ), // CMD_SET_GOAL_COMPLETED
 	DEF_CMD(CmdGoalQuestion,            CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT      ), // CMD_GOAL_QUESTION
 	DEF_CMD(CmdGoalQuestionAnswer,                     CMD_DEITY, CMDT_OTHER_MANAGEMENT      ), // CMD_GOAL_QUESTION_ANSWER
 
--- a/src/command_type.h
+++ b/src/command_type.h
@@ -266,6 +266,9 @@
 	CMD_CUSTOM_NEWS_ITEM,             ///< create a custom news message
 	CMD_CREATE_GOAL,                  ///< create a new goal
 	CMD_REMOVE_GOAL,                  ///< remove a goal
+	CMD_SET_GOAL_TEXT,                ///< update goal text of a goal
+	CMD_SET_GOAL_PROGRESS,            ///< update goal progress text of a goal
+	CMD_SET_GOAL_COMPLETED,           ///< update goal completed status of a goal
 	CMD_GOAL_QUESTION,                ///< ask a goal related question
 	CMD_GOAL_QUESTION_ANSWER,         ///< answer(s) to CMD_GOAL_QUESTION
 	CMD_LEVEL_LAND,                   ///< level land
--- a/src/goal.cpp
+++ b/src/goal.cpp
@@ -81,6 +81,8 @@
 		g->dst = p2;
 		g->company = company;
 		g->text = strdup(text);
+		g->progress = NULL;
+		g->completed = false;
 
 		InvalidateWindowData(WC_GOALS_LIST, 0);
 
@@ -114,6 +116,84 @@
 	return CommandCost();
 }
 
+/**
+ * Update goal text of a goal.
+ * @param tile unused.
+ * @param flags type of operation
+ * @param p1 GoalID to update.
+ * @param p2 unused
+ * @param text Text of the goal.
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdSetGoalText(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+	if (_current_company != OWNER_DEITY) return CMD_ERROR;
+	if (!Goal::IsValidID(p1)) return CMD_ERROR;
+	if (StrEmpty(text)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		Goal *g = Goal::Get(p1);
+		free(g->text);
+		g->text = strdup(text);
+
+		InvalidateWindowData(WC_GOALS_LIST, 0);
+	}
+
+	return CommandCost();
+}
+
+/**
+ * Update progress text of a goal.
+ * @param tile unused.
+ * @param flags type of operation
+ * @param p1 GoalID to update.
+ * @param p2 unused
+ * @param text Progress text of the goal.
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdSetGoalProgress(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+	if (_current_company != OWNER_DEITY) return CMD_ERROR;
+	if (!Goal::IsValidID(p1)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		Goal *g = Goal::Get(p1);
+		free(g->progress);
+		if (StrEmpty(text)) {
+			g->progress = NULL;
+		} else {
+			g->progress = strdup(text);
+		}
+
+		InvalidateWindowData(WC_GOALS_LIST, 0);
+	}
+
+	return CommandCost();
+}
+
+/**
+ * Update completed state of a goal.
+ * @param tile unused.
+ * @param flags type of operation
+ * @param p1 GoalID to update.
+ * @param p2 completed state. If goal is completed, set to 1, otherwise 0.
+ * @param text unused
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdSetGoalCompleted(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+	if (_current_company != OWNER_DEITY) return CMD_ERROR;
+	if (!Goal::IsValidID(p1)) return CMD_ERROR;
+
+	if (flags & DC_EXEC) {
+		Goal *g = Goal::Get(p1);
+		g->completed = p2 == 1;
+
+		InvalidateWindowData(WC_GOALS_LIST, 0);
+	}
+
+	return CommandCost();
+}
 
 /**
  * Ask a goal related question
--- a/src/goal_base.h
+++ b/src/goal_base.h
@@ -19,12 +19,14 @@
 typedef Pool<Goal, GoalID, 1, 256> GoalPool;
 extern GoalPool _goal_pool;
 
-/** Struct about subsidies, offered and awarded */
+/** Struct about goals, current and completed */
 struct Goal : GoalPool::PoolItem<&_goal_pool> {
 	CompanyByte company; ///< Goal is for a specific company; INVALID_COMPANY if it is global
 	GoalTypeByte type;   ///< Type of the goal
 	GoalTypeID dst;      ///< Index of type
 	char *text;          ///< Text of the goal.
+	char *progress;      ///< Progress text of the goal.
+	bool completed;      ///< Is the goal completed or not?
 
 	/**
 	 * We need an (empty) constructor so struct isn't zeroed (as C++ standard states)
@@ -34,7 +36,7 @@
 	/**
 	 * (Empty) destructor has to be defined else operator delete might be called with NULL parameter
 	 */
-	inline ~Goal() { free(this->text); }
+	inline ~Goal() { free(this->text); free(this->progress); }
 };
 
 #define FOR_ALL_GOALS_FROM(var, start) FOR_ALL_ITEMS_FROM(Goal, goal_index, var, start)
--- a/src/goal_gui.cpp
+++ b/src/goal_gui.cpp
@@ -39,9 +39,9 @@
 
 	virtual void OnClick(Point pt, int widget, int click_count)
 	{
-		if (widget != WID_GL_PANEL) return;
+		if (widget != WID_GL_GOAL && widget != WID_GL_PROGRESS) return;
 
-		int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_PANEL, WD_FRAMERECT_TOP);
+		int y = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_GL_GOAL, WD_FRAMERECT_TOP);
 		int num = 0;
 		const Goal *s;
 		FOR_ALL_GOALS(s) {
@@ -135,9 +135,25 @@
 
 	virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
 	{
-		if (widget != WID_GL_PANEL) return;
+		if (widget != WID_GL_GOAL && widget != WID_GL_PROGRESS) return;
 		Dimension d = maxdim(GetStringBoundingBox(STR_GOALS_GLOBAL_TITLE), GetStringBoundingBox(STR_GOALS_COMPANY_TITLE));
 
+		if (widget == WID_GL_PROGRESS) {
+			/* Get max progress width. */
+			d.width = 0;
+			Goal *s;
+			FOR_ALL_GOALS(s) {
+				if (s->progress != NULL) {
+					SetDParamStr(0, s->progress);
+					Dimension goal_d = GetStringBoundingBox(STR_GOALS_PROGRESS);
+
+					if (goal_d.width > d.width) {
+						d.width = goal_d.width;
+					}
+				}
+			}
+		}
+
 		resize->height = d.height;
 
 		d.height *= 5;
@@ -150,9 +166,9 @@
 	 * Draws either the global goals or the company goal section.
 	 * This is a helper method for DrawWidget.
 	 */
-	void DrawPartialGoalList(int &pos, const int cap, int x, int y, int right, bool global_section) const
+	void DrawPartialGoalList(int widget, int &pos, const int cap, int x, int y, int right, bool global_section) const
 	{
-		if (IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, global_section ? STR_GOALS_GLOBAL_TITLE : STR_GOALS_COMPANY_TITLE);
+		if (widget == WID_GL_GOAL && IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, global_section ? STR_GOALS_GLOBAL_TITLE : STR_GOALS_COMPANY_TITLE);
 		pos++;
 
 		uint num = 0;
@@ -160,16 +176,27 @@
 		FOR_ALL_GOALS(s) {
 			if (global_section ? s->company == INVALID_COMPANY : s->company == _local_company && s->company != INVALID_COMPANY) {
 				if (IsInsideMM(pos, 0, cap)) {
-					/* Display the goal */
-					SetDParamStr(0, s->text);
-					DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_GOALS_TEXT);
+					switch (widget) {
+						case WID_GL_GOAL:
+							/* Display the goal. */
+							SetDParamStr(0, s->text);
+							DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_GOALS_TEXT);
+							break;
+
+						case WID_GL_PROGRESS:
+							if (s->progress != NULL) {
+								SetDParamStr(0, s->progress);
+								DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, s->completed ? STR_GOALS_PROGRESS_COMPLETE : STR_GOALS_PROGRESS, TC_FROMSTRING, SA_RIGHT | SA_FORCE);
+							}
+							break;
+					}
 				}
 				pos++;
 				num++;
 			}
 		}
 
-		if (num == 0) {
+		if (widget == WID_GL_GOAL && num == 0) {
 			if (IsInsideMM(pos, 0, cap)) DrawString(x, right, y + pos * FONT_HEIGHT_NORMAL, STR_GOALS_NONE);
 			pos++;
 		}
@@ -177,7 +204,7 @@
 
 	virtual void DrawWidget(const Rect &r, int widget) const
 	{
-		if (widget != WID_GL_PANEL) return;
+		if (widget != WID_GL_GOAL && widget != WID_GL_PROGRESS) return;
 
 		YearMonthDay ymd;
 		ConvertDateToYMD(_date, &ymd);
@@ -190,16 +217,16 @@
 		const int cap = this->vscroll->GetCapacity();
 
 		/* Draw partial list with global goals */
-		DrawPartialGoalList(pos, cap, x, y, right, true);
+		DrawPartialGoalList(widget, pos, cap, x, y, right, true);
 
 		/* Draw partial list with company goals */
 		pos++;
-		DrawPartialGoalList(pos, cap, x, y, right, false);
+		DrawPartialGoalList(widget, pos, cap, x, y, right, false);
 	}
 
 	virtual void OnResize()
 	{
-		this->vscroll->SetCapacityFromWidget(this, WID_GL_PANEL);
+		this->vscroll->SetCapacityFromWidget(this, WID_GL_GOAL);
 	}
 
 	/**
@@ -222,8 +249,15 @@
 		NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN),
 		NWidget(WWT_STICKYBOX, COLOUR_BROWN),
 	EndContainer(),
-	NWidget(NWID_HORIZONTAL),
-		NWidget(WWT_PANEL, COLOUR_BROWN, WID_GL_PANEL), SetDataTip(0x0, STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER), SetResize(1, 1), SetScrollbar(WID_GL_SCROLLBAR), EndContainer(),
+	NWidget(NWID_HORIZONTAL), SetFill(1, 1),
+		NWidget(WWT_PANEL, COLOUR_BROWN), SetDataTip(0x0, STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER), SetResize(1, 1), SetFill(1, 0), SetScrollbar(WID_GL_SCROLLBAR),
+			NWidget(NWID_VERTICAL), SetPIP(WD_FRAMERECT_TOP, 4, WD_FRAMETEXT_BOTTOM),
+				NWidget(NWID_HORIZONTAL), SetPIP(2, 4, 2),
+					NWidget(WWT_EMPTY, COLOUR_GREY, WID_GL_GOAL), SetResize(1, 1), SetMinimalTextLines(2, 0), SetFill(1, 0),
+					NWidget(WWT_EMPTY, COLOUR_GREY, WID_GL_PROGRESS), SetResize(0, 1), SetMinimalTextLines(2, 0), SetFill(0, 1),
+				EndContainer(),
+			EndContainer(),
+		EndContainer(),
 		NWidget(NWID_VERTICAL),
 			NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_GL_SCROLLBAR),
 			NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
--- a/src/lang/english.txt
+++ b/src/lang/english.txt
@@ -2907,6 +2907,8 @@
 STR_GOALS_GLOBAL_TITLE                                          :{BLACK}Global goals:
 STR_GOALS_TEXT                                                  :{ORANGE}{RAW_STRING}
 STR_GOALS_NONE                                                  :{ORANGE}- None -
+STR_GOALS_PROGRESS                                              :{ORANGE}{RAW_STRING}
+STR_GOALS_PROGRESS_COMPLETE                                     :{GREEN}{RAW_STRING}
 STR_GOALS_COMPANY_TITLE                                         :{BLACK}Company goals:
 STR_GOALS_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER                    :{BLACK}Click on goal to centre main view on industry/town/tile. Ctrl+Click opens a new viewport on industry/town/tile location
 
--- a/src/saveload/goal_sl.cpp
+++ b/src/saveload/goal_sl.cpp
@@ -15,10 +15,12 @@
 #include "saveload.h"
 
 static const SaveLoad _goals_desc[] = {
-	    SLE_VAR(Goal, company, SLE_UINT16),
-	    SLE_VAR(Goal, type,    SLE_UINT16),
-	    SLE_VAR(Goal, dst,     SLE_UINT32),
-	    SLE_STR(Goal, text,    SLE_STR | SLF_ALLOW_CONTROL, 0),
+	    SLE_VAR(Goal, company,   SLE_UINT16),
+	    SLE_VAR(Goal, type,      SLE_UINT16),
+	    SLE_VAR(Goal, dst,       SLE_UINT32),
+	    SLE_STR(Goal, text,      SLE_STR | SLF_ALLOW_CONTROL, 0),
+	SLE_CONDSTR(Goal, progress,  SLE_STR | SLF_ALLOW_CONTROL, 0, 182, SL_MAX_VERSION),
+	SLE_CONDVAR(Goal, completed, SLE_BOOL, 182, SL_MAX_VERSION),
 	    SLE_END()
 };
 
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -246,9 +246,9 @@
  *  179   24810
  *  180   24998   1.3.x
  *  181   25012
- *  182   25259
+ *  182   25296
  */
-extern const uint16 SAVEGAME_VERSION = 181; ///< Current savegame version of OpenTTD.
+extern const uint16 SAVEGAME_VERSION = 182; ///< Current savegame version of OpenTTD.
 
 SavegameType _savegame_type; ///< type of savegame we are loading
 
--- a/src/script/api/game/game_goal.hpp.sq
+++ b/src/script/api/game/game_goal.hpp.sq
@@ -53,6 +53,10 @@
 	SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::IsValidGoal,   "IsValidGoal",   2, ".i");
 	SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::New,           "New",           5, ".i.ii");
 	SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::Remove,        "Remove",        2, ".i");
+	SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::SetText,       "SetText",       3, ".i.");
+	SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::SetProgress,   "SetProgress",   3, ".i.");
+	SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::SetCompleted,  "SetCompleted",  3, ".ib");
+	SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::IsCompleted,   "IsCompleted",   2, ".i");
 	SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::Question,      "Question",      6, ".ii.ii");
 	SQGSGoal.DefSQStaticMethod(engine, &ScriptGoal::CloseQuestion, "CloseQuestion", 2, ".i");
 
--- a/src/script/api/game/game_window.hpp.sq
+++ b/src/script/api/game/game_window.hpp.sq
@@ -493,7 +493,8 @@
 	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_PROGRESS_BAR,                       "WID_GP_PROGRESS_BAR");
 	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_PROGRESS_TEXT,                      "WID_GP_PROGRESS_TEXT");
 	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GP_ABORT,                              "WID_GP_ABORT");
-	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_PANEL,                              "WID_GL_PANEL");
+	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_GOAL,                               "WID_GL_GOAL");
+	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_PROGRESS,                           "WID_GL_PROGRESS");
 	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GL_SCROLLBAR,                          "WID_GL_SCROLLBAR");
 	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_CAPTION,                            "WID_GQ_CAPTION");
 	SQGSWindow.DefSQConst(engine, ScriptWindow::WID_GQ_QUESTION,                           "WID_GQ_QUESTION");
--- a/src/script/api/game_changelog.hpp
+++ b/src/script/api/game_changelog.hpp
@@ -20,6 +20,10 @@
  * 1.4.0 is not yet released. The following changes are not set in stone yet.
  *
  * API additions:
+ * \li GSGoal::IsCompleted
+ * \li GSGoal::SetCompleted
+ * \li GSGoal::SetProgress
+ * \li GSGoal::SetText
  * \li GSStation::HasRating
  * \li GSTile::GetTerrainType
  *
--- a/src/script/api/script_goal.cpp
+++ b/src/script/api/script_goal.cpp
@@ -52,6 +52,50 @@
 	return ScriptObject::DoCommand(0, goal_id, 0, CMD_REMOVE_GOAL);
 }
 
+/* static */ bool ScriptGoal::SetText(GoalID goal_id, Text *goal)
+{
+	CCountedPtr<Text> counter(goal);
+
+	EnforcePrecondition(false, IsValidGoal(goal_id));
+	EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
+	EnforcePrecondition(false, goal != NULL);
+	EnforcePrecondition(false, !StrEmpty(goal->GetEncodedText()));
+
+	return ScriptObject::DoCommand(0, goal_id, 0, CMD_SET_GOAL_TEXT, goal->GetEncodedText());
+}
+
+/* static */ bool ScriptGoal::SetProgress(GoalID goal_id, Text *progress)
+{
+	CCountedPtr<Text> counter(progress);
+
+	EnforcePrecondition(false, IsValidGoal(goal_id));
+	EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
+
+	/* Ensure null as used for emtpy string. */
+	if (progress != NULL && StrEmpty(progress->GetEncodedText())) {
+		progress = NULL;
+	}
+
+	return ScriptObject::DoCommand(0, goal_id, 0, CMD_SET_GOAL_PROGRESS, progress != NULL ? progress->GetEncodedText() : NULL);
+}
+
+/* static */ bool ScriptGoal::SetCompleted(GoalID goal_id, bool completed)
+{
+	EnforcePrecondition(false, IsValidGoal(goal_id));
+	EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
+
+	return ScriptObject::DoCommand(0, goal_id, completed ? 1 : 0, CMD_SET_GOAL_COMPLETED);
+}
+
+/* static */ bool ScriptGoal::IsCompleted(GoalID goal_id)
+{
+	EnforcePrecondition(false, IsValidGoal(goal_id));
+	EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
+
+	Goal *g = Goal::Get(goal_id);
+	return g != NULL && g->completed;
+}
+
 /* static */ bool ScriptGoal::Question(uint16 uniqueid, ScriptCompany::CompanyID company, Text *question, QuestionType type, int buttons)
 {
 	CCountedPtr<Text> counter(question);
--- a/src/script/api/script_goal.hpp
+++ b/src/script/api/script_goal.hpp
@@ -109,6 +109,50 @@
 	static bool Remove(GoalID goal_id);
 
 	/**
+	 * Update goal text of a goal.
+	 * @param goal_id The goal to update.
+	 * @param goal The new goal text (can be either a raw string, or a ScriptText object).
+	 * @return True if the action succeeded.
+	 * @pre No ScriptCompanyMode may be in scope.
+	 * @pre goal != NULL && len(goal) != 0.
+	 * @pre IsValidGoal(goal_id).
+	 */
+	static bool SetText(GoalID goal_id, Text *goal);
+
+	/**
+	 * Update the progress text of a goal. The progress text is a text that
+	 * is shown adjacent to the goal but in a separate column. Try to keep
+	 * the progress string short.
+	 * @param goal_id The goal to update.
+	 * @param progress The new progress text for the goal (can be either a raw string,
+	 * or a ScriptText object). To clear the progress string you can pass NULL or an
+	 * empty string.
+	 * @return True if the action succeeded.
+	 * @pre No ScriptCompanyMode may be in scope.
+	 * @pre IsValidGoal(goal_id).
+	 */
+	static bool SetProgress(GoalID goal_id, Text *progress);
+
+	/**
+	 * Update completed status of goal
+	 * @param goal_id The goal to update.
+	 * @param complete The new goal completed status.
+	 * @return True if the action succeeded.
+	 * @pre No ScriptCompanyMode may be in scope.
+	 * @pre IsValidGoal(goal_id).
+	 */
+	static bool SetCompleted(GoalID goal_id, bool complete);
+
+	/**
+	 * Checks if a given goal have been marked as completed.
+	 * @param goal_id The goal to check complete status.
+	 * @return True if the goal is completed, otherwise false.
+	 * @pre No ScriptCompanyMode may be in scope.
+	 * @pre IsValidGoal(goal_id).
+	 */
+	static bool IsCompleted(GoalID goal_id);
+
+	/**
 	 * Ask a question.
 	 * @param uniqueid Your unique id to distinguish results of multiple questions in the returning event.
 	 * @param company The company to ask the question, or ScriptCompany::COMPANY_INVALID for all.
--- a/src/script/api/script_window.hpp
+++ b/src/script/api/script_window.hpp
@@ -1326,8 +1326,9 @@
 	/* automatically generated from ../../widgets/goal_widget.h */
 	/** Widgets of the #GoalListWindow class. */
 	enum GoalListWidgets {
-		WID_GL_PANEL                                 = ::WID_GL_PANEL,                                 ///< Panel of the window.
-		WID_GL_SCROLLBAR                             = ::WID_GL_SCROLLBAR,                             ///< Scrollbar of the panel.
+		WID_GL_GOAL                                  = ::WID_GL_GOAL,                                  ///< Goal text column of the goal list.
+		WID_GL_PROGRESS                              = ::WID_GL_PROGRESS,                              ///< Goal progress column of the goal list.
+		WID_GL_SCROLLBAR                             = ::WID_GL_SCROLLBAR,                             ///< Scrollbar of the goal list.
 	};
 
 	/** Widgets of the #GoalQuestionWindow class. */
--- a/src/widgets/goal_widget.h
+++ b/src/widgets/goal_widget.h
@@ -15,8 +15,9 @@
 
 /** Widgets of the #GoalListWindow class. */
 enum GoalListWidgets {
-	WID_GL_PANEL,     ///< Panel of the window.
-	WID_GL_SCROLLBAR, ///< Scrollbar of the panel.
+	WID_GL_GOAL,      ///< Goal text column of the goal list.
+	WID_GL_PROGRESS,  ///< Goal progress column of the goal list.
+	WID_GL_SCROLLBAR, ///< Scrollbar of the goal list.
 };
 
 /** Widgets of the #GoalQuestionWindow class. */