private void alpha_WhenTextChanged(object sender, EventArgs e)
        {
            if (preventchanges)
            {
                return;
            }
            MakeUndo();             //mxd
            int i = 0;

            //restore values
            if (string.IsNullOrEmpty(alpha.Text))
            {
                foreach (Thing t in things)
                {
                    UniFields.SetFloat(t.Fields, "alpha", thingprops[i++].Alpha, 1.0);
                }
            }
            else             //update values
            {
                foreach (Thing t in things)
                {
                    double value = General.Clamp(alpha.GetResultFloat(t.Fields.GetValue("alpha", 1.0)), 0.0, 1.0);
                    UniFields.SetFloat(t.Fields, "alpha", value, 1.0);
                }
            }

            resetalpha.Visible = (alpha.GetResultFloat(1.0) != 1.0);

            General.Map.IsChanged = true;
            if (OnValuesChanged != null)
            {
                OnValuesChanged(this, EventArgs.Empty);
            }
        }
Exemplo n.º 2
0
        //mxd. Texture scale change
        protected override void ChangeTextureScale(int incrementX, int incrementY)
        {
            if (Texture == null || !Texture.IsImageLoaded)
            {
                return;
            }
            Sector s      = GetControlSector();
            float  scaleX = s.Fields.GetValue("xscalefloor", 1.0f);
            float  scaleY = s.Fields.GetValue("yscalefloor", 1.0f);

            s.Fields.BeforeFieldsChange();

            if (incrementX != 0)
            {
                float pix       = (int)Math.Round(Texture.Width * scaleX) - incrementX;
                float newscaleX = (float)Math.Round(pix / Texture.Width, 3);
                scaleX = (newscaleX == 0 ? scaleX * -1 : newscaleX);
                UniFields.SetFloat(s.Fields, "xscalefloor", scaleX, 1.0f);
            }

            if (incrementY != 0)
            {
                float pix       = (int)Math.Round(Texture.Height * scaleY) - incrementY;
                float newscaleY = (float)Math.Round(pix / Texture.Height, 3);
                scaleY = (newscaleY == 0 ? scaleY * -1 : newscaleY);
                UniFields.SetFloat(s.Fields, "yscalefloor", scaleY, 1.0f);
            }

            mode.SetActionResult("Floor scale changed to " + scaleX.ToString("F03", CultureInfo.InvariantCulture) + ", " + scaleY.ToString("F03", CultureInfo.InvariantCulture) + " (" + (int)Math.Round(Texture.Width / scaleX) + " x " + (int)Math.Round(Texture.Height / scaleY) + ").");
        }
        //mxd
        public virtual void OnChangeTextureRotation(float angle)
        {
            if (!General.Map.UDMF)
            {
                return;
            }

            if ((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket))
            {
                undoticket = mode.CreateUndo("Change texture rotation");
            }

            string key = (GeometryType == VisualGeometryType.FLOOR ? "rotationfloor" : "rotationceiling");

            mode.SetActionResult((GeometryType == VisualGeometryType.FLOOR ? "Floor" : "Ceiling") + " rotation changed to " + angle);

            //set value
            Sector s = GetControlSector();

            s.Fields.BeforeFieldsChange();
            UniFields.SetFloat(s.Fields, key, angle, 0.0f);

            if (s.Index != Sector.Sector.Index)
            {
                s.UpdateNeeded = true;
                s.UpdateCache();
                mode.GetSectorData(s).Update();
                BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(s);
                vs.UpdateSectorGeometry(false);
            }

            Sector.Sector.UpdateNeeded = true;
            Sector.Sector.UpdateCache();
            Sector.UpdateSectorGeometry(false);
        }
        //mxd. Only control sidedef scale is used by GZDoom
        public override void OnChangeScale(int incrementX, int incrementY)
        {
            if (!General.Map.UDMF || Texture == null || !Texture.IsImageLoaded)
            {
                return;
            }

            if ((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket))
            {
                undoticket = mode.CreateUndo("Change wall scale");
            }

            Sidedef target = extrafloor.Linedef.Front;

            if (target == null)
            {
                return;
            }

            float scaleX = target.Fields.GetValue("scalex_mid", 1.0f);
            float scaleY = target.Fields.GetValue("scaley_mid", 1.0f);

            target.Fields.BeforeFieldsChange();

            if (incrementX != 0)
            {
                float pix       = (int)Math.Round(Texture.Width * scaleX) - incrementX;
                float newscaleX = (float)Math.Round(pix / Texture.Width, 3);
                scaleX = (newscaleX == 0 ? scaleX * -1 : newscaleX);
                UniFields.SetFloat(target.Fields, "scalex_mid", scaleX, 1.0f);
            }

            if (incrementY != 0)
            {
                float pix       = (int)Math.Round(Texture.Height * scaleY) - incrementY;
                float newscaleY = (float)Math.Round(pix / Texture.Height, 3);
                scaleY = (newscaleY == 0 ? scaleY * -1 : newscaleY);
                UniFields.SetFloat(target.Fields, "scaley_mid", scaleY, 1.0f);
            }

            // Update the model sector to update all 3d floors
            mode.GetVisualSector(extrafloor.Linedef.Front.Sector).UpdateSectorGeometry(false);

            // Display result
            mode.SetActionResult("Wall scale changed to " + scaleX.ToString("F03", CultureInfo.InvariantCulture) + ", " + scaleY.ToString("F03", CultureInfo.InvariantCulture) + " (" + (int)Math.Round(Texture.Width / scaleX) + " x " + (int)Math.Round(Texture.Height / scaleY) + ").");
        }
Exemplo n.º 5
0
        //mxd. Texture scale change
        protected override void ChangeTextureScale(int incrementX, int incrementY)
        {
            if (Texture == null || !Texture.IsImageLoaded)
            {
                return;
            }
            Sector s      = GetControlSector();
            float  scaleX = s.Fields.GetValue("xscalefloor", 1.0f);
            float  scaleY = s.Fields.GetValue("yscalefloor", 1.0f);

            s.Fields.BeforeFieldsChange();

            if (incrementX != 0)
            {
                float pix       = (int)Math.Round(Texture.Width * scaleX) - incrementX;
                float newscaleX = (float)Math.Round(pix / Texture.Width, 3);
                scaleX = (newscaleX == 0 ? scaleX * -1 : newscaleX);
                UniFields.SetFloat(s.Fields, "xscalefloor", scaleX, 1.0f);
            }

            if (incrementY != 0)
            {
                float pix       = (int)Math.Round(Texture.Height * scaleY) - incrementY;
                float newscaleY = (float)Math.Round(pix / Texture.Height, 3);
                scaleY = (newscaleY == 0 ? scaleY * -1 : newscaleY);
                UniFields.SetFloat(s.Fields, "yscalefloor", scaleY, 1.0f);
            }

            // Update geometry
            if (mode.VisualSectorExists(level.sector))
            {
                BaseVisualSector vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
                vs.UpdateSectorGeometry(false);
            }

            s.UpdateNeeded = true;
            s.UpdateCache();
            if (s.Index != Sector.Sector.Index)
            {
                Sector.Sector.UpdateNeeded = true;
                Sector.Sector.UpdateCache();
            }

            mode.SetActionResult("Floor scale changed to " + scaleX.ToString("F03", CultureInfo.InvariantCulture) + ", " + scaleY.ToString("F03", CultureInfo.InvariantCulture) + " (" + (int)Math.Round(Texture.Width / scaleX) + " x " + (int)Math.Round(Texture.Height / scaleY) + ").");
        }
Exemplo n.º 6
0
        //mxd
        public virtual void OnChangeTextureRotation(float angle)
        {
            if (!General.Map.UDMF)
            {
                return;
            }

            if ((General.Map.UndoRedo.NextUndo == null) || (General.Map.UndoRedo.NextUndo.TicketID != undoticket))
            {
                undoticket = mode.CreateUndo("Change texture rotation");
            }

            string key = (GeometryType == VisualGeometryType.FLOOR ? "rotationfloor" : "rotationceiling");

            mode.SetActionResult((GeometryType == VisualGeometryType.FLOOR ? "Floor" : "Ceiling") + " rotation changed to " + angle);

            // Set new angle
            Sector s = GetControlSector();

            s.Fields.BeforeFieldsChange();
            UniFields.SetFloat(s.Fields, key, angle, 0.0f);

            // Mark as changed
            changed = true;

            // Rebuild sector
            BaseVisualSector vs;

            if (mode.VisualSectorExists(level.sector))
            {
                vs = (BaseVisualSector)mode.GetVisualSector(level.sector);
            }
            else
            {
                //mxd. Need this to apply changes to 3d-floor even if control sector doesn't exist as BaseVisualSector
                vs = mode.CreateBaseVisualSector(level.sector);
            }

            if (vs != null)
            {
                vs.UpdateSectorGeometry(false);
            }
        }
Exemplo n.º 7
0
        public void ApplyTo(UniFields fields, int min, int max, float oldValue1, float oldValue2)
        {
            if (!string.IsNullOrEmpty(value1.Text))
            {
                UniFields.SetFloat(fields, field1, General.Clamp(value1.GetResultFloat(oldValue1), min, max), defaultValue);
            }
            else
            {
                UniFields.SetFloat(fields, field1, oldValue1, defaultValue);
            }

            if (!string.IsNullOrEmpty(value2.Text))
            {
                UniFields.SetFloat(fields, field2, General.Clamp(value2.GetResultFloat(oldValue2), min, max), defaultValue);
            }
            else
            {
                UniFields.SetFloat(fields, field2, oldValue2, defaultValue);
            }
        }
Exemplo n.º 8
0
        //mxd
        protected void AlignTextureToSlopeLine(Linedef slopeSource, float slopeAngle, bool isFront, bool alignx, bool aligny)
        {
            bool isFloor = (geometrytype == VisualGeometryType.FLOOR);

            Sector.Sector.Fields.BeforeFieldsChange();
            float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(slopeSource.Angle) + 90 : -Angle2D.RadToDeg(slopeSource.Angle) - 90), 1);

            if (isFloor)
            {
                if ((isFront && slopeSource.Front.Sector.FloorHeight > slopeSource.Back.Sector.FloorHeight) ||
                    (!isFront && slopeSource.Front.Sector.FloorHeight < slopeSource.Back.Sector.FloorHeight))
                {
                    sourceAngle = General.ClampAngle(sourceAngle + 180);
                }
            }
            else
            {
                if ((isFront && slopeSource.Front.Sector.CeilHeight < slopeSource.Back.Sector.CeilHeight) ||
                    (!isFront && slopeSource.Front.Sector.CeilHeight > slopeSource.Back.Sector.CeilHeight))
                {
                    sourceAngle = General.ClampAngle(sourceAngle + 180);
                }
            }

            //update angle
            UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "rotationfloor" : "rotationceiling"), sourceAngle, 0f);

            //update scaleY
            string xScaleKey = (isFloor ? "xscalefloor" : "xscaleceiling");
            string yScaleKey = (isFloor ? "yscalefloor" : "yscaleceiling");

            float scaleX = Sector.Sector.Fields.GetValue(xScaleKey, 1.0f);
            float scaleY;

            //set scale
            if (aligny)
            {
                scaleY = (float)Math.Round(scaleX * (1 / (float)Math.Cos(slopeAngle)), 2);
                UniFields.SetFloat(Sector.Sector.Fields, yScaleKey, scaleY, 1.0f);
            }
            else
            {
                scaleY = Sector.Sector.Fields.GetValue(yScaleKey, 1.0f);
            }

            //update texture offsets
            Vector2D offset;

            if (isFloor)
            {
                if ((isFront && slopeSource.Front.Sector.FloorHeight < slopeSource.Back.Sector.FloorHeight) ||
                    (!isFront && slopeSource.Front.Sector.FloorHeight > slopeSource.Back.Sector.FloorHeight))
                {
                    offset = slopeSource.End.Position;
                }
                else
                {
                    offset = slopeSource.Start.Position;
                }
            }
            else
            {
                if ((isFront && slopeSource.Front.Sector.CeilHeight > slopeSource.Back.Sector.CeilHeight) ||
                    (!isFront && slopeSource.Front.Sector.CeilHeight < slopeSource.Back.Sector.CeilHeight))
                {
                    offset = slopeSource.End.Position;
                }
                else
                {
                    offset = slopeSource.Start.Position;
                }
            }

            offset = offset.GetRotated(Angle2D.DegToRad(sourceAngle));

            if (alignx)
            {
                if (Texture != null && Texture.IsImageLoaded)
                {
                    offset.x %= Texture.Width / scaleX;
                }
                UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xpanningfloor" : "xpanningceiling"), (float)Math.Round(-offset.x), 0f);
            }

            if (aligny)
            {
                if (Texture != null && Texture.IsImageLoaded)
                {
                    offset.y %= Texture.Height / scaleY;
                }
                UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "ypanningfloor" : "ypanningceiling"), (float)Math.Round(offset.y), 0f);
            }

            //update geometry
            Sector.UpdateSectorGeometry(false);
        }
Exemplo n.º 9
0
        //mxd
        protected void AlignTextureToClosestLine(bool alignx, bool aligny)
        {
            if (!(mode.HighlightedObject is BaseVisualSector))
            {
                return;
            }

            // Do we need to align this? (and also grab texture scale while we are at it)
            float scaleX, scaleY;
            bool  isFloor = (geometrytype == VisualGeometryType.FLOOR);

            if (mode.HighlightedTarget is VisualFloor)
            {
                VisualFloor target = (VisualFloor)mode.HighlightedTarget;

                // Check texture
                if (target.Sector.Sector.FloorTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture))
                {
                    return;
                }

                scaleX = target.Sector.Sector.Fields.GetValue("xscalefloor", 1.0f);
                scaleY = target.Sector.Sector.Fields.GetValue("yscalefloor", 1.0f);
            }
            else
            {
                VisualCeiling target = (VisualCeiling)mode.HighlightedTarget;

                // Check texture
                if (target.Sector.Sector.CeilTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture))
                {
                    return;
                }

                scaleX = target.Sector.Sector.Fields.GetValue("xscaleceiling", 1.0f);
                scaleY = target.Sector.Sector.Fields.GetValue("yscaleceiling", 1.0f);
            }

            //find a linedef to align to
            Vector2D hitpos = mode.GetHitPosition();

            if (!hitpos.IsFinite())
            {
                return;
            }

            //align to line of highlighted sector, which is closest to hitpos
            Sector         highlightedSector = ((BaseVisualSector)mode.HighlightedObject).Sector;
            List <Linedef> lines             = new List <Linedef>();

            foreach (Sidedef side in highlightedSector.Sidedefs)
            {
                lines.Add(side.Line);
            }

            Linedef targetLine = MapSet.NearestLinedef(lines, hitpos);

            if (targetLine == null)
            {
                return;
            }

            bool isFront = targetLine.SideOfLine(hitpos) > 0;

            Sector.Sector.Fields.BeforeFieldsChange();

            //find an angle to rotate texture
            float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(targetLine.Angle) + 90 : -Angle2D.RadToDeg(targetLine.Angle) - 90), 1);

            if (!isFront)
            {
                sourceAngle = General.ClampAngle(sourceAngle + 180);
            }

            //update angle
            UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "rotationfloor" : "rotationceiling"), sourceAngle, 0f);

            //set scale
            UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xscalefloor" : "xscaleceiling"), scaleX, 1.0f);
            UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "yscalefloor" : "yscaleceiling"), scaleY, 1.0f);

            //update offset
            float    distToStart = Vector2D.Distance(hitpos, targetLine.Start.Position);
            float    distToEnd   = Vector2D.Distance(hitpos, targetLine.End.Position);
            Vector2D offset      = (distToStart < distToEnd ? targetLine.Start.Position : targetLine.End.Position).GetRotated(Angle2D.DegToRad(sourceAngle));

            if (alignx)
            {
                if (Texture != null && Texture.IsImageLoaded)
                {
                    offset.x %= Texture.Width / scaleX;
                }
                UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xpanningfloor" : "xpanningceiling"), (float)Math.Round(-offset.x), 0f);
            }

            if (aligny)
            {
                if (Texture != null && Texture.IsImageLoaded)
                {
                    offset.y %= Texture.Height / scaleY;
                }
                UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "ypanningfloor" : "ypanningceiling"), (float)Math.Round(offset.y), 0f);
            }

            //update geometry
            Sector.UpdateSectorGeometry(false);
        }
Exemplo n.º 10
0
        // Apply clicked
        private void apply_Click(object sender, EventArgs e)
        {
            //mxd. Make Undo
            MakeUndo();

            List <string> defaultflags = new List <string>();

            // Verify the tag
            if (General.Map.FormatInterface.HasThingTag)  //mxd
            {
                tagSelector.ValidateTag();                //mxd
                if (((tagSelector.GetTag(0) < General.Map.FormatInterface.MinTag) || (tagSelector.GetTag(0) > General.Map.FormatInterface.MaxTag)))
                {
                    General.ShowWarningMessage("Thing tag must be between " + General.Map.FormatInterface.MinTag + " and " + General.Map.FormatInterface.MaxTag + ".", MessageBoxButtons.OK);
                    return;
                }
            }

            // Verify the type
            if (!string.IsNullOrEmpty(thingtype.TypeStringValue) && ((thingtype.GetResult(0) < General.Map.FormatInterface.MinThingType) || (thingtype.GetResult(0) > General.Map.FormatInterface.MaxThingType)))
            {
                General.ShowWarningMessage("Thing type must be between " + General.Map.FormatInterface.MinThingType + " and " + General.Map.FormatInterface.MaxThingType + ".", MessageBoxButtons.OK);
                return;
            }

            // Verify the action
            if (General.Map.FormatInterface.HasThingAction && ((action.Value < General.Map.FormatInterface.MinAction) || (action.Value > General.Map.FormatInterface.MaxAction)))
            {
                General.ShowWarningMessage("Thing action must be between " + General.Map.FormatInterface.MinAction + " and " + General.Map.FormatInterface.MaxAction + ".", MessageBoxButtons.OK);
                return;
            }

            // Go for all the things
            int offset = 0;             //mxd

            foreach (Thing t in things)
            {
                // Coordination
                //mxd. Randomize rotations?
                if (cbrandomangle.Checked)
                {
                    int newangle = General.Random(0, 359);
                    if (General.Map.Config.DoomThingRotationAngles)
                    {
                        newangle = newangle / 45 * 45;
                    }
                    t.Rotate(newangle);
                }
                if (cbrandompitch.Checked)
                {
                    t.SetPitch(General.Random(0, 359));
                }
                if (cbrandomroll.Checked)
                {
                    t.SetRoll(General.Random(0, 359));
                }

                //mxd. Check position
                double px = General.Clamp(t.Position.x, General.Map.Config.LeftBoundary, General.Map.Config.RightBoundary);
                double py = General.Clamp(t.Position.y, General.Map.Config.BottomBoundary, General.Map.Config.TopBoundary);
                if (t.Position.x != px || t.Position.y != py)
                {
                    t.Move(new Vector2D(px, py));
                }

                // Action/tags
                t.Tag = General.Clamp(tagSelector.GetSmartTag(t.Tag, offset), General.Map.FormatInterface.MinTag, General.Map.FormatInterface.MaxTag);                 //mxd
                if (!action.Empty)
                {
                    t.Action = action.Value;
                }

                //mxd. Apply args
                argscontrol.Apply(t, offset);

                //mxd. Custom fields
                fieldslist.Apply(t.Fields);
                if (!string.IsNullOrEmpty(conversationID.Text))
                {
                    UniFields.SetInteger(t.Fields, "conversation", conversationID.GetResult(t.Fields.GetValue("conversation", 0)), 0);
                }
                if (!string.IsNullOrEmpty(floatbobphase.Text))
                {
                    UniFields.SetInteger(t.Fields, "floatbobphase", General.Clamp(floatbobphase.GetResult(t.Fields.GetValue("floatbobphase", -1)), -1, 63), -1);
                }
                if (!string.IsNullOrEmpty(gravity.Text))
                {
                    UniFields.SetFloat(t.Fields, "gravity", gravity.GetResultFloat(t.Fields.GetValue("gravity", 1.0)), 1.0);
                }
                if (!string.IsNullOrEmpty(health.Text))
                {
                    UniFields.SetInteger(t.Fields, "health", health.GetResult(t.Fields.GetValue("health", 1)), 1);
                }
                if (!string.IsNullOrEmpty(score.Text))
                {
                    UniFields.SetInteger(t.Fields, "score", score.GetResult(t.Fields.GetValue("score", 0)), 0);
                }

                //mxd. User vars. Should be called after fieldslist.Apply()
                ThingTypeInfo ti = General.Map.Data.GetThingInfoEx(t.Type);
                if (ti != null && ti.Actor != null && ti.Actor.UserVars.Count > 0)
                {
                    fieldslist.ApplyUserVars(ti.Actor.UserVars, t.Fields);
                }

                color.ApplyTo(t.Fields, t.Fields.GetValue("fillcolor", 0));

                //mxd. Comments
                commenteditor.Apply(t.Fields);

                // Update settings
                t.UpdateConfiguration();

                //mxd. Increase offset...
                offset++;
            }

            // Set as defaults
            foreach (CheckBox c in flags.Checkboxes)
            {
                if (c.CheckState == CheckState.Checked)
                {
                    defaultflags.Add(c.Tag.ToString());
                }
            }
            General.Settings.DefaultThingType  = thingtype.GetResult(General.Settings.DefaultThingType);
            General.Settings.DefaultThingAngle = Angle2D.DegToRad((float)angle.GetResult((int)Angle2D.RadToDeg(General.Settings.DefaultThingAngle) - 90) + 90);
            General.Settings.SetDefaultThingFlags(defaultflags);

            // Done
            General.Map.IsChanged = true;
            if (OnValuesChanged != null)
            {
                OnValuesChanged(this, EventArgs.Empty);                                     //mxd
            }
            this.DialogResult = DialogResult.OK;
            this.Close();
        }
        //mxd
        protected void AlignTextureToClosestLine(bool alignx, bool aligny)
        {
            if (!(mode.HighlightedObject is BaseVisualSector))
            {
                return;
            }

            // Do we need to align this? (and also grab texture scale while we are at it)
            float scaleX, scaleY;
            bool  isFloor = (geometrytype == VisualGeometryType.FLOOR);

            if (mode.HighlightedTarget is VisualFloor)
            {
                Sector      target;
                VisualFloor vf = (VisualFloor)mode.HighlightedTarget;

                // Use the control sector if the floor belongs to a 3D floor
                if (vf.ExtraFloor == null)
                {
                    target = vf.Sector.Sector;
                }
                else
                {
                    target = vf.GetControlSector();
                }

                // Check texture
                if (target.FloorTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture))
                {
                    return;
                }

                scaleX = target.Fields.GetValue("xscalefloor", 1.0f);
                scaleY = target.Fields.GetValue("yscalefloor", 1.0f);
            }
            else
            {
                Sector        target;
                VisualCeiling vc = (VisualCeiling)mode.HighlightedTarget;

                // Use the control sector if the ceiling belongs to a 3D floor
                if (vc.ExtraFloor == null)
                {
                    target = vc.Sector.Sector;
                }
                else
                {
                    target = vc.GetControlSector();
                }

                // Check texture
                if (target.CeilTexture != (isFloor ? Sector.Sector.FloorTexture : Sector.Sector.CeilTexture))
                {
                    return;
                }

                scaleX = target.Fields.GetValue("xscaleceiling", 1.0f);
                scaleY = target.Fields.GetValue("yscaleceiling", 1.0f);
            }

            //find a linedef to align to
            Vector2D hitpos = mode.GetHitPosition();

            if (!hitpos.IsFinite())
            {
                return;
            }

            //align to line of highlighted sector, which is closest to hitpos
            Sector         highlightedSector = ((BaseVisualSector)mode.HighlightedObject).Sector;
            List <Linedef> lines             = new List <Linedef>();

            foreach (Sidedef side in highlightedSector.Sidedefs)
            {
                lines.Add(side.Line);
            }

            Linedef targetLine = MapSet.NearestLinedef(lines, hitpos);

            if (targetLine == null)
            {
                return;
            }

            bool isFront = targetLine.SideOfLine(hitpos) > 0;

            Sector.Sector.Fields.BeforeFieldsChange();

            //find an angle to rotate texture
            float sourceAngle = (float)Math.Round(General.ClampAngle(isFront ? -Angle2D.RadToDeg(targetLine.Angle) + 90 : -Angle2D.RadToDeg(targetLine.Angle) - 90), 1);

            if (!isFront)
            {
                sourceAngle = General.ClampAngle(sourceAngle + 180);
            }

            //update angle
            UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "rotationfloor" : "rotationceiling"), sourceAngle, 0f);

            // Scale texture if it's a slope and the appropriate option is set
            if (level.plane.Normal.z != 1.0f && BuilderPlug.Me.ScaleTexturesOnSlopes != 2)
            {
                Vector2D basescale = new Vector2D(1.0f, 1.0f);

                // User wants to use the current scale as a base?
                if (BuilderPlug.Me.ScaleTexturesOnSlopes == 1)
                {
                    basescale.x = scaleX;
                    basescale.y = scaleY;
                }

                // Create a unit vector of the direction of the target line in 3D space
                Vector3D targetlinevector = new Line3D(new Vector3D(targetLine.Start.Position, level.plane.GetZ(targetLine.Start.Position)), new Vector3D(targetLine.End.Position, level.plane.GetZ(targetLine.End.Position))).GetDelta().GetNormal();

                // Get a perpendicular vector of the target line in 3D space. This is used to get the slope angle relative to the target line
                Vector3D targetlineperpendicular = Vector3D.CrossProduct(targetlinevector, level.plane.Normal);

                if (alignx)
                {
                    scaleX = Math.Abs(basescale.x * (1.0f / (float)Math.Cos(targetlinevector.GetAngleZ())));
                }

                if (aligny)
                {
                    scaleY = Math.Abs(basescale.y * (1.0f / (float)Math.Cos(targetlineperpendicular.GetAngleZ())));
                }
            }

            //set scale
            UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xscalefloor" : "xscaleceiling"), scaleX, 1.0f);
            UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "yscalefloor" : "yscaleceiling"), scaleY, 1.0f);

            //update offset
            float    distToStart = Vector2D.Distance(hitpos, targetLine.Start.Position);
            float    distToEnd   = Vector2D.Distance(hitpos, targetLine.End.Position);
            Vector2D offset      = (distToStart < distToEnd ? targetLine.Start.Position : targetLine.End.Position).GetRotated(Angle2D.DegToRad(sourceAngle));

            if (alignx)
            {
                if (Texture != null && Texture.IsImageLoaded)
                {
                    offset.x %= Texture.Width / scaleX;
                }
                UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "xpanningfloor" : "xpanningceiling"), (float)Math.Round(-offset.x), 0f);
            }

            if (aligny)
            {
                if (Texture != null && Texture.IsImageLoaded)
                {
                    offset.y %= Texture.Height / scaleY;
                }
                UniFields.SetFloat(Sector.Sector.Fields, (isFloor ? "ypanningfloor" : "ypanningceiling"), (float)Math.Round(offset.y), 0f);
            }

            //update geometry
            Sector.UpdateSectorGeometry(false);
        }