Skip to main content

Seasons System

Titan implements Path of Exile-style seasons (leagues) with temporary and permanent leagues.

Season Types​

Season Model​

interface Season {
seasonId: string; // e.g., "standard", "season-1"
name: string; // Display name
description?: string;
status: SeasonStatus;
isPermanent: boolean;
targetSeasonId?: string; // Migration destination
startedAt?: string;
endsAt?: string;
}

Season Status​

Status Values​

StatusDescription
UpcomingVisible, no characters yet
ActiveOpen for character creation
EndingWarning period, no new characters
EndedFinished, migration pending
MigratingCharacters being moved
MigratedAll characters moved

Character Restrictions​

When creating a character, players can choose restrictions:

RestrictionValueEffect
None0Normal gameplay
Hardcore1Death = migration to permanent
SoloSelfFound2Cannot trade with others

Hardcore Characters​

Solo Self-Found (SSF)​

SSF characters:

  • Cannot participate in trades (blocked by SoloSelfFoundRule)
  • Cannot use shared stash tabs
  • Play completely self-reliant

Season Migration​

When a temporary season ends, characters migrate to the permanent league:

What Migrates​

EntityBehavior
CharactersMoved to permanent league
EquipmentStays on character
Bag ItemsMoved to stash
StashMerged with permanent stash
ProgressCarried over

Migration API​

// Admin: End the season
await connection.invoke("EndSeason", "season-1");

// Admin: Start migration
await connection.invoke("StartMigration", "season-1");

// Check progress
const status = await connection.invoke("GetMigrationStatus", "season-1");
console.log(`${status.completed}/${status.total} characters migrated`);

Void League​

For experimental mechanics, Void leagues prevent migration:

// Create void season
await connection.invoke("CreateSeason", {
seasonId: "void-experimental",
name: "Experimental Void",
isPermanent: true,
targetSeasonId: null // Items don't leave
});

Characters and items in Void leagues:

  • Never migrate to permanent
  • Are "stuck" in the void season
  • Can still be played but isolated

Season Events​

Subscribe to season updates:

connection.on("SeasonEvent", (event) => {
switch (event.eventType) {
case "SeasonCreated":
showNewSeason(event.season);
break;
case "SeasonStatusChanged":
updateSeasonStatus(event.season);
break;
case "MigrationStarted":
showMigrationBanner();
break;
case "MigrationCompleted":
refreshCharacterList();
break;
}
});

await connection.invoke("JoinAllSeasonsGroup");