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.
This commit is contained in:
committed by
GitHub
parent
c972a63c8c
commit
800ade7702
143
src/story.cpp
143
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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user