various improvements and additions to the New World Computing / Heroes of Might and Magic plugin

This commit is contained in:
Michael Becker 2020-05-28 18:16:59 -04:00
parent 98a9a347bc
commit 854ba278c8
No known key found for this signature in database
GPG Key ID: 506F54899E2BFED7
37 changed files with 1571 additions and 128 deletions

View File

@ -38,7 +38,7 @@
<ObjectModel TypeName="UniversalEditor.ObjectModels.NewWorldComputing.Map.MapObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.DataFormats.Gaming.WorldMap2D.NewWorldComputing.Heroes2.Heroes2MapDataFormat" />
<DataFormat TypeName="UniversalEditor.DataFormats.NewWorldComputing.WorldMap2D.NewWorldComputing.Heroes2.Heroes2MapDataFormat" />
</DataFormats>
</Association>
<Association>
@ -67,7 +67,7 @@
<ObjectModel TypeName="UniversalEditor.ObjectModels.NewWorldComputing.Map.MapObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.DataFormats.Gaming.WorldMap2D.NewWorldComputing.Heroes3.Heroes3MapDataFormat" />
<DataFormat TypeName="UniversalEditor.DataFormats.NewWorldComputing.WorldMap2D.NewWorldComputing.Heroes3.Heroes3MapDataFormat" />
</DataFormats>
</Association>
</Associations>

View File

@ -3,7 +3,7 @@
<Associations>
<Association>
<Filters>
<Filter Title="New World Computing palette">
<Filter Title="New World Computing KB palette">
<FileNameFilters>
<FileNameFilter>*.pal</FileNameFilter>
</FileNameFilters>
@ -16,5 +16,26 @@
<DataFormat TypeName="UniversalEditor.DataFormats.Multimedia.Palette.NewWorldComputing.KBPaletteDataFormat" />
</DataFormats>
</Association>
<Association>
<Filters>
<Filter Title="New World Computing RIFF palette">
<FileNameFilters>
<FileNameFilter>*.pal</FileNameFilter>
</FileNameFilters>
<MagicByteSequences>
<MagicByteSequence>
<MagicByte Type="String">RIFF</MagicByte>
<MagicByte Type="String" Offset="8">PAL </MagicByte>
</MagicByteSequence>
</MagicByteSequences>
</Filter>
</Filters>
<ObjectModels>
<ObjectModel TypeName="UniversalEditor.ObjectModels.Multimedia.Palette.PaletteObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.DataFormats.Multimedia.Palette.NewWorldComputing.RIFFPaletteDataFormat" />
</DataFormats>
</Association>
</Associations>
</UniversalEditor>

View File

@ -47,5 +47,20 @@
<DataFormat TypeName="UniversalEditor.DataFormats.Multimedia.Picture.NewWorldComputing.TIL.TILDataFormat" />
</DataFormats>
</Association>
<Association>
<Filters>
<Filter Title="Heroes of Might and Magic PCX image">
<FileNameFilters>
<FileNameFilter>*.pcx</FileNameFilter>
</FileNameFilters>
</Filter>
</Filters>
<ObjectModels>
<ObjectModel TypeName="UniversalEditor.ObjectModels.Multimedia.Picture.PictureObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.DataFormats.Multimedia.Picture.NewWorldComputing.PCX.PCXDataFormat" />
</DataFormats>
</Association>
</Associations>
</UniversalEditor>

View File

@ -3,7 +3,7 @@
<Associations>
<Association>
<Filters>
<Filter Title="New World Computing general resources file">
<Filter Title="New World Computing window layout file">
<FileNameFilters>
<FileNameFilter>*.bin</FileNameFilter>
</FileNameFilters>
@ -16,5 +16,20 @@
<DataFormat TypeName="UniversalEditor.DataFormats.NWCSceneLayout.NewWorldComputing.BIN.BINDataFormat" />
</DataFormats>
</Association>
<Association>
<Filters>
<Filter Title="New World Computing animation definition file">
<FileNameFilters>
<FileNameFilter>*.bin</FileNameFilter>
</FileNameFilters>
</Filter>
</Filters>
<ObjectModels>
<ObjectModel TypeName="UniversalEditor.ObjectModels.Multimedia.SpriteAnimationCollection.SpriteAnimationCollectionObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.DataFormats.NewWorldComputing.Animation.BINDataFormat" />
</DataFormats>
</Association>
</Associations>
</UniversalEditor>

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<UniversalEditor Version="4.0">
<Associations>
<Association>
<Filters>
<Filter Title="New World Computing PAL palette">
<FileNameFilters>
<FileNameFilter>*.pal</FileNameFilter>
</FileNameFilters>
</Filter>
</Filters>
<ObjectModels>
<ObjectModel TypeName="UniversalEditor.ObjectModels.Multimedia.Palette.PaletteObjectModel" />
</ObjectModels>
<DataFormats>
<DataFormat TypeName="UniversalEditor.DataFormats.Multimedia.Palette.NewWorldComputing.KBPaletteDataFormat" />
</DataFormats>
</Association>
</Associations>
</UniversalEditor>

View File

@ -608,7 +608,6 @@
<Content Include="Editors\FileSystem\Commands.uexml" />
<Content Include="splash.bmp" />
<Content Include="Editors\Executable\Commands.uexml" />
<Content Include="Extensions\GraphicDesigner\Associations\Palette\NewWorldComputingPAL.uexml" />
<Content Include="Extensions\Microsoft\Associations\RKV.uexml" />
<Content Include="Panels\SolutionExplorer\Languages\English.uexml" />
<Content Include="Panels\SolutionExplorer\Commands.uexml" />

View File

@ -0,0 +1,41 @@
//
// DataFormatFragment.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using UniversalEditor.IO;
namespace UniversalEditor
{
public abstract class DataFormatFragment<T>
{
protected abstract T ReadInternal(IO.Reader reader);
protected abstract void WriteInternal(IO.Writer writer, T value);
public T Read(IO.Reader reader)
{
return ReadInternal(reader);
}
public void Write(IO.Writer writer, T value)
{
WriteInternal(writer, value);
}
}
}

View File

@ -91,6 +91,7 @@
<Compile Include="CustomOptionAttribute.cs" />
<Compile Include="IO\Transformations\XorTransformation.cs" />
<Compile Include="IO\Transformation.cs" />
<Compile Include="DataFormatFragment.cs" />
</ItemGroup>
<ItemGroup />
<ItemGroup>

View File

@ -0,0 +1,81 @@
//
// RIFFPaletteDataFormat.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using UniversalEditor.DataFormats.Chunked.RIFF;
using UniversalEditor.ObjectModels.Chunked;
using UniversalEditor.ObjectModels.Multimedia.Palette;
namespace UniversalEditor.DataFormats.Multimedia.Palette.NewWorldComputing
{
public class RIFFPaletteDataFormat : RIFFDataFormat
{
private static DataFormatReference _dfr = null;
protected override DataFormatReference MakeReferenceInternal()
{
if (_dfr == null)
{
_dfr = new DataFormatReference(GetType());
_dfr.Capabilities.Add(typeof(PaletteObjectModel), DataFormatCapabilities.All);
}
return _dfr;
}
protected override void BeforeLoadInternal(Stack<ObjectModel> objectModels)
{
base.BeforeLoadInternal(objectModels);
objectModels.Push(new ChunkedObjectModel());
}
protected override void AfterLoadInternal(Stack<ObjectModel> objectModels)
{
base.AfterLoadInternal(objectModels);
ChunkedObjectModel riff = (objectModels.Pop() as ChunkedObjectModel);
PaletteObjectModel palette = (objectModels.Pop() as PaletteObjectModel);
RIFFGroupChunk grp = (riff.Chunks[0] as RIFFGroupChunk);
if (grp.ID != "PAL ")
throw new InvalidDataFormatException("RIFF container does not contain a group chunk with ID 'PAL '");
RIFFDataChunk data = (grp.Chunks["data"] as RIFFDataChunk);
if (data == null)
throw new InvalidDataFormatException("'PAL ' group chunk does not contain a data chunk with ID 'data'");
if (data.Data.Length % 4 != 0)
throw new InvalidDataFormatException("'data' data chunk length is not evenly divisible by 4");
for (int i = 4; i < data.Data.Length; i += 4)
{
MBS.Framework.Drawing.Color color = MBS.Framework.Drawing.Color.FromRGBAByte(data.Data[i], data.Data[i + 1], data.Data[i + 2]);
palette.Entries.Add(new PaletteEntry(color));
}
}
protected override void BeforeSaveInternal(Stack<ObjectModel> objectModels)
{
base.BeforeSaveInternal(objectModels);
PaletteObjectModel palette = (objectModels.Pop() as PaletteObjectModel);
ChunkedObjectModel riff = new ChunkedObjectModel();
objectModels.Push(riff);
}
}
}

View File

@ -0,0 +1,109 @@
//
// PCXDataFormat.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.Multimedia.Palette;
using UniversalEditor.ObjectModels.Multimedia.Picture;
namespace UniversalEditor.DataFormats.Multimedia.Picture.NewWorldComputing.PCX
{
public class PCXDataFormat : DataFormat
{
private static DataFormatReference _dfr = null;
protected override DataFormatReference MakeReferenceInternal()
{
if (_dfr == null)
{
_dfr = base.MakeReferenceInternal();
_dfr.Capabilities.Add(typeof(PictureObjectModel), DataFormatCapabilities.All);
_dfr.ImportOptions.Add(new CustomOptionFile("PaletteFileName", "External _palette", "Palette|*.pal"));
}
return _dfr;
}
public string PaletteFileName { get; set; } = null;
public PaletteObjectModel Palette { get; set; } = null;
protected override void LoadInternal(ref ObjectModel objectModel)
{
PictureObjectModel pic = (objectModel as PictureObjectModel);
if (pic == null) throw new ObjectModelNotSupportedException();
Reader reader = Accessor.Reader;
if (!String.IsNullOrEmpty(PaletteFileName) && System.IO.File.Exists(PaletteFileName))
{
Palette = Common.Reflection.GetAvailableObjectModel<PaletteObjectModel>(PaletteFileName);
}
uint dataLength = reader.ReadUInt32();
uint width = reader.ReadUInt32();
uint height = reader.ReadUInt32();
if (dataLength != (width * height))
{
// TODO: sanity check?
}
pic.Width = (int)width;
pic.Height = (int)height;
byte[] indices = reader.ReadBytes(width * height);
if (Palette == null)
Palette = new PaletteObjectModel();
if (!reader.EndOfStream)
{
// byte nul = reader.ReadByte();
// if (nul != 0) return; //eeee?
for (int i = 0; i < 256; i++)
{
byte r = reader.ReadByte();
byte g = reader.ReadByte();
byte b = reader.ReadByte();
Palette.Entries.Add(new PaletteEntry(MBS.Framework.Drawing.Color.FromRGBAByte(r, g, b)));
}
}
int x = 0, y = 0;
for (int i = 0; i < indices.Length; i++)
{
byte index = indices[i];
pic.SetPixel(Palette.Entries[index].Color, x, y);
x++;
if (x >= pic.Width)
{
reader.Align(4);
x = 0;
y++;
}
}
}
protected override void SaveInternal(ObjectModel objectModel)
{
throw new NotImplementedException();
}
}
}

View File

@ -173,6 +173,12 @@ namespace UniversalEditor.DataFormats.NWCSceneLayout.NewWorldComputing.BIN
if (designer == null)
throw new ObjectModelNotSupportedException();
// HACK: because there simply is no better way to differentiate between window layout BINs and animation BINs (except maybe filename ending in FRM.BIN)
if (Accessor.Length == 821 && Accessor.GetFileName().EndsWith("FRM.BIN"))
{
throw new InvalidDataFormatException(); // to kick it to the *other* BIN format
}
if (!designer.Libraries.Contains(NWCSceneLayoutLibrary))
designer.Libraries.Add(NWCSceneLayoutLibrary);

View File

@ -0,0 +1,61 @@
//
// BINAnimationType.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.DataFormats.NewWorldComputing.Animation
{
public enum BINAnimationType
{
MOVE_START, // Start of the moving sequence on 1st animation cycle: flyers will fly up
MOVE_TILE_START, // Supposed to be played at the beginning of 2nd+ move.
MOVE_MAIN, // Core animation. Most units only have this one.
MOVE_TILE_END, // Cavalry & wolf. Played at the end of the cycle (2nd tile to 3rd), but not at the last one
MOVE_STOP, // End of the moving sequence when arrived: landing for example
MOVE_ONE, // Used when moving 1 tile. LICH and POWER_LICH doesn't have this, use MOVE_MAIN
TEMPORARY, // This is an empty placeholder for combined animation built from previous parts
STATIC, // Frame 1
IDLE1,
IDLE2, // Idle animations: picked at random with different probablities, rarely all 5 present
IDLE3,
IDLE4,
IDLE5,
DEATH,
WINCE_UP,
WINCE_END,
ATTACK1, // Attacks, number represents the angle: 1 is TOP, 2 is CENTER, 3 is BOTTOM
ATTACK1_END,
DOUBLEHEX1,
DOUBLEHEX1_END,
ATTACK2,
ATTACK2_END,
DOUBLEHEX2,
DOUBLEHEX2_END,
ATTACK3,
ATTACK3_END,
DOUBLEHEX3,
DOUBLEHEX3_END,
SHOOT1,
SHOOT1_END,
SHOOT2,
SHOOT2_END,
SHOOT3,
SHOOT3_END
}
}

View File

@ -0,0 +1,147 @@
//
// BINDataFormat.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.Multimedia.SpriteAnimationCollection;
namespace UniversalEditor.DataFormats.NewWorldComputing.Animation
{
public class BINDataFormat : DataFormat
{
public const byte IDLE_ANIMATION_COUNT_MAX = 5;
public const byte PROJECTILE_ANGLE_MAX = 12;
public const byte FRAME_MAX = 16;
private static DataFormatReference _dfr = null;
protected override DataFormatReference MakeReferenceInternal()
{
if (_dfr == null)
{
_dfr = base.MakeReferenceInternal();
_dfr.Capabilities.Add(typeof(SpriteAnimationCollectionObjectModel), DataFormatCapabilities.All);
}
return _dfr;
}
protected override void LoadInternal(ref ObjectModel objectModel)
{
SpriteAnimationCollectionObjectModel anim = (objectModel as SpriteAnimationCollectionObjectModel);
if (anim == null)
throw new ObjectModelNotSupportedException();
// HACK: because there simply is no better way to differentiate between window layout BINs and animation BINs (except maybe filename ending in FRM.BIN)
if (!(Accessor.Length == 821 && Accessor.GetFileName().EndsWith("FRM.BIN")))
{
throw new InvalidDataFormatException(); // to kick it to the *other* BIN format
}
Reader reader = Accessor.Reader;
byte one = reader.ReadByte();
short eyePositionX = reader.ReadInt16();
short eyePositionY = reader.ReadInt16();
// frame offsets for the future use
int[][] moveOffsets = new int[7][];
for (int i = 0; i < 7; i++)
{
int[] moveOffset = new int[16];
for ( int frame = 0; frame < 16; ++frame)
{
moveOffset[frame] = reader.ReadByte();
}
moveOffsets[i] = moveOffset;
}
// at offset 117
byte idleAnimationCount = reader.ReadByte();
float[] idleAnimationPriorities = new float[IDLE_ANIMATION_COUNT_MAX];
uint[] unusedIdleDelays = new uint[IDLE_ANIMATION_COUNT_MAX];
for (byte i = 0; i < IDLE_ANIMATION_COUNT_MAX; i++)
{
idleAnimationPriorities[i] = reader.ReadSingle();
}
for (byte i = 0; i < IDLE_ANIMATION_COUNT_MAX; i++)
{
unusedIdleDelays[i] = reader.ReadUInt32();
}
// at offset 158
uint idleAnimationDelay = reader.ReadUInt32();
uint moveSpeed = reader.ReadUInt32();
uint shootSpeed = reader.ReadUInt32();
uint flightSpeed = reader.ReadUInt32();
// projectile data
for (int i = 0; i < 3; i++)
{
short projectileOffsetX = reader.ReadInt16();
short projectileOffsetY = reader.ReadInt16();
}
// describes how to rotate the projectile when
byte projectileAngleCount = reader.ReadByte();
for (byte i = 0; i < PROJECTILE_ANGLE_MAX; i++)
{
// even though there are only {projectileAngleCount} items, the rest of PROJECTILE_ANGLE_MAX is filled with zeroes
float projectileAngle = reader.ReadSingle();
}
// Positional offsets for sprites & drawing
uint troopCountOffsetLeft = reader.ReadUInt32();
uint troopCountOffsetRight = reader.ReadUInt32();
// Load animation sequences themselves
int nMaxAnimationTypes = Enum.GetValues(typeof(BINAnimationType)).Length;
byte[] animCounts = new byte[nMaxAnimationTypes];
byte[][] animFrames = new byte[nMaxAnimationTypes][];
SpriteAnimation[] anims = new SpriteAnimation[nMaxAnimationTypes];
for (int idx = 0; idx < nMaxAnimationTypes; ++idx)
{
animCounts[idx] = reader.ReadByte();
anims[idx] = new SpriteAnimation();
anims[idx].Name = Enum.GetName(typeof(BINAnimationType), idx);
}
for (int idx = 0; idx < nMaxAnimationTypes; ++idx)
{
animFrames[idx] = new byte[FRAME_MAX];
for (byte frame = 0; frame < FRAME_MAX; frame++)
{
animFrames[idx][frame] = reader.ReadByte();
}
for (byte frame = 0; frame < animCounts[idx]; frame++)
{
anims[idx].Frames.Add(animFrames[idx][frame]);
}
anim.Animations.Add(anims[idx]);
}
}
protected override void SaveInternal(ObjectModel objectModel)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,102 @@
//
// CastleFragment.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.NewWorldComputing.Map;
namespace UniversalEditor.DataFormats.NewWorldComputing.WorldMap2D.NewWorldComputing.Heroes2
{
public class CastleFragment : DataFormatFragment<MapCastle>
{
protected override MapCastle ReadInternal(Reader reader)
{
MapCastle castle = new MapCastle();
castle.Color = (MapCastleColor)reader.ReadByte();
castle.HasCustomBuilding = reader.ReadBoolean();
castle.Buildings = (MapBuildingType)reader.ReadUInt16();
castle.Dwellings = (MapDwellingType)reader.ReadUInt16();
castle.MageGuildLevel = (MapMageGuildLevel)reader.ReadByte();
castle.HasCustomTroops = reader.ReadBoolean();
byte[] monsterTypes = reader.ReadBytes(5);
ushort[] monsterCounts = reader.ReadUInt16Array(5);
for (int i = 0; i < monsterTypes.Length; i++)
{
if (monsterTypes[i] != 0xFF)
{
castle.Monsters[i] = new MapArmyMonster((MapMonsterType)monsterTypes[i], monsterCounts[i]);
}
}
castle.HasCaptain = reader.ReadBoolean();
castle.HasCustomName = reader.ReadBoolean();
castle.Name = reader.ReadFixedLengthString(13).TrimNull();
castle.Type = (MapCastleType)reader.ReadByte();
castle.IsCastle = reader.ReadBoolean();
castle.IsUpgradable = reader.ReadBoolean(); // 00 TRUE, 01 FALSE
byte[] unknown = reader.ReadBytes(29);
return castle;
}
protected override void WriteInternal(Writer writer, MapCastle value)
{
writer.WriteByte((byte)value.Color);
writer.WriteBoolean(value.HasCustomBuilding);
writer.WriteUInt16((ushort)value.Buildings);
writer.WriteUInt16((ushort)value.Dwellings);
writer.WriteByte((byte)value.MageGuildLevel);
writer.WriteBoolean(value.HasCustomTroops);
for (int i = 0; i < 5; i++)
{
if (i < value.Monsters.Length)
{
writer.WriteByte((byte)value.Monsters[i].MonsterType);
}
else
{
writer.WriteByte(0);
}
}
for (int i = 0; i < 5; i++)
{
if (i < value.Monsters.Length)
{
writer.WriteUInt16(value.Monsters[i].Amount);
}
else
{
writer.WriteUInt16(0);
}
}
writer.WriteBoolean(value.HasCaptain);
writer.WriteBoolean(value.HasCustomName);
writer.WriteFixedLengthString(value.Name, 13);
writer.WriteByte((byte)value.Type);
writer.WriteBoolean(value.IsCastle);
writer.WriteBoolean(value.IsUpgradable); // 00 TRUE, 01 FALSE
writer.WriteBytes(new byte[29]);// idk
}
}
}

View File

@ -0,0 +1,93 @@
//
// EventFragment.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.NewWorldComputing.Map;
namespace UniversalEditor.DataFormats.NewWorldComputing.WorldMap2D.NewWorldComputing.Heroes2
{
public class EventFragment : DataFormatFragment<MapEvent>
{
protected override MapEvent ReadInternal(Reader reader)
{
MapEvent evt = new MapEvent();
evt.AmountWood = reader.ReadInt32();
evt.AmountMercury = reader.ReadInt32();
evt.AmountOre = reader.ReadInt32();
evt.AmountSulfur = reader.ReadInt32();
evt.AmountCrystal = reader.ReadInt32();
evt.AmountGems = reader.ReadInt32();
evt.AmountGold = reader.ReadInt32();
short nArtifact = reader.ReadInt16();
// evt.Artifact = (MapArtifact)nArtifact;
evt.AllowComputer = reader.ReadBoolean();
evt.SingleVisit = reader.ReadBoolean();
byte[] unknown = reader.ReadBytes(10);
bool colorBlue = reader.ReadBoolean();
if (colorBlue) evt.AllowedKingdoms |= MapKingdomColor.Blue;
bool colorGreen = reader.ReadBoolean();
if (colorGreen) evt.AllowedKingdoms |= MapKingdomColor.Green;
bool colorRed = reader.ReadBoolean();
if (colorRed) evt.AllowedKingdoms |= MapKingdomColor.Red;
bool colorYellow = reader.ReadBoolean();
if (colorYellow) evt.AllowedKingdoms |= MapKingdomColor.Yellow;
bool colorOrange = reader.ReadBoolean();
if (colorOrange) evt.AllowedKingdoms |= MapKingdomColor.Orange;
bool colorPurple = reader.ReadBoolean();
if (colorPurple) evt.AllowedKingdoms |= MapKingdomColor.Purple;
evt.Message = reader.ReadNullTerminatedString();
return evt;
}
protected override void WriteInternal(Writer writer, MapEvent value)
{
writer.WriteInt32(value.AmountWood);
writer.WriteInt32(value.AmountMercury);
writer.WriteInt32(value.AmountOre);
writer.WriteInt32(value.AmountSulfur);
writer.WriteInt32(value.AmountCrystal);
writer.WriteInt32(value.AmountGems);
writer.WriteInt32(value.AmountGold);
short nArtifact = 0;
writer.WriteInt16(nArtifact);
// evt.Artifact = (MapArtifact)nArtifact;
writer.WriteBoolean(value.AllowComputer);
writer.WriteBoolean(value.SingleVisit);
writer.WriteBytes(new byte[10]);
writer.WriteBoolean((value.AllowedKingdoms & MapKingdomColor.Blue) == MapKingdomColor.Blue);
writer.WriteBoolean((value.AllowedKingdoms & MapKingdomColor.Green) == MapKingdomColor.Green);
writer.WriteBoolean((value.AllowedKingdoms & MapKingdomColor.Red) == MapKingdomColor.Red);
writer.WriteBoolean((value.AllowedKingdoms & MapKingdomColor.Yellow) == MapKingdomColor.Yellow);
writer.WriteBoolean((value.AllowedKingdoms & MapKingdomColor.Orange) == MapKingdomColor.Orange);
writer.WriteBoolean((value.AllowedKingdoms & MapKingdomColor.Purple) == MapKingdomColor.Purple);
writer.WriteNullTerminatedString(value.Message);
}
}
}

View File

@ -0,0 +1,167 @@
//
// HeroFragment.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.NewWorldComputing;
using UniversalEditor.ObjectModels.NewWorldComputing.Map;
namespace UniversalEditor.DataFormats.NewWorldComputing.WorldMap2D.NewWorldComputing.Heroes2
{
public class HeroFragment : DataFormatFragment<MapHero>
{
protected override MapHero ReadInternal(Reader reader)
{
MapHero hero = new MapHero();
bool unk = reader.ReadBoolean();
hero.HasCustomTroops = reader.ReadBoolean();
byte[] monsters = reader.ReadBytes(5);
ushort[] monsterCount = reader.ReadUInt16Array(5);
for (int i = 0; i < monsters.Length; i++)
{
if (monsters[i] != 0xFF)
{
MapMonsterType monsterType = (MapMonsterType)monsters[i];
hero.Monsters.Add(new MapArmyMonster(monsterType, monsterCount[i]));
}
}
hero.HasCustomPortrait = reader.ReadBoolean();
hero.CustomPortraitIndex = reader.ReadByte();
byte[] customArtifacts = reader.ReadBytes(3); // -1 if unset
for (int i = 0; i < customArtifacts.Length; i++)
{
if (customArtifacts[i] != 0xFF)
{
MapArtifact artifact = new MapArtifact((MapArtifactType)customArtifacts[i]);
hero.Artifacts.Add(artifact);
}
}
byte unknown2 = reader.ReadByte();
hero.Experience = reader.ReadUInt32();
hero.HasCustomSkills = reader.ReadBoolean();
byte[] skills = reader.ReadBytes(8); // 0xff none, pathfinding, archery, logistic, scouting, diplomacy, navigation, leadership, wisdom,
// mysticism, luck, ballistics, eagle, necromance, estate
byte[] skillLevels = reader.ReadBytes(8); // 1 = basic, 2 = advanced, 3 = expert, 0 = unset
for (int i = 0; i < skills.Length; i++)
{
if (skills[i] != 0xFF)
{
HeroSkillType type = (HeroSkillType)skills[i];
HeroSkillLevel level = (HeroSkillLevel)skillLevels[i];
hero.Skills.Add(new HeroSkill(type, level));
}
}
byte unknown3 = reader.ReadByte();
hero.HasCustomName = reader.ReadBoolean();
hero.Name = reader.ReadFixedLengthString(13).TrimNull();
hero.Patrol = reader.ReadBoolean();
hero.PatrolSquareCount = reader.ReadByte();
byte[] unknown4 = reader.ReadBytes(15);
return hero;
}
protected override void WriteInternal(Writer writer, MapHero value)
{
writer.WriteBoolean(false);
writer.WriteBoolean(value.HasCustomTroops);
for (int i = 0; i < 5; i++)
{
if (i < value.Monsters.Count)
{
writer.WriteByte((byte)value.Monsters[i].MonsterType);
}
else
{
writer.WriteByte(255);
}
}
for (int i = 0; i < 5; i++)
{
if (i < value.Monsters.Count)
{
writer.WriteUInt16((byte)value.Monsters[i].Amount);
}
else
{
writer.WriteUInt16(0);
}
}
writer.WriteBoolean(value.HasCustomPortrait);
writer.WriteByte(value.CustomPortraitIndex);
for (int i = 0; i < 3; i++)
{
if (i < value.Artifacts.Count)
{
writer.WriteByte((byte)value.Artifacts[i].Type);
}
else
{
writer.WriteByte(255);
}
}
writer.WriteByte(0);
writer.WriteUInt32(value.Experience);
writer.WriteBoolean(value.HasCustomSkills);
for (int i = 0; i < 8; i++)
{
if (i < value.Skills.Count)
{
writer.WriteByte((byte)value.Skills[i].Type);
}
else
{
writer.WriteByte(255);
}
}
for (int i = 0; i < 8; i++)
{
if (i < value.Skills.Count)
{
writer.WriteByte((byte)value.Skills[i].Level);
}
else
{
writer.WriteByte(0);
}
}
writer.WriteByte(0); // unknown3
writer.WriteBoolean(value.HasCustomName);
writer.WriteFixedLengthString(value.Name, 13);
writer.WriteBoolean(value.Patrol);
writer.WriteByte(value.PatrolSquareCount);
writer.WriteBytes(new byte[15]);
}
}
}

View File

@ -20,9 +20,11 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.NewWorldComputing;
using UniversalEditor.ObjectModels.NewWorldComputing.Map;
namespace UniversalEditor.DataFormats.Gaming.WorldMap2D.NewWorldComputing.Heroes2
namespace UniversalEditor.DataFormats.NewWorldComputing.WorldMap2D.NewWorldComputing.Heroes2
{
/// <summary>
/// Pprovides a <see cref="DataFormat" /> for manipulating Heroes of Might and Magic II map files.
@ -119,138 +121,173 @@ namespace UniversalEditor.DataFormats.Gaming.WorldMap2D.NewWorldComputing.Heroes
#endregion
// kingdom count
br.Accessor.Seek(0x1A, IO.SeekOrigin.Begin);
byte kingdomCount = br.ReadByte();
byte nCount1 = br.ReadByte(); // idk?
byte nCount2 = br.ReadByte(); // idk?
br.Accessor.Seek(0x1D, IO.SeekOrigin.Begin);
map.WinConditions = (MapWinCondition)br.ReadByte();
map.ComputerAlsoWins = (MapWinCondition)br.ReadByte();
map.AllowNormalVictory = br.ReadBoolean();
byte wins1 = br.ReadByte();
byte wins2 = br.ReadByte();
ushort wins3 = br.ReadUInt16();
br.Accessor.Seek(0x2C, IO.SeekOrigin.Begin);
ushort wins4 = br.ReadUInt16();
br.Accessor.Seek(0x22, IO.SeekOrigin.Begin);
map.LoseConditions = (MapLoseCondition)br.ReadByte();
ushort loss1 = br.ReadUInt16();
br.Accessor.Seek(0x2E, IO.SeekOrigin.Begin);
ushort loss2 = br.ReadUInt16();
ushort u2 = br.ReadUInt16();
// starting hero
br.Accessor.Seek(0x25, IO.SeekOrigin.Begin);
byte startingHero = br.ReadByte();
bool withHeroes = (startingHero == 0);
byte[] races = br.ReadBytes(5);
byte[] races = br.ReadBytes(6);
// name
ushort wins2 = br.ReadUInt16();
ushort loss2 = br.ReadUInt16();
// map name
br.Accessor.Seek(0x3A, IO.SeekOrigin.Begin);
map.Name = br.ReadFixedLengthString(16);
map.Name = map.Name.TrimNull();
// name
map.Name = br.ReadFixedLengthString(16).TrimNull();
// map description
br.Accessor.Seek(0x76, IO.SeekOrigin.Begin);
map.Description = br.ReadFixedLengthString(143);
map.Description = map.Description.TrimNull();
map.Description = br.ReadFixedLengthString(143).TrimNull();
byte[] unknown = br.ReadBytes(157);
ushort unknown2 = br.ReadUInt16();
ushort nObjects = br.ReadUInt16();
// 33044 bytes between here and there - tiles (36 * 36 * 25 bytes per tile)
// 33044 bytes between here and there - tiles (width * height * 20 bytes per tile)
uint width = br.ReadUInt32();
uint height = br.ReadUInt32();
long pos = br.Accessor.Position;
br.Accessor.Position = pos;
for (ushort i = 0; i < unknown2; i++)
{
MapTile tile = ReadTile(br);
}
TileFragment fragTile = new TileFragment();
for (int y = 0; y < map.Height; y++)
{
for (int x = 0; x < map.Width; x++)
{
MapTile tile = ReadTile(br);
MapTile tile = fragTile.Read(br);
map.Tiles.Add(tile);
}
}
#region Castle
for (byte i = 0; i < kingdomCount; i++)
// addons
uint nAddons = br.ReadUInt32();
for (uint i = 0; i < nAddons; i++)
{
MapCastle castle = ReadCastle(br);
ushort indexAddon = br.ReadUInt16();
byte objectNameN1 = br.ReadByte();
objectNameN1 *= 2; // idk
byte indexNameN1 = br.ReadByte();
byte quantityN = br.ReadByte();
byte objectNameN2 = br.ReadByte();
byte indexNameN2 = br.ReadByte();
uint uniqNumberN1 = br.ReadUInt32();
uint uniqNumberN2 = br.ReadUInt32();
}
for (int i = 0; i < 72; i++)
{
// castle coordinates
// 72 x 3 byte (cx, cy, id)
byte cx = br.ReadByte();
byte cy = br.ReadByte();
byte id = br.ReadByte();
if (cx == 0xFF && cy == 0xFF)
continue;
bool isCastle = false;
if ((id & 0x80) == 0x80)
{
isCastle = true;
id = (byte)(id & ~0x80);
}
MapCastleType castleType = (MapCastleType)id;
// map.Castles.Add(new MapCastle(castleType, cx, cy, isCastle));
}
// kingdom resource coordinates
for (int i = 0; i < 144; i++)
{
byte cx = br.ReadByte();
byte cy = br.ReadByte();
byte id = br.ReadByte();
if (cx == 0xFF && cy == 0xFF)
continue;
MapResourceType resourceType = (MapResourceType)id;
}
map.ObeliskCount = br.ReadByte();
return;
// idk wtf this is
uint countBlock = 0;
while (!br.EndOfStream)
{
byte l = br.ReadByte();
byte h = br.ReadByte();
if (l == 0 && h == 0)
break;
countBlock = (uint)(256 * (h + l) - 1); // wtf
}
MonsterFragment fragMonster = new MonsterFragment();
CastleFragment fragCastle = new CastleFragment();
HeroFragment fragHero = new HeroFragment();
EventFragment fragEvent = new EventFragment();
for (ushort i = 0; i < countBlock; i++)
{
ushort blockSize = br.ReadUInt16();
MapTile tile = FindObject(map, i);
switch ((MapItemType)blockSize)
{
case MapItemType.Monster:
{
MapArmyMonster item = fragMonster.Read(br);
map.Items.Add(item);
break;
}
case MapItemType.Castle:
{
MapCastle castle = fragCastle.Read(br);
map.Items.Add(castle);
break;
}
case MapItemType.Hero:
{
MapHero hero = fragHero.Read(br);
map.Items.Add(hero);
break;
}
}
}
#endregion
}
private MapTile ReadTile(IO.Reader br)
private MapTile FindObject(MapObjectModel map, ushort i)
{
MapTile tile = new MapTile();
tile.GroundType = (MapGroundType)br.ReadUInt16(); // tile (ocean, grass, snow, swamp, lava, desert, dirt, wasteland, beach)
byte objectName1 = br.ReadByte(); // level 1.0
byte indexName1 = br.ReadByte(); // index level 1.0 or 0xFF
byte quantity1 = br.ReadByte(); // count
byte quantity2 = br.ReadByte(); // count
byte objectName2 = br.ReadByte(); // level 2.0
byte indexName2 = br.ReadByte(); // index level 2.0 or 0xFF
byte shape = br.ReadByte(); // shape reflect % 4, 0 none, 1 vertical, 2 horizontal, 3 any
byte generalObject = br.ReadByte(); // zero or object
ushort indexAddon = br.ReadUInt16(); // zero or index addons_t
uint uniqNumber1 = br.ReadUInt32(); // level 1.0
uint uniqNumber2 = br.ReadUInt32(); // level 2.0
byte[] unknown = br.ReadBytes(5);
// 259229
return tile;
ushort indexAddonN = br.ReadUInt16(); // zero or next addons_t
byte objectNameN1 = br.ReadByte(); // level 1.N
byte indexNameN1 = br.ReadByte(); // level 1.N or 0xFF
byte quantityN = br.ReadByte(); //
byte objectNameN2 = br.ReadByte(); // level 2.N
byte indexNameN2 = br.ReadByte(); // level 1.N or 0xFF
uint uniqNumberN1 = br.ReadUInt32(); // level 1.N
uint uniqNumberN2 = br.ReadUInt32(); // level 2.N
return tile;
}
private MapCastle ReadCastle(IO.Reader br)
{
MapCastle castle = new MapCastle();
ushort signal = br.ReadUInt16();
castle.Color = (MapCastleColor)br.ReadByte();
castle.HasCustomBuilding = br.ReadBoolean();
castle.Buildings = (MapBuildingType)br.ReadUInt16();
castle.Dwellings = (MapDwellingType)br.ReadUInt16();
castle.MageGuildLevel = (MapMageGuildLevel)br.ReadByte();
castle.HasCustomTroops = br.ReadBoolean();
for (int i = 0; i < 5; i++)
int findobject = -1;
for (int it_index = 0; it_index < map.Tiles.Count && findobject < 0; ++it_index)
{
castle.Monsters[i] = new MapArmyMonster();
castle.Monsters[i].MonsterType = (MapMonsterType)br.ReadByte();
}
for (int i = 0; i < 5; i++)
{
castle.Monsters[i].Amount = br.ReadUInt16();
MapTile tile = map.Tiles[it_index];
// orders(quantity2, quantity1)
int orders = tile.Quantity2; // (tile.GetQuantity2() ? tile.GetQuantity2() : 0);
orders <<= 8;
orders |= tile.Quantity1; // tile.GetQuantity1();
if ((orders != 0) && !((orders % 0x08) != 0) && (i + 1 == orders / 0x08))
findobject = it_index;
}
if (findobject == -1)
return null;
castle.HasCaptain = br.ReadBoolean();
castle.HasCustomName = br.ReadBoolean();
castle.Name = br.ReadFixedLengthString(13);
castle.Name = castle.Name.TrimNull();
castle.Type = (MapCastleType)br.ReadByte();
castle.IsCastle = br.ReadBoolean();
castle.IsUpgradable = br.ReadBoolean(); // 00 TRUE, 01 FALSE
byte[] unknown = br.ReadBytes(29);
return castle;
return map.Tiles[findobject];
}
protected override void SaveInternal(ObjectModel objectModel)

View File

@ -0,0 +1,39 @@
//
// MonsterFragment.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.NewWorldComputing.Map;
namespace UniversalEditor.DataFormats.NewWorldComputing.WorldMap2D.NewWorldComputing.Heroes2
{
public class MonsterFragment : DataFormatFragment<MapArmyMonster>
{
protected override MapArmyMonster ReadInternal(Reader reader)
{
MapArmyMonster item = null; //new MapArmyMonster();
return item;
}
protected override void WriteInternal(Writer writer, MapArmyMonster value)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,62 @@
//
// TileFragment.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using UniversalEditor.IO;
using UniversalEditor.ObjectModels.NewWorldComputing.Map;
namespace UniversalEditor.DataFormats.NewWorldComputing.WorldMap2D.NewWorldComputing.Heroes2
{
public class TileFragment : DataFormatFragment<MapTile>
{
protected override MapTile ReadInternal(Reader reader)
{
MapTile tile = new MapTile();
tile.GroundType = (MapGroundType)reader.ReadUInt16(); // tile (ocean, grass, snow, swamp, lava, desert, dirt, wasteland, beach)
tile.ObjectName1 = reader.ReadByte(); // level 1.0
tile.IndexName1 = reader.ReadByte(); // index level 1.0 or 0xFF
tile.Quantity1 = reader.ReadByte(); // count
tile.Quantity2 = reader.ReadByte(); // count
tile.ObjectName2 = reader.ReadByte(); // level 2.0
tile.IndexName2 = reader.ReadByte(); // index level 2.0 or 0xFF
tile.Shape = reader.ReadByte(); // shape reflect % 4, 0 none, 1 vertical, 2 horizontal, 3 any
tile.GeneralObject = reader.ReadByte(); // zero or object
tile.IndexAddon = reader.ReadUInt16(); // zero or index addons_t
tile.UniqNumber1 = reader.ReadUInt32(); // level 1.0
tile.UniqNumber2 = reader.ReadUInt32(); // level 2.0
return tile;
}
protected override void WriteInternal(Writer writer, MapTile value)
{
writer.WriteUInt16((ushort)value.GroundType);
writer.WriteByte(value.ObjectName1);
writer.WriteByte(value.IndexName1);
writer.WriteByte(value.Quantity1);
writer.WriteByte(value.Quantity2);
writer.WriteByte(value.ObjectName2);
writer.WriteByte(value.IndexName2);
writer.WriteByte(value.Shape);
writer.WriteByte(value.GeneralObject);
writer.WriteUInt16(value.IndexAddon);
writer.WriteUInt32(value.UniqNumber1);
writer.WriteUInt32(value.UniqNumber2);
}
}
}

View File

@ -19,7 +19,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace UniversalEditor.DataFormats.Gaming.WorldMap2D.NewWorldComputing.Heroes3
namespace UniversalEditor.DataFormats.NewWorldComputing.WorldMap2D.NewWorldComputing.Heroes3
{
/// <summary>
/// Indicates the game campaign type supported by a Heroes of Might and Magic III game map.

View File

@ -22,7 +22,7 @@
using UniversalEditor.Accessors;
using UniversalEditor.ObjectModels.NewWorldComputing.Map;
namespace UniversalEditor.DataFormats.Gaming.WorldMap2D.NewWorldComputing.Heroes3
namespace UniversalEditor.DataFormats.NewWorldComputing.WorldMap2D.NewWorldComputing.Heroes3
{
/// <summary>
/// Provides a <see cref="DataFormat" /> for manipulating Heroes of Might and Magic III map files.

View File

@ -0,0 +1,41 @@
//
// HeroSkill.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.ObjectModels.NewWorldComputing
{
public class HeroSkill
{
public class HeroSkillCollection
: System.Collections.ObjectModel.Collection<HeroSkill>
{
}
public HeroSkillType Type { get; set; }
public HeroSkillLevel Level { get; set; } = HeroSkillLevel.Basic;
public HeroSkill(HeroSkillType type, HeroSkillLevel level)
{
Type = type;
Level = level;
}
}
}

View File

@ -0,0 +1,30 @@
//
// HeroSkillLevel.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.ObjectModels.NewWorldComputing
{
public enum HeroSkillLevel
{
Basic = 1,
Advanced = 2,
Expert = 3
}
}

View File

@ -0,0 +1,28 @@
//
// HeroSkillType.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.ObjectModels.NewWorldComputing
{
public enum HeroSkillType
{
Unknown = 255
}
}

View File

@ -24,9 +24,21 @@ namespace UniversalEditor.ObjectModels.NewWorldComputing.Map
/// <summary>
/// Represents an army monster placed on a Heroes of Might and Magic map.
/// </summary>
public class MapArmyMonster
public class MapArmyMonster : MapItem
{
public class MapArmyMonsterCollection
: System.Collections.ObjectModel.Collection<MapArmyMonster>
{
}
public ushort Amount { get; set; } = 0;
public MapMonsterType MonsterType { get; set; } = MapMonsterType.Unknown;
}
public MapArmyMonster(MapMonsterType monsterType, ushort amount)
{
MonsterType = monsterType;
Amount = amount;
}
}
}

View File

@ -0,0 +1,39 @@
//
// MapArtifact.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.ObjectModels.NewWorldComputing.Map
{
public class MapArtifact : MapItem
{
public class MapArtifactCollection
: System.Collections.ObjectModel.Collection<MapArtifact>
{
}
public MapArtifactType Type { get; set; } = MapArtifactType.Unknown;
public MapArtifact(MapArtifactType type)
{
Type = type;
}
}
}

View File

@ -0,0 +1,28 @@
//
// MapArtifactType.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.ObjectModels.NewWorldComputing.Map
{
public enum MapArtifactType : byte
{
Unknown = 255
}
}

View File

@ -26,7 +26,7 @@ namespace UniversalEditor.ObjectModels.NewWorldComputing.Map
/// <summary>
/// Defines characteristics related to a castle placed on a map.
/// </summary>
public class MapCastle
public class MapCastle : MapItem
{
private MapCastleColor mvarColor = MapCastleColor.Unknown;
public MapCastleColor Color { get { return mvarColor; } set { mvarColor = value; } }

View File

@ -26,12 +26,14 @@ namespace UniversalEditor.ObjectModels.NewWorldComputing.Map
/// </summary>
public enum MapCastleType : byte
{
Unknown = 0xFF,
Knight = 0,
Barbarian = 1,
Sorceress = 2,
Warlock = 3,
Wizard = 4,
Necroman = 5,
Unknown = 6
Multiple = 6,
Random = 7
}
}

View File

@ -0,0 +1,100 @@
//
// MapEvent.cs - represents an event which occurs on the map
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.ObjectModels.NewWorldComputing.Map
{
public class MapEvent
{
public class MapEventCollection
: System.Collections.ObjectModel.Collection<MapEvent>
{
}
// resource counts
/// <summary>
/// Gets or sets the amount of Wood resource that should be given to or taken from the player.
/// </summary>
/// <value>The amount of Wood resource that should be given to or taken from the player.</value>
public int AmountWood { get; set; } = 0;
// resource counts
/// <summary>
/// Gets or sets the amount of Mercury resource that should be given to or taken from the player.
/// </summary>
/// <value>The amount of Mercury resource that should be given to or taken from the player.</value>
public int AmountMercury { get; set; } = 0;
// resource counts
/// <summary>
/// Gets or sets the amount of Ore resource that should be given to or taken from the player.
/// </summary>
/// <value>The amount of Ore resource that should be given to or taken from the player.</value>
public int AmountOre { get; set; } = 0;
// resource counts
/// <summary>
/// Gets or sets the amount of Sulfur resource that should be given to or taken from the player.
/// </summary>
/// <value>The amount of Sulfur resource that should be given to or taken from the player.</value>
public int AmountSulfur { get; set; } = 0;
// resource counts
/// <summary>
/// Gets or sets the amount of Crystal resource that should be given to or taken from the player.
/// </summary>
/// <value>The amount of Crystal resource that should be given to or taken from the player.</value>
public int AmountCrystal { get; set; } = 0;
// resource counts
/// <summary>
/// Gets or sets the amount of Gems resource that should be given to or taken from the player.
/// </summary>
/// <value>The amount of Gems resource that should be given to or taken from the player.</value>
public int AmountGems { get; set; } = 0;
// resource counts
/// <summary>
/// Gets or sets the amount of Gold resource that should be given to or taken from the player.
/// </summary>
/// <value>The amount of Gold resource that should be given to or taken from the player.</value>
public int AmountGold { get; set; } = 0;
/// <summary>
/// Gets or sets a value indicating whether this <see cref="MapEvent"/> is available to be triggered by a non-player (i.e., computer) character.
/// </summary>
/// <value><c>true</c> if computer players are allowed to trigger the event; otherwise, <c>false</c>.</value>
public bool AllowComputer { get; set; } = false;
/// <summary>
/// Gets or sets a value indicating whether this <see cref="MapEvent" /> triggers only once.
/// </summary>
/// <value><c>true</c> if this <see cref="MapEvent" /> triggers only once; otherwise, <c>false</c>.</value>
public bool SingleVisit { get; set; } = false;
/// <summary>
/// Gets or sets a <see cref="MapKingdomColor" /> mask indicating the kingdom alliances which are allowed to trigger this event.
/// </summary>
/// <value>The kingdom alliances which are allowed to trigger this event.</value>
public MapKingdomColor AllowedKingdoms { get; set; } = MapKingdomColor.All;
/// <summary>
/// Gets or sets the message displayed to the player upon triggering this event.
/// </summary>
/// <value>The message displayed to the player upon triggering this event.</value>
public string Message { get; set; } = null;
}
}

View File

@ -0,0 +1,45 @@
//
// MapHero.cs - represents a hero on a map
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace UniversalEditor.ObjectModels.NewWorldComputing.Map
{
public class MapHero : MapItem
{
public bool HasCustomTroops { get; set; } = false;
public bool HasCustomName { get; set; } = false;
public string Name { get; set; } = null;
public MapArmyMonster.MapArmyMonsterCollection Monsters { get; } = new MapArmyMonster.MapArmyMonsterCollection();
public MapArtifact.MapArtifactCollection Artifacts { get; } = new MapArtifact.MapArtifactCollection();
public bool HasCustomSkills { get; set; } = false;
public HeroSkill.HeroSkillCollection Skills { get; } = new HeroSkill.HeroSkillCollection();
public bool HasCustomPortrait { get; set; }
public byte CustomPortraitIndex { get; set; }
public uint Experience { get; set; }
public bool Patrol { get; set; } = false;
public byte PatrolSquareCount { get; set; } = 0;
}
}

View File

@ -0,0 +1,33 @@
//
// MapItem.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.ObjectModels.NewWorldComputing.Map
{
public abstract class MapItem
{
public class MapItemCollection
: System.Collections.ObjectModel.Collection<MapItem>
{
}
}
}

View File

@ -0,0 +1,32 @@
//
// MapItemType.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.ObjectModels.NewWorldComputing.Map
{
public enum MapItemType
{
Monster = 0x16,
Castle = 0x46,
Hero = 0x4C,
Unknown1 = 0xC3
}
}

View File

@ -64,6 +64,9 @@ namespace UniversalEditor.ObjectModels.NewWorldComputing.Map
/// <value>The win conditions.</value>
public MapWinCondition WinConditions { get; set; } = MapWinCondition.None;
public MapWinCondition ComputerAlsoWins { get; set; } = MapWinCondition.None;
public bool AllowNormalVictory { get; set; } = false;
/// <summary>
/// Indicates the condition(s) required to lose a game using this map.
/// </summary>
@ -74,5 +77,8 @@ namespace UniversalEditor.ObjectModels.NewWorldComputing.Map
public string Description { get; set; } = String.Empty;
public MapTile.MapTileCollection Tiles { get; } = new MapTile.MapTileCollection();
public MapItem.MapItemCollection Items { get; } = new MapItem.MapItemCollection();
public byte ObeliskCount { get; set; } = 0;
}
}

View File

@ -0,0 +1,39 @@
//
// MapResourceType.cs
//
// Author:
// Michael Becker <alcexhim@gmail.com>
//
// Copyright (c) 2020 Mike Becker's Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
namespace UniversalEditor.ObjectModels.NewWorldComputing.Map
{
public enum MapResourceType
{
Wood = 0x00,
Mercury,
Ore,
Sulfur,
Crystal,
Gems,
Gold,
Lighthouse = 0x64,
DragonCity = 0x65,
AbandonedMine = 0x67
}
}

View File

@ -36,5 +36,16 @@ namespace UniversalEditor.ObjectModels.NewWorldComputing.Map
/// </summary>
/// <value>The type of the ground.</value>
public MapGroundType GroundType { get; set; } = MapGroundType.Unknown;
}
public byte ObjectName1 { get; set; }
public byte IndexName1 { get; set; }
public byte Quantity1 { get; set; }
public byte Quantity2 { get; set; }
public byte ObjectName2 { get; set; }
public byte IndexName2 { get; set; }
public byte Shape { get; set; }
public byte GeneralObject { get; set; }
public ushort IndexAddon { get; set; }
public uint UniqNumber1 { get; set; }
public uint UniqNumber2 { get; set; }
}
}

View File

@ -85,6 +85,25 @@
<Compile Include="DataFormats\NWCSceneLayout\NewWorldComputing\BIN\BINComponentType.cs" />
<Compile Include="DataFormats\Multimedia\Picture\NewWorldComputing\TIL\TILDataFormat.cs" />
<Compile Include="DataFormats\NWCSceneLayout\NewWorldComputing\BIN\BINComponentFlags.cs" />
<Compile Include="ObjectModels\NewWorldComputing\Map\MapEvent.cs" />
<Compile Include="ObjectModels\NewWorldComputing\Map\MapItemType.cs" />
<Compile Include="ObjectModels\NewWorldComputing\Map\MapItem.cs" />
<Compile Include="ObjectModels\NewWorldComputing\Map\MapHero.cs" />
<Compile Include="ObjectModels\NewWorldComputing\Map\MapArtifact.cs" />
<Compile Include="ObjectModels\NewWorldComputing\Map\MapArtifactType.cs" />
<Compile Include="ObjectModels\NewWorldComputing\HeroSkill.cs" />
<Compile Include="ObjectModels\NewWorldComputing\HeroSkillLevel.cs" />
<Compile Include="ObjectModels\NewWorldComputing\HeroSkillType.cs" />
<Compile Include="ObjectModels\NewWorldComputing\Map\MapResourceType.cs" />
<Compile Include="DataFormats\NewWorldComputing\WorldMap2D\NewWorldComputing\Heroes2\CastleFragment.cs" />
<Compile Include="DataFormats\NewWorldComputing\WorldMap2D\NewWorldComputing\Heroes2\MonsterFragment.cs" />
<Compile Include="DataFormats\NewWorldComputing\WorldMap2D\NewWorldComputing\Heroes2\HeroFragment.cs" />
<Compile Include="DataFormats\NewWorldComputing\WorldMap2D\NewWorldComputing\Heroes2\TileFragment.cs" />
<Compile Include="DataFormats\NewWorldComputing\WorldMap2D\NewWorldComputing\Heroes2\EventFragment.cs" />
<Compile Include="DataFormats\NewWorldComputing\Animation\BINDataFormat.cs" />
<Compile Include="DataFormats\NewWorldComputing\Animation\BINAnimationType.cs" />
<Compile Include="DataFormats\Multimedia\Picture\NewWorldComputing\PCX\PCXDataFormat.cs" />
<Compile Include="DataFormats\Multimedia\Palette\NewWorldComputing\RIFFPaletteDataFormat.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\UniversalEditor.Compression\UniversalEditor.Compression.csproj">
@ -126,6 +145,8 @@
<ItemGroup>
<Folder Include="DataFormats\NWCSceneLayout\NewWorldComputing\BIN\" />
<Folder Include="DataFormats\Multimedia\Picture\NewWorldComputing\TIL\" />
<Folder Include="DataFormats\NewWorldComputing\Animation\" />
<Folder Include="DataFormats\Multimedia\Picture\NewWorldComputing\PCX\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.