SES-158 Added function to send message to player #83

Merged
s426128 merged 4 commits from SES-158 into dev 2021-01-21 17:51:37 +01:00
58 changed files with 60169 additions and 11 deletions
Showing only changes of commit 60895fd395 - Show all commits

View File

@ -42,6 +42,8 @@ namespace SessionCompanion.Database
public virtual DbSet<GameAction> GameActions { get; set; }
public virtual DbSet<LegendaryAction> LegendaryActions { get; set; }
public virtual DbSet<SpecialAbility> SpecialAbilities { get; set; }
public virtual DbSet<Shopkeeper> Shopkeepers { get; set; }
public virtual DbSet<ShopkeeperItem> ShopkeeperItems { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
@ -136,7 +138,6 @@ namespace SessionCompanion.Database
SpecialAbilitiesList = specAbilities;
return specAbilities;
}
protected IEnumerable<GameAction> SeedActions()
{
const string file = "../SessionCompanion.Database/JsonData/monsters.json";
@ -164,7 +165,6 @@ namespace SessionCompanion.Database
GameActionsList = gameActions;
return gameActions;
}
protected IEnumerable<LegendaryAction> SeedLegendaryActions()
{
const string file = "../SessionCompanion.Database/JsonData/monsters.json";
@ -192,7 +192,6 @@ namespace SessionCompanion.Database
LegendaryActionsList = legendaryActions;
return legendaryActions;
}
protected IEnumerable<Monster> SeedMonster()
{
const string file = "../SessionCompanion.Database/JsonData/monsters.json";
@ -206,7 +205,6 @@ namespace SessionCompanion.Database
}
return monsters;
}
protected IEnumerable<MonsterSpecialAbility> SeedMonsterSpecialAbilities()
{
const string file = "../SessionCompanion.Database/JsonData/monsters.json";
@ -231,7 +229,6 @@ namespace SessionCompanion.Database
}
return monsterSpecialAbilities;
}
protected IEnumerable<MonsterAction> SeedMonsterActions()
{
const string file = "../SessionCompanion.Database/JsonData/monsters.json";
@ -256,7 +253,6 @@ namespace SessionCompanion.Database
}
return monsterActions;
}
protected IEnumerable<MonsterLegendaryAction> SeedMonsterLegendaryActions()
{
const string file = "../SessionCompanion.Database/JsonData/monsters.json";
@ -314,6 +310,8 @@ namespace SessionCompanion.Database
builder.Entity<MonsterSpecialAbility>().HasData(SeedMonsterSpecialAbilities());
builder.Entity<MonsterAction>().HasData(SeedMonsterActions());
builder.Entity<MonsterLegendaryAction>().HasData(SeedMonsterLegendaryActions());
builder.Entity<Shopkeeper>().HasData(SeedData.SeedSchopkeepers());
builder.Entity<ShopkeeperItem>().HasData(SeedData.SeedShopkeeperItems());
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,123 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace SessionCompanion.Database.Migrations
{
public partial class shopkepe : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Shopkeepers",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
Name = table.Column<string>(type: "nvarchar(max)", nullable: true),
IsAvailable = table.Column<bool>(type: "bit", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Shopkeepers", x => x.Id);
});
migrationBuilder.CreateTable(
name: "ShopkeeperItems",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("SqlServer:Identity", "1, 1"),
ShopkeeperId = table.Column<int>(type: "int", nullable: false),
ArmorId = table.Column<int>(type: "int", nullable: true),
WeaponId = table.Column<int>(type: "int", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_ShopkeeperItems", x => x.Id);
table.ForeignKey(
name: "FK_ShopkeeperItems_Armors_ArmorId",
column: x => x.ArmorId,
principalTable: "Armors",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_ShopkeeperItems_Shopkeepers_ShopkeeperId",
column: x => x.ShopkeeperId,
principalTable: "Shopkeepers",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ShopkeeperItems_Weapons_WeaponId",
column: x => x.WeaponId,
principalTable: "Weapons",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.InsertData(
table: "Shopkeepers",
columns: new[] { "Id", "IsAvailable", "Name" },
values: new object[,]
{
{ 1, true, "Swędzioch" },
{ 2, false, "Lucius Prawowity" },
{ 3, true, "Bohr Twarda Zbroja" },
{ 4, false, "Skwarczyk Podobny" },
{ 5, true, "Zielony spod Gruszkowego Lasu" },
{ 6, false, "Zmarniały" }
});
migrationBuilder.InsertData(
table: "ShopkeeperItems",
columns: new[] { "Id", "ArmorId", "ShopkeeperId", "WeaponId" },
values: new object[,]
{
{ 1, 2, 1, null },
{ 20, 13, 6, null },
{ 19, 2, 6, null },
{ 18, 7, 5, null },
{ 17, 9, 5, null },
{ 16, 6, 5, null },
{ 15, 11, 4, null },
{ 14, null, 4, 14 },
{ 13, null, 4, 24 },
{ 12, null, 4, 1 },
{ 11, null, 3, 7 },
{ 10, 8, 3, null },
{ 9, 1, 3, null },
{ 8, null, 2, 14 },
{ 7, null, 2, 25 },
{ 6, null, 2, 3 },
{ 5, 12, 1, null },
{ 4, null, 1, 17 },
{ 3, 10, 1, null },
{ 2, null, 1, 33 },
{ 21, 10, 6, null },
{ 22, null, 6, 37 }
});
migrationBuilder.CreateIndex(
name: "IX_ShopkeeperItems_ArmorId",
table: "ShopkeeperItems",
column: "ArmorId");
migrationBuilder.CreateIndex(
name: "IX_ShopkeeperItems_ShopkeeperId",
table: "ShopkeeperItems",
column: "ShopkeeperId");
migrationBuilder.CreateIndex(
name: "IX_ShopkeeperItems_WeaponId",
table: "ShopkeeperItems",
column: "WeaponId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ShopkeeperItems");
migrationBuilder.DropTable(
name: "Shopkeepers");
}
}
}

View File

@ -0,0 +1,178 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace SessionCompanion.Database.Migrations
{
public partial class shopkeepersitems : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "Amount",
table: "ShopkeeperItems",
type: "int",
nullable: false,
defaultValue: 0);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 1,
column: "Amount",
value: 3);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 2,
column: "Amount",
value: 5);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 3,
column: "Amount",
value: 20);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 4,
column: "Amount",
value: 34);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 5,
column: "Amount",
value: 12);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 6,
column: "Amount",
value: 48);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 7,
column: "Amount",
value: 25);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 8,
column: "Amount",
value: 34);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 9,
column: "Amount",
value: 44);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 10,
column: "Amount",
value: 2);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 11,
column: "Amount",
value: 21);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 12,
column: "Amount",
value: 36);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 13,
column: "Amount",
value: 5);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 14,
column: "Amount",
value: 13);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 15,
column: "Amount",
value: 19);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 16,
column: "Amount",
value: 17);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 17,
column: "Amount",
value: 3);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 18,
column: "Amount",
value: 1);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 19,
column: "Amount",
value: 6);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 20,
column: "Amount",
value: 9);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 21,
column: "Amount",
value: 12);
migrationBuilder.UpdateData(
table: "ShopkeeperItems",
keyColumn: "Id",
keyValue: 22,
column: "Amount",
value: 6);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Amount",
table: "ShopkeeperItems");
}
}
}

View File

@ -21521,6 +21521,248 @@ namespace SessionCompanion.Database.Migrations
});
});
modelBuilder.Entity("SessionCompanion.Database.Tables.Shopkeeper", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.UseIdentityColumn();
b.Property<bool>("IsAvailable")
.HasColumnType("bit");
b.Property<string>("Name")
.HasColumnType("nvarchar(max)");
b.HasKey("Id");
b.ToTable("Shopkeepers");
b.HasData(
new
{
Id = 1,
IsAvailable = true,
Name = "Swędzioch"
},
new
{
Id = 2,
IsAvailable = false,
Name = "Lucius Prawowity"
},
new
{
Id = 3,
IsAvailable = true,
Name = "Bohr Twarda Zbroja"
},
new
{
Id = 4,
IsAvailable = false,
Name = "Skwarczyk Podobny"
},
new
{
Id = 5,
IsAvailable = true,
Name = "Zielony spod Gruszkowego Lasu"
},
new
{
Id = 6,
IsAvailable = false,
Name = "Zmarniały"
});
});
modelBuilder.Entity("SessionCompanion.Database.Tables.ShopkeeperItem", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int")
.UseIdentityColumn();
b.Property<int>("Amount")
.HasColumnType("int");
b.Property<int?>("ArmorId")
.HasColumnType("int");
b.Property<int>("ShopkeeperId")
.HasColumnType("int");
b.Property<int?>("WeaponId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("ArmorId");
b.HasIndex("ShopkeeperId");
b.HasIndex("WeaponId");
b.ToTable("ShopkeeperItems");
b.HasData(
new
{
Id = 1,
Amount = 3,
ArmorId = 2,
ShopkeeperId = 1
},
new
{
Id = 2,
Amount = 5,
ShopkeeperId = 1,
WeaponId = 33
},
new
{
Id = 3,
Amount = 20,
ArmorId = 10,
ShopkeeperId = 1
},
new
{
Id = 4,
Amount = 34,
ShopkeeperId = 1,
WeaponId = 17
},
new
{
Id = 5,
Amount = 12,
ArmorId = 12,
ShopkeeperId = 1
},
new
{
Id = 6,
Amount = 48,
ShopkeeperId = 2,
WeaponId = 3
},
new
{
Id = 7,
Amount = 25,
ShopkeeperId = 2,
WeaponId = 25
},
new
{
Id = 8,
Amount = 34,
ShopkeeperId = 2,
WeaponId = 14
},
new
{
Id = 9,
Amount = 44,
ArmorId = 1,
ShopkeeperId = 3
},
new
{
Id = 10,
Amount = 2,
ArmorId = 8,
ShopkeeperId = 3
},
new
{
Id = 11,
Amount = 21,
ShopkeeperId = 3,
WeaponId = 7
},
new
{
Id = 12,
Amount = 36,
ShopkeeperId = 4,
WeaponId = 1
},
new
{
Id = 13,
Amount = 5,
ShopkeeperId = 4,
WeaponId = 24
},
new
{
Id = 14,
Amount = 13,
ShopkeeperId = 4,
WeaponId = 14
},
new
{
Id = 15,
Amount = 19,
ArmorId = 11,
ShopkeeperId = 4
},
new
{
Id = 16,
Amount = 17,
ArmorId = 6,
ShopkeeperId = 5
},
new
{
Id = 17,
Amount = 3,
ArmorId = 9,
ShopkeeperId = 5
},
new
{
Id = 18,
Amount = 1,
ArmorId = 7,
ShopkeeperId = 5
},
new
{
Id = 19,
Amount = 6,
ArmorId = 2,
ShopkeeperId = 6
},
new
{
Id = 20,
Amount = 9,
ArmorId = 13,
ShopkeeperId = 6
},
new
{
Id = 21,
Amount = 12,
ArmorId = 10,
ShopkeeperId = 6
},
new
{
Id = 22,
Amount = 6,
ShopkeeperId = 6,
WeaponId = 37
});
});
modelBuilder.Entity("SessionCompanion.Database.Tables.SpecialAbility", b =>
{
b.Property<int>("Id")
@ -28921,6 +29163,29 @@ namespace SessionCompanion.Database.Migrations
b.Navigation("SpecialAbility");
});
modelBuilder.Entity("SessionCompanion.Database.Tables.ShopkeeperItem", b =>
{
b.HasOne("SessionCompanion.Database.Tables.Armor", "Armor")
.WithMany()
.HasForeignKey("ArmorId");
b.HasOne("SessionCompanion.Database.Tables.Shopkeeper", "Shopkeeper")
.WithMany("ShopkeeperItems")
.HasForeignKey("ShopkeeperId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SessionCompanion.Database.Tables.Weapon", "Weapon")
.WithMany()
.HasForeignKey("WeaponId");
b.Navigation("Armor");
b.Navigation("Shopkeeper");
b.Navigation("Weapon");
});
modelBuilder.Entity("SessionCompanion.Database.Tables.Statistics", b =>
{
b.HasOne("SessionCompanion.Database.Tables.Character", "Character")
@ -29022,6 +29287,11 @@ namespace SessionCompanion.Database.Migrations
b.Navigation("Biography");
});
modelBuilder.Entity("SessionCompanion.Database.Tables.Shopkeeper", b =>
{
b.Navigation("ShopkeeperItems");
});
modelBuilder.Entity("SessionCompanion.Database.Tables.SpecialAbility", b =>
{
b.Navigation("MonsterSpecialAbilities");

View File

@ -0,0 +1,16 @@
using SessionCompanion.Database.Repositories.Base;
using SessionCompanion.Database.Tables;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SessionCompanion.Database.Repositories
{
public class ShopkeeperItemRepository : Repository<ShopkeeperItem>, IRepository<ShopkeeperItem>
{
public ShopkeeperItemRepository(ApplicationDbContext _dbContext) : base(_dbContext)
{ }
}
}

View File

@ -0,0 +1,16 @@
using SessionCompanion.Database.Repositories.Base;
using SessionCompanion.Database.Tables;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SessionCompanion.Database.Repositories
{
public class ShopkeeperRepository : Repository<Shopkeeper>, IRepository<Shopkeeper>
{
public ShopkeeperRepository(ApplicationDbContext _dbContext) : base(_dbContext)
{ }
}
}

View File

@ -843,5 +843,209 @@ namespace SessionCompanion.Database
};
return characterSpellSlots;
}
static public List<Shopkeeper> SeedSchopkeepers()
{
List<Shopkeeper> shopkeepers = new List<Shopkeeper>()
{
new Shopkeeper
{
Id = 1,
Name = "Swędzioch",
IsAvailable = true
},
new Shopkeeper
{
Id = 2,
Name = "Lucius Prawowity",
IsAvailable = false
},
new Shopkeeper
{
Id = 3,
Name = "Bohr Twarda Zbroja",
IsAvailable = true
},
new Shopkeeper
{
Id = 4,
Name = "Skwarczyk Podobny",
IsAvailable = false
},
new Shopkeeper
{
Id = 5,
Name = "Zielony spod Gruszkowego Lasu",
IsAvailable = true
},
new Shopkeeper
{
Id = 6,
Name = "Zmarniały",
IsAvailable = false
}
};
return shopkeepers;
}
static public List<ShopkeeperItem> SeedShopkeeperItems()
{
List<ShopkeeperItem> shopkeeperItems = new List<ShopkeeperItem>()
{
new ShopkeeperItem
{
Id = 1,
ShopkeeperId = 1,
ArmorId = 2,
Amount = 3
},
new ShopkeeperItem
{
Id = 2,
ShopkeeperId = 1,
WeaponId = 33,
Amount = 5
},
new ShopkeeperItem
{
Id = 3,
ShopkeeperId = 1,
ArmorId = 10,
Amount = 20
},
new ShopkeeperItem
{
Id = 4,
ShopkeeperId = 1,
WeaponId = 17,
Amount = 34
},
new ShopkeeperItem
{
Id = 5,
ShopkeeperId = 1,
ArmorId = 12,
Amount = 12
},
new ShopkeeperItem
{
Id = 6,
ShopkeeperId = 2,
WeaponId = 3,
Amount = 48
},
new ShopkeeperItem
{
Id = 7,
ShopkeeperId = 2,
WeaponId = 25,
Amount = 25
},
new ShopkeeperItem
{
Id = 8,
ShopkeeperId = 2,
WeaponId = 14,
Amount = 34
},
new ShopkeeperItem
{
Id = 9,
ShopkeeperId = 3,
ArmorId = 1,
Amount = 44
},
new ShopkeeperItem
{
Id = 10,
ShopkeeperId = 3,
ArmorId = 8,
Amount = 2
},
new ShopkeeperItem
{
Id = 11,
ShopkeeperId = 3,
WeaponId = 7,
Amount = 21
},
new ShopkeeperItem
{
Id = 12,
ShopkeeperId = 4,
WeaponId = 1,
Amount = 36
},
new ShopkeeperItem
{
Id = 13,
ShopkeeperId = 4,
WeaponId = 24,
Amount = 5
},
new ShopkeeperItem
{
Id = 14,
ShopkeeperId = 4,
WeaponId = 14,
Amount = 13
},
new ShopkeeperItem
{
Id = 15,
ShopkeeperId = 4,
ArmorId = 11,
Amount = 19
},
new ShopkeeperItem
{
Id = 16,
ShopkeeperId = 5,
ArmorId = 6,
Amount = 17
},
new ShopkeeperItem
{
Id = 17,
ShopkeeperId = 5,
ArmorId = 9,
Amount = 3
},
new ShopkeeperItem
{
Id = 18,
ShopkeeperId = 5,
ArmorId = 7,
Amount = 1
},
new ShopkeeperItem
{
Id = 19,
ShopkeeperId = 6,
ArmorId = 2,
Amount = 6
},
new ShopkeeperItem
{
Id = 20,
ShopkeeperId = 6,
ArmorId = 13,
Amount = 9
},
new ShopkeeperItem
{
Id = 21,
ShopkeeperId = 6,
ArmorId = 10,
Amount = 12
},
new ShopkeeperItem
{
Id = 22,
ShopkeeperId = 6,
WeaponId = 37,
Amount = 6
}
};
return shopkeeperItems;
}
}
}

View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SessionCompanion.Database.Tables
{
public class Shopkeeper : BaseEntity
{
public string Name { get; set; }
public bool IsAvailable { get; set; }
public virtual ICollection<ShopkeeperItem> ShopkeeperItems { get; set; }
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SessionCompanion.Database.Tables
{
public class ShopkeeperItem : BaseEntity
{
[ForeignKey(nameof(Shopkeeper))]
public int ShopkeeperId { get; set; }
public virtual Shopkeeper Shopkeeper { get; set; }
[ForeignKey(nameof(Armor))]
public int? ArmorId { get; set; }
public virtual Armor Armor { get; set; }
[ForeignKey(nameof(Weapon))]
public int? WeaponId { get; set; }
public virtual Weapon Weapon { get; set; }
public int Amount { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using SessionCompanion.Database.Tables;
using SessionCompanion.Services.Base;
using SessionCompanion.ViewModels.ShopkeeperItemsViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SessionCompanion.Services.Interfaces
{
public interface IShopkeeperItemService : IServiceBase<ShopkeeperItemViewModel, ShopkeeperItem>
{
}
}

View File

@ -0,0 +1,16 @@
using SessionCompanion.Database.Tables;
using SessionCompanion.Services.Base;
using SessionCompanion.ViewModels.ShopkeeperViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SessionCompanion.Services.Interfaces
{
public interface IShopkeeperService : IServiceBase<ShopkeeperViewModel, Shopkeeper>
{
}
}

View File

@ -0,0 +1,19 @@
using AutoMapper;
using SessionCompanion.Database.Tables;
using SessionCompanion.ViewModels.ShopkeeperItemsViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SessionCompanion.Services.Profiles
{
public class ShopkeeperItemsProfile : Profile
{
public ShopkeeperItemsProfile()
{
CreateMap<ShopkeeperItemViewModel, ShopkeeperItem>().ReverseMap();
}
}
}

View File

@ -0,0 +1,19 @@
using AutoMapper;
using SessionCompanion.Database.Tables;
using SessionCompanion.ViewModels.ShopkeeperViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SessionCompanion.Services.Profiles
{
public class ShopkeeperProfile : Profile
{
public ShopkeeperProfile()
{
CreateMap<ShopkeeperViewModel, Shopkeeper>().ReverseMap();
}
}
}

View File

@ -0,0 +1,20 @@
using AutoMapper;
using SessionCompanion.Database.Repositories.Base;
using SessionCompanion.Database.Tables;
using SessionCompanion.Services.Base;
using SessionCompanion.Services.Interfaces;
using SessionCompanion.ViewModels.ShopkeeperItemsViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SessionCompanion.Services.Services
{
public class ShopkeeperItemService : ServiceBase<ShopkeeperItemViewModel, ShopkeeperItem>, IShopkeeperItemService
{
public ShopkeeperItemService(IMapper mapper, IRepository<ShopkeeperItem> repository) : base(mapper, repository)
{ }
}
}

View File

@ -0,0 +1,20 @@
using AutoMapper;
using SessionCompanion.Database.Repositories.Base;
using SessionCompanion.Database.Tables;
using SessionCompanion.Services.Base;
using SessionCompanion.Services.Interfaces;
using SessionCompanion.ViewModels.ShopkeeperViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SessionCompanion.Services.Services
{
public class ShopkeeperService : ServiceBase<ShopkeeperViewModel, Shopkeeper>, IShopkeeperService
{
public ShopkeeperService(IMapper mapper, IRepository<Shopkeeper> repository) : base(mapper, repository)
{ }
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SessionCompanion.ViewModels.ShopkeeperItemsViewModels
{
public class ShopkeeperItemViewModel
{
/// <summary>
/// Id Sprzedawcy
/// </summary>
public int ShopkeeperId { get; set; }
/// <summary>
/// Id zbroi
/// </summary>
public int? ArmorId { get; set; }
/// <summary>
/// Id broni
/// </summary>
public int? WeaponId { get; set; }
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SessionCompanion.ViewModels.ShopkeeperViewModels
{
public class ShopkeeperViewModel
{
/// <summary>
/// Id sprzedawcy
/// </summary>
public int Id { get; set; }
/// <summary>
/// Imie sprzedawcy
/// </summary>
public string Name { get; set; }
/// <summary>
/// Dostępność sprzedawcy
/// </summary>
public bool IsAvailable { get; set; }
}
}

View File

@ -55,6 +55,9 @@ import { SendMessageActionComponent } from './components/game-master-character-a
import { DynamicModule } from 'ng-dynamic-component';
import { SnackbarComponent } from './shared/snackbar/snackbar.component';
import { MessageDialogComponent } from './shared/message-dialog/message-dialog.component';
import { GameMasterTurntrackerComponent } from './components/game-master-turntracker/game-master-turntracker.component';
import { DragDropModule } from '@angular/cdk/drag-drop';
import { ChooseMonsterDialogComponent } from './components/choose-monster-dialog/choose-monster-dialog.component';
@NgModule({
declarations: [
@ -78,6 +81,8 @@ import { MessageDialogComponent } from './shared/message-dialog/message-dialog.c
SendMessageActionComponent,
SnackbarComponent,
MessageDialogComponent,
GameMasterTurntrackerComponent,
ChooseMonsterDialogComponent,
],
imports: [
BrowserModule.withServerTransition({ appId: 'ng-cli-universal' }),
@ -108,6 +113,7 @@ import { MessageDialogComponent } from './shared/message-dialog/message-dialog.c
MatRadioModule,
DynamicModule,
MatSnackBarModule,
DragDropModule,
],
providers: [
UserService,
@ -132,6 +138,8 @@ import { MessageDialogComponent } from './shared/message-dialog/message-dialog.c
SendMessageActionComponent,
SnackbarComponent,
MessageDialogComponent,
GameMasterTurntrackerComponent,
ChooseMonsterDialogComponent,
],
})
export class AppModule {}

View File

@ -0,0 +1,41 @@
table {
background-color: initial;
}
mat-paginator {
background-color: initial;
color: white;
}
::ng-deep .mat-select-arrow {
color: whitesmoke;
}
::ng-deep .mat-select-value {
color: white;
}
.mat-sort-header-container {
color: whitesmoke !important;
}
.mat-form-field {
font-size: 14px;
width: 100%;
}
td,
th {
color: whitesmoke;
}
::ng-deep .mat-dialog-container {
background-color: #4a5867;
color: whitesmoke;
box-shadow: 0 11px 15px -7px rgba(0, 0, 0, 0.2),
0 24px 38px 3px rgba(0, 0, 0, 0.14), 0px 5px 20px 4px #d8d8d8;
}
::ng-deep .mat-checkbox-checked.mat-accent .mat-checkbox-background {
background-color: #df7c0f;
}

View File

@ -0,0 +1,52 @@
<h1 mat-dialog-title>Choose Monsters</h1>
<div mat-dialog-content>
<mat-form-field>
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" placeholder="Ex. Dragon" #input>
</mat-form-field>
<div class="mat-elevation-z8">
<table mat-table [dataSource]="dataSource" matSort class="w-100">
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef> Select Monsters
</th>
<td mat-cell *matCellDef="let row">
<mat-checkbox (click)="$event.stopPropagation()"
(change)="$event ? selection.toggle(row) : null"
[checked]="selection.isSelected(row)">
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
<td mat-cell *matCellDef="let row"> {{row.name}} </td>
</ng-container>
<ng-container matColumnDef="armorClass">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Armor Class </th>
<td mat-cell *matCellDef="let row"> {{row.armorClass}} </td>
</ng-container>
<ng-container matColumnDef="hitPoints">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Hit Points </th>
<td mat-cell *matCellDef="let row"> {{row.hitPoints}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4">No data matching the filter "{{input.value}}"</td>
</tr>
</table>
<mat-paginator [pageSizeOptions]="[5, 10, 25, 100]"></mat-paginator>
</div>
</div>
<div mat-dialog-actions>
<button mat-button (click)="CloseDialog()">Close</button>
<button mat-button (click)="AddMonsters()" cdkFocusInitial>Add monsters</button>
</div>

View File

@ -0,0 +1,67 @@
import { Component, Inject, OnInit, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { MonsterViewModel } from '../../../types/viewmodels/monster-viewmodels/MonsterViewModel';
import { MonsterService } from '../../../services/monster.service';
import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort';
import { first } from 'rxjs/operators';
import { MatTableDataSource } from '@angular/material/table';
import { ErrorResponse } from '../../../types/ErrorResponse';
import { HttpErrorResponse } from '@angular/common/http';
import { SelectionModel } from '@angular/cdk/collections';
@Component({
selector: 'app-choose-monster-dialog',
templateUrl: './choose-monster-dialog.component.html',
styleUrls: ['./choose-monster-dialog.component.css'],
})
export class ChooseMonsterDialogComponent implements OnInit {
displayedColumns: string[] = ['select', 'name', 'armorClass', 'hitPoints'];
dataSource: MatTableDataSource<MonsterViewModel>;
selection = new SelectionModel<MonsterViewModel>(true, []);
@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;
@ViewChild(MatSort, { static: true }) sort: MatSort;
constructor(
public dialogRef: MatDialogRef<ChooseMonsterDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: any,
private monsterService: MonsterService
) {}
ngOnInit() {
this.monsterService
.GetAllMonsters()
.pipe(first())
.subscribe(
(result) => {
this.dataSource = new MatTableDataSource(result);
this.dataSource.sort = this.sort;
this.dataSource.paginator = this.paginator;
},
(error: ErrorResponse | HttpErrorResponse) => {
if (error instanceof HttpErrorResponse) {
error = error.error as ErrorResponse;
}
console.error(error.message);
}
);
}
AddMonsters() {
this.dialogRef.close(this.selection.selected);
}
CloseDialog() {
this.dialogRef.close();
}
applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
if (this.dataSource.paginator) {
this.dataSource.paginator.firstPage();
}
}
}

View File

@ -22,6 +22,7 @@ import { AppState } from '../../store/models/app-state.model';
import { Router } from '@angular/router';
import { GameMasterMonstersTableComponent } from '../game-master-monsters-table/game-master-monsters-table.component';
import { GameMasterShopkeepersTableComponent } from '../game-master-shopkeepers-table/game-master-shopkeepers-table.component';
import { GameMasterTurntrackerComponent } from '../game-master-turntracker/game-master-turntracker.component';
@Component({
selector: 'app-game-master-dashboard',
@ -66,6 +67,12 @@ export class GameMasterDashboardComponent implements OnInit, OnDestroy {
componentToDisplay: 'GameMasterMonstersTableComponent',
expanded: false,
},
{
displayName: 'Turn Tracker',
iconName: 'ra ra-crossed-axes',
componentToDisplay: 'GameMasterTurntrackerComponent',
expanded: false,
},
{
displayName: 'Shopkeepers',
iconName: 'ra ra-wooden-sign',
@ -160,6 +167,9 @@ export class GameMasterDashboardComponent implements OnInit, OnDestroy {
case 'GameMasterShopkeepersTableComponent':
this.middleComponentName = GameMasterShopkeepersTableComponent;
break;
case 'GameMasterTurntrackerComponent':
this.middleComponentName = GameMasterTurntrackerComponent;
break;
}
}

View File

@ -0,0 +1,79 @@
.turn-tracker-main {
margin-left: 20%;
}
.first {
background-color: #df7c0f !important;
}
.turn-tracker-main > div {
width: 400px;
max-width: 100%;
margin: 0 25px 25px 0;
display: inline-block;
vertical-align: top;
}
.turn-tracker-main > div > h2 {
color: whitesmoke;
}
.no-focus:focus {
outline: none;
}
.turn-tracker-main > div > h2 > button {
top: -7px;
}
.turn-tracker-list {
border: solid 1px #3d4751;
min-height: 81px;
background: #606f80;
border-radius: 4px;
overflow: hidden;
display: block;
}
.to-right {
float: right;
color: whitesmoke;
}
.turn-tracker-box {
padding: 20px 10px;
border-bottom: solid 1px #3d4751 !important;
color: whitesmoke;
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
cursor: move;
background: #606f80;
font-size: 14px;
}
.turn-tracker-box-name {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.cdk-drag-preview {
box-sizing: border-box;
border-radius: 4px;
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2),
0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12);
}
.character-list {
height: 81px;
}
.cdk-drag-placeholder {
opacity: 0;
}
.cdk-drag-animating {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}
.example-box:last-child {
border: none;
}
.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) {
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
}

View File

@ -0,0 +1,48 @@
<div class="turn-tracker-main" cdkDropListGroup>
<div>
<h2>
Turn Tracker
<button class="no-focus" mat-icon-button (click)="AddMonster()">
<mat-icon>add_circle_outline</mat-icon>
</button>
</h2>
<div
cdkDropList
[cdkDropListData]="turnTrackerList"
class="turn-tracker-list"
(cdkDropListDropped)="drop($event)">
<div class="turn-tracker-box" *ngFor="let item of turnTrackerList;let first = first" [ngClass]="{first: first}" cdkDrag>
<span class="turn-tracker-box-name">
{{item.name}}
</span>
<button class="no-focus" mat-icon-button (click)="DeleteRow(item)">
<mat-icon>delete</mat-icon>
</button>
</div>
</div>
<button class="no-focus to-right" mat-button (click)="NextTurn()">
Next turn <mat-icon>fast_forward</mat-icon>
</button>
</div>
<div>
<h2>
Players characters list
<button class="no-focus" mat-icon-button (click)="GetLoggedCharacters()">
<mat-icon>autorenew</mat-icon>
</button>
</h2>
<div
cdkDropList
[cdkDropListData]="characterList"
class="turn-tracker-list"
(cdkDropListDropped)="drop($event)">
<div class="turn-tracker-box character-list" *ngFor="let item of characterList" cdkDrag>
<span class="turn-tracker-box-name">
{{item.name}}
</span>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,145 @@
import { Component, OnDestroy, OnInit } from '@angular/core';
import {
CdkDragDrop,
moveItemInArray,
transferArrayItem,
} from '@angular/cdk/drag-drop';
import { CharacterService } from '../../../services/character.service';
import { first } from 'rxjs/operators';
import { MatDialog } from '@angular/material';
import { ChooseMonsterDialogComponent } from '../choose-monster-dialog/choose-monster-dialog.component';
import { MonsterViewModel } from '../../../types/viewmodels/monster-viewmodels/MonsterViewModel';
import { Store } from '@ngrx/store';
import { AddTurnTrackerList } from '../../store/actions/game-master.actions';
import { AppState } from '../../store/models/app-state.model';
@Component({
selector: 'app-game-master-turntracker',
templateUrl: './game-master-turntracker.component.html',
styleUrls: ['./game-master-turntracker.component.css'],
})
export class GameMasterTurntrackerComponent implements OnInit, OnDestroy {
turnTrackerList: {
name: string;
characterId: number;
monsterId: number;
}[] = [];
characterList: {
name: string;
characterId: number;
monsterId: number;
}[] = [];
drop(event: CdkDragDrop<any[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(
event.container.data,
event.previousIndex,
event.currentIndex
);
} else {
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
}
}
constructor(
private characterService: CharacterService,
public dialog: MatDialog,
private store: Store<AppState>
) {
this.store
.select((s) => s.gameMasterStore.turnTrackerList)
.pipe(first())
.subscribe((result) => {
if (result.length > 0) {
this.turnTrackerList = result;
}
this.GetLoggedCharacters();
});
}
ngOnInit() {}
GetLoggedCharacters() {
this.characterService
.getLoggedCharacters()
.pipe(first())
.subscribe((result) => {
const currentCharacterIds = this.turnTrackerList.map(
(e) => e.characterId
);
this.characterList = result
.filter((e) => !currentCharacterIds.includes(e.id))
.map((e) => ({
name: e.name,
characterId: e.id,
monsterId: null,
}));
});
}
DeleteRow(element: { name: string; characterId: number; monsterId: number }) {
if (element.characterId != null) {
this.turnTrackerList = this.turnTrackerList.filter(
(e) => e.characterId !== element.characterId
);
} else {
this.turnTrackerList = this.turnTrackerList.filter((e) => {
return !(e.name == element.name && e.monsterId == element.monsterId);
});
}
}
NextTurn() {
if (this.turnTrackerList.length > 1) {
this.turnTrackerList = [
...this.turnTrackerList.slice(1),
this.turnTrackerList[0],
];
}
}
AddMonster() {
let dialogRef = this.dialog.open(ChooseMonsterDialogComponent, {
width: '600px',
});
dialogRef.afterClosed().subscribe((result: MonsterViewModel[]) => {
if (result != null) {
let monstersOnList = this.turnTrackerList.filter(
(c) => c.monsterId !== null
);
result.forEach((ele) => {
if (monstersOnList.map((e) => e.name).includes(ele.name)) {
debugger;
let maxCurrentId = Math.max(
...monstersOnList.map((e) => e.monsterId),
0
);
maxCurrentId += 1;
this.turnTrackerList = [
...this.turnTrackerList,
{ name: ele.name, characterId: null, monsterId: maxCurrentId },
];
} else {
this.turnTrackerList = [
...this.turnTrackerList,
{ name: ele.name, characterId: null, monsterId: 1 },
];
}
});
}
});
}
ngOnDestroy() {
this.store.dispatch(
new AddTurnTrackerList({ turnTrackerList: this.turnTrackerList })
);
}
}

View File

@ -0,0 +1,21 @@
import { Action } from '@ngrx/store';
export enum GameMasterActionTypes {
ADD_TURN_TRACKER_LIST = '[GAME MASTER] Add turn tracker list',
}
export class AddTurnTrackerList implements Action {
readonly type = GameMasterActionTypes.ADD_TURN_TRACKER_LIST;
constructor(
public payload: {
turnTrackerList: {
name: string;
characterId: number;
monsterId: number;
}[];
}
) {}
}
export type GameMasterAction = AddTurnTrackerList;

View File

@ -1,15 +1,19 @@
import {AppStoreModel} from './app-store.model';
import {ActionReducerMap} from '@ngrx/store';
import {AppReducer} from '../reducers/app.reducer';
import {PlayerStoreModel} from './player-store.model';
import {PlayerReducer} from '../reducers/player.reducer';
import { AppStoreModel } from './app-store.model';
import { ActionReducerMap } from '@ngrx/store';
import { AppReducer } from '../reducers/app.reducer';
import { PlayerStoreModel } from './player-store.model';
import { PlayerReducer } from '../reducers/player.reducer';
import { GameMasterStoreModel } from './game-master-store.model';
import { GameMasterReducer } from '../reducers/game-master.reducer';
export interface AppState {
appStore: AppStoreModel;
playerStore: PlayerStoreModel;
gameMasterStore: GameMasterStoreModel;
}
export const reducers: ActionReducerMap<AppState> = {
appStore: AppReducer,
playerStore: PlayerReducer,
gameMasterStore: GameMasterReducer,
};

View File

@ -0,0 +1,7 @@
export interface GameMasterStoreModel {
turnTrackerList: {
name: string;
characterId: number;
monsterId: number;
}[];
}

View File

@ -0,0 +1,21 @@
import { GameMasterStoreModel } from '../models/game-master-store.model';
import {
GameMasterAction,
GameMasterActionTypes,
} from '../actions/game-master.actions';
const initialState: GameMasterStoreModel = {
turnTrackerList: [],
};
export function GameMasterReducer(
state: GameMasterStoreModel = initialState,
action: GameMasterAction
) {
switch (action.type) {
case GameMasterActionTypes.ADD_TURN_TRACKER_LIST:
return { ...state, turnTrackerList: action.payload.turnTrackerList };
default:
return state;
}
}

View File

@ -43,6 +43,8 @@ namespace SessionCompanion.Configurations
services.AddScoped<IRepository<Monster>, MonsterRepository>();
services.AddScoped<IRepository<MonsterSpecialAbility>, MonsterSpecialAbilitiesRepository>();
services.AddScoped<IRepository<SpecialAbility>, SpecialAbilityRepository>();
services.AddScoped<IRepository<Shopkeeper>, ShopkeeperRepository>();
services.AddScoped<IRepository<ShopkeeperItem>, ShopkeeperItemRepository>();
return services;
}
}

View File

@ -36,6 +36,8 @@ namespace SessionCompanion.Configurations
services.AddScoped<IWeaponService, WeaponService>();
services.AddScoped<ICharacterWeaponService, CharacterWeaponService>();
services.AddScoped<IMonsterService, MonsterService>();
services.AddScoped<IShopkeeperService, ShopkeeperService>();
services.AddScoped<IShopkeeperItemService, ShopkeeperItemService>();
return services;
}

View File

@ -0,0 +1,33 @@
using Microsoft.AspNetCore.Mvc;
using SessionCompanion.Extensions.EitherType;
using SessionCompanion.Services.Interfaces;
using SessionCompanion.ViewModels.ApiResponses;
using SessionCompanion.ViewModels.ShopkeeperViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace SessionCompanion.Controllers
{
[ApiController]
[Route("api/shopkeeper")]
public class ShopkeeperController : Controller
{
private IShopkeeperService _service;
public ShopkeeperController(IShopkeeperService shopkeeperService)
{
_service = shopkeeperService;
}
/// <summary>
/// Endpoint zwracający liste sklepikarzy
/// </summary>
/// <returns>Lista sklepikarzy</returns>
[HttpGet("getShopkeepers")]
public async Task<List<ShopkeeperViewModel>> GetShopkeepers()
{
return _service.Get().ToList();
}
}
}