Compare commits

..

9 Commits

Author SHA1 Message Date
795ca383d6 Remove GameItemsData.csv and update item loading path in Program.cs 2025-02-16 12:27:27 -03:00
77f4ada5f1 Update CI workflow to target ARM64 platform and clean up Dockerfile 2025-02-16 10:30:59 -03:00
a044faa163 Remove Docker installation steps from CI workflow 2025-02-15 22:27:22 -03:00
1cf5f07c80 Add CI workflow for Docker build and deployment; update Dockerfile and adjust health reduction logic in PetActionService; modify database connection string in appsettings.json 2025-02-15 22:20:19 -03:00
b84599b370 Implement base controller for shared functionality; update existing controllers to inherit from BaseController and adjust user ID handling. Add JWT authentication support and modify item retrieval methods in GameDataController. 2025-02-15 21:57:59 -03:00
6d81ff1564 Add GameDataController for item icon retrieval; update GameItemsRepository and GameItemService for new action effects 2025-02-12 21:22:43 -03:00
215d4ecb72 Add action gathering functionality: implement ActionGathered model and repository, update Pet model and services, and enhance GameItemsRepository with item retrieval methods. 2025-02-09 21:22:52 -03:00
653cc451d2 Refactor skill allocation to upgrade; implement skill requirements and resource checks; remove experience from Pet model; update README for skill tree progress 2025-02-08 22:46:19 -03:00
f553196ca0 Refactor inventory unequip logic to use item ID instead of equip target; update README for inventory and skill tree progress 2025-02-05 20:37:12 -03:00
34 changed files with 1447 additions and 462 deletions

58
.gitea/workflows/main.yml Normal file
View File

@@ -0,0 +1,58 @@
name: Main Build & Deploy
on: workflow_dispatch
jobs:
build:
name: Build and Push Docker Image (amd64 and arm64)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
with:
config-inline: |
[registry."git.ivanch.me"]
- name: Login to Docker Hub
uses: https://github.com/docker/login-action@v3.3.0
with:
registry: git.ivanch.me
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_ACCESS_TOKEN }}
- name: Build Docker image and push
id: docker_build
uses: https://github.com/docker/build-push-action@v6.12.0
with:
context: ./
file: ./Dockerfile
push: true
tags: git.ivanch.me/ivanch/pet-companion/pet-companion-api:latest
platforms: linux/arm64
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}
deploy_live:
name: Deploy Live
runs-on: ubuntu-latest
needs: build
steps:
- name: Recreate container
uses: https://github.com/appleboy/ssh-action@v1.2.0
with:
host: ${{ secrets.LIVE_HOST }}
username: ${{ secrets.LIVE_USERNAME }}
key: ${{ secrets.LIVE_KEY }}
port: ${{ secrets.LIVE_PORT }}
script: |
cd ${{ secrets.LIVE_PROJECT_DIR }}
docker compose down
docker compose rm
docker compose pull
docker compose up -d

2
.gitignore vendored
View File

@@ -7,3 +7,5 @@ appsettings.Development.json
*.db-shm
*.db-wal
*.csproj.user
game-data

View File

@@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace PetCompanion.Controllers
{
[Authorize]
[ApiController]
[Route("api/v1/[controller]")]
public class BaseController : Controller
{
protected string userId => User.Claims.FirstOrDefault(c => c.Type == "user_id").Value;
}
}

View File

@@ -0,0 +1,46 @@
using Microsoft.AspNetCore.Mvc;
using PetCompanion.Repositories;
namespace PetCompanion.Controllers
{
public class GameDataController : BaseController
{
private readonly GameItemsRepository gameItemsRepository;
private readonly ILogger<InventoryController> logger;
public GameDataController(
ILogger<InventoryController> logger,
GameItemsRepository gameItemsRepository)
{
this.logger = logger;
this.gameItemsRepository = gameItemsRepository;
}
[HttpGet("item/{itemId}")]
public IActionResult GetItemInfo(int itemId)
{
try
{
return Ok(gameItemsRepository.GetById(itemId));
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
[HttpGet("item/{itemId}/icon")]
public IActionResult GetItemIcon(int itemId)
{
try
{
var iconBytes = gameItemsRepository.GetItemIcon(itemId);
return File(iconBytes, "image/png");
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
}
}

View File

@@ -1,16 +1,14 @@
using Microsoft.AspNetCore.Mvc;
using PetCompanion.Models;
using PetCompanion.Services;
namespace PetCompanion.Controllers
{
[ApiController]
[Route("api/v1/[controller]")]
public class InventoryController : ControllerBase
public class InventoryController : BaseController
{
private readonly PetInventoryService inventoryService;
private readonly ILogger<InventoryController> logger;
private readonly Guid userId = Guid.Parse("f5f4b3b3-3b7b-4b7b-8b7b-7b7b7b7b7b7b");
public InventoryController(
ILogger<InventoryController> logger,
@@ -62,12 +60,12 @@ namespace PetCompanion.Controllers
}
}
[HttpPut("{petId}/{equipTarget}/unequip")]
public IActionResult UnequipItem(string petId, ItemEquipTarget equipTarget)
[HttpPut("{petId}/{itemId}/unequip")]
public IActionResult UnequipItem(string petId, int itemId)
{
try
{
var updatedPet = inventoryService.UnequipItem(petId, userId.ToString(), equipTarget);
var updatedPet = inventoryService.UnequipItem(petId, userId.ToString(), itemId);
return Ok(updatedPet);
}
catch (Exception ex)

View File

@@ -4,14 +4,11 @@ using PetCompanion.Services;
namespace PetCompanion.Controllers
{
[ApiController]
[Route("api/v1/[controller]")]
public class PetController : ControllerBase
public class PetController : BaseController
{
private readonly PetService petService;
private readonly PetClassService petClassService;
private readonly ILogger<PetController> logger;
private Guid userId = Guid.Parse("f5f4b3b3-3b7b-4b7b-8b7b-7b7b7b7b7b7b");
public PetController(
ILogger<PetController> logger,
@@ -69,7 +66,7 @@ namespace PetCompanion.Controllers
{
try
{
var updatedPet = petService.UpdatePetResources(petId, userId.ToString());
var updatedPet = petService.CollectPetGathered(petId, userId.ToString());
return Ok(updatedPet);
}
catch (Exception ex)

View File

@@ -3,14 +3,11 @@ using PetCompanion.Services;
namespace PetCompanion.Controllers
{
[ApiController]
[Route("api/v1/[controller]")]
public class SkillController : ControllerBase
public class SkillController : BaseController
{
private readonly SkillService _skillService;
private readonly PetSkillService _petSkillService;
private readonly ILogger<SkillController> _logger;
private Guid userId = Guid.Parse("f5f4b3b3-3b7b-4b7b-8b7b-7b7b7b7b7b7b");
public SkillController(
ILogger<SkillController> logger,
@@ -34,7 +31,7 @@ namespace PetCompanion.Controllers
{
try
{
var skills = _petSkillService.GetPetSkills(petId, userId.ToString());
var skills = _petSkillService.GetPetSkills(petId, userId);
return Ok(skills);
}
catch (Exception ex)
@@ -44,11 +41,11 @@ namespace PetCompanion.Controllers
}
[HttpPost("{petId}/allocate/{skillId}")]
public IActionResult AllocateSkillPoint(string petId, int skillId)
public IActionResult UpgradeSkill(string petId, int skillId)
{
try
{
var result = _petSkillService.AllocateSkillPoint(petId, userId.ToString(), skillId);
var result = _petSkillService.UpgradeSkill(petId, userId, skillId);
return Ok(result);
}
catch (Exception ex)

View File

@@ -18,6 +18,7 @@ namespace PetCompanion.Data
public DbSet<GameItem> GameItems { get; set; }
public DbSet<Inventory> Inventories { get; set; }
public DbSet<EquippedItem> EquippedItems { get; set; }
public DbSet<ActionGathered> ActionGathered { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
@@ -51,6 +52,11 @@ namespace PetCompanion.Data
.WithMany(s => s.Effects)
.HasForeignKey(se => se.SkillId);
modelBuilder.Entity<SkillRequirement>()
.HasOne(se => se.Skill)
.WithMany(s => s.SkillRequirements)
.HasForeignKey(se => se.SkillId);
modelBuilder.Entity<EquippedItem>()
.HasOne(e => e.Pet)
.WithMany(p => p.EquippedItemsList)
@@ -61,31 +67,25 @@ namespace PetCompanion.Data
.WithMany()
.HasForeignKey(e => e.GameItemId);
// Seed initial skills
var skills = SkillsData.GetInitialSkills();
var skillWithoutEffects = SkillsData.GetInitialSkills().Select(s => new Skill
{
Id = s.Id,
Name = s.Name,
Type = s.Type,
Description = s.Description,
PointsCost = s.PointsCost,
Icon = s.Icon,
SkillsIdRequired = s.SkillsIdRequired
}).ToList();
modelBuilder.Entity<ActionGathered>()
.HasOne(ag => ag.Pet)
.WithMany(p => p.ActionGathered)
.HasForeignKey(ag => ag.PetId)
.OnDelete(DeleteBehavior.Cascade);
foreach (var skill in skillWithoutEffects)
{
modelBuilder.Entity<Skill>().HasData(skill);
}
modelBuilder.Entity<ActionGathered>()
.HasOne(ag => ag.GameItem)
.WithMany()
.HasForeignKey(ag => ag.ItemId);
foreach (var skill in skills)
{
foreach (var effect in skill.Effects)
{
modelBuilder.Entity<SkillEffect>().HasData(effect);
}
}
// Seed initial data
var skills = SkillsData.GetInitialSkillsWithoutRelations();
var requirements = SkillsData.GetInitialSkillRequirements();
var effects = SkillsData.GetInitialSkillEffects();
modelBuilder.Entity<Skill>().HasData(skills);
modelBuilder.Entity<SkillRequirement>().HasData(requirements);
modelBuilder.Entity<SkillEffect>().HasData(effects);
}
}
}

View File

@@ -4,7 +4,7 @@ namespace PetCompanion.Data
{
public static class SkillsData
{
public static IEnumerable<Skill> GetInitialSkills()
public static IEnumerable<Skill> GetInitialSkillsWithoutRelations()
{
return new List<Skill>
{
@@ -14,10 +14,99 @@ namespace PetCompanion.Data
Name = "Vitality Mastery",
Description = "Increases maximum health of your pet, making it more resilient.",
Type = SkillType.GROUND,
PointsCost = 1,
Icon = "❤",
SkillsIdRequired = null,
Effects = new List<SkillEffect>
SkillsIdRequired = null
},
new Skill
{
Id = 2,
Name = "Mind Enhancement",
Description = "Increases maximum intelligence of your pet, improving its learning capabilities.",
Type = SkillType.GROUND,
Icon = "🧠",
SkillsIdRequired = null
},
new Skill
{
Id = 3,
Name = "Strength Training",
Description = "Increases maximum strength of your pet, making it more powerful.",
Type = SkillType.GROUND,
Icon = "💪",
SkillsIdRequired = null
},
new Skill
{
Id = 4,
Name = "Charisma Boost",
Description = "Increases maximum charisma of your pet, making it more charming.",
Type = SkillType.GROUND,
Icon = "🎭",
SkillsIdRequired = null
},
new Skill
{
Id = 5,
Name = "Luck of the Draw",
Description = "Increases luck of your pet, making it more fortunate to find rare items.",
Type = SkillType.GROUND,
Icon = "🍀",
SkillsIdRequired = new List<int> { 4 }
},
new Skill
{
Id = 6,
Name = "Agility Training",
Description = "Increases agility of your pet, making it faster in combat.",
Type = SkillType.GROUND,
Icon = "🏃",
SkillsIdRequired = new List<int> { 3 }
},
new Skill
{
Id = 7,
Name = "Perception Boost",
Description = "Increases perception of your pet, making it more aware of its surroundings.",
Type = SkillType.GROUND,
Icon = "👀",
SkillsIdRequired = new List<int> { 2 }
},
new Skill
{
Id = 8,
Name = "Resourcefulness",
Description = "Increases the amount of resources gathered by your pet.",
Type = SkillType.GRAND,
Icon = "📦",
SkillsIdRequired = new List<int> { 5, 6, 7 }
}
};
}
public static IEnumerable<SkillRequirement> GetInitialSkillRequirements()
{
return new List<SkillRequirement>
{
new SkillRequirement { Id = 1, SkillId = 1, Resource = "Wisdom", Cost = 100 },
new SkillRequirement { Id = 2, SkillId = 1, Resource = "Food", Cost = 150 },
new SkillRequirement { Id = 3, SkillId = 2, Resource = "Wisdom", Cost = 150 },
new SkillRequirement { Id = 4, SkillId = 3, Resource = "Gold", Cost = 100 },
new SkillRequirement { Id = 5, SkillId = 3, Resource = "Food", Cost = 150 },
new SkillRequirement { Id = 6, SkillId = 4, Resource = "Wisdom", Cost = 200 },
new SkillRequirement { Id = 7, SkillId = 5, Resource = "Gold", Cost = 200 },
new SkillRequirement { Id = 8, SkillId = 6, Resource = "Gold", Cost = 200 },
new SkillRequirement { Id = 9, SkillId = 7, Resource = "Gold", Cost = 100 },
new SkillRequirement { Id = 10, SkillId = 7, Resource = "Junk", Cost = 100 },
new SkillRequirement { Id = 11, SkillId = 8, Resource = "Gold", Cost = 500 },
new SkillRequirement { Id = 12, SkillId = 8, Resource = "Junk", Cost = 500 },
new SkillRequirement { Id = 13, SkillId = 8, Resource = "Wisdom", Cost = 300 },
new SkillRequirement { Id = 14, SkillId = 8, Resource = "Food", Cost = 300 }
};
}
public static IEnumerable<SkillEffect> GetInitialSkillEffects()
{
return new List<SkillEffect>
{
new SkillEffect
{
@@ -42,20 +131,7 @@ namespace PetCompanion.Data
Tier = SkillTier.III,
Effect = "MaxHealth",
Value = 100
}
}
},
new Skill
{
Id = 2,
Name = "Mind Enhancement",
Description = "Increases maximum intelligence of your pet, improving its learning capabilities.",
Type = SkillType.GROUND,
PointsCost = 1,
Icon = "🧠",
SkillsIdRequired = null,
Effects = new List<SkillEffect>
{
new SkillEffect
{
Id = 4,
@@ -79,20 +155,7 @@ namespace PetCompanion.Data
Tier = SkillTier.III,
Effect = "MaxIntelligence",
Value = 20
}
}
},
new Skill
{
Id = 3,
Name = "Strength Training",
Description = "Increases maximum strength of your pet, making it more powerful.",
Type = SkillType.GROUND,
PointsCost = 1,
Icon = "💪",
SkillsIdRequired = null,
Effects = new List<SkillEffect>
{
new SkillEffect
{
Id = 7,
@@ -116,20 +179,7 @@ namespace PetCompanion.Data
Tier = SkillTier.III,
Effect = "MaxStrength",
Value = 20
}
}
},
new Skill
{
Id = 4,
Name = "Charisma Boost",
Description = "Increases maximum charisma of your pet, making it more charming.",
Type = SkillType.GROUND,
PointsCost = 1,
Icon = "🎭",
SkillsIdRequired = null,
Effects = new List<SkillEffect>
{
new SkillEffect
{
Id = 10,
@@ -153,20 +203,7 @@ namespace PetCompanion.Data
Tier = SkillTier.III,
Effect = "MaxCharisma",
Value = 20
}
}
},
new Skill
{
Id = 5,
Name = "Luck of the Draw",
Description = "Increases luck of your pet, making it more fortunate to find rare items.",
Type = SkillType.GROUND,
PointsCost = 1,
Icon = "🍀",
SkillsIdRequired = new List<int> { 4 },
Effects = new List<SkillEffect>
{
new SkillEffect
{
Id = 13,
@@ -190,20 +227,7 @@ namespace PetCompanion.Data
Tier = SkillTier.III,
Effect = "Luck",
Value = 3
}
}
},
new Skill
{
Id = 6,
Name = "Agility Training",
Description = "Increases agility of your pet, making it faster in combat.",
Type = SkillType.GROUND,
PointsCost = 1,
Icon = "🏃",
SkillsIdRequired = new List<int> { 3 },
Effects = new List<SkillEffect>
{
new SkillEffect
{
Id = 16,
@@ -227,20 +251,7 @@ namespace PetCompanion.Data
Tier = SkillTier.III,
Effect = "Agility",
Value = 3
}
}
},
new Skill
{
Id = 7,
Name = "Perception Boost",
Description = "Increases perception of your pet, making it more aware of its surroundings.",
Type = SkillType.GROUND,
PointsCost = 1,
Icon = "👀",
SkillsIdRequired = new List<int> { 2 },
Effects = new List<SkillEffect>
{
new SkillEffect
{
Id = 19,
@@ -264,8 +275,30 @@ namespace PetCompanion.Data
Tier = SkillTier.III,
Effect = "Perception",
Value = 3
}
}
},
new SkillEffect
{
Id = 22,
SkillId = 8,
Tier = SkillTier.I,
Effect = "Resourcefulness",
Value = 1
},
new SkillEffect
{
Id = 23,
SkillId = 8,
Tier = SkillTier.II,
Effect = "Resourcefulness",
Value = 2
},
new SkillEffect
{
Id = 24,
SkillId = 8,
Tier = SkillTier.III,
Effect = "Resourcefulness",
Value = 3
}
};
}

View File

@@ -1,13 +1,9 @@
# See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
# This stage is used when running from VS in fast mode (Default for Debug configuration)
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
USER app
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
# This stage is used to build the service project
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG BUILD_CONFIGURATION=Release

View File

@@ -1,21 +0,0 @@
Id,Name,Type,Rarity,Description,Price,Effect,EquipTarget
1,Apple,Material,Common,Crafting material (coming soon),0,Nothing,None
2,Superfood Smoothie,Consumable,Uncommon,Adds +30 food resources; Restores 5 Intelligence,0,ADD_FOOD_RESOURCES_30,None
3,Energy Drink,Consumable,Rare,Reduces Cooldown by 5 min,0,REDUCE_COOLDOWN_5,None
4,Golden Apple,Consumable,Legendary,Adds +20 Intelligence (Permanent); Adds +100 food resources,0,ADD_INTELLIGENCE_20,None
5,Healing Potion,Consumable,Uncommon,Adds +20 to Health; Adds +20 food resources,0,ADD_HEALTH_20_AND_FOOD_20,None
6,Charisma Cookie,Consumable,Rare,Adds +2 Charisma (Permanent),0,ADD_CHARISMA_2,None
7,XP Booster,Consumable,Rare,Award +10 XP,0,ADD_XP_10,None
8,Sleeping Draught,Consumable,Common,Reduces Cooldown for resting by 10 min,0,REDUCE_REST_COOLDOWN_10,None
9,Mystery Meat,Consumable,Uncommon,Randomly ±2 to one stat (Permanent),0,ADD_RANDOM_STAT_2,None
10,Elixir of Vitality,Consumable,Legendary,Fully restores all stats and health; Adds +1 Level,0,RESTORE_STATS;ADD_LEVEL_1,None
11,Leather Hat,Equipment,Common,Helmet: +5 Max Health,0,ADD_MAX_HEALTH_5,Head
12,Wizard Hat,Equipment,Rare,Helmet: +15 Max Intelligence,0,ADD_MAX_INTELLIGENCE_15,Head
13,Knight's Armor,Equipment,Rare,Chest: +15 Max Strength,0,ADD_MAX_STRENGTH_15,Body
14,Golden Boots,Equipment,Uncommon,Legging: +10 Max Charisma,0,ADD_MAX_CHARISMA_10,Legs
15,Laser Pointer,Equipment,Common,Weapon: +5 Max Strength,0,ADD_MAX_STRENGTH_5,Weapon
16,Celestial Crown,Equipment,Legendary,Helmet: +20 max to all stats,0,ADD_MAX_ALL_STATS_20,Head
17,Dragon Scale Shield,Equipment,Legendary,Weapon: +50 Max Health,0,ADD_MAX_HEALTH_50,Weapon
18,Feathers,Material,Common,Crafting material (coming soon),0,Nothing,None
19,Phoenix Feather,Material,Legendary,Crafting material (coming soon),0,Nothing,None
21,Basic Kibble,Consumable,Common,Adds +20 food resources,0,ADD_FOOD_RESOURCES_20,None
1 Id Name Type Rarity Description Price Effect EquipTarget
2 1 Apple Material Common Crafting material (coming soon) 0 Nothing None
3 2 Superfood Smoothie Consumable Uncommon Adds +30 food resources; Restores 5 Intelligence 0 ADD_FOOD_RESOURCES_30 None
4 3 Energy Drink Consumable Rare Reduces Cooldown by 5 min 0 REDUCE_COOLDOWN_5 None
5 4 Golden Apple Consumable Legendary Adds +20 Intelligence (Permanent); Adds +100 food resources 0 ADD_INTELLIGENCE_20 None
6 5 Healing Potion Consumable Uncommon Adds +20 to Health; Adds +20 food resources 0 ADD_HEALTH_20_AND_FOOD_20 None
7 6 Charisma Cookie Consumable Rare Adds +2 Charisma (Permanent) 0 ADD_CHARISMA_2 None
8 7 XP Booster Consumable Rare Award +10 XP 0 ADD_XP_10 None
9 8 Sleeping Draught Consumable Common Reduces Cooldown for resting by 10 min 0 REDUCE_REST_COOLDOWN_10 None
10 9 Mystery Meat Consumable Uncommon Randomly ±2 to one stat (Permanent) 0 ADD_RANDOM_STAT_2 None
11 10 Elixir of Vitality Consumable Legendary Fully restores all stats and health; Adds +1 Level 0 RESTORE_STATS;ADD_LEVEL_1 None
12 11 Leather Hat Equipment Common Helmet: +5 Max Health 0 ADD_MAX_HEALTH_5 Head
13 12 Wizard Hat Equipment Rare Helmet: +15 Max Intelligence 0 ADD_MAX_INTELLIGENCE_15 Head
14 13 Knight's Armor Equipment Rare Chest: +15 Max Strength 0 ADD_MAX_STRENGTH_15 Body
15 14 Golden Boots Equipment Uncommon Legging: +10 Max Charisma 0 ADD_MAX_CHARISMA_10 Legs
16 15 Laser Pointer Equipment Common Weapon: +5 Max Strength 0 ADD_MAX_STRENGTH_5 Weapon
17 16 Celestial Crown Equipment Legendary Helmet: +20 max to all stats 0 ADD_MAX_ALL_STATS_20 Head
18 17 Dragon Scale Shield Equipment Legendary Weapon: +50 Max Health 0 ADD_MAX_HEALTH_50 Weapon
19 18 Feathers Material Common Crafting material (coming soon) 0 Nothing None
20 19 Phoenix Feather Material Legendary Crafting material (coming soon) 0 Nothing None
21 21 Basic Kibble Consumable Common Adds +20 food resources 0 ADD_FOOD_RESOURCES_20 None

View File

@@ -11,7 +11,7 @@ using PetCompanion.Data;
namespace PetCompanion.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20250204213845_InitialCreate")]
[Migration("20250209234852_InitialCreate")]
partial class InitialCreate
{
/// <inheritdoc />
@@ -20,6 +20,34 @@ namespace PetCompanion.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.1");
modelBuilder.Entity("PetCompanion.Models.ActionGathered", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Amount")
.HasColumnType("INTEGER");
b.Property<int?>("ItemId")
.HasColumnType("INTEGER");
b.Property<string>("PetId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Resource")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("ItemId");
b.HasIndex("PetId");
b.ToTable("ActionGathered");
});
modelBuilder.Entity("PetCompanion.Models.EquippedItem", b =>
{
b.Property<int>("Id")
@@ -108,9 +136,6 @@ namespace PetCompanion.Migrations
b.Property<int>("Class")
.HasColumnType("INTEGER");
b.Property<int>("Experience")
.HasColumnType("INTEGER");
b.Property<DateTime>("GatherActionSince")
.HasColumnType("TEXT");
@@ -136,9 +161,6 @@ namespace PetCompanion.Migrations
b.Property<int>("PetGatherAction")
.HasColumnType("INTEGER");
b.Property<int>("SkillPoints")
.HasColumnType("INTEGER");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
@@ -250,9 +272,6 @@ namespace PetCompanion.Migrations
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("PointsCost")
.HasColumnType("INTEGER");
b.PrimitiveCollection<string>("SkillsIdRequired")
.HasColumnType("TEXT");
@@ -270,7 +289,6 @@ namespace PetCompanion.Migrations
Description = "Increases maximum health of your pet, making it more resilient.",
Icon = "❤",
Name = "Vitality Mastery",
PointsCost = 1,
Type = 0
},
new
@@ -279,7 +297,6 @@ namespace PetCompanion.Migrations
Description = "Increases maximum intelligence of your pet, improving its learning capabilities.",
Icon = "🧠",
Name = "Mind Enhancement",
PointsCost = 1,
Type = 0
},
new
@@ -288,7 +305,6 @@ namespace PetCompanion.Migrations
Description = "Increases maximum strength of your pet, making it more powerful.",
Icon = "💪",
Name = "Strength Training",
PointsCost = 1,
Type = 0
},
new
@@ -297,7 +313,6 @@ namespace PetCompanion.Migrations
Description = "Increases maximum charisma of your pet, making it more charming.",
Icon = "🎭",
Name = "Charisma Boost",
PointsCost = 1,
Type = 0
},
new
@@ -306,7 +321,6 @@ namespace PetCompanion.Migrations
Description = "Increases luck of your pet, making it more fortunate to find rare items.",
Icon = "🍀",
Name = "Luck of the Draw",
PointsCost = 1,
SkillsIdRequired = "[4]",
Type = 0
},
@@ -316,7 +330,6 @@ namespace PetCompanion.Migrations
Description = "Increases agility of your pet, making it faster in combat.",
Icon = "🏃",
Name = "Agility Training",
PointsCost = 1,
SkillsIdRequired = "[3]",
Type = 0
},
@@ -326,9 +339,17 @@ namespace PetCompanion.Migrations
Description = "Increases perception of your pet, making it more aware of its surroundings.",
Icon = "👀",
Name = "Perception Boost",
PointsCost = 1,
SkillsIdRequired = "[2]",
Type = 0
},
new
{
Id = 8,
Description = "Increases the amount of resources gathered by your pet.",
Icon = "📦",
Name = "Resourcefulness",
SkillsIdRequired = "[5,6,7]",
Type = 1
});
});
@@ -525,9 +546,173 @@ namespace PetCompanion.Migrations
SkillId = 7,
Tier = 3,
Value = 3m
},
new
{
Id = 22,
Effect = "Resourcefulness",
SkillId = 8,
Tier = 1,
Value = 1m
},
new
{
Id = 23,
Effect = "Resourcefulness",
SkillId = 8,
Tier = 2,
Value = 2m
},
new
{
Id = 24,
Effect = "Resourcefulness",
SkillId = 8,
Tier = 3,
Value = 3m
});
});
modelBuilder.Entity("PetCompanion.Models.SkillRequirement", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Cost")
.HasColumnType("INTEGER");
b.Property<string>("Resource")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("SkillId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("SkillId");
b.ToTable("SkillRequirement");
b.HasData(
new
{
Id = 1,
Cost = 100,
Resource = "Wisdom",
SkillId = 1
},
new
{
Id = 2,
Cost = 150,
Resource = "Food",
SkillId = 1
},
new
{
Id = 3,
Cost = 150,
Resource = "Wisdom",
SkillId = 2
},
new
{
Id = 4,
Cost = 100,
Resource = "Gold",
SkillId = 3
},
new
{
Id = 5,
Cost = 150,
Resource = "Food",
SkillId = 3
},
new
{
Id = 6,
Cost = 200,
Resource = "Wisdom",
SkillId = 4
},
new
{
Id = 7,
Cost = 200,
Resource = "Gold",
SkillId = 5
},
new
{
Id = 8,
Cost = 200,
Resource = "Gold",
SkillId = 6
},
new
{
Id = 9,
Cost = 100,
Resource = "Gold",
SkillId = 7
},
new
{
Id = 10,
Cost = 100,
Resource = "Junk",
SkillId = 7
},
new
{
Id = 11,
Cost = 500,
Resource = "Gold",
SkillId = 8
},
new
{
Id = 12,
Cost = 500,
Resource = "Junk",
SkillId = 8
},
new
{
Id = 13,
Cost = 300,
Resource = "Wisdom",
SkillId = 8
},
new
{
Id = 14,
Cost = 300,
Resource = "Food",
SkillId = 8
});
});
modelBuilder.Entity("PetCompanion.Models.ActionGathered", b =>
{
b.HasOne("PetCompanion.Models.GameItem", "GameItem")
.WithMany()
.HasForeignKey("ItemId");
b.HasOne("PetCompanion.Models.Pet", "Pet")
.WithMany("ActionGathered")
.HasForeignKey("PetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("GameItem");
b.Navigation("Pet");
});
modelBuilder.Entity("PetCompanion.Models.EquippedItem", b =>
{
b.HasOne("PetCompanion.Models.GameItem", "GameItem")
@@ -606,8 +791,21 @@ namespace PetCompanion.Migrations
b.Navigation("Skill");
});
modelBuilder.Entity("PetCompanion.Models.SkillRequirement", b =>
{
b.HasOne("PetCompanion.Models.Skill", "Skill")
.WithMany("SkillRequirements")
.HasForeignKey("SkillId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Skill");
});
modelBuilder.Entity("PetCompanion.Models.Pet", b =>
{
b.Navigation("ActionGathered");
b.Navigation("EquippedItemsList");
b.Navigation("Inventory")
@@ -627,6 +825,8 @@ namespace PetCompanion.Migrations
b.Navigation("Effects");
b.Navigation("PetSkills");
b.Navigation("SkillRequirements");
});
#pragma warning restore 612, 618
}

View File

@@ -40,7 +40,6 @@ namespace PetCompanion.Migrations
Name = table.Column<string>(type: "TEXT", nullable: false),
Class = table.Column<int>(type: "INTEGER", nullable: false),
Level = table.Column<int>(type: "INTEGER", nullable: false),
Experience = table.Column<int>(type: "INTEGER", nullable: false),
Health = table.Column<int>(type: "INTEGER", nullable: false),
MaxHealth = table.Column<int>(type: "INTEGER", nullable: false),
UserId = table.Column<string>(type: "TEXT", nullable: false),
@@ -48,8 +47,7 @@ namespace PetCompanion.Migrations
PetGatherAction = table.Column<int>(type: "INTEGER", nullable: false),
GatherActionSince = table.Column<DateTime>(type: "TEXT", nullable: false),
PetBasicAction = table.Column<int>(type: "INTEGER", nullable: false),
BasicActionCooldown = table.Column<DateTime>(type: "TEXT", nullable: false),
SkillPoints = table.Column<int>(type: "INTEGER", nullable: false)
BasicActionCooldown = table.Column<DateTime>(type: "TEXT", nullable: false)
},
constraints: table =>
{
@@ -65,7 +63,6 @@ namespace PetCompanion.Migrations
Name = table.Column<string>(type: "TEXT", nullable: false),
Description = table.Column<string>(type: "TEXT", nullable: false),
Type = table.Column<int>(type: "INTEGER", nullable: false),
PointsCost = table.Column<int>(type: "INTEGER", nullable: false),
Icon = table.Column<string>(type: "TEXT", nullable: false),
SkillsIdRequired = table.Column<string>(type: "TEXT", nullable: true)
},
@@ -74,6 +71,33 @@ namespace PetCompanion.Migrations
table.PrimaryKey("PK_Skills", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ActionGathered",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
PetId = table.Column<string>(type: "TEXT", nullable: false),
Resource = table.Column<string>(type: "TEXT", nullable: true),
ItemId = table.Column<int>(type: "INTEGER", nullable: true),
Amount = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ActionGathered", x => x.Id);
table.ForeignKey(
name: "FK_ActionGathered_GameItems_ItemId",
column: x => x.ItemId,
principalTable: "GameItems",
principalColumn: "Id");
table.ForeignKey(
name: "FK_ActionGathered_Pets_PetId",
column: x => x.PetId,
principalTable: "Pets",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "EquippedItems",
columns: table => new
@@ -216,18 +240,40 @@ namespace PetCompanion.Migrations
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "SkillRequirement",
columns: table => new
{
Id = table.Column<int>(type: "INTEGER", nullable: false)
.Annotation("Sqlite:Autoincrement", true),
SkillId = table.Column<int>(type: "INTEGER", nullable: false),
Resource = table.Column<string>(type: "TEXT", nullable: false),
Cost = table.Column<int>(type: "INTEGER", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_SkillRequirement", x => x.Id);
table.ForeignKey(
name: "FK_SkillRequirement_Skills_SkillId",
column: x => x.SkillId,
principalTable: "Skills",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.InsertData(
table: "Skills",
columns: new[] { "Id", "Description", "Icon", "Name", "PointsCost", "SkillsIdRequired", "Type" },
columns: new[] { "Id", "Description", "Icon", "Name", "SkillsIdRequired", "Type" },
values: new object[,]
{
{ 1, "Increases maximum health of your pet, making it more resilient.", "❤", "Vitality Mastery", 1, null, 0 },
{ 2, "Increases maximum intelligence of your pet, improving its learning capabilities.", "🧠", "Mind Enhancement", 1, null, 0 },
{ 3, "Increases maximum strength of your pet, making it more powerful.", "💪", "Strength Training", 1, null, 0 },
{ 4, "Increases maximum charisma of your pet, making it more charming.", "🎭", "Charisma Boost", 1, null, 0 },
{ 5, "Increases luck of your pet, making it more fortunate to find rare items.", "🍀", "Luck of the Draw", 1, "[4]", 0 },
{ 6, "Increases agility of your pet, making it faster in combat.", "🏃", "Agility Training", 1, "[3]", 0 },
{ 7, "Increases perception of your pet, making it more aware of its surroundings.", "👀", "Perception Boost", 1, "[2]", 0 }
{ 1, "Increases maximum health of your pet, making it more resilient.", "❤", "Vitality Mastery", null, 0 },
{ 2, "Increases maximum intelligence of your pet, improving its learning capabilities.", "🧠", "Mind Enhancement", null, 0 },
{ 3, "Increases maximum strength of your pet, making it more powerful.", "💪", "Strength Training", null, 0 },
{ 4, "Increases maximum charisma of your pet, making it more charming.", "🎭", "Charisma Boost", null, 0 },
{ 5, "Increases luck of your pet, making it more fortunate to find rare items.", "🍀", "Luck of the Draw", "[4]", 0 },
{ 6, "Increases agility of your pet, making it faster in combat.", "🏃", "Agility Training", "[3]", 0 },
{ 7, "Increases perception of your pet, making it more aware of its surroundings.", "👀", "Perception Boost", "[2]", 0 },
{ 8, "Increases the amount of resources gathered by your pet.", "📦", "Resourcefulness", "[5,6,7]", 1 }
});
migrationBuilder.InsertData(
@@ -255,9 +301,43 @@ namespace PetCompanion.Migrations
{ 18, "Agility", 6, 3, 3m },
{ 19, "Perception", 7, 1, 1m },
{ 20, "Perception", 7, 2, 2m },
{ 21, "Perception", 7, 3, 3m }
{ 21, "Perception", 7, 3, 3m },
{ 22, "Resourcefulness", 8, 1, 1m },
{ 23, "Resourcefulness", 8, 2, 2m },
{ 24, "Resourcefulness", 8, 3, 3m }
});
migrationBuilder.InsertData(
table: "SkillRequirement",
columns: new[] { "Id", "Cost", "Resource", "SkillId" },
values: new object[,]
{
{ 1, 100, "Wisdom", 1 },
{ 2, 150, "Food", 1 },
{ 3, 150, "Wisdom", 2 },
{ 4, 100, "Gold", 3 },
{ 5, 150, "Food", 3 },
{ 6, 200, "Wisdom", 4 },
{ 7, 200, "Gold", 5 },
{ 8, 200, "Gold", 6 },
{ 9, 100, "Gold", 7 },
{ 10, 100, "Junk", 7 },
{ 11, 500, "Gold", 8 },
{ 12, 500, "Junk", 8 },
{ 13, 300, "Wisdom", 8 },
{ 14, 300, "Food", 8 }
});
migrationBuilder.CreateIndex(
name: "IX_ActionGathered_ItemId",
table: "ActionGathered",
column: "ItemId");
migrationBuilder.CreateIndex(
name: "IX_ActionGathered_PetId",
table: "ActionGathered",
column: "PetId");
migrationBuilder.CreateIndex(
name: "IX_EquippedItems_GameItemId",
table: "EquippedItems",
@@ -282,11 +362,19 @@ namespace PetCompanion.Migrations
name: "IX_SkillEffects_SkillId",
table: "SkillEffects",
column: "SkillId");
migrationBuilder.CreateIndex(
name: "IX_SkillRequirement_SkillId",
table: "SkillRequirement",
column: "SkillId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ActionGathered");
migrationBuilder.DropTable(
name: "EquippedItems");
@@ -305,6 +393,9 @@ namespace PetCompanion.Migrations
migrationBuilder.DropTable(
name: "SkillEffects");
migrationBuilder.DropTable(
name: "SkillRequirement");
migrationBuilder.DropTable(
name: "GameItems");

View File

@@ -17,6 +17,34 @@ namespace PetCompanion.Migrations
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.1");
modelBuilder.Entity("PetCompanion.Models.ActionGathered", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Amount")
.HasColumnType("INTEGER");
b.Property<int?>("ItemId")
.HasColumnType("INTEGER");
b.Property<string>("PetId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Resource")
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("ItemId");
b.HasIndex("PetId");
b.ToTable("ActionGathered");
});
modelBuilder.Entity("PetCompanion.Models.EquippedItem", b =>
{
b.Property<int>("Id")
@@ -105,9 +133,6 @@ namespace PetCompanion.Migrations
b.Property<int>("Class")
.HasColumnType("INTEGER");
b.Property<int>("Experience")
.HasColumnType("INTEGER");
b.Property<DateTime>("GatherActionSince")
.HasColumnType("TEXT");
@@ -133,9 +158,6 @@ namespace PetCompanion.Migrations
b.Property<int>("PetGatherAction")
.HasColumnType("INTEGER");
b.Property<int>("SkillPoints")
.HasColumnType("INTEGER");
b.Property<string>("UserId")
.IsRequired()
.HasColumnType("TEXT");
@@ -247,9 +269,6 @@ namespace PetCompanion.Migrations
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("PointsCost")
.HasColumnType("INTEGER");
b.PrimitiveCollection<string>("SkillsIdRequired")
.HasColumnType("TEXT");
@@ -267,7 +286,6 @@ namespace PetCompanion.Migrations
Description = "Increases maximum health of your pet, making it more resilient.",
Icon = "❤",
Name = "Vitality Mastery",
PointsCost = 1,
Type = 0
},
new
@@ -276,7 +294,6 @@ namespace PetCompanion.Migrations
Description = "Increases maximum intelligence of your pet, improving its learning capabilities.",
Icon = "🧠",
Name = "Mind Enhancement",
PointsCost = 1,
Type = 0
},
new
@@ -285,7 +302,6 @@ namespace PetCompanion.Migrations
Description = "Increases maximum strength of your pet, making it more powerful.",
Icon = "💪",
Name = "Strength Training",
PointsCost = 1,
Type = 0
},
new
@@ -294,7 +310,6 @@ namespace PetCompanion.Migrations
Description = "Increases maximum charisma of your pet, making it more charming.",
Icon = "🎭",
Name = "Charisma Boost",
PointsCost = 1,
Type = 0
},
new
@@ -303,7 +318,6 @@ namespace PetCompanion.Migrations
Description = "Increases luck of your pet, making it more fortunate to find rare items.",
Icon = "🍀",
Name = "Luck of the Draw",
PointsCost = 1,
SkillsIdRequired = "[4]",
Type = 0
},
@@ -313,7 +327,6 @@ namespace PetCompanion.Migrations
Description = "Increases agility of your pet, making it faster in combat.",
Icon = "🏃",
Name = "Agility Training",
PointsCost = 1,
SkillsIdRequired = "[3]",
Type = 0
},
@@ -323,9 +336,17 @@ namespace PetCompanion.Migrations
Description = "Increases perception of your pet, making it more aware of its surroundings.",
Icon = "👀",
Name = "Perception Boost",
PointsCost = 1,
SkillsIdRequired = "[2]",
Type = 0
},
new
{
Id = 8,
Description = "Increases the amount of resources gathered by your pet.",
Icon = "📦",
Name = "Resourcefulness",
SkillsIdRequired = "[5,6,7]",
Type = 1
});
});
@@ -522,9 +543,173 @@ namespace PetCompanion.Migrations
SkillId = 7,
Tier = 3,
Value = 3m
},
new
{
Id = 22,
Effect = "Resourcefulness",
SkillId = 8,
Tier = 1,
Value = 1m
},
new
{
Id = 23,
Effect = "Resourcefulness",
SkillId = 8,
Tier = 2,
Value = 2m
},
new
{
Id = 24,
Effect = "Resourcefulness",
SkillId = 8,
Tier = 3,
Value = 3m
});
});
modelBuilder.Entity("PetCompanion.Models.SkillRequirement", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Cost")
.HasColumnType("INTEGER");
b.Property<string>("Resource")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("SkillId")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("SkillId");
b.ToTable("SkillRequirement");
b.HasData(
new
{
Id = 1,
Cost = 100,
Resource = "Wisdom",
SkillId = 1
},
new
{
Id = 2,
Cost = 150,
Resource = "Food",
SkillId = 1
},
new
{
Id = 3,
Cost = 150,
Resource = "Wisdom",
SkillId = 2
},
new
{
Id = 4,
Cost = 100,
Resource = "Gold",
SkillId = 3
},
new
{
Id = 5,
Cost = 150,
Resource = "Food",
SkillId = 3
},
new
{
Id = 6,
Cost = 200,
Resource = "Wisdom",
SkillId = 4
},
new
{
Id = 7,
Cost = 200,
Resource = "Gold",
SkillId = 5
},
new
{
Id = 8,
Cost = 200,
Resource = "Gold",
SkillId = 6
},
new
{
Id = 9,
Cost = 100,
Resource = "Gold",
SkillId = 7
},
new
{
Id = 10,
Cost = 100,
Resource = "Junk",
SkillId = 7
},
new
{
Id = 11,
Cost = 500,
Resource = "Gold",
SkillId = 8
},
new
{
Id = 12,
Cost = 500,
Resource = "Junk",
SkillId = 8
},
new
{
Id = 13,
Cost = 300,
Resource = "Wisdom",
SkillId = 8
},
new
{
Id = 14,
Cost = 300,
Resource = "Food",
SkillId = 8
});
});
modelBuilder.Entity("PetCompanion.Models.ActionGathered", b =>
{
b.HasOne("PetCompanion.Models.GameItem", "GameItem")
.WithMany()
.HasForeignKey("ItemId");
b.HasOne("PetCompanion.Models.Pet", "Pet")
.WithMany("ActionGathered")
.HasForeignKey("PetId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("GameItem");
b.Navigation("Pet");
});
modelBuilder.Entity("PetCompanion.Models.EquippedItem", b =>
{
b.HasOne("PetCompanion.Models.GameItem", "GameItem")
@@ -603,8 +788,21 @@ namespace PetCompanion.Migrations
b.Navigation("Skill");
});
modelBuilder.Entity("PetCompanion.Models.SkillRequirement", b =>
{
b.HasOne("PetCompanion.Models.Skill", "Skill")
.WithMany("SkillRequirements")
.HasForeignKey("SkillId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Skill");
});
modelBuilder.Entity("PetCompanion.Models.Pet", b =>
{
b.Navigation("ActionGathered");
b.Navigation("EquippedItemsList");
b.Navigation("Inventory")
@@ -624,6 +822,8 @@ namespace PetCompanion.Migrations
b.Navigation("Effects");
b.Navigation("PetSkills");
b.Navigation("SkillRequirements");
});
#pragma warning restore 612, 618
}

22
Models/ActionGathered.cs Normal file
View File

@@ -0,0 +1,22 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace PetCompanion.Models
{
public class ActionGathered
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
[ForeignKey("Pet")]
public string PetId { get; set; }
public string? Resource { get; set; }
[ForeignKey("GameItem")]
public int? ItemId { get; set; }
public int Amount { get; set; }
[JsonIgnore]
public virtual Pet Pet { get; set; }
public virtual GameItem? GameItem { get; set; }
}
}

View File

@@ -12,7 +12,6 @@ namespace PetCompanion.Models
public PetStats Stats { get; set; }
public Resources Resources { get; set; }
public int Level { get; set; }
public int Experience { get; set; }
public int Health { get; set; }
public int MaxHealth { get; set; }
public string UserId { get; set; }
@@ -24,12 +23,12 @@ namespace PetCompanion.Models
public PetBasicAction PetBasicAction { get; set; }
public DateTime BasicActionCooldown { get; set; }
public int SkillPoints { get; set; } = 2;
public virtual ICollection<PetSkill> Skills { get; set; } = new List<PetSkill>();
public virtual Inventory Inventory { get; set; }
public virtual ICollection<EquippedItem> EquippedItemsList { get; set; } = new List<EquippedItem>();
public virtual ICollection<ActionGathered> ActionGathered { get; set; } = new List<ActionGathered>();
[NotMapped]
public Dictionary<ItemEquipTarget, int> EquippedItems
{

View File

@@ -14,5 +14,7 @@
GATHERING_WISDOM,
GATHERING_GOLD,
GATHERING_FOOD,
EXPLORE,
BATTLE
}
}

View File

@@ -1,4 +1,5 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.Json.Serialization;
namespace PetCompanion.Models
@@ -23,16 +24,30 @@ namespace PetCompanion.Models
public string Name { get; set; }
public string Description { get; set; }
public SkillType Type { get; set; }
public int PointsCost { get; set; }
public string Icon { get; set; }
public List<int>? SkillsIdRequired { get; set; }
public virtual ICollection<SkillRequirement> SkillRequirements { get; set; }
public virtual ICollection<SkillEffect> Effects { get; set; }
[JsonIgnore]
public virtual ICollection<PetSkill> PetSkills { get; set; }
}
public class SkillRequirement
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public int SkillId { get; set; }
public string Resource { get; set; }
public int Cost { get; set; }
[JsonIgnore]
public virtual Skill Skill { get; set; }
}
public class SkillEffect
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public int Id { get; set; }
public int SkillId { get; set; }

View File

@@ -1,4 +1,6 @@
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using PetCompanion.Data;
using PetCompanion.Repositories;
using PetCompanion.Services;
@@ -12,6 +14,10 @@ namespace PetCompanion
{
var builder = WebApplication.CreateBuilder(args);
// Read Firebase configuration from environment variables
var firebaseAppId = Environment.GetEnvironmentVariable("FIREBASE_APP_ID") ??
throw new InvalidOperationException("FIREBASE_APP_ID environment variable is not set");
// Add services to the container.
builder.Services.AddControllers()
.AddJsonOptions(options =>
@@ -31,6 +37,7 @@ namespace PetCompanion
builder.Services.AddScoped<PetClassRepository>();
builder.Services.AddScoped<PetClassService>();
builder.Services.AddScoped<PetActionService>();
builder.Services.AddScoped<SkillService>();
builder.Services.AddScoped<GameItemsRepository>();
builder.Services.AddScoped<GameItemService>();
@@ -40,6 +47,10 @@ namespace PetCompanion
builder.Services.AddScoped<PetInventoryRepository>();
builder.Services.AddScoped<PetSkillService>();
builder.Services.AddScoped<PetInventoryService>();
builder.Services.AddScoped<ActionGatheredRepository>();
// Add the background service
builder.Services.AddHostedService<PetActionBackgroundService>();
// Add CORS policy
builder.Services.AddCors(options =>
@@ -52,6 +63,21 @@ namespace PetCompanion
});
});
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = $"https://securetoken.google.com/{firebaseAppId}";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = $"https://securetoken.google.com/{firebaseAppId}",
ValidateAudience = true,
ValidAudience = firebaseAppId,
ValidateLifetime = true
};
});
var app = builder.Build();
// Configure the HTTP request pipeline.
@@ -62,13 +88,15 @@ namespace PetCompanion
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
// After app builder is created
using (var scope = app.Services.CreateScope())
{
var itemService = scope.ServiceProvider.GetRequiredService<GameItemService>();
itemService.LoadItemsFromCsv("GameItemsData.csv");
itemService.LoadItemsFromCsv("game-data/GameItemsData.csv");
}
// Use CORS policy

View File

@@ -1,29 +1,39 @@
# Pet Companion
## Todo:
- [ ] Inventory system
- [ ] Skill tree system
## Todo (v1):
- [P] Inventory system
- [P] Skill tree system
- [ ] Explore system
- [ ] Battle system
- [ ] Quest system
- [ ] User login/register system
- [ ] User profile/settings system
### V1.5:
- [ ] Icons and images optimization
### V2:
- [ ] Quest system
- [ ] Market system (internal)
- [ ] Front-End: 3D pet model
- [ ] Front-End: 3D pet animations
- [ ] Front-End: 3D pet interactions
- [ ] Front-End: 3D pet environment (depending on the class)
### V3:
- [ ] Front-End: improved skill tree design
- [ ] Front-End: improved inventory design
## Inventory system
- [ ] Inventory UI
- [ ] Inventory database
- [ ] Inventory item database (items, consumables, equipment)
- [ ] Inventory item interactions (use, equip, unequip, drop)
- [ ] Inventory item stacking
- [ ] Inventory item sorting (UI)
- [x] Inventory UI
- [x] Inventory database
- [x] Inventory item database (items, consumables, equipment)
- [x] Inventory item interactions (use, equip, unequip, drop)
- [/] Inventory item stacking
- [/] Inventory item sorting (UI)
## Skill tree system
- [ ] Skill tree UI
- [ ] Skill tree database
- [ ] Skill tree interactions (learn, unlearn, upgrade)
- [ ] Skill tree requirements (level, skill points, other skills)
- [ ] Skill tree effects (TBD)
- [x] Skill tree UI
- [x] Skill tree database
- [/] Skill tree interactions (learn, unlearn, upgrade)
- [/] Skill tree requirements (level, skill points, other skills)
- [x] Skill tree effects (TBD)

View File

@@ -0,0 +1,47 @@
using PetCompanion.Data;
using PetCompanion.Models;
using Microsoft.EntityFrameworkCore;
namespace PetCompanion.Repositories
{
public class ActionGatheredRepository
{
private readonly ApplicationDbContext _context;
public ActionGatheredRepository(ApplicationDbContext context)
{
_context = context;
}
public IEnumerable<ActionGathered> GetAllActionGatheredByPetId(string petId)
{
return _context.ActionGathered
.Where(ag => ag.PetId == petId)
.Include(ag => ag.GameItem)
.ToList();
}
public ActionGathered CreateActionGathered(ActionGathered actionGathered)
{
var entry = _context.ActionGathered.Add(actionGathered);
_context.SaveChanges();
return entry.Entity;
}
public ActionGathered UpdateActionGathered(ActionGathered actionGathered)
{
var entry = _context.ActionGathered.Update(actionGathered);
_context.SaveChanges();
return entry.Entity;
}
public void DeleteAllActionGatheredByPetId(string petId)
{
var actionsToDelete = _context.ActionGathered
.Where(ag => ag.PetId == petId);
_context.ActionGathered.RemoveRange(actionsToDelete);
_context.SaveChanges();
}
}
}

View File

@@ -17,6 +17,21 @@ namespace PetCompanion.Repositories
return _context.GameItems.Find(id);
}
public IEnumerable<GameItem> GetAll()
{
return _context.GameItems;
}
public byte[] GetItemIcon(int itemId)
{
if (_context.GameItems.Find(itemId) == null)
{
throw new Exception("Item not found");
}
return File.ReadAllBytes($"game-data/item/icons/{itemId}.png");
}
public void Add(GameItem item)
{
_context.GameItems.Add(item);

View File

@@ -21,6 +21,18 @@ namespace PetCompanion.Repositories
.Include(p => p.Resources)
.Include(p => p.Inventory)
.Include(p => p.EquippedItemsList)
.Include(p => p.ActionGathered)
.ToList();
}
public IEnumerable<Pet> GetPetWithActions()
{
return context.Pets
.Where(predicate => predicate.PetGatherAction != PetActionGather.IDLE)
.Include(p => p.Stats)
.Include(p => p.Resources)
.Include(p => p.Inventory)
.Include(p => p.EquippedItemsList)
.ToList();
}
@@ -32,6 +44,7 @@ namespace PetCompanion.Repositories
.Include(p => p.Resources)
.Include(p => p.Inventory)
.Include(p => p.EquippedItemsList)
.Include(p => p.ActionGathered)
.FirstOrDefault();
}

View File

@@ -13,6 +13,22 @@ namespace PetCompanion.Repositories
_context = context;
}
public IEnumerable<Skill> GetAvailableSkills()
{
return _context.Skills
.Include(s => s.Effects)
.Include(s => s.SkillRequirements)
.ToList();
}
public Skill GetSkill(int id)
{
return _context.Skills
.Include(s => s.Effects)
.Include(s => s.SkillRequirements)
.FirstOrDefault(s => s.Id == id);
}
public IEnumerable<PetSkill> GetPetSkills(string petId)
{
return _context.PetSkills

View File

@@ -35,6 +35,14 @@ namespace PetCompanion.Services
}
}
public GameItem GetRandomItem()
{
var items = gameItemsRepository.GetAll();
var random = new Random();
var index = random.Next(items.Count());
return items.ElementAt(index);
}
public void ApplyItemEffect(Pet pet, GameItem item)
{
var effects = item.Effect.Split(';');
@@ -64,19 +72,59 @@ namespace PetCompanion.Services
switch ($"{action}_{target}")
{
case "ADD_FOOD_RESOURCES":
case "ADD_FOOD":
pet.Resources.Food += value;
break;
case "ADD_INTELLIGENCE":
pet.Stats.Intelligence += value;
pet.IncrementIntelligence(value);
break;
case "REDUCE_COOLDOWN":
pet.BasicActionCooldown = pet.BasicActionCooldown.AddMinutes(-value);
break;
case "ADD_HEALTH":
pet.Health = Math.Min(pet.Health + value, pet.MaxHealth);
break;
case "ADD_MAX_HEALTH":
case "ADD_CHARISMA":
pet.IncrementCharisma(value);
break;
case "ADD_STRENGTH":
pet.IncrementStrength(value);
break;
case "ADD_RANDOMSTAT":
var random = new Random();
var stat = random.Next(4);
switch (stat)
{
case 0: pet.IncrementStrength(value); break;
case 1: pet.IncrementIntelligence(value); break;
case 2: pet.IncrementCharisma(value); break;
case 3: pet.Health = Math.Min(pet.Health + value, pet.MaxHealth); break;
}
break;
case "RESTORE_STATS":
pet.Health = pet.MaxHealth;
pet.Stats.Intelligence = pet.Stats.MaxIntelligence;
pet.Stats.Strength = pet.Stats.MaxStrength;
pet.Stats.Charisma = pet.Stats.MaxCharisma;
break;
case "ADD_MAXHEALTH":
pet.MaxHealth += value;
break;
// Add more effect handlers as needed
case "ADD_MAXINTELLIGENCE":
pet.Stats.MaxIntelligence += value;
break;
case "ADD_MAXSTRENGTH":
pet.Stats.MaxStrength += value;
break;
case "ADD_MAXCHARISMA":
pet.Stats.MaxCharisma += value;
break;
case "ADD_MAXALLSTATS":
pet.MaxHealth += value;
pet.Stats.MaxIntelligence += value;
pet.Stats.MaxStrength += value;
pet.Stats.MaxCharisma += value;
break;
}
}
@@ -91,26 +139,28 @@ namespace PetCompanion.Services
switch ($"{action}_{target}")
{
case "ADD_MAX_HEALTH":
case "ADD_MAXHEALTH":
pet.MaxHealth -= value;
pet.Health = Math.Min(pet.Health, pet.MaxHealth);
break;
case "ADD_MAX_INTELLIGENCE":
case "ADD_MAXINTELLIGENCE":
pet.Stats.MaxIntelligence -= value;
pet.Stats.Intelligence = Math.Min(pet.Stats.Intelligence, pet.Stats.MaxIntelligence);
break;
case "ADD_MAX_STRENGTH":
case "ADD_MAXSTRENGTH":
pet.Stats.MaxStrength -= value;
pet.Stats.Strength = Math.Min(pet.Stats.Strength, pet.Stats.MaxStrength);
break;
case "ADD_MAX_CHARISMA":
case "ADD_MAXCHARISMA":
pet.Stats.MaxCharisma -= value;
pet.Stats.Charisma = Math.Min(pet.Stats.Charisma, pet.Stats.MaxCharisma);
break;
case "ADD_MAX_ALL_STATS":
case "ADD_MAXALLSTATS":
pet.MaxHealth -= value;
pet.Stats.MaxIntelligence -= value;
pet.Stats.MaxStrength -= value;
pet.Stats.MaxCharisma -= value;
pet.Health = Math.Min(pet.Health, pet.MaxHealth);
pet.Stats.Intelligence = Math.Min(pet.Stats.Intelligence, pet.Stats.MaxIntelligence);
pet.Stats.Strength = Math.Min(pet.Stats.Strength, pet.Stats.MaxStrength);
pet.Stats.Charisma = Math.Min(pet.Stats.Charisma, pet.Stats.MaxCharisma);

View File

@@ -0,0 +1,26 @@
namespace PetCompanion.Services
{
public class PetActionBackgroundService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
public PetActionBackgroundService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _serviceProvider.CreateScope())
{
var petActionService = scope.ServiceProvider.GetRequiredService<PetActionService>();
petActionService.LoopPetActions();
}
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
}
}
}
}

View File

@@ -0,0 +1,153 @@
using PetCompanion.Models;
using PetCompanion.Repositories;
namespace PetCompanion.Services
{
public class PetActionService
{
private readonly ActionGatheredRepository actionGatheredRepository;
private readonly PetRepository petRepository;
private readonly GameItemService gameItemService;
public PetActionService(ActionGatheredRepository actionGatheredRepository, GameItemService gameItemService, PetRepository petRepository)
{
this.actionGatheredRepository = actionGatheredRepository;
this.gameItemService = gameItemService;
this.petRepository = petRepository;
}
public IEnumerable<ActionGathered> GetGatheredByPet(string petId)
{
return actionGatheredRepository.GetAllActionGatheredByPetId(petId);
}
public void DeleteAllActionGatheredByPetId(string petId)
{
actionGatheredRepository.DeleteAllActionGatheredByPetId(petId);
}
public void LoopPetActions()
{
var pets = petRepository.GetPetWithActions();
foreach (var pet in pets)
{
var gatheredResources = CalculateGatheredResources(pet);
if (gatheredResources != null)
{
var gatheredResourcesDb = actionGatheredRepository.GetAllActionGatheredByPetId(pet.Id);
foreach (var resource in gatheredResources)
{
if (gatheredResourcesDb.Any(ag => ag.Resource == resource.Resource))
{
var existingResource = gatheredResourcesDb.First(ag => ag.Resource == resource.Resource);
existingResource.Amount += resource.Amount;
actionGatheredRepository.UpdateActionGathered(existingResource);
}
else
{
actionGatheredRepository.CreateActionGathered(resource);
}
}
}
}
}
public ICollection<ActionGathered>? CalculateGatheredResources(Pet pet)
{
if (pet.PetGatherAction == PetActionGather.IDLE)
return null;
var timeElapsed = (DateTime.UtcNow - pet.GatherActionSince).TotalMinutes;
var gathered = new List<ActionGathered>();
var baseRate = (timeElapsed + pet.Level) / 10; // Base rate per hour
gathered.Add(new ActionGathered
{
Resource = "Junk",
Amount = (int)(baseRate * 0.2)
});
var random = new Random();
switch (pet.PetGatherAction)
{
case PetActionGather.GATHERING_WISDOM:
gathered.Add(new ActionGathered
{
Resource = "Wisdom",
Amount = (int)(baseRate * (pet.Stats.Intelligence * 0.5))
});
break;
case PetActionGather.GATHERING_GOLD:
gathered.Add(new ActionGathered
{
Resource = "Gold",
Amount = (int)(baseRate * (pet.Stats.Charisma * 0.5))
});
break;
case PetActionGather.GATHERING_FOOD:
gathered.Add(new ActionGathered
{
Resource = "Food",
Amount = (int)(baseRate * (pet.Stats.Strength * 0.5))
});
break;
case PetActionGather.EXPLORE:
gathered.Add(new ActionGathered
{
Resource = "Wisdom",
Amount = (int)(baseRate * (pet.Stats.Strength * 0.25))
});
if (random.Next(0, 100) < 5)
{
pet.Health -= 5;
}
if (random.Next(0, 100) < 2)
{
gathered.Add(new ActionGathered
{
ItemId = gameItemService.GetRandomItem().Id,
Amount = 1
});
}
break;
case PetActionGather.BATTLE:
gathered.Add(new ActionGathered
{
Resource = "Gold",
Amount = (int)(baseRate * (pet.Stats.Strength * 0.25))
});
if (random.Next(0, 100) < 5)
{
pet.Health -= random.Next(5, 10);
}
if (random.Next(0, 100) < 10)
{
gathered.Add(new ActionGathered
{
ItemId = gameItemService.GetRandomItem().Id,
Amount = 1
});
}
break;
}
for (int i = 0; i < gathered.Count; i++)
{
gathered[i].PetId = pet.Id;
}
return gathered;
}
}
}

View File

@@ -16,32 +16,5 @@ namespace PetCompanion.Services
{
return _petClassRepository.GetAllPetClassesInfo();
}
public Resources CalculateGatheredResources(PetStats stats, int petLevel, PetActionGather action, DateTime actionSince)
{
var timeElapsed = (DateTime.UtcNow - actionSince).TotalHours;
var resources = new Resources();
if (action == PetActionGather.IDLE)
return resources;
var baseRate = timeElapsed * 0.5 + petLevel; // Base rate per hour
resources.Junk = (int)(baseRate * 2);
switch (action)
{
case PetActionGather.GATHERING_WISDOM:
resources.Wisdom = (int)(baseRate * (stats.Intelligence * 2));
break;
case PetActionGather.GATHERING_GOLD:
resources.Gold = (int)(baseRate * (stats.Charisma * 2));
break;
case PetActionGather.GATHERING_FOOD:
resources.Food = (int)(baseRate * (stats.Strength * 1.5));
break;
}
return resources;
}
}
}

View File

@@ -79,7 +79,8 @@ namespace PetCompanion.Services
// If there's already an item equipped in that slot, unequip it first
if (pet.EquippedItems.ContainsKey(gameItem.EquipTarget))
{
UnequipItem(petId, userId, gameItem.EquipTarget);
var equippedItemId = pet.EquippedItems[gameItem.EquipTarget];
UnequipItem(petId, userId, equippedItemId);
}
// Apply equipment effects
@@ -96,17 +97,18 @@ namespace PetCompanion.Services
return petRepository.UpdatePet(pet);
}
public Pet UnequipItem(string petId, string userId, ItemEquipTarget equipTarget)
public Pet UnequipItem(string petId, string userId, int itemId)
{
var pet = petRepository.GetPetById(petId, userId);
if (pet == null)
throw new Exception("Pet not found");
if (!pet.EquippedItems.ContainsKey(equipTarget))
var equipTarget = pet.EquippedItems.FirstOrDefault(kvp => kvp.Value == itemId).Key;
if (equipTarget == ItemEquipTarget.None)
throw new Exception("No item equipped in that slot");
var equippedItemId = pet.EquippedItems[equipTarget];
var equippedItem = gameItemsRepository.GetById(equippedItemId);
var equippedItem = gameItemsRepository.GetById(itemId);
if (equippedItem != null)
{
@@ -114,7 +116,7 @@ namespace PetCompanion.Services
gameItemService.RemoveItemEffect(pet, equippedItem);
// Add item back to inventory
pet.Inventory.Items.Add(equippedItemId);
pet.Inventory.Items.Add(itemId);
}
pet.EquippedItems.Remove(equipTarget);
@@ -144,6 +146,12 @@ namespace PetCompanion.Services
if (gameItem == null)
throw new Exception("Item not found");
if (pet == null)
throw new Exception("Pet not found");
if (pet.Inventory.Items.Count + quantity > pet.Inventory.Capacity)
throw new Exception("Not enough space in inventory");
for (int i = 0; i < quantity; i++)
{
pet.Inventory.Items.Add(itemId);

View File

@@ -1,4 +1,5 @@
using PetCompanion.Models;
using Microsoft.EntityFrameworkCore.Query;
using PetCompanion.Models;
using PetCompanion.Repositories;
namespace PetCompanion.Services
@@ -10,39 +11,41 @@ namespace PetCompanion.Services
private readonly GameItemService gameItemService;
private readonly GameItemsRepository gameItemsRepository;
private readonly PetInventoryService petInventoryService;
private readonly PetActionService petActionService;
public PetService(
PetRepository petRepository,
PetClassService petClassService,
GameItemService gameItemService,
GameItemsRepository gameItemsRepository,
PetInventoryService petInventoryService)
PetInventoryService petInventoryService,
PetActionService petActionService)
{
this.petRepository = petRepository;
this.petClassService = petClassService;
this.gameItemService = gameItemService;
this.gameItemsRepository = gameItemsRepository;
this.petInventoryService = petInventoryService;
this.petActionService = petActionService;
}
public IEnumerable<Pet> GetAllPets(Guid userId)
public IEnumerable<Pet> GetAllPets(string userId)
{
return petRepository.GetPetsByUserId(userId.ToString());
return petRepository.GetPetsByUserId(userId);
}
public Pet CreatePet(Guid userId, PetCreationRequest petRequest)
public Pet CreatePet(string userId, PetCreationRequest petRequest)
{
var petId = Guid.NewGuid().ToString();
var pet = new Pet
{
Id = petId,
UserId = userId.ToString(),
UserId = userId,
Name = petRequest.Name,
Class = petRequest.Class,
Health = 100,
MaxHealth = 100,
Level = 1,
Experience = 0,
Stats = PetStats.BuildFromClass(petRequest.Class),
Resources = new Resources(),
GatherActionSince = DateTime.UtcNow,
@@ -124,7 +127,7 @@ namespace PetCompanion.Services
}
}
public Resources GetGatheredResources(string petId, string userId)
public IEnumerable<ActionGathered> GetGatheredResources(string petId, string userId)
{
var pet = petRepository.GetPetById(petId, userId);
@@ -133,10 +136,10 @@ namespace PetCompanion.Services
throw new Exception("Pet not found");
}
return petClassService.CalculateGatheredResources(pet.Stats, pet.Level, pet.PetGatherAction, pet.GatherActionSince);
return petActionService.GetGatheredByPet(petId);
}
public Pet UpdatePetResources(string petId, string userId)
public Pet CollectPetGathered(string petId, string userId)
{
var pet = petRepository.GetPetById(petId, userId);
if (pet == null)
@@ -144,15 +147,43 @@ namespace PetCompanion.Services
throw new Exception("Pet not found");
}
var gatheredResources = petClassService.CalculateGatheredResources(pet.Stats, pet.Level, pet.PetGatherAction, pet.GatherActionSince);
var petGathered = petActionService.GetGatheredByPet(petId);
pet.Resources.Wisdom += gatheredResources.Wisdom;
pet.Resources.Gold += gatheredResources.Gold;
pet.Resources.Food += gatheredResources.Food;
pet.Resources.Junk += gatheredResources.Junk;
pet.GatherActionSince = DateTime.UtcNow;
if (petGathered == null)
{
throw new Exception("No resources to collect");
}
return petRepository.UpdatePetResources(pet);
foreach (var resource in petGathered)
{
if (resource.Resource != null && resource.Resource != string.Empty)
{
switch (resource.Resource)
{
case "Junk":
pet.Resources.Junk += resource.Amount;
break;
case "Food":
pet.Resources.Food += resource.Amount;
break;
case "Gold":
pet.Resources.Gold += resource.Amount;
break;
case "Wisdom":
pet.Resources.Wisdom += resource.Amount;
break;
}
}
else if (resource.ItemId != null && resource.ItemId > 0)
{
petInventoryService.AddItemToPet(petId, userId, resource.ItemId ?? 1, resource.Amount);
}
}
var updatedPet = petRepository.UpdatePet(pet);
petActionService.DeleteAllActionGatheredByPetId(petId);
return updatedPet;
}
public Pet GetPet(string petId, string userId)

View File

@@ -23,14 +23,28 @@ namespace PetCompanion.Services
return _petSkillRepository.GetPetSkills(petId);
}
public PetSkill AllocateSkillPoint(string petId, string userId, int skillId)
public PetSkill UpgradeSkill(string petId, string userId, int skillId)
{
var pet = _petRepository.GetPetById(petId, userId);
if (pet == null)
throw new Exception("Pet not found");
if (pet.SkillPoints <= 0)
throw new Exception("No skill points available");
var skill = _petSkillRepository.GetSkill(skillId);
if (skill == null)
throw new Exception("Skill not found");
foreach (var req in skill.SkillRequirements)
{
if (req.Resource.ToLower() == "wisdom" && pet.Resources.Wisdom < req.Cost)
throw new Exception("Insufficient resources");
if (req.Resource.ToLower() == "food" && pet.Resources.Food < req.Cost)
throw new Exception("Insufficient resources");
if (req.Resource.ToLower() == "gold" && pet.Resources.Gold < req.Cost)
throw new Exception("Insufficient resources");
if (req.Resource.ToLower() == "junk" && pet.Resources.Junk < req.Cost)
throw new Exception("Insufficient resources");
}
var skills = _petSkillRepository.GetPetSkills(petId);
var existingSkill = skills.FirstOrDefault(s => s.SkillId == skillId);
@@ -45,6 +59,11 @@ namespace PetCompanion.Services
}
else
{
if (!skill.SkillsIdRequired?.TrueForAll(ni => pet.Skills.Any(s => s.SkillId == ni)) ?? false)
{
throw new Exception("Missing required skill");
}
existingSkill = new PetSkill
{
PetId = petId,
@@ -54,7 +73,14 @@ namespace PetCompanion.Services
_petSkillRepository.SavePetSkill(existingSkill);
}
pet.SkillPoints--;
foreach (var req in skill.SkillRequirements)
{
if (req.Resource.ToLower() == "wisdom") pet.Resources.Wisdom -= req.Cost;
if (req.Resource.ToLower() == "food") pet.Resources.Food -= req.Cost;
if (req.Resource.ToLower() == "gold") pet.Resources.Gold -= req.Cost;
if (req.Resource.ToLower() == "junk") pet.Resources.Junk -= req.Cost;
}
_petRepository.UpdatePet(pet);
return existingSkill;

View File

@@ -1,84 +1,24 @@
using PetCompanion.Models;
using PetCompanion.Data;
using Microsoft.EntityFrameworkCore;
using PetCompanion.Repositories;
namespace PetCompanion.Services
{
public class SkillService
{
private readonly ApplicationDbContext _context;
private readonly PetRepository _petRepository;
private readonly PetSkillRepository _petSkillRepository;
public SkillService(
ApplicationDbContext context,
PetRepository petRepository,
PetSkillRepository petSkillRepository)
{
_context = context;
_petRepository = petRepository;
_petSkillRepository = petSkillRepository;
}
public PetSkill AllocateSkillPoint(string petId, string userId, int skillId)
{
var pet = _context.Pets
.Include(p => p.Skills)
.FirstOrDefault(p => p.Id == petId && p.UserId == userId);
if (pet == null)
throw new Exception("Pet not found");
if (pet.SkillPoints <= 0)
throw new Exception("No skill points available");
var skill = _context.Skills
.Include(s => s.Effects)
.FirstOrDefault(s => s.Id == skillId);
if (skill == null)
throw new Exception("Skill not found");
var existingSkill = pet.Skills.FirstOrDefault(ps => ps.SkillId == skillId);
if (existingSkill != null)
{
if (existingSkill.CurrentTier == SkillTier.III)
throw new Exception("Skill already at maximum tier");
existingSkill.CurrentTier++;
var effect = skill.Effects.FirstOrDefault(e => e.Tier == existingSkill.CurrentTier);
if (effect != null)
effect.PetSkillUpgrade(ref pet);
_petSkillRepository.SavePetSkill(existingSkill);
}
else
{
var newSkill = new PetSkill
{
PetId = petId,
SkillId = skillId,
CurrentTier = SkillTier.I
};
_petSkillRepository.SavePetSkill(newSkill);
var effect = skill.Effects.FirstOrDefault(e => e.Tier == SkillTier.I);
if (effect != null)
effect.PetSkillUpgrade(ref pet);
}
pet.SkillPoints--;
_context.SaveChanges();
return _petSkillRepository.GetPetSkills(petId).First(ps => ps.SkillId == skillId);
}
public IEnumerable<Skill> GetAvailableSkills()
{
return _context.Skills
.Include(s => s.Effects)
.ToList();
return _petSkillRepository.GetAvailableSkills();
}
}
}

View File

@@ -7,6 +7,6 @@
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Data Source=petcompanion.db"
"DefaultConnection": "Data Source=game-data/petcompanion.db"
}
}

View File

@@ -12,6 +12,7 @@
<ItemGroup>
<PackageReference Include="CsvHelper" Version="33.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.13" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.1">
<PrivateAssets>all</PrivateAssets>