The Moldy Crow

TheCrow’s Nest

Dark Forces Unofficial Specifications v3.2

INF Files

INF files control the dynamic workings of a level. They are text files written in "The INF programming language".

INFs accept C like /* */ comments.

They are made up of item definitions, which are linked to the SCs via the SC names to the WLs via the SC names and WL number

INF File Format

Here is the header of the INF file:

|  INF 1.0
|  LEVELNAME SECBASE   
|
|  items 2

INF File version and level name, followed by total number of items in the file. Don't forget to change this value when you add or remove items in an INF.

Then follow the items:

Sector Item.

|  item: sector  name: secname   
|    seq
|     ........
|    seqend

Wall Item.

|  item: sector  name: secname  num: #wallnum   
|    seq
|     ........
|    seqend

etc.

See also item: level

Each item follows the same format, structured by the seq and seqend statements, between which the definitions are contained.

Note: More than one class statement is allowed per item.

INF Programming language

Each item (apart from an item: level) will have one or more classes. There are 3 types of classes:

elevators They dynamically modify sectors and walls triggers When triggered, they trigger something in their clients teleporter chute A very special item used to "fall" to another sector

Each class will have several variables that can be customized to change how the class functions.

Messages can be sent around a level to modify sectors, walls, and INF items.

There are a few special functions that can be executed: create an adjoin:, page: a sound, and display a text: message.

See also some new INF functions that weren't used in the original levels, but were found in DARK.EXE

INF item: level

This is used to play entire level ambient sounds. Quite useless, but it might be needed if you've got a level with lots of water, wind or machinery and it saves you from putting lots of sound objects all over the place.

This is never successfully used in the original levels. There is, however, a failed attempt in EXECUTOR.INF which is where I found out about it from.

usage:

| item: level
|  seq
|     amb_sound: [voc file] [num] [num]
|  seqend

I'm not sure what the 2 nums do, but including them seems to stop the sound from playing.

Class: Elevators

Elevators make sectors and walls dynamic. They can obviously be used to create lifts, platforms, doors etc., but you often also need dummy (i.e. non-accessible) elevators for level control purposes.

Elevators will usually have stops, which are different values the elevator can arrive at.

Elevators may also have slaves copying their actions.

Here are the elevator classes: elevator changelight elevator basic elevator inv elevator movefloor elevator moveceiling elevator movefc elevator scrollfloor elevator scrollceiling elevator moveoffset elevator basicauto elevator changewalllight elevator morphmove1 elevator morphmove2 elevator morphspin1 elevator morphspin2 elevator movewall elevator rotatewall elevator scrollwall elevator door elevator doormid elevator door_inv

Class: Triggers

Triggers send a message to a client sector when triggered. They can be used to create switches, tripwires etc. Triggers can also be used to display text.

Note: if no message is specified, then the default message (m_trigger) will be sent to the client(s).

Here are the trigger classes: trigger standard trigger trigger switch1 trigger single trigger toggle

Class: Teleporter Chute

Teleporter chutes are a special class of their own. Their function is to teleport the player directly up or down to another sector.

Dark Forces teleporter chutes are not deliberate teleporters like in DOOM. They are usually not intended to be noticed, and are intended to make it look like the player has just fallen through a chute into a layer below, for example, in the Robotics Facility where you fall into the gas room, and Jabba's Ship where you fall into the area where you rescue Jan. These cases need to use teleporter chutes because it is impossible to use the same sector in both layers - its walls would need to be given double adjoins!

Because teleporter chutes send you to the same X and Z coordinates, the target sector MUST occupy the same physical space of the teleporter chute, or it may be possible to teleport outside of a sector. Of course your Y coordinate can change.

usage:

| class: teleporter chute
| target: [target sectorname]

INF Variables

Variables set how elevators and triggers function.

master: eventmask: event: entitymask: speed: start: center: angle: key: flags: sound: object_mask:

INF Messages

Messages are sent from triggers when they are triggered and elevators when they arrive at stops. They are sent to other triggers and elevators, and in some cases just regular sectors and lines (except message: lights, which is sent to the system). They do various things to their recipients. Messages are placed in the sequence of elevators and triggers.

Messages all have these general syntax:

(sent from an elevator)

| message: [stop number] [reciever] [message] [parameters]

(sent from a trigger)

| client: [reciever]
| message: [message] [parameters]
[receiver]  is the reciever of a message. Can be one of the following:
[sectorname] 				reciever is a sector
[sectorname([wallnum])] 		reciever is a wall
SYSTEM 				reciever is the SYSTEM (message: lights only)
[parameters] are parameters specific to the type of message.

Here are the messages:

mtrigger gotostop nextstop prevstop masteron masteroff clearbits setbits complete done wakeup lights

Remember that when you look at an INF file and you see something like :

| class: elevator eeeee
|  stop: 0
|   message: 0 mmmmm
|  stop: 1
|   message: 1 mmmmm

it's only a visual clue, and you could group all the messages in one place and in any order. Important : if you add a stop, you have to renumber !

Notes:

  • When a specific message is not specified, the default message is m_trigger.
  • When messages are sent from an elevator, they are sent when it ARRIVES at a stop.
  • For some reason, messages can't be sent from "terminate" or "complete" stops.

New INF Functions from Dark.exe

Elevators:

  • elevator move_offset
  • elevator basic_auto
  • elevator move_wall
  • elevator door_inv Variables:
  • object_mask: Special Functions:
  • texture:

Here are some INF keywords that were found in DARK.EXE but as yet are not understood. We would appreciate it if people could help work out these as they may be usable!

stopy: triggeraction: condition: enclosed mid entity_enter move:

INF Special Functions

adjoin:

Adjoins a line to another line when an elevator arrives at a stop, removing any adjoins it had with a previous line. This is required if you need a line to remove its adjoin with one line and adjoin with another line midway through a level. "Adjoin" is placed in an elevator's sequence.

For example, in level 6 (detention center), you may notice that the 2 main lifts have a door on each layer adjoined to it on the same line. Since a line cannot be adjoined to more than one other line at once, the following occurs: midway through moving up between 2 layers, the elevator move_floor arrives at a stop which it remains at for 0 seconds. At this stop, a line of the lift sector is adjoined to a line of the door sector on the layer above, at the same time removing its adjoin with a line of the door sector on the layer below. The lift's doors all appear to be directly on top of each other.

usage:

| adjoin: [stopnum] [sector1] [line1] [sector2] [line2]

page:

Plays a sound effect when an elevator arrives at a stop. "Page:" is placed in an elevator's sequence.

usage:

| page: [stopnum] [VOC file]

text:

Displays a text message from TEXT.MSG when a trigger is triggered. "Text:" is placed in a trigger's sequence.

usage:

| text: [text number in text.msg] 

client:

Used with triggers, client defines which sector(s) a message is sent to when the trigger is triggered.

usage:

| client: [client sectorname]

stop:

A stop is a value that an elevator can arrive at. This value varies depending on the class of elevator, and can be floor altitude, ceiling altitude, ambience, degrees etc. Stops can be used practically, such as different heights a lift stops at, or can be used purely for level control as elevators can also send a message, page a sound, or create an adjoin upon arriving at a stop.

Note: Elevators can have any number of stops. If no stops are given, the elevator will start at value 0 and keep increasing its value throughout the entire level. This may be appropriate for an "elevator scrollfloor", but not for an "elevator movefloor" !!!

Note: Door elevators should NOT be given stops. They will have automatic stops set depending on the altitudes of the floor and ceiling of their sector.

usage:

| stop: [value1] [value2]

The first value can be given in three ways:

| [num]	absolute stop
| @[num]	relative stop
| [sectorname]	equal the value of the sector [sectorname]

The second value can be given in 4 ways:

| [time]	time in sec that elevator remains at stop
| hold	elevator will remain at stop indefinitely
| terminate	elevator will stay at the stop permanently
| complete	mission will be complete when elev arrives at stop

slave:

A slave of an elevator will follow whatever the elevator does does. However, if relative stops are used, the slave may not necessarily have the exact same actions. For example, a sector with "elevator move_floor" may have a floor altitude of 0 and a slave of it may have a floor alt of 4. When the elevator moves to "stop: @5" the slave will move to altitude 9.

usage:

| slave: [slave sectorname]

texture:

(by Anthony Hall)

The texture: command's format is like this:

texture: [stopnum] [flag] [donor]

This command will copy the texturing from one specified sector to another one. It must be used in the INF entry of the sector that will be changed. [donor] is the sector to copy a texture from. The flag tells whether to copy ceiling to ceiling texture or floor to floor. If the flag starts with a letter then ceiling textures will be used. If it's a number then floors will be used.

I haven't been able to get it to work with walls or in trigger INF entries though.

Elevator Classes Descriptions

elevator change_light

Changes the AMBIENT of a sector, i.e. changes the light level in a sector.

Stop values are sector ambience.

elevator basic

Changes FLOOR ALTITUDE of a sector.

Stop values are the altitude of the floor.

elevator inv

Changes the CEILING ALTITUDE of a sector. Often used for making doors (as you can set Smart Object Reactions).

Stop values are the altitude of the ceiling.

elevator move_floor

Changes the FLOOR ALTITUDE of a sector. The difference from "elevator basic" is that the smart object flag does not affect this elevator.

Stop values are the altitude of the floor.

elevator move_ceiling

Changes the CEILING ALTITUDE of a sector. The difference from "elevator inv" is that the smart object flag does not affect this elevator.

Stop values are the altitude of the ceiling.

elevator move_fc

Changes both the FLOOR ALTITUDE and CEILING ALTITUDE of a sector, i.e. the floor and ceiling will move up and down together.

Stop values are the altitude of the floor.

elevator scroll_floor

Scrolls the floor texture of a sector. Player moves with the floor texture by default, but see the FLAGS variable.

Stop values are distances in pixels ( x by 8 to get distances in level geometry units).

elevator scroll_ceiling

Scrolls the ceiling texture of a sector.

Stop values are distances in pixels ( x by 8 to get distances in level geometry units).

elevator move_offset

Changes the SECOND ALTITUDE of a sector.

Stop values are second altitude.

elevator basic_auto

Changes the FLOOR ALTITUDE of a sector, but returns to altitude 0 after cycling through all its stops. From there, its event needs to be triggered twice to move it to its first stop again. Otherwise, seems to be the same as elevator_basic.

Stop values are floor altitude.

elevator changewalllight

Changes the LIGHT of any walls in the sector with flag 1 bit 8 (allow change wall light), i.e. the relative light level of a wall to the sector will change.

Note: this elevator won't work if the sector's AMBIENT is 31, in the same way that the LIGHT field of walls won't work in the same case.

Stops values are wall light.

elevator morph_move1

Translates the VERTEX positions of any walls in the sector with flag 1 bit 32 (wall morph with sector). The entire wall will translate on the X-Z plane.

If the walls are adjoined, their mirrors also need to move so should also be set with flag 1 bit 32.

The PLAYER will by default not move with the walls. (but see the FLAGS variable).

Stop values are distances on the X-Z (horizontal) plane relative to the starting location of the wall.

elevator morph_move2

Same as elevator morph_move1 except the PLAYER will by default move relative to the walls if it is in the sector (but see the FLAGS variable).

elevator morph_spin1

Rotates the VERTEX positions of any walls in the sector with flag 1 bit 32 (wall morph with sector). The entire wall will rotate on the X-Z plane.

If the walls are adjoined, their mirrors also need to move so should also be set with flag 1 bit 32.

The PLAYER will by default not spin with the walls (but see the FLAGS variable).

Stop values are angles in degrees.

elevator morph_spin2

Same as elevator morph_spin1 except the PLAYER will spin relative to the walls if it is in the sector (but see the FLAGS variable).

elevator move_wall

This is the same as elevator morphmove1 except that it has a default eventmask of 0.

elevator rotate_wall

This is the same as elevator morphspin1 except that it has a default eventmask of 0.

elevator scroll_wall

Scrolls texture(s) of any walls in the sector with flag 1 bit 64/128/256/512 (allow scroll mid/top/bot/sign texture). Stop values are distances in pixels ( x by 8 to get distances in level geometry units)

elevator door

Instant door. Note, that it is easier to just use flag 1 bit 2 on a sector for an instant door. Elevator door is only really needed if you want to alter variables, for example, create a key door.

Stops and event_mask are set automatically - just make sure that the ceiling altitude of the sector is when the door is OPEN.

elevator door_mid

Instant 2 part door (opens upwards AND downwards). Information for the top and bottom parts are specified individually (so if you want to set a key, you have to set it to both halves of the door).

i.e.

| class: elevator door_mid
|  addon: 0
|  [info for the top part]
|  addon: 1
|  [info for the bottom part]

Stops and event_mask are set automatically - just make sure the floor and ceiling altitudes of the sector are of the door when it is OPEN.

elevator door_inv

A door that opens downwards. Otherwise, the same as any other door elevator.

Stops and event_mask are set automatically - just make sure that the floor altitude of the sector is when the door is OPEN.

flags:

Determines whether or not the player moves with a morphing or a horizontally scrolling elevator.

flag values ||| |--- |--- | |1 |Move on floor | |2 |Move on 2nd altitude |

These are bit values, so can be added (3) for moving on both the floor AND 2nd alt.

Note*: In FUELSTAT.INF (I think) you may find "flags: 7". This suggests that there is a value for 4 as well.

Note: In some places in the original levels, flags is set on vertically moving elevators like movefloor and movefc. I'm not sure whether this is a mistake, or if flags do something different here.

usage:

| flags: [value]

Also See Defaults Below

flag defaults

(elevs scroll_floor, morph_move2, morph_spin2)
| flags: 3

(elevs scroll_ceiling, morph_move1, morph_spin1, move_wall, rotate_wall)
| flags: 0

Note: all slaves will have flags set to 0.

Trigger Classes Descriptions

trigger standard

This can be applied to a sector (entering, leaving, nudging it etc.) or a line (crossing, nudging it etc.). Can't be used with switches, or you get a single vertical line where the sign should be.

trigger

Exactly the same as trigger standard as far as I know (maybe because trigger standard is the default trigger? So if there's a default trigger and a default message than what's the default elevator???)

trigger switch1

This is used specifically for switches. Remember, the wall containing the switch must have a sign which is a switch texture. When the switch is pressed, the first texture will change to the second texture in the multiple bm. The second texture can't be pressed - a message: done must be sent to change the switch back to the first texture. This can be done as many times as you like.

trigger single

This is a trigger that is used with switches. The switch can only be pressed ONCE. Once the switch is on its second texture, it will remain there even if a "message: done" is sent.

trigger toggle

This is a trigger that is used with switches. The switch can be pressed while showing either texture, so there's no need for "message: done".

Variables Descriptions

master:

Determines whether an elevator or trigger is able to function.

usage:

| master: on|off

Default:
| master: on

event_mask:

Determines what event will operate an elevator or trigger. The event, when carried out, will move an elevator to its next stop, or trigger a trigger.

event_mask values ||| |--- |--- | |1 |Cross line from front side | |2 |Cross line from back side | |4 |Enter sector | |8 |Leave sector | |16 |Nudge line from front side / Nudge sector from inside | |32 |Nudge line from back side / Nudge sector from outside | |64 |Explosion | |256 |Shoot or punch line (see entity_mask ) | |512 |Land on floor of sector |

(The above are bit values, so are added up when more than one are needed.)

* or -1 All bits set Custom values Triggered by triggers with an event: or by certain messages with the custom value as a parameter.

usage:

| event_mask: [value]

See Defaults Below

event_mask defaults

(elevs basic, inv, basic_auto)
| event_mask: 52
(elevs morph_move1, morph_move2, morph_spin1, morph_spin2)
| event_mask: 60
(other elevators)
| event_mask: 0
(all triggers)
| event_mask: *

event:

Creates a custom event value for a trigger. The trigger will then only affect an elevator class with this event value set in its event_mask. The custom value should be a bit value (i.e. a power of 2) so that it can be added with the other custom and preset bits (this works fine). LEC always uses 65536 onwards so I suggest you do this too. However, it seems that you do not HAVE to use a bit value because in EXECUTOR.INF LEC uses 2621444 (note the extra 4) and it works OK. But I don't suggest you do this.

Event: is needed with multi-class elevators or triggers where each class is controlled by a separate trigger. For example in the Research Facility (level 4), the sector called "Corecat" (spins around the Phrik metal) is two classes of elevator - elevator movefc and elevator morphspin2. Two switches control these classes individually. If the "event" variable was not used, both switches would move both classes of elevator to its next stop at the same time. Utilising the event variable, it is made possible to have one switch control the spinning and the other control the moving floor/ceiling.

usage:

| event: [value]

See Defaults

entity_mask:

Defines the entity that triggers a trigger

entity_mask values ||| |--- |--- | |1 |Enemy | |8 |Weapon | |2147483648 |Player |

(The above are bit values, so are added up when more than one are needed.)

* or -1 All bits set

Note: Enemies and weapons (laser bolts, rockets etc.) can enter and leave sectors and cross lines just like the PLAYER, but can't nudge or land on the floor. i.e. you can use entitymask values 1 and 8 with eventmask values 1, 2, 4 and 8 but NOT with 16, 32 and 512.

usage:

| entity_mask: [value]

Default:

| entity_mask: 2147483648

speed:

Determines the speed that an elevator moves between stops. If speed: 0 is set the elevator will move between stops instantaneously.

usage:

| speed: [value]

Default: Different for each type of elevator.

start:

Determines which stop an elevator starts at, right at the start of a level after it has loaded up.

usage:

| start: [stopnum]

Default:

| start: 0

center:

Used with rotating elevators, center defines the coordinates of the center of revolution.

usage:

| center: [x coord] [z coord]

Default:

| center: 0 0

angle:

Used with texture-scrolling or horizontally moving elevators, angle defines the direction in which the texture will scroll or the sector will move. For scrolling walls, angle: 0 is down. For scrolling floors, scrolling ceilings and moving sectors, angle: 0 is north.

usage:

| angle: [value in degrees]

Default:

| angle: 0

key:

Defines which key is needed to manually trigger the event of an elevator. Key is optional, of course.

usage:

| key: red|blue|yellow

flags:

Flags

sound:

Sets the sound effects of the elevator or trigger. Elevators have 3 sound effects - leaving a stop (1), moving between stops (2), and arriving at a stop (3). Triggers only have one sound - when triggered.

usage (elevators):

| sound: [sound value (1, 2 or 3)] [VOC file]

usage (triggers):

| sound: [VOC file]

Note: Setting "0" in place of [VOC file] makes the sound effect silent.

Also See Defaults Below

sound defaults

(elevs change_light, change_wall_light, scroll_floor, scroll_ceiling,  and scroll_wall)
| sound: 1 0
| sound: 2 0
| sound: 3 0

(elevs move_floor, move_fc, basic, basic_auto, change_offset,  door_inv and bottom half 
of door_mid)
| sound: 1 elev2-1.voc
| sound: 2 elev2-2.voc
| sound: 3 elev2-3.voc

(elevs move_ceiling, inv, morph_move1, morph_move2, morph_spin1,  morph_spin2, move_wall
, rotate_wall and top half of door_mid)
| sound: 1 door2-1.voc
| sound: 2 door2-2.voc
| sound: 3 door2-3.voc

(elevator door)
| sound: 1 door.voc
| sound: 2 0
| sound: 3 0

(trigger standard)
| sound: 0

(triggers switch1, single and toggle)
| sound: switch3.voc

object_mask:

This seems to work like eventmask when used with an elevator, and like entitymask when used with a trigger.

Messages Descriptions

m_trigger

Triggers the event of an elevator or trigger (no matter what its event_mask value is). An elevator will be moved to its next stop, and a trigger will be triggered.

Sent from an elevator.

Sent to a line trigger or sector trigger or an elevator.

Parameters:

[event value] --	optional -- the message will only be sent to the class with this event value set in its event_mask

goto_stop

Sends an elevator to a specified stop.

Sent from a trigger or an elevator.

Sent to an elevator.

Parameters:

[num]--	Stop number to send elevator to.

next_stop

Sends an elevator to its next stop.

Sent from an elevator or trigger.

Sent to an elevator.

Parameters:

[event value]	optional -- the message will only be sent to the class with this event value set in its event_mask

prev_stop

Sends an elevator to its previous stop.

Sent from an elevator or trigger.

Sent to an elevator.

Parameters:

[event value]	optional -- the message will only be sent to the class with this event value set in its event_mask

master_on

Turns an elevator's or trigger's master on. This message also turns on all generators in the recipient sector with "master: off" set in the .O file.

Sent from an elevator or trigger.

Sent to an elevator or trigger (or a normal sector with generators in it).

Parameters:

[event value]	optional -- the message will only be sent to the class with this event value set in its event_mask

master_off

Turns an elevator's or trigger's master off.

Sent from an elevator or trigger.

Sent to an elevator or trigger.

Parameters:

[event value]	optional -- the message will only be sent to the class with this event value set in its event_mask

clear_bits

Clears specified flag bits from a wall or sector. To clear more than one bit, add the bit values up that you want cleared.

Sent from a trigger or elevator.

Sent to a sector or wall.

Parameters:

[flagnum] --	flag number (1, 2 or 3)
[bitnum] --	bit value to clear

set_bits

Sets specified flag bits to a sector or wall. To set more than one bit, add up the bit values that you want to be set.

Sent from a trigger or elevator.

Sent to a sector or wall.

Parameters:

[flagnum] --	flag number (1, 2 or 3)
[bitnum] --	bit value to set

complete

Tells the GOL file that a trigger goal has been completed, updating the objective screen. Also moves recipient elevator to its next stop.

Sent from a trigger or an elevator.

Sent to an elevator (preferably to your "complete" elevator as it will also be moved one stop closer to its complete stop).

Parameters:

[num] --	refers to the "TRIG: [num]" in the GOL file. The corresponding goal in your PDA will then be shown to be complete (if your ANIM is done correctly, that is!!!)

done

Puts a switch on its first texture - it can be pressed again (UNLESS it is a trigger single).

Sent from an elevator.

Sent to a line trigger.

Parameters: none

wakeup

VUEs with "PAUSE: TRUE" will be played through once when this message is sent to the sector containing the 3DO object.

Sent from an elevator.

Sent to a sector.

Parameters: none

lights

Toggles the ambience of ALL sectors in the level between their original setting and the value of sector flag 3. Using sector flag 3 bits 1, 2, 4, 8, and 16 it is possible to make any ambient level from 0 to 31.

Sent from an elevator or trigger.

Sent to the SYSTEM (treat it like a sector with name "system", but make sure there are NO actual sectors called "system" anywhere in your level!

Parameters: none