Author Topic: Continuing Karajorma's work on SEXP containers  (Read 6174 times)

0 Members and 1 Guest are viewing this topic.

Offline karajorma

  • King Louie - Jungle VIP
  • Administrator
  • 214
    • Karajorma's Freespace FAQ
Re: Continuing Karajorma's work on SEXP containers
Not a bug as such but something which could potentially become annoying for mission designers. Press 3 in the attached mission. The game will send a message which contains this syntax &TestMapContainers&Key 2&

The first time it does this, TestMapContainers exists and contains a key called Key 2. The mission then uses the remove-from-map SEXP to remove this entry and then sends the same message. The game then sends the following warning as expected.

Code: [Select]
Warning: sexp_replace_container_refs_with_values() found a container called TestMapContainers to replace but the modifer is not recognised
File: sexp.cpp
Line: 23938

However, clicking continue simply keeps bringing that message up again seeming forever. It really should only appear once and then bug out gracefully.

The problem seems to be that if the game can't replace the text it returns false immediately and lookHere is never updated. So the game keeps trying to replace the text in the same place instead of giving up and moving on.


EDIT: Line 710 seems to contain an error. It reads

Code: [Select]
{ "get-map-keys", OP_GET_MAP_KEYS, 2, 2, SEXP_ACTION_OPERATOR, }, // Karajormabut it should be
Code: [Select]
{ "get-map-keys", OP_GET_MAP_KEYS, 2, 3, SEXP_ACTION_OPERATOR, }, // KarajormaSo that you can use the optional argument.


EDIT 2: Similar to the first error. Sending a message which uses the contents of a container when the container is empty seems to also put the game into an infinite loop, this time with no error. I've attached a version of the mission that does that too. Press 4 to cause the error.

[attachment deleted to save space]
« Last Edit: March 28, 2021, 09:04:26 am by karajorma »
Karajorma's Freespace FAQ. It's almost like asking me yourself.

[ Diaspora ] - [ Seeds Of Rebellion ] - [ Mind Games ]

 

Offline jg18

  • A very happy zod
  • 210
  • can do more than spellcheck
Re: Continuing Karajorma's work on SEXP containers
Still working on the two bugs in the last post, but wanted to clarify some requirements:

First, I think a few of the new SEXPs should have their names/behaviors reconsidered:

  • "container-data-index" should be "list-data-index". Maps are unordered, so map keys/values don't have indices. Using this SEXP with a map should be an error.
  • "container-has-key" should be "map-has-key". Lists obviously don't have keys. Using this SEXP with a list should be an error.
  • I also think "container-has-data" should be "list-has-data". I don't understand how it's useful to check whether a map's values include certain values. Even if you know that some specific value/data is in the map, you don't know its associated key and thus can't retrieve it.

Thoughts?


Second, I'm unclear on which string comparisons are case-sensitive and which aren't.

From what I understand, these values are case-sensitive:
  • List data
  • Map keys

And these values are not case-sensitive:
  • Container names
  • List modifiers (EDIT: although it would make things easier if they were case-sensitive)

Is this right? Am I missing anything?

Thanks.
« Last Edit: April 01, 2021, 12:38:28 am by jg18 »

 

Offline karajorma

  • King Louie - Jungle VIP
  • Administrator
  • 214
    • Karajorma's Freespace FAQ
Re: Continuing Karajorma's work on SEXP containers
First, I think a few of the new SEXPs should have their names/behaviors reconsidered:

  • "container-data-index" should be "list-data-index". Maps are unordered, so map keys/values don't have indices. Using this SEXP with a map should be an error.
  • "container-has-key" should be "map-has-key". Lists obviously don't have keys. Using this SEXP with a list should be an error.

I'm fine with both of those changes.

Quote
I also think "container-has-data" should be "list-has-data". I don't understand how it's useful to check whether a map's values include certain values. Even if you know that some specific value/data is in the map, you don't know its associated key and thus can't retrieve it.

I disagree with this one though. At the moment the easiest way to iterate through a map is to

  • Export a list of keys to a list
  • Call the list in a second event which repeats
  • Test if the list is empty
  • Use string-equals to compare the data in map for list-remove-first

That will take one frame per key in your map and it requires the overhead of all the other checks needed to make it work. The SEXP I said I'd code to allow the exporting of a list to an argument list will cut down some of that overhead, but you're still going to have a lot of overhead. And sometimes, if the user needs that key that is what the user will have to do.

But sometimes the user might not want the key in this particular event. They might only care if the data is in the map. For instance, a map of surviving wingmen might not care what the key is, only that a certain wingman is alive. We might not need to manipulate the data itself in any way because what we're doing is having another character react to their situation. In cases like that, it seems silly to force the FREDder to roll all that stuff themselves when the SEXP already supports finding that info.

What I might suggest is that we split the SEXP into two SEXPs and map-has-data takes a second argument which is a string variable where we store the key name. I would include a message in the notes for container-has-data to use map-has-data if you need the key name, but otherwise leave it the same.


Quote
Second, I'm unclear on which string comparisons are case-sensitive and which aren't.

From what I understand, these values are case-sensitive:
  • List data
  • Map keys

And these values are not case-sensitive:
  • Container names
  • List modifiers (EDIT: although it would make things easier if they were case-sensitive)

Is this right? Am I missing anything?

Thanks.

That sounds about right. Of course I'm open to comment on if anyone would prefer it if anything was changed.
Karajorma's Freespace FAQ. It's almost like asking me yourself.

[ Diaspora ] - [ Seeds Of Rebellion ] - [ Mind Games ]

 

Offline jg18

  • A very happy zod
  • 210
  • can do more than spellcheck
Re: Continuing Karajorma's work on SEXP containers
Re: "container-has-data" and maps, ok, that's fair and makes sense. Interesting idea about the optional arg for map-has-data.

To sum up, what if we add these SEXPs?
  • list-has-data = like "container-has-data" for lists; returns true only when all of the data items specified are in the list
  • list-data-index = like "container-data-index" for lists; takes only one data item and returns the index of first occurrence, or -1 if not found
  • map-has-keys = like "container-has-key" for maps; returns true only when all of the strings specified are keys in the map. (Will this work if the map has numeric keys?)
  • map-has-data-item = checks if a single data item is the value associated with some key in the map. As you suggested, it'll takes an optional arg of a string variable to store the key if the data is found. If the data is not found, the SEXP returns false and the string variable (if provided) is left unchanged. I guess we could require a number variable if the map has numeric data, but maybe that's getting too complicated.

For "map-has-data-item", if multiple keys have the specified string as their data, which key is assigned to the variable (if provided) is arbitrary.

We'll then remove these SEXPs:
  • container-has-data
  • container-data-index
  • container-has-key

All other container SEXPs will remain unchanged.

The SEXP I said I'd code to allow the exporting of a list to an argument list [...]
Is that for-container? Or are you referring to something else?


Re: container names and list modifiers being case-insensitive, part of the reason I asked is that string comparisons for list modifiers are currently case-sensitive. I wasn't sure if that was intended behavior or a bug.

Can you create a test mission that includes checks that case-insensitive comparison works, both for SEXP usage and in text replacement and both for container names and for list modifiers?

 

Offline karajorma

  • King Louie - Jungle VIP
  • Administrator
  • 214
    • Karajorma's Freespace FAQ
Re: Continuing Karajorma's work on SEXP containers
Re: "container-has-data" and maps, ok, that's fair and makes sense. Interesting idea about the optional arg for map-has-data.

To sum up, what if we add these SEXPs?
  • list-has-data = like "container-has-data" for lists; returns true only when all of the data items specified are in the list
  • list-data-index = like "container-data-index" for lists; takes only one data item and returns the index of first occurrence, or -1 if not found
  • map-has-keys = like "container-has-key" for maps; returns true only when all of the strings specified are keys in the map. (Will this work if the map has numeric keys?)
  • map-has-data-item = checks if a single data item is the value associated with some key in the map. As you suggested, it'll takes an optional arg of a string variable to store the key if the data is found. If the data is not found, the SEXP returns false and the string variable (if provided) is left unchanged. I guess we could require a number variable if the map has numeric data, but maybe that's getting too complicated.

For "map-has-data-item", if multiple keys have the specified string as their data, which key is assigned to the variable (if provided) is arbitrary.

We'll then remove these SEXPs:
  • container-has-data
  • container-data-index
  • container-has-key

All other container SEXPs will remain unchanged.


I'm fine with that. We should add a note to the SEXP description that says the key given by map-has-data-item will be random (and code the SEXP so that it is actually random, not simply the first one).

When it comes to map-has-key with numeric keys, a FREDder might want to use the return value from a numeric SEXP so we might need to think a little about how to set that one up.

Quote
Is that for-container? Or are you referring to something else?

It is. I couldn't remember what I had called it on Discord.

Quote
Re: container names and list modifiers being case-insensitive, part of the reason I asked is that string comparisons for list modifiers are currently case-sensitive. I wasn't sure if that was intended behavior or a bug.

Can you create a test mission that includes checks that case-insensitive comparison works, both for SEXP usage and in text replacement and both for container names and for list modifiers?

Sure, I'll see if I can do that tonight.
Karajorma's Freespace FAQ. It's almost like asking me yourself.

[ Diaspora ] - [ Seeds Of Rebellion ] - [ Mind Games ]

 

Offline jg18

  • A very happy zod
  • 210
  • can do more than spellcheck
Re: Continuing Karajorma's work on SEXP containers
We should add a note to the SEXP description that says the key given by map-has-data-item will be random (and code the SEXP so that it is actually random, not simply the first one).
Notice that I didn't say "random"; I said arbitrary, as in, you get whatever you get, namely the key for the first matching entry found. I'd rather not add the complexity (and processing overhead) of doing truly at random, unless there's a clear use case for it.

When it comes to map-has-key with numeric keys, a FREDder might want to use the return value from a numeric SEXP so we might need to think a little about how to set that one up.
Ok, sure. Can you create a test mission that uses map-has-key this way? We can then fine-tune the syntax to fit how a FREDder would actually want to use it.

Also, I noticed you said "map-has-key". Should the SEXP accept only one key? Or should it be able to check any number of keys?


Finally, can we have a single map-has-key (or map-has-keys) SEXP and a single map-has-data-item SEXP that can work with either string keys or numeric keys (and, in the case of map-has-data-item, either string data or numeric data)? Can FRED support that type of flexibility?

 

Offline karajorma

  • King Louie - Jungle VIP
  • Administrator
  • 214
    • Karajorma's Freespace FAQ
Re: Continuing Karajorma's work on SEXP containers
Notice that I didn't say "random"; I said arbitrary, as in, you get whatever you get, namely the key for the first matching entry found. I'd rather not add the complexity (and processing overhead) of doing truly at random, unless there's a clear use case for it.

I think it would be useful to be able to return a random key. But probably not useful enough that it justifies the overhead of doing it in every case. If making it truly random later gets enough requests we can always change it without breaking correctly made missions since we said that the key it gave you was arbitrary it's the FREDders own fault for assuming that it wouldn't change.

Quote
Ok, sure. Can you create a test mission that uses map-has-key this way? We can then fine-tune the syntax to fit how a FREDder would actually want to use it.

Come to think about it, the player could always just use the int-to-string SEXP so it's probably smarter to let them do that than to complicate things with another SEXP. We only really need the string version.

Quote
Also, I noticed you said "map-has-key". Should the SEXP accept only one key? Or should it be able to check any number of keys?

It should check any number of keys. It's just that FRED tends to use the singular whenever a SEXP takes one or more arguments string-equals, -is-destroyed-delay, etc. so I've gotten into the habit of naming SEXPs that way.

Quote
Can you create a test mission that includes checks that case-insensitive comparison works, both for SEXP usage and in text replacement and both for container names and for list modifiers?

Attached


By the way, the Edit Containers dialog won't let me create a container with a space in it but I'm pretty sure the code does support that. I've certainly had no issues so far with the containers I created before that restriction was added. Of course, if it makes things easier to limit containers in this way, I have no objection. 

[attachment deleted to save space]
Karajorma's Freespace FAQ. It's almost like asking me yourself.

[ Diaspora ] - [ Seeds Of Rebellion ] - [ Mind Games ]

 

Offline jg18

  • A very happy zod
  • 210
  • can do more than spellcheck
Re: Continuing Karajorma's work on SEXP containers
Come to think about it, the player could always just use the int-to-string SEXP so it's probably smarter to let them do that than to complicate things with another SEXP. We only really need the string version.
Ok, good, so FRED supports type casting. That makes the list-has-data/map-has-key/map-has-data-item/list-data-index SEXPs easier to code, since the only type the SEXPs need to support is strings.


By the way, the Edit Containers dialog won't let me create a container with a space in it but I'm pretty sure the code does support that. I've certainly had no issues so far with the containers I created before that restriction was added. Of course, if it makes things easier to limit containers in this way, I have no objection.
As long as FSO/FRED can handle containers with spaces in their names without a problem, there's no reason to have that restriction, so I'll remove it.

In other news, I think I figured out the bug you reported about infinite loops in container reference text replacement. :) I'll test it in the morning.

 

Offline jg18

  • A very happy zod
  • 210
  • can do more than spellcheck
Re: Continuing Karajorma's work on SEXP containers
Builds in OP updated. AFAICT the issues you reported are fixed.

Spaces are now allowed in container names.

The SEXPs we discussed have been updated.

I also fixed an assertion failure in the edit containers dialog that occurred when you press Remove while nothing is selected.

With map-has-data-item, if the optional arg for the variable to hold the key is provided, we could check the type of the map key and compare it to the type of the variable, but I haven't done that type checking yet. Updating the variable with the key should work, though, but I haven't tested it.

I've also rebased against latest master.

 

Offline karajorma

  • King Louie - Jungle VIP
  • Administrator
  • 214
    • Karajorma's Freespace FAQ
Re: Continuing Karajorma's work on SEXP containers
Cool. I'll test that now.
Karajorma's Freespace FAQ. It's almost like asking me yourself.

[ Diaspora ] - [ Seeds Of Rebellion ] - [ Mind Games ]

 

Offline jg18

  • A very happy zod
  • 210
  • can do more than spellcheck
Re: Continuing Karajorma's work on SEXP containers
Next question: What should be the text length limits for container names, map keys, and container data?

The theoretical limit is 65 (2 * TOKEN_LENGTH + 1)  which is the largest string that will fit in sexp_list_item::text (including null char) and is already the max length allowed for variable names.

However, to ensure that multidimensionality is possible, the max data length must be at least 2 chars longer than the max container name length.

The simplest limits:

- 29 chars for container name (TOKEN_LENGTH -1 (null char) - 2 (leave space for enclosing &))
- 31 chars for map key and map/list data (TOKEN_LENGTH - 1)

I can find some ways to enforce these limits, e.g., through the text edit boxes in FRED's edit containers dialog.

Thoughts?
« Last Edit: April 09, 2021, 11:07:59 am by jg18 »

 

Offline karajorma

  • King Louie - Jungle VIP
  • Administrator
  • 214
    • Karajorma's Freespace FAQ
Re: Continuing Karajorma's work on SEXP containers
The only issue I'm worried about is if we end up with a situation where the data or key length is shorter than other arguments that people will try to use it for. For instance, if you name your map keys after ships and then have a ship with a 32 character name, it can't ever match the key.

I'm fine with whichever is easier to enforce.
Karajorma's Freespace FAQ. It's almost like asking me yourself.

[ Diaspora ] - [ Seeds Of Rebellion ] - [ Mind Games ]

 

Offline jg18

  • A very happy zod
  • 210
  • can do more than spellcheck
Re: Continuing Karajorma's work on SEXP containers
AFAICT 31 is the max length for ship names. A limit of 31 chars makes sense, because NAME_LENGTH is 32 chars and you need space for the terminating null char. :)

You can see the limit enforced in this line in CShipEditorDlg::DoDataExchange() in the FRED code:
Code: [Select]
DDV_MaxChars(pDX, m_ship_name, NAME_LENGTH - 1);

Sure enough, when I opened the ships editor in FRED and typed a ship name that was too long, I get a pop-up with "Enter no more than 31 characters."

 

Offline karajorma

  • King Louie - Jungle VIP
  • Administrator
  • 214
    • Karajorma's Freespace FAQ
Re: Continuing Karajorma's work on SEXP containers
Yeah. That does seem to make sense then.
Karajorma's Freespace FAQ. It's almost like asking me yourself.

[ Diaspora ] - [ Seeds Of Rebellion ] - [ Mind Games ]

 

Offline karajorma

  • King Louie - Jungle VIP
  • Administrator
  • 214
    • Karajorma's Freespace FAQ
Re: Continuing Karajorma's work on SEXP containers
Looks like the issue I said might be on my to-do list still is there, I just didn't remember it correctly. If you attempt to edit a container in a mission briefing nothing happens. I'm attaching a mission that has 4 pilots in the Traitors map. The first briefing stage has this SEXP in it.

perform-actions
-true
-remove-from-map
--Traitors
--Capricorn

That should remove Capricorn from the list. Yet when the briefing message is displayed the string &Traitors&Capricorn&Callsign& is still replaced with the callsign for Capricorn from the map with that name.

Briefing stage 2 and 3 are a test whether using the &BriefingPilotList&Remove_Random& syntax works and it does work correctly. Stage 2 should give you the names of the pilots except for Capricorn. Stage 3 should be nonsense since the list should now be empty. I suspect that removing Container_edits_off as we discussed might solve the problem so you might as well do that before running any tests.

[attachment deleted to save space]
« Last Edit: April 11, 2021, 12:04:29 am by karajorma »
Karajorma's Freespace FAQ. It's almost like asking me yourself.

[ Diaspora ] - [ Seeds Of Rebellion ] - [ Mind Games ]

 

Offline jg18

  • A very happy zod
  • 210
  • can do more than spellcheck
Re: Continuing Karajorma's work on SEXP containers
Turns out the issue isn't exactly a "bug" but more of a design choice.

Container text replacement for briefings was happening right after variable replacement, which is long before any briefing SEXPs are evaluated.

I moved container text replacement to take place for a given briefing stage after the stage's SEXPs are evaluated, and now the behavior is what you expected.

Note that there is a warning for Stage 1, because Capricorn is not in the Traitors map. The later failed replacements don't result in warnings because BriefingPilotList is empty at that point. We can add warnings for text replacement failures with empty maps/lists, if you'd like.

BTW, after replacement,  Stage 2 wingman names are Zodiac signs, since those are the keys of Traitors. :)

While I'm working on text replacement, are there any other cases where container replacement should happen at some point other than right after variable replacement? Debriefings, maybe, and presumably only if the debriefing stage is actually added?

I'll update the builds once these questions are sorted out.


EDIT: Also, could a FREDder reasonably want to use '&' in player-facing text? IF so, should we pick a different character to be the container delimiter? Maybe '@'? It would be ideal to avoid spurious warnings when running debug builds just because the FREDder wanted to use an '&' in in-game text.
« Last Edit: April 11, 2021, 05:12:07 pm by jg18 »

 

Offline karajorma

  • King Louie - Jungle VIP
  • Administrator
  • 214
    • Karajorma's Freespace FAQ
Re: Continuing Karajorma's work on SEXP containers
Yeah. I could see them using an "&" in-game now that I think about it. Wouldn't @ also be likely to cause issues? If any player thinks we're still using email in 200 years time they might have used that character too.


Turns out the issue isn't exactly a "bug" but more of a design choice.

Container text replacement for briefings was happening right after variable replacement, which is long before any briefing SEXPs are evaluated.

I moved container text replacement to take place for a given briefing stage after the stage's SEXPs are evaluated, and now the behavior is what you expected.

I did consider that as a possibility though. I originally added stages 2 & 3 to test for that. Stage 3 was originally just a repeat of Stage 2 without the perform actions. Unless ALL the briefing stages are created and only then do they evaluate to see if they are played or not stage 3 should have worked properly but it didn't (at least when I tried it). I'll test the behaviour once I have the builds and see what happens.

This does raise a question of whether the replacement for SEXP variables is also in the wrong place. If a briefing contains "We now still face $MyVariable$ Sathanases" and the briefing SEXP is

perform-actions
-previous-event-true
--Sathanas-Destroyed
-modify-variable
--MyVariable[10]
--- -
---MyVariable[10]
--- 1

I would expect the text displayed to change from "We now still face 10 Sathanases" to We now still face 9 Sathanases" if one was destroyed last mission. But from what you've said it sounds like we'd get the former message and only afterwards would the perform-actions be evaluated. Whatever we do with containers should be consistent with variables whenever possible. So I think it would be a good idea to get some other coders (especially Goober) to weigh in on this one.

Quote
Note that there is a warning for Stage 1, because Capricorn is not in the Traitors map. The later failed replacements don't result in warnings because BriefingPilotList is empty at that point. We can add warnings for text replacement failures with empty maps/lists, if you'd like.

Stage 3 (and 2 I think) should definitely result in warnings because of the attempts to use an empty array. As discussed yesterday, FREDders should run their missions through fast debug builds to catch errors like those. End Users don't need to worry about this sort of error so a warning is appropriate.

Quote
BTW, after replacement,  Stage 2 wingman names are Zodiac signs, since those are the keys of Traitors. :)

Yeah. I'd originally written that stage using the Traitors map and forgot I changed to a list.

Quote
While I'm working on text replacement, are there any other cases where container replacement should happen at some point other than right after variable replacement? Debriefings, maybe, and presumably only if the debriefing stage is actually added?

Pretty much anywhere SEXPs can be used in text should have replacement occur after evaluation. Debriefs, command briefs, fiction viewer, etc. I'm not sure if in those cases the replacement of variables happens then. So we might need to check those for the same possible issue briefings have.
« Last Edit: April 11, 2021, 11:53:26 pm by karajorma »
Karajorma's Freespace FAQ. It's almost like asking me yourself.

[ Diaspora ] - [ Seeds Of Rebellion ] - [ Mind Games ]

 

Offline Goober5000

  • HLP Loremaster
  • Moderator
  • 214
    • Goober5000 Productions
Re: Continuing Karajorma's work on SEXP containers
This is an interesting situation.  You're pushing the entire briefing system (text and SEXPs taken holistically) quite a bit farther than it was originally intended to go.  That's not a bad thing, though.

It seems reasonable that SEXP evaluation should take place before text replacement, as karajorma said.  Whether that means moving the SEXP evaluation earlier or the text replacement later might require deeper investigation.  My first reaction is to move the SEXP evaluation as early as possible because one could argue that the entire briefing context depends on it.  For example, future coders might add the ability to swap out the animation.

 

Offline jg18

  • A very happy zod
  • 210
  • can do more than spellcheck
Re: Continuing Karajorma's work on SEXP containers
Yeah. I could see them using an "&" in-game now that I think about it. Wouldn't @ also be likely to cause issues? If any player thinks we're still using email in 200 years time they might have used that character too.
True, and there are other less frequently used characters that might work, such as ` ^ and |. My vote among those is ^ because it's the easiest to get to on the keyboard and is near $ which FREDders are already used to using as a metacharacter.

This is an interesting situation.  You're pushing the entire briefing system (text and SEXPs taken holistically) quite a bit farther than it was originally intended to go.  That's not a bad thing, though.
Couldn't you say the same thing about practically every part of the engine/editor? :)

It seems reasonable that SEXP evaluation should take place before text replacement, as karajorma said.  Whether that means moving the SEXP evaluation earlier or the text replacement later might require deeper investigation.  My first reaction is to move the SEXP evaluation as early as possible because one could argue that the entire briefing context depends on it.  For example, future coders might add the ability to swap out the animation.
Yup, makes sense. It'll require a case-by-case investigation of the code for briefings, debriefings, fiction viewer, etc., though, to figure out where text replacement and SEXP evaluation should go. That sounds like a project of its own. I can look into starting a separate branch/PR to explore that for variables. I'll keep this task focused on containers.

 

Offline karajorma

  • King Louie - Jungle VIP
  • Administrator
  • 214
    • Karajorma's Freespace FAQ
Re: Continuing Karajorma's work on SEXP containers
Yep. I agree on the separate branch.

It seems reasonable that SEXP evaluation should take place before text replacement, as karajorma said.  Whether that means moving the SEXP evaluation earlier or the text replacement later might require deeper investigation.  My first reaction is to move the SEXP evaluation as early as possible because one could argue that the entire briefing context depends on it.  For example, future coders might add the ability to swap out the animation.

I'd tend to agree with that. A FREDder would probably assume that the first thing that is done is that the SEXP is evaluated to see if that briefing stage even plays in the first place and only after that is anything else for that stage dealt with. And that does seem like a perfectly reasonable assumption to make.

Hell, you could even make the argument that if that stage doesn't play, the game should move on to the next one. In cases where the briefing isn't being played, you definitely shouldn't be doing text replacement with containers since that can alter the contents of a container for a briefing stage the mission designer would expect to not be touched. So it might be an idea to deal with this issue first (in a separate branch of course) and then deal with containers.

But feel free to give me some new builds so I can make test missions for this.
Karajorma's Freespace FAQ. It's almost like asking me yourself.

[ Diaspora ] - [ Seeds Of Rebellion ] - [ Mind Games ]