Modding, Mission Design, and Coding > The FRED Workshop

Karajorma's Advanced FRED2 Lessons

(1/7) > >>

karajorma:
I remember saying to Cetanu after he posted his Advanced FRED tutorial that as soon as I had released a mission I'd make one of my own. Well it's rather embarrassing to have only been able to get around to it 4 years later but here goes.

Since Birth of a Legend from BtRL is about the only released mission I've made which is really complex I'll be using that as the example. I suppose I might cull a few things out of King of the Hill for another tutorial one day but that mission has much less advanced FREDding in it.

The original plan for the mission called for ships to be invisible over a certain distance away from the player. The distance would get smaller depending on the difficulty level you were playing on. This proved to be a complete nightmare as far as playability was concerned cause often enemy ships would wander off after your wingmen and you'd never be able to figure out where either of them were.

However once I had set up the idea of a decreasing distance within which things would happen I found it useful to keep it for other events in the mission. For some strange reason which was necessary at the time I took a very long and complicated method of setting up the distance in the mission. Here's how I should have done it.

Notice how the name of the variable starts with CONST. I frequently use this if I'm setting up a variable to be used as a constant in the rest of the mission. It's slightly naughty cause I'm actually altering the value of the constant but it's done at t=0 and it's never touched again. Why would you set up a variable as a constant I hear the non-programmers amongst you ask? Quite simply if I've got a value of 340 dotted throughout my mission the easiest way to change that later is with a search & replace in notepad. If instead I've used CONST-WeaponRange instead I only need to change the default value of the variable.

Avoiding problems with Gauntlet and Slingshot

One of the main ideas of the mission was that the two pilots Gauntlet and Slingshot would be on point duty but would run into Scar and quickly get out of their depth. The player was meant to be distracted in the meanwhile dealing with more Cylon Raiders. However there is always the chance that during the battle with the Raiders the player would stumble into Gauntlet and Slingshot and notice that they were quietly sitting there sending panicked messages. For this reason once the player is out of range of their wing both ships are transported way out of range of the player

Of course quite a lot had to be done to prevent them from further messing up the mission. Both ships are made stealthy and friendly stealthy, invisible (for good measure), are moved  1,000km away, given orders to play dead, given orders to remain silent and finally protected.

And I still suspect that one day I'll hear a bug report that one of the Cylon Raiders went after them. :D

Anti-Cheating

At one point in the mission the remainder of the players wing is meant to remain behind and guard a mining vessel. The player will head off to investigate a crippled fighter and end up in a 1 on 1 combat with the infamous Cylon ace Scar. The problem was that some method was needed of checking that the player didn't decide to bring his wingmen along with him to help out. However if the player was smart enough to lead Scar back to his wingmen he shouldn't be penalised for this even if the AI later decided to follow Scar away from the mining ship it should have been guarding.

The first thing to do was to check if the player was ordering his wingmen to follow him. This was done using the little used Order SEXP. In an event before this one the reset-orders SEXP was used to make sure that only orders given after the wingmen were told to remain behind were counted. (Don't bother looking for Reset-Orders in 3.6.9. It was only added after it came out. CVS builds and 3.6.10 will have it).

A similar event was needed for Blue 2 and Blue Wing (Different events were used cause the messages were different for Blue 2 and Blue 3).

If any of those events were triggered then a nasty trap was set for the player in the form of an additional wing of ships which would go after the mining vessel. However the trap wouldn't automatically spring shut. The player had to actually be guilty of getting his wingmen to abandon their duty. If he relented and sent them back to guard the miners the trap might be avoided.

First thing that had to be checked was if the player had dragged his wingmen too far away from the ship they were supposed to be guarding.

Notice the reappearance of that CONST variable? As you can see the harder the difficulty level you play on the shorter the distance you have to drag the wingmen away before they trigger the arrival of the extra wing of Raiders. Similar SEXPs were used to check for the same thing with Blue 3 or Blue wing.

Once Scar had arrived the player could order his wingmen to abandon their post and attack him directly. So this needed to be checked for too

Again the distance from the mining vessel was also checked as the second part of that AND SEXP to check that the player had dragged his wingmen out of range.

Now the entire event could be used as the arrival cue for the extra enemy wing.

Double Scars

One problem with the mission was that there were two possible ways to encounter Scar. If you chose to disobey Gauntlet's orders you could follow her and encounter Scar together with the other Raiders in his wing. If you obeyed her orders you would encounter him later on in the mission on his own in a completely different area of space.

This did raise a problem. There had to be two ships in the mission with the same name. Fortunately there is an old trick to get around this. Freespace can't display certain characters that FRED can. Therefore a ship named Fractalÿ4 will appear in-game as Fractal 4 but will be treated by FRED as a completely different ship. This allowed me to give the illusion of having a ship appear to be a member of a wing which didn't actually appear during that particular run through the mission.

Special music for Scar

A rather easy one this but Scar's appearance in the mission demanded the use of his own special theme tune from the show rather than the music that was being used for the rest of the mission.  Use of the change-soundtrack a little earlier on in the mission allowed Scar to appear with his own distinctive theme and leave the players who knew the shows soundtrack in little doubt just who they was facing.

karajorma:
Mission Banter

Banter presented a bit of a challenge. We had seven sets of mission banter, five of these were general chit-chat that could be played in any run through of the mission. The other two would only appear if the player had disobeyed orders in the previous mission and which one was played would be dependant on whether one of the player's wingmen (Chum) had survived the mission or not.
Furthermore in order to improve the replayability of the mission I didn't want any particular set of dialogue to repeat until all the sets that it was possible to hear for a mission had already been played once. I also wanted the system to be flexible in case a problem forced me to pull one of the sets of banter. Lastly I wanted the five standard sets to play in random order or else they'd also be predictable.

As you can imagine this was quite a tall order. The answer obviously required the use of player persistent variables as this was the only way to record which sets of dialogue had already been played. However setting, updating and selecting between seven different persistent variables if I used one for each would be a nightmare. It would be nice if I could store all the information on which messages had played in a single variable. In C you could do this using bitwise operations but I couldn't see any way to make that work in FRED. However there was a way to do something similar.

Take the first seven prime numbers as representatives for the seven different sets of banter (2,3,5,7,11,13,17) and multiply them together and store the result (510510) as the initial value of a variable. This variable can be used to which messages have now been played. If the value of the variable is divisible by 17 it means that the message that corresponds to number 17 (i.e the 7th message) hasn't been played yet. When a message was played I'd simply divide the variable by the prime number that corresponded to it and it would be struck off the list. Once the variable reached a value of 1 I'd know that everything had been played and I could reset the value. And checking whether the number was exactly divisible by another number is simple. I'd just use the mod SEXP.

Sound complicated? It was. But compared with the monster list of events to do it any other way it seemed simple. So it was time to code it.

First I needed a reset event. This was simple. All it had to do was reset the variable to my magic number whenever the variable reached a value of 1.

The next event would deal with the mission banter if this was the first run though the mission and the player had saved Chum. The use of the previous event and goal SEXPs allowed me to check what had happened in the previous mission (A persistent variable would have worked just as well). The next step is to check if the MessagesLeft variable is divisible by 2 (meaning that the set of banter dealing with Chum's survival hasn't been played). If it hasn't then two variables are set. ChooseBanter tells the game whether to keep trying to pick a set to play and SelectedBanter holds the prime number corresponding to the banter set we picked.

Then there was a corresponding event for if Chum had been killed. This was basically the same as the above event except that SelectedBanter was set to 3 instead of 2 if he had died.

The 4th event was designed to be triggered if the player had obeyed his orders in the previous missions. If MessagesLeft was divisible by 2 it meant that the Chum Lived and Chum died banter sets were still in play. This event removed them if the player shouldn't be hearing them by dividing the value of MessagesLeft by 6 (I had to divide by 2*3 because I wanted both messages removed. I could have divided by 2 then 3 of course).

The 5th event did the real work. This was the one that would pick one of the five main sets of banter at random. The five remaining primes are entered into a random-multiple-of list so that one is picked. The game checks if that banter has been played and if it finds one that hasn't it sets the SelectedBanter value to that number.
To be honest now that I look at it I don't think the string-to-int is needed and I probably should have set ChooseBanter to NO but since it doesn't hurt, who cares?

The remaining events dealt with actually playing the banter and were basically the same apart from the messages sent. First they would check what value SelectedBanter was currently set to. If the number corresponded to that events send-message-list then it would trigger.

First thing it would do is divide MessagesLeft to indicate that message had now been played. Then it would send the messages. Finally it would set a value for the PersonaActivation variable. This was because at the start of the game all the wingmen were silenced to stop them butting in with standard chat if the player decided to tell them to form on his wing. PersonaActivation simply held the length of this set of banter so a later event could turn them back on at the right time.

The only remaining issue was with the Chum Lives/Chum Dies banter playing events. These two are obviously mutually exclusive so instead of dividing MessagesLeft by 2 or 3 they divided it by 6 to mark both messages as unplayable and remove them from the list at the same time.

Okay, those are some of the more complex issues I faced while making the mission. Hope this stirs some ideas amongst the FREDders on this board.

The difference between the When and Every-Time SEXPs.

Goober5000:
Wow. :eek2:

Well done. :) :yes:

karajorma:
I'd always said I'd do something like this so I figured it was time.

Of course now I have to go off and come up with a bunch of new tricks. But that's the bit of FREDding I enjoy the most anyway. :D

jr2:
Hmm.  Bookmark.  :yes: