Contract Framework
Deprecated — superseded by Essentials (Ess). This system is absorbed there as native
Ess.Contract— the same objective builders plus the support / trigger / relations / AI-order subsystems — shipped in one drop-in1_Ess.lua. This page and its children stay as historical reference for the standalone predecessor; new mods should build on Ess.
Status: new, in development. This documents a real, substantial system as currently written and read directly from source — not a proposal. It hasn’t yet accumulated the kind of live-test history the rest of this wiki marks with “confirmed working” banners; treat code behavior as authoritative and expect this section to gain confirmation notes (and bugfixes) as more of it gets played.
A save-safe, ephemeral custom-mission system for Mercenaries 2 — built as a framework for other modders to build on, not a one-off mod. It exists because the game’s own native contract system (WifMissionData + MrxTask) corrupts saves if you hook into it: it serializes task nodes into the save file and drives missions through dynamic_import + mrxbriefing + the MrxState load gate. This framework touches none of that — a contract is a plain runtime object built only from safe primitives (Pg.Spawn / Event.* / Object.* / MrxPmc). It can’t corrupt a save because it never writes to one; the tradeoff is that an active contract doesn’t survive a save/reload (it’s simply re-offered next level load).
The four pieces
ContractFramework.lua— the engine. AContract.Register({...})table describes a whole mission: objectives, rewards, spawned units, AI orders, faction relations, triggered support call-ins. Runs entirely fromscripts/OnLoad/.- MissionForge — an in-game, Halo-Forge-style authoring tool (
scripts/OnKey/MissionForge.lua): fly around, place things, capture a mission’s shape directly in the world instead of guessing coordinates by hand. Built on the same input/camera lineage as ForgeCam — see the MissionForge deep dive for how it got there, or the reference page for day-to-day use. - The web tool (
missionforge.html, in the companionmercs2-toolsrepo) — pastes what MissionForge captured, then walks a 9-step form (mission details, start position, objectives, units, relations, support call-ins, triggers, AI orders) and generates the finalContract.Register({...})Lua. This is the piece aimed squarely at non-programmers — no Lua required to build a working mission. See The Web Tool. - The Contract Board (
scripts/OnKey/contracts.lua) — the player-facing side: a category-grouped mission list, a details/rewards/objectives panel, and HUD tracker widgets, all built on the same gfxforge/gfx_tool Scaleform pipeline as Custom UI. Fully decoupled from the engine — it only ever callsContract.All/Accept/Abort/Status, and runs in a demo mode with fake contracts if no framework is loaded, so the UI can be worked on standalone. See The Contract Board.
Reference pages
- Contract.Register & Lifecycle — the modder API surface, why it’s save-safe,
Accept/Status/Abort, and the built-in demo contract. - Objectives Reference — all 16 objective types, sequential vs. parallel execution, nesting, and how objectives source their targets.
- Support Effects & Triggers — scripted call-ins (artillery, airstrikes, reinforcements, music/vfx/vo) and the condition system that fires them.
- Units, AI Orders & Relations — spawning grouped units, commanding them with AI behaviors, and temporarily overriding faction stances for a contract’s duration.
- MissionForge — controls, catalog, and export workflow for the in-game authoring tool (see also the deep dive for the design story).
- The Contract Board — the player-facing UI, its four-function engine adapter, demo mode, and the tracker widgets.
- The Web Tool — the 9-step wizard, round-trip re-editing, the flow graph, and the live map.
- End-to-End Walkthrough — the whole pipeline, start to finish, with a concrete worked example.
- ContractFramework.lua — the engine’s complete, current source, reproduced in full.
- WaveDefense — a full gamemode built on the engine’s
onBegin/hideTrackerescape hatch, using a contract as a bare launcher instead of the whole mission.
Load order
ContractFramework.lua must load before any contract file that calls Contract.Register. Give it a low lua_loader.ini [OnLoad] number:
[OnLoad]
ContractFramework.lua=5
MyContracts.lua=15
Every modder contract file checks _G.Contract on load and logs a clear warning (rather than erroring) if the framework hasn’t loaded yet — see Contract.Register & Lifecycle for why.