### Install and Build the Project Source: https://github.com/jamesplotts/opencombatengine/blob/main/README.md Commands to clone the repository, build the solution, and execute tests with coverage reporting. ```bash # Clone the repository git clone https://github.com/yourusername/OpenCombatEngine.git cd OpenCombatEngine # Build the solution dotnet build # Run tests dotnet test # Run with coverage dotnet test --collect:"XPlat Code Coverage" ``` -------------------------------- ### Content Import Development: AI Importer Prompt Example Source: https://github.com/jamesplotts/opencombatengine/blob/main/docs/contributing/AI-DEVELOPMENT.md An example prompt for creating a content importer for D&D Beyond JSON format. It specifies the class name, parsing logic, fields to extract, fields to ignore, and component mapping. ```text Create importer for D&D Beyond JSON format: 1. Class: DndBeyondImporter : IContentImporter 2. Parse their spell structure 3. Extract: name, level, school, range, components 4. Ignore: description, flavor_text, source_book 5. Map components: "V,S,M" -> Components(Verbal=true, Somatic=true, Material=true) 6. Test with sample JSON from TestData/ ``` -------------------------------- ### AI Test Generation Prompt Example Source: https://github.com/jamesplotts/opencombatengine/blob/main/docs/contributing/AI-DEVELOPMENT.md An example prompt for generating comprehensive tests for a `IDiceRoller.Roll` method, specifying valid and invalid notations, edge cases, and the use of `Theory` with `InlineData`. ```text Generate comprehensive tests for IDiceRoller.Roll method: - Valid notation: "3d6+2", "1d20", "4d4-1" - Invalid notation: "", "abc", "1d0", "0d6" - Edge cases: "1d1", "100d100", negative modifiers - Use Theory/InlineData for all cases ``` -------------------------------- ### Implement AI Controllers in C# Source: https://context7.com/jamesplotts/opencombatengine/llms.txt Demonstrates the creation and usage of different tiers of AI controllers (Basic, Tactical, Role-Based) for NPC combat. Shows how to get AI decisions and execute actions. ```csharp using OpenCombatEngine.Core.Interfaces.AI; using OpenCombatEngine.Implementation.AI; using OpenCombatEngine.Implementation.Actions.Contexts; // Tier 1: Basic AI (Zombie-like aggro) var basicAi = new BasicAiController(grid); // Tier 2: Tactical AI (Intelligent targeting, self-preservation) var tacticalAi = new TacticalAiController(grid); // Tier 3: Role-Based AI (Specialized behavior) // Roles: Artillery (kiting), Brute (aggressive melee) var artilleryAi = new RoleBasedAiController(grid, role: "Artillery"); var bruteAi = new RoleBasedAiController(grid, role: "Brute"); // Get AI decision for a creature's turn var context = new StandardActionContext( source: goblin, target: null, grid: grid ); var decision = await basicAi.DetermineAction(goblin, context); if (decision != null) { Console.WriteLine($"AI Decision: {decision.Action.Name}"); Console.WriteLine($"Target: {decision.Target}"); // Execute the AI's chosen action var actionContext = new StandardActionContext( source: goblin, target: decision.Target, grid: grid ); var result = decision.Action.Execute(actionContext); } // Tag creatures with roles for role-based AI goblin.Tags = new[] { "Role:Artillery" }; orc.Tags = new[] { "Role:Brute" }; // Combat Runner for automated combat var combatRunner = new CombatRunner(turnManager, grid, defaultAi: tacticalAi); combatRunner.RegisterCreature(goblin, tacticalAi); combatRunner.RegisterCreature(orc, bruteAi); await combatRunner.RunCombat(); ``` -------------------------------- ### Implement Unit Tests with xUnit Source: https://github.com/jamesplotts/opencombatengine/blob/main/CONTRIBUTING.md Use this structure for unit testing in C#. It includes examples for standard test methods and parameterized theory tests. ```csharp public class ExampleTests { [Fact] public void Method_HappyPath_ReturnsExpected() { // Arrange var sut = CreateSystemUnderTest(); // Act var result = sut.Method(); // Assert Assert.Equal(expected, result); } [Theory] [InlineData(input1, expected1)] [InlineData(input2, expected2)] public void Method_VariousInputs_ReturnsCorrectResults(int input, int expected) { // Parameterized tests for comprehensive coverage } } ``` -------------------------------- ### Troubleshooting AI Code: Project Conventions Prompt Source: https://github.com/jamesplotts/opencombatengine/blob/main/docs/contributing/AI-DEVELOPMENT.md A crucial starting phrase to ensure the AI adheres to project conventions when working on the OpenCombatEngine. It explicitly mentions following `project-context.md`. ```text I'm working on OpenCombatEngine. CRITICAL: Follow all conventions in project-context.md exactly. [Then describe your task] ``` -------------------------------- ### Run the CLI Demo Source: https://github.com/jamesplotts/opencombatengine/blob/main/README.md Command to execute the demonstration project showcasing the Event and Reaction systems. ```bash dotnet run --project src/OpenCombatEngine.Demo/OpenCombatEngine.Demo.csproj ``` -------------------------------- ### Build and Test Commands Source: https://github.com/jamesplotts/opencombatengine/blob/main/README.md Standard .NET CLI commands for building, testing, and packaging the project. ```bash # Build dotnet build dotnet build --configuration Release # Test dotnet test dotnet test --collect:"XPlat Code Coverage" dotnet test --filter "FullyQualifiedName~DiceRollerTests" # Package dotnet pack --configuration Release ``` -------------------------------- ### Manage Creature Conditions with IConditionManager Source: https://context7.com/jamesplotts/opencombatengine/llms.txt Add, check, and remove conditions affecting creatures. Conditions have durations and can be ticked down at the start of a turn. ```csharp using OpenCombatEngine.Core.Interfaces.Conditions; using OpenCombatEngine.Implementation.Conditions; using OpenCombatEngine.Core.Enums; // Access creature's condition manager var conditionManager = creature.Conditions; // Subscribe to condition events conditionManager.ConditionAdded += (sender, e) => { Console.WriteLine($"Condition added: {e.ConditionType}"); }; conditionManager.ConditionRemoved += (sender, e) => { Console.WriteLine($"Condition removed: {e.ConditionType}"); }; // Add conditions var poisoned = new StandardCondition( ConditionType.Poisoned, duration: 3, // Lasts 3 turns durationType: DurationType.Turns ); conditionManager.AddCondition(poisoned); var prone = new StandardCondition(ConditionType.Prone); conditionManager.AddCondition(prone); // Check conditions bool isPoisoned = conditionManager.HasCondition(ConditionType.Poisoned); // true bool isBlinded = conditionManager.HasCondition(ConditionType.Blinded); // false // List active conditions foreach (var condition in conditionManager.ActiveConditions) { Console.WriteLine($"Active: {condition.Type}, Duration: {condition.RemainingDuration}"); } // Conditions affect combat: // - Blinded: Disadvantage on attacks, advantage for attackers // - Poisoned: Disadvantage on attacks and ability checks // - Prone: Disadvantage on attacks, melee attacks have advantage vs prone // - Paralyzed/Stunned/Unconscious: Auto-critical on hits // - Invisible: Advantage on attacks, disadvantage for attackers // Tick conditions at turn start (decrements duration) conditionManager.Tick(); // Remove conditions conditionManager.RemoveCondition("Prone"); conditionManager.Clear(); // Remove all conditions ``` -------------------------------- ### Build and Test Project Source: https://github.com/jamesplotts/opencombatengine/blob/main/CONTRIBUTING.md Standard commands for building the project and executing tests. ```bash dotnet build ``` ```bash dotnet test ``` -------------------------------- ### Clone and Configure Repository Source: https://github.com/jamesplotts/opencombatengine/blob/main/CONTRIBUTING.md Initial commands to clone the repository and set up the upstream remote. ```bash git clone https://github.com/yourusername/OpenCombatEngine.git cd OpenCombatEngine ``` ```bash git remote add upstream https://github.com/originalowner/OpenCombatEngine.git ``` -------------------------------- ### Create and Manage Creatures with ICreature Source: https://context7.com/jamesplotts/opencombatengine/llms.txt Demonstrates the creation of a creature using the StandardCreature implementation, including setting ability scores, hit points, and inventory. Use this to initialize any combatant in the engine. ```csharp using OpenCombatEngine.Core.Interfaces.Creatures; using OpenCombatEngine.Implementation.Creatures; using OpenCombatEngine.Implementation.Dice; using OpenCombatEngine.Implementation.Items; using OpenCombatEngine.Core.Enums; // Create ability scores (STR, DEX, CON, INT, WIS, CHA) var abilityScores = new StandardAbilityScores(16, 14, 14, 10, 12, 8); Console.WriteLine($"Strength Modifier: {abilityScores.GetModifier(Ability.Strength)}"); // +3 // Create hit points var hitPoints = new StandardHitPoints(maxHitPoints: 45, hitDice: "1d10", hitDiceTotal: 5); // Create turn manager and inventory (required dependencies) var turnManager = new StandardTurnManager(new StandardDiceRoller()); var inventory = new StandardInventory(); // Create the creature var fighter = new StandardCreature( id: Guid.NewGuid().ToString(), name: "Valeria the Fighter", abilityScores: abilityScores, hitPoints: hitPoints, inventory: inventory, turnManager: turnManager ); fighter.Team = "Player"; // Access creature properties Console.WriteLine($"Name: {fighter.Name}"); Console.WriteLine($"HP: {fighter.HitPoints.Current}/{fighter.HitPoints.Max}"); Console.WriteLine($"AC: {fighter.CombatStats.ArmorClass}"); Console.WriteLine($"Initiative Bonus: {fighter.CombatStats.InitiativeBonus}"); Console.WriteLine($"Proficiency Bonus: {fighter.ProficiencyBonus}"); // Damage and healing fighter.HitPoints.TakeDamage(10, DamageType.Slashing); Console.WriteLine($"After damage: {fighter.HitPoints.Current} HP"); fighter.HitPoints.Heal(5); Console.WriteLine($"After healing: {fighter.HitPoints.Current} HP"); // Death saves at 0 HP fighter.HitPoints.TakeDamage(fighter.HitPoints.Current); // Drop to 0 Console.WriteLine($"Is Dead: {fighter.HitPoints.IsDead}"); fighter.HitPoints.RecordDeathSave(success: true); fighter.HitPoints.RecordDeathSave(success: true); fighter.HitPoints.RecordDeathSave(success: true); // Stabilized! Console.WriteLine($"Is Stable: {fighter.HitPoints.IsStable}"); // Resting fighter.Rest(RestType.ShortRest, hitDiceToSpend: 2); fighter.Rest(RestType.LongRest); // Full recovery ``` -------------------------------- ### Calculate Total Path Cost Source: https://github.com/jamesplotts/opencombatengine/blob/main/docs/adr/0034-movement-cost.md Calculates the total movement cost for a path between a start and end position. Currently assumes a straight-line path and sums the costs of entering each cell. ```csharp int GetPathCost(Position start, Position end) ``` -------------------------------- ### GetPathCost Implementation Detail Source: https://github.com/jamesplotts/opencombatengine/blob/main/docs/adr/0034-movement-cost.md The `GetPathCost` method will iterate through points generated by a line algorithm (like Bresenham), excluding the start and including the end point, to sum the movement costs. ```csharp GetPathCost will iterate through the points returned by the line algorithm (excluding start, including end) and sum costs. ``` -------------------------------- ### Import Game Content with JSON and Open5e API Source: https://context7.com/jamesplotts/opencombatengine/llms.txt Demonstrates importing spells and monsters from JSON strings and fetching data from the Open5e API. Requires instances of IContentImporter and Open5eClient. ```csharp using OpenCombatEngine.Core.Interfaces.Content; using OpenCombatEngine.Implementation.Content; using OpenCombatEngine.Implementation.Dice; // JSON Spell Importer var diceRoller = new StandardDiceRoller(); var spellImporter = new JsonSpellImporter(diceRoller); string spellJson = @"[ { ""name"": ""Magic Missile"", ""level"": 1, ""school"": ""Evocation"", ""casting_time"": ""1 Action"", ""range"": ""120 feet"", ""components"": ""V, S"", ""duration"": ""Instantaneous"", ""damage_dice"": ""3d4+3"", ""damage_type"": ""Force"" } ]"; var importResult = spellImporter.Import(spellJson); if (importResult.IsSuccess) { foreach (var spell in importResult.Value) { Console.WriteLine($"Imported: {spell.Name} (Level {spell.Level})"); wizard.Spellcasting.LearnSpell(spell); } } // Monster Importer var monsterImporter = new JsonMonsterImporter(diceRoller); string monsterJson = @"{ ""name"": ""Goblin"", ""size"": ""Small"", ""type"": ""humanoid"", ""armor_class"": 15, ""hit_points"": 7, ""hit_dice"": ""2d6"", ""strength"": 8, ""dexterity"": 14, ""constitution"": 10, ""intelligence"": 10, ""wisdom"": 8, ""charisma"": 8 }"; var monsterResult = monsterImporter.Import(monsterJson); // Open5e API Integration var open5eClient = new Open5eClient(); var srdSpells = await open5eClient.GetSpellsAsync(); var srdMonsters = await open5eClient.GetMonstersAsync(); var srdWeapons = await open5eClient.GetWeaponsAsync(); ``` -------------------------------- ### Enum Validation Pattern Source: https://github.com/jamesplotts/opencombatengine/blob/main/docs/contributing/AI-DEVELOPMENT.md Enums should always start with an 'Unspecified' value and end with a 'LastValue' sentinel for validation purposes. The IsValid method checks if a given enum value falls within these bounds. ```csharp public enum ActionType { Unspecified = 0, // AI: ALWAYS start with this Action, BonusAction, Reaction, FreeAction, LastValue // AI: ALWAYS end with this } // AI should generate this validation method public static bool IsValid(ActionType type) => type > ActionType.Unspecified && type < ActionType.LastValue; ``` -------------------------------- ### Implement Magic Items in C# Source: https://context7.com/jamesplotts/opencombatengine/llms.txt Shows how to create and manage magic items, including setting properties, managing charges, attunement, equipping, and accessing abilities. Supports various item types and effects. ```csharp using OpenCombatEngine.Core.Interfaces.Items; using OpenCombatEngine.Implementation.Items; using OpenCombatEngine.Core.Enums; // Create a magic item var flameTongue = new MagicItem( name: "Flame Tongue Longsword", description: "A magical longsword that bursts into flame", rarity: ItemRarity.Rare, requiresAttunement: true, defaultSlot: EquipmentSlot.MainHand ); // Set weapon properties flameTongue.WeaponProperties = new WeaponStats { DamageDice = "1d8", DamageType = DamageType.Slashing, Properties = new[] { WeaponProperty.Versatile } }; // Add charges for abilities flameTongue.MaxCharges = 3; flameTongue.RechargeFormula = "1d3"; flameTongue.RechargeFrequency = RechargeFrequency.Dawn; // Attune to the item (max 3 attuned items per creature) var attuneResult = flameTongue.Attune(fighter); if (attuneResult.IsSuccess) { Console.WriteLine($"{fighter.Name} attuned to {flameTongue.Name}"); } // Equip the item fighter.Equipment.Equip(flameTongue, EquipmentSlot.MainHand); // Check equipped items foreach (var item in fighter.Equipment.GetEquippedItems()) { Console.WriteLine($"Equipped: {item.Name} in {fighter.Equipment.GetSlot(item)}"); } // Use charges var consumeResult = flameTongue.ConsumeCharges(1); if (consumeResult.IsSuccess) { Console.WriteLine($"Charges remaining: {flameTongue.Charges}/{flameTongue.MaxCharges}"); } // Recharge item flameTongue.Recharge(2); // Access magic item abilities (usable actions) foreach (var ability in flameTongue.Abilities) { Console.WriteLine($"Ability: {ability.Name}, Cost: {ability.ChargeCost} charges"); } // Unattune when done flameTongue.Unattune(); ``` -------------------------------- ### AI Technique: Chain of Thought for Complex Features Source: https://github.com/jamesplotts/opencombatengine/blob/main/docs/contributing/AI-DEVELOPMENT.md This technique involves breaking down complex feature implementation into logical steps, starting with understanding requirements, checking interfaces, writing tests, implementing, and integrating. ```text Implement combat initiative system: 1. First, I need to understand the requirements 2. Check existing interfaces: ICombatManager, IInitiativeTracker 3. Write tests for: roll initiative, sort order, ties, advantages 4. Implement following Result pattern 5. Integrate with existing TurnManager ``` -------------------------------- ### AI Workflow: Implementing an Interface Source: https://github.com/jamesplotts/opencombatengine/blob/main/docs/contributing/AI-DEVELOPMENT.md This workflow describes the steps an AI should take when implementing a new interface, including reading definitions, checking tests, writing missing tests, and ensuring all tests pass. ```text 1. AI reads the interface definition 2. AI checks for existing tests 3. AI writes missing tests if needed 4. AI implements following all patterns 5. AI ensures all tests pass ``` -------------------------------- ### Execute Combat Actions with IAction Source: https://context7.com/jamesplotts/opencombatengine/llms.txt Shows how to create and execute combat actions like attacks and movement using the IAction interface and its implementations. Requires a context object containing the source, target, and game grid. ```csharp using OpenCombatEngine.Core.Interfaces.Actions; using OpenCombatEngine.Core.Enums; using OpenCombatEngine.Implementation.Actions; using OpenCombatEngine.Implementation.Actions.Contexts; using OpenCombatEngine.Implementation.Dice; using OpenCombatEngine.Core.Models.Actions; // Create an attack action (weapon or unarmed) var diceRoller = new StandardDiceRoller(); var swordAttack = new AttackAction( name: "Longsword", description: "A versatile melee weapon attack", attackBonus: 7, // +7 to hit damageDice: "1d8", // 1d8 slashing damage damageType: DamageType.Slashing, damageBonus: 4, // +4 damage modifier diceRoller: diceRoller, type: ActionType.Action, range: 5 // 5 feet melee range ); // Execute an attack (requires context with source, target, and grid) var attacker = CreateFighter(); // Helper to create creature var defender = CreateGoblin(); var grid = new StandardGridManager(); grid.PlaceCreature(attacker, new Position(0, 0, 0)); grid.PlaceCreature(defender, new Position(1, 0, 0)); // Adjacent var context = new StandardActionContext( source: attacker, target: new CreatureTarget(defender), grid: grid ); var result = swordAttack.Execute(context); if (result.IsSuccess) { Console.WriteLine($"Hit: {result.Value.Success}"); Console.WriteLine($"Message: {result.Value.Message}"); Console.WriteLine($"Damage Dealt: {result.Value.DamageDealt}"); } else { Console.WriteLine($"Attack failed: {result.Error}"); } // Movement action var moveAction = new MoveAction(speed: 30); // 30 feet movement var moveContext = new StandardActionContext( source: attacker, target: new PositionTarget(new Position(3, 0, 0)), grid: grid ); var moveResult = moveAction.Execute(moveContext); // Available actions from creature foreach (var action in attacker.Actions) { Console.WriteLine($"Action: {action.Name} ({action.Type})"); } ``` -------------------------------- ### Implement A* Pathfinding Algorithm Source: https://github.com/jamesplotts/opencombatengine/blob/main/ROADMAP.md This snippet is part of the A* pathfinding implementation. It handles the core logic for finding a path through a grid, considering terrain and obstacles. ```csharp public class AStarPathfinder { // ... implementation details ... } ``` -------------------------------- ### Complete Combat Encounter in C# Source: https://context7.com/jamesplotts/opencombatengine/llms.txt Sets up two creatures, places them on a grid, and runs a combat loop until one is defeated or a turn limit is reached. Requires OpenCombatEngine core and implementation libraries. ```csharp using OpenCombatEngine.Core.Interfaces; using OpenCombatEngine.Core.Interfaces.Combat; using OpenCombatEngine.Implementation; using OpenCombatEngine.Implementation.Combat; using OpenCombatEngine.Implementation.Creatures; using OpenCombatEngine.Implementation.Spatial; using OpenCombatEngine.Implementation.Dice; using OpenCombatEngine.Implementation.Items; using OpenCombatEngine.Implementation.Actions; using OpenCombatEngine.Implementation.Actions.Contexts; using OpenCombatEngine.Core.Models.Actions; using OpenCombatEngine.Core.Models.Spatial; // Setup var diceRoller = new StandardDiceRoller(); var turnManager = new StandardTurnManager(diceRoller); var grid = new StandardGridManager(); // Create hero var heroStats = new StandardAbilityScores(16, 14, 14, 10, 12, 8); var heroHp = new StandardHitPoints(45); var hero = new StandardCreature( Guid.NewGuid().ToString(), "Hero", heroStats, heroHp, new StandardInventory(), turnManager ); hero.Team = "Player"; // Create goblin enemy var goblinStats = new StandardAbilityScores(8, 14, 10, 10, 8, 8); var goblinHp = new StandardHitPoints(7); var goblin = new StandardCreature( Guid.NewGuid().ToString(), "Goblin", goblinStats, goblinHp, new StandardInventory(), turnManager ); goblin.Team = "Monster"; // Place on grid grid.PlaceCreature(hero, new Position(0, 0, 0)); grid.PlaceCreature(goblin, new Position(2, 0, 0)); // 10 feet away // Create combat manager var combatManager = new StandardCombatManager(turnManager, grid); // Subscribe to events turnManager.TurnChanged += (s, e) => { Console.WriteLine($"\n=== Round {e.Round}: {e.Creature.Name}'s Turn ==="); Console.WriteLine($"HP: {e.Creature.HitPoints.Current}/{e.Creature.HitPoints.Max}"); }; combatManager.EncounterEnded += (s, e) => { Console.WriteLine($"\n*** Combat Ended! Winner: {e.WinningTeam} ***"); }; // Start combat combatManager.StartEncounter(new[] { hero, goblin }); // Combat loop while (!hero.HitPoints.IsDead && !goblin.HitPoints.IsDead) { var currentCreature = turnManager.CurrentCreature; if (currentCreature == null) break; currentCreature.StartTurn(); // Determine action based on team ICreature target = currentCreature.Team == "Player" ? goblin : hero; // Get attack action var attack = currentCreature.Actions .FirstOrDefault(a => a.Name.Contains("Attack") || a.Name == "Unarmed Strike"); if (attack != null) { var context = new StandardActionContext( currentCreature, new CreatureTarget(target), grid ); var result = currentCreature.PerformAction(attack, context); result.OnSuccess(r => Console.WriteLine($"{currentCreature.Name} attacks {target.Name}: {r.Message}")); } currentCreature.EndTurn(); turnManager.NextTurn(); // Safety limit if (turnManager.CurrentRound > 10) break; } combatManager.EndEncounter(); ``` -------------------------------- ### Manage Combat Turns with StandardTurnManager Source: https://context7.com/jamesplotts/opencombatengine/llms.txt Initialize and manage combat turns, initiative, and round tracking. Subscribe to turn and round change events. ```csharp using OpenCombatEngine.Core.Interfaces; using OpenCombatEngine.Implementation; using OpenCombatEngine.Implementation.Dice; using OpenCombatEngine.Core.Models.Events; // Create turn manager var diceRoller = new StandardDiceRoller(); var turnManager = new StandardTurnManager(diceRoller); // Subscribe to events turnManager.TurnChanged += (sender, e) => { Console.WriteLine($"Round {e.Round}: {e.Creature.Name}'s turn"); }; turnManager.RoundChanged += (sender, e) => { Console.WriteLine($"--- Round {e.Round} begins ---"); }; turnManager.CombatEnded += (sender, e) => { Console.WriteLine("Combat has ended!"); }; // Create combatants var participants = new[] { fighter, goblin, orc }; // Start combat (rolls initiative automatically) turnManager.StartCombat(participants); // Access turn order Console.WriteLine("Initiative Order:"); foreach (var creature in turnManager.TurnOrder) { Console.WriteLine($" {creature.Name}"); } // Get current state Console.WriteLine($"Current Round: {turnManager.CurrentRound}"); Console.WriteLine($"Current Creature: {turnManager.CurrentCreature?.Name}"); // Advance turns turnManager.NextTurn(); // Moves to next creature turnManager.NextTurn(); // When last creature finishes, increments round // End combat turnManager.EndCombat(); ``` -------------------------------- ### AI Technique: Reference Implementation Pattern Source: https://github.com/jamesplotts/opencombatengine/blob/main/docs/contributing/AI-DEVELOPMENT.md When implementing new features, check existing implementation patterns within the project, such as how `BuffManager` uses `IEffect` or the structure of the `StatusEffect` class. ```text Human: How should I implement conditions? AI: Check the existing implementation pattern: - BuffManager uses IEffect with duration - StatusEffect class shows the pattern - Follow the same approach for conditions - See Tests/Effects/BuffTests.cs for test patterns ``` -------------------------------- ### AI Technique: Incremental Implementation Source: https://github.com/jamesplotts/opencombatengine/blob/main/docs/contributing/AI-DEVELOPMENT.md This approach involves implementing a feature in stages (e.g., interface first, then basic implementation, then advanced features) to allow for review and feedback at each step. ```text Human: Implement spell slots system AI: I'll implement this incrementally: 1. First PR: ISpellSlotManager interface 2. Second PR: Basic implementation with tests 3. Third PR: Multiclass support 4. Fourth PR: Warlock pact slots This allows for review and feedback at each stage. ``` -------------------------------- ### Implement Spellcasting with ISpell and ISpellCaster Source: https://context7.com/jamesplotts/opencombatengine/llms.txt Utilize ISpell and ISpellCaster to manage spell slots, learn new spells, handle concentration, and resolve spell effects. ```csharp using OpenCombatEngine.Core.Interfaces.Spells; using OpenCombatEngine.Implementation.Spells; using OpenCombatEngine.Core.Enums; using OpenCombatEngine.Core.Models.Spells; // Create a spellcaster var wizard = CreateWizard(); var spellcaster = wizard.Spellcasting; // Check available spell slots Console.WriteLine($"1st level slots: {spellcaster.GetSlots(1)}/{spellcaster.GetMaxSlots(1)}"); Console.WriteLine($"2nd level slots: {spellcaster.GetSlots(2)}/{spellcaster.GetMaxSlots(2)}"); // Learn spells var fireball = new Spell( name: "Fireball", level: 3, school: SpellSchool.Evocation, castingTime: "1 Action", range: "150 feet", components: "V, S, M", duration: "Instantaneous", description: "A bright streak flashes...", requiresAttackRoll: false, requiresConcentration: false, saveAbility: Ability.Dexterity, saveEffect: SaveEffect.HalfDamage, damageRolls: new List { new DamageFormula("8d6", DamageType.Fire) }, areaOfEffect: new SphereShape(20) // 20-foot radius ); spellcaster.LearnSpell(fireball); // Cast a spell var castResult = fireball.Cast(wizard, target: goblin); if (castResult.IsSuccess) { var resolution = castResult.Value; Console.WriteLine($"Spell Hit: {resolution.Hit}"); Console.WriteLine($"Damage: {resolution.TotalDamage}"); Console.WriteLine($"Save DC: {resolution.SaveDC}"); } // Concentration tracking var holdPerson = CreateHoldPersonSpell(); // Requires concentration spellcaster.PrepareSpell(holdPerson); var concentrateResult = holdPerson.Cast(wizard, target: orc); if (wizard.Spellcasting.ConcentratingOn != null) { Console.WriteLine($"Concentrating on: {wizard.Spellcasting.ConcentratingOn.Name}"); } // Break concentration (taking damage triggers CON save) wizard.HitPoints.TakeDamage(15); // Auto-checks concentration // Or manually: spellcaster.BreakConcentration(); // Slot recovery on rest wizard.Rest(RestType.LongRest); // Recovers all spell slots ``` -------------------------------- ### Create and Use StandardAbilityScores Source: https://context7.com/jamesplotts/opencombatengine/llms.txt Instantiate and access core ability scores and their modifiers. Modifiers are calculated using the standard D20 formula. ```csharp using OpenCombatEngine.Core.Interfaces.Creatures; using OpenCombatEngine.Implementation.Creatures; using OpenCombatEngine.Core.Enums; // Create ability scores var scores = new StandardAbilityScores( strength: 18, // +4 modifier dexterity: 14, // +2 modifier constitution: 16, // +3 modifier intelligence: 10, // +0 modifier wisdom: 12, // +1 modifier charisma: 8 // -1 modifier ); // Access individual scores Console.WriteLine($"Strength: {scores.Strength}"); Console.WriteLine($"Dexterity: {scores.Dexterity}"); // Calculate modifiers: (Score - 10) / 2 int strMod = scores.GetModifier(Ability.Strength); // +4 int dexMod = scores.GetModifier(Ability.Dexterity); // +2 int conMod = scores.GetModifier(Ability.Constitution); // +3 Console.WriteLine($"STR Modifier: {strMod}"); Console.WriteLine($"DEX Modifier: {dexMod}"); // Modifiers are used for: // - Attack rolls (STR for melee, DEX for ranged/finesse) // - Damage rolls // - Saving throws // - Ability checks // - Initiative (DEX) // - Hit point calculation (CON) ``` -------------------------------- ### Perform Dice Rolls Source: https://github.com/jamesplotts/opencombatengine/blob/main/README.md Demonstrates initializing a dice roller and executing standard or advantage-based rolls using the OpenCombatEngine library. ```csharp using OpenCombatEngine.Core.Interfaces.Dice; using OpenCombatEngine.Implementation.Dice; // Create a dice roller IDiceRoller roller = new StandardDiceRoller(); // Roll some dice var result = roller.Roll("3d6+2"); if (result.IsSuccess) { Console.WriteLine($"Rolled: {result.Value.Total}"); Console.WriteLine($"Individual rolls: [{string.Join(", ", result.Value.IndividualRolls)}]"); } // Roll with advantage var advantage = roller.RollWithAdvantage("1d20+5"); Console.WriteLine($"Advantage result: {advantage.Value}"); ``` -------------------------------- ### Project Directory Structure Source: https://github.com/jamesplotts/opencombatengine/blob/main/README.md Visual representation of the repository layout, separating core logic, implementations, tests, and documentation. ```text OpenCombatEngine/ ├── src/ │ ├── OpenCombatEngine.Core/ # Interfaces and contracts only │ ├── OpenCombatEngine.Implementation/ # Concrete implementations │ └── OpenCombatEngine.Content/ # Content import system ├── tests/ │ └── OpenCombatEngine.Core.Tests/ # Comprehensive unit tests ├── docs/ │ ├── architecture/ # Architecture decisions │ └── implementation/ # Implementation details ├── examples/ │ └── DiceRollerDemo.cs # Usage examples └── .ai/ └── project-context.md # AI assistant context ``` -------------------------------- ### Manage Grid-Based Combat with IGridManager Source: https://context7.com/jamesplotts/opencombatengine/llms.txt Use IGridManager to handle creature positioning, movement validation, pathfinding, and spatial queries like line of sight and area effects. ```csharp using OpenCombatEngine.Core.Interfaces.Spatial; using OpenCombatEngine.Implementation.Spatial; using OpenCombatEngine.Core.Models.Spatial; // Create grid manager IGridManager grid = new StandardGridManager(); // Subscribe to movement events grid.CreatureMoved += (sender, e) => { Console.WriteLine($"{e.Creature.Name} moved from {e.From} to {e.To}"); }; // Place creatures on the grid var result = grid.PlaceCreature(fighter, new Position(0, 0, 0)); if (result.IsSuccess) Console.WriteLine("Fighter placed successfully"); grid.PlaceCreature(goblin, new Position(5, 0, 0)); grid.PlaceCreature(orc, new Position(2, 3, 0)); // Query positions Position? fighterPos = grid.GetPosition(fighter); ICreature? creatureAtOrigin = grid.GetCreatureAt(new Position(0, 0, 0)); // Calculate distances (in feet, 5ft per square) int distance = grid.GetDistance(fighter, goblin); // 25 feet (5 squares) int distanceByPos = grid.GetDistance(new Position(0, 0, 0), new Position(3, 4, 0)); // Move creatures var moveResult = grid.MoveCreature(fighter, new Position(1, 0, 0)); // Obstacles and terrain grid.AddObstacle(new Position(3, 0, 0)); // Wall or pillar bool blocked = grid.IsObstructed(new Position(3, 0, 0)); // true grid.AddDifficultTerrain(new Position(2, 0, 0)); // Costs 2x movement bool difficult = grid.IsDifficultTerrain(new Position(2, 0, 0)); // true // Line of sight bool hasLoS = grid.HasLineOfSight( source: new Position(0, 0, 0), target: new Position(5, 0, 0) ); // Flanking detection (grants advantage) bool isFlanked = grid.IsFlanked(target: goblin, attacker: fighter); // Pathfinding (A* algorithm) var path = grid.GetPath(new Position(0, 0, 0), new Position(5, 5, 0)); foreach (var waypoint in path) { Console.WriteLine($"Step: {waypoint.X}, {waypoint.Y}"); } // Get creatures within radius (for AoE) var nearbyCreatures = grid.GetCreaturesWithin( center: new Position(3, 3, 0), radius: 20 // 20 feet ); // Get all creatures on the grid var allCreatures = grid.GetAllCreatures(); ``` -------------------------------- ### Development Workflow Commands Source: https://github.com/jamesplotts/opencombatengine/blob/main/CONTRIBUTING.md Commands for managing feature branches, running coverage, and committing changes. ```bash git checkout -b feature/your-feature-name ``` ```bash dotnet test --collect:"XPlat Code Coverage" ``` ```bash git commit -m "feat(scope): description of change" ``` ```bash git push origin feature/your-feature-name ```