From 7e5e7aad405f5cf454efff87ccddde5046372e40 Mon Sep 17 00:00:00 2001 From: Kara Alexandra Date: Wed, 24 Sep 2025 00:56:17 -0500 Subject: [PATCH] Initial commit --- .gitignore | 428 ++++++++++++ NethackHelper.sln | 25 + NethackHelper/Charisma.cs | 50 ++ NethackHelper/Item.cs | 21 + NethackHelper/ItemDisplay.Designer.cs | 72 ++ NethackHelper/ItemDisplay.cs | 177 +++++ NethackHelper/ItemDisplay.resx | 120 ++++ NethackHelper/MainForm.Designer.cs | 656 ++++++++++++++++++ NethackHelper/MainForm.cs | 180 +++++ NethackHelper/MainForm.resx | 299 ++++++++ NethackHelper/NethackHelper.csproj | 35 + NethackHelper/Program.cs | 17 + .../DataSources/CharismaSource.datasource | 10 + .../DataSources/Intrinsics.datasource | 10 + .../DataSources/SaveSource.datasource | 10 + NethackHelper/Reflection.cs | 9 + NethackHelper/SaveData.cs | 149 ++++ NethackHelper/SokobanFile.cs | 9 + NethackHelper/SokobanSolution.cs | 196 ++++++ NethackHelper/Versions.cs | 9 + NethackHelper/YamlOptions.cs | 28 + NethackHelper/icon.ico | Bin 0 -> 5694 bytes NethackHelper/items/potions-36.yaml | 57 ++ NethackHelper/items/potions-37.yaml | 57 ++ NethackHelper/items/rings.yaml | 57 ++ NethackHelper/items/scrolls.yaml | 68 ++ NethackHelper/items/versions.yaml | 10 + NethackHelper/items/wands.yaml | 49 ++ NethackHelper/sokoban/1a.yaml | 30 + NethackHelper/sokoban/2a.yaml | 49 ++ NethackHelper/sokoban/2b.yaml | 35 + NethackHelper/sokoban/3a.yaml | 33 + NethackHelper/sokoban/3b.yaml | 32 + NethackHelper/sokoban/4a.yaml | 51 ++ NethackHelper/sokoban/4b.yaml | 53 ++ 35 files changed, 3091 insertions(+) create mode 100644 .gitignore create mode 100644 NethackHelper.sln create mode 100644 NethackHelper/Charisma.cs create mode 100644 NethackHelper/Item.cs create mode 100644 NethackHelper/ItemDisplay.Designer.cs create mode 100644 NethackHelper/ItemDisplay.cs create mode 100644 NethackHelper/ItemDisplay.resx create mode 100644 NethackHelper/MainForm.Designer.cs create mode 100644 NethackHelper/MainForm.cs create mode 100644 NethackHelper/MainForm.resx create mode 100644 NethackHelper/NethackHelper.csproj create mode 100644 NethackHelper/Program.cs create mode 100644 NethackHelper/Properties/DataSources/CharismaSource.datasource create mode 100644 NethackHelper/Properties/DataSources/Intrinsics.datasource create mode 100644 NethackHelper/Properties/DataSources/SaveSource.datasource create mode 100644 NethackHelper/Reflection.cs create mode 100644 NethackHelper/SaveData.cs create mode 100644 NethackHelper/SokobanFile.cs create mode 100644 NethackHelper/SokobanSolution.cs create mode 100644 NethackHelper/Versions.cs create mode 100644 NethackHelper/YamlOptions.cs create mode 100644 NethackHelper/icon.ico create mode 100644 NethackHelper/items/potions-36.yaml create mode 100644 NethackHelper/items/potions-37.yaml create mode 100644 NethackHelper/items/rings.yaml create mode 100644 NethackHelper/items/scrolls.yaml create mode 100644 NethackHelper/items/versions.yaml create mode 100644 NethackHelper/items/wands.yaml create mode 100644 NethackHelper/sokoban/1a.yaml create mode 100644 NethackHelper/sokoban/2a.yaml create mode 100644 NethackHelper/sokoban/2b.yaml create mode 100644 NethackHelper/sokoban/3a.yaml create mode 100644 NethackHelper/sokoban/3b.yaml create mode 100644 NethackHelper/sokoban/4a.yaml create mode 100644 NethackHelper/sokoban/4b.yaml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..47a94ef --- /dev/null +++ b/.gitignore @@ -0,0 +1,428 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates +*.env + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ + +[Dd]ebug/x64/ +[Dd]ebugPublic/x64/ +[Rr]elease/x64/ +[Rr]eleases/x64/ +bin/x64/ +obj/x64/ + +[Dd]ebug/x86/ +[Dd]ebugPublic/x86/ +[Rr]elease/x86/ +[Rr]eleases/x86/ +bin/x86/ +obj/x86/ + +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +[Aa][Rr][Mm]64[Ee][Cc]/ +bld/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Build results on 'Bin' directories +**/[Bb]in/* +# Uncomment if you have tasks that rely on *.refresh files to move binaries +# (https://github.com/github/gitignore/pull/3736) +#!**/[Bb]in/*.refresh + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* +*.trx + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Approval Tests result files +*.received.* + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.idb +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +# but not Directory.Build.rsp, as it configures directory-level build defaults +!Directory.Build.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.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 + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_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 Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: 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 +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable 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 +*.appx +*.appxbundle +*.appxupload + +# 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 +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# 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 +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# 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/ + +# CodeRush personal settings +**/.cr/personal + +# Python Tools for Visual Studio (PTVS) +**/__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +#tools/** +#!tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog +MSBuild_Logs/ + +# AWS SAM Build and Temporary Artifacts folder +.aws-sam + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +**/.mfractor/ + +# Local History for Visual Studio +**/.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +**/.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp diff --git a/NethackHelper.sln b/NethackHelper.sln new file mode 100644 index 0000000..e340491 --- /dev/null +++ b/NethackHelper.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.33516.290 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NethackHelper", "NethackHelper\NethackHelper.csproj", "{551E16E7-B2D3-4143-AF0E-BE4691712B60}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {551E16E7-B2D3-4143-AF0E-BE4691712B60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {551E16E7-B2D3-4143-AF0E-BE4691712B60}.Debug|Any CPU.Build.0 = Debug|Any CPU + {551E16E7-B2D3-4143-AF0E-BE4691712B60}.Release|Any CPU.ActiveCfg = Release|Any CPU + {551E16E7-B2D3-4143-AF0E-BE4691712B60}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {0CE91709-1817-4270-943D-93170193950A} + EndGlobalSection +EndGlobal diff --git a/NethackHelper/Charisma.cs b/NethackHelper/Charisma.cs new file mode 100644 index 0000000..767919c --- /dev/null +++ b/NethackHelper/Charisma.cs @@ -0,0 +1,50 @@ +namespace NethackHelper { + using System.Collections.Generic; + using System.Windows.Forms; + + public struct CharismaClass { + public string DisplayName { get; private set; } = string.Empty; + public double Multiplier { get; private set; } + + public CharismaClass() { } + + public static List Classes = [ + new() { + DisplayName = "CHA 5-", + Multiplier = 2.0, + }, + new() { + DisplayName = "CHA 6 - 7", + Multiplier = 1.5, + }, + new() { + DisplayName = "CHA 8 - 10", + Multiplier = 1.3333, + }, + new() { + DisplayName = "CHA 11 - 15", + Multiplier = 1.0, + }, + new() { + DisplayName = "CHA 16 - 17", + Multiplier = 0.75, + }, + new() { + DisplayName = "CHA 18", + Multiplier = 0.6667, + }, + new() { + DisplayName = "CHA 19+", + Multiplier = 0.5, + }, + ]; + + public static readonly CharismaClass DefaultClass = Classes[3]; + } + + public class CharismaSource : BindingSource { + public CharismaSource() { + this.DataSource = CharismaClass.Classes; + } + } +} diff --git a/NethackHelper/Item.cs b/NethackHelper/Item.cs new file mode 100644 index 0000000..0cbb361 --- /dev/null +++ b/NethackHelper/Item.cs @@ -0,0 +1,21 @@ +namespace NethackHelper { + using System.Collections.Generic; + + public class Item { + public string Name { get; set; } = string.Empty; + public int Cost { get; set; } + public int Ink { get; set; } + public string? Appearance { get; set; } + } + + public class ItemList { + public List Items { get; set; } = new(); + } + + public enum ItemAttribute { + Name, + Cost, + Ink, + Appearance, + } +} diff --git a/NethackHelper/ItemDisplay.Designer.cs b/NethackHelper/ItemDisplay.Designer.cs new file mode 100644 index 0000000..2247142 --- /dev/null +++ b/NethackHelper/ItemDisplay.Designer.cs @@ -0,0 +1,72 @@ +namespace NethackHelper { + partial class ItemDisplay { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) { + if (disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() { + itemListView = new System.Windows.Forms.ListView(); + nameColumn = new System.Windows.Forms.ColumnHeader(); + appearanceColumn = new System.Windows.Forms.ColumnHeader(); + SuspendLayout(); + // + // itemListView + // + itemListView.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right; + itemListView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { nameColumn, appearanceColumn }); + itemListView.FullRowSelect = true; + itemListView.Location = new System.Drawing.Point(0, 0); + itemListView.MultiSelect = false; + itemListView.Name = "itemListView"; + itemListView.Size = new System.Drawing.Size(610, 568); + itemListView.Sorting = System.Windows.Forms.SortOrder.Ascending; + itemListView.TabIndex = 0; + itemListView.UseCompatibleStateImageBehavior = false; + itemListView.View = System.Windows.Forms.View.Details; + itemListView.MouseDoubleClick += itemListView_MouseDoubleClick; + // + // nameColumn + // + nameColumn.Text = "Name"; + nameColumn.Width = 144; + // + // appearanceColumn + // + appearanceColumn.Text = "Appearance"; + appearanceColumn.Width = 144; + // + // ItemDisplay + // + AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + Controls.Add(itemListView); + Name = "ItemDisplay"; + Size = new System.Drawing.Size(613, 568); + ResumeLayout(false); + } + + #endregion + + private System.Windows.Forms.ListView itemListView; + private System.Windows.Forms.ColumnHeader nameColumn; + private System.Windows.Forms.ColumnHeader appearanceColumn; + } +} diff --git a/NethackHelper/ItemDisplay.cs b/NethackHelper/ItemDisplay.cs new file mode 100644 index 0000000..10e3ee5 --- /dev/null +++ b/NethackHelper/ItemDisplay.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using static System.Windows.Forms.ListViewItem; +using System.ComponentModel; + +namespace NethackHelper { + public partial class ItemDisplay : UserControl { + public const string UNIDENTIFIED = "[randomized]"; + public static readonly Color SELECTED_COLOR = Color.Black; + public static readonly Color UNSELECTED_COLOR = Color.Gray; + + private static readonly Dictionary> COLUMN_MAP = new() { + [ItemAttribute.Name] = item => item.Name, + [ItemAttribute.Cost] = item => item.Cost.ToString(), + [ItemAttribute.Ink] = item => item.Ink.ToString(), + [ItemAttribute.Appearance] = item => item.Appearance ?? UNIDENTIFIED, + }; + + [Browsable(false)] + [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] + public Func CostFormatter { get; set; } = cost => cost.ToString(); + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] + public List Columns { get; set; } = new(); + + private int[] GroupCosts { get; set; } = []; + + private Dictionary AppearanceMap { get; set; } = new(); + + public ItemDisplay() { + InitializeComponent(); + this.itemListView.ListViewItemSorter = Comparer.Create(CompareItems); + } + + protected override void OnLoad(EventArgs e) { + base.OnLoad(e); + if (this.Columns != null) { + this.itemListView.Columns.Clear(); + foreach (var column in this.Columns) { + this.itemListView.Columns.Add(column.Attribute.ToString(), column.Width); + } + } + } + + public void DisplayItemList(ItemList itemList, IdentificationRecord? idRecord) { + this.itemListView.Groups.Clear(); + this.itemListView.Items.Clear(); + this.AppearanceMap.Clear(); + + this.GroupCosts = itemList.Items.Select(item => item.Cost).Distinct().Order().ToArray(); + var costDictionary = new Dictionary(); + + foreach (var cost in this.GroupCosts) { + var group = new ListViewGroup(this.CostFormatter.Invoke(cost), HorizontalAlignment.Center); + this.itemListView.Groups.Add(group); + costDictionary.Add(cost, group); + } + + foreach (var item in itemList.Items) { + bool identified = false; + ItemRecord record = default; + if (idRecord != null) { + if (idRecord.TryGetValue(item.Name, out var identity)) { + record = identity; + identified = true; + } + } else if (item.Appearance != null) { + record = new ItemRecord() { + Name = item.Name, + Appearance = item.Appearance, + }; + identified = true; + } + + AppearanceMap[item.Name] = record.Appearance; + + var columns = this.Columns.Select(col => COLUMN_MAP[col.Attribute].Invoke(item)).ToArray(); + + var listViewItem = new ListViewItem(columns, costDictionary[item.Cost]); + listViewItem.UseItemStyleForSubItems = false; + var baseFont = new Font(this.itemListView.Font, FontStyle.Regular); + var baseColor = UNSELECTED_COLOR; + if (!identified) { + baseFont = new Font(baseFont, FontStyle.Bold); + baseColor = SELECTED_COLOR; + } + listViewItem.Checked = identified; + listViewItem.Font = baseFont; + listViewItem.ForeColor = baseColor; + foreach (ListViewSubItem subItem in listViewItem.SubItems) { + subItem.Font = baseFont; + subItem.ForeColor = baseColor; + } + if (record.Appearance == null) { + var fontStyle = FontStyle.Italic; + if (!identified) { + fontStyle |= FontStyle.Bold; + } + + for (var i = 0; i < this.Columns.Count; i++) { + if (this.Columns[i].Attribute == ItemAttribute.Appearance) { + listViewItem.SubItems[i].Font = new Font(baseFont, fontStyle); + } + } + } + this.itemListView.Items.Add(listViewItem); + } + } + + public IdentificationRecord Export() { + List records = []; + foreach (ListViewItem item in this.itemListView.Items) { + if (item.Checked) { + string? appearance = this.AppearanceMap[item.Text]; + records.Add(new() { + Name = item.Text, + Appearance = appearance, + }); + } + } + return new(records); + } + + public void UpdateCostHeaders() { + for (int i = 0; i < this.GroupCosts.Length; i++) { + this.itemListView.Groups[i].Header = this.CostFormatter.Invoke(this.GroupCosts[i]); + } + } + + private void itemListView_MouseDoubleClick(object sender, MouseEventArgs e) { + if (this.itemListView.SelectedItems.Count == 1) { + var item = this.itemListView.SelectedItems[0]; + item.Checked = !item.Checked; + var baseFont = item.Font; + foreach (ListViewSubItem subItem in item.SubItems) { + if (item.Checked) { + if (subItem.Font.Italic) { + subItem.Font = new Font(baseFont, FontStyle.Italic); + } else { + subItem.Font = new Font(baseFont, FontStyle.Regular); + } + subItem.ForeColor = UNSELECTED_COLOR; + } else { + if (subItem.Font.Italic) { + subItem.Font = new Font(baseFont, FontStyle.Bold | FontStyle.Italic); + } else { + subItem.Font = new Font(baseFont, FontStyle.Bold | FontStyle.Regular); + } + subItem.ForeColor = SELECTED_COLOR; + } + } + this.itemListView.Sort(); + } + } + + private static int CompareItems(ListViewItem a, ListViewItem b) { + if (a.Checked != b.Checked) { + return a.Checked.CompareTo(b.Checked); + } else { + return a.Text.CompareTo(b.Text); + } + } + } + + [Serializable] + public class ItemDisplayColumn { + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public ItemAttribute Attribute { get; set; } + + [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] + public int Width { get; set; } + } +} diff --git a/NethackHelper/ItemDisplay.resx b/NethackHelper/ItemDisplay.resx new file mode 100644 index 0000000..8b2ff64 --- /dev/null +++ b/NethackHelper/ItemDisplay.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/NethackHelper/MainForm.Designer.cs b/NethackHelper/MainForm.Designer.cs new file mode 100644 index 0000000..ee7efd4 --- /dev/null +++ b/NethackHelper/MainForm.Designer.cs @@ -0,0 +1,656 @@ +using System.Drawing; +using System.Windows.Forms; + +namespace NethackHelper { + partial class MainForm : Form { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) { + if (disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() { + components = new System.ComponentModel.Container(); + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm)); + CharismaClass charismaClass8 = new CharismaClass(); + CharismaClass charismaClass9 = new CharismaClass(); + CharismaClass charismaClass10 = new CharismaClass(); + CharismaClass charismaClass11 = new CharismaClass(); + CharismaClass charismaClass12 = new CharismaClass(); + CharismaClass charismaClass13 = new CharismaClass(); + CharismaClass charismaClass14 = new CharismaClass(); + mainTabControl = new TabControl(); + itemsTab = new TabPage(); + suckerBox = new CheckBox(); + saveSourceBindingSource = new BindingSource(components); + shoppingTabControl = new TabControl(); + scrollPotionTab = new TabPage(); + potionDisplay = new ItemDisplay(); + scrollDisplay = new ItemDisplay(); + wandRingTab = new TabPage(); + ringDisplay = new ItemDisplay(); + wandDisplay = new ItemDisplay(); + charismaSelector = new ComboBox(); + charismaSourceBindingSource = new BindingSource(components); + intrinsicsTab = new TabPage(); + label2 = new Label(); + lastPrayerPicker = new NumericUpDown(); + intrinsicsBindingSource = new BindingSource(components); + label1 = new Label(); + protectionPicker = new NumericUpDown(); + warningCheckbox = new CheckBox(); + teleportitisCheckbox = new CheckBox(); + teleportControlCheckbox = new CheckBox(); + telepathyCheckbox = new CheckBox(); + stealthCheckbox = new CheckBox(); + speedCheckbox = new CheckBox(); + sleepResistanceCheckbox = new CheckBox(); + shockResistanceCheckbox = new CheckBox(); + seeInvisibleCheckbox = new CheckBox(); + searchingCheckbox = new CheckBox(); + poisonResistanceCheckbox = new CheckBox(); + invisibleCheckbox = new CheckBox(); + fireResistanceCheckbox = new CheckBox(); + disintegrationResistanceCheckbox = new CheckBox(); + coldResistanceCheckbox = new CheckBox(); + sokobanTab = new TabPage(); + sokobanVertical = new CheckBox(); + sokobanHorizontal = new CheckBox(); + sokobanPrev = new Button(); + sokobanNext = new Button(); + sokobanSolution = new Label(); + sokobanLevelList = new ListBox(); + mainMenu = new MenuStrip(); + fileToolStripMenuItem = new ToolStripMenuItem(); + resetToolStripMenuItem = new ToolStripMenuItem(); + mainTabControl.SuspendLayout(); + itemsTab.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize) saveSourceBindingSource).BeginInit(); + shoppingTabControl.SuspendLayout(); + scrollPotionTab.SuspendLayout(); + wandRingTab.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize) charismaSourceBindingSource).BeginInit(); + intrinsicsTab.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize) lastPrayerPicker).BeginInit(); + ((System.ComponentModel.ISupportInitialize) intrinsicsBindingSource).BeginInit(); + ((System.ComponentModel.ISupportInitialize) protectionPicker).BeginInit(); + sokobanTab.SuspendLayout(); + mainMenu.SuspendLayout(); + SuspendLayout(); + // + // mainTabControl + // + mainTabControl.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + mainTabControl.Controls.Add(itemsTab); + mainTabControl.Controls.Add(intrinsicsTab); + mainTabControl.Controls.Add(sokobanTab); + mainTabControl.Location = new Point(12, 27); + mainTabControl.Name = "mainTabControl"; + mainTabControl.SelectedIndex = 0; + mainTabControl.Size = new Size(672, 621); + mainTabControl.TabIndex = 0; + // + // itemsTab + // + itemsTab.Controls.Add(suckerBox); + itemsTab.Controls.Add(shoppingTabControl); + itemsTab.Controls.Add(charismaSelector); + itemsTab.Location = new Point(4, 24); + itemsTab.Name = "itemsTab"; + itemsTab.Padding = new Padding(3); + itemsTab.Size = new Size(664, 593); + itemsTab.TabIndex = 1; + itemsTab.Text = "Items"; + itemsTab.UseVisualStyleBackColor = true; + // + // suckerBox + // + suckerBox.AutoSize = true; + suckerBox.DataBindings.Add(new Binding("Checked", saveSourceBindingSource, "Sucker", true)); + suckerBox.Location = new Point(133, 8); + suckerBox.Name = "suckerBox"; + suckerBox.Size = new Size(61, 19); + suckerBox.TabIndex = 2; + suckerBox.Text = "Sucker"; + suckerBox.UseVisualStyleBackColor = true; + suckerBox.CheckedChanged += suckerBox_CheckedChanged; + // + // saveSourceBindingSource + // + saveSourceBindingSource.DataSource = typeof(SaveSource); + saveSourceBindingSource.Position = 0; + // + // shoppingTabControl + // + shoppingTabControl.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; + shoppingTabControl.Controls.Add(scrollPotionTab); + shoppingTabControl.Controls.Add(wandRingTab); + shoppingTabControl.Location = new Point(6, 35); + shoppingTabControl.Name = "shoppingTabControl"; + shoppingTabControl.SelectedIndex = 0; + shoppingTabControl.Size = new Size(652, 555); + shoppingTabControl.TabIndex = 1; + // + // scrollPotionTab + // + scrollPotionTab.Controls.Add(potionDisplay); + scrollPotionTab.Controls.Add(scrollDisplay); + scrollPotionTab.Location = new Point(4, 24); + scrollPotionTab.Name = "scrollPotionTab"; + scrollPotionTab.Padding = new Padding(3); + scrollPotionTab.Size = new Size(644, 527); + scrollPotionTab.TabIndex = 1; + scrollPotionTab.Text = "Scrolls / Potions"; + scrollPotionTab.UseVisualStyleBackColor = true; + // + // potionDisplay + // + potionDisplay.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left; + potionDisplay.Columns = (System.Collections.Generic.List) resources.GetObject("potionDisplay.Columns"); + potionDisplay.Location = new Point(325, 6); + potionDisplay.Name = "potionDisplay"; + potionDisplay.Size = new Size(313, 515); + potionDisplay.TabIndex = 1; + // + // scrollDisplay + // + scrollDisplay.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left; + scrollDisplay.Columns = (System.Collections.Generic.List) resources.GetObject("scrollDisplay.Columns"); + scrollDisplay.Location = new Point(6, 6); + scrollDisplay.Name = "scrollDisplay"; + scrollDisplay.Size = new Size(313, 515); + scrollDisplay.TabIndex = 0; + // + // wandRingTab + // + wandRingTab.Controls.Add(ringDisplay); + wandRingTab.Controls.Add(wandDisplay); + wandRingTab.Location = new Point(4, 24); + wandRingTab.Name = "wandRingTab"; + wandRingTab.Padding = new Padding(3); + wandRingTab.Size = new Size(644, 527); + wandRingTab.TabIndex = 2; + wandRingTab.Text = "Wands / Rings"; + wandRingTab.UseVisualStyleBackColor = true; + // + // ringDisplay + // + ringDisplay.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right; + ringDisplay.Columns = (System.Collections.Generic.List) resources.GetObject("ringDisplay.Columns"); + ringDisplay.Location = new Point(325, 6); + ringDisplay.Name = "ringDisplay"; + ringDisplay.Size = new Size(313, 515); + ringDisplay.TabIndex = 2; + // + // wandDisplay + // + wandDisplay.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left; + wandDisplay.Columns = (System.Collections.Generic.List) resources.GetObject("wandDisplay.Columns"); + wandDisplay.Location = new Point(6, 6); + wandDisplay.Name = "wandDisplay"; + wandDisplay.Size = new Size(313, 515); + wandDisplay.TabIndex = 1; + // + // charismaSelector + // + charismaSelector.DataBindings.Add(new Binding("SelectedItem", saveSourceBindingSource, "CharismaClass", true)); + charismaSelector.DataSource = charismaSourceBindingSource; + charismaSelector.DisplayMember = "DisplayName"; + charismaSelector.FormattingEnabled = true; + charismaSelector.Items.AddRange(new object[] { charismaClass8, charismaClass9, charismaClass10, charismaClass11, charismaClass12, charismaClass13, charismaClass14 }); + charismaSelector.Location = new Point(6, 6); + charismaSelector.Name = "charismaSelector"; + charismaSelector.Size = new Size(121, 23); + charismaSelector.TabIndex = 0; + charismaSelector.ValueMember = "Multiplier"; + charismaSelector.SelectedIndexChanged += charismaSelector_SelectedIndexChanged; + // + // charismaSourceBindingSource + // + charismaSourceBindingSource.DataSource = typeof(CharismaSource); + charismaSourceBindingSource.Position = 0; + // + // intrinsicsTab + // + intrinsicsTab.Controls.Add(label2); + intrinsicsTab.Controls.Add(lastPrayerPicker); + intrinsicsTab.Controls.Add(label1); + intrinsicsTab.Controls.Add(protectionPicker); + intrinsicsTab.Controls.Add(warningCheckbox); + intrinsicsTab.Controls.Add(teleportitisCheckbox); + intrinsicsTab.Controls.Add(teleportControlCheckbox); + intrinsicsTab.Controls.Add(telepathyCheckbox); + intrinsicsTab.Controls.Add(stealthCheckbox); + intrinsicsTab.Controls.Add(speedCheckbox); + intrinsicsTab.Controls.Add(sleepResistanceCheckbox); + intrinsicsTab.Controls.Add(shockResistanceCheckbox); + intrinsicsTab.Controls.Add(seeInvisibleCheckbox); + intrinsicsTab.Controls.Add(searchingCheckbox); + intrinsicsTab.Controls.Add(poisonResistanceCheckbox); + intrinsicsTab.Controls.Add(invisibleCheckbox); + intrinsicsTab.Controls.Add(fireResistanceCheckbox); + intrinsicsTab.Controls.Add(disintegrationResistanceCheckbox); + intrinsicsTab.Controls.Add(coldResistanceCheckbox); + intrinsicsTab.Location = new Point(4, 24); + intrinsicsTab.Name = "intrinsicsTab"; + intrinsicsTab.Padding = new Padding(3); + intrinsicsTab.Size = new Size(664, 593); + intrinsicsTab.TabIndex = 2; + intrinsicsTab.Text = "Intrinsics"; + intrinsicsTab.UseVisualStyleBackColor = true; + // + // label2 + // + label2.AutoSize = true; + label2.Location = new Point(6, 411); + label2.Name = "label2"; + label2.Size = new Size(64, 15); + label2.TabIndex = 18; + label2.Text = "Last Prayer"; + // + // lastPrayerPicker + // + lastPrayerPicker.DataBindings.Add(new Binding("Value", intrinsicsBindingSource, "LastPrayer", true)); + lastPrayerPicker.Increment = new decimal(new int[] { 1000, 0, 0, 0 }); + lastPrayerPicker.Location = new Point(76, 409); + lastPrayerPicker.Maximum = new decimal(new int[] { 100000, 0, 0, 0 }); + lastPrayerPicker.Name = "lastPrayerPicker"; + lastPrayerPicker.Size = new Size(61, 23); + lastPrayerPicker.TabIndex = 17; + lastPrayerPicker.ThousandsSeparator = true; + // + // intrinsicsBindingSource + // + intrinsicsBindingSource.DataSource = typeof(IntrinsicsSource); + intrinsicsBindingSource.Position = 0; + // + // label1 + // + label1.AutoSize = true; + label1.Location = new Point(6, 382); + label1.Name = "label1"; + label1.Size = new Size(62, 15); + label1.TabIndex = 16; + label1.Text = "Protection"; + // + // protectionPicker + // + protectionPicker.DataBindings.Add(new Binding("Value", intrinsicsBindingSource, "Protection", true)); + protectionPicker.Location = new Point(74, 380); + protectionPicker.Maximum = new decimal(new int[] { 30, 0, 0, 0 }); + protectionPicker.Name = "protectionPicker"; + protectionPicker.Size = new Size(41, 23); + protectionPicker.TabIndex = 15; + // + // warningCheckbox + // + warningCheckbox.AutoSize = true; + warningCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "Warning", true)); + warningCheckbox.Location = new Point(6, 355); + warningCheckbox.Name = "warningCheckbox"; + warningCheckbox.Size = new Size(71, 19); + warningCheckbox.TabIndex = 14; + warningCheckbox.Text = "Warning"; + warningCheckbox.UseVisualStyleBackColor = true; + // + // teleportitisCheckbox + // + teleportitisCheckbox.AutoSize = true; + teleportitisCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "Teleportitis", true)); + teleportitisCheckbox.Location = new Point(6, 330); + teleportitisCheckbox.Name = "teleportitisCheckbox"; + teleportitisCheckbox.Size = new Size(83, 19); + teleportitisCheckbox.TabIndex = 13; + teleportitisCheckbox.Text = "Teleportitis"; + teleportitisCheckbox.UseVisualStyleBackColor = true; + // + // teleportControlCheckbox + // + teleportControlCheckbox.AutoSize = true; + teleportControlCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "TeleportControl", true)); + teleportControlCheckbox.Location = new Point(6, 305); + teleportControlCheckbox.Name = "teleportControlCheckbox"; + teleportControlCheckbox.Size = new Size(111, 19); + teleportControlCheckbox.TabIndex = 12; + teleportControlCheckbox.Text = "Teleport Control"; + teleportControlCheckbox.UseVisualStyleBackColor = true; + // + // telepathyCheckbox + // + telepathyCheckbox.AutoSize = true; + telepathyCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "Telepathy", true)); + telepathyCheckbox.Location = new Point(6, 280); + telepathyCheckbox.Name = "telepathyCheckbox"; + telepathyCheckbox.Size = new Size(76, 19); + telepathyCheckbox.TabIndex = 11; + telepathyCheckbox.Text = "Telepathy"; + telepathyCheckbox.UseVisualStyleBackColor = true; + // + // stealthCheckbox + // + stealthCheckbox.AutoSize = true; + stealthCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "Stealth", true)); + stealthCheckbox.Location = new Point(6, 255); + stealthCheckbox.Name = "stealthCheckbox"; + stealthCheckbox.Size = new Size(62, 19); + stealthCheckbox.TabIndex = 10; + stealthCheckbox.Text = "Stealth"; + stealthCheckbox.UseVisualStyleBackColor = true; + // + // speedCheckbox + // + speedCheckbox.AutoSize = true; + speedCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "Speed", true)); + speedCheckbox.Location = new Point(6, 230); + speedCheckbox.Name = "speedCheckbox"; + speedCheckbox.Size = new Size(58, 19); + speedCheckbox.TabIndex = 9; + speedCheckbox.Text = "Speed"; + speedCheckbox.UseVisualStyleBackColor = true; + // + // sleepResistanceCheckbox + // + sleepResistanceCheckbox.AutoSize = true; + sleepResistanceCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "SleepResistance", true)); + sleepResistanceCheckbox.Location = new Point(6, 207); + sleepResistanceCheckbox.Name = "sleepResistanceCheckbox"; + sleepResistanceCheckbox.Size = new Size(112, 19); + sleepResistanceCheckbox.TabIndex = 8; + sleepResistanceCheckbox.Text = "Sleep Resistance"; + sleepResistanceCheckbox.UseVisualStyleBackColor = true; + // + // shockResistanceCheckbox + // + shockResistanceCheckbox.AutoSize = true; + shockResistanceCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "ShockResistance", true)); + shockResistanceCheckbox.Location = new Point(6, 182); + shockResistanceCheckbox.Name = "shockResistanceCheckbox"; + shockResistanceCheckbox.Size = new Size(116, 19); + shockResistanceCheckbox.TabIndex = 7; + shockResistanceCheckbox.Text = "Shock Resistance"; + shockResistanceCheckbox.UseVisualStyleBackColor = true; + // + // seeInvisibleCheckbox + // + seeInvisibleCheckbox.AutoSize = true; + seeInvisibleCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "SeeInvisible", true)); + seeInvisibleCheckbox.Location = new Point(6, 157); + seeInvisibleCheckbox.Name = "seeInvisibleCheckbox"; + seeInvisibleCheckbox.Size = new Size(90, 19); + seeInvisibleCheckbox.TabIndex = 6; + seeInvisibleCheckbox.Text = "See Invisible"; + seeInvisibleCheckbox.UseVisualStyleBackColor = true; + // + // searchingCheckbox + // + searchingCheckbox.AutoSize = true; + searchingCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "Searching", true)); + searchingCheckbox.Location = new Point(6, 131); + searchingCheckbox.Name = "searchingCheckbox"; + searchingCheckbox.Size = new Size(78, 19); + searchingCheckbox.TabIndex = 5; + searchingCheckbox.Text = "Searching"; + searchingCheckbox.UseVisualStyleBackColor = true; + // + // poisonResistanceCheckbox + // + poisonResistanceCheckbox.AutoSize = true; + poisonResistanceCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "PoisonResistance", true)); + poisonResistanceCheckbox.Location = new Point(6, 106); + poisonResistanceCheckbox.Name = "poisonResistanceCheckbox"; + poisonResistanceCheckbox.Size = new Size(120, 19); + poisonResistanceCheckbox.TabIndex = 4; + poisonResistanceCheckbox.Text = "Poison Resistance"; + poisonResistanceCheckbox.UseVisualStyleBackColor = true; + // + // invisibleCheckbox + // + invisibleCheckbox.AutoSize = true; + invisibleCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "Invisible", true)); + invisibleCheckbox.Location = new Point(6, 81); + invisibleCheckbox.Name = "invisibleCheckbox"; + invisibleCheckbox.Size = new Size(69, 19); + invisibleCheckbox.TabIndex = 3; + invisibleCheckbox.Text = "Inivisble"; + invisibleCheckbox.UseVisualStyleBackColor = true; + // + // fireResistanceCheckbox + // + fireResistanceCheckbox.AutoSize = true; + fireResistanceCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "FireResistance", true)); + fireResistanceCheckbox.Location = new Point(6, 56); + fireResistanceCheckbox.Name = "fireResistanceCheckbox"; + fireResistanceCheckbox.Size = new Size(103, 19); + fireResistanceCheckbox.TabIndex = 2; + fireResistanceCheckbox.Text = "Fire Resistance"; + fireResistanceCheckbox.UseVisualStyleBackColor = true; + // + // disintegrationResistanceCheckbox + // + disintegrationResistanceCheckbox.AutoSize = true; + disintegrationResistanceCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "DisintegrationResistance", true)); + disintegrationResistanceCheckbox.Location = new Point(6, 31); + disintegrationResistanceCheckbox.Name = "disintegrationResistanceCheckbox"; + disintegrationResistanceCheckbox.Size = new Size(158, 19); + disintegrationResistanceCheckbox.TabIndex = 1; + disintegrationResistanceCheckbox.Text = "Disintegration Resistance"; + disintegrationResistanceCheckbox.UseVisualStyleBackColor = true; + // + // coldResistanceCheckbox + // + coldResistanceCheckbox.AutoSize = true; + coldResistanceCheckbox.DataBindings.Add(new Binding("Checked", intrinsicsBindingSource, "ColdResistance", true)); + coldResistanceCheckbox.Location = new Point(6, 6); + coldResistanceCheckbox.Name = "coldResistanceCheckbox"; + coldResistanceCheckbox.Size = new Size(109, 19); + coldResistanceCheckbox.TabIndex = 0; + coldResistanceCheckbox.Text = "Cold Resistance"; + coldResistanceCheckbox.UseVisualStyleBackColor = true; + // + // sokobanTab + // + sokobanTab.Controls.Add(sokobanVertical); + sokobanTab.Controls.Add(sokobanHorizontal); + sokobanTab.Controls.Add(sokobanPrev); + sokobanTab.Controls.Add(sokobanNext); + sokobanTab.Controls.Add(sokobanSolution); + sokobanTab.Controls.Add(sokobanLevelList); + sokobanTab.Location = new Point(4, 24); + sokobanTab.Name = "sokobanTab"; + sokobanTab.Padding = new Padding(3); + sokobanTab.Size = new Size(664, 593); + sokobanTab.TabIndex = 0; + sokobanTab.Text = "Sokoban"; + sokobanTab.UseVisualStyleBackColor = true; + // + // sokobanVertical + // + sokobanVertical.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; + sokobanVertical.Location = new Point(151, 564); + sokobanVertical.Name = "sokobanVertical"; + sokobanVertical.Size = new Size(123, 23); + sokobanVertical.TabIndex = 3; + sokobanVertical.Text = "Vertical Reflection"; + sokobanVertical.UseVisualStyleBackColor = true; + sokobanVertical.CheckedChanged += sokobanReflection_CheckedChanged; + sokobanVertical.KeyDown += sokobanLevelList_KeyDown; + // + // sokobanHorizontal + // + sokobanHorizontal.Anchor = AnchorStyles.Bottom | AnchorStyles.Left; + sokobanHorizontal.Location = new Point(6, 564); + sokobanHorizontal.Name = "sokobanHorizontal"; + sokobanHorizontal.Size = new Size(139, 23); + sokobanHorizontal.TabIndex = 2; + sokobanHorizontal.Text = "Horizontal Reflection"; + sokobanHorizontal.UseVisualStyleBackColor = true; + sokobanHorizontal.CheckedChanged += sokobanReflection_CheckedChanged; + sokobanHorizontal.KeyDown += sokobanLevelList_KeyDown; + // + // sokobanPrev + // + sokobanPrev.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + sokobanPrev.Location = new Point(438, 563); + sokobanPrev.Name = "sokobanPrev"; + sokobanPrev.Size = new Size(24, 23); + sokobanPrev.TabIndex = 4; + sokobanPrev.Text = "<"; + sokobanPrev.UseVisualStyleBackColor = true; + sokobanPrev.Click += sokobanPrev_Click; + sokobanPrev.KeyDown += sokobanLevelList_KeyDown; + // + // sokobanNext + // + sokobanNext.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; + sokobanNext.Location = new Point(468, 563); + sokobanNext.Name = "sokobanNext"; + sokobanNext.Size = new Size(24, 23); + sokobanNext.TabIndex = 5; + sokobanNext.Text = ">"; + sokobanNext.UseVisualStyleBackColor = true; + sokobanNext.Click += sokobanNext_Click; + sokobanNext.KeyDown += sokobanLevelList_KeyDown; + // + // sokobanSolution + // + sokobanSolution.Font = new Font("Consolas", 18F); + sokobanSolution.Location = new Point(6, 6); + sokobanSolution.Name = "sokobanSolution"; + sokobanSolution.Size = new Size(486, 554); + sokobanSolution.TabIndex = 1; + // + // sokobanLevelList + // + sokobanLevelList.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Right; + sokobanLevelList.FormattingEnabled = true; + sokobanLevelList.IntegralHeight = false; + sokobanLevelList.Location = new Point(498, 6); + sokobanLevelList.Name = "sokobanLevelList"; + sokobanLevelList.Size = new Size(160, 581); + sokobanLevelList.TabIndex = 1; + sokobanLevelList.SelectedIndexChanged += sokobanLevelList_SelectedIndexChanged; + sokobanLevelList.KeyDown += sokobanLevelList_KeyDown; + // + // mainMenu + // + mainMenu.Items.AddRange(new ToolStripItem[] { fileToolStripMenuItem }); + mainMenu.Location = new Point(0, 0); + mainMenu.Name = "mainMenu"; + mainMenu.Size = new Size(696, 24); + mainMenu.TabIndex = 1; + // + // fileToolStripMenuItem + // + fileToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { resetToolStripMenuItem }); + fileToolStripMenuItem.Name = "fileToolStripMenuItem"; + fileToolStripMenuItem.Size = new Size(37, 20); + fileToolStripMenuItem.Text = "File"; + // + // resetToolStripMenuItem + // + resetToolStripMenuItem.Name = "resetToolStripMenuItem"; + resetToolStripMenuItem.Size = new Size(102, 22); + resetToolStripMenuItem.Text = "Reset"; + // + // MainForm + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(696, 660); + Controls.Add(mainTabControl); + Controls.Add(mainMenu); + Icon = (Icon) resources.GetObject("$this.Icon"); + MainMenuStrip = mainMenu; + MaximizeBox = false; + MaximumSize = new Size(712, 1200); + MinimumSize = new Size(712, 500); + Name = "MainForm"; + SizeGripStyle = SizeGripStyle.Hide; + StartPosition = FormStartPosition.CenterScreen; + Text = "NethackHelper"; + FormClosing += Form1_FormClosing; + mainTabControl.ResumeLayout(false); + itemsTab.ResumeLayout(false); + itemsTab.PerformLayout(); + ((System.ComponentModel.ISupportInitialize) saveSourceBindingSource).EndInit(); + shoppingTabControl.ResumeLayout(false); + scrollPotionTab.ResumeLayout(false); + wandRingTab.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize) charismaSourceBindingSource).EndInit(); + intrinsicsTab.ResumeLayout(false); + intrinsicsTab.PerformLayout(); + ((System.ComponentModel.ISupportInitialize) lastPrayerPicker).EndInit(); + ((System.ComponentModel.ISupportInitialize) intrinsicsBindingSource).EndInit(); + ((System.ComponentModel.ISupportInitialize) protectionPicker).EndInit(); + sokobanTab.ResumeLayout(false); + mainMenu.ResumeLayout(false); + mainMenu.PerformLayout(); + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private TabControl mainTabControl; + private TabPage sokobanTab; + private Label sokobanSolution; + private ListBox sokobanLevelList; + private Button sokobanPrev; + private Button sokobanNext; + private CheckBox sokobanVertical; + private CheckBox sokobanHorizontal; + private TabPage itemsTab; + private ComboBox charismaSelector; + private TabControl shoppingTabControl; + private TabPage potionsTab; + private TabPage scrollPotionTab; + private ItemDisplay scrollDisplay; + private ItemDisplay potionDisplay; + private TabPage wandRingTab; + private ItemDisplay ringDisplay; + private ItemDisplay wandDisplay; + private CheckBox suckerBox; + private TabPage intrinsicsTab; + private CheckBox warningCheckbox; + private CheckBox teleportitisCheckbox; + private CheckBox teleportControlCheckbox; + private CheckBox telepathyCheckbox; + private CheckBox stealthCheckbox; + private CheckBox speedCheckbox; + private CheckBox sleepResistanceCheckbox; + private CheckBox shockResistanceCheckbox; + private CheckBox seeInvisibleCheckbox; + private CheckBox searchingCheckbox; + private CheckBox poisonResistanceCheckbox; + private CheckBox invisibleCheckbox; + private CheckBox fireResistanceCheckbox; + private CheckBox disintegrationResistanceCheckbox; + private CheckBox coldResistanceCheckbox; + private Label label2; + private NumericUpDown lastPrayerPicker; + private Label label1; + private NumericUpDown protectionPicker; + private BindingSource intrinsicsBindingSource; + private BindingSource saveSourceBindingSource; + private BindingSource charismaSourceBindingSource; + private MenuStrip mainMenu; + private ToolStripMenuItem fileToolStripMenuItem; + private ToolStripMenuItem resetToolStripMenuItem; + } +} \ No newline at end of file diff --git a/NethackHelper/MainForm.cs b/NethackHelper/MainForm.cs new file mode 100644 index 0000000..6df035f --- /dev/null +++ b/NethackHelper/MainForm.cs @@ -0,0 +1,180 @@ +namespace NethackHelper { + using System; + using System.Collections.Generic; + using System.IO; + using System.Windows.Forms; + + public partial class MainForm : Form { + private readonly List sokobans = new(); + private int sokobanStepIndex = 0; + + private Dictionary versionMap = new(); + private Version defaultVersion; + + public MainForm() { + InitializeComponent(); + + this.scrollDisplay.CostFormatter = GetCostString; + this.potionDisplay.CostFormatter = GetCostString; + this.wandDisplay.CostFormatter = GetCostString; + this.ringDisplay.CostFormatter = GetCostString; + + foreach (var filename in Directory.EnumerateFiles("sokoban", "*.yaml")) { + var sokoban = new SokobanSolution(YamlOptions.DeserializeFile(filename)); + this.sokobans.Add(sokoban); + this.sokobanLevelList.Items.Add(sokoban.Name); + } + + var versions = YamlOptions.DeserializeFile>("items/versions.yaml"); + defaultVersion = versions[0]; + foreach (var version in versions) { + ToolStripMenuItem toolStripItem = new(version.Name); + toolStripItem.Click += (sender, e) => Reset(version); + resetToolStripMenuItem.DropDownItems.Add(toolStripItem); + versionMap[version.Name] = version; + } + + this.LoadSave(); + } + + private void Reset(Version version) { + SaveData.Instance.Reset(version.Name); + this.LoadSave(); + } + + private void LoadSave() { + var save = SaveData.Instance; + if (!versionMap.TryGetValue(save.Version, out Version version)) { + version = defaultVersion; + save.Version = version.Name; + } + + this.Text = "NethackHelper - " + version.Name; + + intrinsicsBindingSource.DataSource = save.Intrinsics; + saveSourceBindingSource.ResetItem(0); + + var scrolls = YamlOptions.DeserializeFile(Path.Join("items", version.Scrolls)); + this.scrollDisplay.DisplayItemList(scrolls, save.Scrolls); + + var potions = YamlOptions.DeserializeFile(Path.Join("items", version.Potions)); + this.potionDisplay.DisplayItemList(potions, save.Potions); + + var wands = YamlOptions.DeserializeFile(Path.Join("items", version.Wands)); + this.wandDisplay.DisplayItemList(wands, save.Wands); + + var rings = YamlOptions.DeserializeFile(Path.Join("items", version.Rings)); + this.ringDisplay.DisplayItemList(rings, save.Rings); + } + + private string GetCostString(int cost) { + double buyModifier = (double) (charismaSelector.SelectedValue ?? 1.0); + double sellModifier = 0.5; + if (suckerBox.Checked) { + sellModifier = 0.3333; + buyModifier *= 1.3333; + } + + if (cost == 0) { + return string.Format( + "{0} - Buy: {1}/{2}", + cost, + Math.Round(5 * buyModifier), + Math.Round(5 * buyModifier * 1.3333)); + } + + return string.Format( + "{0} - Buy: {1}/{2}, Sell: {3}/{4}", + cost, + Math.Round(cost * buyModifier), + Math.Round(cost * buyModifier * 1.3333), + Math.Round(cost * sellModifier), + Math.Round(cost * sellModifier * 0.75)); + } + + private void NextStep() { + if (sokobanLevelList.SelectedIndex >= 0) { + if (sokobanStepIndex < sokobans[sokobanLevelList.SelectedIndex].States.Count - 1) { + sokobanStepIndex++; + DisplaySokoban(); + } + } + } + + private void PrevStep() { + if (sokobanLevelList.SelectedIndex >= 0) { + if (sokobanStepIndex > 0) { + sokobanStepIndex--; + DisplaySokoban(); + } + } + } + + private void sokobanNext_Click(object sender, EventArgs e) { + this.NextStep(); + } + + private void sokobanPrev_Click(object sender, EventArgs e) { + this.PrevStep(); + } + + private void DisplaySokoban() { + if (sokobanLevelList.SelectedIndex >= 0) { + Reflection reflection = 0; + if (sokobanHorizontal.Checked) { + reflection |= Reflection.HORIZONTAL; + } + if (sokobanVertical.Checked) { + reflection |= Reflection.VERTICAL; + } + sokobanSolution.Text = sokobans[sokobanLevelList.SelectedIndex].States[sokobanStepIndex].GetArrowString(reflection); + } else { + sokobanSolution.Text = ""; + } + } + + private void sokobanReflection_CheckedChanged(object sender, EventArgs e) { + DisplaySokoban(); + } + + private void sokobanLevelList_SelectedIndexChanged(object sender, EventArgs e) { + this.sokobanStepIndex = 0; + DisplaySokoban(); + } + + private void UpdatePrices() { + this.scrollDisplay.UpdateCostHeaders(); + this.potionDisplay.UpdateCostHeaders(); + this.wandDisplay.UpdateCostHeaders(); + this.ringDisplay.UpdateCostHeaders(); + } + + private void charismaSelector_SelectedIndexChanged(object sender, EventArgs e) { + this.UpdatePrices(); + } + + private void suckerBox_CheckedChanged(object sender, EventArgs e) { + this.UpdatePrices(); + } + + private void sokobanLevelList_KeyDown(object sender, KeyEventArgs e) { + if (e.KeyCode == Keys.Right) { + this.NextStep(); + e.Handled = true; + } else if (e.KeyCode == Keys.Left) { + this.PrevStep(); + e.Handled = true; + } + } + + private void Form1_FormClosing(object sender, FormClosingEventArgs e) { + var save = SaveData.Instance; + save.Potions = this.potionDisplay.Export(); + save.Rings = this.ringDisplay.Export(); + save.Scrolls = this.scrollDisplay.Export(); + save.Wands = this.wandDisplay.Export(); + + save.Save(); + } + } +} \ No newline at end of file diff --git a/NethackHelper/MainForm.resx b/NethackHelper/MainForm.resx new file mode 100644 index 0000000..f8edac3 --- /dev/null +++ b/NethackHelper/MainForm.resx @@ -0,0 +1,299 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 410, 17 + + + 410, 17 + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAEROZXRoYWNrSGVscGVyLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAeVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbTmV0aGFja0hlbHBlci5JdGVtRGlzcGxheUNvbHVtbiwgTmV0aGFja0hlbHBlciwg + Q3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVy + c2lvbgQAACFOZXRoYWNrSGVscGVyLkl0ZW1EaXNwbGF5Q29sdW1uW10CAAAACAgJAwAAAAIAAAAIAAAA + DAQAAAAzTmV0aGFja0hlbHBlciwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMA + AAAAAQAAAAQAAAAEH05ldGhhY2tIZWxwZXIuSXRlbURpc3BsYXlDb2x1bW4EAAAACQUAAAAJBgAAAA0C + BQUAAAAfTmV0aGFja0hlbHBlci5JdGVtRGlzcGxheUNvbHVtbgIAAAAaPEF0dHJpYnV0ZT5rX19CYWNr + aW5nRmllbGQWPFdpZHRoPmtfX0JhY2tpbmdGaWVsZAQAG05ldGhhY2tIZWxwZXIuSXRlbUF0dHJpYnV0 + ZQQAAAAIBAAAAAX5////G05ldGhhY2tIZWxwZXIuSXRlbUF0dHJpYnV0ZQEAAAAHdmFsdWVfXwAIBAAA + AAAAAACQAAAAAQYAAAAFAAAAAfj////5////AwAAAJAAAAAL + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAEROZXRoYWNrSGVscGVyLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAeVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbTmV0aGFja0hlbHBlci5JdGVtRGlzcGxheUNvbHVtbiwgTmV0aGFja0hlbHBlciwg + Q3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVy + c2lvbgQAACFOZXRoYWNrSGVscGVyLkl0ZW1EaXNwbGF5Q29sdW1uW10CAAAACAgJAwAAAAMAAAAmAAAA + DAQAAAAzTmV0aGFja0hlbHBlciwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMA + AAAAAQAAAAQAAAAEH05ldGhhY2tIZWxwZXIuSXRlbURpc3BsYXlDb2x1bW4EAAAACQUAAAAJBgAAAAkH + AAAACgUFAAAAH05ldGhhY2tIZWxwZXIuSXRlbURpc3BsYXlDb2x1bW4CAAAAGjxBdHRyaWJ1dGU+a19f + QmFja2luZ0ZpZWxkFjxXaWR0aD5rX19CYWNraW5nRmllbGQEABtOZXRoYWNrSGVscGVyLkl0ZW1BdHRy + aWJ1dGUEAAAACAQAAAAF+P///xtOZXRoYWNrSGVscGVyLkl0ZW1BdHRyaWJ1dGUBAAAAB3ZhbHVlX18A + CAQAAAAAAAAAcgAAAAEGAAAABQAAAAH3////+P///wIAAAAoAAAAAQcAAAAFAAAAAfb////4////AwAA + AIYAAAAL + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAEROZXRoYWNrSGVscGVyLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAeVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbTmV0aGFja0hlbHBlci5JdGVtRGlzcGxheUNvbHVtbiwgTmV0aGFja0hlbHBlciwg + Q3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVy + c2lvbgQAACFOZXRoYWNrSGVscGVyLkl0ZW1EaXNwbGF5Q29sdW1uW10CAAAACAgJAwAAAAIAAAAIAAAA + DAQAAAAzTmV0aGFja0hlbHBlciwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMA + AAAAAQAAAAQAAAAEH05ldGhhY2tIZWxwZXIuSXRlbURpc3BsYXlDb2x1bW4EAAAACQUAAAAJBgAAAA0C + BQUAAAAfTmV0aGFja0hlbHBlci5JdGVtRGlzcGxheUNvbHVtbgIAAAAaPEF0dHJpYnV0ZT5rX19CYWNr + aW5nRmllbGQWPFdpZHRoPmtfX0JhY2tpbmdGaWVsZAQAG05ldGhhY2tIZWxwZXIuSXRlbUF0dHJpYnV0 + ZQQAAAAIBAAAAAX5////G05ldGhhY2tIZWxwZXIuSXRlbUF0dHJpYnV0ZQEAAAAHdmFsdWVfXwAIBAAA + AAAAAACQAAAAAQYAAAAFAAAAAfj////5////AwAAAJAAAAAL + + + + + AAEAAAD/////AQAAAAAAAAAMAgAAAEROZXRoYWNrSGVscGVyLCBWZXJzaW9uPTEuMC4wLjAsIEN1bHR1 + cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49bnVsbAQBAAAAeVN5c3RlbS5Db2xsZWN0aW9ucy5HZW5l + cmljLkxpc3RgMVtbTmV0aGFja0hlbHBlci5JdGVtRGlzcGxheUNvbHVtbiwgTmV0aGFja0hlbHBlciwg + Q3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsXV0DAAAABl9pdGVtcwVfc2l6ZQhfdmVy + c2lvbgQAACFOZXRoYWNrSGVscGVyLkl0ZW1EaXNwbGF5Q29sdW1uW10CAAAACAgJAwAAAAIAAAAIAAAA + DAQAAAAzTmV0aGFja0hlbHBlciwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1udWxsBwMA + AAAAAQAAAAQAAAAEH05ldGhhY2tIZWxwZXIuSXRlbURpc3BsYXlDb2x1bW4EAAAACQUAAAAJBgAAAA0C + BQUAAAAfTmV0aGFja0hlbHBlci5JdGVtRGlzcGxheUNvbHVtbgIAAAAaPEF0dHJpYnV0ZT5rX19CYWNr + aW5nRmllbGQWPFdpZHRoPmtfX0JhY2tpbmdGaWVsZAQAG05ldGhhY2tIZWxwZXIuSXRlbUF0dHJpYnV0 + ZQQAAAAIBAAAAAX5////G05ldGhhY2tIZWxwZXIuSXRlbUF0dHJpYnV0ZQEAAAAHdmFsdWVfXwAIBAAA + AAAAAACQAAAAAQYAAAAFAAAAAfj////5////AwAAAJAAAAAL + + + + 17, 17 + + + 232, 17 + + + 232, 17 + + + 600, 17 + + + + + AAABAAEAQEAAAAEACAAoFgAAFgAAACgAAABAAAAAgAAAAAEACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAADQ0NABYWFgAcHBwAIiIiACYmJgAqKioALi4uADIyMgA1NTUAODg4AEJCQgBFRUUAR0dHAElJ + SQBLS0sAT09PAFFRUQBTU1MAWFhYAF1dXQBgYGAAYmJiAGNjYwBlZWUAZmZmAGhoaABpaWkAampqAGxs + bABubm4AcXFxAHJycgBzc3MAdXV1AHZ2dgB3d3cAeXl5AHp6egB/f38AgICAAIODgwCFhYUAh4eHAImJ + iQCLi4sAjo6OAJGRkQCSkpIAk5OTAJSUlACWlpYAl5eXAJmZmQCbm5sAnJycAJ2dnQCenp4An5+fAKGh + oQCioqIAo6OjAKWlpQCmpqYAp6enAKioqACpqakAqqqqAK2trQCurq4Ar6+vALCwsACysrIAtLS0ALW1 + tQC2trYAt7e3ALi4uAC5ubkAurq6ALu7uwC8vLwAvb29AL+/vwDAwMAAwsLCAMTExADFxcUAx8fHAMjI + yADJyckAysrKAMzMzADNzc0Az8/PANDQ0ADR0dEA0tLSANPT0wDU1NQA1dXVANbW1gDX19cA2NjYANnZ + 2QDa2toA29vbANzc3ADd3d0A3t7eAN/f3wDg4OAA4eHhAOLi4gDj4+MA5OTkAOXl5QDm5uYA5+fnAOnp + 6QDq6uoA6+vrAOzs7ADt7e0A7u7uAO/v7wDx8fEA8vLyAPPz8wD09PQA9fX1APb29gD39/cA+Pj4APn5 + +QD6+voA+/v7APz8/AD9/f0A/v7+AP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAdUnGCiomDeGNGGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAABFhjIyMjIyMjIyMjIx1PAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAB9+jIyMjIh7c3mEjIyMjH4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAABOAjIyMdjYDAAAAABY+a4t+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAABrjIyMXQYAAAAAAAAAAAAYTQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAyjIyMZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAc4yMgQ4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIIyMjEkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFGMjIYMAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABzjIxlAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHioyMRAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJoyMjB8AAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADuMjIsFAAAAJWyH + g2UbAAAjbYOEcDUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABOjIx+AAAA + H4eMjIyMghoQhYyMjIyMVwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWoyM + bwAAAGeMjIyMjIxzRoyMjIyMjIxDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AGOMjGYAAAqJjIyEOluMjH2MjGc1b4yMhA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAABrjIxgAAAojIyMVgAAZoyMjIwdAAuBjIxKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAb4yMXAAAN4yMjEIAABeKjIyMCwAAT4yMeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAHGMjFgAAECMjIw3AAAAZoyMjBIAAB6MjIwTAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAABujIxbAABAjIyMNQAAAFKMjIwhAAAAg4yMNgAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAaoyMXgAAOYyMjDoAAAA7jIyMMQAAAG6MjFMAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGaMjGMAADKMjIxCAAAAJ4yMjEcAAABajIxlAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABejIxuAAAkjIyMUgAAAA2MjIxaAAAAS4yMdgAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU4yMegAACIuMjGAAAAAAg4yMbQAAAECMjIAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAESMjIUAAAB8jIx6AAAAAHOMjH4AAAA0 + jIyIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzjIyMEAAAXoyMjA4AAABfjIyM + CAAAL4yMjAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG4yMjCwAADOMjIw9AAAA + TYyMjCIAAC2MjIwJAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGGjIxFAAAIh4yM + bwAAADeMjIw2AAArjIyMCwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcoyMYQAA + AFuMjIwwAAAkjIyMTAAALoyMjAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFWM + jH8AAAAVh4yMhkY2aYyMjF4AADOMjIoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAujIyMGQAAAEOMjIyMjIyMjIxzAAA4jIyGAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAACIiMjEgAAAAAS4uMjIyMjIyMgwAARoyMgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAABnjIxzAAAAAAAoZIGIe15LaYQOAFWMjHIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAANYyMjB0AAAAAAAAAAAAAAAABAgBijIxfAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAaDjIxYAAAAAAAAAAAAAAAAAAAAe4yMTwAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUYyMhhAAAAAAAAAAAAAAAAAADYyMjDIAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+GjIxYAAAAAAAAAAAAAAAAADaMjIsOAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUIyMiiMAAAAAAAAAAAAAAABpjIxwAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAd7jIx5CAAAAAAAAAAAAAAcioyMPwAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKoqMjGcEAAAAAAAAAAAAboyM + gAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABDjIyMaA4AAAAAAAAB + WYyMjD8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFKMjIx/QQkA + AAAla4yMjGcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQoqM + jIyIeXSBjIyMjG4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAicIyMjIyMjIyMiVQFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAApWXeDioNxTxQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + + + \ No newline at end of file diff --git a/NethackHelper/NethackHelper.csproj b/NethackHelper/NethackHelper.csproj new file mode 100644 index 0000000..dd58048 --- /dev/null +++ b/NethackHelper/NethackHelper.csproj @@ -0,0 +1,35 @@ + + + + WinExe + net9-windows + enable + true + disable + icon.ico + + + + + + + + + + + + + PreserveNewest + + + PreserveNewest + + + + + + + + + + \ No newline at end of file diff --git a/NethackHelper/Program.cs b/NethackHelper/Program.cs new file mode 100644 index 0000000..2ad8581 --- /dev/null +++ b/NethackHelper/Program.cs @@ -0,0 +1,17 @@ +using System; +using System.Windows.Forms; + +namespace NethackHelper { + internal static class Program { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new MainForm()); + } + } +} \ No newline at end of file diff --git a/NethackHelper/Properties/DataSources/CharismaSource.datasource b/NethackHelper/Properties/DataSources/CharismaSource.datasource new file mode 100644 index 0000000..544530c --- /dev/null +++ b/NethackHelper/Properties/DataSources/CharismaSource.datasource @@ -0,0 +1,10 @@ + + + + NethackHelper.CharismaSource, NethackHelper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/NethackHelper/Properties/DataSources/Intrinsics.datasource b/NethackHelper/Properties/DataSources/Intrinsics.datasource new file mode 100644 index 0000000..dfdca3e --- /dev/null +++ b/NethackHelper/Properties/DataSources/Intrinsics.datasource @@ -0,0 +1,10 @@ + + + + NethackHelper.Intrinsics, NethackHelper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/NethackHelper/Properties/DataSources/SaveSource.datasource b/NethackHelper/Properties/DataSources/SaveSource.datasource new file mode 100644 index 0000000..5677ed5 --- /dev/null +++ b/NethackHelper/Properties/DataSources/SaveSource.datasource @@ -0,0 +1,10 @@ + + + + NethackHelper.SaveSource, NethackHelper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null + \ No newline at end of file diff --git a/NethackHelper/Reflection.cs b/NethackHelper/Reflection.cs new file mode 100644 index 0000000..95981f6 --- /dev/null +++ b/NethackHelper/Reflection.cs @@ -0,0 +1,9 @@ +using System; + +namespace NethackHelper { + [Flags] + internal enum Reflection { + HORIZONTAL = 0x1, + VERTICAL = 0x2, + } +} diff --git a/NethackHelper/SaveData.cs b/NethackHelper/SaveData.cs new file mode 100644 index 0000000..34b6d92 --- /dev/null +++ b/NethackHelper/SaveData.cs @@ -0,0 +1,149 @@ +namespace NethackHelper { + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Windows.Forms; + + public class SaveData { + private const string SAVE_NAME = "savedata.yaml"; + + private static SaveData? _instance; + + public static SaveData Instance { + get { + _instance ??= new(); + return _instance; + } + } + + private SaveData() { + var fileName = Path.Combine(Application.UserAppDataPath, SAVE_NAME); + var save = YamlOptions.DeserializeFileOrDefault(fileName); + + if (save != null) { + this.Version = save.Version; + this.CharismaClass = save.CharismaClass; + this.Sucker = save.Sucker; + this.Intrinsics = save.Intrinsics; + if (save.Potions != null && save.Potions.Count > 0) { + this.Potions = new(save.Potions); + } + if (save.Rings != null && save.Rings.Count > 0) { + this.Rings = new(save.Rings); + } + if (save.Scrolls != null && save.Scrolls.Count > 0) { + this.Scrolls = new(save.Scrolls); + } + if (save.Wands != null && save.Wands.Count > 0) { + this.Wands = new(save.Wands); + } + } + } + + public void Save() { + var fileName = Path.Combine(Application.UserAppDataPath, SAVE_NAME); + + var save = new SaveFile() { + Version = this.Version, + CharismaClass = this.CharismaClass, + Sucker = this.Sucker, + Intrinsics = this.Intrinsics, + Potions = this.Potions?.Export() ?? [], + Rings = this.Rings?.Export() ?? [], + Scrolls = this.Scrolls?.Export() ?? [], + Wands = this.Wands?.Export() ?? [], + }; + + YamlOptions.SerializeToFile(fileName, save); + } + + public void Reset(string version) { + this.Version = version; + this.CharismaClass = CharismaClass.DefaultClass; + this.Sucker = false; + this.Potions = null; + this.Rings = null; + this.Scrolls = null; + this.Wands = null; + this.Intrinsics = new(); + } + + public string Version { get; set; } = string.Empty; + public CharismaClass CharismaClass { get; set; } = CharismaClass.DefaultClass; + public bool Sucker { get; set; } + public Intrinsics Intrinsics { get; set; } = new(); + public IdentificationRecord? Potions { get; set; } + public IdentificationRecord? Rings { get; set; } + public IdentificationRecord? Scrolls { get; set; } + public IdentificationRecord? Wands { get; set; } + } + + public struct ItemRecord { + public string Name { get; set; } + public string? Appearance { get; set; } + } + + public class IdentificationRecord { + private readonly Dictionary identifications = new(); + + public IdentificationRecord(List records) { + this.identifications = records.ToDictionary(record => record.Name); + } + + public bool HasIdentified(string name) { + return identifications.ContainsKey(name); + } + + public bool TryGetValue(string name, out ItemRecord record) { + return identifications.TryGetValue(name, out record); + } + + public List Export() { + return identifications.Values.ToList(); + } + } + + public class SaveFile { + public string Version { get; set; } = string.Empty; + public CharismaClass CharismaClass { get; set; } = CharismaClass.DefaultClass; + public bool Sucker { get; set; } + public Intrinsics Intrinsics { get; set; } = new(); + + public List Potions { get; set; } = new(); + public List Rings { get; set; } = new(); + public List Scrolls { get; set; } = new(); + public List Wands { get; set; } = new(); + } + + public class Intrinsics { + public bool ColdResistance { get; set; } + public bool DisintegrationResistance { get; set; } + public bool FireResistance { get; set; } + public bool Invisible { get; set; } + public bool PoisonResistance { get; set; } + public bool Searching { get; set; } + public bool SeeInvisible { get; set; } + public bool ShockResistance { get; set; } + public bool SleepResistance { get; set; } + public bool Speed { get; set; } + public bool Stealth { get; set; } + public bool Telepathy { get; set; } + public bool TeleportControl { get; set; } + public bool Teleportitis { get; set; } + public bool Warning { get; set; } + public int Protection { get; set; } + public int LastPrayer { get; set; } + } + + public class IntrinsicsSource : BindingSource { + public IntrinsicsSource() { + this.DataSource = SaveData.Instance.Intrinsics; + } + } + + public class SaveSource : BindingSource { + public SaveSource() { + this.DataSource = SaveData.Instance; + } + } +} diff --git a/NethackHelper/SokobanFile.cs b/NethackHelper/SokobanFile.cs new file mode 100644 index 0000000..fbc0c25 --- /dev/null +++ b/NethackHelper/SokobanFile.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace NethackHelper { + internal class SokobanFile { + public string Name { get; set; } = ""; + public string Map { get; set; } = ""; + public List Solution { get; set; } = new(); + } +} diff --git a/NethackHelper/SokobanSolution.cs b/NethackHelper/SokobanSolution.cs new file mode 100644 index 0000000..c8c64dd --- /dev/null +++ b/NethackHelper/SokobanSolution.cs @@ -0,0 +1,196 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace NethackHelper { + internal class SokobanSolution { + public string Name { get; } + public List States { get; } + + public SokobanSolution(SokobanFile file) { + Name = file.Name; + States = new(); + SokobanState current = new(file.Map); + States.Add(current); + foreach (string step in file.Solution) { + current = new SokobanState(current, step); + States.Add(current); + } + } + } + + internal class SokobanState { + private static readonly Dictionary horizSubstitute = new() { + ['←'] = '→', + ['→'] = '←', + ['┌'] = '┐', + ['┐'] = '┌', + ['└'] = '┘', + ['┘'] = '└', + ['├'] = '┤', + ['┤'] = '├', + }; + private static readonly Dictionary vertSubstitute = new() { + ['↑'] = '↓', + ['↓'] = '↑', + ['┌'] = '└', + ['┐'] = '┘', + ['└'] = '┌', + ['┘'] = '┐', + ['┬'] = '┴', + ['┴'] = '┬', + }; + + private char[,] Start { get; } + private char[,] Arrows { get; } + private char[,] End { get; } + + public SokobanState(string map) { + List lines = new(); + int maxLen = 0; + + using (StringReader reader = new(map)) { + string? line; + while ((line = reader.ReadLine()) is not null) { + lines.Add(line); + maxLen = Math.Max(maxLen, line.Length); + } + } + + Start = new char[lines.Count, maxLen]; + for (int y = 0; y < lines.Count; y++) { + for (int x = 0; x < lines[y].Length; x++) { + Start[y, x] = lines[y][x]; + } + for (int x = lines[y].Length; x < maxLen; x++) { + Start[y, x] = ' '; + } + } + + Arrows = Start; + End = Start; + } + + public SokobanState(SokobanState prior, string step) { + Start = prior.End; + Arrows = (char[,]) Start.Clone(); + End = (char[,]) Start.Clone(); + + int height = Start.GetLength(0); + int width = Start.GetLength(1); + + int x = 0; + int y = 0; + + char boulder = step[0]; + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + if (Start[i, j] == boulder) { + x = j; + y = i; + } + } + } + + foreach (char c in step[1..]) { + switch (c) { + case ' ': + continue; + case 'u': + if (y == 0) { throw new SokobanError(); } + SetEnd(y - 1, x, boulder); + SetEmpty(y, x); + Arrows[y, x] = '↑'; + y--; + break; + case 'd': + if (y >= height - 1) { throw new SokobanError(); } + SetEnd(y + 1, x, boulder); + SetEmpty(y, x); + Arrows[y, x] = '↓'; + y++; + break; + case 'l': + if (x == 0) { throw new SokobanError(); } + SetEnd(y, x - 1, boulder); + SetEmpty(y, x); + Arrows[y, x] = '←'; + x--; + break; + case 'r': + if (x >= width - 1) { throw new SokobanError(); } + SetEnd(y, x + 1, boulder); + SetEmpty(y, x); + Arrows[y, x] = '→'; + x++; + break; + default: + throw new SokobanError(); + } + } + } + + private void SetEmpty(int y, int x) { + switch (Start[y, x]) { + case '>': + End[y, x] = '>'; + break; + default: + End[y, x] = '.'; + break; + } + } + + private void SetEnd(int y, int x, char boulder) { + switch (Start[y, x]) { + case '.': + case '>': + End[y, x] = boulder; + Arrows[y, x] = boulder; + break; + case '^': + End[y, x] = '.'; + Arrows[y, x] = '*'; + break; + default: + throw new SokobanError(); + } + } + + public string GetArrowString(Reflection reflection) { + return GetString(Arrows, reflection); + } + + public string GetEndString(Reflection reflection) { + return GetString(End, reflection); + } + + private static string GetString(char[,] map, Reflection reflection) { + StringBuilder sb = new(); + int height = map.GetLength(0); + int width = map.GetLength(1); + char c; + + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + int mappedI = reflection.HasFlag(Reflection.VERTICAL) ? height - 1 - i : i; + int mappedJ = reflection.HasFlag(Reflection.HORIZONTAL) ? width - 1 - j : j; + c = map[mappedI, mappedJ]; + if (reflection.HasFlag(Reflection.HORIZONTAL)) { + c = horizSubstitute.GetValueOrDefault(c, c); + } + if (reflection.HasFlag(Reflection.VERTICAL)) { + c = vertSubstitute.GetValueOrDefault(c, c); + } + sb.Append(c); + } + sb.AppendLine(); + } + + return sb.ToString(); + } + } + + public class SokobanError : Exception { } +} diff --git a/NethackHelper/Versions.cs b/NethackHelper/Versions.cs new file mode 100644 index 0000000..98bcba4 --- /dev/null +++ b/NethackHelper/Versions.cs @@ -0,0 +1,9 @@ +namespace NethackHelper { + internal struct Version { + public string Name { get; set; } + public string Scrolls { get; set; } + public string Potions { get; set; } + public string Wands { get; set; } + public string Rings { get; set; } + } +} diff --git a/NethackHelper/YamlOptions.cs b/NethackHelper/YamlOptions.cs new file mode 100644 index 0000000..4853094 --- /dev/null +++ b/NethackHelper/YamlOptions.cs @@ -0,0 +1,28 @@ +namespace NethackHelper { + using System.IO; + using YamlDotNet.Serialization; + using YamlDotNet.Serialization.NamingConventions; + + internal class YamlOptions { + private static readonly IDeserializer deserializer = new DeserializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build(); + private static readonly ISerializer serializer = new SerializerBuilder().WithNamingConvention(CamelCaseNamingConvention.Instance).Build(); + + public static T DeserializeFile(string filename) { + using var reader = new StreamReader(filename); + return deserializer.Deserialize(reader); + } + + public static T? DeserializeFileOrDefault(string filename) { + if (File.Exists(filename)) { + using var reader = new StreamReader(filename); + return deserializer.Deserialize(reader); + } + return default; + } + + public static void SerializeToFile(string filename, T value) { + using var writer = new StreamWriter(filename); + serializer.Serialize(writer, value); + } + } +} diff --git a/NethackHelper/icon.ico b/NethackHelper/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3714b12a6a6960243eef2659957a522a3e72c52c GIT binary patch literal 5694 zcmeHKc}&zt6#nR;R*Tx&(nBmQR%&TWTUwCX%c4LjwG`=rS`?w2A_7}Lu$9#XVd2HZ zBN_v0)F^1;5#xPCV>BYsc!2kP$CKcJf>*y;Dy-SV-!}2TeXzWlH{UmJ=FOWo3*f?^ zK7GKy?a9&y#v(2*4)O8vNJvOP zQc@Cl7iIKRHUV)AtNILnVFf;>2%1-%0hN_Hga-ukei!}yu3W*=jTJO*TY~i zps=tIMMXt08jUC|EyaWh6EJb&L`<4A36m#J#*`^jFm>uwOq(_h)2B~ISy>s%%gZri z#th7yITN#H&BE;2voUAR9L$|N7xU)L!~FU4QBhHW%F0SCSg-&K7cRu2MT@X_@nS4l zvII+)F2%BC%dmX;a;#Xf0xMUp#Hv-RuzK}stXZ=LYuB#Dx^?TYe*JoE*suW`H*UnH zO`EWJ^JZ+>vISeWZpF53+fY?ih3(t7qq@2pJ9g~A&Ye54Yu7I9-n|=p_Uysly?aqp zQ-j*tTI}1m5BvA;$AJR}aPZ(k96EFehYugdkt0WN^ypC>J9Z4mj~~a06DM%;NLPJ9XZr{F*J9qA&v9S?NO-;Ca_b%?;yNCPt@8iLP2YC4K zp}kacjyWUXjDRx&j6k;m8RJTfhEZ|BUH?ZsUK%E?lJ%9NGkA9_ zo}_I5XBExuo8hI7@`sZi-KNFq>-}4rni{^OCul-i2kAt{cCO67BiP0uLWlV)3!vUpN%msW-o5vLkrLb=1Y;%=Q-9Rwa5_9-0wcZP>}9t18l|o zQ**w06mcCg?#<4HO3Uw7kk(CuL`HHX(L@tnaI==a*3p*MI8*YqH;NSW9xU>YNTT0J zb~;%?ty-A;G5i8bx4!`i%6m6-7%TFFRkWp%zWxAukrxQO#>12jK)A>#OQ=;#hDa2@ z{F2v;<7xpf18-4vu?n{^ril!0=Bq;+K;k>p1`&S?s8vIX$PnNQ@_KWe*&v@%bJj?! za0??>90#Zx!2RPr>JVz4s>Vw(L?jJ(m%IVwxl#|J4r4*1(jbu{c|f~T(=nPhK7uU9 zQ?G$cNI#K6s=rOs0KCnre16Vytd0K}SKJxkHbfP%q162UM&3;^$+x<@JzdGa4nF%Pv!rpPejcz5KJ=7abV@L{j@MX)=~ zuOj&byvhZP5B5(ck@>{!l-Omp4k}k~u-liqS#&@ECu@b+ZM7>F`CcKym;)v;0KuBi z-&A_&k<#59*)e;jE2a|TFX};eT;3m;V<<6XgumiA)yZ&1z!?E&1fFsP{sq)EAB_M2 literal 0 HcmV?d00001 diff --git a/NethackHelper/items/potions-36.yaml b/NethackHelper/items/potions-36.yaml new file mode 100644 index 0000000..c36a35d --- /dev/null +++ b/NethackHelper/items/potions-36.yaml @@ -0,0 +1,57 @@ +items: + - name: Water + cost: 0 + appearance: clear + - name: Booze + cost: 50 + - name: Fruit Juice + cost: 50 + - name: See Invisible + cost: 50 + - name: Sickness + cost: 50 + - name: Confusion + cost: 100 + - name: Extra Healing + cost: 100 + - name: Hallucination + cost: 100 + - name: Healing + cost: 100 + - name: Restore Ability + cost: 100 + - name: Sleeping + cost: 100 + - name: (Un)Holy Water + cost: 100 + appearance: clear + - name: Blindness + cost: 150 + - name: Gain Energy + cost: 150 + - name: Invisibility + cost: 150 + - name: Monster Detection + cost: 150 + - name: Object Detection + cost: 150 + - name: Enlightenment + cost: 200 + - name: Full Healing + cost: 200 + - name: Levitation + cost: 200 + - name: Polymorph + cost: 200 + - name: Speed + cost: 200 + - name: Acid + cost: 250 + - name: Oil + cost: 250 + - name: Gain Ability + cost: 300 + - name: Gain Level + cost: 300 + - name: Paralysis + cost: 300 \ No newline at end of file diff --git a/NethackHelper/items/potions-37.yaml b/NethackHelper/items/potions-37.yaml new file mode 100644 index 0000000..244ae9a --- /dev/null +++ b/NethackHelper/items/potions-37.yaml @@ -0,0 +1,57 @@ +items: + - name: Water + cost: 0 + appearance: clear + - name: Healing + cost: 20 + - name: Booze + cost: 50 + - name: Fruit Juice + cost: 50 + - name: See Invisible + cost: 50 + - name: Sickness + cost: 50 + - name: Confusion + cost: 100 + - name: Extra Healing + cost: 100 + - name: Hallucination + cost: 100 + - name: Restore Ability + cost: 100 + - name: Sleeping + cost: 100 + - name: (Un)Holy Water + cost: 100 + appearance: clear + - name: Blindness + cost: 150 + - name: Gain Energy + cost: 150 + - name: Invisibility + cost: 150 + - name: Monster Detection + cost: 150 + - name: Object Detection + cost: 150 + - name: Enlightenment + cost: 200 + - name: Full Healing + cost: 200 + - name: Levitation + cost: 200 + - name: Polymorph + cost: 200 + - name: Speed + cost: 200 + - name: Acid + cost: 250 + - name: Oil + cost: 250 + - name: Gain Ability + cost: 300 + - name: Gain Level + cost: 300 + - name: Paralysis + cost: 300 \ No newline at end of file diff --git a/NethackHelper/items/rings.yaml b/NethackHelper/items/rings.yaml new file mode 100644 index 0000000..28356eb --- /dev/null +++ b/NethackHelper/items/rings.yaml @@ -0,0 +1,57 @@ +items: + - name: Adornment + cost: 100 + - name: Hunger + cost: 100 + - name: Protection + cost: 100 + - name: Protection from Shape Changers + cost: 100 + - name: Stealth + cost: 100 + - name: Sustain Ability + cost: 100 + - name: Warning + cost: 100 + - name: Aggravate Monster + cost: 150 + - name: Cold Resistance + cost: 150 + - name: Gain Constitution + cost: 150 + - name: Gain Strength + cost: 150 + - name: Increase Accuracy + cost: 150 + - name: Increase Damage + cost: 150 + - name: Invisibility + cost: 150 + - name: Poison Resistance + cost: 150 + - name: See Invisible + cost: 150 + - name: Shock Resistance + cost: 150 + - name: Fire Resistance + cost: 200 + - name: Free Action + cost: 200 + - name: Levitation + cost: 200 + - name: Regeneration + cost: 200 + - name: Searching + cost: 200 + - name: Slow Digestion + cost: 200 + - name: Teleportation + cost: 200 + - name: Conflict + cost: 300 + - name: Polymorph + cost: 300 + - name: Polymorph Control + cost: 300 + - name: Teleport Control + cost: 300 \ No newline at end of file diff --git a/NethackHelper/items/scrolls.yaml b/NethackHelper/items/scrolls.yaml new file mode 100644 index 0000000..407bbfa --- /dev/null +++ b/NethackHelper/items/scrolls.yaml @@ -0,0 +1,68 @@ +items: + - name: Identify + ink: 14 + cost: 20 + - name: Light + ink: 8 + cost: 50 + - name: Enchant Weapon + ink: 16 + cost: 60 + - name: Blank Paper + ink: 0 + cost: 60 + appearance: unlabeled + - name: Enchant Armor + ink: 16 + cost: 80 + - name: Remove Curse + ink: 16 + cost: 80 + - name: Confuse Monster + ink: 12 + cost: 100 + - name: Destroy Armor + ink: 10 + cost: 100 + - name: Fire + ink: 8 + cost: 100 + - name: Food Detection + ink: 8 + cost: 100 + - name: Gold Detection + ink: 8 + cost: 100 + - name: Magic Mapping + ink: 8 + cost: 100 + - name: Scare Monster + ink: 20 + cost: 100 + - name: Teleportation + ink: 20 + cost: 100 + - name: Amnesia + ink: 8 + cost: 200 + - name: Create Monster + ink: 10 + cost: 200 + - name: Earth + ink: 8 + cost: 200 + - name: Taming + ink: 20 + cost: 200 + - name: Charging + ink: 16 + cost: 300 + - name: Genocide + ink: 30 + cost: 300 + - name: Punishment + ink: 10 + cost: 300 + - name: Stinking Cloud + ink: 20 + cost: 300 \ No newline at end of file diff --git a/NethackHelper/items/versions.yaml b/NethackHelper/items/versions.yaml new file mode 100644 index 0000000..f08d137 --- /dev/null +++ b/NethackHelper/items/versions.yaml @@ -0,0 +1,10 @@ +- name: Vanilla 3.6 + scrolls: scrolls.yaml + rings: rings.yaml + potions: potions-36.yaml + wands: wands.yaml +- name: Vanilla 3.7 + scrolls: scrolls.yaml + rings: rings.yaml + potions: potions-37.yaml + wands: wands.yaml \ No newline at end of file diff --git a/NethackHelper/items/wands.yaml b/NethackHelper/items/wands.yaml new file mode 100644 index 0000000..af9e757 --- /dev/null +++ b/NethackHelper/items/wands.yaml @@ -0,0 +1,49 @@ +items: + - name: Light + cost: 100 + - name: Nothing + cost: 100 + - name: Digging + cost: 150 + - name: Enlightenment + cost: 150 + - name: Locking + cost: 150 + - name: Magic Missile + cost: 150 + - name: Make Invisible + cost: 150 + - name: Opening + cost: 150 + - name: Probing + cost: 150 + - name: Secret Door Detection + cost: 150 + - name: Slow Monster + cost: 150 + - name: Speed Monster + cost: 150 + - name: Striking + cost: 150 + - name: Undead Turning + cost: 150 + - name: Cold + cost: 175 + - name: Fire + cost: 175 + - name: Lightning + cost: 175 + - name: Sleep + cost: 175 + - name: Cancellation + cost: 200 + - name: Create Monster + cost: 200 + - name: Polymorph + cost: 200 + - name: Teleportation + cost: 200 + - name: Death + cost: 500 + - name: Wishing + cost: 500 \ No newline at end of file diff --git a/NethackHelper/sokoban/1a.yaml b/NethackHelper/sokoban/1a.yaml new file mode 100644 index 0000000..2e3f694 --- /dev/null +++ b/NethackHelper/sokoban/1a.yaml @@ -0,0 +1,30 @@ +name: Sokoban Level 1a +map: | + ┌─┬────┐ ┌────┐ + │<│>...└─┘....│ + │^├┐.AB....C..│ + │^││..DE│.F.G.│ + │^││....│.....│ + │^│└───┬┘H────┤ + │^│ │......│ + │^└────┘......│ + │..^^^^IJKL...│ + │??┌───┐......│ + └──┘ └──────┘ +solution: + - A d + - B rrrr + - H dd + - J u + - I l + - L u + - K llll + - L dlll lll + - H dlll lll + - J dlll llll u + - F r + - B ddld dddl llll lllu u + - G dlll dddd llll llll uuu + - F lldd dddl llll lllu uuu + - C ddll dddd llll llll uuuu u + - E urrr ddld dddl llll lllu uuuu u diff --git a/NethackHelper/sokoban/2a.yaml b/NethackHelper/sokoban/2a.yaml new file mode 100644 index 0000000..ef20379 --- /dev/null +++ b/NethackHelper/sokoban/2a.yaml @@ -0,0 +1,49 @@ +name: Sokoban Level 2a +map: | +  ┌──┐ ┌─────────┐ + ┌┘.>└──────┐ │.........│ + │..........│ │.........│ + │.A┌───┐B─.│ │.........│ + │..│...│.C.│ │....<....│ + │.D.E....F─┤ │.........│ + │.G..H..│..│ │.........│ + │.────I.└┐.│ │.........│ + │..J...K.│.└┐ │.........│ + │.──┐L─...M.└──┴────────+┤ + │...│..N─.O.^^^^^^^^^^^^.│ + │..P......┌──────────────┘ + └───┐..│..│ + └──┴──┘ +solution: + - P rrru + - O rr + - N dlll ll + - B dd + - C l + - M l + - F u + - B ll + - K d + - M rdrr r + - N rrrr rrru urdr rrr + - K ddll lll + - K rrrr rrru urdr rrrr + - L ddll l + - L rrrr rrru urdr rrrr r + - P rdrr uurd rrrr rrr + - I drdd drru urdr rrrr rrr + - C d + - F l + - A u + - G r + - D u + - E r + - B ddd + - D d + - A d + - B rddd rruu rdrr rrrr rrr + - E rddd rddd rruu rdrr rrrr rrrr + - C lll + - C rddd rddd rruu rdrr rrrr rrrr r + - H rrdd dddr ruur drrr rrrr rrrr r + - J rrrr dddr ruur drrr rrrr rrrr rr diff --git a/NethackHelper/sokoban/2b.yaml b/NethackHelper/sokoban/2b.yaml new file mode 100644 index 0000000..8e4ac18 --- /dev/null +++ b/NethackHelper/sokoban/2b.yaml @@ -0,0 +1,35 @@ +name: Sokoban Level 2b +map: | + ┌────┬────┐ ┌─────────┐ + │....│....└─┐ │.........│ + │..AB│CD...>│ │.........│ + │.....E...┌─┘ │.........│ + │....│....│ │....<....│ + ├─.──┼────┴┐ │.........│ + │..F.│.....│ │.........│ + │.GH.│I.J.K│ │.........│ + │..L.....M.│ │.........│ + │.NOP│Q..R.└──────┴────────+┤ + │....│..S.T.^^^^^^^^^^^^^^^.│ + └────┴──────────────────────┘ +solution: + - E lll + - L rrrr r + - R r + - T rr + - S rrrr r + - M ddrr rrr + - R drrr rr + - K dddr rrrr r + - L rrdd rrrr rrr + - J dddr rrrr rrrr r + - O urrr rrrr ddrr rrrr rrr + - P urrr rrrd drrr rrrr rrr + - G drrr rrrr rddr rrrr rrrr rr + - H ldrr rrrr rrdd rrrr rrrr rrrr + - N urrr rrrr rddr rrrr rrrr rrrr + - Q ulll + - Q rrrr rrrd drrr rrrr rrrr rrr + - I dlll + - I rrrr rrrd drrr rrrr rrrr rrrr + - E lddd ddrr rrrr rddr rrrr rrrr rrrr rrrr diff --git a/NethackHelper/sokoban/3a.yaml b/NethackHelper/sokoban/3a.yaml new file mode 100644 index 0000000..ae55961 --- /dev/null +++ b/NethackHelper/sokoban/3a.yaml @@ -0,0 +1,33 @@ +name: Sokoban Level 3a +map: | +   ┌─┬────┐ + ┌─┘.│....│ + │...A....├─┬───────┐ + │.─.BC─DE│.│.......│ + │.FG─......│.......│ + │.─..H.│...│.......│ + │....─I└─J─┤...<...│ + │..KL..M...│.......│ + │.──...│...│.......│ + │....─N├───┤.......│ + └─┐..O.└───┴──────+┤ + │..P>^^^^^^^^^^^.│ + └────────────────┘ +solution: + - O ll + - P rr + - N ddrr + - L ddd + - O u + - L rrdr rr + - O rddr rrrr r + - K rddd drrr rrrr + - G dddr dddd rrrr rrrr + - F rddd rddd drrr rrrr rr + - M rr + - M llll lddd drrr rrrr rrr + - J uu + - I dddd drrr rrrr rr + - H rddd dddr rrrr rrrr r + - A rr + - C ddrd dddd drrr rrrr rrrr diff --git a/NethackHelper/sokoban/3b.yaml b/NethackHelper/sokoban/3b.yaml new file mode 100644 index 0000000..0a00c6e --- /dev/null +++ b/NethackHelper/sokoban/3b.yaml @@ -0,0 +1,32 @@ +name: Sokoban Level 3b +map: | + ┌────────┬───┬─────┐ + │........│...│.....│ + │.AB..─CD│.─.│.....│ + │..│.E.F.│GH.│.....│ + ├─.│..─..│.─.│..<..│ + │...┌─.......│.....│ + │...│.I.─...┌┤.....│ + │.J.│K.│...┌┘│.....│ + ├─L.│..└───┴─┴────+┤ + │..M....^^^^^^^^^^.│ + │...│.>┌───────────┘ + └───┴──┘ +solution: + - M l + - M rrrr rr + - J r + - L drrr rrrr + - J ddrr rrrr r + - A dddd dddr rrrr rrrr + - B lddd dddd rrrr rrrr rr + - E u + - D dd + - F lllu + - E d + - F lldd dddd drrr rrrr rrrr + - E lull dddd dddr rrrr rrrr rrr + - C dlll ulld dddd ddrr rrrr rrrr rrr + - I dddr rrrr rrrr r + - K ddll l + - K rrrr rrrr rrrr rrr diff --git a/NethackHelper/sokoban/4a.yaml b/NethackHelper/sokoban/4a.yaml new file mode 100644 index 0000000..3010fc1 --- /dev/null +++ b/NethackHelper/sokoban/4a.yaml @@ -0,0 +1,51 @@ +name: Sokoban Level 4a +map: | + ┌────────────────────────┐ + │>......^^^^^^^^^^^^^^^^.│ + │.......┌──────────────┐.│ + └┬─────.└────┐ │.│ + │...........│ │.│ + │.A.B.C.D.E.│ │.│ + ┌┴──────.────┤ │.│ + │...F.G..H.I.│ │.│ + │...J........│ │.│ + └┬───.──────┬┘ ┌─────┤.│ + │..K.L.M...│ ┌─┤.....│.│ + │.....N....│ │.+.....│.│ + │.O.P...Q.┌┘ ├─┤.....│.│ + ┌┴─────.─┬─┘ │.+.....+.│ + │..R.....│ ├─┤.....├─┘ + │........│ │.+.....│ + │...┌────┘ └─┤.....│ + └───┘ └─────┘ +solution: + - K l + - N rrr + - R rrr + - P rrdd dlll lur + - F ll + - J rddd drrd ddll lllu + - G ll + - H ll + - D lddd llld dddr + - C rddd llld dd + - H ruuu luuu r + - G rrrr uuul uuur r + - F rrrr rruu uluu urrr + - I lllu uulu uurr rr + - C uuuu rrru uulu uurr rrr + - K rruu urrr uuul uuur rrrr r + - L luuu rrru uulu uurr rrrr r + - M lllu uurr ruuu luuu rrrr rrrr + - N llll luuu urrr uuul uuur rrrr rrrr + - R ruuu ullu uurr ruuu luuu rrrr rrrr rr + - P rrru uuul luuu rrru uulu uurr rrrr rrrr r + - J rrrr ruuu ullu uurr ruuu luuu rrrr rrrr rrrr + - D rddd llll lu + - D rr rrru uuul luuu rrru uulu uurr rrrr rrrr rrr + - B rrrd ddll lddd + - B uuuu rrru uulu uurr rrrr rrrr rrrr + - A rrrr rddd llld dd + - A uu uurr ruuu luuu rrrr rrrr rrrr rrr + - E llld ddll lddd + - E uuuu rrru uulu uurr rrrr rrrr rrrr rr diff --git a/NethackHelper/sokoban/4b.yaml b/NethackHelper/sokoban/4b.yaml new file mode 100644 index 0000000..73a8798 --- /dev/null +++ b/NethackHelper/sokoban/4b.yaml @@ -0,0 +1,53 @@ +name: Sokoban Level 4b +map: | +   ┌──────────────────────┐ + │..^^^^^^^^^^^^^^^^^^..│ + │..┌─────────────────┐.│ + ┌─┴┐.│ ┌───┐ │.│ + │..│A└┐ ┌┘...│ │.│ + │.....├──┤.B..│ │.│ + │.CD..│..│..E.│ │.│ + └┐..FG│...HI.┌┘ │.│ + │J..K...│L..│ ┌─────┤.│ + │.MN.│..│..O│ ┌─┤.....│.│ + │.P.Q└──┤.R.│ │.+.....│.│ + │.......│..┌┘ ├─┤.....│.│ + └──┐.S..│.┌┘ │.+.....+.│ + └┬─.─┘.│ ├─┤.....├─┘ + │.T...│ │.+.....│ + │>.│..│ └─┤.....│ + └──┴──┘ └─────┘ +solution: + - T rrru uuu + - R u + - O uu + - I u + - H lll + - K ll + - N d + - F u + - G u + - C u + - C d + - A uuur + - F dd + - F uu uuuu urr + - C u + - D ruuu uurr r + - C rruu uurr rr + - N uuuu uuuu urrr rr + - P ruuu uuuu uurr rrrr + - M ruuu uuuu urrr rrrr + - K uuur uuuu rrrr rrrr + - J uuur ruuu urrr rrrr rr + - H dlll uuuu uuur rrrr rrrr r + - R d + - L ulll dlll uuuu uuur rrrr rrrr rr + - T uuul lldl lluu uuuu urrr rrrr rrrr r + - R luuu llld lllu uuuu uurr rrrr rrrr rrr + - B r + - I dddl uull ldll luuu uuuu rrrr rrrr rrrr rr + - E lldl lldl lluu uuuu urrr rrrr rrrr rrrr + - B dlld llld lllu uuuu uurr rrrr rrrr rrrr rr + - G ddlu uuuu uurr rrrr rrrr rrrr rrr + - Q uulu uuuu uurr rrrr rrrr rrrr rrrr