From c068f22329d5cc722622a2183bbb22eef2093df7 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Mon, 24 Aug 2026 11:16:07 +0200 Subject: initial import --- docs/tutorial.txt | 790 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 790 insertions(+) create mode 100644 docs/tutorial.txt (limited to 'docs/tutorial.txt') diff --git a/docs/tutorial.txt b/docs/tutorial.txt new file mode 100644 index 0000000..a75d120 --- /dev/null +++ b/docs/tutorial.txt @@ -0,0 +1,790 @@ + +------------------------------------------------------------------------------ +PARSEC DEVELOPER TUTORIAL V1.0 +------------------------------------------------------------------------------ +mailto:parsec@parsec.org http://www.parsec.org/ +------------------------------------------------------------------------------ + + +------------------------------------------------------------------------------ +1. INTRODUCTION +------------------------------------------------------------------------------ + +This document is supposed to give you a quick start with the Parsec source +code. Of course this can only be an incomplete guide, a full documentation +has yet to be written, please keep this in mind while reading this tutorial. + +We'll cover some of the more easy modifications of Parsec, such as +changing/adding new graphics, 3D objects, samples and console commands. + +Some of these modifications can be done without changing source code, and +some require you to change the source code and recompile the Parsec +executable. + +Conventions used in this document: + + * Commands that have to be issued on the command-line, are written like + this: + + > program -option1 -option2 + + * Commands that have to be issued on Parsec's console, are written like + this: + + ::command option1 option2 + + NOTE: Parsec's command console can be opened using the tilde key (~). + + +------------------------------------------------------------------------------ +2. EXTRACTING THE DATA PACKAGES +------------------------------------------------------------------------------ + +All the data files used by Parsec are stored in the package files called +pscdata0.dat, pscdata2.dat and pscdata3.dat (pscdata1.dat only contains the +splashscreen image). +To change/view the data files, you need to extract the package files. This +can be achieved using the packaging tools that are built right into the +Parsec executable. + +Start Parsec with the following command line option to extract all the +data files from a package (pscdata2.dat in this example): + + > parsec -getpack --pack pscdata2.dat --list pscdata2.lst + +To view the contents of a package file use. + + > parsec -getpack --pack pscdata2.dat --view + +To extract a single file from the package use: + + > parsec -getpack --pack pscdata2.dat --file + +If you want to rebuild the package file with new data files, you need +to edit the .lst file and rebuild the package using: + + > parsec -makepack --pack pscdata2.dat --list pscdata2.lst + +NOTE: +Be careful not to put .mp3 files into pscdata0.dat, as they will be +converted to .wav files at startup, increasing the size of pscdata0.dat +significantly! + + +------------------------------------------------------------------------------ +3. ADDING/CHANGING GRAPHICS +------------------------------------------------------------------------------ + +This section explains how to change/add graphics in Parsec. +Nearly all graphics in Parsec are textures, drawn on triangles or polygons +using the rendering or drawing subsystems, even the 2D graphics found in +the menu or the spacecraft viewer. +All textures are loaded by the 'load' console command, so to change +Parsec's graphics, all you need to do is write a little console script +issuing multiple 'load' commands. +For testing purposes, you can issue the 'load' command directly on the +console. This will cause your new texture to show up immediately. +Textures in Parsec usually come in one of the following three image file +formats: + + (*) .3df (Glide texture format by 3dfx) + (*) .tga (Targa) + (*) .jpg (JPEG) + +3DF files can contain pre-calculated mipmaps and textures in various formats +(both with and without alpha channel), but are limited to 16 bit per pixel +color depth. +TGA files can contain 32 bit per pixel data (that is 24 bits for color and +an 8 bit alpha channel), but usually only offer a cheap RLE compression. +JPG files are usually very small, so they're are very well suited for high +resolution textures, in full 24 bit color. However, they don't support an +alpha channel. + +So before you can add your new textures to the game, you need to convert them +into one of the supported texture file formats. Your image editor of choice +will most likely be able to save JPG and TGA. +For creating .3df files, there are tools available for various platforms. +We recommend Texus by 3dfx (part of the Glide SDK, source code is included, +which can be compiled on nearly every platform), +or AsinDes (for Windows only). + +Here's a step-by-step guide for creating a new texture as a .3df file: +(if you choose to use .jpg or .tga files, you can skip points (2) and (3)) + + (1) Draw a texture in your graphics program of choice, e.g. + Photoshop or Gimp. Ensure that the dimensions of your texture are + powers of 2, and not larger than 256. Valid texture sizes are 128x64, + 256x256, 256x128, 64x32, 64x64 and so on. + If your texture size does not conform to this standard, it will not + show up if the Glide rendering subsystem is used, or performance on + OpenGL cards might suffer. + + (2) Save your texture in a format that your .3df converter is able to + read. We recommend .tga. Be sure to include an alpha channel if your + texture is supposed to have transparent areas. + + (3) Convert the texture to a -3df file. + Using the command-line version of Texus, this might look like this: + + > texus -mn -R 128 128 -t argb4444 -o texture.3df texture.tga + + This converts a 128x128 .tga image into a .3df texture including the + alpha channel without generating mipmaps. This is a suitable way to + convert textures for use in the menu or the cockpit. + + If you want to convert textures for use on a 3D object, you should + include mipmaps by removing the -mn option. + + If your texture has many similiar colors (e.g. lots of brown, or lots + of grey), you might get better results by using the ap88 color format + instead of argb4444. If your texture does not have an alpha channel, + you should use the rgb565 command with the -t parameter. + + (4) Copy the texture in the same directory that the Parsec executable + resides in. + + (5) Start up Parsec and enter the console by pressing the tilde key. + + (6) Type the command: + + ::listdata textures + + (8) Browse through the texture list, until you've found the texture you + want to replace. Unless you know the filename of the texture you want to + replace, this might require some trial and error. + You can also locate the correct texture by looking in one of the .con + files that are used to load the textures, for example _cockpit.con. + Remember the name of the texture, which is printed in parantheses. + + (9) Ensure that the AUX_ENABLE_TEXTURE_OVERLOADING flag is set, by typing + + ::AUX_ENABLE_TEXTURE_OVERLOADING 1 + + on the console. + + (10) Replace the texture by overloading it with the newly created one, + using the load command: + + ::load texture (texturename) file texture.3df + + where texturename is the name you remembered from the texture list + in step (8). + The parantheses are only required if the texture name contains + space characters. + +Please note that the new texture doesn't necessarily need to have the same +width/height as the original texture. If your new texture has a different +size, it will be scaled automatically. + +Some textures you might want to try to change are: + +(scv00.3df) - the spacecraft viewer background (256x256 tiles +(scv01.3df) starting at the top left corner) +(scv02.3df) +(scv10.3df) +(scv11.3df) +(scv12.3df) + +(loganiXX) - the logo animation in the bottom right corner of the menu + (30 frames) + +(sg_int.3df) - the water-like surface inside a stargate + +(corner1) - the little decorations at the corners of translucent panels +(corner2) +(corner3) +(corner4) + +(helix001) - the helix cannon particle texture + +Get the correct dimensions of those textures from the texture list, and +create new ones with the same size. + +You can use texus or some other .3df convertor to convert the .3df +textures back to the graphics format of your choice to edit them in your +favourite graphics program. + +If you want to keep your new graphics, you need to make sure they are +loaded when Parsec starts up. To do this, you should write a .con console +script containing the 'load' commands and add the name of the script to +the sys_dat.con file. This is necessary to ensure that the texture data is +correctly converted when switching video subsystems. + +It's important that you're familiar with the methods used to create and load +textures in Parsec, because this is part of creating new ship models. + + +------------------------------------------------------------------------------ +4. ADDING/CHANGING A 3D OBJECT +------------------------------------------------------------------------------ + +To modify 3D objects in Parsec, you take a simliar route as with changing +textures, so you also need to be familiar with that technique. Be sure +to read the previous section, and make sure you understood everything +there, because you'll need it when dealing with objects. + +Parsec uses its own flexible 3D object file format, called ODT, or the +newer revision OD2. In general, you'll only need to deal with .od2 files. +These files are usually created by our own tool called "makeodt". +Please consult the document on makeodt, to learn how to use it. +Makeodt is able to import VRML files (.wrl extension), and convert these +along with all the necessary texture information into .od2 files. It does +NOT read VRML2 (VRML97) files! + +Once you have an .od2 file you can load this just like a texture, using +the load command. + +load object (firebird) file fighter1.od2 + +Here's a step-by-step guide for creating a new ship for Parsec: + + (1) Use a good 3D modelling program (e.g. 3D Studio Max) to create your + model. Paint some textures for the model, and use UV mapping to map + them onto your ship. + + (2) Save your model as a VRML file (.wrl), and your textures as Targa + files (.tga). Use the procedures described in the previous chapter to + convert the textures to .3df or alternatively .jpg files. + + (3) Use makeodt to convert your ship into a .od2 file. + + (5) Take a look at mon_f1.3df and recreate a similiar texture showing + your ship, using your 3D rendering program. This texture will be + displayed in the cockpit monitors on the top of the screen. + + (6) Make a copy of _f1_2.con (from pscdata2.dat) and edit it. You need to + change the load texture commands to load the textures of your ship, + replace every occurence of firebird with your new ship's name, change + the ship description and adapt the weapon outlet positions to suit your + model. + + (7) Load your edited .con file and you should be able to select your new + ship in the spacecraft viewer. + +If you followed these steps, your ship will be fully functional, but it +won't have any propulsion effects yet. Take a look at the more modern scripts, +e.g. _f8_2.con, to find out how to define the particle position for the +propulsion effects (commands are called "classpart" and "classiter"). + +If you just want to convert a simple object for a weapon effect or similar, +you can skip steps (5) and (6), as these are specific to ships. + +Please consult the makeodt documentation for a more thorough discussion of +console script commands for loading objects, specifying shaders, etc. + + +------------------------------------------------------------------------------ +5. ADDING/CHANGING A SAMPLE +------------------------------------------------------------------------------ + +Replacing one of Parsec's soundeffects is just as simple as changing a +texture, maybe even simpler. +Using the listdata command you can get a list of all currently loaded +samples. + +::listdata samples + +Pick one that you want to replace, and create a .wav file for it, +using your favourite sample editor. +Now open _sound.con and change the line corresponding to the sample that +you want to replace. You can also specify a new volume. +Reload _sound.con on the console or restart Parsec to test the new sample. + + +------------------------------------------------------------------------------ +6. ADDING A CONSOLE COMMAND +------------------------------------------------------------------------------ + +Parsec's console contains a large number of available commands, most of which +are defined within the console modules (source files named con_*). +Console commands that are specific to a part of the game are usually defined +within the modules responsible for the implementation of that part (e.g. +commands related to the network code are implemented in the net_* source files +directly). These commands (usually called user commands) are registered from +the REGISTER_MODULE function, which is called automatically upon program +startup. + +The registration of a user command might look like this: + +// module registration function ----------------------------------------------- +// +REGISTER_MODULE( STARMAP ) +{ + user_command_s regcom; + memset( ®com, 0, sizeof( user_command_s ) ); + + // register "starmap" command + regcom.command = "starmap"; + regcom.numparams = 0; + regcom.execute = Cmd_STARMAP; + regcom.statedump = NULL; + CON_RegisterUserCommand( ®com ); +} + +The user_command_s structure contains necessary parameters that describe the +user command, and a function pointer to the actual implementation of the +command. +A string containing the parameters of the command will be passed to the +implementation function. +Here's an example of a the above "starmap" command, which is very simple, as +it doesn't require any parameters. It just calls the internal function +MAP_ActivateStarmap() to activate the starmap. + +// console command to activate/deactivate the starmap ------------------------- +// +PRIVATE +int Cmd_STARMAP( char *paramstr ) +{ + ASSERT( paramstr != NULL ); + HANDLE_COMMAND_DOMAIN_SEP( paramstr ); + + MAP_ActivateStarmap(); + + return TRUE; +} + +For more complex console commands, it's necessary to parse the parameter +string. +There are helper functions available which make this task a lot easier (and +less error prone) if the parameters have a key/value pair structure. + +You start by defining a table of the keys that you want to be able to parse: + +// key table for net.master command ------------------------------------------- +// +key_value_s net_master_key_value[] = { + + { "num", NULL, KEYVALFLAG_NONE }, + { "addr", NULL, KEYVALFLAG_NONE }, + + { NULL, NULL, KEYVALFLAG_NONE }, +}; + +Possible KEYVALFLAG values are: +KEYVALFLAG_NONE -> no specific options for this key +KEYVALFLAG_DISALLOW -> if this key exists, an error will be returned +KEYVALFLAG_IGNORE -> ignore this key and its value. +KEYVALFLAG_MANDATORY -> if this key is missing, an error will be returned +KEYVALFLAG_PARENTHESIZE -> the value of this key might be enclosed by (), which + is used for value strings that contain whitespace. + +Of course these flags can be combined if necessary, e.g: +KEYVALFLAG_MANDATORY | KEYVALFLAG_PARENTHESIZE +to specify a key that is both mandatory and uses a string value that +contains a space character, for example. + +enum { + + KEY_NET_MASTER_NUM, + KEY_MET_MASTER_ADDR, +}; + +The enum declarations are used to allow easier access to the entries of the +key table. + +In your command implementation function, you then call: + + // scan out all values to keys + if ( !ScanKeyValuePairs( net_master_key_value, paramstr ) ) { + return TRUE; + } + +This will automatically parse the parameter string into key/value pairs. +If the parameter string does not conform to the constraints specified in +the key table (e.g. mandatory keys are missing), FALSE will be returned, +and an error will be output on the console automatically. + +If the parsing was sucessful, the key table will be populated with the +values for each key, in the value field of the key_value_s structure. +If the value field is NULL, this means that the key was optional and +has not been found. So make sure the check against NULL, before using +the value. + +Additional helper functions are available to convert the value field +(which is still a string) to its integer or float representation: + + // get masterserver number + int num = 0; + if ( ScanKeyValueInt( &net_master_key_value[ KEY_NET_MASTER_NUM ], &num ) < 0 ) { + CON_AddLine( invalid_arg ); + return TRUE; + } + +This will retrieve the value string for the "num" key, as defined in the +key table, and convert the string to an integer, which will be stored in +the num variable. +Other functions that can be used here include: +ScanKeyValueIntList(), ScanKeyValueFloat(), ScanKeyValueFloatList(), etc. + +If your command parameter parsing becomes more complex, it is highly +recommended that you include a syntax definition in Backus-Naur Form as a +comment in the source code. +You can see examples of this with nearly every console command implementation +in Parsec. You can also find a list of all syntax definitions at the end of +this document. + +------------------------------------------------------------------------------ +APPENDIX A: CONSOLE COMMAND SYNTAX DEFINITIONS +------------------------------------------------------------------------------ + +In this section you can find syntax definitions of some of the common +Parsec console commands in Backus-Naur Form (BNF). +Please note that this list does not include the vast amount of integer +commands. These don't require a special syntax, and can be shown by using +the 'listintcommands' command. +Parameters in brackets are optional, the | character is used to denote a +logical or condition. + + + bkgn_add_command ::= 'bkgn.add' + itemspec ::= | | + samplespec ::= 'sample' + trackspec ::= 'track' + streamspec ::= 'stream' + silencespec ::= 'silence' + + + bkgn_remove_command ::= 'bkgn.remove' + itemspec ::= | | + idspec ::= 'id' + samplespec ::= 'sample' + trackspec ::= 'track' + + + bkgn_list_command ::= 'bkgn.list' + + + bkgn_group_command ::= 'bkgn.group' + itemspec ::= 'item' + + + aud_volume_command ::= 'aud.volume' [] + + + aud_samplevolume_command ::= 'aud.samplevolume' [] + + + aud_playsample_command ::= 'aud.playsample' + samplespec ::= | + samplename ::= 'name' + sampleid ::= 'id' + + + play_command ::= 'play' + demo_name ::= "valid script name" + + + level_load_command ::= 'level.load' levelname_spec + levelname_spec ::= + + + level_save_command ::= 'level.save' levelname_spec + levelname_spec ::= + + + level_info_command ::= 'level.info' + + + swaying_command ::= 'gfx.swaying' [] [] [] + period_spec ::= '(' ')' + ampl_spec ::= '(' ')' + phase_spec ::= + + + crosstarget_command ::= 'crosstarget' + + + scale_command ::= 'cockpit.scale' [] + + + weaponreg_command ::= 'weaponreg' [] + slot_spec ::= 'slot' + icon_avail_spec ::= 'icon_avail' | + icon_unavail_spec ::= 'icon_unavail' + picture_spec ::= 'pic' | + texture_list ::= '(' + ')' + + + quicksay_command ::= 'quicksay' + + + range_command ::= 'radar.range' [] + + + shipdesc_command ::= 'shipdesc' [] + class_spec ::= 'class' | 'id' + text_spec ::= 'text' + caption_spec ::= 'caption' + clear_spec ::= 'clear' ['caption'|'text'] + + + emp_conf_command ::= 'emp.conf' [] [] + lifetime_spec ::= 'lifetime' + maxwidth_spec ::= 'maxwidth' + lambda_spec ::= 'lambda' + fadeout_spec ::= 'fadeout' + waves_spec ::= 'waves' + delay_spec ::= 'delay' + energy_spec ::= 'energy' + + + emp_conf_command ::= 'empup1.conf' [] [] + lifetime_spec ::= 'lifetime' + maxwidth_spec ::= 'maxwidth' + lambda_spec ::= 'lambda' + fadeout_spec ::= 'fadeout' + waves_spec ::= 'waves' + delay_spec ::= 'delay' + energy_spec ::= 'energy' + + + emp_conf_command ::= 'empup2.conf' [] [] + lifetime_spec ::= 'lifetime' + maxwidth_spec ::= 'maxwidth' + lambda_spec ::= 'lambda' + fadeout_spec ::= 'fadeout' + waves_spec ::= 'waves' + delay_spec ::= 'delay' + energy_spec ::= 'energy' + emp_command ::= 'emp' + + shockwave_command ::= 'shockwave' [] [] + lifetime_spec ::= 'lifetime' + maxwidth_spec ::= 'maxwidth' + lambda_spec ::= 'lambda' + fadeout_spec ::= 'fadeout' + + + inp_weaponsel_command ::= 'inp.weaponsel' + + + inp_cycleguns_command ::= 'inp.cycleguns' + + + inp_cyclemissiles_command ::= 'inp.cyclemissiles' + + + inp_cycletargets_command ::= 'inp.cycletargets' + + + inp_zerospeed_command ::= 'inp.cycletargets' + + + inp_targetspeed_command ::= 'inp.targetspeed' + + + inp_cyclepanel_command ::= 'inp.cyclepanel' + + + clientrate_command ::= 'net.clientrate' [] + + + serverrate_command ::= 'net.serverrate' [] + + + jump_command ::= 'jump' + server ::= valid hostname or IP address of gameserver + + + net_master_command ::= 'net.master' [] + num_spec ::= 'num' + addr_spec ::= 'addr' valid hostname or IP address of masterserver + + + serverlist_request_command ::= 'serverlist.request' [] [] + max_ping ::= 'ping' + min_players ::= 'players' + + + serverlist_show_command ::= 'serverlist.show' + + + srvcmd_command ::= 'srvcmd' + command_spec ::= + + + colanim_command ::= 'colanim' [] [] + name ::= "may be parenthesized to include whitespace" + coltab0 ::= 'src' 'len' + coltab1 ::= 'src2' 'len2' + coltab_src ::= '(' | ')' + coltab_len ::= + mode_spec ::= 'mode' 'add' | 'mul' + tab_spec ::= 'tab' [] [] [ | ] + col_list ::= '(' + ')' + comp ::= 'comp' '1' | '3' | '4' + t_equi ::= 't' + t_list ::= 'tl' '(' + ')' + wave_spec ::= 'wave' [] [] [] [] + wave_name ::= 'tri' | 'saw' | 'ramp' | 'sine' + max ::= 'max' + min ::= 'min' + mask ::= 'mask' ['r'] ['g'] ['b'] ['a'] + + + net_config ::= 'net.subsys' [[] ] + protocol ::= 'peer-to-peer' | 'slot-server' | 'game-server' + packet_api ::= 'ipx' | 'udp' + + + audio_config ::= 'aud.conf' [conf_spec] [conf_spec] + conf_spec ::= 'off' | 'music' | 'sfx' + + + input_config ::= 'inp.conf' [conf_spec] [conf_spec] + conf_spec ::= 'off' | 'joystick' | 'mouse' + + + classiter_command ::= 'classiter' ( [] [] ) | + class_spec ::= 'class' | 'id' + command ::= 'cmd' 'reset' + trafo ::= 'trafo' '(' [] ')' + apex_info ::= 'apex' '(' [ []] ')' + prim_type ::= 'prim' 'tri' | 'quad' | 'pent' + vertex_list ::= 'vtxs' '(' + ')' + vertex_spec ::= + + + classpart_command ::= 'classpart' ( [] [] ) | + class_spec ::= 'class' | 'id' + command ::= 'cmd' 'reset' + trafo ::= 'trafo' '(' [] ')' + pdef ::= 'pdef' + position ::= 'pos' '(' ')' + size ::= 'size' + render_mode ::= 'render' 'poslight' | 'thrust' | 'missile' + vertex_spec ::= + + + faceinfo_command ::= 'faceinfo' + class_spec ::= | + class_name ::= 'class' + class_id ::= 'classid' + face_spec ::= | + face_id_spec ::= 'faceid' + attrib_spec ::= | + shader_spec ::= 'shader' | + shader_iter ::= '(' 'iter_xx'* 'flag_xx'* ')' + shader_name ::= "valid name of shader" + tex_spec ::= 'texture' + + + key_command ::= 'key' ( | ) + key_spec ::= 'akc_*' + command ::= "arbitrary string, may contain whitespace" + func_spec ::= 'func_*' | 'func_1_*' | 'func_2_*' + mkc_code ::= 'mkc_*' | '0x' | + hex-digit ::= [0-9a-f] + nil ::= "if no mkc_code is supplied mapping will be deassigned." + + + bind_command ::= 'bind' ( | ) + key_spec ::= 'akc_*' + command ::= "arbitrary string, may contain whitespace" + func_spec ::= 'func_*' | 'func_1_*' | 'func_2_*' + mkc_code ::= 'mkc_*' | '0x' | + hex-digit ::= [0-9a-f] + nil ::= "if no mkc_code is supplied mapping will be deassigned." + + + load_command ::= 'load' [ ]* + data_type ::= 'object' | 'texture' | 'texfont' | 'bitmap' | 'sample' + name ::= "may be parenthesized () to include whitespace" + key ::= "valid keys depend on data type" + + + defshader_command ::= 'shader.def' [] [] [] + shader_name ::= "may be parenthesized to include whitespace" + shader_spec ::= 'shader' | + shader_iter ::= '(' 'iter_xx'* 'flag_xx'* ')' + shader_name ::= "valid name of shader" + color ::= 'color' '(' [] ')' + anims ::= [] [ []] + texanim ::= 'texanim' "valid name of texanim" + colanim ::= 'colanim' "valid name of colanim" + colanim_mode ::= 'colmode' 'add' | 'mul' | 'nobase' + + + setshader_command ::= 'shader.set' [] + class_spec ::= | [] + class_name ::= 'class' + class_id ::= 'id' + lod_spec ::= 'lod' + shader_spec ::= 'shader' | + shader_iter ::= '(' 'iter_xx'* 'flag_xx'* ')' + shader_name ::= "valid name of shader" + face_spec ::= | + tex_spec ::= 'texture' + face_id_spec ::= 'faceid' | + face_id_list ::= '(' + ')' + + + texanim_command ::= 'texanim' + name ::= "may be parenthesized to include whitespace" + + + summon_command ::= 'summon' [] [] + object_spec ::= | | | + classname_spec ::= 'class' + classid_spec ::= 'id' + sfx_spec ::= 'sfx' + vtype_spec ::= 'vtype' + init_spec ::= [ []] [] [] + origin_spec ::= 'origin' '(' ')' + space_spec ::= 'space' 'vv' | 'vw' | 'wv' | 'ww' + speed_spec ::= 'speed' + frame_spec ::= 'frame' '(' ')' + multi_spec ::= [ [] []] + repl_spec ::= | + count_spec ::= 'count' + offset_spec ::= 'offs' '(' ')' + scatter_spec ::= 'scatter' '(' ')' + classname ::= "may be parenthesized () to include whitespace" + classid ::= + sfxname ::= 'energyfield' + + + do_creg_command ::= 'do_creg' [] + int_list ::= [] + + + shipclass_command ::= 'shipclass' [] + class_spec ::= 'class' | 'id' + monitor_texture_spec ::= 'texture' + + + extraclass_command ::= 'extraclass' + class_spec ::= 'class' | 'id' + + + decoy_command ::= 'decoy' + + + cloak_command ::= 'cloak' + + + pdef_command ::= 'pdef' [] + name ::= "may be parenthesized () to include whitespace" + texanispec ::= [] [] [] + basename ::= 'base' + tablen ::= 'len' + basedig ::= 'dig' '1' | '2' | '3' | '4' + textab ::= 'tab' '(' ')' + texframespec ::= ( ['base' ] ['stride' ] ) | ['frm' '(' ')'] + textimespec ::= ['t' ] | ['tl' '(' ')'] + textabctrl ::= ['bgn' ] ['rep' ] ['end' ] + xfoanispec ::= 'xfolen' ['xfotab' ] [] + xfotab ::= '(' ')' + xfotabctrl ::= ['xfobgn' ] ['xforep' ] ['xfoend' ] + intlist ::= [] + + + pattach_command ::= 'pattach' [] [] + shipspec ::= 'ship' 'local' | 'target' + origin ::= 'origin' '(' ')' + ref_z ::= 'size' + type ::= 'normal' | 'flare' | 'light' + + + inp_weaponsel_command ::= 'inp.weaponsel' + -- cgit v1.2.3