Browse Source

Merge branch 'develop'

main
Jonathan McCaffrey 4 years ago
parent
commit
c921003483
  1. 16
      Components/Components.csproj
  2. 1
      Components/Form/FormToggleComponent.razor
  3. 8
      Components/Inputs/CodeLinkComponent.razor
  4. 2
      Components/Inputs/EditLinkComponent.razor
  5. 35
      Components/Inputs/LinkButtonComponent.razor
  6. 27
      Components/Inputs/SearchButtonComponent.razor
  7. 16
      Components/Inputs/SearchIconButtonComponent.razor
  8. 4
      Components/Layout/WebsiteTitleComponent.razor
  9. 14
      Components/Navigation/DesktopNavComponent.razor
  10. 10
      Components/Navigation/MobileNavComponent.razor
  11. 2
      Components/Navigation/TabletNavComponent.razor
  12. 5
      Components/Utils/Links.cs
  13. BIN
      IGP/Database.db
  14. 14
      IGP/Dialog/SearchDialogComponent.razor
  15. 5
      IGP/Index.razor
  16. 117
      IGP/Pages/Agile/AgilePage.razor
  17. 66
      IGP/Pages/Agile/AgilePage.razor.css
  18. 183
      IGP/Pages/Agile/Parts/BacklogComponent.razor
  19. 224
      IGP/Pages/Agile/Parts/SprintComponent.razor
  20. 3
      IGP/Pages/BasePage.razor
  21. 3
      IGP/Pages/BuildCalculator/BuildCalculatorPage.razor
  22. 42
      IGP/Pages/BuildCalculator/Parts/ArmyComponent.razor
  23. 3
      IGP/Pages/BuildCalculator/Parts/BuildChartComponent.razor
  24. 1
      IGP/Pages/BuildCalculator/Parts/EntityClickViewComponent.razor
  25. 24
      IGP/Pages/BuildCalculator/Parts/FilterComponent.razor
  26. 165
      IGP/Pages/BuildCalculator/Parts/HotkeyViewerComponent.razor
  27. 2
      IGP/Pages/BuildCalculator/Parts/InputPanelComponent.razor
  28. 3
      IGP/Pages/BuildCalculator/Parts/OptionsComponent.razor
  29. 133
      IGP/Pages/ChangeLogPage.razor
  30. 13
      IGP/Pages/ChangeLogPage.razor.css
  31. 106
      IGP/Pages/Comparision/ComparisionPage.razor
  32. 37
      IGP/Pages/Comparision/Parts/BuildLoaderComponent.razor
  33. 25
      IGP/Pages/Comparision/Parts/SandComponent.razor
  34. 1
      IGP/Pages/Database/DatabaseSinglePage.razor
  35. 3
      IGP/Pages/Database/Parts/EntityFilterComponent.razor
  36. 117
      IGP/Pages/Documentation/DocumentationIndexPage.razor
  37. 123
      IGP/Pages/Documentation/DocumentationPage.razor
  38. 6
      IGP/Pages/Documentation/Parts/DocumentComponent.razor
  39. 70
      IGP/Pages/Documentation/Parts/DocumentInnerNavComponent.razor
  40. 47
      IGP/Pages/Documentation/Parts/DocumentNavComponent.razor
  41. 4
      IGP/Pages/EconomyComparison/EconomyComparisonPage.razor
  42. 2
      IGP/Pages/EconomyComparison/Parts/ChartComponent.razor
  43. 3
      IGP/Pages/EconomyComparison/Parts/EconomyDifferenceComponent.razor
  44. 4
      IGP/Pages/EconomyComparison/Parts/EconomyInputComponent.razor
  45. 99
      IGP/Pages/HarassCalculatorPage.razor
  46. 8
      IGP/Pages/Home/HomePage.razor
  47. 88
      IGP/Pages/MakingOf/MakingOfPage.razor
  48. 188
      IGP/Pages/MakingOf/Parts/MakingOfColours.razor
  49. 49
      IGP/Pages/MakingOf/Parts/MakingOfColours.razor.css
  50. 16
      IGP/Pages/MakingOf/Parts/MakingOfDialogs.razor
  51. 188
      IGP/Pages/MakingOf/Parts/MakingOfDisplays.razor
  52. 58
      IGP/Pages/MakingOf/Parts/MakingOfFeedback.razor
  53. 35
      IGP/Pages/MakingOf/Parts/MakingOfForms.razor
  54. 80
      IGP/Pages/MakingOf/Parts/MakingOfNavigation.razor
  55. 7
      IGP/Pages/Notes/NotesIndexPage.razor
  56. 6
      IGP/Pages/Notes/Parts/NoteComponent.razor
  57. 7
      IGP/Pages/PermissionsPage.razor
  58. 19
      IGP/Pages/RoadMap/Parts/RoadMapComponent.razor
  59. 32
      IGP/Pages/RoadMap/RoadMapPage.razor
  60. 8
      IGP/Pages/StoragePage.razor
  61. 12
      IGP/Pages/StreamsPage.razor
  62. 1
      IGP/Portals/SearchPortal.razor
  63. 7
      IGP/_Imports.razor
  64. 2
      IGP/wwwroot/generated/WebSectionModels.json
  65. 3
      IGP/wwwroot/index.html
  66. 187
      Model/Entity/Data/DATA.cs
  67. 1
      Model/Entity/Data/Ids_Entity.cs
  68. 1
      Model/Entity/Parts/EntityFactionModel.cs
  69. 4
      Model/Model.csproj
  70. 3
      Model/Website/WebSectionModel.cs
  71. 1
      Services/IServices.cs
  72. 17
      Services/Immortal/BuildOrderService.cs
  73. 5
      Services/Immortal/EntityFilterService.cs
  74. 3
      Services/Immortal/ImmortalSelectionService.cs
  75. 12
      Services/Services.csproj
  76. 19
      Services/Website/DataCollectionService.cs
  77. 7
      Services/Website/DialogService.cs
  78. 2
      Services/Website/PermissionService.cs
  79. 1
      Services/Website/StorageService.cs
  80. 5
      TestAutomation/BaseTest.cs
  81. 22
      TestAutomation/Pages/DatabasePage.cs
  82. 7
      TestAutomation/Pages/DatabaseSinglePage.cs
  83. 8
      TestAutomation/Shared/NavigationBar.cs
  84. 1
      TestAutomation/Shared/WebsiteSearchDialog.cs
  85. 22
      TestAutomation/TestAutomation.csproj
  86. 16
      TestAutomation/TestSearchFeatures.cs
  87. 10
      TestAutomation/Utils/Website.cs

16
Components/Components.csproj

@ -15,24 +15,24 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Markdig" Version="0.28.1" /> <PackageReference Include="Markdig" Version="0.28.1"/>
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="7.0.0-preview.2.22153.2" /> <PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="7.0.0-preview.2.22153.2"/>
<PackageReference Include="Microsoft.Extensions.Localization" Version="7.0.0-preview.2.22153.2" /> <PackageReference Include="Microsoft.Extensions.Localization" Version="7.0.0-preview.2.22153.2"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Inputs\" /> <Folder Include="Inputs\"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Model\Model.csproj" /> <ProjectReference Include="..\Model\Model.csproj"/>
<ProjectReference Include="..\Services\Services.csproj" /> <ProjectReference Include="..\Services\Services.csproj"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="Inputs\" /> <None Remove="Inputs\"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

1
Components/Form/FormToggleComponent.razor

@ -122,4 +122,5 @@
base.OnInitialized(); base.OnInitialized();
labelId = Label.ToLower().Replace(" ", "_"); labelId = Label.ToLower().Replace(" ", "_");
} }
} }

8
Components/Inputs/CodeLinkComponent.razor

@ -1,16 +1,16 @@
<a href="@Href" class="codeLinkButton"> <a href="@Href" target="_blank" class="codeLinkButton">
View on GitHub View on GitHub <i class="fa-brands fa-github" style="font-size: 24px; margin-left: 5px;"></i>
</a> </a>
<style> <style>
.codeLinkButton { .codeLinkButton {
color: white; color: white;
background-color: var(--info); background-color: var(--info);
border: 1px solid var(--info-border); border: 2px solid var(--info-border);
padding: 16px; padding: 16px;
border-radius: 3px; border-radius: 3px;
display: block; display: block;
width: 180px; width: 200px;
text-align: center; text-align: center;
} }

2
Components/Inputs/EditLinkComponent.razor

@ -1,4 +1,4 @@
<a href="@Href" class="editLinkButton"> <a href="@Href" target="_blank" class="editLinkButton">
Edit on GitHub Edit on GitHub
</a> </a>

35
Components/Inputs/LinkButtonComponent.razor

@ -0,0 +1,35 @@
<a href="@Href" class="linkButtonContainer">
@ChildContent
</a>
<style>
.linkButtonContainer {
padding: 16px;
border: 1px solid;
border-radius: 8px;
font-weight: 800;
font-size: 1.2rem;
border-color: var(--primary);
background-color: var(--primary);
}
.linkButtonContainer:hover {
background-color: var(--primary-hover);
border-color: var(--primary-border-hover);
color: white;
}
</style>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; } = default!;
[Parameter]
public string Href { get; set; } = "";
}

27
Components/Inputs/SearchButtonComponent.razor

@ -4,10 +4,18 @@
<button id="@Id" class="searchButtonContainer" @onclick="ButtonClicked"> <button id="@Id" class="searchButtonContainer" @onclick="ButtonClicked">
<div class="searchText"> <div class="searchText">
Search... <i class="fa-solid fa-magnifying-glass" style="margin-left: 3px; margin-right: 6px;"></i> Search...
</div> </div>
<div class="searchHotkey"> <div class="searchHotkey">
@CommandKey + K @if (IsMac)
{
<span><i class="fa-solid fa-command"></i>K</span>
}
else
{
<span>CTRL + K</span>
}
</div> </div>
</button> </button>
@ -28,23 +36,24 @@
} }
.searchHotkey { .searchHotkey {
padding: 2px; padding: 4px;
background-color: rgba(255,255,255,0.05);
background-color: var(--info); border: 2px solid rgba(255,255,255,0.25);
border: 2px solid var(--primary-border); border-radius: 4px;
} }
</style> </style>
@code { @code {
[Parameter] [Parameter]
public RenderFragment ChildContent { get; set; } = default!; public RenderFragment ChildContent { get; set; } = default!;
[Parameter] [Parameter]
public string Id { get; set; } = default!; public string Id { get; set; } = default!;
private string userAgent = ""; private string _userAgent = "";
string CommandKey => userAgent.Contains("Mac OS") ? "CMD" : "Ctrl"; bool IsMac => _userAgent.Contains("Mac OS");
private void ButtonClicked(EventArgs eventArgs) private void ButtonClicked(EventArgs eventArgs)
{ {
@ -53,7 +62,7 @@
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
userAgent = await JsRuntime.InvokeAsync<string>("getUserAgent"); _userAgent = await JsRuntime.InvokeAsync<string>("getUserAgent");
} }
} }

16
Components/Inputs/SearchIconButtonComponent.razor

@ -3,27 +3,32 @@
@inject IJSRuntime JsRuntime @inject IJSRuntime JsRuntime
<button id="@Id" class="searchIconButtonContainer" @onclick="ButtonClicked"> <button id="@Id" class="searchIconButtonContainer" @onclick="ButtonClicked">
<div class="searchText"> <div class="searchIcon">
S <i class="fa-solid fa-magnifying-glass"></i>
</div> </div>
</button> </button>
<style> <style>
.searchIconButtonContainer { .searchIconButtonContainer {
background-color: var(--primary);
border: 2px solid var(--primary-border);
border-radius: 8px; border-radius: 8px;
font-weight: 800; font-weight: 800;
width: 32px; width: 100%;
padding: 5px; padding: 5px;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
} }
.searchIcon {
font-size: 28px;
text-align: center;
margin: auto;
}
</style> </style>
@code { @code {
[Parameter] [Parameter]
public RenderFragment ChildContent { get; set; } = default!; public RenderFragment ChildContent { get; set; } = default!;
@ -34,4 +39,5 @@
{ {
SearchService.Show(); SearchService.Show();
} }
} }

4
Components/Layout/WebsiteTitleComponent.razor

@ -1,6 +1,6 @@
<div class="title"> <h1 class="title">
@ChildContent @ChildContent
</div> </h1>
<style> <style>

14
Components/Navigation/DesktopNavComponent.razor

@ -13,7 +13,7 @@
<div class="desktopNavContainer"> <div class="desktopNavContainer">
<div class="menuHeader"> <div class="menuHeader">
<NavLink id="desktop-homeLink" href="/" class="websiteTitle"> <NavLink id="desktop-homeLink" href="/" class="websiteTitle">
IGP Fan Reference <i class="fa-solid fa-house" style="margin-right: 4px;"></i> IGP Fan Reference
</NavLink> </NavLink>
<div class="sectionNavs"> <div class="sectionNavs">
@ -27,7 +27,14 @@
} }
<div class="sectionNav"> <div class="sectionNav">
<button onclick="@(() => { MenuClicked(webSection.Id); })" class="@sectionButtonStyle">@webSection.Name</button>
<button onclick="@(() => { MenuClicked(webSection.Id); })" class="@sectionButtonStyle">
<i class="fa-solid @webSection.Icon"></i>
@if (!webSection.OnlyIcon)
{
<span style="margin-left: 12px">@webSection.Name</span>
}
</button>
@if (isSelected) @if (isSelected)
{ {
<div class="navMenuPosition"> <div class="navMenuPosition">
@ -95,7 +102,7 @@
.sectionNavs { .sectionNavs {
display: flex; display: flex;
gap: 8px; gap: 16px;
align-items: center; align-items: center;
} }
@ -140,6 +147,7 @@
box-shadow: 0 2px 3px black; box-shadow: 0 2px 3px black;
background-color: var(--info); background-color: var(--info);
transform: translateY(-1px) scale(1.08); transform: translateY(-1px) scale(1.08);
border-radius: 12px;
} }
@@media only screen and (max-width: 1025px) { @@media only screen and (max-width: 1025px) {

10
Components/Navigation/MobileNavComponent.razor

@ -1,13 +1,10 @@
 <div class="mobileFooter">
<div class="mobileFooter">
<div class="mobileNavSectionsContainer"> <div class="mobileNavSectionsContainer">
@foreach (var webSection in WebSections) @foreach (var webSection in WebSections)
{ {
<div class="mobileNavSectionButton" @onclick="() => OnSectionClicked(webSection)" @onclick:preventDefault="true" @onclick:stopPropagation="true"> <div class="mobileNavSectionButton" @onclick="() => OnSectionClicked(webSection)" @onclick:preventDefault="true" @onclick:stopPropagation="true">
<div class="mobileNavSectionButtonText"> <div class="mobileNavSectionButtonText">
@webSection?.Name <i class="fa-solid @webSection.Icon" style="font-size: 28px;"></i>
</div> </div>
</div> </div>
} }
@ -96,6 +93,7 @@
border: 1px solid var(--primary); border: 1px solid var(--primary);
width: 100%; width: 100%;
height: 64px; height: 64px;
border-radius: 2px;
display: flex; display: flex;
background-color: var(--primary); background-color: var(--primary);
cursor: pointer; cursor: pointer;
@ -146,7 +144,7 @@
@code { @code {
#if NO_SQL #if NO_SQL
[Parameter] [Parameter]
public List<WebSectionModel?> WebSections { get; set; } = default!; public List<WebSectionModel> WebSections { get; set; } = default!;
[Parameter] [Parameter]
public List<WebPageModel> WebPages { get; set; } = default!; public List<WebPageModel> WebPages { get; set; } = default!;

2
Components/Navigation/TabletNavComponent.razor

@ -10,7 +10,7 @@
<SearchButtonComponent/> <SearchButtonComponent/>
<div class="tabletButton"> <div class="tabletButton">
<div class="tabletMenuTitle"> <div class="tabletMenuTitle">
Menu <i class="fa-solid fa-bars" style="font-size: 32px; margin:auto"></i>
</div> </div>
</div> </div>
</div> </div>

5
Components/Utils/Links.cs

@ -4,10 +4,7 @@ public static class Links
{ {
public static string GetTarget(string link) public static string GetTarget(string link)
{ {
if (link.StartsWith("https://")) if (link.StartsWith("https://")) return "_blank";
{
return "_blank";
}
return "_self"; return "_self";
} }

BIN
IGP/Database.db

Binary file not shown.

14
IGP/Dialog/SearchDialogComponent.razor

@ -1,5 +1,4 @@
@using System.Timers @implements IDisposable;
@implements IDisposable;
@inject ISearchService searchService @inject ISearchService searchService
@inject IJSRuntime jsRuntime @inject IJSRuntime jsRuntime
@ -116,8 +115,18 @@
.searchLink { .searchLink {
text-decoration: underline; text-decoration: underline;
}
@@media only screen and (max-width: 1025px) {
.searchContainer {
height: 300px;
}
.searchBox {
height: 230px;
}
} }
</style> </style>
} }
@ -145,6 +154,7 @@
} }
private Timer timer = null!; private Timer timer = null!;
private void OnSearchChanged() private void OnSearchChanged()
{ {
if (timer.Enabled != searchService.IsVisible) if (timer.Enabled != searchService.IsVisible)

5
IGP/Index.razor

@ -6,7 +6,8 @@
@layout PageLayout @layout PageLayout
<DevOnlyComponent> <DevOnlyComponent>
<PermissionsPage/> <LinkButtonComponent Href="https://github.com/JonathanMcCaffrey/IGP-Fan-Reference/blob/main/IGP/Pages/HarassCalculatorPage.razor">
View on GitHub <i class="fa-brands fa-github" style="font-size: 24px; margin-left: 5px;"></i>
</LinkButtonComponent>
</DevOnlyComponent> </DevOnlyComponent>
<HomePage/> <HomePage/>

117
IGP/Pages/Agile/AgilePage.razor

@ -1,117 +0,0 @@
@implements IDisposable;
@inject IAgileService AgileService;
@layout PageLayout
@inherits BasePage
@page "/agile"
@if (!AgileService.IsLoaded())
{
<LoadingComponent/>
}
else
{
<LayoutMediumContentComponent>
<WebsiteTitleComponent>Agile</WebsiteTitleComponent>
<div class="agileViewContainer">
@foreach (var sprint in AgileService.AgileSprintModels!
.OrderBy(e => e.EndDate).Reverse())
{
<details class="sprintDisplayContainer @sprint.GetSprintType().ToLower()"
open="@(sprint.GetSprintType() == SprintType.Current)">
<summary class="sprintSummary">
<div class="sprintTitle">@sprint.Name</div>
<div style="flex: 1; flex-grow: 1;"></div>
<div class="sprintDates">
<div class="sprintStartDate">
@if (sprint.StartDate != null)
{
<b>Start: </b>
@sprint.StartDate.Value.ToString("dd/MM/yyyy")
}
</div>
<div class="sprintEndDate">
@if (sprint.EndDate != null)
{
<b>End: </b>
@sprint.EndDate.Value.ToString("dd/MM/yyyy")
}
</div>
</div>
</summary>
<SprintComponent AgileSprint="sprint"></SprintComponent>
</details>
}
<details class="sprintDisplayContainer">
<summary class="sprintSummary">
<div class="sprintTitle">Backlog</div>
<div style="flex: 1; flex-grow: 1;"></div>
</summary>
<div>
<BacklogComponent Backlog=backlog></BacklogComponent>
</div>
</details>
</div>
<ContentDividerComponent></ContentDividerComponent>
<PaperComponent>
<InfoBodyComponent>
<InfoQuestionComponent>What is Agile?</InfoQuestionComponent>
<InfoAnswerComponent>
Agile is a work methodology for determing task assignment and release deadlines.
<br/><br/>
My agile practice will be creating tasks in a backlog. Assigning them to weekly sprints. And completing all tasks in the allotted time frame.
<br/><br/>
Any unfinished tasks are moved into the next sprint, or the sprint will be extended by a week.
</InfoAnswerComponent>
</InfoBodyComponent>
</PaperComponent>
</LayoutMediumContentComponent>
}
@code {
private readonly List<AgileTaskModel> backlog = new();
protected override void OnInitialized()
{
base.OnInitialized();
AgileService.Subscribe(HasChanged);
HasChanged();
}
void IDisposable.Dispose()
{
AgileService.Unsubscribe(HasChanged);
}
void HasChanged()
{
if (!AgileService.IsLoaded()) return;
backlog.Clear();
foreach (var task in AgileService.AgileTaskModels!)
{
if (task.AgileSprintModelId == null)
{
backlog.Add(task);
}
}
StateHasChanged();
}
protected override async Task OnInitializedAsync()
{
await AgileService.Load();
}
}

66
IGP/Pages/Agile/AgilePage.razor.css

@ -1,66 +0,0 @@

.agileViewContainer {
display: flex;
gap: 12px;
flex-direction: column;
}
.sprintDisplayContainer {
border: 4px solid var(--paper);
box-shadow: 0px 2px 12px rgba(0, 0, 0, 0.2);
border-radius: 2px;
padding: 25px;
margin: auto;
width: 100%;
background-color: var(--paper);
}
@media only screen and (max-width: 1025px) {
.sprintDisplayContainer {
padding: 2px;
}
}
.sprintSummary {
display: flex;
width: 100%;
}
.sprintDisplayContainer.current {
border-color: #042901;
background-color: var(--paper);
}
.sprintDisplayContainer.planned {
border-color: #2a2000;
background-color: var(--paper);
}
.sprintDisplayContainer.completed {
border-color: #2a2000;
background-color: var(--paper);
}
details .sprintSummary::before {
content: "+";
font-weight: bolder;
font-size: 1.5rem;
padding-right: 8px;
}
details[open] .sprintSummary::before {
content: "-";
}
.sprintTitle {
width: 400px;
font-size: 1.6rem;
font-weight: 800;
}
.sprintDates {
width: 160px;
text-align: right;
}

183
IGP/Pages/Agile/Parts/BacklogComponent.razor

@ -1,183 +0,0 @@
<div class="sprintContainer">
<div class="tasksContainer">
@foreach (var task in Backlog)
{
<div class="taskContainer @task.Status.ToLower()">
<div class="taskName">@task.Name</div>
<div class="taskDetails">
<LayoutRowComponent>
<LayoutColumnComponent>
<div class="taskType">
<b>Type: </b>@task.Task.Replace("_", " ")
</div>
<div class="taskStatus">
<b>Status: </b>@task.Status.Replace("_", " ")
</div>
<div class="taskPriority">
<b>Priority: </b>@task.Priority
</div>
</LayoutColumnComponent>
<LayoutColumnComponent>
@if (task.Finished != null)
{
<div class="taskFinished">
<b>Finished: </b>@task.Finished
</div>
}
<div class="taskCreated">
<b>Created: </b>@task.Created
</div>
</LayoutColumnComponent>
</LayoutRowComponent>
</div>
<div class="taskDescription">
<b>Description: </b>@task.Description
</div>
<div class="taskNotes">
<b>Notes: </b>@task.Notes
</div>
</div>
}
</div>
</div>
<style>
.sprintContainer {
display: flex;
flex-direction: column;
gap: 12px;
padding-top: 16px;
}
@@media only screen and (max-width: 1025px) {
.sprintContainer {
display: flex;
flex-direction: column;
gap: 6px;
border: none;
margin-top: 12px;
box-shadow: none;
padding: 8px;
}
}
.tasksContainer {
grid-area: tasks;
display: flex;
flex-direction: column;
gap: 20px;
padding: 25px;
align-items: stretch;
justify-content: stretch;
justify-items: stretch;
}
.taskContainer {
padding: 25px;
border: 1px dashed rgba(0,0,0,0.6);
box-shadow: 0px 2px 6px rgba(0,0,0,0.1);
}
.taskContainer.@StatusType.In_Progress.ToLower() {
border-color: #030129;
background-color: #2c3a4c;
}
.taskContainer.@StatusType.Todo.ToLower() {
border-color: #2a2000;
background-color: #ffbf0029;
}
.taskContainer.@StatusType.To_Test.ToLower() {
border-color: #030129;
background-color: #2c3a4c;
}
.taskContainer.@StatusType.Canceled.ToLower() {
border-color: #290102;
background-color: #4C2C33;
}
.taskContainer.@StatusType.Done.ToLower() {
border-color: #042901;
background-color: #2E4C2C;
}
.taskName {
font-weight: bold;
grid-area: name;
}
.taskCreated {
grid-area: created;
}
.taskFinished {
grid-area: finished;
}
.taskStatus {
grid-area: status;
}
.taskDescription {
margin-top: 10px;
grid-area: description;
}
.taskNotes {
grid-area: notes;
}
@@media only screen and (max-width: 1025px) {
.tasksContainer {
padding: 0px;
margin-top: 12px;
padding-top: 12px;
border-top: 4px solid rgba(0,0,0,0.4)
}
.taskContainer {
padding: 2px;
border: none;
box-shadow: none;
}
.taskContainer.@StatusType.In_Progress.ToLower() {
border-color: transparent;
background-color: transparent;
}
.taskContainer.@StatusType.Todo.ToLower() {
border-color: transparent;
background-color: transparent;
}
.taskContainer.@StatusType.Canceled.ToLower() {
border-color: transparent;
background-color: transparent;
}
.taskContainer.@StatusType.Done.ToLower() {
border-color: transparent;
background-color: transparent;
}
}
</style>
@code {
[Parameter]
public List<AgileTaskModel> Backlog { get; set; } = default!;
}

224
IGP/Pages/Agile/Parts/SprintComponent.razor

@ -1,224 +0,0 @@
<div class="sprintContainer">
<div class="sprintStatus">
<b>Status: </b>@AgileSprint.GetSprintType()
</div>
<div class="sprintDescription">
<b>Description: </b>@AgileSprint.Description
</div>
<div class="sprintNotes">
<b>Notes: </b>@AgileSprint.Notes
</div>
<div class="tasksContainer">
@if (AgileSprint.AgileTaskModels.Count > 0)
{
@foreach (var task in AgileSprint.AgileTaskModels.OrderBy(x => x.OrderPriority))
{
<div class="taskContainer @task.Status.ToLower() @task.Task.ToLower()">
<div class="taskName">@task.Name</div>
<div class="taskDetails">
<LayoutRowComponent>
<LayoutColumnComponent>
<div class="taskType">
<b>Type: </b>@task.Task.Replace("_", " ")
</div>
<div class="taskStatus">
<b>Status: </b>@task.Status.Replace("_", " ")
</div>
<div class="taskPriority">
<b>Priority: </b>@task.Priority
</div>
</LayoutColumnComponent>
<LayoutColumnComponent>
@if (task.Finished != null)
{
<div class="taskFinished">
<b>Finished: </b>@task.Finished.Value.ToString("dd/MM/yyyy")
</div>
}
<div class="taskCreated">
<b>Created: </b>@task.Created!.Value.ToString("dd/MM/yyyy")
</div>
</LayoutColumnComponent>
</LayoutRowComponent>
</div>
<div class="taskDescription">
<b>Description: </b>@task.Description
</div>
<div class="taskNotes">
<b>Notes: </b>@task.Notes
</div>
</div>
}
}
else
{
<div>Add Tasks...</div>
}
</div>
</div>
<style>
.sprintContainer {
display: flex;
flex-direction: column;
gap: 12px;
padding-top: 16px;
}
.sprintDescription {
grid-area: description;
}
@@media only screen and (max-width: 1025px) {
.sprintContainer {
display: flex;
flex-direction: column;
gap: 6px;
border: none;
margin-top: 12px;
box-shadow: none;
padding: 8px;
}
.sprintStartDate {
text-align: left;
}
.sprintEndDate {
text-align: left;
}
}
.tasksContainer {
grid-area: tasks;
display: flex;
flex-direction: column;
gap: 20px;
padding: 25px;
align-items: stretch;
justify-content: stretch;
justify-items: stretch;
}
.taskContainer {
padding: 25px;
border: 1px dashed rgba(0,0,0,0.6);
box-shadow: 0px 2px 6px rgba(0,0,0,0.1);
}
.taskContainer.@StatusType.In_Progress.ToLower() {
border-color: #030129;
background-color: #2c3a4c;
}
.taskContainer.@StatusType.Todo.ToLower() {
border-color: #2a2000;
background-color: #ffbf0029;
}
.taskContainer.@StatusType.To_Test.ToLower() {
border-color: #030129;
background-color: #2c3a4c;
}
.taskContainer.@StatusType.Canceled.ToLower() {
border-color: #290102;
background-color: #4C2C33;
}
.taskContainer.@StatusType.Done.ToLower() {
border-color: #042901;
background-color: #2E4C2C;
}
.taskContainer.@TaskType.Bug.ToLower() {
border-style: dotted;
border-width: 8px;
}
.taskContainer.@TaskType.Document.ToLower() {
border-style: dashed;
border-width: 2px;
}
.taskName {
font-weight: bold;
grid-area: name;
font-size: 1.2rem;
}
.taskDetails {
font-size: 0.8rem;
}
.taskCreated {
grid-area: created;
}
.taskFinished {
grid-area: finished;
}
.taskStatus {
grid-area: status;
}
.taskDescription {
margin-top: 10px;
grid-area: description;
}
.taskNotes {
grid-area: notes;
}
@@media only screen and (max-width: 1025px) {
.tasksContainer {
padding: 0px;
margin-top: 12px;
padding-top: 12px;
border-top: 4px solid rgba(0,0,0,0.4)
}
.taskContainer {
padding: 2px;
border: none;
box-shadow: none;
}
.taskContainer.@StatusType.In_Progress.ToLower() {
border-color: transparent;
background-color: transparent;
}
.taskContainer.@StatusType.Todo.ToLower() {
border-color: transparent;
background-color: transparent;
}
.taskContainer.@StatusType.Canceled.ToLower() {
border-color: transparent;
background-color: transparent;
}
.taskContainer.@StatusType.Done.ToLower() {
border-color: transparent;
background-color: transparent;
}
}
</style>
@code {
[Parameter]
public AgileSprintModel AgileSprint { get; set; } = default!;
}

3
IGP/Pages/BasePage.razor

@ -1,5 +1,4 @@
@using Services.Website @using Services.Website
@inject IDataCollectionService DataCollectionService @inject IDataCollectionService DataCollectionService
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@ -26,7 +25,7 @@
rootUrl = "home"; rootUrl = "home";
} }
var eventData = new Dictionary<string, string> { { "page", rootUrl }}; var eventData = new Dictionary<string, string> { { "page", rootUrl } };
if (splitData.Length > 1) if (splitData.Length > 1)
{ {
eventData["inner-page"] = splitData.Last(); eventData["inner-page"] = splitData.Last();

3
IGP/Pages/BuildCalculator/BuildCalculatorPage.razor

@ -13,7 +13,6 @@
@inject IDataCollectionService DataCollectionService @inject IDataCollectionService DataCollectionService
@page "/build-calculator" @page "/build-calculator"
@using Services.Website @using Services.Website
@implements IDisposable @implements IDisposable
@ -228,7 +227,7 @@
DataCollectionService.SendEvent( DataCollectionService.SendEvent(
DataCollectionKeys.PageInitialized, DataCollectionKeys.PageInitialized,
new Dictionary<string, string> {{"page", "build-calculator"}} new Dictionary<string, string> { { "page", "build-calculator" } }
); );
} }

42
IGP/Pages/BuildCalculator/Parts/ArmyComponent.razor

@ -19,7 +19,8 @@
<FormDisplayComponent Label="Army units built"> <FormDisplayComponent Label="Army units built">
<Display> <Display>
<div class="armyCardsContainer"> <div class="armyCardsContainer">
@foreach (var unit in armyCount) { @foreach (var unit in armyCount)
{
<div class="armyCard"> <div class="armyCard">
<div class="armyCountPosition"> <div class="armyCountPosition">
<div class="armyCount">@unit.Value.ToString()x</div> <div class="armyCount">@unit.Value.ToString()x</div>
@ -72,33 +73,39 @@
List<EntityModel> army = new(); List<EntityModel> army = new();
protected override void OnInitialized() { protected override void OnInitialized()
{
base.OnInitialized(); base.OnInitialized();
buildOrder.Subscribe(OnBuildOrderChanged); buildOrder.Subscribe(OnBuildOrderChanged);
timingService.Subscribe(StateHasChanged); timingService.Subscribe(StateHasChanged);
} }
void IDisposable.Dispose() { void IDisposable.Dispose()
{
buildOrder.Unsubscribe(OnBuildOrderChanged); buildOrder.Unsubscribe(OnBuildOrderChanged);
timingService.Unsubscribe(StateHasChanged); timingService.Unsubscribe(StateHasChanged);
} }
protected override bool ShouldRender() { protected override bool ShouldRender()
{
#if DEBUG #if DEBUG
jsRuntime.InvokeVoidAsync("console.time", "ArmyComponent"); jsRuntime.InvokeVoidAsync("console.time", "ArmyComponent");
#endif #endif
return true; return true;
} }
protected override void OnAfterRender(bool firstRender) { protected override void OnAfterRender(bool firstRender)
{
#if DEBUG #if DEBUG
jsRuntime.InvokeVoidAsync("console.timeEnd", "ArmyComponent"); jsRuntime.InvokeVoidAsync("console.timeEnd", "ArmyComponent");
#endif #endif
} }
void OnBuildOrderChanged() { void OnBuildOrderChanged()
{
var armyCountWas = 0; var armyCountWas = 0;
foreach (var army in armyCount) { foreach (var army in armyCount)
{
armyCountWas += army.Value; armyCountWas += army.Value;
} }
@ -108,14 +115,19 @@
var entitiesOverTime = buildOrder.GetOrders(); var entitiesOverTime = buildOrder.GetOrders();
foreach (var entitiesAtTime in entitiesOverTime) { foreach (var entitiesAtTime in entitiesOverTime)
foreach (var entity in entitiesAtTime.Value) { {
if (entity.EntityType == EntityType.Army) { foreach (var entity in entitiesAtTime.Value)
if (!armyCount.TryAdd(entity.Info().Name, 1)) { {
if (entity.EntityType == EntityType.Army)
{
if (!armyCount.TryAdd(entity.Info().Name, 1))
{
armyCount[entity.Info().Name]++; armyCount[entity.Info().Name]++;
} }
if (entity.Production() != null && entity.Production().BuildTime + entitiesAtTime.Key > lastInterval) { if (entity.Production() != null && entity.Production().BuildTime + entitiesAtTime.Key > lastInterval)
{
lastInterval = entity.Production().BuildTime + entitiesAtTime.Key; lastInterval = entity.Production().BuildTime + entitiesAtTime.Key;
} }
} }
@ -124,12 +136,14 @@
//TODO Better //TODO Better
var armyCountIs = 0; var armyCountIs = 0;
foreach (var army in armyCount) { foreach (var army in armyCount)
{
armyCountIs += army.Value; armyCountIs += army.Value;
} }
if (armyCountWas != armyCountIs) { if (armyCountWas != armyCountIs)
{
StateHasChanged(); StateHasChanged();
} }
} }

3
IGP/Pages/BuildCalculator/Parts/BuildChartComponent.razor

@ -13,7 +13,7 @@ else
<div class="chartsContainer"> <div class="chartsContainer">
@foreach (var chart in charts) @foreach (var chart in charts)
{ {
Dictionary<int, bool> takenPixels = new Dictionary<int, bool>(); var takenPixels = new Dictionary<int, bool>();
<div style="width: @chart.IntervalDisplayMax.ToString()px; height: @chart.ValueDisplayMax.ToString()px"> <div style="width: @chart.IntervalDisplayMax.ToString()px; height: @chart.ValueDisplayMax.ToString()px">
<div style="position: relative; border: 2px solid gray; border-radius:2px; width: @chart.IntervalDisplayMax.ToString()px; height: @chart.ValueDisplayMax.ToString()px"> <div style="position: relative; border: 2px solid gray; border-radius:2px; width: @chart.IntervalDisplayMax.ToString()px; height: @chart.ValueDisplayMax.ToString()px">
@ -26,7 +26,6 @@ else
takenPixels.Add(x, true); takenPixels.Add(x, true);
<div style="position: absolute; <div style="position: absolute;
bottom:@point.GetValue(chart.HighestValuePoint, chart.ValueDisplayMax)px; bottom:@point.GetValue(chart.HighestValuePoint, chart.ValueDisplayMax)px;
left:@point.GetInterval(chart.HighestIntervalPoint, chart.IntervalDisplayMax)px; left:@point.GetInterval(chart.HighestIntervalPoint, chart.IntervalDisplayMax)px;

1
IGP/Pages/BuildCalculator/Parts/EntityClickViewComponent.razor

@ -3,7 +3,6 @@
@inject IImmortalSelectionService FilterService @inject IImmortalSelectionService FilterService
@inject IBuildOrderService BuildOrderService @inject IBuildOrderService BuildOrderService
@inject IStorageService StorageService @inject IStorageService StorageService
@using Services.Website @using Services.Website
@implements IDisposable @implements IDisposable

24
IGP/Pages/BuildCalculator/Parts/FilterComponent.razor

@ -6,9 +6,13 @@
<FormLabelComponent>Faction</FormLabelComponent> <FormLabelComponent>Faction</FormLabelComponent>
<ChildContent> <ChildContent>
<option value="@DataType.FACTION_Aru" <option value="@DataType.FACTION_Aru"
selected="@(FilterService.GetFaction().Equals(DataType.FACTION_Aru))">Aru</option> selected="@(FilterService.GetFaction().Equals(DataType.FACTION_Aru))">
Aru
</option>
<option value="@DataType.FACTION_QRath" <option value="@DataType.FACTION_QRath"
selected="@(FilterService.GetFaction().Equals(DataType.FACTION_QRath))">Q'Rath</option> selected="@(FilterService.GetFaction().Equals(DataType.FACTION_QRath))">
Q'Rath
</option>
</ChildContent> </ChildContent>
</FormSelectComponent> </FormSelectComponent>
@ -18,16 +22,24 @@
@if (FilterService.GetFaction() == DataType.FACTION_QRath) @if (FilterService.GetFaction() == DataType.FACTION_QRath)
{ {
<option value="@DataType.IMMORTAL_Orzum" <option value="@DataType.IMMORTAL_Orzum"
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Orzum))">Orzum</option> selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Orzum))">
Orzum
</option>
<option value="@DataType.IMMORTAL_Ajari" <option value="@DataType.IMMORTAL_Ajari"
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Ajari))">Ajari</option> selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Ajari))">
Ajari
</option>
} }
@if (FilterService.GetFaction() == DataType.FACTION_Aru) @if (FilterService.GetFaction() == DataType.FACTION_Aru)
{ {
<option value="@DataType.IMMORTAL_Mala" <option value="@DataType.IMMORTAL_Mala"
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Mala))">Mala</option> selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Mala))">
Mala
</option>
<option value="@DataType.IMMORTAL_Xol" <option value="@DataType.IMMORTAL_Xol"
selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Xol))">Xol</option> selected="@(FilterService.GetImmortal().Equals(DataType.IMMORTAL_Xol))">
Xol
</option>
} }
</ChildContent> </ChildContent>
</FormSelectComponent> </FormSelectComponent>

165
IGP/Pages/BuildCalculator/Parts/HotkeyViewerComponent.razor

@ -13,8 +13,10 @@
<InputPanelComponent> <InputPanelComponent>
<div class="keyContainer"> <div class="keyContainer">
@foreach (var hotkey in hotkeys) { @foreach (var hotkey in hotkeys)
if (hotkey.IsHidden) { {
if (hotkey.IsHidden)
{
continue; continue;
} }
@ -31,14 +33,17 @@
var borderRadius = hotkey.PositionY == 0 ? 12 : 0; var borderRadius = hotkey.PositionY == 0 ? 12 : 0;
var border = "1px solid black"; var border = "1px solid black";
if (hotkey.KeyText.Equals(key)) { if (hotkey.KeyText.Equals(key))
{
border = "5px solid black"; border = "5px solid black";
} }
if (hotkey.KeyText.Equals(controlGroup)) { if (hotkey.KeyText.Equals(controlGroup))
{
color = "#257525"; color = "#257525";
} }
if (hotkey.KeyText.Equals("SPACE") && KeyService.IsHoldingSpace()) { if (hotkey.KeyText.Equals("SPACE") && KeyService.IsHoldingSpace())
{
border = "5px solid green"; border = "5px solid green";
} }
@ -77,23 +82,28 @@
<div @onclick="e => ButtonClicked(e, hotkey)" style="@usedStyle"> <div @onclick="e => ButtonClicked(e, hotkey)" style="@usedStyle">
@keyText @keyText
@foreach (var entity in data.Values) { @foreach (var entity in data.Values)
if (InvalidKey(entity, hotkey) || InvalidKeyGroup(entity, hotkey) || InvalidHoldSpace(entity)) { {
if (InvalidKey(entity, hotkey) || InvalidKeyGroup(entity, hotkey) || InvalidHoldSpace(entity))
{
continue; continue;
} }
if (InvalidFaction(entity)) { if (InvalidFaction(entity))
{
continue; continue;
} }
if (InvalidVanguard(entity) || InvalidNonVanguard(entity)) { if (InvalidVanguard(entity) || InvalidNonVanguard(entity))
{
continue; continue;
} }
var isVanguard = entity.VanguardAdded() != null; var isVanguard = entity.VanguardAdded() != null;
var style = isVanguard ? "font-weight: bold;" : ""; var style = isVanguard ? "font-weight: bold;" : "";
if (BuildOrderService.WillMeetRequirements(entity) == null) { if (BuildOrderService.WillMeetRequirements(entity) == null)
{
style += "color:gray; font-style: italic;"; style += "color:gray; font-style: italic;";
} }
@ -137,7 +147,8 @@
private string controlGroup = "C"; private string controlGroup = "C";
private string key = ""; private string key = "";
protected override void OnInitialized() { protected override void OnInitialized()
{
base.OnInitialized(); base.OnInitialized();
KeyService.Subscribe(OnKeyPressed); KeyService.Subscribe(OnKeyPressed);
@ -145,7 +156,8 @@
BuildOrderService.Subscribe(OnBuilderOrderChanged); BuildOrderService.Subscribe(OnBuilderOrderChanged);
} }
void IDisposable.Dispose() { void IDisposable.Dispose()
{
KeyService.Unsubscribe(OnKeyPressed); KeyService.Unsubscribe(OnKeyPressed);
FilterService.Unsubscribe(StateHasChanged); FilterService.Unsubscribe(StateHasChanged);
BuildOrderService.Unsubscribe(OnBuilderOrderChanged); BuildOrderService.Unsubscribe(OnBuilderOrderChanged);
@ -153,14 +165,17 @@
int completedTimeCount = 0; int completedTimeCount = 0;
void OnBuilderOrderChanged() { void OnBuilderOrderChanged()
if (BuildOrderService.UniqueCompletedTimes.Count != completedTimeCount) { {
if (BuildOrderService.UniqueCompletedTimes.Count != completedTimeCount)
{
completedTimeCount = BuildOrderService.UniqueCompletedTimes.Count; completedTimeCount = BuildOrderService.UniqueCompletedTimes.Count;
StateHasChanged(); StateHasChanged();
} }
} }
protected override bool ShouldRender() { protected override bool ShouldRender()
{
#if DEBUG #if DEBUG
JsRuntime.InvokeVoidAsync("console.time", "HotKeyViewerComponent"); JsRuntime.InvokeVoidAsync("console.time", "HotKeyViewerComponent");
#endif #endif
@ -168,15 +183,18 @@
return true; return true;
} }
protected override void OnAfterRender(bool firstRender) { protected override void OnAfterRender(bool firstRender)
{
#if DEBUG #if DEBUG
JsRuntime.InvokeVoidAsync("console.timeEnd", "HotKeyViewerComponent"); JsRuntime.InvokeVoidAsync("console.timeEnd", "HotKeyViewerComponent");
#endif #endif
} }
// Move to Filter Service // Move to Filter Service
bool InvalidFaction(EntityModel entity) { bool InvalidFaction(EntityModel entity)
if (entity.Faction() != null && entity.Faction()?.Faction != FilterService.GetFaction() && FilterService.GetFaction() != DataType.Any) { {
if (entity.Faction() != null && entity.Faction()?.Faction != FilterService.GetFaction() && FilterService.GetFaction() != DataType.Any)
{
return true; return true;
} }
@ -184,10 +202,12 @@
} }
// Move to Filter Service // Move to Filter Service
bool InvalidVanguard(EntityModel entity) { bool InvalidVanguard(EntityModel entity)
{
if (entity.VanguardAdded() != null if (entity.VanguardAdded() != null
&& entity.VanguardAdded()?.ImmortalId != FilterService.GetImmortal() && entity.VanguardAdded()?.ImmortalId != FilterService.GetImmortal()
&& FilterService.GetImmortal() != DataType.Any) { && FilterService.GetImmortal() != DataType.Any)
{
return true; return true;
} }
@ -195,10 +215,14 @@
} }
// Move to Filter Service // Move to Filter Service
bool InvalidNonVanguard(EntityModel entity) { bool InvalidNonVanguard(EntityModel entity)
if (entity.Replaceds().Count > 0) { {
foreach (var replaced in entity.Replaceds()) { if (entity.Replaceds().Count > 0)
if (FilterService.GetImmortal() == replaced.ImmortalId) { {
foreach (var replaced in entity.Replaceds())
{
if (FilterService.GetImmortal() == replaced.ImmortalId)
{
return true; return true;
} }
} }
@ -207,90 +231,114 @@
return false; return false;
} }
bool InvalidKey(EntityModel entity, HotkeyModel key) { bool InvalidKey(EntityModel entity, HotkeyModel key)
if (entity.Hotkey()?.Hotkey == key.KeyText) { {
if (entity.Hotkey()?.Hotkey == key.KeyText)
{
return false; return false;
} }
return true; return true;
} }
bool InvalidKeyGroup(EntityModel entity, HotkeyModel key) { bool InvalidKeyGroup(EntityModel entity, HotkeyModel key)
if (entity.Hotkey()?.HotkeyGroup == controlGroup) { {
if (entity.Hotkey()?.HotkeyGroup == controlGroup)
{
return false; return false;
} }
return true; return true;
} }
bool InvalidKey(EntityModel entity) { bool InvalidKey(EntityModel entity)
if (entity.Hotkey()?.Hotkey == key) { {
if (entity.Hotkey()?.Hotkey == key)
{
return false; return false;
} }
return true; return true;
} }
bool InvalidKeyGroup(EntityModel entity) { bool InvalidKeyGroup(EntityModel entity)
if (entity.Hotkey()?.HotkeyGroup == controlGroup) { {
if (entity.Hotkey()?.HotkeyGroup == controlGroup)
{
return false; return false;
} }
return true; return true;
} }
bool InvalidHoldSpace(EntityModel entity) { bool InvalidHoldSpace(EntityModel entity)
if (entity.Hotkey()?.HoldSpace == KeyService.IsHoldingSpace()) { {
if (entity.Hotkey()?.HoldSpace == KeyService.IsHoldingSpace())
{
return false; return false;
} }
return true; return true;
} }
void OnKeyPressed() { void OnKeyPressed()
{
var controlGroupWas = controlGroup; var controlGroupWas = controlGroup;
var keyWas = key; var keyWas = key;
if (KeyService.GetAllPressedKeys().Contains("Z")) { if (KeyService.GetAllPressedKeys().Contains("Z"))
{
controlGroup = "Z"; controlGroup = "Z";
} }
if (KeyService.GetAllPressedKeys().Contains("TAB")) { if (KeyService.GetAllPressedKeys().Contains("TAB"))
{
controlGroup = "TAB"; controlGroup = "TAB";
} }
if (KeyService.GetAllPressedKeys().Contains("C")) { if (KeyService.GetAllPressedKeys().Contains("C"))
{
controlGroup = "C"; controlGroup = "C";
} }
if (KeyService.GetAllPressedKeys().Contains("D")) { if (KeyService.GetAllPressedKeys().Contains("D"))
{
controlGroup = "D"; controlGroup = "D";
} }
if (KeyService.GetAllPressedKeys().Contains("V")) { if (KeyService.GetAllPressedKeys().Contains("V"))
{
controlGroup = "V"; controlGroup = "V";
} }
if (KeyService.GetAllPressedKeys().Contains("ALT")) { if (KeyService.GetAllPressedKeys().Contains("ALT"))
{
controlGroup = "ALT"; controlGroup = "ALT";
} }
if (KeyService.GetAllPressedKeys().Contains("SHIFT")) { if (KeyService.GetAllPressedKeys().Contains("SHIFT"))
{
controlGroup = "SHIFT"; controlGroup = "SHIFT";
} }
if (KeyService.GetAllPressedKeys().Contains("CONTROL")) { if (KeyService.GetAllPressedKeys().Contains("CONTROL"))
{
controlGroup = "CONTROL"; controlGroup = "CONTROL";
} }
if (KeyService.GetAllPressedKeys().Count > 0) { if (KeyService.GetAllPressedKeys().Count > 0)
{
key = KeyService.GetAllPressedKeys().First(); key = KeyService.GetAllPressedKeys().First();
} }
if (controlGroupWas != controlGroup || keyWas != key) { if (controlGroupWas != controlGroup || keyWas != key)
{
StateHasChanged(); StateHasChanged();
} }
} }
private void HandleClick() { private void HandleClick()
{
var hotkey = KeyService.GetHotkey(); var hotkey = KeyService.GetHotkey();
if (hotkey == "") { if (hotkey == "")
{
return; return;
} }
if (hotkey == "`") { if (hotkey == "`")
{
BuildOrderService.RemoveLast(); BuildOrderService.RemoveLast();
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval()); EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
return; return;
@ -303,31 +351,38 @@
var entity = EntityModel.GetFrom(hotkey!, hotkeyGroup, isHoldSpace, faction, immortal); var entity = EntityModel.GetFrom(hotkey!, hotkeyGroup, isHoldSpace, faction, immortal);
if (entity == null) { if (entity == null)
{
return; return;
} }
if (BuildOrderService.Add(entity, EconomyService)) { if (BuildOrderService.Add(entity, EconomyService))
{
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval()); EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
} }
} }
private void ButtonClicked(MouseEventArgs mouseEventArgs, HotkeyModel hotkey) { private void ButtonClicked(MouseEventArgs mouseEventArgs, HotkeyModel hotkey)
{
DataCollectionService.SendEvent( DataCollectionService.SendEvent(
DataCollectionKeys.BuildCalcInput, DataCollectionKeys.BuildCalcInput,
new Dictionary<string, string> { { "key", hotkey.KeyText.ToLower() }, { "input-source", "mouse" } } new Dictionary<string, string> { { "key", hotkey.KeyText.ToLower() }, { "input-source", "mouse" } }
); );
if (hotkey.KeyText.Equals(HotKeyType.SPACE.ToString())) { if (hotkey.KeyText.Equals(HotKeyType.SPACE.ToString()))
if (KeyService.IsHoldingSpace()) { {
if (KeyService.IsHoldingSpace())
{
KeyService.RemovePressedKey(hotkey.KeyText); KeyService.RemovePressedKey(hotkey.KeyText);
} }
else { else
{
KeyService.AddPressedKey(hotkey.KeyText); KeyService.AddPressedKey(hotkey.KeyText);
} }
} }
else { else
{
KeyService.AddPressedKey(hotkey.KeyText); KeyService.AddPressedKey(hotkey.KeyText);
KeyService.RemovePressedKey(hotkey.KeyText); KeyService.RemovePressedKey(hotkey.KeyText);
} }

2
IGP/Pages/BuildCalculator/Parts/InputPanelComponent.razor

@ -23,7 +23,7 @@
{ {
DataCollectionService.SendEvent( DataCollectionService.SendEvent(
DataCollectionKeys.BuildCalcInput, DataCollectionKeys.BuildCalcInput,
new Dictionary<string, string> {{"key", e.Key.ToLower()}, {"input-source", "keyboard"}} new Dictionary<string, string> { { "key", e.Key.ToLower() }, { "input-source", "keyboard" } }
); );
KeyService.AddPressedKey(e.Key); KeyService.AddPressedKey(e.Key);

3
IGP/Pages/BuildCalculator/Parts/OptionsComponent.razor

@ -4,8 +4,6 @@
@inject IEconomyService EconomyService @inject IEconomyService EconomyService
@inject IToastService ToastService @inject IToastService ToastService
@inject ITimingService TimingService @inject ITimingService TimingService
@using System.Data
@implements IDisposable @implements IDisposable
<FormLayoutComponent> <FormLayoutComponent>
@ -70,7 +68,6 @@
WaitTo = TimingService.WaitTo; WaitTo = TimingService.WaitTo;
StateHasChanged(); StateHasChanged();
} }
void OnBuildingInputDelayChanged(ChangeEventArgs changeEventArgs) void OnBuildingInputDelayChanged(ChangeEventArgs changeEventArgs)

133
IGP/Pages/ChangeLogPage.razor

@ -1,133 +0,0 @@
@page "/changelog"
@implements IDisposable;
@inject IGitService GitService;
@inherits BasePage
@inject IDataCollectionService DataCollectionService
@layout PageLayout
@if (GitService.IsLoaded())
{
<LayoutMediumContentComponent>
<WebsiteTitleComponent>Change Log</WebsiteTitleComponent>
<PaperComponent>
<FormLayoutComponent>
<FormCheckboxComponent Label="Show Important"
Info="Only show important patches. Like database updates to the latest game patch."
Value="@isViewImportant"
OnChange="OnChangeClicked">
</FormCheckboxComponent>
</FormLayoutComponent>
</PaperComponent>
<PaperComponent>
@foreach (var patch in Patches.OrderBy(x => x.Date).Reverse())
{
@if (!patch.Important.Equals("True") && isViewImportant)
{
continue;
}
var daysAgo = Math.Floor(DateTime.Now.Subtract(patch.Date).TotalDays);
<div class="patchContainer">
<div style="display: flex; justify-content: space-between;">
<div style="font-size: 1.2rem; font-weight: bolder; margin-bottom:4px;">
@patch.Name
</div>
<div>
@if (daysAgo == 0)
{
<i>Today</i>
}
else if (daysAgo < 8)
{
<i>@daysAgo days ago</i>
}
else
{
<i>@patch.Date.ToString("dd/MM/yyyy")</i>
}
</div>
</div>
<div>
@foreach (var change in Changes.FindAll(e => e.GitPatchModelId == patch.Id))
{
@if (!change.Important.Equals("True") && isViewImportant)
{
continue;
}
<div style="display: flex; justify-content: space-between; ">
<div>
<div>
<b>
<span>- @change.Name </span>
@if (change.Commit != CommitType.None)
{
<span>(@change.Commit)</span>
}
<span>: </span>
</b> @((MarkupString)change.Description)
</div>
</div>
</div>
}
</div>
</div>
}
</PaperComponent>
</LayoutMediumContentComponent>
}
else
{
<LoadingComponent/>
}
@code {
private IEnumerable<GitPatchModel> Patches => GitService.GitPatchModels;
private List<GitChangeModel> Changes => GitService.GitChangeModels;
private bool isViewImportant = true;
protected override void OnInitialized()
{
base.OnInitialized();
GitService.Subscribe(HasChanged);
}
void IDisposable.Dispose()
{
GitService.Unsubscribe(HasChanged);
}
void OnChangeClicked(ChangeEventArgs changeEventArgs)
{
isViewImportant = (bool)changeEventArgs.Value!;
StateHasChanged();
}
void HasChanged()
{
StateHasChanged();
}
protected override async Task OnInitializedAsync()
{
await GitService.Load();
}
}

13
IGP/Pages/ChangeLogPage.razor.css

@ -1,13 +0,0 @@
.patchContainer {
padding: 16px;
}
@media only screen and (max-width: 1025px) {
.patchContainer {
border: none;
padding-left: 8px;
padding-right: 8px;
padding-top: 16px;
padding-bottom: 16px;
}
}

106
IGP/Pages/Comparision/ComparisionPage.razor

@ -1,106 +0,0 @@
@layout PageLayout
@inherits BasePage
@implements IDisposable
@inject IToastService ToastService
<div style="display:grid; gap: 8px;padding: 16px; height: 94vh; width: 90vw; margin: auto; margin-top: 32px;
grid-template-columns: 27% 25% 25% 23%; grid-template-rows: auto;
grid-template-areas: 'loader sand compare compare' ;">
<div style="grid-area: loader; border: 2px solid black; padding: 20px;">
Comparision Loader
<BuildLoaderComponent></BuildLoaderComponent>
</div>
<div style="grid-area: sand; border: 2px solid black; padding: 20px;">
Sand
<SandComponent></SandComponent>
</div>
<div style="grid-area: compare; border: 2px solid black; padding: 20px;">
Comparision Charts
</div>
</div>
@code {
[Inject]
IKeyService KeyService { get; set; } = default!;
[Inject]
IImmortalSelectionService FilterService { get; set; } = default!;
[Inject]
IBuildOrderService BuildOrderService { get; set; } = default!;
[Inject]
IEconomyService EconomyService { get; set; } = default!;
[Inject]
ITimingService TimingService { get; set; } = default!;
Dictionary<int, List<EntityModel>> completedEntities = new();
List<EntityModel> entities = EntityModel.GetListOnlyHotkey();
protected override void OnInitialized()
{
base.OnInitialized();
KeyService.Subscribe(HandleClick);
FilterService.Subscribe(StateHasChanged);
EconomyService.Subscribe(StateHasChanged);
TimingService.Subscribe(HandleTimingChanged);
EconomyService.Calculate(BuildOrderService, TimingService, 0);
}
void IDisposable.Dispose()
{
KeyService.Unsubscribe(HandleClick);
FilterService.Unsubscribe(StateHasChanged);
TimingService.Unsubscribe(StateHasChanged);
EconomyService.Unsubscribe(StateHasChanged);
}
protected void HandleTimingChanged()
{
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
}
protected void HandleClick()
{
var hotkey = KeyService.GetHotkey();
var hotkeyGroup = KeyService.GetHotkeyGroup();
var isHoldSpace = KeyService.IsHoldingSpace();
var faction = FilterService.GetFaction();
var immortal = FilterService.GetImmortal();
if (hotkey == "`")
{
BuildOrderService.RemoveLast();
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
StateHasChanged();
return;
}
var entity = EntityModel.GetFrom(hotkey!, hotkeyGroup, isHoldSpace, faction, immortal);
if (entity == null)
{
return;
}
if (BuildOrderService.Add(entity, EconomyService))
{
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
}
}
}

37
IGP/Pages/Comparision/Parts/BuildLoaderComponent.razor

@ -1,37 +0,0 @@
@implements IDisposable
<div>
<Button Color="Color.Primary" @onclick="OnLoad">Load</Button>
<button @onclick="OnLoad">Load</button>
</div>
<div>
<textarea @bind="buildData" @bind:event="oninput"
style="background-color: #36393F; width: 330px; height: 400px;">
</textarea>
</div>
@code {
string buildData = "";
[Inject]
IBuildComparisonService BuildComparisionService { get; set; } = default!;
protected override void OnInitialized()
{
base.OnInitialized();
BuildComparisionService.Subscribe(StateHasChanged);
}
void IDisposable.Dispose()
{
BuildComparisionService.Unsubscribe(StateHasChanged);
}
void OnLoad()
{
BuildComparisionService.LoadJson(buildData);
}
}

25
IGP/Pages/Comparision/Parts/SandComponent.razor

@ -1,25 +0,0 @@
@implements IDisposable
<div>
<textarea readonly style="background-color: #36393F; width: 330px; height: 400px;">
@BuildComparisonService.AsJson()
</textarea>
</div>
@code {
[Inject]
IBuildComparisonService BuildComparisonService { get; set; } = default!;
protected override void OnInitialized()
{
base.OnInitialized();
BuildComparisonService.Subscribe(StateHasChanged);
}
void IDisposable.Dispose()
{
BuildComparisonService.Unsubscribe(StateHasChanged);
}
}

1
IGP/Pages/Database/DatabaseSinglePage.razor

@ -11,7 +11,6 @@
<LayoutLargeContentComponent> <LayoutLargeContentComponent>
<PaperComponent> <PaperComponent>
<FormDisplayComponent Label="Patch"> <FormDisplayComponent Label="Patch">
<Display> <Display>

3
IGP/Pages/Database/Parts/EntityFilterComponent.razor

@ -10,7 +10,8 @@
styleClass = "selected"; styleClass = "selected";
} }
<button @onclick="@(e => OnChangeFaction(choice))" <button @onclick="@(e => OnChangeFaction(choice))"
class="choiceButton @styleClass">@(choice == DataType.Any class="choiceButton @styleClass">
@(choice == DataType.Any
? DataType.Any ? DataType.Any
: DATA.Get()[choice].Info().Name) : DATA.Get()[choice].Info().Name)
</button> </button>

117
IGP/Pages/Documentation/DocumentationIndexPage.razor

@ -1,117 +0,0 @@
@layout PageLayout
@inherits BasePage
@inject IDocumentationService DocumentationService
@implements IDisposable
@page "/docs"
@if (!DocumentationService.IsLoaded())
{
<LoadingComponent/>
}
else
{
<LayoutMediumContentComponent>
<PaperComponent>
@foreach (var docSection in DocumentationService.DocSectionModels)
{
<div class="docSectionContainer">
<div class="docSectionTitle">@docSection.Name</div>
<div class="docContentContainer">
@foreach (var docContent in docSection.DocumentationModels)
{
<NavLink class="docContentLink" href="@docContent.GetDocLink()">
<div class="docContentName">@docContent.Name</div>
<div class="docContentDescription">@docContent.Description</div>
</NavLink>
}
</div>
</div>
}
</PaperComponent>
</LayoutMediumContentComponent>
}
<style>
.docSectionContainer {
width: 100%;
padding: 8px;
}
.docSectionTitle {
font-size: 3rem;
font-weight: bold;
text-align: center;
margin-bottom: 32px;
}
.docContentContainer {
display: grid;
gap: 12px;
grid-template-columns: 1fr 1fr;
}
@@media only screen and (max-width: 1025px) {
.docContentContainer {
grid-template-columns: 1fr;
}
}
.docContentName {
font-weight: bold;
font-size: 1.6rem;
}
.docContentDescription {
font-weight: normal;
}
.docContentLink {
background-color: var(--paper);
border: 1px solid var(--paper-border);
border-radius: 2px;
padding-left: 12px;
padding-right: 12px;
padding-top: 24px;
padding-bottom: 24px;
color: white;
display: flex;
flex-direction: column;
gap: 12px;
text-align: center;
margin-left: 12px;
margin-right: 12px;
}
.docContentLink:hover {
background-color: var(--paper-hover);
border-color: var(--paper-border-hover);
text-decoration: none;
box-shadow: 0 4px 6px rgba(0,0,0,0.6);
transform: translateY(-2px) scale(1.01);
}
</style>
@code {
[Parameter]
public string? Text { get; set; }
protected override void OnInitialized()
{
base.OnInitialized();
DocumentationService.Subscribe(StateHasChanged);
DocumentationService.Load();
}
void IDisposable.Dispose()
{
DocumentationService.Unsubscribe(StateHasChanged);
}
}

123
IGP/Pages/Documentation/DocumentationPage.razor

@ -1,123 +0,0 @@
@layout PageLayout
@inherits BasePage
@inject IDocumentationService DocumentationService
@implements IDisposable
@page "/docs/{href1}/{href2?}/{href3?}/{href4?}/{href5?}"
@if (!DocumentationService.IsLoaded())
{
<LoadingComponent/>
}
else
{
<LayoutWithSidebarComponent>
<Sidebar>
<DocumentNavComponent
Connections="DocumentationService.DocConnectionModels"
Documents="DocumentationService.DocContentModels"/>
</Sidebar>
<Content>
<PaperComponent>
@foreach (var doc in DocumentationService.DocContentModels)
{
if (!doc.Href.Equals(Href))
{
continue;
}
<DocumentComponent DocContentModel="doc"/>
}
</PaperComponent>
</Content>
</LayoutWithSidebarComponent>
}
<style>
pre code {
color: white;
}
h1 {
display: block;
font-size: 2em;
margin-top: 0.67em;
margin-bottom: 0.67em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
}
h2 {
display: block;
font-size: 1.5em;
margin-top: 0.83em;
margin-bottom: 0.83em;
margin-left: 0;
margin-right: 0;
font-weight: bold;
}
li {
display: list-item;
}
p {
display: block;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
}
ul {
display: block;
list-style-type: disc;
margin-top: 1em;
margin-bottom: 1em;
margin-left: 0;
margin-right: 0;
padding-left: 40px;
}
pre {
background: black;
padding: 2px;
}
</style>
@code {
[Parameter]
public string? Href1 { get; set; }
[Parameter]
public string? Href2 { get; set; }
[Parameter]
public string? Href3 { get; set; }
[Parameter]
public string? Href4 { get; set; }
[Parameter]
public string? Href5 { get; set; }
private string Href => Href5 ?? Href4 ?? Href3 ?? Href2 ?? Href1 ?? "";
protected override void OnInitialized()
{
base.OnInitialized();
DocumentationService.Subscribe(StateHasChanged);
DocumentationService.Load();
}
void IDisposable.Dispose()
{
DocumentationService.Unsubscribe(StateHasChanged);
}
}

6
IGP/Pages/Documentation/Parts/DocumentComponent.razor

@ -16,7 +16,9 @@ else
</div> </div>
<div class="docContent">@((MarkupString)Markdown.ToHtml(content, Pipeline))</div> <div class="docContent">@((MarkupString)Markdown.ToHtml(content, Pipeline))</div>
<div class="docFooter"> <div class="docFooter">
<EditLinkComponent Href="@GitUrl"></EditLinkComponent> <LinkButtonComponent Href="@GitUrl">
Edit on GitHub <i class="fa-brands fa-github" style="font-size: 24px; margin-left: 5px;"></i>
</LinkButtonComponent>
</div> </div>
</div> </div>
} }
@ -57,7 +59,7 @@ else
public DocContentModel DocContentModel { get; set; } = default!; public DocContentModel DocContentModel { get; set; } = default!;
DocFrontMatterModel docFrontMatter = null!; DocFrontMatterModel docFrontMatter = null!;
private string? content = null; private string? content;
private string Filepath => $"content/docs/{DocContentModel.Content}.md"; private string Filepath => $"content/docs/{DocContentModel.Content}.md";
private string GitUrl => $"{Project.GitResourcesUrl}/{Filepath}"; private string GitUrl => $"{Project.GitResourcesUrl}/{Filepath}";

70
IGP/Pages/Documentation/Parts/DocumentInnerNavComponent.razor

@ -1,70 +0,0 @@
@if (Document!.DocumentationModels.Count > 0)
{
<div class="docInnerNavContainer">
@foreach (var innerDoc in Document.DocumentationModels)
{
var linkStyle = $"docInnerNavButton inner_{Layers}";
<NavLink class="@linkStyle" href="@innerDoc.GetDocLink()">@innerDoc.Name</NavLink>
<DocumentInnerNavComponent Document="@innerDoc" Layers="@IncrementLayers()"/>
}
</div>
}
<style>
.docInnerNavContainer {
display: flex;
flex-direction: column;
}
.docInnerNavButton a {
color: white;
}
.docInnerNavButton a:hover {
color: white;
}
.docInnerNavButton {
padding: 8px;
margin-left: 8px;
color: white;
}
.inner_1 {
margin-left: 8px;
}
.inner_2 {
margin-left: 16px;
}
.inner_3 {
margin-left: 24px;
}
</style>
@code {
[Parameter]
public DocContentModel? Document { get; set; } = default!;
[Parameter]
public int Layers { get; set; } = 1;
public int IncrementLayers()
{
return Layers + 1;
}
private string GetLink(DocContentModel doc)
{
return $"docs/{doc.Href}";
}
}

47
IGP/Pages/Documentation/Parts/DocumentNavComponent.razor

@ -1,47 +0,0 @@
<div class="docNavContainer">
@foreach (var doc in Documents)
{
if (doc.Parent == null)
{
<NavLink class="docNavButton" href="@doc.GetDocLink()">@doc.Name</NavLink>
<DocumentInnerNavComponent Document="@doc"/>
}
}
</div>
<style>
.docNavContainer {
display: flex;
flex-direction: column;
gap: 8px;
}
.docNavButton a {
color: white;
}
.docNavButton a:hover {
color: white;
}
.docNavButton {
padding: 8px;
color: white;
}
</style>
@code {
[Parameter]
public List<DocContentModel> Documents { get; set; } = default!;
[Parameter]
public List<DocConnectionModel> Connections { get; set; } = default!;
private string GetLink(DocContentModel doc)
{
return $"docs/{doc.Href}";
}
}

4
IGP/Pages/EconomyComparison/EconomyComparisonPage.razor

@ -7,6 +7,8 @@
@layout PageLayout @layout PageLayout
<LayoutMediumContentComponent> <LayoutMediumContentComponent>
<WebsiteTitleComponent>Economy Comparision</WebsiteTitleComponent>
<PaperComponent> <PaperComponent>
<div>You</div> <div>You</div>
<EconomyInputComponent ForPlayer="0"/> <EconomyInputComponent ForPlayer="0"/>
@ -40,6 +42,7 @@
</LayoutMediumContentComponent> </LayoutMediumContentComponent>
@code { @code {
protected override void OnInitialized() protected override void OnInitialized()
{ {
base.OnInitialized(); base.OnInitialized();
@ -50,4 +53,5 @@
{ {
EconomyComparisonService.Unsubscribe(StateHasChanged); EconomyComparisonService.Unsubscribe(StateHasChanged);
} }
} }

2
IGP/Pages/EconomyComparison/Parts/ChartComponent.razor

@ -79,7 +79,6 @@
void OnBuilderOrderChanged() void OnBuilderOrderChanged()
{ {
charts = new List<ChartModel>(); charts = new List<ChartModel>();
var index = 0; var index = 0;
@ -124,7 +123,6 @@
}; };
for (var interval = 0; interval < economyOverTime.Count(); interval++) for (var interval = 0; interval < economyOverTime.Count(); interval++)
{ {
var alloyPoint = new PointModel { Interval = interval }; var alloyPoint = new PointModel { Interval = interval };

3
IGP/Pages/EconomyComparison/Parts/EconomyDifferenceComponent.razor

@ -88,7 +88,7 @@
WorseningTime = 0; WorseningTime = 0;
MiracleTime = 0; MiracleTime = 0;
for (int interval = 0; interval < economyComparisonService.BuildsToCompare[0].EconomyOverTimeModel.Count; interval++) for (var interval = 0; interval < economyComparisonService.BuildsToCompare[0].EconomyOverTimeModel.Count; interval++)
{ {
var yourEconomy = economyComparisonService.BuildsToCompare[0].EconomyOverTimeModel[interval]; var yourEconomy = economyComparisonService.BuildsToCompare[0].EconomyOverTimeModel[interval];
var theirEconomy = economyComparisonService.BuildsToCompare[1].EconomyOverTimeModel[interval]; var theirEconomy = economyComparisonService.BuildsToCompare[1].EconomyOverTimeModel[interval];
@ -109,7 +109,6 @@
} }
else else
{ {
if (PeakAdvantageByAlloy > 0 && WorseningTime == 0) if (PeakAdvantageByAlloy > 0 && WorseningTime == 0)
{ {
WorseningTime = interval; WorseningTime = interval;

4
IGP/Pages/EconomyComparison/Parts/EconomyInputComponent.razor

@ -22,14 +22,14 @@
{ {
index++; index++;
<FormNumberComponent Value="@timing" OnChange="(e)=> ChangeBuildTime(e, index - 1)"> <FormNumberComponent Value="@timing" OnChange="e => ChangeBuildTime(e, index - 1)">
<FormLabelComponent> <FormLabelComponent>
TownHall build time TownHall build time
</FormLabelComponent> </FormLabelComponent>
</FormNumberComponent> </FormNumberComponent>
} }
<ContentDividerComponent/> <ContentDividerComponent/>
<FormTextComponent Label="Chart Color" Value="@ChartColor" OnChange="ChangeColor" /> <FormTextComponent Label="Chart Color" Value="@ChartColor" OnChange="ChangeColor"/>
</FormLayoutComponent> </FormLayoutComponent>

99
IGP/Pages/HarassCalculatorPage.razor

@ -51,9 +51,11 @@
@{ @{
var index = 0; var index = 0;
} }
@foreach (var travelTime in TravelTimes) { @foreach (var travelTime in TravelTimes)
{
index++; index++;
if (index == 1) { if (index == 1)
{
continue; continue;
} }
var id = $"numberOfTownHallsExisting_{index}"; var id = $"numberOfTownHallsExisting_{index}";
@ -104,8 +106,11 @@
</InfoQuestionComponent> </InfoQuestionComponent>
<InfoAnswerComponent> <InfoAnswerComponent>
The Harass Calculator allows you to calculate damage done to an enemy alloy line. For example, if you The Harass Calculator allows you to calculate damage done to an enemy alloy line. For example, if you
were to attack with Ichors, and kill 6 enemy workers, you can set the <b>Number of workers lost to were to attack with Ichors, and kill 6 enemy workers, you can set the
harass</b> to 6. This would determine a loss of <span id="exampleTotalAlloyLoss">@ExampleTotalAlloyLoss</span> alloy. Quite <b>
Number of workers lost to
harass
</b> to 6. This would determine a loss of <span id="exampleTotalAlloyLoss">@ExampleTotalAlloyLoss</span> alloy. Quite
the large number. the large number.
</InfoAnswerComponent> </InfoAnswerComponent>
</InfoBodyComponent> </InfoBodyComponent>
@ -126,10 +131,16 @@
entirely accurate, you are also going to have to bump up the <b>Worker travel time to alloy</b> to account for the time it takes the transferred workers to arrive at the decimated alloy line. entirely accurate, you are also going to have to bump up the <b>Worker travel time to alloy</b> to account for the time it takes the transferred workers to arrive at the decimated alloy line.
<br/><br/> <br/><br/>
Let's say it takes 10 seconds for workers to transfer from your second base. Let's enter that for the Let's say it takes 10 seconds for workers to transfer from your second base. Let's enter that for the
second base travel time for the more accurate loss of <span second base travel time for the more accurate loss of
id="exampleTotalAlloyLossAccurate">@ExampleTotalAlloyLossAccurate</span> alloy <span
(saving you <span id="exampleTotalAlloyLossAccurateDifference">@ExampleTotalAlloyLossAccurateDifference</span> alloy.) <i>Which is id="exampleTotalAlloyLossAccurate">
much better than not transferring workers!</i> @ExampleTotalAlloyLossAccurate
</span> alloy
(saving you <span id="exampleTotalAlloyLossAccurateDifference">@ExampleTotalAlloyLossAccurateDifference</span> alloy.)
<i>
Which is
much better than not transferring workers!
</i>
</InfoAnswerComponent> </InfoAnswerComponent>
</InfoBodyComponent> </InfoBodyComponent>
@ -180,7 +191,10 @@
Can I see the code for the calculation? Can I see the code for the calculation?
</InfoQuestionComponent> </InfoQuestionComponent>
<InfoAnswerComponent> <InfoAnswerComponent>
<CodeLinkComponent Href="https://github.com/JonathanMcCaffrey/IGP-Fan-Reference/blob/main/IGP/Pages/HarassCalculatorPage.razor"/> <br/>
<LinkButtonComponent Href="https://github.com/JonathanMcCaffrey/IGP-Fan-Reference/blob/main/IGP/Pages/HarassCalculatorPage.razor">
View on GitHub <i class="fa-brands fa-github" style="font-size: 24px; margin-left: 5px;"></i>
</LinkButtonComponent>
</InfoAnswerComponent> </InfoAnswerComponent>
</InfoBodyComponent> </InfoBodyComponent>
</PaperComponent> </PaperComponent>
@ -211,7 +225,7 @@
// Example calcs // Example calcs
float ExampleTotalAlloyLoss => Calculate( float ExampleTotalAlloyLoss => Calculate(
WorkerReplacementCost(6), WorkerReplacementCost(6),
SimultaneousProductionFloor(1,6), SimultaneousProductionFloor(1, 6),
6, 6,
new List<float> { 0 }); new List<float> { 0 });
@ -221,19 +235,19 @@
float ExampleTotalAlloyLossDifference => ExampleTotalAlloyLoss - Calculate( float ExampleTotalAlloyLossDifference => ExampleTotalAlloyLoss - Calculate(
WorkerReplacementCost(6), WorkerReplacementCost(6),
SimultaneousProductionFloor(2,6), SimultaneousProductionFloor(2, 6),
6, 6,
new List<float> { 0, 0 }); new List<float> { 0, 0 });
float ExampleTotalAlloyLossAccurate => Calculate( float ExampleTotalAlloyLossAccurate => Calculate(
WorkerReplacementCost(6), WorkerReplacementCost(6),
SimultaneousProductionFloor(2,6), SimultaneousProductionFloor(2, 6),
6, 6,
new List<float> { 0, 10 }); new List<float> { 0, 10 });
float ExampleTotalAlloyLossAccurateDifference => ExampleTotalAlloyLoss - ExampleTotalAlloyLossAccurate; float ExampleTotalAlloyLossAccurateDifference => ExampleTotalAlloyLoss - ExampleTotalAlloyLossAccurate;
float TotalAlloyHarassment = 0; float TotalAlloyHarassment;
readonly float CostOfWorker = 50; readonly float CostOfWorker = 50;
readonly float AlloyMinedPerSecondByWorker = 1; readonly float AlloyMinedPerSecondByWorker = 1;
@ -241,14 +255,17 @@
float NumberOfWorkersLostToHarass = 1; float NumberOfWorkersLostToHarass = 1;
float NumberOfTownHallsExisting = 1; float NumberOfTownHallsExisting = 1;
float GetAverageTravelTime() { float GetAverageTravelTime()
if (TravelTimes.Count == 0) { {
if (TravelTimes.Count == 0)
{
return 0; return 0;
} }
float sum = 0; float sum = 0;
foreach (var travelTime in TravelTimes) { foreach (var travelTime in TravelTimes)
{
sum += travelTime.Value; sum += travelTime.Value;
} }
@ -256,35 +273,43 @@
} }
float SimultaneousProductionFloor() { float SimultaneousProductionFloor()
if (NumberOfTownHallsExisting <= 0 || NumberOfWorkersLostToHarass <= 0) { {
if (NumberOfTownHallsExisting <= 0 || NumberOfWorkersLostToHarass <= 0)
{
return 0; return 0;
} }
return NumberOfWorkersLostToHarass / Math.Min(NumberOfTownHallsExisting, NumberOfWorkersLostToHarass); return NumberOfWorkersLostToHarass / Math.Min(NumberOfTownHallsExisting, NumberOfWorkersLostToHarass);
} }
float SimultaneousProductionFloor(float existingTownHalls, float numberOfWorkersLost) { float SimultaneousProductionFloor(float existingTownHalls, float numberOfWorkersLost)
if (existingTownHalls <= 0 || numberOfWorkersLost <= 0) { {
if (existingTownHalls <= 0 || numberOfWorkersLost <= 0)
{
return 0; return 0;
} }
return numberOfWorkersLost / Math.Min(existingTownHalls, numberOfWorkersLost); return numberOfWorkersLost / Math.Min(existingTownHalls, numberOfWorkersLost);
} }
float WorkerReplacementCost() { float WorkerReplacementCost()
{
return CostOfWorker * NumberOfWorkersLostToHarass; return CostOfWorker * NumberOfWorkersLostToHarass;
} }
float WorkerReplacementCost(int numberOfWorkersLostToHarass) { float WorkerReplacementCost(int numberOfWorkersLostToHarass)
{
return CostOfWorker * numberOfWorkersLostToHarass; return CostOfWorker * numberOfWorkersLostToHarass;
} }
float DelayedMiningCost() { float DelayedMiningCost()
{
return TotalAlloyHarassment - WorkerReplacementCost(); return TotalAlloyHarassment - WorkerReplacementCost();
} }
void Calculate() { void Calculate()
{
TotalAlloyHarassment = Calculate(WorkerReplacementCost(), TotalAlloyHarassment = Calculate(WorkerReplacementCost(),
SimultaneousProductionFloor(), SimultaneousProductionFloor(),
NumberOfWorkersLostToHarass, NumberOfWorkersLostToHarass,
@ -298,20 +323,23 @@
float numberOfWorkersLostToHarass, float numberOfWorkersLostToHarass,
IList<float> travelTimes, IList<float> travelTimes,
float timeToProduceWorker = 20, float timeToProduceWorker = 20,
float alloyMinedPerSecondByWorker = 1) { float alloyMinedPerSecondByWorker = 1)
{
float totalAlloyHarassment = workerReplacementCost; var totalAlloyHarassment = workerReplacementCost;
for (var workerProductionIndex = 0; workerProductionIndex < simultaneousProductionFloor; workerProductionIndex++) { for (var workerProductionIndex = 0; workerProductionIndex < simultaneousProductionFloor; workerProductionIndex++)
{
totalAlloyHarassment += alloyMinedPerSecondByWorker * timeToProduceWorker * (workerProductionIndex + 1); totalAlloyHarassment += alloyMinedPerSecondByWorker * timeToProduceWorker * (workerProductionIndex + 1);
} }
var remainder = (int)(numberOfWorkersLostToHarass % simultaneousProductionFloor); var remainder = (int)(numberOfWorkersLostToHarass % simultaneousProductionFloor);
for (var remainderIndex = 0; remainderIndex < remainder; remainderIndex++) { for (var remainderIndex = 0; remainderIndex < remainder; remainderIndex++)
{
totalAlloyHarassment += alloyMinedPerSecondByWorker * timeToProduceWorker * (simultaneousProductionFloor + 1); totalAlloyHarassment += alloyMinedPerSecondByWorker * timeToProduceWorker * (simultaneousProductionFloor + 1);
} }
for (var travelTimeIndex = 0; travelTimeIndex < numberOfWorkersLostToHarass; travelTimeIndex++) { for (var travelTimeIndex = 0; travelTimeIndex < numberOfWorkersLostToHarass; travelTimeIndex++)
{
var townHallIndex = travelTimeIndex % travelTimes.Count; var townHallIndex = travelTimeIndex % travelTimes.Count;
totalAlloyHarassment += alloyMinedPerSecondByWorker * travelTimes[townHallIndex]; totalAlloyHarassment += alloyMinedPerSecondByWorker * travelTimes[townHallIndex];
} }
@ -319,7 +347,8 @@
return totalAlloyHarassment; return totalAlloyHarassment;
} }
protected override void OnInitialized() { protected override void OnInitialized()
{
base.OnInitialized(); base.OnInitialized();
Calculate(); Calculate();
} }
@ -327,18 +356,20 @@
public List<TravelTime> TravelTimes { get; set; } = new() { new TravelTime(0, 0) }; public List<TravelTime> TravelTimes { get; set; } = new() { new TravelTime(0, 0) };
private void OnTownHallsChanged(ChangeEventArgs obj) { private void OnTownHallsChanged(ChangeEventArgs obj)
{
NumberOfTownHallsExisting = int.Parse(obj.Value!.ToString()!); NumberOfTownHallsExisting = int.Parse(obj.Value!.ToString()!);
while (TravelTimes.Count > NumberOfTownHallsExisting) while (TravelTimes.Count > NumberOfTownHallsExisting)
TravelTimes.Remove(TravelTimes.Last()); TravelTimes.Remove(TravelTimes.Last());
while (TravelTimes.Count < NumberOfTownHallsExisting) while (TravelTimes.Count < NumberOfTownHallsExisting)
TravelTimes.Add(new TravelTime(TravelTimes.Count, 10 * (TravelTimes.Count))); TravelTimes.Add(new TravelTime(TravelTimes.Count, 10 * TravelTimes.Count));
Calculate(); Calculate();
} }
private void OnTownHallTravelTimeChanged(ChangeEventArgs obj, TravelTime travelTime) { private void OnTownHallTravelTimeChanged(ChangeEventArgs obj, TravelTime travelTime)
{
travelTime.Value = (int)obj.Value!; travelTime.Value = (int)obj.Value!;
Calculate(); Calculate();

8
IGP/Pages/Home/HomePage.razor

@ -48,14 +48,6 @@
</div> </div>
</PaperComponent> </PaperComponent>
<ContentDividerComponent></ContentDividerComponent>
<AlertComponent>
<Title>Under Construction</Title>
<Message>Website is still being made. Check out <NavLink Href="/roadmap">Road Map</NavLink> for future plans, <NavLink Href="/agile">Agile</NavLink> for present tasks, and <NavLink Href="/changelog">Change Log</NavLink> for past changes.</Message>
</AlertComponent>
</LayoutMediumContentComponent> </LayoutMediumContentComponent>
<style> <style>

88
IGP/Pages/MakingOf/MakingOfPage.razor

@ -1,88 +0,0 @@
@page "/makingof"
@inherits BasePage
@inject IDataCollectionService DataCollectionService
@layout PageLayout
<LayoutLargeContentComponent>
<WebsiteTitleComponent>Making Of</WebsiteTitleComponent>
<AlertComponent Type="@SeverityType.Warning">
<Title>Under Construction</Title>
<Message>This page is still being worked on. It will list the tech and design choices made for this website. It's is strictly for educational and reference purposes, and it has nothing to do with IMMORTAL: Gates of Pyre.</Message>
</AlertComponent>
<ContentDividerComponent></ContentDividerComponent>
<FormLayoutComponent>
<FormDisplayComponent Label="Tech Stack">
<Display>Blazor (C# and HTML)</Display>
</FormDisplayComponent>
<FormDisplayComponent Label="Stack Details">
<Display>This is a Static Single Page Application hosted on Azure.</Display>
</FormDisplayComponent>
</FormLayoutComponent>
<ContentDividerComponent></ContentDividerComponent>
<MakingOfColours></MakingOfColours>
<ContentDividerComponent></ContentDividerComponent>
<DevOnlyComponent>
<MakingOfSectionComponent Title="Empty">
<MakingOfComponent>
<Title>
Empty
</Title>
<Description>
Empty
</Description>
<Example>
Empty
</Example>
<Usage>
<CodeComponent>Empty</CodeComponent>
</Usage>
<Code>
<CodeComponent>Empty</CodeComponent>
</Code>
</MakingOfComponent>
</MakingOfSectionComponent>
</DevOnlyComponent>
<DevOnlyComponent>
<MakingOfSectionComponent Title="Dialogs">
<MakingOfDialogs></MakingOfDialogs>
</MakingOfSectionComponent>
</DevOnlyComponent>
<DevOnlyComponent>
<FormLayoutComponent>
<FormEscapeCodeComponent></FormEscapeCodeComponent>
</FormLayoutComponent>
</DevOnlyComponent>
<MakingOfSectionComponent Title="Displays">
<MakingOfDisplays></MakingOfDisplays>
</MakingOfSectionComponent>
<DevOnlyComponent>
<MakingOfSectionComponent Title="Navigation">
<MakingOfNavigation></MakingOfNavigation>
</MakingOfSectionComponent>
</DevOnlyComponent>
<MakingOfSectionComponent Title="Feedback">
<MakingOfFeedback></MakingOfFeedback>
</MakingOfSectionComponent>
<MakingOfSectionComponent Title="Forms">
<MakingOfForms></MakingOfForms>
</MakingOfSectionComponent>
</LayoutLargeContentComponent>

188
IGP/Pages/MakingOf/Parts/MakingOfColours.razor

@ -1,188 +0,0 @@
<div>Colors</div>
<div class="colorContainer">
<CodeComponent>
--accent: @accent;
--primary: @primary;
--primary-border: @primary_border;
--primary-hover: @primary_hover;
--primary-border-hover: @primary_border_hover;
--background: @background;
--secondary: @secondary;
--secondary-hover: @secondary_hover;
--secondary-border-hover: @secondary_border_hover;
--paper: @paper;
--paper-border: @paper_border;
--info: @info;
--info-border: @info_border;
--info-secondary: @info_secondary;
--info-secondary-border: @info_secondary_border;
</CodeComponent>
<br/>
<div class="color accent">
<div>Accent</div>
<div>
Base: <input type="color" value="@accent" @onchange="e => accent = e.Value!.ToString()!"/>
</div>
</div>
<div class="color primary">
<div>Primary</div>
<div>
Base: <input type="color" value="@primary" @onchange="e => primary = e.Value!.ToString()!"/>
</div>
<div>
Border: <input type="color" value="@primary_border" @onchange="e => primary_border = e.Value!.ToString()!"/>
</div>
<div>
Hover Base: <input type="color" value="@primary_hover" @onchange="e => primary_hover = e.Value!.ToString()!"/>
</div>
<div>
Hover Border: <input type="color" value="@primary_border_hover" @onchange="e => primary_border_hover = e.Value!.ToString()!"/>
</div>
</div>
<div class="color secondary">
<div>Secondary</div>
<div>
Base: <input type="color" value="@secondary" @onchange="e => secondary = e.Value!.ToString()!"/>
</div>
<div>
Hover Base: <input type="color" value="@secondary_hover" @onchange="e => secondary_hover = e.Value!.ToString()!"/>
</div>
<div>
Hover Border: <input type="color" value="@secondary_border_hover" @onchange="e => secondary_border_hover = e.Value!.ToString()!"/>
</div>
</div>
<div class="color paper">
<div>Paper</div>
<div>
Base: <input type="color" value="@paper" @onchange="e => paper = e.Value!.ToString()!"/>
</div>
<div>
Border: <input type="color" value="@paper_border" @onchange="e => paper_border = e.Value!.ToString()!"/>
</div>
</div>
<div class="color background">
<div>Background</div>
<div>
Base: <input type="color" value="@background" @onchange="e => background = e.Value!.ToString()!"/>
</div>
</div>
<div class="color info">
<div>Info</div>
<div>
Base: <input type="color" value="@info" @onchange="e => info = e.Value!.ToString()!"/>
</div>
<div>
Border: <input type="color" value="@info_border" @onchange="e => info_border = e.Value!.ToString()!"/>
</div>
</div>
<div class="color info_secondary">
<div>Info Secondary</div>
<div>
Base: <input type="color" value="@info_secondary" @onchange="e => info_secondary = e.Value!.ToString()!"/>
</div>
<div>
Border: <input type="color" value="@info_secondary_border" @onchange="e => info_secondary_border = e.Value!.ToString()!"/>
</div>
</div>
</div>
<style>
:root {
--accent: @accent;
--primary: @primary;
--primary-border: @primary_border;
--primary-hover: @primary_hover;
--primary-border-hover: @primary_border_hover;
--background: @background;
--secondary: @secondary;
--secondary-hover: @secondary_hover;
--secondary-border-hover: @secondary_border_hover;
--paper: @paper;
--paper-border: @paper_border;
--info: @info;
--info-border: @info_border;
--info-secondary: @info_secondary;
--info-secondary-border: @info_secondary_border;
}
.colorContainer {
display: flex;
flex-direction: column;
}
.color {
padding: 12px;
display: flex;
flex-direction: row;
gap: 32px;
align-items: center;
}
.accent {
background-color: var(--accent);
}
.primary {
background-color: var(--primary);
border: 1px solid var(--primary-border);
}
.primary:hover {
background-color: var(--primary-hover);
border-color: var(--primary-border-hover);
}
.secondary {
background-color: var(--secondary);
border: 1px solid var(--secondary);
}
.secondary:hover {
background-color: var(--secondary-hover);
border-color: var(--secondary-border-hover);
}
.paper {
background-color: var(--paper);
border: 4px solid var(--paper-border);
}
.background {
background-color: var(--background);
}
.info {
background-color: var(--info);
border: 1px solid var(--info-border);
}
.info_secondary {
background-color: var(--info-secondary);
border: 1px solid var(--info-secondary-border);
}
</style>
@code {
string accent = "#432462";
string primary = "#4308a3";
string primary_border = "#2c0b62";
string primary_hover = "#5e00f7";
string primary_border_hover = "#a168ff";
string background = "#161618";
string secondary = "#23133e";
string secondary_hover = "#2a0070";
string secondary_border_hover = "#a168ff";
string paper = "#252526";
string paper_border = "#151516";
string info = "#451376";
string info_border = "#210b36";
string info_secondary = "#4c3e59";
string info_secondary_border = "#7e58a2";
}

49
IGP/Pages/MakingOf/Parts/MakingOfColours.razor.css

@ -1,49 +0,0 @@
.colorContainer {
display: flex;
flex-direction: column;
}
.color {
padding: 12px;
display: flex;
flex-direction: row;
gap: 32px;
align-items: center;
}
.accent {
background-color: var(--accent);
}
.primary {
background-color: var(--primary);
border: 1px solid var(--primary-border);
}
.primary:hover {
background-color: var(--primary-hover);
border-color: var(--primary-border-hover);
}
.secondary {
background-color: var(--secondary);
border: 1px solid var(--secondary);
}
.secondary:hover {
background-color: var(--secondary-hover);
border-color: var(--secondary-border-hover);
}
.paper {
background-color: var(--paper);
border: 4px solid var(--paper-border);
}
.background {
background-color: var(--background);
}
.info {
background-color: var(--info);
}

16
IGP/Pages/MakingOf/Parts/MakingOfDialogs.razor

@ -1,16 +0,0 @@
<MakingOfComponent>
<Title>Dialog</Title>
<Description>...</Description>
<Example>
</Example>
<Usage>
//TODO
</Usage>
<Code>
//TODO
</Code>
</MakingOfComponent>
@code {
}

188
IGP/Pages/MakingOf/Parts/MakingOfDisplays.razor

@ -1,188 +0,0 @@
<MakingOfComponent>
<Title>
Entity Display
</Title>
<Description>
Display element for holding entity information.
</Description>
<Example>
<LayoutRowComponent>
<EntityDisplayComponent Title="Example Entity Info">
<div>
Example Entity Content
</div>
@for (var i = 0; i < 1; i++)
{
<div>
-@i Example Entity Content
</div>
}
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</EntityDisplayComponent>
<EntityDisplayComponent Title="Example Entity Info">
<div>
Example Entity Content
</div>
@for (var i = 0; i < 2; i++)
{
<div>
-@i Example Entity Content
</div>
}
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation.
</div>
</EntityDisplayComponent>
<EntityDisplayComponent Title="Example Entity Info">
<div>
Example Entity Content
</div>
@for (var i = 0; i < 1; i++)
{
<div>
-@i Example Entity Content
</div>
}
<div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</EntityDisplayComponent>
</LayoutRowComponent>
</Example>
<Usage>
<CodeComponent>
&lt;LayoutRowComponent&gt;
&lt;EntityDisplayComponent Title=&quot;Example Entity Info&quot;&gt;
&lt;div&gt;
Example Entity Content
&lt;/div&gt;
@@for (var i = 0; i &lt; 1; i++) {
&lt;div&gt;
-@@i Example Entity Content
&lt;/div&gt;
}
&lt;div&gt;
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
&lt;/div&gt;
&lt;/EntityDisplayComponent&gt;
&lt;EntityDisplayComponent Title=&quot;Example Entity Info&quot;&gt;
&lt;div&gt;
Example Entity Content
&lt;/div&gt;
@@for (var i = 0; i &lt; 2; i++) {
&lt;div&gt;
-@@i Example Entity Content
&lt;/div&gt;
}
&lt;div&gt;
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation.
&lt;/div&gt;
&lt;/EntityDisplayComponent&gt;
&lt;EntityDisplayComponent Title=&quot;Example Entity Info&quot;&gt;
&lt;div&gt;
Example Entity Content
&lt;/div&gt;
@@for (var i = 0; i &lt; 1; i++) {
&lt;div&gt;
-@@i Example Entity Content
&lt;/div&gt;
}
&lt;div&gt;
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
&lt;/div&gt;
&lt;/EntityDisplayComponent&gt;
&lt;/LayoutRowComponent&gt;
</CodeComponent>
</Usage>
<Code>
<CodeComponent>
&lt;div class=&quot;entityDisplaySection&quot;&gt;
&lt;div class=&quot;entityDisplayHeader&quot;&gt;
&lt;div class=&quot;entityDisplayTitle&quot;&gt;
@@Title
&lt;/div&gt;
&lt;div class=&quot;entityDisplayBorder&quot;&gt;
&lt;/div&gt;
&lt;/div&gt;
@@ChildContent
&lt;/div&gt;
&lt;style&gt;
.entityDisplaySection {
position: relative;
padding: 8px;
display: flex;
gap: 12px;
flex-direction: column;
margin-top: 14px;
margin-top: 20px;
padding: 12px;
background-color: var(--info);
border-top-right-radius: 12px;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
.entityDisplayHeader {
bottom: 100%;
position: absolute;
white-space: pre;
width: 100%;
line-height: 0px;
right: 0px;
top: -4px;
display: flex;
}
.entityDisplayTitle {
font-weight: 800;
font-size: 1.4rem;
padding-right: 8px;
text-shadow: 3px 0 0 var(--info), -3px 0 0 var(--info), 0 3px 0 var(--info), 0 -3px 0 var(--info), 2px 2px var(--info), -2px -2px 0 var(--info), 2px -2px 0 var(--info), -2px 2px 0 var(--info);
}
@@@@media only screen and (max-width: 1025px) {
.entityDisplayHeader {
position: inherit;
width: 100%;
margin: 0px;
}
.entityDisplaySection {
position: inherit;
width: 100%;
margin: 0px;
max-width: none;
border-top-right-radius: 0px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
}
.entityDisplayTitle {
position: inherit;
margin: 0px;
}
}
&lt;/style&gt;
@@code {
[Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public string Title { get; set; }
}
</CodeComponent>
</Code>
</MakingOfComponent>

58
IGP/Pages/MakingOf/Parts/MakingOfFeedback.razor

@ -1,58 +0,0 @@
<WebsiteTitleComponent>
Feedback
</WebsiteTitleComponent>
<MakingOfComponent>
<Title>
Loading
</Title>
<Description>
Indicates a component is being loaded (a component that relies on JSON)
</Description>
<Example>
<div style="width: 300px; height: 450px;">
<LoadingComponent/>
</div>
</Example>
<Usage>
<CodeComponent>Empty</CodeComponent>
</Usage>
<Code>
<CodeComponent>Empty</CodeComponent>
</Code>
</MakingOfComponent>
<MakingOfComponent>
<Title>Alert Message</Title>
<Description>Used to convey important information to the viewer. Comes in Yellow (Warning), Blue (Information), Red (Error), and Green (Success). Mostly used to warn viewers of pre-alpha or incomplete content being viewed.</Description>
<Example>
<AlertComponent Type="@SeverityType.Warning">
<Title>Warning Alert Title</Title>
<Message>Warning Alert Message</Message>
</AlertComponent>
<AlertComponent Type="@SeverityType.Information">
<Title>Information Alert Title</Title>
<Message>Information Alert Message</Message>
</AlertComponent>
<AlertComponent Type="@SeverityType.Error">
<Title>Error Alert Title</Title>
<Message>Error Alert Message</Message>
</AlertComponent>
<AlertComponent Type="@SeverityType.Success">
<Title>Succsess Alert Title</Title>
<Message>Succsess Alert Message</Message>
</AlertComponent>
</Example>
<Usage>
<CodeComponent>&lt;AlertComponent Type=SeverityType.Warning&gt;<br/> &lt;Title&gt;Warning Alert Title&lt;/Title&gt;<br/> &lt;Message&gt;Warning Alert Message&lt;/Message&gt;<br/>&lt;/AlertComponent&gt;<br/>&lt;AlertComponent Type=SeverityType.Information&gt;<br/> &lt;Title&gt;Information Alert Title&lt;/Title&gt;<br/> &lt;Message&gt;Information Alert Message&lt;/Message&gt;<br/>&lt;/AlertComponent&gt;<br/>&lt;AlertComponent Type=SeverityType.Error&gt;<br/> &lt;Title&gt;Error Alert Title&lt;/Title&gt;<br/> &lt;Message&gt;Error Alert Message&lt;/Message&gt;<br/>&lt;/AlertComponent&gt;<br/>&lt;AlertComponent Type=SeverityType.Success&gt;<br/> &lt;Title&gt;Succsess Alert Title&lt;/Title&gt;<br/> &lt;Message&gt;Succsess Alert Message&lt;/Message&gt;<br/>&lt;/AlertComponent&gt;<br/></CodeComponent>
</Usage>
<Code>
<CodeComponent>@@using Components.Pages.Utils<br/><br/>&lt;div class=&quot;alertContainer @@Type.ToString().ToLower()&quot;&gt;<br/> @@if (Title != null) {<br/> &lt;div class=&quot;alertTitle&quot;&gt;<br/> @@Title<br/> &lt;/div&gt;<br/> }<br/> @@if (Message != null) {<br/> &lt;div&gt;<br/> @@Message<br/> &lt;/div&gt;<br/><br/> }<br/>&lt;/div&gt;<br/>&lt;style&gt;<br/> .alertContainer {<br/> border: 4px solid;<br/> border-radius: 4px;<br/> padding: 16px;<br/> display: flex;<br/> flex-direction: column;<br/> justify-items: stretch;<br/> width: 100%;<br/> }<br/><br/> .alertContainer.@@SeverityType.Warning.ToString().ToLower() {<br/> border-color: #2a2000;<br/> background-color: #ffbf0029;<br/> }<br/><br/> .alertContainer.@@SeverityType.Error.ToString().ToLower() {<br/> border-color: #290102;<br/> background-color: #4C2C33;<br/> }<br/><br/> .alertContainer.@@SeverityType.Information.ToString().ToLower() {<br/> border-color: #030129;<br/> background-color: #2c3a4c;<br/> }<br/><br/> .alertContainer.@@SeverityType.Success.ToString().ToLower() {<br/> border-color: #042901;<br/> background-color: #2E4C2C;<br/> }<br/><br/> .alertTitle {<br/> font-weight: 800;<br/> }<br/><br/>&lt;/style&gt;<br/>@@code {<br/> [Parameter] public RenderFragment? Title { get; set; }<br/> [Parameter] public RenderFragment? Message { get; set; }<br/> [Parameter] public SeverityType Type { get; set; } = SeverityType.Warning;<br/>}</CodeComponent>
</Code>
</MakingOfComponent>
@code {
}

35
IGP/Pages/MakingOf/Parts/MakingOfForms.razor

@ -1,35 +0,0 @@
<MakingOfComponent>
<Title>Form Text</Title>
<Description>Add Text Input</Description>
<Example>
<FormLayoutComponent>
<FormTextComponent Label="Label Text" Info="Info Text" Placeholder="Placeholder Text..." Value="Value Text"/>
<FormTextAreaComponent Label="Label Text" Info="Info Text" Placeholder="Placeholder Text..." Value="Value Text"/>
</FormLayoutComponent>
</Example>
<Usage>
//TODO
</Usage>
<Code>
//TODO
</Code>
</MakingOfComponent>
<MakingOfComponent>
<Title>Form Area</Title>
<Description>Add Text Body Input</Description>
<Example>
<FormTextAreaComponent Label="Label Text" Info="Info Text" Placeholder="Placeholder Text..." Value="Value Text"/>
</Example>
<Usage>
//TODO
</Usage>
<Code>
//TODO
</Code>
</MakingOfComponent>
@code {
}

80
IGP/Pages/MakingOf/Parts/MakingOfNavigation.razor

@ -1,80 +0,0 @@
<MakingOfComponent>
<Title>
Nav Section with Nav Links
</Title>
<Description>
Group specfic webpages. Each webpage link is used to navigate to that specific webpage. If on the webpage, the link turns dark gray. It can be clicked again to leave the page and return to home.
</Description>
<Example>
<DesktopNavSectionComponent Section=@(new WebSectionModel { Name = "Example Section" })
Children=@(new List<WebPageModel> { new() { Name = "Example Page", Href = "immortal-makingof", IsPrivate = "False" }, new() { Name = "Database", Href = "immortal-database", IsPrivate = "False" } })>
</DesktopNavSectionComponent>
</Example>
<Usage>
<CodeComponent>
&lt;DesktopNavSectionComponent Section=@@(new WebSectionModel{Name = &quot;Example Section&quot;})
Children=@@(new List&lt;WebPageModel&gt;{new WebPageModel{Name=&quot;Example Page&quot;, Href = &quot;immortal-makingof&quot;, IsPrivate = false}, new WebPageModel{Name=&quot;Database&quot;, Href = &quot;immortal-database&quot;, IsPrivate = false}})&gt;
&lt;/DesktopNavSectionComponent&gt;
</CodeComponent>
</Usage>
<Code>
<CodeComponent>
@@using Model.Website;
@@using Model.Website.Enums;
&lt;div class=&quot;sectionContainer&quot;&gt;
&lt;div class=&quot;sectionHeader&quot;&gt;
&lt;div class=&quot;sectionTitle&quot;&gt;
@@Section.Name
&lt;/div&gt;
&lt;/div&gt;
@@foreach (var childPage in Children) {
if (childPage.IsPrivate) {
continue;
}
&lt;NavLinkComponent Page=childPage&gt;&lt;/NavLinkComponent&gt;
}
&lt;/div&gt;
&lt;style&gt;
.sectionContainer {
display: flex;
flex-direction: column;
gap: 4px;
justify-content: flex-start;
position: relative;
margin-top: 12px;
padding: 18px;
width: 300px;
margin-left: 4px;
}
.sectionHeader {
bottom: 100%;
position: absolute;
top: 0px;
left: -8px;
padding-right: 12px;
padding-left: 4px;
width: 100%;
display: flex;
line-height: 0px;
}
.sectionTitle {
font-weight: bold;
padding-right: 8px;
margin-top: -2px;
white-space: pre;
}
&lt;/style&gt;
@@code {
[Parameter] public WebSectionModel? Section { get; set; }
[Parameter] public List&lt;WebPageModel&gt;? Children { get; set; }
}
</CodeComponent>
</Code>
</MakingOfComponent>

7
IGP/Pages/Notes/NotesIndexPage.razor

@ -18,6 +18,8 @@ else
{ {
<LayoutMediumContentComponent> <LayoutMediumContentComponent>
<WebsiteTitleComponent>Notes</WebsiteTitleComponent>
<PaperComponent> <PaperComponent>
@foreach (var noteSection in NoteService.NoteSectionModels) @foreach (var noteSection in NoteService.NoteSectionModels)
{ {
@ -40,7 +42,10 @@ else
<style> <style>
.noteSectionContainer { .noteSectionContainer {
width: 100%; width: 100%;
padding: 8px; padding-left: 8px;
padding-right: 8px;
padding-top: 8px;
padding-bottom: 64px;
} }
.noteSectionTitle { .noteSectionTitle {

6
IGP/Pages/Notes/Parts/NoteComponent.razor

@ -8,7 +8,7 @@ else
{ {
<div class="note"> <div class="note">
<div class="noteHeader"> <div class="noteHeader">
<div class="noteTitle">@noteFrontMatter.Title</div> <h1 class="noteTitle">@noteFrontMatter.Title</h1>
<div class="noteDates"> <div class="noteDates">
<div class="noteDateUpdated"><b>Updated</b>: @noteFrontMatter.UpdatedDate.ToString("MM/dd/yyyy")</div> <div class="noteDateUpdated"><b>Updated</b>: @noteFrontMatter.UpdatedDate.ToString("MM/dd/yyyy")</div>
<div class="noteDateCreated"><b>Created</b>: @noteFrontMatter.CreatedDate.ToString("MM/dd/yyyy")</div> <div class="noteDateCreated"><b>Created</b>: @noteFrontMatter.CreatedDate.ToString("MM/dd/yyyy")</div>
@ -16,7 +16,9 @@ else
</div> </div>
<div class="noteContent">@((MarkupString)Markdown.ToHtml(content, Pipeline))</div> <div class="noteContent">@((MarkupString)Markdown.ToHtml(content, Pipeline))</div>
<div class="noteFooter"> <div class="noteFooter">
<EditLinkComponent Href="@GitUrl"></EditLinkComponent> <LinkButtonComponent Href="@GitUrl">
Edit on GitHub <i class="fa-brands fa-github" style="font-size: 24px; margin-left: 5px;"></i>
</LinkButtonComponent>
</div> </div>
</div> </div>
} }

7
IGP/Pages/PermissionsPage.razor

@ -47,7 +47,8 @@
<InfoBodyComponent> <InfoBodyComponent>
<InfoQuestionComponent>What data does this website collect?</InfoQuestionComponent> <InfoQuestionComponent>What data does this website collect?</InfoQuestionComponent>
<InfoAnswerComponent>This website usages Google Analytics to collect data on usage of this website. <InfoAnswerComponent>
This website usages Google Analytics to collect data on usage of this website.
<br/><br/> <br/><br/>
Items include: if people use keyboard or mouse in build calculator, what pages people visit, and other usages. Items include: if people use keyboard or mouse in build calculator, what pages people visit, and other usages.
</InfoAnswerComponent> </InfoAnswerComponent>
@ -62,8 +63,8 @@
@code { @code {
private bool _storageEnabled = false; private bool _storageEnabled;
private bool _dataCollectionEnabled = false; private bool _dataCollectionEnabled;
protected override void OnInitialized() protected override void OnInitialized()
{ {

19
IGP/Pages/RoadMap/Parts/RoadMapComponent.razor

@ -1,19 +0,0 @@
<PanelComponent>
<div class="roadMapTitle">@RoadMap.Name</div>
<div>@((MarkupString)RoadMap.Description)</div>
</PanelComponent>
<style>
.roadMapTitle {
font-weight: 800;
font-size: 1.2rem;
}
</style>
@code {
[Parameter]
public ImmortalRoadMapModel? RoadMap { get; set; }
}

32
IGP/Pages/RoadMap/RoadMapPage.razor

@ -1,32 +0,0 @@
@layout PageLayout
@inherits BasePage
@inject IDataCollectionService DataCollectionService
@page "/roadmap"
<LayoutMediumContentComponent>
<WebsiteTitleComponent>Road Map</WebsiteTitleComponent>
<div class="roadMapsContainer">
@foreach (var roadMap in data)
{
<RoadMapComponent RoadMap=roadMap/>
}
</div>
</LayoutMediumContentComponent>
<style>
.roadMapsContainer {
display: flex;
gap: 20px;
flex-wrap: wrap;
align-items: stretch;
justify-content: center;
}
</style>
@code {
readonly List<ImmortalRoadMapModel> data = ImmortalRoadMapModel.Data;
}

8
IGP/Pages/StoragePage.razor

@ -161,11 +161,11 @@
StorageService.Unsubscribe(RefreshDefaults); StorageService.Unsubscribe(RefreshDefaults);
} }
private int? _attackTime = null; private int? _attackTime;
private int? _travelTime = null; private int? _travelTime;
private string? _faction = null; private string? _faction;
private string? _immortal = null; private string? _immortal;
private string? Faction => _faction == null ? DataType.FACTION_QRath : _faction; private string? Faction => _faction == null ? DataType.FACTION_QRath : _faction;
private string? Immortal => _immortal == null ? DataType.IMMORTAL_Orzum : _immortal; private string? Immortal => _immortal == null ? DataType.IMMORTAL_Orzum : _immortal;

12
IGP/Pages/StreamsPage.razor

@ -14,17 +14,21 @@
</InfoBodyComponent> </InfoBodyComponent>
<InfoBodyComponent> <InfoBodyComponent>
<InfoQuestionComponent>What exactly are you streaming?</InfoQuestionComponent> <InfoQuestionComponent>What exactly are you streaming?</InfoQuestionComponent>
<InfoAnswerComponent>The plan will be sprint planning and general development of this website. <InfoAnswerComponent>
The plan will be sprint planning and general development of this website.
<br/><br/> <br/><br/>
Feel free to jump into the stream to ask questions or make feature requests for the website.</InfoAnswerComponent> Feel free to jump into the stream to ask questions or make feature requests for the website.
</InfoAnswerComponent>
</InfoBodyComponent> </InfoBodyComponent>
<InfoBodyComponent> <InfoBodyComponent>
<InfoQuestionComponent>Why should you watch these streams?</InfoQuestionComponent> <InfoQuestionComponent>Why should you watch these streams?</InfoQuestionComponent>
<InfoAnswerComponent>You shouldn't. By nature of being live coding streams, I think they will have little entertainment and educational value. <InfoAnswerComponent>
You shouldn't. By nature of being live coding streams, I think they will have little entertainment and educational value.
<br/><br/> <br/><br/>
The most reason (that comes to mind) is to see a coding day of one software developer. Although please note that I stream content that I think is easy (to look smart), so it's not a "truly random" coding day. For example, you won't find any vods of the five-week sprint where I (figuratively) bash my head against the table trying to get SQL working in Blazor WASM before giving up and moving on. </InfoAnswerComponent> The most reason (that comes to mind) is to see a coding day of one software developer. Although please note that I stream content that I think is easy (to look smart), so it's not a "truly random" coding day. For example, you won't find any vods of the five-week sprint where I (figuratively) bash my head against the table trying to get SQL working in Blazor WASM before giving up and moving on.
</InfoAnswerComponent>
</InfoBodyComponent> </InfoBodyComponent>
<InfoBodyComponent> <InfoBodyComponent>
<InfoQuestionComponent>Anything else I should know?</InfoQuestionComponent> <InfoQuestionComponent>Anything else I should know?</InfoQuestionComponent>

1
IGP/Portals/SearchPortal.razor

@ -20,7 +20,6 @@
} }
public void Dispose() public void Dispose()
{ {
searchService.Unsubscribe(OnUpdate); searchService.Unsubscribe(OnUpdate);

7
IGP/_Imports.razor

@ -8,25 +8,18 @@
@using Components.Shared @using Components.Shared
@using IGP.Dialog @using IGP.Dialog
@using IGP.Pages @using IGP.Pages
@using IGP.Pages.Agile.Parts
@using IGP.Pages.BuildCalculator @using IGP.Pages.BuildCalculator
@using IGP.Pages.BuildCalculator.Parts @using IGP.Pages.BuildCalculator.Parts
@using IGP.Pages.Comparision
@using IGP.Pages.Comparision.Parts
@using IGP.Pages.Database.Entity @using IGP.Pages.Database.Entity
@using IGP.Pages.Database.Entity.Parts @using IGP.Pages.Database.Entity.Parts
@using IGP.Pages.Database.Parts @using IGP.Pages.Database.Parts
@using IGP.Pages.Documentation
@using IGP.Pages.Documentation.Parts
@using IGP.Pages.EconomyComparison @using IGP.Pages.EconomyComparison
@using IGP.Pages.EconomyComparison.Parts @using IGP.Pages.EconomyComparison.Parts
@using IGP.Pages.Home @using IGP.Pages.Home
@using IGP.Pages.Home.Parts @using IGP.Pages.Home.Parts
@using IGP.Pages.MakingOf.Parts
@using IGP.Pages.MemoryTester.Parts @using IGP.Pages.MemoryTester.Parts
@using IGP.Pages.Notes @using IGP.Pages.Notes
@using IGP.Pages.Notes.Parts @using IGP.Pages.Notes.Parts
@using IGP.Pages.RoadMap.Parts
@using IGP.Portals @using IGP.Portals
@using IGP.Utils @using IGP.Utils
@using Markdig @using Markdig

2
IGP/wwwroot/generated/WebSectionModels.json

@ -1 +1 @@
[{"Id":1,"Name":"Tools","Description":"Tools Stuff","Order":1,"IsPrivate":"False","WebPageModels":[]},{"Id":2,"Name":"Resources","Description":"Resources Stuff","Order":2,"IsPrivate":"False","WebPageModels":[]},{"Id":3,"Name":"General","Description":"About Stuff","Order":3,"IsPrivate":"False","WebPageModels":[]},{"Id":4,"Name":"Development","Description":"Development Stuff","Order":4,"IsPrivate":"False","WebPageModels":[]},{"Id":5,"Name":"Settings","Description":"Settings Stuff","Order":5,"IsPrivate":"False","WebPageModels":[]}] [{"Id":1,"Name":"Tools","Description":"Tools Stuff","Order":1,"IsPrivate":"False","Icon":"fa-screwdriver-wrench","OnlyIcon":false,"WebPageModels":[]},{"Id":2,"Name":"Resources","Description":"Resources Stuff","Order":2,"IsPrivate":"False","Icon":"fa-toolbox","OnlyIcon":false,"WebPageModels":[]},{"Id":3,"Name":"General","Description":"About Stuff","Order":3,"IsPrivate":"False","Icon":"fa-circle-info","OnlyIcon":false,"WebPageModels":[]},{"Id":4,"Name":"Development","Description":"Development Stuff","Order":4,"IsPrivate":"False","Icon":"fa-code","OnlyIcon":false,"WebPageModels":[]},{"Id":5,"Name":"Settings","Description":"Settings Stuff","Order":5,"IsPrivate":"False","Icon":"fa-gear","OnlyIcon":false,"WebPageModels":[]}]

3
IGP/wwwroot/index.html

@ -5,6 +5,8 @@
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/> <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<title>IGP Fan Reference</title> <title>IGP Fan Reference</title>
<meta name="description" content='"IMMORTAL: Gates of Pyre" Fan Reference Community Tool, such as build calculator, unit database and gameplay notes.'/>
<meta name="keywords" content="Immortal Build Calculator, Immortal Calculator, Immortal Database, Immortal Harass Calculator, Immortal Tools, IMMORTAL: Gates of Pyre Build Calculator, IMMORTAL: Gates of Pyre Calculator, IMMORTAL: Gates of Pyre Database, IMMORTAL: Gates of Pyre Harass Calculator, IMMORTAL: Gates of Pyre Tools"/>
<base href="/"/> <base href="/"/>
<link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" <link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css"
integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" rel="stylesheet"> integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" rel="stylesheet">
@ -32,6 +34,7 @@
src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js"></script> src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.min.js"></script>
<script src="javascript/download.js"></script> <script src="javascript/download.js"></script>
<script src="_content/Blazor-Analytics/blazor-analytics.js"></script> <script src="_content/Blazor-Analytics/blazor-analytics.js"></script>
<script src="https://kit.fontawesome.com/c77aa98347.js" crossorigin="anonymous"></script>
<script> <script>
Blazor.start({ Blazor.start({
applicationCulture: 'en-US' applicationCulture: 'en-US'

187
Model/Entity/Data/DATA.cs

@ -60,12 +60,11 @@ public class DATA
Notes = @"Doesn't take up a scout slot." Notes = @"Doesn't take up a scout slot."
}) })
.AddPart(new EntityRequirementModel { Id = DataType.TEAPOT_Teapot }) .AddPart(new EntityRequirementModel { Id = DataType.TEAPOT_Teapot })
.AddPart(new EntitySupplyModel{Takes = 1}) .AddPart(new EntitySupplyModel { Takes = 1 })
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 50 }) .AddPart(new EntityProductionModel { Alloy = 100, Ether = 50 })
.AddPart(new EntityVitalityModel { Health = 100, DefenseLayer = 30, Armor = ArmorType.Light }) .AddPart(new EntityVitalityModel { Health = 100, DefenseLayer = 30, Armor = ArmorType.Light })
.AddPart(new EntityMovementModel { Speed = 280, Movement = MovementType.Air }) .AddPart(new EntityMovementModel { Speed = 280, Movement = MovementType.Air })
.AddPart(new EntityIdPassiveModel{ Id = DataType.PASSIVE_Detection}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Detection })
}, },
// Families // Families
@ -448,7 +447,8 @@ public class DATA
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
{ ReplaceId = DataType.UNIT_Sipari, ImmortalId = DataType.IMMORTAL_Orzum }) { ReplaceId = DataType.UNIT_Sipari, ImmortalId = DataType.IMMORTAL_Orzum })
.AddPart(new EntityProductionModel { Alloy = 100, BuildTime = 24, ProducedBy = DataType.BUILDING_LegionHall}) .AddPart(new EntityProductionModel
{ Alloy = 100, BuildTime = 24, ProducedBy = DataType.BUILDING_LegionHall })
.AddPart(new EntitySupplyModel { Takes = 4 }) .AddPart(new EntitySupplyModel { Takes = 4 })
.AddPart(new EntityVitalityModel { Health = 180, DefenseLayer = 100, Armor = ArmorType.Light }) .AddPart(new EntityVitalityModel { Health = 180, DefenseLayer = 100, Armor = ArmorType.Light })
.AddPart(new EntityWeaponModel .AddPart(new EntityWeaponModel
@ -477,7 +477,8 @@ public class DATA
.AddPart(new EntityTierModel { Tier = 3 }) .AddPart(new EntityTierModel { Tier = 3 })
.AddPart(new EntityHotkeyModel { Hotkey = "R", HoldSpace = true, HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "R", HoldSpace = true, HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 200, Ether = 125, BuildTime = 40, ProducedBy = DataType.BUILDING_Angelarium }) .AddPart(new EntityProductionModel
{ Alloy = 200, Ether = 125, BuildTime = 40, ProducedBy = DataType.BUILDING_Angelarium })
.AddPart(new EntityVitalityModel { Health = 350, DefenseLayer = 120, Armor = ArmorType.Heavy }) .AddPart(new EntityVitalityModel { Health = 350, DefenseLayer = 120, Armor = ArmorType.Heavy })
.AddPart(new EntitySupplyModel { Takes = 6 }) .AddPart(new EntitySupplyModel { Takes = 6 })
.AddPart(new EntityWeaponModel .AddPart(new EntityWeaponModel
@ -516,7 +517,8 @@ public class DATA
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
{ ReplaceId = DataType.UNIT_Magi, ImmortalId = DataType.IMMORTAL_Ajari }) { ReplaceId = DataType.UNIT_Magi, ImmortalId = DataType.IMMORTAL_Ajari })
.AddPart(new EntityProductionModel { Alloy = 75, Ether = 75, BuildTime = 35, ProducedBy = DataType.BUILDING_LegionHall }) .AddPart(new EntityProductionModel
{ Alloy = 75, Ether = 75, BuildTime = 35, ProducedBy = DataType.BUILDING_LegionHall })
.AddPart(new EntitySupplyModel { Takes = 4 }) .AddPart(new EntitySupplyModel { Takes = 4 })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Health = 140, DefenseLayer = 100, Armor = ArmorType.Light, IsEtheric = true }) { Health = 140, DefenseLayer = 100, Armor = ArmorType.Light, IsEtheric = true })
@ -550,7 +552,8 @@ public class DATA
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
{ ReplaceId = DataType.UNIT_Hallower, ImmortalId = DataType.IMMORTAL_Ajari }) { ReplaceId = DataType.UNIT_Hallower, ImmortalId = DataType.IMMORTAL_Ajari })
.AddPart(new EntityProductionModel { Alloy = 150, Ether = 100, BuildTime = 40, ProducedBy = DataType.BUILDING_SoulFoundry }) .AddPart(new EntityProductionModel
{ Alloy = 150, Ether = 100, BuildTime = 40, ProducedBy = DataType.BUILDING_SoulFoundry })
.AddPart(new EntitySupplyModel { Takes = 5 }) .AddPart(new EntitySupplyModel { Takes = 5 })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Energy = 100, Health = 100, DefenseLayer = 100, Armor = ArmorType.Medium, IsEtheric = true }) { Energy = 100, Health = 100, DefenseLayer = 100, Armor = ArmorType.Medium, IsEtheric = true })
@ -586,7 +589,8 @@ public class DATA
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
{ ReplaceId = DataType.UNIT_Underspine, ImmortalId = DataType.IMMORTAL_Mala }) { ReplaceId = DataType.UNIT_Underspine, ImmortalId = DataType.IMMORTAL_Mala })
.AddPart(new EntityProductionModel { Alloy = 175, Ether = 50, BuildTime = 35, ProducedBy = DataType.BUILDING_AmberWomb }) .AddPart(new EntityProductionModel
{ Alloy = 175, Ether = 50, BuildTime = 35, ProducedBy = DataType.BUILDING_AmberWomb })
.AddPart(new EntitySupplyModel { Takes = 5 }) .AddPart(new EntitySupplyModel { Takes = 5 })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Health = 160, DefenseLayer = 40, Armor = ArmorType.Medium, IsEtheric = false }) { Health = 160, DefenseLayer = 40, Armor = ArmorType.Medium, IsEtheric = false })
@ -615,7 +619,8 @@ public class DATA
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
{ ReplaceId = DataType.UNIT_RedSeer, ImmortalId = DataType.IMMORTAL_Mala }) { ReplaceId = DataType.UNIT_RedSeer, ImmortalId = DataType.IMMORTAL_Mala })
.AddPart(new EntityProductionModel { Alloy = 60, Ether = 150, BuildTime = 45, ProducedBy = DataType.BUILDING_AltarOfTheWorthy }) .AddPart(new EntityProductionModel
{ Alloy = 60, Ether = 150, BuildTime = 45, ProducedBy = DataType.BUILDING_AltarOfTheWorthy })
.AddPart(new EntitySupplyModel { Takes = 4 }) .AddPart(new EntitySupplyModel { Takes = 4 })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ {
@ -645,7 +650,8 @@ public class DATA
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
{ ReplaceId = DataType.UNIT_MaskedHunter, ImmortalId = DataType.IMMORTAL_Xol }) { ReplaceId = DataType.UNIT_MaskedHunter, ImmortalId = DataType.IMMORTAL_Xol })
.AddPart(new EntityProductionModel { Alloy = 50, Ether = 0, BuildTime = 20, ProducedBy = DataType.BUILDING_AltarOfTheWorthy }) .AddPart(new EntityProductionModel
{ Alloy = 50, Ether = 0, BuildTime = 20, ProducedBy = DataType.BUILDING_AltarOfTheWorthy })
.AddPart(new EntitySupplyModel { Takes = 2 }) .AddPart(new EntitySupplyModel { Takes = 2 })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Health = 85, DefenseLayer = 10, Armor = ArmorType.Light, IsEtheric = false }) { Health = 85, DefenseLayer = 10, Armor = ArmorType.Light, IsEtheric = false })
@ -674,7 +680,8 @@ public class DATA
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
{ ReplaceId = DataType.UNIT_Bloodbound, ImmortalId = DataType.IMMORTAL_Xol }) { ReplaceId = DataType.UNIT_Bloodbound, ImmortalId = DataType.IMMORTAL_Xol })
.AddPart(new EntityProductionModel { Alloy = 80, Ether = 80, BuildTime = 35, ProducedBy = DataType.BUILDING_AltarOfTheWorthy }) .AddPart(new EntityProductionModel
{ Alloy = 80, Ether = 80, BuildTime = 35, ProducedBy = DataType.BUILDING_AltarOfTheWorthy })
.AddPart(new EntitySupplyModel { Takes = 4 }) .AddPart(new EntitySupplyModel { Takes = 4 })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ {
@ -689,7 +696,6 @@ public class DATA
}) })
.AddPart(new EntityIdAbilityModel { Id = DataType.ABILITY_LethalBond }) .AddPart(new EntityIdAbilityModel { Id = DataType.ABILITY_LethalBond })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_CastingFromBlood }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_CastingFromBlood })
}, },
// Units // Units
// Q'Rath // Q'Rath
@ -719,7 +725,8 @@ public class DATA
.AddPart(new EntityVanguardReplacedModel .AddPart(new EntityVanguardReplacedModel
{ ImmortalId = DataType.IMMORTAL_Orzum, ReplacedById = DataType.VANGUARD_Zentari_Orzum }) { ImmortalId = DataType.IMMORTAL_Orzum, ReplacedById = DataType.VANGUARD_Zentari_Orzum })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 75, BuildTime = 25, ProducedBy = DataType.BUILDING_LegionHall }) .AddPart(new EntityProductionModel
{ Alloy = 75, BuildTime = 25, ProducedBy = DataType.BUILDING_LegionHall })
.AddPart(new EntitySupplyModel { Takes = 3 }) .AddPart(new EntitySupplyModel { Takes = 3 })
.AddPart(new EntityVitalityModel { Health = 140, DefenseLayer = 70, Armor = ArmorType.Light }) .AddPart(new EntityVitalityModel { Health = 140, DefenseLayer = 70, Armor = ArmorType.Light })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
@ -750,7 +757,8 @@ public class DATA
.AddPart(new EntityTierModel { Tier = 1.5f }) .AddPart(new EntityTierModel { Tier = 1.5f })
.AddPart(new EntityHotkeyModel { Hotkey = "E", HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "E", HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 75, Ether = 75, BuildTime = 35, ProducedBy = DataType.BUILDING_LegionHall }) .AddPart(new EntityProductionModel
{ Alloy = 75, Ether = 75, BuildTime = 35, ProducedBy = DataType.BUILDING_LegionHall })
.AddPart(new EntitySupplyModel { Takes = 3 }) .AddPart(new EntitySupplyModel { Takes = 3 })
.AddPart(new EntityVanguardReplacedModel .AddPart(new EntityVanguardReplacedModel
{ ImmortalId = DataType.IMMORTAL_Ajari, ReplacedById = DataType.VANGUARD_Saoshin_Ajari }) { ImmortalId = DataType.IMMORTAL_Ajari, ReplacedById = DataType.VANGUARD_Saoshin_Ajari })
@ -788,7 +796,8 @@ public class DATA
.AddPart(new EntityTierModel { Tier = 1.5f }) .AddPart(new EntityTierModel { Tier = 1.5f })
.AddPart(new EntityHotkeyModel { Hotkey = "W", HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "W", HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 40, BuildTime = 30, ProducedBy = DataType.BUILDING_SoulFoundry }) .AddPart(new EntityProductionModel
{ Alloy = 100, Ether = 40, BuildTime = 30, ProducedBy = DataType.BUILDING_SoulFoundry })
.AddPart(new EntitySupplyModel { Takes = 4 }) .AddPart(new EntitySupplyModel { Takes = 4 })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
@ -823,7 +832,8 @@ public class DATA
.AddPart(new EntityTierModel { Tier = 2 }) .AddPart(new EntityTierModel { Tier = 2 })
.AddPart(new EntityHotkeyModel { Hotkey = "R", HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "R", HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 125, Ether = 10, BuildTime = 35, ProducedBy = DataType.BUILDING_SoulFoundry }) .AddPart(new EntityProductionModel
{ Alloy = 125, Ether = 10, BuildTime = 35, ProducedBy = DataType.BUILDING_SoulFoundry })
.AddPart(new EntitySupplyModel { Takes = 4 }) .AddPart(new EntitySupplyModel { Takes = 4 })
.AddPart(new EntityVitalityModel { Health = 120, DefenseLayer = 100, Armor = ArmorType.Medium }) .AddPart(new EntityVitalityModel { Health = 120, DefenseLayer = 100, Armor = ArmorType.Medium })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
@ -855,7 +865,8 @@ public class DATA
.AddPart(new EntityTierModel { Tier = 2 }) .AddPart(new EntityTierModel { Tier = 2 })
.AddPart(new EntityHotkeyModel { Hotkey = "F", HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "F", HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 150, Ether = 75, BuildTime = 35, ProducedBy = DataType.BUILDING_SoulFoundry }) .AddPart(new EntityProductionModel
{ Alloy = 150, Ether = 75, BuildTime = 35, ProducedBy = DataType.BUILDING_SoulFoundry })
.AddPart(new EntitySupplyModel { Takes = 5 }) .AddPart(new EntitySupplyModel { Takes = 5 })
.AddPart(new EntityVitalityModel { Health = 175, DefenseLayer = 150, Armor = ArmorType.Medium }) .AddPart(new EntityVitalityModel { Health = 175, DefenseLayer = 150, Armor = ArmorType.Medium })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
@ -890,7 +901,8 @@ public class DATA
.AddPart(new EntityTierModel { Tier = 2 }) .AddPart(new EntityTierModel { Tier = 2 })
.AddPart(new EntityHotkeyModel { Hotkey = "W", HoldSpace = true, HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "W", HoldSpace = true, HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 190, Ether = 75, BuildTime = 35, ProducedBy = DataType.BUILDING_SoulFoundry }) .AddPart(new EntityProductionModel
{ Alloy = 190, Ether = 75, BuildTime = 35, ProducedBy = DataType.BUILDING_SoulFoundry })
.AddPart(new EntitySupplyModel { Takes = 5 }) .AddPart(new EntitySupplyModel { Takes = 5 })
.AddPart(new EntityVitalityModel { Health = 200, DefenseLayer = 100, Armor = ArmorType.Heavy }) .AddPart(new EntityVitalityModel { Health = 200, DefenseLayer = 100, Armor = ArmorType.Heavy })
.AddPart(new EntityMovementModel { Speed = 340, Movement = MovementType.Ground }) .AddPart(new EntityMovementModel { Speed = 340, Movement = MovementType.Ground })
@ -924,7 +936,8 @@ public class DATA
.AddPart(new EntityVanguardReplacedModel .AddPart(new EntityVanguardReplacedModel
{ ImmortalId = DataType.IMMORTAL_Ajari, ReplacedById = DataType.VANGUARD_ArkMother_Ajari }) { ImmortalId = DataType.IMMORTAL_Ajari, ReplacedById = DataType.VANGUARD_ArkMother_Ajari })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 150, Ether = 75, BuildTime = 35, ProducedBy = DataType.BUILDING_SoulFoundry }) .AddPart(new EntityProductionModel
{ Alloy = 150, Ether = 75, BuildTime = 35, ProducedBy = DataType.BUILDING_SoulFoundry })
.AddPart(new EntitySupplyModel { Takes = 5 }) .AddPart(new EntitySupplyModel { Takes = 5 })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
@ -956,7 +969,8 @@ public class DATA
.AddPart(new EntityTierModel { Tier = 3 }) .AddPart(new EntityTierModel { Tier = 3 })
.AddPart(new EntityHotkeyModel { Hotkey = "E", HoldSpace = true, HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "E", HoldSpace = true, HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 150, Ether = 75, BuildTime = 35, ProducedBy = DataType.BUILDING_Angelarium }) .AddPart(new EntityProductionModel
{ Alloy = 150, Ether = 75, BuildTime = 35, ProducedBy = DataType.BUILDING_Angelarium })
.AddPart(new EntitySupplyModel { Takes = 5 }) .AddPart(new EntitySupplyModel { Takes = 5 })
.AddPart(new EntityVitalityModel { Health = 150, DefenseLayer = 100, Armor = ArmorType.Medium }) .AddPart(new EntityVitalityModel { Health = 150, DefenseLayer = 100, Armor = ArmorType.Medium })
.AddPart(new EntityMovementModel { Speed = 525, Movement = MovementType.Air }) .AddPart(new EntityMovementModel { Speed = 525, Movement = MovementType.Air })
@ -982,7 +996,8 @@ public class DATA
.AddPart(new EntityTierModel { Tier = 3 }) .AddPart(new EntityTierModel { Tier = 3 })
.AddPart(new EntityHotkeyModel { Hotkey = "A", HoldSpace = true, HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "A", HoldSpace = true, HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 250, Ether = 100, BuildTime = 50, ProducedBy = DataType.BUILDING_Angelarium }) .AddPart(new EntityProductionModel
{ Alloy = 250, Ether = 100, BuildTime = 50, ProducedBy = DataType.BUILDING_Angelarium })
.AddPart(new EntitySupplyModel { Takes = 9 }) .AddPart(new EntitySupplyModel { Takes = 9 })
.AddPart(new EntityVitalityModel { Health = 350, DefenseLayer = 200, Armor = ArmorType.Heavy }) .AddPart(new EntityVitalityModel { Health = 350, DefenseLayer = 200, Armor = ArmorType.Heavy })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
@ -1020,7 +1035,8 @@ public class DATA
.AddPart(new EntityVanguardReplacedModel .AddPart(new EntityVanguardReplacedModel
{ ImmortalId = DataType.IMMORTAL_Orzum, ReplacedById = DataType.VANGUARD_Sceptre_Orzum }) { ImmortalId = DataType.IMMORTAL_Orzum, ReplacedById = DataType.VANGUARD_Sceptre_Orzum })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 175, Ether = 100, BuildTime = 40, ProducedBy = DataType.BUILDING_Angelarium }) .AddPart(new EntityProductionModel
{ Alloy = 175, Ether = 100, BuildTime = 40, ProducedBy = DataType.BUILDING_Angelarium })
.AddPart(new EntitySupplyModel { Takes = 6 }) .AddPart(new EntitySupplyModel { Takes = 6 })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
@ -1042,7 +1058,8 @@ public class DATA
.AddPart(new EntityTierModel { Tier = 3.5f }) .AddPart(new EntityTierModel { Tier = 3.5f })
.AddPart(new EntityHotkeyModel { Hotkey = "F", HoldSpace = true, HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "F", HoldSpace = true, HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 110, Ether = 250, BuildTime = 55, ProducedBy = DataType.BUILDING_Angelarium }) .AddPart(new EntityProductionModel
{ Alloy = 110, Ether = 250, BuildTime = 55, ProducedBy = DataType.BUILDING_Angelarium })
.AddPart(new EntitySupplyModel { Takes = 6 }) .AddPart(new EntitySupplyModel { Takes = 6 })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
@ -1102,7 +1119,8 @@ public class DATA
Requirement = RequirementType.Production_Building Requirement = RequirementType.Production_Building
}) })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityProductionModel { Alloy = 50, BuildTime = 20, ProducedBy = DataType.BUILDING_AltarOfTheWorthy }) .AddPart(new EntityProductionModel
{ Alloy = 50, BuildTime = 20, ProducedBy = DataType.BUILDING_AltarOfTheWorthy })
.AddPart(new EntitySupplyModel { Takes = 2 }) .AddPart(new EntitySupplyModel { Takes = 2 })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Health = 85, DefenseLayer = 25, Defense = DefenseType.Overgrowth, Armor = ArmorType.Light }) { Health = 85, DefenseLayer = 25, Defense = DefenseType.Overgrowth, Armor = ArmorType.Light })
@ -1130,7 +1148,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityProductionModel { Alloy = 75, Ether = 30, BuildTime = 25, ProducedBy = DataType.BUILDING_AltarOfTheWorthy }) .AddPart(new EntityProductionModel
{ Alloy = 75, Ether = 30, BuildTime = 25, ProducedBy = DataType.BUILDING_AltarOfTheWorthy })
.AddPart(new EntitySupplyModel { Takes = 3 }) .AddPart(new EntitySupplyModel { Takes = 3 })
.AddPart(new EntityVitalityModel { Health = 160, DefenseLayer = 70, Armor = ArmorType.Heavy }) .AddPart(new EntityVitalityModel { Health = 160, DefenseLayer = 70, Armor = ArmorType.Heavy })
.AddPart(new EntityMovementModel { Speed = 378, Movement = MovementType.Ground }) .AddPart(new EntityMovementModel { Speed = 378, Movement = MovementType.Ground })
@ -1161,7 +1180,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "E", HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "E", HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityProductionModel { Alloy = 80, Ether = 80, BuildTime = 30, ProducedBy = DataType.BUILDING_AltarOfTheWorthy }) .AddPart(new EntityProductionModel
{ Alloy = 80, Ether = 80, BuildTime = 30, ProducedBy = DataType.BUILDING_AltarOfTheWorthy })
.AddPart(new EntitySupplyModel { Takes = 4 }) .AddPart(new EntitySupplyModel { Takes = 4 })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Energy = 60, Health = 100, DefenseLayer = 40, Armor = ArmorType.Light }) { Energy = 60, Health = 100, DefenseLayer = 40, Armor = ArmorType.Light })
@ -1174,7 +1194,6 @@ public class DATA
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_QuenchingScythes }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_QuenchingScythes })
.AddPart(new EntityIdPassiveModel { Id = DataType.ABILITY_CullingStrike }) .AddPart(new EntityIdPassiveModel { Id = DataType.ABILITY_CullingStrike })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_CastingFromBlood }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_CastingFromBlood })
}, },
{ {
DataType.UNIT_RedSeer, DataType.UNIT_RedSeer,
@ -1195,7 +1214,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "F", HoldSpace = true, HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "F", HoldSpace = true, HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityProductionModel { Alloy = 40, Ether = 140, BuildTime = 40, ProducedBy = DataType.BUILDING_AltarOfTheWorthy }) .AddPart(new EntityProductionModel
{ Alloy = 40, Ether = 140, BuildTime = 40, ProducedBy = DataType.BUILDING_AltarOfTheWorthy })
.AddPart(new EntitySupplyModel { Takes = 3 }) .AddPart(new EntitySupplyModel { Takes = 3 })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ {
@ -1233,7 +1253,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "Q", HoldSpace = true, HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "Q", HoldSpace = true, HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityProductionModel { Alloy = 70, Ether = 50, BuildTime = 25, ProducedBy = DataType.BUILDING_AltarOfTheWorthy }) .AddPart(new EntityProductionModel
{ Alloy = 70, Ether = 50, BuildTime = 25, ProducedBy = DataType.BUILDING_AltarOfTheWorthy })
.AddPart(new EntitySupplyModel { Takes = 3 }) .AddPart(new EntitySupplyModel { Takes = 3 })
.AddPart(new EntityVitalityModel { Health = 140, DefenseLayer = 40, Armor = ArmorType.Medium }) .AddPart(new EntityVitalityModel { Health = 140, DefenseLayer = 40, Armor = ArmorType.Medium })
.AddPart(new EntityMovementModel { Speed = 350, Movement = MovementType.Ground }) .AddPart(new EntityMovementModel { Speed = 350, Movement = MovementType.Ground })
@ -1263,7 +1284,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "R", HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "R", HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityProductionModel { Alloy = 95, Ether = 20, BuildTime = 30, ProducedBy = DataType.BUILDING_AmberWomb }) .AddPart(new EntityProductionModel
{ Alloy = 95, Ether = 20, BuildTime = 30, ProducedBy = DataType.BUILDING_AmberWomb })
.AddPart(new EntitySupplyModel { Takes = 4 }) .AddPart(new EntitySupplyModel { Takes = 4 })
.AddPart(new EntityVitalityModel { Health = 100, DefenseLayer = 40, Armor = ArmorType.Medium }) .AddPart(new EntityVitalityModel { Health = 100, DefenseLayer = 40, Armor = ArmorType.Medium })
.AddPart(new EntityMovementModel { Speed = 382, Movement = MovementType.Ground }) .AddPart(new EntityMovementModel { Speed = 382, Movement = MovementType.Ground })
@ -1293,7 +1315,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "F", HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "F", HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityProductionModel { Alloy = 150, Ether = 80, BuildTime = 40, ProducedBy = DataType.BUILDING_AmberWomb }) .AddPart(new EntityProductionModel
{ Alloy = 150, Ether = 80, BuildTime = 40, ProducedBy = DataType.BUILDING_AmberWomb })
.AddPart(new EntitySupplyModel { Takes = 5 }) .AddPart(new EntitySupplyModel { Takes = 5 })
.AddPart(new EntityVitalityModel { Health = 175, DefenseLayer = 60, Armor = ArmorType.Heavy }) .AddPart(new EntityVitalityModel { Health = 175, DefenseLayer = 60, Armor = ArmorType.Heavy })
.AddPart(new EntityMovementModel { Speed = 350, Movement = MovementType.Ground }) .AddPart(new EntityMovementModel { Speed = 350, Movement = MovementType.Ground })
@ -1328,7 +1351,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "E", HoldSpace = true, HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "E", HoldSpace = true, HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityProductionModel { Alloy = 40, Ether = 40, BuildTime = 30, ProducedBy = DataType.BUILDING_BoneCanopy }) .AddPart(new EntityProductionModel
{ Alloy = 40, Ether = 40, BuildTime = 30, ProducedBy = DataType.BUILDING_BoneCanopy })
.AddPart(new EntitySupplyModel { Takes = 2 }) .AddPart(new EntitySupplyModel { Takes = 2 })
.AddPart(new EntityVitalityModel { Health = 35, DefenseLayer = 10, Armor = ArmorType.Light }) .AddPart(new EntityVitalityModel { Health = 35, DefenseLayer = 10, Armor = ArmorType.Light })
.AddPart(new EntityMovementModel { Speed = 532, Movement = MovementType.Air }) .AddPart(new EntityMovementModel { Speed = 532, Movement = MovementType.Air })
@ -1353,7 +1377,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "R", HoldSpace = true, HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "R", HoldSpace = true, HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityProductionModel { Alloy = 80, Ether = 50, BuildTime = 30, ProducedBy = DataType.BUILDING_BoneCanopy }) .AddPart(new EntityProductionModel
{ Alloy = 80, Ether = 50, BuildTime = 30, ProducedBy = DataType.BUILDING_BoneCanopy })
.AddPart(new EntitySupplyModel { Takes = 3 }) .AddPart(new EntitySupplyModel { Takes = 3 })
.AddPart(new EntityVitalityModel { Health = 120, DefenseLayer = 40, Armor = ArmorType.Light }) .AddPart(new EntityVitalityModel { Health = 120, DefenseLayer = 40, Armor = ArmorType.Light })
.AddPart(new EntityMovementModel { Speed = 525, Movement = MovementType.Air }) .AddPart(new EntityMovementModel { Speed = 525, Movement = MovementType.Air })
@ -1375,7 +1400,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "W", HoldSpace = true, HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "W", HoldSpace = true, HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityProductionModel { Alloy = 80, Ether = 30, BuildTime = 30, ProducedBy = DataType.BUILDING_AmberWomb }) .AddPart(new EntityProductionModel
{ Alloy = 80, Ether = 30, BuildTime = 30, ProducedBy = DataType.BUILDING_AmberWomb })
.AddPart(new EntitySupplyModel { Takes = 3 }) .AddPart(new EntitySupplyModel { Takes = 3 })
.AddPart(new EntityVitalityModel { Health = 120, DefenseLayer = 45, Armor = ArmorType.Medium }) .AddPart(new EntityVitalityModel { Health = 120, DefenseLayer = 45, Armor = ArmorType.Medium })
.AddPart(new EntityMovementModel { Speed = 350, Movement = MovementType.Ground }) .AddPart(new EntityMovementModel { Speed = 350, Movement = MovementType.Ground })
@ -1403,7 +1429,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "A", HoldSpace = true, HotkeyGroup = "Z" }) .AddPart(new EntityHotkeyModel { Hotkey = "A", HoldSpace = true, HotkeyGroup = "Z" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityProductionModel { Alloy = 190, Ether = 150, BuildTime = 50, ProducedBy = DataType.BUILDING_BoneCanopy }) .AddPart(new EntityProductionModel
{ Alloy = 190, Ether = 150, BuildTime = 50, ProducedBy = DataType.BUILDING_BoneCanopy })
.AddPart(new EntitySupplyModel { Takes = 8 }) .AddPart(new EntitySupplyModel { Takes = 8 })
.AddPart(new EntityVitalityModel { Health = 350, DefenseLayer = 100, Armor = ArmorType.Heavy }) .AddPart(new EntityVitalityModel { Health = 350, DefenseLayer = 100, Armor = ArmorType.Heavy })
.AddPart(new EntityMovementModel { Speed = 210, Movement = MovementType.Air }) .AddPart(new EntityMovementModel { Speed = 210, Movement = MovementType.Air })
@ -1438,7 +1465,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "TAB" }) .AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "TAB" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 100, BuildTime = 100, ProducedBy = DataType.BUILDING_Reliquary }) .AddPart(new EntityProductionModel
{ Alloy = 100, Ether = 100, BuildTime = 100, ProducedBy = DataType.BUILDING_Reliquary })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
Id = DataType.BUILDING_Reliquary, Id = DataType.BUILDING_Reliquary,
@ -1457,7 +1485,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "R", HoldSpace = true, HotkeyGroup = "TAB" }) .AddPart(new EntityHotkeyModel { Hotkey = "R", HoldSpace = true, HotkeyGroup = "TAB" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 80, Ether = 80, BuildTime = 34, ProducedBy = DataType.BUILDING_HouseOfFadingSaints }) .AddPart(new EntityProductionModel
{ Alloy = 80, Ether = 80, BuildTime = 34, ProducedBy = DataType.BUILDING_HouseOfFadingSaints })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
Id = DataType.BUILDING_HouseOfFadingSaints, Id = DataType.BUILDING_HouseOfFadingSaints,
@ -1475,7 +1504,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "TAB", HoldSpace = true }) .AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "TAB", HoldSpace = true })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 100, BuildTime = 43, ProducedBy = DataType.BUILDING_EyeOfAros }) .AddPart(new EntityProductionModel
{ Alloy = 100, Ether = 100, BuildTime = 43, ProducedBy = DataType.BUILDING_EyeOfAros })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
Id = DataType.BUILDING_EyeOfAros, Id = DataType.BUILDING_EyeOfAros,
@ -1495,7 +1525,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "TAB" }) .AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "TAB" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 50, Ether = 100, BuildTime = 60, ProducedBy = DataType.BUILDING_Reliquary }) .AddPart(new EntityProductionModel
{ Alloy = 50, Ether = 100, BuildTime = 60, ProducedBy = DataType.BUILDING_Reliquary })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ Id = DataType.BUILDING_Reliquary, Requirement = RequirementType.Research_Building }) { Id = DataType.BUILDING_Reliquary, Requirement = RequirementType.Research_Building })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
@ -1511,7 +1542,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "W", HotkeyGroup = "TAB", HoldSpace = true }) .AddPart(new EntityHotkeyModel { Hotkey = "W", HotkeyGroup = "TAB", HoldSpace = true })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 75, Ether = 75, BuildTime = 29, ProducedBy = DataType.BUILDING_HouseOfFadingSaints }) .AddPart(new EntityProductionModel
{ Alloy = 75, Ether = 75, BuildTime = 29, ProducedBy = DataType.BUILDING_HouseOfFadingSaints })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
Id = DataType.BUILDING_HouseOfFadingSaints, Id = DataType.BUILDING_HouseOfFadingSaints,
@ -1525,7 +1557,8 @@ public class DATA
{ Name = "Windstep", Descriptive = DescriptiveType.Upgrade, Description = "Unlocks windstep." }) { Name = "Windstep", Descriptive = DescriptiveType.Upgrade, Description = "Unlocks windstep." })
.AddPart(new EntityHotkeyModel { Hotkey = "W", HotkeyGroup = "TAB" }) .AddPart(new EntityHotkeyModel { Hotkey = "W", HotkeyGroup = "TAB" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 50, Ether = 75, BuildTime = 55, ProducedBy = DataType.BUILDING_Reliquary }) .AddPart(new EntityProductionModel
{ Alloy = 50, Ether = 75, BuildTime = 55, ProducedBy = DataType.BUILDING_Reliquary })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ Id = DataType.BUILDING_Reliquary, Requirement = RequirementType.Production_Building }) { Id = DataType.BUILDING_Reliquary, Requirement = RequirementType.Production_Building })
}, },
@ -1539,7 +1572,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "E", HotkeyGroup = "TAB" }) .AddPart(new EntityHotkeyModel { Hotkey = "E", HotkeyGroup = "TAB" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 150, Ether = 100, BuildTime = 43, ProducedBy = DataType.BUILDING_Reliquary }) .AddPart(new EntityProductionModel
{ Alloy = 150, Ether = 100, BuildTime = 43, ProducedBy = DataType.BUILDING_Reliquary })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ Id = DataType.BUILDING_Reliquary, Requirement = RequirementType.Research_Building }) { Id = DataType.BUILDING_Reliquary, Requirement = RequirementType.Research_Building })
.AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_WindStep }) .AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_WindStep })
@ -1555,7 +1589,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "R", HotkeyGroup = "TAB" }) .AddPart(new EntityHotkeyModel { Hotkey = "R", HotkeyGroup = "TAB" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 75, Ether = 100, BuildTime = 60, ProducedBy = DataType.BUILDING_HouseOfFadingSaints }) .AddPart(new EntityProductionModel
{ Alloy = 75, Ether = 100, BuildTime = 60, ProducedBy = DataType.BUILDING_HouseOfFadingSaints })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
Id = DataType.BUILDING_HouseOfFadingSaints, Id = DataType.BUILDING_HouseOfFadingSaints,
@ -1572,7 +1607,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "Q", HoldSpace = true, HotkeyGroup = "TAB" }) .AddPart(new EntityHotkeyModel { Hotkey = "Q", HoldSpace = true, HotkeyGroup = "TAB" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 100, BuildTime = 43, ProducedBy = DataType.BUILDING_EyeOfAros }) .AddPart(new EntityProductionModel
{ Alloy = 100, Ether = 100, BuildTime = 43, ProducedBy = DataType.BUILDING_EyeOfAros })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
Id = DataType.BUILDING_EyeOfAros, Id = DataType.BUILDING_EyeOfAros,
@ -1591,7 +1627,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "A", HoldSpace = true, HotkeyGroup = "TAB" }) .AddPart(new EntityHotkeyModel { Hotkey = "A", HoldSpace = true, HotkeyGroup = "TAB" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 75, BuildTime = 45, ProducedBy = DataType.BUILDING_BearerOfTheCrown }) .AddPart(new EntityProductionModel
{ Alloy = 100, Ether = 75, BuildTime = 45, ProducedBy = DataType.BUILDING_BearerOfTheCrown })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
Id = DataType.BUILDING_BearerOfTheCrown, Requirement = RequirementType.Production_Building Id = DataType.BUILDING_BearerOfTheCrown, Requirement = RequirementType.Production_Building
@ -1607,7 +1644,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "R", HoldSpace = true, HotkeyGroup = "TAB" }) .AddPart(new EntityHotkeyModel { Hotkey = "R", HoldSpace = true, HotkeyGroup = "TAB" })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityProductionModel { Alloy = 150, Ether = 100, BuildTime = 30, ProducedBy = DataType.BUILDING_EyeOfAros }) .AddPart(new EntityProductionModel
{ Alloy = 150, Ether = 100, BuildTime = 30, ProducedBy = DataType.BUILDING_EyeOfAros })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
Id = DataType.BUILDING_EyeOfAros, Requirement = RequirementType.Production_Building Id = DataType.BUILDING_EyeOfAros, Requirement = RequirementType.Production_Building
@ -1638,7 +1676,8 @@ public class DATA
Id = DataType.BUILDING_Neurocyte, Id = DataType.BUILDING_Neurocyte,
Requirement = RequirementType.Production_Building Requirement = RequirementType.Production_Building
}) })
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 80, BuildTime = 60, ProducedBy = DataType.BUILDING_Neurocyte }) .AddPart(new EntityProductionModel
{ Alloy = 100, Ether = 80, BuildTime = 60, ProducedBy = DataType.BUILDING_Neurocyte })
}, },
{ {
DataType.UPGRADE_BloodMothersFevor, DataType.UPGRADE_BloodMothersFevor,
@ -1659,7 +1698,8 @@ public class DATA
Id = DataType.BUILDING_AltarOfTheWorthy, Id = DataType.BUILDING_AltarOfTheWorthy,
Requirement = RequirementType.Research_Building Requirement = RequirementType.Research_Building
}) })
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 150, BuildTime = 80, ProducedBy = DataType.BUILDING_RedVale }) .AddPart(new EntityProductionModel
{ Alloy = 100, Ether = 150, BuildTime = 80, ProducedBy = DataType.BUILDING_RedVale })
}, },
{ {
DataType.UPGRADE_DenInstinct, DataType.UPGRADE_DenInstinct,
@ -1672,7 +1712,8 @@ public class DATA
Id = DataType.BUILDING_Neurocyte, Id = DataType.BUILDING_Neurocyte,
Requirement = RequirementType.Research_Building Requirement = RequirementType.Research_Building
}) })
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 120, BuildTime = 45, ProducedBy = DataType.BUILDING_Neurocyte }) .AddPart(new EntityProductionModel
{ Alloy = 100, Ether = 120, BuildTime = 45, ProducedBy = DataType.BUILDING_Neurocyte })
}, },
{ {
DataType.UPGRADE_PursuitLigaments, DataType.UPGRADE_PursuitLigaments,
@ -1685,7 +1726,8 @@ public class DATA
Id = DataType.BUILDING_Neurocyte, Id = DataType.BUILDING_Neurocyte,
Requirement = RequirementType.Research_Building Requirement = RequirementType.Research_Building
}) })
.AddPart(new EntityProductionModel { Alloy = 75, Ether = 100, BuildTime = 45, ProducedBy = DataType.BUILDING_Neurocyte }) .AddPart(new EntityProductionModel
{ Alloy = 75, Ether = 100, BuildTime = 45, ProducedBy = DataType.BUILDING_Neurocyte })
}, },
{ {
DataType.UPGRADE_ResinantDeploy, DataType.UPGRADE_ResinantDeploy,
@ -1703,7 +1745,8 @@ public class DATA
Id = DataType.BUILDING_AmberWomb, Id = DataType.BUILDING_AmberWomb,
Requirement = RequirementType.Research_Building Requirement = RequirementType.Research_Building
}) })
.AddPart(new EntityProductionModel { Alloy = 50, Ether = 100, BuildTime = 43, ProducedBy = DataType.BUILDING_Neurocyte }) .AddPart(new EntityProductionModel
{ Alloy = 50, Ether = 100, BuildTime = 43, ProducedBy = DataType.BUILDING_Neurocyte })
}, },
{ {
DataType.UPGRADE_XacalDamage, DataType.UPGRADE_XacalDamage,
@ -1716,7 +1759,8 @@ public class DATA
Id = DataType.BUILDING_Neurocyte, Id = DataType.BUILDING_Neurocyte,
Requirement = RequirementType.Research_Building Requirement = RequirementType.Research_Building
}) })
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 75, BuildTime = 60, ProducedBy = DataType.BUILDING_Neurocyte }) .AddPart(new EntityProductionModel
{ Alloy = 100, Ether = 75, BuildTime = 60, ProducedBy = DataType.BUILDING_Neurocyte })
}, },
{ {
DataType.UPGRADE_BehemothCapacity, DataType.UPGRADE_BehemothCapacity,
@ -1729,7 +1773,8 @@ public class DATA
Id = DataType.BUILDING_DeepNest, Id = DataType.BUILDING_DeepNest,
Requirement = RequirementType.Research_Building Requirement = RequirementType.Research_Building
}) })
.AddPart(new EntityProductionModel { Alloy = 150, Ether = 150, BuildTime = 46, ProducedBy = DataType.BUILDING_DeepNest }) .AddPart(new EntityProductionModel
{ Alloy = 150, Ether = 150, BuildTime = 46, ProducedBy = DataType.BUILDING_DeepNest })
}, },
{ {
DataType.UPGRADE_WraithBowRange, DataType.UPGRADE_WraithBowRange,
@ -1747,7 +1792,8 @@ public class DATA
Id = DataType.BUILDING_Neurocyte, Id = DataType.BUILDING_Neurocyte,
Requirement = RequirementType.Research_Building Requirement = RequirementType.Research_Building
}) })
.AddPart(new EntityProductionModel { Alloy = 50, Ether = 75, BuildTime = 29, ProducedBy = DataType.BUILDING_Neurocyte }) .AddPart(new EntityProductionModel
{ Alloy = 50, Ether = 75, BuildTime = 29, ProducedBy = DataType.BUILDING_Neurocyte })
}, },
{ {
@ -1766,7 +1812,8 @@ public class DATA
Id = DataType.BUILDING_Neurocyte, Id = DataType.BUILDING_Neurocyte,
Requirement = RequirementType.Research_Building Requirement = RequirementType.Research_Building
}) })
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 80, BuildTime = 60, ProducedBy = DataType.BUILDING_Neurocyte }) .AddPart(new EntityProductionModel
{ Alloy = 100, Ether = 80, BuildTime = 60, ProducedBy = DataType.BUILDING_Neurocyte })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
{ ReplaceId = DataType.UPGRADE_Offering, ImmortalId = DataType.IMMORTAL_Xol }) { ReplaceId = DataType.UPGRADE_Offering, ImmortalId = DataType.IMMORTAL_Xol })
}, },
@ -1782,7 +1829,8 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "CAPSLOCK", HotkeyGroup = "TAB", HoldSpace = false }) .AddPart(new EntityHotkeyModel { Hotkey = "CAPSLOCK", HotkeyGroup = "TAB", HoldSpace = false })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 125, BuildTime = 80, ProducedBy = DataType.BUILDING_RedVale }) .AddPart(new EntityProductionModel
{ Alloy = 100, Ether = 125, BuildTime = 80, ProducedBy = DataType.BUILDING_RedVale })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
Id = DataType.BUILDING_RedVale, Id = DataType.BUILDING_RedVale,
@ -1808,7 +1856,8 @@ public class DATA
Id = DataType.BUILDING_RedVale, Id = DataType.BUILDING_RedVale,
Requirement = RequirementType.Research_Building Requirement = RequirementType.Research_Building
}) })
.AddPart(new EntityProductionModel { Alloy = 75, Ether = 120, BuildTime = 80, ProducedBy = DataType.BUILDING_RedVale }) .AddPart(new EntityProductionModel
{ Alloy = 75, Ether = 120, BuildTime = 80, ProducedBy = DataType.BUILDING_RedVale })
.AddPart(new EntityVanguardReplacedModel .AddPart(new EntityVanguardReplacedModel
{ ImmortalId = DataType.IMMORTAL_Xol, ReplacedById = DataType.ABILITY_BirthingStorm }) { ImmortalId = DataType.IMMORTAL_Xol, ReplacedById = DataType.ABILITY_BirthingStorm })
}, },
@ -1823,7 +1872,8 @@ public class DATA
Id = DataType.BUILDING_RedVale, Id = DataType.BUILDING_RedVale,
Requirement = RequirementType.Research_Building Requirement = RequirementType.Research_Building
}) })
.AddPart(new EntityProductionModel { Alloy = 75, Ether = 120, BuildTime = 80, ProducedBy = DataType.BUILDING_RedVale }) .AddPart(new EntityProductionModel
{ Alloy = 75, Ether = 120, BuildTime = 80, ProducedBy = DataType.BUILDING_RedVale })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
{ ImmortalId = DataType.IMMORTAL_Mala, ReplaceId = DataType.ABILITY_BloodPlague }) { ImmortalId = DataType.IMMORTAL_Mala, ReplaceId = DataType.ABILITY_BloodPlague })
}, },
@ -2401,8 +2451,7 @@ public class DATA
@"Spawns a mine that reveals enemy units, slows them, and makes them take increased damage for a duration." @"Spawns a mine that reveals enemy units, slows them, and makes them take increased damage for a duration."
}) })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_QRath })
.AddPart(new EntityHotkeyModel { Hotkey = "R", HotkeyGroup = "D", HoldSpace = true}) .AddPart(new EntityHotkeyModel { Hotkey = "R", HotkeyGroup = "D", HoldSpace = true })
.AddPart(new EntityProductionModel { DefensiveLayer = 30, Cooldown = 40 }) .AddPart(new EntityProductionModel { DefensiveLayer = 30, Cooldown = 40 })
.AddPart(new EntityRequirementModel { Id = DataType.UPGRADE_RadiantWard }) .AddPart(new EntityRequirementModel { Id = DataType.UPGRADE_RadiantWard })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
@ -2591,7 +2640,7 @@ public class DATA
.AddPart(new EntityHotkeyModel { Hotkey = "R", HotkeyGroup = "D" }) .AddPart(new EntityHotkeyModel { Hotkey = "R", HotkeyGroup = "D" })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
{ ImmortalId = DataType.IMMORTAL_Xol, ReplaceId = DataType.ABILITY_CullingStrike }) { ImmortalId = DataType.IMMORTAL_Xol, ReplaceId = DataType.ABILITY_CullingStrike })
.AddPart(new EntityProductionModel { Energy = 40, Cooldown = 4}) .AddPart(new EntityProductionModel { Energy = 40, Cooldown = 4 })
.AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru }) .AddPart(new EntityFactionModel { Faction = DataType.FACTION_Aru })
}, },
{ {
@ -2686,8 +2735,11 @@ public class DATA
{ ImmortalId = DataType.IMMORTAL_Mala, ReplaceId = DataType.UNIT_Acaaluk }) { ImmortalId = DataType.IMMORTAL_Mala, ReplaceId = DataType.UNIT_Acaaluk })
.AddPart(new EntityProductionModel { Energy = 80, BuildTime = 10, Cooldown = 30 }) .AddPart(new EntityProductionModel { Energy = 80, BuildTime = 10, Cooldown = 30 })
.AddPart(new EntitySupplyModel { Takes = 0 }) .AddPart(new EntitySupplyModel { Takes = 0 })
.AddPart(new EntityVitalityModel { Health = 300, DefenseLayer = 100, Armor = ArmorType.Heavy, .AddPart(new EntityVitalityModel
Lasts = 75, Vision = 1000}) {
Health = 300, DefenseLayer = 100, Armor = ArmorType.Heavy,
Lasts = 75, Vision = 1000
})
.AddPart(new EntityMovementModel { Speed = 0, Movement = MovementType.Ground }) .AddPart(new EntityMovementModel { Speed = 0, Movement = MovementType.Ground })
.AddPart(new EntityWeaponModel .AddPart(new EntityWeaponModel
{ {
@ -3021,9 +3073,12 @@ public class DATA
Id = DataType.BUILDING_KeeperOfTheHardenedFlames, Id = DataType.BUILDING_KeeperOfTheHardenedFlames,
Requirement = RequirementType.Research_Building Requirement = RequirementType.Research_Building
}) })
.AddPart(new EntityWeaponModel {Damage = 14, Range = 700, SecondsBetweenAttacks = 1.8f, Targets .AddPart(new EntityWeaponModel
= TargetType.All}) {
.AddPart(new EntityIdPassiveModel {Id = DataType.PASSIVE_HallowedWeapons}) Damage = 14, Range = 700, SecondsBetweenAttacks = 1.8f, Targets
= TargetType.All
})
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_HallowedWeapons })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Health = 300, DefenseLayer = 150, Armor = ArmorType.Heavy, IsStructure = true }) { Health = 300, DefenseLayer = 150, Armor = ArmorType.Heavy, IsStructure = true })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_PsalmOfFire }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_PsalmOfFire })

1
Model/Entity/Data/Ids_Entity.cs

@ -56,7 +56,6 @@ public static class DataType
public static string ISPELL_RainOfBlood = "792df385-c66a-4710-9f75-97731897a565"; public static string ISPELL_RainOfBlood = "792df385-c66a-4710-9f75-97731897a565";
public static string IPASSIVE_HealingGround = "3ec17526-8dc5-4592-9c15-ef1d9b1ca2f6"; public static string IPASSIVE_HealingGround = "3ec17526-8dc5-4592-9c15-ef1d9b1ca2f6";
public static string IPASSIVE_Expansionist = "b6cd4335-2165-44c3-b3dc-4500c0111870"; public static string IPASSIVE_Expansionist = "b6cd4335-2165-44c3-b3dc-4500c0111870";

1
Model/Entity/Parts/EntityFactionModel.cs

@ -1,5 +1,4 @@
using Model.Entity.Data; using Model.Entity.Data;
using Model.Types;
namespace Model.Entity.Parts; namespace Model.Entity.Parts;

4
Model/Model.csproj

@ -4,7 +4,7 @@
<TargetFramework>net7.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
<PackageReference Include="YamlDotNet" Version="11.2.1" /> <PackageReference Include="YamlDotNet" Version="11.2.1"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

3
Model/Website/WebSectionModel.cs

@ -11,5 +11,8 @@ public class WebSectionModel
public int Order { get; set; } = 0; public int Order { get; set; } = 0;
public string IsPrivate { get; set; } = "True"; public string IsPrivate { get; set; } = "True";
public string Icon { get; set; } = "fa-icons";
public bool OnlyIcon { get; set; } = false;
[NotMapped] public List<WebPageModel> WebPageModels { get; set; } = new(); [NotMapped] public List<WebPageModel> WebPageModels { get; set; } = new();
} }

1
Services/IServices.cs

@ -29,7 +29,6 @@ public interface IToastService
public interface IDataCollectionService public interface IDataCollectionService
{ {
public void SendEvent<T>(string eventName, T eventData); public void SendEvent<T>(string eventName, T eventData);
} }
public interface IStorageService public interface IStorageService

17
Services/Immortal/BuildOrderService.cs

@ -343,16 +343,10 @@ public class BuildOrderService : IBuildOrderService
var checkedInterval = _lastInterval; var checkedInterval = _lastInterval;
if (supply == null || production == null || supply.Takes.Equals(0)) if (supply == null || production == null || supply.Takes.Equals(0)) return 1;
{
return 1;
}
var producedBy = production.ProducedBy; var producedBy = production.ProducedBy;
if (producedBy == null) if (producedBy == null) return 1;
{
return 1;
}
var uniqueCompleted = _buildOrder.UniqueCompleted[producedBy]; var uniqueCompleted = _buildOrder.UniqueCompleted[producedBy];
@ -372,7 +366,7 @@ public class BuildOrderService : IBuildOrderService
usedSlots += used.UsedSlots; usedSlots += used.UsedSlots;
var duration = used.StopUsageTime - used.StartingUsageTime; var duration = used.StopUsageTime - used.StartingUsageTime;
if (duration < shortestIncrement) shortestIncrement = duration; if (duration < shortestIncrement) shortestIncrement = duration;
} }
if (usedSlots + supply.Takes <= trainingSlots) if (usedSlots + supply.Takes <= trainingSlots)
{ {
@ -389,10 +383,7 @@ public class BuildOrderService : IBuildOrderService
checkedInterval += shortestIncrement; checkedInterval += shortestIncrement;
didDelay = true; didDelay = true;
if (shortestIncrement == int.MaxValue) if (shortestIncrement == int.MaxValue) return null;
{
return null;
}
} }
} }

5
Services/Immortal/EntityFilterService.cs

@ -1,5 +1,4 @@
using Model.Entity.Data; using Model.Entity.Data;
using Model.Types;
using static Services.IEntityFilterService; using static Services.IEntityFilterService;
namespace Services.Immortal; namespace Services.Immortal;
@ -16,7 +15,9 @@ public class EntityFilterService : IEntityFilterService
{ {
private readonly List<string> _entityChoices = new(); private readonly List<string> _entityChoices = new();
private readonly List<string> _factionChoices = new() { DataType.Any, DataType.FACTION_QRath, DataType.FACTION_Aru }; private readonly List<string> _factionChoices = new()
{ DataType.Any, DataType.FACTION_QRath, DataType.FACTION_Aru };
private readonly List<string> _immortalChoices = new(); private readonly List<string> _immortalChoices = new();
private string _entityType = EntityType.Army; private string _entityType = EntityType.Army;
private string _searchText = ""; private string _searchText = "";

3
Services/Immortal/ImmortalSelectionService.cs

@ -5,11 +5,10 @@ namespace Services.Immortal;
public class ImmortalSelectionService : IImmortalSelectionService, IDisposable public class ImmortalSelectionService : IImmortalSelectionService, IDisposable
{ {
private readonly IStorageService _storageService;
private string _selectedFaction = DataType.FACTION_QRath; private string _selectedFaction = DataType.FACTION_QRath;
private string _selectedImmortal = DataType.IMMORTAL_Orzum; private string _selectedImmortal = DataType.IMMORTAL_Orzum;
private readonly IStorageService _storageService;
public ImmortalSelectionService(IStorageService storageService) public ImmortalSelectionService(IStorageService storageService)
{ {
_storageService = storageService; _storageService = storageService;

12
Services/Services.csproj

@ -15,15 +15,15 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Blazor-Analytics" Version="3.11.0" /> <PackageReference Include="Blazor-Analytics" Version="3.11.0"/>
<PackageReference Include="Blazored.LocalStorage" Version="4.3.0-preview.1" /> <PackageReference Include="Blazored.LocalStorage" Version="4.3.0-preview.1"/>
<PackageReference Include="Microsoft.AspNetCore.Components.ProtectedBrowserStorage" Version="5.0.0-rc.1.20451.17" /> <PackageReference Include="Microsoft.AspNetCore.Components.ProtectedBrowserStorage" Version="5.0.0-rc.1.20451.17"/>
<PackageReference Include="Microsoft.JSInterop" Version="7.0.0-preview.2.22153.2" /> <PackageReference Include="Microsoft.JSInterop" Version="7.0.0-preview.2.22153.2"/>
<PackageReference Include="YamlDotNet" Version="11.2.1" /> <PackageReference Include="YamlDotNet" Version="11.2.1"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Model\Model.csproj" /> <ProjectReference Include="..\Model\Model.csproj"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

19
Services/Website/DataCollectionService.cs

@ -1,6 +1,4 @@
using Blazor.Analytics; using Blazor.Analytics;
using Blazored.LocalStorage;
using Model.Feedback;
namespace Services.Website; namespace Services.Website;
@ -14,10 +12,10 @@ public class DataCollectionKeys
public class DataCollectionService : IDataCollectionService, IDisposable public class DataCollectionService : IDataCollectionService, IDisposable
{ {
private readonly IAnalytics _globalTracking;
private readonly IStorageService _storageService; private readonly IStorageService _storageService;
private bool _isEnabled = false; private bool _isEnabled;
private readonly IAnalytics _globalTracking;
public DataCollectionService(IAnalytics globalTracking, public DataCollectionService(IAnalytics globalTracking,
IStorageService storageService) IStorageService storageService)
@ -30,6 +28,11 @@ public class DataCollectionService : IDataCollectionService, IDisposable
Refresh(); Refresh();
} }
public void SendEvent<T>(string eventName, T eventData)
{
if (_isEnabled) _globalTracking.TrackEvent(eventName, eventData);
}
void IDisposable.Dispose() void IDisposable.Dispose()
{ {
_storageService.Unsubscribe(Refresh); _storageService.Unsubscribe(Refresh);
@ -39,12 +42,4 @@ public class DataCollectionService : IDataCollectionService, IDisposable
{ {
_isEnabled = _storageService.GetValue<bool>(StorageKeys.EnabledDataCollection); _isEnabled = _storageService.GetValue<bool>(StorageKeys.EnabledDataCollection);
} }
public void SendEvent<T>(string eventName, T eventData)
{
if (_isEnabled)
{
_globalTracking.TrackEvent(eventName, eventData);
}
}
} }

7
Services/Website/DialogService.cs

@ -1,7 +1,4 @@
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Model.Entity.Data;
using Model.Website;
namespace Services.Website; namespace Services.Website;
@ -18,10 +15,6 @@ public class DialogService : IDialogService
{ {
private DialogContents _dialogContents; private DialogContents _dialogContents;
public DialogService()
{
}
public bool IsVisible { get; set; } public bool IsVisible { get; set; }
public void Subscribe(Action action) public void Subscribe(Action action)

2
Services/Website/PermissionService.cs

@ -4,8 +4,8 @@ namespace Services.Website;
public class PermissionService : IPermissionService, IDisposable public class PermissionService : IPermissionService, IDisposable
{ {
private IJSRuntime _jsRuntime;
private readonly IStorageService _storageService; private readonly IStorageService _storageService;
private IJSRuntime _jsRuntime;
private IToastService _toastService; private IToastService _toastService;
private bool isLoaded; private bool isLoaded;
private bool isStorageEnabled = false; private bool isStorageEnabled = false;

1
Services/Website/StorageService.cs

@ -93,6 +93,7 @@ public class StorageService : IStorageService
} }
private event Action OnChange = null!; private event Action OnChange = null!;
private void NotifyDataChanged() private void NotifyDataChanged()
{ {
OnChange(); OnChange();

5
TestAutomation/BaseTest.cs

@ -35,10 +35,7 @@ public class BaseTest
options.AcceptInsecureCertificates = true; options.AcceptInsecureCertificates = true;
if (DeploymentType.Equals(DeploymentType.Dev)) if (DeploymentType.Equals(DeploymentType.Dev)) options.AddArgument("--headless");
{
options.AddArgument("--headless");
}
options.AddArgument("--ignore-certificate-errors"); options.AddArgument("--ignore-certificate-errors");
options.AddArgument("--start-maximized"); options.AddArgument("--start-maximized");
options.AddArgument("--test-type"); options.AddArgument("--test-type");

22
TestAutomation/Pages/DatabasePage.cs

@ -6,20 +6,24 @@ namespace TestAutomation.Pages;
public class DatabasePage : BaseElement public class DatabasePage : BaseElement
{ {
public DatabasePage(Website website) : base(website)
{
}
private IWebElement FilterNameInput => Website.Find("filterName"); private IWebElement FilterNameInput => Website.Find("filterName");
private ReadOnlyCollection<IWebElement> EntityNames() => private ReadOnlyCollection<IWebElement> EntityNames()
Website.FindAll("entityName"); {
return Website.FindAll("entityName");
}
private IWebElement EntityName(string entityType, string entityName) => private IWebElement EntityName(string entityType, string entityName)
Website.Find("entityName", {
return Website.Find("entityName",
$"{entityType.ToLower()}-{entityName.ToLower()}"); $"{entityType.ToLower()}-{entityName.ToLower()}");
}
public DatabasePage(Website website) : base(website) { }
public DatabasePage FilterName(string name) public DatabasePage FilterName(string name)
{ {
@ -34,11 +38,9 @@ public class DatabasePage : BaseElement
return this; return this;
} }
public DatabasePage GetEntityName(int index,out string result) public DatabasePage GetEntityName(int index, out string result)
{ {
result = EntityNames()[index].Text; result = EntityNames()[index].Text;
return this; return this;
} }
} }

7
TestAutomation/Pages/DatabaseSinglePage.cs

@ -5,14 +5,16 @@ namespace TestAutomation.Pages;
public class DatabaseSinglePage : BaseElement public class DatabaseSinglePage : BaseElement
{ {
public DatabaseSinglePage(Website website) : base(website)
{
}
private IWebElement EntityName => Website.Find("entityName"); private IWebElement EntityName => Website.Find("entityName");
private IWebElement EntityHealth => Website.Find("entityHealth"); private IWebElement EntityHealth => Website.Find("entityHealth");
private IWebElement InvalidSearch => Website.Find("invalidSearch"); private IWebElement InvalidSearch => Website.Find("invalidSearch");
private IWebElement ValidSearch => Website.Find("validSearch"); private IWebElement ValidSearch => Website.Find("validSearch");
public DatabaseSinglePage(Website website) : base(website) { }
public DatabaseSinglePage GetEntityName(out string result) public DatabaseSinglePage GetEntityName(out string result)
{ {
@ -37,5 +39,4 @@ public class DatabaseSinglePage : BaseElement
result = ValidSearch.Text; result = ValidSearch.Text;
return this; return this;
} }
} }

8
TestAutomation/Shared/NavigationBar.cs

@ -1,13 +1,13 @@
using TestAutomation.Enums;
using TestAutomation.Utils; using TestAutomation.Utils;
namespace TestAutomation.Shared; namespace TestAutomation.Shared;
public class NavigationBar : BaseElement public class NavigationBar : BaseElement
{ {
public NavigationBar(Website website) : base(website) { } public NavigationBar(Website website) : base(website)
{
}
private IWebElement HomeLink => Website.FindScreenSpecific("homeLink"); private IWebElement HomeLink => Website.FindScreenSpecific("homeLink");
private IWebElement SearchButton => Website.FindScreenSpecific("searchButton"); private IWebElement SearchButton => Website.FindScreenSpecific("searchButton");

1
TestAutomation/Shared/WebsiteSearchDialog.cs

@ -1,4 +1,3 @@
using Discord.Rest;
using TestAutomation.Utils; using TestAutomation.Utils;
namespace TestAutomation.Shared; namespace TestAutomation.Shared;

22
TestAutomation/TestAutomation.csproj

@ -9,20 +9,20 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Discord.Net.Webhook" Version="3.6.0" /> <PackageReference Include="Discord.Net.Webhook" Version="3.6.0"/>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0-preview.2.22152.2" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="7.0.0-preview.2.22152.2"/>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0"/>
<PackageReference Include="NUnit" Version="3.13.2" /> <PackageReference Include="NUnit" Version="3.13.2"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.2.0" /> <PackageReference Include="NUnit3TestAdapter" Version="4.2.0"/>
<PackageReference Include="NUnit.Analyzers" Version="3.2.0" /> <PackageReference Include="NUnit.Analyzers" Version="3.2.0"/>
<PackageReference Include="coverlet.collector" Version="3.1.0" /> <PackageReference Include="coverlet.collector" Version="3.1.0"/>
<PackageReference Include="Selenium.WebDriver" Version="4.1.0" /> <PackageReference Include="Selenium.WebDriver" Version="4.1.0"/>
<PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="101.0.4951.4100" /> <PackageReference Include="Selenium.WebDriver.ChromeDriver" Version="101.0.4951.4100"/>
<PackageReference Include="Selenium.WebDriver.GeckoDriver" Version="0.31.0" /> <PackageReference Include="Selenium.WebDriver.GeckoDriver" Version="0.31.0"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Pages\" /> <Folder Include="Pages\"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

16
TestAutomation/TestSearchFeatures.cs

@ -32,8 +32,10 @@ public class TestSearchFeatures : BaseTest
.GetEntityName(out var name) .GetEntityName(out var name)
.GetEntityHealth(out var health); .GetEntityHealth(out var health);
TestReport.CheckPassed(name.Equals("Throne"), new TestMessage(){ Description = "Couldn't find Throne via search."}); TestReport.CheckPassed(name.Equals("Throne"),
TestReport.CheckPassed(!health.Trim().Equals(""), new TestMessage(){ Description = "Throne has no visible health!"}); new TestMessage { Description = "Couldn't find Throne via search." });
TestReport.CheckPassed(!health.Trim().Equals(""),
new TestMessage { Description = "Throne has no visible health!" });
} }
[Test] [Test]
@ -48,7 +50,7 @@ public class TestSearchFeatures : BaseTest
.GetEntityName(0, out var name); .GetEntityName(0, out var name);
TestReport.CheckPassed(name.Equals("Throne"), TestReport.CheckPassed(name.Equals("Throne"),
new TestMessage(){ Description = "Couldn't find Throne via filter."}); new TestMessage { Description = "Couldn't find Throne via filter." });
} }
[Test] [Test]
@ -59,10 +61,10 @@ public class TestSearchFeatures : BaseTest
Website.WebDriver.Navigate().GoToUrl(WebsiteUrl + "/database"); Website.WebDriver.Navigate().GoToUrl(WebsiteUrl + "/database");
Website.DatabasePage Website.DatabasePage
.GetEntityName( "army", "throne", out var name); .GetEntityName("army", "throne", out var name);
TestReport.CheckPassed(name.Equals("Throne"), TestReport.CheckPassed(name.Equals("Throne"),
new TestMessage(){ Description = "Couldn't find Throne on the page by default."}); new TestMessage { Description = "Couldn't find Throne on the page by default." });
} }
[Test] [Test]
@ -77,9 +79,9 @@ public class TestSearchFeatures : BaseTest
.GetValidSearch(out var validSearch); .GetValidSearch(out var validSearch);
TestReport.CheckPassed(invalidSearch.Equals("not throne"), TestReport.CheckPassed(invalidSearch.Equals("not throne"),
new TestMessage(){ Description = "Couldn't find invalid search text on the page."}); new TestMessage { Description = "Couldn't find invalid search text on the page." });
TestReport.CheckPassed(validSearch.Equals("Throne"), TestReport.CheckPassed(validSearch.Equals("Throne"),
new TestMessage(){ Description = "Couldn't find valid search text on the page."}); new TestMessage { Description = "Couldn't find valid search text on the page." });
Website.WebDriver.Navigate().GoToUrl(WebsiteUrl + "/database/not throne"); Website.WebDriver.Navigate().GoToUrl(WebsiteUrl + "/database/not throne");
} }

10
TestAutomation/Utils/Website.cs

@ -44,7 +44,7 @@ public class Website
catch (Exception e) catch (Exception e)
{ {
throw new Exception($"Couldn't find {screenSpecificId}. Element does not exist on current page. " + throw new Exception($"Couldn't find {screenSpecificId}. Element does not exist on current page. " +
$"\n\nPerhaps an Id is missing."); "\n\nPerhaps an Id is missing.");
} }
} }
@ -60,7 +60,7 @@ public class Website
catch (Exception e) catch (Exception e)
{ {
throw new Exception($"Couldn't find parent {withParentId}. Element does not exist on current page. " + throw new Exception($"Couldn't find parent {withParentId}. Element does not exist on current page. " +
$"\n\nPerhaps an Id is missing."); "\n\nPerhaps an Id is missing.");
} }
try try
@ -70,7 +70,7 @@ public class Website
catch (Exception e) catch (Exception e)
{ {
throw new Exception($"Couldn't find {byId}. Element does not exist on current page. " + throw new Exception($"Couldn't find {byId}. Element does not exist on current page. " +
$"\n\nPerhaps an Id is missing."); "\n\nPerhaps an Id is missing.");
} }
} }
@ -83,7 +83,7 @@ public class Website
catch (Exception e) catch (Exception e)
{ {
throw new Exception($"Couldn't find {byId}. Element does not exist on current page. " + throw new Exception($"Couldn't find {byId}. Element does not exist on current page. " +
$"\n\nPerhaps an Id is missing."); "\n\nPerhaps an Id is missing.");
} }
} }
@ -96,7 +96,7 @@ public class Website
catch (Exception e) catch (Exception e)
{ {
throw new Exception($"Couldn't find {byId}. Element does not exist on current page. " + throw new Exception($"Couldn't find {byId}. Element does not exist on current page. " +
$"\n\nPerhaps an Id is missing."); "\n\nPerhaps an Id is missing.");
} }
} }

Loading…
Cancel
Save