• We have updated our Community Code of Conduct. Please read through the new rules for the forum that are an integral part of Paradox Interactive’s User Agreement.

Amechwarrior

General
9 Badges
Feb 23, 2018
1.863
146
  • BATTLETECH - Backer
  • BATTLETECH - Beta Backer
  • BATTLETECH - Initiate of the Order
  • BATTLETECH
  • BATTLETECH: Flashpoint
  • BATTLETECH: Season pass
  • BATTLETECH: Heavy Metal
Looking to tell your own story in BATTLETECH? This thread is a guide on how to craft a story in to a Flashpoint (FP) using ModTek and other free tools. I will cover the basics of the FP system and how to get them loaded in to the game via ModTek.

The second post will cover advanced topics like spawning requirements, complex Event Results, failure Milestones and contextual conversation options.

One thing I want to say at the start, writing these Flashpoints is a lot of fun. It might take you a while to get it done, but others like @akodoreign manage to put them out incredibly fast. I want to encourage everyone to try and make their own FPs. I've only just got started pioneering the process. I'm sure with more people diving in and experimenting in ways I haven't, we'd be able to tell ever greater stories and expand the experiences possible with BATTLETECH.

Also, I know nothing. I've only been able to hack this all together with experimentation, a lot of help from other modders and asking questions to HBS staff when they had the time to assist on Discord. I'm sure something in here will be wrong or not quite correct, and something I think isn't possible probably is. So, take all this with a grain of salt, I've barely scratched the surface of this beast.

The Idea

First thing is "Why?" Why are you trying to make a FP? Is it to create a challenge? To tell a story? To give players a fun experience? For the challenge of creating something? The reason why you are doing this should be thought about at every stage of the process. Keep this idea in mind as kind of a "mission statement" or anchor that will shape how you form things from the choices the player can make to the kinds of missions you use.
  • "I want to make a challenging set of missions based around a planetary invasion"
  • "I want to make a few low difficulty FPs for the early game"
  • "I want to tell the story about that one time Darius and Sumire got stuck on a frozen world and we had to go rescue them from ice pirates"
The Decision

Second thing is that Flashpoints are about making a decision. Either A or B, not A & B. Now, you don't need to have a branching choice in your FP, you could just as easily make a full FP with nothing but a single mission and conversation around it, or 4 missions with no conversation or choices. However, the choices you want the players to make, and where those decisions are, will greatly impact the amount of work that needs to be done. Doubly so if you have more than one FP Decision point.

If you make an initial split like "Joint Venture" the missions are on two separate branches for the entire FP. If you make a five mission FP with an initial "A or B" branch, that's ten missions to construct. The earlier the split, or the more splits you make, the more work that needs to be done with missions, conversations, rewards, tag tracking and anything else that makes one branch different than another.

The Tools

Once you have an idea and how the players choices will affect that idea, you can get to work actually building something. HBS has graciously included a set of editors in the game here:
..\BATTLETECH\BattleTech_Data\StreamingAssets\editors
  • Flashpoint Editor - For editing FPs and their associated Milestone Sets
  • Event Editor - For editing Argo Events like "The Last Cup" or "Happy Accidents" (FFF Burgers)
  • Contract Parser - For taking .txt files and converting them in to fully qualified contract .jsons
You will also need the following free tools:
  • Notepad++ - For editing .jsons (a fancy txt file with rules, almost everything in HBS BT is run by .jsons)
  • ConverseTek - For creating custom conversations on the Argo with your crew.
  • CSVed - For editing .csv files used in itemCollections for FP rewards.
Optionally, some kind of image editor like Photoshop, GIMP or Paint.net may be needed if you want custom art assets like Holoscreen images or a unique title card. They need to be able to save in both .png and .dds formats.

Debug Mode
debug_on.jpg
You're going to want to enable Debug Mode to allow quick turnaround for testing. A Debug Save populates all available FPs within 14-30 days and lets them re-populate quickly if failed. Be aware, don't leave this on all the time. It generates some default dump files and will mess with your PvP sync if the other end doesn't have it enabled too.

@HBS_Eck has created Eck's Debug Guide for modders.

What can Debug Mode get you?
simgame Debug Window
You can spawn 'Mechs whole, grant cash and rep/MRB ratings and more. You can't access this window in a non-Debug save.

combatgame Debug Window
You can enable "God Mode," auto-win a contract, dump info and more. This can be accessed in either Debug or non-Debug saves.

Over the course of figuring out how to make an FP, I've come back to a lot of lists, charts and other references over and over again. I've compiled the stuff I needed to reference together in to one googledoc. This contains a lot of data pulled directly from the game's MetaData Database (MDDB) and other sources. Huge shout out to @scJazz who compiled the immensely useful "Contracts" sheet for me with the optional chunks listed. That saved a lot of time narrowing down which contracts I could build from quickly.

Flashpoint Reference Sheets - GoogleDoc
  • Map Names - List of all maps by Biome
  • MoodIDs (Weather) - List of all weather types, "Verdant" set is used for High/Lowlands
  • EncounterLayer (Map+Contract) - List of all possible combinations of Map+Contact type sorted by contract type
  • Contracts - Listing of contract .json names and what kind of optional chunks they have active by default
  • CastID/SpeakerID for Group Conversation - List of likely cast members for Argo conversations, not every castDef is listed, just those used in the stock game in an Argo conversation
  • uixTxrConv for Viewscreen Image - The list of images that can be shown on the Holoscreen, the "uixTxrConv_" prefix has been removed for easy copy/paste in to ConverseTek
  • Commander Tags - Your Commanders history choices like "Taurian Ancestry" or "Exiled"
  • 'Mech Lance Tags - Used in procedurally generated Lances, so you can get an idea of what could spawn
  • Color Swatches - For custom Heraldry, these are the same color options for your 'Mechs paint-job
Flashpoint Aid: "Flashpoint Stock Photos"
Flashpoint Stock Photos is a small mod with some very basic Holoscreen images like the missing "Locals Liaison" and a map of the Inner Sphere that are not present in the base game. I made this streamlined image pack to allow FP authors to share some basic imagery without needing to duplicate it for each FP.

Flashpoint Aid: FP_choice_placeholder.bytes
FP_choice_placeholder.zip attached in this post contains a single .bytes conversation file. This file is nothing more than a simple conversation with the common Flashpoint Decision Tags clearly displayed. It is used as a placeholder for your FP's TalkChoice conversation until you have written your own. This allows you to test out the FP's Milestone linkages and tags quickly. You can also open this in ConverseTek and edit the tags or node as needed for testing.

Flashpoint Aid: "The Sound of Music"
"The Sound of Music" is a Flashpoint I created to just listen to each possible music track you can call for Argo conversations.

Flashpoint Aid: "Training Wheels"

"Training Wheels" was my initial proof of concept that a custom FP could be done. I'll re-work this in to a proper guide/FP in time.

Flashpoint Aid: "The Raid"
"The Raid" is my first fully featured FP and touches nearly every aspect of the game, from custom missions and OPFOR, to failure branches and post FP events. This can serve as a comprehensive working reference for about anything that needs to be done.

Writing Aid: Classic Battletech Style Guide (Archived)
This archived page contained the writers guide for BattleCorps story submissions. This is an excellent source for how you should write BT specific words like 'Mech, MechWarrior, DropShips, ranks like Tai-sa and units like the Twenty-first Galedon Regulars in the correct format.

Eck's Contract Parser Guide
@HBS_Eck has also put together a Contract Parser Guide to the Contract Parser I will cover below. This tool that comes with the game will allow you to quickly put together the custom contracts for your FP.

The Workflow

"This is a lot of crap! Where do I start?" is something you might be asking. I find it's best to create the Flashpoint file in the editor, formulate your FP structure and branching, test that format with placeholder conversations, missions and rewards and then fill in the rest as you wish. Getting a solid FP structure and testing them out to make sure you can go from one link in the chain to the next is essential and should be robustly stress tested to make sure you won't leave a player stranded with a bad conversation, tag or branch that goes nowhere. It's really easy to make a FP that links to a bad/missing item and enter a shadow-zone where Farah or some other crewmate has gone invisible and you can't complete or abandon the FP to get them back. I've done it many times...

The Templates

HBS has included a bundle of templates for just about everything in the game, including FPs. These are the same templates the stock FPs are built from and their conversation filenames still reference the type they were built from. These templates are great examples for almost any combination of FP branches from early/mid/late splits, optional objectives and even three-way splits. You can also use a modders FP files as working examples. The stock FPs are kept inside an asset bundle, away from easy access. They can be extracted and referenced, but I'm not going to discuss that in this post. The default templates are located here:
..\BATTLETECH\BattleTech_Data\StreamingAssets\data\flashpoints
The Flashpoint Editor will look for .json files in this location by default and save files there as well.

THIS IS NOT WHERE YOUR FP NEEDS TO BE TO LOAD IN TO THE GAME.

I'll address this down in the ModTek section below.

The Stand-Alone Editor Folder
While this is an optional step, I highly recommend doing this before you start editing anything.

There's a really big chance you might insert something in to the stock folders or edit something you shouldn't have if you work out of the game's running \StreamingAssets\data\ structure. However, the various editors assume this structure and pull items from it. What I did was copy everything I needed out of the game's folders. This also ensures any HBS update or steam/GoG/etc validation doesn't remove your files.
editors_standAlone.jpg

Before you copy these HBS folders out of the \BATTLETECH\BattleTech_Data\StreamingAssets\ you need to make sure you copy the folders inside \data\ without the "assetbundle" or "maps" folder, these are massive and you don't need them. Removing them cuts the Stand-Alone Editors to about 150mb from many gigs in size.

Afterwards, I made a desktop shortcut for the FP editor at the new location. This makes it easy to use in the isolated location and my actual game files stay unaltered even when I make mistakes at 3am. You do need to make sure you copy over all of these again anytime HBS pushes an update.

The Flashpoint .json Structure

The Flashpoint Editor opens a FP file, "fp_TEMPLATE_initialChoice.json" from the location above. This file contains:
  • The displayed name, InternalName and Id of the FP as a whole ("Joint Venture" is displayed, "longRoad" is the InternalName and fp_longRoad is the Id)
  • Icon - The image at the top of the title card, all stock FPs use a blank entry for the default FP banner - Must be .png or .dds, default size is 750x300 pixels
  • Weight - The odds this FP spawns next, default is 10, Joint Venture is 200, Alliance FPs are 1000
  • Difficulty - 1-10, this is 2x the skull values you see in game. Diff. 10 = 5 Skulls, Diff. 5 = 2.5 Skulls
  • Required or Excluded Tags - Like requiring "ALLIED_FACTION_Liao" for the Liao Alliance FP
  • Location Requirements - What planet(s) it takes place on, usually the tag of the planet itself "planet_name_adrar"
  • PotentialEmployers - Who's paying for this mission
  • TargetFaction - Who the Employer is paying you to hit
  • Optional Restrictions - Min/Max Drop weight warnings, no refit time, etc
  • MilestoneSetID - This tells the game what Milestone Set to use, the most line of code in your FP
  • RewardCollectionID - The default reward and title card reward description
  • FlashpointShortDescription - The short description seen at the bottom of the title card
  • FlashpointDescriberCastDefId - Who is telling the player about this FP
All of this becomes the Title Card:
The Raid Title Card.jpg

In the FP editor it looks like this:
fpeditor_mainScreen.jpg

Editing FP Files
HBS Formatting for FP files:
  • Filename: fp_yourStory.json - Created by saving the FP after setting InternalName
  • Id: fp_yourStory - Created by setting the InternalName
  • InternalName: yourStory - The first word is often not capitalized in HBS-Land, consider it a general rule
  • Name: Your Story Title - What you want the title card, and thus the player to see as the title for this FP
Set your InternalName first!
Changing your internal name has cascading effects on the resulting files created and associated with this FP. The first step in editing your FP should be giving it a unique internal name you don't intend to change. Remember, this isn't the name shown to the player, ever. This is just the name the game uses to categorize your stuff from another FP.

Set the Location Requirements (Employer, Target and Planet)
The next thing you would want to define is who is this FP fighting for, against and what planet it starts on. The section labeled "Location Requirements" shows the "Potential Employers" which can be edited and selected from the list of faction tags. I've not experimented with multiple potentials yet.

The Target Faction is a drop-down list, take note of the spelling and capitalization of factions on this list. You will need to copy these exactly as shown for later when you define your contracts in milestones.

The "Required Tags" is where you would define what planet it starts on. I believe it might be possible to start a FP at one location and move to others, but I haven't tested this. You can find the tag you need by opening up the data/starsystem folder and opening the planet's .json file you need. You will see a tag with the planet's name on it:
planet_name_Tiverton
This would set the possible starting planet to require the tag "planet_name_Tiverton" of which only one planet has, Tiverton. I picked Tiverton for "The Raid" because it fit my needs the best. The story dealt with assaulting the Black Market on an independent world and I had certain Biomes in mind. I had to look around in-game in one of my saves with Black Market access and looked for the one or two that fit my needs best. I recommend doing this in a Debug save, to see if any FPs already appear on that world. You will also need to pay attention to the Biomes that world supports, found in that planet's .json. You don't really want a Martian or Lunar only FP taking place on worlds that don't have that available. However, I did manage to set my first two missions on a Lunar Biome, even though the Tiverton.json did not have that in the list of supported Biomes that generated contracts would select from. I also made sure to write in why I was using a normally unsupported Biome for that planet. In my case, one of Tiverton's moons was being used for a Black Market exchange and officially the moons had never been colonized.

Set the Optional Restrictions

This can be done near the end of your process. You might want to check some of them right away, but I don't think the game or the editor cares too much if what is selected is accurate. You could check "Allow Refit" and then make a FP with all consecutive drops with no refit pause in between. Make sure your final product is accurately reflected in your optional restrictions.

Set the Short Description
This is the text at the bottom of the title card. This is should be short and sweet and try to entice the player in to accepting your job. Like the optional restrictions, this can be saved for later to make sure it accurately reflects the final product. You may want to look at other stock title cards to get an idea of what info they deemed important, sometimes less is more.

Setting Conditional Requirements for FP Spawning
You can set FPs to only appear if the player's save has or doesn't have certain tags or values like "MRB Rating greater than X" or must have/not have "ALLIED_FACTION_Liao" and I'll cover that in the Advanced Editing Post below this one. For now, it's better to just get your FP structure laid out and tested before adding restrictions on it appearing.

Setting the Icon
A picture can say a thousand words and HBS made one title card icon to represent all FPs from Joint Venture to ones featuring Morgan Kell and Justin Allard. You don't need to make a custom icon for every FP. I'm going to recommend it though. This will help clearly separate stock FPs from modded ones even if a player has left the game for months and comes back to it, forgetting what was stock and what was modded, then makes a bug report about a non-stock FP.

The format for title card icons are:
  • .dds or .png files
  • 750x300
  • Flipped on the vertical axis for both formats
  • Filename prefixed by "uixTxrSpot_"
Here is the one for "The Raid" saved as uixTxrSpot_fp_theRaid.png for display in this post, the real one is saved as .dds.
uixTxrSpot_fp_theRaid.png

Note the dark bar at the "bottom" of the image, this is to make the "Flashpoint: Expires in X Days" stand out against a similarly colored background, this bar is 24px tall and I think the in-game bar is roughly 24 or 25px high. There is also a light blue "Active Flashpoint" bar that replaces the expiration date once you accept the job, so I recommend a darkened or full black bar so any status message pops out and is easily readable.

The Milestone Sets Structure

The Milestone Sets (MS) are the most important part of the FP. If the FP file is the "cover" of a choose-your-own-adventure book, the MS .json is the index and the breadcrumbs at the bottom of the pages. The MS file such as "ms_fp_TEMPLATE_initialChoice.json" contains all of the triggers, event results, branches and mission parameters for the FP.

The MS file is created by the FP Editor alongside your FP file when you save it for the first time. As it's created by the Editor for you, it takes care of a lot of the naming and formatting. The "Reorder Milestones by Links" will format them automatically. MS files are .jsons stored in and read from:
..\BATTLETECH\BattleTech_Data\StreamingAssets\data\milestoneSets
Be aware, the "milestones" and "milestoneSets" folders are different. "milestones" is used for the main campaign and each milestone was a separate .json, where milestoneSets are collections of milestones all inside a single .json for FPs. This is a much neater system and some of the functions are not the same between the two.

In general, MS start a 001 and increment up until they branch out. Each branch increments the first digit by one. In the initialChoice template, where the branch is at the start, we see this:
  • ms_fp_TEMPLATE_initialChoice_001_Start
  • ms_fp_TEMPLATE_initialChoice_002_TalkChoice
  • ms_fp_TEMPLATE_initialChoice_003_Branch
  • ms_fp_TEMPLATE_initialChoice_100_A-Mission
  • ...
  • ms_fp_TEMPLATE_initialChoice_103_A-Complete
  • ms_fp_TEMPLATE_initialChoice_104_A-Reward
  • ms_fp_TEMPLATE_initialChoice_200_B-Mission
  • ...
  • ms_fp_TEMPLATE_initialChoice_203_B-Complete
  • ms_fp_TEMPLATE_initialChoice_204_B-Reward
  • ms_fp_TEMPLATE_initialChoice_300_Cancel-Complete
  • ms_fp_TEMPLATE_initialChoice_301_Cancel-Reward
We start at the 000 series, that hits a branch that splits in to the 100, 200 and 300 branches. 100 and 200 are separate missions, conversations, completions MS and rewards. The 300 series here is the cancel track. This is an optional track that most FP's don't need. You only really need this one if you are either giving the player a chance to turn it down forever and complete the FP without participating (Like "Flattened Earth's" initial conversation) or maybe used as a partial reward if they are offered an out in the middle. However, there is already an optionalEncounter template that does this better. This "300_Cancel-Complete" branch is already setup for canceling the FP permanently with no rewards.

At this point, the best thing you can do is to open up the FP Editor, pick a template like "Initial Split" and browse through every MS by clicking on one to highlight and then hit "Edit" to see more details. Going through these first, then looking up how each data field is used will help you put it together better than reading this guide strait through.

This initialChoice template would have us start, go in to a "TalkChoice" MS where it would call a conversation, have us pick a Flashpoint Decision inside that conversation and set a unique tag. Then, the Branch MS would trigger and pick one result that matches the tag applied in the conversation, sending us on either the 100, 200 or 300 branches. The 100 and 200 branches have missions, talks and other MS labeled "A" and "B" respectively. You can have a "C" branch, and maybe even more, but the workload starts to become cumbersome.

Inside each MS, there is an "Action" that must contain a link to the next one in the chain. You can have multiple actions in a branching MS that link to different MS but make sure your use of Required/Excluded tags is logical sound and won't allow double dipping. The three kinds of actions that can set a next milestone link are:
  • Flashpoint_SetNextMilestone - Just type in the next MS id in the data here
  • Flashpoint_AddContract - Has the line "Next Milestone Id" works the same as "SetNextMilestone"
  • Flashpoint_StartContract - Has the line "Next Milestone Id" works the same as "SetNextMilestone"
If you have one of these in an Event Result, you don't need the others. If you are working on a Branch MS, you would have a few "Flashpoint_SetNextMilestone" statements, one in each Event Result. This will be detailed bellow.

You should edit and create MS inside the FP editor, but you can copy/paste and edit MS whole or in part in the .json with a text editor. So far, I create the MS and names in the editor, click "Reorder MS By Links" and then save the FP and exit the editor. I then open the ms_fp_yourStory.json in Notepad++ and correct the rewards MS numbers as they are bugged and get re-numbered. If you don't like the default numbering scheme, you can change that manually too, but be careful. Once that's edited, I re-open the FP editor and click Reorder again, if the only errors look like this:
Code:
ERROR-Milestone with old id [ms_fp_theRaid_108_HalfCredit-Reward] and new index[800] doesn't have anyone who points to it.
For each reward MS you have, then the rest are good as is and you can hit "Cancel" to preserve your formatting. If you see other errors like these:
Code:
ERROR-Milestone with old id [ms_fp_theRaid_002_TalkForCancel] and new index[2] has a next milestone id [ms_fp_theRaid_003_BranchForCancel1] which could not be found.

ERROR-Milestone with old id [ms_fp_theRaid_003_BranchForCancel] and new index[100] doesn't have anyone who points to it.

ERROR-Milestone with old id [ms_fp_theRaid_100_MissionSim] and new index[101] doesn't have anyone who points to it.
You got some more basic problems and the editor can't find missing links in your chain.

NOTE: BUG FIXED IGNORE THIS -There is a bug with the Reorder Links Button, it doesn't recognize "Rewards" MS that come after "Complete" MS and you can just hand edit them back to 100/200 series as needed using your .json editor.
fpeditor_milestoneEditor.jpg
Here is the pop-out Milestone Editor Form, opened by clicking "Edit" after highlighting one of them in the MS list at the bottom of the FP editor. The Id and Name are somewhat hard to edit and grasp at first. Changing the name, then hitting the "Reorder Milestones By Links" in the main FP editor window will update the Id to "ms_(FP Id)_(Number)_(Name of Milestone)"

The "Scope" of these is usually "Flashpoint" to tell the game it takes place in the realm of this specific FP. The Scopes cover the areas you'd expect in that the "Company" scope covers the kinds of things like tags you take with you after events or completing the Campaign or FPs. The "Mech" or "Mechwarrior" Scopes would get used in Argo Events to wound or impact a specific pilot or 'Mech. For FPs, the two scopes that are the most used will be "Company" and "Flashpoint." At first, just keep these to what the templates use, which is usually "Flashpoint" for the MS Editor Form.

Towards the bottom of the MS Editor Form, there is a list of "Results," these are the core of what happens during this MS and where to link to the next MS in the chain. The titles of these events are declared in their "Scope" in the MS Event Results Screen.
  • Company - Almost all of your Event Results (missions, convos, complete, rewards) will be Company Scope
  • Flashpoint - Your starting MS will have one of these to clear any FP choice tags at the start, also possibly to set a choice tag in a later MS
You can have multiple Event Results with the same or different scopes as needed, if you make them temporary, they will be prefixed by "(Temp)" and you can have many different Temp-Results for as many different periods of time as you need. For example, you would have a permanent result that generates the current mission in the chain and also adds 1 to the company's morale. Along with this could be a temp result that sets the companies MedTechs higher or lower for x days, and another temp result that removes the tag "company_blackMarket_OFF" to turn off Black Market access for y days.

Keep in mind, Company Scope tags and status modification edits like Mech/MedTech numbers will carry on after the FP is completed or abandoned. If you are not careful to set some of these things as temporary, you can permanently alter the players Argo Tech crew counts, morale, cash and even make cast members go invisible forever. Use these carefully and try to test them thoroughly to make sure anything you alter can be undone in a reasonable time.

The MS Event Results Screen
fpeditor_eventResult.jpg

This is what you see when you hit Add/Edit a MS result. In this case, there are two things this Event Result does:
  • Flashpoint_AddContract-mapGeneral_tropicalCove_vJung
  • System_ForceDropshipRoom-Contract
These are "Actions" and can be added or deleted at the "Action Type" at the bottom.

First, at the top, there is the Scope of this Event Result, "Company" in this case, no tags are added or removed and just below we see the "Random Scope" area. This is a LIE. This area is a "Required Scope" area, not "Random." This is where you would check for if the player has/has not certain tags or comparisons such as "Morale Greater Than X." This area is where your FP Branch MS detects which fp_choice_x tag the player has been given and where to go from there. This is an incredibly important thing to pay attention to and below I will show you how the branching works.

Within this Company Scope Event Result, the first Action sets up the details of the currently available contract. You can see the details of it on the lower right. There are two different Actions that generate a FP contract.
  • Flashpoint_AddContract - Creates a non-consecutive Contract, like a normal job
  • Flashpoint_StartContract - Forces a consecutive Contract to start immediately
Obviously, choosing the right one is really important. If you want to force the player to launch back to back, "Flashpoint_StartContract" would be used for the 2nd or higher mission to force them to start the next contract. "Flashpoint_AddContract" Adds it to the top of the Contracts screen in the Argo's menu to be launched at the players convenience. The next Action in the example "System_ForceDropshipRoom-Contract" forces the players Argo menu to the Contract Negotiation Screen, where the new contract called in "Flashpoint_AddContract" will appear. This sets them up to negotiate their Pay/Salvage sliders and carry on playing. Yes, you could dump them in say the 'Mech Bay or Cmd. Quarters, but why?

A "Flashpoint_StartContract" does not need a "System_ForceDropshipRoom" Action as it's implied and does that for you.

If you are going any kind of drop restrictions (Min/Max Tonnage by unit or Lance), I'd recommend you not drop them on a player as "Flashpoint_StartContract" or else they may be forced in to a DropShip Equip screen they can't exit, with no valid units to select and can get stuck. You can still do this, but make sure they are very well informed before entering a mission chain they can't back out of.

Currently, I don't believe it is possible to safely set a "Flashpoint_AddContract" that is also on a kind of timer that would force-start it once the timer expires. I tried this for "The Raid" and asked the devs if this was possible, but while it might be, it's an incredibly risky implementation of tags, events and other parts that shouldn't be used in such a way as it risks harming the save. The devs did not recommend I use it and I agreed.

Flashpoint_AddContract/StartContract Data
Flashpoint_AddContract_data.jpg

The Flashpoint_AddContract sets up a lot of essential items for the contract it generates. It however, is not the entire contract. First and foremost, it must point to a contract .json file in the "Contract Name" entry. You can just use a default contract found in the \data\contracts\ folder as a placeholder. I made sure to pick some very low difficulty ones from the FP Reference Sheet that had the right type of contract (Assassinate, Convoy Assault, etc) So I could get an idea of how the FP flow and branching works before I take the time to customize the contracts.

Next most important thing is going to be the map this takes place on with "Map Name" and "Encounter Guid" defining what map, and which part of that map to use. This is where the spawn points, buildings, convoy routes and other map layer stuff gets selected. I can have a contract.json that is a "simpleBattle" but that .json cares not what map it is applied to. You can give it a valid "Map Name" and if available, an "Encounter Guid" to apply that contract.json to. If you leave both of them blank, the game will use a fallback default map every time. Use my FP Reference googleDoc's "Encounter Layer" sheet in the "References and Resources" tab to pick from the possible combinations of map + encounter type. You will see some "simpleBattle" encounters have up to 4 different possibilities on a single map. If you want to use one of those that isn't the default or first entry, paste that EncounterLayerGUID in to the "Encounter Guid" section of the Flashpoint_AddContract Data, along with the corresponding Map Name.

Now that you have a contract.json and the map+encounterLayer it takes place on, you can copy/paste the Employer and Target Factions from the main FP screen. Spelling, spaces (none) and capitalization are critical here, I highly recommend a strait copy/paste and make sure no leading or trailing spaces get inserted. You can have these be different than the base FP's factions, but be careful. This would be used for you betraying your employer for the enemy, or hitting your own target, that kind of thing.

Optionally, if your contract has a special Employer's/Target's Ally Lance appearing (by default only some Target Acquisition contracts can do Enemy Allies) you set that here too. However, I ran in to a number of bugs getting this to "stick" on to the contract and to be sure, doubled up that info where it was present in the contract.json for that mission.

The Difficulty is out of 1-to-10, with 1 = 0.5 Skull and 10 = 5 Skull contracts in-game. This overrides the base difficulty setting in the contract.json, as they are only formatted as Easy/Med/Hard (2/5/8) and I'll address that later in the Contracts section. Normally, this difficulty will be the same as what you declared your FP to be and the game will scale the payments as appropriate. This difficulty is what the pay rate for the contract is built from in addition to the type of contract!

Next Milestone ID is exactly what you think it is. It defines which MS to link to next, if the mission is a success.

Failure Milestone ID is the same, but for when you fail the primary objectives or withdraw from the mission. I'll discuss this in more detail in the next post below.

Conversation MS
So that covers a mission, the map it takes place on, and where to go in the MS links once completed. But what does a conversation MS look like?
fpeditor_talk_eventResult.jpg
This is the ms_fp_theRaid_104_TalkChoice Event Result. It has two Actions:
  • System_StartConversation - Starts a conversation with a title card defined here
  • Flashpoint_SetNextMilestone - Sets the next MS link in the chain once the conversation is done
Note that the System_StartConversation has a string of numbers and letters next to it. This is my conversations GUID defined in the ConverseTek conversation I will make later. Usually, you would select one from a dropdown in the Action's Data to the right. However, this drop-down does not support live updates from the \data\simGameConversations folder and pulls from a static list in the MDDB.

You will need to open the ms_fp_yourStory.json and hand enter the convo GUID in to the space provided!
Code:
"Actions" : [
                        {
                            "Type" : "System_StartConversation",
                            "value" : "9cc52ed03b2514c7432b5978",
                            "valueConstant" : null,
                            "additionalValues" : [
                                "The Raid",
                                "High Orbit \u2014 Tiverton",
                                "Conference",
                                null
                            ]
                        },
                        {
                            "Type" : "Flashpoint_SetNextMilestone",
                            "value" : "ms_fp_theRaid_003_BranchForCancel",
                            "valueConstant" : null,
                            "additionalValues" : null
                        }
                    ],
Where it says "value" : "9cc52ed03b2514c7432b5978", will likely be blank when this is new and just paste your Conversion's GUID in between the quotes. Once the convo ends, the game will go to the next MS set in the "Flashpoint_SetNextMilestone" statement. The most important conversations in your FP will be the ones that set the branching paths determined by your Flashpoint Decision options in the convo. Once the convo with the FP decision is over, you go to a special "Branch" MS.

In The Conversation segment below, I'll show how the FP Aid: FP_choice_placeholder.bytes can be used as a placeholder until your proper conversion is written.

Branch MS
The Branch Milestone is a kind of filter. It will check for some default tags like "fp_choice_a" or "fp_choice_b" and have different Event Results for each. Here is the Event Result in the Branch MS for "The Raid" that sets you down the A branch.
fpeditor_branch_eventResult_require.jpg
Take a look at the top, it has a Scope of "Company" and a Random Scope (really "Required Scope" and "random" is an error) of "Flashpoint" with a Requirement of "fp_choice_a" in the Required Scope. This means, to get to this Company Event Result, the Flashpoint Scope must contain a tag of "fp_choice_a" and that's how you start down this FP's "200_A" branch. In the previous conversation, it is possible to pick up either "fp_choice_a" or "fp_choice_b" or pick up none of them at all. I used this "no tag applied" setup for an early exit, allowing the player to take the A or B branch as an optional objective.
fpeditor_branch_eventResult_exclude.jpg
Here is that early exit MS Event Result, same Company Scope and FP Required Scope as the one above. However, the requirements are in Excluded Tags, which means you "must not have either fp_choice_a or fp_choice_b" in your FP Scope to get here. I could have also used a Requirement Tag of "fp_choice_c" instead, but when I built this, I didn't need to add a third tag. In the end, I did need one for some advanced conversation filtering, but that's for later in the advanced editing post.

The templates usually include this cancel path, but honestly, I don't think most FP's need one. You're really going to be pushing the player to complete the FP. Once you get in a few missions, offering them an out is kind of a red herring. If they fail/abandon it, it goes back in to the pool to try again. If you have a "Cancel Complete" it will "Finish" the FP once and for all. If you only want to give the player one shot at something, this is where to use it. Use "one shots" sparingly, probably for a great reward like a AS7-D-HT or a pair of Gauss Rifles and ammo.

Complete and Reward MS
Once it's all said and done, Darius usually puts everyone back to work and now you hit the completion Milestone and your reward. At the top, you will usually set some Company Scope tags to signal this company has completed this FP and took a specific branch.
fpeditor_complete_eventResult.jpg
The aptly named "Flashpoint_CompleteFlashpoint" declares it over. Here you set the final "Reward" MS to point to and then if you want to override the default reward you set in the FP json on the main FP editor options. In this case, the A branch gives more payout than the base and I overrode that to point at my A branch reward .csv file. If the default reward is what you want, leave the override blank.

If this is a "Cancel Complete" the "FP End Type" would be "CompletedWithoutReward" otherwise it seems to be left blank by default.
fpeditor_cancelComplete_eventResult.jpg

The "System_ForceDropshipRoom" to "Ship" just sets the menu back to the main Argo screen once we are done with the reward issue.

The Rewards MS does not set any loot rewards!
Those are defined in whatever .csv file you pointed the FP or Rewards Override to.
fpeditor_reward_eventResult.jpg
What the Rewards MS does set is any non-loot items like C-Bills, Morale, Reputation changes and other "status" type numbers. These are in a specific format, the same kind of format the Event Editor uses and if you need one for reference, you can check stock events that modify that value in either the .json or in the Event Editor. This reward shown has:
  • Funds|System.Int32|3900000
  • Reputation.AuriganPirates|System.Int32|-30
  • Morale|System.Int32|1
  • BlackMarketAccess_Display|System.Int32|-1
20190221154104_1.jpg
It pays out 3,900,000 C-Bills, lowers your Rep with the AuriganPirates by 30 (this is in addition to the Rep loss from contracts taken in the FP), adds +1 Morale and sets the "Black Market Access Display" to -1 or off. This FP dealt with raiding the Black Market and once you finish it, they are quite pissed and this is part of the steps needed to remove the players access. Note, in the background in the MS Editor Form, there is a second Event Result that is (Temp), this one sets the temporary time for the Market to not show back up. If you look at the top, you will see a list of tags added and removed. These deal with Black Market, mainly shutting it off and once it can come back on, giving the players company a "BANNED" status to let only the most expensive offer give them renewed access. It was worth it, or at least I think so. Main thing is, everything this FP does with the BM is actually temporary. It might take 666 days before you are available to get the "Banned offer" to restore access, but I'm not permanently cutting a save off from what is a pretty big feature in the simgame.

I'll cover Temporary Event Results in the Advanced Editing portion below. What you have above is the heart of the FP system. You have a set of Milestones linked together with a branching path of conversations, missions and finally the rewards. That's how you assemble a basic Flashpoint in to a playable state.

The Conversations

The main page of CWolf's ConverseTek (CT)has a general use guide and for FP's your conversations are going to take place in the "Conference" room as set by the "Talk" MS that calls it. Most of what goes in the conversation is the same as the CT usage guides and videos on CWolf's page. I'd recommend calling cast member by "CastID" over the harder to read "SpeakerID" and have made a chart of the common ones in the CastID/SpeakerID for Group Conversation of the FP References Sheet in the Resources and References tab. This isn't a comprehensive list, just what already appears in the stock game. You can type in any other castID and it will appear in the chat box just fine and it will show their Name/Title and portrait as defined in the castdef.

Setting a Holoscreen Image
Adding the Action "Set Battletech Viewscreen Image" and enter the filename of the image you want without the "uixTxrConv_" prefix in front. The sheet after the CastID/SpeakerID is a list of all the stock images you can call. You can add custom Holoscreen images and I will cover that in "Original Assets" below.

There is no stock way to "clear" the Holoscreen without error that I am aware of. If you call a image it can't find, it will display a clear screen. I don't like this method and so made a "screenoff" empty image file as part of the Flashpoint Aid: "Flashpoint Stock Photos" mod that I highly recommend using for your FP.

The custom castdef, Holoscreen image and the instructions on the CT git for contextual responses will get you here:
CT_customConvo.jpg

NOTE: Once you use a "Lock Camera" Action, you must manually assign any further camera changes in the scene. I don't know if it's possible to return the camera to "Normal" mode in CT at this time.

Setting a Flashpoint Decision Response

The big thing unique to conversations in FPs is the Decision Choice that takes place somewhere in the FP. These are responses as such:
Code:
<color=#85DBF6FF>[Flashpoint Decision: Make a choice]</color> I'm making this choice.
This gives them the blue color for "[Flashpoint Decision: Make a choice]" and then your players "spoken" response. In general, you don't have much room for responses and the brackets eat up even more space, so try to keep them short. Once you have the look down, you going to have to apply a Flashpoint Scope "fp_choice_x" tag to that dialogue branch. This can be applied to the response, but HBS does it to the first Node after the choice.

ConverseTek Action: Apply a Flashpoint ScopeTag
Give a Node or Response an "Action" select, "Set BattleTech Tag"
Action:
Operation: Get Preset Value (int)
Key:
string: SimGameAddRemove​
Value:
Int: 0 (Add to)​
Type:
Operation: Get Preset Value (int)
Key:
string: SimGameScope​
Value:
Int: 3 (Flashpoint)​
Tag Key:
string: fp_choice_a​
CT_Action_fp_choice_a.jpg

This is basically saying "Add to SimGameScope: "Flashpoint" the tag string: "fp_choice_a" and this is usually done to a Node in HBS's examples. It can be applied to a response as well and should work.
CT_choice_inGame.jpg

To make this easy for everyone, I've made a placeholder conversation, check the Resources and References segment above for Flashpoint Aid: FP_choice_placeholder.bytes which is in a .zip file at the end of this post.
CT_FP_choice_placeholder.jpg
All you need to do is D/L this file, paste it's GUID "9caaf9ff484fe7d2823c5d7e" in to your TalkChoce MS Conversation value and you should have a working conversation that can apply the tags needed for most default Branch MS.

The Contracts
The contract .jsons can be edited to make custom missions within their general type. A "SimpleBattle" isn't going to become a mutated "Defend Base" no matter what kind of cut/paste hack job you do in the .json. This is an incredibly limiting factor at this time and I don't know if it can be bypassed yet.

This is because the contract .json is a map agnostic file. It specifies an existing contract type (SimpleBattle, Rescue, Destroy Base, etc) and that calls a specific EncounterLayer for the map selected. This layer is part of the map files and includes the coordinates for spawning locations, patrol routes for AI and everything else needed to run that type of contract on that specific map. Currently, we don't have an easy way to edit and create EncounterLayers and associated files, Mission Control by CWolf is very close to becoming this tool.

So how do we go about customizing the missions we have? First, you need to figure out which type of contract you want to build from. Then, I'd recommend selecting a map. You need to make sure the map you want had the appropriate EncounterLayer for the contract type. You can check the EncounterLayer (Map+Contract) of the FP References Sheet in the Resources and References tab to check maps sorted by contract type. I'm usually searching for a specific Biome (Lunar, Tropical, Highlands, etc) and make a list of maps available in that contract. Watch out, some maps or Biomes only have one possible setup. A Lunar Rescue for example only has one map available, but a Lunar Destroy Base has two. Still, that's only two possible Lunar maps where Tundra has four. Remember, some maps+contracts have up to 4 different EncounterLayers on a single map and they can all take place on drastically different terrain layouts even if they are on the same Biome and larger map space. The EncounterLayerGUID can be pasted in to the Action Data if it's not the first default entry for that map to use the other layers.

The next biggest thing we can customize are Optional Chunks. Some Defend Base contracts have APCs that turn on turrets, most don't, some Battles have a second Lance, others are just four units. These can be turned on and off by setting their Optional Chunk to "true" or "false" and what contracts have what chunks turned on or off can be found in Contracts of the FP References Sheet in the Resources and References tab above.

As a placeholder, you can find the stock contract that has all or most of the optional chunks you need turned on and then place that in your Mission MS and along with a map. You might have to go through a number of maps until you find one you like as enemy spawns, extraction zones and of course the terrain itself greatly changes how easy or hard that contract will be. A "SimpleBattle" with two far off Lances at the players 2&10 o'clock a mountain in between them is going to be handled much easier than the same two Lances spawning at 12&6 with no intervening terrain or cover at player spawn.

Now you have a general idea of how a mission will play out and maybe narrowed down the possible maps to 2-4 candidates. You can either take a stock contract .json and edit it, or build your own from scratch using the Contract Parser Tool in the edtitors folder alongside the FP editor. I'll cover editing the .json directly below the parser, but recommend using the parser first.

Contract Parser
The Parser takes a template .txt file and turns it in to a fully qualified contract .json for you. I recommend this method for all contracts except "FireMissions" (Target Acquisition) as the parser we have doesn't handle them at this time. HBS included all the stock contracts and stock template .txt files for us here:
BATTLETECH\BattleTech_Data\StreamingAssets\design\contracts
The Parser can be found in the editors folder and is called "ContractParser.exe" but opening it will do nothing, it needs to be run via .bat file. You will see some .bat files in the folder, but they will not work out of the box. You must edit these files in Notepad++ and change the file destination away from the dev. file addresses they come with by default. I recommend saving your edited .bat files under a new name so game updates or a copy/paste dump for your Stand-Alone Editor Folder won't overwrite them by accident.

@HBS_Eck made this Contract Parser Guide that goes in to far more detail about the specifics of the contracts.

Here is a copy of one of my .bat files, with the file path changed to reflect my person Stand-Alone Folder:
Code:
REM In the built game, change StreamingAssetsSource to just StreamingAssets
contractparser "..\..\Editor Stand Alone Folder\design\contracts"
I edited the "..\..\StreamingAssetsSource\design\contracts" line to reflect my file-system structure and running this .bat file will parse all contracts found in the entire design\contracts folder. This is usually a bad idea. I don't need to parse every possible contract as HBS gave us all of the stock ones as .txts and .txt templates. What I did was make my own folder and had it parse those:
Code:
REM In the built game, change StreamingAssetsSource to just StreamingAssets
contractparser "..\..\Editor Stand Alone Folder\design\contracts\amechcustoms"
Parser_firstRun.jpg

This makes it easy to find my output and not regenerate a ton of stock contracts every time I need to run it. On the first you will get at least 1 warning, that it needed to create a custom output folder as "amechcustoms" or "yourfoldernamehere" will not exist in the data\contracts folder already. Here we see two random design\contract files I put in to my custom design\contracts\amechcustoms folder and they pop out as valid game ready .jsons on the right inside my Editor Stand Alone Folder\data\contracts\amechcustoms folder created by the parser's first run above.
Parser_inOut.jpg


For the next three sections I'm going to notate these for both the .json and .txt templates using the DefendBase_BreakthroughBrink.json, DefendBase_BreakthroughBrink.txt and DefendBase_Template.txt as an example except when special FP options are needed.

Editing Contracts for Flashpoints

At the top of all the files we got our basics, ID, Name and Difficulty. FP contracts ID and Naming Conventions:
For a first mission, no branching yet:
  • ID: "c_fp_yourStory_1_defendBase - prefix c_fp_yourStory_(mission #)_contractType"
  • contractName: "Your Story" - Displayed to user, FP Displayed Title with no Mission # in Roman Numerals
For a 4th total mission, first in a Branch:
  • ID: "c_fp_yourStory_a1_defendBase - prefix c_fp_yourStory_(branch)(mission # in branch)_contractType"
  • contractName: "Your Story IV" - Displayed to user, FP Displayed Title and Mission # by total missions played
"difficulty" or [Difficulty] - There is only "Easy, Medium, Hard" or "2, 5, 8" and it's overwritten by the MS Action Data anyway, just use the closest to your intended FP difficulty without going over. Pay is set by the Difficulty set in the MS Action Data and the contract type.
Code:
"difficulty" : 8, or [Difficulty]Hard
"shortDescription" or [ShortDesc]
&
"longDescription" or [LongDesc]
Oddly, these are flipped. The Short Description is the paragraph in the negotiation and loading window. The Long Description is the one or two liner that Darius usually gives you underneath the full description.
Code:
    "shortDescription" : "A {TEAM_EMP.FactionDef.Demonym} industrial lab is at a critical juncture in its R&D program. Any disruption would set us back a decade. {TEAM_TAR.FactionDef.Name} on {TGT_SYSTEM.name} has discovered this, and they've already interdicted the first lance of 'Mechs that were sent to defend the facility. We need mercenaries to step in and buy the time necessary for further reinforcements to arrive.",
    "longDescription" : "I'm guessing our employers know that a hammer blow is coming, so we'll expected to take the brunt of the attack until their reinforcements arrive on the field.",

[ShortDesc]A {TEAM_EMP.FactionDef.Demonym} industrial lab is at a critical juncture in its R&D program. Any disruption would set us back a decade. {TEAM_TAR.FactionDef.Name} on {TGT_SYSTEM.name} has discovered this, and they've already interdicted the first lance of 'Mechs that were sent to defend the facility. We need mercenaries to step in and buy the time necessary for further reinforcements to arrive.
[LongDesc]I'm guessing our employers know that a hammer blow is coming, so we'll expected to take the brunt of the attack until their reinforcements arrive on the field.
See the "{TEAM_EMP.FactionDef.Demonym}" this allows a procedural contract to ask "Who is the employer and what do I call them?" and another one is present for the target faction who is the OPFOR. You can leave these, or just write in manually as this FP has those fixed in the MS Action Data above. I chose to manually put the faction's names in so I could read the text naturally for checking.

"salvagePotential" or [Salvage]
This must be a multiple of four! I also don't think a value higher than 28 is found in the game. The game also doesn't let players pick priority salvage over 7 (7/28?) and if they have "Generous Salvage" on they might even see 8/?? but only get to pick 7 items priority. Pay is set by the Difficulty set in the MS Action Data and the contract type.
Code:
"salvagePotential" : 24, or [Salvage]24
FPs contracts need some special settings to separate them from normal ones. They take up a special slot at the top of the contract window, shouldn't show up in randomly generated contracts, usually don't have any special requirements on the contract level like min/max Employer Rep. and so on.
Code:
"requirementList" : [], or [Requirement]
This clears any specific requirements usually found in a procedural contract like Rep. or MRB ratings.
Code:
"contractDisplayStyle" : "BaseFlashpoint", or [ContractDisplayStyle]BaseFlashpoint
This gives it the blue top slot in the contract selection screen.
Code:
"scope" : "MID_CAMPAIGN", or [ContractScope]MID_CAMPAIGN
This is normally "STANDARD" but this is for a FP, so it gets a "MID_CAMPAIGN" scope.

Total Lance Size, Lance and 'Mech Min/Max Tonnage Requirements

Not listed in the design templates, but present in the final .json file are parameters for setting the total Lance number, or Lance and individual 'Mech Tonnage restrictions. I'm going to have to use a different file's data for this, as a generated contract doesn't use these and they are not formatted in the template.txt.
Code:
"maxNumberOfPlayerUnits" : 4,
This one is pretty strait forward, want them to only be able to take two units? Change to two, don't go over four. This number is including any forced ally 'Mechs you put in player control like Kamea or Mastiff from the SP tutorial missions. If you want allies to be present on the map and controlled by the AI, that would be in a different section below.
Code:
    "lanceMinTonnage" : -1,
    "lanceMaxTonnage" : -1,
    "mechMinTonnages" : [
        -1,
        -1,
        -1,
        -1
    ],
    "mechMaxTonnages" : [
        50,
        50,
        50,
        50
    ],
Code:
    "lanceMinTonnage" : 320,
    "lanceMaxTonnage" : -1,
    "mechMinTonnages" : [
        -1,
        -1,
        -1,
        -1
    ],
    "mechMaxTonnages" : [
        -1,
        -1,
        -1,
        -1
    ],
We see the "lanceMinTonnage" and "lanceMaxTonnage" set the total mass for all of the players units added up. you could take 320t either by 3x 100t KGCs and 1x 20t LCT or 4x 80t VTRs as long as it adds up to 320t or greater.
WARNING: The game doesn't like "lanceMaxTonnage" less than 120t for 2-4 slots. This 100t Max is OK for a SINGLE slot deployment (including forced units below)

With "mechMinTonnages" and "mechMaxTonnages" in the example above, each of the four units the player can bring must be 50t or less. It might be possible to edit each of the four values in the array, but I haven't tested that yet. I would assume it should work if you set up:
"mechMaxTonnages" : [
25,
50,
65,
85
]
It would allow a one slot with no greater than 25t, 50t, 65t and 85t respectively. You propably could mix and match Lance and 'Mech min/max limits but it starts to get confusing to explain to the player. I'd also consider following the guideline brackets set by HBS in the SimGameConstants.json for how to set your restrictions in the FP.json settings:
Code:
        "LessThanThisWeightIsLightUnit" : 55,
        "GreaterThanThisWeightIsHeavyUnit" : 60,
        "LessThanThisTotalWeightIsLightLance" : 220,
        "GreaterThanThisTotalWeightIsHeavyLance" : 240,
In the main FP editor screen, where it says "Unit Drop Hint" and "Lance Drop Hint" you would match your hint to whatever tonnage limits are in your contract. This may make unfortunate expectations by the player. If they see "UnitDropTonnageHint" : "Light", and think "Oh, that's 50t or less. I'll ready my CN9's..." and they get hit by a 35t or less limit, they might be equipped for that mission and have to abandon the FP.

Try not to force consecutive drops with new tonnage restrictions in the consecutive mission! What I'm saying is, don't let a player launch thinking nothing is different and then suddenly forcing them to drop with <40t immediately without a ton of forewarning before launching the first non-consecutive mission. You might want to tell them the exact limits while they are able to refit and pass time in case they misjudged the restrictions. Given there is no way to exit the DropShip Deployment window, if the player has no valid units readied, they are stuck.

Try to give them time before a special restriction to ready the appropriate units. Now, if your FP is all one single restriction across all missions, you can do that as long as you warn the player in the initial conversation before forcing a mission on them.
Code:
    "mapMood" : null,
The weather and time of day effects are set in the contract, left alone it will pick a random valid Mood for the biome. This is also not editable in the template.txt. You must make sure you have your Biome set in the MS before setting the Mood here, or else it will throw an error and default to a fallback. The list of Moods per Biome can be found in the MoodIDs page of the FP References Sheet in the Resources and References tab above.

Further Flashpoint Options Not In Template.txt
Code:
    "overrideAutoCompleteDialogueId" : "DialogBucketDef_c_fp_theRaid_b2_defendBase",
    "disableNegotations" : true,
    "disableLanceConfiguration" : false,
    "disableCancelButton" : true,
    "disableAfterAction" : false,
    "contractRewardOverride" : -1,
    "travelOnly" : false,
    "useTravelCostPenalty" : false,
    "usesExpiration" : false,
    "expirationTimeOverride" : -1,
    "negotiatedSalary" : 0.25,
    "negotiatedSalvage" : 0.75,
    "excludedFromProceduralGeneration" : true,

SUPER IMPORTANT LINE TO ADD!
"excludedFromProceduralGeneration" : true,
You need this set to true to exclude this FP mission from being generated outside of the FP! Always double check every contracts "excludedFromProceduralGeneration" statement before releasing your FP.

When you are making a consecutive mission, you must remove the players ability to negotiate, cancel back out in to the simGame and set a fixed negotiation rate for them as below:
  • "disableNegotations" : true,
  • "disableCancelButton" : true,
  • "negotiatedSalary" : 0.25,
  • "negotiatedSalvage" : 0.75,
The negotiated scale values are "0, 0.25, 0.5, 0.75, 1" to represent the 5 levels of both Salary and Salvage. In the example above, it is set to Salary at one tick from minimum and Salvage at one tick from max. You may want to tune this to the mission type and how good or bad the employer's relation is at this point in the FP. There could be ways to setup a high Salvage payout on a mission like Target Acquisition or a minimum salvage rate for a Battle and then have a conversation after where the crew and employer get in to an argument over getting screwed out of a good reward.

Editing Objectives
Code:
.json -
    "contractObjectiveList" : [
        {
            "contractObjective" : {
                "EncounterObjectGuid" : "6f5f8d17-70ed-44a8-acc0-ccf9258925aa"
            },
            "title" : "Defend a {TEAM_EMP.FactionDef.Demonym} R&D Facility",
            "description" : "",
            "isPrimary" : true,
            "forPlayer" : "Player1",
            "objectiveGuids" : [
                "ca677a4d-19c8-4d0c-9c5e-3ed712081336",
                "0e4ac925-d95a-4019-aeb0-0aa553830f46",
                "d4d20990-fbeb-4f6e-81b7-7e94bba6a2c5",
                "4bfadebf-a277-4ddb-8a36-f70ab7c0c68c",
                "240577eb-b4b0-43b7-b2af-a94d692a022a",
                "d01959cc-5ef1-4856-8918-1848c051368d"
            ]
        }

.txt -
// Contract Objectives
[ContractObjective]Defend a {TEAM_EMP.FactionDef.Demonym} R&D Facility
    [Description]
The "contractObjective" or [ContractObjective] section is the general single objective shown in the loading screen and also becomes populated with a default list of "objectiveGuids" which are unique Ids for the various sub-objectives like "Defend Industrial Laboratory" or "Destroy the Enemy Vanguard" that make up parts of the larger objective. Again we see the MadLibs statement used here "Defend a {TEAM_EMP.FactionDef.Demonym} R&D Facility" and this can be left in place or you can change this to plain text of whatever faction you want.

Right below that is the "objectiveList" or "// Battle Objectives" segment that details each objective and any bonus rewards for completing them.
Code:
.json -
    "objectiveList" : [
        {
            "objective" : {
                "EncounterObjectGuid" : "ca677a4d-19c8-4d0c-9c5e-3ed712081336"
            },
            "title" : "Defend Industrial Laboratory",
            "description" : "Defend Base from Attackers",
            "isPrimary" : true,
            "OnSuccessResults" : [],
            "OnFailureResults" : []
        },
        {
            "objective" : {
                "EncounterObjectGuid" : "0e4ac925-d95a-4019-aeb0-0aa553830f46"
            },
            "title" : "Destroy the Enemy Vanguard",
            "description" : "",
            "isPrimary" : false,
            "OnSuccessResults" : [
                {
                    "Scope" : "Company",
                    "Requirements" : null,
                    "AddedTags" : {
                        "items" : [],
                        "tagSetSourceFile" : ""
                    },
                    "RemovedTags" : {
                        "items" : [],
                        "tagSetSourceFile" : ""
                    },
                    "Stats" : [
                        {
                            "typeString" : "System.Single",
                            "name" : "ContractBonusRewardPct",
                            "value" : "0.1",
                            "set" : false,
                            "valueConstant" : null
                        }
                    ],
                    "Actions" : [],
                    "ForceEvents" : [],
                    "TemporaryResult" : false,
                    "ResultDuration" : 0
                }
            ],
            "OnFailureResults" : []
        },
        {
            "objective" : {
                "EncounterObjectGuid" : "240577eb-b4b0-43b7-b2af-a94d692a022a"
            },
            "title" : "Ensure All Buildings Survive",
            "description" : "",
            "isPrimary" : false,
            "OnSuccessResults" : [
                {
                    "Scope" : "Company",
                    "Requirements" : null,
                    "AddedTags" : {
                        "items" : [],
                        "tagSetSourceFile" : ""
                    },
                    "RemovedTags" : {
                        "items" : [],
                        "tagSetSourceFile" : ""
                    },
                    "Stats" : [
                        {
                            "typeString" : "System.Single",
                            "name" : "ContractBonusRewardPct",
                            "value" : "0.2",
                            "set" : false,
                            "valueConstant" : null
                        }
                    ],
                    "Actions" : [],
                    "ForceEvents" : [],
                    "TemporaryResult" : false,
                    "ResultDuration" : 0
                }
            ],
            "OnFailureResults" : []
        },
        {
            "objective" : {
                "EncounterObjectGuid" : "4bfadebf-a277-4ddb-8a36-f70ab7c0c68c"
            },
            "title" : "Hold Out for Reinforcements",
            "description" : "Hold Out for Reinforcements",
            "isPrimary" : true,
            "OnSuccessResults" : [],
            "OnFailureResults" : []
        },
        {
            "objective" : {
                "EncounterObjectGuid" : "d4d20990-fbeb-4f6e-81b7-7e94bba6a2c5"
            },
            "title" : "Escort Engineer APCs to Base Defenses",
            "description" : "Escort Engineer APCs to Base Defenses in order to take control of them.",
            "isPrimary" : false,
            "OnSuccessResults" : [
                {
                    "Scope" : "Company",
                    "Requirements" : null,
                    "AddedTags" : {
                        "items" : [],
                        "tagSetSourceFile" : ""
                    },
                    "RemovedTags" : {
                        "items" : [],
                        "tagSetSourceFile" : ""
                    },
                    "Stats" : [
                        {
                            "typeString" : "System.Single",
                            "name" : "ContractBonusRewardPct",
                            "value" : "0.1",
                            "set" : false,
                            "valueConstant" : null
                        }
                    ],
                    "Actions" : [],
                    "ForceEvents" : [],
                    "TemporaryResult" : false,
                    "ResultDuration" : 0
                }
            ],
            "OnFailureResults" : []
        },
        {
            "objective" : {
                "EncounterObjectGuid" : "46d1c317-2344-4e53-aa9f-d9769edbb89d"
            },
            "title" : "Baddies Inbound",
            "description" : "",
            "isPrimary" : false,
            "OnSuccessResults" : [],
            "OnFailureResults" : []
        },
        {
            "objective" : {
                "EncounterObjectGuid" : "00d98f37-5576-43c3-ba74-953fb54bd497"
            },
            "title" : "Hidden Objective: Destroy the Third Lance",
            "description" : "Hidden Objective: Destroy the Third Lance",
            "isPrimary" : false,
            "OnSuccessResults" : [],
            "OnFailureResults" : []
        },
        {
            "objective" : {
                "EncounterObjectGuid" : "d01959cc-5ef1-4856-8918-1848c051368d"
            },
            "title" : "Baddies Inbound",
            "description" : "",
            "isPrimary" : false,
            "OnSuccessResults" : [],
            "OnFailureResults" : []
        }
    ],

.txt -
// Battle Objectives

    // Primary Objective
    [Objective]Defend Industrial Laboratory
        [Description]Defend Base from Attackers

    // Optional Objective
    [Objective]Destroy the Enemy Vanguard
        [Description]
        [OnSuccess]
            [Result]Company|Stat|ContractBonusRewardPct|0.1

    // Optional Objective
    [Objective]Ensure All Buildings Survive
        [Description]
        [OnSuccess]
            [Result]Company|Stat|ContractBonusRewardPct|0.2

    // Primary Objective
    [Objective]Hold Out for Reinforcements
        [Description]Hold Out for Reinforcements

    // Optional Objective
    [Objective]Escort Engineer APCs to Base Defenses
        [Description]Escort Engineer APCs to Base Defenses in order to take control of them.
        [OnSuccess]
            [Result]Company|Stat|ContractBonusRewardPct|0.1

    // Optional Objective
    [Objective]Baddies Inbound
        [Description]
While this list may always be a mile long, not all of these objectives are used in every contract, they can be tuned on and off in the next section, "Editing Optional Chunks" and the important things here are editing the "title" along with if the objective is primary for the mission along with any rewards for completing it. Look at the "Ensure All Buildings Survive" Objective above. There is no information about how many building this is, what buildings are chosen or how much HP they have, what exactly triggers a pass/fail and other qualifications. These are part of the EncounterLayer and can't be edited easily at this time. What we can edit is "isPrimary" : false, and changing that to true would mean a single building loss is a failure. There is some Building statements in the contract, but I haven't explored them yet. The results should look familar to you if you've looked at the MS .json or other Event Result screens. This uses the same format in the "OnSuccessResults" and "OnFailureResults" as MS and Events in the FP and Event Editors.

This means you can add or remove Tags, edit cash payouts by either % (as the default examples show) or by an absolute value and even do things like add/remove MedTech or MechTech levels. You should be able to assign whatever reward or penalty by using the same formatting from Event Results you may have already used in the FP or an Event.

Editing Optional Chunks
Code:
.json -
    "chunkList" : [
        {
            "name" : "Chunk_EscortAPC_DefensiveTurrets (Bonus)",
            "encounterChunk" : {
                "EncounterObjectGuid" : "2340cc58-51b0-4db7-a9ff-f5ff08d86d01"
            },
            "enableChunkFromContract" : true,
            "requirementList" : []
        },
        {
            "name" : "Chunk_Wave3Attackers (Bonus)",
            "encounterChunk" : {
                "EncounterObjectGuid" : "5dca4e7f-ea4c-4582-8a4c-bb531e2c0754"
            },
            "enableChunkFromContract" : false,
            "requirementList" : []
        }
    ],

.txt-
// Optional Chunks
[OptionalChunk]Chunk_EscortAPC_DefensiveTurrets (Bonus)|on
[OptionalChunk]Chunk_Wave3Attackers (Bonus)|off
This contract has APCs appear that can turn on Turrets, it also doesn't have a 3rd wave of OPFOR appear. Most Base Defense contracts don't have one or the other or either. This is where we can turn these "Chunks" of the objective list on or off.

Inside this "chunkList" the chunk "Chunk_EscortAPC_DefensiveTurrets (Bonus)" is set to true and the chunk "Chunk_Wave3Attackers (Bonus)" is false. This is how you control which Lances will spawn and if other special events like turrets, DropShips and APCs appear in the contract. The Contracts of the FP References Sheet in the Resources and References tab above has most of the optional chunks listed, but is still incomplete at this time.

Editing Lances
Code:
.json -
            {
                "lanceSpawner" : {
                    "EncounterObjectGuid" : "4d39e72c-4f99-4cc6-8fe0-d4d18cad0063"
                },
                "name" : "Lance_Enemy_Wave1Attackers",
                "lanceDefId" : "Tagged",
                "lanceTagSet" : {
                    "items" : [
                        "lance_type_battle",
                        "lance_type_notallvehicles"
                    ],
                    "tagSetSourceFile" : "tags/LanceTags"
                },
                "lanceExcludedTagSet" : {
                    "items" : [],
                    "tagSetSourceFile" : "tags/LanceTags"
                },
                "spawnEffectTags" : {
                    "items" : [],
                    "tagSetSourceFile" : "tags/SpawnEffectTags"
                },
                "lanceDifficultyAdjustment" : 0,
                "selectedLanceDefId" : null,
                "selectedLanceDifficulty" : 0,
                "unitSpawnPointOverrideList" : [
                    {
                        "unitSpawnPoint" : {
                            "EncounterObjectGuid" : "52137684-666c-43d1-9528-99dc96471645"
                        },
                        "customUnitName" : null,
                        "customHeraldryDefId" : null,
                        "unitType" : "Mech",
                        "unitDefId" : "UseLance",
                        "unitTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/UnitTags"
                        },
                        "unitExcludedTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/UnitTags"
                        },
                        "spawnEffectTags" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/SpawnEffectTags"
                        },
                        "pilotDefId" : "pilotDef_InheritLance",
                        "pilotTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/PilotTags"
                        },
                        "pilotExcludedTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/PilotTags"
                        },
                        "selectedUnitType" : "UNDEFINED",
                        "selectedUnitDefId" : null,
                        "selectedPilotDefId" : null
                    },
                    {
                        "unitSpawnPoint" : {
                            "EncounterObjectGuid" : "1d32f819-a4d2-4df1-a66b-c641855e3b3b"
                        },
                        "customUnitName" : null,
                        "customHeraldryDefId" : null,
                        "unitType" : "Mech",
                        "unitDefId" : "UseLance",
                        "unitTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/UnitTags"
                        },
                        "unitExcludedTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/UnitTags"
                        },
                        "spawnEffectTags" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/SpawnEffectTags"
                        },
                        "pilotDefId" : "pilotDef_InheritLance",
                        "pilotTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/PilotTags"
                        },
                        "pilotExcludedTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/PilotTags"
                        },
                        "selectedUnitType" : "UNDEFINED",
                        "selectedUnitDefId" : null,
                        "selectedPilotDefId" : null
                    },
                    {
                        "unitSpawnPoint" : {
                            "EncounterObjectGuid" : "0b168027-919d-4d87-ae88-853711e26b67"
                        },
                        "customUnitName" : null,
                        "customHeraldryDefId" : null,
                        "unitType" : "Mech",
                        "unitDefId" : "UseLance",
                        "unitTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/UnitTags"
                        },
                        "unitExcludedTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/UnitTags"
                        },
                        "spawnEffectTags" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/SpawnEffectTags"
                        },
                        "pilotDefId" : "pilotDef_InheritLance",
                        "pilotTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/PilotTags"
                        },
                        "pilotExcludedTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/PilotTags"
                        },
                        "selectedUnitType" : "UNDEFINED",
                        "selectedUnitDefId" : null,
                        "selectedPilotDefId" : null
                    },
                    {
                        "unitSpawnPoint" : {
                            "EncounterObjectGuid" : "1843b49d-e943-46fc-88aa-954eb78be8d3"
                        },
                        "customUnitName" : null,
                        "customHeraldryDefId" : null,
                        "unitType" : "Mech",
                        "unitDefId" : "UseLance",
                        "unitTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/UnitTags"
                        },
                        "unitExcludedTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/UnitTags"
                        },
                        "spawnEffectTags" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/SpawnEffectTags"
                        },
                        "pilotDefId" : "pilotDef_InheritLance",
                        "pilotTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/PilotTags"
                        },
                        "pilotExcludedTagSet" : {
                            "items" : [],
                            "tagSetSourceFile" : "tags/PilotTags"
                        },
                        "selectedUnitType" : "UNDEFINED",
                        "selectedUnitDefId" : null,
                        "selectedPilotDefId" : null
                    }
                ]
            },

.txt -
    [Lance]Lance_Enemy_Wave1Attackers
        [LanceDef]Tagged
        // Tagged: lance def will be randomly chosen using tags field
        [Tags]lance_type_battle|lance_type_notallvehicles
        // upped the diff: medium & battle
        [ExcludedTags]
        [SpawnEffects]
        [DifficultyAdjustment]0
        // upped the diff.
        // unit entries are only required if you want to override the lancedef (or if set to Manual)
        [Unit]Mech
            [UnitDef]UseLance
            // UseLance: spawner will respect the lance def
            [Tags]
            [SpawnEffects]
            [PilotDef]pilotDef_InheritLance
        [Unit]Mech
            [UnitDef]UseLance
            // UseLance: spawner will respect the lance def
            [Tags]
            [SpawnEffects]
            [PilotDef]pilotDef_InheritLance
        [Unit]Mech
            [UnitDef]UseLance
            // UseLance: spawner will respect the lance def
            [Tags]
            [SpawnEffects]
            [PilotDef]pilotDef_InheritLance
        [Unit]Mech
            [UnitDef]UseLance
            // UseLance: spawner will respect the lance def
            [Tags]
            [SpawnEffects]
            [PilotDef]pilotDef_InheritLance
Now that we have the objectives turned on or off as we need and the contract loads as a FP formatted one, we need to pick our OPFOR and if need be, allies and turrets. You can use any combination of generated Lances like a normal mission, manually assigning all four units in a Lance or a mix of both. This is up to you with what kind of story you want to tell or choices you want the player to make. You could bump up or down the difficulty of a generated Lance, manually assign a KGC in one slot of a low difficulty Scout Lance, or set all four units to custom 'Mechs you've designed for this FP, driven by custom pilots you tuned for each 'Mech.

The above example has the "Lance_Enemy_Wave1Attackers" and they are generating an entire procedural Lance. "lanceDefId" : "Tagged", sets this in motion and then below it you set the Tags you want that Lance to look for or exclude. In the example, it is looking for a Lance with the lags "lance_type_battle" and "lance_type_notallvehicles" with the difficulty scale of the Lance determined by the contract difficulty above, for FP's this is set in the MS Event Result Data for that mission. If this was a 10 Difficulty FP, it would look for lancedefs that meet all three of those conditions, as there is no further exclusions. Some of the valid options would be "lancedef_mixed_d10_dynamic_assaultBattle1" or "lancedef_mech_d10_dynamic_assaultBattle" and note that the second contains no vehicles where the first does, but none of them are all vehicle Lances. You can also tune up or down the difficulty of a Lance relative to the contract's difficulty with "lanceDifficultyAdjustment" : 0, and set to -2 would pull a lancedef 2 levels (one whole skull) lower. The "spawnEffectTags" is where you could set Lance-wide effects like starting at 50% armor using this example from another contract:
Code:
                "spawnEffectTags" : {
                    "items" : [
                        "spawn_poorly_maintained_50"
                    ],
                    "tagSetSourceFile" : "tags/SpawnEffectTags"
                },
To use a "Manual" Lance, replace "lanceDefId" : "Tagged", with "lanceDefId" : "Manual" and it will ignore the Tag filters and only assign what you enter. Each unit would need these lines replaced:
  • "unitType" : "Mech", with either Mech, Vehicle or Turret as needed
  • "unitDefId" : "UseLance", with the Id of the mechdef/vehicledef/turretdef
  • "pilotDefId" : "pilotDef_InheritLance", with the Id of the pilotdef
To set a custom Name or Heraldry from the defaults edit these lines for each unit:
  • "customUnitName" : "",
  • "customHeraldryDefId" : null,
All together we get this example:
  • "customUnitName" : "Hired Goons - Lancer",
  • "customHeraldryDefId" : "heraldrydef_steiner",
  • "unitDefId" : "mechdef_zeus_ZEU-6S",
  • "pilotDefId" : "pilot_d10_lancer",
The custom name can be about anything, some special characters may not work. The data\heraldry folder has all of the stock color sets and you can also make your own and then call them here. This case the name above the unit will show "Hired Goons - Lancer" and I assigned a "Lancer" pilot to this unit. The custom names will overwrite the Pilot Skill set you normally see, like an assassination target. If you leave the pilot as "pilotDef_InheritLance", I wouldn't add the pilot type unless you narrowed the required/excluded tags to exactly 1 type. This unit would also be flying Steiner Blue and Gold on a Zeus ZEU-6S, and if it had it visible, the Steiner fist emblem on the side of the 'Mech. However, the emblem when it takes its turn would still show the actual faction controlling it.

You then repeat this process for each Lance and unit in play. You can assign 'Mechs and pilots to the player Lance in the same way, like Kamea in the campaign or the Hatchetman and pilot in Joint Venture. Keeping a Lance as "lanceDefId" : "Tagged", with Tag filters, and then manually assigning a single Lancemate would let you assign that one member and then let the Lance generator fill out the rest procedurally.

Editing Dialogue
The Dialogue is fairly strait forward, at first. You can copy and paste whole sections and just replace the "selectedCastDefId" or [Cast] with whoever you want to do the talking and edit the text as you wish. I don't recommend making these too long.

A problem arises with the mission finishing text. Some missions finish when you enter a Extraction Point, others end where you stand when the field is clear of all forces and objectives have been completed. This is where "Dialogue Buckets" come in. This is a special "bucket" or "pool" of chat boxes for a situation. We generally only need one.

Dialogue Buckets and DialogBucketDef
The line "overrideAutoCompleteDialogueId" : null, in a contract can be replaced with a custom DialogBucketDef for when your mission autocompletes. Some missions don't autocomplete or autocomplete by default (Battle) and may not need this.
  • "overrideAutoCompleteDialogueId" : "DialogBucketDef_c_fp_theRaid_b2_defendBase",
This tells the game to not use the generic "Defend Base" bucket list and to instead use one I made and set the Id the same as shown above. The DialogBucketDef is an incredibly simple file to make:
{
"identifier" : "DialogBucketDef_c_fp_theRaid_b2_defendBase",
"DialogueContentIDs" : [
"Bkt_c_fp_theRaid_b2_defendBase"
]
}

This just says "Hey, use this Id when I'm called." The DialogueContentID is where the actual dialogue is. You usually will want to copy whatever is already in your mission success dialogue and add an opening line about "Coming in to pick-up where you are." or "All targets eliminated. Sit tight, and I can collect you from where you are at right now." and then the rest of the chatter.
Code:
{
    "identifier" : "Bkt_c_fp_theRaid_b2_defendBase",
    "contents" : [
        {
            "words" : "All targets eliminated. Sit tight, and I can collect you from where you are at right now.",
            "wordsColor" : {
                "r" : 1,
                "g" : 1,
                "b" : 1,
                "a" : 1
            },
            "selectedCastDefId" : "castDef_SumireDefault",
            "emote" : "Default",
            "dialogueOrigin" : "pilot",
            "audioEventEntryIndex" : 0,
            "audioEventEntryText" : "NONE",
            "conversationIdx" : 0,
            "cameraFocus" : {
                "EncounterObjectGuid" : ""
            },
            "revealRadius" : -1
        },
    {
        "words" : "Excellent work, Commander. Let's open this thing and see what's inside.",
        "wordsColor" : {
        "r" : 1,
        "g" : 1,
        "b" : 1,
        "a" : 1
        },
        "selectedCastDefId" : "castDef_DariusDefault",
        "emote" : "Default",
        "audioName" : "NONE",
        "cameraFocusGuid" : "",
        "cameraDistance" : "Far",
        "cameraHeight" : "Default",
        "revealRadius" : -1
    },
    {
        "words" : "We detected The Muscles DropShip is feeling! Tiverton is free from these criminals and pirates once and for all.",
        "wordsColor" : {
        "r" : 1,
        "g" : 1,
        "b" : 1,
        "a" : 1
        },
        "selectedCastDefId" : "castDef_LocalsDefault",
        "emote" : "Default",
        "audioName" : "NONE",
        "cameraFocusGuid" : "",
        "cameraDistance" : "Far",
        "cameraHeight" : "Default",
        "revealRadius" : -1
    },
    {
        "words" : "We know the truth, we will be back. Today, everyone gets to feel like they won, even if we've all lost something.",
        "wordsColor" : {
        "r" : 1,
        "g" : 1,
        "b" : 1,
        "a" : 1
    },
        "selectedCastDefId" : "castDef_TeamLeader_Target",
        "emote" : "Default",
        "audioName" : "NONE",
        "cameraFocusGuid" : "",
        "cameraDistance" : "Far",
        "cameraHeight" : "Default",
        "revealRadius" : -1
    },
    {
        "words" : "Until next time\u2026",
        "wordsColor" : {
        "r" : 1,
        "g" : 1,
        "b" : 1,
        "a" : 1
        },
        "selectedCastDefId" : "castDef_TeamLeader_Target",
        "emote" : "Default",
        "audioName" : "NONE",
        "cameraFocusGuid" : "",
        "cameraDistance" : "Far",
        "cameraHeight" : "Default",
        "revealRadius" : -1
    }
    ]
}
Strangely, the default folders for these seem backwards, DialogBucketDef files are inside a "conversationBuckets" folder and the actual conversation dialogue .json inside the "dialogue_buckets" folder.

The Rewards
Flashpoint rewards are listed as a .csv file, or "Comma Separated Values" and if you open the file raw, it would a lot of items separated by commas. However, it's far easier to edit these types of files with an editor like CSVed or others available online. The itemCollection.csv's used for shop inventory and FP rewards have 4 columns:
  • Item
  • Type
  • How many of that item
  • "Drop Weight" of that item
csv_theRaid.jpg
Here we can see a custom reward table for "The Raid" with the first row, first column giving a title for the .csv table "itemCollection_loot_fp_reward_a_theRaid" and this is what you would type in for the rewards in the MS reward data or in the FP editor main screen as the reward displayed on the title card.

The second row defines a part of a 'Mech, a "mechdef_atlas_AS7-D-HT" and in the third column "1" it defines giving the player 1 of these parts. Take a look at the last two entries, the Gyro and Medium Lasers, you get 4 and 15 of those for this FP. The fourth column, the "weight" or "drop weight" is usually just 1 for a reward listing. For FP's, it will dish out every item on each row of this list in the amount defined in column three.

But what if you want to use a pool of potential items to roll from and give one or two to a player?

Referencing
To use the weighted pool of items, you need to reference another .csv. In rows 3-5 we see "Reference" type entries with a "1" in the third column. This will grant one item from those referenced .csv files.

Calling Other .csv Files
The reference lines must have the Id of the next .csv and lets take a look at the one stock .csv files called in the above reward list. The stock itemCollections are found in:
...\BATTLETECH\BattleTech_Data\StreamingAssets\data\itemCollections
csv_table_Weapon_SLDF.jpg
Opening up "itemCollection_table_Weapon_SLDF.csv" and we only see 2 entries and no weapons. That's because this .csv file we referenced, calls two more .csv files based on RNG. Here, we see the first entry as a fourth column value of "4" and the second entry has "1."

This means the "itemCollection_Weapons_SLDF_uncommon.csv" has a 4/5 chance (80%) of being picked over the "itemCollection_Weapons_SLDF_rare.csv" which has the corresponding 1/5 chance (20%) of getting selected on any one roll. This is how weights work to adjust how common or rare an item or reference can be picked. This isn't out of 100 or any preset total, just add up all the weights in the table and divide you current item by the total to find the odds of it dropping.

Let's say we're feeling lucky and the "itemCollection_Weapons_SLDF_rare.csv" is selected.
csv_table_Weapon_SLDF.jpg
Now we see actual weapons. So far, the original reward .csv called for 1 item from "itemCollection_table_Weapon_SLDF.csv" and on that one roll, "itemCollection_Weapons_SLDF_rare.csv" was selected, and now inside that table we will get one roll from the weapons in here. We can see items like the "Weapon_Gauss_Gauss_2-M9" have a weight of just 2 out of a total of 72, or 1/36 (2.78%) which oddly enough is the same as rolling a "12" on two six-sided dice. The other higher weight items like "Weapon_Laser_SmallLaserPulse_1-Maxell" have a 10/72 or 5/36 (13.89%) chance.

Now that you know how to drill through references to other .csv files and how the weights work, take some time to explore around the different possible pools of weapons and gear. You might find some odd stuff in the tables, like the CDA's being in the same rare 'Mech pool as a HGNb in the "itemCollection_Mechs_rare.csv" or other seemingly out of place rewards. If you ever need to find the type of item like "Weapon," "Mech" or "Upgrade" just find them in an existing table.

You would need to determine if your FP needs it's own custom reward list, and if that list would need to reference another custom .csv, or a stock one. These aren't too hard to make, but they can be hard to test, as they are at the end of the FP.

Testing Rewards
I recommend taking my "Sound of Music" FP in the Resources and References above and editing the rewards in the FP file to whatever file you want to test. This FP is just a conversation that you can cancel at any time and then hit the reward screen. This allows for rapid reward testing and you can see what kind of real end results will appear.

One note about the rewards screen - It doesn't show you the amount of the items rewarded in game. So if you see "DHS" on the rewards screen, it looks the same if it's one or a hundred. What I did was setup a "Sound of Music" save just before I accepted the FP but after selling all my gear and anything in storage. Remember, this is using a debug save for testing, so this is fine as long as you are careful. This gives me a clean slate once I'm out of the FP and I can easily see if I got multiples of the same item.

The Original Assets


You might want to create custom images, 'Mechs, Vehicles, cast members, heraldry, Lore descriptions and more. You don't need these, but they can add a special touch to your FP.

In general images should be in the .dds format, and try to keep them as small as possible. The performance modders have advised me to use .dds when possible as it is a lower overhead format for GFX processors compared to .png. However, there are cases where a file must be .png. You can find existing portraits, banners and such in the games files for examples. I'll keep the exact size and more detailed descriptions in the Advanced Editing Post below this one.

CastDef
Code:
{
    "id" : "castDef_FP_MuscleDefault",
    "internalName" : "FP_MuscleDefault",
    "firstName" : "The",
    "lastName" : "Muscle",
    "callsign" : "",
    "rank" : "Black Market Enforcer",
    "gender" : "NonBinary",
    "faction" : "AuriganPirates",
    "sgCharType" : "UNSET",
    "showRank" : true,
    "showFirstName" : true,
    "showCallsign" : false,
    "showLastName" : true,
    "localizeName" : false,
    "defaultEmotePortrait" : {
        "emote" : "Default",
        "portraitAssetPath" : "../../Mods/Flashpoint-The-Raid-1.0.1/castSprites/guiTxrPort_Muscle_default_utr.png"
    },
    "emotePotraitList" : [
 
    ]
}
Creating a new CastDef makes a new name and icon for chat boxes. This does not make a new 3d model of a character in the Argo scenes like Kamea or Yang. This just controls the chat boxes in combat and during Argo conversations. You can however, make a custom portrait for the chat box.

CastDef Portraits Must Be .png Images!

For whatever reason, CastDef portraits are defined by explicit file paths and must be in .png format. This portrait doesn't need to be added to the Version Manifest in ModTek, but you need to keep the file path in mind if you put the version number in your folder structure like "The Raid" does above. When I go to "Flashpoint-The-Raid-1.1.1" from 1.0.1 my file path will break unless I change this before release.

See the advanced FP Editing post below for more details on Art Asset Creation for CastDef Portraits.

Descriptions (Lore Tool-Tips)
Code:
{
    "Id" : "LoreBattleROM",
    "Name" : "BattleROM",
    "Details" : "The equivalent of a Flight Data Recorder found in nearly every combat vehicle used today. Records hundreds of hours of sensor readings, video feeds and status updates in to a blastproof enclosure. Records can be played back as video or even fully recreated in simulator pods.",
    "Icon" : ""
}

This is for the yellow text that you can mouse over in a description or conversation. You can insert these in to a conversation or event like this:
[[DM.BaseDescriptionDefs[LoreBattleROM],BattleROMs]]
That last part "BattleROMs" is where you put the plaintext you want the user to read and the first part inside the inner brackets is where the Id for the description goes.

HeraldryDef
Code:
{
    "Description" : {
        "Cost" : 0,
        "Rarity" : 1,
        "Purchasable" : false,
        "Manufacturer" : "null",
        "Model" : "null",
        "UIName" : "null",
        "Id" : "heraldrydef_FP_theRaid_aces",
        "Name" : "Ace Pirates",
        "Details" : "Super Arrrrrrrr",
        "Icon" : ""
    },
    "textureLogoID" : "uixTxrIcon_blackmarketEmblem",
    "primaryMechColorID" : "Greyscale_05",
    "secondaryMechColorID" : "Greyscale_05",
    "tertiaryMechColorID" : "BrightRed_01"
}
The HeraldryDef is what colors and emblems game puts on 'Mechs and Vehicles. The three color ID's work the same as they do in the game's color selection. The colors white and black are named "Greyscale_01" and "Greyscale_05" respectively and the numbers in between are for shades of grey from lighter to dark. The other colors follow a similar progression, with darker colors having higher numbers.

The textureLogoID is not a direct filepath like what is needed for the CastDef. I believe you could add a custom emblem and call it here, as long as it starts with "uixTxrIcon_" and maybe not even that. Can't say I've tried a full custom yet, but I don't doubt it's possible. Keep in mind, only a very narrow selection of skins even shows this emblem. The Shadow Hawk DLC skin is one of those.

MechDef + ChassisDef
I'm not going to cover the basics of custom MechDef and ChassisDef's here, but there are some things you need to know for FPs.

Unit Tag:
"BLACKLISTED"

Make sure your MechDef has this tag added or else it will appear in random procgen contracts outside of your FP or also in Skirmish Mode. Note that this will also prevent the unit's salvage parts from appearing in the salvage pool, so take this in to consideration. It's also a good idea to make your own unique ChassisDef and add the "BLACKLISTED" tag if you really want to make sure the unit does not show up in salvage.

Making a custom enemy is a great way to increase the challenge without adding more units. However, you must keep in mind the difficulty rating of the FP as a whole, what kinds of custom units the player might have at that level and the rest of that mission OPFOR when you're making your custom unit. A simple and generally safe way to make a unit harder is to take the stock 'Mech and just add upgraded weapons in place of the stock components. This is a fast and easy way to add something different without having to create and balance many Lances of custom OPFOR.

PilotDef
Code:
{
    "Description": {
        "Id": "pilot_FP_ace_brawler",
        "Name": "Ace Brawler",
        "FirstName": "Ace Brawler",
        "LastName": "NONE",
        "Callsign": "Ace Brawler",
        "Gender": "Female",
        "Faction": "Davion",
        "Age": 30,
        "Details": "NONE",
        "Icon": "Wildfire"
    },
    "BaseGunnery": "10",
    "BonusGunnery": 0,
    "BasePiloting": "10",
    "BonusPiloting": 0,
    "BaseGuts": "10",
    "BonusGuts": 0,
    "BaseTactics": "10",
    "BonusTactics": 0,
    "ExperienceUnspent": 0,
    "ExperienceSpent": 0,
    "Injuries": 0,
    "Health": 3,
    "LethalInjury": false,
    "Incapacitated": false,
    "Morale": 0,
    "Voice": "f_overload01",
    "abilityDefNames": [
        "AbilityDefGu5",
        "AbilityDefGu8",
        "AbilityDefP5",
        "TraitDefUnsteadySet60",
        "TraitDefEvasiveChargeAddOne",
        "TraitDefSprintIncrease20",
        "TraitDefUnsteadySet80",
        "TraitDefEvasiveChargeAddTwo",
       "TraitDefHealthAddOne",
        "TraitDefRefireReduceOne",
        "TraitDefOverheatAddFifteen",
        "TraitDefHealthAddTwo",
        "TraitDefRefireReduceTwo",
       "TraitDefOverheatAddThirty",
       "TraitDefHealthAddThree",
       "TraitDefIndirectReduceOne",
       "TraitDefMinRangeReduce45",
       "TraitDefCalledShotImprove",
       "TraitDefIndirectReduceTwo",
       "TraitDefMinRangeReduce90",
       "TraitDefCalledShotMaster",
       "TraitDefIndirectReduceThree"
    ],
    "AIPersonality": "Undefined",
    "PilotTags": {
        "items": [
            "pilot_npc_brawler",
            "pilot_npc_dynamic",
            "BLACKLISTED"
        ],
        "tagSetSourceFile": ""
    },
    "PilotCost": 0
}
The PilotDef controls what Abilities and Traits that unit has access to. You can even set some of the skill levels to 11 or higher and add more Abilities than would be legally available. Check the Mastiff or Kamea files in the stock folder for examples. The PilotDef doesn't have to follow most of the rules around when a pilot should or shouldn't have something. This example is what a full 10 across the board pilot with the "Brawler" (Coolant Vent/Sure Footing) mastery would look like.

Make sure to add the "BLACKLISTED" tag on your pilots! If you don't they'll show up outside your FP in random contracts.

VehicleDef + VehicleChassisDef
Same as MechDef's above, make sure you add the "BLACKLISTED" tag to prevent a custom vehicle from showing up in procgen contracts.

Special note for SRM/LRM Carriers: They don't have turrets and have some bugs that come with it. There are some mods out there like the Vehicle Improvment Project that fix this by adding a turret to the stock vehicle and the associated VehicleChassisDef. If you have a custom SRM/LRM carrier with or without a turret, make your own VehicleChassisDef to match it to prevent mis-matches and failure to load.

The Loading


This is done via ModTek. You will need to use the mod.json format documented here and here. You will need to add any files you want added in to your mod.json manifest. I recommend keeping the same kind of folder structure as HBS in the "BATTLETECH\BattleTech_Data\StreamingAssets\data" folder.

The one exception is .png portraits used for custom castdef.jsons. These are called by direct file paths in the castdef and don't need to be added to the ModTek manifest, they can be, but don't need to. I named my folder "castSprites" to keep it separate from sprites I want loaded in for other things.

The mod.json and folder structure for "The Raid" looks like this:
Code:
{
    "Name": "Flashpoint_The_Raid",
    "Enabled": true,
 
    "Version": "1.0.0",
    "Description": "Flashpoint - The Raid: Tiverton wants the Black Market out, are you in?",
    "Author": "amechwarrior",

    "DependsOn": [ "Flashpoint_Stock_Photos" ],
    "OptionallyDependsOn": [ "cFixes" ],

    "Manifest": [
 
        { "Type": "BaseDescriptionDef", "Path": "descriptions" },
        { "Type": "CastDef", "Path": "cast" },
        { "Type": "ChassisDef", "Path": "chassis" },
        { "Type": "ContractOverride", "Path": "contracts" },
        { "Type": "ConversationContent", "Path": "dialogue_buckets" },
        { "Type": "DialogBucketDef", "Path": "conversationBuckets" },
        { "Type": "FlashpointDef", "Path": "flashpoints" },
        { "Type": "HeraldryDef", "Path": "heraldry" },
        { "Type": "ItemCollectionDef", "Path": "itemCollections" },
        { "Type": "MechDef", "Path": "mech" },
        { "Type": "PilotDef", "Path": "pilot" },
        { "Type": "SimGameConversations", "Path": "simGameConversations" },
        { "Type": "SimGameEventDef", "Path": "events" },
        { "Type": "SimGameMilestoneSet", "Path": "milestoneSets" },
        { "Type": "Sprite", "Path": "sprites" },
        { "Type": "Texture2D",  "Path": "textures", "AddToAddendum": "ConversationTexture" },
        { "Type": "VehicleDef", "Path": "vehicle" }

    ]
}
modtek_folders.jpg
Each file has a type that can be found in the "VersionManifest.csv" if it isn't listed in the example above. The "Path" is the name of the folder to look for that type of file. Take note at the "Texture2D" line near the end. It has a special addendum "AddToAddendum": "ConversationTexture" as in the VersionManifest.csv there is a specific section called "ConversationTexture" and this is the only way to gracefully add custom images to the Holoscreen. If something isn't loading right, make sure it isn't defined in an addendum specifically.

I'm assuming you built your FP and MS files in a stand-alone folder suggested above. You will need to manually copy them over in to your FP's mod folder, in to their appropriate individual folder each time you save with the editor.




[Mod edit: Reminder. No unapproved links]
 

Attachments

  • FP_choice_placeholder.zip
    865 bytes · Views: 37
  • csv_Weapons_SLDF_rare.jpg
    csv_Weapons_SLDF_rare.jpg
    242 KB · Views: 340
Last edited:
Reserved for future use. The OP is complete, but this post of advance topics is still a work-in-progress. Please check back to see if I've added more. If you need a specific area fleshed out, PM me or post here and I'll move it up the list.

Advanced Editing Topics

Setting Conditional Requirements for FP Spawning

Failure Milestones


Contextual Conversion Options

Dialogue Buckets for Contracts

Events

Art Asset Creation

  • Title Card Banners
    • WIP But here's a quick and dirty FP Icon in banner size I used for "The Raid" and you can use this to just apply on a layer on top of your own banner once it's flipped vertically.
    • FP Icon Flipped.png
    • .dds preferred
    • 750x300
    • Flipped Vertically Only
    • Filename prefixed by "uixTxrSpot_"
  • castdef Portraits
    • .png only
    • 512x512 stock size (practically this could be far smaller)
    • not rotated or flipped
    • Filename prefixed by "guiTxrPort_"
  • Faction Emblems
    • .dds only
    • 256x256 stock size
    • Flipped Vertically Only
    • Filename prefixed by "uixTxrIcon_"
  • Holoscreen Images (Thanks to @bullethead, @Hobbes & @T-bone on discord for troubleshooting this)
    • .dds only
    • 512x512 stock size - wider images will be horizontally compressed to fit
    • Rotate canvas by 180 degrees if adding text to ima
    • Filename prefixed by "uixTxrConv_"
 
Last edited:
This needs to be stickied
 
:eek:

<3 <3 <3 <3
Thanks! That's how I felt the first time I played "The Raid" from start to end without debug mode and all the conversations in place. It's a magical feeling I'm sure you and everyone at HBS feels when something comes together right. I'd love to see how you or other HBS devs handle "The Raid" on their first play!

If you have any topics or areas in this guide that I might have missed, need more work, or got wrong - Let me know!
 
Currently, I don't believe it is possible to safely set a "Flashpoint_AddContract" that is also on a kind of timer that would force-start it once the timer expires. I tried this for "The Raid" and asked the devs if this was possible, but while it might be, it's an incredibly risky implementation of tags, events and other parts that shouldn't be used in such a way as it risks harming the save. The devs did not recommend I use it and I agreed.
The timer I'd be more interested in would be auto-failing the mission if not taken within the time limit... or spawning the next contract only after time passes. Seems like those would be far more realistic timers than forcing the mission to start, and would be useful for making flashpoints that emulate garrison duty contracts and the like. Any idea if that would be possible?

Regardless, thanks for taking the time to write all of this up! Very helpful.
 
The timer I'd be more interested in would be auto-failing the mission if not taken within the time limit... or spawning the next contract only after time passes. Seems like those would be far more realistic timers than forcing the mission to start, and would be useful for making flashpoints that emulate garrison duty contracts and the like. Any idea if that would be possible?

Regardless, thanks for taking the time to write all of this up! Very helpful.

Yes, that was my intent as well - force launch or fail within x days. I was going to make the pattern 2 missions > 2 days off > 1 mission > 1 day off > 2 missions but I couldn't get it to work. I don't think failing within X days would be possible either, without some complex event work. So...

As far as I know, and my understanding of what the devs told me - Once the MS is triggered and populated the game doesn't really "check" for them on a daily basis until the Actions in that MS are done and that triggers a check for the "Next MS" entry. It might be possible to trigger the "setnextMS" in an event that is force triggered after X days of a MS, but it's going to get weird on you fast.

Turns out, doing a convo, triggering a MS or doing a mission "advances a day" in the event day counter, likely a hold over from when 1 mission was 1 day hard coded until 1.3. So while I have an event in "The Raid" that takes place "20 days" or so after it is triggered, simply completing the FP normally makes it trigger 5 days sooner than you would think. I wouldn't relay on timed events for this kind of thing given even if a player abandons a FP,m that event WILL still trigger even if it has all kinds of exclusion tags and the FP has been abandoned or completed. "Forced Events" are totally forced to happen within the min/max days and % weight to spawn chance set in the Event Result Window. I haven't gotten to that part of the guide yet.

This made my "Infiltration Demoralization" event really hard to write. I was forced to write it without any context of where the player could have gone after the trigger. Pass, Fail, A or B branch, I couldn't have any of that in the event and that is unfortunate.

Also, that event is a stealth bug fix...

Farah leaves for a bit, and if you abandon the FP RIGHT THERE or fail the next mission, she won't come back. That event also forces her to return, hopefully without the player noticing. Given the event is triggered at the same time she goes away, it's a fairly reliable fix for an edge case situation.
 
Alright, so the basics of the FP json and MS json are done. The Convo, contracts and the rest will be next. But, what I got now should be about enough to get a FP structure going and maybe playable with some placeholder convos and stock contracts.
 
Work continues, but I added a really useful aid for anyone looking to start.

FP_choice_placeholder.zip at the bottom of the OP is a placeholder convo used for applying the default FP tags in a known good conversation file. Just drop this file's GUID in your TalkChoice MS and you should be able to select your branch for testing.
 
The Flashpoint Reference Sheets are now updated to 1.6.1. The only sheet in there not yet updated is the Contracts, with all the optional chunks. I will work on that once my other mods are updated for 1.6. If anyone wants to help maintain this sheet, let me know.
 
Just ran into this and figured it out, but figured I would comment here since the guide makes mention of the textureIconID but uses a vanilla ID in the examples.

If you are using a custom textureIconID (such as in the heraldrydef files), you need to make sure the path for those icons is specified twice, as a Sprite as well as a Texture2D.

Code:
        { "Type": "Sprite", "Path": "myUnitIcons" },
        { "Type": "Texture2D",  "Path": "myUnitIcons" },
 
Another sort of 'hiccup' that I ran into (and I'm not sure if it's better suited in the Flashpoint Guide or in @CWolfs ConverseTek FAQ) was getting the conversation to show the command deck. It wasn't obvious how to do that until I looked at an existing conversation and saw the Fade action at the beginning of the conversation.
 
How do I generate the following sequence?

Start Flashpoint
Have conversation describing Flashpoint - Contract generated
Select Contract - negotiate contract
New conversation*
Select Mechs
Deploy

It's the (*) I am unable to execute. I would like to have another conversation prior to the mission beginning. I am pretty sure this happened in the Vanilla campaign, is it possible in this?

Edit: to clarify, if you use addcontract/startcontract, it seems the next milestone you add will only occur AFTER the mission has taken place.
 
Another question, is it possible to generate a sequence of missions that do not have to be played sequentially, but will always occur in the specified order?

I am thinking for the purposes of making something similar to the main campaign? Perhaps by adding a persistent tag to the company that is used as a requirement for the next Flashpoint spawning?
 
How do I generate the following sequence?

Start Flashpoint
Have conversation describing Flashpoint - Contract generated
Select Contract - negotiate contract
New conversation*
Select Mechs
Deploy

It's the (*) I am unable to execute. I would like to have another conversation prior to the mission beginning. I am pretty sure this happened in the Vanilla campaign, is it possible in this?

Edit: to clarify, if you use addcontract/startcontract, it seems the next milestone you add will only occur AFTER the mission has taken place.

I don’t think you can have an actual conversation with choices, but you can edit the contract dialogue to suit that purpose in a way.
 
Another question, is it possible to generate a sequence of missions that do not have to be played sequentially, but will always occur in the specified order?

I am thinking for the purposes of making something similar to the main campaign? Perhaps by adding a persistent tag to the company that is used as a requirement for the next Flashpoint spawning?

YES! You can have one contract milestone set a tag and have several other milestones depend on that tag being set.

Each of those branches would set their own tags as well.

And then for bringing them back together you can have a milestone that depends on all of those other tags.
 
Although this may sound like a strange request, it is what happens in the "Benefactor" mission of the vanilla campaign, and I suspect others too although I can't be bothered checking.

I am looking at whether I can make a "flashpoint" that is just a conversation as a workaround, although I can't terminate it without having the reward screen come up.

Once this flashpoint is complete, another will be generated that provides a follow-up conversation as you prepare to drop.
 
Last edited:
So, yeah. You can have a Flashpoint just be a conversation and set the reward to be something minimal (cash advance, nothing at all, reputation, whatever). I'm not sure you can entirely get rid of the reward screen though. Definitely keep us posted if you try it out.