![]() Mechstorm's Complete Map Making Tutorial or MCM for Short. Covering Mechwarrior4, Mechwarrior4:BK and Mechwarrior4:Mercs. If you have any questions feel free to drop by our Mechstorm Editor/Scripting help Forum after you have registered on our forums. |
NFM Anatomy: Guide to creating NFM files.NFM files flat TEXT (ANSI) files that are basically broken down into four parts. Use Notepad or any text editor that does not add formatting to the file. For a point of reference we will be using the NFM attached at the bottom of this document. It contains several variations that show the different types of data that can be specified for a server and team entry. There are default conditions that a game will use if no entry is provided. Some NFMs will appear to be missing information, but what happens is the Hosting engine will use default properties when no entry is available. The Anatomy of an NFM file:
The top two lines are used to include another file as part of this file. This tells the Hosting engine to copy in the identified file as part of the .NFM. It essentially is a way for programmers to develop code once and not have to replicate it for each .nfm file they create. Hence INCLUDE !include=Content\GameTypes.h The path/filename can be opened and viewed on your machine with Notepad. DO NOT MODIFY or ALTER THIS FILE!!! When you examine it, what you should see is this: #define StockBattle 0 #define StockTeamBattle 1 #define StockDestruction 2 #define StockTeamDestruction 3 #define StockMissionPlay 4
#define StockCampaign 5
#define CustomBattle 6 #define CustomTeamBattle 7 #define CustomDestruction 8 #define CustomTeamDestruction 9 #define CustomMissionPlay 10
#define CustomCampaign 11
#define CustomUndefined 12 #define SinglePlayer 13
// make sure this is always set to the number of game types #define GameTypeCount CustomUndefined + 1
The file creates a numeric relationship with a gametype. Gametypes are used for scoring and default properties that are used/required to play. If you opened this file, please close it without saving any modifications now.
[INFO] This section has the name the Author wanted to provide, a single line to identify it being a Standard Mission, a URL pointing to a web site where the map can be found if you connect to the server and don’t have this map, and the name of the map. [info] This is NOT the name of the terrain but the map file names that are in the directory you find the .NFM in. For stock maps, you find the NFM files in Mechwarrior Mercenaries\Resource\Missions. For Custom or maps not provided by Microsoft, you find the NFMs in Mechwarrior Mercenaries\Resource\UserMissions. Do not change the LONGNAME of the NFM. It’s how it finds the other file relationships needed to host the game. Normally you don’t modify anything in the [INFO] section. [RULESET] This section tells the editor and hosting engine what game type categories are supported in the .NFM. In the example below, Battle, Team Battle, Destruction, Team Destruction are the Stock games supported and understood by the hosting engine. The Custom gametypes being supported with this map are Custom Battle, Custom Team Battle and Custom Undefined. TEAMS/TEAM The first problem is that any NFM with TEAMS in the ruleset should be altered to TEAM. The variable TEAMS is created by the editor but even the editor requires the work to be TEAM in order to read it. Sadly, when you save the map (while editing it) it overwrites this variable name back to TEAMS screwing it up. Just remove the ‘S’ off of this variable name so that the syntax is correct. TEAM is the total number of bases/dropzones supported for this map / game type. I.e. Big City as it was created had 8 drop zones in it for Tatt, Att type games. Only 2 DZ in big city are used for CTF. Cleanup in this section is almost always required for non-stock games. It’s common to see all the values set to 1. When it should be the total number of teams available for that given scenario. This value is used by the NFMEditor and will show up in the server cycle list of the NFM editor.
A value of 1 will indicate a zero in the NFMEditor. This value only indicates the total number of teams that can be selected from to play with in a game and must not exceed the total number of dropzones on a map. Crossover has 8 dropzones, 4 built for CTF and the other 4 as team drops for Goliaths (5 vs 6 and 7 vs 8) So the value of an entry here will be dependent upon the maximum number of teams for a ruleset. I.e. Goliaths and Tatt are both set in CustomUndefined (12) ruleset and while we’d never have teams 5-8 used for Tatt, the value would be 8 to set the stage correctly for Goliaths on Crossover. Alignment is normally always set to 1 as is Teams for this section. The alignment function is believed to be used for games where 2 or 3 teams would be grouped to work cooperatively against one or more other teams. To date we’ve not seen this option exercised. Some NFMs include the scriptnames under [Ruleset] section that are embedded within the map that are used for the custom name. Some NFMs don’t have this entry here. SCRIPTNAME lines are not required by the HOST server. They are used soley by the author/map creator in this section. They can be stripped out of ruleset. The paths where the files are normally packed are ones that show the following: Content\Missions\<mapname>\Scripts\<filename>.ablMost of the time the filename will be descriptive of what type of game it’s for.
[ruleset] [SCENARIOS] This is the meat of what admins should focus on in order to make hand edits to NFM.
Look at one and you'll see a pattern between game scenarios.
Here’s a sample of gametype that has a name of Battle. Battle={ } The first line is a unique name/header for this scenario. A couple of samples of unique headers are: Battle={CTF 1 vs 2={ StockTeamDestruction={
Doesn't matter what the name is left of the equal sign (within reasonable length) it’s just a way for the hosting engine to uniquely identify a given scenario. I usually use very descriptive names. i.e
CTF 1 vs 2 ={ Goliaths 5 vs 6={ CTF All 4={
Other map makers may use some of the default assigned naming conventions that the editor places in their NFM file for them. You’ll see why it’s important after reviewing the attached NFM below. Easy to locate, make modifications and to select from when using the NFM editor to modify your server cycle. Important Note on open and closed braces within a section: Like algebra syntax is very important for the formula to come out right. In the NFM there is one open brace at the start of a scenario and one at the end of a scenario definition. Blow a brace and the game can't load. You’ll net a missing ‘}’ error as the host reads NFMs when it loads up. Within the scenario braces you can have team data information, which itself also has an open and close brace for each team. Once again like in algebra, for every open brace you need a corresponding close brace.
This attached below is Crossover.NFM. The section you want to focus on is in the BLUE. Teal is for my comments.
Ok....that was easy. Now lets do a CTF game where there are 4 teams for the map.
Rulesets.....well under custom game type custom undefined, custom team battle and custom battle are where most map makers are throwing the BK gametypes. Mektek's done a lot in Custom Undefined -12 , Mercstorm is moving their maps to Custom battle - 6 Custom Team Battle - 7 and Custom Undefined - 12 dedending upon the game type supporting teams, and bots.
Under Custom Team Battle, bots are not supported. So depending on how the map maker put elected to set up his initial NFM file, you may be able to play with bots in games you normally haven’t in the past. Note: Bots aren’t smart enough to play games like Koth, Tkoth, STB and CTF. To date, I don't think anyone has loaded up games in Custom Destruction and Custom Team Destruction, but those are available depending upon the mapmaker’s choice.
A couple more variables for the nfm.....are described in Sysopreadme.RTF in your Mercenaries directory. For a view of the Mercenaries skin chart please see the attached HTML file. Server Variables RadarMode 0 means the default radar can be used, 1 means team radar can be used, and 2 means no radar can be used. IsNight 0 means always day, and 1 means always night. Visibility 0 is default visibility, 1 means clear , 2 light fog, 3 means heaviest fog, 4 mean pea soup (Thanks to PerryRaptor for the correction). Weather 0 means there are no weather effects, and 1 means there are weather effects. KillLimit 0 means there is no kill limit, and 1 means there is a kill limit. KillLimitNumber 1 means the kill limit is one, 2 means the kill limit is two, and so on. If the value of KillLimit is 0, then the value for this parameter has no effect. NoRespawnLimit 0 means players can respawn, and 1 means players cannot respawn. MaximumCBills Number indicates the maximum amount, in C-Bills, that any individual ‘Mech owned by a player can cost. Possible values range from 10,000,000 through 25,000,000. Note that commas cannot be used in entering MaximumCBills values.
Teamdata variablesMaximumTonnage Number indicates the maximum drop weight (in tons) allowed per Mech MinimumTonnage Number indicates the minimum drop weight (in tons) allowed per Mech MaximumTotalTonnage Number indicated the Total drop weight of the team (in tons) allowed OnlyStockMech 0 means variant ’Mechs are allowed, and 1 means only stock ’Mechs are allowed. Alignment (not sure what this is for) Gotcha’sThe NFM editor has some bugs in it. It tends to strip out script names for all custom game scenarios short of Custom Undefined games. In this case for a custom game, you’ll get the File Not Found error and the game will exit. You’ll either have to manually recreate the line by hand that it stripped, or you’ll need to reinstall the NFM file to correct the problem. You really can’t add Custom Undefined games at all, unless the map maker distributed the scripts with the games. It will also strip MaxplayerOnTeam=0 out. While it can create rules with that syntax in the NFM, if you open it again, the editor removes that line when you exit. I personally recommend using the NFM editor only for adding rules to the server cycle. ConclusionWhen you start out editing an NFM, just make a backup so if you have a problem can return to the original. It's only text. Manipulate, copy and paste sections, change variables. It's really quite easy. Read through the attached script and see if there’s anything that isn’t clear at this point. !include=Content\GameTypes.h !preservecase=true [info] author=CTF Timberliners info=Standard Mission link=www.mercstorm.com/mercsctf.html longname=Crossover
[ruleset] type=$(StockTeamBattle) Team=4 Alignment=1 type=$(StockTeamDestruction) Team=4 Alignment=1 type=$(CustomBattle) Team=1 Alignment=1 type=$(CustomTeamBattle) Team=4 Alignment=1 type=$(CustomUndefined) Team=8
[scenarios] Battle={ !preservecase=true [server] name=Battle ruleset=0 TeamAllowed=0 }
TeamBattle={ !preservecase=true [server] name=Team Battle ruleset=1 TeamAllowed=1 TeamCount=4 team_0={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=b } team_1={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=d } team_2={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=l } team_3={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=o } }
Destruction={ !preservecase=true [server] name=Destruction ruleset=2 TeamAllowed=0 }
TeamDestruction={ !preservecase=true [server] name=Team Dest ruleset=3 TeamAllowed=1 TeamCount=4 team_0={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=b } team_1={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=d } team_2={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=l } team_3={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=o } }
CTF1vs2={ !preservecase=true [server] ruleset=7 name=CTF 1 vs 2 teamAllowed=1 teamcount=4 ScriptName=Content\Missions\Crossover\Scripts\ctf.abl scenariotext=resource\missions\ctf.txt gameLength=30 team_0={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=b } team_1={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=d } team_2={ !preservecase=true [teamdata] MaxPlayersOnTeam=0 skin=l } team_3={ !preservecase=true [teamdata] MaxPlayersOnTeam=0 skin=o } }
CTF1vs3={ !preservecase=true [server] ruleset=7 name=CTF 1 vs 3 teamAllowed=1 teamcount=4 ScriptName=Content\Missions\Crossover\Scripts\ctf.abl scenariotext=resource\missions\ctf.txt gameLength=30 team_0={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=b } team_1={ !preservecase=true [teamdata] MaxPlayersOnTeam=0 skin=d } team_2={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=l } team_3={ !preservecase=true [teamdata] MaxPlayersOnTeam=0 skin=o } }
CTF1vs4={ !preservecase=true [server] ruleset=7 name=CTF 1 vs 4 teamAllowed=1 teamcount=4 ScriptName=Content\Missions\Crossover\Scripts\ctf.abl scenariotext=resource\missions\ctf.txt gameLength=30 team_0={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=b } team_1={ !preservecase=true [teamdata] MaxPlayersOnTeam=0 skin=d } team_2={ !preservecase=true [teamdata] MaxPlayersOnTeam=0 skin=l } team_3={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=o } }
CTF2vs3={ !preservecase=true [server] ruleset=7 name=CTF 2 vs 3 teamAllowed=1 teamcount=4 ScriptName=Content\Missions\Crossover\Scripts\ctf.abl scenariotext=resource\missions\ctf.txt gameLength=30 team_0={ !preservecase=true [teamdata] MaxPlayersOnTeam=0 skin=b } team_1={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=d } team_2={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=l } team_3={ !preservecase=true [teamdata] MaxPlayersOnTeam=0 skin=o } }
CTF2vs4={ !preservecase=true [server] ruleset=7 name=CTF 2 vs 4 teamAllowed=1 teamcount=4 ScriptName=Content\Missions\Crossover\Scripts\ctf.abl scenariotext=resource\missions\ctf.txt gameLength=30 IsNight=1 team_0={ !preservecase=true [teamdata] MaxPlayersOnTeam=0 skin=b } team_1={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=d } team_2={ !preservecase=true [teamdata] MaxPlayersOnTeam=0 skin=l } team_3={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=o } }
CTF3vs4={ !preservecase=true [server] ruleset=7 name=CTF 3 vs 4 teamAllowed=1 teamcount=4 ScriptName=Content\Missions\Crossover\Scripts\ctf.abl scenariotext=resource\missions\ctf.txt gameLength=30 team_0={ !preservecase=true [teamdata] MaxPlayersOnTeam=0 skin=b } team_1={ !preservecase=true [teamdata] MaxPlayersOnTeam=0 skin=d } team_2={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=l } team_3={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=o } }
CTFAll4={ !preservecase=true [server] ruleset=7 name=CTF All 4 teamAllowed=1 teamcount=4 scenariotext=resource\missions\ctf.txt scriptname=Content\Missions\Crossover\Scripts\CTF.ABL gameLength=30 team_0={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=b } team_1={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=d } team_2={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=l } team_3={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=o } }
GiantKillers56={ !preservecase=true [server] name=Goliaths 56 45-90 ruleset=12 ScriptName=Content\Missions\Crossover\Scripts\GiantKillers.abl scenariotext=resource\missions\giant.txt TeamAllowed=1 TeamCount=8 gamelength=30 team_0={ !preservecase=true [teamdata] minimumTonnage=45 MaxPlayersOnTeam=0 Skin=b } team_1={ !preservecase=true [teamdata] maximumTonnage=90 minimumTonnage=100 MaxPlayersOnTeam=0 Skin=d } team_2={ !preservecase=true [teamdata] maximumTonnage=25 minimumTonnage=45 MaxPlayersOnTeam=0 Skin=l } team_3={ !preservecase=true [teamdata] maximumTonnage=90 minimumTonnage=100 MaxPlayersOnTeam=0 Skin=o } team_4={ !preservecase=true [teamdata] maximumTonnage=100 minimumTonnage=90 MaxPlayersOnTeam=5 Skin=d } team_5={ !preservecase=true [teamdata] maximumTonnage=45 minimumTonnage=25 MaxPlayersOnTeam=11 Skin=y } team_6={ !preservecase=true [teamdata] maximumTonnage=45 minimumTonnage=25 MaxPlayersOnTeam=0 Skin=t } team_7={ !preservecase=true [teamdata] maximumTonnage=100 minimumTonnage=90 MaxPlayersOnTeam=0 Skin=z } }
GiantKillers78={ !preservecase=true [server] name=Goliaths 78 45-90 ruleset=12 ScriptName=Content\Missions\Crossover\Scripts\GiantKillers.abl scenariotext=resource\missions\giant.txt TeamAllowed=1 TeamCount=8 gamelength=30 team_0={ !preservecase=true [teamdata] minimumTonnage=45 MaxPlayersOnTeam=0 Skin=b } team_1={ !preservecase=true [teamdata] maximumTonnage=90 minimumTonnage=100 MaxPlayersOnTeam=0 Skin=d } team_2={ !preservecase=true [teamdata] maximumTonnage=25 minimumTonnage=45 MaxPlayersOnTeam=0 Skin=l } team_3={ !preservecase=true [teamdata] maximumTonnage=90 minimumTonnage=100 MaxPlayersOnTeam=0 Skin=o } team_4={ !preservecase=true [teamdata] maximumTonnage=100 minimumTonnage=90 MaxPlayersOnTeam=0 Skin=d } team_5={ !preservecase=true [teamdata] maximumTonnage=45 minimumTonnage=25 MaxPlayersOnTeam=0 Skin=y } team_6={ !preservecase=true [teamdata] maximumTonnage=45 minimumTonnage=25 MaxPlayersOnTeam=11 Skin=t } team_7={ !preservecase=true [teamdata] maximumTonnage=100 minimumTonnage=90 MaxPlayersOnTeam=5 Skin=z } }
KOTH={ !preservecase=true [server] name=KOTH ruleset=6 TeamAllowed=0 ScriptName=Content\Missions\crossover\Scripts\KOTH.abl scenariotext=resource\missions\koth.txt }
TABS={ !preservecase=true [server] name=Team ABS ruleset=12 TeamAllowed=1 TeamCount=4 ScriptName=Content\Missions\crossover\Scripts\TeamAbsoluteAttrition.abl scenariotext=resource\missions\tabatt.txt team_0={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=b } team_1={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=d } team_2={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=l } team_3={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=o } }
Attrition={ !preservecase=true [server] name=Attrition ruleset=12 TeamAllowed=0 scriptname=Content\Missions\crossover\Scripts\Attrition.abl scenariotext=resource\missions\att.txt }
AbsAtt={ !preservecase=true [server] name=AbsAtt ruleset=12 TeamAllowed=0 scriptname=Content\Missions\crossover\Scripts\AbsoluteAttrition.abl scenariotext=resource\missions\abatt.txt }
TATT={ !preservecase=true [server] name=Team Att ruleset=12 TeamAllowed=1 TeamCount=4 scriptname=Content\Missions\crossover\Scripts\TeamAttrition.abl scenariotext=resource\missions\att.txt team_0={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=b } team_1={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=d } team_2={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=l } team_3={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=o } }
TKOTH={ !preservecase=true [server] name=Team KOTH ruleset=7 TeamAllowed=1 TeamCount=4 scriptname=Content\Missions\crossover\Scripts\TKOTH.abl scenariotext=resource\missions\koth.txt team_0={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=b } team_1={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=d } team_2={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=l } team_3={ !preservecase=true [teamdata] MaxPlayersOnTeam=8 skin=o } }
STB={ !preservecase=true [server] ruleset=6 name=Steal the Beacon teamAllowed=0 scriptname=Content\Missions\crossover\Scripts\StealBacon.abl scenariotext=resource\missions\stb.txt gameLength=30 } |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||