Looking for an example of opening a story book

Discuss the new AI features ("NoAI") introduced into OpenTTD 0.7, allowing you to implement custom AIs, and the new Game Scripts available in OpenTTD 1.2 and higher.

Moderator: OpenTTD Developers

Post Reply
Rocko Bonaparte
Engineer
Engineer
Posts: 18
Joined: 13 Jan 2008 16:06

Looking for an example of opening a story book

Post by Rocko Bonaparte »

Per some discussion elsewhere, it was suggested a story book could give me an option to allow players to pause and unpause on my cooperative server. I'd like to take a swing at this but I can't find a working example of a script that would open when the story book icon is clicked. For that matter, I don't even know how to make the story book icon in the main bar clickable.

The code off the main Wiki is dead so I'm at a loss at what to use as a reference. I can pull down some promising script that does this kind of thing if somebody can refer one. I am not daunted by the scripting syntax but I'm lacking on all of the OpenTTD bindings to it so I'm pretty helpless doing anything with it without some reference.
User avatar
Firrel
Engineer
Engineer
Posts: 118
Joined: 13 Aug 2019 17:06

Re: Looking for an example of opening a story book

Post by Firrel »

Here is an example of creating and showing global story book page taken from RenewedVillageGrowth story.nut

Code: Select all

/* Issue an initial warning if game's cargo list doesn't match with settings. */
function StoryEditor::TownsWarningPage(num_towns)
{
    // Creating the page
    local sp_warning = this.NewStoryPage(GSCompany.COMPANY_INVALID, GSText(GSText.STR_SB_WARNING_TITLE));
    GSStoryPage.NewElement(sp_warning, GSStoryPage.SPET_TEXT, 0, GSText(GSText.STR_SB_WARNING_1, num_towns, SELF_MAX_TOWNS));
    GSStoryPage.Show(sp_warning);
}
Rocko Bonaparte
Engineer
Engineer
Posts: 18
Joined: 13 Jan 2008 16:06

Re: Looking for an example of opening a story book

Post by Rocko Bonaparte »

That's some useful stuff there. I'm assuming the story gets created in main.nut:

Code: Select all

    // Create and fill StoryBook. This can't be done before OTTD is ready.
    local story_editor = StoryEditor();
    story_editor.CreateStoryBook(this.towns.len());
Does that story book ungray the story book icon in the toolbar? I don't understand what plumbing has to happen to make it possible to make it open there. All the stories I've tried to run so far basically create popups and stuff but I want something I can trust people to be able to click on their clients. I could just try to install and run this one but I'm not in a spot where I can try it right away.

Edit: Also, nice concept. I'd roll it out on my buddies if I didn't think it would melt their brains more than I am already hahaha.
User avatar
Firrel
Engineer
Engineer
Posts: 118
Joined: 13 Aug 2019 17:06

Re: Looking for an example of opening a story book

Post by Firrel »

Check the reference documentation of GSStoryPage. There you can find all functions and their explanations.

static StoryPageID New (GSCompany::CompanyID company, Text *title)
- create new story page for a company/all with a title, this will also ungray the button, you can create multiple pages

static StoryPageElementID NewElement (StoryPageID story_page_id, StoryPageElementType type, uint32 reference, Text *text)
- add element to a story page, this is used to add content/text to a page, you can add multiple elements to a single page

static StoryPageButtonFormatting MakePushButtonReference (StoryPageButtonColour colour, StoryPageButtonFlags flags)
- add button to the story page which creates an event upon clicking and can be used for pause/unpause action
- use GSEventController to read events and check for GSEventStoryPageButtonClick event
Rocko Bonaparte
Engineer
Engineer
Posts: 18
Joined: 13 Jan 2008 16:06

Re: Looking for an example of opening a story book

Post by Rocko Bonaparte »

Thanks. That should finally give me enough length of rope to shoot myself in the foot! But at least I can now! :mrgreen:
User avatar
jfs
Tycoon
Tycoon
Posts: 1750
Joined: 08 Jan 2003 23:09
Location: Denmark

Re: Looking for an example of opening a story book

Post by jfs »

It's worth remembering that the story book is saved in the savegame, so when your GS reloads from a saved game, you need to either be able to resume from the saved story book, or delete all pages from the story book and re-create it.
Resuming from a saved story book basically involves keeping track of, or knowing, the page and element IDs in the script's save data.
Rocko Bonaparte
Engineer
Engineer
Posts: 18
Joined: 13 Jan 2008 16:06

Re: Looking for an example of opening a story book

Post by Rocko Bonaparte »

Are those button events actually some kind of callback-driven event or something I have to poll? My first glance made me think I had to implement an event receiver like I'd normally expect in a GUI toolkit, but this code here:

https://github.com/MinchinWeb/openttd-g ... r/main.nut

is polling the event controller:

Code: Select all

		if(GSEventController.IsEventWaiting())
		{
			local ev = GSEventController.GetNextEvent();
			local ev_type = ev.GetEventType();

			if(ev_type == GSEvent.ET_GOAL_QUESTION_ANSWER)
			{
				local click_event = GSEventGoalQuestionAnswer.Convert(ev);
				if(click_event.GetUniqueID() == questionUniqueId)
					return click_event.GetButton();
			}
		}
I saw a lot of polling in other code but I know that's something people typically do if they're not comfortable with callbacks. Well, I'm not much better in this language because I don't know how I connect to it.
Rocko Bonaparte
Engineer
Engineer
Posts: 18
Joined: 13 Jan 2008 16:06

Re: Looking for an example of opening a story book

Post by Rocko Bonaparte »

Regarding save state: if I'm having to save any state here then I've probably done something really wrong. I am basically present a pause button in the store and having it pause/resume when pressed. Presumably that should be stateless...
User avatar
jfs
Tycoon
Tycoon
Posts: 1750
Joined: 08 Jan 2003 23:09
Location: Denmark

Re: Looking for an example of opening a story book

Post by jfs »

Regarding polling:
The structure of a GS (and AI) is that it has a single "main" function that gets called when the script is started by the game, and this one function call lasts for the entire game. The game suspends execution of the script at certain times: When the script executes a command, which requires a simulation tick to execute. When the script calls the Delay function to request suspension for a number of ticks. And if the script runs out of execution time allotted for the current tick.
There are generally no callbacks, everything is synchronous and events are received by polling for them. You should not run the event polling in a tight loop, but make sure there is a Delay call between each poll for events. Basically the main loop of a script should look like: Poll events, perform planned actions, delay until next tick.

Regarding save state:
The script is started over when the game is loaded. In multiplayer, only the server runs the script, so this start-over only happens when the server loads the game.
If the first thing you do in the script is create a new story book page, unconditionally, then when the saved game is reloaded, the script will create a new story book page on top of the saved one, leaving you with two story book pages.
For that reason, you should at the very least store a flag in the script save data that the story book page has already been created and doesn't need to be created again.
Also consider the case of whether the script may need to support upgrades, i.e. a newer version that has more elements on pages, or more pages, and need to be able to upgrade an existing saved game's story book.

I hope this makes sense, it's a rather condensed explanation.
Rocko Bonaparte
Engineer
Engineer
Posts: 18
Joined: 13 Jan 2008 16:06

Re: Looking for an example of opening a story book

Post by Rocko Bonaparte »

This is some meatball garbage I'm coding and hopefully posting 61 lines of code is a no-no (I can use an online code sharing portal next time if it is). I don't know if this code works at all but this is the gist of what I see. I can't figure out how I should properly detect the button I'm creating and definitely not how to rediscover that on a game load for a story book that was previously connected.

Code: Select all

class MainClass extends GSController
{
	version = 1;
	loaded = false;
}

function MainClass::Start()
{
	if(!loaded)
	{
		local sp_pause = GSStoryPage.New(GSCompany.CompanyID.COMPANY_INVALID, "Cooperative Server Pause/Unpause");
		
		GSStoryPage.NewElement(sp_pause, GSStoryPage.SPET_TEXT, 0, "Cooperative Server Pause/Unpause Script");
	
		// I believe I need this ID to be certain with story button clicks that I'm getting the right one. I don't know how to rebind it on load.
		local pauseButtonId = GSStoryPage.NewElement(sp_pause, GSStoryPage.SPET_BUTTON_PUSH, GSStoryPage.MakePushButtonReference(GSStoryPage.SPBC_RED, GSStoryPage.SPBF_FLOAT_LEFT), "Pause Toggle");
	}
	else
	{
		// TODO: Need to bind to any existing, preloaded story if we're loading from a save in order to get pauseButtonId
	} 
	
	while(true)
	{
		if(GSEventController.IsEventWaiting())
		{
			local ev = GSEventController.GetNextEvent();
			local ev_type = ev.GetEventType();

			if(ev_type == GSEvent.ET_STORYPAGE_BUTTON_CLICK)
			{
				local button_event = GSEventStoryPageButtonClick.Convert(ev);
				if(click_event.GetElementID() == pauseButtonId)
				{
					if(GSGame.IsPaused())
					{
						GSGame.Unpause()	
					}
					else
					{
						GSGame.Pause()						
					}
				}
			}
		}

		this.Sleep(1);
	}	
}

function MainClass::Save() {
	local Save = {
		version = version,
	};
	return Save;
}

function MainClass::Load(version, data) {
	if ("version" in data) version = data.version;
	loaded = true;
}
User avatar
jfs
Tycoon
Tycoon
Posts: 1750
Joined: 08 Jan 2003 23:09
Location: Denmark

Re: Looking for an example of opening a story book

Post by jfs »

You can take a look at the IntroGameTool GS I wrote: https://github.com/nielsmh/IntroGameToo ... n.nut#L217

It has versioned pages with buttons, and saves/restores button id's.
Post Reply

Return to “OpenTTD AIs and Game Scripts”

Who is online

Users browsing this forum: No registered users and 2 guests