Larian Banner: Baldur's Gate Patch 9
Previous Thread
Next Thread
Print Thread
#581269 10/04/16 02:47 PM
Joined: Mar 2016
Location: Belgium
T
addict
OP Offline
addict
T
Joined: Mar 2016
Location: Belgium
Hi,

I'd like to share a WIP status of the Rails mod I'm working on. It is not a campaign or something that changes the main story, but rather something that can be used to add extra mechanics to other mods.

This mod allows you to lay down a track using objects and have any character (via an associated charScript) follow that track without having to place any triggers! The tracks, via their itemScripts, determine their connection points automatically when the level is loaded based on two external variables: their base size and their scale (because it appears you cannot query these properties inside an itemScript, or at least I haven't found the correct arguments to ItemGetStat() yet -- just the scaled size would be enough as well; I just split them so you don't have to manually calculate the result).

The only thing you have to do to set things in motion, is tell the track on which the train is located to put the train in motion. Everything else happens via item/charScripts (the train and the tracks communicate via events), no story scripting is involved.

You can see a short demo at http://divinity.watlock.be

Known issues:
• The turning is not very smooth. The reason is that it's done by calculating a couple of points in the turn and sequentially moving the train to those points. Ideally, a continuous RotateY() coupled to a constant "forward' movement would be used, but the game engine does not support that afaics.
• Since the train has to be a character (to be able to use CharacterMoveTo, since there is no ItemMoveTo), possibly derived from an item, it also moves like a character. E.g. if its path is blocked, it will happily move outside the track (although that could also be an advantage in case you'd use this not for a train, but e.g. for an animal or person following a road).
• Currently, the moving itself is done via an endless loop in which CharacterMoveTo() is called (the destinations are updated in parallel by a reaction to minimise pauses between different movement steps), but the game engine doesn't like this (it kills the loop after 500 iterations)

Some todos:
1) Write an itemScript for switches/road forks
2) Add support to the train charScript to pause and continue (I originally started working on this with the idea of implementing a quest with some kind of train heist)
3) Rework the way the train moves (the endless loop mentioned above), although it's hard without introducing jarring pauses
4) Remove the requirement for all tracks to be global. In principle, only the track on which the train initially is located needs to be global (to be able to send the "start moving" event from Osiris), but right now the event to tell the tracks to connect themselves (connection event) is also sent from Osiris: in their OnInit event, the tracks calculate their end point positions, and then during the connection event they query the positions of all other tracks in order to see which ones connect at which places. I should be able to move that to a behaviour instead (since those are guaranteed to run after the OnInit events).

Joined: Aug 2014
old hand
Offline
old hand
Joined: Aug 2014
Coolbeans! I might use that for something in the future.

Joined: Dec 2013
enthusiast
Offline
enthusiast
Joined: Dec 2013
Nice work Tinkerer!
(i think, lol.. /clueless)


Pride, honour and purity
Joined: Mar 2016
Location: Belgium
T
addict
OP Offline
addict
T
Joined: Mar 2016
Location: Belgium
I've made the following improvements in the mean time:
• No more choppy movement by sending events from the cart's charScript to the story, which then uses CharacterMoveToPosition(). The reason this works better is because that call returns immediately and you can queue multiple movements. So right now I make sure that always two movements are queued, so that the cart can still move while I calculate the next two positions.
• Support for (configurable) track switches. As an added advantage, there are no more infinite loops anymore that can get killed after a while, and the train can move faster without visual problems since there are no more short pauses at waypoints
• Updated the calculation of the waypoints for the turns to full 3D smile (slightly more accurate waypoints in turns on slopes)
• No need for the tracks to be global anymore

I uploaded a new movie (https now works too for the ssl-everywhere people wink ) that
• shows every waypoint of the cart as it gets queued using a light pillar. The colours indicate the index of the waypoint for that particular part of the track (by increasing index: red, white, orange, green, blue, purple)
• demonstrates that running over the same track in multiple directions in no problem
• shows some slopes. The terrain disappeared after the editor crashed at some point, so those tracks are just floating in the air now.

Joined: Aug 2014
old hand
Offline
old hand
Joined: Aug 2014
Looks WAY better now. Good work! Presumably this would work fine with non-cart objects using invisible tracks, too? Except you still need it to be a character so it has to be an AI grid... Just wondering if this would be possible with a boat.

Joined: Mar 2016
Location: Belgium
T
addict
OP Offline
addict
T
Joined: Mar 2016
Location: Belgium
Thanks!

Yes, any character on top of any kind of tracks can be handled. Well, at least if these tracks correspond to the kind of paths described by the rail tracks:
* a straight track of any length
* a 90 degree circular turn of any radius
* a switch consisting of a straight part and a 90 degree circular turn, whereby the turn's radius is 3/4 of the length of the straight part

Some of these properties could be parametrised, of course. And it's of course also possible to write additional itemScripts to calculate the connection points and waypoints of other tracks/shapes. There's a bunch of reusable infrastructure in the RAILS_ConnectedTrackBase.itemScript (via INCLUDE/USING)

Initially, the main reason it needed to be a character was because there is no ItemMoveTo() call in itemScripts. Now that the movement happens via the story anyway, I can use CharacterMoveToPosition() there.

There are a couple of extra caveats for items though:
• I will have to implement explicit rotations for the moving item in that case, since unlike a character, a moving item does not automatically orient itself to the target
• I make quite a bit of use of CharacterItemEvent() to send messages to the tracks that the cart (character) is on top of them (item). Since there's no ItemItemEvent(), I have to find another way to tell a track that it should update the cart's internal state to tell it where it should move to next
• I have to see how I can reuse as much code as possible from the track itemScripts for when the moving actor is a an item instead of a character (mainly CharacterSetVar() and CharacterEvent()

That said: if you want boats on the water, maybe plain triggers are actually easier? The main reason I created this was to avoid having to place tons of triggers on top of all of your track objects, so that you don't have to create the same path twice. And also to be able to visually design paths, and so that when you change the path you don't have to change both the visual path and the triggers.

Since you'd have an invisible path on the water, even the advantage of being able to visually design the path would be (largely?) lost. Well, maybe you could use regular cart tracks and then move them off-stage when the level gets loaded, but I'm not sure whether off-stage items can send and receive events. Or maybe you wanted to use a kind of track that's mostly transparent and then place it below the water?

Joined: Mar 2016
Location: Belgium
T
addict
OP Offline
addict
T
Joined: Mar 2016
Location: Belgium
One small (but rather important) correction:

Originally Posted by Tinkerer
Initially, the main reason it needed to be a character was because there is no ItemMoveTo() call in itemScripts. Now that the movement happens via the story anyway, I can use CharacterMoveToPosition() there.


The "CharacterMoveToPosition()" above should have read "ItemMoveToPosition()" obviously, but the bad news is that there is no ItemMoveToPosition() story call either. There's only ItemMoveToTrigger(), which rather defeats the whole concept...

On the flip side, ItemMoveToTrigger() does have a _UseRotation parameter, so manual rotating would probably not have been necessary after all should there have been an ItemMoveToPosition()

Joined: Mar 2016
Location: Belgium
T
addict
OP Offline
addict
T
Joined: Mar 2016
Location: Belgium
I'm happy to announce the first release of the Source on Rails mod, along with a small demo level that shows the basic concepts. Information, a demo movie and the mod itself can be gotten from http://divinity.watlock.be/sourceonrails/

There's almost no programming involved to use the mod's functionality. In fact, the only scripting code in the demo level is the following:
Code
IF
GlobalEventSet("RAILS_TracksConnected")
THEN
CharacterItemSetEvent(CHARACTER_SelfDrivingCart,ITEM_RAILS_MINE_Track_4m_Straight_A_008,"RAILS_SetNextTrack");

IF
CharacterItemEvent(_,_,"SourceOnRailsDemo_Pause")
THEN
CharacterSetEvent(CHARACTER_SelfDrivingCart,"RAILS_Pause");

IF
CharacterItemEvent(_,_,"SourceOnRailsDemo_Resume")
THEN
CharacterSetEvent(CHARACTER_SelfDrivingCart,"RAILS_Resume");

As an aside: the reason the signs indicating the settings of the track switches sometimes make a 270 degree turn rather than turning 90 degrees the other way, is that ItemRotateY() doesn't accept negative angles smile

The scripts and story code are extensively documented, so they may also be useful to people learning about the scripting system.

Finally, since trains by themselves are nice, but not particularly useful (except possibly for creating a train heist scenario/quest), I've already started on implementing the next step towards having full Transport Tycoon-style production chains in D:OS. Or, in other words: since crafting everyday items is often not the most interesting to do in CRPGs (has a nice reference to Larian/D:OS2 btw), why not have the characters in the game do it for you?

What already works in my Resources mod (which combines well with Source on Rails, but is independent from it):
  • • A planter/harvester that can plant and harvest stuff, and while the plants are growing also tends them. After harvesting, he can drop off the produce in a container or (if the container has been destroyed) on a platform
  • • Plants that grow smoothly! (well, some of them)
  • • A platform worker that loads the items the farmer drops off on a train (any character) that halts when it reaches the platform, and when finished tells the train it can leave (which it does)

The next steps are workers to unload trains (characters), and artisans to produce stuff based on availability (wheat -> flour, flour + water -> bread, wheat + water -> beer, ...).

It's sometimes a bit tricky due to having to spread things over char/itemScripts and the story due to missing functionality in one or the other, but I managed to resolve all problems I've encountered until now. I'll record and upload a movie tomorrow of the WIP. I'm very happy with my strolling wheat farmer smile


Link Copied to Clipboard
Powered by UBB.threads™ PHP Forum Software 7.7.5