Skip to content

Your first battle

This tutorial adds a one-round sparring fight to the mod from Your first weapon. Finish that tutorial first so you know your manifest, localization, and script load correctly. No additional capabilities or asset downloads are required: the fight reuses core art and a core warrior template.

Part Purpose
Zone A map page that contains your battle entry.
Battle The entry the player selects.
Location The arena background and fighter positions.
Warrior The opponent’s template, level, and tactic.
Rewards What the player receives for each result.
Fight The connection between the battle and those gameplay definitions.
Quest Reveals the battle when a map session begins.

Keep the registrations in this order where one definition depends on another. The variable names below hold handles returned by earlier calls.

Append these lines to localizations/eng.toml:

battle.training = "Sparring Practice"
battle.description = "Win one round against a training opponent."
opponent.name = "Sparring Partner"

The battle and warrior presentation fields below expect qualified strings, while the weapon’s display_name expects a localization handle. The reference states which form each field uses.

Append this to scripts/main.lua, after the existing weapon script. Keep its existing local sf2 = require("sf2") at the top.

local arena = sf2.locations.register {
id = "training_arena",
width = 1936, height = 512,
floor = 80, wall = 200,
layers = {
{
type = 1,
images = { {
sprite = sf2.assets.sprite(
"core:textures/locations/battlefield/battlefield_bg1.back_1"),
width = 1936, height = 1024,
} },
},
{
type = 2,
fighters = {
player_x = 868, player_y = -94,
enemy_x = 1068, enemy_y = -94,
},
},
},
}

The first layer draws the background. The second positions the fighters. These coordinates come from the matching core battlefield layout; when using different art, test the floor and camera framing in game.

Append:

local zone = sf2.zones.register {
id = "training_zone", file = "Map1.1", start = false,
}
local battle = sf2.battles.register {
id = "training_battle", zone = zone, type = sf2.battles.STORY,
x = 0, y = 0,
alias = sf2.localization.key("battle.training"),
title = sf2.localization.key("battle.training"),
description = sf2.localization.key("battle.description"),
location = arena,
}
local opponent = sf2.warriors.register {
id = "sparring_partner",
template = sf2.warriors.get_template("core:warrior-templates/default"),
first_name = sf2.localization.key("opponent.name"),
level = 1,
tactic = "Standard",
}

sf2.localization.key looks up a line from your localizations/ files, so the text follows the player’s language. The core template supplies the opponent’s starting definition. Standard selects an existing AI tactic. You can add compatible equipment through items = { ... } later.

Append:

local no_reward = sf2.rewards.register { id = "training_no_reward" }
local fight = sf2.fights.register {
id = "training_fight",
battle = battle,
warriors = { opponent },
rounds = 1,
round_time = 99,
rewards = { no_reward, no_reward },
}

This practice fight awards nothing on either result. The first reward slot is for zero wins. The second is for one win. To add a victory prize later, register a separate reward and put its handle in the second slot. See Rewards and fights for item grants and gem rewards.

Append:

sf2.quests.register {
id = "reveal_training",
place = "map",
events = { "session" },
actions = {
{ type = "show_battle", battle = battle, locked = false },
{ type = "map_focus", battle = battle },
},
}
sf2.log.info("Sparring Practice registered")

The quest reveals the battle and focuses the map when its session event runs. For a larger mod, use conditions and progression so the map does not repeatedly focus on your practice battle. Registering the battle alone would not supply that reveal step.

Exit Eclipse completely after saving the files, launch it again, and enter Campaign with the mod enabled. On a profile that can open the map, look for Sparring Practice. Check that its panel opens, the arena and opponent appear, and winning or losing returns you cleanly to the game. Confirm the practice fight does not grant a reward.

If the entry is missing, inspect mod errors first, then check the quest event and its battle handle. If the fight fails to start, check the arena, template, and localization references. A successful registration is only the first check; this new combination still needs an in-game playtest in your build.

Next, try adding a fight rule, an opponent perk, or a mode that tracks a sequence of fights.