#region ================== Copyright (c) 2021 Boris Iwanski /* * 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. */ #endregion #region ================== Namespaces using System; using System.Collections.Generic; using System.ComponentModel; using System.Dynamic; using CodeImp.DoomBuilder.Editing; using CodeImp.DoomBuilder.BuilderModes; using CodeImp.DoomBuilder.Geometry; using CodeImp.DoomBuilder.Map; using CodeImp.DoomBuilder.VisualModes; #endregion namespace CodeImp.DoomBuilder.UDBScript.Wrapper { class SidedefWrapper : MapElementWrapper, IEquatable { #region ================== Variables private Sidedef sidedef; #endregion #region IEquatable members public bool Equals(SidedefWrapper other) { return sidedef == other.sidedef; } public override bool Equals(object obj) { return Equals((SidedefWrapper)obj); } public override int GetHashCode() { return sidedef.GetHashCode(); } #endregion #region ================== Properties /// /// The `Sidedef`'s index. Read-only. /// public int index { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the isFront property can not be accessed."); return sidedef.Index; } } /// /// `true` if this `Sidedef` is the front of its `Linedef`, otherwise `false`. Read-only. /// public bool isFront { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the isFront property can not be accessed."); return sidedef.IsFront; } } /// /// The `Sector` the `Sidedef` belongs to. Read-only. /// public SectorWrapper sector { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the sector property can not be accessed."); return new SectorWrapper(sidedef.Sector); } } /// /// The `Linedef` the `Sidedef` belongs to. Read-only. /// public LinedefWrapper line { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the line property can not be accessed."); return new LinedefWrapper(sidedef.Line); } } /// /// The `Sidedef` on the other side of this `Sidedef`'s `Linedef`. Returns `null` if there is no other. Read-only. /// public SidedefWrapper other { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the other property can not be accessed."); if (sidedef.Other == null) return null; return new SidedefWrapper(sidedef.Other); } } /// /// The `Sidedef`'s angle in degrees. Read-only. /// public double angle { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the angle property can not be accessed."); return Angle2D.RadToDeg(sidedef.Angle); } } /// /// The `Sidedef`'s angle in radians. Read-only. /// public double angleRad { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the angleRad property can not be accessed."); return sidedef.Angle; } } /// /// The x offset of the `Sidedef`'s textures. /// public int offsetX { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the offsetX property can not be accessed."); return sidedef.OffsetX; } set { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the offsetX property can not be accessed."); sidedef.OffsetX = value; } } /// /// The y offset of the `Sidedef`'s textures. /// public int offsetY { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the offsetY property can not be accessed."); return sidedef.OffsetY; } set { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the offsetY property can not be accessed."); sidedef.OffsetY = value; } } /// /// `Sidedef` flags. It's an object with the flags as properties. Only available in UDMF. /// /// ``` /// s.flags['noattack'] = true; // Monsters in this sector don't attack /// s.flags.noattack = true; // Also works /// ``` /// public ExpandoObject flags { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the flags property can not be accessed."); dynamic eo = new ExpandoObject(); IDictionary o = eo as IDictionary; foreach (KeyValuePair kvp in sidedef.GetFlags()) { o.Add(kvp.Key, kvp.Value); } // Create event that gets called when a property is changed. This sets the flag ((INotifyPropertyChanged)eo).PropertyChanged += new PropertyChangedEventHandler((sender, ea) => { PropertyChangedEventArgs pcea = ea as PropertyChangedEventArgs; IDictionary so = sender as IDictionary; // Only allow known flags to be set if (!General.Map.Config.SectorFlags.Keys.Contains(pcea.PropertyName)) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Flag name '" + pcea.PropertyName + "' is not valid."); // New value must be bool if (!(so[pcea.PropertyName] is bool)) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Flag values must be bool."); sidedef.SetFlag(pcea.PropertyName, (bool)so[pcea.PropertyName]); }); return eo; } } /// /// The `Sidedef`'s upper texture. /// public string upperTexture { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the upperTexture property can not be accessed."); return sidedef.HighTexture; } set { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the upperTexture property can not be accessed."); sidedef.SetTextureHigh(value); // Make sure to update the used textures, so that they are shown immediately General.Map.Data.UpdateUsedTextures(); } } /// /// The `Sidedef`'s middle texture. /// public string middleTexture { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the middleTexture property can not be accessed."); return sidedef.MiddleTexture; } set { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the middleTexture property can not be accessed."); sidedef.SetTextureMid(value); // Make sure to update the used textures, so that they are shown immediately General.Map.Data.UpdateUsedTextures(); } } /// /// The `Sidedef`'s lower texture. /// public string lowerTexture { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the lowerTexture property can not be accessed."); return sidedef.LowTexture; } set { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the lowerTexture property can not be accessed."); sidedef.SetTextureLow(value); // Make sure to update the used textures, so that they are shown immediately General.Map.Data.UpdateUsedTextures(); } } /// /// If the `Sidedef`'s upper part is selected or not. Will always return `true` in classic modes if the parent `Linedef` is selected. /// /// 3 public bool upperSelected { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the upperSelected property can not be accessed."); if(General.Editing.Mode is BaseVisualMode) { bool u, m, l; ((BaseVisualMode)General.Editing.Mode).GetSelectedSurfaceTypesBySidedef(sidedef, out u, out m, out l); return u; } else { return sidedef.Line.Selected; } } } /// /// If the `Sidedef`'s upper part is highlighted or not. Will always return `true` in classic modes if the parent `Linedef` is selected. /// /// 3 public bool upperHighlighted { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the upperHighlighted property can not be accessed."); if (General.Editing.Mode is BaseVisualMode) { VisualGeometry vs = (VisualGeometry)((BaseVisualMode)General.Editing.Mode).Highlighted; if (vs == null) return false; return (vs.Sidedef == sidedef && vs.GeometryType == VisualGeometryType.WALL_UPPER); } else { Linedef ld = ((ClassicMode)General.Editing.Mode).HighlightedObject as Linedef; if (ld == null) return false; return (ld.Front == sidedef || (ld.Back != null && ld.Back == sidedef)); } } } /// /// If the `Sidedef`'s middle part is selected or not. Will always return `true` in classic modes if the parent `Linedef` is selected. /// /// 3 public bool middleSelected { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the middleSelected property can not be accessed."); if (General.Editing.Mode is BaseVisualMode) { bool u, m, l; ((BaseVisualMode)General.Editing.Mode).GetSelectedSurfaceTypesBySidedef(sidedef, out u, out m, out l); return m; } else { return sidedef.Line.Selected; } } } /// /// If the `Sidedef`'s middle part is highlighted or not. Will always return `true` in classic modes if the parent `Linedef` is selected. /// /// 3 public bool middleHighlighted { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the middleHighlighted property can not be accessed."); if (General.Editing.Mode is BaseVisualMode) { VisualGeometry vs = (VisualGeometry)((BaseVisualMode)General.Editing.Mode).Highlighted; if (vs == null) return false; return (vs.Sidedef == sidedef && (vs.GeometryType == VisualGeometryType.WALL_MIDDLE || vs.GeometryType == VisualGeometryType.WALL_MIDDLE_3D)); } else { Linedef ld = ((ClassicMode)General.Editing.Mode).HighlightedObject as Linedef; if (ld == null) return false; return (ld.Front == sidedef || (ld.Back != null && ld.Back == sidedef)); } } } /// /// If the `Sidedef`'s lower part is selected or not. Will always return `true` in classic modes if the parent `Linedef` is selected. /// /// 3 public bool lowerSelected { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the lowerSelected property can not be accessed."); if (General.Editing.Mode is BaseVisualMode) { bool u, m, l; ((BaseVisualMode)General.Editing.Mode).GetSelectedSurfaceTypesBySidedef(sidedef, out u, out m, out l); return l; } else { return sidedef.Line.Selected; } } } /// /// If the `Sidedef`'s lower part is highlighted or not. Will always return `true` in classic modes if the parent `Linedef` is selected. /// /// 3 public bool lowerHighlighted { get { if (sidedef.IsDisposed) throw BuilderPlug.Me.ScriptRunner.CreateRuntimeException("Sidedef is disposed, the lowerHighlighted property can not be accessed."); if (General.Editing.Mode is BaseVisualMode) { VisualGeometry vs = (VisualGeometry)((BaseVisualMode)General.Editing.Mode).Highlighted; if (vs == null) return false; return (vs.Sidedef == sidedef && vs.GeometryType == VisualGeometryType.WALL_LOWER); } else { Linedef ld = ((ClassicMode)General.Editing.Mode).HighlightedObject as Linedef; if (ld == null) return false; return (ld.Front == sidedef || (ld.Back != null && ld.Back == sidedef)); } } } #endregion #region ================== Constructors internal SidedefWrapper(Sidedef sidedef) : base(sidedef) { this.sidedef = sidedef; } #endregion #region ================== Update internal override void AfterFieldsUpdate() { } #endregion #region ================== Methods public override string ToString() { return sidedef.ToString(); } #endregion } }