Upcoming dock screen changes

This is a moderated forum that collects tutorials, guides, and references for creating Transcendence extensions and scripts.
Post Reply
george moromisato
Developer
Developer
Posts: 2997
Joined: Thu Jul 24, 2003 9:53 pm
Contact:

I've implemented a bunch of changes and enhancements to dock screens in 1.04 and I wanted to give you all a preview:

RENAMED TAGS AND FUNCTIONS
------------------------------------

In order to have a little more consistency, I've renamed some of the elements in dock screens.

The <OnInit> element for a screen has been renamed to <OnScreenInit>.
The <Initialize> element for a pane has been renamed to <OnPaneInit>.
The <Initialize> element for a display panel has been renamed to <OnDisplayInit>.

In all cases, the old names still work, so there is full compatibility with old mods. But new mods should start using the new names.

I've also deprecated the scrExitDock function and replaced it with a scrExitScreen function (for reasons described below).

NESTED SCREENS
-------------------

Imagine this example: You are creating a dock screen and you want one of your actions to show the looting screen. When looting is done, you want to return to your screen.

The current way of doing this is to create an action like this:

Code: Select all

<Action name="Loot" ...>
   (block Nil
      (setq gPrevScreen "MyDockScreen")
      (scrShowScreen gScreen &dsLoot;)
      )
</Action>
There is code inside of dsLoot that expects gPrevScreen to be set and returns back to it when looting is done. This works perfectly well, but it's a little cumbersome.

In 1.04 I've implemented a new attribute on <DockScreen>:

Code: Select all

<DockScreen UNID="&dsLoot;" nestedScreen="true">
...
The nestedScreen attribute on the destination screen tells the engine that this screen will be called from another screen and that we should remember where we came from.

Inside of dsLoot (the nested screen) an action can call:

(scrExitScreen gScreen)

The above will return to the original screen and pane that invoked the nested screen.

If the nested screen wants to force an undock (and not return to the original screen) it can call:

(scrExitScreen gScreen 'forceUndock)

Note that with this implementation, callers don't have to do anything special. They can still invoke a nested screen with scrShowScreen.

CHOOSING AN INITIAL SCREEN
----------------------------------

Today, a station can define its first screen using the dockScreen= attribute. But sometimes you want the first screen to change depending on circumstances. For example, if the ship is contaminated you might want to show the decontamination screen instead of the default one.

The old way to do that is to add an <OnScreenInit> (previously <OnInit>) on a dock screen and call scrShowScreen if you want to redirect to a different screen.

Again, this works well, but it is somewhat limiting.

1.04 adds a new event to stations (and ships with dock ports):

Code: Select all

<Events>
   <GetDockScreen>
      (switch
         {ship is radioactive}
            (list &dsDecontaminate; 10)
         
         {mission success}
            (list "MissionSuccess" 4)

         Nil
         )
   </GetDockScreen>
</Events>
The GetDockScreen event is called when the player docks with that station. It can return Nil to indicate that we should use the station's default screen. Or it can return a list where the first element is a dock screen and the second element is a positive number representing a priority (higher numbers are higher priorities).

[I'll describe how priorities work a little further down.]

As always, you can specify a dock screen as either an UNID (in which case we look for a global dock screen) or as a string, which makes the engine look for any dock screens contained by the station.

[Note that GetDockScreen (and all events that start with Get...) must NOT have any side-effects. That is, you can't make any assumptions about how many times it will get called or what will be done with the result. In particular, you cannot assume that the screen that you return will actually be shown, because it could be overridden later (see below).]

But GetDockScreen alone is not very interesting. The real power comes from having a global version of that event:

GetGlobalDockScreen

As you might imagine, GetGlobalDockScreen is an event that can be added to any type. It is called whenever the player docks with anything, and it is allowed to return a dock screen to show instead of the station's default screen.

For example, instead of having every commonwealth station check for a contaminated ship, we can now do this globally:

Code: Select all

<Sovereign UNID="&svCommonwealth;">
   <Events>
      <GetGlobalDockScreen>
         (if (and {we docked with a commonwealth station}
                   {ship is radioactive})
            (list &dsDecontaminate; 10)
            Nil
            )
      </GetGlobalDockScreen>
   </Events>
</Sovereign>
The above code will be called whenever the player docks with something. gSource will be set to the object that we docked with. The code checks to see if we docked with a Commonwealth station and if the ship is radioactive. If so, we ask to show the dsDecontaminate screen (with priority 10).

[Remember: As with all global events, the type that the event is attached to does NOT alter how the event is called. Although the event above is attached to the svCommonwealth sovereign, the event will be called regardless of what station we dock with--that's why we have to explicitly check to see if we've docked with a Commonwealth station.]

Perhaps you are starting to see why the priority field is necessary. There are now potentially multiple pieces of code telling us what screen to show:

1. Multiple types with a <GetGlobalDockScreen> could tell us to show different screens.
2. The station's <GetDockScreen> could tell us to show a particular screen.

To resolve this conflict we simply pick the screen with the highest priority. For example, if a station's <GetDockScreen> tells us to show the "MissionComplete" screen with priority 4, but a <GetGlobalDockScreen> tells us to show dsDecontaminate with priority 10, then we will show the dsDecontaminate screen.

Note: If the screen returned by <GetDockScreen> or <GetGlobalDockScreen> is a nestedScreen, then we will ask for a screen again when the nested screen exits. In the example above, if dsDecontaminate is a nested screen, then after it decontaminates the ship and exits, we call <GetDockScreen> and <GetGlobalDockScreen> again. This time, the "MissionComplete" screen wins, so we show that screen.

ADDING NEW ACTIONS
-------------------------

1.04 adds a new function:

Code: Select all

(scrAddAction gScreen actionID pos label [key] [special] code)
This function is designed to be called from inside <OnPaneInit> (previously <Initialize>) to dynamically add actions to a pane.

actionID is a string to identify the action (use it in calls like scrEnableAction).

pos is the position of the action. 0 inserts the action before all other actions; 1 inserts it after the first action, etc.

label is the label for the action.

key is the short-cut key for the action.

special can be either 'cancel, 'default, 'nextKey, or 'prevKey to set those short-cuts to the action.

code is the code to execute when the action is selected by the user.

Of course, the real use for this function is to add new actions to existing screen. The OnGlobalPaneInit event allows you to do that:

Code: Select all

<Events>
   <OnGlobalPaneInit>
      ; aScreenUNID is the UNID of the screen being shown
      ; aScreen is the screen name (if this is a local screen)
      ; aPane is the pane being shown
      (if (and (eq aScreenUNID &dsShipInterior;) (eq aPane "Default"))
         (scrAddAction 
            gScreen
            'myNewAction
            3
            "Do something cool"
            {some code}
            )
          )
   </OnGlobalPaneInit>
</Events>
The above event is called whenever a pane on any screen is initialized. In this case, it checks to see if this is the default pane for the ship's status screen. If so, it inserts a new action.

This technique will allow multiple mods to add entries to the ship's status screen without having to override the whole screen.

Of course, the usual limits for the number of actions per pane still applies.

NEW ATTRIBUTES
--------------------

In 1.04 I've converted many stations to use the new techniques above. I'm using attributes on a station to determine which screens to invoke. If you are creating (e.g.,) new Commonwealth stations, you should use the following attributes instead of the intCommonwealthOnInit function. Search the XMLs for <GetGlobalDockScreen> to see how these are used.

Any station with the "blackMarket" attribute will refuse docking unless you have a Black Market ID and will check for debts to the Black Market.

Any station with the "commonwealthCustoms" attribute will check for contamination, slaves, contraband, etc.

Any station with the "corporateCustoms" attribute will check for contamination and crimes against the Corporate Hierarchy. If a station has the "corporateDecon" attribute, then the player will be decontaminated (otherwise, docking will be refused).

Any station with the "commonwealthFleet" attribute will check for Fleet crimes, etc.

Any station with the "ringers" attribute will check for crimes against the Ringers.

Any station with the "sistersOfDomina" attribute will check for contamination.

COMPATIBILITY
------------------

The new mechanics introduce in 1.04 should not break any mods, but some other changes to Transcendence.xml might cause some problems.

In particular, I've migrated many of the special screens (such as decontamination) that used to be called in <OnScreenInit> to use <GetGlobalDockScreen>.

In many cases, functions like intCommonwealtOnInit have been removed, because they were no longer needed. If your mod relied on those functions, then you should either make your own copy or migrate to the new techniques.

Of course, none of the new techniques will work on version 1.0. Starting in 1.04 the engine will accept extensions marked as version "1.1". If you have an extension that requires 1.04 or higher, then you should mark it as "1.1" (because this is part of the 1.1 stream).
User avatar
alterecco
Fleet Officer
Fleet Officer
Posts: 1658
Joined: Wed Jan 14, 2009 3:08 am
Location: Previously enslaved by the Iocrym

This is very nice! I look forward to playing with it, once 1.04 hits the street.

The global events look particularly nice!
You have no worries about lag in OnGlobalPaneInit? As far as I recall, OnPaneInit is called for every cursor movement in a CustomPicker list. Is that the case with the global as well? I hope you don't change that behaviour, as it leads to some really nice dynamic screens.

Any chance of getting scrSetDefaultAction / scrSetCancelAction?
Perhaps I can use scrAddAction and screens with no predefined actions instead?
george moromisato
Developer
Developer
Posts: 2997
Joined: Thu Jul 24, 2003 9:53 pm
Contact:

alterecco wrote:This is very nice! I look forward to playing with it, once 1.04 hits the street.

The global events look particularly nice!
You have no worries about lag in OnGlobalPaneInit? As far as I recall, OnPaneInit is called for every cursor movement in a CustomPicker list. Is that the case with the global as well? I hope you don't change that behaviour, as it leads to some really nice dynamic screens.

Any chance of getting scrSetDefaultAction / scrSetCancelAction?
Perhaps I can use scrAddAction and screens with no predefined actions instead?
Cool--I was definitely thinking about DSF when creating this.

You are right that OnGlobalPaneInit will get called every time a list item is displayed. I don't think there will be performance problems as long as there are a small number of overrides (around a dozen). But I haven't tried any limit testing, so perhaps someone will experiment and let us know.

I have also enhanced the scrSetActionLabel function. It now takes a fifth parameter that can specify one of the following:

Nil: Removes any special shortcuts from the action.

'cancel: Makes the action the cancel action.
'default: Makes the action the default action.
'nextKey: Right-arrow key is a shortcut for this action.
'prevKey: Left-arrow key is a shortcut fo this action.

List: A list of any of the above keywords specifies a combination of shortcuts. E.g., (list 'cancel 'default) marks the action as both the cancel and the default action.
User avatar
Star Weaver
Militia Commander
Militia Commander
Posts: 311
Joined: Sun Nov 07, 2010 10:20 pm
Location: . . . between the stars and the warm black sky . . .

Hm, would it be possible to have a dockable object which doesn't have a dockscreen="foo", or a GetDockscreen event, but is only covered by the GlobalGetDockscreen event?

I'm curious because I have a very long list of dockable ships here that should all have identical GetDockscreens, and I'd like to minimize duplication :).

Oh, and one more thought: could we have a global gPlayershipScreen, which points to whichever dockscreen UNID the ship uses? When I get to making custom playerships, I'd like to create custom interior graphics for the main dockscreen, but I still want functionality from mods to show up there.

Also: awesome
Jeoshua
Militia Lieutenant
Militia Lieutenant
Posts: 163
Joined: Sat Sep 06, 2008 3:48 pm

I'm curious because I have a very long list of dockable ships here that should all have identical GetDockscreens, and I'd like to minimize duplication .
:twisted: [/quote]
User avatar
Prophet
Militia Captain
Militia Captain
Posts: 826
Joined: Tue Nov 18, 2008 6:09 pm

Very nice!
This looks like an amazing addition and very much look forward to playing with it.

This will make missions much more interesting by allowing us to use virtually any object with dockingports!

Would it be terrible difficult to add a scrGetActions function?
(scrGetActions screen pane (pos)) -> (list '(pos label key special code) (actionN+1) )

This would allow us to query a screen and add/remove/modify existing actions. We could even store actions beyond 7 to be displayed later or hijack an existing action to change its code dynamically.
Coming soon: The Syrtian War adventure mod!
A Turret defense genre mod exploring the worst era in Earth's history.
Can you defend the Earth from the Syrtian invaders?
Stay tuned for updates!
relanat
Militia Captain
Militia Captain
Posts: 941
Joined: Tue Nov 05, 2013 9:56 am

Big necro bump from 2010. Info on dockscreen changes in Version 1.04.

Lots of info in the OP that I would have loved to know a couple of months ago.
Beautifully explained by George.

Yes, some of it may be deprecated but in the abscence of any other more recent dockscreen info, "sometime you gotta dance with who brung ya".
Stupid code. Do what I want, not what I typed in!
RPC
Fleet Admiral
Fleet Admiral
Posts: 2876
Joined: Thu Feb 03, 2011 5:21 am
Location: Hmm... I'm confused. Anybody have a starmap to the Core?

Good point. Most of the info is still relevant so I'm moving it to Modding Resources so it doesn't get lost.
Tutorial List on the Wiki and Installing Mods
Get on Discord for mod help and general chat
Image
Image
Der Tod ist der zeitlose Frieden und das leben ist der Krieg
Wir müssen wissen — wir werden wissen!
I don't want any sort of copyright on my Transcendence mods. Feel free to take/modify whatever you want.
gunship256
Militia Commander
Militia Commander
Posts: 451
Joined: Sat Jul 25, 2015 11:41 pm
Location: repairing armor

It might also be helpful to sticky this thread unless there's a more recent one that goes over the same material.
RPC
Fleet Admiral
Fleet Admiral
Posts: 2876
Joined: Thu Feb 03, 2011 5:21 am
Location: Hmm... I'm confused. Anybody have a starmap to the Core?

All right, stickied. Technically I should find a way to just redo this and Periculi's thread but aaaahhhhhh so much to write.
Tutorial List on the Wiki and Installing Mods
Get on Discord for mod help and general chat
Image
Image
Der Tod ist der zeitlose Frieden und das leben ist der Krieg
Wir müssen wissen — wir werden wissen!
I don't want any sort of copyright on my Transcendence mods. Feel free to take/modify whatever you want.
Post Reply