Notes and Vibe start

This commit is contained in:
2026-06-14 14:55:42 -04:00
commit d231ceded9
150 changed files with 62364 additions and 0 deletions
+270
View File
@@ -0,0 +1,270 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
# Visual Studio 2015 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUNIT
*.VisualState.xml
TestResult.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# DNX
project.lock.json
project.fragment.lock.json
artifacts/
*_i.c
*_p.c
*_i.h
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# JustCode is a .NET coding add-in
.JustCode
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
publish_release/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# TODO: Comment the next line if you want to checkin your web deploy settings
# but database connection strings (with potential passwords) will be unencrypted
#*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# The packages folder can be ignored because of Package Restore
**/packages/*
# except build/, which is used as an MSBuild target.
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
# NuGet v3's project.json files produces more ignoreable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
node_modules/
orleans.codegen.cs
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
*.mdf
*.ldf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# JetBrains Rider
.idea/
*.sln.iml
# CodeRush
.cr/
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
**/.DS_Store
**/.vs/
.DS_Store
publish_release/
View File
View File
+1
View File
@@ -0,0 +1 @@
[]
+1
View File
@@ -0,0 +1 @@
3.0
View File
+10
View File
@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
+392
View File
@@ -0,0 +1,392 @@
using System.Globalization;
using System.Text;
var solutionRoot = FindSolutionRoot();
var docsRoot = args.Length > 0
? Path.GetFullPath(args[0])
: Path.GetFullPath(Path.Combine(solutionRoot, "..", "zs.docs"));
var modelRoot = Path.Combine(solutionRoot, "Model");
var outputPath = Path.Combine(modelRoot, "Units.g.cs");
if (!Directory.Exists(docsRoot))
{
throw new DirectoryNotFoundException($"Could not find docs directory: {docsRoot}");
}
if (!Directory.Exists(modelRoot))
{
throw new DirectoryNotFoundException($"Could not find model project directory: {modelRoot}");
}
var units = new List<UnitSource>();
var skipped = new List<string>();
foreach (var path in Directory.EnumerateFiles(docsRoot, "*.md").Order(StringComparer.OrdinalIgnoreCase))
{
var frontMatter = ReadFrontMatter(path);
if (frontMatter is null)
{
continue;
}
if (!IsUnit(frontMatter))
{
continue;
}
if (!TryReadUnit(path, frontMatter, out var unit, out var reason))
{
skipped.Add($"{Path.GetFileName(path)} ({reason})");
continue;
}
units.Add(unit);
}
units.Sort((left, right) =>
{
var faction = string.Compare(left.Faction, right.Faction, StringComparison.OrdinalIgnoreCase);
if (faction != 0)
{
return faction;
}
var tier = left.Tier.CompareTo(right.Tier);
return tier != 0
? tier
: string.Compare(left.Name, right.Name, StringComparison.OrdinalIgnoreCase);
});
File.WriteAllText(outputPath, GenerateUnits(units), Encoding.UTF8);
Console.WriteLine($"Generated {units.Count} units: {Path.GetRelativePath(solutionRoot, outputPath)}");
if (skipped.Count > 0)
{
Console.WriteLine($"Skipped {skipped.Count} incomplete unit files:");
foreach (var entry in skipped.Order(StringComparer.OrdinalIgnoreCase))
{
Console.WriteLine($"- {entry}");
}
}
static string FindSolutionRoot()
{
var directory = new DirectoryInfo(Environment.CurrentDirectory);
while (directory is not null)
{
if (directory.EnumerateFiles("ZS.sln").Any())
{
return directory.FullName;
}
directory = directory.Parent;
}
throw new DirectoryNotFoundException("Could not find ZS.sln in the current directory or its parents.");
}
static Dictionary<string, FrontMatterValue>? ReadFrontMatter(string path)
{
var lines = File.ReadAllLines(path);
if (lines.Length == 0 || lines[0].Trim() != "---")
{
return null;
}
var values = new Dictionary<string, FrontMatterValue>(StringComparer.OrdinalIgnoreCase);
string? listKey = null;
for (var i = 1; i < lines.Length; i++)
{
var line = lines[i];
if (line.Trim() == "---")
{
return values;
}
if (listKey is not null && line.StartsWith(" - ", StringComparison.Ordinal))
{
values[listKey].List.Add(CleanValue(line[4..]));
continue;
}
listKey = null;
var separatorIndex = line.IndexOf(':');
if (separatorIndex < 0)
{
continue;
}
var key = line[..separatorIndex].Trim();
var rawValue = line[(separatorIndex + 1)..].Trim();
if (rawValue.Length == 0)
{
values[key] = new FrontMatterValue(null);
listKey = key;
continue;
}
values[key] = new FrontMatterValue(CleanValue(rawValue));
}
return null;
}
static bool IsUnit(IReadOnlyDictionary<string, FrontMatterValue> frontMatter)
{
return frontMatter.TryGetValue("category", out var category)
&& string.Equals(category.Scalar, "Unit", StringComparison.OrdinalIgnoreCase);
}
static bool TryReadUnit(
string path,
IReadOnlyDictionary<string, FrontMatterValue> frontMatter,
out UnitSource unit,
out string reason)
{
unit = default!;
if (!TryGetRequiredString(frontMatter, "Faction", out var faction, out reason) ||
!TryGetRequiredInt(frontMatter, "hexite", out var hexite, out reason) ||
!TryGetRequiredInt(frontMatter, "Flux", out var flux, out reason) ||
!TryGetRequiredInt(frontMatter, "supply", out var supply, out reason) ||
!TryGetRequiredInt(frontMatter, "productionTime", out var productionTime, out reason) ||
!TryGetRequiredInt(frontMatter, "health", out var health, out reason) ||
!TryGetRequiredInt(frontMatter, "Energy", out var energy, out reason) ||
!TryGetRequiredInt(frontMatter, "Shields", out var shields, out reason) ||
!TryGetRequiredInt(frontMatter, "Armor rating", out var armorRating, out reason) ||
!TryGetRequiredInt(frontMatter, "movementSpeed", out var movementSpeed, out reason) ||
!TryGetRequiredInt(frontMatter, "damagePerSecond", out var damagePerSecond, out reason) ||
!TryGetRequiredInt(frontMatter, "attackRange", out var attackRange, out reason) ||
!TryGetRequiredInt(frontMatter, "Tier", out var tier, out reason) ||
!TryGetRequiredInt(frontMatter, "buildAtSameTime", out var buildAtSameTime, out reason))
{
return false;
}
var id = ToIdentifier(Path.GetFileNameWithoutExtension(path));
var hotkey = TryGetOptionalString(frontMatter, "Hotkey");
var attributes = frontMatter.TryGetValue("attributes", out var attributeValue)
? attributeValue.List.Where(static value => !string.IsNullOrWhiteSpace(value)).ToArray()
: [];
var limit = TryGetOptionalInt(frontMatter, "limit");
unit = new UnitSource(
id,
Path.GetFileNameWithoutExtension(path),
hexite,
flux,
supply,
productionTime,
health,
energy,
shields,
armorRating,
movementSpeed,
damagePerSecond,
attackRange,
attributes,
tier,
faction,
hotkey,
buildAtSameTime,
limit);
reason = string.Empty;
return true;
}
static bool TryGetRequiredString(
IReadOnlyDictionary<string, FrontMatterValue> frontMatter,
string key,
out string value,
out string reason)
{
if (!frontMatter.TryGetValue(key, out var frontMatterValue) ||
string.IsNullOrWhiteSpace(frontMatterValue.Scalar))
{
value = string.Empty;
reason = $"missing {key}";
return false;
}
value = frontMatterValue.Scalar;
reason = string.Empty;
return true;
}
static string? TryGetOptionalString(IReadOnlyDictionary<string, FrontMatterValue> frontMatter, string key)
{
return frontMatter.TryGetValue(key, out var frontMatterValue) &&
!string.IsNullOrWhiteSpace(frontMatterValue.Scalar)
? frontMatterValue.Scalar
: null;
}
static bool TryGetRequiredInt(
IReadOnlyDictionary<string, FrontMatterValue> frontMatter,
string key,
out int value,
out string reason)
{
if (!frontMatter.TryGetValue(key, out var frontMatterValue) ||
string.IsNullOrWhiteSpace(frontMatterValue.Scalar))
{
value = default;
reason = $"missing {key}";
return false;
}
if (!int.TryParse(frontMatterValue.Scalar, NumberStyles.Integer, CultureInfo.InvariantCulture, out value))
{
reason = $"invalid {key}";
return false;
}
reason = string.Empty;
return true;
}
static int? TryGetOptionalInt(IReadOnlyDictionary<string, FrontMatterValue> frontMatter, string key)
{
if (!frontMatter.TryGetValue(key, out var frontMatterValue) ||
string.IsNullOrWhiteSpace(frontMatterValue.Scalar))
{
return null;
}
return int.TryParse(frontMatterValue.Scalar, NumberStyles.Integer, CultureInfo.InvariantCulture, out var value)
? value
: null;
}
static string CleanValue(string value)
{
value = value.Trim();
if (value.Length >= 2 && value[0] == '"' && value[^1] == '"')
{
value = value[1..^1];
}
if (value.StartsWith("[[", StringComparison.Ordinal) && value.EndsWith("]]", StringComparison.Ordinal))
{
value = value[2..^2];
}
return value;
}
static string ToIdentifier(string name)
{
var builder = new StringBuilder();
var capitalizeNext = true;
foreach (var character in name)
{
if (char.IsLetterOrDigit(character))
{
builder.Append(capitalizeNext ? char.ToUpperInvariant(character) : character);
capitalizeNext = false;
}
else
{
capitalizeNext = true;
}
}
if (builder.Length == 0)
{
return "Unit";
}
if (char.IsDigit(builder[0]))
{
builder.Insert(0, 'U');
}
return builder.ToString();
}
static string GenerateUnits(IReadOnlyList<UnitSource> units)
{
var builder = new StringBuilder();
builder.AppendLine("// <auto-generated />");
builder.AppendLine("namespace Model;");
builder.AppendLine();
builder.AppendLine("public static class Units");
builder.AppendLine("{");
foreach (var unit in units)
{
builder.AppendLine($" public static readonly UnitData {unit.Id} = new(");
builder.AppendLine($" Id: {Literal(unit.Id)},");
builder.AppendLine($" Name: {Literal(unit.Name)},");
builder.AppendLine($" Hexite: {unit.Hexite.ToString(CultureInfo.InvariantCulture)},");
builder.AppendLine($" Flux: {unit.Flux.ToString(CultureInfo.InvariantCulture)},");
builder.AppendLine($" Supply: {unit.Supply.ToString(CultureInfo.InvariantCulture)},");
builder.AppendLine($" ProductionTime: {unit.ProductionTime.ToString(CultureInfo.InvariantCulture)},");
builder.AppendLine($" Health: {unit.Health.ToString(CultureInfo.InvariantCulture)},");
builder.AppendLine($" Energy: {unit.Energy.ToString(CultureInfo.InvariantCulture)},");
builder.AppendLine($" Shields: {unit.Shields.ToString(CultureInfo.InvariantCulture)},");
builder.AppendLine($" ArmorRating: {unit.ArmorRating.ToString(CultureInfo.InvariantCulture)},");
builder.AppendLine($" MovementSpeed: {unit.MovementSpeed.ToString(CultureInfo.InvariantCulture)},");
builder.AppendLine($" DamagePerSecond: {unit.DamagePerSecond.ToString(CultureInfo.InvariantCulture)},");
builder.AppendLine($" AttackRange: {unit.AttackRange.ToString(CultureInfo.InvariantCulture)},");
builder.AppendLine($" Attributes: [{string.Join(", ", unit.Attributes.Select(Literal))}],");
builder.AppendLine($" Tier: {unit.Tier.ToString(CultureInfo.InvariantCulture)},");
builder.AppendLine($" Faction: {Literal(unit.Faction)},");
builder.AppendLine($" Hotkey: {Literal(unit.Hotkey)},");
builder.AppendLine($" BuildAtSameTime: {unit.BuildAtSameTime.ToString(CultureInfo.InvariantCulture)},");
builder.AppendLine($" Limit: {unit.Limit?.ToString(CultureInfo.InvariantCulture) ?? "null"});");
builder.AppendLine();
}
builder.AppendLine(" public static IReadOnlyList<UnitData> All { get; } =");
builder.AppendLine(" [");
foreach (var unit in units)
{
builder.AppendLine($" {unit.Id},");
}
builder.AppendLine(" ];");
builder.AppendLine("}");
return builder.ToString();
}
static string Literal(string? value)
{
return value is null
? "null"
: "\"" + value.Replace("\\", "\\\\").Replace("\"", "\\\"") + "\"";
}
internal sealed class FrontMatterValue(string? scalar)
{
public string? Scalar { get; } = scalar;
public List<string> List { get; } = [];
}
internal sealed record UnitSource(
string Id,
string Name,
int Hexite,
int Flux,
int Supply,
int ProductionTime,
int Health,
int Energy,
int Shields,
int ArmorRating,
int MovementSpeed,
int DamagePerSecond,
int AttackRange,
IReadOnlyList<string> Attributes,
int Tier,
string Faction,
string? Hotkey,
int BuildAtSameTime,
int? Limit);
+9
View File
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
+32
View File
@@ -0,0 +1,32 @@
namespace Model;
public sealed record UnitData(
string Id,
string Name,
int Hexite,
int Flux,
int Supply,
int ProductionTime,
int Health,
int Energy,
int Shields,
int ArmorRating,
int MovementSpeed,
int DamagePerSecond,
int AttackRange,
IReadOnlyList<string> Attributes,
int Tier,
string Faction,
string? Hotkey,
int BuildAtSameTime,
int? Limit)
{
public double DpsPerHexite => UnitEfficiency.CalculateDpsPerHexite(DamagePerSecond, Hexite);
public double DpsPerFlux => UnitEfficiency.CalculateDpsPerFlux(DamagePerSecond, Flux);
public double DpsPerTotalCost => UnitEfficiency.CalculateDpsPerTotalCost(DamagePerSecond, Hexite, Flux);
public double HealthPerHexite => UnitEfficiency.CalculateHealthPerHexite(Health, Hexite);
public double HealthPerFlux => UnitEfficiency.CalculateHealthPerFlux(Health, Flux);
public double HealthPerTotalCost => UnitEfficiency.CalculateHealthPerTotalCost(Health, Hexite, Flux);
}
+22
View File
@@ -0,0 +1,22 @@
namespace Model;
public static class UnitEfficiency
{
public static double CalculateDpsPerHexite(int damagePerSecond, int hexite) => CalculateEfficiency(damagePerSecond, hexite);
public static double CalculateDpsPerFlux(int damagePerSecond, int flux) => CalculateEfficiency(damagePerSecond, flux);
public static double CalculateDpsPerTotalCost(int damagePerSecond, int hexite, int flux) => CalculateEfficiency(damagePerSecond, hexite + flux);
public static double CalculateHealthPerHexite(int health, int hexite) => CalculateEfficiency(health, hexite);
public static double CalculateHealthPerFlux(int health, int flux) => CalculateEfficiency(health, flux);
public static double CalculateHealthPerTotalCost(int health, int hexite, int flux) => CalculateEfficiency(health, hexite + flux);
private static double CalculateEfficiency(int value, int cost)
{
if (cost <= 0)
{
return value > 0 ? double.PositiveInfinity : 0;
}
return (double)value / cost;
}
}
+361
View File
@@ -0,0 +1,361 @@
// <auto-generated />
namespace Model;
public static class Units
{
public static readonly UnitData CorsairRaiders = new(
Id: "CorsairRaiders",
Name: "Corsair Raiders",
Hexite: 58,
Flux: 0,
Supply: 2,
ProductionTime: 30,
Health: 175,
Energy: 0,
Shields: 0,
ArmorRating: 0,
MovementSpeed: 650,
DamagePerSecond: 8,
AttackRange: 8,
Attributes: ["Light Armor", "Biological"],
Tier: 1,
Faction: "Corsair",
Hotkey: "Z",
BuildAtSameTime: 3,
Limit: null);
public static readonly UnitData CorsairRovers = new(
Id: "CorsairRovers",
Name: "Corsair Rovers",
Hexite: 100,
Flux: 25,
Supply: 3,
ProductionTime: 35,
Health: 320,
Energy: 0,
Shields: 0,
ArmorRating: 0,
MovementSpeed: 750,
DamagePerSecond: 17,
AttackRange: 7,
Attributes: ["Light Armor"],
Tier: 1,
Faction: "Corsair",
Hotkey: "X",
BuildAtSameTime: 2,
Limit: null);
public static readonly UnitData CorsairSnipers = new(
Id: "CorsairSnipers",
Name: "Corsair Snipers",
Hexite: 38,
Flux: 100,
Supply: 4,
ProductionTime: 30,
Health: 100,
Energy: 0,
Shields: 100,
ArmorRating: 0,
MovementSpeed: 425,
DamagePerSecond: 14,
AttackRange: 20,
Attributes: ["Light Armor", "Biological", "Bonus Damage vs Light Armor"],
Tier: 1,
Faction: "Corsair",
Hotkey: "C",
BuildAtSameTime: 2,
Limit: null);
public static readonly UnitData CorsairHovercraft = new(
Id: "CorsairHovercraft",
Name: "Corsair Hovercraft",
Hexite: 100,
Flux: 62,
Supply: 4,
ProductionTime: 20,
Health: 375,
Energy: 0,
Shields: 0,
ArmorRating: 0,
MovementSpeed: 550,
DamagePerSecond: 20,
AttackRange: 9,
Attributes: ["Medium Armor"],
Tier: 2,
Faction: "Corsair",
Hotkey: null,
BuildAtSameTime: 2,
Limit: null);
public static readonly UnitData CorsairFlamer = new(
Id: "CorsairFlamer",
Name: "Corsair Flamer",
Hexite: 100,
Flux: 200,
Supply: 6,
ProductionTime: 35,
Health: 1000,
Energy: 0,
Shields: 0,
ArmorRating: 2,
MovementSpeed: 450,
DamagePerSecond: 64,
AttackRange: 4,
Attributes: ["Heavy Armor", "Bonus Damage vs Light Armor", "Respawns for free after death"],
Tier: 3,
Faction: "Corsair",
Hotkey: "V",
BuildAtSameTime: 1,
Limit: null);
public static readonly UnitData Gatherer = new(
Id: "Gatherer",
Name: "Gatherer",
Hexite: 100,
Flux: 0,
Supply: 0,
ProductionTime: 18,
Health: 275,
Energy: 0,
Shields: 0,
ArmorRating: 0,
MovementSpeed: 510,
DamagePerSecond: 0,
AttackRange: 0,
Attributes: ["Biological", "Respawns for free after death"],
Tier: 0,
Faction: "Grell",
Hotkey: "H",
BuildAtSameTime: 1,
Limit: 5);
public static readonly UnitData BroodGuard = new(
Id: "BroodGuard",
Name: "Brood Guard",
Hexite: 125,
Flux: 0,
Supply: 3,
ProductionTime: 33,
Health: 250,
Energy: 0,
Shields: 0,
ArmorRating: 0,
MovementSpeed: 550,
DamagePerSecond: 15,
AttackRange: 1,
Attributes: ["Medium Armor", "Biological"],
Tier: 1,
Faction: "Grell",
Hotkey: "G",
BuildAtSameTime: 1,
Limit: null);
public static readonly UnitData Lasher = new(
Id: "Lasher",
Name: "Lasher",
Hexite: 50,
Flux: 25,
Supply: 2,
ProductionTime: 26,
Health: 150,
Energy: 0,
Shields: 0,
ArmorRating: 0,
MovementSpeed: 550,
DamagePerSecond: 14,
AttackRange: 8,
Attributes: ["Light Armor", "Biological", "Bonus Damage vs Medium Armor"],
Tier: 1,
Faction: "Grell",
Hotkey: "R",
BuildAtSameTime: 1,
Limit: null);
public static readonly UnitData Skrell = new(
Id: "Skrell",
Name: "Skrell",
Hexite: 12,
Flux: 19,
Supply: 1,
ProductionTime: 35,
Health: 50,
Energy: 0,
Shields: 0,
ArmorRating: 0,
MovementSpeed: 900,
DamagePerSecond: 5,
AttackRange: 2,
Attributes: ["Air unit", "Light Armor", "Biological", "Bonus Damage vs Air"],
Tier: 1,
Faction: "Grell",
Hotkey: "T",
BuildAtSameTime: 4,
Limit: null);
public static readonly UnitData Stinger = new(
Id: "Stinger",
Name: "Stinger",
Hexite: 25,
Flux: 0,
Supply: 1,
ProductionTime: 39,
Health: 90,
Energy: 0,
Shields: 0,
ArmorRating: 0,
MovementSpeed: 700,
DamagePerSecond: 9,
AttackRange: 1,
Attributes: ["Light Armor", "Biological"],
Tier: 1,
Faction: "Grell",
Hotkey: "Q",
BuildAtSameTime: 3,
Limit: null);
public static readonly UnitData Harbinger = new(
Id: "Harbinger",
Name: "Harbinger",
Hexite: 75,
Flux: 50,
Supply: 4,
ProductionTime: 35,
Health: 400,
Energy: 0,
Shields: 0,
ArmorRating: 1,
MovementSpeed: 475,
DamagePerSecond: 14,
AttackRange: 6,
Attributes: ["Biological", "Medium Armor", "Bonus Damage vs Heavy Armor"],
Tier: 2,
Faction: "Grell",
Hotkey: "W",
BuildAtSameTime: 1,
Limit: null);
public static readonly UnitData Mandragora = new(
Id: "Mandragora",
Name: "Mandragora",
Hexite: 125,
Flux: 25,
Supply: 4,
ProductionTime: 48,
Health: 450,
Energy: 0,
Shields: 0,
ArmorRating: 1,
MovementSpeed: 550,
DamagePerSecond: 22,
AttackRange: 4,
Attributes: ["Medium Armor", "Biological"],
Tier: 2,
Faction: "Grell",
Hotkey: "F",
BuildAtSameTime: 1,
Limit: null);
public static readonly UnitData Thresher = new(
Id: "Thresher",
Name: "Thresher",
Hexite: 100,
Flux: 175,
Supply: 8,
ProductionTime: 65,
Health: 300,
Energy: 0,
Shields: 0,
ArmorRating: 0,
MovementSpeed: 450,
DamagePerSecond: 36,
AttackRange: 27,
Attributes: ["Biological", "Heavy Armor", "Bonus Damage vs Buildings"],
Tier: 2,
Faction: "Grell",
Hotkey: "S",
BuildAtSameTime: 1,
Limit: null);
public static readonly UnitData Behemoth = new(
Id: "Behemoth",
Name: "Behemoth",
Hexite: 100,
Flux: 200,
Supply: 8,
ProductionTime: 80,
Health: 625,
Energy: 5,
Shields: 0,
ArmorRating: 1,
MovementSpeed: 500,
DamagePerSecond: 15,
AttackRange: 12,
Attributes: ["Air unit", "Regains Energy From Attacking", "Biological", "Heavy Armor", "Bonus Damage vs Heavy Armor"],
Tier: 3,
Faction: "Grell",
Hotkey: "D",
BuildAtSameTime: 1,
Limit: null);
public static readonly UnitData Reaver = new(
Id: "Reaver",
Name: "Reaver",
Hexite: 200,
Flux: 100,
Supply: 8,
ProductionTime: 80,
Health: 900,
Energy: 15,
Shields: 0,
ArmorRating: 3,
MovementSpeed: 525,
DamagePerSecond: 51,
AttackRange: 2,
Attributes: ["Regains Energy From Attacking", "Biological", "Heavy Armor"],
Tier: 3,
Faction: "Grell",
Hotkey: "A",
BuildAtSameTime: 1,
Limit: null);
public static readonly UnitData Weaver = new(
Id: "Weaver",
Name: "Weaver",
Hexite: 75,
Flux: 175,
Supply: 4,
ProductionTime: 40,
Health: 200,
Energy: 80,
Shields: 0,
ArmorRating: 0,
MovementSpeed: 650,
DamagePerSecond: 10,
AttackRange: 12,
Attributes: ["Medium Armor", "Biological", "Bonus Damage vs Air"],
Tier: 3,
Faction: "Grell",
Hotkey: "E",
BuildAtSameTime: 1,
Limit: null);
public static IReadOnlyList<UnitData> All { get; } =
[
CorsairRaiders,
CorsairRovers,
CorsairSnipers,
CorsairHovercraft,
CorsairFlamer,
Gatherer,
BroodGuard,
Lasher,
Skrell,
Stinger,
Harbinger,
Mandragora,
Thresher,
Behemoth,
Reaver,
Weaver,
];
}
+6
View File
@@ -0,0 +1,6 @@
<Router AppAssembly="@typeof(App).Assembly" NotFoundPage="typeof(Pages.NotFound)">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"/>
<FocusOnNavigate RouteData="@routeData" Selector="h1"/>
</Found>
</Router>
+15
View File
@@ -0,0 +1,15 @@
@using Telerik.Blazor.Components
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu/>
</div>
<main>
<article class="content px-4">
<TelerikRootComponent>
@Body
</TelerikRootComponent>
</article>
</main>
</div>
+77
View File
@@ -0,0 +1,77 @@
.page {
position: relative;
display: flex;
flex-direction: column;
}
main {
flex: 1;
}
.sidebar {
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
}
.top-row {
background-color: #f7f7f7;
border-bottom: 1px solid #d6d5d5;
justify-content: flex-end;
height: 3.5rem;
display: flex;
align-items: center;
}
.top-row ::deep a, .top-row ::deep .btn-link {
white-space: nowrap;
margin-left: 1.5rem;
text-decoration: none;
}
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
text-decoration: underline;
}
.top-row ::deep a:first-child {
overflow: hidden;
text-overflow: ellipsis;
}
@media (max-width: 640.98px) {
.top-row {
justify-content: space-between;
}
.top-row ::deep a, .top-row ::deep .btn-link {
margin-left: 0;
}
}
@media (min-width: 641px) {
.page {
flex-direction: row;
}
.sidebar {
width: 250px;
height: 100vh;
position: sticky;
top: 0;
}
.top-row {
position: sticky;
top: 0;
z-index: 1;
}
.top-row.auth ::deep a:first-child {
flex: 1;
text-align: right;
width: 0;
}
.top-row, article {
padding-left: 2rem !important;
padding-right: 1.5rem !important;
}
}
+40
View File
@@ -0,0 +1,40 @@
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">Web</a>
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</div>
<div class="@NavMenuCssClass nav-scrollable" @onclick="ToggleNavMenu">
<nav class="nav flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="weather">
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
</NavLink>
</div>
</nav>
</div>
@code {
private bool collapseNavMenu = true;
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}
+83
View File
@@ -0,0 +1,83 @@
.navbar-toggler {
background-color: rgba(255, 255, 255, 0.1);
}
.top-row {
min-height: 3.5rem;
background-color: rgba(0,0,0,0.4);
}
.navbar-brand {
font-size: 1.1rem;
}
.bi {
display: inline-block;
position: relative;
width: 1.25rem;
height: 1.25rem;
margin-right: 0.75rem;
top: -1px;
background-size: cover;
}
.bi-house-door-fill-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
}
.bi-plus-square-fill-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
}
.bi-list-nested-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
}
.nav-item {
font-size: 0.9rem;
padding-bottom: 0.5rem;
}
.nav-item:first-of-type {
padding-top: 1rem;
}
.nav-item:last-of-type {
padding-bottom: 1rem;
}
.nav-item ::deep a {
color: #d7d7d7;
border-radius: 4px;
height: 3rem;
display: flex;
align-items: center;
line-height: 3rem;
}
.nav-item ::deep a.active {
background-color: rgba(255,255,255,0.37);
color: white;
}
.nav-item ::deep a:hover {
background-color: rgba(255,255,255,0.1);
color: white;
}
@media (min-width: 641px) {
.navbar-toggler {
display: none;
}
.collapse {
/* Never collapse the sidebar for wide screens */
display: block;
}
.nav-scrollable {
/* Allow sidebar to scroll for tall menus */
height: calc(100vh - 3.5rem);
overflow-y: auto;
}
}
+19
View File
@@ -0,0 +1,19 @@
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
+7
View File
@@ -0,0 +1,7 @@
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
+5
View File
@@ -0,0 +1,5 @@
@page "/not-found"
@layout MainLayout
<h3>Not Found</h3>
<p>Sorry, the content you are looking for does not exist.</p>
+65
View File
@@ -0,0 +1,65 @@
@page "/units"
@using Model
@using Telerik.Blazor
@using Telerik.Blazor.Components
<PageTitle>Units</PageTitle>
<div class="section-header d-flex align-items-center mb-4">
<h1 class="mb-0">Units</h1>
<div class="ms-3 flex-grow-1 border-bottom opacity-25"></div>
</div>
@if (gearNotes == null)
{
<div class="d-flex justify-content-center py-5">
<div class="spinner-border text-success" role="status">
<span class="visually-hidden">Loading...</span>
</div>
</div>
}
else
{
<div class="grid-container">
<TelerikGrid Data="@gearNotes" Pageable="true" PageSize="50" Sortable="true" FilterMode="@GridFilterMode.FilterRow"
Height="calc(100vh - 250px)">
<GridColumns>
<GridColumn Field="@(nameof(UnitData.Name))" Title="Name" Width="200px"/>
<GridColumn Field="@(nameof(UnitData.Hexite))" Title="Hexite" Width="90px" />
<GridColumn Field="@(nameof(UnitData.Flux))" Title="Flux" Width="90px" />
<GridColumn Field="@(nameof(UnitData.DpsPerTotalCost))" Title="DpsPerTotalCost" Width="90px" />
<GridColumn Field="@(nameof(UnitData.HealthPerTotalCost))" Title="HealthPerTotalCost" Width="90px" />
<GridColumn Field="@(nameof(UnitData.Supply))" Title="Supply" Width="90px" />
<GridColumn Field="@(nameof(UnitData.ProductionTime))" Title="Production Time" Width="90px" />
<GridColumn Field="@(nameof(UnitData.Health))" Title="Health" Width="90px" />
<GridColumn Field="@(nameof(UnitData.Shields))" Title="Shields" Width="90px" />
<GridColumn Field="@(nameof(UnitData.ArmorRating))" Title="Armor Rating" Width="90px" />
<GridColumn Field="@(nameof(UnitData.MovementSpeed))" Title="Movement Speed" Width="90px" />
<GridColumn Field="@(nameof(UnitData.DamagePerSecond))" Title="Damage Per Second" Width="90px" />
<GridColumn Field="@(nameof(UnitData.AttackRange))" Title="Attack Range" Width="90px" />
<GridColumn Field="@(nameof(UnitData.Attributes))" Title="Attributes" Width="90px" />
<GridColumn Field="@(nameof(UnitData.Tier))" Title="Tier" Width="90px" />
<GridColumn Field="@(nameof(UnitData.Faction))" Title="Faction" Width="90px" />
<GridColumn Field="@(nameof(UnitData.Hotkey))" Title="Hotkey" Width="90px" />
<GridColumn Field="@(nameof(UnitData.BuildAtSameTime))" Title="Build At Same Time" Width="90px" />
<GridColumn Field="@(nameof(UnitData.Limit))" Title="Limit" Width="90px" />
</GridColumns>
</TelerikGrid>
</div>
}
@code {
private List<UnitData>? gearNotes;
protected override async Task OnInitializedAsync()
{
var index = Model.Units.All;
gearNotes = index
.ToList();
}
}
+60
View File
@@ -0,0 +1,60 @@
@page "/weather"
@inject HttpClient Http
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p>
<em>Loading...</em>
</p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th aria-label="Temperature in Celsius">Temp. (C)</th>
<th aria-label="Temperature in Fahrenheit">Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json");
}
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}
+13
View File
@@ -0,0 +1,13 @@
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Web;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddTelerikBlazor();
await builder.Build().RunAsync();
+25
View File
@@ -0,0 +1,25 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "http://localhost:5114",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "https://localhost:7205;http://localhost:5114",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
+20
View File
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<OverrideHtmlAssetPlaceholders>true</OverrideHtmlAssetPlaceholders>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="10.0.9"/>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="10.0.9" PrivateAssets="all"/>
<PackageReference Include="Telerik.UI.for.Blazor" Version="14.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Model\Model.csproj" />
</ItemGroup>
</Project>
+10
View File
@@ -0,0 +1,10 @@
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using Web
@using Web.Layout
+115
View File
@@ -0,0 +1,115 @@
html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
h1:focus {
outline: none;
}
a, .btn-link {
color: #0071c1;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}
.content {
padding-top: 1.1rem;
}
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}
.invalid {
outline: 1px solid red;
}
.validation-message {
color: red;
}
#blazor-error-ui {
color-scheme: light only;
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
box-sizing: border-box;
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000;
}
#blazor-error-ui .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}
.blazor-error-boundary {
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
padding: 1rem 1rem 1rem 3.7rem;
color: white;
}
.blazor-error-boundary::after {
content: "An error has occurred."
}
.loading-progress {
position: absolute;
display: block;
width: 8rem;
height: 8rem;
inset: 20vh 0 auto 0;
margin: 0 auto 0 auto;
}
.loading-progress circle {
fill: none;
stroke: #e0e0e0;
stroke-width: 0.6rem;
transform-origin: 50% 50%;
transform: rotate(-90deg);
}
.loading-progress circle:last-child {
stroke: #1b6ec2;
stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
transition: stroke-dasharray 0.05s ease-in-out;
}
.loading-progress-text {
position: absolute;
text-align: center;
font-weight: bold;
inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}
.loading-progress-text:after {
content: var(--blazor-load-percentage-text, "Loading");
}
code {
color: #c02d76;
}
.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
color: var(--bs-secondary-color);
text-align: end;
}
.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
text-align: start;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

+35
View File
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Web</title>
<base href="/" />
<link rel="preload" id="webassembly" />
<link rel="stylesheet" href="lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="css/app.css" />
<link rel="icon" type="image/png" href="favicon.png" />
<link href="_content/Telerik.UI.for.Blazor/css/kendo-theme-default/all.css" rel="stylesheet"/>
<link href="Web.styles.css" rel="stylesheet" />
<script type="importmap"></script>
</head>
<body>
<div id="app">
<svg class="loading-progress">
<circle r="40%" cx="50%" cy="50%" />
<circle r="40%" cx="50%" cy="50%" />
</svg>
<div class="loading-progress-text"></div>
</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="." class="reload">Reload</a>
<span class="dismiss">🗙</span>
</div>
<script src="_framework/blazor.webassembly#[.{fingerprint}].js"></script>
</body>
</html>
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,597 @@
/*!
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
:root,
[data-bs-theme=light] {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-black: #000;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-primary-text-emphasis: #052c65;
--bs-secondary-text-emphasis: #2b2f32;
--bs-success-text-emphasis: #0a3622;
--bs-info-text-emphasis: #055160;
--bs-warning-text-emphasis: #664d03;
--bs-danger-text-emphasis: #58151c;
--bs-light-text-emphasis: #495057;
--bs-dark-text-emphasis: #495057;
--bs-primary-bg-subtle: #cfe2ff;
--bs-secondary-bg-subtle: #e2e3e5;
--bs-success-bg-subtle: #d1e7dd;
--bs-info-bg-subtle: #cff4fc;
--bs-warning-bg-subtle: #fff3cd;
--bs-danger-bg-subtle: #f8d7da;
--bs-light-bg-subtle: #fcfcfd;
--bs-dark-bg-subtle: #ced4da;
--bs-primary-border-subtle: #9ec5fe;
--bs-secondary-border-subtle: #c4c8cb;
--bs-success-border-subtle: #a3cfbb;
--bs-info-border-subtle: #9eeaf9;
--bs-warning-border-subtle: #ffe69c;
--bs-danger-border-subtle: #f1aeb5;
--bs-light-border-subtle: #e9ecef;
--bs-dark-border-subtle: #adb5bd;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg: #fff;
--bs-body-bg-rgb: 255, 255, 255;
--bs-emphasis-color: #000;
--bs-emphasis-color-rgb: 0, 0, 0;
--bs-secondary-color: rgba(33, 37, 41, 0.75);
--bs-secondary-color-rgb: 33, 37, 41;
--bs-secondary-bg: #e9ecef;
--bs-secondary-bg-rgb: 233, 236, 239;
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
--bs-tertiary-color-rgb: 33, 37, 41;
--bs-tertiary-bg: #f8f9fa;
--bs-tertiary-bg-rgb: 248, 249, 250;
--bs-heading-color: inherit;
--bs-link-color: #0d6efd;
--bs-link-color-rgb: 13, 110, 253;
--bs-link-decoration: underline;
--bs-link-hover-color: #0a58ca;
--bs-link-hover-color-rgb: 10, 88, 202;
--bs-code-color: #d63384;
--bs-highlight-color: #212529;
--bs-highlight-bg: #fff3cd;
--bs-border-width: 1px;
--bs-border-style: solid;
--bs-border-color: #dee2e6;
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
--bs-border-radius: 0.375rem;
--bs-border-radius-sm: 0.25rem;
--bs-border-radius-lg: 0.5rem;
--bs-border-radius-xl: 1rem;
--bs-border-radius-xxl: 2rem;
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
--bs-border-radius-pill: 50rem;
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
--bs-focus-ring-width: 0.25rem;
--bs-focus-ring-opacity: 0.25;
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
--bs-form-valid-color: #198754;
--bs-form-valid-border-color: #198754;
--bs-form-invalid-color: #dc3545;
--bs-form-invalid-border-color: #dc3545;
}
[data-bs-theme=dark] {
color-scheme: dark;
--bs-body-color: #dee2e6;
--bs-body-color-rgb: 222, 226, 230;
--bs-body-bg: #212529;
--bs-body-bg-rgb: 33, 37, 41;
--bs-emphasis-color: #fff;
--bs-emphasis-color-rgb: 255, 255, 255;
--bs-secondary-color: rgba(222, 226, 230, 0.75);
--bs-secondary-color-rgb: 222, 226, 230;
--bs-secondary-bg: #343a40;
--bs-secondary-bg-rgb: 52, 58, 64;
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
--bs-tertiary-color-rgb: 222, 226, 230;
--bs-tertiary-bg: #2b3035;
--bs-tertiary-bg-rgb: 43, 48, 53;
--bs-primary-text-emphasis: #6ea8fe;
--bs-secondary-text-emphasis: #a7acb1;
--bs-success-text-emphasis: #75b798;
--bs-info-text-emphasis: #6edff6;
--bs-warning-text-emphasis: #ffda6a;
--bs-danger-text-emphasis: #ea868f;
--bs-light-text-emphasis: #f8f9fa;
--bs-dark-text-emphasis: #dee2e6;
--bs-primary-bg-subtle: #031633;
--bs-secondary-bg-subtle: #161719;
--bs-success-bg-subtle: #051b11;
--bs-info-bg-subtle: #032830;
--bs-warning-bg-subtle: #332701;
--bs-danger-bg-subtle: #2c0b0e;
--bs-light-bg-subtle: #343a40;
--bs-dark-bg-subtle: #1a1d20;
--bs-primary-border-subtle: #084298;
--bs-secondary-border-subtle: #41464b;
--bs-success-border-subtle: #0f5132;
--bs-info-border-subtle: #087990;
--bs-warning-border-subtle: #997404;
--bs-danger-border-subtle: #842029;
--bs-light-border-subtle: #495057;
--bs-dark-border-subtle: #343a40;
--bs-heading-color: inherit;
--bs-link-color: #6ea8fe;
--bs-link-hover-color: #8bb9fe;
--bs-link-color-rgb: 110, 168, 254;
--bs-link-hover-color-rgb: 139, 185, 254;
--bs-code-color: #e685b5;
--bs-highlight-color: #dee2e6;
--bs-highlight-bg: #664d03;
--bs-border-color: #495057;
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
--bs-form-valid-color: #75b798;
--bs-form-valid-border-color: #75b798;
--bs-form-invalid-color: #ea868f;
--bs-form-invalid-border-color: #ea868f;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
border: 0;
border-top: var(--bs-border-width) solid;
opacity: 0.25;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
color: var(--bs-heading-color);
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-left: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-left: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.1875em;
color: var(--bs-highlight-color);
background-color: var(--bs-highlight-bg);
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
text-decoration: underline;
}
a:hover {
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: var(--bs-font-monospace);
font-size: 1em;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: var(--bs-code-color);
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.1875rem 0.375rem;
font-size: 0.875em;
color: var(--bs-body-bg);
background-color: var(--bs-body-color);
border-radius: 0.25rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: var(--bs-secondary-color);
text-align: left;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
display: none !important;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: left;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: left;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
/* rtl:raw:
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
*/
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
::file-selector-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.css.map */
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,594 @@
/*!
* Bootstrap Reboot v5.3.3 (https://getbootstrap.com/)
* Copyright 2011-2024 The Bootstrap Authors
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
:root,
[data-bs-theme=light] {
--bs-blue: #0d6efd;
--bs-indigo: #6610f2;
--bs-purple: #6f42c1;
--bs-pink: #d63384;
--bs-red: #dc3545;
--bs-orange: #fd7e14;
--bs-yellow: #ffc107;
--bs-green: #198754;
--bs-teal: #20c997;
--bs-cyan: #0dcaf0;
--bs-black: #000;
--bs-white: #fff;
--bs-gray: #6c757d;
--bs-gray-dark: #343a40;
--bs-gray-100: #f8f9fa;
--bs-gray-200: #e9ecef;
--bs-gray-300: #dee2e6;
--bs-gray-400: #ced4da;
--bs-gray-500: #adb5bd;
--bs-gray-600: #6c757d;
--bs-gray-700: #495057;
--bs-gray-800: #343a40;
--bs-gray-900: #212529;
--bs-primary: #0d6efd;
--bs-secondary: #6c757d;
--bs-success: #198754;
--bs-info: #0dcaf0;
--bs-warning: #ffc107;
--bs-danger: #dc3545;
--bs-light: #f8f9fa;
--bs-dark: #212529;
--bs-primary-rgb: 13, 110, 253;
--bs-secondary-rgb: 108, 117, 125;
--bs-success-rgb: 25, 135, 84;
--bs-info-rgb: 13, 202, 240;
--bs-warning-rgb: 255, 193, 7;
--bs-danger-rgb: 220, 53, 69;
--bs-light-rgb: 248, 249, 250;
--bs-dark-rgb: 33, 37, 41;
--bs-primary-text-emphasis: #052c65;
--bs-secondary-text-emphasis: #2b2f32;
--bs-success-text-emphasis: #0a3622;
--bs-info-text-emphasis: #055160;
--bs-warning-text-emphasis: #664d03;
--bs-danger-text-emphasis: #58151c;
--bs-light-text-emphasis: #495057;
--bs-dark-text-emphasis: #495057;
--bs-primary-bg-subtle: #cfe2ff;
--bs-secondary-bg-subtle: #e2e3e5;
--bs-success-bg-subtle: #d1e7dd;
--bs-info-bg-subtle: #cff4fc;
--bs-warning-bg-subtle: #fff3cd;
--bs-danger-bg-subtle: #f8d7da;
--bs-light-bg-subtle: #fcfcfd;
--bs-dark-bg-subtle: #ced4da;
--bs-primary-border-subtle: #9ec5fe;
--bs-secondary-border-subtle: #c4c8cb;
--bs-success-border-subtle: #a3cfbb;
--bs-info-border-subtle: #9eeaf9;
--bs-warning-border-subtle: #ffe69c;
--bs-danger-border-subtle: #f1aeb5;
--bs-light-border-subtle: #e9ecef;
--bs-dark-border-subtle: #adb5bd;
--bs-white-rgb: 255, 255, 255;
--bs-black-rgb: 0, 0, 0;
--bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
--bs-body-font-family: var(--bs-font-sans-serif);
--bs-body-font-size: 1rem;
--bs-body-font-weight: 400;
--bs-body-line-height: 1.5;
--bs-body-color: #212529;
--bs-body-color-rgb: 33, 37, 41;
--bs-body-bg: #fff;
--bs-body-bg-rgb: 255, 255, 255;
--bs-emphasis-color: #000;
--bs-emphasis-color-rgb: 0, 0, 0;
--bs-secondary-color: rgba(33, 37, 41, 0.75);
--bs-secondary-color-rgb: 33, 37, 41;
--bs-secondary-bg: #e9ecef;
--bs-secondary-bg-rgb: 233, 236, 239;
--bs-tertiary-color: rgba(33, 37, 41, 0.5);
--bs-tertiary-color-rgb: 33, 37, 41;
--bs-tertiary-bg: #f8f9fa;
--bs-tertiary-bg-rgb: 248, 249, 250;
--bs-heading-color: inherit;
--bs-link-color: #0d6efd;
--bs-link-color-rgb: 13, 110, 253;
--bs-link-decoration: underline;
--bs-link-hover-color: #0a58ca;
--bs-link-hover-color-rgb: 10, 88, 202;
--bs-code-color: #d63384;
--bs-highlight-color: #212529;
--bs-highlight-bg: #fff3cd;
--bs-border-width: 1px;
--bs-border-style: solid;
--bs-border-color: #dee2e6;
--bs-border-color-translucent: rgba(0, 0, 0, 0.175);
--bs-border-radius: 0.375rem;
--bs-border-radius-sm: 0.25rem;
--bs-border-radius-lg: 0.5rem;
--bs-border-radius-xl: 1rem;
--bs-border-radius-xxl: 2rem;
--bs-border-radius-2xl: var(--bs-border-radius-xxl);
--bs-border-radius-pill: 50rem;
--bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
--bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
--bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
--bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
--bs-focus-ring-width: 0.25rem;
--bs-focus-ring-opacity: 0.25;
--bs-focus-ring-color: rgba(13, 110, 253, 0.25);
--bs-form-valid-color: #198754;
--bs-form-valid-border-color: #198754;
--bs-form-invalid-color: #dc3545;
--bs-form-invalid-border-color: #dc3545;
}
[data-bs-theme=dark] {
color-scheme: dark;
--bs-body-color: #dee2e6;
--bs-body-color-rgb: 222, 226, 230;
--bs-body-bg: #212529;
--bs-body-bg-rgb: 33, 37, 41;
--bs-emphasis-color: #fff;
--bs-emphasis-color-rgb: 255, 255, 255;
--bs-secondary-color: rgba(222, 226, 230, 0.75);
--bs-secondary-color-rgb: 222, 226, 230;
--bs-secondary-bg: #343a40;
--bs-secondary-bg-rgb: 52, 58, 64;
--bs-tertiary-color: rgba(222, 226, 230, 0.5);
--bs-tertiary-color-rgb: 222, 226, 230;
--bs-tertiary-bg: #2b3035;
--bs-tertiary-bg-rgb: 43, 48, 53;
--bs-primary-text-emphasis: #6ea8fe;
--bs-secondary-text-emphasis: #a7acb1;
--bs-success-text-emphasis: #75b798;
--bs-info-text-emphasis: #6edff6;
--bs-warning-text-emphasis: #ffda6a;
--bs-danger-text-emphasis: #ea868f;
--bs-light-text-emphasis: #f8f9fa;
--bs-dark-text-emphasis: #dee2e6;
--bs-primary-bg-subtle: #031633;
--bs-secondary-bg-subtle: #161719;
--bs-success-bg-subtle: #051b11;
--bs-info-bg-subtle: #032830;
--bs-warning-bg-subtle: #332701;
--bs-danger-bg-subtle: #2c0b0e;
--bs-light-bg-subtle: #343a40;
--bs-dark-bg-subtle: #1a1d20;
--bs-primary-border-subtle: #084298;
--bs-secondary-border-subtle: #41464b;
--bs-success-border-subtle: #0f5132;
--bs-info-border-subtle: #087990;
--bs-warning-border-subtle: #997404;
--bs-danger-border-subtle: #842029;
--bs-light-border-subtle: #495057;
--bs-dark-border-subtle: #343a40;
--bs-heading-color: inherit;
--bs-link-color: #6ea8fe;
--bs-link-hover-color: #8bb9fe;
--bs-link-color-rgb: 110, 168, 254;
--bs-link-hover-color-rgb: 139, 185, 254;
--bs-code-color: #e685b5;
--bs-highlight-color: #dee2e6;
--bs-highlight-bg: #664d03;
--bs-border-color: #495057;
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
--bs-form-valid-color: #75b798;
--bs-form-valid-border-color: #75b798;
--bs-form-invalid-color: #ea868f;
--bs-form-invalid-border-color: #ea868f;
}
*,
*::before,
*::after {
box-sizing: border-box;
}
@media (prefers-reduced-motion: no-preference) {
:root {
scroll-behavior: smooth;
}
}
body {
margin: 0;
font-family: var(--bs-body-font-family);
font-size: var(--bs-body-font-size);
font-weight: var(--bs-body-font-weight);
line-height: var(--bs-body-line-height);
color: var(--bs-body-color);
text-align: var(--bs-body-text-align);
background-color: var(--bs-body-bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
hr {
margin: 1rem 0;
color: inherit;
border: 0;
border-top: var(--bs-border-width) solid;
opacity: 0.25;
}
h6, h5, h4, h3, h2, h1 {
margin-top: 0;
margin-bottom: 0.5rem;
font-weight: 500;
line-height: 1.2;
color: var(--bs-heading-color);
}
h1 {
font-size: calc(1.375rem + 1.5vw);
}
@media (min-width: 1200px) {
h1 {
font-size: 2.5rem;
}
}
h2 {
font-size: calc(1.325rem + 0.9vw);
}
@media (min-width: 1200px) {
h2 {
font-size: 2rem;
}
}
h3 {
font-size: calc(1.3rem + 0.6vw);
}
@media (min-width: 1200px) {
h3 {
font-size: 1.75rem;
}
}
h4 {
font-size: calc(1.275rem + 0.3vw);
}
@media (min-width: 1200px) {
h4 {
font-size: 1.5rem;
}
}
h5 {
font-size: 1.25rem;
}
h6 {
font-size: 1rem;
}
p {
margin-top: 0;
margin-bottom: 1rem;
}
abbr[title] {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
cursor: help;
-webkit-text-decoration-skip-ink: none;
text-decoration-skip-ink: none;
}
address {
margin-bottom: 1rem;
font-style: normal;
line-height: inherit;
}
ol,
ul {
padding-right: 2rem;
}
ol,
ul,
dl {
margin-top: 0;
margin-bottom: 1rem;
}
ol ol,
ul ul,
ol ul,
ul ol {
margin-bottom: 0;
}
dt {
font-weight: 700;
}
dd {
margin-bottom: 0.5rem;
margin-right: 0;
}
blockquote {
margin: 0 0 1rem;
}
b,
strong {
font-weight: bolder;
}
small {
font-size: 0.875em;
}
mark {
padding: 0.1875em;
color: var(--bs-highlight-color);
background-color: var(--bs-highlight-bg);
}
sub,
sup {
position: relative;
font-size: 0.75em;
line-height: 0;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
a {
color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
text-decoration: underline;
}
a:hover {
--bs-link-color-rgb: var(--bs-link-hover-color-rgb);
}
a:not([href]):not([class]), a:not([href]):not([class]):hover {
color: inherit;
text-decoration: none;
}
pre,
code,
kbd,
samp {
font-family: var(--bs-font-monospace);
font-size: 1em;
}
pre {
display: block;
margin-top: 0;
margin-bottom: 1rem;
overflow: auto;
font-size: 0.875em;
}
pre code {
font-size: inherit;
color: inherit;
word-break: normal;
}
code {
font-size: 0.875em;
color: var(--bs-code-color);
word-wrap: break-word;
}
a > code {
color: inherit;
}
kbd {
padding: 0.1875rem 0.375rem;
font-size: 0.875em;
color: var(--bs-body-bg);
background-color: var(--bs-body-color);
border-radius: 0.25rem;
}
kbd kbd {
padding: 0;
font-size: 1em;
}
figure {
margin: 0 0 1rem;
}
img,
svg {
vertical-align: middle;
}
table {
caption-side: bottom;
border-collapse: collapse;
}
caption {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
color: var(--bs-secondary-color);
text-align: right;
}
th {
text-align: inherit;
text-align: -webkit-match-parent;
}
thead,
tbody,
tfoot,
tr,
td,
th {
border-color: inherit;
border-style: solid;
border-width: 0;
}
label {
display: inline-block;
}
button {
border-radius: 0;
}
button:focus:not(:focus-visible) {
outline: 0;
}
input,
button,
select,
optgroup,
textarea {
margin: 0;
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
button,
select {
text-transform: none;
}
[role=button] {
cursor: pointer;
}
select {
word-wrap: normal;
}
select:disabled {
opacity: 1;
}
[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator {
display: none !important;
}
button,
[type=button],
[type=reset],
[type=submit] {
-webkit-appearance: button;
}
button:not(:disabled),
[type=button]:not(:disabled),
[type=reset]:not(:disabled),
[type=submit]:not(:disabled) {
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border-style: none;
}
textarea {
resize: vertical;
}
fieldset {
min-width: 0;
padding: 0;
margin: 0;
border: 0;
}
legend {
float: right;
width: 100%;
padding: 0;
margin-bottom: 0.5rem;
font-size: calc(1.275rem + 0.3vw);
line-height: inherit;
}
@media (min-width: 1200px) {
legend {
font-size: 1.5rem;
}
}
legend + * {
clear: right;
}
::-webkit-datetime-edit-fields-wrapper,
::-webkit-datetime-edit-text,
::-webkit-datetime-edit-minute,
::-webkit-datetime-edit-hour-field,
::-webkit-datetime-edit-day-field,
::-webkit-datetime-edit-month-field,
::-webkit-datetime-edit-year-field {
padding: 0;
}
::-webkit-inner-spin-button {
height: auto;
}
[type=search] {
-webkit-appearance: textfield;
outline-offset: -2px;
}
[type="tel"],
[type="url"],
[type="email"],
[type="number"] {
direction: ltr;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
::-webkit-color-swatch-wrapper {
padding: 0;
}
::-webkit-file-upload-button {
font: inherit;
-webkit-appearance: button;
}
::file-selector-button {
font: inherit;
-webkit-appearance: button;
}
output {
display: inline-block;
}
iframe {
border: 0;
}
summary {
display: list-item;
cursor: pointer;
}
progress {
vertical-align: baseline;
}
[hidden] {
display: none !important;
}
/*# sourceMappingURL=bootstrap-reboot.rtl.css.map */
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+27
View File
@@ -0,0 +1,27 @@
[
{
"date": "2022-01-06",
"temperatureC": 1,
"summary": "Freezing"
},
{
"date": "2022-01-07",
"temperatureC": 14,
"summary": "Bracing"
},
{
"date": "2022-01-08",
"temperatureC": -13,
"summary": "Freezing"
},
{
"date": "2022-01-09",
"temperatureC": -16,
"summary": "Balmy"
},
{
"date": "2022-01-10",
"temperatureC": -2,
"summary": "Chilly"
}
]
+28
View File
@@ -0,0 +1,28 @@

Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Web", "Web\Web.csproj", "{16296B27-D17B-4BFF-B08F-60F20DF36066}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Build", "Build\Build.csproj", "{C1C04020-AFD6-493B-ABDB-277977D3488E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Model", "Model\Model.csproj", "{E31A06B0-9B2B-4805-B343-5687A5992E9A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{16296B27-D17B-4BFF-B08F-60F20DF36066}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{16296B27-D17B-4BFF-B08F-60F20DF36066}.Debug|Any CPU.Build.0 = Debug|Any CPU
{16296B27-D17B-4BFF-B08F-60F20DF36066}.Release|Any CPU.ActiveCfg = Release|Any CPU
{16296B27-D17B-4BFF-B08F-60F20DF36066}.Release|Any CPU.Build.0 = Release|Any CPU
{C1C04020-AFD6-493B-ABDB-277977D3488E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C1C04020-AFD6-493B-ABDB-277977D3488E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C1C04020-AFD6-493B-ABDB-277977D3488E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C1C04020-AFD6-493B-ABDB-277977D3488E}.Release|Any CPU.Build.0 = Release|Any CPU
{E31A06B0-9B2B-4805-B343-5687A5992E9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E31A06B0-9B2B-4805-B343-5687A5992E9A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E31A06B0-9B2B-4805-B343-5687A5992E9A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E31A06B0-9B2B-4805-B343-5687A5992E9A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
+1
View File
@@ -0,0 +1 @@
{}
+3
View File
@@ -0,0 +1,3 @@
{
"theme": "obsidian"
}
+33
View File
@@ -0,0 +1,33 @@
{
"file-explorer": true,
"global-search": true,
"switcher": true,
"graph": true,
"backlink": true,
"canvas": true,
"outgoing-link": true,
"tag-pane": true,
"footnotes": false,
"properties": true,
"page-preview": true,
"daily-notes": true,
"templates": true,
"note-composer": true,
"command-palette": true,
"slash-command": false,
"editor-status": true,
"bookmarks": true,
"markdown-importer": false,
"zk-prefixer": false,
"random-note": false,
"outline": true,
"word-count": true,
"slides": false,
"audio-recorder": false,
"workspaces": false,
"file-recovery": true,
"publish": false,
"sync": true,
"bases": true,
"webviewer": false
}
+22
View File
@@ -0,0 +1,22 @@
{
"collapse-filter": true,
"search": "",
"showTags": false,
"showAttachments": false,
"hideUnresolved": false,
"showOrphans": true,
"collapse-color-groups": true,
"colorGroups": [],
"collapse-display": true,
"showArrow": false,
"textFadeMultiplier": 0,
"nodeSizeMultiplier": 1,
"lineSizeMultiplier": 1,
"collapse-forces": true,
"centerStrength": 0.518713248970312,
"repelStrength": 10,
"linkStrength": 1,
"linkDistance": 250,
"scale": 1,
"close": true
}
+23
View File
@@ -0,0 +1,23 @@
{
"types": {
"aliases": "aliases",
"cssclasses": "multitext",
"tags": "tags",
"attributes": "multitext",
"hexite": "number",
"supply": "number",
"productionTime": "number",
"health": "number",
"movementSpeed": "number",
"damagePerSecond": "number",
"attackRange": "number",
"Tier": "number",
"Flux": "number",
"buildAtSameTime": "number",
"Shields": "number",
"limit": "number",
"Armor rating": "number",
"Energy": "number",
"Rank": "number"
}
}
+255
View File
@@ -0,0 +1,255 @@
{
"main": {
"id": "b06de083018bcdef",
"type": "split",
"children": [
{
"id": "13b8bdd9d3b8e3be",
"type": "tabs",
"children": [
{
"id": "1544041239dba496",
"type": "leaf",
"pinned": true,
"state": {
"type": "bases",
"state": {
"file": "_Units.base",
"viewName": "Table"
},
"pinned": true,
"icon": "lucide-table",
"title": "_Units"
}
},
{
"id": "f3119cebe3b9fdab",
"type": "leaf",
"pinned": true,
"state": {
"type": "bases",
"state": {
"file": "_Talents.base",
"viewName": "Table"
},
"pinned": true,
"icon": "lucide-table",
"title": "_Talents"
}
}
],
"currentTab": 1
},
{
"id": "756d9924fb5e23c2",
"type": "tabs",
"children": [
{
"id": "6e58412b029dfbac",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Koru Symbiosis.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Koru Symbiosis"
}
}
]
}
],
"direction": "vertical"
},
"left": {
"id": "483930a0514d0ef6",
"type": "split",
"children": [
{
"id": "66a1e71b6425f2ae",
"type": "tabs",
"children": [
{
"id": "3efcfe8f9cdde01b",
"type": "leaf",
"state": {
"type": "file-explorer",
"state": {
"sortOrder": "alphabetical",
"autoReveal": false
},
"icon": "lucide-folder-closed",
"title": "Files"
}
},
{
"id": "e5cc22e40223c366",
"type": "leaf",
"state": {
"type": "search",
"state": {
"query": "",
"matchingCase": false,
"explainSearch": false,
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical"
},
"icon": "lucide-search",
"title": "Search"
}
},
{
"id": "507ab36e67fb61a7",
"type": "leaf",
"state": {
"type": "bookmarks",
"state": {},
"icon": "lucide-bookmark",
"title": "Bookmarks"
}
}
]
}
],
"direction": "horizontal",
"width": 300
},
"right": {
"id": "004c8ca1c3bc51a3",
"type": "split",
"children": [
{
"id": "1afcc149866ef422",
"type": "tabs",
"children": [
{
"id": "b7472a1d4e25ce94",
"type": "leaf",
"state": {
"type": "backlink",
"state": {
"file": "_Buildings.base",
"collapseAll": false,
"extraContext": false,
"sortOrder": "alphabetical",
"showSearch": false,
"searchQuery": "",
"backlinkCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-coming-in",
"title": "Backlinks for _Buildings"
}
},
{
"id": "095e5dbebfe2b367",
"type": "leaf",
"state": {
"type": "outgoing-link",
"state": {
"file": "_Buildings.base",
"linksCollapsed": false,
"unlinkedCollapsed": true
},
"icon": "links-going-out",
"title": "Outgoing links from _Buildings"
}
},
{
"id": "f0714110409072de",
"type": "leaf",
"state": {
"type": "tag",
"state": {
"sortOrder": "frequency",
"useHierarchy": true,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-tags",
"title": "Tags"
}
},
{
"id": "a35be0737212302e",
"type": "leaf",
"state": {
"type": "all-properties",
"state": {
"sortOrder": "frequency",
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-archive",
"title": "All properties"
}
},
{
"id": "48907237d99e68b6",
"type": "leaf",
"state": {
"type": "outline",
"state": {
"file": "_Buildings.base",
"followCursor": false,
"showSearch": false,
"searchQuery": ""
},
"icon": "lucide-list",
"title": "Outline of _Buildings"
}
}
]
}
],
"direction": "horizontal",
"width": 300,
"collapsed": true
},
"left-ribbon": {
"hiddenItems": {
"switcher:Open quick switcher": false,
"graph:Open graph view": false,
"canvas:Create new canvas": false,
"daily-notes:Open today's daily note": false,
"templates:Insert template": false,
"command-palette:Open command palette": false,
"bases:Create new base": false
}
},
"active": "6e58412b029dfbac",
"lastOpenFiles": [
"_Talents.base",
"Corsair Flamer.md",
"Koru Symbiosis.md",
"_Units.base",
"Research Upgrade.md",
"Build Building.md",
"Untitled 8.md",
"_Buildings.base",
"Lasher.md",
"Production of Army.md",
"Recruit Mercenaries.md",
"Corsair.md",
"_.md",
"Pasted image 20260614164156.png",
"Untitled 7.md",
"Air unit.md",
"Bonus Damage vs Buildings.md",
"Bonus Damage vs Heavy Armor.md",
"Vine Feeder.md",
"Bonus Damage vs Air.md",
"Biological.md",
"Skyclutch.md",
"Bloodwell Attacker.md",
"Cultivator Defender.md",
"Synapse Canopy.md",
"Macrogenisis Canopy.md",
"Young Canopy.md",
"Elderwomb.md",
"Incubator.md"
]
}
View File
+24
View File
@@ -0,0 +1,24 @@
---
category: "[[Unit]]"
hexite: 100
Flux: 200
supply: 8
productionTime: 80
health: 625
movementSpeed: 500
damagePerSecond: 15
attackRange: 12
attributes:
- "[[Air unit]]"
- "[[Regains Energy From Attacking]]"
- "[[Biological]]"
- "[[Heavy Armor]]"
- "[[Bonus Damage vs Heavy Armor]]"
Tier: 3
Faction: "[[Grell]]"
Hotkey: D
buildAtSameTime: 1
Armor rating: 1
Energy: 5
Shields: 0
---
+1
View File
@@ -0,0 +1 @@
Tag of entity. Can influence damage it can take.
+9
View File
@@ -0,0 +1,9 @@
---
category: Building
hexite:
Flux:
productionTime:
health:
Armor rating:
Faction:
---
+9
View File
@@ -0,0 +1,9 @@
---
category: Building
hexite:
Flux:
productionTime:
health:
Armor rating:
Faction:
---
View File
+1
View File
@@ -0,0 +1 @@
This unit does extra damage to medium armour.
+21
View File
@@ -0,0 +1,21 @@
---
category: "[[Unit]]"
hexite: 125
supply: 3
productionTime: 33
health: 250
movementSpeed: 550
damagePerSecond: 15
attackRange: 1
attributes:
- "[[Medium Armor]]"
- "[[Biological]]"
Tier: 1
Flux: 0
Faction: "[[Grell]]"
Hotkey: G
buildAtSameTime: 1
Armor rating: 0
Energy: 0
Shields: 0
---
+9
View File
@@ -0,0 +1,9 @@
---
category: Building
hexite:
Flux:
productionTime:
health:
Armor rating:
Faction:
---
+5
View File
@@ -0,0 +1,5 @@
---
Hotkey: B
Faction: General
category: Menu
---
+22
View File
@@ -0,0 +1,22 @@
---
category: "[[Unit]]"
hexite: 100
Flux: 200
supply: 6
productionTime: 35
health: 1000
movementSpeed: 450
damagePerSecond: 64
attackRange: 4
attributes:
- "[[Heavy Armor]]"
- "[[Bonus Damage vs Light Armor]]"
- "[[Respawns for free after death]]"
Tier: 3
Faction: "[[Corsair]]"
Hotkey: V
buildAtSameTime: 1
Armor rating: 2
Energy: 0
Shields: 0
---
+20
View File
@@ -0,0 +1,20 @@
---
category: "[[Unit]]"
hexite: 100
Flux: 62
supply: 4
productionTime: 20
health: 375
Shields: 0
movementSpeed: 550
damagePerSecond: 20
attackRange: 9
attributes:
- "[[Medium Armor]]"
Tier: 2
Faction: "[[Corsair]]"
Hotkey:
buildAtSameTime: 2
Armor rating: 0
Energy: 0
---
+21
View File
@@ -0,0 +1,21 @@
---
category: "[[Unit]]"
hexite: 58
Flux: 0
supply: 2
productionTime: 30
health: 175
movementSpeed: 650
damagePerSecond: 8
attackRange: 8
attributes:
- "[[Light Armor]]"
- "[[Biological]]"
Tier: 1
Faction: "[[Corsair]]"
Hotkey: Z
buildAtSameTime: 3
Shields: 0
Armor rating: 0
Energy: 0
---
+20
View File
@@ -0,0 +1,20 @@
---
category: "[[Unit]]"
hexite: 100
Flux: 25
supply: 3
productionTime: 35
health: 320
movementSpeed: 750
damagePerSecond: 17
attackRange: 7
attributes:
- "[[Light Armor]]"
Tier: 1
Faction: "[[Corsair]]"
Hotkey: X
buildAtSameTime: 2
Shields: 0
Armor rating: 0
Energy: 0
---
+22
View File
@@ -0,0 +1,22 @@
---
category: "[[Unit]]"
hexite: 38
Flux: 100
supply: 4
productionTime: 30
health: 100
movementSpeed: 425
damagePerSecond: 14
attackRange: 20
attributes:
- "[[Light Armor]]"
- "[[Biological]]"
- "[[Bonus Damage vs Light Armor]]"
Tier: 1
Faction: "[[Corsair]]"
Hotkey: C
buildAtSameTime: 2
Shields: 100
Armor rating: 0
Energy: 0
---

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