Browse Source

feature(BuildCalc) Added reset button, can change micro delay, and can alter timing interval again

main
Jonathan McCaffrey 4 years ago
parent
commit
04c1718259
  1. 2
      .github/workflows/development.yml
  2. 2
      .github/workflows/production.yml
  3. 10
      Components/Components.csproj
  4. 6
      Components/Display/DevOnlyComponent.razor
  5. 21
      Components/Display/PanelComponent.razor
  6. 9
      Components/Feedback/AlertComponent.razor
  7. 6
      Components/Form/FormCheckboxComponent.razor
  8. 6
      Components/Form/FormDisplayComponent.razor
  9. 3
      Components/Form/FormEscapeCodeComponent.razor
  10. 45
      Components/Form/FormGuessComponent.razor
  11. 6
      Components/Form/FormNumberComponent.razor
  12. 6
      Components/Form/FormSelectComponent.razor
  13. 9
      Components/Form/FormTextAreaComponent.razor
  14. 9
      Components/Form/FormTextComponent.razor
  15. 6
      Components/Info/InfoBodyComponent.razor
  16. 3
      Components/Inputs/ButtonComponent.razor
  17. 15
      Components/Inputs/ButtonGroupComponent.razor
  18. 3
      Components/Inputs/ButtonType.cs
  19. 1
      Components/Inputs/CodeLinkComponent.razor
  20. 1
      Components/Inputs/EditLinkComponent.razor
  21. 8
      Components/Inputs/EntityLabelComponent.razor
  22. 2
      Components/Inputs/EntityLabelComponent.razor.css
  23. 5
      Components/Layout/LayoutWithSidebarComponent.razor
  24. 10
      Components/MarkdownContent/MarkdownContent.razor
  25. 15
      Components/Navigation/DesktopNavLinkComponent.razor
  26. 10
      Components/Navigation/DesktopNavSectionComponent.razor
  27. 26
      Components/Navigation/MobileNavComponent.razor
  28. 16
      Components/Navigation/TabletNavComponent.razor
  29. 10
      Components/Shared/DisplayableContent.razor
  30. 10
      Components/Shared/DisplayableRoute.razor
  31. 2
      Contexts/Contexts.csproj
  32. 9
      Contexts/DatabaseContext.cs
  33. BIN
      IGP/Database.db
  34. 16
      IGP/Index.razor
  35. 6
      IGP/Localizations.Designer.cs
  36. 6
      IGP/Localizations.resx
  37. 2
      IGP/Pages/Agile/AgilePage.razor
  38. 2
      IGP/Pages/Agile/Parts/SprintComponent.razor
  39. 103
      IGP/Pages/BuildCalculator/BuildCalculatorPage.razor
  40. 15
      IGP/Pages/BuildCalculator/Parts/ArmyComponent.razor
  41. 2
      IGP/Pages/BuildCalculator/Parts/BuildOrderComponent.razor
  42. 6
      IGP/Pages/BuildCalculator/Parts/ChartComponent.razor
  43. 9
      IGP/Pages/BuildCalculator/Parts/EntityClickViewComponent.razor
  44. 13
      IGP/Pages/BuildCalculator/Parts/FilterComponent.razor
  45. 25
      IGP/Pages/BuildCalculator/Parts/HighlightsComponent.razor
  46. 14
      IGP/Pages/BuildCalculator/Parts/HotkeyViewerComponent.razor
  47. 2
      IGP/Pages/BuildCalculator/Parts/InputPanelComponent.razor
  48. 41
      IGP/Pages/BuildCalculator/Parts/OptionsComponent.razor
  49. 27
      IGP/Pages/BuildCalculator/Parts/TimelineComponent.razor
  50. 13
      IGP/Pages/BuildCalculator/Parts/TimingComponent.razor
  51. 1
      IGP/Pages/Database/Entity/Parts/EntityPassivesComponent.razor
  52. 29
      IGP/Pages/Documentation/Parts/DocumentComponent.razor
  53. 8
      IGP/Pages/MakingOf/Parts/MakingOfNavigation.razor
  54. 22
      IGP/Pages/Notes/Parts/NoteComponent.razor
  55. 5
      IGP/Portals/ToastPortal.razor
  56. 3
      IGP/Program.cs
  57. 6
      IGP/Utils/Interval.cs
  58. 7
      IGP/Utils/Markdown.cs
  59. 7
      IGP/Utils/Project.cs
  60. 14
      IGP/_Imports.razor
  61. 6
      IGP/wwwroot/content/docs/cheat-sheet.md
  62. 15
      IGP/wwwroot/content/docs/project-data.md
  63. 29
      IGP/wwwroot/content/docs/setup.md
  64. 36
      IGP/wwwroot/content/notes/coop/holdout.md
  65. 177
      IGP/wwwroot/content/notes/settings/hotkeys.md
  66. 36
      IGP/wwwroot/content/notes/the-basics/armor-types.md
  67. 6
      IGP/wwwroot/content/notes/the-basics/economy-overview.md
  68. 6
      IGP/wwwroot/content/notes/the-basics/families-factions-and-immortal-vanguards.md
  69. 6
      IGP/wwwroot/content/notes/the-basics/immortal-spells-and-pyre.md
  70. 5
      IGP/wwwroot/content/notes/the-basics/timing-and-scouting.md
  71. 2
      IGP/wwwroot/generated/AgileTaskModels.json
  72. 6
      IGP/wwwroot/service-worker.published.js
  73. 3
      IGP_Convert/Program.cs
  74. 73
      Model/BuildOrders/BuildOrderModel.cs
  75. 5
      Model/Doc/DocContentModel.cs
  76. 5
      Model/Economy/EconomyOverTimeModel.cs
  77. 220
      Model/Entity/Data/DATA.cs
  78. 12
      Model/Entity/EntityModel.cs
  79. 4
      Model/Git/GitChangeModel.cs
  80. 12
      Model/Model.csproj
  81. 7
      Model/Notes/NoteContentModel.cs
  82. 2
      Model/Website/WebSectionModel.cs
  83. 11
      Services/Development/DocumentationService.cs
  84. 37
      Services/Development/GitService.cs
  85. 77
      Services/Development/NoteService.cs
  86. 60
      Services/IServices.cs
  87. 53
      Services/Immortal/BuildComparisionService.cs
  88. 81
      Services/Immortal/BuildOrderService.cs
  89. 47
      Services/Immortal/EconomyService.cs
  90. 26
      Services/Immortal/EntityDisplayService.cs
  91. 87
      Services/Immortal/EntityFilterService.cs
  92. 6
      Services/Immortal/EntityService.cs
  93. 25
      Services/Immortal/ImmortalSelectionService.cs
  94. 53
      Services/Immortal/KeyService.cs
  95. 52
      Services/Immortal/MemoryTesterService.cs
  96. 26
      Services/Immortal/TimingService.cs
  97. 6
      Services/Services.csproj
  98. 28
      Services/Website/EntityDialogService.cs
  99. 56
      Services/Website/NavigationService.cs
  100. 34
      Services/Website/ToastService.cs
  101. Some files were not shown because too many files have changed in this diff Show More

2
.github/workflows/development.yml

@ -5,7 +5,7 @@ on:
branches: branches:
- develop - develop
pull_request: pull_request:
types: [opened, synchronize, reopened, closed] types: [ opened, synchronize, reopened, closed ]
branches: branches:
- develop - develop

2
.github/workflows/production.yml

@ -5,7 +5,7 @@ on:
branches: branches:
- main - main
pull_request: pull_request:
types: [opened, synchronize, reopened, closed] types: [ opened, synchronize, reopened, closed ]
branches: branches:
- main - main

10
Components/Components.csproj

@ -15,7 +15,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<SupportedPlatform Include="browser" /> <SupportedPlatform Include="browser"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
@ -25,14 +25,14 @@
</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>

6
Components/Display/DevOnlyComponent.razor

@ -1,4 +1,5 @@
@if (isOnDev) { @if (isOnDev)
{
<div class="devOnlyContainer"> <div class="devOnlyContainer">
<div class="devOnlyTitleContainer"> <div class="devOnlyTitleContainer">
<div class="devOnlyTitle"> <div class="devOnlyTitle">
@ -65,7 +66,8 @@
bool isOnDev; bool isOnDev;
protected override void OnInitialized() { protected override void OnInitialized()
{
isOnDev = NavigationManager.BaseUri.Contains("https://localhost"); isOnDev = NavigationManager.BaseUri.Contains("https://localhost");
} }

21
Components/Display/PanelComponent.razor

@ -0,0 +1,21 @@
<div class="panelDisplay">
@ChildContent
</div>
<style>
.panelDisplay {
border: 2px solid var(--paper-border);
padding: 20px;
background-color: var(--paper);
display: flex;
flex-direction: column;
flex-grow: 1;
}
</style>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; } = default!;
}

9
Components/Feedback/AlertComponent.razor

@ -1,11 +1,12 @@
@using Model.Feedback <div class="alertContainer @Type.ToLower()">
<div class="alertContainer @Type.ToLower()"> @if (Title != null)
@if (Title != null) { {
<div class="alertTitle"> <div class="alertTitle">
@Title @Title
</div> </div>
} }
@if (Message != null) { @if (Message != null)
{
<div> <div>
@Message @Message
</div> </div>

6
Components/Form/FormCheckboxComponent.razor

@ -10,7 +10,8 @@
checked="@Value checked="@Value
"@onchange="OnChange"/> "@onchange="OnChange"/>
</div> </div>
@if (Info != "") { @if (Info != "")
{
<div class="formInfo"> <div class="formInfo">
@Info @Info
</div> </div>
@ -66,7 +67,8 @@
private string labelId = ""; private string labelId = "";
protected override void OnInitialized() { protected override void OnInitialized()
{
labelId = Label.ToLower().Replace(" ", "_"); labelId = Label.ToLower().Replace(" ", "_");
} }

6
Components/Form/FormDisplayComponent.razor

@ -1,5 +1,6 @@
<div class="displayContainer"> <div class="displayContainer">
@if (Label != "") { @if (Label != "")
{
<div class="formLabel"> <div class="formLabel">
@Label @Label
</div> </div>
@ -7,7 +8,8 @@
<div class="displayContent"> <div class="displayContent">
@Display @Display
</div> </div>
@if (Info != "") { @if (Info != "")
{
<div class="formInfo"> <div class="formInfo">
@Info @Info
</div> </div>

3
Components/Form/FormEscapeCodeComponent.razor

@ -20,7 +20,8 @@
@code { @code {
string Output = ""; string Output = "";
public void OnChange(ChangeEventArgs changeEventArgs) { public void OnChange(ChangeEventArgs changeEventArgs)
{
var encoded = HttpUtility.HtmlEncode(changeEventArgs.Value!.ToString()); var encoded = HttpUtility.HtmlEncode(changeEventArgs.Value!.ToString());
Output = encoded?.Replace("@", "@@")!; Output = encoded?.Replace("@", "@@")!;
Output = Output.Replace("\n", "<br />"); Output = Output.Replace("\n", "<br />");

45
Components/Form/FormGuessComponent.razor

@ -1,12 +1,12 @@
@using Services @using Model.MemoryTester
@using Services.Immortal @using Services.Immortal
@using Model.MemoryTester
@implements IDisposable @implements IDisposable
@inject IMemoryTesterService MemoryTesterService @inject IMemoryTesterService MemoryTesterService
<div class="formGuessContainer"> <div class="formGuessContainer">
@if (MemoryQuestion.Name != "") { @if (MemoryQuestion.Name != "")
{
<div class="formLabel"> <div class="formLabel">
@MemoryQuestion.Name @MemoryQuestion.Name
</div> </div>
@ -94,46 +94,57 @@
private string labelId = ""; private string labelId = "";
protected override void OnInitialized() { protected override void OnInitialized()
{
labelId = Label.ToLower().Replace(" ", "_") + MemoryQuestion.Id; labelId = Label.ToLower().Replace(" ", "_") + MemoryQuestion.Id;
MemoryTesterService.Subscribe(OnMemoryEvent); MemoryTesterService.Subscribe(OnMemoryEvent);
if (MemoryQuestion.IsRevealed) { if (MemoryQuestion.IsRevealed)
{
guess = MemoryQuestion.Answer.ToString(); guess = MemoryQuestion.Answer.ToString();
} }
OnRefresh(); OnRefresh();
} }
void IDisposable.Dispose() { void IDisposable.Dispose()
{
MemoryTesterService.Unsubscribe(OnMemoryEvent); MemoryTesterService.Unsubscribe(OnMemoryEvent);
} }
void OnMemoryEvent(MemoryTesterEvent memoryTesterEvent) { void OnMemoryEvent(MemoryTesterEvent memoryTesterEvent)
if (memoryTesterEvent == MemoryTesterEvent.OnVerify) { {
if (memoryTesterEvent == MemoryTesterEvent.OnVerify)
{
OnVerify(); OnVerify();
} }
if (memoryTesterEvent == MemoryTesterEvent.OnRefresh) { if (memoryTesterEvent == MemoryTesterEvent.OnRefresh)
{
OnRefresh(); OnRefresh();
} }
} }
protected override void OnAfterRender(bool firstRender) { protected override void OnAfterRender(bool firstRender)
if (MemoryQuestion.IsRevealed) { {
if (MemoryQuestion.IsRevealed)
{
guess = MemoryQuestion.Answer.ToString(); guess = MemoryQuestion.Answer.ToString();
} }
} }
void OnVerify() { void OnVerify()
{
IsSubmitted = true; IsSubmitted = true;
} }
void OnRefresh() { void OnRefresh()
{
guess = ""; guess = "";
if (MemoryQuestion.IsRevealed) { if (MemoryQuestion.IsRevealed)
{
guess = MemoryQuestion.Answer.ToString(); guess = MemoryQuestion.Answer.ToString();
} }
@ -141,10 +152,12 @@
IsSubmitted = false; IsSubmitted = false;
} }
void OnGuessChanged(ChangeEventArgs changeEventArgs) { void OnGuessChanged(ChangeEventArgs changeEventArgs)
{
guess = changeEventArgs.Value!.ToString()!; guess = changeEventArgs.Value!.ToString()!;
OnChange.InvokeAsync(new AnswerEventArgs { OnChange.InvokeAsync(new AnswerEventArgs
{
Name = MemoryQuestion.Name, Name = MemoryQuestion.Name,
IsCorrect = int.Parse(guess) == MemoryQuestion.Answer, IsCorrect = int.Parse(guess) == MemoryQuestion.Answer,
Guess = int.Parse(guess) Guess = int.Parse(guess)

6
Components/Form/FormNumberComponent.razor

@ -1,5 +1,6 @@
<div class="formNumberContainer"> <div class="formNumberContainer">
@if (FormLabelComponent != null) { @if (FormLabelComponent != null)
{
<FormLabelComponent>@FormLabelComponent</FormLabelComponent> <FormLabelComponent>@FormLabelComponent</FormLabelComponent>
} }
<div> <div>
@ -11,7 +12,8 @@
value="@Value" value="@Value"
@onchange="OnChange"/> @onchange="OnChange"/>
</div> </div>
@if (FormInfoComponent != null) { @if (FormInfoComponent != null)
{
<FormInfoComponent>@FormInfoComponent</FormInfoComponent> <FormInfoComponent>@FormInfoComponent</FormInfoComponent>
} }
</div> </div>

6
Components/Form/FormSelectComponent.razor

@ -1,5 +1,6 @@
<div style="display: flex; width: 100%; flex-direction: column; gap:6px;"> <div style="display: flex; width: 100%; flex-direction: column; gap:6px;">
@if (FormLabelComponent != null) { @if (FormLabelComponent != null)
{
<FormLabelComponent>@FormLabelComponent</FormLabelComponent> <FormLabelComponent>@FormLabelComponent</FormLabelComponent>
} }
<select style="background-color: #2C2E33; width: 100%; border:3px solid #A8ADB9; border-radius:1px; padding: 8px;" <select style="background-color: #2C2E33; width: 100%; border:3px solid #A8ADB9; border-radius:1px; padding: 8px;"
@ -7,7 +8,8 @@
@ChildContent @ChildContent
</select> </select>
@if (FormInfoComponent != null) { @if (FormInfoComponent != null)
{
<FormInfoComponent>@FormInfoComponent</FormInfoComponent> <FormInfoComponent>@FormInfoComponent</FormInfoComponent>
} }
</div> </div>

9
Components/Form/FormTextAreaComponent.razor

@ -1,5 +1,6 @@
<div class="form-text-container"> <div class="form-text-container">
@if (Label != "") { @if (Label != "")
{
<div class="form-label"> <div class="form-label">
@Label @Label
</div> </div>
@ -12,7 +13,8 @@
value="@Value" value="@Value"
@onchange="OnChange" /> @onchange="OnChange" />
</div> </div>
@if (Info != "") { @if (Info != "")
{
<div class="form-info"> <div class="form-info">
@Info @Info
</div> </div>
@ -83,7 +85,8 @@
private string labelId = ""; private string labelId = "";
protected override void OnInitialized() { protected override void OnInitialized()
{
labelId = Label.ToLower().Replace(" ", "_"); labelId = Label.ToLower().Replace(" ", "_");
} }

9
Components/Form/FormTextComponent.razor

@ -1,5 +1,6 @@
<div class="formContainer"> <div class="formContainer">
@if (Label != "") { @if (Label != "")
{
<div class="formLabel"> <div class="formLabel">
@Label @Label
</div> </div>
@ -13,7 +14,8 @@
id="@labelId" id="@labelId"
@onchange="OnChange"/> @onchange="OnChange"/>
</div> </div>
@if (Info != "") { @if (Info != "")
{
<div class="formInfo"> <div class="formInfo">
@Info @Info
</div> </div>
@ -68,7 +70,8 @@
private string labelId = ""; private string labelId = "";
protected override void OnInitialized() { protected override void OnInitialized()
{
labelId = Label.ToLower().Replace(" ", "_"); labelId = Label.ToLower().Replace(" ", "_");
} }

6
Components/Info/InfoBodyComponent.razor

@ -1,8 +1,10 @@
<div class="infoContainer"> <div class="infoContainer">
@if (InfoQuestionComponent != null) { @if (InfoQuestionComponent != null)
{
<div class="infoTitle">@InfoQuestionComponent</div> <div class="infoTitle">@InfoQuestionComponent</div>
} }
@if (InfoAnswerComponent != null) { @if (InfoAnswerComponent != null)
{
<div>@InfoAnswerComponent</div> <div>@InfoAnswerComponent</div>
} }
</div> </div>

3
Components/Inputs/ButtonComponent.razor

@ -45,7 +45,8 @@
[Parameter] [Parameter]
public ButtonType ButtonType { get; set; } = default!; public ButtonType ButtonType { get; set; } = default!;
private void ButtonClicked(EventArgs eventArgs) { private void ButtonClicked(EventArgs eventArgs)
{
OnClick.InvokeAsync(eventArgs); OnClick.InvokeAsync(eventArgs);
} }

15
Components/Inputs/ButtonGroupComponent.razor

@ -1,13 +1,15 @@
<div class="groupButtonContainerContainer"> <div class="groupButtonContainerContainer">
<div class="groupButtonContainer"> <div class="groupButtonContainer">
@foreach (var choice in Choices) { @foreach (var choice in Choices)
{
var styleClass = ""; var styleClass = "";
if (choice.Equals(Choice)) { if (choice.Equals(Choice))
{
styleClass = "selected"; styleClass = "selected";
} }
<button @onclick="@(e => OnChangeChoice(choice))" class="groupChoiceButton @styleClass">@choice</button> <button @onclick="@(e => OnChangeChoice(choice))" class="groupChoiceButton @styleClass">@choice</button>
} }
</div> </div>
</div> </div>
<style> <style>
@ -77,11 +79,14 @@
public EventCallback<string> OnClick { get; set; } public EventCallback<string> OnClick { get; set; }
protected override void OnInitialized() { } protected override void OnInitialized()
{
}
void OnChangeChoice(string choice) void OnChangeChoice(string choice)
{ {
Choice = choice; Choice = choice;
OnClick.InvokeAsync(choice); OnClick.InvokeAsync(choice);
} }
} }

3
Components/Inputs/ButtonType.cs

@ -1,6 +1,7 @@
namespace Components.Inputs; namespace Components.Inputs;
public enum ButtonType { public enum ButtonType
{
Primary, // Positive Actions Primary, // Positive Actions
Secondary // Destruction Action Secondary // Destruction Action
} }

1
Components/Inputs/CodeLinkComponent.razor

@ -25,4 +25,5 @@
[Parameter] [Parameter]
public string Href { get; set; } = ""; public string Href { get; set; } = "";
} }

1
Components/Inputs/EditLinkComponent.razor

@ -25,4 +25,5 @@
[Parameter] [Parameter]
public string Href { get; set; } = ""; public string Href { get; set; } = "";
} }

8
Components/Inputs/EntityLabelComponent.razor

@ -1,9 +1,5 @@
@using Model.Entity @using Model.Entity
@using Services.Website
@using System.ComponentModel.DataAnnotations
@using Model.Entity.Data @using Model.Entity.Data
@using Services
@inject IEntityDialogService entityDialogService @inject IEntityDialogService entityDialogService
@ -18,7 +14,8 @@ else
@code { @code {
[Parameter] public string EntityId { get; set; } = default!; [Parameter]
public string EntityId { get; set; } = default!;
private EntityModel Entity => DATA.Get()[EntityId]; private EntityModel Entity => DATA.Get()[EntityId];
@ -26,4 +23,5 @@ else
{ {
entityDialogService.AddDialog(EntityId); entityDialogService.AddDialog(EntityId);
} }
} }

2
Components/Inputs/EntityLabelComponent.razor.css

@ -1,7 +1,7 @@
 
.entityLabel { .entityLabel {
font-weight: bolder; font-weight: bolder;
box-shadow: 1px 1px 0 0 rgba(0,0,0,0.2); box-shadow: 1px 1px 0 0 rgba(0, 0, 0, 0.2);
padding-right: 4px; padding-right: 4px;
} }

5
Components/Layout/LayoutWithSidebarComponent.razor

@ -1,5 +1,4 @@
 <div class="layoutWithSidebar">
<div class="layoutWithSidebar">
<div class="layoutSidebar"> <div class="layoutSidebar">
@Sidebar @Sidebar
</div> </div>
@ -50,9 +49,11 @@
</style> </style>
@code { @code {
[Parameter] [Parameter]
public RenderFragment Sidebar { get; set; } = default!; public RenderFragment Sidebar { get; set; } = default!;
[Parameter] [Parameter]
public RenderFragment Content { get; set; } = default!; public RenderFragment Content { get; set; } = default!;
} }

10
Components/MarkdownContent/MarkdownContent.razor

@ -1,6 +1,8 @@
@((MarkupString)MarkdownText) @using Markdig
@((MarkupString)MarkdownText)
@code { @code {
[Inject] [Inject]
protected HttpClient Http { get; set; } = default!; protected HttpClient Http { get; set; } = default!;
@ -9,7 +11,9 @@
private string MarkdownText { get; set; } = ""; private string MarkdownText { get; set; } = "";
protected override async Task OnInitializedAsync() { protected override async Task OnInitializedAsync()
MarkdownText = Markdig.Markdown.ToHtml(await Http.GetStringAsync($"markdown/{MarkdownFileName}.md")); {
MarkdownText = Markdown.ToHtml(await Http.GetStringAsync($"markdown/{MarkdownFileName}.md"));
} }
} }

15
Components/Navigation/DesktopNavLinkComponent.razor

@ -1,14 +1,16 @@
@inject INavigationService navigationService; @inject INavigationService navigationService;
@inject NavigationManager navigationManager; @inject NavigationManager navigationManager;
@if (isOnPage) { @if (isOnPage)
{
<NavLink href="@Page.Href" class="desktopNavLink navSelected"> <NavLink href="@Page.Href" class="desktopNavLink navSelected">
<div class="navName"> <div class="navName">
@Page.Name @Page.Name
</div> </div>
</NavLink> </NavLink>
} }
else { else
{
<NavLink @onclick="() => navigationService.ChangeNavigationState(NavigationStateType.Default)" href="@Page.Href" class="desktopNavLink"> <NavLink @onclick="() => navigationService.ChangeNavigationState(NavigationStateType.Default)" href="@Page.Href" class="desktopNavLink">
<div class="navName"> <div class="navName">
@Page.Name @Page.Name
@ -67,7 +69,8 @@ else {
bool isOnPage = false; bool isOnPage = false;
protected override Task OnParametersSetAsync() { protected override Task OnParametersSetAsync()
{
var uri = navigationManager.Uri.Remove(0, navigationManager.BaseUri.Count()).ToLower(); var uri = navigationManager.Uri.Remove(0, navigationManager.BaseUri.Count()).ToLower();
isOnPage = Page.Href.ToLower().Equals(uri); isOnPage = Page.Href.ToLower().Equals(uri);
@ -75,11 +78,13 @@ else {
} }
void OnNavigationChanged() { void OnNavigationChanged()
{
StateHasChanged(); StateHasChanged();
} }
void OnBack() { void OnBack()
{
navigationService.Back(); navigationService.Back();
} }

10
Components/Navigation/DesktopNavSectionComponent.razor

@ -1,8 +1,8 @@
@using Model.Website <div class="sectionContainer">
@foreach (var childPage in Section.WebPageModels)
<div class="sectionContainer"> {
@foreach (var childPage in Section.WebPageModels) { if (childPage.IsPrivate.Equals("True"))
if (childPage.IsPrivate.Equals("True")) { {
continue; continue;
} }
<DesktopNavLinkComponent Page=childPage></DesktopNavLinkComponent> <DesktopNavLinkComponent Page=childPage></DesktopNavLinkComponent>

26
Components/Navigation/MobileNavComponent.razor

@ -1,9 +1,7 @@
@using Model.Website <div class="mobileFooter">
@using Microsoft.EntityFrameworkCore
<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 @webSection?.Name
@ -15,14 +13,17 @@
<div class="fullPageButton @(selectedSection != null)" @onclick="OnPageClicked" @onclick:stopPropagation="false" @onclick:preventDefault="false"> <div class="fullPageButton @(selectedSection != null)" @onclick="OnPageClicked" @onclick:stopPropagation="false" @onclick:preventDefault="false">
</div> </div>
@if (selectedSection != null) { @if (selectedSection != null)
{
List<WebPageModel?> webPages = (from page in WebPages List<WebPageModel?> webPages = (from page in WebPages
where page.WebSectionModelId == selectedSection.Id where page.WebSectionModelId == selectedSection.Id
select page).ToList()!; select page).ToList()!;
<div class="mobileNavPagesContainer"> <div class="mobileNavPagesContainer">
@foreach (var webPage in webPages) { @foreach (var webPage in webPages)
if (webPage!.IsPrivate.Equals("True")) { {
if (webPage!.IsPrivate.Equals("True"))
{
continue; continue;
} }
<div class="mobileNavPageButton" @onclick="() => OnPageLinkClicked(webPage)" @onclick:preventDefault="true" @onclick:stopPropagation="true"> <div class="mobileNavPageButton" @onclick="() => OnPageLinkClicked(webPage)" @onclick:preventDefault="true" @onclick:stopPropagation="true">
@ -160,18 +161,21 @@
private WebPageModel? selectedPage; private WebPageModel? selectedPage;
void OnSectionClicked(WebSectionModel? webSection) { void OnSectionClicked(WebSectionModel? webSection)
{
selectedSection = webSection; selectedSection = webSection;
} }
void OnPageLinkClicked(WebPageModel? webPage) { void OnPageLinkClicked(WebPageModel? webPage)
{
selectedPage = webPage; selectedPage = webPage;
selectedSection = null; selectedSection = null;
NavigationManager.NavigateTo(webPage?.Href!); NavigationManager.NavigateTo(webPage?.Href!);
} }
void OnPageClicked(EventArgs eventArgs) { void OnPageClicked(EventArgs eventArgs)
{
selectedPage = null; selectedPage = null;
selectedSection = null; selectedSection = null;
} }

16
Components/Navigation/TabletNavComponent.razor

@ -19,7 +19,8 @@
<div class="tabletNav @navOpen"> <div class="tabletNav @navOpen">
@foreach (var webSection in WebSections) { @foreach (var webSection in WebSections)
{
var pages = (from page in WebPages var pages = (from page in WebPages
where page.WebSectionModelId == webSection.Id where page.WebSectionModelId == webSection.Id
select page).ToList(); select page).ToList();
@ -30,8 +31,10 @@
</div> </div>
<div class="tabletNavItems"> <div class="tabletNavItems">
@foreach (var webPage in pages) { @foreach (var webPage in pages)
if (webPage.IsPrivate.Equals("True")) { {
if (webPage.IsPrivate.Equals("True"))
{
continue; continue;
} }
<NavLink href="@webPage.Href" class="tabletNavItem" @onclick="OnPageClicked"> <NavLink href="@webPage.Href" class="tabletNavItem" @onclick="OnPageClicked">
@ -156,15 +159,16 @@
#endif #endif
bool navOpen = true; bool navOpen = true;
void OnNavClicked(EventArgs eventArgs) { void OnNavClicked(EventArgs eventArgs)
{
navOpen = !navOpen; navOpen = !navOpen;
} }
void OnPageClicked(EventArgs eventArgs) { void OnPageClicked(EventArgs eventArgs)
{
navOpen = false; navOpen = false;
} }

10
Components/Shared/DisplayableContent.razor

@ -1,6 +1,5 @@
@using Model.Website.Enums @if (isDisplayable)
@using Model.Website {
@if (isDisplayable) {
@ChildContent @ChildContent
} }
@ -10,14 +9,15 @@
public RenderFragment ChildContent { get; set; } = default!; public RenderFragment ChildContent { get; set; } = default!;
[Parameter] [Parameter]
public WebDeploymentType DeploymentType { get; set; } = default!; public WebDeploymentType DeploymentType { get; set; }
[Inject] [Inject]
public NavigationManager MyNavigationManager { get; set; } = default!; public NavigationManager MyNavigationManager { get; set; } = default!;
bool isDisplayable; bool isDisplayable;
protected override void OnInitialized() { protected override void OnInitialized()
{
isDisplayable = DeploymentType == WebDeploymentModel.DeploymentType; isDisplayable = DeploymentType == WebDeploymentModel.DeploymentType;
} }

10
Components/Shared/DisplayableRoute.razor

@ -1,8 +1,9 @@
@using Model.Website @if (isDisplayable)
@if (isDisplayable) { {
@ChildContent @ChildContent
} }
else { else
{
<LayoutView Layout="@typeof(MainLayout)"> <LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p> <p>Sorry, there's nothing at this address.</p>
</LayoutView> </LayoutView>
@ -18,7 +19,8 @@ else {
bool isDisplayable; bool isDisplayable;
protected override void OnInitialized() { protected override void OnInitialized()
{
var page = MyNavigationManager.Uri.Remove(0, MyNavigationManager.BaseUri.Length); var page = MyNavigationManager.Uri.Remove(0, MyNavigationManager.BaseUri.Length);
isDisplayable = WebDeploymentModel.Get().Contains(page); isDisplayable = WebDeploymentModel.Get().Contains(page);
} }

2
Contexts/Contexts.csproj

@ -23,7 +23,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Model\Model.csproj" /> <ProjectReference Include="..\Model\Model.csproj"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

9
Contexts/DatabaseContext.cs

@ -1,18 +1,19 @@
#if NO_SQL #if NO_SQL
#else #else
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Model.Doc; using Model.Doc;
using Model.Git;
using Model.Notes; using Model.Notes;
using Model.Website; using Model.Website;
using Model.Git;
using Model.Work.Tasks; using Model.Work.Tasks;
namespace Contexts; namespace Contexts;
public class DatabaseContext : DbContext { public class DatabaseContext : DbContext
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options) { {
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
{
Database.EnsureCreated(); Database.EnsureCreated();
} }

BIN
IGP/Database.db

Binary file not shown.

16
IGP/Index.razor

@ -1,19 +1,5 @@
@page "/" @page "/"
@using Microsoft.Extensions.Localization
@layout PageLayout @layout PageLayout
<HomePage/>
@inject IStringLocalizer<Localizations> locale
<DevOnlyComponent>
<DocumentationIndexPage></DocumentationIndexPage>
@locale["Greeting"].Value
@locale["Greeting"]
@locale["Greeting"].Name
@locale["Greeting"].ResourceNotFound
</DevOnlyComponent>
<HomePage></HomePage>

6
IGP/Localizations.Designer.cs generated

@ -104,5 +104,11 @@ namespace IGP {
return ResourceManager.GetString("Tooltip Hotkey Info", resourceCulture); return ResourceManager.GetString("Tooltip Hotkey Info", resourceCulture);
} }
} }
internal static string Tooltip_Options_Info {
get {
return ResourceManager.GetString("Tooltip Options Info", resourceCulture);
}
}
} }
} }

6
IGP/Localizations.resx

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root" <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"
id="root"
xmlns=""> xmlns="">
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
@ -66,4 +67,7 @@ You can also use the default Immortal hotkeys, but the above hotkey UI must have
Additionally, more entities will appear as you build the required technology. You can click or press ` to remove the last made entity. &lt;i&gt;But you cannot remove the starting entities at interval 0.&lt;/i&gt;</value> Additionally, more entities will appear as you build the required technology. You can click or press ` to remove the last made entity. &lt;i&gt;But you cannot remove the starting entities at interval 0.&lt;/i&gt;</value>
</data> </data>
<data name="Tooltip Options Info" xml:space="preserve">
<value>Misc calculator controls.</value>
</data>
</root> </root>

2
IGP/Pages/Agile/AgilePage.razor

@ -91,7 +91,7 @@ else
void HasChanged() void HasChanged()
{ {
if(!agileService.IsLoaded()) return; if (!agileService.IsLoaded()) return;
backlog.Clear(); backlog.Clear();

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

@ -11,7 +11,7 @@
<div class="tasksContainer"> <div class="tasksContainer">
@if (AgileSprint.AgileTaskModels.Count > 0) @if (AgileSprint.AgileTaskModels.Count > 0)
{ {
@foreach (var task in AgileSprint.AgileTaskModels.OrderBy(x=>x.OrderPriority)) @foreach (var task in AgileSprint.AgileTaskModels.OrderBy(x => x.OrderPriority))
{ {
<div class="taskContainer @task.Status.ToLower() @task.Task.ToLower()"> <div class="taskContainer @task.Status.ToLower() @task.Task.ToLower()">
<div class="taskName">@task.Name</div> <div class="taskName">@task.Name</div>

103
IGP/Pages/BuildCalculator/BuildCalculatorPage.razor

@ -10,7 +10,6 @@
@inject ITimingService timingService @inject ITimingService timingService
@page "/build-calculator" @page "/build-calculator"
@using Microsoft.Extensions.Localization
@implements IDisposable @implements IDisposable
@ -20,89 +19,93 @@
<AlertComponent Type="@SeverityType.Warning"> <AlertComponent Type="@SeverityType.Warning">
<Title>Work In Progress and Not Fully Tested</Title> <Title>Work In Progress and Not Fully Tested</Title>
<Message> <Message>
Currently not considering training queue times. Lacking error toasts for invalid actions. Performance needs to be optimized. Calculations haven't been thoroughly compared against real gameplay. Added a 2 second delay to actions to account for casual micro (will probably tweak later). Currently not considering training queue times.
</Message> </Message>
</AlertComponent> </AlertComponent>
<ContentDividerComponent></ContentDividerComponent> <ContentDividerComponent></ContentDividerComponent>
<div class="calculatorGrid"> <div class="calculatorGrid">
<div class="gridItem" style="grid-area: timing;">
<div style="grid-area: timing;" class="gridItem"> <ButtonComponent OnClick="OnResetClicked">Clear Build Order</ButtonComponent>
<PanelComponent>
<InfoTooltipComponent InfoText="@locale["Tooltip Timing Info"]"> <InfoTooltipComponent InfoText="@locale["Tooltip Timing Info"]">
<TimingComponent></TimingComponent> <TimingComponent></TimingComponent>
</InfoTooltipComponent> </InfoTooltipComponent>
</PanelComponent>
</div> </div>
@if (true) <div class="gridItem" style="grid-area: chart;">
{ <PanelComponent>
<div style="grid-area: chart;" class="gridItem">
<InfoTooltipComponent InfoText="@locale["Tooltip Chart Info"]"> <InfoTooltipComponent InfoText="@locale["Tooltip Chart Info"]">
<ChartComponent></ChartComponent> <ChartComponent></ChartComponent>
</InfoTooltipComponent> </InfoTooltipComponent>
</PanelComponent>
</div> </div>
}
<div style="grid-area: filter;" class="gridItem"> <div class="gridItem" style="grid-area: filter;">
<PanelComponent>
<InfoTooltipComponent InfoText="@locale["Tooltip Filter Info"]"> <InfoTooltipComponent InfoText="@locale["Tooltip Filter Info"]">
<FilterComponent></FilterComponent> <FilterComponent></FilterComponent>
</InfoTooltipComponent> </InfoTooltipComponent>
</PanelComponent>
<PanelComponent>
<InfoTooltipComponent InfoText="@locale["Tooltip Options Info"]">
<OptionsComponent></OptionsComponent>
</InfoTooltipComponent>
</PanelComponent>
</div> </div>
@if (true) <div class="gridItem" style="grid-area: view;">
{ <PanelComponent>
<div style="grid-area: view;" class="gridItem">
<InfoTooltipComponent InfoText="@locale["Tooltip Entity Info"]"> <InfoTooltipComponent InfoText="@locale["Tooltip Entity Info"]">
<EntityClickViewComponent/> <EntityClickViewComponent/>
</InfoTooltipComponent> </InfoTooltipComponent>
</PanelComponent>
</div> </div>
}
@if (true) <div class="gridItem" style="grid-area: bank;">
{ <PanelComponent>
<div style="grid-area: bank;" class="gridItem">
<InfoTooltipComponent InfoText="@locale["Tooltip Bank Info"]"> <InfoTooltipComponent InfoText="@locale["Tooltip Bank Info"]">
<BankComponent></BankComponent> <BankComponent></BankComponent>
</InfoTooltipComponent> </InfoTooltipComponent>
</PanelComponent>
</div> </div>
}
@if (true) <div class="gridItem" style="grid-area: army;">
{ <PanelComponent>
<div style="grid-area: army;" class="gridItem">
<InfoTooltipComponent InfoText="@locale["Tooltip Army Info"]"> <InfoTooltipComponent InfoText="@locale["Tooltip Army Info"]">
<ArmyComponent></ArmyComponent> <ArmyComponent></ArmyComponent>
</InfoTooltipComponent> </InfoTooltipComponent>
</PanelComponent>
</div> </div>
}
<div class="gridItem gridKeys"> <div class="gridItem gridKeys">
<PanelComponent>
<InfoTooltipComponent InfoText="@locale["Tooltip Hotkey Info"]"> <InfoTooltipComponent InfoText="@locale["Tooltip Hotkey Info"]">
<HotkeyViewerComponent Size="80"></HotkeyViewerComponent> <HotkeyViewerComponent Size="80"></HotkeyViewerComponent>
</InfoTooltipComponent> </InfoTooltipComponent>
</PanelComponent>
</div> </div>
@if (true) <div class="gridItem" style="grid-area: highlights;">
{ <PanelComponent>
<div style="grid-area: highlights;" class="gridItem">
<InfoTooltipComponent InfoText="@locale["Tooltip Highlights Info"]"> <InfoTooltipComponent InfoText="@locale["Tooltip Highlights Info"]">
<HighlightsComponent></HighlightsComponent> <HighlightsComponent></HighlightsComponent>
</InfoTooltipComponent> </InfoTooltipComponent>
</PanelComponent>
</div> </div>
}
@if (true) <div class="gridItem" style="grid-area: buildorder;">
{ <PanelComponent>
<div style="grid-area: buildorder;" class="gridItem">
<InfoTooltipComponent InfoText="@locale["Tooltip BuildOrder Info"]"> <InfoTooltipComponent InfoText="@locale["Tooltip BuildOrder Info"]">
<BuildOrderComponent></BuildOrderComponent> <BuildOrderComponent></BuildOrderComponent>
</InfoTooltipComponent> </InfoTooltipComponent>
</PanelComponent>
</div> </div>
}
</div> </div>
<ContentDividerComponent></ContentDividerComponent> <ContentDividerComponent></ContentDividerComponent>
@ -135,7 +138,7 @@
<InfoBodyComponent> <InfoBodyComponent>
<InfoQuestionComponent> <InfoQuestionComponent>
What is CONTROl key for? What is CONTROL key for?
</InfoQuestionComponent> </InfoQuestionComponent>
<InfoAnswerComponent> <InfoAnswerComponent>
Economy and tech related upgrades for townhalls. Economy and tech related upgrades for townhalls.
@ -165,6 +168,12 @@
<style> <style>
.gridItem {
display: flex;
flex-direction: column;
gap: 8px;
}
.calculatorGrid { .calculatorGrid {
display: grid; display: grid;
gap: 8px; gap: 8px;
@ -178,12 +187,6 @@
'chart chart chart chart'; 'chart chart chart chart';
} }
.gridItem {
border: 2px solid var(--paper-border);
padding: 20px;
background-color: var(--paper);
}
.gridKeys { .gridKeys {
grid-area: keys; grid-area: keys;
} }
@ -209,17 +212,12 @@
padding-left: 2px; padding-left: 2px;
padding-right: 2px; padding-right: 2px;
} }
.gridItem {
padding: 0px;
border: 0px;
width: 100%;
}
} }
</style> </style>
@code { @code {
protected override void OnInitialized() protected override void OnInitialized()
{ {
economyService.Calculate(buildOrderService, timingService, 0); economyService.Calculate(buildOrderService, timingService, 0);
@ -232,6 +230,16 @@
keyService.Unsubscribe(HandleClick); keyService.Unsubscribe(HandleClick);
} }
private void OnResetClicked()
{
toastService.AddToast(new ToastModel(){
SeverityType = SeverityType.Success,
Message = "Build order has been cleared.",
Title = "Reset"});
buildOrderService.Reset();
}
private void HandleClick() private void HandleClick()
{ {
@ -254,7 +262,7 @@
var faction = filterService.GetFactionType(); var faction = filterService.GetFactionType();
var immortal = filterService.GetImmortalType(); var immortal = filterService.GetImmortalType();
EntityModel? entity = EntityModel.GetFrom(hotkey!, hotkeyGroup, isHoldSpace, faction, immortal); var entity = EntityModel.GetFrom(hotkey!, hotkeyGroup, isHoldSpace, faction, immortal);
if (entity == null) if (entity == null)
{ {
@ -266,4 +274,5 @@
economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval()); economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval());
} }
} }
} }

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

@ -1,6 +1,6 @@
@inject IJSRuntime jsRuntime; @inject IJSRuntime jsRuntime
@inject IBuildOrderService BuildOrder @inject IBuildOrderService buildOrder
@implements IDisposable @implements IDisposable
@ -35,12 +35,12 @@
protected override void OnInitialized() protected override void OnInitialized()
{ {
BuildOrder.Subscribe(OnBuildOrderChanged); buildOrder.Subscribe(OnBuildOrderChanged);
} }
void IDisposable.Dispose() void IDisposable.Dispose()
{ {
BuildOrder.Unsubscribe(OnBuildOrderChanged); buildOrder.Unsubscribe(OnBuildOrderChanged);
} }
protected override bool ShouldRender() protected override bool ShouldRender()
@ -60,7 +60,7 @@
void OnBuildOrderChanged() void OnBuildOrderChanged()
{ {
int armyCountWas = 0; var armyCountWas = 0;
foreach (var army in armyCount) foreach (var army in armyCount)
{ {
armyCountWas += army.Value; armyCountWas += army.Value;
@ -70,7 +70,7 @@
lastInterval = 0; lastInterval = 0;
var entitiesOverTime = BuildOrder.GetOrders(); var entitiesOverTime = buildOrder.GetOrders();
foreach (var entitiesAtTime in entitiesOverTime) foreach (var entitiesAtTime in entitiesOverTime)
{ {
@ -92,7 +92,7 @@
} }
//TODO Better //TODO Better
int armyCountIs = 0; var armyCountIs = 0;
foreach (var army in armyCount) foreach (var army in armyCount)
{ {
armyCountIs += army.Value; armyCountIs += army.Value;
@ -103,7 +103,6 @@
{ {
StateHasChanged(); StateHasChanged();
} }
} }
} }

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

@ -1,6 +1,5 @@
@inject IJSRuntime jsRuntime; @inject IJSRuntime jsRuntime;
@inject IBuildOrderService buildOrderService @inject IBuildOrderService buildOrderService
@implements IDisposable @implements IDisposable
@ -39,4 +38,5 @@
jsRuntime.InvokeVoidAsync("console.timeEnd", "BuildOrderComponent"); jsRuntime.InvokeVoidAsync("console.timeEnd", "BuildOrderComponent");
#endif #endif
} }
} }

6
IGP/Pages/BuildCalculator/Parts/ChartComponent.razor

@ -6,7 +6,6 @@
@if (lastRequestedRefreshIndex != requestedRefreshIndex) @if (lastRequestedRefreshIndex != requestedRefreshIndex)
{ {
<LoadingComponent/> <LoadingComponent/>
} }
else else
{ {
@ -60,8 +59,6 @@ else
<Display>@highestArmyPoint</Display> <Display>@highestArmyPoint</Display>
</FormDisplayComponent> </FormDisplayComponent>
</FormLayoutComponent> </FormLayoutComponent>
} }
@code { @code {
@ -95,6 +92,7 @@ else
int lastRequestedRefreshIndex = 0; int lastRequestedRefreshIndex = 0;
void OnAge(object? sender, ElapsedEventArgs elapsedEventArgs) void OnAge(object? sender, ElapsedEventArgs elapsedEventArgs)
{ {
if (requestedRefreshIndex > 0) if (requestedRefreshIndex > 0)
@ -113,7 +111,6 @@ else
} }
void IDisposable.Dispose() void IDisposable.Dispose()
{ {
buildOrderService.Unsubscribe(OnBuilderOrderChanged); buildOrderService.Unsubscribe(OnBuilderOrderChanged);
@ -121,6 +118,7 @@ else
int requestedRefreshIndex = 0; int requestedRefreshIndex = 0;
void OnBuilderOrderChanged() void OnBuilderOrderChanged()
{ {
requestedRefreshIndex++; requestedRefreshIndex++;

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

@ -1,9 +1,7 @@
@inject IJSRuntime jsRuntime; @inject IJSRuntime jsRuntime;
@inject IKeyService keyService
@inject IImmortalSelectionService filterService
@inject IKeyService keyService @inject IBuildOrderService buildOrderService
@inject IImmortalSelectionService filterService
@inject IBuildOrderService buildOrderService
@implements IDisposable @implements IDisposable
@ -68,4 +66,5 @@
StateHasChanged(); StateHasChanged();
} }
} }
} }

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

@ -1,4 +1,5 @@
@inject IJSRuntime jsRuntime; @inject IJSRuntime jsRuntime;
@inject IImmortalSelectionService filterService
<FormLayoutComponent> <FormLayoutComponent>
<FormSelectComponent OnChange="@OnFactionChanged"> <FormSelectComponent OnChange="@OnFactionChanged">
@ -12,12 +13,12 @@
<FormSelectComponent OnChange="@OnImmortalChanged"> <FormSelectComponent OnChange="@OnImmortalChanged">
<FormLabelComponent>Immortal</FormLabelComponent> <FormLabelComponent>Immortal</FormLabelComponent>
<ChildContent> <ChildContent>
@if (FilterService.GetFactionType() == FactionType.QRath) @if (filterService.GetFactionType() == FactionType.QRath)
{ {
<option value="@DataType.IMMORTAL_Orzum" selected>Orzum</option> <option value="@DataType.IMMORTAL_Orzum" selected>Orzum</option>
<option value="@DataType.IMMORTAL_Ajari">Ajari</option> <option value="@DataType.IMMORTAL_Ajari">Ajari</option>
} }
@if (FilterService.GetFactionType() == FactionType.Aru) @if (filterService.GetFactionType() == FactionType.Aru)
{ {
<option value="@DataType.IMMORTAL_Mala" selected>Mala</option> <option value="@DataType.IMMORTAL_Mala" selected>Mala</option>
<option value="@DataType.IMMORTAL_Xol">Xol</option> <option value="@DataType.IMMORTAL_Xol">Xol</option>
@ -28,17 +29,14 @@
@code { @code {
[Inject]
public IImmortalSelectionService FilterService { get; set; } = default!;
void OnFactionChanged(ChangeEventArgs e) void OnFactionChanged(ChangeEventArgs e)
{ {
FilterService.SelectFactionType(e.Value!.ToString()!); filterService.SelectFactionType(e.Value!.ToString()!);
} }
void OnImmortalChanged(ChangeEventArgs e) void OnImmortalChanged(ChangeEventArgs e)
{ {
FilterService.SelectImmortalType(e.Value!.ToString()!); filterService.SelectImmortalType(e.Value!.ToString()!);
} }
protected override bool ShouldRender() protected override bool ShouldRender()
@ -56,4 +54,5 @@
jsRuntime.InvokeVoidAsync("console.timeEnd", "FilterComponent"); jsRuntime.InvokeVoidAsync("console.timeEnd", "FilterComponent");
#endif #endif
} }
} }

25
IGP/Pages/BuildCalculator/Parts/HighlightsComponent.razor

@ -1,5 +1,7 @@
@inject IJSRuntime jsRuntime; @inject IJSRuntime jsRuntime;
@inject IEconomyService economyService
@inject IBuildOrderService buildOrderService
@inject ITimingService timingService
@implements IDisposable @implements IDisposable
@ -7,7 +9,7 @@
<div> <div>
<div>Requested</div> <div>Requested</div>
@foreach (var ordersAtTime in BuildOrderService.StartedOrders.Reverse()) @foreach (var ordersAtTime in buildOrderService.StartedOrders.Reverse())
{ {
foreach (var order in ordersAtTime.Value) foreach (var order in ordersAtTime.Value)
{ {
@ -26,7 +28,7 @@
<div> <div>
<div>Finished</div> <div>Finished</div>
@foreach (var ordersAtTime in BuildOrderService.CompletedOrders.Reverse()) @foreach (var ordersAtTime in buildOrderService.CompletedOrders.Reverse())
{ {
foreach (var order in ordersAtTime.Value) foreach (var order in ordersAtTime.Value)
{ {
@ -57,25 +59,16 @@
@code { @code {
[Inject]
IEconomyService EconomyService { get; set; } = default!;
[Inject]
IBuildOrderService BuildOrderService { get; set; } = default!;
[Inject]
ITimingService TimingService { get; set; } = default!;
protected override void OnInitialized() protected override void OnInitialized()
{ {
EconomyService.Subscribe(StateHasChanged); economyService.Subscribe(StateHasChanged);
BuildOrderService.Subscribe(StateHasChanged); buildOrderService.Subscribe(StateHasChanged);
} }
void IDisposable.Dispose() void IDisposable.Dispose()
{ {
EconomyService.Unsubscribe(StateHasChanged); economyService.Unsubscribe(StateHasChanged);
BuildOrderService.Unsubscribe(StateHasChanged); buildOrderService.Unsubscribe(StateHasChanged);
} }
protected override bool ShouldRender() protected override bool ShouldRender()

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

@ -1,6 +1,4 @@
@inject IJSRuntime jsRuntime; @inject IJSRuntime jsRuntime;
@using System.Diagnostics
@implements IDisposable @implements IDisposable
@inject IKeyService keyService @inject IKeyService keyService
@inject IBuildOrderService buildOrderService @inject IBuildOrderService buildOrderService
@ -57,7 +55,6 @@
@hotkey.KeyText @hotkey.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;
@ -138,6 +135,7 @@
} }
int completedTimeCount = 0; int completedTimeCount = 0;
void OnBuilderOrderChanged() void OnBuilderOrderChanged()
{ {
if (buildOrderService.UniqueCompletedTimes.Count != completedTimeCount) if (buildOrderService.UniqueCompletedTimes.Count != completedTimeCount)
@ -252,9 +250,8 @@
void OnKeyPressed() void OnKeyPressed()
{ {
var controlGroupWas = controlGroup;
string controlGroupWas = controlGroup; var keyWas = key;
string keyWas = key;
if (keyService.GetAllPressedKeys().Contains("Z")) if (keyService.GetAllPressedKeys().Contains("Z"))
@ -299,10 +296,8 @@
if (controlGroupWas != controlGroup || keyWas != key) if (controlGroupWas != controlGroup || keyWas != key)
{ {
StateHasChanged(); StateHasChanged();
} }
} }
@ -327,7 +322,7 @@
var faction = filterService.GetFactionType(); var faction = filterService.GetFactionType();
var immortal = filterService.GetImmortalType(); var immortal = filterService.GetImmortalType();
EntityModel? entity = EntityModel.GetFrom(hotkey!, hotkeyGroup, isHoldSpace, faction, immortal); var entity = EntityModel.GetFrom(hotkey!, hotkeyGroup, isHoldSpace, faction, immortal);
if (entity == null) if (entity == null)
{ {
@ -339,4 +334,5 @@
economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval()); economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval());
} }
} }
} }

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

@ -13,6 +13,7 @@
</div> </div>
@code { @code {
[Parameter] [Parameter]
public RenderFragment ChildContent { get; set; } = default!; public RenderFragment ChildContent { get; set; } = default!;
@ -41,4 +42,5 @@
jsRuntime.InvokeVoidAsync("console.timeEnd", "InputPanelComponent"); jsRuntime.InvokeVoidAsync("console.timeEnd", "InputPanelComponent");
#endif #endif
} }
} }

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

@ -0,0 +1,41 @@
@inject IJSRuntime jsRuntime;
@inject IBuildOrderService buildOrderService
@inject IEconomyService economyService
@inject IToastService toastService
@inject ITimingService timingService
<FormLayoutComponent>
<FormNumberComponent Max="600"
Min="0"
Value="@buildOrderService.BuildingInputDelay"
OnChange="@OnBuildingInputDelayChanged">
<FormLabelComponent>Building Input Delay</FormLabelComponent>
<FormInfoComponent>Add a input delay to constructing buildings for simulating worker movement and player micro.</FormInfoComponent>
</FormNumberComponent>
</FormLayoutComponent>
@code {
void OnBuildingInputDelayChanged(ChangeEventArgs changeEventArgs)
{
buildOrderService.BuildingInputDelay = int.Parse(changeEventArgs.Value!.ToString()!);
}
protected override bool ShouldRender()
{
#if DEBUG
jsRuntime.InvokeVoidAsync("console.time", "TimingComponent");
#endif
return true;
}
protected override void OnAfterRender(bool firstRender)
{
#if DEBUG
jsRuntime.InvokeVoidAsync("console.timeEnd", "TimingComponent");
#endif
}
}

27
IGP/Pages/BuildCalculator/Parts/TimelineComponent.razor

@ -1,9 +1,10 @@
@inject IJSRuntime jsRuntime; @inject IJSRuntime jsRuntime
@inject IEconomyService economyService
@inject IBuildOrderService buildOrderService
@implements IDisposable @implements IDisposable
<Virtualize Items="@EconomyService.GetOverTime()" Context="economyAtSecond" ItemSize="400" OverscanCount="4"> <Virtualize Items="@economyService.GetOverTime()" Context="economyAtSecond" ItemSize="400" OverscanCount="4">
<div style="display: grid; gap: 8px; grid-template-columns: 1fr 1fr;"> <div style="display: grid; gap: 8px; grid-template-columns: 1fr 1fr;">
<div> <div>
<div> <div>
@ -28,18 +29,18 @@
</div> </div>
<div> <div>
@if (BuildOrderService.StartedOrders.TryGetValue(economyAtSecond.Interval, out var ordersAtTime)) @if (buildOrderService.StartedOrders.TryGetValue(economyAtSecond.Interval, out var ordersAtTime))
{ {
@foreach (var order in ordersAtTime) @foreach (var order in ordersAtTime)
{ {
<div> <div>
Requested: @order.Info().Name Requested: @order.Info().Name
</div> </div>
} }
} }
@if (BuildOrderService.CompletedOrders.TryGetValue(economyAtSecond.Interval, out var ordersCompletedAtTime)) @if (buildOrderService.CompletedOrders.TryGetValue(economyAtSecond.Interval, out var ordersCompletedAtTime))
{ {
@foreach (var order in ordersCompletedAtTime) @foreach (var order in ordersCompletedAtTime)
{ {
@ -55,22 +56,16 @@
@code { @code {
[Inject]
IEconomyService EconomyService { get; set; } = default!;
[Inject]
IBuildOrderService BuildOrderService { get; set; } = default!;
protected override void OnInitialized() protected override void OnInitialized()
{ {
EconomyService.Subscribe(StateHasChanged); economyService.Subscribe(StateHasChanged);
BuildOrderService.Subscribe(StateHasChanged); buildOrderService.Subscribe(StateHasChanged);
} }
void IDisposable.Dispose() void IDisposable.Dispose()
{ {
EconomyService.Unsubscribe(StateHasChanged); economyService.Unsubscribe(StateHasChanged);
BuildOrderService.Unsubscribe(StateHasChanged); buildOrderService.Unsubscribe(StateHasChanged);
} }
protected override bool ShouldRender() protected override bool ShouldRender()

13
IGP/Pages/BuildCalculator/Parts/TimingComponent.razor

@ -5,11 +5,8 @@
@inject IToastService toastService @inject IToastService toastService
@inject ITimingService timingService @inject ITimingService timingService
<FormLayoutComponent> <FormLayoutComponent>
<FormNumberComponent ReadOnly="true" <FormNumberComponent Max="2048"
Max="600"
Min="0" Min="0"
Value="@timingService.GetTiming()" Value="@timingService.GetTiming()"
OnChange="@OnTimingChanged"> OnChange="@OnTimingChanged">
@ -27,10 +24,17 @@
</FormLayoutComponent> </FormLayoutComponent>
@code { @code {
void OnTimingChanged(ChangeEventArgs changeEventArgs) void OnTimingChanged(ChangeEventArgs changeEventArgs)
{ {
timingService.SetTiming(int.Parse(changeEventArgs.Value!.ToString()!)); timingService.SetTiming(int.Parse(changeEventArgs.Value!.ToString()!));
economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval()); economyService.Calculate(buildOrderService, timingService, buildOrderService.GetLastRequestInterval());
toastService.AddToast(new ToastModel()
{
Title = "Timing Interval",
Message = "Timing interval has changed.",
SeverityType = SeverityType.Success
});
} }
void OnNameChanged(ChangeEventArgs changeEventArgs) void OnNameChanged(ChangeEventArgs changeEventArgs)
@ -65,5 +69,4 @@
#endif #endif
} }
} }

1
IGP/Pages/Database/Entity/Parts/EntityPassivesComponent.razor

@ -122,7 +122,6 @@
} }
</div> </div>
} }
} }
</EntityDisplayComponent> </EntityDisplayComponent>
} }

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

@ -1,7 +1,3 @@
@using System.Net.Http.Json
@using Markdig.Extensions.Yaml
@using Markdig.Syntax
@using YamlDotNet.Serialization
@inject HttpClient httpClient @inject HttpClient httpClient
@if (content == null) @if (content == null)
@ -19,10 +15,10 @@ else
</div> </div>
</div> </div>
<div class="docContent">@((MarkupString)Markdown.ToHtml(content, Pipeline))</div> <div class="docContent">@((MarkupString)Markdown.ToHtml(content, Pipeline))</div>
<div class="docFooter"><EditLinkComponent Href="@GitUrl"></EditLinkComponent></div> <div class="docFooter">
<EditLinkComponent Href="@GitUrl"></EditLinkComponent>
</div>
</div> </div>
} }
<style> <style>
@ -56,7 +52,9 @@ else
</style> </style>
@code { @code {
[Parameter] public DocContentModel DocContentModel { get; set; } = default!;
[Parameter]
public DocContentModel DocContentModel { get; set; } = default!;
DocFrontMatterModel docFrontMatter = null!; DocFrontMatterModel docFrontMatter = null!;
private string? content = null; private string? content = null;
@ -65,13 +63,22 @@ else
private string GitUrl => $"{Project.GitResourcesUrl}/{Filepath}"; private string GitUrl => $"{Project.GitResourcesUrl}/{Filepath}";
private MarkdownPipeline Pipeline => MarkdownFiles.Pipeline; private MarkdownPipeline Pipeline => MarkdownFiles.Pipeline;
private async Task<DocFrontMatterModel> LoadContent() { private async Task<DocFrontMatterModel> LoadContent()
{
content = await MarkdownFiles.LoadMarkdown(httpClient, Filepath); content = await MarkdownFiles.LoadMarkdown(httpClient, Filepath);
return docFrontMatter = return docFrontMatter =
await MarkdownFiles.LoadFrontMatter<DocFrontMatterModel>(httpClient, Filepath); await MarkdownFiles.LoadFrontMatter<DocFrontMatterModel>(httpClient, Filepath);
} }
protected override async Task OnParametersSetAsync() => await LoadContent(); protected override async Task OnParametersSetAsync()
protected override async Task OnInitializedAsync() => await LoadContent(); {
await LoadContent();
}
protected override async Task OnInitializedAsync()
{
await LoadContent();
}
} }

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

@ -6,15 +6,15 @@
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. 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> </Description>
<Example> <Example>
<NavSectionComponent Section=@(new WebSectionModel { Name = "Example Section" }) <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" } })> Children=@(new List<WebPageModel> { new() { Name = "Example Page", Href = "immortal-makingof", IsPrivate = "False" }, new() { Name = "Database", Href = "immortal-database", IsPrivate = "False" } })>
</NavSectionComponent> </DesktopNavSectionComponent>
</Example> </Example>
<Usage> <Usage>
<CodeComponent> <CodeComponent>
&lt;NavSectionComponent Section=@@(new WebSectionModel{Name = &quot;Example Section&quot;}) &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; 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;/NavSectionComponent&gt; &lt;/DesktopNavSectionComponent&gt;
</CodeComponent> </CodeComponent>
</Usage> </Usage>
<Code> <Code>

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

@ -15,7 +15,9 @@ else
</div> </div>
</div> </div>
<div class="noteContent">@((MarkupString)Markdown.ToHtml(content, Pipeline))</div> <div class="noteContent">@((MarkupString)Markdown.ToHtml(content, Pipeline))</div>
<div class="noteFooter"><EditLinkComponent Href="@GitUrl"></EditLinkComponent></div> <div class="noteFooter">
<EditLinkComponent Href="@GitUrl"></EditLinkComponent>
</div>
</div> </div>
} }
@ -43,7 +45,9 @@ else
</style> </style>
@code { @code {
[Parameter] public NoteContentModel NoteContentModel { get; set; } = default!;
[Parameter]
public NoteContentModel NoteContentModel { get; set; } = default!;
NoteFrontMatterModel noteFrontMatter = null!; NoteFrontMatterModel noteFrontMatter = null!;
private string? content = null; private string? content = null;
@ -52,14 +56,22 @@ else
private string GitUrl => $"{Project.GitResourcesUrl}/{Filepath}"; private string GitUrl => $"{Project.GitResourcesUrl}/{Filepath}";
private MarkdownPipeline Pipeline => MarkdownFiles.Pipeline; private MarkdownPipeline Pipeline => MarkdownFiles.Pipeline;
private async Task<NoteFrontMatterModel> LoadContent() { private async Task<NoteFrontMatterModel> LoadContent()
{
content = await MarkdownFiles.LoadMarkdown(httpClient, Filepath); content = await MarkdownFiles.LoadMarkdown(httpClient, Filepath);
return noteFrontMatter = return noteFrontMatter =
await MarkdownFiles.LoadFrontMatter<NoteFrontMatterModel>(httpClient, Filepath); await MarkdownFiles.LoadFrontMatter<NoteFrontMatterModel>(httpClient, Filepath);
} }
protected override async Task OnParametersSetAsync() => await LoadContent(); protected override async Task OnParametersSetAsync()
protected override async Task OnInitializedAsync() => await LoadContent(); {
await LoadContent();
}
protected override async Task OnInitializedAsync()
{
await LoadContent();
}
} }

5
IGP/Portals/ToastPortal.razor

@ -5,9 +5,8 @@
@if (toastService.HasToasts()) @if (toastService.HasToasts())
{ {
<div class="toastsContainer"> <div class="toastsContainer">
@foreach(var toast in Toasts) @foreach (var toast in Toasts)
{ {
<ToastComponent Toast="toast"/> <ToastComponent Toast="toast"/>
} }
</div> </div>
@ -37,7 +36,6 @@
ageTimer = new Timer(10); ageTimer = new Timer(10);
ageTimer.Elapsed += OnAge!; ageTimer.Elapsed += OnAge!;
ageTimer.Enabled = true; ageTimer.Enabled = true;
} }
public void Dispose() public void Dispose()
@ -57,4 +55,5 @@
{ {
StateHasChanged(); StateHasChanged();
} }
} }

3
IGP/Program.cs

@ -6,7 +6,6 @@ using Services.Development;
using Services.Immortal; using Services.Immortal;
using Services.Website; using Services.Website;
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US"); CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US"); CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");
@ -44,7 +43,6 @@ builder.Services.AddSingleton(new HttpClient
}); });
#if NO_SQL #if NO_SQL
#else #else
@ -52,7 +50,6 @@ builder.Services.AddSingleton(new HttpClient
#endif #endif
await builder.Build().RunAsync(); await builder.Build().RunAsync();

6
IGP/Utils/Interval.cs

@ -1,7 +1,9 @@
namespace IGP.Utils; namespace IGP.Utils;
public static class Interval { public static class Interval
public static string ToTime(int interval) { {
public static string ToTime(int interval)
{
return TimeSpan.FromSeconds(interval).ToString(@"mm\:ss"); return TimeSpan.FromSeconds(interval).ToString(@"mm\:ss");
} }
} }

7
IGP/Utils/Markdown.cs

@ -1,12 +1,12 @@
using Markdig; using Markdig;
using Markdig.Extensions.Yaml; using Markdig.Extensions.Yaml;
using Markdig.Syntax; using Markdig.Syntax;
using Model.Doc;
using YamlDotNet.Serialization; using YamlDotNet.Serialization;
namespace IGP.Utils; namespace IGP.Utils;
public static class MarkdownFiles { public static class MarkdownFiles
{
private static readonly IDeserializer YamlDeserializer = private static readonly IDeserializer YamlDeserializer =
new DeserializerBuilder() new DeserializerBuilder()
.IgnoreUnmatchedProperties() .IgnoreUnmatchedProperties()
@ -23,7 +23,8 @@ public static class MarkdownFiles {
return await httpClient.GetStringAsync(filepath); return await httpClient.GetStringAsync(filepath);
} }
public static async Task<T> LoadFrontMatter<T>(HttpClient httpClient, string filepath) { public static async Task<T> LoadFrontMatter<T>(HttpClient httpClient, string filepath)
{
var markdown = await LoadMarkdown(httpClient, filepath); var markdown = await LoadMarkdown(httpClient, filepath);
var document = Markdown.Parse(markdown, Pipeline); var document = Markdown.Parse(markdown, Pipeline);

7
IGP/Utils/Project.cs

@ -1,6 +1,7 @@
namespace IGP.Utils; namespace IGP.Utils;
public static class Project { public static class Project
public static string GitResourcesUrl => "https://github.com/JonathanMcCaffrey/IGP-Fan-Reference/blob/develop/IGP/wwwroot/"; {
public static string GitResourcesUrl =>
"https://github.com/JonathanMcCaffrey/IGP-Fan-Reference/blob/develop/IGP/wwwroot/";
} }

14
IGP/_Imports.razor

@ -6,11 +6,10 @@
@using Components.Layout @using Components.Layout
@using Components.Navigation @using Components.Navigation
@using Components.Shared @using Components.Shared
@using IGP.Utils
@using System.Globalization
@using IGP.Dialog @using IGP.Dialog
@using IGP.Pages @using IGP.Pages
@using IGP.Pages.Agile.Parts @using IGP.Pages.Agile.Parts
@using IGP.Pages.BuildCalculator
@using IGP.Pages.BuildCalculator.Parts @using IGP.Pages.BuildCalculator.Parts
@using IGP.Pages.Comparision @using IGP.Pages.Comparision
@using IGP.Pages.Comparision.Parts @using IGP.Pages.Comparision.Parts
@ -23,27 +22,28 @@
@using IGP.Pages.Home.Parts @using IGP.Pages.Home.Parts
@using IGP.Pages.MakingOf.Parts @using IGP.Pages.MakingOf.Parts
@using IGP.Pages.MemoryTester.Parts @using IGP.Pages.MemoryTester.Parts
@using IGP.Pages.RoadMap.Parts
@using IGP.Pages.Notes @using IGP.Pages.Notes
@using IGP.Pages.Notes.Parts @using IGP.Pages.Notes.Parts
@using System.Timers @using IGP.Pages.RoadMap.Parts
@using IGP.Portals @using IGP.Portals
@using IGP.Utils
@using Markdig @using Markdig
@using Model.Feedback
@using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http @using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.EntityFrameworkCore @using Microsoft.EntityFrameworkCore
@using Microsoft.Extensions.Localization
@using Microsoft.JSInterop @using Microsoft.JSInterop
@using Model.Chart @using Model.Chart
@using Model.Git
@using Model.Doc @using Model.Doc
@using Model.Economy @using Model.Economy
@using Model.Entity @using Model.Entity
@using Model.Entity.Data @using Model.Entity.Data
@using Model.Entity.Parts @using Model.Entity.Parts
@using Model.Feedback
@using Model.Git
@using Model.Hotkeys @using Model.Hotkeys
@using Model.MemoryTester @using Model.MemoryTester
@using Model.Notes @using Model.Notes
@ -55,4 +55,6 @@
@using Model.Work.Tasks.Enums @using Model.Work.Tasks.Enums
@using Services @using Services
@using Services.Immortal @using Services.Immortal
@using System.Globalization
@using System.Reflection @using System.Reflection
@using System.Timers

6
IGP/wwwroot/content/docs/cheat-sheet.md

@ -1,8 +1,6 @@
--- ---
title: Cheat Sheet title: Cheat Sheet summary: Handy links or quick information on this project. created_date: 2022-04-11 updated_date:
summary: Handy links or quick information on this project. 2022-04-11
created_date: 2022-04-11
updated_date: 2022-04-11
--- ---
# Overview # Overview

15
IGP/wwwroot/content/docs/project-data.md

@ -1,8 +1,5 @@
--- ---
title: Project Data title: Project Data summary: Using data in this project. created_date: 2022-04-11 updated_date: 2022-04-11
summary: Using data in this project.
created_date: 2022-04-11
updated_date: 2022-04-11
--- ---
# Overview # Overview
@ -11,7 +8,8 @@ This document will contain general information on data in this project.
## General Note ## General Note
This project is a work in progress. As such, most of the data in the website doesn't follow the document. Ideally, this will be fixed over time. This project is a work in progress. As such, most of the data in the website doesn't follow the document. Ideally, this
will be fixed over time.
## SQL ## SQL
@ -19,7 +17,9 @@ Relational data is stored in a local SQL database.
This data is converted into JSON so it can be handled by Blazor WASM. This data is converted into JSON so it can be handled by Blazor WASM.
<i>Currently, Blazor WASM has a bug that prevents SQL from being used in production. Although, given SQL doesn't seem to provide much, aside from increased build times and load times, it might just be best to use the design principals of SQL, and it's interface, without using the actual technology in production.</i> <i>Currently, Blazor WASM has a bug that prevents SQL from being used in production. Although, given SQL doesn't seem to
provide much, aside from increased build times and load times, it might just be best to use the design principals of
SQL, and it's interface, without using the actual technology in production.</i>
The data is then loaded in by a Service, via it's load method. The data is then loaded in by a Service, via it's load method.
@ -90,7 +90,8 @@ else
Localized strings are handled in the Localizations.resx file. Localized strings are handled in the Localizations.resx file.
Most text isn't using localized strings yet. And English is the only plan of support in the short term, and probably in the long term as well. Most text isn't using localized strings yet. And English is the only plan of support in the short term, and probably in
the long term as well.
## Markdown Files ## Markdown Files

29
IGP/wwwroot/content/docs/setup.md

@ -1,18 +1,15 @@
--- ---
title: Setup title: Setup summary: Get set up on developing this web project. created_date: 3/30/2022 updated_date: 4/7/2022
summary: Get set up on developing this web project.
created_date: 3/30/2022
updated_date: 4/7/2022
--- ---
# Overview # Overview
This document will contain general setup notes for the project. This document will contain general setup notes for the project.
## Prerequisite ## Prerequisite
To understand content in this document, it is recommended to have some software development experience. Particularly using GitHub and Visual Studio. To understand content in this document, it is recommended to have some software development experience. Particularly
using GitHub and Visual Studio.
- [GitHub Documentation](https://docs.github.com/en/get-started) - [GitHub Documentation](https://docs.github.com/en/get-started)
@ -24,10 +21,13 @@ To make updates to this website, it is recommended to understand HTML/CSS and C#
- [Mozilla's HTML Documentation](https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started) - [Mozilla's HTML Documentation](https://developer.mozilla.org/en-US/docs/Learn/HTML/Introduction_to_HTML/Getting_started)
- [W3SCHOOLS' HTML Documentation](https://www.w3schools.com/html/) - [W3SCHOOLS' HTML Documentation](https://www.w3schools.com/html/)
Further, you should understand the product and clients this website is for. So it is recommended to play "Immortal: Gates of Pyre". Further, you should understand the product and clients this website is for. So it is recommended to play "Immortal:
Gates of Pyre".
- [IGP Website](https://gatesofpyre.com/) - [IGP Website](https://gatesofpyre.com/)
- **Please Note:** This product currently has restricted access with it is in a pre-alpha state. If you are not aware or interested in IGP, I recommend to wait for product release. Otherwise, check out their discord for steps of getting access. - **Please Note:** This product currently has restricted access with it is in a pre-alpha state. If you are not
aware or interested in IGP, I recommend to wait for product release. Otherwise, check out their discord for steps
of getting access.
## Installation ## Installation
@ -37,7 +37,8 @@ Download and install Visual Studio preview.
[https://visualstudio.microsoft.com/vs/preview/](https://visualstudio.microsoft.com/vs/preview/) [https://visualstudio.microsoft.com/vs/preview/](https://visualstudio.microsoft.com/vs/preview/)
When installing, ensure you have selected "Workloads | **ASP.NET and web development**" and "Individual components | **.NET WebAssembly build tools**". When installing, ensure you have selected "Workloads | **ASP.NET and web development**" and "Individual components | **
.NET WebAssembly build tools**".
## Download Project ## Download Project
@ -77,11 +78,13 @@ C:.
Code committed to the `main` branch will automatically be deployed to [production](https://www.igpfanreference.com/). Code committed to the `main` branch will automatically be deployed to [production](https://www.igpfanreference.com/).
Code committed to the `develop` branch will automatically be deployed to [development](https://calm-mud-04916b210.1.azurestaticapps.net/). Code committed to the `develop` branch will automatically be deployed
to [development](https://calm-mud-04916b210.1.azurestaticapps.net/).
_This is handle via the files in `.github/workflow`. Look into these [GitHub Actions Documents](https://docs.github.com/en/actions) if curious about how this CI system works._ _This is handle via the files in `.github/workflow`. Look into
these [GitHub Actions Documents](https://docs.github.com/en/actions) if curious about how this CI system works._
## Troubleshooting ## Troubleshooting
Nothing that some good internet searches cannot resolved. But you can also contact the project maintainer
Nothing that some good internet searches cannot resolved. But you can also contact the project maintainer on [Discord](https://discord.gg/uMq8bMGeeN). on [Discord](https://discord.gg/uMq8bMGeeN).

36
IGP/wwwroot/content/notes/coop/holdout.md

@ -1,26 +1,27 @@
--- ---
title: Holdout title: Holdout summary: First coop test map in pre-alpha. created_date: 2/18/2022 updated_date: 2/18/2022
summary: First coop test map in pre-alpha.
created_date: 2/18/2022
updated_date: 2/18/2022
--- ---
Information contained in this note is based on this <a href="https://www.youtube.com/watch?v=XkAgOCIz3DE">YouTube, Reference Video</a>. Information contained in this note is based on this <a href="https://www.youtube.com/watch?v=XkAgOCIz3DE">YouTube,
Reference Video</a>.
![Open Bases](./image/notes/coop-holdout/OpenBases.png) ![Open Bases](./image/notes/coop-holdout/OpenBases.png)
**Open Bases** **Open Bases**
On this map, you start with around 500 alloy and 100 ether. You are probably going to want to expand to the bases in the marked order, given the density of defending enemies shown on the minimap. On this map, you start with around 500 alloy and 100 ether. You are probably going to want to expand to the bases in the
marked order, given the density of defending enemies shown on the minimap.
You should know that these are all standard bases that will mine out in 10 minutes. Giving a total of 18,000 alloy and 7,200 ether. Plus an additional 6,000 alloy from the starting Bastion. In the late game, you will have zero income, aside from pyre.
You should know that these are all standard bases that will mine out in 10 minutes. Giving a total of 18,000 alloy and
7,200 ether. Plus an additional 6,000 alloy from the starting Bastion. In the late game, you will have zero income,
aside from pyre.
![Enemy Spawns](./image/notes/coop-holdout/EnemySpawns.png) ![Enemy Spawns](./image/notes/coop-holdout/EnemySpawns.png)
**Enemy Spawn Areas** **Enemy Spawn Areas**
The first enemy wave will spawn at 1 minute, and every 2 minutes after will spawn a new wave. These waves are small, and won't be a threat until the 15-minute mark. The first enemy wave will spawn at 1 minute, and every 2 minutes after will spawn a new wave. These waves are small, and
won't be a threat until the 15-minute mark.
![Defend Points](./image/notes/coop-holdout/DefendPoints.png) ![Defend Points](./image/notes/coop-holdout/DefendPoints.png)
@ -28,19 +29,26 @@ The first enemy wave will spawn at 1 minute, and every 2 minutes after will spaw
You have till then to take all 5 of your bases, and set a defensive line at the outer Pyre towers. You have till then to take all 5 of your bases, and set a defensive line at the outer Pyre towers.
The spawn size post the 15-minute mark does become rather large. You may be tempted to fall back and abandon forward bases, but the waves will stack if not dealt with. Eventually, more units than the game can handle, so ensure outer pyre towers are held. Try to take them back if you lose them. The spawn size post the 15-minute mark does become rather large. You may be tempted to fall back and abandon forward
bases, but the waves will stack if not dealt with. Eventually, more units than the game can handle, so ensure outer pyre
towers are held. Try to take them back if you lose them.
![Pyre](./image/notes/coop-holdout/Pyre.png) ![Pyre](./image/notes/coop-holdout/Pyre.png)
**Pyre Camps** **Pyre Camps**
When you have the time you are also going to need to take the 4 pyre camps spread around the map. It will probably be ideal to split your army in half, to protect your two outer towers, and just have a small force of Ichors or Dervishes to clear the camps quickly. When you have the time you are also going to need to take the 4 pyre camps spread around the map. It will probably be
ideal to split your army in half, to protect your two outer towers, and just have a small force of Ichors or Dervishes
to clear the camps quickly.
![Multipliers](./image/notes/coop-holdout/Multipliers.png) ![Multipliers](./image/notes/coop-holdout/Multipliers.png)
**Multipliers** **Multipliers**
If you have additional free time, you can take out the Altar of the Worthys on the edges of the map to double your current more multiplier: 2, 4, 8, to the max of 16. Amber Wombs will also spawn, with a pack of enemies to defend them. Killing an Amber Womb will increase your score, but also spawn random friendly and enemy units. With this spawning, it's possible to go past the supply cap. If you have additional free time, you can take out the Altar of the Worthys on the edges of the map to double your
current more multiplier: 2, 4, 8, to the max of 16. Amber Wombs will also spawn, with a pack of enemies to defend them.
Killing an Amber Womb will increase your score, but also spawn random friendly and enemy units. With this spawning, it's
possible to go past the supply cap.
But really, these optional objectives can be completely ignored, so you can just focus on surviving for as long as possible. But really, these optional objectives can be completely ignored, so you can just focus on surviving for as long as
possible.

177
IGP/wwwroot/content/notes/settings/hotkeys.md

@ -1,8 +1,6 @@
--- ---
title: Custom HotKey Setup title: Custom HotKey Setup summary: Customize your hotkeys in the pre-alpha. created_date: 4/13/2022 updated_date:
summary: Customize your hotkeys in the pre-alpha. 4/13/2022
created_date: 4/13/2022
updated_date: 4/13/2022
--- ---
In the pre-alpha, IGP comes with some Unreal default hotkey setup. In the pre-alpha, IGP comes with some Unreal default hotkey setup.
@ -15,78 +13,79 @@ This document will explain how to set up, modify, and use a new hotkey setup.
```ini ```ini
[/Script/Engine.InputSettings] [/Script/Engine.InputSettings]
ActionMappings=(ActionName="Ability1",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Q) ActionMappings = (ActionName="Ability1",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Q)
ActionMappings=(ActionName="Ability2",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=W) ActionMappings = (ActionName="Ability2",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=W)
ActionMappings=(ActionName="Ability3",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=E) ActionMappings = (ActionName="Ability3",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=E)
ActionMappings=(ActionName="Ability4",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=R) ActionMappings = (ActionName="Ability4",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=R)
ActionMappings=(ActionName="Ability5",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=F) ActionMappings = (ActionName="Ability5",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=F)
ActionMappings=(ActionName="Ability6",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=V) ActionMappings = (ActionName="Ability6",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=V)
ActionMappings=(ActionName="Ability7",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=A) ActionMappings = (ActionName="Ability7",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=A)
ActionMappings=(ActionName="Ability8",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=S) ActionMappings = (ActionName="Ability8",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=S)
ActionMappings=(ActionName="AttackMove",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=A) ActionMappings = (ActionName="AttackMove",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=A)
ActionMappings=(ActionName="CancelOrders",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Tilde) ActionMappings = (ActionName="CancelOrders",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Tilde)
ActionMappings=(ActionName="CompleteAllTraining",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=I) ActionMappings = (ActionName="CompleteAllTraining",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=I)
ActionMappings=(ActionName="CompleteConstructions",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=K) ActionMappings = (ActionName="CompleteConstructions",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=K)
ActionMappings=(ActionName="ConstructionTab",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=C) ActionMappings = (ActionName="ConstructionTab",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=C)
ActionMappings=(ActionName="ControlGroup1",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=D) ActionMappings = (ActionName="ControlGroup1",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=D)
ActionMappings=(ActionName="ControlGroup10",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Zero) ActionMappings = (ActionName="ControlGroup10",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Zero)
ActionMappings=(ActionName="ControlGroup2",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Two) ActionMappings = (ActionName="ControlGroup2",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Two)
ActionMappings=(ActionName="ControlGroup3",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Three) ActionMappings = (ActionName="ControlGroup3",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Three)
ActionMappings=(ActionName="ControlGroup4",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Four) ActionMappings = (ActionName="ControlGroup4",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Four)
ActionMappings=(ActionName="ControlGroup5",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Five) ActionMappings = (ActionName="ControlGroup5",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Five)
ActionMappings=(ActionName="ControlGroup6",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Six) ActionMappings = (ActionName="ControlGroup6",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Six)
ActionMappings=(ActionName="ControlGroup7",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Seven) ActionMappings = (ActionName="ControlGroup7",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Seven)
ActionMappings=(ActionName="ControlGroup8",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Eight) ActionMappings = (ActionName="ControlGroup8",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Eight)
ActionMappings=(ActionName="ControlGroup9",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Nine) ActionMappings = (ActionName="ControlGroup9",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Nine)
ActionMappings=(ActionName="ControlGroupAddStealKey",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=SpaceBar) ActionMappings = (ActionName="ControlGroupAddStealKey",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=SpaceBar)
ActionMappings=(ActionName="Delete",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Delete) ActionMappings = (ActionName="Delete",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Delete)
ActionMappings=(ActionName="DisableWeapons",bShift=True,bCtrl=False,bAlt=True,bCmd=False,Key=J) ActionMappings = (ActionName="DisableWeapons",bShift=True,bCtrl=False,bAlt=True,bCmd=False,Key=J)
ActionMappings=(ActionName="DownArrow",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Down) ActionMappings = (ActionName="DownArrow",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Down)
ActionMappings=(ActionName="DragPan",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MiddleMouseButton) ActionMappings = (ActionName="DragPan",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MiddleMouseButton)
ActionMappings=(ActionName="Enter Cinematic Camera",bShift=True,bCtrl=False,bAlt=True,bCmd=False,Key=L) ActionMappings = (ActionName="Enter Cinematic Camera",bShift=True,bCtrl=False,bAlt=True,bCmd=False,Key=L)
ActionMappings=(ActionName="FullMana",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=J) ActionMappings = (ActionName="FullMana",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=J)
ActionMappings=(ActionName="FullyDamageSelectedUnits",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=P) ActionMappings = (ActionName="FullyDamageSelectedUnits",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=P)
ActionMappings=(ActionName="GetAlloyEther",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=M) ActionMappings = (ActionName="GetAlloyEther",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=M)
ActionMappings=(ActionName="GetPyre",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=L) ActionMappings = (ActionName="GetPyre",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=L)
ActionMappings=(ActionName="Hide HUD",bShift=True,bCtrl=False,bAlt=True,bCmd=False,Key=O) ActionMappings = (ActionName="Hide HUD",bShift=True,bCtrl=False,bAlt=True,bCmd=False,Key=O)
ActionMappings=(ActionName="InclusiveSelect/QueueCommand",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=LeftShift) ActionMappings = (ActionName="InclusiveSelect/QueueCommand",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=LeftShift)
ActionMappings=(ActionName="JumpToCameraLocation1",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=Z) ActionMappings = (ActionName="JumpToCameraLocation1",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=Z)
ActionMappings=(ActionName="JumpToCameraLocation2",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=X) ActionMappings = (ActionName="JumpToCameraLocation2",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=X)
ActionMappings=(ActionName="JumpToCameraLocation3",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=C) ActionMappings = (ActionName="JumpToCameraLocation3",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=C)
ActionMappings=(ActionName="JumpToCameraLocation4",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=V) ActionMappings = (ActionName="JumpToCameraLocation4",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=V)
ActionMappings=(ActionName="JumpToCameraLocation5",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=Two) ActionMappings = (ActionName="JumpToCameraLocation5",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=Two)
ActionMappings=(ActionName="JumpToCameraLocation6",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=Three) ActionMappings = (ActionName="JumpToCameraLocation6",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=Three)
ActionMappings=(ActionName="JumpToCameraLocation7",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=Four) ActionMappings = (ActionName="JumpToCameraLocation7",bShift=True,bCtrl=False,bAlt=False,bCmd=False,Key=Four)
ActionMappings=(ActionName="LeftArrow",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Left) ActionMappings = (ActionName="LeftArrow",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Left)
ActionMappings=(ActionName="LeftMouseClick",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=LeftMouseButton) ActionMappings = (ActionName="LeftMouseClick",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=LeftMouseButton)
ActionMappings=(ActionName="MarcoPolo",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Comma) ActionMappings = (ActionName="MarcoPolo",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Comma)
ActionMappings=(ActionName="Menu",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Escape) ActionMappings = (ActionName="Menu",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Escape)
ActionMappings=(ActionName="Menu",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=F10) ActionMappings = (ActionName="Menu",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=F10)
ActionMappings=(ActionName="MinimapJumpTo",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=LeftMouseButton) ActionMappings = (ActionName="MinimapJumpTo",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=LeftMouseButton)
ActionMappings=(ActionName="Move/ContextCommand",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=RightMouseButton) ActionMappings = (ActionName="Move/ContextCommand",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=RightMouseButton)
ActionMappings=(ActionName="PyreTab",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=One) ActionMappings = (ActionName="PyreTab",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=One)
ActionMappings=(ActionName="ResearchTab",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Tab) ActionMappings = (ActionName="ResearchTab",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Tab)
ActionMappings=(ActionName="RespawnNeutrals",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=N) ActionMappings = (ActionName="RespawnNeutrals",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=N)
ActionMappings=(ActionName="RightArrow",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Right) ActionMappings = (ActionName="RightArrow",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Right)
ActionMappings=(ActionName="RightMouseClick",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=RightMouseButton) ActionMappings = (ActionName="RightMouseClick",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=RightMouseButton)
ActionMappings=(ActionName="Select/ConfirmAbility",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=LeftMouseButton) ActionMappings = (ActionName="Select/ConfirmAbility",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=LeftMouseButton)
ActionMappings=(ActionName="SelectUnitProductionBuildings",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Z) ActionMappings = (ActionName="SelectUnitProductionBuildings",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Z)
ActionMappings=(ActionName="SetCameraLocation1",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=Z) ActionMappings = (ActionName="SetCameraLocation1",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=Z)
ActionMappings=(ActionName="SetCameraLocation2",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=X) ActionMappings = (ActionName="SetCameraLocation2",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=X)
ActionMappings=(ActionName="SetCameraLocation3",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=C) ActionMappings = (ActionName="SetCameraLocation3",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=C)
ActionMappings=(ActionName="SetCameraLocation4",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=V) ActionMappings = (ActionName="SetCameraLocation4",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=V)
ActionMappings=(ActionName="SetCameraLocation5",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=Two) ActionMappings = (ActionName="SetCameraLocation5",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=Two)
ActionMappings=(ActionName="SetCameraLocation6",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=Three) ActionMappings = (ActionName="SetCameraLocation6",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=Three)
ActionMappings=(ActionName="SetCameraLocation7",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=Four) ActionMappings = (ActionName="SetCameraLocation7",bShift=False,bCtrl=True,bAlt=False,bCmd=False,Key=Four)
ActionMappings=(ActionName="StandGround",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=S) ActionMappings = (ActionName="StandGround",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=S)
ActionMappings=(ActionName="SwitchAbilityCommandLayer",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=SpaceBar) ActionMappings = (ActionName="SwitchAbilityCommandLayer",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=SpaceBar)
ActionMappings=(ActionName="TheCheatToRuleThemAll",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=None) ActionMappings = (ActionName="TheCheatToRuleThemAll",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=None)
ActionMappings=(ActionName="Toggle Gamepad",bShift=False,bCtrl=True,bAlt=True,bCmd=False,Key=Slash) ActionMappings = (ActionName="Toggle Gamepad",bShift=False,bCtrl=True,bAlt=True,bCmd=False,Key=Slash)
ActionMappings=(ActionName="UpArrow",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Up) ActionMappings = (ActionName="UpArrow",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=Up)
ActionMappings=(ActionName="ZoomIn",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MouseScrollUp) ActionMappings = (ActionName="ZoomIn",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MouseScrollUp)
ActionMappings=(ActionName="ZoomOut",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MouseScrollDown) ActionMappings = (ActionName="ZoomOut",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=MouseScrollDown)
ActionMappings=(ActionName="UnitTypeSelectionModifier",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=LeftControl) ActionMappings = (ActionName="UnitTypeSelectionModifier",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=LeftControl)
``` ```
***Copy the above content and save the file as `Input.ini`.*** ***Copy the above content and save the file as `Input.ini`.***
## Understand the Input.ini ## Understand the Input.ini
@ -94,13 +93,20 @@ ActionMappings=(ActionName="UnitTypeSelectionModifier",bShift=False,bCtrl=False,
You can notice a single line of this file can be broken down like this. You can notice a single line of this file can be broken down like this.
`ActionMappings=(ActionName="AttackMove",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=A)` `ActionMappings=(ActionName="AttackMove",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=A)`
- `ActionMappings=(***)`: Indicates content is an action mapping. i.e. a hotkey - `ActionMappings=(***)`: Indicates content is an action mapping. i.e. a hotkey
- `ActionName="AttackMove"`: Indicates the name of the selected action. Here, we are using the `AttackMove` move action, that forces your selected army to attack. - `ActionName="AttackMove"`: Indicates the name of the selected action. Here, we are using the `AttackMove` move action,
- `Key=A`: Indicates key being mapped to the action. Set to `Key=Tab` to require the Tab key to be pressed instead, to perform the `AttackMove` action. that forces your selected army to attack.
- `bShift=False`: Indicates that the Shift key is not held. Set to `bShift=True` to require a shift key held to perform the mapped action. - `Key=A`: Indicates key being mapped to the action. Set to `Key=Tab` to require the Tab key to be pressed instead, to
- `bCtrl=False`: Indicates that the Ctrl key is not held. Set to `bCtrl=True` to require a ctrl key held to perform the mapped action. perform the `AttackMove` action.
- `bAlt=False`: Indicates that the Alt key is not held. Set to `bAlt=True` to require a alt key held to perform the mapped action. - `bShift=False`: Indicates that the Shift key is not held. Set to `bShift=True` to require a shift key held to
- `bCmd=False`: Indicates that the Cmd key is not held. Set to `bCmd=True` to require a cmd key held to perform the mapped action. (Macs not supported by IGP) perform the mapped action.
- `bCtrl=False`: Indicates that the Ctrl key is not held. Set to `bCtrl=True` to require a ctrl key held to perform
the mapped action.
- `bAlt=False`: Indicates that the Alt key is not held. Set to `bAlt=True` to require a alt key held to perform the
mapped action.
- `bCmd=False`: Indicates that the Cmd key is not held. Set to `bCmd=True` to require a cmd key held to perform the
mapped action. (Macs not supported by IGP)
## Modify the Input.ini file ## Modify the Input.ini file
@ -108,9 +114,11 @@ You are now going to want to modify the file with your own hotkey setup.
To do this, replace any of the Key=`VALUE` mapped to the desired actions with any value from the list below. To do this, replace any of the Key=`VALUE` mapped to the desired actions with any value from the list below.
*For example, you can swap the Z Key value in SelectUnitProductionBuildings to C. Which would look like this: `ActionMappings=(ActionName="SelectUnitProductionBuildings",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=C)`* *For example, you can swap the Z Key value in SelectUnitProductionBuildings to C. Which would look like
this: `ActionMappings=(ActionName="SelectUnitProductionBuildings",bShift=False,bCtrl=False,bAlt=False,bCmd=False,Key=C)`*
**Key Values** **Key Values**
- `AnyKey` - `AnyKey`
- `MouseX` - `MouseX`
- `MouseY` - `MouseY`
@ -242,8 +250,9 @@ To do this, replace any of the Key=`VALUE` mapped to the desired actions with an
# Transfer the Input.ini file # Transfer the Input.ini file
Drag and drop this new `Input.ini` file into `WindowsClient` folder in IGP. This folder can be found under `C:\Users\YOUR_USER\AppData\Local\Programs\CURRENT_IMMORTAL_CLIENT\Immortal\Saved\Config\WindowsClient\`. Drag and drop this new `Input.ini` file into `WindowsClient` folder in IGP. This folder can be found
Remember to use proper values for `YOUR_USER` and `CURRENT_IMMORTAL_CLIENT`. under `C:\Users\YOUR_USER\AppData\Local\Programs\CURRENT_IMMORTAL_CLIENT\Immortal\Saved\Config\WindowsClient\`. Remember
to use proper values for `YOUR_USER` and `CURRENT_IMMORTAL_CLIENT`.
There will be a blank `Input.ini` file in this folder. You can safely override it with your modified file. There will be a blank `Input.ini` file in this folder. You can safely override it with your modified file.

36
IGP/wwwroot/content/notes/the-basics/armor-types.md

@ -1,8 +1,5 @@
--- ---
title: Armor Types title: Armor Types summary: Heavy, Medium, and Light. What does it mean? created_date: 4/13/2000 updated_date: 4/13/2000
summary: Heavy, Medium, and Light. What does it mean?
created_date: 4/13/2000
updated_date: 4/13/2000
--- ---
## Armor Types ## Armor Types
@ -13,12 +10,14 @@ All units in "IMMORTAL: Gates of Pyre" have one of the three armor types.
- Medium - Medium
- Light - Light
These types mean nothing inherently. A Light armor unit will not take more damage than a Heavy armor unit, from the same damage source. These types mean nothing inherently. A Light armor unit will not take more damage than a Heavy armor unit, from the same
damage source.
Where this change is some units deal particular damage to a particular armor type. Where this change is some units deal particular damage to a particular armor type.
For example, a Dervish deals 16 damage generally, 24 to medium, and 32 damage to heavy armor types. For example, a Dervish deals 16 damage generally, 24 to medium, and 32 damage to heavy armor types. As an opposite
As an opposite example, the Zephyr will deal 20 damage generally, 24 to medium and 28 to heavy armor types. And as a different example, Sipari deals 20 damage generally, 18 damage to heavy armor. example, the Zephyr will deal 20 damage generally, 24 to medium and 28 to heavy armor types. And as a different example,
Sipari deals 20 damage generally, 18 damage to heavy armor.
Wait? There was no pattern to what general and specific damage is. Wait? There was no pattern to what general and specific damage is.
@ -32,29 +31,36 @@ They have two armies, one is a pack of Masked Hunters, and one is a pack of Xaca
Masked Hunters have the light armor type and Xacals have the heavy armor type. Masked Hunters have the light armor type and Xacals have the heavy armor type.
Well, you know Dervish deals the most damage to Light, and Zephyr deals the most damage to heavy, so you should generally have your Dervish attack the Masked Hunters and the Zephyr's attack the Xacals. Well, you know Dervish deals the most damage to Light, and Zephyr deals the most damage to heavy, so you should
generally have your Dervish attack the Masked Hunters and the Zephyr's attack the Xacals.
But wait, your opponent moved their two armies together! But wait, your opponent moved their two armies together!
Defensively, Masked Hunters deal less damage to the heavy armor type, and Xacals do less damage to Light. Defensively, Masked Hunters deal less damage to the heavy armor type, and Xacals do less damage to Light.
So while you want your Dervish to attack Masked Hunters, and the Zephyrs to attack the Xacals, you also want your Dervish to defend against the Xacals and Zephyrs to defend against the Masked Hunters. So while you want your Dervish to attack Masked Hunters, and the Zephyrs to attack the Xacals, you also want your
Dervish to defend against the Xacals and Zephyrs to defend against the Masked Hunters.
In mixed battles, you can spend some micro on your units to defend against enemy attackers they are strong against while having them attack potentially different enemies. In mixed battles, you can spend some micro on your units to defend against enemy attackers they are strong against while
having them attack potentially different enemies.
So what should you do? Build some Sipari, a Light armor unit, to help tank some Xacal shots, to give your Dervish and Zephyrs room to maneuver against their key targets.
So what should you do? Build some Sipari, a Light armor unit, to help tank some Xacal shots, to give your Dervish and
Zephyrs room to maneuver against their key targets.
## What else is there? ## What else is there?
Some units have additional tags, such as Structure and Etheric. Units can deal particular, or BONUS damage against enemies with those tags. Some units have additional tags, such as Structure and Etheric. Units can deal particular, or BONUS damage against
enemies with those tags.
**What are structures?** Structures are any building. Pretty much anything not a part of your moving army. **What are structures?** Structures are any building. Pretty much anything not a part of your moving army.
As an example of bonus damage, the Absolver deals +8 damage to structures, giving it 29 DPS to heavy structures. Conversely, it has 23 DPS against heavy structures when deployed, meaning Absolvers are better at sniping most structures when mobilized. As an example of bonus damage, the Absolver deals +8 damage to structures, giving it 29 DPS to heavy structures.
Conversely, it has 23 DPS against heavy structures when deployed, meaning Absolvers are better at sniping most
structures when mobilized.
Heads up though, that not all structures are heavy, examples include Radiant Wards generated by the Dervish. Heads up though, that not all structures are heavy, examples include Radiant Wards generated by the Dervish.
**What are etherics?** Etherics are most caster units in the game. These casters can generally win long drawn-out fights, so are good to snipe with units that deal extra damage against them. **What are etherics?** Etherics are most caster units in the game. These casters can generally win long drawn-out
fights, so are good to snipe with units that deal extra damage against them.
An etheric example would be the Bloodbounds Culling Strike ability, which deals bonus damage against etheric. An etheric example would be the Bloodbounds Culling Strike ability, which deals bonus damage against etheric.

6
IGP/wwwroot/content/notes/the-basics/economy-overview.md

@ -1,6 +1,4 @@
--- ---
title: Economy Overview title: Economy Overview summary: Alloy, Ether and Supply. Don't forget to expand!
summary: Alloy, Ether and Supply. Don't forget to expand! created_date: 1/01/2000 updated_date: 1/01/2000
created_date: 1/01/2000
updated_date: 1/01/2000
--- ---

6
IGP/wwwroot/content/notes/the-basics/families-factions-and-immortal-vanguards.md

@ -1,6 +1,4 @@
--- ---
title: Families, Factions, and Immortal Vanguards title: Families, Factions, and Immortal Vanguards summary: How IMMORTAL: Gates of Pyre handle your army selection
summary: How IMMORTAL: Gates of Pyre handle your army selection choices choices created_date: 1/01/2000 updated_date: 1/01/2000
created_date: 1/01/2000
updated_date: 1/01/2000
--- ---

6
IGP/wwwroot/content/notes/the-basics/immortal-spells-and-pyre.md

@ -1,8 +1,6 @@
--- ---
title: Immortals Spells and Pyre title: Immortals Spells and Pyre summary: Customize your hotkeys in the pre-alpha. created_date: 1/01/2000 updated_date:
summary: Customize your hotkeys in the pre-alpha. 1/01/2000
created_date: 1/01/2000
updated_date: 1/01/2000
--- ---
## What are Immortals ## What are Immortals

5
IGP/wwwroot/content/notes/the-basics/timing-and-scouting.md

@ -1,8 +1,5 @@
--- ---
title: Timing and Scouting title: Timing and Scouting summary: Knowing is half the battle. created_date: 1/01/2000 updated_date: 1/01/2000
summary: Knowing is half the battle.
created_date: 1/01/2000
updated_date: 1/01/2000
--- ---
## Timing ## Timing

2
IGP/wwwroot/generated/AgileTaskModels.json

File diff suppressed because one or more lines are too long

6
IGP/wwwroot/service-worker.published.js

@ -8,8 +8,8 @@ self.addEventListener('fetch', event => event.respondWith(onFetch(event)));
const cacheNamePrefix = 'offline-cache-'; const cacheNamePrefix = 'offline-cache-';
const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`; const cacheName = `${cacheNamePrefix}${self.assetsManifest.version}`;
const offlineAssetsInclude = [ /\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/, /\.blat$/, /\.dat$/ ]; const offlineAssetsInclude = [/\.dll$/, /\.pdb$/, /\.wasm/, /\.html/, /\.js$/, /\.json$/, /\.css$/, /\.woff$/, /\.png$/, /\.jpe?g$/, /\.gif$/, /\.ico$/, /\.blat$/, /\.dat$/];
const offlineAssetsExclude = [ /^service-worker\.js$/ ]; const offlineAssetsExclude = [/^service-worker\.js$/];
async function onInstall(event) { async function onInstall(event) {
console.info('Service worker: Install'); console.info('Service worker: Install');
@ -18,7 +18,7 @@ async function onInstall(event) {
const assetsRequests = self.assetsManifest.assets const assetsRequests = self.assetsManifest.assets
.filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url))) .filter(asset => offlineAssetsInclude.some(pattern => pattern.test(asset.url)))
.filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url))) .filter(asset => !offlineAssetsExclude.some(pattern => pattern.test(asset.url)))
.map(asset => new Request(asset.url, { integrity: asset.hash, cache: 'no-cache' })); .map(asset => new Request(asset.url, {integrity: asset.hash, cache: 'no-cache'}));
await caches.open(cacheName).then(cache => cache.addAll(assetsRequests)); await caches.open(cacheName).then(cache => cache.addAll(assetsRequests));
} }

3
IGP_Convert/Program.cs

@ -10,7 +10,8 @@ var options = new DbContextOptionsBuilder<DatabaseContext>();
options.UseSqlite($"Filename={projectPath}/{webProjectName}/Database.db"); options.UseSqlite($"Filename={projectPath}/{webProjectName}/Database.db");
// Load our database // Load our database
using (var db = new DatabaseContext(options.Options)) { using (var db = new DatabaseContext(options.Options))
{
// And save data in format Blazor Wasm can use // And save data in format Blazor Wasm can use
File.WriteAllTextAsync($"{webPath}/GitPatchModels.json", JsonSerializer.Serialize(db.GitPatchModels)); File.WriteAllTextAsync($"{webPath}/GitPatchModels.json", JsonSerializer.Serialize(db.GitPatchModels));
File.WriteAllTextAsync($"{webPath}/GitChangeModels.json", JsonSerializer.Serialize(db.GitChangeModels)); File.WriteAllTextAsync($"{webPath}/GitChangeModels.json", JsonSerializer.Serialize(db.GitChangeModels));

73
Model/BuildOrders/BuildOrderModel.cs

@ -1,7 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Model.Entity; using Model.Entity;
using Model.Entity.Data;
namespace Model.BuildOrders; namespace Model.BuildOrders;
@ -9,75 +8,15 @@ public class BuildOrderModel
{ {
public string Name { get; set; } = ""; public string Name { get; set; } = "";
public string Color { get; set; } = "red"; public string Color { get; set; } = "red";
public int CurrentSupplyUsed { get; set; } = 0;
public Dictionary<int, List<EntityModel>> StartedOrders { get; set; } = new()
{
{
0,
new List<EntityModel>
{
EntityModel.Get(DataType.STARTING_Bastion),
EntityModel.Get(DataType.STARTING_TownHall_Aru)
}
}
};
public Dictionary<int, List<EntityModel>> CompletedOrders { get; set; } = new()
{
{
0,
new List<EntityModel>
{
EntityModel.Get(DataType.STARTING_Bastion),
EntityModel.Get(DataType.STARTING_TownHall_Aru)
}
}
};
public Dictionary<string, int> UniqueCompletedTimes { get; set; } = new()
{
{
DataType.STARTING_Bastion, 0
},
{
DataType.STARTING_TownHall_Aru, 0
}
};
public Dictionary<string, int> UniqueCompletedCount { get; set; } = new()
{
{
DataType.STARTING_Bastion, 1
},
{
DataType.STARTING_TownHall_Aru, 1
}
};
public Dictionary<int, int> SupplyCountTimes { get; set; } = new()
{
{
0, 0
}
};
public string Notes { get; set; } = @""; public string Notes { get; set; } = @"";
public List<string> BuildTypes { get; set; } = new(); public List<string> BuildTypes { get; set; } = new();
public int CurrentSupplyUsed { get; set; } = 0;
public Dictionary<int, List<EntityModel>> StartedOrders { get; set; } = new();
public List<EntityModel> GetCompletedBefore(int interval) public Dictionary<int, List<EntityModel>> CompletedOrders { get; set; } = new();
{ public Dictionary<string, int> UniqueCompletedTimes { get; set; } = new();
return (from ordersAtTime in StartedOrders public Dictionary<string, int> UniqueCompletedCount { get; set; } = new();
from orders in ordersAtTime.Value public Dictionary<int, int> SupplyCountTimes { get; set; } = new();
where ordersAtTime.Key >= interval
where ordersAtTime.Key + (orders.Production() == null ? 0 : orders.Production().BuildTime) <= interval
select orders).ToList();
}
public List<EntityModel> GetHarvestersCompletedBefore(int interval) public List<EntityModel> GetHarvestersCompletedBefore(int interval)
{ {

5
Model/Doc/DocContentModel.cs

@ -12,7 +12,10 @@ public class DocContentModel
public int? ParentId { get; set; } = null; public int? ParentId { get; set; } = null;
public int? DocSectionModelId { get; set; } = null; public int? DocSectionModelId { get; set; } = null;
public string Href { get; set; } public string Href { get; set; }
[NotMapped] public virtual ICollection<DocContentModel> DocumentationModels { get; set; } = new List<DocContentModel>();
[NotMapped]
public virtual ICollection<DocContentModel> DocumentationModels { get; set; } = new List<DocContentModel>();
[NotMapped] public virtual DocContentModel Parent { get; set; } [NotMapped] public virtual DocContentModel Parent { get; set; }
[NotMapped] public virtual int PageOrder { get; set; } [NotMapped] public virtual int PageOrder { get; set; }
public DateTime CreatedDate { get; set; } public DateTime CreatedDate { get; set; }

5
Model/Economy/EconomyOverTimeModel.cs

@ -100,7 +100,6 @@ public class EconomyOverTimeModel
// Remove Funds from Build Order // Remove Funds from Build Order
if (buildOrder.StartedOrders.TryGetValue(interval, out var ordersAtTime)) if (buildOrder.StartedOrders.TryGetValue(interval, out var ordersAtTime))
{
foreach (var order in ordersAtTime) foreach (var order in ordersAtTime)
{ {
var foundEntity = EntityModel.GetDictionary()[order.DataType]; var foundEntity = EntityModel.GetDictionary()[order.DataType];
@ -116,11 +115,8 @@ public class EconomyOverTimeModel
} }
} }
}
// Handle new entities // Handle new entities
if (buildOrder.StartedOrders.TryGetValue(interval, out var ordersCompletedAtTime)) if (buildOrder.StartedOrders.TryGetValue(interval, out var ordersCompletedAtTime))
{
foreach (var newEntity in ordersCompletedAtTime) foreach (var newEntity in ordersCompletedAtTime)
{ {
var harvest = newEntity; var harvest = newEntity;
@ -131,5 +127,4 @@ public class EconomyOverTimeModel
} }
} }
} }
}
} }

220
Model/Entity/Data/DATA.cs

@ -55,7 +55,8 @@ public class DATA
DataType.TEAPOT_FlyingTeapot, new EntityModel(DataType.TEAPOT_FlyingTeapot, EntityType.Teapot) DataType.TEAPOT_FlyingTeapot, new EntityModel(DataType.TEAPOT_FlyingTeapot, EntityType.Teapot)
.AddPart(new EntityInfoModel .AddPart(new EntityInfoModel
{ {
Name = "Flying Teapot", Description = "Basic observer. Can fly and see hidden units within 1000 range.", Name = "Flying Teapot",
Description = "Basic observer. Can fly and see hidden units within 1000 range.",
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 })
@ -236,7 +237,7 @@ public class DATA
Resource = ResourceType.Pyre, HarvestedPerInterval = 1, HarvestDelay = 3, Resource = ResourceType.Pyre, HarvestedPerInterval = 1, HarvestDelay = 3,
RequiresWorker = false, Slots = 1, TotalAmount = -1 RequiresWorker = false, Slots = 1, TotalAmount = -1
}) })
.AddPart(new EntityIdPassiveModel {Id = DataType.IPASSIVE_MothersHunger}) .AddPart(new EntityIdPassiveModel { Id = DataType.IPASSIVE_MothersHunger })
.AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_SummonGroveGuardian }) .AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_SummonGroveGuardian })
.AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_InfuseTroops }) .AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_InfuseTroops })
.AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_ConstructBloodWell }) .AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_ConstructBloodWell })
@ -255,7 +256,7 @@ public class DATA
Resource = ResourceType.Pyre, HarvestedPerInterval = 1, HarvestDelay = 3, Resource = ResourceType.Pyre, HarvestedPerInterval = 1, HarvestDelay = 3,
RequiresWorker = false, Slots = 1, TotalAmount = -1 RequiresWorker = false, Slots = 1, TotalAmount = -1
}) })
.AddPart(new EntityIdPassiveModel {Id = DataType.IPASSIVE_StalkersSense}) .AddPart(new EntityIdPassiveModel { Id = DataType.IPASSIVE_StalkersSense })
.AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_SummonGroveGuardian }) .AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_SummonGroveGuardian })
.AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_InfuseTroops }) .AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_InfuseTroops })
.AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_ConstructBloodWell }) .AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_ConstructBloodWell })
@ -276,7 +277,7 @@ public class DATA
Resource = ResourceType.Pyre, HarvestedPerInterval = 1, HarvestDelay = 3, Resource = ResourceType.Pyre, HarvestedPerInterval = 1, HarvestDelay = 3,
RequiresWorker = false, Slots = 1, TotalAmount = -1 RequiresWorker = false, Slots = 1, TotalAmount = -1
}) })
.AddPart(new EntityIdPassiveModel {Id = DataType.IPASSIVE_HealingGround}) .AddPart(new EntityIdPassiveModel { Id = DataType.IPASSIVE_HealingGround })
.AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_SummonCitadel }) .AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_SummonCitadel })
.AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_InfuseTroops }) .AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_InfuseTroops })
.AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_DeliverFromEvil }) .AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_DeliverFromEvil })
@ -294,7 +295,7 @@ public class DATA
Resource = ResourceType.Pyre, HarvestedPerInterval = 1, HarvestDelay = 3, Resource = ResourceType.Pyre, HarvestedPerInterval = 1, HarvestDelay = 3,
RequiresWorker = false, Slots = 1, TotalAmount = -1 RequiresWorker = false, Slots = 1, TotalAmount = -1
}) })
.AddPart(new EntityIdPassiveModel {Id = DataType.IPASSIVE_Expansionist}) .AddPart(new EntityIdPassiveModel { Id = DataType.IPASSIVE_Expansionist })
.AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_InfuseTroops }) .AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_InfuseTroops })
.AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_SummonCitadel }) .AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_SummonCitadel })
.AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_EmpireUnbroken }) .AddPart(new EntityIdPyreSpellModel { Id = DataType.ISPELL_EmpireUnbroken })
@ -322,16 +323,19 @@ public class DATA
.AddPart(new EntityInfoModel .AddPart(new EntityInfoModel
{ {
Name = "Mother's Hunger", Name = "Mother's Hunger",
Description = "Mala's Blood Wells grant you pyre for nearby non-quitl deaths, based on the supply.", Description =
"Mala's Blood Wells grant you pyre for nearby non-quitl deaths, based on the supply.",
Notes = "+1 per supply" Notes = "+1 per supply"
}) })
}, },
{ {
DataType.IPASSIVE_StalkersSense, DataType.IPASSIVE_StalkersSense,
new EntityModel(DataType.IPASSIVE_StalkersSense, EntityType.Passive) new EntityModel(DataType.IPASSIVE_StalkersSense, EntityType.Passive)
.AddPart(new EntityInfoModel .AddPart(new EntityInfoModel
{ Name = "Stalker's Sense", Description = "Xol's units sense nearby enemies in the fog of war.", Notes = "Not implemented."}) {
Name = "Stalker's Sense", Description = "Xol's units sense nearby enemies in the fog of war.",
Notes = "Not implemented."
})
}, },
// Keys // Keys
@ -369,7 +373,7 @@ public class DATA
.AddPart(new EntityVitalityModel { Health = 500, Armor = ArmorType.Heavy }) .AddPart(new EntityVitalityModel { Health = 500, Armor = ArmorType.Heavy })
.AddPart(new EntityWeaponModel .AddPart(new EntityWeaponModel
{ Damage = 30, AttacksPerSecond = 1.401f, Targets = TargetType.All, Range = 700 }) { Damage = 30, AttacksPerSecond = 1.401f, Targets = TargetType.All, Range = 700 })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_BastionPassives}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_BastionPassives })
}, },
{ {
DataType.STARTING_Tower, DataType.STARTING_Tower,
@ -389,7 +393,7 @@ public class DATA
MediumDamage = 25, HeavyDamage = 30 MediumDamage = 25, HeavyDamage = 30
}) })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Respite }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Respite })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_HallowedGround}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_HallowedGround })
}, },
// Starting Structures // Starting Structures
// Aru // Aru
@ -406,7 +410,7 @@ public class DATA
HarvestedPerInterval = 1, RequiresWorker = true, Resource = ResourceType.Alloy, Slots = 6, HarvestedPerInterval = 1, RequiresWorker = true, Resource = ResourceType.Alloy, Slots = 6,
TotalAmount = 6000 TotalAmount = 6000
}) })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_Rootway}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Rootway })
}, },
// Starting Structures // Starting Structures
// Q'Rath // Q'Rath
@ -423,7 +427,7 @@ public class DATA
HarvestedPerInterval = 6, RequiresWorker = false, Resource = ResourceType.Alloy, Slots = 1, HarvestedPerInterval = 6, RequiresWorker = false, Resource = ResourceType.Alloy, Slots = 1,
TotalAmount = 6000 TotalAmount = 6000
}) })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_HallowedGround}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_HallowedGround })
}, },
// Vanguard // Vanguard
@ -457,7 +461,7 @@ public class DATA
.AddPart(new EntityMovementModel { Speed = 380, Movement = MovementType.Ground }) .AddPart(new EntityMovementModel { Speed = 380, Movement = MovementType.Ground })
.AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_FaithCastBlades }) .AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_FaithCastBlades })
.AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_IconOfKhastEem }) .AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_IconOfKhastEem })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_IconOfKhastEem}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_IconOfKhastEem })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_FaithCastBlades }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_FaithCastBlades })
}, },
{ {
@ -589,8 +593,6 @@ public class DATA
{ Damage = 16, Range = 700, AttacksPerSecond = 0.606f, Targets = TargetType.Ground }) { Damage = 16, Range = 700, AttacksPerSecond = 0.606f, Targets = TargetType.Ground })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_ProjectileGestation }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_ProjectileGestation })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_FallenHarvest }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_FallenHarvest })
}, },
{ {
DataType.VANGUARD_DreadSister_Mala, DataType.VANGUARD_DreadSister_Mala,
@ -647,8 +649,8 @@ public class DATA
.AddPart(new EntityMovementModel { Speed = 350, Movement = MovementType.Ground }) .AddPart(new EntityMovementModel { Speed = 350, Movement = MovementType.Ground })
.AddPart(new EntityWeaponModel .AddPart(new EntityWeaponModel
{ Damage = 11, Range = 400, AttacksPerSecond = 1.02f, Targets = TargetType.All }) { Damage = 11, Range = 400, AttacksPerSecond = 1.02f, Targets = TargetType.All })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_Stalk}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Stalk })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_Ambush}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Ambush })
}, },
{ {
DataType.VANGUARD_WhiteWoodReaper_Xol, DataType.VANGUARD_WhiteWoodReaper_Xol,
@ -726,10 +728,10 @@ public class DATA
Damage = 20, HeavyDamage = 18, Range = 180, AttacksPerSecond = 0.699f, Damage = 20, HeavyDamage = 18, Range = 180, AttacksPerSecond = 0.699f,
SecondsBetweenAttacks = 1.43f, Targets = TargetType.Ground SecondsBetweenAttacks = 1.43f, Targets = TargetType.Ground
}) })
.AddPart(new EntityIdUpgradeModel() { Id = DataType.UPGRADE_GreavesOfAhqar}) .AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_GreavesOfAhqar })
.AddPart(new EntityIdUpgradeModel() { Id = DataType.UPGRADE_FortifiedIcons}) .AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_FortifiedIcons })
.AddPart(new EntityIdPassiveModel() { Id = DataType.PASSIVE_GreavesOfAhqar}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_GreavesOfAhqar })
.AddPart(new EntityIdPassiveModel() { Id = DataType.PASSIVE_FortifiedIcons}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_FortifiedIcons })
}, },
{ {
DataType.UNIT_Magi, DataType.UNIT_Magi,
@ -832,9 +834,8 @@ public class DATA
}) })
.AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_SiroccoScript }) .AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_SiroccoScript })
.AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_RadiantWard }) .AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_RadiantWard })
.AddPart(new EntityIdAbilityModel {Id = DataType.ABILITY_RadiantWard}) .AddPart(new EntityIdAbilityModel { Id = DataType.ABILITY_RadiantWard })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_SiroccoScript}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_SiroccoScript })
}, },
{ {
DataType.UNIT_Absolver, DataType.UNIT_Absolver,
@ -937,7 +938,6 @@ public class DATA
Damage = 60, MediumDamage = 80, HeavyDamage = 100, Range = 1300, AttacksPerSecond = 0.143f, Damage = 60, MediumDamage = 80, HeavyDamage = 100, Range = 1300, AttacksPerSecond = 0.143f,
Targets = TargetType.Ground Targets = TargetType.Ground
}) })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_HallowedRuin }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_HallowedRuin })
}, },
{ {
@ -1026,9 +1026,9 @@ public class DATA
.AddPart(new EntityMovementModel { Speed = 420, Movement = MovementType.Air }) .AddPart(new EntityMovementModel { Speed = 420, Movement = MovementType.Air })
.AddPart(new EntityWeaponModel .AddPart(new EntityWeaponModel
{ Damage = 32, Range = 600, AttacksPerSecond = 0.556f, Targets = TargetType.Ground }) { Damage = 32, Range = 600, AttacksPerSecond = 0.556f, Targets = TargetType.Ground })
.AddPart(new EntityIdUpgradeModel(){Id = DataType.UPGRADE_WingsOfTheKenLatir}) .AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_WingsOfTheKenLatir })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_WingsOfTheKenLatir}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_WingsOfTheKenLatir })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_ExecutionRites}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_ExecutionRites })
}, },
{ {
DataType.UNIT_SharU, DataType.UNIT_SharU,
@ -1167,7 +1167,6 @@ public class DATA
Targets = TargetType.Ground Targets = TargetType.Ground
}) })
.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 })
}, },
{ {
@ -1267,7 +1266,7 @@ public class DATA
}) })
.AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_DenInstinct }) .AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_DenInstinct })
.AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_PursuitLigaments }) .AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_PursuitLigaments })
.AddPart(new EntityIdPassiveModel() { Id = DataType.PASSIVE_ExternalDigestion }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_ExternalDigestion })
}, },
{ {
DataType.UNIT_Resinant, DataType.UNIT_Resinant,
@ -1332,8 +1331,7 @@ public class DATA
TargetType.Air TargetType.Air
}) })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_AaroxBurn }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_AaroxBurn })
.AddPart(new EntityIdAbilityModel { Id = DataType.ABILITY_DiveBomb })
.AddPart(new EntityIdAbilityModel() { Id = DataType.ABILITY_DiveBomb })
}, },
{ {
DataType.UNIT_Thrum, DataType.UNIT_Thrum,
@ -1378,7 +1376,7 @@ public class DATA
.AddPart(new EntityWeaponModel .AddPart(new EntityWeaponModel
{ Damage = 9, Range = 500, AttacksPerSecond = 0.714f, Targets = TargetType.Ground }) { Damage = 9, Range = 500, AttacksPerSecond = 0.714f, Targets = TargetType.Ground })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_GuidingAmber }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_GuidingAmber })
.AddPart(new EntityIdPassiveModel() { Id = DataType.PASSIVE_WraithBowRange }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_WraithBowRange })
}, },
{ {
DataType.UNIT_Behemoth, DataType.UNIT_Behemoth,
@ -1409,8 +1407,6 @@ public class DATA
.AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_BehemothCapacity }) .AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_BehemothCapacity })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_BehemothCapacity }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_BehemothCapacity })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_QuitlStorage2 }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_QuitlStorage2 })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_FireQuitl }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_FireQuitl })
}, },
{ {
@ -1420,7 +1416,7 @@ public class DATA
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
.AddPart(new EntityVitalityModel { Health = 65, Armor = ArmorType.Light }) .AddPart(new EntityVitalityModel { Health = 65, Armor = ArmorType.Light })
.AddPart(new EntityMovementModel { Speed = 168, Movement = MovementType.Ground }) .AddPart(new EntityMovementModel { Speed = 168, Movement = MovementType.Ground })
.AddPart(new EntityIdPassiveModel() {Id = DataType.PASSIVE_Temporary}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Temporary })
}, },
// Upgrades // Upgrades
// Q'Rath // Q'Rath
@ -1442,8 +1438,6 @@ public class DATA
}) })
.AddPart(new EntityVanguardReplacedModel .AddPart(new EntityVanguardReplacedModel
{ ImmortalId = DataType.IMMORTAL_Orzum, ReplacedById = DataType.UPGRADE_FaithCastBlades }) { ImmortalId = DataType.IMMORTAL_Orzum, ReplacedById = DataType.UPGRADE_FaithCastBlades })
}, },
{ {
DataType.UPGRADE_RadiantWard, DataType.UPGRADE_RadiantWard,
@ -1471,7 +1465,7 @@ public class DATA
Name = "Fortified Icons", Descriptive = DescriptiveType.Upgrade, Name = "Fortified Icons", Descriptive = DescriptiveType.Upgrade,
Description = "Sipari gain +20 shields, and Hallowed Ground grants an additional +20 shields." Description = "Sipari gain +20 shields, and Hallowed Ground grants an additional +20 shields."
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "TAB", HoldSpace = true}) .AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "TAB", HoldSpace = true })
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 100, BuildTime = 43 }) .AddPart(new EntityProductionModel { Alloy = 100, Ether = 100, BuildTime = 43 })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
@ -1481,8 +1475,6 @@ public class DATA
}) })
.AddPart(new EntityVanguardReplacedModel .AddPart(new EntityVanguardReplacedModel
{ ImmortalId = DataType.IMMORTAL_Orzum, ReplacedById = DataType.UPGRADE_IconOfKhastEem }) { ImmortalId = DataType.IMMORTAL_Orzum, ReplacedById = DataType.UPGRADE_IconOfKhastEem })
}, },
{ {
@ -1496,10 +1488,10 @@ public class DATA
.AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "TAB" }) .AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "TAB" })
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
.AddPart(new EntityProductionModel { Alloy = 50, Ether = 100, BuildTime = 60 }) .AddPart(new EntityProductionModel { Alloy = 50, Ether = 100, BuildTime = 60 })
.AddPart(new EntityRequirementModel { Id = DataType.BUILDING_Reliquary, Requirement = RequirementType.Research_Building}) .AddPart(new EntityRequirementModel
{ Id = DataType.BUILDING_Reliquary, Requirement = RequirementType.Research_Building })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
{ ReplaceId = DataType.UPGRADE_GreavesOfAhqar, ImmortalId = DataType.IMMORTAL_Orzum }) { ReplaceId = DataType.UPGRADE_GreavesOfAhqar, ImmortalId = DataType.IMMORTAL_Orzum })
}, },
{ {
DataType.UPGRADE_RelicOfTheWrathfulGaze, DataType.UPGRADE_RelicOfTheWrathfulGaze,
@ -1526,7 +1518,8 @@ public class DATA
.AddPart(new EntityHotkeyModel { Hotkey = "W", HotkeyGroup = "TAB" }) .AddPart(new EntityHotkeyModel { Hotkey = "W", HotkeyGroup = "TAB" })
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
.AddPart(new EntityProductionModel { Alloy = 50, Ether = 75, BuildTime = 55 }) .AddPart(new EntityProductionModel { Alloy = 50, Ether = 75, BuildTime = 55 })
.AddPart(new EntityRequirementModel { Id = DataType.BUILDING_Reliquary, Requirement = RequirementType.Production_Building }) .AddPart(new EntityRequirementModel
{ Id = DataType.BUILDING_Reliquary, Requirement = RequirementType.Production_Building })
}, },
{ {
DataType.UPGRADE_ZephyrRange, DataType.UPGRADE_ZephyrRange,
@ -1539,7 +1532,8 @@ public class DATA
.AddPart(new EntityHotkeyModel { Hotkey = "E", HotkeyGroup = "TAB" }) .AddPart(new EntityHotkeyModel { Hotkey = "E", HotkeyGroup = "TAB" })
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
.AddPart(new EntityProductionModel { Alloy = 150, Ether = 100, BuildTime = 43 }) .AddPart(new EntityProductionModel { Alloy = 150, Ether = 100, BuildTime = 43 })
.AddPart(new EntityRequirementModel { Id = DataType.UPGRADE_ZephyrRange, Requirement = RequirementType.Production_Building }) .AddPart(new EntityRequirementModel
{ Id = DataType.UPGRADE_ZephyrRange, Requirement = RequirementType.Production_Building })
.AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_WindStep }) .AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_WindStep })
.AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_ZephyrRange }) .AddPart(new EntityIdUpgradeModel { Id = DataType.UPGRADE_ZephyrRange })
}, },
@ -1578,8 +1572,6 @@ public class DATA
}) })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
{ ReplaceId = DataType.UPGRADE_FortifiedIcons, ImmortalId = DataType.IMMORTAL_Orzum }) { ReplaceId = DataType.UPGRADE_FortifiedIcons, ImmortalId = DataType.IMMORTAL_Orzum })
}, },
{ {
DataType.UPGRADE_BladesOfTheGodhead, DataType.UPGRADE_BladesOfTheGodhead,
@ -1622,12 +1614,12 @@ public class DATA
{ {
Name = "Offering", Name = "Offering",
Descriptive = DescriptiveType.Upgrade, Descriptive = DescriptiveType.Upgrade,
Description = "Unlocks Offering" }) Description = "Unlocks Offering"
})
.AddPart(new EntityHotkeyModel { Hotkey = "W", HotkeyGroup = "TAB" }) .AddPart(new EntityHotkeyModel { Hotkey = "W", HotkeyGroup = "TAB" })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
.AddPart(new EntityVanguardReplacedModel .AddPart(new EntityVanguardReplacedModel
{ ImmortalId = DataType.IMMORTAL_Xol, ReplacedById = DataType.UPGRADE_Stalk }) { ImmortalId = DataType.IMMORTAL_Xol, ReplacedById = DataType.UPGRADE_Stalk })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
Id = DataType.BUILDING_AltarOfTheWorthy, Id = DataType.BUILDING_AltarOfTheWorthy,
@ -1649,7 +1641,6 @@ public class DATA
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
.AddPart(new EntityVanguardReplacedModel .AddPart(new EntityVanguardReplacedModel
{ ImmortalId = DataType.IMMORTAL_Xol, ReplacedById = DataType.UPGRADE_Ambush }) { ImmortalId = DataType.IMMORTAL_Xol, ReplacedById = DataType.UPGRADE_Ambush })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
Id = DataType.BUILDING_AmberWomb, Id = DataType.BUILDING_AmberWomb,
@ -1770,7 +1761,6 @@ public class DATA
.AddPart(new EntityProductionModel { Alloy = 100, Ether = 80, BuildTime = 60 }) .AddPart(new EntityProductionModel { Alloy = 100, Ether = 80, BuildTime = 60 })
.AddPart(new EntityVanguardAddedModel .AddPart(new EntityVanguardAddedModel
{ ReplaceId = DataType.UPGRADE_Offering, ImmortalId = DataType.IMMORTAL_Xol }) { ReplaceId = DataType.UPGRADE_Offering, ImmortalId = DataType.IMMORTAL_Xol })
}, },
{ {
@ -1889,7 +1879,8 @@ public class DATA
Name = "Greaves Of Ahqar", Descriptive = DescriptiveType.Ability, Name = "Greaves Of Ahqar", Descriptive = DescriptiveType.Ability,
Description = @"+75 Sipari Speed" Description = @"+75 Sipari Speed"
}) })
.AddPart(new EntityRequirementModel(){ Id = DataType.UPGRADE_GreavesOfAhqar, Requirement = RequirementType.Research_Upgrade}) .AddPart(new EntityRequirementModel
{ Id = DataType.UPGRADE_GreavesOfAhqar, Requirement = RequirementType.Research_Upgrade })
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
}, },
@ -1901,7 +1892,10 @@ public class DATA
Name = "Relic Of The Wrathful Gaze", Descriptive = DescriptiveType.Ability, Name = "Relic Of The Wrathful Gaze", Descriptive = DescriptiveType.Ability,
Description = @"Increases Castigator range against air." Description = @"Increases Castigator range against air."
}) })
.AddPart(new EntityRequirementModel(){ Id = DataType.UPGRADE_RelicOfTheWrathfulGaze, Requirement = RequirementType.Research_Upgrade}) .AddPart(new EntityRequirementModel
{
Id = DataType.UPGRADE_RelicOfTheWrathfulGaze, Requirement = RequirementType.Research_Upgrade
})
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
}, },
{ {
@ -1912,7 +1906,8 @@ public class DATA
Name = "Wings of the Ken'Latir", Descriptive = DescriptiveType.Passive, Name = "Wings of the Ken'Latir", Descriptive = DescriptiveType.Passive,
Description = @"Increases the Warden's speed and shields significantly." Description = @"Increases the Warden's speed and shields significantly."
}) })
.AddPart(new EntityRequirementModel(){ Id = DataType.UPGRADE_WingsOfTheKenLatir, Requirement = RequirementType.Research_Upgrade}) .AddPart(new EntityRequirementModel
{ Id = DataType.UPGRADE_WingsOfTheKenLatir, Requirement = RequirementType.Research_Upgrade })
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
}, },
@ -1935,7 +1930,8 @@ public class DATA
Name = "Icon Of Khast'Eem", Descriptive = DescriptiveType.Passive, Name = "Icon Of Khast'Eem", Descriptive = DescriptiveType.Passive,
Description = @"Grants the Zentari shields and flat armor reduction." Description = @"Grants the Zentari shields and flat armor reduction."
}) })
.AddPart(new EntityRequirementModel(){ Id = DataType.UPGRADE_IconOfKhastEem, Requirement = RequirementType.Research_Upgrade}) .AddPart(new EntityRequirementModel
{ Id = DataType.UPGRADE_IconOfKhastEem, Requirement = RequirementType.Research_Upgrade })
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
}, },
@ -1947,9 +1943,9 @@ public class DATA
Name = "Faith Cast Blades", Descriptive = DescriptiveType.Passive, Name = "Faith Cast Blades", Descriptive = DescriptiveType.Passive,
Description = @"Increases the range of the Zentari's ranged weapon." Description = @"Increases the range of the Zentari's ranged weapon."
}) })
.AddPart(new EntityRequirementModel(){ Id = DataType.UPGRADE_FaithCastBlades, Requirement = RequirementType.Research_Upgrade}) .AddPart(new EntityRequirementModel
{ Id = DataType.UPGRADE_FaithCastBlades, Requirement = RequirementType.Research_Upgrade })
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
}, },
{ {
@ -1971,7 +1967,7 @@ public class DATA
Name = "Sirocco Script Rites", Descriptive = DescriptiveType.Passive, Name = "Sirocco Script Rites", Descriptive = DescriptiveType.Passive,
Description = @"Increases the derish's movement speed" Description = @"Increases the derish's movement speed"
}) })
.AddPart(new EntityRequirementModel(){ Id = DataType.UPGRADE_SiroccoScript}) .AddPart(new EntityRequirementModel { Id = DataType.UPGRADE_SiroccoScript })
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
}, },
@ -2003,7 +1999,8 @@ public class DATA
.AddPart(new EntityInfoModel .AddPart(new EntityInfoModel
{ {
Name = "Regent's Wrath", Descriptive = DescriptiveType.Passive, Name = "Regent's Wrath", Descriptive = DescriptiveType.Passive,
Description = @"Scepters gain energy when stabilized. They lose energy when moving. Energy is spent to have splash on attack." Description =
@"Scepters gain energy when stabilized. They lose energy when moving. Energy is spent to have splash on attack."
}) })
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
}, },
@ -2061,7 +2058,8 @@ public class DATA
Name = "Wraith Bow Range", Descriptive = DescriptiveType.Ability, Name = "Wraith Bow Range", Descriptive = DescriptiveType.Ability,
Description = @"Increases Wraith Bow range against air." Description = @"Increases Wraith Bow range against air."
}) })
.AddPart(new EntityRequirementModel(){ Id = DataType.UPGRADE_WraithBowRange, Requirement = RequirementType.Research_Upgrade}) .AddPart(new EntityRequirementModel
{ Id = DataType.UPGRADE_WraithBowRange, Requirement = RequirementType.Research_Upgrade })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
}, },
@ -2071,7 +2069,7 @@ public class DATA
.AddPart(new EntityInfoModel .AddPart(new EntityInfoModel
{ {
Name = "Rootway", Descriptive = DescriptiveType.Passive, Name = "Rootway", Descriptive = DescriptiveType.Passive,
Description = @"Building generates Rootway.", Description = @"Building generates Rootway."
}) })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
}, },
@ -2082,7 +2080,7 @@ public class DATA
.AddPart(new EntityInfoModel .AddPart(new EntityInfoModel
{ {
Name = "Quitl Storage", Descriptive = DescriptiveType.Passive, Name = "Quitl Storage", Descriptive = DescriptiveType.Passive,
Description = @"Unit stores quitl for attacks.", Description = @"Unit stores quitl for attacks."
}) })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
}, },
@ -2093,10 +2091,11 @@ public class DATA
.AddPart(new EntityInfoModel .AddPart(new EntityInfoModel
{ {
Name = "Quitl Storage", Descriptive = DescriptiveType.Passive, Name = "Quitl Storage", Descriptive = DescriptiveType.Passive,
Description = @"Unit stores more quitl for attacks.", Description = @"Unit stores more quitl for attacks."
}) })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
.AddPart(new EntityRequirementModel { Id = DataType.UPGRADE_BehemothCapacity, Requirement = RequirementType.Research_Upgrade} ) .AddPart(new EntityRequirementModel
{ Id = DataType.UPGRADE_BehemothCapacity, Requirement = RequirementType.Research_Upgrade })
}, },
{ {
@ -2116,24 +2115,24 @@ public class DATA
.AddPart(new EntityInfoModel .AddPart(new EntityInfoModel
{ {
Name = "Temporary", Descriptive = DescriptiveType.Passive, Name = "Temporary", Descriptive = DescriptiveType.Passive,
Description = @"This unit has a limited duration before it dies.", Description = @"This unit has a limited duration before it dies."
}) })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
}, },
{ {
DataType.PASSIVE_Stalk, DataType.PASSIVE_Stalk,
new EntityModel(DataType.PASSIVE_Stalk, EntityType.Passive) new EntityModel(DataType.PASSIVE_Stalk, EntityType.Passive)
.AddPart(new EntityInfoModel .AddPart(new EntityInfoModel
{ {
Name = "Stalk", Descriptive = DescriptiveType.Passive, Name = "Stalk", Descriptive = DescriptiveType.Passive,
Description = @"After remaining stationary for several seconds, gain Hidden 3 and a movement speed boost.", Description =
@"After remaining stationary for several seconds, gain Hidden 3 and a movement speed boost.",
Notes = "Lose hidden on attacking" Notes = "Lose hidden on attacking"
}) })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
.AddPart(new EntityRequirementModel{Id=DataType.UPGRADE_Stalk}) .AddPart(new EntityRequirementModel { Id = DataType.UPGRADE_Stalk })
}, },
{ {
@ -2142,10 +2141,10 @@ public class DATA
.AddPart(new EntityInfoModel .AddPart(new EntityInfoModel
{ {
Name = "Ambush", Descriptive = DescriptiveType.Passive, Name = "Ambush", Descriptive = DescriptiveType.Passive,
Description = @"This unit deals double damage when attacking from hidden.", Description = @"This unit deals double damage when attacking from hidden."
}) })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
.AddPart(new EntityRequirementModel(){Id=DataType.UPGRADE_Ambush}) .AddPart(new EntityRequirementModel { Id = DataType.UPGRADE_Ambush })
}, },
{ {
@ -2154,7 +2153,7 @@ public class DATA
.AddPart(new EntityInfoModel .AddPart(new EntityInfoModel
{ {
Name = "Hidden X", Descriptive = DescriptiveType.Passive, Name = "Hidden X", Descriptive = DescriptiveType.Passive,
Description = @"This unit cannot be seen unless enemies units are within X.", Description = @"This unit cannot be seen unless enemies units are within X."
}) })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
}, },
@ -2194,8 +2193,6 @@ public class DATA
}, },
{ {
DataType.PASSIVE_FortifiedIcons, DataType.PASSIVE_FortifiedIcons,
new EntityModel(DataType.PASSIVE_FortifiedIcons, EntityType.Passive) new EntityModel(DataType.PASSIVE_FortifiedIcons, EntityType.Passive)
@ -2205,7 +2202,8 @@ public class DATA
Description = @"Increases Sipari shields and increases the bonus while in Hallowed Ground", Description = @"Increases Sipari shields and increases the bonus while in Hallowed Ground",
Notes = "+20 Shields, and +20 Shields on Hallowed Ground." Notes = "+20 Shields, and +20 Shields on Hallowed Ground."
}) })
.AddPart(new EntityRequirementModel(){ Id = DataType.UPGRADE_FortifiedIcons, Requirement = RequirementType.Research_Upgrade}) .AddPart(new EntityRequirementModel
{ Id = DataType.UPGRADE_FortifiedIcons, Requirement = RequirementType.Research_Upgrade })
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
}, },
{ {
@ -2265,7 +2263,8 @@ public class DATA
Description = Description =
@"Xacal builds up charges for double damage overtime. These charges can be spent on attacking." @"Xacal builds up charges for double damage overtime. These charges can be spent on attacking."
}) })
.AddPart(new EntityRequirementModel(){ Id = DataType.UPGRADE_XacalDamage, Requirement = RequirementType.Research_Upgrade}) .AddPart(new EntityRequirementModel
{ Id = DataType.UPGRADE_XacalDamage, Requirement = RequirementType.Research_Upgrade })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
}, },
{ {
@ -2362,12 +2361,14 @@ public class DATA
.AddPart(new EntityInfoModel .AddPart(new EntityInfoModel
{ {
Name = "Radiant Ward", Descriptive = DescriptiveType.Ability, Name = "Radiant Ward", Descriptive = DescriptiveType.Ability,
Description = @"Spawns a mine that reveals enemy units, slows them, and makes them take increased damage for a duration.", Description =
@"Spawns a mine that reveals enemy units, slows them, and makes them take increased damage for a duration."
}) })
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
.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 {Health = 30, DefenseLayer = 30, Lasts = 30, Armor = ArmorType.Light, IsStructure = true}) .AddPart(new EntityVitalityModel
{ Health = 30, DefenseLayer = 30, Lasts = 30, Armor = ArmorType.Light, IsStructure = true })
.AddPart(new EntityRequirementModel .AddPart(new EntityRequirementModel
{ {
Id = DataType.BUILDING_HouseOfFadingSaints, Id = DataType.BUILDING_HouseOfFadingSaints,
@ -2513,8 +2514,7 @@ public class DATA
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "E", HotkeyGroup = "D" }) .AddPart(new EntityHotkeyModel { Hotkey = "E", HotkeyGroup = "D" })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
.AddPart(new EntityRequirementModel(){ Id= DataType.UPGRADE_Offering}) .AddPart(new EntityRequirementModel { Id = DataType.UPGRADE_Offering })
}, },
{ {
DataType.ABILITY_DiveBomb, DataType.ABILITY_DiveBomb,
@ -2668,12 +2668,13 @@ public class DATA
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
.AddPart(new EntityProductionModel { Alloy = 100, BuildTime = 25 }) .AddPart(new EntityProductionModel { Alloy = 100, BuildTime = 25 })
.AddPart(new EntitySupplyModel { Takes = 6 }) .AddPart(new EntitySupplyModel { Takes = 6 })
.AddPart(new EntityRequirementModel { Id = DataType.UNIT_RedSeer, Requirement = RequirementType.Morph }) .AddPart(new EntityRequirementModel
{ Id = DataType.UNIT_RedSeer, Requirement = RequirementType.Morph })
.AddPart(new EntityVitalityModel { Health = 200, DefenseLayer = 60, Armor = ArmorType.Heavy }) .AddPart(new EntityVitalityModel { Health = 200, DefenseLayer = 60, Armor = ArmorType.Heavy })
.AddPart(new EntityMovementModel { Speed = 210, Movement = MovementType.Ground }) .AddPart(new EntityMovementModel { Speed = 210, Movement = MovementType.Ground })
.AddPart(new EntityWeaponModel .AddPart(new EntityWeaponModel
{ Damage = 125, Range = 1500, AttacksPerSecond = 0.175f, Targets = TargetType.Ground }) { Damage = 125, Range = 1500, AttacksPerSecond = 0.175f, Targets = TargetType.Ground })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_HiddenX}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_HiddenX })
}, },
// Pyre Spells // Pyre Spells
// Q'Rath // Q'Rath
@ -2696,7 +2697,7 @@ public class DATA
MediumDamage = 25, HeavyDamage = 30 MediumDamage = 25, HeavyDamage = 30
}) })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Respite }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Respite })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_HallowedGround}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_HallowedGround })
}, },
{ {
DataType.ISPELL_PillarOfHeaven, DataType.ISPELL_PillarOfHeaven,
@ -2711,7 +2712,8 @@ public class DATA
.AddPart(new EntityFactionModel { Faction = FactionType.QRath }) .AddPart(new EntityFactionModel { Faction = FactionType.QRath })
.AddPart(new EntityVanguardAddedModel { ImmortalId = DataType.IMMORTAL_Orzum }) .AddPart(new EntityVanguardAddedModel { ImmortalId = DataType.IMMORTAL_Orzum })
.AddPart(new EntityProductionModel { Pyre = 100, Cooldown = 15 }) .AddPart(new EntityProductionModel { Pyre = 100, Cooldown = 15 })
.AddPart(new EntityVitalityModel { Health = 300, DefenseLayer = 200, Armor = ArmorType.Heavy, IsStructure = true}) .AddPart(new EntityVitalityModel
{ Health = 300, DefenseLayer = 200, Armor = ArmorType.Heavy, IsStructure = true })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Zeal }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Zeal })
}, },
{ {
@ -2787,7 +2789,7 @@ public class DATA
.AddPart(new EntityWeaponModel .AddPart(new EntityWeaponModel
{ Damage = 15, Range = 800, AttacksPerSecond = 1.887f, Targets = TargetType.All }) { Damage = 15, Range = 800, AttacksPerSecond = 1.887f, Targets = TargetType.All })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Respite }) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Respite })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_Rootway}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Rootway })
}, },
{ {
DataType.ISPELL_ConstructBloodWell, DataType.ISPELL_ConstructBloodWell,
@ -2801,10 +2803,11 @@ public class DATA
.AddPart(new EntityHotkeyModel { Hotkey = "F", HotkeyGroup = "1" }) .AddPart(new EntityHotkeyModel { Hotkey = "F", HotkeyGroup = "1" })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
.AddPart(new EntityProductionModel { Pyre = 50, Cooldown = 21 }) .AddPart(new EntityProductionModel { Pyre = 50, Cooldown = 21 })
.AddPart(new EntityVitalityModel {Health = 400, Energy = 100, DefenseLayer = 50, Armor = ArmorType.Heavy, IsStructure = true}) .AddPart(new EntityVitalityModel
.AddPart(new EntityIdPassiveModel {Id = DataType.PASSIVE_RestoreLifeblood}) { Health = 400, Energy = 100, DefenseLayer = 50, Armor = ArmorType.Heavy, IsStructure = true })
.AddPart(new EntityIdPassiveModel {Id = DataType.PASSIVE_Transfusion}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_RestoreLifeblood })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_Rootway}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Transfusion })
.AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Rootway })
}, },
{ {
DataType.ISPELL_RedTithe, DataType.ISPELL_RedTithe,
@ -2835,19 +2838,26 @@ public class DATA
{ {
DataType.ISPELL_MarkPrey, DataType.ISPELL_MarkPrey,
new EntityModel(DataType.ISPELL_MarkPrey, EntityType.Pyre_Spell) new EntityModel(DataType.ISPELL_MarkPrey, EntityType.Pyre_Spell)
.AddPart(new EntityInfoModel { Name = "Mark Prey", .AddPart(new EntityInfoModel
Description = @"Enemy units in the target area are <b>Revealed</b> through fog of war. Units still in the area after a short delay are marked for 10 seconds to take bonus damage and provide Pyre when killed.", {
Name = "Mark Prey",
Description =
@"Enemy units in the target area are <b>Revealed</b> through fog of war. Units still in the area after a short delay are marked for 10 seconds to take bonus damage and provide Pyre when killed.",
Notes = "+3 pyre for kills" Notes = "+3 pyre for kills"
}) })
.AddPart(new EntityHotkeyModel { Hotkey = "E", HotkeyGroup = "1" }) .AddPart(new EntityHotkeyModel { Hotkey = "E", HotkeyGroup = "1" })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
.AddPart(new EntityVanguardAddedModel { ImmortalId = DataType.IMMORTAL_Xol }) .AddPart(new EntityVanguardAddedModel { ImmortalId = DataType.IMMORTAL_Xol })
.AddPart(new EntityProductionModel { Cooldown = 15, Pyre = 25}) .AddPart(new EntityProductionModel { Cooldown = 15, Pyre = 25 })
}, },
{ {
DataType.ISPELL_TheGreatHunt, DataType.ISPELL_TheGreatHunt,
new EntityModel(DataType.ISPELL_TheGreatHunt, EntityType.Pyre_Spell) new EntityModel(DataType.ISPELL_TheGreatHunt, EntityType.Pyre_Spell)
.AddPart(new EntityInfoModel { Name = "The Great Hunt", Description = "Enemy unit and structures have their vision reduce to 3 for a short time."}) .AddPart(new EntityInfoModel
{
Name = "The Great Hunt",
Description = "Enemy unit and structures have their vision reduce to 3 for a short time."
})
.AddPart(new EntityHotkeyModel { Hotkey = "R", HotkeyGroup = "1" }) .AddPart(new EntityHotkeyModel { Hotkey = "R", HotkeyGroup = "1" })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
.AddPart(new EntityVanguardAddedModel { ImmortalId = DataType.IMMORTAL_Xol }) .AddPart(new EntityVanguardAddedModel { ImmortalId = DataType.IMMORTAL_Xol })
@ -2875,7 +2885,7 @@ public class DATA
HarvestedPerInterval = 1, RequiresWorker = true, Resource = ResourceType.Alloy, Slots = 2, HarvestedPerInterval = 1, RequiresWorker = true, Resource = ResourceType.Alloy, Slots = 2,
TotalAmount = 3600 TotalAmount = 3600
}) })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_HallowedGround}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_HallowedGround })
}, },
{ {
DataType.BUPGRADE_MiningLevel2_QRath, DataType.BUPGRADE_MiningLevel2_QRath,
@ -2954,7 +2964,7 @@ public class DATA
.AddPart(new EntityProductionModel { Alloy = 250, BuildTime = 38, RequiresWorker = true }) .AddPart(new EntityProductionModel { Alloy = 250, BuildTime = 38, RequiresWorker = true })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Health = 500, DefenseLayer = 500, Armor = ArmorType.Heavy, IsStructure = true }) { Health = 500, DefenseLayer = 500, Armor = ArmorType.Heavy, IsStructure = true })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_HallowedGround}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_HallowedGround })
}, },
{ {
DataType.DEFENSE_FireSinger, DataType.DEFENSE_FireSinger,
@ -3032,7 +3042,7 @@ public class DATA
}) })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Health = 450, DefenseLayer = 450, Armor = ArmorType.Heavy, IsStructure = true }) { Health = 450, DefenseLayer = 450, Armor = ArmorType.Heavy, IsStructure = true })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_HallowedGround}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_HallowedGround })
}, },
{ {
DataType.BUILDING_HouseOfFadingSaints, DataType.BUILDING_HouseOfFadingSaints,
@ -3074,7 +3084,7 @@ public class DATA
}) })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Health = 600, DefenseLayer = 600, Armor = ArmorType.Heavy, IsStructure = true }) { Health = 600, DefenseLayer = 600, Armor = ArmorType.Heavy, IsStructure = true })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_HallowedGround}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_HallowedGround })
}, },
{ {
DataType.BUILDING_EyeOfAros, DataType.BUILDING_EyeOfAros,
@ -3139,7 +3149,7 @@ public class DATA
HarvestedPerInterval = 1, RequiresWorker = true, Resource = ResourceType.Alloy, Slots = 2, HarvestedPerInterval = 1, RequiresWorker = true, Resource = ResourceType.Alloy, Slots = 2,
TotalAmount = 3600 TotalAmount = 3600
}) })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_Rootway}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Rootway })
}, },
{ {
DataType.BUPGRADE_GodHeart, DataType.BUPGRADE_GodHeart,
@ -3161,7 +3171,7 @@ public class DATA
}) })
.AddPart(new EntityProductionModel .AddPart(new EntityProductionModel
{ Alloy = 100, Ether = 75, BuildTime = 36, RequiresWorker = false }) { Alloy = 100, Ether = 75, BuildTime = 36, RequiresWorker = false })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_Rootway}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Rootway })
}, },
{ {
DataType.BUPGRADE_MiningLevel2_Aru, DataType.BUPGRADE_MiningLevel2_Aru,
@ -3240,7 +3250,7 @@ public class DATA
.AddPart(new EntityProductionModel { Alloy = 250, BuildTime = 36, RequiresWorker = true }) .AddPart(new EntityProductionModel { Alloy = 250, BuildTime = 36, RequiresWorker = true })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Health = 900, DefenseLayer = 100, Armor = ArmorType.Heavy, IsStructure = true }) { Health = 900, DefenseLayer = 100, Armor = ArmorType.Heavy, IsStructure = true })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_Rootway}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Rootway })
}, },
{ {
DataType.BUILDING_Neurocyte, DataType.BUILDING_Neurocyte,
@ -3282,9 +3292,11 @@ public class DATA
.AddPart(new EntityInfoModel { Name = "Omnivore", Descriptive = DescriptiveType.Upgrade }) .AddPart(new EntityInfoModel { Name = "Omnivore", Descriptive = DescriptiveType.Upgrade })
.AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "SHIFT" }) .AddPart(new EntityHotkeyModel { Hotkey = "Q", HotkeyGroup = "SHIFT" })
.AddPart(new EntityFactionModel { Faction = FactionType.Aru }) .AddPart(new EntityFactionModel { Faction = FactionType.Aru })
.AddPart(new EntityRequirementModel { .AddPart(new EntityRequirementModel
{
Id = DataType.DEFENSE_Aerovore, Id = DataType.DEFENSE_Aerovore,
Requirement = RequirementType.Morph }) Requirement = RequirementType.Morph
})
.AddPart(new EntityProductionModel { Alloy = 50, BuildTime = 18, RequiresWorker = false }) .AddPart(new EntityProductionModel { Alloy = 50, BuildTime = 18, RequiresWorker = false })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Health = 400, DefenseLayer = 50, Armor = ArmorType.Heavy, IsStructure = true }) { Health = 400, DefenseLayer = 50, Armor = ArmorType.Heavy, IsStructure = true })
@ -3314,7 +3326,7 @@ public class DATA
}) })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Health = 1000, DefenseLayer = 250, Armor = ArmorType.Heavy, IsStructure = true }) { Health = 1000, DefenseLayer = 250, Armor = ArmorType.Heavy, IsStructure = true })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_Rootway}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Rootway })
}, },
{ {
DataType.BUILDING_BoneCanopy, DataType.BUILDING_BoneCanopy,
@ -3336,7 +3348,7 @@ public class DATA
}) })
.AddPart(new EntityVitalityModel .AddPart(new EntityVitalityModel
{ Health = 1000, DefenseLayer = 300, Armor = ArmorType.Heavy, IsStructure = true }) { Health = 1000, DefenseLayer = 300, Armor = ArmorType.Heavy, IsStructure = true })
.AddPart(new EntityIdPassiveModel(){Id = DataType.PASSIVE_Rootway}) .AddPart(new EntityIdPassiveModel { Id = DataType.PASSIVE_Rootway })
}, },
{ {
DataType.BUILDING_RedVale, DataType.BUILDING_RedVale,

12
Model/Entity/EntityModel.cs

@ -14,13 +14,13 @@ public class EntityModel
{ {
public static readonly string GameVersion = "0.0.6.9121a"; public static readonly string GameVersion = "0.0.6.9121a";
private static Dictionary<string, EntityModel> _database= null!; private static Dictionary<string, EntityModel> _database = null!;
private static List<EntityModel> _entityModels= null!; private static List<EntityModel> _entityModels = null!;
private static List<EntityModel> _entityModelsOnlyHotkey = null!; private static List<EntityModel> _entityModelsOnlyHotkey = null!;
private static Dictionary<string, List<EntityModel>>? _entityModelsByHotkey= null!; private static Dictionary<string, List<EntityModel>>? _entityModelsByHotkey;
public EntityModel(string data, string entity, bool isSpeculative = false) public EntityModel(string data, string entity, bool isSpeculative = false)
@ -224,19 +224,19 @@ public class EntityModel
public EntityHotkeyModel Hotkey() public EntityHotkeyModel Hotkey()
{ {
return ((EntityHotkeyModel)EntityParts.Find(x => x.GetType() == typeof(EntityHotkeyModel))!); return (EntityHotkeyModel)EntityParts.Find(x => x.GetType() == typeof(EntityHotkeyModel))!;
} }
public EntityFactionModel Faction() public EntityFactionModel Faction()
{ {
return ((EntityFactionModel)EntityParts.Find(x => x.GetType() == typeof(EntityFactionModel))!); return (EntityFactionModel)EntityParts.Find(x => x.GetType() == typeof(EntityFactionModel))!;
} }
public EntityHarvestModel Harvest() public EntityHarvestModel Harvest()
{ {
return ((EntityHarvestModel)EntityParts.Find(x => x.GetType() == typeof(EntityHarvestModel))!); return (EntityHarvestModel)EntityParts.Find(x => x.GetType() == typeof(EntityHarvestModel))!;
} }

4
Model/Git/GitChangeModel.cs

@ -1,6 +1,4 @@
using System; namespace Model.Git;
namespace Model.Git;
public class GitChangeModel public class GitChangeModel
{ {

12
Model/Model.csproj

@ -5,14 +5,14 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Remove="_PaperWork\**" /> <Compile Remove="_PaperWork\**"/>
<EmbeddedResource Remove="_PaperWork\**" /> <EmbeddedResource Remove="_PaperWork\**"/>
<None Remove="_PaperWork\**" /> <None Remove="_PaperWork\**"/>
<None Remove="Immortal\MemoryTester\" /> <None Remove="Immortal\MemoryTester\"/>
</ItemGroup> </ItemGroup>
<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>

7
Model/Notes/NoteContentModel.cs

@ -1,7 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations.Schema;
using Model.Doc;
namespace Model.Notes; namespace Model.Notes;
@ -12,6 +11,7 @@ public class NoteContentModel
public int? ParentId { get; set; } = null; public int? ParentId { get; set; } = null;
public int? NoteSectionModelId { get; set; } = null; public int? NoteSectionModelId { get; set; } = null;
public string Href { get; set; } public string Href { get; set; }
//public DateTime LastUpdated { get; set; } //public DateTime LastUpdated { get; set; }
@ -25,7 +25,9 @@ public class NoteContentModel
public string IsHidden { get; set; } = "False"; public string IsHidden { get; set; } = "False";
public string IsPreAlpha { get; set; } = "True"; public string IsPreAlpha { get; set; } = "True";
[NotMapped] public virtual ICollection<NoteContentModel> NoteContentModels { get; set; } = new List<NoteContentModel>(); [NotMapped]
public virtual ICollection<NoteContentModel> NoteContentModels { get; set; } = new List<NoteContentModel>();
[NotMapped] public virtual NoteContentModel Parent { get; set; } [NotMapped] public virtual NoteContentModel Parent { get; set; }
[NotMapped] public virtual int PageOrder { get; set; } [NotMapped] public virtual int PageOrder { get; set; }
@ -43,5 +45,4 @@ public class NoteContentModel
{ {
return $"notes/{GetLink()}"; return $"notes/{GetLink()}";
} }
} }

2
Model/Website/WebSectionModel.cs

@ -12,5 +12,5 @@ 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";
[NotMapped] public List<WebPageModel> WebPageModels { get; set; } = new List<WebPageModel>(); [NotMapped] public List<WebPageModel> WebPageModels { get; set; } = new();
} }

11
Services/Development/DocumentationService.cs

@ -22,7 +22,6 @@ public class DocumentationService : IDocumentationService
public List<DocConnectionModel> DocConnectionModels { get; set; } = new(); public List<DocConnectionModel> DocConnectionModels { get; set; } = new();
public void Subscribe(Action? action) public void Subscribe(Action? action)
{ {
OnChange += action; OnChange += action;
@ -88,18 +87,10 @@ public class DocumentationService : IDocumentationService
} }
foreach (var content in DocContentModels) foreach (var content in DocContentModels)
{
if (content.DocSectionModelId != null) if (content.DocSectionModelId != null)
{
foreach (var section in DocSectionModels) foreach (var section in DocSectionModels)
{
if (section.Id == content.DocSectionModelId) if (section.Id == content.DocSectionModelId)
{
section.DocumentationModels.Add(content); section.DocumentationModels.Add(content);
}
}
}
}
ByPageOrder(); ByPageOrder();
} }
@ -109,7 +100,7 @@ public class DocumentationService : IDocumentationService
{ {
DocContentModelsByPageOrder = new List<DocContentModel>(); DocContentModelsByPageOrder = new List<DocContentModel>();
int order = 1; var order = 1;
foreach (var documentation in DocContentModels) foreach (var documentation in DocContentModels)
{ {
if (documentation.Parent != null) continue; if (documentation.Parent != null) continue;

37
Services/Development/GitService.cs

@ -10,7 +10,8 @@ using Microsoft.EntityFrameworkCore;
namespace Services.Development; namespace Services.Development;
public class GitService : IGitService { public class GitService : IGitService
{
private readonly HttpClient httpClient; private readonly HttpClient httpClient;
private bool isLoaded; private bool isLoaded;
@ -18,7 +19,8 @@ public class GitService : IGitService {
private event Action OnChange = default!; private event Action OnChange = default!;
public GitService(HttpClient httpClient) { public GitService(HttpClient httpClient)
{
this.httpClient = httpClient; this.httpClient = httpClient;
} }
@ -32,30 +34,32 @@ public class GitService : IGitService {
#endif #endif
public void Subscribe(Action action)
public void Subscribe(Action action) { {
OnChange += action; OnChange += action;
} }
public void Unsubscribe(Action action) { public void Unsubscribe(Action action)
{
OnChange -= action; OnChange -= action;
} }
public bool IsLoaded() { public bool IsLoaded()
{
return isLoaded; return isLoaded;
} }
#if NO_SQL #if NO_SQL
public async Task Load() { public async Task Load()
{
if (isLoaded) { if (isLoaded) return;
return;
}
GitChangeModels = (await httpClient.GetFromJsonAsync<GitChangeModel[]>("generated/GitChangeModels.json") ?? Array.Empty<GitChangeModel>()).ToList(); GitChangeModels = (await httpClient.GetFromJsonAsync<GitChangeModel[]>("generated/GitChangeModels.json") ??
GitPatchModels = (await httpClient.GetFromJsonAsync<GitPatchModel[]>("generated/GitPatchModels.json") ?? Array.Empty<GitPatchModel>()).ToList(); Array.Empty<GitChangeModel>()).ToList();
GitPatchModels = (await httpClient.GetFromJsonAsync<GitPatchModel[]>("generated/GitPatchModels.json") ??
Array.Empty<GitPatchModel>()).ToList();
isLoaded = true; isLoaded = true;
@ -64,7 +68,6 @@ public class GitService : IGitService {
} }
#else #else
public async Task Load(DatabaseContext database) { public async Task Load(DatabaseContext database) {
Database = database; Database = database;
@ -85,11 +88,13 @@ public class GitService : IGitService {
#endif #endif
public void Update() { public void Update()
{
NotifyDataChanged(); NotifyDataChanged();
} }
private void NotifyDataChanged() { private void NotifyDataChanged()
{
OnChange?.Invoke(); OnChange?.Invoke();
} }
} }

77
Services/Development/NoteService.cs

@ -10,49 +10,52 @@ using Microsoft.EntityFrameworkCore;
namespace Services.Development; namespace Services.Development;
public class NoteService : INoteService { public class NoteService : INoteService
{
private readonly HttpClient httpClient; private readonly HttpClient httpClient;
private bool isLoaded; private bool isLoaded;
public NoteService(HttpClient httpClient)
private event Action OnChange = default!; {
private void NotifyDataChanged() {
OnChange?.Invoke();
}
public NoteService(HttpClient httpClient) {
this.httpClient = httpClient; this.httpClient = httpClient;
} }
public List<NoteContentModel> NoteContentModelsByPageOrder { get; set; } = new();
public List<NoteContentModel> NoteContentModels { get; set; } = default!; public List<NoteContentModel> NoteContentModels { get; set; } = default!;
public List<NoteConnectionModel> NoteConnectionModels { get; set; } = null!; public List<NoteConnectionModel> NoteConnectionModels { get; set; } = null!;
public List<NoteSectionModel> NoteSectionModels { get; set; } = null!; public List<NoteSectionModel> NoteSectionModels { get; set; } = null!;
public List<NoteContentModel> NoteContentModelsByPageOrder { get; set; } = new();
public void Subscribe(Action action) { public void Subscribe(Action action)
{
OnChange += action; OnChange += action;
} }
public void Unsubscribe(Action action) { public void Unsubscribe(Action action)
{
OnChange -= action; OnChange -= action;
} }
public bool IsLoaded() { public bool IsLoaded()
{
return isLoaded; return isLoaded;
} }
public async Task Load() { public async Task Load()
if (isLoaded) { {
return; if (isLoaded) return;
}
NoteContentModels =
NoteContentModels = (await httpClient.GetFromJsonAsync<NoteContentModel[]>("generated/NoteContentModels.json") ?? Array.Empty<NoteContentModel>()).ToList(); (await httpClient.GetFromJsonAsync<NoteContentModel[]>("generated/NoteContentModels.json") ??
NoteConnectionModels = (await httpClient.GetFromJsonAsync<NoteConnectionModel[]>("generated/NoteConnectionModels.json") ?? Array.Empty<NoteConnectionModel>()).ToList(); Array.Empty<NoteContentModel>()).ToList();
NoteSectionModels = (await httpClient.GetFromJsonAsync<NoteSectionModel[]>("generated/NoteSectionModels.json") ?? Array.Empty<NoteSectionModel>()).ToList(); NoteConnectionModels =
(await httpClient.GetFromJsonAsync<NoteConnectionModel[]>("generated/NoteConnectionModels.json") ??
Array.Empty<NoteConnectionModel>()).ToList();
NoteSectionModels =
(await httpClient.GetFromJsonAsync<NoteSectionModel[]>("generated/NoteSectionModels.json") ??
Array.Empty<NoteSectionModel>()).ToList();
isLoaded = true; isLoaded = true;
@ -61,6 +64,19 @@ public class NoteService : INoteService {
NotifyDataChanged(); NotifyDataChanged();
} }
public void Update()
{
NotifyDataChanged();
}
private event Action OnChange = default!;
private void NotifyDataChanged()
{
OnChange?.Invoke();
}
private NoteContentModel? ContentById(int id) private NoteContentModel? ContentById(int id)
{ {
foreach (var data in NoteContentModels!) foreach (var data in NoteContentModels!)
@ -79,18 +95,10 @@ public class NoteService : INoteService {
} }
foreach (var content in NoteContentModels) foreach (var content in NoteContentModels)
{
if (content.NoteSectionModelId != null) if (content.NoteSectionModelId != null)
{
foreach (var section in NoteSectionModels) foreach (var section in NoteSectionModels)
{
if (section.Id == content.NoteSectionModelId) if (section.Id == content.NoteSectionModelId)
{
section.NoteContentModels.Add(content); section.NoteContentModels.Add(content);
}
}
}
}
ByPageOrder(); ByPageOrder();
} }
@ -99,7 +107,7 @@ public class NoteService : INoteService {
{ {
NoteContentModelsByPageOrder = new List<NoteContentModel>(); NoteContentModelsByPageOrder = new List<NoteContentModel>();
int order = 1; var order = 1;
foreach (var note in NoteContentModels) foreach (var note in NoteContentModels)
{ {
if (note.Parent != null) continue; if (note.Parent != null) continue;
@ -121,10 +129,7 @@ public class NoteService : INoteService {
GetAllChildren(note); GetAllChildren(note);
} }
NoteContentModelsByPageOrder = NoteContentModelsByPageOrder.OrderBy(noteContent => noteContent.PageOrder).ToList(); NoteContentModelsByPageOrder =
} NoteContentModelsByPageOrder.OrderBy(noteContent => noteContent.PageOrder).ToList();
public void Update() {
NotifyDataChanged();
} }
} }

60
Services/IServices.cs

@ -1,20 +1,18 @@
 using Model.BuildOrders;
using Model.Doc; using Model.Doc;
using Model.BuildOrders;
using Model.Economy; using Model.Economy;
using Model.Entity; using Model.Entity;
using Model.Feedback;
using Model.Git;
using Model.MemoryTester; using Model.MemoryTester;
using Model.Notes; using Model.Notes;
using Model.Website; using Model.Website;
using Model.Website.Enums; using Model.Website.Enums;
using Model.Git;
using Model.Feedback;
using Model.Work.Tasks; using Model.Work.Tasks;
using Services.Immortal; using Services.Immortal;
namespace Services; namespace Services;
public interface IToastService public interface IToastService
{ {
public void Subscribe(Action action); public void Subscribe(Action action);
@ -27,7 +25,6 @@ public interface IToastService
void ClearAllToasts(); void ClearAllToasts();
} }
public interface IEntityDialogService public interface IEntityDialogService
{ {
public void Subscribe(Action action); public void Subscribe(Action action);
@ -44,7 +41,8 @@ public interface IEntityDialogService
public bool HasHistory(); public bool HasHistory();
} }
public interface IWebsiteService { public interface IWebsiteService
{
public List<WebPageModel> WebPageModels { get; set; } public List<WebPageModel> WebPageModels { get; set; }
public List<WebSectionModel> WebSectionModels { get; set; } public List<WebSectionModel> WebSectionModels { get; set; }
@ -58,8 +56,8 @@ public interface IWebsiteService {
public bool IsLoaded(); public bool IsLoaded();
} }
public interface IAgileService { public interface IAgileService
{
#if NO_SQL #if NO_SQL
public List<AgileSprintModel>? AgileSprintModels { get; set; } public List<AgileSprintModel>? AgileSprintModels { get; set; }
public List<AgileTaskModel>? AgileTaskModels { get; set; } public List<AgileTaskModel>? AgileTaskModels { get; set; }
@ -76,7 +74,8 @@ public interface IAgileService {
public bool IsLoaded(); public bool IsLoaded();
} }
public interface INoteService { public interface INoteService
{
public List<NoteContentModel> NoteContentModels { get; set; } public List<NoteContentModel> NoteContentModels { get; set; }
public List<NoteConnectionModel> NoteConnectionModels { get; set; } public List<NoteConnectionModel> NoteConnectionModels { get; set; }
public List<NoteSectionModel> NoteSectionModels { get; set; } public List<NoteSectionModel> NoteSectionModels { get; set; }
@ -101,9 +100,8 @@ public interface IDocumentationService
public bool IsLoaded(); public bool IsLoaded();
} }
public interface IGitService
public interface IGitService { {
#if NO_SQL #if NO_SQL
public List<GitChangeModel> GitChangeModels { get; set; } public List<GitChangeModel> GitChangeModels { get; set; }
public List<GitPatchModel> GitPatchModels { get; set; } public List<GitPatchModel> GitPatchModels { get; set; }
@ -124,7 +122,8 @@ public interface IGitService {
public bool IsLoaded(); public bool IsLoaded();
} }
public interface INavigationService { public interface INavigationService
{
public void Subscribe(Action action); public void Subscribe(Action action);
public void Unsubscribe(Action action); public void Unsubscribe(Action action);
@ -143,7 +142,8 @@ public interface INavigationService {
public Type GetRenderType(); public Type GetRenderType();
} }
public interface IBuildComparisonService { public interface IBuildComparisonService
{
public void SetBuilds(BuildComparisonModel buildComparisonModel); public void SetBuilds(BuildComparisonModel buildComparisonModel);
public BuildComparisonModel Get(); public BuildComparisonModel Get();
public string BuildOrderAsYaml(); public string BuildOrderAsYaml();
@ -153,14 +153,16 @@ public interface IBuildComparisonService {
public void Unsubscribe(Action action); public void Unsubscribe(Action action);
} }
public interface ITimingService { public interface ITimingService
{
public int GetTiming(); public int GetTiming();
public void SetTiming(int timing); public void SetTiming(int timing);
public void Subscribe(Action? action); public void Subscribe(Action? action);
public void Unsubscribe(Action? action); public void Unsubscribe(Action? action);
} }
public interface IEconomyService { public interface IEconomyService
{
public List<EconomyModel> GetOverTime(); public List<EconomyModel> GetOverTime();
public EconomyModel GetEconomy(int atInterval); public EconomyModel GetEconomy(int atInterval);
public void Calculate(IBuildOrderService buildOrder, ITimingService timing, int fromInterval); public void Calculate(IBuildOrderService buildOrder, ITimingService timing, int fromInterval);
@ -168,7 +170,8 @@ public interface IEconomyService {
public void Unsubscribe(Action action); public void Unsubscribe(Action action);
} }
public interface IEntityFilterService { public interface IEntityFilterService
{
public delegate void EntityFilterAction(EntityFilterEvent entityFilterEvent); public delegate void EntityFilterAction(EntityFilterEvent entityFilterEvent);
public string GetFactionType(); public string GetFactionType();
@ -191,13 +194,11 @@ public interface IEntityFilterService {
public void Unsubscribe(EntityFilterAction action); public void Unsubscribe(EntityFilterAction action);
} }
public interface IEntityService
public interface IEntityService { {
public List<EntityModel> GetEntities(); public List<EntityModel> GetEntities();
} }
public interface IEntityDisplayService public interface IEntityDisplayService
{ {
public List<string> DefaultChoices(); public List<string> DefaultChoices();
@ -208,7 +209,8 @@ public interface IEntityDisplayService
public void Unsubscribe(Action action); public void Unsubscribe(Action action);
} }
public interface IImmortalSelectionService { public interface IImmortalSelectionService
{
public string GetFactionType(); public string GetFactionType();
public string GetImmortalType(); public string GetImmortalType();
public bool SelectFactionType(string factionType); public bool SelectFactionType(string factionType);
@ -217,7 +219,8 @@ public interface IImmortalSelectionService {
public void Unsubscribe(Action action); public void Unsubscribe(Action action);
} }
public interface IKeyService { public interface IKeyService
{
public List<string> GetAllPressedKeys(); public List<string> GetAllPressedKeys();
public string? GetHotkey(); public string? GetHotkey();
public string GetHotkeyGroup(); public string GetHotkeyGroup();
@ -228,7 +231,8 @@ public interface IKeyService {
public void Unsubscribe(Action? action); public void Unsubscribe(Action? action);
} }
public interface IMemoryTesterService { public interface IMemoryTesterService
{
public delegate void MemoryAction(MemoryTesterEvent memoryEvent); public delegate void MemoryAction(MemoryTesterEvent memoryEvent);
public List<MemoryEntityModel> GetEntities(); public List<MemoryEntityModel> GetEntities();
@ -244,8 +248,9 @@ public interface IMemoryTesterService {
public void Unsubscribe(MemoryAction memoryAction); public void Unsubscribe(MemoryAction memoryAction);
} }
public interface IBuildOrderService { public interface IBuildOrderService
{
public int BuildingInputDelay { get; set; }
public Dictionary<int, List<EntityModel>> StartedOrders { get; } public Dictionary<int, List<EntityModel>> StartedOrders { get; }
public Dictionary<int, List<EntityModel>> CompletedOrders { get; } public Dictionary<int, List<EntityModel>> CompletedOrders { get; }
public Dictionary<string, int> UniqueCompletedTimes { get; } public Dictionary<string, int> UniqueCompletedTimes { get; }
@ -272,6 +277,7 @@ public interface IBuildOrderService {
public List<EntityModel> GetHarvestersCompletedBefore(int interval); public List<EntityModel> GetHarvestersCompletedBefore(int interval);
public void RemoveLast(); public void RemoveLast();
public void Reset();
public int GetLastRequestInterval(); public int GetLastRequestInterval();
public string BuildOrderAsYaml(); public string BuildOrderAsYaml();

53
Services/Immortal/BuildComparisionService.cs

@ -3,48 +3,51 @@ using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using Model.BuildOrders; using Model.BuildOrders;
using Model.Entity; using Model.Entity;
using Model.Entity.Data;
using YamlDotNet.Serialization; using YamlDotNet.Serialization;
namespace Services.Immortal; namespace Services.Immortal;
public class BuildComparisionService : IBuildComparisonService { public class BuildComparisionService : IBuildComparisonService
private event Action OnChange = default!; {
private BuildComparisonModel buildComparison = new(); private BuildComparisonModel buildComparison = new();
public void Subscribe(Action action) { public void Subscribe(Action action)
{
OnChange += action; OnChange += action;
} }
public void Unsubscribe(Action action) { public void Unsubscribe(Action action)
{
OnChange -= action; OnChange -= action;
} }
private void NotifyDataChanged() { public void SetBuilds(BuildComparisonModel buildComparisonModel)
OnChange?.Invoke(); {
}
public void SetBuilds(BuildComparisonModel buildComparisonModel) {
buildComparison = buildComparisonModel; buildComparison = buildComparisonModel;
NotifyDataChanged(); NotifyDataChanged();
} }
public BuildComparisonModel Get() { public BuildComparisonModel Get()
{
return buildComparison; return buildComparison;
} }
public string AsJson() { public string AsJson()
var options = new JsonSerializerOptions { {
var options = new JsonSerializerOptions
{
WriteIndented = true WriteIndented = true
}; };
options.Converters.Add(new JsonStringEnumConverter()); options.Converters.Add(new JsonStringEnumConverter());
return JsonSerializer.Serialize(buildComparison, options); return JsonSerializer.Serialize(buildComparison, options);
} }
public bool LoadJson(string data) { public bool LoadJson(string data)
try { {
var options = new JsonSerializerOptions { try
{
var options = new JsonSerializerOptions
{
WriteIndented = true WriteIndented = true
}; };
options.Converters.Add(new JsonStringEnumConverter()); options.Converters.Add(new JsonStringEnumConverter());
@ -56,12 +59,14 @@ public class BuildComparisionService : IBuildComparisonService {
NotifyDataChanged(); NotifyDataChanged();
return true; return true;
} }
catch { catch
{
return false; return false;
} }
} }
public string BuildOrderAsYaml() { public string BuildOrderAsYaml()
{
var stringBuilder = new StringBuilder(); var stringBuilder = new StringBuilder();
var serializer = new Serializer(); var serializer = new Serializer();
stringBuilder.AppendLine(serializer.Serialize(buildComparison)); stringBuilder.AppendLine(serializer.Serialize(buildComparison));
@ -69,8 +74,16 @@ public class BuildComparisionService : IBuildComparisonService {
return buildOrderText; return buildOrderText;
} }
private event Action OnChange = default!;
private void NotifyDataChanged()
{
OnChange?.Invoke();
}
public void HydratedLoadedJson() { public void HydratedLoadedJson()
{
foreach (var build in buildComparison.Builds) foreach (var build in buildComparison.Builds)
foreach (var orders in build.StartedOrders.Values) foreach (var orders in build.StartedOrders.Values)
foreach (var order in orders) foreach (var order in orders)

81
Services/Immortal/BuildOrderService.cs

@ -12,11 +12,14 @@ namespace Services.Immortal;
public class BuildOrderService : IBuildOrderService public class BuildOrderService : IBuildOrderService
{ {
private readonly BuildOrderModel buildOrder = new(); private BuildOrderModel buildOrder = new();
private readonly int HumanMicro = 2; public int BuildingInputDelay { get; set; } = 2;
private int lastInterval; private int lastInterval = 0;
private event Action OnChange = null!; public BuildOrderService()
{
Reset();
}
public Dictionary<int, List<EntityModel>> StartedOrders => buildOrder.StartedOrders; public Dictionary<int, List<EntityModel>> StartedOrders => buildOrder.StartedOrders;
public Dictionary<int, List<EntityModel>> CompletedOrders => buildOrder.CompletedOrders; public Dictionary<int, List<EntityModel>> CompletedOrders => buildOrder.CompletedOrders;
@ -92,7 +95,6 @@ public class BuildOrderService : IBuildOrderService
var metTime = 0; var metTime = 0;
foreach (var requiredEntity in requirements) foreach (var requiredEntity in requirements)
{
if (buildOrder.UniqueCompletedTimes.TryGetValue(requiredEntity.Id, out var completedTime)) if (buildOrder.UniqueCompletedTimes.TryGetValue(requiredEntity.Id, out var completedTime))
{ {
if (completedTime > metTime) metTime = completedTime; if (completedTime > metTime) metTime = completedTime;
@ -101,7 +103,6 @@ public class BuildOrderService : IBuildOrderService
{ {
return null; return null;
} }
}
return metTime; return metTime;
} }
@ -135,7 +136,6 @@ public class BuildOrderService : IBuildOrderService
public void RemoveLast() public void RemoveLast()
{ {
if (buildOrder.StartedOrders.Keys.Count > 1) if (buildOrder.StartedOrders.Keys.Count > 1)
{ {
var lastStarted = buildOrder.StartedOrders.Keys.Last(); var lastStarted = buildOrder.StartedOrders.Keys.Last();
@ -166,9 +166,8 @@ public class BuildOrderService : IBuildOrderService
buildOrder.UniqueCompletedCount[entityRemoved!.DataType]--; buildOrder.UniqueCompletedCount[entityRemoved!.DataType]--;
if (buildOrder.UniqueCompletedCount[entityRemoved!.DataType] == 0) { if (buildOrder.UniqueCompletedCount[entityRemoved!.DataType] == 0)
UniqueCompletedTimes.Remove(entityRemoved.DataType); UniqueCompletedTimes.Remove(entityRemoved.DataType);
}
if (entityRemoved.Info().Descriptive == DescriptiveType.Worker) if (entityRemoved.Info().Descriptive == DescriptiveType.Worker)
{ {
@ -252,6 +251,65 @@ public class BuildOrderService : IBuildOrderService
return buildOrder.Color; return buildOrder.Color;
} }
public void Reset()
{
lastInterval = 0;
buildOrder = new BuildOrderModel
{
StartedOrders = new Dictionary<int, List<EntityModel>>
{
{
0,
new List<EntityModel>
{
EntityModel.Get(DataType.STARTING_Bastion),
EntityModel.Get(DataType.STARTING_TownHall_Aru)
}
}
},
CompletedOrders = new Dictionary<int, List<EntityModel>>
{
{
0,
new List<EntityModel>
{
EntityModel.Get(DataType.STARTING_Bastion),
EntityModel.Get(DataType.STARTING_TownHall_Aru)
}
}
},
UniqueCompletedTimes = new Dictionary<string, int>
{
{
DataType.STARTING_Bastion, 0
},
{
DataType.STARTING_TownHall_Aru, 0
}
},
UniqueCompletedCount = new Dictionary<string, int>
{
{
DataType.STARTING_Bastion, 1
},
{
DataType.STARTING_TownHall_Aru, 1
}
},
SupplyCountTimes = new Dictionary<int, int>
{
{
0, 0
}
}
};
NotifyDataChanged();
}
private event Action OnChange = null!;
private bool HandleEconomy(EntityModel entity, IEconomyService withEconomy, IToastService withToasts, private bool HandleEconomy(EntityModel entity, IEconomyService withEconomy, IToastService withToasts,
ref int atInterval) ref int atInterval)
{ {
@ -267,10 +325,7 @@ public class BuildOrderService : IBuildOrderService
{ {
atInterval = interval; atInterval = interval;
if (entity.EntityType != EntityType.Army) if (entity.EntityType != EntityType.Army) atInterval += BuildingInputDelay;
{
atInterval += HumanMicro;
}
return true; return true;

47
Services/Immortal/EconomyService.cs

@ -1,43 +1,47 @@
using Model.Economy; using Model.Economy;
using Model.Entity; using Model.Entity;
using Model.Feedback;
using Model.Types; using Model.Types;
using Services.Website;
namespace Services.Immortal; namespace Services.Immortal;
public class EconomyService : IEconomyService { public class EconomyService : IEconomyService
{
private List<EconomyModel> _economyOverTime = null!; private List<EconomyModel> _economyOverTime = null!;
private event Action OnChange = null!; public List<EconomyModel> GetOverTime()
{
public List<EconomyModel> GetOverTime() {
return _economyOverTime; return _economyOverTime;
} }
public void Subscribe(Action action) { public void Subscribe(Action action)
{
OnChange += action; OnChange += action;
} }
public void Unsubscribe(Action action) { public void Unsubscribe(Action action)
{
OnChange -= action; OnChange -= action;
} }
public void Calculate(IBuildOrderService buildOrder, ITimingService timing, int fromInterval) { public void Calculate(IBuildOrderService buildOrder, ITimingService timing, int fromInterval)
{
//TODO Break all this up //TODO Break all this up
if (_economyOverTime == null) { if (_economyOverTime == null)
{
_economyOverTime = new List<EconomyModel>(); _economyOverTime = new List<EconomyModel>();
for (var interval = 0; interval < timing.GetTiming(); interval++) for (var interval = 0; interval < timing.GetTiming(); interval++)
_economyOverTime.Add(new EconomyModel { Interval = interval }); _economyOverTime.Add(new EconomyModel { Interval = interval });
} }
if (_economyOverTime.Count > timing.GetTiming()) if (_economyOverTime.Count > timing.GetTiming())
_economyOverTime.RemoveRange(timing.GetTiming(), _economyOverTime.Count - timing.GetTiming()); _economyOverTime.RemoveRange(timing.GetTiming(), _economyOverTime.Count - timing.GetTiming());
while (_economyOverTime.Count < timing.GetTiming()) _economyOverTime.Add(new EconomyModel { Interval = _economyOverTime.Count - 1 }); while (_economyOverTime.Count < timing.GetTiming())
_economyOverTime.Add(new EconomyModel { Interval = _economyOverTime.Count - 1 });
for (var interval = fromInterval; interval < timing.GetTiming(); interval++) for (var interval = fromInterval; interval < timing.GetTiming(); interval++)
{ {
@ -119,8 +123,6 @@ public class EconomyService : IEconomyService {
// Remove Funds from Build Order // Remove Funds from Build Order
if (buildOrder.StartedOrders.TryGetValue(interval, out var ordersAtTime)) if (buildOrder.StartedOrders.TryGetValue(interval, out var ordersAtTime))
{
foreach (var order in ordersAtTime) foreach (var order in ordersAtTime)
{ {
var foundEntity = EntityModel.GetDictionary()[order.DataType]; var foundEntity = EntityModel.GetDictionary()[order.DataType];
@ -138,11 +140,9 @@ public class EconomyService : IEconomyService {
if (production.ConsumesWorker) economyAtSecond.WorkerCount -= 1; if (production.ConsumesWorker) economyAtSecond.WorkerCount -= 1;
} }
} }
}
// Handle new entities // Handle new entities
if (buildOrder.CompletedOrders.TryGetValue(interval, out var completedAtInterval)) if (buildOrder.CompletedOrders.TryGetValue(interval, out var completedAtInterval))
{
foreach (var newEntity in completedAtInterval) foreach (var newEntity in completedAtInterval)
{ {
var harvest = newEntity; var harvest = newEntity;
@ -152,17 +152,26 @@ public class EconomyService : IEconomyService {
if (production != null && production.RequiresWorker) economyAtSecond.BusyWorkerCount -= 1; if (production != null && production.RequiresWorker) economyAtSecond.BusyWorkerCount -= 1;
} }
} }
}
NotifyDataChanged(); NotifyDataChanged();
} }
public EconomyModel GetEconomy(int atInterval) { public EconomyModel GetEconomy(int atInterval)
{
if (atInterval >= _economyOverTime.Count)
{
return _economyOverTime.Last();
}
return _economyOverTime[atInterval]; return _economyOverTime[atInterval];
} }
private void NotifyDataChanged() {
private event Action OnChange = null!;
private void NotifyDataChanged()
{
OnChange?.Invoke(); OnChange?.Invoke();
} }
} }

26
Services/Immortal/EntityDisplayService.cs

@ -1,28 +1,24 @@
using Model.Types; namespace Services.Immortal;
namespace Services.Immortal; public class EntityDisplayService : IEntityDisplayService
{
public class EntityDisplayService : IEntityDisplayService {
private string displayType = "Detailed"; private string displayType = "Detailed";
private event Action OnChange = null!;
public List<string> DefaultChoices() public List<string> DefaultChoices()
{ {
return new List<string>() { "Detailed", "Plain" }; return new List<string> { "Detailed", "Plain" };
} }
public void Subscribe(Action action) { public void Subscribe(Action action)
{
OnChange += action; OnChange += action;
} }
public void Unsubscribe(Action action) { public void Unsubscribe(Action action)
{
OnChange -= action; OnChange -= action;
} }
private void NotifyDataChanged() {
OnChange?.Invoke();
}
public string GetDisplayType() public string GetDisplayType()
{ {
return displayType; return displayType;
@ -34,4 +30,10 @@ public class EntityDisplayService : IEntityDisplayService {
NotifyDataChanged(); NotifyDataChanged();
} }
private event Action OnChange = null!;
private void NotifyDataChanged()
{
OnChange?.Invoke();
}
} }

87
Services/Immortal/EntityFilterService.cs

@ -4,14 +4,16 @@ using static Services.IEntityFilterService;
namespace Services.Immortal; namespace Services.Immortal;
public enum EntityFilterEvent { public enum EntityFilterEvent
{
OnRefreshFaction, OnRefreshFaction,
OnRefreshImmortal, OnRefreshImmortal,
OnRefreshEntity, OnRefreshEntity,
OnRefreshSearch OnRefreshSearch
} }
public class EntityFilterService : IEntityFilterService { public class EntityFilterService : IEntityFilterService
{
private readonly List<string> _entityChoices = new(); private readonly List<string> _entityChoices = new();
private readonly List<string> _factionChoices = new() { FactionType.Any, FactionType.QRath, FactionType.Aru }; private readonly List<string> _factionChoices = new() { FactionType.Any, FactionType.QRath, FactionType.Aru };
@ -21,36 +23,42 @@ public class EntityFilterService : IEntityFilterService {
private string _selectedFaction = FactionType.Any; private string _selectedFaction = FactionType.Any;
private string _selectedImmortal = ImmortalType.Any; private string _selectedImmortal = ImmortalType.Any;
private event EntityFilterAction OnChange = null!; public EntityFilterService()
{
public EntityFilterService() {
RefreshImmortalChoices(); RefreshImmortalChoices();
RefreshEntityChoices(); RefreshEntityChoices();
} }
public void Subscribe(EntityFilterAction action) { public void Subscribe(EntityFilterAction action)
{
OnChange += action; OnChange += action;
} }
public void Unsubscribe(EntityFilterAction action) { public void Unsubscribe(EntityFilterAction action)
{
OnChange -= action; OnChange -= action;
} }
public string GetEntityType() { public string GetEntityType()
{
return _entityType; return _entityType;
} }
public string GetFactionType() { public string GetFactionType()
{
return _selectedFaction; return _selectedFaction;
} }
public string GetImmortalType() { public string GetImmortalType()
{
return _selectedImmortal; return _selectedImmortal;
} }
public bool SelectFactionType(string factionType) { public bool SelectFactionType(string factionType)
if (_selectedFaction == factionType) { {
if (_selectedFaction == factionType)
{
_selectedFaction = FactionType.None; _selectedFaction = FactionType.None;
_selectedImmortal = ImmortalType.None; _selectedImmortal = ImmortalType.None;
@ -72,8 +80,10 @@ public class EntityFilterService : IEntityFilterService {
return true; return true;
} }
public bool SelectImmortalType(string immortalType) { public bool SelectImmortalType(string immortalType)
if (_selectedImmortal == immortalType) { {
if (_selectedImmortal == immortalType)
{
_selectedImmortal = ImmortalType.None; _selectedImmortal = ImmortalType.None;
NotifyDataChanged(EntityFilterEvent.OnRefreshImmortal); NotifyDataChanged(EntityFilterEvent.OnRefreshImmortal);
return true; return true;
@ -84,14 +94,16 @@ public class EntityFilterService : IEntityFilterService {
return true; return true;
} }
public bool SelectEntityType(string entityType) { public bool SelectEntityType(string entityType)
{
if (_entityType == entityType) return false; if (_entityType == entityType) return false;
_entityType = entityType; _entityType = entityType;
NotifyDataChanged(EntityFilterEvent.OnRefreshEntity); NotifyDataChanged(EntityFilterEvent.OnRefreshEntity);
return true; return true;
} }
public bool EnterSearchText(string searchText) { public bool EnterSearchText(string searchText)
{
if (_searchText.Equals(searchText)) if (_searchText.Equals(searchText))
return false; return false;
_searchText = searchText; _searchText = searchText;
@ -99,23 +111,30 @@ public class EntityFilterService : IEntityFilterService {
return true; return true;
} }
public List<string> GetFactionChoices() { public List<string> GetFactionChoices()
{
return _factionChoices; return _factionChoices;
} }
public List<string> GetImmortalChoices() { public List<string> GetImmortalChoices()
{
return _immortalChoices; return _immortalChoices;
} }
public List<string> GetEntityChoices() { public List<string> GetEntityChoices()
{
return _entityChoices; return _entityChoices;
} }
public string GetSearchText() { public string GetSearchText()
{
return _searchText; return _searchText;
} }
private void RefreshImmortalChoices() { private event EntityFilterAction OnChange = null!;
private void RefreshImmortalChoices()
{
_immortalChoices.Clear(); _immortalChoices.Clear();
//TODO Consider getting these values from the database //TODO Consider getting these values from the database
@ -129,21 +148,26 @@ public class EntityFilterService : IEntityFilterService {
_immortalChoices.Add(ImmortalType.Xol); _immortalChoices.Add(ImmortalType.Xol);
}*/ }*/
if (_selectedFaction == FactionType.QRath || _selectedFaction == FactionType.Any) { if (_selectedFaction == FactionType.QRath || _selectedFaction == FactionType.Any)
{
_immortalChoices.Add(DataType.IMMORTAL_Orzum); _immortalChoices.Add(DataType.IMMORTAL_Orzum);
_immortalChoices.Add(DataType.IMMORTAL_Ajari); _immortalChoices.Add(DataType.IMMORTAL_Ajari);
} }
if (_selectedFaction == FactionType.Aru || _selectedFaction == FactionType.Any) { if (_selectedFaction == FactionType.Aru || _selectedFaction == FactionType.Any)
{
_immortalChoices.Add(DataType.IMMORTAL_Mala); _immortalChoices.Add(DataType.IMMORTAL_Mala);
_immortalChoices.Add(DataType.IMMORTAL_Xol); _immortalChoices.Add(DataType.IMMORTAL_Xol);
} }
} }
private void RefreshEntityChoices() { private void RefreshEntityChoices()
{
_entityChoices.Clear(); _entityChoices.Clear();
if (_selectedFaction == FactionType.QRath || _selectedFaction == FactionType.Aru || _selectedFaction == FactionType.Any) { if (_selectedFaction == FactionType.QRath || _selectedFaction == FactionType.Aru ||
_selectedFaction == FactionType.Any)
{
_entityChoices.Add(EntityType.Army); _entityChoices.Add(EntityType.Army);
_entityChoices.Add(EntityType.Immortal); _entityChoices.Add(EntityType.Immortal);
_entityChoices.Add(EntityType.Passive); _entityChoices.Add(EntityType.Passive);
@ -154,21 +178,22 @@ public class EntityFilterService : IEntityFilterService {
_entityChoices.Add(EntityType.Worker); _entityChoices.Add(EntityType.Worker);
} }
if (_selectedFaction == FactionType.Any) { if (_selectedFaction == FactionType.Any) _entityChoices.Add(EntityType.Any);
_entityChoices.Add(EntityType.Any);
}
} }
private void NotifyDataChanged(EntityFilterEvent entityFilterEvent) { private void NotifyDataChanged(EntityFilterEvent entityFilterEvent)
{
OnChange?.Invoke(entityFilterEvent); OnChange?.Invoke(entityFilterEvent);
} }
public void Subscribe(Action action) { public void Subscribe(Action action)
{
throw new NotImplementedException(); throw new NotImplementedException();
} }
public void Unsubscribe(Action action) { public void Unsubscribe(Action action)
{
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }

6
Services/Immortal/EntityService.cs

@ -2,8 +2,10 @@
namespace Services.Immortal; namespace Services.Immortal;
public class EntityService : IEntityService { public class EntityService : IEntityService
public List<EntityModel> GetEntities() { {
public List<EntityModel> GetEntities()
{
throw new NotImplementedException(); throw new NotImplementedException();
} }
} }

25
Services/Immortal/ImmortalSelectionService.cs

@ -3,27 +3,33 @@ using Model.Types;
namespace Services.Immortal; namespace Services.Immortal;
public class ImmortalSelectionService : IImmortalSelectionService { public class ImmortalSelectionService : IImmortalSelectionService
{
private string _selectedFaction = FactionType.QRath; private string _selectedFaction = FactionType.QRath;
private string _selectedImmortal = DataType.IMMORTAL_Orzum; private string _selectedImmortal = DataType.IMMORTAL_Orzum;
public void Subscribe(Action action) { public void Subscribe(Action action)
{
OnChange += action; OnChange += action;
} }
public void Unsubscribe(Action action) { public void Unsubscribe(Action action)
{
OnChange -= action; OnChange -= action;
} }
public string GetFactionType() { public string GetFactionType()
{
return _selectedFaction; return _selectedFaction;
} }
public string GetImmortalType() { public string GetImmortalType()
{
return _selectedImmortal; return _selectedImmortal;
} }
public bool SelectFactionType(string factionType) { public bool SelectFactionType(string factionType)
{
if (_selectedFaction == factionType) return false; if (_selectedFaction == factionType) return false;
_selectedFaction = factionType; _selectedFaction = factionType;
@ -35,7 +41,8 @@ public class ImmortalSelectionService : IImmortalSelectionService {
return true; return true;
} }
public bool SelectImmortalType(string immortalType) { public bool SelectImmortalType(string immortalType)
{
if (_selectedImmortal == immortalType) return false; if (_selectedImmortal == immortalType) return false;
_selectedImmortal = immortalType; _selectedImmortal = immortalType;
NotifyDataChanged(); NotifyDataChanged();
@ -44,8 +51,8 @@ public class ImmortalSelectionService : IImmortalSelectionService {
private event Action OnChange = null!; private event Action OnChange = null!;
private void NotifyDataChanged() { private void NotifyDataChanged()
{
OnChange?.Invoke(); OnChange?.Invoke();
} }
} }

53
Services/Immortal/KeyService.cs

@ -2,31 +2,35 @@
namespace Services.Immortal; namespace Services.Immortal;
public class KeyService : IKeyService { public class KeyService : IKeyService
{
private static readonly List<string> PressedKeys = new(); private static readonly List<string> PressedKeys = new();
private string? _hotkey; private string? _hotkey;
private string _hotkeyGroup = "C"; private string _hotkeyGroup = "C";
private bool _isHoldingSpace; private bool _isHoldingSpace;
private event Action? OnChange;
public void Subscribe(Action? action) { public void Subscribe(Action? action)
{
OnChange += action; OnChange += action;
} }
public void Unsubscribe(Action? action) { public void Unsubscribe(Action? action)
{
OnChange -= action; OnChange -= action;
} }
public bool AddPressedKey(string key) { public bool AddPressedKey(string key)
{
_hotkey = null; _hotkey = null;
if (PressedKeys.Count > 0) return false; if (PressedKeys.Count > 0) return false;
var pressedKey = key.ToUpper(); var pressedKey = key.ToUpper();
if (pressedKey.Equals(" ") || pressedKey.Equals("SPACE")) { if (pressedKey.Equals(" ") || pressedKey.Equals("SPACE"))
if (!_isHoldingSpace) { {
if (!_isHoldingSpace)
{
_isHoldingSpace = true; _isHoldingSpace = true;
NotifyDataChanged(); NotifyDataChanged();
} }
@ -34,7 +38,8 @@ public class KeyService : IKeyService {
return false; return false;
} }
if (!PressedKeys.Contains(pressedKey)) { if (!PressedKeys.Contains(pressedKey))
{
if (HotkeyModel.KeyGroups.Contains(pressedKey)) _hotkeyGroup = pressedKey; if (HotkeyModel.KeyGroups.Contains(pressedKey)) _hotkeyGroup = pressedKey;
if (HotkeyModel.HotKeys.Contains(pressedKey)) _hotkey = pressedKey; if (HotkeyModel.HotKeys.Contains(pressedKey)) _hotkey = pressedKey;
@ -47,16 +52,20 @@ public class KeyService : IKeyService {
return false; return false;
} }
public List<string> GetAllPressedKeys() { public List<string> GetAllPressedKeys()
{
return PressedKeys; return PressedKeys;
} }
public bool RemovePressedKey(string key) { public bool RemovePressedKey(string key)
{
_hotkey = null; _hotkey = null;
var pressedKey = key.ToUpper(); var pressedKey = key.ToUpper();
if (pressedKey.Equals(" ") || pressedKey.Equals("SPACE")) { if (pressedKey.Equals(" ") || pressedKey.Equals("SPACE"))
if (_isHoldingSpace || true) { {
if (_isHoldingSpace || true)
{
_isHoldingSpace = false; _isHoldingSpace = false;
NotifyDataChanged(); NotifyDataChanged();
} }
@ -64,7 +73,8 @@ public class KeyService : IKeyService {
return false; return false;
} }
if (PressedKeys.Contains(pressedKey)) { if (PressedKeys.Contains(pressedKey))
{
PressedKeys.Remove(pressedKey); PressedKeys.Remove(pressedKey);
NotifyDataChanged(); NotifyDataChanged();
return true; return true;
@ -73,20 +83,25 @@ public class KeyService : IKeyService {
return false; return false;
} }
public bool IsHoldingSpace() { public bool IsHoldingSpace()
{
return _isHoldingSpace; return _isHoldingSpace;
} }
public string? GetHotkey() { public string? GetHotkey()
{
return _hotkey; return _hotkey;
} }
public string GetHotkeyGroup() { public string GetHotkeyGroup()
{
return _hotkeyGroup; return _hotkeyGroup;
} }
private void NotifyDataChanged() { private event Action? OnChange;
private void NotifyDataChanged()
{
OnChange?.Invoke(); OnChange?.Invoke();
} }
} }

52
Services/Immortal/MemoryTesterService.cs

@ -5,12 +5,14 @@ using static Services.IMemoryTesterService;
namespace Services.Immortal; namespace Services.Immortal;
public enum MemoryTesterEvent { public enum MemoryTesterEvent
{
OnVerify, OnVerify,
OnRefresh OnRefresh
} }
public class MemoryTesterService : IMemoryTesterService { public class MemoryTesterService : IMemoryTesterService
{
private readonly List<MemoryEntityModel> memoryEntities = MemoryEntityModel.TestData; private readonly List<MemoryEntityModel> memoryEntities = MemoryEntityModel.TestData;
private readonly List<MemoryQuestionModel> memoryQuestions = MemoryQuestionModel.TestData; private readonly List<MemoryQuestionModel> memoryQuestions = MemoryQuestionModel.TestData;
@ -18,18 +20,18 @@ public class MemoryTesterService : IMemoryTesterService {
private readonly Random random = new(); private readonly Random random = new();
private event MemoryAction OnChange = null!; public void Subscribe(MemoryAction action)
{
public void Subscribe(MemoryAction action) {
OnChange += action; OnChange += action;
} }
public void Unsubscribe(MemoryAction action) { public void Unsubscribe(MemoryAction action)
{
OnChange -= action; OnChange -= action;
} }
public void GenerateQuiz() { public void GenerateQuiz()
{
memoryEntities.Clear(); memoryEntities.Clear();
memoryQuestions.Clear(); memoryQuestions.Clear();
@ -42,17 +44,21 @@ public class MemoryTesterService : IMemoryTesterService {
var entityIndex = 0; var entityIndex = 0;
var questionIndex = 0; var questionIndex = 0;
foreach (var unit in units) { foreach (var unit in units)
memoryEntities.Add(new MemoryEntityModel { {
memoryEntities.Add(new MemoryEntityModel
{
Id = ++entityIndex, Id = ++entityIndex,
Name = unit.Info().Name Name = unit.Info().Name
}); });
var weaponIndex = 0; var weaponIndex = 0;
foreach (var weapon in unit.Weapons()) { foreach (var weapon in unit.Weapons())
{
weaponIndex++; weaponIndex++;
memoryQuestions.Add(new MemoryQuestionModel { memoryQuestions.Add(new MemoryQuestionModel
{
Id = ++questionIndex, Id = ++questionIndex,
MemoryEntityModelId = entityIndex, MemoryEntityModelId = entityIndex,
Name = $"Range (Weapon {weaponIndex})", Name = $"Range (Weapon {weaponIndex})",
@ -61,7 +67,8 @@ public class MemoryTesterService : IMemoryTesterService {
}); });
} }
memoryQuestions.Add(new MemoryQuestionModel { memoryQuestions.Add(new MemoryQuestionModel
{
Id = ++questionIndex, Id = ++questionIndex,
MemoryEntityModelId = entityIndex, MemoryEntityModelId = entityIndex,
Name = "Speed", Name = "Speed",
@ -73,27 +80,34 @@ public class MemoryTesterService : IMemoryTesterService {
NotifyDataChanged(MemoryTesterEvent.OnRefresh); NotifyDataChanged(MemoryTesterEvent.OnRefresh);
} }
public List<MemoryEntityModel> GetEntities() { public List<MemoryEntityModel> GetEntities()
{
return memoryEntities; return memoryEntities;
} }
public List<MemoryQuestionModel> GetQuestions() { public List<MemoryQuestionModel> GetQuestions()
{
return memoryQuestions; return memoryQuestions;
} }
public void Update(MemoryQuestionModel memoryQuestion) { public void Update(MemoryQuestionModel memoryQuestion)
{
memoryQuestions[memoryQuestion.Id - 1].Guess = memoryQuestion.Guess; memoryQuestions[memoryQuestion.Id - 1].Guess = memoryQuestion.Guess;
} }
public void Verify() { public void Verify()
{
NotifyDataChanged(MemoryTesterEvent.OnVerify); NotifyDataChanged(MemoryTesterEvent.OnVerify);
} }
private event MemoryAction OnChange = null!;
//public delegate void MemoryAction(MemoryTesterActions memoryAction); //public delegate void MemoryAction(MemoryTesterActions memoryAction);
private void NotifyDataChanged(MemoryTesterEvent memoryAction) { private void NotifyDataChanged(MemoryTesterEvent memoryAction)
{
OnChange?.Invoke(memoryAction); OnChange?.Invoke(memoryAction);
} }
} }

26
Services/Immortal/TimingService.cs

@ -1,31 +1,37 @@
namespace Services.Immortal; namespace Services.Immortal;
public class TimingService : ITimingService { public class TimingService : ITimingService
{
private int _timing = 1500; private int _timing = 1500;
private event Action? OnChange; public void Subscribe(Action? action)
{
public void Subscribe(Action? action) {
OnChange += action; OnChange += action;
} }
public void Unsubscribe(Action? action) { public void Unsubscribe(Action? action)
{
OnChange -= action; OnChange -= action;
} }
public int GetTiming() { public int GetTiming()
{
return _timing; return _timing;
} }
public void SetTiming(int timing) { public void SetTiming(int timing)
if (_timing != timing) { {
if (_timing != timing)
{
_timing = timing; _timing = timing;
NotifyDataChanged(); NotifyDataChanged();
} }
} }
private void NotifyDataChanged() { private event Action? OnChange;
private void NotifyDataChanged()
{
OnChange?.Invoke(); OnChange?.Invoke();
} }
} }

6
Services/Services.csproj

@ -15,12 +15,12 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="YamlDotNet" Version="11.2.1" /> <PackageReference Include="YamlDotNet" Version="11.2.1"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Contexts\Contexts.csproj" /> <ProjectReference Include="..\Contexts\Contexts.csproj"/>
<ProjectReference Include="..\Model\Model.csproj" /> <ProjectReference Include="..\Model\Model.csproj"/>
</ItemGroup> </ItemGroup>
</Project> </Project>

28
Services/Website/EntityDialogService.cs

@ -1,26 +1,19 @@
using System.ComponentModel.DataAnnotations; namespace Services.Website;
using DataType = Model.Entity.Data.DataType;
namespace Services.Website;
//TODO Move to a database folder, with EntityService, EntityFilterService //TODO Move to a database folder, with EntityService, EntityFilterService
public class EntityDialogService : IEntityDialogService public class EntityDialogService : IEntityDialogService
{ {
private string? entityId = null; private string? entityId;
private List<string> history = new List<string>();
private event Action OnChange = null!; private readonly List<string> history = new();
private void NotifyDataChanged() { public void Subscribe(Action action)
OnChange?.Invoke(); {
}
public void Subscribe(Action action) {
OnChange += action; OnChange += action;
} }
public void Unsubscribe(Action action) { public void Unsubscribe(Action action)
{
OnChange += action; OnChange += action;
} }
@ -74,6 +67,11 @@ public class EntityDialogService : IEntityDialogService
{ {
return entityId; return entityId;
} }
}
private event Action OnChange = null!;
private void NotifyDataChanged()
{
OnChange?.Invoke();
}
}

56
Services/Website/NavigationService.cs

@ -2,27 +2,26 @@
namespace Services.Website; namespace Services.Website;
public class NavigationService : INavigationService { public class NavigationService : INavigationService
private string navigationStateType = NavigationStateType.Default; {
private int navigationStateId = -1; private int navigationStateId = -1;
private string navigationStateType = NavigationStateType.Default;
private NavSelectionType navSelectionType = NavSelectionType.None; private NavSelectionType navSelectionType = NavSelectionType.None;
private Type renderType = null!; private Type renderType = null!;
private int webPageType; private int webPageType;
private int webSectionType; private int webSectionType;
private event Action OnChange = null!;
public void Subscribe(Action action) { public void Subscribe(Action action)
{
OnChange += action; OnChange += action;
} }
public void Unsubscribe(Action action) { public void Unsubscribe(Action action)
{
OnChange += action; OnChange += action;
} }
@ -37,7 +36,8 @@ public class NavigationService : INavigationService {
return navigationStateId; return navigationStateId;
} }
public void ChangeNavigationState(string newState) { public void ChangeNavigationState(string newState)
{
if (newState.Equals(navigationStateType)) if (newState.Equals(navigationStateType))
return; return;
@ -46,12 +46,15 @@ public class NavigationService : INavigationService {
NotifyDataChanged(); NotifyDataChanged();
} }
public string GetNavigationState() { public string GetNavigationState()
{
return navigationStateType; return navigationStateType;
} }
public void SelectPage(int pageType, Type page) { public void SelectPage(int pageType, Type page)
if (renderType != page) { {
if (renderType != page)
{
renderType = page; renderType = page;
webPageType = pageType; webPageType = pageType;
navSelectionType = NavSelectionType.Page; navSelectionType = NavSelectionType.Page;
@ -60,7 +63,8 @@ public class NavigationService : INavigationService {
} }
public void SelectSection(int section) { public void SelectSection(int section)
{
if (section == webSectionType) return; if (section == webSectionType) return;
webSectionType = section; webSectionType = section;
navSelectionType = NavSelectionType.Section; navSelectionType = NavSelectionType.Section;
@ -68,15 +72,18 @@ public class NavigationService : INavigationService {
NotifyDataChanged(); NotifyDataChanged();
} }
public void Back() { public void Back()
if (navSelectionType == NavSelectionType.Page) { {
if (navSelectionType == NavSelectionType.Page)
{
navSelectionType = NavSelectionType.Section; navSelectionType = NavSelectionType.Section;
webPageType = 0; webPageType = 0;
NotifyDataChanged(); NotifyDataChanged();
return; return;
} }
if (navSelectionType == NavSelectionType.Section) { if (navSelectionType == NavSelectionType.Section)
{
navSelectionType = NavSelectionType.None; navSelectionType = NavSelectionType.None;
webSectionType = 0; webSectionType = 0;
webPageType = 0; webPageType = 0;
@ -84,23 +91,30 @@ public class NavigationService : INavigationService {
} }
} }
public NavSelectionType GetNavSelectionType() { public NavSelectionType GetNavSelectionType()
{
return navSelectionType; return navSelectionType;
} }
public int GetWebPageId() { public int GetWebPageId()
{
return webPageType; return webPageType;
} }
public int GetWebSectionId() { public int GetWebSectionId()
{
return webSectionType; return webSectionType;
} }
public Type GetRenderType() { public Type GetRenderType()
{
return renderType; return renderType;
} }
private void NotifyDataChanged() { private event Action OnChange = null!;
private void NotifyDataChanged()
{
OnChange?.Invoke(); OnChange?.Invoke();
} }
} }

34
Services/Website/ToastService.cs

@ -6,28 +6,13 @@ public class ToastService : IToastService
{ {
private readonly List<ToastModel> toasts = new(); private readonly List<ToastModel> toasts = new();
private event Action OnChange = null!; public void Subscribe(Action action)
#if DEBUG
public ToastService()
{ {
toasts.Add(new ToastModel(){Message = "Example message", SeverityType = SeverityType.Error, Title = "Example Error"});
toasts.Add(new ToastModel(){Message = "Example message", SeverityType = SeverityType.Information, Title = "Example Information"});
toasts.Add(new ToastModel(){Message = "Example message", SeverityType = SeverityType.Success, Title = "Example Success"});
toasts.Add(new ToastModel(){Message = "Example message", SeverityType = SeverityType.Warning, Title = "Example Warning"});
}
#endif
private void NotifyDataChanged() {
OnChange();
}
public void Subscribe(Action action) {
OnChange += action; OnChange += action;
} }
public void Unsubscribe(Action action) { public void Unsubscribe(Action action)
{
OnChange += action; OnChange += action;
} }
@ -55,10 +40,7 @@ public class ToastService : IToastService
public void AgeToasts() public void AgeToasts()
{ {
foreach (var toast in toasts) foreach (var toast in toasts) toast.Age++;
{
toast.Age++;
}
NotifyDataChanged(); NotifyDataChanged();
} }
@ -69,6 +51,10 @@ public class ToastService : IToastService
NotifyDataChanged(); NotifyDataChanged();
} }
} private event Action OnChange = null!;
private void NotifyDataChanged()
{
OnChange();
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save