Learn how to combine multiple Argonath frameworks to create rich, interconnected features.
Create quests that interact with NPCs for dialogues and quest givers.
<dependency>
<groupId>com.hytalemod.argonath</groupId>
<artifactId>framework-quest</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>com.hytalemod.argonath</groupId>
<artifactId>framework-npc</artifactId>
<version>1.0.0</version>
</dependency>
// Create an NPC quest giver
NPC questGiver = npcManager.createNPC("village_elder")
.withName("Village Elder")
.withDialogue("greeting", "Welcome, traveler!")
.build();
// Create a quest from this NPC
Quest quest = questManager.createQuest("elder_quest")
.withQuestGiver(questGiver.getId())
.addObjective(ObjectiveType.TALK_TO_NPC, questGiver.getId())
.onComplete(() -> {
questGiver.updateDialogue("greeting", "Thank you for your help!");
})
.build();
// Link NPC interaction to quest
npcManager.onInteract(questGiver.getId(), (player, npc) -> {
if (!questManager.hasQuest(player, quest.getId())) {
questManager.offerQuest(player, quest);
} else {
questManager.advanceObjective(player, quest.getId());
}
});
Display quest information in custom UI elements.
<dependency>
<groupId>com.hytalemod.argonath</groupId>
<artifactId>framework-quest</artifactId>
</dependency>
<dependency>
<groupId>com.hytalemod.argonath</groupId>
<artifactId>framework-ui</artifactId>
</dependency>
// Create a quest tracker UI component
UIComponent questTracker = uiManager.createPanel("quest_tracker")
.withTitle("Active Quests")
.withSize(300, 400)
.build();
// Bind quest data to UI
questManager.onQuestAccepted((player, quest) -> {
questTracker.addChild(
uiManager.createLabel(quest.getId())
.withText(quest.getName())
.withDescription(quest.getDescription())
.build()
);
});
questManager.onQuestCompleted((player, quest) -> {
questTracker.removeChild(quest.getId());
});
// Update UI on objective progress
questManager.onObjectiveProgress((player, quest, objective) -> {
questTracker.updateChild(quest.getId(),
label -> label.setProgress(objective.getProgress())
);
});
Use conditions to control quest availability and progression.
<dependency>
<groupId>com.hytalemod.argonath</groupId>
<artifactId>framework-quest</artifactId>
</dependency>
<dependency>
<groupId>com.hytalemod.argonath</groupId>
<artifactId>framework-condition</artifactId>
</dependency>
// Define quest prerequisites using conditions
Condition levelRequirement = conditionManager.create()
.type(ConditionType.PLAYER_LEVEL)
.withParameter("minLevel", 10)
.build();
Condition previousQuestCompleted = conditionManager.create()
.type(ConditionType.QUEST_COMPLETED)
.withParameter("questId", "intro_quest")
.build();
// Create quest with conditions
Quest advancedQuest = questManager.createQuest("advanced_quest")
.withName("Advanced Challenge")
.withPrerequisites(levelRequirement, previousQuestCompleted)
.build();
// Use conditions for branching quest paths
Quest moralChoice = questManager.createQuest("moral_choice")
.addObjective(ObjectiveType.CHOICE, "help_or_harm")
.onChoice("help", () -> {
questManager.createFollowUpQuest("hero_path")
.withPrerequisite(
conditionManager.questChoice("moral_choice", "help")
)
.build();
})
.onChoice("harm", () -> {
questManager.createFollowUpQuest("villain_path")
.withPrerequisite(
conditionManager.questChoice("moral_choice", "harm")
)
.build();
})
.build();
Persist quest and NPC data across sessions.
<dependency>
<groupId>com.hytalemod.argonath</groupId>
<artifactId>framework-quest</artifactId>
</dependency>
<dependency>
<groupId>com.hytalemod.argonath</groupId>
<artifactId>framework-storage</artifactId>
</dependency>
// Configure quest storage
storageManager.register(QuestProgress.class)
.withSerializer(new QuestProgressSerializer())
.withBackend(StorageBackend.JSON)
.build();
// Auto-save quest progress
questManager.onQuestProgress((player, quest) -> {
QuestProgress progress = questManager.getProgress(player, quest);
storageManager.save("quest_progress", player.getId(), progress);
});
// Load quest progress on player join
playerManager.onPlayerJoin(player -> {
QuestProgress progress = storageManager.load(
"quest_progress",
player.getId(),
QuestProgress.class
);
if (progress != null) {
questManager.restoreProgress(player, progress);
}
});
Centralize configuration for multiple frameworks.
quest:
maxActiveQuests: 5
autoSave: true
saveInterval: 300 # seconds
npc:
maxInteractionDistance: 5.0
enableDialogueHistory: true
ui:
questTracker:
enabled: true
position:
x: 10
y: 10
size:
width: 300
height: 400
storage:
backend: JSON
path: ./data/quests
// Load central configuration
Config config = configManager.load("argonath.yml");
// Configure quest manager
questManager.configure(builder -> builder
.maxActiveQuests(config.getInt("quest.maxActiveQuests"))
.autoSave(config.getBoolean("quest.autoSave"))
.saveInterval(config.getInt("quest.saveInterval"))
);
// Configure NPC manager
npcManager.configure(builder -> builder
.maxInteractionDistance(config.getDouble("npc.maxInteractionDistance"))
.enableDialogueHistory(config.getBoolean("npc.enableDialogueHistory"))
);
// Configure UI
if (config.getBoolean("ui.questTracker.enabled")) {
uiManager.createQuestTracker()
.atPosition(
config.getInt("ui.questTracker.position.x"),
config.getInt("ui.questTracker.position.y")
)
.withSize(
config.getInt("ui.questTracker.size.width"),
config.getInt("ui.questTracker.size.height")
)
.build();
}
public class CompleteQuestMod {
private ServiceRegistry registry;
private QuestManager questManager;
private NPCManager npcManager;
private UIManager uiManager;
private ConditionManager conditionManager;
private StorageManager storageManager;
public void initialize() {
// 1. Initialize service registry
registry = ServiceRegistry.create();
// 2. Initialize managers
storageManager = new StorageManager(registry);
conditionManager = new ConditionManager(registry);
npcManager = new NPCManager(registry);
questManager = new QuestManager(registry);
uiManager = new UIManager(registry);
// 3. Configure storage
configureStorage();
// 4. Create NPCs
NPC questGiver = createQuestGiver();
// 5. Create quests
Quest mainQuest = createMainQuest(questGiver);
// 6. Set up UI
createQuestTrackerUI();
// 7. Wire everything together
wireEventHandlers();
}
private void configureStorage() {
storageManager.register(QuestProgress.class)
.withBackend(StorageBackend.JSON)
.build();
}
private NPC createQuestGiver() {
return npcManager.createNPC("elder")
.withName("Village Elder")
.withDialogue("greeting", "Greetings, adventurer!")
.withDialogue("quest_available", "I need your help!")
.withDialogue("quest_complete", "Thank you!")
.build();
}
private Quest createMainQuest(NPC questGiver) {
Condition levelReq = conditionManager.create()
.type(ConditionType.PLAYER_LEVEL)
.withParameter("minLevel", 5)
.build();
return questManager.createQuest("main_quest")
.withName("The Elder's Request")
.withDescription("Help the village elder")
.withQuestGiver(questGiver.getId())
.withPrerequisite(levelReq)
.addObjective(ObjectiveType.TALK_TO_NPC, questGiver.getId())
.addObjective(ObjectiveType.COLLECT_ITEM, "ancient_scroll", 1)
.addObjective(ObjectiveType.RETURN_TO_NPC, questGiver.getId())
.addReward("gold", 500)
.addReward("experience", 1000)
.build();
}
private void createQuestTrackerUI() {
UIComponent tracker = uiManager.createPanel("quest_tracker")
.withTitle("Active Quests")
.atPosition(10, 10)
.withSize(300, 400)
.build();
questManager.onQuestAccepted((player, quest) -> {
tracker.addQuestDisplay(quest);
});
questManager.onObjectiveProgress((player, quest, objective) -> {
tracker.updateObjectiveProgress(quest.getId(), objective);
});
questManager.onQuestCompleted((player, quest) -> {
tracker.removeQuestDisplay(quest.getId());
});
}
private void wireEventHandlers() {
// Save progress on changes
questManager.onQuestProgress((player, quest) -> {
storageManager.save("progress", player.getId(),
questManager.getProgress(player, quest));
});
// Load progress on join
registry.getEventBus().on(PlayerJoinEvent.class, event -> {
QuestProgress progress = storageManager.load(
"progress",
event.getPlayer().getId(),
QuestProgress.class
);
questManager.restoreProgress(event.getPlayer(), progress);
});
}
}
Always register your managers with the service registry for proper dependency injection:
registry.register(QuestManager.class, questManager);
registry.register(NPCManager.class, npcManager);
Prefer events over direct coupling:
// Good: Event-driven
questManager.onQuestComplete((player, quest) -> {
npcManager.updateDialogue(...);
});
// Avoid: Direct coupling
questManager.completeQuest(player, quest, npcManager);
Keep configuration external for flexibility:
// Good: Configurable
int maxQuests = config.getInt("quest.maxActiveQuests");
// Avoid: Hardcoded
int maxQuests = 5;
Initialize in correct order (dependencies first):
1. Platform Core
2. Storage & Config
3. Condition System
4. Individual Frameworks (NPC, Quest)
5. UI Components
6. Wiring/Event Handlers
Solution: Use event bus to break circular dependencies.
Solution: Ensure proper initialization order and service registration.
Solution: Verify storage backend configuration and serializers.
Ready to integrate? Start with the Complete Example project!