A .NET library for quest and inventory management systems in games and applications. This library provides a comprehensive framework for managing players, quests, inventories, and item systems.
- Quest System: Create and manage quests with dependencies, repeatability, rewards, and abandonment
- Inventory System: Flexible slot-based inventory with weight limits and item stacking
- Player Management: Unified player interface for quest and inventory operations
- Requirement System: Extensible system for quest prerequisites
Install the package via NuGet Package Manager:
dotnet add package PilgrimageOr via Package Manager Console:
Install-Package Pilgrimage- Slot Containers: Each container has a fixed number of slots and optional weight limit
- Item Stacking: Items stack up to their
MaxQuantityPerSlotvalue - Weight System: Items can have weight, and containers can have weight limits
- Multiple Containers: Players can have multiple containers for organization
- Requirements Check: Quest dependencies must be met
- Start Quest: Player receives up-front items (if any)
- Complete Quest: Player receives reward items (if inventory has space)
- Abort Quest: Player can abandon quest, up-front items are removed, quest returns to Available state
- Repeatability: Some quests can be repeated with cooldowns and limits
- RequirementBase: Create custom quest requirements by inheriting from this class
- Item System: Extend the item system by inheriting from
ItemorWorldItem
This project is licensed under the MIT License.
using Pilgrimage;
// Create a player
Player player = new();
// Add inventory space (16 slots, max 100 weight)
player.AddSlotContainer(16, 100);
// Create a quest system
Quests questSystem = new();
// Create and add a quest
Quest welcomeQuest = new()
{
Id = 1
};
questSystem.AddQuest(welcomeQuest);
// Start the quest
if (questSystem.CanStartQuest(player, welcomeQuest, DateTime.UtcNow))
{
questSystem.StartQuest(player, welcomeQuest, DateTime.UtcNow);
}The Player class is the main interface for managing a player's inventory and quest progress.
Player player = new();
// Inventory management
player.AddSlotContainer(maxSlots: 20, maxWeight: 150);
player.AddItem(sword, quantity: 1);
bool hasPotion = player.HasItem(healthPotion, quantity: 5);
// Quest management
bool canStart = player.CanStartQuest(quest, DateTime.UtcNow);
player.StartQuest(quest, DateTime.UtcNow);
bool hasCompleted = player.HasCompletedQuest(quest);
bool canComplete = player.CanCompleteQuest(quest);
player.CompleteQuest(quest, DateTime.UtcNow);
// Quest abortion
bool canAbort = player.CanAbortQuest(quest);
player.AbortQuest(quest, DateTime.UtcNow);// Create a basic item
WorldItem sword = new()
{
Id = 1,
MaxQuantityPerSlot = 1, // Only one sword per slot
Weight = 5 // Each sword weighs 5 units
};
// Create a stackable item
WorldItem arrow = new()
{
Id = 2,
MaxQuantityPerSlot = 99, // Up to 99 arrows per slot
Weight = 1 // Each arrow weighs 1 unit
};Player player = new();
// Add a container with 16 slots and no weight limit
player.AddSlotContainer(16);
// Add a container with 8 slots and 50 weight limit
player.AddSlotContainer(8, 50);
// Add multiple containers for different purposes
player.AddSlotContainer(20); // General inventory
player.AddSlotContainer(10, 25); // Equipment bag with weight limit// Add items to inventory
bool success = player.AddItem(sword, 1);
player.AddItem(arrows, 50);
// Check if player has items
bool hasSword = player.HasItem(sword, 1);
bool hasEnoughArrows = player.HasItem(arrows, 30);
// Remove items from inventory
bool removed = player.RemoveItem(arrows, 10); // Remove 10 arrows
player.RemoveItem(sword, 1); // Remove the sword
// Quest items cannot be removed while quest is active
WorldItem questMap = new() { Id = 3, QuestId = 100 }; // Associated with quest 100
// This will fail if quest 100 is currently in progress
bool canRemove = player.RemoveItem(questMap, 1);// Basic quest
Quest deliveryQuest = new()
{
Id = 100
};
// Quest with rewards
Quest treasureHunt = new()
{
Id = 101,
Rewards = new List<RewardItem>
{
new() { WorldItem = goldCoin, Quantity = 50 },
new() { WorldItem = magicRing, Quantity = 1 }
}
};
// Repeatable quest
Quest dailyQuest = new()
{
Id = 102,
Repeatable = new QuestRepeatable
{
IsRepeatable = true,
TimeBeforeRepeatable = TimeSpan.FromHours(24),
MaxTimes = 10 // Can only be done 10 times total
}
};
// Quest with quest items (items that can't be removed while quest is active)
Quest escortQuest = new()
{
Id = 300,
UpFrontItems = new List<UpFrontItem>
{
new() { WorldItem = new WorldItem { Id = 10, QuestId = 300 }, Quantity = 1 } // Quest item
}
};Quest items are special items that cannot be removed from inventory while their associated quest is active:
// Create a quest item by setting the QuestId property
WorldItem questMap = new()
{
Id = 50,
QuestId = 100, // Associated with quest ID 100
MaxQuantityPerSlot = 1
};
// Quest items can be given as up-front items
Quest treasureHuntQuest = new()
{
Id = 100,
UpFrontItems = new List<UpFrontItem>
{
new() { WorldItem = questMap, Quantity = 1 }
}
};
// Start the quest (player receives quest map)
questSystem.StartQuest(player, treasureHuntQuest, DateTime.UtcNow);
// This will fail because quest is active
bool canRemove = player.RemoveItem(questMap, 1); // Returns false
// Complete the quest first
questSystem.CompleteQuest(player, treasureHuntQuest, DateTime.UtcNow);
// Now the quest item can be removed
canRemove = player.RemoveItem(questMap, 1); // Returns truePlayers can abandon quests that are in progress. When a quest is aborted:
- The quest state returns to Available (can be started again)
- All up-front items are removed from the player's inventory
- The quest does not count as completed
QuestAbortedevent is fired
// Create a quest with up-front items
Quest deliveryQuest = new()
{
Id = 150,
UpFrontItems = new List<UpFrontItem>
{
new() { WorldItem = new WorldItem { Id = 20 }, Quantity = 1 }, // Delivery package
new() { WorldItem = new WorldItem { Id = 21 }, Quantity = 5 } // Travel supplies
}
};
// Subscribe to abortion event
questSystem.QuestAborted += (sender, e) =>
{
Console.WriteLine($"Quest {e.Quest.Id} was aborted at {e.AbortedAt}");
};
// Start the quest (player receives up-front items)
if (questSystem.CanStartQuest(player, deliveryQuest, DateTime.UtcNow))
{
questSystem.StartQuest(player, deliveryQuest, DateTime.UtcNow);
}
// Player decides to abandon the quest
if (questSystem.CanAbortQuest(player, deliveryQuest))
{
bool aborted = questSystem.AbortQuest(player, deliveryQuest, DateTime.UtcNow);
if (aborted)
{
Console.WriteLine("Quest aborted! Up-front items have been removed.");
// Quest can now be started again
bool canRestart = questSystem.CanStartQuest(player, deliveryQuest, DateTime.UtcNow);
Console.WriteLine($"Can restart quest: {canRestart}"); // True
}
else
{
Console.WriteLine("Quest abortion failed! Some up-front items could not be removed.");
Console.WriteLine("Quest remains in progress. Check ItemRemoveFailed events for details.");
}
}The quest system uses events to notify about failures during quest operations. This is particularly useful for debugging and providing user feedback:
// Subscribe to item operation events for better error handling
player.ItemAddFailed += (sender, e) =>
{
Console.WriteLine($"Failed to add {e.RequestedQuantity} of item {e.WorldItem.Id}. " +
$"Only {e.AddedQuantity} were added. Reason: Insufficient inventory space.");
};
player.ItemRemoveFailed += (sender, e) =>
{
Console.WriteLine($"Failed to remove {e.RequestedQuantity} of item {e.WorldItem.Id}. " +
$"Only {e.RemovedQuantity} were removed. Item may have been consumed or removed.");
};
// Create a quest with up-front items that might not fit
Quest challengingQuest = new()
{
Id = 300,
UpFrontItems = new List<UpFrontItem>
{
new() { WorldItem = new WorldItem { Id = 30 }, Quantity = 10 }, // Lots of items
new() { WorldItem = new WorldItem { Id = 31 }, Quantity = 5 }
}
};
// Start quest with limited inventory - events will fire for failures
player.AddSlotContainer(2); // Only 2 slots available
questSystem.StartQuest(player, challengingQuest, DateTime.UtcNow);
// ItemAddFailed events will fire for items that don't fit
// Later, when aborting, some items might not be removable
questSystem.AbortQuest(player, challengingQuest, DateTime.UtcNow);
// ItemRemoveFailed events will fire for items that couldn't be removed// Quest with completion requirements
Quest advancedQuest = new()
{
Id = 200,
Requirements = new List<RequirementBase>
{
new QuestCompletionRequirement { Id = 100 }, // Must complete quest 100 first
new QuestCompletionRequirement { Id = 101 } // Must complete quest 101 first
}
};
// Quest with level requirement
Quest expertQuest = new()
{
Id = 300,
MinPlayerLevel = 10 // Must be at least level 10
};
// Quest with multiple requirement types
Quest masterQuest = new()
{
Id = 400,
MinPlayerLevel = 25, // Must be at least level 25
Requirements = new List<RequirementBase>
{
new QuestCompletionRequirement { Id = 200 } // Must complete advanced quest
}
};Quests questSystem = new();
// Add quests to the system
questSystem.AddQuest(deliveryQuest);
questSystem.AddQuest(treasureHunt);
questSystem.AddQuest(dailyQuest);
// Check if player can start a quest
if (questSystem.CanStartQuest(player, deliveryQuest, DateTime.UtcNow))
{
questSystem.StartQuest(player, deliveryQuest, DateTime.UtcNow);
}
// Complete a quest
if (questSystem.CanCompleteQuest(player, deliveryQuest))
{
bool completed = questSystem.CompleteQuest(player, deliveryQuest, DateTime.UtcNow);
if (completed)
{
Console.WriteLine("Quest completed! Rewards added to inventory.");
}
else
{
Console.WriteLine("Quest completion failed - not enough inventory space for rewards.");
}
}Up-front items are given to players when they start a quest (like quest items or tools):
Quest escortQuest = new()
{
Id = 300,
UpFrontItems = new List<UpFrontItem>
{
new() { WorldItem = questMap, Quantity = 1 },
new() { WorldItem = specialKey, Quantity = 1 }
}
};// Daily quest that can be repeated indefinitely
Quest dailyChallenge = new()
{
Id = 400,
Repeatable = new QuestRepeatable
{
IsRepeatable = true,
TimeBeforeRepeatable = TimeSpan.FromDays(1)
}
};
// Weekly quest with limited repetitions
Quest weeklyRaid = new()
{
Id = 401,
Repeatable = new QuestRepeatable
{
IsRepeatable = true,
TimeBeforeRepeatable = TimeSpan.FromDays(7),
MaxTimes = 4 // Can only be done 4 times total
}
};Here's a complete example showing how to set up a simple quest and inventory system:
using Pilgrimage;
// Create items
WorldItem sword = new() { Id = 1, MaxQuantityPerSlot = 1, Weight = 5 };
WorldItem potion = new() { Id = 2, MaxQuantityPerSlot = 10, Weight = 1 };
WorldItem gold = new() { Id = 3, MaxQuantityPerSlot = 100, Weight = 0 };
// Create a player with inventory
Player player = new();
player.AddSlotContainer(20, 100); // 20 slots, 100 weight limit
// Add some starting items
player.AddItem(sword, 1);
player.AddItem(potion, 5);
// Create quest system
Quests questSystem = new();
// Create a simple quest with rewards
Quest firstQuest = new()
{
Id = 1,
Rewards = new List<RewardItem>
{
new() { WorldItem = gold, Quantity = 100 },
new() { WorldItem = potion, Quantity = 3 }
}
};
// Create a follow-up quest that requires the first quest
Quest secondQuest = new()
{
Id = 2,
Requirements = new List<RequirementBase>
{
new QuestCompletionRequirement { Id = 1 } // Must complete quest 1 first
},
Rewards = new List<RewardItem>
{
new() { WorldItem = gold, Quantity = 250 }
}
};
// Add quests to system
questSystem.AddQuest(firstQuest);
questSystem.AddQuest(secondQuest);
// Player completes first quest
if (questSystem.CanStartQuest(player, firstQuest, DateTime.UtcNow))
{
questSystem.StartQuest(player, firstQuest, DateTime.UtcNow);
// Simulate quest completion
if (questSystem.CanCompleteQuest(player, firstQuest))
{
questSystem.CompleteQuest(player, firstQuest, DateTime.UtcNow);
Console.WriteLine("First quest completed!");
}
}
// Player can now start second quest
if (questSystem.CanStartQuest(player, secondQuest, DateTime.UtcNow))
{
questSystem.StartQuest(player, secondQuest, DateTime.UtcNow);
Console.WriteLine("Second quest started!");
}
// Check inventory
Console.WriteLine($"Player has {(player.HasItem(gold, 100) ? "at least 100" : "less than 100")} gold");
Console.WriteLine($"Player has {(player.HasItem(potion, 8) ? "at least 8" : "less than 8")} potions");