osrlib.Core
0.0.3-alpha
See the version list below for details.
dotnet add package osrlib.Core --version 0.0.3-alpha
NuGet\Install-Package osrlib.Core -Version 0.0.3-alpha
<PackageReference Include="osrlib.Core" Version="0.0.3-alpha" />
paket add osrlib.Core --version 0.0.3-alpha
#r "nuget: osrlib.Core, 0.0.3-alpha"
// Install osrlib.Core as a Cake Addin #addin nuget:?package=osrlib.Core&version=0.0.3-alpha&prerelease // Install osrlib.Core as a Cake Tool #tool nuget:?package=osrlib.Core&version=0.0.3-alpha&prerelease
OSRlib.NET
License | Build status (main) | Docs | Reference | Package |
---|---|---|---|---|
Documentation | API reference | NuGet |
OSRlib.NET is a .NET Core class library written in C# that you can use as the game mechanics engine for a turn-based computer role-playing game (CRPG).
The osrlib.Core
object model and API were designed with the original Bard's Tale and similar CRPGs in mind. The library is appropriate for use in any game modeled after the Dungeons & Dragons Basic/Expert (or B/X) edition or other tabletop RPG in the Old School Renaissance (OSR) style.
Add your own UI (or even CLI) that talks to the OSRlib.NET API, and you've got yourself a turn-based RPG!
⚠️ OSRlib.NET is early in development and several critical systems have yet to be built. To get an idea of what's missing, check out the open issues.
Prerequisites
- .NET SDK 7.0+
Install the package
Run this dotnet
CLI command to add a reference to your project:
dotnet add package osrlib.Core
Getting started
The OSRlib.NET object model represents well-known RPG entities like adventures, dungeons, beings (player characters and monsters), encounters, and weapons. It has an event-based interaction model for manipulating these entities, their relationships, and state.
Any game you build with OSRlib.NET will include at least these four core operations, presented here with example code and in typical order of operation:
- Create a player character
- Stock the dungeon with monsters and encounters
- Subscribe to battle events
- Start the battle
ℹ️ TIP: You can see these code snippets in context in OSRlib.NET's test project: src/osrlib.Tests/ReadMeTests.cs
Create a character
// Get a ten-sided die ready
DiceRoll roll = new DiceRoll(new DiceHand(1, DieType.d10));
// Roll up a fighter-type character
Being fighter = new Being
{
Name = "Blarg the Destructor",
Defense = roll.RollDice(),
MaxHitPoints = roll.RollDice() + 10
};
fighter.HitPoints = fighter.MaxHitPoints;
fighter.RollAbilities();
// Give Blarg a sweet sword
Weapon magicSword = new Weapon
{
Name = "Long Sword + 1",
Description = "A finely crafted sword, its blade dimly glows.",
Type = WeaponType.Melee,
DamageDie = new DiceHand(1, DieType.d8)
};
magicSword.AttackModifiers.Add(new Modifier { ModifierSource = magicSword, ModifierValue = 1 });
magicSword.DamageModifiers.Add(new Modifier { ModifierSource = magicSword, ModifierValue = 1 });
fighter.ActiveWeapon = magicSword;
// Now, add the fighter to the player's party
Party playerParty = new Party();
playerParty.AddPartyMember(fighter);
Stock the dungeon
Dungeon dungeon = new Dungeon();
// Create some monsters for an encounter
Being goblin1 = new Being
{
Name = "Goblin Chieftain",
Defense = 10,
HitPoints = 10,
MaxHitPoints = 10
};
goblin1.RollAbilities();
Being goblin2 = new Being
{
Name = "Goblin",
Defense = 5,
HitPoints = 4,
MaxHitPoints = 4
};
goblin2.RollAbilities();
// Add the goblins to the monster party
Party monsterParty = new Party();
monsterParty.AddPartyMember(goblin1);
monsterParty.AddPartyMember(goblin2);
// Add the monsters to an encounter
Encounter encounter = new Encounter
{
EncounterParty = monsterParty,
Position = new GamePosition(10, 10)
};
// Add the encounter to the dungeon
dungeon.Encounters.Add(encounter);
Subscribe to battle events
The Encounter
, like most top-level entities in OSRlib, exposes events to notify subscribers of actions it performs and actions performed on it.
Subscribe to events like these and use them as triggers to update your game's user interface or perform other runtime actions.
// OSRlib is heavily event-driven and most top-level classes expose public events. Determine when and
// how to change the state of your game at runtime by subscribing to events exposed such objects. For
// example, to know when to prompt for target selection or play a sound when a monster is killed.
encounter.EncounterStarted += (sender, eventArgs) =>
{
Console.WriteLine($"Encounter has started! Monsters:\r\n{((Encounter)sender).EncounterParty}");
};
// Example of subscribing to an event that you might use to update the UI state to notify the player or
// make some other change in your application at runtime.
encounter.EncounterEnded += (sender, eventArgs) =>
{
Encounter enc = sender as Encounter;
if (enc.AdventuringParty.IsAlive)
{
Console.WriteLine("Your party has won the battle!");
}
else if (enc.EncounterParty.IsAlive)
{
Console.WriteLine("Sorry, your party has been vanquished.");
}
};
Start the battle
We're now ready to let the adventuring party (currently comprised of only one character, Blarg the Destructor) and the encounter party (the evil orcs) battle to the death.
// You can set encounters auto-resolve the battle as is done in this example. In a typical game, however,
// you wouldn't enable auto-battle, and instead would prompt your player to select a target(s) or perform
// some other action before proceeding with the next battle step.
encounter.AutoBattleEnabled = true;
// Add the adventuring party to the encounter
encounter.SetAdventuringParty(playerParty);
// Subscribe to some events on the combatants so we can respond to things
// that happen to them.
List<Being> combatants = encounter.AdventuringParty.Members.Concat(encounter.EncounterParty.Members).ToList();
foreach (Being combatant in combatants)
{
combatant.SelectedAsTarget += (s, e) =>
{
Being attackedBeing = s as Being;
BeingTargetingEventArgs args = e as BeingTargetingEventArgs;
Console.WriteLine($"{e.TargetingBeing} attacks {attackedBeing} with their {e.TargetingBeing.ActiveWeapon}...");
};
combatant.ActionPerformed += (s, e) =>
{
GameActionEventArgs actionArgs = e as GameActionEventArgs;
GameAction action = actionArgs.Action;
if (action.Victor.Equals(combatant))
{
Console.WriteLine($"{combatant} rolled a {action.AttackRoll} and hit for {action.DamageRoll} points of damage.");
}
else
{
Console.WriteLine($"{combatant} rolled a {action.AttackRoll} and missed.");
}
};
combatant.Killed += (s, e) =>
{
Console.WriteLine($"{((Being)s).Name} was killed!");
};
}
// Start the battle. This will fire the EncounterStarted event we subscribed to above, and since we set
// this encounter to resolve all combat automatically with AutoBattleEnabled, each member of both parties
// takes turns attacking each other until one side has been defeated.
encounter.StartEncounter();
Display event data
The battle resolves fully (because we set Encounter.AutoBattleEnabled = true
) and, because we subscribed Being
and Encounter
events, we can see what transpires during the battle:
Encounter has started! Monsters:
[0] Goblin Chieftain Hit points: 10
[1] Goblin Hit points: 4
Blarg the Destructor (18/18) attacks Goblin (4/4) with their Long Sword + 1...
Goblin was killed!
Blarg the Destructor (18/18) rolled a 9 (1d20+1) and hit for 6 (1d8+1) points of damage.
Goblin Chieftain (10/10) attacks Blarg the Destructor (18/18) with their Fists...
Goblin Chieftain (10/10) rolled a 16 (1d20-1) and hit for 0 (1d2-1) points of damage.
Blarg the Destructor (18/18) attacks Goblin Chieftain (10/10) with their Long Sword + 1...
Blarg the Destructor (18/18) rolled a 15 (1d20+1) and hit for 7 (1d8+1) points of damage.
Goblin Chieftain (3/10) attacks Blarg the Destructor (18/18) with their Fists...
Goblin Chieftain (3/10) rolled a 15 (1d20-1) and hit for 1 (1d2-1) points of damage.
Blarg the Destructor (17/18) attacks Goblin Chieftain (3/10) with their Long Sword + 1...
Your party has won the battle!
Goblin Chieftain was killed!
Blarg the Destructor (17/18) rolled a 13 (1d20+1) and hit for 3 (1d8+1) points of damage.
Next steps
This README was a quick intro to a few of the types and operations available in OSRlib. Here are some other resources to help you use OSRlib.NET in your turn-based RPG:
- API reference
- Library documentation
- OSRlib tests
- ASP.NET Web API for OSRlib.NET (a work-in-progress code sample)
Have fun!
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
-
net7.0
- Newtonsoft.Json (>= 13.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
0.0.4-alpha | 112 | 2/14/2023 |
0.0.3-alpha | 90 | 2/14/2023 |
0.0.2-alpha | 91 | 2/14/2023 |
0.0.1-alpha | 105 | 12/24/2022 |
Initial NuGet release of OSRlib.NET.