├── .gitignore
├── ArcNET.DataTypes
├── ArcNET.DataTypes.csproj
├── BinaryReaderExtensions.cs
├── Common
│ ├── ArtId.cs
│ ├── Color.cs
│ ├── Location.cs
│ └── PrefixedString.cs
├── FacadeWalk.cs
├── FacadeWalkReader.cs
├── GameObjects
│ ├── Classes
│ │ ├── AIPacket.cs
│ │ ├── AutoLevelSchemes.cs
│ │ ├── Background.cs
│ │ ├── CritterXpLevels.cs
│ │ ├── Descriptions.cs
│ │ ├── Entity.cs
│ │ ├── Faction.cs
│ │ ├── InventorySource.cs
│ │ ├── InventorySourceBuy.cs
│ │ ├── Monster.cs
│ │ ├── NPC.cs
│ │ ├── QuestXpLevels.cs
│ │ ├── RandomEncounters.cs
│ │ ├── Unique.cs
│ │ ├── WorldMapEncounterInfo.cs
│ │ └── XpLevels.cs
│ ├── Enums.cs
│ ├── Flags
│ │ ├── ObjFBlitFlag.cs
│ │ ├── ObjFCritterFlags.cs
│ │ ├── ObjFCritterFlags2.cs
│ │ ├── ObjFFlags.cs
│ │ ├── ObjFNpcFlags.cs
│ │ └── ObjFSpellFlags.cs
│ ├── GameObject.cs
│ ├── GameObjectGuid.cs
│ ├── GameObjectHeader.cs
│ ├── GameObjectHeaderReader.cs
│ ├── GameObjectManager.cs
│ ├── GameObjectReader.cs
│ ├── GameObjectScript.cs
│ └── Types
│ │ ├── Ammo.cs
│ │ ├── Armor.cs
│ │ ├── Common.cs
│ │ ├── Container.cs
│ │ ├── Critter.cs
│ │ ├── Food.cs
│ │ ├── Generic.cs
│ │ ├── Gold.cs
│ │ ├── Item.cs
│ │ ├── Key.cs
│ │ ├── KeyRing.cs
│ │ ├── NPC.cs
│ │ ├── PC.cs
│ │ ├── Portal.cs
│ │ ├── Projectile.cs
│ │ ├── Scenery.cs
│ │ ├── Scroll.cs
│ │ ├── Trap.cs
│ │ ├── Unknown.cs
│ │ ├── Wall.cs
│ │ ├── Weapon.cs
│ │ └── Written.cs
├── Generators
│ └── Wikia.cs
├── MessageEntry.cs
├── MessageEntryReader.cs
├── MessageReader.cs
├── Sector.cs
├── SectorReader.cs
└── TextDataReader.cs
├── ArcNET.Terminal
├── ArcNET.Terminal.csproj
├── Parser.cs
├── Program.cs
└── Terminal.cs
├── ArcNET.Utilities
├── ArcNET.Utilities.csproj
├── GitHub.cs
└── HighResConfig.cs
├── ArcNET.sln
├── ArcNET.sln.DotSettings
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # StyleCop
65 | StyleCopReport.xml
66 |
67 | # Files built by Visual Studio
68 | *_i.c
69 | *_p.c
70 | *_h.h
71 | *.ilk
72 | *.meta
73 | *.obj
74 | *.iobj
75 | *.pch
76 | *.pdb
77 | *.ipdb
78 | *.pgc
79 | *.pgd
80 | *.rsp
81 | *.sbr
82 | *.tlb
83 | *.tli
84 | *.tlh
85 | *.tmp
86 | *.tmp_proj
87 | *_wpftmp.csproj
88 | *.log
89 | *.vspscc
90 | *.vssscc
91 | .builds
92 | *.pidb
93 | *.svclog
94 | *.scc
95 |
96 | # Chutzpah Test files
97 | _Chutzpah*
98 |
99 | # Visual C++ cache files
100 | ipch/
101 | *.aps
102 | *.ncb
103 | *.opendb
104 | *.opensdf
105 | *.sdf
106 | *.cachefile
107 | *.VC.db
108 | *.VC.VC.opendb
109 |
110 | # Visual Studio profiler
111 | *.psess
112 | *.vsp
113 | *.vspx
114 | *.sap
115 |
116 | # Visual Studio Trace Files
117 | *.e2e
118 |
119 | # TFS 2012 Local Workspace
120 | $tf/
121 |
122 | # Guidance Automation Toolkit
123 | *.gpState
124 |
125 | # ReSharper is a .NET coding add-in
126 | _ReSharper*/
127 | *.[Rr]e[Ss]harper
128 | *.DotSettings.user
129 |
130 | # TeamCity is a build add-in
131 | _TeamCity*
132 |
133 | # DotCover is a Code Coverage Tool
134 | *.dotCover
135 |
136 | # AxoCover is a Code Coverage Tool
137 | .axoCover/*
138 | !.axoCover/settings.json
139 |
140 | # Visual Studio code coverage results
141 | *.coverage
142 | *.coveragexml
143 |
144 | # NCrunch
145 | _NCrunch_*
146 | .*crunch*.local.xml
147 | nCrunchTemp_*
148 |
149 | # MightyMoose
150 | *.mm.*
151 | AutoTest.Net/
152 |
153 | # Web workbench (sass)
154 | .sass-cache/
155 |
156 | # Installshield output folder
157 | [Ee]xpress/
158 |
159 | # DocProject is a documentation generator add-in
160 | DocProject/buildhelp/
161 | DocProject/Help/*.HxT
162 | DocProject/Help/*.HxC
163 | DocProject/Help/*.hhc
164 | DocProject/Help/*.hhk
165 | DocProject/Help/*.hhp
166 | DocProject/Help/Html2
167 | DocProject/Help/html
168 |
169 | # Click-Once directory
170 | publish/
171 |
172 | # Publish Web Output
173 | *.[Pp]ublish.xml
174 | *.azurePubxml
175 | # Note: Comment the next line if you want to checkin your web deploy settings,
176 | # but database connection strings (with potential passwords) will be unencrypted
177 | *.pubxml
178 | *.publishproj
179 |
180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
181 | # checkin your Azure Web App publish settings, but sensitive information contained
182 | # in these scripts will be unencrypted
183 | PublishScripts/
184 |
185 | # NuGet Packages
186 | *.nupkg
187 | # NuGet Symbol Packages
188 | *.snupkg
189 | # The packages folder can be ignored because of Package Restore
190 | **/[Pp]ackages/*
191 | # except build/, which is used as an MSBuild target.
192 | !**/[Pp]ackages/build/
193 | # Uncomment if necessary however generally it will be regenerated when needed
194 | #!**/[Pp]ackages/repositories.config
195 | # NuGet v3's project.json files produces more ignorable files
196 | *.nuget.props
197 | *.nuget.targets
198 |
199 | # Microsoft Azure Build Output
200 | csx/
201 | *.build.csdef
202 |
203 | # Microsoft Azure Emulator
204 | ecf/
205 | rcf/
206 |
207 | # Windows Store app package directories and files
208 | AppPackages/
209 | BundleArtifacts/
210 | Package.StoreAssociation.xml
211 | _pkginfo.txt
212 | *.appx
213 | *.appxbundle
214 | *.appxupload
215 |
216 | # Visual Studio cache files
217 | # files ending in .cache can be ignored
218 | *.[Cc]ache
219 | # but keep track of directories ending in .cache
220 | !?*.[Cc]ache/
221 |
222 | # Others
223 | ClientBin/
224 | ~$*
225 | *~
226 | *.dbmdl
227 | *.dbproj.schemaview
228 | *.jfm
229 | *.pfx
230 | *.publishsettings
231 | orleans.codegen.cs
232 |
233 | # Including strong name files can present a security risk
234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
235 | #*.snk
236 |
237 | # Since there are multiple workflows, uncomment next line to ignore bower_components
238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
239 | #bower_components/
240 |
241 | # RIA/Silverlight projects
242 | Generated_Code/
243 |
244 | # Backup & report files from converting an old project file
245 | # to a newer Visual Studio version. Backup files are not needed,
246 | # because we have git ;-)
247 | _UpgradeReport_Files/
248 | Backup*/
249 | UpgradeLog*.XML
250 | UpgradeLog*.htm
251 | ServiceFabricBackup/
252 | *.rptproj.bak
253 |
254 | # SQL Server files
255 | *.mdf
256 | *.ldf
257 | *.ndf
258 |
259 | # Business Intelligence projects
260 | *.rdl.data
261 | *.bim.layout
262 | *.bim_*.settings
263 | *.rptproj.rsuser
264 | *- [Bb]ackup.rdl
265 | *- [Bb]ackup ([0-9]).rdl
266 | *- [Bb]ackup ([0-9][0-9]).rdl
267 |
268 | # Microsoft Fakes
269 | FakesAssemblies/
270 |
271 | # GhostDoc plugin setting file
272 | *.GhostDoc.xml
273 |
274 | # Node.js Tools for Visual Studio
275 | .ntvs_analysis.dat
276 | node_modules/
277 |
278 | # Visual Studio 6 build log
279 | *.plg
280 |
281 | # Visual Studio 6 workspace options file
282 | *.opt
283 |
284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
285 | *.vbw
286 |
287 | # Visual Studio LightSwitch build output
288 | **/*.HTMLClient/GeneratedArtifacts
289 | **/*.DesktopClient/GeneratedArtifacts
290 | **/*.DesktopClient/ModelManifest.xml
291 | **/*.Server/GeneratedArtifacts
292 | **/*.Server/ModelManifest.xml
293 | _Pvt_Extensions
294 |
295 | # Paket dependency manager
296 | .paket/paket.exe
297 | paket-files/
298 |
299 | # FAKE - F# Make
300 | .fake/
301 |
302 | # CodeRush personal settings
303 | .cr/personal
304 |
305 | # Python Tools for Visual Studio (PTVS)
306 | __pycache__/
307 | *.pyc
308 |
309 | # Cake - Uncomment if you are using it
310 | # tools/**
311 | # !tools/packages.config
312 |
313 | # Tabs Studio
314 | *.tss
315 |
316 | # Telerik's JustMock configuration file
317 | *.jmconfig
318 |
319 | # BizTalk build output
320 | *.btp.cs
321 | *.btm.cs
322 | *.odx.cs
323 | *.xsd.cs
324 |
325 | # OpenCover UI analysis results
326 | OpenCover/
327 |
328 | # Azure Stream Analytics local run output
329 | ASALocalRun/
330 |
331 | # MSBuild Binary and Structured Log
332 | *.binlog
333 |
334 | # NVidia Nsight GPU debugger configuration file
335 | *.nvuser
336 |
337 | # MFractors (Xamarin productivity tool) working folder
338 | .mfractor/
339 |
340 | # Local History for Visual Studio
341 | .localhistory/
342 |
343 | # BeatPulse healthcheck temp database
344 | healthchecksdb
345 |
346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
347 | MigrationBackup/
348 |
349 | # Ionide (cross platform F# VS Code tools) working folder
350 | .ionide/
351 |
--------------------------------------------------------------------------------
/ArcNET.DataTypes/ArcNET.DataTypes.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/ArcNET.DataTypes/BinaryReaderExtensions.cs:
--------------------------------------------------------------------------------
1 | using ArcNET.DataTypes.Common;
2 | using ArcNET.DataTypes.GameObjects;
3 | using System;
4 | using System.Collections;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Reflection;
8 |
9 | namespace ArcNET.DataTypes;
10 |
11 | public static class BinaryReaderExtensions
12 | {
13 | public static Location ReadLocation(this BinaryReader reader, bool force = false)
14 | {
15 | var loc = new Location();
16 | if (!force)
17 | {
18 | byte flag = reader.ReadByte();
19 | if (flag == 0x00) return null;
20 |
21 | if (flag != 0x01)
22 | throw new Exception();
23 | }
24 |
25 | loc.X = reader.ReadInt32();
26 | loc.Y = reader.ReadInt32();
27 | return loc;
28 | }
29 |
30 | public static GameObjectGuid ReadGameObjectGuid(this BinaryReader reader, bool force = false)
31 | {
32 | if (!force)
33 | {
34 | byte flag = reader.ReadByte();
35 | if (flag == 0x00) return null;
36 |
37 | if (flag != 0x01)
38 | throw new Exception();
39 | }
40 |
41 | var result = new GameObjectGuid
42 | {
43 | Type = reader.ReadInt16(),
44 | Foo0 = reader.ReadInt16(),
45 | Foo2 = reader.ReadInt32()
46 | };
47 | byte[] guidData = reader.ReadBytes(16);
48 | result.Guid = new Guid(guidData);
49 |
50 | return result;
51 | }
52 |
53 | public static ArtId ReadArtId(this BinaryReader reader)
54 | => new(reader.ReadInt32().ToString("X2"));
55 | }
56 |
57 | public static class BitArrayUtils
58 | {
59 | public static bool Get(this BitArray bitArray, int index, bool isPrototype)
60 | => bitArray.Get(index) || isPrototype;
61 | }
62 |
63 | public class OrderAttribute : Attribute
64 | {
65 | public int Order { get; private set; }
66 |
67 | public OrderAttribute(int order)
68 | {
69 | Order = order;
70 | }
71 | }
72 |
73 | public static class PropertyInfoUtils
74 | {
75 | public static int PropertyOrder(this PropertyInfo propInfo)
76 | {
77 | var orderAttr = (OrderAttribute)propInfo.GetCustomAttributes(typeof(OrderAttribute), true).SingleOrDefault();
78 | int output = orderAttr?.Order ?? int.MaxValue;
79 | return output;
80 | }
81 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/Common/ArtId.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ArcNET.DataTypes.Common;
4 |
5 | public class ArtId
6 | {
7 | public string Path;
8 | public static List ArtIds = new();
9 |
10 | public ArtId(string path)
11 | {
12 | Path = path;
13 | }
14 |
15 | public override string ToString()
16 | => Path;
17 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/Common/Color.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ArcNET.DataTypes.Common;
4 |
5 | public class Color
6 | {
7 | public byte R;
8 | public byte G;
9 | public byte B;
10 | public byte A;
11 |
12 | public Color()
13 | {
14 | R = 255;
15 | G = 255;
16 | B = 255;
17 | A = 0;
18 | }
19 |
20 | public Color(int data)
21 | {
22 | byte[] temp = BitConverter.GetBytes(data);
23 | B = temp[0];
24 | G = temp[1];
25 | R = temp[2];
26 | A = temp[3];
27 | }
28 |
29 | public override string ToString()
30 | => "R: " + R + "," + "G: " + G + "," + "B: " + B + "," + "A: " + A;
31 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/Common/Location.cs:
--------------------------------------------------------------------------------
1 | namespace ArcNET.DataTypes.Common;
2 |
3 | public class Location
4 | {
5 | public int X { get; set; }
6 | public int Y { get; set; }
7 |
8 | public override string ToString()
9 | => $"{X},{Y}";
10 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/Common/PrefixedString.cs:
--------------------------------------------------------------------------------
1 | namespace ArcNET.DataTypes.Common;
2 |
3 | public class PrefixedString
4 | {
5 | private readonly string _value;
6 |
7 | public PrefixedString()
8 | {
9 | _value = string.Empty;
10 | }
11 |
12 | public PrefixedString(string value)
13 | {
14 | _value = value;
15 | }
16 |
17 | public override string ToString()
18 | => _value;
19 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/FacadeWalk.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace ArcNET.DataTypes;
5 |
6 | public class FacadeWalk
7 | {
8 | public FacWalkMarker Marker;
9 | public FacWalkHeader Header;
10 | public FacWalkEntry[] Entries;
11 | }
12 |
13 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
14 | public struct FacWalkMarker
15 | {
16 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
17 | public string fileMarker; // fileTypeMarker 'F', 'a', 'c', 'W', 'a', 'l', 'k', ' ', + fileTypeVersion 'V', '1', '0', '1', ' ', ' '
18 | }
19 |
20 | [Serializable]
21 | [StructLayout(LayoutKind.Sequential)]
22 | public struct FacWalkHeader
23 | {
24 | // base terrain, index + outdoor + flippable
25 | [MarshalAs(UnmanagedType.U4)]
26 | public uint terrain; // index to tilename.mes
27 |
28 | [MarshalAs(UnmanagedType.U4)]
29 | public uint outdoor; // boolean, 1 = outdoor
30 |
31 | [MarshalAs(UnmanagedType.U4)]
32 | public uint flippable; // boolean, 1 = flippable
33 |
34 | [MarshalAs(UnmanagedType.U4)]
35 | public uint width; // width of facade, isometric
36 |
37 | // ReSharper disable once MissingBlankLines
38 | [MarshalAs(UnmanagedType.U4)]
39 | public uint height; // height of facade, isometric
40 |
41 | [MarshalAs(UnmanagedType.U4)]
42 | public uint entryCount; // equals to number of frames of equivalent Art file.
43 | }
44 |
45 | [Serializable]
46 | [StructLayout(LayoutKind.Sequential)]
47 | public struct FacWalkEntry
48 | {
49 | [MarshalAs(UnmanagedType.U4)]
50 | public uint x; // x position
51 |
52 | [MarshalAs(UnmanagedType.U4)]
53 | public uint y; // y position
54 |
55 | [MarshalAs(UnmanagedType.U4)]
56 | public uint walkable; // boolean, 0 = blocked
57 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/FacadeWalkReader.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using Utils.Console;
3 | using Utils.Marshalling;
4 |
5 | namespace ArcNET.DataTypes;
6 |
7 | public class FacadeWalkReader
8 | {
9 | private readonly BinaryReader _reader;
10 |
11 | public FacadeWalkReader(BinaryReader reader)
12 | {
13 | _reader = reader;
14 | }
15 |
16 | public FacadeWalk Read()
17 | {
18 | var obj = new FacadeWalk
19 | {
20 | Marker = MarshallingExtensions.ByteArrayToStructure(_reader)
21 | };
22 | //ConsoleExtensions.Log($"Parsed file marker: {obj.Marker.fileMarker}", "success");
23 |
24 | const string markerConst = "FacWalk V101 ";
25 | string markerActual = obj.Marker.fileMarker;
26 | if (markerActual != markerConst)
27 | {
28 | ConsoleExtensions.Log("Filetype or version mismatch!", "error");
29 | ConsoleExtensions.Log($"Expected: {markerConst}", "error");
30 | ConsoleExtensions.Log($"Parsed: {markerActual}", "error");
31 | return null;
32 | }
33 |
34 | obj.Header = MarshallingExtensions.ByteArrayToStructure(_reader);
35 | obj.Entries = new FacWalkEntry[obj.Header.entryCount];
36 |
37 | #if DEBUG
38 | //ConsoleExtensions.Log($"Parsed Header: {obj.Header}", "success");
39 | //ConsoleExtensions.Log($"Parsing {obj.Header.entryCount} entries", "info");
40 | #endif
41 |
42 | for (var i = 0; i < obj.Header.entryCount; i++)
43 | obj.Entries[i] = MarshallingExtensions.ByteArrayToStructure(_reader);
44 | //AnsiConsole.WriteLine($"Parsing entry: {obj.Entries[i]} index:{i}");
45 | return obj;
46 | }
47 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/AIPacket.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace ArcNET.DataTypes.GameObjects.Classes;
5 |
6 | public class AIPacket
7 | {
8 | public struct Packet
9 | {
10 | public struct FleeingParams
11 | {
12 | public int NPCHPBelow; //percentage of NPC hit points below which NPC will flee
13 | public int PeopleAround; //number of people besides PC beyond which NPC will flee
14 | public int LevelAbove; //number of levels above NPC beyond which NPC will flee
15 | public int PCHPBelow; //percentage of PC hit points below which NPC will never flee
16 | public int FleeRange; //how far to flee, in tiles
17 | }
18 |
19 | public struct FollowerParams
20 | {
21 | public int ReactionLevel; //the reaction level at which the NPC will not follow the PC
22 | public int PCAlignAboveNPC; //how far PC alignment is above NPC align before NPC wont follow
23 | public int PCAlignBelowNPC; //how far PC align is below NPC align before NPC wont follow
24 | public int NPCLevelsAbovePC; //how many levels the NPC can be above the PC and still join
25 | public int NPCAbuseReaction; //how much a non-accidental hit will lower a follower's reaction
26 | }
27 |
28 | public struct KillOnSightParams
29 | {
30 | public int NPCReactionLevelBelow; //NPC will attack if his reaction is below this
31 | public int NPCAlignDiffToPC; //how different alignments can be before non-follower NPC attacks
32 | public int TargetAlignGoodNoAtt; //alignment of target at (or above) which the good-aligned follower NPC will not attack
33 | }
34 |
35 | public struct SpellParams
36 | {
37 | public int DefensiveSpellChance; //chance of throwing defensive spell (as opposed to offensive)
38 | public int HealingSpellInCmbChance; //chance of throwing a healing spell in combat
39 | }
40 |
41 | public struct CombatParams
42 | {
43 | public int CombatMinDistance; //minimum distance in combat
44 | }
45 |
46 | public struct DoorAndWindowsParams
47 | {
48 | public int CanOpenPortals; //the NPC can open portals if this is nonzero and cannot if it is zero
49 | }
50 | }
51 |
52 | public List> Entries;
53 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/AutoLevelSchemes.cs:
--------------------------------------------------------------------------------
1 | using Spectre.Console;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics.CodeAnalysis;
5 |
6 | namespace ArcNET.DataTypes.GameObjects.Classes;
7 |
8 | public class AutoLevelSchemes
9 | {
10 | public static AutoLevelSchemes LoadedAutoLevelSchemes = new();
11 |
12 | [SuppressMessage("ReSharper", "InconsistentNaming")]
13 | public enum Abbreviations
14 | {
15 | //Stats
16 | st,
17 | dx,
18 | cn,
19 | be,
20 | @in,
21 | pe,
22 | wp,
23 | ch,
24 |
25 | //Skills
26 | bow,
27 | dodge,
28 | melee,
29 | throwing,
30 | backstab,
31 | pickpocket,
32 | prowling,
33 | spottrap,
34 | gambling,
35 | haggle,
36 | heal,
37 | persuasion,
38 | repair,
39 | firearms,
40 | picklock,
41 | armtrap,
42 |
43 | //Spells
44 | conveyance,
45 | divination,
46 | air,
47 | earth,
48 | fire,
49 | water,
50 | force,
51 | mental,
52 | meta,
53 | morph,
54 | nature,
55 | necro_evil,
56 | necro_good,
57 | phantasm,
58 | summoning,
59 | temporal,
60 |
61 | //Tech
62 | anatomical,
63 | chemistry,
64 | electric,
65 | explosives,
66 | gun_smithy,
67 | mechanical,
68 | smithy,
69 | therapeutics,
70 |
71 | //Misc
72 | maxhps,
73 | maxfatigue
74 | }
75 |
76 | public class AutoLevelSchemeEntry
77 | {
78 | public int Id;
79 | public string Name;
80 | public List> Data;
81 |
82 | public AutoLevelSchemeEntry(int id, string name)
83 | {
84 | Id = id;
85 | Name = name;
86 | Data = new List>();
87 | }
88 | }
89 |
90 | public List Entries = new();
91 |
92 | public static void InitFromText(IEnumerable textData)
93 | {
94 | try
95 | {
96 | foreach (string line in textData)
97 | {
98 | string[] idNameData = line.Split("}", 2);
99 | idNameData[0] = idNameData[0].Replace("{", "");
100 | var id = int.Parse(idNameData[0]);
101 |
102 | string nameAndData = idNameData[1];
103 | if (nameAndData.StartsWith("-")) nameAndData.Remove(0);
104 |
105 | string[] nameAndDataSplit = nameAndData.Split("{");
106 | string name = nameAndDataSplit[0].Trim();
107 | string data = nameAndDataSplit[1];
108 |
109 | var schemeEntry = new AutoLevelSchemeEntry(id, name);
110 |
111 | data = data.Replace("}", "");
112 |
113 | //bad data cleanup
114 | if (data.EndsWith(",")) data = data.Remove(data.Length - 1, 1);
115 | if (data.EndsWith("\t// default level scheme")) data = data.Replace("\t// default level scheme", "");
116 | if (data.Contains(" ")) data = data.Replace(" ", " ");
117 |
118 | string[] dataArray = data.Split(",");
119 | foreach (string dataValueTuple in dataArray)
120 | {
121 | string[] abbreviationAndValue = dataValueTuple.TrimStart().Split(" ");
122 | string abbreviation = abbreviationAndValue[0];
123 | var value = int.Parse(abbreviationAndValue[1]);
124 |
125 | Tuple dataTuple = null;
126 | foreach (Abbreviations abrev in (Abbreviations[])Enum.GetValues(typeof(Abbreviations)))
127 | {
128 | string enumValueName = Enum.GetName(typeof(Abbreviations), abrev);
129 | if (enumValueName != null && !enumValueName.Equals(abbreviation)) continue;
130 |
131 | dataTuple = new Tuple(abrev, value);
132 | }
133 |
134 | schemeEntry.Data.Add(dataTuple);
135 | }
136 |
137 | LoadedAutoLevelSchemes.Entries.Add(schemeEntry);
138 | }
139 | }
140 | catch (Exception ex)
141 | {
142 | AnsiConsole.WriteException(ex);
143 | throw;
144 | }
145 | }
146 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/Background.cs:
--------------------------------------------------------------------------------
1 | using Spectre.Console;
2 | using System;
3 | using System.Collections.Generic;
4 | using Utils.Console;
5 |
6 | namespace ArcNET.DataTypes.GameObjects.Classes;
7 |
8 | public class Background
9 | {
10 | public static List LoadedBackgrounds = new();
11 |
12 | public enum RaceGenderCombo
13 | {
14 | HumanFemale, // HUF - human female
15 | HumanMale, // HUM - human male
16 | DwarfFemale, // DWF - dwarf female
17 | DwarfMale, // DWM - dwarf male
18 | ElfFemale, // ELF - elf female
19 | ElfMale, // ELM - elf male
20 | HalfElfFemale, // HEF - half elf female
21 | HalfElfMale, // HEM - half elf male
22 | GnomeFemale, // GNF - gnome female
23 | GnomeMale, // GNM - gnome male
24 | HalflingFemale, // HAF - halfling female
25 | HalflingMale, // HAM - halfling male
26 | HalfOrcFemale, // HOF - half orc female
27 | HalfOrcMale, // HOM - half orc male
28 | HalfOrgeFemale, // HGF - half ogre female
29 | HalfOrgeMale, // HGM - half ogre male
30 | AnyNPC, // NPC - any NPC can use this background, regardless of their race or gender
31 | Any, // ANY - anyone can use this background (same as blank line, included for clarity)
32 | }
33 |
34 | public int DescriptionMessageIndex;
35 | public int EffectMessageIndex;
36 | public List ValidRaceGenderCombinations;
37 | public int MoneyGiven;
38 | public List ItemsGiven;
39 |
40 | public static void InitFromText(IEnumerable textData)
41 | {
42 | Background curBackground = null;
43 |
44 | try
45 | {
46 | foreach (string line in textData)
47 | {
48 | string[] indexAndData = line.Split("}", 2);
49 | indexAndData[0] = indexAndData[0].Replace("{", "");
50 | var index = int.Parse(indexAndData[0]);
51 |
52 | indexAndData[1] = indexAndData[1].Replace("{", "");
53 | indexAndData[1] = indexAndData[1].Replace("}", "");
54 | indexAndData[1] = indexAndData[1].TrimEnd();
55 | string data = indexAndData[1];
56 | if (data.Contains("//"))
57 | {
58 | string[] idAndName = data.Split("//");
59 | data = idAndName[0];
60 | }
61 |
62 | if (index == 0 || index % 10 == 0)
63 | curBackground = new Background
64 | {
65 | DescriptionMessageIndex = int.Parse(data),
66 | ValidRaceGenderCombinations = new List(),
67 | ItemsGiven = new List()
68 | };
69 | else switch (index % 10)
70 | {
71 | case 1:
72 | if (data.Equals("")) break;
73 |
74 | if (curBackground != null)
75 | curBackground.EffectMessageIndex = int.Parse(data);
76 | break;
77 | case 2:
78 | string[] combos = indexAndData[1].Split(" ");
79 | foreach (string combo in combos)
80 | switch (combo)
81 | {
82 | case "HUF":
83 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.HumanFemale);
84 | break;
85 | case "HUM":
86 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.HumanMale);
87 | break;
88 | case "DWF":
89 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.DwarfFemale);
90 | break;
91 | case "DWM":
92 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.DwarfMale);
93 | break;
94 | case "ELF":
95 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.ElfFemale);
96 | break;
97 | case "ELM":
98 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.ElfMale);
99 | break;
100 | case "HEF":
101 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.HalfElfFemale);
102 | break;
103 | case "HEM":
104 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.HalfElfMale);
105 | break;
106 | case "GNF":
107 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.GnomeFemale);
108 | break;
109 | case "GNM":
110 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.GnomeMale);
111 | break;
112 | case "HAF":
113 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.HalflingFemale);
114 | break;
115 | case "HAM":
116 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.HalflingMale);
117 | break;
118 | case "HOF":
119 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.HalfOrcFemale);
120 | break;
121 | case "HOM":
122 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.HalfOrcMale);
123 | break;
124 | case "HGF":
125 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.HalfOrgeFemale);
126 | break;
127 | case "HGM":
128 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.HalfOrgeMale);
129 | break;
130 | case "NPC":
131 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.AnyNPC);
132 | break;
133 | case "" or "ANY" or "400": //400 is supposed to be money given
134 | curBackground?.ValidRaceGenderCombinations.Add(RaceGenderCombo.Any);
135 | break;
136 |
137 | default:
138 | ConsoleExtensions.Log($"Unrecognized race gender combo:|{combo}|", "warn");
139 | break;
140 | }
141 |
142 | break;
143 | case 3:
144 | if (data.Equals("")) data = "400";
145 | if (curBackground != null) curBackground.MoneyGiven = int.Parse(data);
146 |
147 | break;
148 | case 4:
149 | string[] items = indexAndData[1].Split(" ");
150 | if (items[0].Equals(""))
151 | {
152 | LoadedBackgrounds.Add(curBackground);
153 | break;
154 | }
155 |
156 | foreach (string itemId in items)
157 | curBackground?.ItemsGiven.Add(int.Parse(itemId));
158 |
159 | LoadedBackgrounds.Add(curBackground);
160 | break;
161 | }
162 | }
163 | }
164 | catch (Exception ex)
165 | {
166 | AnsiConsole.WriteException(ex);
167 | throw;
168 | }
169 | }
170 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/CritterXpLevels.cs:
--------------------------------------------------------------------------------
1 | using Spectre.Console;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace ArcNET.DataTypes.GameObjects.Classes;
6 |
7 | public class CritterXpLevels
8 | {
9 | public static CritterXpLevels LoadedCritterXpLevels = new();
10 |
11 | public class CritterXpLevelEntry
12 | {
13 | public int Level;
14 | public int Experience;
15 |
16 | public CritterXpLevelEntry(int level, int experience)
17 | {
18 | Level = level;
19 | Experience = experience;
20 | }
21 | }
22 |
23 | public List Entries = new();
24 |
25 | public static void InitFromText(IEnumerable textData)
26 | {
27 | try
28 | {
29 | foreach (string line in textData)
30 | {
31 | string[] levelAndXp = line.Split("}", 2);
32 | levelAndXp[0] = levelAndXp[0].Replace("{", "");
33 | var level = int.Parse(levelAndXp[0]);
34 | levelAndXp[1] = levelAndXp[1].Replace("{", "");
35 | levelAndXp[1] = levelAndXp[1].Replace("}", "");
36 | levelAndXp[1] = levelAndXp[1].TrimEnd();
37 | var xp = int.Parse(levelAndXp[1]);
38 |
39 | LoadedCritterXpLevels.Entries.Add(new CritterXpLevelEntry(level, xp));
40 | }
41 | }
42 | catch (Exception ex)
43 | {
44 | AnsiConsole.WriteException(ex);
45 | throw;
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/Descriptions.cs:
--------------------------------------------------------------------------------
1 | using Spectre.Console;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using Utils.Console;
6 |
7 | namespace ArcNET.DataTypes.GameObjects.Classes;
8 |
9 | public class Descriptions
10 | {
11 | public static Descriptions LoadedDescriptions = new();
12 |
13 | public class DescriptionsEntry
14 | {
15 | public int Id;
16 | public string Name;
17 |
18 | public DescriptionsEntry(int id, string name)
19 | {
20 | Id = id;
21 | Name = name;
22 | }
23 | }
24 |
25 | public List Entries = new();
26 |
27 | public static string GetNameFromId(int id)
28 | {
29 | var entries = LoadedDescriptions.Entries.Where(entry => entry.Id.Equals(id)).ToList();
30 | if (entries.Count == 0) return $"NOT_FOUND id:{id}";
31 |
32 | string name = entries.First().Name;
33 | ConsoleExtensions.Log($"Entries found: |{entries.Count}| Name: |{name}|", "info");
34 |
35 | return name;
36 | }
37 |
38 | public static void InitFromText(IEnumerable textData)
39 | {
40 | try
41 | {
42 | foreach (string line in textData)
43 | {
44 | string noFirstBrace = line.Replace("{", "");
45 | string[] idName = noFirstBrace.Split("}", 2);
46 | var id = int.Parse(idName[0]);
47 | idName[1] = idName[1].Replace("}", "");
48 |
49 | LoadedDescriptions.Entries.Add(new DescriptionsEntry(id, idName[1]));
50 | }
51 | }
52 | catch (Exception ex)
53 | {
54 | AnsiConsole.WriteException(ex);
55 | throw;
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/Entity.cs:
--------------------------------------------------------------------------------
1 | using ArcNET.DataTypes.GameObjects.Flags;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace ArcNET.DataTypes.GameObjects.Classes;
6 |
7 | public class Entity
8 | {
9 | public enum BasicStatType
10 | {
11 | Gender,
12 | Race,
13 | Strength,
14 | Dexterity,
15 | Constitution,
16 | Beauty,
17 | Intelligence,
18 | Willpower,
19 | Charisma,
20 | Perception,
21 | TechPoints,
22 | MagickPoints
23 | }
24 |
25 | public enum DamageType
26 | {
27 | Normal,
28 | Fatigue,
29 | Poison,
30 | Electrical,
31 | Fire,
32 | }
33 |
34 | public enum ResistanceType
35 | {
36 | Damage,
37 | Fire,
38 | Electrical,
39 | Poison,
40 | Magic,
41 | }
42 |
43 | public Tuple Description;
44 | public int InternalName;
45 | public int Level;
46 | public Tuple ArtNumberAndPalette;
47 | public int Scale;
48 | public int Alignment;
49 | public List ObjectFlags;
50 | public List CritterFlags; //4 critter flags
51 | public List CritterFlags2; //4 critter flags2
52 | public List NpcFlags; //4 npc flags?
53 | public List BlitFlags; //4 blit flags?
54 | public List SpellFlags; //4 spell flags?
55 | public int HitChart;
56 | public List> BasicStats; // max 12 basic stats
57 | public List Spells; //max 10??
58 | public List> Scripts; // max ?? scripts
59 | public int Faction;
60 | public int AIPacket;
61 | public int Material;
62 | public int HitPoints;
63 | public int Fatigue;
64 | public List> Resistances; // max 5 resistances
65 | public List> Damages; // max ?? dmg types
66 | public int SoundBank;
67 | public int Category;
68 | public int AutoLevelScheme;
69 | public int InventorySource;
70 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/Faction.cs:
--------------------------------------------------------------------------------
1 | using Spectre.Console;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace ArcNET.DataTypes.GameObjects.Classes;
6 |
7 | public class Faction
8 | {
9 | public static Faction LoadedFactions = new();
10 |
11 | public class FactionEntry
12 | {
13 | public int Id;
14 | public string FactionName;
15 |
16 | public FactionEntry(int id, string factionName)
17 | {
18 | Id = id;
19 | FactionName = factionName;
20 | }
21 | }
22 |
23 | public List Entries = new();
24 |
25 | public static void InitFromText(IEnumerable textData)
26 | {
27 | try
28 | {
29 | foreach (string line in textData)
30 | {
31 | string[] idAndFaction = line.Split("}", 2);
32 | idAndFaction[0] = idAndFaction[0].Replace("{", "");
33 | var id = int.Parse(idAndFaction[0]);
34 | idAndFaction[1] = idAndFaction[1].Replace("{", "");
35 | idAndFaction[1] = idAndFaction[1].Replace("}", "");
36 | idAndFaction[1] = idAndFaction[1].TrimEnd();
37 | string faction = idAndFaction[1];
38 |
39 | LoadedFactions.Entries.Add(new FactionEntry(id, faction));
40 | }
41 | }
42 | catch (Exception ex)
43 | {
44 | AnsiConsole.WriteException(ex);
45 | throw;
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/InventorySource.cs:
--------------------------------------------------------------------------------
1 | using Spectre.Console;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using Utils.Enumeration;
6 |
7 | namespace ArcNET.DataTypes.GameObjects.Classes;
8 |
9 | public class InventorySource
10 | {
11 | public static List LoadedInventorySources = new();
12 |
13 | public class InventorySourceEntry
14 | {
15 | public int PrototypeId;
16 | public double Chance;
17 |
18 | public InventorySourceEntry(int prototypeId, double chance)
19 | {
20 | PrototypeId = prototypeId;
21 | Chance = chance;
22 | }
23 | }
24 |
25 | public int Id; //0 reserved
26 | public string Name;
27 | public List Entries;
28 |
29 | public static IEnumerable> NamedDropTableFromId(int id)
30 | {
31 | return (from inventorySource in LoadedInventorySources.Where(invSrc => invSrc.Id.Equals(id))
32 | from inventorySourceEntry in inventorySource.Entries
33 | let name = Descriptions.GetNameFromId(inventorySourceEntry.PrototypeId)
34 | select new Tuple(name, inventorySourceEntry.Chance)).ToList();
35 | }
36 |
37 | public static void InitFromText(IEnumerable textData)
38 | {
39 | try
40 | {
41 | foreach ((string line, int _) in textData.WithIndex())
42 | {
43 | string[] idAndData = line.Split("}", 2);
44 | string id = idAndData[0];
45 | string data = idAndData[1];
46 |
47 | id = id.Remove(0, 1);
48 | var invSource = new InventorySource
49 | {
50 | Id = int.Parse(id),
51 | Entries = new List()
52 | };
53 | string[] nameAndData = data.Split(":", 2);
54 | invSource.Name = nameAndData[0];
55 |
56 | string dropsAndChance = nameAndData[1];
57 | dropsAndChance = dropsAndChance.Replace("}", "");
58 | dropsAndChance = dropsAndChance.TrimStart().TrimEnd();
59 |
60 | //order matters else recursion is needed
61 | string[] badSplits = new[] { " ", " ", " ", " ", " " };
62 | foreach (string badSplit in badSplits)
63 | {
64 | if (!dropsAndChance.Contains(badSplit)) continue;
65 |
66 | dropsAndChance = dropsAndChance.Replace(badSplit, " ");
67 | }
68 |
69 | //fix buggy data
70 | if (dropsAndChance.Contains(", "))
71 | dropsAndChance = dropsAndChance.Replace(", ", ",");
72 | if (dropsAndChance.Contains(" 10141 "))
73 | dropsAndChance = dropsAndChance.Replace(" 10141 ", "");
74 |
75 | string[] dropChanceArray = dropsAndChance.Split(" ");
76 | foreach (string dropChance in dropChanceArray)
77 | {
78 | string[] dropAndChance = dropChance.Split(",");
79 | var chance = int.Parse(dropAndChance[0]);
80 | var dropId = int.Parse(dropAndChance[1]);
81 |
82 | invSource.Entries.Add(new InventorySourceEntry(dropId, chance));
83 | }
84 |
85 | LoadedInventorySources.Add(invSource);
86 | }
87 | }
88 | catch (Exception ex)
89 | {
90 | AnsiConsole.WriteException(ex);
91 | throw;
92 | }
93 | }
94 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/InventorySourceBuy.cs:
--------------------------------------------------------------------------------
1 | using Spectre.Console;
2 | using System;
3 | using System.Collections.Generic;
4 | using Utils.Enumeration;
5 |
6 | namespace ArcNET.DataTypes.GameObjects.Classes;
7 |
8 | public class InventorySourceBuy
9 | {
10 | public static List LoadedInventoryBuySources = new();
11 |
12 | public class InventorySourceBuyEntry
13 | {
14 | public int PrototypeId;
15 |
16 | public InventorySourceBuyEntry(int prototypeId)
17 | {
18 | PrototypeId = prototypeId;
19 | }
20 | }
21 |
22 | public int Id; //0 reserved
23 | public string Name;
24 | public List Entries; //TODO: Can be just {all}
25 |
26 | public static void InitFromText(IEnumerable textData)
27 | {
28 | try
29 | {
30 | foreach ((string line, int _) in textData.WithIndex())
31 | {
32 | string[] idAndData = line.Split("}", 2);
33 | string id = idAndData[0];
34 | string data = idAndData[1];
35 |
36 | id = id.Remove(0, 1);
37 | var invSourceBuy = new InventorySourceBuy
38 | {
39 | Id = int.Parse(id),
40 | Entries = new List()
41 | };
42 | string[] nameAndData = data.Split(":", 2);
43 | invSourceBuy.Name = nameAndData[0];
44 | string itemId = nameAndData[1];
45 |
46 | //bad data
47 | if (itemId.Contains(" 0,0"))
48 | itemId = itemId.Replace(" 0,0", "");
49 |
50 | itemId = itemId.Replace("{", "");
51 | itemId = itemId.Replace("}", "");
52 | itemId = itemId.TrimStart().TrimEnd();
53 |
54 | //placeholders
55 | if (itemId.Equals("all")) itemId = "99999";
56 | if (itemId.Equals("")) itemId = "00000";
57 |
58 | //order matters else recursion is needed
59 | string[] badSplits = new[] { " ", " ", " ", " ", " " };
60 | foreach (string badSplit in badSplits)
61 | {
62 | if (!itemId.Contains(badSplit)) continue;
63 |
64 | itemId = itemId.Replace(badSplit, " ");
65 | }
66 |
67 | string[] boughtItemsIds = itemId.Split(" ");
68 | foreach (string boughtItemId in boughtItemsIds)
69 | invSourceBuy.Entries.Add(new InventorySourceBuyEntry(int.Parse(boughtItemId)));
70 | LoadedInventoryBuySources.Add(invSourceBuy);
71 | }
72 | }
73 | catch (Exception ex)
74 | {
75 | AnsiConsole.WriteException(ex);
76 | throw;
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/Monster.cs:
--------------------------------------------------------------------------------
1 | using ArcNET.DataTypes.GameObjects.Flags;
2 | using Spectre.Console;
3 | using System;
4 | using System.Collections;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using Utils.Console;
8 | using Utils.Enumeration;
9 |
10 | namespace ArcNET.DataTypes.GameObjects.Classes;
11 |
12 | public class Monster : Entity
13 | {
14 | private static List GetWhitespaceIndexes(string input)
15 | {
16 | var whiteSpaceIndexes = new List();
17 | char[] stringAsChars = input.ToCharArray();
18 |
19 | foreach ((char item, int index) in stringAsChars.WithIndex())
20 | if (char.IsWhiteSpace(item))
21 | whiteSpaceIndexes.Add(index);
22 |
23 | return whiteSpaceIndexes;
24 | }
25 |
26 | private static ObjFFlags ParseObjFFlags(string paramValue)
27 | {
28 | var flag = (ObjFFlags) 0;
29 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
30 |
31 | if (!((IList)Enum.GetNames(typeof(ObjFFlags))).Contains(trimmedFlag))
32 | ConsoleExtensions.Log($"Unrecognized ObjFFlags param:|{trimmedFlag}|", "warn");
33 |
34 | foreach (ObjFFlags objFlag in (ObjFFlags[])Enum.GetValues(typeof(ObjFFlags)))
35 | {
36 | if (!Enum.GetName(typeof(ObjFFlags), objFlag).Equals(trimmedFlag)) continue;
37 | //ConsoleExtensions.Log($"Recognized ObjFFlags param:|{trimmedFlag}|", "success");
38 | flag = objFlag;
39 | }
40 |
41 | return flag;
42 | }
43 |
44 | private static ObjFCritterFlags ParseObjFCritterFlags(string paramValue)
45 | {
46 | var flag = (ObjFCritterFlags)0;
47 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
48 |
49 | if (!((IList)Enum.GetNames(typeof(ObjFCritterFlags))).Contains(trimmedFlag))
50 | ConsoleExtensions.Log($"Unrecognized ObjFCritterFlags param:|{trimmedFlag}|", "warn");
51 |
52 | foreach (ObjFCritterFlags critterFlag in (ObjFCritterFlags[])Enum.GetValues(typeof(ObjFCritterFlags)))
53 | {
54 | if (!Enum.GetName(typeof(ObjFCritterFlags), critterFlag).Equals(trimmedFlag)) continue;
55 | //ConsoleExtensions.Log($"Recognized ObjFCritterFlags param:|{trimmedFlag}|", "success");
56 | flag = critterFlag;
57 | }
58 |
59 | return flag;
60 | }
61 |
62 | private static ObjFCritterFlags2 ParseObjFCritterFlags2(string paramValue)
63 | {
64 | var flag = (ObjFCritterFlags2)0;
65 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
66 |
67 | if (!((IList)Enum.GetNames(typeof(ObjFCritterFlags2))).Contains(trimmedFlag))
68 | ConsoleExtensions.Log($"Unrecognized ObjFCritterFlags2 param:|{trimmedFlag}|", "warn");
69 |
70 | foreach (ObjFCritterFlags2 critterFlag2 in (ObjFCritterFlags2[])Enum.GetValues(typeof(ObjFCritterFlags2)))
71 | {
72 | if (!Enum.GetName(typeof(ObjFCritterFlags2), critterFlag2).Equals(trimmedFlag)) continue;
73 | //ConsoleExtensions.Log($"Recognized ObjFCritterFlags2 param:|{trimmedFlag}|", "success");
74 | flag = critterFlag2;
75 | }
76 |
77 | return flag;
78 | }
79 |
80 | private static ObjFNpcFlags ParseObjFNpcFlags(string paramValue)
81 | {
82 | var flag = (ObjFNpcFlags)0;
83 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
84 |
85 | if (!((IList)Enum.GetNames(typeof(ObjFNpcFlags))).Contains(trimmedFlag))
86 | ConsoleExtensions.Log($"Unrecognized ObjFNpcFlags param:|{trimmedFlag}|", "warn");
87 |
88 | foreach (ObjFNpcFlags npcFlag in (ObjFNpcFlags[])Enum.GetValues(typeof(ObjFNpcFlags)))
89 | {
90 | if (!Enum.GetName(typeof(ObjFNpcFlags), npcFlag).Equals(trimmedFlag)) continue;
91 | //ConsoleExtensions.Log($"Recognized ObjFNpcFlags param:|{trimmedFlag}|", "success");
92 | flag = npcFlag;
93 | }
94 |
95 | return flag;
96 | }
97 |
98 | private static ObjFBlitFlag ParseObjFBlitFlag(string paramValue)
99 | {
100 | var flag = (ObjFBlitFlag)0;
101 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
102 |
103 | if (!((IList)Enum.GetNames(typeof(ObjFBlitFlag))).Contains(trimmedFlag))
104 | ConsoleExtensions.Log($"Unrecognized ObjFBlitFlag param:|{trimmedFlag}|", "warn");
105 |
106 | foreach (ObjFBlitFlag blitFlags in (ObjFBlitFlag[])Enum.GetValues(typeof(ObjFBlitFlag)))
107 | {
108 | if (!Enum.GetName(typeof(ObjFBlitFlag), blitFlags).Equals(trimmedFlag)) continue;
109 | //ConsoleExtensions.Log($"Recognized ObjFBlitFlag param:|{trimmedFlag}|", "success");
110 | flag = blitFlags;
111 | }
112 |
113 | return flag;
114 | }
115 |
116 | private static ObjFSpellFlags ParseObjFSpellFlags(string paramValue)
117 | {
118 | var flag = (ObjFSpellFlags)0;
119 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
120 |
121 | if (!((IList)Enum.GetNames(typeof(ObjFSpellFlags))).Contains(trimmedFlag))
122 | ConsoleExtensions.Log($"Unrecognized ObjFSpellFlags param:|{trimmedFlag}|", "warn");
123 |
124 | foreach (ObjFSpellFlags spellFlags in (ObjFSpellFlags[])Enum.GetValues(typeof(ObjFSpellFlags)))
125 | {
126 | if (!Enum.GetName(typeof(ObjFSpellFlags), spellFlags).Equals(trimmedFlag)) continue;
127 | //ConsoleExtensions.Log($"Recognized ObjFSpellFlags param:|{trimmedFlag}|", "success");
128 | flag = spellFlags;
129 | }
130 |
131 | return flag;
132 | }
133 |
134 | private static Tuple GetBasicStat(string paramValue)
135 | {
136 | Tuple basicStatTuple = null;
137 | string trimmedStats = paramValue.TrimStart();
138 |
139 | //skip junk
140 | if (trimmedStats.Equals("Strength 13") || trimmedStats.Equals("Dexterity 15") ||
141 | trimmedStats.Equals("Dexterity 14")) return null;
142 |
143 | var separator = "\t\t";
144 | if (trimmedStats.Contains("Gender") || trimmedStats.Contains("Race"))
145 | separator = " ";
146 | if (trimmedStats.Contains("tech points") || trimmedStats.Contains("magick points"))
147 | {
148 | List whitespaceIndexes = GetWhitespaceIndexes(trimmedStats);
149 | if (whitespaceIndexes.Count >= 2)
150 | trimmedStats = trimmedStats.Remove(whitespaceIndexes.First(), 1);
151 | //ConsoleExtensions.Log($"trimmedStats after removal:|{trimmedStats}|", "warn");
152 | separator = " ";
153 | }
154 |
155 | if (trimmedStats.Contains("Constitution") || trimmedStats.Contains("Intelligence"))
156 | separator = "\t";
157 |
158 | string[] statAndValue = trimmedStats.Split(separator, 2);
159 | string statType = statAndValue[0].Trim();
160 | statType = statType switch
161 | {
162 | "magickpoints" => "MagickPoints",
163 | "techpoints" => "TechPoints",
164 | _ => statType
165 | };
166 |
167 | if (!((IList)Enum.GetNames(typeof(BasicStatType))).Contains(statType))
168 | ConsoleExtensions.Log($"unrecognized Entity.BasicStatType param:|{statType}|", "warn");
169 |
170 | string statValue = statAndValue[1].Trim();
171 | //ConsoleExtensions.Log($"statType:|{statType}| value:|{statValue}|", "warn");
172 |
173 | foreach (BasicStatType basicStatType in (BasicStatType[])Enum.GetValues(typeof(BasicStatType)))
174 | {
175 | string enumValueName = Enum.GetName(typeof(BasicStatType), basicStatType);
176 | if (!enumValueName.Equals(statType))
177 | //ConsoleExtensions.Log($"Failed to match enumValueName:|{enumValueName}| vs statType:|{statType}|", "warn");
178 | continue;
179 |
180 | basicStatTuple = new Tuple(basicStatType, int.Parse(statValue));
181 | }
182 |
183 | return basicStatTuple;
184 | }
185 |
186 | private static Tuple GetResistTuple(string paramName, string paramValue)
187 | {
188 | string trimmedResist = paramName.TrimStart();
189 | string[] resist = trimmedResist.Split(" ", 2);
190 | string resistTypeStr = resist[0];
191 | var resistanceTypes = (ResistanceType[])Enum.GetValues(typeof(ResistanceType));
192 |
193 | return (from resistType in resistanceTypes
194 | let resistTypeName = Enum.GetName(typeof(ResistanceType), resistType)
195 | where resistTypeName.Equals(resistTypeStr)
196 | select new Tuple(resistType, int.Parse(paramValue)))
197 | .FirstOrDefault();
198 | }
199 |
200 | private static Tuple GetDmgTuple(string paramName, string paramValue)
201 | {
202 | string trimmedDmg = paramValue.TrimStart();
203 | string[] dmgRange = trimmedDmg.Split(" ", 2);
204 | var min = int.Parse(dmgRange[0]);
205 | var max = int.Parse(dmgRange[1]);
206 |
207 | return paramName switch
208 | {
209 | "Normal Damage" => new Tuple(DamageType.Normal, min, max),
210 | "Fatigue Damage" => new Tuple(DamageType.Fatigue, min, max),
211 | "Poison Damage" => new Tuple(DamageType.Poison, min, max),
212 | "Electrical Damage" => new Tuple(DamageType.Electrical, min, max),
213 | "Fire Damage" => new Tuple(DamageType.Fire, min, max),
214 | _ => null
215 | };
216 | }
217 |
218 | public static Monster GetFromText(IEnumerable mobText)
219 | {
220 | var monster = new Monster
221 | {
222 | ObjectFlags = new List(),
223 | CritterFlags = new List(),
224 | CritterFlags2 = new List(),
225 | NpcFlags = new List(),
226 | BlitFlags = new List(),
227 | SpellFlags = new List(),
228 | BasicStats = new List>(),
229 | Spells = new List(),
230 | Scripts = new List>(),
231 | Resistances = new List>(),
232 | Damages = new List>()
233 | };
234 |
235 | foreach (string curLine in mobText)
236 | {
237 | if (string.IsNullOrWhiteSpace(curLine)) continue;
238 |
239 | string[] lines = curLine.Split(":", 2);
240 | string paramName = lines[0];
241 | string paramValue = lines[1];
242 |
243 | try
244 | {
245 | switch (paramName)
246 | {
247 | case "Description" when paramValue.Contains("//"):
248 | {
249 | string[] idAndName = paramValue.Split("//", 2);
250 | string monsterId = idAndName[0];
251 | string monsterName = idAndName[1];
252 |
253 | monster.Description = new Tuple(int.Parse(monsterId), monsterName);
254 | break;
255 | }
256 | case "Description":
257 | //ConsoleExtensions.Log($"paramValue:|{paramValue}|", "warn");
258 | break;
259 | case "Internal Name" or "internal name":
260 | monster.InternalName = int.Parse(paramValue);
261 | break;
262 | case "Level":
263 | monster.Level = int.Parse(paramValue);
264 | break;
265 | case "Art Number and Palette":
266 | string trimmed = paramValue.TrimStart();
267 | string[] artNumberAndPalette = trimmed.Split(" ", 2);
268 | string artNumber = artNumberAndPalette[0];
269 | string paletteNumber = artNumberAndPalette[1];
270 |
271 | monster.ArtNumberAndPalette = new Tuple(int.Parse(artNumber), int.Parse(paletteNumber));
272 | break;
273 | case "Scale":
274 | monster.Scale = int.Parse(paramValue);
275 | break;
276 | case "Alignment":
277 | monster.Alignment = int.Parse(paramValue);
278 | break;
279 | case "Object Flag":
280 | monster.ObjectFlags.Add(ParseObjFFlags(paramValue));
281 | break;
282 | case "Critter Flag":
283 | monster.CritterFlags.Add(ParseObjFCritterFlags(paramValue));
284 | break;
285 | case "Critter2 Flag":
286 | monster.CritterFlags2.Add(ParseObjFCritterFlags2(paramValue));
287 | break;
288 | case "NPC Flag":
289 | monster.NpcFlags.Add(ParseObjFNpcFlags(paramValue));
290 | break;
291 | case "Blit Flag":
292 | monster.BlitFlags.Add(ParseObjFBlitFlag(paramValue));
293 | break;
294 | case "Spell Flag":
295 | monster.SpellFlags.Add(ParseObjFSpellFlags(paramValue));
296 | break;
297 | case "Hit Chart":
298 | monster.HitChart = int.Parse(paramValue);
299 | break;
300 | case "Basic Stat" or "basic stat":
301 | monster.BasicStats.Add(GetBasicStat(paramValue));
302 | break;
303 | case "Spell" or "spell":
304 | monster.Spells.Add(paramValue);
305 | break;
306 | case "Script":
307 | string trimmedScript = paramValue.TrimStart();
308 | string[] scriptParams = trimmedScript.Split(" ", 6);
309 |
310 | //foreach (var paramVal in scriptParams)
311 | // ConsoleExtensions.Log($"script param value:|{paramVal}|", "warn");
312 |
313 | var paramValues = scriptParams.Select(int.Parse).ToList();
314 |
315 | monster.Scripts.Add(new Tuple(paramValues[0], paramValues[1], paramValues[2], paramValues[3], paramValues[4], paramValues[5]));
316 | break;
317 | case "Faction":
318 | monster.Faction = int.Parse(paramValue);
319 | break;
320 | case "AI Packet":
321 | if (paramValue.Contains("//"))
322 | paramValue = paramValue.Split("//")[0].Trim();
323 |
324 | monster.AIPacket = int.Parse(paramValue);
325 | break;
326 | case "Material":
327 | if (paramValue.Contains("//"))
328 | paramValue = paramValue.Split("//")[0].Trim();
329 |
330 | monster.Material = int.Parse(paramValue);
331 | break;
332 | case "Hit Points":
333 | monster.HitPoints = int.Parse(paramValue);
334 | break;
335 | case "Fatigue":
336 | monster.Fatigue = int.Parse(paramValue);
337 | break;
338 | case "Damage Resistance" or "damage resistance":
339 | monster.Resistances.Add(GetResistTuple(paramName, paramValue));
340 | break;
341 | case "Fire Resistance":
342 | monster.Resistances.Add(GetResistTuple(paramName, paramValue));
343 | break;
344 | case "Electrical Resistance":
345 | monster.Resistances.Add(GetResistTuple(paramName, paramValue));
346 | break;
347 | case "Poison Resistance":
348 | monster.Resistances.Add(GetResistTuple(paramName, paramValue));
349 | break;
350 | case "Magic Resistance":
351 | monster.Resistances.Add(GetResistTuple(paramName, paramValue));
352 | break;
353 | case "Normal Damage":
354 | monster.Damages.Add(GetDmgTuple(paramName, paramValue));
355 | break;
356 | case "Fatigue Damage":
357 | monster.Damages.Add(GetDmgTuple(paramName, paramValue));
358 | break;
359 | case "Poison Damage":
360 | monster.Damages.Add(GetDmgTuple(paramName, paramValue));
361 | break;
362 | case "Electrical Damage":
363 | monster.Damages.Add(GetDmgTuple(paramName, paramValue));
364 | break;
365 | case "Fire Damage":
366 | monster.Damages.Add(GetDmgTuple(paramName, paramValue));
367 | break;
368 | case "Sound Bank" or "sound bank":
369 | monster.SoundBank = int.Parse(paramValue);
370 | break;
371 | case "Category":
372 | monster.Category = int.Parse(paramValue);
373 | break;
374 | case "Auto Level Scheme":
375 | monster.AutoLevelScheme = int.Parse(paramValue);
376 | break;
377 | case "Inventory Source":
378 | monster.InventorySource = int.Parse(paramValue);
379 | break;
380 |
381 | default:
382 | ConsoleExtensions.Log($"unrecognized entity param:|{paramName}|", "error");
383 | break;
384 | }
385 | }
386 | catch (Exception ex)
387 | {
388 | AnsiConsole.WriteException(ex);
389 | throw;
390 | }
391 | }
392 |
393 | return monster;
394 | }
395 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/NPC.cs:
--------------------------------------------------------------------------------
1 | using ArcNET.DataTypes.GameObjects.Flags;
2 | using Spectre.Console;
3 | using System;
4 | using System.Collections;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using Utils.Console;
8 |
9 | namespace ArcNET.DataTypes.GameObjects.Classes;
10 |
11 | public class NPC : Entity
12 | {
13 | public int Portrait;
14 | public int RetailPriceMultiplier;
15 | public int SocialClass;
16 |
17 | private static ObjFFlags ParseObjFFlags(string paramValue)
18 | {
19 | var flag = (ObjFFlags)0;
20 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
21 |
22 | if (!((IList)Enum.GetNames(typeof(ObjFFlags))).Contains(trimmedFlag))
23 | ConsoleExtensions.Log($"Unrecognized ObjFFlags param:|{trimmedFlag}|", "warn");
24 |
25 | foreach (ObjFFlags objFlag in (ObjFFlags[])Enum.GetValues(typeof(ObjFFlags)))
26 | {
27 | if (!Enum.GetName(typeof(ObjFFlags), objFlag).Equals(trimmedFlag)) continue;
28 | //ConsoleExtensions.Log($"Recognized ObjFFlags param:|{trimmedFlag}|", "success");
29 | flag = objFlag;
30 | }
31 |
32 | return flag;
33 | }
34 |
35 | private static ObjFCritterFlags ParseObjFCritterFlags(string paramValue)
36 | {
37 | var flag = (ObjFCritterFlags)0;
38 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
39 |
40 | if (!((IList)Enum.GetNames(typeof(ObjFCritterFlags))).Contains(trimmedFlag))
41 | ConsoleExtensions.Log($"Unrecognized ObjFCritterFlags param:|{trimmedFlag}|", "warn");
42 |
43 | foreach (ObjFCritterFlags critterFlag in (ObjFCritterFlags[])Enum.GetValues(typeof(ObjFCritterFlags)))
44 | {
45 | if (!Enum.GetName(typeof(ObjFCritterFlags), critterFlag).Equals(trimmedFlag)) continue;
46 | //ConsoleExtensions.Log($"Recognized ObjFCritterFlags param:|{trimmedFlag}|", "success");
47 | flag = critterFlag;
48 | }
49 |
50 | return flag;
51 | }
52 |
53 | private static ObjFCritterFlags2 ParseObjFCritterFlags2(string paramValue)
54 | {
55 | var flag = (ObjFCritterFlags2)0;
56 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
57 |
58 | if (!((IList)Enum.GetNames(typeof(ObjFCritterFlags2))).Contains(trimmedFlag))
59 | ConsoleExtensions.Log($"Unrecognized ObjFCritterFlags2 param:|{trimmedFlag}|", "warn");
60 |
61 | foreach (ObjFCritterFlags2 critterFlag2 in (ObjFCritterFlags2[])Enum.GetValues(typeof(ObjFCritterFlags2)))
62 | {
63 | if (!Enum.GetName(typeof(ObjFCritterFlags2), critterFlag2).Equals(trimmedFlag)) continue;
64 | //ConsoleExtensions.Log($"Recognized ObjFCritterFlags2 param:|{trimmedFlag}|", "success");
65 | flag = critterFlag2;
66 | }
67 |
68 | return flag;
69 | }
70 |
71 | private static ObjFNpcFlags ParseObjFNpcFlags(string paramValue)
72 | {
73 | var flag = (ObjFNpcFlags)0;
74 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
75 |
76 | if (!((IList)Enum.GetNames(typeof(ObjFNpcFlags))).Contains(trimmedFlag))
77 | ConsoleExtensions.Log($"Unrecognized ObjFNpcFlags param:|{trimmedFlag}|", "warn");
78 |
79 | foreach (ObjFNpcFlags npcFlag in (ObjFNpcFlags[])Enum.GetValues(typeof(ObjFNpcFlags)))
80 | {
81 | if (!Enum.GetName(typeof(ObjFNpcFlags), npcFlag).Equals(trimmedFlag)) continue;
82 | //ConsoleExtensions.Log($"Recognized ObjFNpcFlags param:|{trimmedFlag}|", "success");
83 | flag = npcFlag;
84 | }
85 |
86 | return flag;
87 | }
88 |
89 | private static ObjFBlitFlag ParseObjFBlitFlag(string paramValue)
90 | {
91 | var flag = (ObjFBlitFlag)0;
92 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
93 |
94 | if (!((IList)Enum.GetNames(typeof(ObjFBlitFlag))).Contains(trimmedFlag))
95 | ConsoleExtensions.Log($"Unrecognized ObjFBlitFlag param:|{trimmedFlag}|", "warn");
96 |
97 | foreach (ObjFBlitFlag blitFlags in (ObjFBlitFlag[])Enum.GetValues(typeof(ObjFBlitFlag)))
98 | {
99 | if (!Enum.GetName(typeof(ObjFBlitFlag), blitFlags).Equals(trimmedFlag)) continue;
100 | //ConsoleExtensions.Log($"Recognized ObjFBlitFlag param:|{trimmedFlag}|", "success");
101 | flag = blitFlags;
102 | }
103 |
104 | return flag;
105 | }
106 |
107 | private static ObjFSpellFlags ParseObjFSpellFlags(string paramValue)
108 | {
109 | var flag = (ObjFSpellFlags)0;
110 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
111 |
112 | if (!((IList)Enum.GetNames(typeof(ObjFSpellFlags))).Contains(trimmedFlag))
113 | ConsoleExtensions.Log($"Unrecognized ObjFSpellFlags param:|{trimmedFlag}|", "warn");
114 |
115 | foreach (ObjFSpellFlags spellFlags in (ObjFSpellFlags[])Enum.GetValues(typeof(ObjFSpellFlags)))
116 | {
117 | if (!Enum.GetName(typeof(ObjFSpellFlags), spellFlags).Equals(trimmedFlag)) continue;
118 | //ConsoleExtensions.Log($"Recognized ObjFSpellFlags param:|{trimmedFlag}|", "success");
119 | flag = spellFlags;
120 | }
121 |
122 | return flag;
123 | }
124 |
125 | private static Tuple GetBasicStat(string paramValue)
126 | {
127 | Tuple basicStatTuple = null;
128 | string trimmedStats = paramValue.TrimStart();
129 | string[] statAndValue = trimmedStats.Split(" ", 2);
130 | string statType = statAndValue[0].Trim();
131 |
132 | if (!((IList)Enum.GetNames(typeof(BasicStatType))).Contains(statType))
133 | ConsoleExtensions.Log($"unrecognized Entity.BasicStatType param:|{statType}|", "warn");
134 |
135 | string statValue = statAndValue[1].Trim();
136 | //ConsoleExtensions.Log($"statType:|{statType}| value:|{statValue}|", "warn");
137 |
138 | foreach (BasicStatType basicStatType in (BasicStatType[])Enum.GetValues(typeof(BasicStatType)))
139 | {
140 | string enumValueName = Enum.GetName(typeof(BasicStatType), basicStatType);
141 | if (!enumValueName.Equals(statType))
142 | //ConsoleExtensions.Log($"Failed to match enumValueName:|{enumValueName}| vs statType:|{statType}|", "warn");
143 | continue;
144 |
145 | basicStatTuple = new Tuple(basicStatType, int.Parse(statValue));
146 | }
147 |
148 | return basicStatTuple;
149 | }
150 |
151 | private static Tuple GetResistTuple(string paramName, string paramValue)
152 | {
153 | string trimmedResist = paramName.TrimStart();
154 | string[] resist = trimmedResist.Split(" ", 2);
155 | string resistTypeStr = resist[0];
156 | var resistanceTypes = (ResistanceType[])Enum.GetValues(typeof(ResistanceType));
157 |
158 | return (from resistType in resistanceTypes
159 | let resistTypeName = Enum.GetName(typeof(ResistanceType), resistType)
160 | where resistTypeName.Equals(resistTypeStr)
161 | select new Tuple(resistType, int.Parse(paramValue)))
162 | .FirstOrDefault();
163 | }
164 |
165 | private static Tuple GetDmgTuple(string paramName, string paramValue)
166 | {
167 | string trimmedDmg = paramValue.TrimStart();
168 | string[] dmgRange = trimmedDmg.Split(" ", 2);
169 | var min = int.Parse(dmgRange[0]);
170 | var max = int.Parse(dmgRange[1]);
171 |
172 | return paramName switch
173 | {
174 | "Normal Damage" => new Tuple(DamageType.Normal, min, max),
175 | "Fatigue Damage" => new Tuple(DamageType.Fatigue, min, max),
176 | "Poison Damage" => new Tuple(DamageType.Poison, min, max),
177 | "Electrical Damage" => new Tuple(DamageType.Electrical, min, max),
178 | "Fire Damage" => new Tuple(DamageType.Fire, min, max),
179 | _ => null
180 | };
181 | }
182 |
183 | public static NPC GetFromText(IEnumerable npcText)
184 | {
185 | var npc = new NPC
186 | {
187 | ObjectFlags = new List(),
188 | CritterFlags = new List(),
189 | CritterFlags2 = new List(),
190 | NpcFlags = new List(),
191 | BlitFlags = new List(),
192 | SpellFlags = new List(),
193 | BasicStats = new List>(),
194 | Spells = new List(),
195 | Scripts = new List>(),
196 | Resistances = new List>(),
197 | Damages = new List>()
198 | };
199 |
200 | foreach (string curLine in npcText)
201 | {
202 | if (string.IsNullOrWhiteSpace(curLine)) continue;
203 |
204 | string[] lines = curLine.Split(":", 2);
205 | string paramName = lines[0];
206 | string paramValue = lines[1];
207 |
208 | try
209 | {
210 | switch (paramName)
211 | {
212 | case "Description" when paramValue.Contains("//"):
213 | {
214 | string[] idAndName = paramValue.Split("//", 2);
215 | string monsterId = idAndName[0];
216 | string monsterName = idAndName[1];
217 |
218 | npc.Description = new Tuple(int.Parse(monsterId), monsterName);
219 | break;
220 | }
221 | case "Description":
222 | break;
223 | case "Internal Name" or "internal name":
224 | npc.InternalName = int.Parse(paramValue);
225 | break;
226 | case "Level":
227 | npc.Level = int.Parse(paramValue);
228 | break;
229 | case "Art Number and Palette":
230 | string trimmed = paramValue.TrimStart();
231 | string[] artNumberAndPalette = trimmed.Split(" ", 2);
232 | string artNumber = artNumberAndPalette[0];
233 | string paletteNumber = artNumberAndPalette[1];
234 |
235 | npc.ArtNumberAndPalette = new Tuple(int.Parse(artNumber), int.Parse(paletteNumber));
236 | break;
237 | case "Scale":
238 | npc.Scale = int.Parse(paramValue);
239 | break;
240 | case "Alignment":
241 | npc.Alignment = int.Parse(paramValue);
242 | break;
243 | case "Object Flag":
244 | npc.ObjectFlags.Add(ParseObjFFlags(paramValue));
245 | break;
246 | case "Critter Flag":
247 | npc.CritterFlags.Add(ParseObjFCritterFlags(paramValue));
248 | break;
249 | case "Critter2 Flag":
250 | npc.CritterFlags2.Add(ParseObjFCritterFlags2(paramValue));
251 | break;
252 | case "NPC Flag":
253 | npc.NpcFlags.Add(ParseObjFNpcFlags(paramValue));
254 | break;
255 | case "Blit Flag":
256 | npc.BlitFlags.Add(ParseObjFBlitFlag(paramValue));
257 | break;
258 | case "Spell Flag":
259 | npc.SpellFlags.Add(ParseObjFSpellFlags(paramValue));
260 | break;
261 | case "Hit Chart":
262 | npc.HitChart = int.Parse(paramValue);
263 | break;
264 | case "Basic Stat" or "basic stat":
265 | npc.BasicStats.Add(GetBasicStat(paramValue));
266 | break;
267 | case "Spell" or "spell":
268 | npc.Spells.Add(paramValue);
269 | break;
270 | case "Script":
271 | string trimmedScript = paramValue.TrimStart();
272 | string[] scriptParams = trimmedScript.Split(" ", 6);
273 | var paramValues = scriptParams.Select(int.Parse).ToList();
274 |
275 | npc.Scripts.Add(new Tuple(paramValues[0], paramValues[1], paramValues[2], paramValues[3], paramValues[4], paramValues[5]));
276 | break;
277 | case "Faction":
278 | npc.Faction = int.Parse(paramValue);
279 | break;
280 | case "AI Packet":
281 | if (paramValue.Contains("//"))
282 | paramValue = paramValue.Split("//")[0].Trim();
283 |
284 | npc.AIPacket = int.Parse(paramValue);
285 | break;
286 | case "Material":
287 | if (paramValue.Contains("//"))
288 | paramValue = paramValue.Split("//")[0].Trim();
289 |
290 | npc.Material = int.Parse(paramValue);
291 | break;
292 | case "Hit Points":
293 | npc.HitPoints = int.Parse(paramValue);
294 | break;
295 | case "Fatigue":
296 | npc.Fatigue = int.Parse(paramValue);
297 | break;
298 | case "Damage Resistance" or "damage resistance":
299 | npc.Resistances.Add(GetResistTuple(paramName, paramValue));
300 | break;
301 | case "Fire Resistance":
302 | npc.Resistances.Add(GetResistTuple(paramName, paramValue));
303 | break;
304 | case "Electrical Resistance":
305 | npc.Resistances.Add(GetResistTuple(paramName, paramValue));
306 | break;
307 | case "Poison Resistance":
308 | npc.Resistances.Add(GetResistTuple(paramName, paramValue));
309 | break;
310 | case "Magic Resistance":
311 | npc.Resistances.Add(GetResistTuple(paramName, paramValue));
312 | break;
313 | case "Normal Damage":
314 | npc.Damages.Add(GetDmgTuple(paramName, paramValue));
315 | break;
316 | case "Fatigue Damage":
317 | npc.Damages.Add(GetDmgTuple(paramName, paramValue));
318 | break;
319 | case "Poison Damage":
320 | npc.Damages.Add(GetDmgTuple(paramName, paramValue));
321 | break;
322 | case "Electrical Damage":
323 | npc.Damages.Add(GetDmgTuple(paramName, paramValue));
324 | break;
325 | case "Fire Damage":
326 | npc.Damages.Add(GetDmgTuple(paramName, paramValue));
327 | break;
328 | case "Sound Bank" or "sound bank":
329 | npc.SoundBank = int.Parse(paramValue);
330 | break;
331 | case "Portrait":
332 | npc.Portrait = int.Parse(paramValue);
333 | break;
334 | case "Retail Price Multiplier":
335 | npc.RetailPriceMultiplier = int.Parse(paramValue);
336 | break;
337 | case "Social Class":
338 | npc.SocialClass = int.Parse(paramValue);
339 | break;
340 | case "Category":
341 | npc.Category = int.Parse(paramValue);
342 | break;
343 | case "Auto Level Scheme":
344 | npc.AutoLevelScheme = int.Parse(paramValue);
345 | break;
346 | case "Inventory Source":
347 | npc.InventorySource = int.Parse(paramValue);
348 | break;
349 |
350 | default:
351 | ConsoleExtensions.Log($"unrecognized entity param:|{paramName}|", "error");
352 | break;
353 | }
354 | }
355 | catch (Exception ex)
356 | {
357 | AnsiConsole.WriteException(ex);
358 | throw;
359 | }
360 | }
361 |
362 | return npc;
363 | }
364 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/QuestXpLevels.cs:
--------------------------------------------------------------------------------
1 | using Spectre.Console;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace ArcNET.DataTypes.GameObjects.Classes;
6 |
7 | public class QuestXpLevels
8 | {
9 | public static QuestXpLevels LoadedXpQuestLevels = new();
10 |
11 | public class QuestXpLevelEntry
12 | {
13 | public int Level;
14 | public int Experience;
15 |
16 | public QuestXpLevelEntry(int level, int experience)
17 | {
18 | Level = level;
19 | Experience = experience;
20 | }
21 | }
22 |
23 | public List Entries = new();
24 |
25 | public static void InitFromText(IEnumerable textData)
26 | {
27 | try
28 | {
29 | foreach (string line in textData)
30 | {
31 | string[] levelAndXp = line.Split("}", 2);
32 | levelAndXp[0] = levelAndXp[0].Replace("{", "");
33 | var level = int.Parse(levelAndXp[0]);
34 | levelAndXp[1] = levelAndXp[1].Replace("{", "");
35 | levelAndXp[1] = levelAndXp[1].Replace("}", "");
36 | levelAndXp[1] = levelAndXp[1].TrimEnd();
37 | var xp = int.Parse(levelAndXp[1]);
38 |
39 | LoadedXpQuestLevels.Entries.Add(new QuestXpLevelEntry(level, xp));
40 | }
41 | }
42 | catch (Exception ex)
43 | {
44 | AnsiConsole.WriteException(ex);
45 | throw;
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/RandomEncounters.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ArcNET.DataTypes.GameObjects.Classes;
4 |
5 | public class RandomEncounters
6 | {
7 | public static List LoadedEncounters;
8 |
9 | public class EncounterEntry
10 | {
11 | public int PrototypeId;
12 | public int CountMin;
13 | public int CountMax;
14 | public int MinLevel;
15 | public int MaxLevel;
16 | public int GlobalFlag;
17 | }
18 |
19 | public int Id;
20 | public int ChancePercentage;
21 | public List EncounterEntries;
22 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/Unique.cs:
--------------------------------------------------------------------------------
1 | using ArcNET.DataTypes.GameObjects.Flags;
2 | using Spectre.Console;
3 | using System;
4 | using System.Collections;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using Utils.Console;
8 | using Utils.Enumeration;
9 |
10 | namespace ArcNET.DataTypes.GameObjects.Classes;
11 |
12 | public class Unique : Entity
13 | {
14 | private static List GetWhitespaceIndexes(string input)
15 | {
16 | var whiteSpaceIndexes = new List();
17 | char[] stringAsChars = input.ToCharArray();
18 |
19 | foreach ((char item, int index) in stringAsChars.WithIndex())
20 | if (char.IsWhiteSpace(item))
21 | whiteSpaceIndexes.Add(index);
22 |
23 | return whiteSpaceIndexes;
24 | }
25 |
26 | private static ObjFFlags ParseObjFFlags(string paramValue)
27 | {
28 | var flag = (ObjFFlags)0;
29 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
30 |
31 | if (!((IList)Enum.GetNames(typeof(ObjFFlags))).Contains(trimmedFlag))
32 | ConsoleExtensions.Log($"Unrecognized ObjFFlags param:|{trimmedFlag}|", "warn");
33 |
34 | foreach (ObjFFlags objFlag in (ObjFFlags[])Enum.GetValues(typeof(ObjFFlags)))
35 | {
36 | if (!Enum.GetName(typeof(ObjFFlags), objFlag).Equals(trimmedFlag)) continue;
37 | //ConsoleExtensions.Log($"Recognized ObjFFlags param:|{trimmedFlag}|", "success");
38 | flag = objFlag;
39 | }
40 |
41 | return flag;
42 | }
43 |
44 | private static ObjFCritterFlags ParseObjFCritterFlags(string paramValue)
45 | {
46 | var flag = (ObjFCritterFlags)0;
47 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
48 |
49 | if (!((IList)Enum.GetNames(typeof(ObjFCritterFlags))).Contains(trimmedFlag))
50 | ConsoleExtensions.Log($"Unrecognized ObjFCritterFlags param:|{trimmedFlag}|", "warn");
51 |
52 | foreach (ObjFCritterFlags critterFlag in (ObjFCritterFlags[])Enum.GetValues(typeof(ObjFCritterFlags)))
53 | {
54 | if (!Enum.GetName(typeof(ObjFCritterFlags), critterFlag).Equals(trimmedFlag)) continue;
55 | //ConsoleExtensions.Log($"Recognized ObjFCritterFlags param:|{trimmedFlag}|", "success");
56 | flag = critterFlag;
57 | }
58 |
59 | return flag;
60 | }
61 |
62 | private static ObjFCritterFlags2 ParseObjFCritterFlags2(string paramValue)
63 | {
64 | var flag = (ObjFCritterFlags2)0;
65 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
66 |
67 | if (!((IList)Enum.GetNames(typeof(ObjFCritterFlags2))).Contains(trimmedFlag))
68 | ConsoleExtensions.Log($"Unrecognized ObjFCritterFlags2 param:|{trimmedFlag}|", "warn");
69 |
70 | foreach (ObjFCritterFlags2 critterFlag2 in (ObjFCritterFlags2[])Enum.GetValues(typeof(ObjFCritterFlags2)))
71 | {
72 | if (!Enum.GetName(typeof(ObjFCritterFlags2), critterFlag2).Equals(trimmedFlag)) continue;
73 | //ConsoleExtensions.Log($"Recognized ObjFCritterFlags2 param:|{trimmedFlag}|", "success");
74 | flag = critterFlag2;
75 | }
76 |
77 | return flag;
78 | }
79 |
80 | private static ObjFNpcFlags ParseObjFNpcFlags(string paramValue)
81 | {
82 | var flag = (ObjFNpcFlags)0;
83 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
84 |
85 | if (!((IList)Enum.GetNames(typeof(ObjFNpcFlags))).Contains(trimmedFlag))
86 | ConsoleExtensions.Log($"Unrecognized ObjFNpcFlags param:|{trimmedFlag}|", "warn");
87 |
88 | foreach (ObjFNpcFlags npcFlag in (ObjFNpcFlags[])Enum.GetValues(typeof(ObjFNpcFlags)))
89 | {
90 | if (!Enum.GetName(typeof(ObjFNpcFlags), npcFlag).Equals(trimmedFlag)) continue;
91 | //ConsoleExtensions.Log($"Recognized ObjFNpcFlags param:|{trimmedFlag}|", "success");
92 | flag = npcFlag;
93 | }
94 |
95 | return flag;
96 | }
97 |
98 | private static ObjFBlitFlag ParseObjFBlitFlag(string paramValue)
99 | {
100 | var flag = (ObjFBlitFlag)0;
101 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
102 |
103 | if (!((IList)Enum.GetNames(typeof(ObjFBlitFlag))).Contains(trimmedFlag))
104 | ConsoleExtensions.Log($"Unrecognized ObjFBlitFlag param:|{trimmedFlag}|", "warn");
105 |
106 | foreach (ObjFBlitFlag blitFlags in (ObjFBlitFlag[])Enum.GetValues(typeof(ObjFBlitFlag)))
107 | {
108 | if (!Enum.GetName(typeof(ObjFBlitFlag), blitFlags).Equals(trimmedFlag)) continue;
109 | //ConsoleExtensions.Log($"Recognized ObjFBlitFlag param:|{trimmedFlag}|", "success");
110 | flag = blitFlags;
111 | }
112 |
113 | return flag;
114 | }
115 |
116 | private static ObjFSpellFlags ParseObjFSpellFlags(string paramValue)
117 | {
118 | var flag = (ObjFSpellFlags)0;
119 | string trimmedFlag = paramValue.TrimStart().TrimEnd();
120 |
121 | if (!((IList)Enum.GetNames(typeof(ObjFSpellFlags))).Contains(trimmedFlag))
122 | ConsoleExtensions.Log($"Unrecognized ObjFSpellFlags param:|{trimmedFlag}|", "warn");
123 |
124 | foreach (ObjFSpellFlags spellFlags in (ObjFSpellFlags[])Enum.GetValues(typeof(ObjFSpellFlags)))
125 | {
126 | if (!Enum.GetName(typeof(ObjFSpellFlags), spellFlags).Equals(trimmedFlag)) continue;
127 | //ConsoleExtensions.Log($"Recognized ObjFSpellFlags param:|{trimmedFlag}|", "success");
128 | flag = spellFlags;
129 | }
130 |
131 | return flag;
132 | }
133 |
134 | private static Tuple GetBasicStat(string paramValue)
135 | {
136 | Tuple basicStatTuple = null;
137 | string trimmedStats = paramValue.TrimStart();
138 |
139 | //skip junk
140 | if (trimmedStats.Equals("Strength 13") || trimmedStats.Equals("Dexterity 15") ||
141 | trimmedStats.Equals("Dexterity 14")) return null;
142 |
143 | var separator = "\t\t";
144 | if (trimmedStats.Contains("Gender") || trimmedStats.Contains("Race"))
145 | separator = " ";
146 | if (trimmedStats.Contains("tech points") || trimmedStats.Contains("magick points"))
147 | {
148 | List whitespaceIndexes = GetWhitespaceIndexes(trimmedStats);
149 | if (whitespaceIndexes.Count >= 2)
150 | trimmedStats = trimmedStats.Remove(whitespaceIndexes.First(), 1);
151 | //ConsoleExtensions.Log($"trimmedStats after removal:|{trimmedStats}|", "warn");
152 | separator = " ";
153 | }
154 |
155 | if (trimmedStats.Contains("Constitution") || trimmedStats.Contains("Intelligence"))
156 | separator = "\t";
157 |
158 | string[] statAndValue = trimmedStats.Split(separator, 2);
159 | string statType = statAndValue[0].Trim();
160 | statType = statType switch
161 | {
162 | "magickpoints" => "MagickPoints",
163 | "techpoints" => "TechPoints",
164 | _ => statType
165 | };
166 |
167 | if (!((IList)Enum.GetNames(typeof(BasicStatType))).Contains(statType))
168 | ConsoleExtensions.Log($"unrecognized Entity.BasicStatType param:|{statType}|", "warn");
169 |
170 | string statValue = statAndValue[1].Trim();
171 | //ConsoleExtensions.Log($"statType:|{statType}| value:|{statValue}|", "warn");
172 |
173 | foreach (BasicStatType basicStatType in (BasicStatType[])Enum.GetValues(typeof(BasicStatType)))
174 | {
175 | string enumValueName = Enum.GetName(typeof(BasicStatType), basicStatType);
176 | if (!enumValueName.Equals(statType))
177 | //ConsoleExtensions.Log($"Failed to match enumValueName:|{enumValueName}| vs statType:|{statType}|", "warn");
178 | continue;
179 |
180 | basicStatTuple = new Tuple(basicStatType, int.Parse(statValue));
181 | }
182 |
183 | return basicStatTuple;
184 | }
185 |
186 | private static Tuple GetResistTuple(string paramName, string paramValue)
187 | {
188 | if (paramValue.Equals("1 0")) paramValue = " 10";
189 | //ConsoleExtensions.Log($"paramName:|{paramName}| paramValue:|{paramValue}|", "warn");
190 |
191 |
192 | string trimmedResist = paramName.TrimStart();
193 | string[] resist = trimmedResist.Split(" ", 2);
194 | string resistTypeStr = resist[0];
195 | var resistanceTypes = (ResistanceType[])Enum.GetValues(typeof(ResistanceType));
196 |
197 | return (from resistType in resistanceTypes
198 | let resistTypeName = Enum.GetName(typeof(ResistanceType), resistType)
199 | where resistTypeName.Equals(resistTypeStr)
200 | select new Tuple(resistType, int.Parse(paramValue)))
201 | .FirstOrDefault();
202 | }
203 |
204 | private static Tuple GetDmgTuple(string paramName, string paramValue)
205 | {
206 | string trimmedDmg = paramValue.TrimStart();
207 | string[] dmgRange = trimmedDmg.Split(" ", 2);
208 | var min = int.Parse(dmgRange[0]);
209 | var max = int.Parse(dmgRange[1]);
210 |
211 | return paramName switch
212 | {
213 | "Normal Damage" => new Tuple(DamageType.Normal, min, max),
214 | "Fatigue Damage" => new Tuple(DamageType.Fatigue, min, max),
215 | "Poison Damage" => new Tuple(DamageType.Poison, min, max),
216 | "Electrical Damage" => new Tuple(DamageType.Electrical, min, max),
217 | "Fire Damage" => new Tuple(DamageType.Fire, min, max),
218 | _ => null
219 | };
220 | }
221 |
222 | public static Unique GetFromText(IEnumerable uniqueText)
223 | {
224 | var unique = new Unique
225 | {
226 | ObjectFlags = new List(),
227 | CritterFlags = new List(),
228 | CritterFlags2 = new List(),
229 | NpcFlags = new List(),
230 | BlitFlags = new List(),
231 | SpellFlags = new List(),
232 | BasicStats = new List>(),
233 | Spells = new List(),
234 | Scripts = new List>(),
235 | Resistances = new List>(),
236 | Damages = new List>()
237 | };
238 |
239 | foreach (string curLine in uniqueText)
240 | {
241 | if (string.IsNullOrWhiteSpace(curLine)) continue;
242 |
243 | string[] lines = curLine.Split(":", 2);
244 | string paramName = lines[0];
245 | string paramValue = lines[1];
246 |
247 | try
248 | {
249 | switch (paramName)
250 | {
251 | case "Description" when paramValue.Contains("//"):
252 | {
253 | string[] idAndName = paramValue.Split("//", 2);
254 | string monsterId = idAndName[0];
255 | string monsterName = idAndName[1];
256 |
257 | unique.Description = new Tuple(int.Parse(monsterId), monsterName);
258 | break;
259 | }
260 | case "Description":
261 | break;
262 | case "Internal Name" or "internal name":
263 | unique.InternalName = int.Parse(paramValue);
264 | break;
265 | case "Level":
266 | unique.Level = int.Parse(paramValue);
267 | break;
268 | case "Art Number and Palette":
269 | string trimmed = paramValue.TrimStart();
270 | string[] artNumberAndPalette = trimmed.Split(" ", 2);
271 | string artNumber = artNumberAndPalette[0];
272 | string paletteNumber = artNumberAndPalette[1];
273 |
274 | unique.ArtNumberAndPalette = new Tuple(int.Parse(artNumber), int.Parse(paletteNumber));
275 | break;
276 | case "Scale":
277 | unique.Scale = int.Parse(paramValue);
278 | break;
279 | case "Alignment":
280 | unique.Alignment = int.Parse(paramValue);
281 | break;
282 | case "Object Flag":
283 | unique.ObjectFlags.Add(ParseObjFFlags(paramValue));
284 | break;
285 | case "Critter Flag":
286 | unique.CritterFlags.Add(ParseObjFCritterFlags(paramValue));
287 | break;
288 | case "Critter2 Flag":
289 | unique.CritterFlags2.Add(ParseObjFCritterFlags2(paramValue));
290 | break;
291 | case "NPC Flag":
292 | unique.NpcFlags.Add(ParseObjFNpcFlags(paramValue));
293 | break;
294 | case "Blit Flag":
295 | unique.BlitFlags.Add(ParseObjFBlitFlag(paramValue));
296 | break;
297 | case "Spell Flag":
298 | unique.SpellFlags.Add(ParseObjFSpellFlags(paramValue));
299 | break;
300 | case "Hit Chart":
301 | unique.HitChart = int.Parse(paramValue);
302 | break;
303 | case "Basic Stat" or "basic stat":
304 | unique.BasicStats.Add(GetBasicStat(paramValue));
305 | break;
306 | case "Spell" or "spell":
307 | unique.Spells.Add(paramValue);
308 | break;
309 | case "Script":
310 | string trimmedScript = paramValue.TrimStart();
311 | string[] scriptParams = trimmedScript.Split(" ", 6);
312 | var paramValues = scriptParams.Select(int.Parse).ToList();
313 |
314 | unique.Scripts.Add(new Tuple(paramValues[0], paramValues[1], paramValues[2], paramValues[3], paramValues[4], paramValues[5]));
315 | break;
316 | case "Faction":
317 | unique.Faction = int.Parse(paramValue);
318 | break;
319 | case "AI Packet":
320 | if (paramValue.Contains("//"))
321 | paramValue = paramValue.Split("//")[0].Trim();
322 |
323 | unique.AIPacket = int.Parse(paramValue);
324 | break;
325 | case "Material":
326 | if (paramValue.Contains("//"))
327 | paramValue = paramValue.Split("//")[0].Trim();
328 |
329 | unique.Material = int.Parse(paramValue);
330 | break;
331 | case "Hit Points":
332 | unique.HitPoints = int.Parse(paramValue);
333 | break;
334 | case "Fatigue":
335 | unique.Fatigue = int.Parse(paramValue);
336 | break;
337 | case "Damage Resistance" or "damage resistance":
338 | unique.Resistances.Add(GetResistTuple(paramName, paramValue));
339 | break;
340 | case "Fire Resistance":
341 | unique.Resistances.Add(GetResistTuple(paramName, paramValue));
342 | break;
343 | case "Electrical Resistance":
344 | unique.Resistances.Add(GetResistTuple(paramName, paramValue));
345 | break;
346 | case "Poison Resistance":
347 | unique.Resistances.Add(GetResistTuple(paramName, paramValue));
348 | break;
349 | case "Magic Resistance":
350 | unique.Resistances.Add(GetResistTuple(paramName, paramValue));
351 | break;
352 | case "Normal Damage":
353 | unique.Damages.Add(GetDmgTuple(paramName, paramValue));
354 | break;
355 | case "Fatigue Damage":
356 | unique.Damages.Add(GetDmgTuple(paramName, paramValue));
357 | break;
358 | case "Poison Damage":
359 | unique.Damages.Add(GetDmgTuple(paramName, paramValue));
360 | break;
361 | case "Electrical Damage":
362 | unique.Damages.Add(GetDmgTuple(paramName, paramValue));
363 | break;
364 | case "Fire Damage":
365 | unique.Damages.Add(GetDmgTuple(paramName, paramValue));
366 | break;
367 | case "Sound Bank" or "sound bank":
368 | unique.SoundBank = int.Parse(paramValue);
369 | break;
370 | case "Category":
371 | unique.Category = int.Parse(paramValue);
372 | break;
373 | case "Auto Level Scheme":
374 | unique.AutoLevelScheme = int.Parse(paramValue);
375 | break;
376 | case "Inventory Source":
377 | unique.InventorySource = int.Parse(paramValue);
378 | break;
379 |
380 | default:
381 | ConsoleExtensions.Log($"unrecognized entity param:|{paramName}|", "error");
382 | break;
383 | }
384 | }
385 | catch (Exception ex)
386 | {
387 | AnsiConsole.WriteException(ex);
388 | throw;
389 | }
390 | }
391 |
392 | return unique;
393 | }
394 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/WorldMapEncounterInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace ArcNET.DataTypes.GameObjects.Classes;
4 |
5 | public class WorldMapEncounterInfo
6 | {
7 | public List LoadedWorldMapEncounters;
8 |
9 | public class WorldMapEncounterInfoEntry
10 | {
11 | public int WorldWidth;
12 | public int WorldHeight;
13 | public int TriggerRadius;
14 | public int OccurrenceChance;
15 | }
16 |
17 | public int Id;
18 | public List Entries;
19 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Classes/XpLevels.cs:
--------------------------------------------------------------------------------
1 | using Spectre.Console;
2 | using System;
3 | using System.Collections.Generic;
4 |
5 | namespace ArcNET.DataTypes.GameObjects.Classes;
6 |
7 | public class XpLevels
8 | {
9 | public static XpLevels LoadedXpLevels = new();
10 |
11 | public class LevelXpEntry
12 | {
13 | public int Level;
14 | public int Experience;
15 |
16 | public LevelXpEntry(int level, int experience)
17 | {
18 | Level = level;
19 | Experience = experience;
20 | }
21 | }
22 |
23 | public List Entries = new();
24 |
25 | public static void InitFromText(IEnumerable textData)
26 | {
27 | try
28 | {
29 | foreach (string line in textData)
30 | {
31 | string[] levelAndXp = line.Split("}", 2);
32 | levelAndXp[0] = levelAndXp[0].Replace("{", "");
33 | var level = int.Parse(levelAndXp[0]);
34 | levelAndXp[1] = levelAndXp[1].Replace("{", "");
35 | levelAndXp[1] = levelAndXp[1].Replace("}", "");
36 | levelAndXp[1] = levelAndXp[1].TrimEnd();
37 | var xp = int.Parse(levelAndXp[1]);
38 |
39 | LoadedXpLevels.Entries.Add(new LevelXpEntry(level, xp));
40 | }
41 | }
42 | catch (Exception ex)
43 | {
44 | AnsiConsole.WriteException(ex);
45 | throw;
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Enums.cs:
--------------------------------------------------------------------------------
1 | namespace ArcNET.DataTypes.GameObjects;
2 |
3 | public static class Enums
4 | {
5 | public enum ObjectFieldBitmap
6 | {
7 | Wall = 12,
8 | Portal = 12,
9 | Container = 12,
10 | Scenery = 12,
11 | Projectile = 12,
12 | Trap = 12,
13 | Weapon = 16,
14 | Ammo = 16,
15 | Armor = 16,
16 | Gold = 16,
17 | Food = 16,
18 | Scroll = 16,
19 | Key = 16,
20 | KeyRing = 16,
21 | Written = 16,
22 | Generic = 16,
23 | Pc = 20,
24 | Npc = 20,
25 | }
26 |
27 | public enum ObjectType
28 | {
29 | Wall = 0,
30 | Portal,
31 | Container,
32 | Scenery,
33 | Projectile,
34 | Weapon,
35 | Ammo,
36 | Armor,
37 | Gold,
38 | Food,
39 | Scroll,
40 | Key,
41 | KeyRing,
42 | Written,
43 | Generic,
44 | Pc,
45 | Npc,
46 | Trap
47 | }
48 |
49 | public enum ObjectField
50 | {
51 | ObjFCurrentAid = 0,
52 | ObjFLocation = 1,
53 | ObjFOffsetX = 2,
54 | ObjFOffsetY = 3,
55 | ObjFShadow = 4,
56 | ObjFOverlayFore = 5,
57 | ObjFOverlayBack = 6,
58 | ObjFUnderlay = 7,
59 | ObjFBlitFlags = 8,
60 | ObjFBlitColor = 9,
61 | ObjFBlitAlpha = 10,
62 | ObjFBlitScale = 11,
63 | ObjFLightFlags = 12,
64 | ObjFLightAid = 13,
65 | ObjFLightColor = 14,
66 | ObjFOverlayLightFlags = 15,
67 | ObjFOverlayLightAid = 16,
68 | ObjFOverlayLightColor = 17,
69 | ObjFFlags = 18,
70 | ObjFSpellFlags = 19,
71 | ObjFBlockingMask = 20,
72 | ObjFName = 21,
73 | ObjFDescription = 22,
74 | ObjFAid = 23,
75 | ObjFDestroyedAid = 24,
76 | ObjFAc = 25,
77 | ObjFHpPts = 26,
78 | ObjFHpAdj = 27,
79 | ObjFHpDamage = 28,
80 | ObjFMaterial = 29,
81 | ObjFResistanceIdx = 30,
82 | ObjFScriptsIdx = 31,
83 | ObjFSoundEffect = 32,
84 | ObjFCategory = 33,
85 | ObjFPadIas1 = 34,
86 | ObjFPadI64As1 = 35,
87 | ObjFWallFlags = 64,
88 | ObjFWallPadI1 = 65,
89 | ObjFWallPadI2 = 66,
90 | ObjFWallPadIas1 = 67,
91 | ObjFWallPadI64As1 = 68,
92 |
93 | ObjFPortalFlags = 64,
94 | ObjFPortalLockDifficulty = 65,
95 | ObjFPortalKeyId = 66,
96 | ObjFPortalNotifyNpc = 67,
97 | ObjFPortalPadI1 = 68,
98 | ObjFPortalPadI2 = 69,
99 | ObjFPortalPadIas1 = 70,
100 | ObjFPortalPadI64As1 = 71,
101 |
102 | ObjFContainerFlags = 64,
103 | ObjFContainerLockDifficulty = 65,
104 | ObjFContainerKeyId = 66,
105 | ObjFContainerInventoryNum = 67,
106 | ObjFContainerInventoryListIdx = 68,
107 | ObjFContainerInventorySource = 69,
108 | ObjFContainerNotifyNpc = 70,
109 | ObjFContainerPadI1 = 71,
110 | ObjFContainerPadI2 = 72,
111 | ObjFContainerPadIas1 = 73,
112 | ObjFContainerPadI64As1 = 74,
113 |
114 | ObjFSceneryFlags = 64,
115 | ObjFSceneryWhosInMe = 65,
116 | ObjFSceneryRespawnDelay = 66,
117 | ObjFSceneryPadI2 = 67,
118 | ObjFSceneryPadIas1 = 68,
119 | ObjFSceneryPadI64As1 = 69,
120 |
121 | ObjFProjectileFlagsCombat = 0,
122 | ObjFProjectileFlagsCombatDamage = 1,
123 | ObjFProjectileHitLoc = 2,
124 | ObjFProjectileParentWeapon = 3,
125 | ObjFProjectilePadI1 = 4,
126 | ObjFProjectilePadI2 = 5,
127 | ObjFProjectilePadIas1 = 6,
128 | ObjFProjectilePadI64As1 = 7,
129 |
130 | ObjFItemFlags = 64,
131 | ObjFItemParent = 65,
132 | ObjFItemWeight = 66,
133 | ObjFItemMagicWeightAdj = 67,
134 | ObjFItemWorth = 68,
135 | ObjFItemManaStore = 69,
136 | ObjFItemInvAid = 70,
137 | ObjFItemInvLocation = 71,
138 | ObjFItemUseAidFragment = 72,
139 | ObjFItemMagicTechComplexity = 73,
140 | ObjFItemDiscipline = 74,
141 | ObjFItemDescriptionUnknown = 75,
142 | ObjFItemDescriptionEffects = 76,
143 | ObjFItemSpell1 = 77,
144 | ObjFItemSpell2 = 78,
145 | ObjFItemSpell3 = 79,
146 | ObjFItemSpell4 = 80,
147 | ObjFItemSpell5 = 81,
148 | ObjFItemSpellManaStore = 82,
149 | ObjFItemAiAction = 83,
150 | ObjFItemPadI1 = 84,
151 | ObjFItemPadIas1 = 85,
152 | ObjFItemPadI64As1 = 86,
153 |
154 | ObjFWeaponFlags = 96,
155 | ObjFWeaponPaperDollAid = 97,
156 | ObjFWeaponBonusToHit = 98,
157 | ObjFWeaponMagicHitAdj = 99,
158 | ObjFWeaponDamageLowerIdx = 100,
159 | ObjFWeaponDamageUpperIdx = 101,
160 | ObjFWeaponMagicDamageAdjIdx = 102,
161 | ObjFWeaponSpeedFactor = 103,
162 | ObjFWeaponMagicSpeedAdj = 104,
163 | ObjFWeaponRange = 105,
164 | ObjFWeaponMagicRangeAdj = 106,
165 | ObjFWeaponMinStrength = 107,
166 | ObjFWeaponMagicMinStrengthAdj = 108,
167 | ObjFWeaponAmmoType = 109,
168 | ObjFWeaponAmmoConsumption = 110,
169 | ObjFWeaponMissileAid = 111,
170 | ObjFWeaponVisualEffectAid = 112,
171 | ObjFWeaponCritHitChart = 113,
172 | ObjFWeaponMagicCritHitChance = 114,
173 | ObjFWeaponMagicCritHitEffect = 115,
174 | ObjFWeaponCritMissChart = 116,
175 | ObjFWeaponMagicCritMissChance = 117,
176 | ObjFWeaponMagicCritMissEffect = 118,
177 |
178 | ObjFWeaponPadI1 = 119,
179 | ObjFWeaponPadI2 = 120,
180 | ObjFWeaponPadIas1 = 121,
181 | ObjFWeaponPadI64As1 = 122,
182 |
183 | ObjFAmmoFlags = 96,
184 | ObjFAmmoQuantity = 97,
185 | ObjFAmmoType = 98,
186 | ObjFAmmoPadI1 = 99,
187 | ObjFAmmoPadI2 = 100,
188 | ObjFAmmoPadIas1 = 101,
189 | ObjFAmmoPadI64As1 = 102,
190 |
191 | ObjFArmorFlags = 96,
192 | ObjFArmorPaperDollAid = 97,
193 | ObjFArmorAcAdj = 98,
194 | ObjFArmorMagicAcAdj = 99,
195 | ObjFArmorResistanceAdjIdx = 100,
196 | ObjFArmorMagicResistanceAdjIdx = 101,
197 | ObjFArmorSilentMoveAdj = 102,
198 | ObjFArmorMagicSilentMoveAdj = 103,
199 | ObjFArmorUnarmedBonusDamage = 104,
200 | ObjFArmorPadI2 = 105,
201 | ObjFArmorPadIas1 = 106,
202 | ObjFArmorPadI64As1 = 107,
203 |
204 | ObjFGoldFlags = 96,
205 | ObjFGoldQuantity = 97,
206 | ObjFGoldPadI1 = 98,
207 | ObjFGoldPadI2 = 99,
208 | ObjFGoldPadIas1 = 100,
209 | ObjFGoldPadI64As1 = 101,
210 |
211 | ObjFFoodFlags = 96,
212 | ObjFFoodPadI1 = 97,
213 | ObjFFoodPadI2 = 98,
214 | ObjFFoodPadIas1 = 99,
215 | ObjFFoodPadI64As1 = 100,
216 |
217 | ObjFScrollFlags = 96,
218 | ObjFScrollPadI1 = 97,
219 | ObjFScrollPadI2 = 98,
220 | ObjFScrollPadIas1 = 99,
221 | ObjFScrollPadI64As1 = 100,
222 |
223 | ObjFKeyKeyId = 96,
224 | ObjFKeyPadI1 = 97,
225 | ObjFKeyPadI2 = 98,
226 | ObjFKeyPadIas1 = 99,
227 | ObjFKeyPadI64As1 = 100,
228 | ObjFKeyRingFlags = 96,
229 | ObjFKeyRingListIdx = 97,
230 | ObjFKeyRingPadI1 = 98,
231 | ObjFKeyRingPadI2 = 99,
232 | ObjFKeyRingPadIas1 = 100,
233 | ObjFKeyRingPadI64As1 = 101,
234 |
235 | ObjFWrittenFlags = 96,
236 | ObjFWrittenSubtype = 97,
237 | ObjFWrittenTextStartLine = 98,
238 | ObjFWrittenTextEndLine = 99,
239 | ObjFWrittenPadI1 = 100,
240 | ObjFWrittenPadI2 = 101,
241 | ObjFWrittenPadIas1 = 102,
242 | ObjFWrittenPadI64As1 = 103,
243 |
244 | ObjFGenericFlags = 96,
245 | ObjFGenericUsageBonus = 97,
246 | ObjFGenericUsageCountRemaining = 98,
247 | ObjFGenericPadIas1 = 99,
248 | ObjFGenericPadI64As1 = 100,
249 |
250 | ObjFCritterFlags = 64,
251 | ObjFCritterFlags2 = 65,
252 | ObjFCritterStatBaseIdx = 66,
253 | ObjFCritterBasicSkillIdx = 67,
254 | ObjFCritterTechSkillIdx = 68,
255 | ObjFCritterSpellTechIdx = 69,
256 | ObjFCritterFatiguePts = 70,
257 | ObjFCritterFatigueAdj = 71,
258 | ObjFCritterFatigueDamage = 72,
259 | ObjFCritterCritHitChart = 73,
260 | ObjFCritterEffectsIdx = 74,
261 | ObjFCritterEffectCauseIdx = 75,
262 | ObjFCritterFleeingFrom = 76,
263 | ObjFCritterPortrait = 77,
264 | ObjFCritterGold = 78,
265 | ObjFCritterArrows = 79,
266 | ObjFCritterBullets = 80,
267 | ObjFCritterPowerCells = 81,
268 | ObjFCritterFuel = 82,
269 | ObjFCritterInventoryNum = 83,
270 | ObjFCritterInventoryListIdx = 84,
271 | ObjFCritterInventorySource = 85,
272 | ObjFCritterDescriptionUnknown = 86,
273 | ObjFCritterFollowerIdx = 87,
274 | ObjFCritterTeleportDest = 88,
275 | ObjFCritterTeleportMap = 89,
276 | ObjFCritterDeathTime = 90,
277 | ObjFCritterAutoLevelScheme = 91,
278 | ObjFCritterPadI1 = 92,
279 | ObjFCritterPadI2 = 93,
280 | ObjFCritterPadI3 = 94,
281 | ObjFCritterPadIas1 = 95,
282 | ObjFCritterPadI64As1 = 96,
283 |
284 | ObjFPcFlags = 128,
285 | ObjFPcFlagsFate = 129,
286 | ObjFPcReputationIdx = 130,
287 | ObjFPcReputationTsIdx = 131,
288 | ObjFPcBackground = 132,
289 | ObjFPcBackgroundText = 133,
290 | ObjFPcQuestIdx = 134,
291 | ObjFPcBlessingIdx = 134,
292 | ObjFPcBlessingTsIdx = 135,
293 | ObjFPcCurseIdx = 136,
294 | ObjFPcCurseTsIdx = 137,
295 | ObjFPcPartyId = 138,
296 | ObjFPcRumorIdx = 139,
297 | ObjFPcPadIas2 = 140,
298 | ObjFPcSchematicsFoundIdx = 141,
299 | ObjFPcLogbookEgoIdx = 142,
300 | ObjFPcFogMask = 143,
301 | ObjFPcPlayerName = 144,
302 | ObjFPcBankMoney = 145,
303 | ObjFPcGlobalFlags = 146,
304 | ObjFPcGlobalVariables = 147,
305 | ObjFPcPadI1 = 148,
306 | ObjFPcPadI2 = 149,
307 | ObjFPcPadIas1 = 150,
308 | ObjFPcPadI64As1 = 151,
309 | ObjFPcPadI64As2 = 152,
310 |
311 | ObjFNpcFlags = 128,
312 | ObjFNpcLeader = 129,
313 | ObjFNpcAiData = 130,
314 | ObjFNpcCombatFocus = 131,
315 | ObjFNpcWhoHitMeLast = 132,
316 | ObjFNpcExperienceWorth = 133,
317 | ObjFNpcExperiencePool = 134,
318 | ObjFNpcWaypointsIdx = 135,
319 | ObjFNpcWaypointCurrent = 136,
320 | ObjFNpcStandpointDay = 137,
321 | ObjFNpcStandpointNight = 138,
322 | ObjFNpcOrigin = 139,
323 | ObjFNpcFaction = 140,
324 | ObjFNpcRetailPriceMultiplier = 141,
325 | ObjFNpcSubstituteInventory = 142,
326 | ObjFNpcReactionBase = 143,
327 | ObjFNpcSocialClass = 144,
328 | ObjFNpcReactionPcIdx = 145,
329 | ObjFNpcReactionLevelIdx = 146,
330 | ObjFNpcReactionTimeIdx = 147,
331 | ObjFNpcWait = 148,
332 | ObjFNpcGeneratorData = 149,
333 | ObjFNpcPadI1 = 150,
334 | ObjFNpcDamageIdx = 151,
335 | ObjFNpcShitListIdx = 152,
336 |
337 | ObjFTrapFlags = 64,
338 | ObjFTrapDifficulty = 65,
339 | ObjFTrapPadI2 = 66,
340 | ObjFTrapPadIas1 = 67,
341 | ObjFTrapPadI64As1 = 68
342 | }
343 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Flags/ObjFBlitFlag.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ArcNET.DataTypes.GameObjects.Flags;
4 |
5 | [Flags]
6 | public enum ObjFBlitFlag
7 | {
8 | TAB_BLEND_ADD,
9 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Flags/ObjFCritterFlags.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace ArcNET.DataTypes.GameObjects.Flags;
5 |
6 | [Flags]
7 | [SuppressMessage("ReSharper", "InconsistentNaming")]
8 | public enum ObjFCritterFlags
9 | {
10 | OCF_IS_CONCEALED = 1,
11 | OCF_MOVING_SILENTLY,
12 | OCF_UNDEAD,
13 | OCF_ANIMAL,
14 | OCF_FLEEING,
15 | OCF_STUNNED,
16 | OCF_PARALYZED,
17 | OCF_BLINDED,
18 | OCF_CRIPPLED_ARMS_ONE,
19 | OCF_CRIPPLED_ARMS_BOTH,
20 | OCF_CRIPPLED_LEGS_BOTH,
21 | OCF_UNUSED,
22 | OCF_SLEEPING,
23 | OCF_MUTE,
24 | OCF_SURRENDERED,
25 | OCF_MONSTER,
26 | OCF_SPELL_FLEE,
27 | OCF_ENCOUNTER,
28 | OCF_COMBAT_MODE_ACTIVE,
29 | OCF_LIGHT_SMALL,
30 | OCF_LIGHT_MEDIUM,
31 | OCF_LIGHT_LARGE,
32 | OCF_LIGHT_XLARGE,
33 | OCF_UNREVIVIFIABLE,
34 | OCF_UNRESSURECTABLE,
35 | OCF_DEMON,
36 | OCF_FATIGUE_IMMUNE,
37 | OCF_NO_FLEE,
38 | OCF_NON_LETHAL_COMBAT,
39 | OCF_MECHANICAL,
40 | OCF_ANIMAL_ENSHROUD,
41 | OCF_FATIGUE_LIMITING
42 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Flags/ObjFCritterFlags2.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace ArcNET.DataTypes.GameObjects.Flags;
5 |
6 | [Flags]
7 | [SuppressMessage("ReSharper", "InconsistentNaming")]
8 | public enum ObjFCritterFlags2
9 | {
10 | OCF2_ITEM_STOLEN = 1,
11 | OCF2_AUTO_ANIMATES,
12 | OCF2_USING_BOOMERANG,
13 | OCF2_FATIGUE_DRAINING,
14 | OCF2_SLOW_PARTY,
15 | OCF2_COMBAT_TOGGLE_FX,
16 | OCF2_NO_DECAY,
17 | OCF2_NO_PICKPOCKET,
18 | OCF2_NO_BLOOD_SPLOTCHES,
19 | OCF2_NIGH_INVULNERABLE,
20 | OCF2_ELEMENTAL,
21 | OCF2_DARK_SIGHT,
22 | OCF2_NO_SLIP,
23 | OCF2_NO_DISINTEGRATE,
24 | OCF2_REACTION_0,
25 | OCF2_REACTION_1,
26 | OCF2_REACTION_2,
27 | OCF2_REACTION_3,
28 | OCF2_REACTION_4,
29 | OCF2_REACTION_5,
30 | OCF2_REACTION_6,
31 | OCF2_TARGET_LOCK,
32 | OCF2_PERMA_POLYMORPH,
33 | OCF2_SAFE_OFF,
34 | OCF2_CHECK_REACTION_BAD,
35 | OCF2_CHECK_ALIGN_GOOD,
36 | OCF2_CHECK_ALIGN_BAD
37 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Flags/ObjFFlags.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ArcNET.DataTypes.GameObjects.Flags;
4 |
5 | [Flags]
6 | public enum ObjFFlags
7 | {
8 | OF_DESTROYED = 1,
9 | OF_OFF,
10 | OF_FLAT,
11 | OF_TEXT,
12 | OF_SEE_THROUGH,
13 | OF_SHOOT_THROUGH,
14 | OF_TRANSLUCENT,
15 | OF_SHRUNK,
16 | OF_DONTDRAW,
17 | OF_INVISIBLE,
18 | OF_NO_BLOCK,
19 | OF_CLICK_THROUGH,
20 | OF_INVENTORY,
21 | OF_DYNAMIC,
22 | OF_PROVIDES_COVER,
23 | OF_HAS_OVERLAYS,
24 | OF_HAS_UNDERLAYS,
25 | OF_WADING,
26 | OF_WATER_WALKING,
27 | OF_STONED,
28 | OF_DONTLIGHT,
29 | OF_TEXT_FLOATER,
30 | OF_INVULNERABLE,
31 | OF_EXTINCT,
32 | OF_TRAP_PC,
33 | OF_TRAP_SPOTTED,
34 | OF_DISALLOW_WADING,
35 | OF_MULTIPLAYER_LOCK,
36 | OF_FROZEN,
37 | OF_ANIMATED_DEAD,
38 | OF_TELEPORTED
39 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Flags/ObjFNpcFlags.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace ArcNET.DataTypes.GameObjects.Flags;
5 |
6 | [Flags]
7 | [SuppressMessage("ReSharper", "InconsistentNaming")]
8 | public enum ObjFNpcFlags
9 | {
10 | ONF_FIGHTING = 1,
11 | ONF_WAYPOINTS_DAY,
12 | ONF_WAYPOINTS_NIGHT,
13 | ONF_AI_WAIT_HERE,
14 | ONF_AI_SPREAD_OUT,
15 | ONF_JILTED,
16 | ONF_CHECK_WIELD,
17 | ONF_CHECK_WEAPON,
18 | ONF_KOS,
19 | ONF_WAYPOINTS_BED,
20 | ONF_FORCED_FOLLOWER,
21 | ONF_KOS_OVERRIDE,
22 | ONF_WANDERS,
23 | ONF_WANDERS_IN_DARK,
24 | ONF_FENCE,
25 | ONF_FAMILIAR,
26 | ONF_CHECK_LEADER,
27 | ONF_ALOOF,
28 | ONF_CAST_HIGHEST,
29 | ONF_GENERATOR,
30 | ONF_GENERATED,
31 | ONF_GENERATOR_RATE1,
32 | ONF_GENERATOR_RATE2,
33 | ONF_GENERATOR_RATE3,
34 | ONF_DEMAINTAIN_SPELLS,
35 | ONF_LOOK_FOR_WEAPON,
36 | ONF_LOOK_FOR_ARMOR,
37 | ONF_LOOK_FOR_AMMO,
38 | ONF_BACKING_OFF,
39 | ONF_NO_ATTACK
40 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/Flags/ObjFSpellFlags.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 |
4 | namespace ArcNET.DataTypes.GameObjects.Flags;
5 |
6 | [Flags]
7 | [SuppressMessage("ReSharper", "InconsistentNaming")]
8 | public enum ObjFSpellFlags
9 | {
10 | OSF_INVISIBLE = 1,
11 | OSF_FLOATING,
12 | OSF_BODY_OF_AIR,
13 | OSF_BODY_OF_EARTH,
14 | OSF_BODY_OF_FIRE,
15 | OSF_BODY_OF_WATER,
16 | OSF_DETECTING_MAGIC,
17 | OSF_DETECTING_ALIGNMENT,
18 | OSF_DETECTING_TRAPS,
19 | OSF_DETECTING_INVISIBLE,
20 | OSF_SHIELDED,
21 | OSF_ANTI_MAGIC_SHELL,
22 | OSF_BONDS_OF_MAGIC,
23 | OSF_FULL_REFLECTION,
24 | OSF_SUMMONED,
25 | OSF_ILLUSION,
26 | OSF_STONED,
27 | OSF_POLYMORPHED,
28 | OSF_MIRRORED,
29 | OSF_SHRUNK,
30 | OSF_PASSWALLED,
31 | OSF_WATER_WALKING,
32 | OSF_MAGNETIC_INVERSION,
33 | OSF_CHARMED,
34 | OSF_ENTANGLED,
35 | OSF_SPOKEN_WITH_DEAD,
36 | OSF_TEMPUS_FUGIT,
37 | OSF_MIND_CONTROLLED,
38 | OSF_DRUNK,
39 | OSF_ENSHROUDED,
40 | OSF_FAMILIAR,
41 | OSF_HARDENED_HANDS
42 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/GameObject.cs:
--------------------------------------------------------------------------------
1 | namespace ArcNET.DataTypes.GameObjects;
2 |
3 | public class GameObject
4 | {
5 | public GameObjectHeader Header;
6 | public object Obj;
7 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/GameObjectGuid.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ArcNET.DataTypes.GameObjects;
4 |
5 | public class GameObjectGuid
6 | {
7 | public short Type;
8 | public short Foo0;
9 | public int Foo2;
10 | public Guid Guid;
11 |
12 | public GameObjectGuid()
13 | {
14 | }
15 |
16 | public GameObjectGuid(short type, short foo0, int foo2)
17 | {
18 | Type = type;
19 | Foo0 = foo0;
20 | Foo2 = foo2;
21 | }
22 |
23 | public bool IsProto()
24 | => Type == -1;
25 |
26 | public int GetId()
27 | => BitConverter.ToInt32(Guid.ToByteArray(), 0);
28 |
29 | public override string ToString()
30 | => $"{Type} {Foo0:x8} {Foo2:x8} {Guid}";
31 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/GameObjectHeader.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 |
3 | namespace ArcNET.DataTypes.GameObjects;
4 |
5 | public class GameObjectHeader
6 | {
7 | public string Filename;
8 | public int Version;
9 | public GameObjectGuid ProtoId { get; set; }
10 | public GameObjectGuid ObjectId { get; set; }
11 | public Enums.ObjectType GameObjectType { get; set; }
12 | public short PropCollectionItems;
13 | public BitArray Bitmap;
14 |
15 | public bool IsPrototype()
16 | => ProtoId.IsProto();
17 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/GameObjectHeaderReader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.IO;
4 | using Utils.Console;
5 |
6 | namespace ArcNET.DataTypes.GameObjects;
7 |
8 | public static class GameObjectHeaderReader
9 | {
10 | public static GameObjectHeader Read(this BinaryReader reader)
11 | {
12 | var header = new GameObjectHeader
13 | {
14 | Version = reader.ReadInt32()
15 | };
16 |
17 | if (header.Version != 0x77)
18 | throw new InvalidDataException("Unknown object file version: " + header.Version);
19 |
20 | header.ProtoId = reader.ReadGameObjectGuid(true);
21 | header.ObjectId = reader.ReadGameObjectGuid(true);
22 | header.GameObjectType = (Enums.ObjectType)reader.ReadUInt32();
23 |
24 | if (!header.ProtoId.IsProto())
25 | header.PropCollectionItems = reader.ReadInt16();
26 |
27 | var bitmapLength = (int)Enum.Parse(typeof(Enums.ObjectFieldBitmap), header.GameObjectType.ToString());
28 | header.Bitmap = new BitArray(reader.ReadBytes(bitmapLength));
29 |
30 | ConsoleExtensions.Log($"Parsed GameOjb headerVersion: {header.Version} "
31 | + $"\n ProtoId: {header.ProtoId}"
32 | + $"\n ObjectId: {header.ObjectId}"
33 | + $"\n GameObjectType: {header.GameObjectType}"
34 | + $"\n bitmapLength: {bitmapLength}"
35 | + $"\n Bitmap: {header.Bitmap}", "warn");
36 | return header;
37 | }
38 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/GameObjectManager.cs:
--------------------------------------------------------------------------------
1 | using ArcNET.DataTypes.GameObjects.Classes;
2 | using System.Collections.Generic;
3 |
4 | namespace ArcNET.DataTypes.GameObjects;
5 |
6 | public class GameObjectManager
7 | {
8 | public static List ObjectList;
9 | public static List Monsters;
10 | public static List NPCs = new();
11 | public static List Uniques = new();
12 |
13 | public static void Init()
14 | {
15 | ObjectList = new List();
16 | Monsters = new List();
17 | NPCs = new List();
18 | Uniques = new List();
19 | }
20 | }
--------------------------------------------------------------------------------
/ArcNET.DataTypes/GameObjects/GameObjectReader.cs:
--------------------------------------------------------------------------------
1 | using ArcNET.DataTypes.Common;
2 | using Spectre.Console;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Reflection;
8 | using Utils.Console;
9 |
10 | namespace ArcNET.DataTypes.GameObjects;
11 |
12 | public static class GameObjectReader
13 | {
14 | public static GameObject GetGameObject(this BinaryReader reader)
15 | {
16 | var gameObject = new GameObject();
17 | var prototypeGameObject = new GameObject();
18 |
19 | gameObject.Header = GameObjectHeaderReader.Read(reader);
20 |
21 | if (!gameObject.Header.IsPrototype())
22 | prototypeGameObject = GameObjectManager.ObjectList.Find(x =>
23 | x.Header.ObjectId.GetId().CompareTo(gameObject.Header.ProtoId.GetId()) == 0);
24 |
25 | const string pathToTypes = "ArcNET.DataTypes.GameObjects.Types.";
26 | var gameObjectObjType = Type.GetType(pathToTypes + gameObject.Header.GameObjectType);
27 | const string pathToCustomReader = "ArcNET.DataTypes.BinaryReaderExtensions";
28 | var binaryReader = Type.GetType(pathToCustomReader);
29 | gameObject.Obj = Activator.CreateInstance(gameObjectObjType ?? throw new InvalidOperationException());
30 |
31 | IOrderedEnumerable props = from p in gameObjectObjType.GetProperties()
32 | where p.CanWrite
33 | orderby p.PropertyOrder()
34 | select p;
35 |
36 | PropertyInfo[] propertyArray = props.ToArray();
37 |
38 | foreach (PropertyInfo propertyInfo in propertyArray)
39 | {
40 | if (binaryReader == null)
41 | throw new InvalidOperationException("binaryReader is null");
42 |
43 | MethodInfo readMethod = binaryReader.GetMethod(propertyInfo.PropertyType.Name.Contains("Tuple")
44 | ? "ReadArray"
45 | : "Read" + propertyInfo.PropertyType.Name);
46 |
47 | if (readMethod is not null && readMethod.IsGenericMethod)
48 | if (propertyInfo.PropertyType.FullName != null)
49 | {
50 | string genericTypeName = propertyInfo.PropertyType.FullName
51 | .Replace("System.Tuple`2[[", "").Split(new[] { ',' })[0]
52 | .Replace("[]", "");
53 | readMethod = readMethod.MakeGenericMethod(Type.GetType(genericTypeName) ?? throw new InvalidOperationException());
54 | }
55 |
56 | var parameters = new List