summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorzuu <zuu@openttd.org>2013-06-09 12:19:09 +0000
committerzuu <zuu@openttd.org>2013-06-09 12:19:09 +0000
commit9aa1bf026443ddc65ab4381e86c294943ddc30d8 (patch)
tree82af61f4b6f346bd71046a5d6fa6bab1f49b3d34 /src
parentbea60988c67b40fb5b3058990779a4d572511224 (diff)
downloadopenttd-9aa1bf026443ddc65ab4381e86c294943ddc30d8.tar.xz
(svn r25342) -Add: StoryPage data structures and GS API
Diffstat (limited to 'src')
-rw-r--r--src/command.cpp10
-rw-r--r--src/command_type.h5
-rw-r--r--src/economy.cpp8
-rw-r--r--src/game/game_instance.cpp2
-rw-r--r--src/saveload/saveload.cpp2
-rw-r--r--src/saveload/story_sl.cpp89
-rw-r--r--src/script/api/game/game_story_page.hpp.sq39
-rw-r--r--src/script/api/script_object.cpp22
-rw-r--r--src/script/api/script_object.hpp22
-rw-r--r--src/script/api/script_story_page.cpp119
-rw-r--r--src/script/api/script_story_page.hpp142
-rw-r--r--src/script/api/script_types.hpp2
-rw-r--r--src/script/api/template/template_story_page.hpp.sq29
-rw-r--r--src/script/script_instance.cpp10
-rw-r--r--src/script/script_instance.hpp10
-rw-r--r--src/script/script_storage.hpp3
-rw-r--r--src/story.cpp271
-rw-r--r--src/story_base.h85
-rw-r--r--src/story_type.h28
19 files changed, 897 insertions, 1 deletions
diff --git a/src/command.cpp b/src/command.cpp
index d49eb5cf6..38dc43521 100644
--- a/src/command.cpp
+++ b/src/command.cpp
@@ -155,6 +155,11 @@ CommandProc CmdSetGoalProgress;
CommandProc CmdSetGoalCompleted;
CommandProc CmdGoalQuestion;
CommandProc CmdGoalQuestionAnswer;
+CommandProc CmdCreateStoryPage;
+CommandProc CmdCreateStoryPageElement;
+CommandProc CmdUpdateStoryPageElement;
+CommandProc CmdSetStoryPageTitle;
+CommandProc CmdRemoveStoryPage;
CommandProc CmdLevelLand;
@@ -300,6 +305,11 @@ static const Command _command_proc_table[] = {
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
+ DEF_CMD(CmdCreateStoryPage, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CREATE_STORY_PAGE
+ DEF_CMD(CmdCreateStoryPageElement, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_CREATE_STORY_PAGE_ELEMENT
+ DEF_CMD(CmdUpdateStoryPageElement, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_UPDATE_STORY_PAGE_ELEMENT
+ DEF_CMD(CmdSetStoryPageTitle, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_SET_STORY_PAGE_TITLE
+ DEF_CMD(CmdRemoveStoryPage, CMD_STR_CTRL | CMD_DEITY, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_STORY_PAGE
DEF_CMD(CmdLevelLand, CMD_ALL_TILES | CMD_NO_TEST | CMD_AUTO, CMDT_LANDSCAPE_CONSTRUCTION), // CMD_LEVEL_LAND; test run might clear tiles multiple times, in execution that only happens once
diff --git a/src/command_type.h b/src/command_type.h
index 540421928..78e8c188e 100644
--- a/src/command_type.h
+++ b/src/command_type.h
@@ -271,6 +271,11 @@ enum Commands {
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_CREATE_STORY_PAGE, ///< create a new story page
+ CMD_CREATE_STORY_PAGE_ELEMENT, ///< create a new story page element
+ CMD_UPDATE_STORY_PAGE_ELEMENT, ///< update a story page element
+ CMD_SET_STORY_PAGE_TITLE, ///< update title of a story page
+ CMD_REMOVE_STORY_PAGE, ///< remove a story page
CMD_LEVEL_LAND, ///< level land
CMD_BUILD_LOCK, ///< build a lock
diff --git a/src/economy.cpp b/src/economy.cpp
index 7ae5daccb..552839192 100644
--- a/src/economy.cpp
+++ b/src/economy.cpp
@@ -46,6 +46,7 @@
#include "game/game.hpp"
#include "cargomonitor.h"
#include "goal_base.h"
+#include "story_base.h"
#include "table/strings.h"
#include "table/pricebase.h"
@@ -509,7 +510,7 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner)
if (si->owner == old_owner) si->owner = new_owner == INVALID_OWNER ? OWNER_NONE : new_owner;
}
- /* Remove Game Script created Goals and CargoMonitors. */
+ /* Remove Game Script created Goals, CargoMonitors and Story pages. */
Goal *g;
FOR_ALL_GOALS(g) {
if (g->company == old_owner) delete g;
@@ -518,6 +519,11 @@ void ChangeOwnershipOfCompanyItems(Owner old_owner, Owner new_owner)
ClearCargoPickupMonitoring(old_owner);
ClearCargoDeliveryMonitoring(old_owner);
+ StoryPage *sp;
+ FOR_ALL_STORY_PAGES(sp) {
+ if (sp->company == old_owner) delete sp;
+ }
+
/* Change colour of existing windows */
if (new_owner != INVALID_OWNER) ChangeWindowOwner(old_owner, new_owner);
diff --git a/src/game/game_instance.cpp b/src/game/game_instance.cpp
index df52ca91a..bd588e039 100644
--- a/src/game/game_instance.cpp
+++ b/src/game/game_instance.cpp
@@ -66,6 +66,7 @@
#include "../script/api/game/game_signlist.hpp.sq"
#include "../script/api/game/game_station.hpp.sq"
#include "../script/api/game/game_stationlist.hpp.sq"
+#include "../script/api/game/game_story_page.hpp.sq"
#include "../script/api/game/game_subsidy.hpp.sq"
#include "../script/api/game/game_subsidylist.hpp.sq"
#include "../script/api/game/game_testmode.hpp.sq"
@@ -169,6 +170,7 @@ void GameInstance::RegisterAPI()
SQGSStation_Register(this->engine);
SQGSStationList_Register(this->engine);
SQGSStationList_Vehicle_Register(this->engine);
+ SQGSStoryPage_Register(this->engine);
SQGSSubsidy_Register(this->engine);
SQGSSubsidyList_Register(this->engine);
SQGSTestMode_Register(this->engine);
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index 9a18c33d9..1e7a2f0e0 100644
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -419,6 +419,7 @@ extern const ChunkHandler _economy_chunk_handlers[];
extern const ChunkHandler _subsidy_chunk_handlers[];
extern const ChunkHandler _cargomonitor_chunk_handlers[];
extern const ChunkHandler _goal_chunk_handlers[];
+extern const ChunkHandler _story_page_chunk_handlers[];
extern const ChunkHandler _ai_chunk_handlers[];
extern const ChunkHandler _game_chunk_handlers[];
extern const ChunkHandler _animated_tile_chunk_handlers[];
@@ -449,6 +450,7 @@ static const ChunkHandler * const _chunk_handlers[] = {
_subsidy_chunk_handlers,
_cargomonitor_chunk_handlers,
_goal_chunk_handlers,
+ _story_page_chunk_handlers,
_engine_chunk_handlers,
_town_chunk_handlers,
_sign_chunk_handlers,
diff --git a/src/saveload/story_sl.cpp b/src/saveload/story_sl.cpp
new file mode 100644
index 000000000..fd2d142c2
--- /dev/null
+++ b/src/saveload/story_sl.cpp
@@ -0,0 +1,89 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * 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.
+ * 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.
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/** @file story_page_sl.cpp Code handling saving and loading of story pages */
+
+#include "../stdafx.h"
+#include "../story_base.h"
+
+#include "saveload.h"
+
+static const SaveLoad _story_page_elements_desc[] = {
+ SLE_VAR(StoryPageElement, sort_value, SLE_UINT16),
+ SLE_VAR(StoryPageElement, page, SLE_UINT16),
+ SLE_VAR(StoryPageElement, type, SLE_UINT16),
+ SLE_VAR(StoryPageElement, referenced_id, SLE_UINT32),
+ SLE_STR(StoryPageElement, text, SLE_STR | SLF_ALLOW_CONTROL, 0),
+ SLE_END()
+};
+
+static void Save_STORY_PAGE_ELEMENT()
+{
+ StoryPageElement *s;
+ FOR_ALL_STORY_PAGE_ELEMENTS(s) {
+ SlSetArrayIndex(s->index);
+ SlObject(s, _story_page_elements_desc);
+ }
+}
+
+static void Load_STORY_PAGE_ELEMENT()
+{
+ int index;
+ uint32 max_sort_value = 0;
+ while ((index = SlIterateArray()) != -1) {
+ StoryPageElement *s = new (index) StoryPageElement();
+ SlObject(s, _story_page_elements_desc);
+ if (s->sort_value > max_sort_value) {
+ max_sort_value = s->sort_value;
+ }
+ }
+ /* Update the next sort value, so that the next
+ * created page is shown after all existing pages.
+ */
+ _story_page_element_next_sort_value = max_sort_value + 1;
+}
+
+static const SaveLoad _story_pages_desc[] = {
+ SLE_VAR(StoryPage, sort_value, SLE_UINT16),
+ SLE_VAR(StoryPage, date, SLE_UINT32),
+ SLE_VAR(StoryPage, company, SLE_UINT16),
+ SLE_STR(StoryPage, title, SLE_STR | SLF_ALLOW_CONTROL, 0),
+ SLE_END()
+};
+
+static void Save_STORY_PAGE()
+{
+ StoryPage *s;
+ FOR_ALL_STORY_PAGES(s) {
+ SlSetArrayIndex(s->index);
+ SlObject(s, _story_pages_desc);
+ }
+}
+
+static void Load_STORY_PAGE()
+{
+ int index;
+ uint32 max_sort_value = 0;
+ while ((index = SlIterateArray()) != -1) {
+ StoryPage *s = new (index) StoryPage();
+ SlObject(s, _story_pages_desc);
+ if (s->sort_value > max_sort_value) {
+ max_sort_value = s->sort_value;
+ }
+ }
+ /* Update the next sort value, so that the next
+ * created page is shown after all existing pages.
+ */
+ _story_page_next_sort_value = max_sort_value + 1;
+}
+
+extern const ChunkHandler _story_page_chunk_handlers[] = {
+ { 'STPE', Save_STORY_PAGE_ELEMENT, Load_STORY_PAGE_ELEMENT, NULL, NULL, CH_ARRAY},
+ { 'STPA', Save_STORY_PAGE, Load_STORY_PAGE, NULL, NULL, CH_ARRAY | CH_LAST},
+};
diff --git a/src/script/api/game/game_story_page.hpp.sq b/src/script/api/game/game_story_page.hpp.sq
new file mode 100644
index 000000000..abc9500d1
--- /dev/null
+++ b/src/script/api/game/game_story_page.hpp.sq
@@ -0,0 +1,39 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * 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.
+ * 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.
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
+
+#include "../script_story_page.hpp"
+#include "../template/template_story_page.hpp.sq"
+
+
+template <> const char *GetClassName<ScriptStoryPage, ST_GS>() { return "GSStoryPage"; }
+
+void SQGSStoryPage_Register(Squirrel *engine)
+{
+ DefSQClass<ScriptStoryPage, ST_GS> SQGSStoryPage("GSStoryPage");
+ SQGSStoryPage.PreRegister(engine);
+ SQGSStoryPage.AddConstructor<void (ScriptStoryPage::*)(), 1>(engine, "x");
+
+ SQGSStoryPage.DefSQConst(engine, ScriptStoryPage::STORY_PAGE_INVALID, "STORY_PAGE_INVALID");
+ SQGSStoryPage.DefSQConst(engine, ScriptStoryPage::STORY_PAGE_ELEMENT_INVALID, "STORY_PAGE_ELEMENT_INVALID");
+ SQGSStoryPage.DefSQConst(engine, ScriptStoryPage::SPET_TEXT, "SPET_TEXT");
+ SQGSStoryPage.DefSQConst(engine, ScriptStoryPage::SPET_LOCATION, "SPET_LOCATION");
+ SQGSStoryPage.DefSQConst(engine, ScriptStoryPage::SPET_GOAL, "SPET_GOAL");
+
+ SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::IsValidStoryPage, "IsValidStoryPage", 2, ".i");
+ SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::IsValidStoryPageElement, "IsValidStoryPageElement", 2, ".i");
+ SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::New, "New", 3, ".i.");
+ SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::NewElement, "NewElement", 5, ".iii.");
+ SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::UpdateElement, "UpdateElement", 4, ".ii.");
+ SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::SetTitle, "SetTitle", 3, ".i.");
+ SQGSStoryPage.DefSQStaticMethod(engine, &ScriptStoryPage::Remove, "Remove", 2, ".i");
+
+ SQGSStoryPage.PostRegister(engine);
+}
diff --git a/src/script/api/script_object.cpp b/src/script/api/script_object.cpp
index 2852c4ae9..6615b58de 100644
--- a/src/script/api/script_object.cpp
+++ b/src/script/api/script_object.cpp
@@ -144,6 +144,8 @@ ScriptObject::ActiveInstance::~ActiveInstance()
SetNewSignID(_new_sign_id);
SetNewGroupID(_new_group_id);
SetNewGoalID(_new_goal_id);
+ SetNewStoryPageID(_new_story_page_id);
+ SetNewStoryPageElementID(_new_story_page_element_id);
}
/* static */ bool ScriptObject::GetLastCommandRes()
@@ -191,6 +193,26 @@ ScriptObject::ActiveInstance::~ActiveInstance()
return GetStorage()->new_goal_id;
}
+/* static */ void ScriptObject::SetNewStoryPageID(StoryPageID story_page_id)
+{
+ GetStorage()->new_story_page_id = story_page_id;
+}
+
+/* static */ GroupID ScriptObject::GetNewStoryPageID()
+{
+ return GetStorage()->new_story_page_id;
+}
+
+/* static */ void ScriptObject::SetNewStoryPageElementID(StoryPageElementID story_page_element_id)
+{
+ GetStorage()->new_story_page_element_id = story_page_element_id;
+}
+
+/* static */ GroupID ScriptObject::GetNewStoryPageElementID()
+{
+ return GetStorage()->new_story_page_element_id;
+}
+
/* static */ void ScriptObject::SetAllowDoCommand(bool allow)
{
GetStorage()->allow_do_command = allow;
diff --git a/src/script/api/script_object.hpp b/src/script/api/script_object.hpp
index a2631dd3d..482e76f66 100644
--- a/src/script/api/script_object.hpp
+++ b/src/script/api/script_object.hpp
@@ -167,6 +167,16 @@ protected:
static GoalID GetNewGoalID();
/**
+ * Get the latest stored new_story_page_id.
+ */
+ static StoryPageID GetNewStoryPageID();
+
+ /**
+ * Get the latest stored new_story_page_id.
+ */
+ static StoryPageID GetNewStoryPageElementID();
+
+ /**
* Store a allow_do_command per company.
* @param allow The new allow.
*/
@@ -266,6 +276,18 @@ private:
* @param goal_id The new GoalID.
*/
static void SetNewGoalID(GoalID goal_id);
+
+ /**
+ * Store a new_story_page_id per company.
+ * @param story_page_id The new StoryPageID.
+ */
+ static void SetNewStoryPageID(StoryPageID story_page_id);
+
+ /**
+ * Store a new_story_page_id per company.
+ * @param story_page_id The new StoryPageID.
+ */
+ static void SetNewStoryPageElementID(StoryPageElementID story_page_element_id);
};
#endif /* SCRIPT_OBJECT_HPP */
diff --git a/src/script/api/script_story_page.cpp b/src/script/api/script_story_page.cpp
new file mode 100644
index 000000000..e94bc0017
--- /dev/null
+++ b/src/script/api/script_story_page.cpp
@@ -0,0 +1,119 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * 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.
+ * 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.
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/** @file script_story_page.cpp Implementation of ScriptStoryPage. */
+
+#include "../../stdafx.h"
+#include "script_story_page.hpp"
+#include "script_error.hpp"
+#include "script_industry.hpp"
+#include "script_map.hpp"
+#include "script_town.hpp"
+#include "script_goal.hpp"
+#include "../script_instance.hpp"
+#include "../../story_base.h"
+#include "../../goal_base.h"
+#include "../../string_func.h"
+#include "../../tile_map.h"
+
+/* static */ bool ScriptStoryPage::IsValidStoryPage(StoryPageID story_page_id)
+{
+ return ::StoryPage::IsValidID(story_page_id);
+}
+
+/* static */ bool ScriptStoryPage::IsValidStoryPageElement(StoryPageElementID story_page_element_id)
+{
+ return ::StoryPageElement::IsValidID(story_page_element_id);
+}
+
+/* static */ ScriptStoryPage::StoryPageID ScriptStoryPage::New(ScriptCompany::CompanyID company, Text *title)
+{
+ CCountedPtr<Text> counter(title);
+
+ EnforcePrecondition(STORY_PAGE_INVALID, ScriptObject::GetCompany() == OWNER_DEITY);
+ EnforcePrecondition(STORY_PAGE_INVALID, company == ScriptCompany::COMPANY_INVALID || ScriptCompany::ResolveCompanyID(company) != ScriptCompany::COMPANY_INVALID);
+
+ uint8 c = company;
+ if (company == ScriptCompany::COMPANY_INVALID) c = INVALID_COMPANY;
+
+ if (!ScriptObject::DoCommand(0,
+ c,
+ 0,
+ CMD_CREATE_STORY_PAGE,
+ title != NULL? title->GetEncodedText() : NULL,
+ &ScriptInstance::DoCommandReturnStoryPageID)) return STORY_PAGE_INVALID;
+
+ /* In case of test-mode, we return StoryPageID 0 */
+ return (ScriptStoryPage::StoryPageID)0;
+}
+
+/* static */ ScriptStoryPage::StoryPageElementID ScriptStoryPage::NewElement(StoryPageID story_page_id, StoryPageElementType type, uint32 reference, Text *text)
+{
+ CCountedPtr<Text> counter(text);
+
+ EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, ScriptObject::GetCompany() == OWNER_DEITY);
+ EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, IsValidStoryPage(story_page_id));
+ EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, (type != SPET_TEXT && type != SPET_LOCATION) || (text != NULL && !StrEmpty(text->GetEncodedText())));
+ EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, type != SPET_LOCATION || ::IsValidTile(reference));
+ EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, type != SPET_GOAL || ScriptGoal::IsValidGoal((ScriptGoal::GoalID)reference));
+ EnforcePrecondition(STORY_PAGE_ELEMENT_INVALID, type != SPET_GOAL || !(StoryPage::Get(story_page_id)->company == INVALID_COMPANY && Goal::Get(reference)->company != INVALID_COMPANY));
+
+ if (!ScriptObject::DoCommand(type == SPET_LOCATION ? reference : 0,
+ story_page_id + (type << 16),
+ type == SPET_GOAL ? reference : 0,
+ CMD_CREATE_STORY_PAGE_ELEMENT,
+ type == SPET_TEXT || type == SPET_LOCATION ? text->GetEncodedText() : NULL,
+ &ScriptInstance::DoCommandReturnStoryPageElementID)) return STORY_PAGE_ELEMENT_INVALID;
+
+ /* In case of test-mode, we return StoryPageElementID 0 */
+ return (ScriptStoryPage::StoryPageElementID)0;
+}
+
+/* static */ bool ScriptStoryPage::UpdateElement(StoryPageElementID story_page_element_id, uint32 reference, Text *text)
+{
+ CCountedPtr<Text> counter(text);
+
+ EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
+ EnforcePrecondition(false, IsValidStoryPageElement(story_page_element_id));
+
+ StoryPageElement *pe = StoryPageElement::Get(story_page_element_id);
+ StoryPage *p = StoryPage::Get(pe->page);
+ ::StoryPageElementType type = pe->type;
+
+ EnforcePrecondition(false, (type != SPET_TEXT && type != SPET_LOCATION) || (text != NULL && !StrEmpty(text->GetEncodedText())));
+ EnforcePrecondition(false, type != SPET_LOCATION || ::IsValidTile(reference));
+ EnforcePrecondition(false, type != SPET_GOAL || ScriptGoal::IsValidGoal((ScriptGoal::GoalID)reference));
+ EnforcePrecondition(false, type != SPET_GOAL || !(p->company == INVALID_COMPANY && Goal::Get(reference)->company != INVALID_COMPANY));
+
+ return ScriptObject::DoCommand(type == SPET_LOCATION ? reference : 0,
+ pe->page,
+ type == SPET_GOAL ? reference : 0,
+ CMD_UPDATE_STORY_PAGE_ELEMENT,
+ type == SPET_TEXT || type == SPET_LOCATION ? text->GetEncodedText() : NULL,
+ &ScriptInstance::DoCommandReturnStoryPageElementID);
+}
+
+/* static */ bool ScriptStoryPage::SetTitle(StoryPageID story_page_id, Text *title)
+{
+ CCountedPtr<Text> counter(title);
+
+ EnforcePrecondition(false, IsValidStoryPage(story_page_id));
+ EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
+
+ return ScriptObject::DoCommand(0, story_page_id, 0, CMD_SET_STORY_PAGE_TITLE, title != NULL? title->GetEncodedText() : NULL);
+}
+
+/* static */ bool ScriptStoryPage::Remove(StoryPageID story_page_id)
+{
+ EnforcePrecondition(false, ScriptObject::GetCompany() == OWNER_DEITY);
+ EnforcePrecondition(false, IsValidStoryPage(story_page_id));
+
+ return ScriptObject::DoCommand(0, story_page_id, 0, CMD_REMOVE_STORY_PAGE);
+}
+
diff --git a/src/script/api/script_story_page.hpp b/src/script/api/script_story_page.hpp
new file mode 100644
index 000000000..b013f2515
--- /dev/null
+++ b/src/script/api/script_story_page.hpp
@@ -0,0 +1,142 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * 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.
+ * 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.
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/** @file script_story_page.hpp Everything to manipulate a story page. */
+
+#ifndef SCRIPT_STORY_HPP
+#define SCRIPT_STORY_HPP
+
+#include "script_company.hpp"
+#include "../../story_type.h"
+#include "../../story_base.h"
+
+/**
+ * Class that handles story page related functions.
+ *
+ * To create a page:
+ * 1. Create the page
+ * 2. Create page elements that will be appended to the page in the order which they are created.
+ *
+ * Pages can be either global or company specific. It is possible to mix, but the only mixed solution
+ * that will work is to have all global pages first. Once you create the first company specific page,
+ * it is not recommended to add additional global pages unless you clear up all pages first.
+ *
+ * Page elements are stacked vertically on a page. If goal elements are used, the element will
+ * become empty if the goal is removed while the page still exist. Instead of removing the goal,
+ * you can mark it as complete and the Story Book will show that the goal is completed.
+ *
+ * Mind that users might want to go back to old pages later on. Thus do not remove pages in
+ * the story book unless you really need to.
+ *
+ * @api game
+ */
+class ScriptStoryPage : public ScriptObject {
+public:
+ /**
+ * The story page IDs.
+ */
+ enum StoryPageID {
+ /* Note: these values represent part of the in-game StoryPageID enum */
+ STORY_PAGE_INVALID = ::INVALID_STORY_PAGE, ///< An invalid story page id.
+ };
+
+ /**
+ * The story page element IDs.
+ */
+ enum StoryPageElementID {
+ /* Note: these values represent part of the in-game StoryPageElementID enum */
+ STORY_PAGE_ELEMENT_INVALID = ::INVALID_STORY_PAGE_ELEMENT, ///< An invalid story page element id.
+ };
+
+ /**
+ * Story page element types.
+ */
+ enum StoryPageElementType {
+ SPET_TEXT = ::SPET_TEXT, ///< An element that displays a block of text.
+ SPET_LOCATION = ::SPET_LOCATION, ///< An element that displays a single line of text along with a button to view the referenced location.
+ SPET_GOAL = ::SPET_GOAL, ///< An element that displays a goal.
+ };
+
+ /**
+ * Check whether this is a valid story page ID.
+ * @param story_page_id The StoryPageID to check.
+ * @return True if and only if this story page is valid.
+ */
+ static bool IsValidStoryPage(StoryPageID story_page_id);
+
+ /**
+ * Check whether this is a valid story page element ID.
+ * @param story_page_element_id The StoryPageElementID to check.
+ * @return True if and only if this story page element is valid.
+ */
+ static bool IsValidStoryPageElement(StoryPageElementID story_page_element_id);
+
+ /**
+ * Create a new story page.
+ * @param company The company to create the story page for, or ScriptCompany::COMPANY_INVALID for all.
+ * @param title Page title (can be either a raw string, a ScriptText object, or null).
+ * @return The new StoryPageID, or STORY_INVALID if it failed.
+ * @pre No ScriptCompanyMode may be in scope.
+ * @pre company == COMPANY_INVALID || ResolveCompanyID(company) != COMPANY_INVALID.
+ */
+ static StoryPageID New(ScriptCompany::CompanyID company, Text *title);
+
+ /**
+ * Create a new story page element.
+ * @param story_page_id The page id of the story page which the page element should be appended to.
+ * @param type Which page element type to create.
+ * @param reference A reference value to the object that is refered to by some page element types. When type is SPET_GOAL, this is the goal ID. When type is SPET_LOCATION, this is the TileIndex.
+ * @param text The body text of page elements that allow custom text. (SPET_TEXT and SPET_LOCATION)
+ * @return The new StoryPageID, or STORY_INVALID if it failed.
+ * @pre No ScriptCompanyMode may be in scope.
+ * @pre IsValidStoryPage(story_page).
+ * @pre (type != SPET_TEXT && type != SPET_LOCATION) || (text != NULL && len(text) != 0).
+ * @pre type != SPET_LOCATION || ScriptMap::IsValidTile(reference).
+ * @pre type != SPET_GOAL || ScriptGoal::IsValidGoal(reference).
+ * @pre if type is SPET_GOAL and story_page is a global page, then referenced goal must be global.
+ */
+ static StoryPageElementID NewElement(StoryPageID story_page_id, StoryPageElementType type, uint32 reference, Text *text);
+
+ /**
+ * Update the content of a page element
+ * @param story_page_element_id The page id of the story page which the page element should be appended to.
+ * @param reference A reference value to the object that is refered to by some page element types. See also NewElement.
+ * @param text The body text of page elements that allow custom text. See also NewElement.
+ * @return The new StoryPageID, or STORY_INVALID if it failed.
+ * @pre No ScriptCompanyMode may be in scope.
+ * @pre IsValidStoryPage(story_page).
+ * @pre (type != SPET_TEXT && type != SPET_LOCATION) || (text != NULL && len(text) != 0).
+ * @pre type != SPET_LOCATION || ScriptMap::IsValidTile(reference).
+ * @pre type != SPET_GOAL || ScriptGoal::IsValidGoal(reference).
+ * @pre if type is SPET_GOAL and story_page is a global page, then referenced goal must be global.
+ */
+ static bool UpdateElement(StoryPageElementID story_page_element_id, uint32 reference, Text *text);
+
+ /**
+ * Update title of a story page. The title is shown in the page selector drop down.
+ * @param story_page_id The story page to update.
+ * @param title Page title (can be either a raw string, a ScriptText object, or null).
+ * @return True if the action succeeded.
+ * @pre No ScriptCompanyMode may be in scope.
+ * @pre IsValidStoryPage(story_page_id).
+ */
+ static bool SetTitle(StoryPageID story_page_id, Text *title);
+
+ /**
+ * Remove a story page from the list.
+ * @param story_page_id The story page to remove.
+ * @return True if the action succeeded.
+ * @pre No ScriptCompanyMode may be in scope.
+ * @pre IsValidStoryPage(story_page_id).
+ */
+ static bool Remove(StoryPageID story_page_id);
+};
+
+#endif /* SCRIPT_STORY_HPP */
+
diff --git a/src/script/api/script_types.hpp b/src/script/api/script_types.hpp
index d4b72ea80..d3ac70b4d 100644
--- a/src/script/api/script_types.hpp
+++ b/src/script/api/script_types.hpp
@@ -100,6 +100,8 @@ typedef uint16 SignID; ///< The ID of a sign.
typedef uint16 StationID; ///< The ID of a station.
typedef uint16 StringID; ///< The ID of a string.
typedef uint16 SubsidyID; ///< The ID of a subsidy.
+typedef uint16 StoryPageID; ///< The ID of a story page.
+typedef uint16 StoryPageElementID; ///< The ID of a story page element.
typedef uint32 TileIndex; ///< The ID of a tile (just named differently).
typedef uint16 TownID; ///< The ID of a town.
typedef uint32 VehicleID; ///< The ID of a vehicle.
diff --git a/src/script/api/template/template_story_page.hpp.sq b/src/script/api/template/template_story_page.hpp.sq
new file mode 100644
index 000000000..4c322a3ac
--- /dev/null
+++ b/src/script/api/template/template_story_page.hpp.sq
@@ -0,0 +1,29 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * 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.
+ * 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.
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/* THIS FILE IS AUTO-GENERATED; PLEASE DO NOT ALTER MANUALLY */
+
+#include "../script_story_page.hpp"
+
+namespace SQConvert {
+ /* Allow enums to be used as Squirrel parameters */
+ template <> inline ScriptStoryPage::StoryPageID GetParam(ForceType<ScriptStoryPage::StoryPageID>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptStoryPage::StoryPageID)tmp; }
+ template <> inline int Return<ScriptStoryPage::StoryPageID>(HSQUIRRELVM vm, ScriptStoryPage::StoryPageID res) { sq_pushinteger(vm, (int32)res); return 1; }
+ template <> inline ScriptStoryPage::StoryPageElementID GetParam(ForceType<ScriptStoryPage::StoryPageElementID>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptStoryPage::StoryPageElementID)tmp; }
+ template <> inline int Return<ScriptStoryPage::StoryPageElementID>(HSQUIRRELVM vm, ScriptStoryPage::StoryPageElementID res) { sq_pushinteger(vm, (int32)res); return 1; }
+ template <> inline ScriptStoryPage::StoryPageElementType GetParam(ForceType<ScriptStoryPage::StoryPageElementType>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptStoryPage::StoryPageElementType)tmp; }
+ template <> inline int Return<ScriptStoryPage::StoryPageElementType>(HSQUIRRELVM vm, ScriptStoryPage::StoryPageElementType res) { sq_pushinteger(vm, (int32)res); return 1; }
+
+ /* Allow ScriptStoryPage to be used as Squirrel parameter */
+ template <> inline ScriptStoryPage *GetParam(ForceType<ScriptStoryPage *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStoryPage *)instance; }
+ template <> inline ScriptStoryPage &GetParam(ForceType<ScriptStoryPage &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPage *)instance; }
+ template <> inline const ScriptStoryPage *GetParam(ForceType<const ScriptStoryPage *>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return (ScriptStoryPage *)instance; }
+ template <> inline const ScriptStoryPage &GetParam(ForceType<const ScriptStoryPage &>, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQUserPointer instance; sq_getinstanceup(vm, index, &instance, 0); return *(ScriptStoryPage *)instance; }
+ template <> inline int Return<ScriptStoryPage *>(HSQUIRRELVM vm, ScriptStoryPage *res) { if (res == NULL) { sq_pushnull(vm); return 1; } res->AddRef(); Squirrel::CreateClassInstanceVM(vm, "StoryPage", res, NULL, DefSQDestructorCallback<ScriptStoryPage>, true); return 1; }
+} // namespace SQConvert
diff --git a/src/script/script_instance.cpp b/src/script/script_instance.cpp
index 6a4471166..33a0c4d10 100644
--- a/src/script/script_instance.cpp
+++ b/src/script/script_instance.cpp
@@ -275,6 +275,16 @@ void ScriptInstance::CollectGarbage() const
instance->engine->InsertResult(ScriptObject::GetNewGoalID());
}
+/* static */ void ScriptInstance::DoCommandReturnStoryPageID(ScriptInstance *instance)
+{
+ instance->engine->InsertResult(ScriptObject::GetNewStoryPageID());
+}
+
+/* static */ void ScriptInstance::DoCommandReturnStoryPageElementID(ScriptInstance *instance)
+{
+ instance->engine->InsertResult(ScriptObject::GetNewStoryPageElementID());
+}
+
ScriptStorage *ScriptInstance::GetStorage()
{
return this->storage;
diff --git a/src/script/script_instance.hpp b/src/script/script_instance.hpp
index 2e7eb55cc..e6f3c64b2 100644
--- a/src/script/script_instance.hpp
+++ b/src/script/script_instance.hpp
@@ -108,6 +108,16 @@ public:
static void DoCommandReturnGoalID(ScriptInstance *instance);
/**
+ * Return a StoryPageID reply for a DoCommand.
+ */
+ static void DoCommandReturnStoryPageID(ScriptInstance *instance);
+
+ /**
+ * Return a StoryPageElementID reply for a DoCommand.
+ */
+ static void DoCommandReturnStoryPageElementID(ScriptInstance *instance);
+
+ /**
* Get the controller attached to the instance.
*/
class ScriptController *GetController() { return controller; }
diff --git a/src/script/script_storage.hpp b/src/script/script_storage.hpp
index 79de2de8f..50e2b8dd5 100644
--- a/src/script/script_storage.hpp
+++ b/src/script/script_storage.hpp
@@ -17,6 +17,7 @@
#include "../road_type.h"
#include "../group.h"
#include "../goal_type.h"
+#include "../story_type.h"
#include "table/strings.h"
#include <vector>
@@ -49,6 +50,8 @@ private:
SignID new_sign_id; ///< The ID of the new Sign.
GroupID new_group_id; ///< The ID of the new Group.
GoalID new_goal_id; ///< The ID of the new Goal.
+ StoryPageID new_story_page_id; ///< The ID of the new StoryPage.
+ StoryPageID new_story_page_element_id; ///< The ID of the new StoryPageElement.
std::vector<int> callback_value; ///< The values which need to survive a callback.
diff --git a/src/story.cpp b/src/story.cpp
new file mode 100644
index 000000000..3574cf525
--- /dev/null
+++ b/src/story.cpp
@@ -0,0 +1,271 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * 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.
+ * 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.
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/** @file story.cpp Handling of stories. */
+
+#include "stdafx.h"
+#include "story_base.h"
+#include "core/pool_func.hpp"
+#include "command_func.h"
+#include "company_base.h"
+#include "company_func.h"
+#include "string_func.h"
+#include "date_func.h"
+#include "tile_map.h"
+#include "goal_type.h"
+#include "goal_base.h"
+
+
+StoryPageElementID _new_story_page_element_id;
+StoryPageID _new_story_page_id;
+uint32 _story_page_element_next_sort_value;
+uint32 _story_page_next_sort_value;
+
+StoryPageElementPool _story_page_element_pool("StoryPageElement");
+StoryPagePool _story_page_pool("StoryPage");
+INSTANTIATE_POOL_METHODS(StoryPageElement)
+INSTANTIATE_POOL_METHODS(StoryPage)
+
+/**
+ * This helper for Create/Update PageElement Cmd procedure verifies if the page
+ * element parameters are correct for the given page element type.
+ * @param page_id The page id of the page which the page element (will) belong to
+ * @param type The type of the page element to create/update
+ * @param tile The tile parameter of the DoCommand proc
+ * @param reference The reference parameter of the DoCommand proc (p2)
+ * @param text The text parameter of the DoCommand proc
+ * @return true, if and only if the given parameters are valid for the given page elment type and page id.
+ */
+static bool VerifyElementContentParameters(uint32 page_id, StoryPageElementType type, TileIndex tile, uint32 reference, const char *text)
+{
+ switch (type) {
+ case SPET_TEXT:
+ if (StrEmpty(text)) return false;
+ break;
+ case SPET_LOCATION:
+ if (StrEmpty(text)) return false;
+ if (!IsValidTile(tile)) return false;
+ break;
+ case SPET_GOAL:
+ if (!Goal::IsValidID((GoalID)reference)) return false;
+ /* 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;
+ default:
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * This helper for Create/Update PageElement Cmd procedure updates a page
+ * element with new content data.
+ * @param pe The page element to update
+ * @param tile The tile parameter of the DoCommand proc
+ * @param reference The reference parameter of the DoCommand proc (p2)
+ * @param text The text parameter of the DoCommand proc
+ */
+static void UpdateElement(StoryPageElement &pe, TileIndex tile, uint32 reference, const char *text)
+{
+ switch (pe.type) {
+ case SPET_TEXT:
+ pe.text = strdup(text);
+ break;
+ case SPET_LOCATION:
+ pe.text = strdup(text);
+ pe.referenced_id = tile;
+ break;
+ case SPET_GOAL:
+ pe.referenced_id = (GoalID)reference;
+ break;
+ }
+}
+
+/**
+ * Create a new story page.
+ * @param tile unused.
+ * @param flags type of operation
+ * @param p1 various bitstuffed elements
+ * - p1 = (bit 0 - 7) - Company for which this story page belongs to.
+ * @param p2 unused.
+ * @param text Title of the story page. Null is allowed in wich case a generic page title is provided by OpenTTD.
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdCreateStoryPage(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+ if (!StoryPage::CanAllocateItem()) return CMD_ERROR;
+
+ CompanyID company = (CompanyID)GB(p1, 0, 8);
+
+ if (_current_company != OWNER_DEITY) return CMD_ERROR;
+ if (company != INVALID_COMPANY && !Company::IsValidID(company)) return CMD_ERROR;
+
+ if (flags & DC_EXEC) {
+ if (_story_page_pool.items == 0) {
+ /* Initialize the next sort value variable. */
+ _story_page_next_sort_value = 0;
+ }
+
+ StoryPage *s = new StoryPage();
+ s->sort_value = _story_page_next_sort_value;
+ s->date = _date;
+ s->company = company;
+ if (StrEmpty(text)) {
+ s->title = NULL;
+ } else {
+ s->title = strdup(text);
+ }
+
+ _new_story_page_id = s->index;
+ _story_page_next_sort_value++;
+ }
+
+ return CommandCost();
+}
+
+/**
+ * Create a new story page element.
+ * @param tile Tile location if it is a location page element, otherwise unused.
+ * @param flags type of operation
+ * @param p1 various bitstuffed elements
+ * - p1 = (bit 0 - 15) - The page which the element belongs to.
+ * (bit 16 - 31) - Page element type
+ * @param p2 Id of referenced object
+ * @param text Text content in case it is a text or location page element
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdCreateStoryPageElement(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+ if (!StoryPageElement::CanAllocateItem()) return CMD_ERROR;
+
+ StoryPageID page_id = (CompanyID)GB(p1, 0, 16);
+ StoryPageElementType type = (StoryPageElementType) GB(p1, 16, 16);
+
+ /* Allow at most 128 elements per page. */
+ uint16 element_count = 0;
+ StoryPageElement *iter;
+ FOR_ALL_STORY_PAGE_ELEMENTS(iter) {
+ if (iter->page == page_id) element_count++;
+ }
+ if (element_count >= 128) return CMD_ERROR;
+
+ if (_current_company != OWNER_DEITY) return CMD_ERROR;
+ if (!StoryPage::IsValidID(page_id)) return CMD_ERROR;
+ if (!VerifyElementContentParameters(page_id, type, tile, p2, text)) return CMD_ERROR;
+
+ if (flags & DC_EXEC) {
+ if (_story_page_element_pool.items == 0) {
+ /* Initialize the next sort value variable. */
+ _story_page_element_next_sort_value = 0;
+ }
+
+ StoryPageElement *pe = new StoryPageElement();
+ pe->sort_value = _story_page_element_next_sort_value;
+ pe->type = type;
+ pe->page = page_id;
+ UpdateElement(*pe, tile, p2, text);
+
+ _new_story_page_element_id = pe->index;
+ _story_page_element_next_sort_value++;
+ }
+
+ return CommandCost();
+}
+
+/**
+ * Update a new story page element.
+ * @param tile Tile location if it is a location page element, otherwise unused.
+ * @param flags type of operation
+ * @param p1 various bitstuffed elements
+ * - p1 = (bit 0 - 15) - The page element to update.
+ * (bit 16 - 31) - unused
+ * @param p2 Id of referenced object
+ * @param text Text content in case it is a text or location page element
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdUpdateStoryPageElement(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+ StoryPageElementID page_element_id = (StoryPageElementID)GB(p1, 0, 16);
+
+ if (_current_company != OWNER_DEITY) return CMD_ERROR;
+ if (!StoryPageElement::IsValidID(page_element_id)) return CMD_ERROR;
+
+ StoryPageElement *pe = StoryPageElement::Get(page_element_id);
+ StoryPageID page_id = pe->page;
+ StoryPageElementType type = pe->type;
+
+ if (!VerifyElementContentParameters(page_id, type, tile, p2, text)) return CMD_ERROR;
+
+ if (flags & DC_EXEC) {
+ UpdateElement(*pe, tile, p2, text);
+ }
+
+ return CommandCost();
+}
+
+/**
+ * Update title of a story page.
+ * @param tile unused.
+ * @param flags type of operation
+ * @param p1 StoryPageID to update.
+ * @param p2 unused
+ * @param text title text of the story page.
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdSetStoryPageTitle(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+ if (_current_company != OWNER_DEITY) return CMD_ERROR;
+ StoryPageID page_id = (StoryPageID)p1;
+ if (!StoryPage::IsValidID(page_id)) return CMD_ERROR;
+
+ if (flags & DC_EXEC) {
+ StoryPage *p = StoryPage::Get(page_id);
+ free(p->title);
+ if (StrEmpty(text)) {
+ p->title = NULL;
+ } else {
+ p->title = strdup(text);
+ }
+ }
+
+ return CommandCost();
+}
+
+/**
+ * Remove a story page and associated story page elements.
+ * @param tile unused.
+ * @param flags type of operation
+ * @param p1 StoryPageID to remove.
+ * @param p2 unused.
+ * @param text unused.
+ * @return the cost of this operation or an error
+ */
+CommandCost CmdRemoveStoryPage(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
+{
+ if (_current_company != OWNER_DEITY) return CMD_ERROR;
+ StoryPageID page_id = (StoryPageID)p1;
+ if (!StoryPage::IsValidID(page_id)) return CMD_ERROR;
+
+ if (flags & DC_EXEC) {
+ StoryPage *p = StoryPage::Get(page_id);
+
+ StoryPageElement *pe;
+ FOR_ALL_STORY_PAGE_ELEMENTS(pe) {
+ if (pe->page == p->index) {
+ delete pe;
+ }
+ }
+
+ delete p;
+ }
+
+ return CommandCost();
+}
+
diff --git a/src/story_base.h b/src/story_base.h
new file mode 100644
index 000000000..edb89db7a
--- /dev/null
+++ b/src/story_base.h
@@ -0,0 +1,85 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * 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.
+ * 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.
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/** @file story_base.h %StoryPage base class. */
+
+#ifndef STORY_BASE_H
+#define STORY_BASE_H
+
+#include "company_type.h"
+#include "story_type.h"
+#include "date_type.h"
+#include "core/pool_type.hpp"
+
+typedef Pool<StoryPageElement, StoryPageElementID, 64, 64000> StoryPageElementPool;
+typedef Pool<StoryPage, StoryPageID, 64, 64000> StoryPagePool;
+extern StoryPageElementPool _story_page_element_pool;
+extern StoryPagePool _story_page_pool;
+extern uint32 _story_page_element_next_sort_value;
+extern uint32 _story_page_next_sort_value;
+
+/*
+ * Each story page element is one of these types.
+ */
+enum StoryPageElementType {
+ SPET_TEXT, ///< A text element.
+ SPET_LOCATION, ///< An element that references a tile along with a one-line text.
+ SPET_GOAL, ///< An element that references a goal.
+};
+
+/**
+ * Struct about story page elements.
+ * Each StoryPage is composed of one or more page elements that provide
+ * page content. Each element only contain one type of content.
+ **/
+struct StoryPageElement : StoryPageElementPool::PoolItem<&_story_page_element_pool> {
+ uint32 sort_value; ///< A number that increases for every created story page element. Used for sorting. The id of a story page element is the pool index.
+ uint16 page; ///< Id of the page which the page element belongs to
+ StoryPageElementType type; ///< Type of page element
+
+ uint32 referenced_id; ///< Id of referenced object (location, goal etc.)
+ char *text; ///< Static content text of page element
+
+ /**
+ * We need an (empty) constructor so struct isn't zeroed (as C++ standard states)
+ */
+ inline StoryPageElement() { }
+
+ /**
+ * (Empty) destructor has to be defined else operator delete might be called with NULL parameter
+ */
+ inline ~StoryPageElement() { free(this->text); }
+};
+
+/** Struct about stories, current and completed */
+struct StoryPage : StoryPagePool::PoolItem<&_story_page_pool> {
+ uint32 sort_value; ///< A number that increases for every created story page. Used for sorting. The id of a story page is the pool index.
+ Date date; ///< Date when the page was created.
+ CompanyByte company; ///< StoryPage is for a specific company; INVALID_COMPANY if it is global
+
+ char *title; ///< Title of story page
+
+ /**
+ * We need an (empty) constructor so struct isn't zeroed (as C++ standard states)
+ */
+ inline StoryPage() { }
+
+ /**
+ * (Empty) destructor has to be defined else operator delete might be called with NULL parameter
+ */
+ inline ~StoryPage() { free(this->title); }
+};
+
+#define FOR_ALL_STORY_PAGE_ELEMENTS_FROM(var, start) FOR_ALL_ITEMS_FROM(StoryPageElement, story_page_element_index, var, start)
+#define FOR_ALL_STORY_PAGE_ELEMENTS(var) FOR_ALL_STORY_PAGE_ELEMENTS_FROM(var, 0)
+#define FOR_ALL_STORY_PAGES_FROM(var, start) FOR_ALL_ITEMS_FROM(StoryPage, story_page_index, var, start)
+#define FOR_ALL_STORY_PAGES(var) FOR_ALL_STORY_PAGES_FROM(var, 0)
+
+#endif /* STORY_BASE_H */
+
diff --git a/src/story_type.h b/src/story_type.h
new file mode 100644
index 000000000..392249da2
--- /dev/null
+++ b/src/story_type.h
@@ -0,0 +1,28 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * 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.
+ * 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.
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+/** @file story_type.h basic types related to story pages */
+
+#ifndef STORY_TYPE_H
+#define STORY_TYPE_H
+
+#include "core/enum_type.hpp"
+
+typedef uint16 StoryPageElementID; ///< ID of a story page element
+typedef uint16 StoryPageID; ///< ID of a story page
+struct StoryPageElement;
+struct StoryPage;
+
+extern StoryPageElementID _new_story_page_element_id;
+extern StoryPageID _new_story_page_id;
+static const StoryPageElementID INVALID_STORY_PAGE_ELEMENT = 0xFFFF; ///< Constant representing a non-existing story page element.
+static const StoryPageID INVALID_STORY_PAGE = 0xFFFF; ///< Constant representing a non-existing story page.
+
+#endif /* STORY_TYPE_H */
+