summaryrefslogtreecommitdiff
path: root/src/story.cpp
diff options
context:
space:
mode:
authorNiels Martin Hansen <nielsm@indvikleren.dk>2020-05-22 22:22:55 +0200
committerGitHub <noreply@github.com>2020-05-22 22:22:55 +0200
commit800ade77021b34adf8daa5ca5de0efaa8df24152 (patch)
tree7a2eb5c73c926476c81cd782bcb9b42c93bafdc4 /src/story.cpp
parentc972a63c8cbee7fa8d6d5af2cbbecb8c75ee561a (diff)
downloadopenttd-800ade77021b34adf8daa5ca5de0efaa8df24152.tar.xz
Feature: Push-buttons on storybook pages (#7896)
Allow more direct player-initiated interaction for Game Scripts, by letting the GS put push-buttons on storybook pages. These buttons can either trigger an immediate event, or require the player to first select a tile on the map, or a vehicle. Additionally this reworks how the storybook pages are layouted and rendered, to allow for slightly more complex layouts, and maybe speeding drawing up a bit.
Diffstat (limited to 'src/story.cpp')
-rw-r--r--src/story.cpp143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/story.cpp b/src/story.cpp
index 0d465fde8..e60c60a9f 100644
--- a/src/story.cpp
+++ b/src/story.cpp
@@ -21,6 +21,10 @@
#include "goal_base.h"
#include "window_func.h"
#include "gui.h"
+#include "vehicle_base.h"
+#include "game/game.hpp"
+#include "script/api/script_story_page.hpp"
+#include "script/api/script_event_types.hpp"
#include "safeguards.h"
@@ -47,6 +51,8 @@ INSTANTIATE_POOL_METHODS(StoryPage)
*/
static bool VerifyElementContentParameters(StoryPageID page_id, StoryPageElementType type, TileIndex tile, uint32 reference, const char *text)
{
+ StoryPageButtonData button_data{ reference };
+
switch (type) {
case SPET_TEXT:
if (StrEmpty(text)) return false;
@@ -60,6 +66,18 @@ static bool VerifyElementContentParameters(StoryPageID page_id, StoryPageElement
/* Reject company specific goals on global pages */
if (StoryPage::Get(page_id)->company == INVALID_COMPANY && Goal::Get((GoalID)reference)->company != INVALID_COMPANY) return false;
break;
+ case SPET_BUTTON_PUSH:
+ if (!button_data.ValidateColour()) return false;
+ return true;
+ case SPET_BUTTON_TILE:
+ if (!button_data.ValidateColour()) return false;
+ if (!button_data.ValidateCursor()) return false;
+ return true;
+ case SPET_BUTTON_VEHICLE:
+ if (!button_data.ValidateColour()) return false;
+ if (!button_data.ValidateCursor()) return false;
+ if (!button_data.ValidateVehicleType()) return false;
+ return true;
default:
return false;
}
@@ -88,10 +106,94 @@ static void UpdateElement(StoryPageElement &pe, TileIndex tile, uint32 reference
case SPET_GOAL:
pe.referenced_id = (GoalID)reference;
break;
+ case SPET_BUTTON_PUSH:
+ case SPET_BUTTON_TILE:
+ case SPET_BUTTON_VEHICLE:
+ pe.text = stredup(text);
+ pe.referenced_id = reference;
+ break;
default: NOT_REACHED();
}
}
+/** Set the button background colour. */
+void StoryPageButtonData::SetColour(Colours button_colour)
+{
+ assert(button_colour < COLOUR_END);
+ SB(this->referenced_id, 0, 8, button_colour);
+}
+
+void StoryPageButtonData::SetFlags(StoryPageButtonFlags flags)
+{
+ SB(this->referenced_id, 24, 8, flags);
+}
+
+/** Set the mouse cursor used while waiting for input for the button. */
+void StoryPageButtonData::SetCursor(StoryPageButtonCursor cursor)
+{
+ assert(cursor < SPBC_END);
+ SB(this->referenced_id, 8, 8, cursor);
+}
+
+/** Set the type of vehicles that are accepted by the button */
+void StoryPageButtonData::SetVehicleType(VehicleType vehtype)
+{
+ assert(vehtype == VEH_INVALID || vehtype < VEH_COMPANY_END);
+ SB(this->referenced_id, 16, 8, vehtype);
+}
+
+/** Get the button background colour. */
+Colours StoryPageButtonData::GetColour() const
+{
+ return Extract<Colours, 0, 8>(this->referenced_id);
+}
+
+StoryPageButtonFlags StoryPageButtonData::GetFlags() const
+{
+ return (StoryPageButtonFlags)GB(this->referenced_id, 24, 8);
+}
+
+/** Get the mouse cursor used while waiting for input for the button. */
+StoryPageButtonCursor StoryPageButtonData::GetCursor() const
+{
+ return Extract<StoryPageButtonCursor, 8, 8>(this->referenced_id);
+}
+
+/** Get the type of vehicles that are accepted by the button */
+VehicleType StoryPageButtonData::GetVehicleType() const
+{
+ return (VehicleType)GB(this->referenced_id, 16, 8);
+}
+
+/** Verify that the data stored a valid Colour value */
+bool StoryPageButtonData::ValidateColour() const
+{
+ return GB(this->referenced_id, 0, 8) < COLOUR_END;
+}
+
+bool StoryPageButtonData::ValidateFlags() const
+{
+ byte flags = GB(this->referenced_id, 24, 8);
+ /* 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;
+}
+
+/** Verify that the data stores a valid StoryPageButtonCursor value */
+bool StoryPageButtonData::ValidateCursor() const
+{
+ return GB(this->referenced_id, 8, 8) < SPBC_END;
+}
+
+/** Verity that the data stored a valid VehicleType value */
+bool StoryPageButtonData::ValidateVehicleType() const
+{
+ byte vehtype = GB(this->referenced_id, 16, 8);
+ return vehtype == VEH_INVALID || vehtype < VEH_COMPANY_END;
+}
+
/**
* Create a new story page.
* @param tile unused.
@@ -358,3 +460,44 @@ CommandCost CmdRemoveStoryPageElement(TileIndex tile, DoCommandFlag flags, uint3
return CommandCost();
}
+/**
+ * Clicked/used a button on a story page.
+ * @param tile Tile selected, for tile selection buttons, otherwise unused.
+ * @param flags Type of operation.
+ * @param p1 Bit 0..15 = story page element id of button.
+ * @param p2 ID of selected item for buttons that select an item (e.g. vehicle), otherwise unused.
+ * @param text Unused.
+ * @return The cost of the operation, or an error.
+ */
+CommandCost CmdStoryPageButton(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+ StoryPageElementID page_element_id = (StoryPageElementID)GB(p1, 0, 16);
+
+ if (!StoryPageElement::IsValidID(page_element_id)) return CMD_ERROR;
+ const StoryPageElement *const pe = StoryPageElement::Get(page_element_id);
+
+ /* Check the player belongs to the company that owns the page. */
+ const StoryPage *const sp = StoryPage::Get(pe->page);
+ if (sp->company != INVALID_COMPANY && sp->company != _current_company) return CMD_ERROR;
+
+ switch (pe->type) {
+ case SPET_BUTTON_PUSH:
+ /* No validation required */
+ if (flags & DC_EXEC) Game::NewEvent(new ScriptEventStoryPageButtonClick(_current_company, pe->page, page_element_id));
+ break;
+ case SPET_BUTTON_TILE:
+ if (!IsValidTile(tile)) return CMD_ERROR;
+ if (flags & DC_EXEC) Game::NewEvent(new ScriptEventStoryPageTileSelect(_current_company, pe->page, page_element_id, tile));
+ break;
+ case SPET_BUTTON_VEHICLE:
+ if (!Vehicle::IsValidID(p2)) return CMD_ERROR;
+ if (flags & DC_EXEC) Game::NewEvent(new ScriptEventStoryPageVehicleSelect(_current_company, pe->page, page_element_id, (VehicleID)p2));
+ break;
+ default:
+ /* Invalid page element type, not a button. */
+ return CMD_ERROR;
+ }
+
+ return CommandCost();
+}
+