2022-10-05 16:02:11 -06:00

497 lines
14 KiB
C#

// Resizeable box to select all bricks inside a volume.
// -------------------------------------------------------------------
//Create a new selection box
function ND_SelectionBox(%shapeName)
{
ND_ServerGroup.add(
%this = new ScriptObject(ND_SelectionBox)
);
%this.innerBox = new StaticShape(){datablock = ND_SelectionBoxInner;};
%this.outerBox = new StaticShape(){datablock = ND_SelectionBoxOuter;};
%this.shapeName = new StaticShape(){datablock = ND_SelectionBoxShapeName;};
%this.corner1 = new StaticShape(){datablock = ND_SelectionBoxOuter;};
%this.corner2 = new StaticShape(){datablock = ND_SelectionBoxOuter;};
%this.selectedCorner = true;
%this.innerBox.setScopeAlways();
%this.outerBox.setScopeAlways();
%this.shapeName.setScopeAlways();
%this.corner1.setScopeAlways();
%this.corner2.setScopeAlways();
for(%i = 0; %i < 4; %i++)
{
%this.border_x[%i] = new StaticShape(){datablock = ND_SelectionBoxBorder;};
%this.border_y[%i] = new StaticShape(){datablock = ND_SelectionBoxBorder;};
%this.border_z[%i] = new StaticShape(){datablock = ND_SelectionBoxBorder;};
%this.border_x[%i].setScopeAlways();
%this.border_y[%i].setScopeAlways();
%this.border_z[%i].setScopeAlways();
}
%this.boxName = %shapeName;
%this.setNormalMode();
return %this;
}
//Destroy static shapes when selection box is removed
function ND_SelectionBox::onRemove(%this)
{
%this.innerBox.delete();
%this.outerBox.delete();
%this.shapeName.delete();
%this.corner1.delete();
%this.corner2.delete();
for(%i = 0; %i < 4; %i++)
{
%this.border_x[%i].delete();
%this.border_y[%i].delete();
%this.border_z[%i].delete();
}
}
//Set normal color values and borders
function ND_SelectionBox::setNormalMode(%this)
{
%this.innerColor = "0 0 0 0.60";
%this.outerColor = "0 0 0 0.35";
%this.borderColor = "1 0.84 0 0.99";
%this.borderColorSelected = "0 0 1 0.99";
%this.cornerColor1 = "0.8 0.74 0 0.99";
%this.cornerColor2 = "1 0.94 0.1 0.99";
%this.cornerColorSelected1 = "0 0.2 1 0.99";
%this.cornerColorSelected2 = "0 0.1 0.9 0.99";
%this.isNormalMode = true;
//Unhide the corners and inner/outer box (hidden in disabled mode)
%this.innerBox.unHideNode("ALL");
%this.corner1.unHideNode("ALL");
%this.corner2.unHideNode("ALL");
if(%this.hasVolume())
%this.outerBox.unHideNode("ALL");
//Apply changes
%this.applyColors();
%this.setSize(%this.point1, %this.point2);
%this.shapeName.setShapeName(%this.boxName);
}
//Set grayscale color values and slightly smaller border
function ND_SelectionBox::setDisabledMode(%this)
{
%this.borderColor = "0.1 0.1 0.1 0.4";
%this.borderColorSelected = "0.1 0.1 0.1 0.4";
%this.isNormalMode = false;
//Hide the corners and inner/outer box (looks better)
%this.innerBox.hideNode("ALL");
%this.outerBox.hideNode("ALL");
%this.corner1.hideNode("ALL");
%this.corner2.hideNode("ALL");
//Apply changes
%this.applyColors();
%this.setSize(%this.point1, %this.point2);
%this.shapeName.setShapeName("");
}
//Apply color changes to the selection box
function ND_SelectionBox::applyColors(%this)
{
%this.innerBox.setNodeColor("ALL", %this.innerColor);
%this.outerBox.setNodeColor("ALL", %this.outerColor);
%this.shapeName.setShapeNameColor(%this.borderColor);
for(%i = 0; %i < 4; %i++)
{
%this.border_x[%i].setNodeColor("ALL", %this.borderColor);
%this.border_y[%i].setNodeColor("ALL", %this.borderColor);
%this.border_z[%i].setNodeColor("ALL", %this.borderColor);
}
%bColor = %this.borderColorSelected;
if(%this.selectedCorner)
{
%this.border_x2.setNodeColor("ALL", %bColor);
%this.border_y2.setNodeColor("ALL", %bColor);
%this.border_z2.setNodeColor("ALL", %bColor);
%corner1 = %this.corner1;
%corner2 = %this.corner2;
}
else
{
%this.border_x0.setNodeColor("ALL", %bColor);
%this.border_y0.setNodeColor("ALL", %bColor);
%this.border_z0.setNodeColor("ALL", %bColor);
%corner1 = %this.corner2;
%corner2 = %this.corner1;
}
%corner1.setNodeColor("out+X", %this.borderColor);
%corner1.setNodeColor("out-X", %this.borderColor);
%corner1.setNodeColor("out+Y", %this.cornerColor1);
%corner1.setNodeColor("out-Y", %this.cornerColor1);
%corner1.setNodeColor("out+Z", %this.cornerColor2);
%corner1.setNodeColor("out-Z", %this.cornerColor2);
//Illusion of shaded box
%corner2.setNodeColor("out+X", %this.borderColorSelected);
%corner2.setNodeColor("out-X", %this.borderColorSelected);
%corner2.setNodeColor("out+Y", %this.cornerColorSelected1);
%corner2.setNodeColor("out-Y", %this.cornerColorSelected1);
%corner2.setNodeColor("out+Z", %this.cornerColorSelected2);
%corner2.setNodeColor("out-Z", %this.cornerColorSelected2);
}
//Return current size of selection box
function ND_SelectionBox::getSize(%this)
{
%x1 = getWord(%this.point1, 0);
%y1 = getWord(%this.point1, 1);
%z1 = getWord(%this.point1, 2);
%x2 = getWord(%this.point2, 0);
%y2 = getWord(%this.point2, 1);
%z2 = getWord(%this.point2, 2);
%min = getMin(%x1, %x2) SPC getMin(%y1, %y2) SPC getMin(%z1, %z2);
%max = getMax(%x1, %x2) SPC getMax(%y1, %y2) SPC getMax(%z1, %z2);
return vectorSub(%max, %min);
}
//Return current world box of selection box
function ND_SelectionBox::getWorldBox(%this)
{
%x1 = getWord(%this.point1, 0);
%y1 = getWord(%this.point1, 1);
%z1 = getWord(%this.point1, 2);
%x2 = getWord(%this.point2, 0);
%y2 = getWord(%this.point2, 1);
%z2 = getWord(%this.point2, 2);
%min = getMin(%x1, %x2) SPC getMin(%y1, %y2) SPC getMin(%z1, %z2);
%max = getMax(%x1, %x2) SPC getMax(%y1, %y2) SPC getMax(%z1, %z2);
return %min SPC %max;
}
//Resize the selection box
function ND_SelectionBox::setSize(%this, %point1, %point2)
{
if(getWordCount(%point1) == 6)
{
%point2 = getWords(%point1, 3, 5);
%point1 = getWords(%point1, 0, 2);
}
%this.point1 = %point1;
%this.point2 = %point2;
%x1 = getWord(%point1, 0);
%y1 = getWord(%point1, 1);
%z1 = getWord(%point1, 2);
%x2 = getWord(%point2, 0);
%y2 = getWord(%point2, 1);
%z2 = getWord(%point2, 2);
%len_x = mAbs(%x2 - %x1);
%len_y = mAbs(%y2 - %y1);
%len_z = mAbs(%z2 - %z1);
%center_x = (%x1 + %x2) / 2;
%center_y = (%y1 + %y2) / 2;
%center_z = (%z1 + %z2) / 2;
%rot_x = "0 1 0 1.57079";
%rot_y = "1 0 0 1.57079";
%rot_z = "0 0 1 0";
%this.innerBox.setTransform(%center_x SPC %center_y SPC %center_z);
%this.outerBox.setTransform(%center_x SPC %center_y SPC %center_z);
%this.shapeName.setTransform(%center_X SPC %center_y SPC %z2);
%this.border_x0.setTransform(%center_x SPC %y1 SPC %z1 SPC %rot_x);
%this.border_x1.setTransform(%center_x SPC %y2 SPC %z1 SPC %rot_x);
%this.border_x2.setTransform(%center_x SPC %y2 SPC %z2 SPC %rot_x);
%this.border_x3.setTransform(%center_x SPC %y1 SPC %z2 SPC %rot_x);
%this.border_y0.setTransform(%x1 SPC %center_y SPC %z1 SPC %rot_y);
%this.border_y1.setTransform(%x2 SPC %center_y SPC %z1 SPC %rot_y);
%this.border_y2.setTransform(%x2 SPC %center_y SPC %z2 SPC %rot_y);
%this.border_y3.setTransform(%x1 SPC %center_y SPC %z2 SPC %rot_y);
%this.border_z0.setTransform(%x1 SPC %y1 SPC %center_z SPC %rot_z);
%this.border_z1.setTransform(%x2 SPC %y1 SPC %center_z SPC %rot_z);
%this.border_z2.setTransform(%x2 SPC %y2 SPC %center_z SPC %rot_z);
%this.border_z3.setTransform(%x1 SPC %y2 SPC %center_z SPC %rot_z);
%this.corner1.setTransform(%x1 SPC %y1 SPC %z1);
%this.corner2.setTransform(%x2 SPC %y2 SPC %z2);
%this.innerBox.setScale(%len_x - 0.02 SPC %len_y - 0.02 SPC %len_z - 0.02);
%this.outerBox.setScale(%len_x + 0.02 SPC %len_y + 0.02 SPC %len_z + 0.02);
if(%this.isNormalMode)
{
//Normal mode (box with two colored corners)
%maxLen = getMax(getMax(%len_x, %len_y), %len_z);
%width = (7/1024) * %maxLen + 1;
for(%i = 0; %i < 4; %i++)
{
%this.border_x[%i].setScale(%width SPC %width SPC %len_x + %width * 0.05);
%this.border_y[%i].setScale(%width SPC %width SPC %len_y + %width * 0.05);
%this.border_z[%i].setScale(%width SPC %width SPC %len_z + %width * 0.05);
}
if(%this.selectedCorner)
{
%width1 = %width;
%width2 = %width + 0.02;
}
else
{
%width1 = %width + 0.02;
%width2 = %width;
}
//The borders touching the two corners are thicker to prevent Z fighting
//with the highlight box if it covers the same area as the selection
%this.border_x0.setScale(%width1 SPC %width1 SPC %len_x - %width * 0.05);
%this.border_y0.setScale(%width1 SPC %width1 SPC %len_y - %width * 0.05);
%this.border_z0.setScale(%width1 SPC %width1 SPC %len_z - %width * 0.05);
%this.border_x2.setScale(%width2 SPC %width2 SPC %len_x - %width * 0.05);
%this.border_y2.setScale(%width2 SPC %width2 SPC %len_y - %width * 0.05);
%this.border_z2.setScale(%width2 SPC %width2 SPC %len_z - %width * 0.05);
//Corners scale with the border width
%cs1 = 0.35 * %width1;
%cs2 = 0.35 * %width2;
%this.corner1.setScale(%cs1 SPC %cs1 SPC %cs1);
%this.corner2.setScale(%cs2 SPC %cs2 SPC %cs2);
}
else
{
//Disabled mode (transparent greyscale box)
%maxLen = getMax(getMax(%len_x, %len_y), %len_z);
%width = (21/5120) * %maxLen + 1;
for(%i = 0; %i < 4; %i++)
{
//Horizontal borders are a bit shorter to prevent z fighting
%this.border_x[%i].setScale(%width SPC %width SPC %len_x - %width * 0.05);
%this.border_y[%i].setScale(%width SPC %width SPC %len_y - %width * 0.05);
%this.border_z[%i].setScale(%width SPC %width SPC %len_z + %width * 0.05);
}
}
}
//Resize the selection box and align it to a player
function ND_SelectionBox::setSizeAligned(%this, %point1, %point2, %player)
{
//Set the selection box to correct orientation
%x1 = getWord(%point1, 0);
%y1 = getWord(%point1, 1);
%z1 = getWord(%point1, 2);
%x2 = getWord(%point2, 0);
%y2 = getWord(%point2, 1);
%z2 = getWord(%point2, 2);
switch(getAngleIDFromPlayer(%player))
{
case 0:
%p1 = %x1 SPC %y2 SPC %z1;
%p2 = %x2 SPC %y1 SPC %z2;
case 1:
%p1 = %x1 SPC %y1 SPC %z1;
%p2 = %x2 SPC %y2 SPC %z2;
case 2:
%p1 = %x2 SPC %y1 SPC %z1;
%p2 = %x1 SPC %y2 SPC %z2;
case 3:
%p1 = %x2 SPC %y2 SPC %z1;
%p2 = %x1 SPC %y1 SPC %z2;
}
//Select first corner
if(!%this.selectedCorner)
{
%this.selectedCorner = true;
%this.applyColors();
}
%this.setSize(%p1, %p2);
}
//Select one of the two corners
function ND_SelectionBox::switchCorner(%this)
{
%this.selectedCorner = !%this.selectedCorner;
if(%this.selectedCorner)
serverPlay3d(BrickRotateSound, %this.point2);
else
serverPlay3d(BrickRotateSound, %this.point1);
%this.setSize(%this.point1, %this.point2);
%this.applyColors();
}
//Move the selected corner
function ND_SelectionBox::shiftCorner(%this, %offset, %limit)
{
%oldP1 = %this.point1;
%oldP2 = %this.point2;
%limitReached = false;
//Size of a plate in TU
%unit[0] = 0.5;
%unit[1] = 0.5;
%unit[2] = 0.2;
for(%dim = 0; %dim < 3; %dim++)
{
//Copy current
%point1[%dim] = getWord(%this.point1, %dim);
%point2[%dim] = getWord(%this.point2, %dim);
//Get the size of the box in the current axis after resizing
%size = getWord(%this.point2, %dim) - getWord(%this.point1, %dim);
if(%this.selectedCorner)
{
//Update point2
%size += getWord(%offset, %dim);
%point2[%dim] += getWord(%offset, %dim);
//Check limits
if(mAbs(%size) > %limit)
{
%limitReached = true;
%point2[%dim] -= %size - %limit * (mAbs(%size) / %size);
}
}
else
{
//Update point1
%size -= getWord(%offset, %dim);
%point1[%dim] += getWord(%offset, %dim);
//Check limits
if(mAbs(%size) > %limit)
{
%limitReached = true;
%point1[%dim] += %size - %limit * (mAbs(%size) / %size);
}
}
}
//Update corner positions
%point1 = %point1[0] SPC %point1[1] SPC %point1[2];
%point2 = %point2[0] SPC %point2[1] SPC %point2[2];
%this.setSize(%point1, %point2);
//Play sounds
if(%this.selectedCorner)
%soundPoint = %point2;
else
%soundPoint = %point1;
if(%point1 !$= %oldP1 || %point2 !$= %oldP2)
serverPlay3d(BrickMoveSound, %soundPoint);
else
serverPlay3d(errorSound, %soundPoint);
//Hide outer box on selection boxes without volume
if(%this.hasVolume())
%this.outerBox.unHideNode("ALL");
else
%this.outerBox.hideNode("ALL");
return %limitReached;
}
//Move the entire box
function ND_SelectionBox::shift(%this, %offset)
{
%this.point1 = vectorAdd(%this.point1, %offset);
%this.point2 = vectorAdd(%this.point2, %offset);
%this.setSize(%this.point1, %this.point2);
//Play sounds
if(%this.selectedCorner)
serverPlay3d(BrickMoveSound, %this.point1);
else
serverPlay3d(BrickMoveSound, %this.point2);
}
//Rotate the entire box
function ND_SelectionBox::rotate(%this, %direction)
{
%point1 = %this.point1;
%point2 = %this.point2;
%center = vectorScale(vectorAdd(%point1, %point2), 0.5);
%brickSizeX = mAbs(mFloatLength((getWord(%point2, 0) - getWord(%point1, 0)) * 2, 0));
%brickSizeY = mAbs(mFloatLength((getWord(%point2, 1) - getWord(%point1, 1)) * 2, 0));
%shiftCorrect = "0 0 0";
if((%brickSizeX % 2) != (%brickSizeY % 2))
{
if(%brickSizeX % 2)
%shiftCorrect = "-0.25 -0.25 0";
else
%shiftCorrect = "0.25 0.25 0";
}
%point1 = vectorAdd(ndRotateVector(vectorSub(%point1, %center), %direction), %center);
%point2 = vectorAdd(ndRotateVector(vectorSub(%point2, %center), %direction), %center);
%this.setSize(vectorAdd(%point1, %shiftCorrect), vectorAdd(%point2, %shiftCorrect));
//Play sounds
if(%this.selectedCorner)
serverPlay3d(BrickRotateSound, %this.point1);
else
serverPlay3d(BrickRotateSound, %this.point2);
}
//Check if the box has a volume
function ND_SelectionBox::hasVolume(%this)
{
if(mAbs(getWord(%this.point1, 0) - getWord(%this.point2, 0)) < 0.05
|| mAbs(getWord(%this.point1, 1) - getWord(%this.point2, 1)) < 0.05
|| mAbs(getWord(%this.point1, 2) - getWord(%this.point2, 2)) < 0.05)
return false;
return true;
}