Initial commit
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
@layout PageLayout
|
||||
|
||||
|
||||
@page "/about"
|
||||
|
||||
<LayoutMediumContentComponent>
|
||||
<WebsiteTitleComponent>About</WebsiteTitleComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What is this website for?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
This is just a "yet another third-party tool" website for a video game. If you played a game like Path of Exile, you are probably already used to seeing a bunch of said tools.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
So what is <i>this</i> specific tool for?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
Ideally, this website will be a casual reference, for getting started with understanding the themes and game patterns of IMMORTAL: Gates of Pyre. That said, this tool is currently not near to achieving said goal. In the meantime, you can check out the simple calculator and database tools on this website.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
The game hasn't even been released. Isn't it a bit early for publishing community tools?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
Maybe 🙂
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
Any disclaimers?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
This website has no association with "SunSpear Games." Beyond that, any game data displayed on this website for "IMMORTAL: Gates of Pyre" may be inaccurate due to my own human error and time limitations. Use with caution.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
</PaperComponent>
|
||||
</LayoutMediumContentComponent>
|
||||
@@ -0,0 +1,172 @@
|
||||
@implements IDisposable;
|
||||
@inject IAgileService AgileService;
|
||||
@inject DatabaseContext Database;
|
||||
|
||||
@layout PageLayout
|
||||
|
||||
@page "/agile"
|
||||
|
||||
@if (AgileService.IsLoaded()) {
|
||||
<LayoutMediumContentComponent>
|
||||
|
||||
<WebsiteTitleComponent>Agile</WebsiteTitleComponent>
|
||||
|
||||
<div class="agileViewContainer">
|
||||
@foreach (var sprint in AgileService.SprintModels.OrderBy(e => e.EndDate).Reverse()) {
|
||||
<details class="sprintDisplayContainer @sprint.GetSprintType().ToLower()" open="@(sprint.GetSprintType() == SprintType.Current)">
|
||||
<summary class="sprintSummary">
|
||||
<div class="sprintTitle">@sprint.Name</div>
|
||||
<div style="flex: 1; flex-grow: 1;"></div>
|
||||
<div class="sprintDates">
|
||||
<div class="sprintStartDate">
|
||||
<b>Start: </b>@sprint.StartDate.Value.ToString("dd/MM/yyyy")
|
||||
</div>
|
||||
<div class="sprintEndDate">
|
||||
<b>End: </b>@sprint.EndDate.Value.ToString("dd/MM/yyyy")
|
||||
</div>
|
||||
</div>
|
||||
</summary>
|
||||
<SprintComponent Sprint=sprint Tasks=AgileService.TaskModels></SprintComponent>
|
||||
</details>
|
||||
}
|
||||
|
||||
<details class="sprintDisplayContainer">
|
||||
<summary class="sprintSummary">
|
||||
<div class="sprintTitle">Backlog</div>
|
||||
<div style="flex: 1; flex-grow: 1;"></div>
|
||||
</summary>
|
||||
<div>
|
||||
<BacklogComponent Backlog=backlog></BacklogComponent>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>What is Agile?</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
Agile is a work methodology for determing task assignment and release deadlines.
|
||||
<br/><br/>
|
||||
My agile practice will be creating tasks in a backlog. Assigning them to weekly sprints. And completing all tasks in the allotted time frame.
|
||||
<br/><br/>
|
||||
Any unfinished tasks are moved into the next sprint, or the sprint will be extended by a week.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
</LayoutMediumContentComponent>
|
||||
}
|
||||
else {
|
||||
<LoadingComponent></LoadingComponent>
|
||||
}
|
||||
|
||||
|
||||
<style>
|
||||
.agileViewContainer {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.sprintDisplayContainer {
|
||||
border: 4px solid var(--paper);
|
||||
box-shadow: 0px 2px 12px rgba(0,0,0,0.2);
|
||||
border-radius: 2px;
|
||||
padding: 25px;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
background-color:var(--paper);
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.sprintDisplayContainer {
|
||||
padding: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.sprintSummary {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sprintDisplayContainer.@SprintType.Current.ToLower() {
|
||||
border-color: #042901;
|
||||
background-color:var(--paper);
|
||||
}
|
||||
|
||||
.sprintDisplayContainer.@SprintType.Planned.ToLower() {
|
||||
border-color: #2a2000;
|
||||
background-color:var(--paper);
|
||||
}
|
||||
|
||||
.sprintDisplayContainer.@SprintType.Completed.ToLower() {
|
||||
border-color: #2a2000;
|
||||
background-color:var(--paper);
|
||||
}
|
||||
|
||||
|
||||
details .sprintSummary::before {
|
||||
content: "+";
|
||||
font-weight: bolder;
|
||||
font-size: 1.5rem;
|
||||
padding-right: 8px;
|
||||
}
|
||||
|
||||
details[open] .sprintSummary::before {
|
||||
content: "-";
|
||||
}
|
||||
|
||||
|
||||
.sprintTitle {
|
||||
width: 400px;
|
||||
font-size: 1.6rem;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.sprintDates {
|
||||
width: 160px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public DbSet<SprintModel> Sprints { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public DbSet<TaskModel> Tasks { get; set; }
|
||||
|
||||
|
||||
private readonly List<TaskModel> backlog = new();
|
||||
|
||||
|
||||
protected override void OnInitialized() {
|
||||
AgileService.Subscribe(HasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
AgileService.Unsubscribe(HasChanged);
|
||||
}
|
||||
|
||||
void HasChanged() {
|
||||
Sprints = AgileService.SprintModels;
|
||||
Tasks = AgileService.TaskModels;
|
||||
|
||||
backlog.Clear();
|
||||
|
||||
foreach (var task in Tasks) {
|
||||
if (task.SprintModelId == null) {
|
||||
backlog.Add(task);
|
||||
}
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
await AgileService.Load(Database);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
<div class="sprintContainer">
|
||||
<div class="tasksContainer">
|
||||
@foreach (var task in Backlog) {
|
||||
<div class="taskContainer @task.Status.ToLower()">
|
||||
<div class="taskName">@task.Name</div>
|
||||
<div class="taskDetails">
|
||||
<LayoutRowComponent>
|
||||
<LayoutColumnComponent>
|
||||
<div class="taskType">
|
||||
<b>Type: </b>@task.Task.Replace("_", " ")
|
||||
</div>
|
||||
<div class="taskStatus">
|
||||
<b>Status: </b>@task.Status.Replace("_", " ")
|
||||
</div>
|
||||
<div class="taskPriority">
|
||||
<b>Priority: </b>@task.Priority
|
||||
</div>
|
||||
</LayoutColumnComponent>
|
||||
<LayoutColumnComponent>
|
||||
@if (task.Finished != null) {
|
||||
<div class="taskFinished">
|
||||
<b>Finished: </b>@task.Finished
|
||||
</div>
|
||||
}
|
||||
<div class="taskCreated">
|
||||
<b>Created: </b>@task.Created
|
||||
</div>
|
||||
</LayoutColumnComponent>
|
||||
</LayoutRowComponent>
|
||||
</div>
|
||||
<div class="taskDescription">
|
||||
<b>Description: </b>@task.Description
|
||||
</div>
|
||||
<div class="taskNotes">
|
||||
<b>Notes: </b>@task.Notes
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<style>
|
||||
.sprintContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.sprintDescription {
|
||||
grid-area: description;
|
||||
}
|
||||
|
||||
.sprintStartDate {
|
||||
}
|
||||
|
||||
.sprintEndDate {
|
||||
}
|
||||
|
||||
.sprintNotes {
|
||||
}
|
||||
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.sprintContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
border: none;
|
||||
margin-top: 12px;
|
||||
box-shadow: none;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.sprintStartDate {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.sprintEndDate {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.tasksContainer {
|
||||
grid-area: tasks;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
padding: 25px;
|
||||
align-items: stretch;
|
||||
justify-content: stretch;
|
||||
justify-items: stretch;
|
||||
}
|
||||
|
||||
.taskContainer {
|
||||
padding: 25px;
|
||||
border: 1px dashed rgba(0,0,0,0.6);
|
||||
box-shadow: 0px 2px 6px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.taskContainer.@StatusType.In_Progress.ToLower() {
|
||||
border-color: #030129;
|
||||
background-color: #2c3a4c;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.Todo.ToLower() {
|
||||
border-color: #2a2000;
|
||||
background-color: #ffbf0029;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.To_Test.ToLower() {
|
||||
border-color: #030129;
|
||||
background-color: #2c3a4c;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.Canceled.ToLower() {
|
||||
border-color: #290102;
|
||||
background-color: #4C2C33;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.Done.ToLower() {
|
||||
border-color: #042901;
|
||||
background-color: #2E4C2C;
|
||||
}
|
||||
|
||||
|
||||
.taskName {
|
||||
font-weight: bold;
|
||||
grid-area: name;
|
||||
}
|
||||
|
||||
.taskCreated {
|
||||
grid-area: created;
|
||||
}
|
||||
|
||||
.taskFinished {
|
||||
grid-area: finished;
|
||||
}
|
||||
|
||||
.taskStatus {
|
||||
grid-area: status;
|
||||
}
|
||||
|
||||
.taskDescription {
|
||||
margin-top: 10px;
|
||||
grid-area: description;
|
||||
}
|
||||
|
||||
.taskNotes {
|
||||
grid-area: notes;
|
||||
}
|
||||
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.tasksContainer {
|
||||
padding: 0px;
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
border-top: 4px solid rgba(0,0,0,0.4)
|
||||
}
|
||||
|
||||
.taskContainer {
|
||||
padding: 2px;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.In_Progress.ToLower() {
|
||||
border-color: transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.Todo.ToLower() {
|
||||
border-color: transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.Canceled.ToLower() {
|
||||
border-color: transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.Done.ToLower() {
|
||||
border-color: transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public List<TaskModel> Backlog { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
<div class="sprintContainer">
|
||||
<div class="sprintStatus">
|
||||
<b>Status: </b>@Sprint.GetSprintType()
|
||||
</div>
|
||||
<div class="sprintDescription">
|
||||
<b>Description: </b>@Sprint.Description
|
||||
</div>
|
||||
<div class="sprintNotes">
|
||||
<b>Notes: </b>@Sprint.Notes
|
||||
</div>
|
||||
<div class="tasksContainer">
|
||||
@if (selectedTasks.Count > 0) {
|
||||
@foreach (var task in selectedTasks) {
|
||||
<div class="taskContainer @task.Status.ToLower() @task.Task.ToLower()">
|
||||
<div class="taskName">@task.Name</div>
|
||||
<div class="taskDetails">
|
||||
<LayoutRowComponent>
|
||||
<LayoutColumnComponent>
|
||||
<div class="taskType">
|
||||
<b>Type: </b>@task.Task.Replace("_", " ")
|
||||
</div>
|
||||
<div class="taskStatus">
|
||||
<b>Status: </b>@task.Status.Replace("_", " ")
|
||||
</div>
|
||||
<div class="taskPriority">
|
||||
<b>Priority: </b>@task.Priority
|
||||
</div>
|
||||
|
||||
</LayoutColumnComponent>
|
||||
<LayoutColumnComponent>
|
||||
@if (task.Finished != null) {
|
||||
<div class="taskFinished">
|
||||
<b>Finished: </b>@task.Finished.Value.ToString("dd/MM/yyyy")
|
||||
</div>
|
||||
}
|
||||
<div class="taskCreated">
|
||||
<b>Created: </b>@task.Created.Value.ToString("dd/MM/yyyy")
|
||||
</div>
|
||||
</LayoutColumnComponent>
|
||||
</LayoutRowComponent>
|
||||
</div>
|
||||
<div class="taskDescription">
|
||||
<b>Description: </b>@task.Description
|
||||
</div>
|
||||
<div class="taskNotes">
|
||||
<b>Notes: </b>@task.Notes
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else {
|
||||
<div>Add Tasks...</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sprintContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
padding-top: 16px;
|
||||
}
|
||||
|
||||
.sprintDescription {
|
||||
grid-area: description;
|
||||
}
|
||||
|
||||
.sprintStartDate {
|
||||
}
|
||||
|
||||
.sprintEndDate {
|
||||
}
|
||||
|
||||
.sprintNotes {
|
||||
}
|
||||
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.sprintContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
border: none;
|
||||
margin-top: 12px;
|
||||
box-shadow: none;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.sprintStartDate {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.sprintEndDate {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.tasksContainer {
|
||||
grid-area: tasks;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
padding: 25px;
|
||||
align-items: stretch;
|
||||
justify-content: stretch;
|
||||
justify-items: stretch;
|
||||
}
|
||||
|
||||
.taskContainer {
|
||||
padding: 25px;
|
||||
border: 1px dashed rgba(0,0,0,0.6);
|
||||
box-shadow: 0px 2px 6px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.taskContainer.@StatusType.In_Progress.ToLower() {
|
||||
border-color: #030129;
|
||||
background-color: #2c3a4c;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.Todo.ToLower() {
|
||||
border-color: #2a2000;
|
||||
background-color: #ffbf0029;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.To_Test.ToLower() {
|
||||
border-color: #030129;
|
||||
background-color: #2c3a4c;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.Canceled.ToLower() {
|
||||
border-color: #290102;
|
||||
background-color: #4C2C33;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.Done.ToLower() {
|
||||
border-color: #042901;
|
||||
background-color: #2E4C2C;
|
||||
}
|
||||
|
||||
|
||||
.taskContainer.@TaskType.Bug.ToLower() {
|
||||
border-style: dotted;
|
||||
border-width: 8px;
|
||||
}
|
||||
|
||||
|
||||
.taskName {
|
||||
font-weight: bold;
|
||||
grid-area: name;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.taskDetails {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.taskCreated {
|
||||
grid-area: created;
|
||||
}
|
||||
|
||||
.taskFinished {
|
||||
grid-area: finished;
|
||||
}
|
||||
|
||||
.taskStatus {
|
||||
grid-area: status;
|
||||
}
|
||||
|
||||
.taskDescription {
|
||||
margin-top: 10px;
|
||||
grid-area: description;
|
||||
}
|
||||
|
||||
.taskNotes {
|
||||
grid-area: notes;
|
||||
}
|
||||
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.tasksContainer {
|
||||
padding: 0px;
|
||||
margin-top: 12px;
|
||||
padding-top: 12px;
|
||||
border-top: 4px solid rgba(0,0,0,0.4)
|
||||
}
|
||||
|
||||
.taskContainer {
|
||||
padding: 2px;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
|
||||
.taskContainer.@StatusType.In_Progress.ToLower() {
|
||||
border-color: transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.Todo.ToLower() {
|
||||
border-color: transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.Canceled.ToLower() {
|
||||
border-color: transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.taskContainer.@StatusType.Done.ToLower() {
|
||||
border-color: transparent;
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public SprintModel Sprint { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public DbSet<TaskModel> Tasks { get; set; }
|
||||
|
||||
private List<TaskModel> selectedTasks { get; set; }
|
||||
|
||||
protected override void OnInitialized() {
|
||||
selectedTasks = (from task in Tasks
|
||||
where task.SprintModelId == Sprint.Id
|
||||
select task).OrderBy(x => x.Created).OrderBy(x => x.Finished).Reverse().OrderBy(x => x.Status).ToList();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
@implements IDisposable
|
||||
|
||||
@layout PageLayout
|
||||
|
||||
@page "/build-calculator"
|
||||
|
||||
<LayoutLargeContentComponent>
|
||||
<WebsiteTitleComponent>Build Calculator</WebsiteTitleComponent>
|
||||
|
||||
<AlertComponent Type="SeverityType.Warning">
|
||||
<Title>Work In Progress and Not Fully Tested</Title>
|
||||
<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).
|
||||
</Message>
|
||||
</AlertComponent>
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent>
|
||||
|
||||
|
||||
<div class="calculatorGrid">
|
||||
|
||||
<div style="grid-area: timing;" class="gridItem">
|
||||
<InfoTooltipComponent InfoText="Enter build details.
|
||||
|
||||
<b>Timing Interval:</b> set the max interval length for the build. <i>Ex. 240 (seconds) is 4 minutes, a possible timing for Thrum build order.</i>
|
||||
<b>Name:</b> the name of the build for saving purposes. <i>Ex. 'Safe Thrum Opener'</i>
|
||||
<b>Notes:</b> additional notes of the build for saving purposes. <i>Ex. 'Thrums are for harassing and defending against a ground Q'Rath army.'</i>
|
||||
<b>Color:</b> value to color charts when comparing builds. Not currently implemented.">
|
||||
|
||||
<TimingComponent></TimingComponent>
|
||||
</InfoTooltipComponent>
|
||||
</div>
|
||||
|
||||
|
||||
@if (true) {
|
||||
<div style="grid-area: chart;" class="gridItem">
|
||||
<InfoTooltipComponent InfoText="Shows economy at each game interval. Use to determine if spending additional resourcses on harvesters will help or hinder overall timing attack.">
|
||||
<ChartComponent></ChartComponent>
|
||||
</InfoTooltipComponent>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div style="grid-area: filter;" class="gridItem">
|
||||
<InfoTooltipComponent InfoText="Select build details, such as Faction and Immortal. Affects entities you can build.">
|
||||
<FilterComponent></FilterComponent>
|
||||
</InfoTooltipComponent>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="grid-area: view;" class="gridItem">
|
||||
<InfoTooltipComponent InfoText="Summary of the entity you just selected.">
|
||||
<EntityClickViewComponent></EntityClickViewComponent>
|
||||
</InfoTooltipComponent>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="grid-area: bank;" class="gridItem">
|
||||
<InfoTooltipComponent InfoText="Bank at time of last requested action. Use this section to determine if your build is floating too much alloy or ether.">
|
||||
<BankComponent></BankComponent>
|
||||
</InfoTooltipComponent>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="grid-area: army;" class="gridItem">
|
||||
<InfoTooltipComponent InfoText="Overview of current army, and when it will be ready to begin an attack.">
|
||||
<ArmyComponent></ArmyComponent>
|
||||
</InfoTooltipComponent>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="gridItem gridKeys">
|
||||
|
||||
<InfoTooltipComponent InfoText="Click on the desired entity to build it. <i>You cannot build entities you cannot afford, construct an ether extractor before spending ether.</i>
|
||||
|
||||
You can also use the default Immortal hotkeys, but the above hotkey UI must have focus for this to work. <i>I.e. click on it if hotkeys aren't working, and a white border should appear after key input to indicate focus.</i>
|
||||
|
||||
Additionally, more entities will appear as you build the required technology. You can click or press ` to remove the last made entity. <i>But you cannot remove the starting entities at interval 0.</i>">
|
||||
|
||||
<HotkeyViewerComponent Size="80"></HotkeyViewerComponent>
|
||||
</InfoTooltipComponent>
|
||||
</div>
|
||||
|
||||
|
||||
@if (false) {
|
||||
<div style="grid-area: timeline;" class="gridItem">
|
||||
<TimelineComponent></TimelineComponent>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div style="grid-area: highlights;" class="gridItem">
|
||||
<InfoTooltipComponent InfoText="Timeline highlights of your build order. Shows when you start a new action and when the action is done.">
|
||||
<HighlightsComponent></HighlightsComponent>
|
||||
</InfoTooltipComponent>
|
||||
</div>
|
||||
|
||||
<div style="grid-area: buildorder;" class="gridItem">
|
||||
<InfoTooltipComponent InfoText="Some raw JSON data to represent your build order.">
|
||||
<BuildOrderComponent></BuildOrderComponent>
|
||||
</InfoTooltipComponent>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<FormLayoutComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What is this tool?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
This is a calculator to determine build timings. Mostly so someone can quickly try out a few build orders to see if they somewhat make sense.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
How does it work?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
The tool calculates every second of game time. So if you attempt to build a <b>Legion Hall</b> as your first action, the tool will scan every second, until you get to one where the request can be made. In this case, that is interval 58.
|
||||
<br/>
|
||||
<br/>
|
||||
If you then build 2 <b>Apostle of Bindings</b> a <b>Soul Foundry</b> and a 3 <b>Absolvers</b> you should see yourself roughly floating 500 alloy, with barely having any ether. Which means you could of gotten an <b>Acropolis</b> and a <b>Zentari</b> without hurting your build.
|
||||
<br/>
|
||||
<br/>
|
||||
Try building <b>Apostle of Bindings</b> before the <b>Legion Hall</b> and see how that changes the timing of your 3 <b>Absolvers</b>. (Spoiler: <SpoilerTextComponent> your <b>Absolvers</b> will be built much faster, and you won't be floating so much alloy.</SpoilerTextComponent>)
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What is CONTROl key for?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
Economy and tech related upgrades for townhalls.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What is SHIFT key for?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
Misc building related upgrades. (Omnivores)
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What is 2 key for?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
It will be for Pyre camps. Currently not implemented.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
</FormLayoutComponent>
|
||||
</PaperComponent>
|
||||
</LayoutLargeContentComponent>
|
||||
|
||||
|
||||
<style>
|
||||
.calculatorGrid {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
max-width: 90vw;
|
||||
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||
grid-template-rows: 600px 400px 450px;
|
||||
grid-template-areas:
|
||||
'timing view view view'
|
||||
'filter bank army army'
|
||||
'keys keys highlights buildorder'
|
||||
'chart chart chart chart';
|
||||
}
|
||||
|
||||
.gridItem {
|
||||
border: 2px solid var(--paper-border);
|
||||
padding: 20px;
|
||||
background-color: var(--paper);
|
||||
}
|
||||
|
||||
.gridKeys {
|
||||
grid-area: keys;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.gridKeys {
|
||||
background-color: #282A30;
|
||||
}
|
||||
|
||||
.calculatorGrid {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: auto;
|
||||
grid-template-areas:
|
||||
'timing'
|
||||
'view'
|
||||
'filter'
|
||||
'keys'
|
||||
'bank'
|
||||
'army'
|
||||
'highlights'
|
||||
'buildorder'
|
||||
'chart';
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
|
||||
.gridItem {
|
||||
padding: 0px;
|
||||
border: 0px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Inject]
|
||||
IKeyService KeyService { get; set; }
|
||||
|
||||
[Inject]
|
||||
IImmortalSelectionService FilterService { get; set; }
|
||||
|
||||
[Inject]
|
||||
IBuildOrderService BuildOrderService { get; set; }
|
||||
|
||||
[Inject]
|
||||
IEconomyService EconomyService { get; set; }
|
||||
|
||||
[Inject]
|
||||
ITimingService TimingService { get; set; }
|
||||
|
||||
Dictionary<int, List<EntityModel>> completedEntities = new();
|
||||
|
||||
List<EntityModel> entities = EntityModel.GetListOnlyHotkey();
|
||||
|
||||
protected override void OnInitialized() {
|
||||
KeyService.Subscribe(HandleClick);
|
||||
FilterService.Subscribe(StateHasChanged);
|
||||
EconomyService.Subscribe(StateHasChanged);
|
||||
TimingService.Subscribe(HandleTimingChanged);
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, 0);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
KeyService.Unsubscribe(HandleClick);
|
||||
FilterService.Unsubscribe(StateHasChanged);
|
||||
TimingService.Unsubscribe(StateHasChanged);
|
||||
EconomyService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
|
||||
protected void HandleTimingChanged() {
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
}
|
||||
|
||||
protected void HandleClick() {
|
||||
var hotkey = KeyService.GetHotkey();
|
||||
|
||||
if (hotkey == "") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (hotkey == "`") {
|
||||
BuildOrderService.RemoveLast();
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
StateHasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
var hotkeyGroup = KeyService.GetHotkeyGroup();
|
||||
var isHoldSpace = KeyService.IsHoldingSpace();
|
||||
var faction = FilterService.GetFactionType();
|
||||
var immortal = FilterService.GetImmortalType();
|
||||
|
||||
var entity = EntityModel.GetFrom(hotkey, hotkeyGroup, isHoldSpace, faction, immortal);
|
||||
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
if (BuildOrderService.Add(entity, EconomyService)) {
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
@implements IDisposable
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormDisplayComponent Label="Army ready at">
|
||||
<Display>@LastInterval | T @Interval.ToTime(LastInterval)</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Army units built">
|
||||
<Display>
|
||||
<div style="display: flex; width: 100%; gap: 12px; flex-wrap: wrap;">
|
||||
@foreach (var unit in armyCount) {
|
||||
<div style="width:90px; height: 60px; border: 1px solid gray; padding: 8px;">
|
||||
<div>@unit.Value.ToString()x</div>
|
||||
<div>@unit.Key</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</Display>
|
||||
</FormDisplayComponent>
|
||||
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
[Inject]
|
||||
public IBuildOrderService BuildOrder { get; set; }
|
||||
|
||||
int LastInterval;
|
||||
|
||||
readonly Dictionary<string, int> armyCount = new();
|
||||
|
||||
List<EntityModel> army = new();
|
||||
|
||||
protected override void OnInitialized() {
|
||||
BuildOrder.Subscribe(OnBuildOrderChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
BuildOrder.Unsubscribe(OnBuildOrderChanged);
|
||||
}
|
||||
|
||||
void OnBuildOrderChanged() {
|
||||
armyCount.Clear();
|
||||
|
||||
LastInterval = 0;
|
||||
|
||||
var entitiesOverTime = BuildOrder.GetOrders();
|
||||
|
||||
foreach (var entitiesAtTime in entitiesOverTime) {
|
||||
foreach (var entity in entitiesAtTime.Value) {
|
||||
if (entity.EntityType == EntityType.Army) {
|
||||
if (!armyCount.TryAdd(entity.Info().Name, 1)) {
|
||||
armyCount[entity.Info().Name]++;
|
||||
}
|
||||
|
||||
if (entity.Production() != null && entity.Production().BuildTime + entitiesAtTime.Key > LastInterval) {
|
||||
LastInterval = entity.Production().BuildTime + entitiesAtTime.Key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
@implements IDisposable
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormDisplayComponent Label="Time">
|
||||
<Display>@BuildOrderService.GetLastRequestInterval() | T @Interval.ToTime(BuildOrderService.GetLastRequestInterval())</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Alloy">
|
||||
<Display>@economy.Alloy</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Ether">
|
||||
<Display>@economy.Ether</Display>
|
||||
</FormDisplayComponent>
|
||||
<DevOnlyComponent>
|
||||
<FormDisplayComponent Label="Pyre">
|
||||
<Display>@economy.Pyre</Display>
|
||||
</FormDisplayComponent>
|
||||
</DevOnlyComponent>
|
||||
<FormDisplayComponent Label="Supply">
|
||||
<Display>@supplyTaken / @supplyGranted (@(supplyGranted / 16)@(extraBuildings > 0 ? "+" + extraBuildings : ""))</Display>
|
||||
</FormDisplayComponent>
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
[Inject]
|
||||
IBuildOrderService BuildOrderService { get; set; }
|
||||
|
||||
[Inject]
|
||||
IEconomyService EconomyService { get; set; }
|
||||
|
||||
EconomyModel economy = new();
|
||||
int supplyGranted;
|
||||
int supplyTaken;
|
||||
int extraBuildings;
|
||||
|
||||
protected override void OnInitialized() {
|
||||
BuildOrderService.Subscribe(OnBuildOrderChanged);
|
||||
EconomyService.Subscribe(OnBuildOrderChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
BuildOrderService.Unsubscribe(OnBuildOrderChanged);
|
||||
EconomyService.Subscribe(OnBuildOrderChanged);
|
||||
}
|
||||
|
||||
void OnBuildOrderChanged() {
|
||||
economy = EconomyService.GetEconomy(BuildOrderService.GetLastRequestInterval());
|
||||
|
||||
var ordersOverTime = BuildOrderService.GetOrders();
|
||||
|
||||
supplyTaken = (from ordersAtInterval in ordersOverTime
|
||||
from order in ordersAtInterval.Value
|
||||
where order.Supply() != null
|
||||
where order.Supply().Takes > 0
|
||||
select order.Supply().Takes).Sum();
|
||||
|
||||
supplyGranted = (from ordersAtInterval in ordersOverTime
|
||||
from order in ordersAtInterval.Value
|
||||
where order.Supply() != null
|
||||
where order.Supply().Grants > 0
|
||||
select order.Supply().Grants).Sum();
|
||||
|
||||
extraBuildings = 0;
|
||||
if (supplyGranted > 160) {
|
||||
extraBuildings = (supplyGranted - 160) / 16;
|
||||
supplyGranted = 160;
|
||||
}
|
||||
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
@implements IDisposable
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormTextAreaComponent Label="JSON Data"
|
||||
Rows="14"
|
||||
Value="@BuildOrderService.AsJson()">
|
||||
</FormTextAreaComponent>
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
[Inject]
|
||||
IBuildOrderService BuildOrderService { get; set; }
|
||||
|
||||
protected override void OnInitialized() {
|
||||
BuildOrderService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
BuildOrderService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
@implements IDisposable
|
||||
|
||||
<div class="chartsContainer">
|
||||
@foreach (var chart in charts) {
|
||||
<div style="width: @chart.IntervalDisplayMax.ToString()px; height: @chart.ValueDisplayMax.ToString()px">
|
||||
<div style="position: relative; border: 2px solid gray; border-radius:2px; width: @chart.IntervalDisplayMax.ToString()px; height: @chart.ValueDisplayMax.ToString()px">
|
||||
@foreach (var point in chart.Points) {
|
||||
<div style="position: absolute;
|
||||
bottom:@point.GetValue(chart.HighestValuePoint, chart.ValueDisplayMax)px;
|
||||
left:@point.GetInterval(chart.HighestIntervalPoint, chart.IntervalDisplayMax)px;
|
||||
width: 0px;
|
||||
height: 0px;">
|
||||
<div style="width:1px; height: 1px; border-top-right-radius:10px; border-top-left-radius:10px; border: 2px solid @chart.ChartColor; background-color:@chart.ChartColor">
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.chartsContainer {
|
||||
position: relative;
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormDisplayComponent Label="Highest Alloy">
|
||||
<Display>@highestAlloyPoint</Display>
|
||||
</FormDisplayComponent>
|
||||
<FormDisplayComponent Label="Highest Ether">
|
||||
<Display>@highestEtherPoint</Display>
|
||||
</FormDisplayComponent>
|
||||
<DevOnlyComponent>
|
||||
<FormDisplayComponent Label="Highest Pyre">
|
||||
<Display>@highestEtherPoint</Display>
|
||||
</FormDisplayComponent>
|
||||
</DevOnlyComponent>
|
||||
<FormDisplayComponent Label="Highest Army">
|
||||
<Display>@highestArmyPoint</Display>
|
||||
</FormDisplayComponent>
|
||||
</FormLayoutComponent>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Inject]
|
||||
IEconomyService EconomyService { get; set; }
|
||||
|
||||
[Inject]
|
||||
IBuildOrderService BuildOrderService { get; set; }
|
||||
|
||||
|
||||
int height = 100;
|
||||
readonly int width = 250;
|
||||
|
||||
List<int> valueList = new();
|
||||
|
||||
readonly List<ChartModel> charts = new();
|
||||
|
||||
|
||||
float highestAlloyPoint;
|
||||
float highestEtherPoint;
|
||||
float highestPyrePoint;
|
||||
float highestArmyPoint;
|
||||
|
||||
protected override void OnInitialized() {
|
||||
EconomyService.Subscribe(GenerateChart);
|
||||
BuildOrderService.Subscribe(GenerateChart);
|
||||
|
||||
GenerateChart();
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
EconomyService.Unsubscribe(GenerateChart);
|
||||
BuildOrderService.Unsubscribe(GenerateChart);
|
||||
}
|
||||
|
||||
void GenerateChart() {
|
||||
var economyOverTime = EconomyService.GetOverTime();
|
||||
|
||||
charts.Clear();
|
||||
|
||||
var alloyChart = new ChartModel {
|
||||
IntervalDisplayMax = width,
|
||||
ValueDisplayMax = 100,
|
||||
ChartColor = "Cyan"
|
||||
};
|
||||
var etherChart = new ChartModel {
|
||||
Offset = width,
|
||||
IntervalDisplayMax = width,
|
||||
ValueDisplayMax = 100,
|
||||
ChartColor = "LightGreen"
|
||||
};
|
||||
|
||||
var pyreChart = new ChartModel {
|
||||
Offset = width * 2,
|
||||
IntervalDisplayMax = width,
|
||||
ValueDisplayMax = 100,
|
||||
ChartColor = "Red"
|
||||
};
|
||||
|
||||
var armyChart = new ChartModel {
|
||||
Offset = width * 3,
|
||||
IntervalDisplayMax = width,
|
||||
ValueDisplayMax = 100,
|
||||
ChartColor = "White"
|
||||
};
|
||||
|
||||
highestAlloyPoint = 0;
|
||||
highestEtherPoint = 0;
|
||||
highestPyrePoint = 0;
|
||||
highestArmyPoint = 0;
|
||||
|
||||
for (var interval = 0; interval < economyOverTime.Count(); interval++) {
|
||||
var army = from unit in BuildOrderService.GetCompletedBefore(interval)
|
||||
where unit.EntityType == EntityType.Army
|
||||
select unit;
|
||||
|
||||
var armyValue = 0;
|
||||
foreach (var unit in army) {
|
||||
armyValue += unit.Production().Alloy + unit.Production().Ether;
|
||||
}
|
||||
|
||||
|
||||
highestArmyPoint = Math.Max(highestArmyPoint, armyValue);
|
||||
|
||||
armyChart.Points.Add(new PointModel { Interval = interval, Value = armyValue });
|
||||
}
|
||||
|
||||
|
||||
for (var interval = 0; interval < economyOverTime.Count(); interval++) {
|
||||
var alloyPoint = new PointModel { Interval = interval };
|
||||
var etherPoint = new PointModel { Interval = interval };
|
||||
var pyrePoint = new PointModel { Interval = interval };
|
||||
|
||||
var economyAtSecond = economyOverTime[interval];
|
||||
|
||||
var alloyWorkerHarvesters = from harvester in economyAtSecond.Harvesters
|
||||
where harvester.Harvest() != null
|
||||
where harvester.Harvest().RequiresWorker
|
||||
where harvester.Harvest().Resource == ResourceType.Alloy
|
||||
select harvester;
|
||||
|
||||
var alloyAutomaticHarvesters = from harvester in economyAtSecond.Harvesters
|
||||
where harvester.Harvest() != null
|
||||
where harvester.Harvest().RequiresWorker == false
|
||||
where harvester.Harvest().Resource == ResourceType.Alloy
|
||||
select harvester;
|
||||
|
||||
var etherAutomaticHarvesters = from harvester in economyAtSecond.Harvesters
|
||||
where harvester.Harvest() != null
|
||||
where harvester.Harvest().RequiresWorker == false
|
||||
where harvester.Harvest().Resource == ResourceType.Ether
|
||||
select harvester;
|
||||
|
||||
float autoAlloy = 0;
|
||||
float workerSlots = 0;
|
||||
float workerAlloy = 0;
|
||||
float autoEther = 0;
|
||||
|
||||
float economySpending = 0;
|
||||
|
||||
foreach (var alloyAutoHarvester in alloyAutomaticHarvesters) {
|
||||
autoAlloy += alloyAutoHarvester.Harvest().Slots * alloyAutoHarvester.Harvest().HarvestedPerInterval;
|
||||
var production = alloyAutoHarvester.Production();
|
||||
if (production != null) {
|
||||
economySpending += production.Alloy;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var alloyWorkerHarvester in alloyWorkerHarvesters) {
|
||||
workerSlots += alloyWorkerHarvester.Harvest().Slots;
|
||||
var production = alloyWorkerHarvester.Production();
|
||||
if (production != null) {
|
||||
economySpending += production.Alloy;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var etherWorkerHarvester in etherAutomaticHarvesters) {
|
||||
autoEther += etherWorkerHarvester.Harvest().Slots * etherWorkerHarvester.Harvest().HarvestedPerInterval;
|
||||
var production = etherWorkerHarvester.Production();
|
||||
if (production != null) {
|
||||
economySpending += production.Alloy;
|
||||
}
|
||||
}
|
||||
|
||||
economySpending += (economyAtSecond.WorkerCount - 6) * 50;
|
||||
|
||||
workerAlloy = Math.Min(economyAtSecond.WorkerCount - economyAtSecond.BusyWorkerCount, workerSlots);
|
||||
|
||||
|
||||
alloyPoint.TempValue = workerAlloy + autoAlloy;
|
||||
etherPoint.Value = autoEther;
|
||||
|
||||
|
||||
if (interval > 0) {
|
||||
alloyPoint.TempValue += alloyChart.Points.Last().TempValue;
|
||||
etherPoint.Value += etherChart.Points.Last().Value;
|
||||
pyrePoint.Value = pyreChart.Points.Last().Value + 1;
|
||||
}
|
||||
|
||||
alloyPoint.Value = alloyPoint.TempValue - economySpending;
|
||||
|
||||
highestAlloyPoint = Math.Max(highestAlloyPoint, alloyPoint.Value);
|
||||
highestEtherPoint = Math.Max(highestEtherPoint, etherPoint.Value);
|
||||
|
||||
alloyChart.Points.Add(alloyPoint);
|
||||
etherChart.Points.Add(etherPoint);
|
||||
pyreChart.Points.Add(pyrePoint);
|
||||
}
|
||||
|
||||
alloyChart.HighestValuePoint = (int)Math.Max(highestAlloyPoint, 5000.0f);
|
||||
etherChart.HighestValuePoint = (int)Math.Max(highestEtherPoint, 2000.0f);
|
||||
pyreChart.HighestValuePoint = (int)Math.Max(highestPyrePoint, 2000.0f);
|
||||
|
||||
alloyChart.HighestIntervalPoint = economyOverTime.Count();
|
||||
etherChart.HighestIntervalPoint = economyOverTime.Count();
|
||||
pyreChart.HighestIntervalPoint = economyOverTime.Count();
|
||||
|
||||
armyChart.HighestValuePoint = (int)Math.Max(highestArmyPoint, 2000.0f);
|
||||
armyChart.HighestIntervalPoint = economyOverTime.Count();
|
||||
|
||||
|
||||
charts.Add(alloyChart);
|
||||
charts.Add(etherChart);
|
||||
|
||||
|
||||
//TODO WIP
|
||||
//charts.Add(pyreChart);
|
||||
|
||||
charts.Add(armyChart);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
@implements IDisposable
|
||||
|
||||
<div style="overflow-y: scroll; width: 100%; overflow-x: hidden; height: 550px;">
|
||||
@if (Entity != null) {
|
||||
<EntityViewComponent Entity=Entity></EntityViewComponent>
|
||||
}
|
||||
</div>
|
||||
|
||||
@code {
|
||||
EntityModel Entity;
|
||||
|
||||
[Inject]
|
||||
IKeyService KeyService { get; set; }
|
||||
|
||||
[Inject]
|
||||
IImmortalSelectionService FilterService { get; set; }
|
||||
|
||||
[Inject]
|
||||
IBuildOrderService BuildOrderService { get; set; }
|
||||
|
||||
protected override void OnInitialized() {
|
||||
KeyService.Subscribe(HandleClick);
|
||||
BuildOrderService.Subscribe(OnBuildOrderChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
KeyService.Unsubscribe(HandleClick);
|
||||
BuildOrderService.Unsubscribe(OnBuildOrderChanged);
|
||||
}
|
||||
|
||||
|
||||
protected void HandleClick() {
|
||||
var hotkey = KeyService.GetHotkey();
|
||||
var hotkeyGroup = KeyService.GetHotkeyGroup();
|
||||
var isHoldSpace = KeyService.IsHoldingSpace();
|
||||
var faction = FilterService.GetFactionType();
|
||||
var immortal = FilterService.GetImmortalType();
|
||||
|
||||
var foundEntity = EntityModel.GetFrom(hotkey, hotkeyGroup, isHoldSpace, faction, immortal);
|
||||
|
||||
if (foundEntity != null) {
|
||||
Entity = foundEntity;
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void OnBuildOrderChanged() {
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<FormLayoutComponent>
|
||||
<FormSelectComponent OnChange="@OnFactionChanged">
|
||||
<FormLabelComponent>Faction</FormLabelComponent>
|
||||
<ChildContent>
|
||||
<option value="@FactionType.Aru">Aru</option>
|
||||
<option value="@FactionType.QRath" selected>Q'Rath</option>
|
||||
</ChildContent>
|
||||
</FormSelectComponent>
|
||||
|
||||
<FormSelectComponent OnChange="@OnImmortalChanged">
|
||||
<FormLabelComponent>Immortal</FormLabelComponent>
|
||||
<ChildContent>
|
||||
@if (FilterService.GetFactionType() == FactionType.QRath) {
|
||||
<option value="@ImmortalType.Orzum" selected>Orzum</option>
|
||||
<option value="@ImmortalType.Ajari">Ajari</option>
|
||||
}
|
||||
@if (FilterService.GetFactionType() == FactionType.Aru) {
|
||||
<option value="@ImmortalType.Mala" selected>Mala</option>
|
||||
<option value="@ImmortalType.Xol">Xol</option>
|
||||
}
|
||||
</ChildContent>
|
||||
</FormSelectComponent>
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
[Inject]
|
||||
public IImmortalSelectionService FilterService { get; set; }
|
||||
|
||||
void OnFactionChanged(ChangeEventArgs e) {
|
||||
FilterService.SelectFactionType(e.Value.ToString());
|
||||
}
|
||||
|
||||
void OnImmortalChanged(ChangeEventArgs e) {
|
||||
FilterService.SelectImmortalType(e.Value.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
@implements IDisposable
|
||||
|
||||
<div class="highlightsContainer">
|
||||
<div>
|
||||
<div>Requested</div>
|
||||
|
||||
@for (var i = TimingService.GetTiming() - 1; i >= 0; i--) {
|
||||
@foreach (var order in BuildOrderService.GetOrdersAt(i)) {
|
||||
if (order.EntityType == EntityType.Worker) {
|
||||
continue;
|
||||
}
|
||||
<div>
|
||||
@i | T @Interval.ToTime(i)
|
||||
</div>
|
||||
<div>
|
||||
@order.Info().Name
|
||||
</div>
|
||||
<br/>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div>
|
||||
<div>Finished</div>
|
||||
|
||||
@for (var i = TimingService.GetTiming() - 1; i >= 0; i--) {
|
||||
@foreach (var order in BuildOrderService.GetCompletedAt(i)) {
|
||||
if (order.EntityType == EntityType.Worker) {
|
||||
continue;
|
||||
}
|
||||
<div>
|
||||
@i | T @Interval.ToTime(i)
|
||||
</div>
|
||||
<div>
|
||||
@order.Info().Name
|
||||
</div>
|
||||
<br/>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.highlightsContainer {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
height: 400px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Inject]
|
||||
IEconomyService EconomyService { get; set; }
|
||||
|
||||
[Inject]
|
||||
IBuildOrderService BuildOrderService { get; set; }
|
||||
|
||||
[Inject]
|
||||
ITimingService TimingService { get; set; }
|
||||
|
||||
protected override void OnInitialized() {
|
||||
EconomyService.Subscribe(StateHasChanged);
|
||||
BuildOrderService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
EconomyService.Unsubscribe(StateHasChanged);
|
||||
BuildOrderService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
@implements IDisposable
|
||||
|
||||
<InputPanelComponent>
|
||||
<div class="keyContainer">
|
||||
@foreach (var hotkey in hotkeys) {
|
||||
if (hotkey.IsHidden) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var color = hotkey.KeyText.Equals("SPACE") && KeyService.IsHoldingSpace() || KeyService.GetAllPressedKeys().Contains(hotkey.KeyText)
|
||||
? "#0a0f12" : hotkey.GetColor();
|
||||
|
||||
var x = hotkey.PositionX * Size;
|
||||
var y = hotkey.PositionY * Size;
|
||||
|
||||
var border = "1px solid black";
|
||||
if (hotkey.KeyText.Equals(_key)) {
|
||||
border = "5px solid black";
|
||||
}
|
||||
if (hotkey.KeyText.Equals(_controlGroup)) {
|
||||
border = "5px solid green";
|
||||
}
|
||||
|
||||
if (hotkey.KeyText.Equals("SPACE") && KeyService.IsHoldingSpace()) {
|
||||
border = "5px solid green";
|
||||
}
|
||||
|
||||
<div style="position:relative;
|
||||
cursor:pointer;
|
||||
top:@y.ToString()px;
|
||||
left:@x.ToString()px;
|
||||
width: 0px;
|
||||
height: 0px;">
|
||||
|
||||
<div @onclick="x => { if (hotkey.KeyText.Equals(HotKeyType.SPACE.ToString())) { if (KeyService.IsHoldingSpace()) { KeyService.RemovePressedKey(hotkey.KeyText); } else { KeyService.AddPressedKey(hotkey.KeyText); } } else { KeyService.AddPressedKey(hotkey.KeyText); KeyService.RemovePressedKey(hotkey.KeyText); }}" style="background-color:@color;
|
||||
border: @border;
|
||||
width: @Size.ToString()px;
|
||||
height: @Size.ToString()px;
|
||||
overflow: hidden;
|
||||
padding: 4px;">
|
||||
@hotkey.KeyText
|
||||
@foreach (var entity in data.Values) {
|
||||
if (!BuildOrderService.MeetsRequirements(entity, 9000)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InvalidKey(entity, hotkey) || InvalidKeyGroup(entity, hotkey) || InvalidHoldSpace(entity)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (InvalidFaction(entity) || InvalidVanguard(entity) || InvalidNonVanguard(entity)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var isVanguard = entity.Vanguard() != null;
|
||||
var style = isVanguard ? "font-weight: bold;" : "";
|
||||
|
||||
<div style="@style">@entity.Info()?.Name</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</InputPanelComponent>
|
||||
|
||||
<style>
|
||||
.keyContainer {
|
||||
width: 400px;
|
||||
max-width: 95vw;
|
||||
height: 400px;
|
||||
outline: 3px solid black;
|
||||
border-radius: 8px;
|
||||
background-color: #282A30;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.keyContainer {
|
||||
transform: scale(0.85) translateX(-20px);
|
||||
background-color: none;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public int Size { get; set; } = 100;
|
||||
|
||||
[Inject]
|
||||
public IKeyService KeyService { get; set; }
|
||||
|
||||
[Inject]
|
||||
public IBuildOrderService BuildOrderService { get; set; }
|
||||
|
||||
[Inject]
|
||||
public IImmortalSelectionService FilterService { get; set; }
|
||||
|
||||
readonly Dictionary<string, EntityModel> data = EntityModel.GetDictionary();
|
||||
readonly List<HotkeyModel> hotkeys = HotkeyModel.GetAll();
|
||||
|
||||
public string _controlGroup = "C";
|
||||
public string _key = "";
|
||||
|
||||
protected override void OnInitialized() {
|
||||
base.OnInitialized();
|
||||
|
||||
KeyService.Subscribe(OnKeyPressed);
|
||||
FilterService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
KeyService.Unsubscribe(OnKeyPressed);
|
||||
FilterService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
// Move to Filter Service
|
||||
bool InvalidFaction(EntityModel entity) {
|
||||
if (entity.Faction() != null && entity.Faction()?.Faction != FilterService.GetFactionType() && FilterService.GetFactionType() != FactionType.Any) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Move to Filter Service
|
||||
bool InvalidVanguard(EntityModel entity) {
|
||||
if (entity.Vanguard() != null && entity.Vanguard()?.Immortal != FilterService.GetImmortalType() && FilterService.GetImmortalType() != ImmortalType.Any) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Move to Filter Service
|
||||
bool InvalidNonVanguard(EntityModel entity) {
|
||||
if (entity.Replaceds().Count > 0) {
|
||||
var isReplaced = false;
|
||||
foreach (var replaced in entity.Replaceds()) {
|
||||
if (FilterService.GetImmortalType() == replaced.Immortal) {
|
||||
isReplaced = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isReplaced) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InvalidRequirements(EntityModel entity) {
|
||||
return !BuildOrderService.MeetsRequirements(entity, 9000);
|
||||
}
|
||||
|
||||
bool InvalidKey(EntityModel entity, HotkeyModel key) {
|
||||
if (entity.Hotkey()?.Hotkey == key.KeyText) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InvalidKeyGroup(EntityModel entity, HotkeyModel key) {
|
||||
if (entity.Hotkey()?.HotkeyGroup == _controlGroup) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InvalidKey(EntityModel entity) {
|
||||
if (entity.Hotkey()?.Hotkey == _key) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InvalidKeyGroup(EntityModel entity) {
|
||||
if (entity.Hotkey()?.HotkeyGroup == _controlGroup) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool InvalidHoldSpace(EntityModel entity) {
|
||||
if (entity.Hotkey()?.HoldSpace == KeyService.IsHoldingSpace()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void OnKeyPressed() {
|
||||
if (KeyService.GetAllPressedKeys().Contains("Z")) {
|
||||
_controlGroup = "Z";
|
||||
}
|
||||
if (KeyService.GetAllPressedKeys().Contains("TAB")) {
|
||||
_controlGroup = "TAB";
|
||||
}
|
||||
if (KeyService.GetAllPressedKeys().Contains("C")) {
|
||||
_controlGroup = "C";
|
||||
}
|
||||
if (KeyService.GetAllPressedKeys().Contains("D")) {
|
||||
_controlGroup = "D";
|
||||
}
|
||||
if (KeyService.GetAllPressedKeys().Contains("1")) {
|
||||
_controlGroup = "1";
|
||||
}
|
||||
//TODO This could be better. Duplicated code
|
||||
if (KeyService.GetAllPressedKeys().Contains("2")) {
|
||||
_controlGroup = "2";
|
||||
}
|
||||
if (KeyService.GetAllPressedKeys().Contains("SHIFT")) {
|
||||
_controlGroup = "SHIFT";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Contains("CONTROL")) {
|
||||
_controlGroup = "CONTROL";
|
||||
}
|
||||
|
||||
if (KeyService.GetAllPressedKeys().Count > 0) {
|
||||
_key = KeyService.GetAllPressedKeys().First();
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<div tabindex="0"
|
||||
style="margin: auto;"
|
||||
@onkeydown="HandleKeyDown"
|
||||
@onkeyup="HandleKeyUp"
|
||||
@onkeydown:preventDefault="true"
|
||||
colorwn:stopPropagation="true">
|
||||
@ChildContent
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public RenderFragment ChildContent { get; set; }
|
||||
|
||||
[Inject]
|
||||
public IKeyService KeyService { get; set; }
|
||||
|
||||
private void HandleKeyDown(KeyboardEventArgs e) {
|
||||
KeyService.AddPressedKey(e.Key);
|
||||
}
|
||||
|
||||
private void HandleKeyUp(KeyboardEventArgs e) {
|
||||
KeyService.RemovePressedKey(e.Key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
@implements IDisposable
|
||||
|
||||
<Virtualize Items="@EconomyService.GetOverTime()" Context="economyAtSecond" ItemSize="400" OverscanCount="4">
|
||||
<div style="display: grid; gap: 8px; grid-template-columns: 1fr 1fr;">
|
||||
<div>
|
||||
<div>
|
||||
@economyAtSecond.Interval
|
||||
</div>
|
||||
<div>
|
||||
T @Interval.ToTime(economyAtSecond.Interval) | A @economyAtSecond.Alloy | E @economyAtSecond.Ether
|
||||
</div>
|
||||
<div>
|
||||
Worker Count: @(economyAtSecond.WorkerCount)
|
||||
</div>
|
||||
<div>
|
||||
Free Worker Count: @(economyAtSecond.WorkerCount - economyAtSecond.BusyWorkerCount)
|
||||
</div>
|
||||
<div>
|
||||
Busy Worker Count: @economyAtSecond.BusyWorkerCount
|
||||
</div>
|
||||
<div>
|
||||
Creating Worker Count: @economyAtSecond.CreatingWorkerCount
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
<div>
|
||||
@foreach (var order in BuildOrderService.GetOrdersAt(economyAtSecond.Interval)) {
|
||||
<div>
|
||||
Requested: @order.Info().Name
|
||||
</div>
|
||||
}
|
||||
@foreach (var order in BuildOrderService.GetCompletedAt(economyAtSecond.Interval)) {
|
||||
<div>
|
||||
New: @order.Info().Name
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</Virtualize>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Inject]
|
||||
IEconomyService EconomyService { get; set; }
|
||||
|
||||
[Inject]
|
||||
IBuildOrderService BuildOrderService { get; set; }
|
||||
|
||||
protected override void OnInitialized() {
|
||||
EconomyService.Subscribe(StateHasChanged);
|
||||
BuildOrderService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
EconomyService.Unsubscribe(StateHasChanged);
|
||||
BuildOrderService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<FormLayoutComponent>
|
||||
<FormNumberComponent ReadOnly="true"
|
||||
Max="600"
|
||||
Min="0"
|
||||
Value="@TimingService.GetTiming()"
|
||||
OnChange="@OnTimingChanged">
|
||||
<FormLabelComponent>Timing interval</FormLabelComponent>
|
||||
<FormInfoComponent>Altering the time interval is currently disabled.</FormInfoComponent>
|
||||
</FormNumberComponent>
|
||||
|
||||
<FormTextComponent Label="Name" Placeholder="Fast Thrones..." Value="@BuildOrderService.GetName()" OnChange="OnNameChanged"/>
|
||||
|
||||
<FormTextAreaComponent Label="Notes"
|
||||
Value="@BuildOrderService.GetNotes()"
|
||||
OnChange="@OnNotesChanged">
|
||||
</FormTextAreaComponent>
|
||||
<FormTextComponent Label="Color" Placeholder="red..." Value="@BuildOrderService.GetColor()" OnChange="OnColorChanged"/>
|
||||
</FormLayoutComponent>
|
||||
|
||||
@code {
|
||||
|
||||
[Inject]
|
||||
public ITimingService TimingService { get; set; }
|
||||
|
||||
[Inject]
|
||||
public IBuildOrderService BuildOrderService { get; set; }
|
||||
|
||||
|
||||
void OnTimingChanged(ChangeEventArgs changeEventArgs) {
|
||||
TimingService.SetTiming(int.Parse(changeEventArgs.Value.ToString()));
|
||||
}
|
||||
|
||||
void OnTimingChanged(int value) {
|
||||
TimingService.SetTiming(value);
|
||||
}
|
||||
|
||||
void OnNameChanged(ChangeEventArgs changeEventArgs) {
|
||||
BuildOrderService.SetName(changeEventArgs.Value.ToString());
|
||||
}
|
||||
|
||||
void OnColorChanged(ChangeEventArgs changeEventArgs) {
|
||||
BuildOrderService.SetColor(changeEventArgs.Value.ToString());
|
||||
}
|
||||
|
||||
|
||||
void OnNotesChanged(ChangeEventArgs changeEventArgs) {
|
||||
BuildOrderService.SetNotes(changeEventArgs.Value.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
@page "/changelog"
|
||||
@implements IDisposable;
|
||||
@inject IGitService GitService;
|
||||
@inject DatabaseContext Database;
|
||||
|
||||
@layout PageLayout
|
||||
|
||||
|
||||
@if (GitService.IsLoaded()) {
|
||||
<LayoutMediumContentComponent>
|
||||
<WebsiteTitleComponent>Change Log</WebsiteTitleComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<FormLayoutComponent>
|
||||
<FormCheckboxComponent Label="Show Important"
|
||||
Info="Only show important patches. Like database updates to the latest game patch."
|
||||
Value="@isViewImportant"
|
||||
OnChange="OnChangeClicked">
|
||||
</FormCheckboxComponent>
|
||||
</FormLayoutComponent>
|
||||
</PaperComponent>
|
||||
|
||||
<PaperComponent>
|
||||
@foreach (var patch in Patches.OrderBy(x => x.Date).Reverse()) {
|
||||
@if (!patch.Important.Equals("True") && isViewImportant) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var daysAgo = Math.Floor(DateTime.Now.Subtract(patch.Date).TotalDays);
|
||||
|
||||
<div class="patchContainer">
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<div style="font-size: 1.2rem; font-weight: bolder; margin-bottom:4px;">
|
||||
@patch.Name
|
||||
</div>
|
||||
<div>
|
||||
@if (daysAgo == 0) {
|
||||
<i>Today</i>
|
||||
}
|
||||
else if (daysAgo < 8) {
|
||||
<i>@daysAgo days ago</i>
|
||||
}
|
||||
else {
|
||||
<i>@patch.Date.ToString("dd/MM/yyyy")</i>
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
@foreach (var change in patch.ChangeModels) {
|
||||
@if (!change.Important.Equals("True") && isViewImportant) {
|
||||
continue;
|
||||
}
|
||||
|
||||
<div style="display: flex; justify-content: space-between; ">
|
||||
<div>
|
||||
<div>
|
||||
<b>
|
||||
- @change.Name
|
||||
|
||||
@if (change.Commit != CommitType.None) {
|
||||
<span>(@change.Commit)</span>
|
||||
}
|
||||
:
|
||||
</b> @((MarkupString)change.Description)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<br/>
|
||||
}
|
||||
|
||||
</PaperComponent>
|
||||
</LayoutMediumContentComponent>
|
||||
}
|
||||
else {
|
||||
<LoadingComponent></LoadingComponent>
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public DbSet<PatchModel> Patches { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public DbSet<ChangeModel> Changes { get; set; }
|
||||
|
||||
private bool isViewImportant = true;
|
||||
|
||||
|
||||
protected override void OnInitialized() {
|
||||
GitService.Subscribe(HasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
GitService.Unsubscribe(HasChanged);
|
||||
}
|
||||
|
||||
|
||||
void OnChangeClicked(ChangeEventArgs changeEventArgs) {
|
||||
isViewImportant = (bool)changeEventArgs.Value;
|
||||
}
|
||||
|
||||
void HasChanged() {
|
||||
Changes = GitService.ChangeModels;
|
||||
Patches = GitService.PatchModels;
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
protected override async Task OnInitializedAsync() {
|
||||
GitService.Load(Database);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
@layout PageLayout
|
||||
@implements IDisposable
|
||||
|
||||
<div style="display:grid; gap: 8px;padding: 16px; height: 94vh; width: 90vw; margin: auto; margin-top: 32px;
|
||||
grid-template-columns: 27% 25% 25% 23%; grid-template-rows: auto;
|
||||
grid-template-areas: 'loader sand compare compare' ;">
|
||||
|
||||
|
||||
<div style="grid-area: loader; border: 2px solid black; padding: 20px;">
|
||||
Comparision Loader
|
||||
<BuildLoaderComponent></BuildLoaderComponent>
|
||||
</div>
|
||||
|
||||
<div style="grid-area: sand; border: 2px solid black; padding: 20px;">
|
||||
Sand
|
||||
<SandComponent></SandComponent>
|
||||
</div>
|
||||
|
||||
|
||||
<div style="grid-area: compare; border: 2px solid black; padding: 20px;">
|
||||
Comparision Charts
|
||||
<ComparisonChartsComponent></ComparisonChartsComponent>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
[Inject]
|
||||
IKeyService KeyService { get; set; }
|
||||
|
||||
[Inject]
|
||||
IImmortalSelectionService FilterService { get; set; }
|
||||
|
||||
[Inject]
|
||||
IBuildOrderService BuildOrderService { get; set; }
|
||||
|
||||
[Inject]
|
||||
IEconomyService EconomyService { get; set; }
|
||||
|
||||
[Inject]
|
||||
ITimingService TimingService { get; set; }
|
||||
|
||||
|
||||
Dictionary<int, List<EntityModel>> completedEntities = new();
|
||||
|
||||
|
||||
List<EntityModel> entities = EntityModel.GetListOnlyHotkey();
|
||||
|
||||
protected override void OnInitialized() {
|
||||
KeyService.Subscribe(HandleClick);
|
||||
FilterService.Subscribe(StateHasChanged);
|
||||
EconomyService.Subscribe(StateHasChanged);
|
||||
TimingService.Subscribe(HandleTimingChanged);
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, 0);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
KeyService.Unsubscribe(HandleClick);
|
||||
FilterService.Unsubscribe(StateHasChanged);
|
||||
TimingService.Unsubscribe(StateHasChanged);
|
||||
EconomyService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
|
||||
protected void HandleTimingChanged() {
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
}
|
||||
|
||||
protected void HandleClick() {
|
||||
var hotkey = KeyService.GetHotkey();
|
||||
var hotkeyGroup = KeyService.GetHotkeyGroup();
|
||||
var isHoldSpace = KeyService.IsHoldingSpace();
|
||||
var faction = FilterService.GetFactionType();
|
||||
var immortal = FilterService.GetImmortalType();
|
||||
|
||||
if (hotkey == "`") {
|
||||
BuildOrderService.RemoveLast();
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
StateHasChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
var entity = EntityModel.GetFrom(hotkey, hotkeyGroup, isHoldSpace, faction, immortal);
|
||||
if (entity == null) {
|
||||
return;
|
||||
}
|
||||
if (BuildOrderService.Add(entity, EconomyService)) {
|
||||
EconomyService.Calculate(BuildOrderService, TimingService, BuildOrderService.GetLastRequestInterval());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
@implements IDisposable
|
||||
|
||||
|
||||
<div>
|
||||
<Button Color="Color.Primary" @onclick="OnLoad">Load</Button>
|
||||
<button @onclick="OnLoad">Load</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<textarea @bind="buildData" @bind:event="oninput"
|
||||
style="background-color: #36393F; width: 330px; height: 400px;">
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
string buildData = "";
|
||||
|
||||
[Inject]
|
||||
IBuildComparisonService BuildComparisionService { get; set; }
|
||||
|
||||
protected override void OnInitialized() {
|
||||
BuildComparisionService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
BuildComparisionService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void OnLoad() {
|
||||
BuildComparisionService.LoadJson(buildData);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
@implements IDisposable
|
||||
|
||||
<div>
|
||||
<textarea readonly style="background-color: #36393F; width: 330px; height: 400px;">
|
||||
@BuildComparisonService.AsJson()
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
@code {
|
||||
|
||||
[Inject]
|
||||
IBuildComparisonService BuildComparisonService { get; set; }
|
||||
|
||||
protected override void OnInitialized() {
|
||||
BuildComparisonService.Subscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
BuildComparisonService.Unsubscribe(StateHasChanged);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
@layout PageLayout
|
||||
|
||||
@page "/contact"
|
||||
|
||||
<LayoutMediumContentComponent>
|
||||
<WebsiteTitleComponent>Contact</WebsiteTitleComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
How do I contact you for feature requests and bug reports?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
You can direct message me at <b>Iremirror#3544</b> on the <a href="https://discord.gg/uMq8bMGeeN" target="_blank">IGP Fan Reference</a> discord.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
</PaperComponent>
|
||||
</LayoutMediumContentComponent>
|
||||
@@ -0,0 +1,220 @@
|
||||
@layout PageLayout
|
||||
|
||||
@page "/database"
|
||||
|
||||
@implements IDisposable
|
||||
|
||||
<LayoutLargeContentComponent>
|
||||
<WebsiteTitleComponent>Database</WebsiteTitleComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<FormDisplayComponent Label="Patch">
|
||||
<Display>
|
||||
Game Patch: @EntityModel.GameVersion
|
||||
</Display>
|
||||
</FormDisplayComponent>
|
||||
</PaperComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<EntityFilterComponent></EntityFilterComponent>
|
||||
|
||||
@if (searches != null) {
|
||||
<div class="databaseItems">
|
||||
@foreach (var entity in searches) {
|
||||
<EntityViewComponent Entity=entity></EntityViewComponent>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</PaperComponent>
|
||||
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What is this tool?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
This is a reference database. Mostly so unit stats can be reviewed outside of the game, IMMORTAL: Gates of Pyre.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
Is this database complete?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
No. A lot of content is missing, that needs to be manually transfered from screenshots of IMMORTAL: Gates of Pyre. This will happen slowly over-time.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
Is this database updated to the latest version?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
Maybe. Check this <b>@EntityModel.GameVersion</b> version number, and compare it to the number on discord, in the <b>#game-updates</b> channel. That should give a general sense of how out of date the data is.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
This database has some errors in it.
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
Yup. The content is being transferred by hand, so some mistakes are expected.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
Can I see this data as raw JSON?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
<a href="/raw-database">raw json link</a>
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
</PaperComponent>
|
||||
</LayoutLargeContentComponent>
|
||||
|
||||
<style>
|
||||
.databaseItems {
|
||||
height: 700px;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
background-color: var(--background);
|
||||
gap: 4px;
|
||||
border-top: 4px solid var(--accent);
|
||||
border-bottom: 4px solid var(--accent);
|
||||
padding: 4px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Inject]
|
||||
public IEntityFilterService EntityFilterService { get; set; }
|
||||
|
||||
readonly List<EntityModel> defaults = (from entity in EntityModel.GetList()
|
||||
where entity.IsSpeculative == false
|
||||
select entity).ToList();
|
||||
|
||||
List<EntityModel> factions;
|
||||
List<EntityModel> immortals;
|
||||
List<EntityModel> entities;
|
||||
List<EntityModel> searches;
|
||||
|
||||
|
||||
string selectedFactionType = FactionType.Any;
|
||||
string selectedImmortalType = ImmortalType.Any;
|
||||
string selectedEntityType = EntityType.Army;
|
||||
string searchText = "";
|
||||
|
||||
protected override void OnInitialized() {
|
||||
RefreshFactionSearch();
|
||||
|
||||
EntityFilterService.Subscribe(OnChange);
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
EntityFilterService.Subscribe(OnChange);
|
||||
}
|
||||
|
||||
void OnChange(EntityFilterEvent filterEntityEvent) {
|
||||
if (filterEntityEvent == EntityFilterEvent.OnRefreshFaction) {
|
||||
RefreshFactionSearch();
|
||||
}
|
||||
|
||||
if (filterEntityEvent == EntityFilterEvent.OnRefreshImmortal) {
|
||||
RefreshImmortalSearch();
|
||||
}
|
||||
|
||||
if (filterEntityEvent == EntityFilterEvent.OnRefreshEntity) {
|
||||
RefreshEntitySearch();
|
||||
}
|
||||
|
||||
|
||||
if (filterEntityEvent == EntityFilterEvent.OnRefreshSearch) {
|
||||
RefreshTextSearch();
|
||||
}
|
||||
}
|
||||
|
||||
void RefreshFactionSearch() {
|
||||
selectedFactionType = EntityFilterService.GetFactionType();
|
||||
|
||||
if (selectedFactionType == FactionType.Any) {
|
||||
factions = defaults.ToList();
|
||||
}
|
||||
else {
|
||||
factions = (from entity in defaults
|
||||
where entity.Faction() != null && entity.Faction().Faction == selectedFactionType
|
||||
select entity).ToList();
|
||||
}
|
||||
|
||||
RefreshImmortalSearch();
|
||||
}
|
||||
|
||||
|
||||
void OnImmortalChanged(ChangeEventArgs e) {
|
||||
selectedImmortalType = e.Value.ToString();
|
||||
RefreshImmortalSearch();
|
||||
}
|
||||
|
||||
void RefreshImmortalSearch() {
|
||||
selectedImmortalType = EntityFilterService.GetImmortalType();
|
||||
|
||||
if (selectedImmortalType == ImmortalType.Any) {
|
||||
immortals = factions.ToList();
|
||||
}
|
||||
else {
|
||||
immortals = (from entity in factions
|
||||
where entity.Vanguard() == null || entity.Vanguard().Immortal == selectedImmortalType
|
||||
select entity).ToList();
|
||||
}
|
||||
|
||||
RefreshEntitySearch();
|
||||
}
|
||||
|
||||
void OnEntityChanged(ChangeEventArgs e) {
|
||||
selectedEntityType = e.Value.ToString();
|
||||
RefreshEntitySearch();
|
||||
}
|
||||
|
||||
void RefreshEntitySearch() {
|
||||
selectedEntityType = EntityFilterService.GetEntityType();
|
||||
|
||||
if (selectedEntityType == EntityType.Any) {
|
||||
entities = immortals.ToList();
|
||||
}
|
||||
else {
|
||||
entities = (from entity in immortals
|
||||
where entity.EntityType == selectedEntityType
|
||||
select entity).ToList();
|
||||
}
|
||||
|
||||
RefreshTextSearch();
|
||||
}
|
||||
|
||||
void OnSearchTextChanged(ChangeEventArgs e) {
|
||||
searchText = e.Value.ToString();
|
||||
RefreshTextSearch();
|
||||
}
|
||||
|
||||
void RefreshTextSearch() {
|
||||
searchText = EntityFilterService.GetSearchText();
|
||||
|
||||
if (searchText.Trim() == "") {
|
||||
searches = entities.ToList();
|
||||
}
|
||||
else {
|
||||
searches = (from entity in entities
|
||||
where entity.Info().Name.ToLower().Contains(searchText.ToLower())
|
||||
select entity).ToList();
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
@if (Entity != null) {
|
||||
var isVanguard = Entity.Vanguard() != null ? " vanguard" : "";
|
||||
|
||||
<div class="enititiesContainer @isVanguard">
|
||||
<EntityHeaderComponent Entity=Entity></EntityHeaderComponent>
|
||||
|
||||
<div class="entityPartsContainer">
|
||||
<EntityVanguardComponent Entity=Entity></EntityVanguardComponent>
|
||||
<EntityInfoComponent Entity=Entity></EntityInfoComponent>
|
||||
<EntityVanguardsComponent Entity=Entity></EntityVanguardsComponent>
|
||||
<EntityProductionComponent Entity=Entity></EntityProductionComponent>
|
||||
<EntityStatsComponent Entity=Entity></EntityStatsComponent>
|
||||
<EntityMechanicsComponent Entity=Entity></EntityMechanicsComponent>
|
||||
<EntityPassivesComponent Entity=Entity></EntityPassivesComponent>
|
||||
<EntityPyreSpellsComponent Entity=Entity></EntityPyreSpellsComponent>
|
||||
<EntityUpgradesComponent Entity=Entity></EntityUpgradesComponent>
|
||||
<EntityWeaponsComponent Entity=Entity></EntityWeaponsComponent>
|
||||
<EntityAbilitiesComponent Entity=Entity></EntityAbilitiesComponent>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<style>
|
||||
.enititiesContainer {
|
||||
margin-bottom: 12px;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 30px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.vanguard {
|
||||
border: 4px solid var(--accent);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.entityPartsContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.enititiesContainer {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.entityPartsContainer {
|
||||
margin: 0px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public EntityModel Entity { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
@if (Entity.IdAbilities().Count > 0) {
|
||||
<EntityDisplayComponent Title="Abilities">
|
||||
@foreach (var idAbility in Entity.IdAbilities()) {
|
||||
var spell = EntityModel.Get(idAbility.Id);
|
||||
|
||||
var info = spell.Info();
|
||||
var production = spell.Production();
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<b>Name:</b> @info.Name
|
||||
</div>
|
||||
<div style="max-width: 600px;">
|
||||
<b>Description:</b> @((MarkupString)info.Description)
|
||||
</div>
|
||||
<div>
|
||||
@if (production != null) {
|
||||
if (production.Energy != 0) {
|
||||
<b> Energy: </b>
|
||||
@production.Energy
|
||||
}
|
||||
if (production.BuildTime != 0) {
|
||||
<b> BuildTime: </b>
|
||||
@production.BuildTime
|
||||
}
|
||||
if (production.Cooldown != 0) {
|
||||
<b> Cooldown: </b>
|
||||
@production.Cooldown
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</EntityDisplayComponent>
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public EntityModel Entity { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<div class="entityHeader">
|
||||
<div class="entityHeaderText">
|
||||
@Entity.Info().Name
|
||||
</div>
|
||||
<div style="font-size:1.4rem;">
|
||||
<b>@Entity.EntityType.Replace("_", " ")</b>
|
||||
@if (Entity.Info().Descriptive != DescriptiveType.None) {
|
||||
<span>
|
||||
<b>:</b> @Entity.Info().Descriptive.Replace("_", " ")
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.entityHeader {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 4px;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 22px;
|
||||
width: 100%;
|
||||
margin-left: -6px;
|
||||
}
|
||||
|
||||
.entityHeaderText {
|
||||
font-size: 2rem;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.entityHeader {
|
||||
flex-direction: column;
|
||||
justify-content: normal;
|
||||
margin-left: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public EntityModel Entity { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<EntityDisplayComponent Title="Info">
|
||||
@if (Entity.Info().Description != "") {
|
||||
<div>
|
||||
<b>Description:</b> @((MarkupString)Entity.Info().Description)
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="infoDisplayContainer">
|
||||
<div>
|
||||
@if (Entity.Faction() != null) {
|
||||
<div>
|
||||
<b>Faction:</b> @Entity.Faction().Faction
|
||||
</div>
|
||||
}
|
||||
@if (Entity.Tier() != null) {
|
||||
<div>
|
||||
<b>Tier:</b> @Entity.Tier().Tier
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (Entity.Hotkey() != null) {
|
||||
<div>
|
||||
<div>
|
||||
<b>Hotkey Group:</b> @Entity.Hotkey().HotkeyGroup
|
||||
</div>
|
||||
<div>
|
||||
<b>Hotkey:</b> @Entity.Hotkey().Hotkey
|
||||
</div>
|
||||
<div>
|
||||
<b>Hold Space:</b> @(Entity.Hotkey().HoldSpace ? "Yes" : "No")
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</EntityDisplayComponent>
|
||||
|
||||
<style>
|
||||
.infoDisplayContainer {
|
||||
display: flex;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.infoDisplayContainer {
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public EntityModel Entity { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
@if (Entity.Mechanics().Count > 0) {
|
||||
<EntityDisplayComponent Title="Mechanics">
|
||||
<div>
|
||||
@foreach (var data in Entity.Mechanics()) {
|
||||
<div>
|
||||
<div>
|
||||
<span>
|
||||
<b>Name:</b> @data.Name
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<b>Description:</b> @data.Description
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
</EntityDisplayComponent>
|
||||
}
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public EntityModel Entity { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
@if (Entity.IdPassives().Count > 0) {
|
||||
<EntityDisplayComponent Title="Passives">
|
||||
@foreach (var idPassive in Entity.IdPassives()) {
|
||||
var passive = EntityModel.Get(idPassive.Id);
|
||||
|
||||
var info = passive.Info();
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<b>Name:</b> @info.Name
|
||||
</div>
|
||||
<div style="max-width: 600px;">
|
||||
<b>Description:</b> @((MarkupString)info.Description)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</EntityDisplayComponent>
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public EntityModel Entity { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
@{
|
||||
var production = Entity.Production();
|
||||
var supply = Entity.Supply();
|
||||
var requirements = Entity.Requirements();
|
||||
}
|
||||
|
||||
@if (production != null || supply != null || requirements.Count > 0) {
|
||||
<EntityDisplayComponent Title="Production">
|
||||
<div class="productionContainer">
|
||||
@if (requirements.Count() > 0) {
|
||||
<div>
|
||||
@foreach (var requirement in requirements) {
|
||||
<div>
|
||||
|
||||
<span>
|
||||
<b>@requirement.Requirement.Replace("_", " "):</b> @requirement.Name
|
||||
</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (production != null && (!production.Alloy.Equals(0)
|
||||
|| !production.Ether.Equals(0)
|
||||
|| !production.BuildTime.Equals(0)
|
||||
|| !production.Cooldown.Equals(0))) {
|
||||
<div>
|
||||
@if (!production.Alloy.Equals(0)) {
|
||||
<div>
|
||||
<b>Alloy:</b> @production.Alloy
|
||||
</div>
|
||||
}
|
||||
@if (!production.Ether.Equals(0)) {
|
||||
<div>
|
||||
<b>Ether:</b> @production.Ether
|
||||
</div>
|
||||
}
|
||||
@if (!production.Pyre.Equals(0)) {
|
||||
<div>
|
||||
<b>Pyre:</b> @production.Pyre
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!production.BuildTime.Equals(0)) {
|
||||
<div>
|
||||
<b>Build Time:</b> @production.BuildTime.ToString()s
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!production.Cooldown.Equals(0)) {
|
||||
<div>
|
||||
<b>Cooldown:</b> @production.Cooldown.ToString()s
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
@if (supply != null) {
|
||||
<div>
|
||||
@if (!supply.Grants.Equals(0)) {
|
||||
<div>
|
||||
<b>Grants:</b> @supply.Grants
|
||||
</div>
|
||||
}
|
||||
@if (!supply.Takes.Equals(0)) {
|
||||
<div>
|
||||
<b>Takes:</b> @supply.Takes Supply
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</EntityDisplayComponent>
|
||||
}
|
||||
|
||||
<style>
|
||||
.productionContainer {
|
||||
display: flex;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.productionContainer {
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public EntityModel Entity { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
@if (Entity.IdPyreSpells().Count > 0) {
|
||||
<EntityDisplayComponent Title="Pyre Spells">
|
||||
@foreach (var pyreSpell in Entity.IdPyreSpells()) {
|
||||
var spell = EntityModel.Get(pyreSpell.Id);
|
||||
|
||||
var info = spell.Info();
|
||||
var production = spell.Production();
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<b>Name:</b> @info.Name
|
||||
</div>
|
||||
<div>
|
||||
<b>Description:</b> @((MarkupString)info.Description)
|
||||
</div>
|
||||
<div>
|
||||
@if (production != null) {
|
||||
if (production.Pyre != 0) {
|
||||
<b> Pyre: </b>
|
||||
@production.Pyre
|
||||
}
|
||||
if (production.BuildTime != 0) {
|
||||
<b> BuildTime: </b>
|
||||
@production.BuildTime
|
||||
}
|
||||
if (production.Cooldown != 0) {
|
||||
<b> Cooldown: </b>
|
||||
@production.Cooldown
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</EntityDisplayComponent>
|
||||
}
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public EntityModel Entity { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
@{
|
||||
var vitality = Entity.Vitality();
|
||||
var movement = Entity.Movement();
|
||||
}
|
||||
|
||||
@if (vitality != null || movement != null) {
|
||||
<EntityDisplayComponent Title="Stats">
|
||||
<div class="statContainer">
|
||||
@if (vitality != null) {
|
||||
<div>
|
||||
@if (!vitality.DefenseLayer.Equals(0)) {
|
||||
<div>
|
||||
<b>Shield:</b> @vitality.DefenseLayer
|
||||
</div>
|
||||
}
|
||||
@if (!vitality.Health.Equals(0)) {
|
||||
<div>
|
||||
<b>Health:</b> @vitality.Health
|
||||
</div>
|
||||
}
|
||||
@if (!vitality.Energy.Equals(0)) {
|
||||
<div>
|
||||
<b>Energy:</b> @vitality.Energy
|
||||
</div>
|
||||
}
|
||||
@if (vitality.Armor != "") {
|
||||
<div>
|
||||
<b>Armor:</b> @vitality.Armor
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (vitality.IsEtheric) {
|
||||
<div>
|
||||
<b> + Etheric</b>
|
||||
</div>
|
||||
}
|
||||
@if (vitality.IsStructure) {
|
||||
<div>
|
||||
<b> + Structure</b>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@if (movement != null) {
|
||||
<div>
|
||||
@if (!movement.Speed.Equals(0)) {
|
||||
<div>
|
||||
<b>Speed:</b> @movement.Speed
|
||||
</div>
|
||||
}
|
||||
else {
|
||||
<div>
|
||||
<b>Speed:</b> Immobile
|
||||
</div>
|
||||
}
|
||||
<div>
|
||||
<b>Move Type:</b> @movement.Movement
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</EntityDisplayComponent>
|
||||
}
|
||||
|
||||
<style>
|
||||
.statContainer {
|
||||
display: flex;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.statContainer {
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public EntityModel Entity { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
@if (Entity.IdUpgrades().Count > 0) {
|
||||
<EntityDisplayComponent Title="Upgrades">
|
||||
<div class="upgradesContainer">
|
||||
@foreach (var upgradeId in Entity.IdUpgrades()) {
|
||||
var entity = EntityModel.Get(upgradeId.Id);
|
||||
<div>
|
||||
<div>
|
||||
<b>Name:</b> @entity.Info().Name
|
||||
</div>
|
||||
<div>
|
||||
<b>Description:</b> @entity.Info().Description
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</EntityDisplayComponent>
|
||||
}
|
||||
|
||||
<style>
|
||||
.upgradesContainer {
|
||||
display: flex;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.upgradesContainer {
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public EntityModel Entity { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
@if (Entity.Vanguard() != null) {
|
||||
<EntityDisplayComponent Title="Vanguard">
|
||||
<div>
|
||||
<div>
|
||||
<b>Immortal:</b> @Entity.Vanguard().Immortal.Replace("_", " ")
|
||||
</div>
|
||||
@if (Entity.Vanguard().Replaces != "") {
|
||||
<div>
|
||||
<b>Replaces:</b> @Entity.Vanguard().Replaces.Replace("_", " ")
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</EntityDisplayComponent>
|
||||
}
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public EntityModel Entity { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
@if (Entity.IdVanguards().Count > 0) {
|
||||
<EntityDisplayComponent Title="Vanguards">
|
||||
@foreach (var data in Entity.IdVanguards()) {
|
||||
var entity = EntityModel.Get(data.Id);
|
||||
|
||||
var info = entity.Info();
|
||||
var production = entity.Production();
|
||||
var requirements = entity.Requirements();
|
||||
var vanguard = entity.Vanguard();
|
||||
var productionBuilding = (from building in requirements
|
||||
where building.Requirement == RequirementType.Production_Building
|
||||
select building).First().Name;
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<b>Name:</b> @info.Name
|
||||
</div>
|
||||
<div>
|
||||
<b>Replaces:</b> @vanguard.Replaces
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<b>Built From:</b> @productionBuilding
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</EntityDisplayComponent>
|
||||
}
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public EntityModel Entity { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
@if (Entity.Weapons().Count > 0) {
|
||||
<EntityDisplayComponent Title="Weapons">
|
||||
<div class="weaponsContainer">
|
||||
@foreach (var data in Entity.Weapons()) {
|
||||
<div>
|
||||
<div>
|
||||
<div class="damageContainer">
|
||||
<div>
|
||||
<b>Damage:</b> @data.Damage
|
||||
</div>
|
||||
@if (data.LightDamage != 0) {
|
||||
<div class="alternateDamage">
|
||||
<i>vs Light: @data.LightDamage</i>
|
||||
</div>
|
||||
}
|
||||
@if (data.MediumDamage != 0) {
|
||||
<div class="alternateDamage">
|
||||
<i>vs Medium: @data.MediumDamage</i>
|
||||
</div>
|
||||
}
|
||||
@if (data.HeavyDamage != 0) {
|
||||
<div class="alternateDamage">
|
||||
<i>vs Heavy: @data.HeavyDamage</i>
|
||||
</div>
|
||||
}
|
||||
@if (data.EthericDamageBonus != 0) {
|
||||
<div class="alternateDamage">
|
||||
<i>vs Etheric +@data.EthericDamageBonus</i>
|
||||
</div>
|
||||
}
|
||||
@if (data.StructureDamageBonus != 0) {
|
||||
<div class="alternateDamage">
|
||||
<i>vs Structure: +@data.StructureDamageBonus</i>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<b>Range:</b> @data.Range
|
||||
</div>
|
||||
@if (data.SecondsBetweenAttacks > 0) {
|
||||
<div>
|
||||
<b>AttacksPerSecond:</b> @(1 / data.SecondsBetweenAttacks)
|
||||
</div>
|
||||
<div>
|
||||
(or <b>SecondsBetweenAttacks:</b> @data.SecondsBetweenAttacks)
|
||||
</div>
|
||||
}
|
||||
else if (data.AttacksPerSecond > 0) {
|
||||
<div>
|
||||
<b>AttacksPerSecond:</b> @data.AttacksPerSecond
|
||||
</div>
|
||||
<div>
|
||||
(or <b>SecondsBetweenAttacks:</b> @(1 / data.AttacksPerSecond))
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
<b>Targets:</b> @data.Targets
|
||||
</div>
|
||||
@if (data.AttacksPerSecond != 0) {
|
||||
<span>
|
||||
<b>DPS:</b> @(Math.Round(data.Damage * data.AttacksPerSecond))
|
||||
</span>
|
||||
@if (data.LightDamage != 0) {
|
||||
<span>
|
||||
<i>L: @(Math.Round(data.LightDamage * data.AttacksPerSecond))</i>
|
||||
</span>
|
||||
}
|
||||
@if (data.MediumDamage != 0) {
|
||||
<span>
|
||||
<i>M: @(Math.Round(data.MediumDamage * data.AttacksPerSecond))</i>
|
||||
</span>
|
||||
}
|
||||
@if (data.HeavyDamage != 0) {
|
||||
<span>
|
||||
<i>H: @(Math.Round(data.HeavyDamage * data.AttacksPerSecond))</i>
|
||||
</span>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</EntityDisplayComponent>
|
||||
}
|
||||
|
||||
<style>
|
||||
.weaponsContainer {
|
||||
display: flex;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.weaponsContainer {
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.alternateDamage {
|
||||
margin-left: 18px;
|
||||
}
|
||||
|
||||
.damageContainer {
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public EntityModel Entity { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
<div class="desktopFilters">
|
||||
<div class="desktopFiltersContainer">
|
||||
<div class="filtersContainer">
|
||||
<div class="filterContainer">
|
||||
@foreach (var choice in EntityFilterService.GetFactionChoices()) {
|
||||
var styleClass = "";
|
||||
if (choice.Equals(EntityFilterService.GetFactionType())) {
|
||||
styleClass = "selected";
|
||||
}
|
||||
<button @onclick="@(e => OnChangeFaction(choice))" class="choiceButton @styleClass">@choice</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if (EntityFilterService.GetFactionType() != "Any" && EntityFilterService.GetFactionType() != "None") {
|
||||
<div class="filterContainer">
|
||||
@foreach (var choice in EntityFilterService.GetImmortalChoices()) {
|
||||
var styleClass = "";
|
||||
if (choice.Equals(EntityFilterService.GetImmortalType())) {
|
||||
styleClass = "selected";
|
||||
}
|
||||
<button class="choiceButton @styleClass" @onclick="@(e => OnChangeImmortal(choice))">@choice</button>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="filterContainer">
|
||||
@foreach (var choice in EntityFilterService.GetEntityChoices()) {
|
||||
var styleClass = "";
|
||||
if (choice.Equals(EntityFilterService.GetEntityType())) {
|
||||
styleClass = "selected";
|
||||
}
|
||||
|
||||
<button class="choiceButton @styleClass" @onclick="@(e => OnChangeEntity(choice))">@choice.Replace("_", " ")</button>
|
||||
}
|
||||
</div>
|
||||
<FormTextComponent Label="Search Label" Placeholder="Throne..." OnChange="@(e => EntityFilterService.EnterSearchText(e.Value.ToString()))"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mobileFilters">
|
||||
<FormLayoutComponent>
|
||||
<FormSelectComponent OnChange="@OnFactionChanged">
|
||||
<FormLabelComponent>Faction</FormLabelComponent>
|
||||
<ChildContent>
|
||||
<option value="@FactionType.Any" selected>Any</option>
|
||||
<option value="@FactionType.Aru">Aru</option>
|
||||
<option value="@FactionType.QRath">Q'Rath</option>
|
||||
</ChildContent>
|
||||
</FormSelectComponent>
|
||||
|
||||
<FormSelectComponent OnChange="@OnImmortalChanged">
|
||||
<FormLabelComponent>Immortal</FormLabelComponent>
|
||||
<ChildContent>
|
||||
<option value="@ImmortalType.Any" selected>Any</option>
|
||||
<option value="@ImmortalType.Mala">Mala</option>
|
||||
<option value="@ImmortalType.Xol">Xol</option>
|
||||
<option value="@ImmortalType.Orzum">Orzum</option>
|
||||
<option value="@ImmortalType.Ajari">Ajari</option>
|
||||
</ChildContent>
|
||||
</FormSelectComponent>
|
||||
|
||||
<FormSelectComponent OnChange="@OnEntityChanged">
|
||||
<FormLabelComponent>Entity</FormLabelComponent>
|
||||
<ChildContent>
|
||||
<option value="@EntityType.Any">Any</option>
|
||||
<option value="@EntityType.Ability">Ability</option>
|
||||
<option value="@EntityType.Army" selected>Army</option>
|
||||
<option value="@EntityType.Building">Building</option>
|
||||
<option value="@EntityType.Building_Upgrade">Building Upgrade</option>
|
||||
<option value="@EntityType.Command">Command</option>
|
||||
<option value="@EntityType.Faction">Faction</option>
|
||||
<option value="@EntityType.Immortal">Immortal</option>
|
||||
<option value="@EntityType.Pyre_Spell">Spell</option>
|
||||
<option value="@EntityType.Passive">Passive</option>
|
||||
<option value="@EntityType.Tech">Tech</option>
|
||||
<option value="@EntityType.Worker">Worker</option>
|
||||
</ChildContent>
|
||||
</FormSelectComponent>
|
||||
|
||||
|
||||
<FormTextComponent Label="Search Label" Placeholder="Throne..." OnChange="OnSearchTextChanged"/>
|
||||
</FormLayoutComponent>
|
||||
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
.desktopFilters {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
justify-items: flex-start;
|
||||
top: 50px;
|
||||
padding: 12px;
|
||||
width: 100%;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.desktopFiltersContainer {
|
||||
width: 75%;
|
||||
min-width: 1000px;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
justify-items: flex-start;
|
||||
}
|
||||
|
||||
.filtersContainer {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.filterContainer {
|
||||
display: flex;
|
||||
background-color: var(--background);
|
||||
gap: 2px;
|
||||
margin-right: auto;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.choiceButton {
|
||||
background-color: var(--primary);
|
||||
color: white;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--primary);
|
||||
}
|
||||
|
||||
.choiceButton:hover {
|
||||
background-color: var(--primary-hover);
|
||||
border-color: var(--primary-border-hover);
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: var(--secondary);
|
||||
color: white;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.selected:hover {
|
||||
background-color: var(--secondary-hover);
|
||||
border-color: var(--secondary-border-hover);
|
||||
}
|
||||
|
||||
|
||||
.filterContainer .choiceButton:first-child {
|
||||
border-top-left-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
}
|
||||
|
||||
|
||||
.filterContainer .choiceButton:last-child {
|
||||
border-top-right-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.desktopNavContainer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 480px) {
|
||||
.filtersContainer {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.filterContainer {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.mobileFilters {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1024px) {
|
||||
.mobileFilters {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.desktopFilters {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.desktopSpacer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
[Inject]
|
||||
public IEntityFilterService EntityFilterService { get; set; }
|
||||
|
||||
protected override void OnInitialized() { }
|
||||
|
||||
void OnChangeFaction(string clickedFaction) {
|
||||
EntityFilterService.SelectFactionType(clickedFaction);
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void OnChangeImmortal(string clickedImmortal) {
|
||||
EntityFilterService.SelectImmortalType(clickedImmortal);
|
||||
}
|
||||
|
||||
void OnChangeEntity(string clickedEntity) {
|
||||
EntityFilterService.SelectEntityType(clickedEntity);
|
||||
}
|
||||
|
||||
void OnFactionChanged(ChangeEventArgs e) {
|
||||
EntityFilterService.SelectFactionType(e.Value.ToString());
|
||||
}
|
||||
|
||||
void OnImmortalChanged(ChangeEventArgs e) {
|
||||
EntityFilterService.SelectImmortalType(e.Value.ToString());
|
||||
}
|
||||
|
||||
|
||||
void OnEntityChanged(ChangeEventArgs e) {
|
||||
EntityFilterService.SelectEntityType(e.Value.ToString());
|
||||
}
|
||||
|
||||
|
||||
void OnSearchTextChanged(ChangeEventArgs e) {
|
||||
EntityFilterService.EnterSearchText(e.Value.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
|
||||
.desktopFilters {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
justify-items: flex-start;
|
||||
top: 50px;
|
||||
padding: 12px;
|
||||
width: 100%;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.desktopFiltersContainer {
|
||||
width: 75%;
|
||||
min-width: 1000px;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
justify-items: flex-start;
|
||||
}
|
||||
|
||||
.filtersContainer {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.filterContainer {
|
||||
display: flex;
|
||||
background-color: var(--background);
|
||||
gap: 2px;
|
||||
margin-right: auto;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.choiceButton {
|
||||
background-color: var(--primary);
|
||||
color: white;
|
||||
padding: 12px;
|
||||
border: 1px solid var(--primary);
|
||||
}
|
||||
|
||||
.choiceButton:hover {
|
||||
background-color: var(--primary-hover);
|
||||
border-color: var(--primary-border-hover);
|
||||
}
|
||||
|
||||
.selected {
|
||||
background-color: var(--secondary);
|
||||
color: white;
|
||||
font-style: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.selected:hover {
|
||||
background-color: var(--secondary-hover);
|
||||
border-color: var(--secondary-border-hover);
|
||||
}
|
||||
|
||||
|
||||
.filterContainer .choiceButton:first-child {
|
||||
border-top-left-radius: 8px;
|
||||
border-bottom-left-radius: 8px;
|
||||
}
|
||||
|
||||
|
||||
.filterContainer .choiceButton:last-child {
|
||||
border-top-right-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1025px) {
|
||||
.desktopNavContainer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 480px) {
|
||||
.filtersContainer {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.filterContainer {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.mobileFilters {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1024px) {
|
||||
.mobileFilters {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.desktopFilters {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.desktopSpacer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
@layout PageLayout
|
||||
|
||||
@page "/harass-calculator"
|
||||
|
||||
<LayoutMediumContentComponent>
|
||||
<WebsiteTitleComponent>Harass Calculator</WebsiteTitleComponent>
|
||||
|
||||
<PaperComponent>
|
||||
Credit to Zard for deriving the formula.
|
||||
</PaperComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<LayoutRowComponent>
|
||||
<LayoutColumnComponent>
|
||||
<FormLayoutComponent>
|
||||
<FormDisplayComponent Label="Cost of worker">
|
||||
<Display>@CostOfWorker</Display>
|
||||
</FormDisplayComponent>
|
||||
|
||||
<FormDisplayComponent Label="Alloy mined per second by worker">
|
||||
<Display>@AlloyMinedPerSecondByWorker</Display>
|
||||
</FormDisplayComponent>
|
||||
|
||||
<FormDisplayComponent Label="Time to produce worker">
|
||||
<Display>@TimeToProduceWorker</Display>
|
||||
</FormDisplayComponent>
|
||||
</FormLayoutComponent>
|
||||
</LayoutColumnComponent>
|
||||
|
||||
<LayoutColumnComponent>
|
||||
<FormLayoutComponent>
|
||||
<FormNumberComponent Min="0"
|
||||
Value="@((int)NumberOfWorkersLostToHarass)"
|
||||
OnChange="@(e => { NumberOfWorkersLostToHarass = int.Parse(e.Value.ToString()); Calculate();})">
|
||||
<FormLabelComponent>Number of workers lost to harass</FormLabelComponent>
|
||||
</FormNumberComponent>
|
||||
|
||||
<FormNumberComponent Min="0"
|
||||
Value="@((int)NumberOfTownHallsExisting)"
|
||||
OnChange="@(e => { NumberOfTownHallsExisting = int.Parse(e.Value.ToString()); Calculate();})">
|
||||
<FormLabelComponent>Number of townhalls existing</FormLabelComponent>
|
||||
</FormNumberComponent>
|
||||
|
||||
<FormNumberComponent Min="0"
|
||||
Value="@((int)TravelTime)"
|
||||
OnChange="@(e => { TravelTime = int.Parse(e.Value.ToString()); Calculate();})">
|
||||
<FormLabelComponent>Travel time</FormLabelComponent>
|
||||
</FormNumberComponent>
|
||||
|
||||
<FormDisplayComponent Label="Total alloy lost">
|
||||
<Display>
|
||||
<div style="font-size: 1.5rem; font-weight: 800;">
|
||||
@TotalAlloyHarassment
|
||||
</div>
|
||||
</Display>
|
||||
</FormDisplayComponent>
|
||||
|
||||
|
||||
</FormLayoutComponent>
|
||||
|
||||
<br/>
|
||||
<div>
|
||||
(<b>Worker replacement costs:</b> @WorkerReplacementCost())
|
||||
</div>
|
||||
<div>
|
||||
|
||||
(<b>Delayed mining time:</b> @DelayedMiningCost())
|
||||
</div>
|
||||
|
||||
|
||||
</LayoutColumnComponent>
|
||||
|
||||
|
||||
</LayoutRowComponent>
|
||||
</PaperComponent>
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What is this tool?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
The Harass Calculator allows you to calculate damage done to an enemy alloy line. For example, if you were to attack with Ichors, and kill 6 enemy workers, you can set the <b>Number of workers lost to harass</b> to 6. This would determine a loss of 741 alloy. Quite the large number.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What can I learn from this?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
Well, let's assume you lost a full alloy line of workers, and have to take that 741 alloy cost (300 to rebuy the workers, and 441 in lost mining time.)
|
||||
<br/><br/>
|
||||
If you were to set the <b>Number of townhalls existing</b> to 2, the calculator will consider worker transfer micro. Allowing you to cut the total cost by roughly 315 alloy. However, that number isn't entirely accurate, you are also going to have to bump up the <b>Travel time</b> to account for the time it takes the transferred workers to arrive at the decimated alloy line.
|
||||
<br/><br/>
|
||||
Let's say it takes 10 seconds for workers to transfer from your second base. We can divide that number by 2, to represent our bases, and add those 5 additional seconds to <b>Travel time</b>, for the more accurate loss of 456 alloy (saving you 285 alloy.) <i>Which is much better than not transferring workers!</i>
|
||||
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
Can I see the formula for the calculation?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
<br/>
|
||||
<div class="mathContainer">
|
||||
<div> =c*m+r*g*(t+l) + </div>
|
||||
|
||||
<MathLoopSumComponent>
|
||||
<LoopStart><i>x</i> =1</LoopStart>
|
||||
<LoopEnd>
|
||||
⌊
|
||||
<MathDivisionComponent>
|
||||
<Dividee>m</Dividee><Divider>a</Divider>
|
||||
</MathDivisionComponent>⌋
|
||||
</LoopEnd>
|
||||
<IndexSymbol>
|
||||
<i>x</i>
|
||||
</IndexSymbol>
|
||||
</MathLoopSumComponent>
|
||||
|
||||
<div style="width: 132px">g*<i>x</i>*(t+l)</div>
|
||||
</div>
|
||||
<br/>
|
||||
<div style="font-family:monospace;">
|
||||
<div>c is CostOfWorker </div>
|
||||
<div>m is NumberOfWorkersLostToHarass, <i>m for [M]otes</i></div>
|
||||
<div>a is NumberOfTownHallsExisting, <i>a for [A]cropolis</i></div>
|
||||
<div>r is m mod a is LeftOverWorkersToProduceCount()</div>
|
||||
<div>g is AlloyMinedPerSecondByWorker</div>
|
||||
<div>t is TimeToProduceWorker</div>
|
||||
<div>l is TravelTime</div>
|
||||
<div><i>x</i> is workerProductionIndex</div>
|
||||
</div>
|
||||
<br/><br/>
|
||||
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
Can I see the code for the calculation?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
|
||||
<CodeComponent>
|
||||
<div style="color: green;">//TotalAlloyHarassment is set after Calculate() function is called</div>
|
||||
<div>
|
||||
float TotalAlloyHarassment;
|
||||
|
||||
float CostOfWorker = 50;
|
||||
float AlloyMinedPerSecondByWorker = 1;
|
||||
float TimeToProduceWorker = 20;
|
||||
float TravelTime = 1;
|
||||
float NumberOfWorkersLostToHarass = 1;
|
||||
float NumberOfTownHallsExisting = 1;
|
||||
|
||||
float SimultaneousProductionFloor() {
|
||||
if (NumberOfTownHallsExisting <= 0 || NumberOfWorkersLostToHarass <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (float)Math.Floor(NumberOfWorkersLostToHarass / Math.Min(NumberOfTownHallsExisting, NumberOfWorkersLostToHarass));
|
||||
}
|
||||
float LeftOverWorkersToProduceCount() {
|
||||
return NumberOfWorkersLostToHarass % (Math.Min(NumberOfTownHallsExisting, NumberOfWorkersLostToHarass));
|
||||
}
|
||||
|
||||
float WorkerReplacementCost() {
|
||||
return CostOfWorker * NumberOfWorkersLostToHarass;
|
||||
}
|
||||
|
||||
|
||||
float DelayedMiningCost() {
|
||||
return TotalAlloyHarassment - WorkerReplacementCost();
|
||||
}
|
||||
|
||||
void Calculate() {
|
||||
TotalAlloyHarassment = WorkerReplacementCost();
|
||||
|
||||
for (var workerProductionIndex = 0; workerProductionIndex < SimultaneousProductionFloor(); workerProductionIndex++) {
|
||||
TotalAlloyHarassment += AlloyMinedPerSecondByWorker * (TimeToProduceWorker + TravelTime) * (workerProductionIndex + 1);
|
||||
}
|
||||
|
||||
TotalAlloyHarassment += LeftOverWorkersToProduceCount() * (TimeToProduceWorker + TravelTime) * AlloyMinedPerSecondByWorker;
|
||||
}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</CodeComponent>
|
||||
</InfoAnswerComponent>
|
||||
|
||||
</InfoBodyComponent>
|
||||
</PaperComponent>
|
||||
|
||||
|
||||
</LayoutMediumContentComponent>
|
||||
|
||||
<style>
|
||||
.mathContainer {
|
||||
font-family: monospace;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-start;
|
||||
border: 1px black solid;
|
||||
padding: 32px;
|
||||
background-color: #1A1B1E
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.mathContainer {
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
float TotalAlloyHarassment;
|
||||
|
||||
readonly float CostOfWorker = 50;
|
||||
readonly float AlloyMinedPerSecondByWorker = 1;
|
||||
readonly float TimeToProduceWorker = 20;
|
||||
float TravelTime = 1;
|
||||
float NumberOfWorkersLostToHarass = 1;
|
||||
float NumberOfTownHallsExisting = 1;
|
||||
|
||||
float SimultaneousProductionFloor() {
|
||||
if (NumberOfTownHallsExisting <= 0 || NumberOfWorkersLostToHarass <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (float)Math.Floor(NumberOfWorkersLostToHarass / Math.Min(NumberOfTownHallsExisting, NumberOfWorkersLostToHarass));
|
||||
}
|
||||
|
||||
float LeftOverWorkersToProduceCount() {
|
||||
return NumberOfWorkersLostToHarass % Math.Min(NumberOfTownHallsExisting, NumberOfWorkersLostToHarass);
|
||||
}
|
||||
|
||||
float WorkerReplacementCost() {
|
||||
return CostOfWorker * NumberOfWorkersLostToHarass;
|
||||
}
|
||||
|
||||
|
||||
float DelayedMiningCost() {
|
||||
return TotalAlloyHarassment - WorkerReplacementCost();
|
||||
}
|
||||
|
||||
void Calculate() {
|
||||
TotalAlloyHarassment = WorkerReplacementCost();
|
||||
|
||||
for (var workerProductionIndex = 0; workerProductionIndex < SimultaneousProductionFloor(); workerProductionIndex++) {
|
||||
TotalAlloyHarassment += AlloyMinedPerSecondByWorker * (TimeToProduceWorker + TravelTime) * (workerProductionIndex + 1);
|
||||
}
|
||||
|
||||
TotalAlloyHarassment += LeftOverWorkersToProduceCount() * (TimeToProduceWorker + TravelTime) * AlloyMinedPerSecondByWorker;
|
||||
}
|
||||
|
||||
protected override void OnInitialized() {
|
||||
Calculate();
|
||||
}
|
||||
|
||||
void ValueChanged(float test) {
|
||||
Calculate();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
@layout PageLayout;
|
||||
|
||||
@page "/immortal-home"
|
||||
|
||||
<LayoutMediumContentComponent>
|
||||
<div class="mainContainer">
|
||||
<div class="mainTitle">
|
||||
Fan Reference
|
||||
</div>
|
||||
|
||||
<div>
|
||||
Refer to various aspects of "IMMORTAL: Gates of Pyre" from this external reference!
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent>
|
||||
|
||||
<div class="herosContainer">
|
||||
<div class="hero">
|
||||
<div class="heroTitle">
|
||||
Database
|
||||
</div>
|
||||
<img src="image/hero/Database.png" class="heroImage"/>
|
||||
<NavLink Href="/database" class="heroCallToAction">
|
||||
Review the units!
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="hero">
|
||||
<div class="heroTitle">
|
||||
Build Calculator
|
||||
</div>
|
||||
<img src="image/hero/Build.png" class="heroImage"/>
|
||||
<NavLink Href="/build-calculator" class="heroCallToAction">
|
||||
Make a build!
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="hero">
|
||||
<div class="heroTitle">
|
||||
Notes
|
||||
</div>
|
||||
<img src="image/hero/Notes.png" class="heroImage"/>
|
||||
<NavLink Href="/notes" class="heroCallToAction">
|
||||
Read some notes!
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="hero">
|
||||
<div class="heroTitle">
|
||||
Streams
|
||||
</div>
|
||||
<img src="image/hero/Streams.png" class="heroImage"/>
|
||||
<NavLink Href="/streams" class="heroCallToAction">
|
||||
Watch live development!
|
||||
</NavLink>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent>
|
||||
|
||||
<AlertComponent>
|
||||
<Title>Under Construction</Title>
|
||||
<Message>Website is still being made. Check out <NavLink Href="/immortal-roadmap">Road Map</NavLink> for future plans, <NavLink Href="/immortal-agile">Agile</NavLink> for present tasks, and <NavLink Href="/immortal-changelog">Change Log</NavLink> for past changes.</Message>
|
||||
|
||||
</AlertComponent>
|
||||
|
||||
</LayoutMediumContentComponent>
|
||||
|
||||
<style>
|
||||
.mainContainer {
|
||||
padding-bottom: 32px;
|
||||
}
|
||||
|
||||
.mainTitle {
|
||||
font-size: 2.2rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.quoteContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
max-width: 600px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.quoteTitle {
|
||||
font-weight: 800;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.quoteText {
|
||||
margin: auto;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.herosContainer {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 64px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hero {
|
||||
padding: 32px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
|
||||
.heroTitle {
|
||||
font-weight: 800;
|
||||
font-size: 1.3rem;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.heroImage {
|
||||
border: 1px solid rgba(0,0,0,0.5);
|
||||
box-shadow: 2px 2px 2px rgba(0,0,0,0.5);
|
||||
height: 400px;
|
||||
width: 400px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.heroCallToAction {
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
margin: auto;
|
||||
background-color: var(--primary);
|
||||
border: 1px solid var(--primary);
|
||||
padding: 16px;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.heroCallToAction:hover {
|
||||
background-color: var(--primary-hover);
|
||||
border-color: var(--primary-border-hover);
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,84 @@
|
||||
@page "/makingof"
|
||||
|
||||
@layout PageLayout
|
||||
|
||||
<LayoutLargeContentComponent>
|
||||
<WebsiteTitleComponent>Making Of</WebsiteTitleComponent>
|
||||
|
||||
<AlertComponent Type="SeverityType.Warning">
|
||||
<Title>Under Construction</Title>
|
||||
<Message>This page is still being worked on. It will list the tech and design choices made for this website. It's is strictly for educational and reference purposes, and it has nothing to do with IMMORTAL: Gates of Pyre.</Message>
|
||||
</AlertComponent>
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent>
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormDisplayComponent Label="Tech Stack">
|
||||
<Display>Blazor (C# and HTML)</Display>
|
||||
</FormDisplayComponent>
|
||||
|
||||
<FormDisplayComponent Label="Stack Details">
|
||||
<Display>This is a Static Single Page Application hosted on Azure.</Display>
|
||||
</FormDisplayComponent>
|
||||
</FormLayoutComponent>
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent>
|
||||
|
||||
<MakingOfColours></MakingOfColours>
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent>
|
||||
|
||||
<DevOnlyComponent>
|
||||
<MakingOfSectionComponent Title="Empty">
|
||||
<MakingOfComponent>
|
||||
<Title>
|
||||
Empty
|
||||
</Title>
|
||||
<Description>
|
||||
Empty
|
||||
</Description>
|
||||
<Example>
|
||||
Empty
|
||||
</Example>
|
||||
<Usage>
|
||||
<CodeComponent>Empty</CodeComponent>
|
||||
</Usage>
|
||||
<Code>
|
||||
<CodeComponent>Empty</CodeComponent>
|
||||
</Code>
|
||||
</MakingOfComponent>
|
||||
|
||||
</MakingOfSectionComponent>
|
||||
</DevOnlyComponent>
|
||||
|
||||
<DevOnlyComponent>
|
||||
<MakingOfSectionComponent Title="Dialogs">
|
||||
<MakingOfDialogs></MakingOfDialogs>
|
||||
</MakingOfSectionComponent>
|
||||
</DevOnlyComponent>
|
||||
|
||||
<DevOnlyComponent>
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormEscapeCodeComponent></FormEscapeCodeComponent>
|
||||
</FormLayoutComponent>
|
||||
</DevOnlyComponent>
|
||||
|
||||
<MakingOfSectionComponent Title="Displays">
|
||||
<MakingOfDisplays></MakingOfDisplays>
|
||||
</MakingOfSectionComponent>
|
||||
|
||||
<DevOnlyComponent>
|
||||
<MakingOfSectionComponent Title="Navigation">
|
||||
<MakingOfNavigation></MakingOfNavigation>
|
||||
</MakingOfSectionComponent>
|
||||
</DevOnlyComponent>
|
||||
|
||||
<MakingOfSectionComponent Title="Feedback">
|
||||
<MakingOfFeedback></MakingOfFeedback>
|
||||
</MakingOfSectionComponent>
|
||||
|
||||
<MakingOfSectionComponent Title="Forms">
|
||||
<MakingOfForms></MakingOfForms>
|
||||
</MakingOfSectionComponent>
|
||||
</LayoutLargeContentComponent>
|
||||
@@ -0,0 +1,160 @@
|
||||
<div>Colors</div>
|
||||
|
||||
<div class="colorContainer">
|
||||
<CodeComponent>
|
||||
--accent: @accent;
|
||||
--primary: @primary;
|
||||
--primary-border: @primary_border;
|
||||
--primary-hover: @primary_hover;
|
||||
--primary-border-hover: @primary_border_hover;
|
||||
--background: @background;
|
||||
--secondary: @secondary;
|
||||
--secondary-hover: @secondary_hover;
|
||||
--secondary-border-hover: @secondary_border_hover;
|
||||
--paper: @paper;
|
||||
--paper-border: @paper_border;
|
||||
--info: @info;
|
||||
--info-border: @info_border;
|
||||
</CodeComponent>
|
||||
<br />
|
||||
<div class="color accent">
|
||||
<div>Accent</div>
|
||||
<div>
|
||||
Base: <input type="color" value="@accent" @onchange="e => accent = e.Value.ToString()" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="color primary">
|
||||
<div>Primary</div>
|
||||
<div>
|
||||
Base: <input type="color" value="@primary" @onchange="e => primary = e.Value.ToString()" />
|
||||
</div>
|
||||
<div>
|
||||
Border: <input type="color" value="@primary_border" @onchange="e => primary_border = e.Value.ToString()" />
|
||||
</div>
|
||||
<div>
|
||||
Hover Base: <input type="color" value="@primary_hover" @onchange="e => primary_hover = e.Value.ToString()" />
|
||||
</div>
|
||||
<div>
|
||||
Hover Border: <input type="color" value="@primary_border_hover" @onchange="e => primary_border_hover = e.Value.ToString()" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="color secondary">
|
||||
<div>Secondary</div>
|
||||
<div>
|
||||
Base: <input type="color" value="@secondary" @onchange="e => secondary = e.Value.ToString()" />
|
||||
</div>
|
||||
<div>
|
||||
Hover Base: <input type="color" value="@secondary_hover" @onchange="e => secondary_hover = e.Value.ToString()" />
|
||||
</div>
|
||||
<div>
|
||||
Hover Border: <input type="color" value="@secondary_border_hover" @onchange="e => secondary_border_hover = e.Value.ToString()" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="color paper">
|
||||
<div>Paper</div>
|
||||
<div>
|
||||
Base: <input type="color" value="@paper" @onchange="e => paper = e.Value.ToString()" />
|
||||
</div>
|
||||
<div>
|
||||
Border: <input type="color" value="@paper_border" @onchange="e => paper_border = e.Value.ToString()" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="color background">
|
||||
<div>Background</div>
|
||||
<div>
|
||||
Base: <input type="color" value="@background" @onchange="e => background = e.Value.ToString()" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="color info">
|
||||
<div>Info</div>
|
||||
<div>
|
||||
Base: <input type="color" value="@info" @onchange="e => info = e.Value.ToString()" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--accent: @accent;
|
||||
--primary: @primary;
|
||||
--primary-border: @primary_border;
|
||||
--primary-hover: @primary_hover;
|
||||
--primary-border-hover: @primary_border_hover;
|
||||
--background: @background;
|
||||
--secondary: @secondary;
|
||||
--secondary-hover: @secondary_hover;
|
||||
--secondary-border-hover: @secondary_border_hover;
|
||||
--paper: @paper;
|
||||
--paper-border: @paper_border;
|
||||
--info: @info;
|
||||
--info-border: @info_border;
|
||||
}
|
||||
|
||||
.colorContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.color {
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 32px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.accent {
|
||||
background-color: var(--accent);
|
||||
}
|
||||
|
||||
.primary {
|
||||
background-color: var(--primary);
|
||||
border: 1px solid var(--primary-border);
|
||||
}
|
||||
|
||||
.primary:hover {
|
||||
background-color: var(--primary-hover);
|
||||
border-color: var(--primary-border-hover);
|
||||
}
|
||||
|
||||
.secondary {
|
||||
background-color: var(--secondary);
|
||||
border: 1px solid var(--secondary);
|
||||
}
|
||||
|
||||
.secondary:hover {
|
||||
background-color: var(--secondary-hover);
|
||||
border-color: var(--secondary-border-hover);
|
||||
}
|
||||
|
||||
.paper {
|
||||
background-color: var(--paper);
|
||||
border: 4px solid var(--paper-border);
|
||||
}
|
||||
|
||||
.background {
|
||||
background-color: var(--background);
|
||||
}
|
||||
|
||||
.info {
|
||||
background-color: var(--info);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@code {
|
||||
string accent = "#432462";
|
||||
string primary = "#4308a3";
|
||||
string primary_border = "#2c0b62";
|
||||
string primary_hover = "#5e00f7";
|
||||
string primary_border_hover = "#a168ff";
|
||||
string background = "#161618";
|
||||
string secondary = "#23133e";
|
||||
string secondary_hover = "#2a0070";
|
||||
string secondary_border_hover = "#a168ff";
|
||||
string paper = "#252526";
|
||||
string paper_border = "#151516";
|
||||
string info = "#451376";
|
||||
readonly string info_border = "#210b36";
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
.colorContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.color {
|
||||
padding: 12px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 32px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.accent {
|
||||
background-color: var(--accent);
|
||||
}
|
||||
|
||||
.primary {
|
||||
background-color: var(--primary);
|
||||
border: 1px solid var(--primary-border);
|
||||
}
|
||||
|
||||
.primary:hover {
|
||||
background-color: var(--primary-hover);
|
||||
border-color: var(--primary-border-hover);
|
||||
}
|
||||
|
||||
.secondary {
|
||||
background-color: var(--secondary);
|
||||
border: 1px solid var(--secondary);
|
||||
}
|
||||
|
||||
.secondary:hover {
|
||||
background-color: var(--secondary-hover);
|
||||
border-color: var(--secondary-border-hover);
|
||||
}
|
||||
|
||||
.paper {
|
||||
background-color: var(--paper);
|
||||
border: 4px solid var(--paper-border);
|
||||
}
|
||||
|
||||
.background {
|
||||
background-color: var(--background);
|
||||
}
|
||||
|
||||
.info {
|
||||
background-color: var(--info);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<MakingOfComponent>
|
||||
<Title>Dialog</Title>
|
||||
<Description>...</Description>
|
||||
<Example>
|
||||
<DialogComponent></DialogComponent>
|
||||
</Example>
|
||||
<Usage>
|
||||
//TODO
|
||||
</Usage>
|
||||
<Code>
|
||||
//TODO
|
||||
</Code>
|
||||
</MakingOfComponent>
|
||||
|
||||
|
||||
@code {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
<MakingOfComponent>
|
||||
<Title>
|
||||
Entity Display
|
||||
</Title>
|
||||
<Description>
|
||||
Display element for holding entity information.
|
||||
</Description>
|
||||
<Example>
|
||||
<LayoutRowComponent>
|
||||
<EntityDisplayComponent Title="Example Entity Info">
|
||||
<div>
|
||||
Example Entity Content
|
||||
</div>
|
||||
|
||||
@for (var i = 0; i < 1; i++) {
|
||||
<div>
|
||||
-@i Example Entity Content
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
</div>
|
||||
</EntityDisplayComponent>
|
||||
<EntityDisplayComponent Title="Example Entity Info">
|
||||
<div>
|
||||
Example Entity Content
|
||||
</div>
|
||||
|
||||
@for (var i = 0; i < 2; i++) {
|
||||
<div>
|
||||
-@i Example Entity Content
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation.
|
||||
</div>
|
||||
</EntityDisplayComponent>
|
||||
<EntityDisplayComponent Title="Example Entity Info">
|
||||
<div>
|
||||
Example Entity Content
|
||||
</div>
|
||||
|
||||
@for (var i = 0; i < 1; i++) {
|
||||
<div>
|
||||
-@i Example Entity Content
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
</div>
|
||||
</EntityDisplayComponent>
|
||||
</LayoutRowComponent>
|
||||
</Example>
|
||||
<Usage>
|
||||
<CodeComponent>
|
||||
<LayoutRowComponent>
|
||||
<EntityDisplayComponent Title="Example Entity Info">
|
||||
<div>
|
||||
Example Entity Content
|
||||
</div>
|
||||
|
||||
@@for (var i = 0; i < 1; i++) {
|
||||
<div>
|
||||
-@@i Example Entity Content
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
</div>
|
||||
</EntityDisplayComponent>
|
||||
<EntityDisplayComponent Title="Example Entity Info">
|
||||
<div>
|
||||
Example Entity Content
|
||||
</div>
|
||||
|
||||
@@for (var i = 0; i < 2; i++) {
|
||||
<div>
|
||||
-@@i Example Entity Content
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation.
|
||||
</div>
|
||||
</EntityDisplayComponent>
|
||||
<EntityDisplayComponent Title="Example Entity Info">
|
||||
<div>
|
||||
Example Entity Content
|
||||
</div>
|
||||
|
||||
@@for (var i = 0; i < 1; i++) {
|
||||
<div>
|
||||
-@@i Example Entity Content
|
||||
</div>
|
||||
}
|
||||
|
||||
<div>
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||
</div>
|
||||
</EntityDisplayComponent>
|
||||
</LayoutRowComponent>
|
||||
</CodeComponent>
|
||||
</Usage>
|
||||
<Code>
|
||||
<CodeComponent>
|
||||
<div class="entityDisplaySection">
|
||||
<div class="entityDisplayHeader">
|
||||
<div class="entityDisplayTitle">
|
||||
@@Title
|
||||
</div>
|
||||
<div class="entityDisplayBorder">
|
||||
</div>
|
||||
</div>
|
||||
@@ChildContent
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.entityDisplaySection {
|
||||
position: relative;
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-direction: column;
|
||||
margin-top: 14px;
|
||||
margin-top: 20px;
|
||||
padding: 12px;
|
||||
background-color: var(--info);
|
||||
border-top-right-radius: 12px;
|
||||
border-bottom-left-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
|
||||
.entityDisplayHeader {
|
||||
bottom: 100%;
|
||||
position: absolute;
|
||||
white-space: pre;
|
||||
width: 100%;
|
||||
line-height: 0px;
|
||||
right: 0px;
|
||||
top: -4px;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.entityDisplayTitle {
|
||||
font-weight: 800;
|
||||
font-size: 1.4rem;
|
||||
padding-right: 8px;
|
||||
text-shadow: 3px 0 0 var(--info), -3px 0 0 var(--info), 0 3px 0 var(--info), 0 -3px 0 var(--info), 2px 2px var(--info), -2px -2px 0 var(--info), 2px -2px 0 var(--info), -2px 2px 0 var(--info);
|
||||
}
|
||||
|
||||
@@@@media only screen and (max-width: 1025px) {
|
||||
.entityDisplayHeader {
|
||||
position: inherit;
|
||||
width: 100%;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.entityDisplaySection {
|
||||
position: inherit;
|
||||
width: 100%;
|
||||
margin: 0px;
|
||||
max-width: none;
|
||||
border-top-right-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
border-bottom-right-radius: 0px;
|
||||
}
|
||||
|
||||
.entityDisplayTitle {
|
||||
position: inherit;
|
||||
margin: 0px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@code {
|
||||
[Parameter] public RenderFragment ChildContent { get; set; }
|
||||
[Parameter] public string Title { get; set; }
|
||||
}
|
||||
</CodeComponent>
|
||||
</Code>
|
||||
</MakingOfComponent>
|
||||
@@ -0,0 +1,58 @@
|
||||
<WebsiteTitleComponent>
|
||||
Feedback
|
||||
</WebsiteTitleComponent>
|
||||
|
||||
<MakingOfComponent>
|
||||
<Title>
|
||||
Loading
|
||||
</Title>
|
||||
<Description>
|
||||
Indicates a component is being loaded (a component that relies on JSON)
|
||||
</Description>
|
||||
<Example>
|
||||
<div style="width: 300px; height: 450px;">
|
||||
|
||||
<LoadingComponent></LoadingComponent>
|
||||
</div>
|
||||
</Example>
|
||||
<Usage>
|
||||
<CodeComponent>Empty</CodeComponent>
|
||||
</Usage>
|
||||
<Code>
|
||||
<CodeComponent>Empty</CodeComponent>
|
||||
</Code>
|
||||
</MakingOfComponent>
|
||||
|
||||
|
||||
<MakingOfComponent>
|
||||
<Title>Alert Message</Title>
|
||||
<Description>Used to convey important information to the viewer. Comes in Yellow (Warning), Blue (Information), Red (Error), and Green (Success). Mostly used to warn viewers of pre-alpha or incomplete content being viewed.</Description>
|
||||
<Example>
|
||||
<AlertComponent Type="SeverityType.Warning">
|
||||
<Title>Warning Alert Title</Title>
|
||||
<Message>Warning Alert Message</Message>
|
||||
</AlertComponent>
|
||||
<AlertComponent Type="SeverityType.Information">
|
||||
<Title>Information Alert Title</Title>
|
||||
<Message>Information Alert Message</Message>
|
||||
</AlertComponent>
|
||||
<AlertComponent Type="SeverityType.Error">
|
||||
<Title>Error Alert Title</Title>
|
||||
<Message>Error Alert Message</Message>
|
||||
</AlertComponent>
|
||||
<AlertComponent Type="SeverityType.Success">
|
||||
<Title>Succsess Alert Title</Title>
|
||||
<Message>Succsess Alert Message</Message>
|
||||
</AlertComponent>
|
||||
</Example>
|
||||
<Usage>
|
||||
<CodeComponent><AlertComponent Type=SeverityType.Warning><br/> <Title>Warning Alert Title</Title><br/> <Message>Warning Alert Message</Message><br/></AlertComponent><br/><AlertComponent Type=SeverityType.Information><br/> <Title>Information Alert Title</Title><br/> <Message>Information Alert Message</Message><br/></AlertComponent><br/><AlertComponent Type=SeverityType.Error><br/> <Title>Error Alert Title</Title><br/> <Message>Error Alert Message</Message><br/></AlertComponent><br/><AlertComponent Type=SeverityType.Success><br/> <Title>Succsess Alert Title</Title><br/> <Message>Succsess Alert Message</Message><br/></AlertComponent><br/></CodeComponent>
|
||||
</Usage>
|
||||
<Code>
|
||||
<CodeComponent>@@using Components.Pages.Utils<br/><br/><div class="alertContainer @@Type.ToString().ToLower()"><br/> @@if (Title != null) {<br/> <div class="alertTitle"><br/> @@Title<br/> </div><br/> }<br/> @@if (Message != null) {<br/> <div><br/> @@Message<br/> </div><br/><br/> }<br/></div><br/><style><br/> .alertContainer {<br/> border: 4px solid;<br/> border-radius: 4px;<br/> padding: 16px;<br/> display: flex;<br/> flex-direction: column;<br/> justify-items: stretch;<br/> width: 100%;<br/> }<br/><br/> .alertContainer.@@SeverityType.Warning.ToString().ToLower() {<br/> border-color: #2a2000;<br/> background-color: #ffbf0029;<br/> }<br/><br/> .alertContainer.@@SeverityType.Error.ToString().ToLower() {<br/> border-color: #290102;<br/> background-color: #4C2C33;<br/> }<br/><br/> .alertContainer.@@SeverityType.Information.ToString().ToLower() {<br/> border-color: #030129;<br/> background-color: #2c3a4c;<br/> }<br/><br/> .alertContainer.@@SeverityType.Success.ToString().ToLower() {<br/> border-color: #042901;<br/> background-color: #2E4C2C;<br/> }<br/><br/> .alertTitle {<br/> font-weight: 800;<br/> }<br/><br/></style><br/>@@code {<br/> [Parameter] public RenderFragment? Title { get; set; }<br/> [Parameter] public RenderFragment? Message { get; set; }<br/> [Parameter] public SeverityType Type { get; set; } = SeverityType.Warning;<br/>}</CodeComponent>
|
||||
</Code>
|
||||
</MakingOfComponent>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<MakingOfComponent>
|
||||
<Title>Form Text</Title>
|
||||
<Description>Add Text Input</Description>
|
||||
<Example>
|
||||
<FormLayoutComponent>
|
||||
<FormTextComponent Label="Label Text" Info="Info Text" Placeholder="Placeholder Text..." Value="Value Text"/>
|
||||
<FormTextAreaComponent Label="Label Text" Info="Info Text" Placeholder="Placeholder Text..." Value="Value Text"/>
|
||||
</FormLayoutComponent>
|
||||
</Example>
|
||||
<Usage>
|
||||
//TODO
|
||||
</Usage>
|
||||
<Code>
|
||||
//TODO
|
||||
</Code>
|
||||
</MakingOfComponent>
|
||||
|
||||
|
||||
<MakingOfComponent>
|
||||
<Title>Form Area</Title>
|
||||
<Description>Add Text Body Input</Description>
|
||||
<Example>
|
||||
<FormTextAreaComponent Label="Label Text" Info="Info Text" Placeholder="Placeholder Text..." Value="Value Text"/>
|
||||
</Example>
|
||||
<Usage>
|
||||
//TODO
|
||||
</Usage>
|
||||
<Code>
|
||||
//TODO
|
||||
</Code>
|
||||
</MakingOfComponent>
|
||||
|
||||
@code {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<MakingOfComponent>
|
||||
<Title>
|
||||
Nav Section with Nav Links
|
||||
</Title>
|
||||
<Description>
|
||||
Group specfic webpages. Each webpage link is used to navigate to that specific webpage. If on the webpage, the link turns dark gray. It can be clicked again to leave the page and return to home.
|
||||
</Description>
|
||||
<Example>
|
||||
<NavSectionComponent 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" } })>
|
||||
</NavSectionComponent>
|
||||
</Example>
|
||||
<Usage>
|
||||
<CodeComponent>
|
||||
<NavSectionComponent Section=@@(new WebSectionModel{Name = "Example Section"})
|
||||
Children=@@(new List<WebPageModel>{new WebPageModel{Name="Example Page", Href = "immortal-makingof", IsPrivate = false}, new WebPageModel{Name="Database", Href = "immortal-database", IsPrivate = false}})>
|
||||
</NavSectionComponent>
|
||||
</CodeComponent>
|
||||
</Usage>
|
||||
<Code>
|
||||
<CodeComponent>
|
||||
@@using Model.Website;
|
||||
@@using Model.Website.Enums;
|
||||
|
||||
<div class="sectionContainer">
|
||||
<div class="sectionHeader">
|
||||
<div class="sectionTitle">
|
||||
@@Section.Name
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@foreach (var childPage in Children) {
|
||||
if (childPage.IsPrivate) {
|
||||
continue;
|
||||
}
|
||||
<NavLinkComponent Page=childPage></NavLinkComponent>
|
||||
}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.sectionContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
justify-content: flex-start;
|
||||
position: relative;
|
||||
margin-top: 12px;
|
||||
padding: 18px;
|
||||
width: 300px;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.sectionHeader {
|
||||
bottom: 100%;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: -8px;
|
||||
padding-right: 12px;
|
||||
padding-left: 4px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
line-height: 0px;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-weight: bold;
|
||||
padding-right: 8px;
|
||||
margin-top: -2px;
|
||||
white-space: pre;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@code {
|
||||
[Parameter] public WebSectionModel? Section { get; set; }
|
||||
[Parameter] public List<WebPageModel>? Children { get; set; }
|
||||
}
|
||||
|
||||
</CodeComponent>
|
||||
</Code>
|
||||
</MakingOfComponent>
|
||||
@@ -0,0 +1,39 @@
|
||||
@layout PageLayout
|
||||
|
||||
@page "/memory-tester"
|
||||
|
||||
<LayoutMediumContentComponent>
|
||||
<WebsiteTitleComponent>Memory Tester</WebsiteTitleComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<UnitMemoryManager></UnitMemoryManager>
|
||||
</PaperComponent>
|
||||
|
||||
<ContentDividerComponent></ContentDividerComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
What is this tool?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
A tool to test your memory of unit stats. Look at the first unit given, and fill in the remaining stats based on how they should compare.
|
||||
|
||||
<br/><br/>
|
||||
For example, if the first unit you see is the Masked Hunter of range 400, do you remember the range of the Scepter? Are they the same? Does the Scepter have double the range of the Masked Hunter? Less range than it? Well, enter your guess and submit! <SpoilerTextComponent>The range is 200 longer, so if you remember that, you know you are going to need more than Masked Hunters to deal with hard to reach enemy Scepters.</SpoilerTextComponent>
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>
|
||||
Why is this tool here?
|
||||
</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>
|
||||
It was just a tool to quickly develop for fun when I didn't want to cover something larger on the 02/27/2022 live coding stream.
|
||||
<br/><br/>
|
||||
It may get expanded upon later.
|
||||
</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
</PaperComponent>
|
||||
|
||||
</LayoutMediumContentComponent>
|
||||
@@ -0,0 +1,117 @@
|
||||
@implements IDisposable;
|
||||
@inject IMemoryTesterService MemoryTesterService;
|
||||
|
||||
<div class="unitMemoryContainer@(isCorrect ? " correct" : isWrong ? "wrong" : "")">
|
||||
<FormLayoutComponent>
|
||||
<FormDisplayComponent Label="Name">
|
||||
<Display>@EntityMemory.Name</Display>
|
||||
</FormDisplayComponent>
|
||||
|
||||
@foreach (var question in questions) {
|
||||
var questionWrong = hasBeenSubmitted && !question.IsRevealed && question.Guess != question.Answer;
|
||||
|
||||
<FormGuessComponent IsSubmitted="hasBeenSubmitted"
|
||||
OnChange="answerEventArgs => OnAnswerEntered(answerEventArgs, question)"
|
||||
MemoryQuestion="question"/>
|
||||
|
||||
@if (questionWrong) {
|
||||
<div class="wrongAnswer">The correct answer was @question.Answer</div>
|
||||
}
|
||||
}
|
||||
|
||||
</FormLayoutComponent>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.unitMemoryContainer {
|
||||
}
|
||||
|
||||
.unitMemoryContainer.correct {
|
||||
border-color: green;
|
||||
|
||||
}
|
||||
|
||||
.unitMemoryContainer.wrong {
|
||||
border-color: red;
|
||||
}
|
||||
|
||||
.wrongAnswer {
|
||||
padding: 12px;
|
||||
color: #ff2525;
|
||||
font-weight: 700;
|
||||
background-color: rgba(0,0,0,0.4);
|
||||
padding: 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
|
||||
[Parameter]
|
||||
public MemoryEntityModel EntityMemory { get; set; }
|
||||
|
||||
private List<MemoryQuestionModel> questions { get; set; }
|
||||
|
||||
private bool hasBeenSubmitted = false;
|
||||
private bool isCorrect = false;
|
||||
private bool isWrong = false;
|
||||
|
||||
public int Guess { get; set; }
|
||||
|
||||
protected override void OnInitialized() {
|
||||
MemoryTesterService.Subscribe(OnMemoryEvent);
|
||||
|
||||
OnRefresh();
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
MemoryTesterService.Unsubscribe(OnMemoryEvent);
|
||||
}
|
||||
|
||||
void OnMemoryEvent(MemoryTesterEvent memoryTesterEvent) {
|
||||
if (memoryTesterEvent == MemoryTesterEvent.OnVerify) {
|
||||
OnVerify();
|
||||
}
|
||||
|
||||
if (memoryTesterEvent == MemoryTesterEvent.OnRefresh) {
|
||||
OnRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void OnAnswerEntered(AnswerEventArgs answerEventArgs, MemoryQuestionModel question) {
|
||||
question.Guess = answerEventArgs.Guess;
|
||||
|
||||
MemoryTesterService.Update(question);
|
||||
}
|
||||
|
||||
void OnVerify() {
|
||||
hasBeenSubmitted = true;
|
||||
|
||||
isCorrect = true;
|
||||
|
||||
foreach (var question in questions) {
|
||||
if (question.Answer != question.Guess) {
|
||||
isCorrect = false;
|
||||
isWrong = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
void OnRefresh() {
|
||||
hasBeenSubmitted = false;
|
||||
isCorrect = false;
|
||||
isWrong = false;
|
||||
|
||||
questions = (from question in MemoryTesterService.GetQuestions()
|
||||
where question.MemoryEntityModelId == EntityMemory.Id
|
||||
select question).ToList();
|
||||
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
@implements IDisposable;
|
||||
|
||||
@inject IMemoryTesterService MemoryTesterService;
|
||||
|
||||
<div class="quizContainer">
|
||||
<div class="quizListContainer">
|
||||
@if (entities != null && questions != null) {
|
||||
@foreach (var entityMemory in entities) {
|
||||
<UnitMemory EntityMemory="entityMemory"></UnitMemory>
|
||||
}
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="quizButtons">
|
||||
<ButtonComponent ButtonType="ButtonType.Secondary" OnClick="OnRefreshQuiz">Refresh</ButtonComponent>
|
||||
<ButtonComponent ButtonType="ButtonType.Primary" OnClick="OnSubmitQuiz">Submit</ButtonComponent>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.quizContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.quizListContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
@@media (min-width: @SupportedWebSizes.Tablet) {
|
||||
.quizContainer {
|
||||
}
|
||||
|
||||
.quizButtons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 16px;
|
||||
justify-content: flex-end;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.quizListContainer {
|
||||
}
|
||||
}
|
||||
|
||||
@@media (min-width: @SupportedWebSizes.Desktop) {
|
||||
.quizListContainer {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@code {
|
||||
private List<MemoryEntityModel> entities;
|
||||
private List<MemoryQuestionModel> questions;
|
||||
|
||||
protected override void OnInitialized() {
|
||||
MemoryTesterService.Subscribe(OnMemoryEvent);
|
||||
|
||||
MemoryTesterService.GenerateQuiz();
|
||||
}
|
||||
|
||||
void IDisposable.Dispose() {
|
||||
MemoryTesterService.Unsubscribe(OnMemoryEvent);
|
||||
}
|
||||
|
||||
void OnMemoryEvent(MemoryTesterEvent memoryTesterEvent) {
|
||||
if (memoryTesterEvent == MemoryTesterEvent.OnVerify) {
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
if (memoryTesterEvent == MemoryTesterEvent.OnRefresh) {
|
||||
entities = MemoryTesterService.GetEntities();
|
||||
questions = MemoryTesterService.GetQuestions();
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void OnSubmitQuiz(EventArgs eventArgs) {
|
||||
MemoryTesterService.Verify();
|
||||
}
|
||||
|
||||
void OnRefreshQuiz(EventArgs eventArgs) {
|
||||
MemoryTesterService.GenerateQuiz();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
@layout PageLayout
|
||||
|
||||
@page "/notes"
|
||||
|
||||
<LayoutMediumContentComponent>
|
||||
<WebsiteTitleComponent>Notes</WebsiteTitleComponent>
|
||||
|
||||
<div class="section">
|
||||
<div for="noteSection">Section: </div>
|
||||
<div style="flex: 1"></div>
|
||||
<select @oninput="OnSectionChanged" style="background-color: #36393F; width: 250px; margin-right: 16px;" name="noteSection">
|
||||
<option value="All">All</option>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="notesContainer">
|
||||
@foreach (var note in data) {
|
||||
if (note.IsHidden) {
|
||||
continue;
|
||||
}
|
||||
if (selectedSection != "All" && note.Section != selectedSection) {
|
||||
continue;
|
||||
}
|
||||
@if (note.IsPreAlpha) {
|
||||
<AlertComponent Type=SeverityType.Warning>
|
||||
<Title>Pre Alpha</Title>
|
||||
<Message>This note refers to content that is in pre-alpha. It won't be accurate in future updates to IGP.</Message>
|
||||
</AlertComponent>
|
||||
}
|
||||
<PaperComponent>
|
||||
<div style="display: flex; flex-direction: row;">
|
||||
<span style="font-weight: bold; font-style:italic;">@note.Section</span>
|
||||
<div style="flex: 1"></div>
|
||||
<span style="font-weight: bold; font-style:italic;">Last Updated on @note.LastUpdated</span>
|
||||
</div>
|
||||
<div>
|
||||
<div id="@note.DEPRECATED_Id()" style="font-weight: bold; font-size: 1.4rem;">@note.Name</div>
|
||||
<div style="white-space:break-spaces;">@((MarkupString)note.Description)</div>
|
||||
</div>
|
||||
</PaperComponent>
|
||||
}
|
||||
</div>
|
||||
</LayoutMediumContentComponent>
|
||||
|
||||
<style>
|
||||
.section {
|
||||
display: flex;
|
||||
width: 500px;
|
||||
flex-direction: row;
|
||||
padding: 4px;
|
||||
border: 2px solid black;
|
||||
background-color: var(--paper);
|
||||
justify-content: center;
|
||||
padding: 24px;
|
||||
border: 4px solid var(--paper-border);
|
||||
box-shadow: 0px 6px var(--paper-border);
|
||||
}
|
||||
|
||||
.notesContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.noteContainer {
|
||||
padding: 24px;
|
||||
border: 2px solid black;
|
||||
margin: auto;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
background-color: var(--paper);
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
readonly List<NoteModel> data = NoteModel.Notes.Values.ToList();
|
||||
|
||||
string selectedSection = "All";
|
||||
|
||||
void OnSectionChanged(ChangeEventArgs e) {
|
||||
selectedSection = e.Value.ToString();
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
@page "/notes/coop-holdout"
|
||||
|
||||
<div class="page">
|
||||
<PageContainerComponent>
|
||||
<LayoutNoteContentComponent>
|
||||
@if (note.IsPreAlpha) {
|
||||
<AlertComponent>
|
||||
<Title>Pre Alpha</Title>
|
||||
<Message>This note refers to content that is in pre-alpha. It won't be accurate in future updates to IGP.</Message>
|
||||
</AlertComponent>
|
||||
}
|
||||
|
||||
<div class="paper">
|
||||
<div style="display: flex; flex-direction: row;">
|
||||
<span style="font-weight: bold; font-style:italic;">@note.Section</span>
|
||||
<div style="flex: 1"></div>
|
||||
<span style="font-weight: bold; font-style:italic;">Last Updated on @note.LastUpdated</span>
|
||||
</div>
|
||||
<div>
|
||||
<div id="@note.DEPRECATED_Id()" style="font-weight: bold; font-size: 1.4rem;">@note.Name</div>
|
||||
<div style="white-space:break-spaces;">@((MarkupString)note.Description)</div>
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
|
||||
</LayoutNoteContentComponent>
|
||||
</PageContainerComponent>
|
||||
|
||||
</div>
|
||||
<style>
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
gap: 16px;
|
||||
|
||||
}
|
||||
|
||||
.paper {
|
||||
padding: 24px;
|
||||
overflow-x:hidden;
|
||||
background-color:var(--paper);
|
||||
}
|
||||
|
||||
@@media only screen and (max-width: 1025px) {
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 2px;
|
||||
gap: 2px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
readonly NoteModel note = NoteModel.Notes["79d80c48-67d4-4945-a3ed-7c7803b5f6b5"];
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
href: /notes/example title: Example
|
||||
---
|
||||
|
||||
Information contained in this note is based on this <a href="https://www.youtube.com/watch?v=XkAgOCIz3DE">YouTube,
|
||||
Reference Video</a>.
|
||||
|
||||
<img width="420" style="margin: auto; border:2px solid black;" src="notes/coop-holdout/OpenBases.png" />
|
||||
<div style="margin: auto; text-align:center;"><b>Open Bases</b></div>
|
||||
|
||||
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.
|
||||
|
||||
|
||||
<img width="420" style="margin: auto; border:2px solid black;" src="notes/coop-holdout/EnemySpawns.png" />
|
||||
<div style="margin: auto; text-align:center;"><b>Enemy Spawn Areas</b></div>
|
||||
|
||||
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.
|
||||
|
||||
<img width="420" style="margin: auto; border:2px solid black;" src="notes/coop-holdout/DefendPoints.png" />
|
||||
<div style="margin: auto; text-align:center;"><b>Pyre Towers</b></div>
|
||||
|
||||
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.
|
||||
|
||||
<img width="420" style="margin: auto; border:2px solid black;" src="notes/coop-holdout/Pyre.png" />
|
||||
<div style="margin: auto; text-align:center;"><b>Pyre Camps</b></div>
|
||||
|
||||
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.
|
||||
|
||||
<img width="420" style="margin: auto; border:2px solid black;" src="notes/coop-holdout/Multipliers.png" />
|
||||
<div style="margin: auto; text-align:center;"><b>Multipliers</b></div>
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,12 @@
|
||||
@page "/raw-database"
|
||||
|
||||
<div class="page">
|
||||
<AlertComponent>
|
||||
<Title>Placeholders and Speculative</Title>
|
||||
<Message>The data I am using contains placeholders and speculation on future mechanics. Ignore said data when using this JSON.</Message>
|
||||
</AlertComponent>
|
||||
|
||||
<CodeComponent>
|
||||
@DATA.AsJson()
|
||||
</CodeComponent>
|
||||
</div>
|
||||
@@ -0,0 +1,15 @@
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 16px;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1025px) {
|
||||
.page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 2px;
|
||||
gap: 2px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<div class="roadMapContainer @RoadMap.Status.ToLower()">
|
||||
<div class="roadMapTitle">@RoadMap.Name</div>
|
||||
<div>
|
||||
<b>Priority:</b> @RoadMap.Priority.Replace("_", " ")
|
||||
</div>
|
||||
<div>
|
||||
<b>Status:</b> @RoadMap.Status.Replace("_", " ")
|
||||
</div>
|
||||
<div>@((MarkupString)RoadMap.Description)</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.roadMapContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 2px solid black;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
width: 100%;
|
||||
gap: 10px;
|
||||
padding-bottom: 26px;
|
||||
max-width: 420px;
|
||||
}
|
||||
|
||||
.roadMapContainer.@ReleaseStatusType.In_Development.ToLower() {
|
||||
border-color: #030129;
|
||||
background-color: #2c3a4c;
|
||||
}
|
||||
|
||||
.roadMapContainer.@ReleaseStatusType.Cancelled.ToLower() {
|
||||
border-color: #290102;
|
||||
background-color: #290102;
|
||||
}
|
||||
|
||||
.roadMapContainer.@ReleaseStatusType.Done.ToLower() {
|
||||
border-color: #042901;
|
||||
background-color: #2E4C2C;
|
||||
}
|
||||
|
||||
.roadMapContainer.@ReleaseStatusType.Future_Possibility.ToLower() {
|
||||
border-color: #2a2000;
|
||||
background-color: #ffbf0029;
|
||||
}
|
||||
|
||||
.roadMapContainer.@ReleaseStatusType.Planned.ToLower() {
|
||||
background-color: var(--paper);
|
||||
}
|
||||
|
||||
.roadMapTitle {
|
||||
font-weight: 800;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
[Parameter]
|
||||
public ImmortalRoadMapModel? RoadMap { get; set; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
@layout PageLayout
|
||||
|
||||
@page "/roadmap"
|
||||
|
||||
<LayoutLargeContentComponent>
|
||||
<WebsiteTitleComponent>Road Map</WebsiteTitleComponent>
|
||||
|
||||
<div class="roadMapsContainer">
|
||||
@foreach (var roadMap in data) {
|
||||
<RoadMapComponent RoadMap=roadMap/>
|
||||
}
|
||||
</div>
|
||||
</LayoutLargeContentComponent>
|
||||
|
||||
<style>
|
||||
.roadMapsContainer {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
flex-wrap: wrap;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
readonly List<ImmortalRoadMapModel> data = ImmortalRoadMapModel.Data;
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
@layout PageLayout
|
||||
@page "/sandbox"
|
||||
@inject IJSRuntime JS
|
||||
|
||||
<LayoutLargeContentComponent>
|
||||
<WebsiteTitleComponent>Sandbox</WebsiteTitleComponent>
|
||||
|
||||
<div>
|
||||
Generic Page of Testing In Progress code
|
||||
</div>
|
||||
|
||||
<button @onclick="() => DownloadFile(typeof(WebPageModel))">
|
||||
WebPageModel
|
||||
</button>
|
||||
|
||||
<button @onclick="() => DownloadFile(typeof(WebSectionModel))">
|
||||
WebSectionModel
|
||||
</button>
|
||||
|
||||
<button @onclick="() => DownloadFile(typeof(PatchModel))">
|
||||
PatchModel
|
||||
</button>
|
||||
|
||||
<button @onclick="() => DownloadFile(typeof(ChangeModel))">
|
||||
ChangeModel
|
||||
</button>
|
||||
|
||||
<button @onclick="() => DownloadFile(typeof(SprintModel))">
|
||||
SprintModel
|
||||
</button>
|
||||
|
||||
<button @onclick="() => DownloadFile(typeof(TaskModel))">
|
||||
TaskModel
|
||||
</button>
|
||||
|
||||
<FormLayoutComponent>
|
||||
<FormTextAreaComponent Value="@infoText"></FormTextAreaComponent>
|
||||
</FormLayoutComponent>
|
||||
|
||||
|
||||
</LayoutLargeContentComponent>
|
||||
|
||||
|
||||
@code {
|
||||
readonly List<EntityModel> entities = EntityModel.GetList();
|
||||
|
||||
List<EntityInfoModel> infos = new();
|
||||
|
||||
string infoText = "";
|
||||
string weaponText = "";
|
||||
|
||||
readonly List<ChangeModel> changes = new();
|
||||
readonly List<PatchModel> patches = new();
|
||||
|
||||
private async Task DownloadFile(Type type) {
|
||||
var fileName = $"{type.ToString().Split(".").Last()}s.csv";
|
||||
|
||||
var objectData =
|
||||
type == typeof(PatchModel) ? new List<object>(patches)
|
||||
: type == typeof(ChangeModel) ? new List<object>(changes)
|
||||
: new List<object>();
|
||||
|
||||
await JS.InvokeVoidAsync("download", fileName, Generate(type, objectData));
|
||||
}
|
||||
|
||||
void GenerateEntityModels() {
|
||||
var properties = typeof(EntityInfoModel).GetProperties();
|
||||
|
||||
infoText += "Id,Name,Descriptive,Description,Notes\n";
|
||||
|
||||
var id = 1;
|
||||
foreach (var entity in entities) {
|
||||
infoText += $"{id++},{entity.Info().Name},{entity.Info().Descriptive},{entity.Info().Description},{entity.Info().Notes}\n";
|
||||
}
|
||||
}
|
||||
|
||||
string Generate(Type type, List<object> dataList) {
|
||||
var properties = type.GetProperties();
|
||||
|
||||
var generatedText = "";
|
||||
|
||||
for (var index = 0; index < properties.Count(); index++) {
|
||||
var property = properties[index];
|
||||
|
||||
if (property.GetAccessors().First().IsVirtual) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var attributes = property.GetCustomAttributes().OfType<ObsoleteAttribute>();
|
||||
if (attributes.Count() > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
generatedText += property.Name;
|
||||
if (index != properties.Count() - 1) {
|
||||
generatedText += ",";
|
||||
}
|
||||
}
|
||||
|
||||
generatedText = generatedText.Trim();
|
||||
if (generatedText.EndsWith(",")) {
|
||||
generatedText = generatedText.Remove(generatedText.Length - 1);
|
||||
}
|
||||
|
||||
|
||||
generatedText += "\n";
|
||||
|
||||
foreach (var data in dataList) {
|
||||
for (var index = 0; index < properties.Count(); index++) {
|
||||
var property = properties[index];
|
||||
|
||||
if (property.GetAccessors().First().IsVirtual) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var attributes = property.GetCustomAttributes().OfType<ObsoleteAttribute>();
|
||||
if (attributes.Count() > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (property.GetValue(data) != null) {
|
||||
generatedText += "\"" + property.GetValue(data).ToString().Replace("\"", "\"\"") + "\"";
|
||||
if (index != properties.Count() - 1) {
|
||||
generatedText += ",";
|
||||
}
|
||||
}
|
||||
else {
|
||||
generatedText += "\"" + " " + "\"";
|
||||
if (index != properties.Count() - 1) {
|
||||
generatedText += ",";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generatedText = generatedText.Trim();
|
||||
if (generatedText.EndsWith(",")) {
|
||||
generatedText = generatedText.Remove(generatedText.Length - 1);
|
||||
}
|
||||
|
||||
generatedText += "\n";
|
||||
}
|
||||
|
||||
|
||||
return generatedText;
|
||||
}
|
||||
|
||||
|
||||
void GenerateWeapons() {
|
||||
var properties = typeof(EntityWeaponModel).GetProperties();
|
||||
|
||||
for (var index = 0; index < properties.Count(); index++) {
|
||||
var property = properties[index];
|
||||
|
||||
if (property.GetAccessors().First().IsVirtual) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var attributes = property.GetCustomAttributes().OfType<ObsoleteAttribute>
|
||||
();
|
||||
if (attributes.Count() > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
weaponText += property.Name;
|
||||
if (index != properties.Count() - 1) {
|
||||
weaponText += ",";
|
||||
}
|
||||
}
|
||||
|
||||
weaponText += "\n";
|
||||
|
||||
foreach (var entity in entities) {
|
||||
foreach (var weapon in entity.Weapons()) {
|
||||
for (var index = 0; index < properties.Count(); index++) {
|
||||
var property = properties[index];
|
||||
|
||||
if (property.GetAccessors().First().IsVirtual) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
var attributes = property.GetCustomAttributes().OfType<ObsoleteAttribute>
|
||||
();
|
||||
if (attributes.Count() > 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
weaponText += property.GetValue(weapon);
|
||||
if (index != properties.Count() - 1) {
|
||||
weaponText += ",";
|
||||
}
|
||||
}
|
||||
|
||||
weaponText += "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GenerateExample() {
|
||||
var properties = typeof(EntityInfoModel).GetProperties();
|
||||
|
||||
for (var index = 0; index < properties.Count(); index++) {
|
||||
var property = properties[index];
|
||||
infoText += property.Name;
|
||||
if (index != properties.Count() - 1) {
|
||||
infoText += ",";
|
||||
}
|
||||
}
|
||||
|
||||
infoText += "\n";
|
||||
|
||||
foreach (var entity in entities) {
|
||||
if (entity.Info() != null) {
|
||||
for (var index = 0; index < properties.Count(); index++) {
|
||||
var property = properties[index];
|
||||
infoText += property.GetValue(entity.Info());
|
||||
if (index != properties.Count() - 1) {
|
||||
infoText += ",";
|
||||
}
|
||||
}
|
||||
|
||||
infoText += "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
@page "/streams"
|
||||
|
||||
@layout PageLayout
|
||||
|
||||
<LayoutMediumContentComponent>
|
||||
<WebsiteTitleComponent>Streams</WebsiteTitleComponent>
|
||||
|
||||
<PaperComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>When and where are you streaming?</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>I stream Sunday updates on <a href="https://www.twitch.tv/iremirror" target="_blank">Twitch</a>.</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>What exactly are you streaming?</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>The plan will be: sprint planning, and general development of this website.</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
<InfoBodyComponent>
|
||||
<InfoQuestionComponent>Anything else I should know?</InfoQuestionComponent>
|
||||
<InfoAnswerComponent>I'll be streaming under the "<a href="https://www.twitch.tv/directory/game/Software%20and%20Game%20Development" target="_blank">Twitch, Software and Game Development</a>" category. If you are looking to see some realy IGP gameplay, there are better and more focused streamers to provide said content. Check out the "<a href="https://www.twitch.tv/directory/game/IMMORTAL%3A%20Gates%20of%20Pyre/videos/all" target="_blank">Twitch, IMMORTAL: Gates of Pyre</a>" category for some examples.</InfoAnswerComponent>
|
||||
</InfoBodyComponent>
|
||||
</PaperComponent>
|
||||
</LayoutMediumContentComponent>
|
||||
Reference in New Issue
Block a user