CFED(6)
CFED(6) โ like, the level compiler manual, bestie ๐
okay so. this is the page for cfed, and it lives in section 6 of the manual. buckle up, it's a long one, but it's so worth it. ๐
โจ NAME โจ
cfed โ a level compiler for Crimson Fields
๐ฆ SYNOPSIS ๐ฆ
cfed mapsource --tiles tileset --units unitset [-o outfile]
cfed {--help | --version}
๐ DESCRIPTION ๐
cfed is the Crimson Fields level compiler. no cap.
It takes a source file *.src and turns it into a *.lev file. and the best part? you can make those source files in literally any standard text editor you want, no fancy tooling required. (the syntax for those files lives down in the FILE FORMAT section below, don't worry, we'll get there ๐)
cfed reads the input file and creates the level file. If you don't tell it what to name the output on the command line, it just makes it in the same location as the source file, swapping the .src suffix for .lev. iconic behaviour honestly.
๐ OPTIONS ๐
--helpโ prints a usage message on standard output and dips. โ๏ธ--tilestilesetโ use the tile definitions fromtilesetwhen compiling the map.--unitsunitsetโ use the unit definitions fromunitsetwhen compiling the map.--versionโ prints version info on standard output and exits.-oโ sets the name and path of the converted level file.
๐ธ FILE FORMAT ๐ธ
A level source file is made of sections. A section starts with the section name in square brackets, so like, the line
[unit]
starts a unit section. and the lines inside a section are usually shaped like this:
qualifier = value
The only ones that don't play by that rule are the map and messages sections. (they're the exceptions, they're built different, iykyk ๐)
Lines starting with # are comments. The following sections exist:
๐ง mission
This section sets some global mission parameters, like map size or which graphics set to use. The mission section is mandatory and has to show up before the map section in the file. Valid qualifiers are:
nameโ index of a message containing the mission title. This name gets used when showing the player the list of available maps. (maximum length 30 characters, mandatory)mapwidthโ[10-200](mandatory)mapheightโ[10-200](mandatory)nextmapโ the name of another map (without path and file ending). After the current map has been completed, this new map gets loaded automatically. This tag is only valid for campaign maps.infoโ index of the information message shown when a player requests level info. This message can hold the level name, author, revision, etc.campaignโ says whether the map is part of a campaign[0|1]. Default is0(not part of a campaign). See alsocampaignnameandcampaigninfo.campaignnameโ index of the campaign name. It should be set only when the map actually is the first of a campaign. See alsocampaignandcampaigninfo. (mandatory and valid only for the introductory map of a campaign)campaigninfoโ index of the information message for the campaign. This info is displayed when starting a new campaign and should contain a short outline of the background story. It's useful only when the map actually is the first of a campaign. See alsocampaignandcampaignname.skirmishโ says whether the map can be played in skirmish mode[0|1]. Default is1(true).playersโ picks whether the map is meant for play against another human being (2) or against the computer (1). This is for informational purposes only and defaults to2.musicโ name of a soundtrack (either MIDI or Ogg Vorbis) excluding the file type suffix, to be played during this map. If the setting is missing, the default track for Crimson Fields gets played.tilesetโ tileset file to be used. A tileset contains the map graphics and terrain definitions. The filename must be given without the.tilessuffix. If omitted, the tile set defaults toยดdefaultยด.unitsetโ unit set file to be used. A unit set contains the unit graphics and definitions. The filename must be given without the.unitssuffix. If omitted, the unit set defaults toยดdefaultยด.
๐ map
The map section defines the actual map layout. It's a rectangle of the size specified in the mission section, made of various symbols that each describe a certain map tile type. The map section is mandatory and may not contain comments. The following symbols exist:
.โ plains*โ forest%โ mountains=โ shallow water~โ water-โ deep water#โ swamp"โ cliff0โ headquarters, neutral entrance, east1โ headquarters, yellow entrance, east2โ headquarters, blue entrance, east3โ depot, neutral entrance, north4โ depot, yellow entrance, north5โ depot, blue entrance, north6โ factory, neutral entrance, north7โ factory, yellow entrance, north8โ factory, blue entrance, north9โ factory, neutral entrance, eastJโ factory, yellow entrance, eastLโ factory, blue entrance, eastAโ city, yellowBโ city, blueCโ city, neutralDโ headquarters, yellow entrance, westEโ headquarters, blue entrance, westFโ headquarters, neutral entrance, westGโ headquarters, yellow entrance, northHโ headquarters, blue entrance, northIโ headquarters, neutral entrance, north>โ headquarters, east<โ headquarters, west^โ headquarters, northvโ headquarters, south\โ road, se-nw|โ road, s-n/โ road, sw-neyโ road, sw-n-neYโ road, se-n-nwXโ road, s-se-nw-nxโ road, s-sw-n-neoโ road, sw-nw-ne-sekโ road, sw-s-neKโ road, s-se-nw(โ road, n-se)โ road, n-sw]โ road, nw-s[โ road, ne-snโ road, sw-seuโ road, nw-neTโ road, n-s-seUโ road, n-s-swVโ road, n-s-neWโ road, n-s-nw!โ bridge, n-s`โ bridge, sw-neยดโ bridge, se-nwaโ fence, se-nw endbโ fence, nw-se endcโ fence, ne-sw enddโ fence, sw-ne endeโ fence, n-sfโ fence, sw-negโ fence, nw-sehโ fence, nw-siโ fence, ne-sjโ fence, sw-nlโ fence, se-nmโ fence, nw-nepโ fence, sw-se
There's also an alternative format. If the section is called map-raw instead, the map gets defined by giving the hexagon identifiers directly, using the comma as a tile separator. fair warning though: this approach requires intimate knowledge of the tileset you're using and may break the map if the tileset changes. ๐ The format exists because there are now more tiles than can be represented with single ASCII characters. so like, choose wisely bestie.
๐ player
This one lets you set some player definitions. There may be a maximum of two player sections in a file. The first section encountered corresponds to the first player, the next to the second. Valid qualifiers are:
nameโ index of a message containing the player name (mandatory, maximum length 20 characters)briefingโ index of the playerยดs briefing message. The briefing can be reviewed during the game by choosing the Briefing item from the Game Menu. It's also recommended to create a message event to tell the players about their objectives on the first turn (see event and messages sections below). If omitted, it defaults to-1, meaning that no briefing is available.fcolorโ foreground color to use for this player, in the formatr,g,b, e.g.255,0,0for red. The default player colors match the default unit set, but different sets may use different color schemes (also seebcolor).bcolorโ background color to use for this player, in the formatr,g,b, e.g.0,0,255for blue. The default player colors match the default unit set, but different sets may use different color schemes (also seefcolor).
โญ unit
Each one of these sections creates a unit on the map. Loaded transporter units must be specified before any units they carry. ๐ข Valid qualifiers for units are:
posโ location of the unit on the map. If there's a building at the given location, the unit gets put in. It's also possible to let units begin inside a transport. In that case you have to make sure, however, that in the level file the transport is declared before the carried unit[x/y]. (mandatory)idโ unique unit identifier[0-10000]. (mandatory)typeโ unit type definition to use for this unit. Known definitions for the default unit set areInfantry,Medium Tanks,Heavy Tanks,Anti-Aircraft Tanks,Anti-Aircraft Guns,Artillery,Mines,Patrol Boats,Fighter Squadron,Personnel Carriers,Troopships,Transport Planes,Scouts,Interceptors,Bunkers,Torpedo Boats,Bomber Wing,Hovercraft,Gunships,Troop Train,Rail Guns,Armoured Train,Submarines, andAircraft Carriers. (mandatory)playerโ unit controller[1|2]. (mandatory)sizeโ number of vehicles for this unit[1-6]. Defaults to6(undamaged).xpโ experience level this unit starts at[0-6]. Defaults to0(Rookie, no experience).faceโ direction the unit is heading[0-5]. Directions are numbered clockwise from North (0) to Northwest (5). Defaults are North (0) for units controlled by player 1, and South (3) for the second player.crystalsโ amount of crystals the unit carries. This may only be given for transports and defaults to0.
๐ building
A building section is required to actually create a building (sometimes also called a shop) on the map that units can enter. This is not automatically done by placing the symbol for a building entrance in the map section. so don't skip this one, fr fr.
posโ location of the building entrance on the map[x/y]. (mandatory)idโ unique building identifier[0-10000]. (mandatory)playerโ building controller[1|2|0]. Units starting in unaligned buildings are automatically tagged unaligned as well. (mandatory)typeโ the vibe of the building, bestie ๐ . Units can get repaired in buildings of typeWorkshop. New units can be produced in buildings of typeFactory. A building can have multiple types, she's versatile โจ. Defaults toDepot, which means no special attributes. Also, a shop that produces crystals is (automatically) called aMine๐.nameโ index of a message containing the shop name. Mandatory, max length 30 characters. You literally gotta have it ๐.miningโ amount of crystals produced each turn[0-1000]. Defaults to0. If you give it, it implies typeMine๐.capacityโ maximum amount of crystals[0-10000]. Defaults to1000๐.crystalsโ amount of crystals in stock[0-capacity]. Defaults to0๐ฆ.factoryโ name of a unit type definition that can be built here. If given, impliestype = factory. You can have multiplefactorylines for a shop, go off ๐ฅ.minweightโ weight of the smallest unit allowed to enter the building[0-99]. Defaults to0๐ธ.maxweightโ weight of the heaviest unit allowed to enter the building[0-99]. Defaults to99๐.
๐ event ๐
Events are literally how you interact with players during a game. They can cause actions like points being awarded or messages being displayed under certain conditions. The event type defines what happens, the event trigger controls when (or if) the event is executed. No cap ๐.
โจ Event Types โจ
configureโ dynamically change the setting for various internal strings during the course of a game, e.g. the players' mission briefings ๐ฌ.createunitโ create a unit somewhere on the map ๐.destroyunitโ destroy a unit and remove it from the map ๐.manipulateeventโ modify event internals. Currently this can be used to dynamically enable or disable an event ๐.messageโ display a message ๐ฉ.miningโ set the amount of crystals for a building ๐.researchโ make a new unit type available for production in a factory, or remove it from the list of available units ๐ฌ.scoreโ award points to a player ๐.sethexโ change a tile on the map ๐บ๏ธ.settimerโ dynamically adjust the timer trigger of another event โฐ.
๐ธ Event Triggers ๐ธ
handicapโ the event is executed if the set handicap matches the current game settings. Usually such an event is triggered immediately on the first turn or not at all. You can, however, combine multiple events (e.g. a handicap and a timer trigger) to change the default behaviour ๐ฎ.havebuildingโ the event is executed when the player controls a certain building at a specified time ๐ฐ.havecrystalsโ the event is executed when the player owns a certain amount of crystals ๐.haveunitโ the event is executed when the player controls a certain unit at a specified time ๐ก๏ธ.timerโ the event is unconditionally executed at the specified time โณ.unitdestroyedโ the event is executed when a specified unit is destroyed or captured by the enemy ๐ฅ.unitpositionโ the event is executed when a specified unit ends its move on a certain target hex ๐.
The following list contains generic qualifiers which are valid for all event types.
๐ Qualifiers ๐
idโ unique event identifier[0-200]. (mandatory) ๐typeโ event type (mandatory, see below) ๐ท๏ธ.triggerโ event trigger (mandatory). This describes the circumstances under which the event is executed (see below) ๐ฏ.messageโ index of a message to be displayed when the event occurs ๐ฌ.titleโ title of the message window. Only useful when a message is shown ๐ช.dependโ identifier of another event. This makes the current event depend on the given event. Prior to event execution, the trigger conditions for both events are checked, and the event is activated only if both checks are successful. Mutual, circular, and transitive dependencies are supported ๐.discardโ identifier of another event. When the current event is executed, the given event is discarded from the event stack and removed from the mission ๐๏ธ.flagsโ event flags. Currently, the only available flag is1(disable). A disabled event will never execute, regardless of the trigger conditions ๐ซ.
In addition there are special qualifiers which can only be used with certain event types or triggers. All of these are mandatory if nothing else is stated.
action(manipulateevent,mining,research) โ Formanipulateeventthis defines how to handle the specified flags. A value of0will set,1will clear, and2will toggle the flags. Formining0will set the crystal storage to an absolute amount,1will modify the current amount by the given number,2will set the mining rate, i.e. the amount mined each turn, and3will change the current mining rate by the given value. Minimum mining rate is0, maximum is200. Forresearch0allows and1disallows producing the specified unit type. Default is0๐๏ธ.building(mining,research) โ Identifier of the building referenced in the event ๐ข.crystals(mining) โ Amount of crystals. The action flag controls how this number is actually interpreted ๐.eflags(manipulateevent) โ Event flags to be modified. Currently the only legal value for this is1, the disable flag, which can be used to deactivate an event. Disabled events won't be triggered even if their trigger conditions are met ๐ซ.event(manipulateevent,settimer) โ Identifier of the event to be modified ๐.face(createunit) โ Direction the created unit faces[0-5]. Directions are numbered clockwise from North (0) to Northwest (5). Optional, defaults to0๐งญ.offset(settimer) โ Offset to use when adjusting the timer.0means absolute, i.e. set the triggerttimeto the value oftime.1means execution time, i.e. set it to the value oftimeplus the current time index when executing the event.2means current trigger configuration, i.e. add thetimeto the triggerttime. Note that if the target event is disabled,settimerwill automatically enable it โฑ๏ธ.othermsg(score) โ Forscoreevents, one often wants to show a message not only to the player who benefits from the event but also to his opponent. Instead of creating a separate message event with inverted trigger conditions you can use this qualifier andothertitleto do just that (optional) ๐จ.othertitle(score) โ Index of the message title for the other player (optional, seeothermsg) ๐.owner(destroyunit) โ Only destroy the unit if it is controlled by this player[1,2,-1]. Optional, default is any player (-1) ๐ค.pos(createunit) โ hex to create the unit on. The unit will only be created if the target hex is empty at creation time or there is a shop or a valid transporter which is controlled by the player for whom the event is set up[x/y]๐.pos(destroyunit) โ hex to destroy the unit on[x/y]. Theposparameter can only be used ifunitis-1๐ฃ.pos(message) โ hex to focus the display on when showing the message[x/y](optional). If this parameter is absent the game will try to guess a suitable hex from the trigger data, e.g. ahavebuildingtrigger will cause it to use the shop location ๐.pos(sethex) โ hex to change. If the hex is occupied by a unit at the time the event is executed it may end up on terrain it would not normally be able to enter[x/y]โ ๏ธ.setting(configure) โ Name of the setting you wish to change. Valid names arebriefing1for the briefing for the first player,briefing2for the objectives for the second player, andnextmapfor the next mission in a campaign โ๏ธ.size(createunit) โ Unit group size[1-6]. Optional, defaults to6๐ฅ.success(score) โ Amount of success points the player receives when the event occurs. Any player with a success score of100or more wins the game ๐ .unit(createunit,research) โ Name of a unit type specification to build or make available, respectively ๐ ๏ธ.unit(destroyunit) โ Identifier of the unit to be destroyed. Set to-1and configure theposparameter to destroy a unit in a specified location instead ๐ฏ.tbuilding(havebuilding,havecrystals) โ Identifier of the building to be controlled. Forhavecrystalsthis parameter may be set to-1to check all shops a player controls, or to-2to check all shops and all transporters anywhere on the map ๐ญ.tcrystals(havecrystals) โ Amount of crystals needed to trigger the event[-5000-5000]. If the amount given is greater than0the player needs at least that many crystals. If it is negative, the event occurs when the player's resources drop below the absolute number ๐.thandicap(handicap) โ Handicap setting to trigger the event[1 (none)|2 (player 1 handicapped)|4 (player 2 handicapped)]. You can add up the numbers to trigger on more than one setting โ๏ธ.tile(sethex) โ Identifier of the terrain the target hex will be changed to ๐ฟ.time(settimer) โ Time index. Theoffsetflag controls in what way this number is used to adjust the targeted trigger โณ.towner(havebuilding,havecrystals,haveunit,unitdestroyed,unitposition) โ The event will only occur if the owner of the building or unit is the same as the player specified here[1|2]. For theunitdestroyedtrigger it is only required iftunitis-1. In this case you can select the player whose units have to be destroyed to activate the event. This setting may be omitted and defaults to the player not owning the event, while forhavecrystalsandunitpositionthe default is the player owning the event. You must supply this key for the other two trigger types ๐.ttime(havebuilding,haveunit,timer) โ Time at which the event conditions should be checked. Fortimerthe event will always be executed at this time. Time calculation starts with0at the start of a mission and increases by1each time the players change. The movement phase of player 2 on turn 10 is at time index19((turn - 1) * 2 + (player - 1)), for example. (mandatory only fortimer. If omitted for the other triggers, the condition will be checked each turn.) โฐtunit(haveunit,unitdestroyed,unitposition) โ bestie, this is the identifier of the unit you're targeting ๐ฏ. Forunitdestroyedandunitpositionit can literally be-1, and that makes the event fire when all enemy units have been destroyed, or when any unit controlled by this player has reached the destination hex, respectively โจ. And for those same two triggers you can also just drop in a unit type โ likeInfantryโ to target a whole entire unit class ๐.tpos(unitposition) โ coordinates of the target hex, written as[x/y]๐.value(configure) โ when you're changing a briefing, this is the index of the message to use as the new briefing; when you're setting the next map, it's the file name of the next mission (suffix excluded) ๐บ๏ธ.xp(createunit) โ the initial experience level,[0-6]โญ. Optional, defaults to0.
๐ messages ๐
The messages section holds all the text messages that could possibly be displayed at any point during a mission ๐ซถ. Lowkey important: the format of this section is different from all the other sections. Here's an excerpt from an imaginary level file, so you can see the vibe:
[messages(en)]
This is a message.
% this line separates messages
This is the second message.
% separator lines can be used for comments
This is the third message,
containing a line break.
[/messages] this marks the end of the messages section
The two characters in brackets tell you which language the messages in this section are written in ๐. There's one messages section for each language the mission supports. So that (en) in the section title means this section contains English messages. And no cap โ all messages must be encoded in UTF-8 ๐.
๐ EXAMPLE ๐
okay bestie, here's a whole entire mission file. read it, it's giving tutorial ๐
### This is a simple example mission file
[mission]
# mission title is "The Great Example"
name = 5
mapwidth = 11
mapheight = 10
# the first message in the [messages] section
# will be used as level information
info = 0
# we use the default tileset and unit set so we could
# omit the next two lines
tileset = default
unitset = default
[map]
***...***..
**...****.=
*<^1n]*..==
**v..(..==~
***...].=~~
#=#.==!====
=====(]...
%*.=...E^>.
%%..%...v..
%%%%.%...**
### first player - The Good
[player]
name = 6
# second message is briefing for this player
briefing = 1
### second player - The Bad
[player]
name = 7
# third message is briefing for this player
briefing = 2
### units for player 1
[unit]
# this unit will start in the building
pos = 3/2
player = 1
id = 0
type = Infantry
[unit]
pos = 5/4
player = 1
id = 1
type = Medium Tanks
[unit]
pos = 6/3
player = 1
id = 2
type = Medium Tanks
[unit]
pos = 3/2
player = 1
id = 3
type = Scouts
### units for player 2
[unit]
pos = 7/7
player = 2
id = 10
type = Anti-Aircraft Tanks
[unit]
pos = 6/6
player = 2
id = 11
type = Personnel Carriers
[unit]
pos = 7/6
player = 2
id = 12
type = Infantry
[unit]
pos = 7/7
player = 2
id = 13
type = Heavy Tanks
### buildings
# HQ of the Good
[building]
name = 8
pos = 3/2
id = 0
player = 1
# can repair units here
type = workshop
crystals = 25
# HQ of the Bad
[building]
name = 9
pos = 7/7
id = 1
player = 2
# can repair and build units
type = workshop
type = factory
# the following units can be built
factory = personnel carriers
factory = anti-aircraft guns
factory = bomber wing
crystals = 25
### events
# player 1 wins if he conquers
# the enemy building at any time...
[event]
type = score
id = 0
player = 1
trigger = havebuilding
tbuilding = 1
towner = 1
# the next line could be left out
ttime = -1
success = 100
message = 3
title = 4
# ...or destroys all enemy units
[event]
type = score
id = 1
player = 1
trigger = unitdestroyed
tunit = -1
success = 100
# player 2 wins if he conquers
# the enemy building at any time...
[event]
type = score
id = 2
player = 2
trigger = havebuilding
tbuilding = 0
towner = 2
success = 100
message = 3
title = 4
# ...or destroys all enemy units as well
[event]
type = score
id = 3
player = 2
trigger = unitdestroyed
tunit = -1
success = 100
# display briefings on first turn
#
[event]
type = message
id = 4
player = 1
trigger = timer
ttime = 0
title = 5
message = 1
# Even though time index 0 is during player 1ยดs phase
# we want to trigger the message for player 2 as well.
# This way it gets queued for display during the turn
# replay. Otherwise player 2 would only see the briefing
# after his replay.
[event]
type = message
id = 5
player = 2
trigger = timer
ttime = 0
title = 5
message = 2
# we want to support difficulty levels (handicaps)
#
# if player 1 is handicapped we allocate some more
# crystals to players 2ยดs factory
[event]
type = mining
id = 6
player = 2
trigger = handicap
# 1 is no handicap, 2 is player 1, 4 is player 2
thandicap = 2
building = 1
action = 1
crystals = 35
# if player 2 is handicapped player 1 gets another tank
[event]
type = createunit
id = 7
player = 1
trigger = handicap
thandicap = 4
unit = Medium Tanks
pos = 3/2
### english messages
[messages(en)]
The Great Example
Revision 6 (16-08-2004)
by Jens Granseuer <jensgr@gmx.net>
%
This is a nice introductory message, so that player 1 knows what he is expected to do. Word wraps are done automatically, so donยดt include line breaks if you donยดt want them. So, Player 1, letยดs take them apart:
Either conquer the enemy headquarters or destroy all their troops.
%
This should present the situation to player 2.
You are being attacked. Defend yourself. The attack is considered repelled if you gain control of the enemy headquarters or the entire attacking army is no more.
%
This is the success message for conquering the enemy headquarters.
Congratulations!
%
Hip! Hip! Hurrah!
%
The Great Example
%
The Good
%
The Bad
%
HQ of the Good
%
HQ of the Bad
[/messages]
๐ธ NOTES ๐ธ
okay so the file format of level files (both source and data) is subject to change without notice ๐. If you ever get the error "File not of the required type", it mostly should be enough to feed the appropriate source file to cfed again to create a valid level file โ but no promises are being made. You have been warned! ๐
Also, cfed will eventually be phased out in favour of CoMET, the graphical map editor for crimson. it's giving retirement era ๐ซ
๐ SEE ALSO ๐
ยฉ๏ธ COPYRIGHT ยฉ๏ธ
Copyright ยฉ 2000-2007 Jens Granseuer ๐
This software is distributed under the terms of the GNU General Public License[1] (GPL).
โ๏ธ AUTHOR โ๏ธ
Jens Granseuer <jensgr@gmx.net> Author.
๐ NOTES ๐
- GNU General Public License http://www.gnu.org/copyleft/gpl.html
and that's the whole entire page bestie, we ate ๐
โจ this one came from the cfed man page, source/version [FIXME: source], dated January 18 2007 โ iconic, honestly ๐๐ฆ
๐ฆ where this page comes from
- debian trixie: crimson 0.5.3-1
- ubuntu questing: crimson 0.5.3-1
- ubuntu resolute: crimson 0.5.3-1build1
- ubuntu stonking: crimson 0.5.3-1build1
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms