C# API
Extend the Alegacy Quest Framework with custom actions, objectives, and integrations using the C# API.
💡 For chat commands, see Commands.
Getting a Reference
Access the quest system from any mod system class:
// In your ModSystem class
QuestSystem questSystem = api.ModLoader.GetModSystem();Registering Custom Actions
Actions are executable commands triggered by quest events. Register your own during startup:
public class MyCustomAction : QuestActionBase
{
public override string ActionId => "mycustomaction";
public override void Execute(IServerPlayer player, string[] args, ActionContext ctx)
{
// args[0], args[1], etc. from the JSON "args" array
string message = args.Length > 0 ? args[0] : "Hello!";
player.SendMessage(GlobalConstants.GeneralChatGroup, message, EnumChatType.Notification);
}
}
// Register in your ModSystem.StartServerSide():
questSystem.ActionRegistry.Register(new MyCustomAction());Use in quest JSON:
{
"id": "mycustomaction",
"args": ["Welcome to the quest!"]
}Or as an action string in dialogues:
mycustomaction 'Welcome to the quest!'Registering Custom Objectives
Objectives define conditions players must complete:
public class MyCustomObjective : QuestObjectiveBase
{
public override string ObjectiveId => "mycustomobjective";
public override bool CheckProgress(IServerPlayer player, QuestObjectiveInstance instance)
{
// Return true when the objective is complete
int current = GetPlayerProgress(player, instance);
return current >= instance.Demand;
}
}
// Register in your ModSystem.StartServerSide():
questSystem.ObjectiveRegistry.Register(new MyCustomObjective());Then use in quest JSON:
{
"id": "mycustomobjective",
"args": ["param1", "5"]
}Action String Executor
The ActionStringExecutor.Execute() method parses and runs action strings from dialogues and other triggers.
Parsing Rules
- The input string is split by
;(semicolon) into individual action commands - Each command is parsed using regex:
(?:'([^']*)')|([^\s]+) - The first token is the action ID
- Subsequent tokens are arguments
- Arguments wrapped in single quotes
'...'preserve spaces inside them - The action ID is looked up in
QuestSystem.ActionRegistryand executed
actionId arg1 arg2 'argument with spaces'; anotherActionId arg1Reputation API
// Get current reputation value
int rep = questSystem.ReputationManager.GetReputation(player, "npcId");
// Add reputation (with optional max and once-key)
questSystem.ReputationManager.AddReputation(player, "npc", "npcId", 10, max: 100, onceKey: "quest1");
// Get current rank info
ReputationRank rank = questSystem.ReputationManager.GetCurrentRank(player, "npcId");
// Check if player meets reputation requirements
bool meets = questSystem.ReputationManager.MeetsRequirements(player, new[] {
new ReputationRequirement { scope = "npc", id = "yourmod:innkeeper", min = 500 }
});Quest Events
questSystem.OnQuestAccepted += (player, questId) => {
// Fired when any quest is accepted
};
questSystem.OnQuestCompleted += (player, questId) => {
// Fired when any quest is completed
};
questSystem.OnQuestFailed += (player, questId) => {
// Fired when any quest fails
};
questSystem.OnObjectiveProgress += (player, questId, objectiveIndex, current, demand) => {
// Fired when objective progress changes
};
questSystem.OnStageCompleted += (player, questId, stageIndex) => {
// Fired when a stage is completed
};Boss Hunt API
// Get current active boss key
string activeBoss = questSystem.BossHuntManager.GetActiveBossKey();
// Get time until next rotation
double hoursLeft = questSystem.BossHuntManager.GetHoursUntilRotation();
// Force rotate to next boss
questSystem.BossHuntManager.ForceRotate();
// Check if a specific boss is currently active
bool isActive = questSystem.BossHuntManager.IsBossActive("yourmod:dragon");Journal API
// Add a journal entry
questSystem.JournalManager.AddEntry(player, "yourmod:lore-1", "group1");
// Get all entries for a player
List<JournalEntry> entries = questSystem.JournalManager.GetEntries(player, "group1");
// Check if player has an entry
bool has = questSystem.JournalManager.HasEntry(player, "yourmod:lore-1");
// Remove all entries in a group
questSystem.JournalManager.ClearGroup(player, "group1");Database Sync API
// Manually sync a player (if you need to force-update)
questSystem.DbSyncService.SyncPlayer(player);
// Check if sync is enabled
bool enabled = questSystem.DbSyncService.IsEnabled;Item Quality API
// Generate a quality item from action item config
ItemStack stack = questSystem.QualityManager.GenerateItem(
player,
"yourmod:epic-sword",
qualityOverride: 3
);
// Get quality bonus for a specific attribute
float bonus = questSystem.QualityManager.GetBonus(stack, "damage");
// Reroll an item (consumes reroll token)
bool success = questSystem.QualityManager.Reroll(player, stack, "yourmod:weapon-reroll");Building from Source
Requirements:
- .NET 10 SDK
- Vintage Story 1.22.1+
dotnet buildComplete ModSystem Example
using Vintagestory.API.Common;
using Vintagestory.API.Server;
using AlegacyVSQuest;
public class MyQuestMod : ModSystem
{
private QuestSystem questSystem;
public override void StartServerSide(ICoreServerAPI api)
{
questSystem = api.ModLoader.GetModSystem<QuestSystem>();
// Register custom action
questSystem.ActionRegistry.Register(new MyCustomAction());
// Register custom objective
questSystem.ObjectiveRegistry.Register(new MyCustomObjective());
// Subscribe to events
questSystem.OnQuestCompleted += (player, questId) => {
api.Logger.Notification($"Player {player.PlayerName} completed {questId}");
};
}
}