diff --git a/src/script/api/game_changelog.hpp b/src/script/api/game_changelog.hpp
index 241b955304..71ff4b6d5a 100644
--- a/src/script/api/game_changelog.hpp
+++ b/src/script/api/game_changelog.hpp
@@ -82,6 +82,9 @@
  * \li GSIndustry::GetProductionLevel
  * \li GSIndustry::SetProductionLevel
  * \li GSStoryPage::IsValidStoryPageElementType
+ * \li GSStoryPage::IsValidStoryPageButtonColour
+ * \li GSStoryPage::IsValidStoryPageButtonFlags
+ * \li GSStoryPage::IsValidStoryPageButtonCursor
  *
  * API removals:
  * \li GSError::ERR_PRECONDITION_TOO_MANY_PARAMETERS, that error is never returned anymore.
diff --git a/src/script/api/script_story_page.cpp b/src/script/api/script_story_page.cpp
index b99c703aa1..d2f963e76a 100644
--- a/src/script/api/script_story_page.cpp
+++ b/src/script/api/script_story_page.cpp
@@ -224,10 +224,32 @@ static inline bool StoryPageElementTypeRequiresText(StoryPageElementType type)
 	return ScriptObject::Command<CMD_REMOVE_STORY_PAGE_ELEMENT>::Do(story_page_element_id);
 }
 
+/* static */ bool ScriptStoryPage::IsValidStoryPageButtonColour(StoryPageButtonColour colour)
+{
+	return ::IsValidColours((::Colours)colour);
+}
+
+/* static */ bool ScriptStoryPage::IsValidStoryPageButtonFlags(StoryPageButtonFlags flags)
+{
+	/* Don't allow float left and right together */
+	if ((flags & SPBF_FLOAT_LEFT) && (flags & SPBF_FLOAT_RIGHT)) return false;
+	/* Don't allow undefined flags */
+	if (flags & ~(SPBF_FLOAT_LEFT | SPBF_FLOAT_RIGHT)) return false;
+	return true;
+}
+
+/* static */ bool ScriptStoryPage::IsValidStoryPageButtonCursor(StoryPageButtonCursor cursor)
+{
+	return ::IsValidStoryPageButtonCursor((::StoryPageButtonCursor)cursor);
+}
+
 /* static */ ScriptStoryPage::StoryPageButtonFormatting ScriptStoryPage::MakePushButtonReference(StoryPageButtonColour colour, StoryPageButtonFlags flags)
 {
+	EnforcePrecondition(UINT32_MAX, IsValidStoryPageButtonColour(colour));
+	EnforcePrecondition(UINT32_MAX, IsValidStoryPageButtonFlags(flags));
+
 	StoryPageButtonData data;
-	data.SetColour((Colours)colour);
+	data.SetColour((::Colours)colour);
 	data.SetFlags((::StoryPageButtonFlags)flags);
 	if (!data.ValidateColour()) return UINT32_MAX;
 	if (!data.ValidateFlags()) return UINT32_MAX;
@@ -236,8 +258,12 @@ static inline bool StoryPageElementTypeRequiresText(StoryPageElementType type)
 
 /* static */ ScriptStoryPage::StoryPageButtonFormatting ScriptStoryPage::MakeTileButtonReference(StoryPageButtonColour colour, StoryPageButtonFlags flags, StoryPageButtonCursor cursor)
 {
+	EnforcePrecondition(UINT32_MAX, IsValidStoryPageButtonColour(colour));
+	EnforcePrecondition(UINT32_MAX, IsValidStoryPageButtonFlags(flags));
+	EnforcePrecondition(UINT32_MAX, IsValidStoryPageButtonCursor(cursor));
+
 	StoryPageButtonData data;
-	data.SetColour((Colours)colour);
+	data.SetColour((::Colours)colour);
 	data.SetFlags((::StoryPageButtonFlags)flags);
 	data.SetCursor((::StoryPageButtonCursor)cursor);
 	if (!data.ValidateColour()) return UINT32_MAX;
@@ -248,8 +274,13 @@ static inline bool StoryPageElementTypeRequiresText(StoryPageElementType type)
 
 /* static */ ScriptStoryPage::StoryPageButtonFormatting ScriptStoryPage::MakeVehicleButtonReference(StoryPageButtonColour colour, StoryPageButtonFlags flags, StoryPageButtonCursor cursor, ScriptVehicle::VehicleType vehtype)
 {
+	EnforcePrecondition(UINT32_MAX, IsValidStoryPageButtonColour(colour));
+	EnforcePrecondition(UINT32_MAX, IsValidStoryPageButtonFlags(flags));
+	EnforcePrecondition(UINT32_MAX, IsValidStoryPageButtonCursor(cursor));
+	EnforcePrecondition(UINT32_MAX, vehtype == ScriptVehicle::VT_INVALID || vehtype == ScriptVehicle::VT_RAIL || vehtype == ScriptVehicle::VT_ROAD || vehtype == ScriptVehicle::VT_WATER || vehtype == ScriptVehicle::VT_AIR);
+
 	StoryPageButtonData data;
-	data.SetColour((Colours)colour);
+	data.SetColour((::Colours)colour);
 	data.SetFlags((::StoryPageButtonFlags)flags);
 	data.SetCursor((::StoryPageButtonCursor)cursor);
 	data.SetVehicleType((::VehicleType)vehtype);
@@ -259,4 +290,3 @@ static inline bool StoryPageElementTypeRequiresText(StoryPageElementType type)
 	if (!data.ValidateVehicleType()) return UINT32_MAX;
 	return data.referenced_id;
 }
-
diff --git a/src/script/api/script_story_page.hpp b/src/script/api/script_story_page.hpp
index edebc0bf1c..4e16876664 100644
--- a/src/script/api/script_story_page.hpp
+++ b/src/script/api/script_story_page.hpp
@@ -146,7 +146,7 @@ public:
 	 * Colour codes usable for story page button elements.
 	 * Place a colour value in the lowest 8 bits of the \c reference parameter to the button.
 	 */
-	enum StoryPageButtonColour {
+	enum StoryPageButtonColour : byte {
 		SPBC_DARK_BLUE  = ::COLOUR_DARK_BLUE,
 		SPBC_PALE_GREEN = ::COLOUR_PALE_GREEN,
 		SPBC_PINK       = ::COLOUR_PINK,
@@ -320,11 +320,34 @@ public:
 	 */
 	static bool RemoveElement(StoryPageElementID story_page_element_id);
 
+	/**
+	 * Check whether this is a valid story page button colour.
+	 * @param colour The StoryPageButtonColour to check.
+	 * @return True if and only if this story page button colour is valid.
+	 */
+	static bool IsValidStoryPageButtonColour(StoryPageButtonColour colour);
+
+	/**
+	* Check whether this is a valid story page button flag.
+	* @param colour The StoryPageButtonFlags to check.
+	* @return True if and only if this story page button flag is valid.
+	*/
+	static bool IsValidStoryPageButtonFlags(StoryPageButtonFlags flags);
+
+	/**
+	 * Check whether this is a valid story page button cursor.
+	 * @param colour The StoryPageButtonCursor to check.
+	 * @return True if and only if this story page button cursor is valid.
+	 */
+	static bool IsValidStoryPageButtonCursor(StoryPageButtonCursor cursor);
+
 	/**
 	 * Create a reference value for SPET_BUTTON_PUSH element parameters.
 	 * @param colour The colour for the face of the button.
 	 * @param flags The formatting and layout flags for the button.
 	 * @return A reference value usable with the #NewElement and #UpdateElement functions.
+	 * @pre IsValidStoryPageButtonColour(colour).
+	 * @pre IsValidStoryPageButtonFlags(flags).
 	 */
 	static StoryPageButtonFormatting MakePushButtonReference(StoryPageButtonColour colour, StoryPageButtonFlags flags);
 
@@ -334,6 +357,9 @@ public:
 	 * @param flags The formatting and layout flags for the button.
 	 * @param cursor The mouse cursor to use when the player clicks the button and the game is ready for the player to select a tile.
 	 * @return A reference value usable with the #NewElement and #UpdateElement functions.
+	 * @pre IsValidStoryPageButtonColour(colour).
+	 * @pre IsValidStoryPageButtonFlags(flags).
+	 * @pre IsValidStoryPageButtonCursor(cursor).
 	 */
 	static StoryPageButtonFormatting MakeTileButtonReference(StoryPageButtonColour colour, StoryPageButtonFlags flags, StoryPageButtonCursor cursor);
 
@@ -344,6 +370,10 @@ public:
 	 * @param cursor  The mouse cursor to use when the player clicks the button and the game is ready for the player to select a vehicle.
 	 * @param vehtype The type of vehicle that will be selectable, or \c VT_INVALID to allow all types.
 	 * @return A reference value usable with the #NewElement and #UpdateElement functions.
+	 * @pre IsValidStoryPageButtonColour(colour).
+	 * @pre IsValidStoryPageButtonFlags(flags).
+	 * @pre IsValidStoryPageButtonCursor(cursor).
+	 * @pre vehtype == ScriptVehicle::VT_INVALID || vehtype == ScriptVehicle::VT_RAIL || vehtype == ScriptVehicle::VT_ROAD || vehtype == ScriptVehicle::VT_WATER || vehtype == ScriptVehicle::VT_AIR.
 	 */
 	static StoryPageButtonFormatting MakeVehicleButtonReference(StoryPageButtonColour colour, StoryPageButtonFlags flags, StoryPageButtonCursor cursor, ScriptVehicle::VehicleType vehtype);
 };
diff --git a/src/story.cpp b/src/story.cpp
index ad732f9d37..0b7f0f920b 100644
--- a/src/story.cpp
+++ b/src/story.cpp
@@ -66,13 +66,16 @@ static bool VerifyElementContentParameters(StoryPageID page_id, StoryPageElement
 			break;
 		case SPET_BUTTON_PUSH:
 			if (!button_data.ValidateColour()) return false;
+			if (!button_data.ValidateFlags()) return false;
 			return true;
 		case SPET_BUTTON_TILE:
 			if (!button_data.ValidateColour()) return false;
+			if (!button_data.ValidateFlags()) return false;
 			if (!button_data.ValidateCursor()) return false;
 			return true;
 		case SPET_BUTTON_VEHICLE:
 			if (!button_data.ValidateColour()) return false;
+			if (!button_data.ValidateFlags()) return false;
 			if (!button_data.ValidateCursor()) return false;
 			if (!button_data.ValidateVehicleType()) return false;
 			return true;