diff --git a/Build/Configurations/Includes/ZDoom_misc.cfg b/Build/Configurations/Includes/ZDoom_misc.cfg
index e3331977..e9214876 100644
--- a/Build/Configurations/Includes/ZDoom_misc.cfg
+++ b/Build/Configurations/Includes/ZDoom_misc.cfg
@@ -861,6 +861,17 @@ enums
75 = "75%";
100 = "100%";
}
+
+ ambient_sounds
+ {
+ 0 = "None";
+ }
+
+ sound_sequences
+ {
+ 0 = "None";
+ 255 = "Default";
+ }
setadd
{
diff --git a/Build/Configurations/Includes/ZDoom_things.cfg b/Build/Configurations/Includes/ZDoom_things.cfg
index 041385cb..13740cdc 100644
--- a/Build/Configurations/Includes/ZDoom_things.cfg
+++ b/Build/Configurations/Includes/ZDoom_things.cfg
@@ -114,10 +114,7 @@ zdoom
{
title = "Sound Sequence Index";
type = 11;
- enum
- {
- 255 = "Default";
- }
+ enum = "sound_sequences";
}
}
@@ -193,6 +190,8 @@ zdoom
arg0
{
title = "Ambient Sound Index";
+ type = 11;
+ enum = "ambient_sounds";
}
arg1
{
@@ -221,6 +220,8 @@ zdoom
arg0
{
title = "Sound Sequence Index";
+ type = 11;
+ enum = "sound_sequences";
}
arg1
{
@@ -235,6 +236,8 @@ zdoom
arg0
{
title = "Ambient Sound Index";
+ type = 11;
+ enum = "ambient_sounds";
}
arg1
{
diff --git a/Help/gzdb/text_lumps.html b/Help/gzdb/text_lumps.html
index 25817d50..d1157263 100644
--- a/Help/gzdb/text_lumps.html
+++ b/Help/gzdb/text_lumps.html
@@ -38,7 +38,8 @@
Both new and old MAPINFO definition styles are supported.
You can use "//$GZDB_SKIP" special comment to abort parsing of the current file.
DoomEdNum overrides are supported.
- SpawnNums overrides are supported. The values are used to update "spawnthing" Game Configuration enum.
+ SpawnNums overrides are supported. The values are used to update "spawnthing" Game Configuration enum.
+
In addition, following values from (Z)MAPINFO are supported by Visual mode:
- fade;
@@ -55,6 +56,9 @@
REVERBS:
Sound environment definitions are loaded and can be used in the Sound Environment Mode.
+ SNDINFO:
+ Ambient sound definitions are loaded. The values are used to update the titles of "Ambient Sound NN" things and to populate "ambient_sounds" Game Configuration enum.
+
SNDSEQ:
Sound Sequence and Sound Sequence Group definitions are loaded and can be selected in the "Sound sequence" drop-down of the Edit Sector window (UDMF only).
diff --git a/Source/Core/Builder.csproj b/Source/Core/Builder.csproj
index 3eeee099..0c8b6777 100644
--- a/Source/Core/Builder.csproj
+++ b/Source/Core/Builder.csproj
@@ -1035,6 +1035,7 @@
+
diff --git a/Source/Core/Config/ScriptConfiguration.cs b/Source/Core/Config/ScriptConfiguration.cs
index e8d33473..1bb3b464 100644
--- a/Source/Core/Config/ScriptConfiguration.cs
+++ b/Source/Core/Config/ScriptConfiguration.cs
@@ -44,6 +44,7 @@ namespace CodeImp.DoomBuilder.Config
TERRAIN,
X11R6RGB,
CVARINFO,
+ SNDINFO,
}
internal class ScriptConfiguration : IComparable
diff --git a/Source/Core/Config/ThingTypeInfo.cs b/Source/Core/Config/ThingTypeInfo.cs
index dc968607..d1db8523 100644
--- a/Source/Core/Config/ThingTypeInfo.cs
+++ b/Source/Core/Config/ThingTypeInfo.cs
@@ -95,7 +95,7 @@ namespace CodeImp.DoomBuilder.Config
#region ================== Properties
public int Index { get { return index; } }
- public string Title { get { return title; } }
+ public string Title { get { return title; } internal set { title = value; } } //mxd. Added setter
public string Sprite { get { return sprite; } }
public SpriteFrameInfo[] SpriteFrame { get { return spriteframe; } }
public ActorStructure Actor { get { return actor; } }
@@ -405,7 +405,8 @@ namespace CodeImp.DoomBuilder.Config
#region ================== Methods
// This updates the properties from a decorate actor
- internal void ModifyByDecorateActor(ActorStructure actor)
+ internal void ModifyByDecorateActor(ActorStructure actor) { ModifyByDecorateActor(actor, false); } //mxd
+ internal void ModifyByDecorateActor(ActorStructure actor, bool replacetitle)
{
// Keep reference to actor
this.actor = actor;
@@ -420,7 +421,7 @@ namespace CodeImp.DoomBuilder.Config
if(!tag.StartsWith("\"$")) title = tag; //mxd. Don't use LANGUAGE keywords.
}
- if(string.IsNullOrEmpty(title)) title = actor.ClassName;
+ if(string.IsNullOrEmpty(title) || replacetitle) title = actor.ClassName;
//mxd. Color override?
if(actor.HasPropertyWithValue("$color"))
diff --git a/Source/Core/Data/DataManager.cs b/Source/Core/Data/DataManager.cs
index de4e3068..29794eee 100644
--- a/Source/Core/Data/DataManager.cs
+++ b/Source/Core/Data/DataManager.cs
@@ -432,6 +432,7 @@ namespace CodeImp.DoomBuilder.Data
//mxd. Load more stuff
LoadReverbs();
LoadSndSeq();
+ LoadSndInfo();
LoadVoxels();
Dictionary actorsbyclass = CreateActorsByClassList();
LoadModeldefs(actorsbyclass);
@@ -1785,12 +1786,26 @@ namespace CodeImp.DoomBuilder.Data
// Apply to collection
damagetypes = new string[dtypes.Count];
dtypes.CopyTo(damagetypes);
+
+ // Step 0. Create ThingTypeInfo by classname collection...
+ Dictionary thingtypesbyclass = new Dictionary(thingtypes.Count, StringComparer.OrdinalIgnoreCase);
+ foreach(ThingTypeInfo info in thingtypes.Values)
+ if(!string.IsNullOrEmpty(info.ClassName)) thingtypesbyclass[info.ClassName] = info;
// Step 1. Go for all actors in the decorate to make things or update things
foreach(ActorStructure actor in decorate.Actors)
{
+ //mxd. Apply "replaces" DECORATE override...
+ if(!string.IsNullOrEmpty(actor.ReplacesClass) && thingtypesbyclass.ContainsKey(actor.ReplacesClass))
+ {
+ // Update info
+ thingtypesbyclass[actor.ReplacesClass].ModifyByDecorateActor(actor, true);
+
+ // Count
+ counter++;
+ }
// Check if we want to add this actor
- if(actor.DoomEdNum > 0)
+ else if(actor.DoomEdNum > 0)
{
// Check if we can find this thing in our existing collection
if(thingtypes.ContainsKey(actor.DoomEdNum))
@@ -1818,13 +1833,6 @@ namespace CodeImp.DoomBuilder.Data
if(doomednumsoverride.Count > 0)
{
List toremove = new List();
- Dictionary thingtypesbyclass = new Dictionary();
- foreach(KeyValuePair group in thingtypes)
- {
- if(string.IsNullOrEmpty(group.Value.ClassName)) continue;
- thingtypesbyclass[group.Value.ClassName.ToLowerInvariant()] = group.Value;
- }
-
foreach(KeyValuePair group in doomednumsoverride)
{
// Remove thing from the list?
@@ -2093,7 +2101,7 @@ namespace CodeImp.DoomBuilder.Data
if(!string.IsNullOrEmpty(ti.Value.ClassName))
{
if(actors.ContainsKey(ti.Value.ClassName) && actors[ti.Value.ClassName] != ti.Key)
- General.ErrorLogger.Add(ErrorType.Warning, "Actor \"" + ti.Value.ClassName + "\" has several editor numbers! Only the last one (" + ti.Key + ") will be used.");
+ General.ErrorLogger.Add(ErrorType.Warning, "Actor \"" + ti.Value.ClassName + "\" has several editor numbers (" + actors[ti.Value.ClassName] + " and " + ti.Key + "). Only the last one will be used.");
actors[ti.Value.ClassName] = ti.Key;
}
}
@@ -2451,6 +2459,81 @@ namespace CodeImp.DoomBuilder.Data
reverbs = parser.GetReverbs();
}
+ //mxd. This loads SNDINFO
+ private void LoadSndInfo()
+ {
+ // Bail out when not supported by current game configuration
+ if(string.IsNullOrEmpty(General.Map.Config.DecorateGames)) return;
+
+ SndInfoParser parser = new SndInfoParser();
+ foreach(DataReader dr in containers)
+ {
+ currentreader = dr;
+ IEnumerable streams = dr.GetSndInfoData();
+
+ // Parse the data
+ foreach(TextResourceData data in streams)
+ {
+ parser.Parse(data, true);
+
+ // Report errors?
+ if(parser.HasError) parser.LogError();
+ }
+ }
+
+ // Add to text resources collection
+ textresources[parser.ScriptType] = new HashSet(parser.TextResources.Values);
+ currentreader = null;
+
+ // Anything to do?
+ if(parser.AmbientSounds.Count > 0)
+ {
+ // Update or create the main enums list
+ Dictionary configenums = new Dictionary();
+ if(General.Map.Config.Enums.ContainsKey("ambient_sounds"))
+ {
+ foreach(EnumItem item in General.Map.Config.Enums["ambient_sounds"])
+ configenums.Add(item.GetIntValue(), item);
+ }
+ if(configenums.ContainsKey(0)) configenums.Remove(0);
+
+ foreach(KeyValuePair group in parser.AmbientSounds)
+ {
+ configenums[group.Key] = new EnumItem(group.Key.ToString(), group.Value);
+ }
+
+ // Store results in "ambient_sounds" enum
+ EnumList newenums = new EnumList();
+ newenums.AddRange(configenums.Values);
+ newenums.Sort((a, b) => a.Title.CompareTo(b.Title)); // Sort by title
+ newenums.Insert(0, new EnumItem("0", "None")); // Add "None" value
+ General.Map.Config.Enums["ambient_sounds"] = newenums;
+
+ // Update all ArgumentInfos...
+ foreach(ThingTypeInfo info in thingtypes.Values)
+ {
+ foreach(ArgumentInfo ai in info.Args)
+ if(ai.Enum.Name == "ambient_sounds") ai.Enum = newenums;
+ }
+
+ foreach(LinedefActionInfo info in General.Map.Config.LinedefActions.Values)
+ {
+ foreach(ArgumentInfo ai in info.Args)
+ if(ai.Enum.Name == "ambient_sounds") ai.Enum = newenums;
+ }
+
+ // Update "Ambient Sound XX" thing names. Hardcoded for things 14001 - 14064 for now...
+ for(int i = 14001; i < 14065; i++)
+ {
+ int ambsoundindex = i - 14000;
+ if(!configenums.ContainsKey(ambsoundindex) || !thingtypes.ContainsKey(i) || !string.IsNullOrEmpty(thingtypes[i].ClassName)) continue;
+
+ // Update title
+ thingtypes[i].Title += " (" + configenums[ambsoundindex] + ")";
+ }
+ }
+ }
+
//mxd. This loads SNDSEQ
private void LoadSndSeq()
{
@@ -2473,7 +2556,7 @@ namespace CodeImp.DoomBuilder.Data
}
}
- //mxd. Add to text resources collection
+ // Add to text resources collection
textresources[parser.ScriptType] = new HashSet(parser.TextResources.Values);
currentreader = null;
soundsequences = parser.GetSoundSequences();
diff --git a/Source/Core/Data/DataReader.cs b/Source/Core/Data/DataReader.cs
index 5f1ab25e..64b88021 100644
--- a/Source/Core/Data/DataReader.cs
+++ b/Source/Core/Data/DataReader.cs
@@ -221,37 +221,40 @@ namespace CodeImp.DoomBuilder.Data
#region ================== Decorate, Modeldef, Mapinfo, Gldefs, etc...
- // When implemented, this returns the DECORATE lump
+ // When implemented, this returns DECORATE lumps
public abstract IEnumerable GetDecorateData(string pname);
- //mxd. When implemented, this returns the MODELDEF lump
+ //mxd. When implemented, this returns MODELDEF lumps
public abstract IEnumerable GetModeldefData();
- //mxd. When implemented, this returns the MAPINFO lump
+ //mxd. When implemented, this returns MAPINFO lumps
public abstract IEnumerable GetMapinfoData();
- //mxd. When implemented, this returns the GLDEFS lump
+ //mxd. When implemented, this returns GLDEFS lumps
public abstract IEnumerable GetGldefsData(GameType gametype);
- //mxd. When implemented, this returns the REVERBS lump
+ //mxd. When implemented, this returns REVERBS lumps
public abstract IEnumerable GetReverbsData();
- //mxd. When implemented, this returns the VOXELDEF lump
+ //mxd. When implemented, this returns VOXELDEF lumps
public abstract IEnumerable GetVoxeldefData();
- //mxd. When implemented, this returns the SNDSEQ lump
+ //mxd. When implemented, this returns SNDINFO lumps
+ public abstract IEnumerable GetSndInfoData();
+
+ //mxd. When implemented, this returns SNDSEQ lumps
public abstract IEnumerable GetSndSeqData();
- //mxd. When implemented, this returns the ANIMDEFS lump
+ //mxd. When implemented, this returns ANIMDEFS lumps
public abstract IEnumerable GetAnimdefsData();
- //mxd. When implemented, this returns the TERRAIN lump
+ //mxd. When implemented, this returns TERRAIN lumps
public abstract IEnumerable GetTerrainData();
- //mxd. When implemented, this returns the X11R6RGB lump
+ //mxd. When implemented, this returns X11R6RGB lumps
public abstract IEnumerable GetX11R6RGBData();
- //mxd. When implemented, this returns the CVARINFO lump
+ //mxd. When implemented, this returns CVARINFO lumps
public abstract IEnumerable GetCvarInfoData();
//mxd. When implemented, this returns the list of voxel model names
diff --git a/Source/Core/Data/PK3StructuredReader.cs b/Source/Core/Data/PK3StructuredReader.cs
index d2886c55..c2c4328d 100644
--- a/Source/Core/Data/PK3StructuredReader.cs
+++ b/Source/Core/Data/PK3StructuredReader.cs
@@ -675,6 +675,28 @@ namespace CodeImp.DoomBuilder.Data
#endregion
+ #region ================== SNDINFO (mxd)
+
+ public override IEnumerable GetSndInfoData()
+ {
+ // Error when suspended
+ if(issuspended) throw new Exception("Data reader is suspended");
+
+ List result = new List();
+ string[] files = GetAllFilesWithTitle("", "SNDINFO", false);
+
+ // Add to collection
+ foreach(string s in files)
+ result.Add(new TextResourceData(this, LoadFile(s), s, true));
+
+ // Find in any of the wad files
+ foreach(WADReader wr in wads) result.AddRange(wr.GetSndInfoData());
+
+ return result;
+ }
+
+ #endregion
+
#region ================== SNDSEQ (mxd)
public override IEnumerable GetSndSeqData()
diff --git a/Source/Core/Data/WADReader.cs b/Source/Core/Data/WADReader.cs
index 83373514..d24d7665 100644
--- a/Source/Core/Data/WADReader.cs
+++ b/Source/Core/Data/WADReader.cs
@@ -1047,6 +1047,13 @@ namespace CodeImp.DoomBuilder.Data
return GetAllLumps("REVERBS");
}
+ //mxd
+ public override IEnumerable GetSndInfoData()
+ {
+ if(issuspended) throw new Exception("Data reader is suspended");
+ return GetAllLumps("SNDINFO");
+ }
+
//mxd
public override IEnumerable GetSndSeqData()
{
diff --git a/Source/Core/ZDoom/ActorStructure.cs b/Source/Core/ZDoom/ActorStructure.cs
index 903e992a..5da6f145 100644
--- a/Source/Core/ZDoom/ActorStructure.cs
+++ b/Source/Core/ZDoom/ActorStructure.cs
@@ -331,7 +331,7 @@ namespace CodeImp.DoomBuilder.ZDoom
int arrlen = -1;
if(!parser.ReadSignedInt(ref arrlen))
{
- parser.ReportError("Expected User Array length, but got \"" + next + "\"");
+ parser.ReportError("Expected User Array length");
return;
}
if(arrlen < 1)
diff --git a/Source/Core/ZDoom/SndInfoParser.cs b/Source/Core/ZDoom/SndInfoParser.cs
new file mode 100644
index 00000000..f8676443
--- /dev/null
+++ b/Source/Core/ZDoom/SndInfoParser.cs
@@ -0,0 +1,94 @@
+#region ================== Namespaces
+
+using System.Collections.Generic;
+using CodeImp.DoomBuilder.Config;
+using CodeImp.DoomBuilder.Data;
+
+#endregion
+
+namespace CodeImp.DoomBuilder.ZDoom
+{
+ internal sealed class SndInfoParser : ZDTextParser
+ {
+ #region ================== Variables
+
+ private Dictionary ambientsounds;
+
+ #endregion
+
+ #region ================== Properties
+
+ internal override ScriptType ScriptType { get { return ScriptType.SNDINFO; } }
+
+ internal Dictionary AmbientSounds { get { return ambientsounds; } }
+
+ #endregion
+
+ #region ================== Constructor
+
+ public SndInfoParser()
+ {
+ specialtokens = "";
+ ambientsounds = new Dictionary();
+ }
+
+ #endregion
+
+ #region ================== Parsing
+
+ public override bool Parse(TextResourceData data, bool clearerrors)
+ {
+ //mxd. Already parsed?
+ if(!base.AddTextResource(data))
+ {
+ if(clearerrors) ClearError();
+ return true;
+ }
+
+ // Cannot process?
+ if(!base.Parse(data, clearerrors)) return false;
+
+ // Continue until at the end of the stream
+ while(SkipWhitespace(true))
+ {
+ string token = ReadToken().ToLowerInvariant();
+ if(string.IsNullOrEmpty(token)) continue;
+
+ switch(token)
+ {
+ //$ambient [type]
+ case "$ambient":
+ // Read index
+ SkipWhitespace(true);
+ int index = -1;
+ if(!ReadSignedInt(ref index) || index < 0)
+ {
+ // Not numeric!
+ ReportError("Expected ambient sound index");
+ return false;
+ }
+
+ // Read name
+ SkipWhitespace(true);
+ string logicalsound = StripQuotes(ReadToken(false));
+ if(string.IsNullOrEmpty(logicalsound))
+ {
+ ReportError("Expected ambient sound logicalname");
+ return false;
+ }
+
+ // Add to collection
+ if(ambientsounds.ContainsKey(index))
+ LogWarning("Ambient sound " + index + " is double-defined as \"" + ambientsounds[index] + "\" and \"" + logicalsound + "\"");
+
+ ambientsounds[index] = logicalsound;
+ break;
+ }
+ }
+
+ return true;
+ }
+
+ #endregion
+ }
+}