initial commit
This commit is contained in:
commit
93d385e859
462
classes/server/duplimode/boxselect.cs
Normal file
462
classes/server/duplimode/boxselect.cs
Normal file
@ -0,0 +1,462 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Changing modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Switch to this mode
|
||||||
|
function NDM_BoxSelect::onStartMode(%this, %client, %lastMode)
|
||||||
|
{
|
||||||
|
if(%lastMode == $NDM::StackSelect)
|
||||||
|
{
|
||||||
|
if(isObject(%client.ndSelection) && %client.ndSelection.brickCount)
|
||||||
|
{
|
||||||
|
//Create selection box from the size of the previous selection
|
||||||
|
%root = %client.ndSelection.rootPosition;
|
||||||
|
%min = vectorAdd(%root, %client.ndSelection.minSize);
|
||||||
|
%max = vectorAdd(%root, %client.ndSelection.maxSize);
|
||||||
|
|
||||||
|
if(%client.isAdmin)
|
||||||
|
%limit = $Pref::Server::ND::MaxBoxSizeAdmin;
|
||||||
|
else
|
||||||
|
%limit = $Pref::Server::ND::MaxBoxSizePlayer;
|
||||||
|
|
||||||
|
if((getWord(%max, 0) - getWord(%min, 0) <= %limit)
|
||||||
|
&& (getWord(%max, 1) - getWord(%min, 1) <= %limit)
|
||||||
|
&& (getWord(%max, 2) - getWord(%min, 2) <= %limit))
|
||||||
|
{
|
||||||
|
%name = %client.name;
|
||||||
|
|
||||||
|
if(getSubStr(%name, strLen(%name - 1), 1) $= "s")
|
||||||
|
%shapeName = %name @ "' Selection Box";
|
||||||
|
else
|
||||||
|
%shapeName = %name @ "'s Selection Box";
|
||||||
|
|
||||||
|
%client.ndSelectionBox = ND_SelectionBox(%shapeName);
|
||||||
|
%client.ndSelectionBox.setSizeAligned(%min, %max, %client.getControlObject());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Oops!\n<font:Verdana:17>" @
|
||||||
|
"\c6Your selection box is limited to \c3" @ mFloor(%limit * 2) @ " \c6studs.", 5);
|
||||||
|
|
||||||
|
%client.ndSelection.deleteData();
|
||||||
|
}
|
||||||
|
|
||||||
|
%client.ndSelectionAvailable = false;
|
||||||
|
}
|
||||||
|
else if(%lastMode == $NDM::BoxSelectProgress && %client.ndSelection.brickCount > 0)
|
||||||
|
{
|
||||||
|
%client.ndSelectionBox.setDisabledMode();
|
||||||
|
%client.ndSelectionAvailable = true;
|
||||||
|
}
|
||||||
|
else if(%lastMode != $NDM::FillColor && %lastMode != $NDM::WrenchProgress)
|
||||||
|
%client.ndSelectionAvailable = false;
|
||||||
|
|
||||||
|
%client.ndLastSelectMode = %this;
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Switch away from this mode
|
||||||
|
function NDM_BoxSelect::onChangeMode(%this, %client, %nextMode)
|
||||||
|
{
|
||||||
|
if(%nextMode == $NDM::StackSelect)
|
||||||
|
{
|
||||||
|
//Clear selection
|
||||||
|
if(isObject(%client.ndSelection))
|
||||||
|
%client.ndSelection.deleteData();
|
||||||
|
|
||||||
|
//Remove the selection box
|
||||||
|
if(isObject(%client.ndSelectionBox))
|
||||||
|
%client.ndSelectionBox.delete();
|
||||||
|
}
|
||||||
|
else if(%nextMode == $NDM::PlantCopy)
|
||||||
|
{
|
||||||
|
//Start de-highlighting the bricks
|
||||||
|
%client.ndSelection.deHighlight();
|
||||||
|
|
||||||
|
//Remove the selection box
|
||||||
|
if(isObject(%client.ndSelectionBox))
|
||||||
|
%client.ndSelectionBox.delete();
|
||||||
|
}
|
||||||
|
else if(%nextMode == $NDM::CutProgress)
|
||||||
|
{
|
||||||
|
//Remove the selection box
|
||||||
|
if(isObject(%client.ndSelectionBox))
|
||||||
|
%client.ndSelectionBox.delete();
|
||||||
|
}
|
||||||
|
else if(%nextMode == $NDM::FillColor)
|
||||||
|
{
|
||||||
|
//Start de-highlighting the bricks
|
||||||
|
%client.ndSelection.deHighlight();
|
||||||
|
}
|
||||||
|
else if(%nextMode == $NDM::WrenchProgress)
|
||||||
|
{
|
||||||
|
//Start de-highlighting the bricks
|
||||||
|
%client.ndSelection.deHighlight();
|
||||||
|
}
|
||||||
|
else if(%nextMode == $NDM::LoadProgress)
|
||||||
|
{
|
||||||
|
//Remove the selection box
|
||||||
|
if(isObject(%client.ndSelectionBox))
|
||||||
|
%client.ndSelectionBox.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Kill this mode
|
||||||
|
function NDM_BoxSelect::onKillMode(%this, %client)
|
||||||
|
{
|
||||||
|
//Destroy selection
|
||||||
|
if(isObject(%client.ndSelection))
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
|
||||||
|
//Delete the selection box
|
||||||
|
if(isObject(%client.ndSelectionBox))
|
||||||
|
%client.ndSelectionBox.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Duplicator image callbacks
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Selecting an object with the duplicator
|
||||||
|
function NDM_BoxSelect::onSelectObject(%this, %client, %obj, %pos, %normal)
|
||||||
|
{
|
||||||
|
if((%obj.getType() & $TypeMasks::FxBrickAlwaysObjectType) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(!ndTrustCheckMessage(%obj, %client))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(%client.ndSelectionAvailable)
|
||||||
|
{
|
||||||
|
messageClient(%client, 'MsgError', "");
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Selection canceled! " @
|
||||||
|
"You can now edit the box again.", 5);
|
||||||
|
|
||||||
|
%client.ndSelectionAvailable = false;
|
||||||
|
%client.ndSelection.deleteData();
|
||||||
|
%client.ndSelectionBox.setNormalMode();
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isObject(%client.ndSelectionBox))
|
||||||
|
{
|
||||||
|
if(%client.ndMultiSelect)
|
||||||
|
{
|
||||||
|
%box1 = %client.ndSelectionBox.getWorldBox();
|
||||||
|
//%box2 = ndGetPlateBoxFromRayCast(%pos, %normal);
|
||||||
|
%box2 = %obj.getWorldBox();
|
||||||
|
|
||||||
|
%p1 = getMin(getWord(%box1, 0), getWord(%box2, 0))
|
||||||
|
SPC getMin(getWord(%box1, 1), getWord(%box2, 1))
|
||||||
|
SPC getMin(getWord(%box1, 2), getWord(%box2, 2));
|
||||||
|
|
||||||
|
%p2 = getMax(getWord(%box1, 3), getWord(%box2, 3))
|
||||||
|
SPC getMax(getWord(%box1, 4), getWord(%box2, 4))
|
||||||
|
SPC getMax(getWord(%box1, 5), getWord(%box2, 5));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%box = %obj.getWorldBox();
|
||||||
|
%p1 = getWords(%box, 0, 2);
|
||||||
|
%p2 = getWords(%box, 3, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%name = %client.name;
|
||||||
|
|
||||||
|
if(getSubStr(%name, strLen(%name - 1), 1) $= "s")
|
||||||
|
%shapeName = %name @ "' Selection Box";
|
||||||
|
else
|
||||||
|
%shapeName = %name @ "'s Selection Box";
|
||||||
|
|
||||||
|
%client.ndSelectionBox = ND_SelectionBox(%shapeName);
|
||||||
|
|
||||||
|
// if(%client.ndMultiSelect)
|
||||||
|
// %box = ndGetPlateBoxFromRayCast(%pos, %normal);
|
||||||
|
// else
|
||||||
|
%box = %obj.getWorldBox();
|
||||||
|
|
||||||
|
%p1 = getWords(%box, 0, 2);
|
||||||
|
%p2 = getWords(%box, 3, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
%client.ndSelectionBox.setSizeAligned(%p1, %p2, %client.getControlObject());
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Generic inputs
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Light key
|
||||||
|
function NDM_BoxSelect::onLight(%this, %client)
|
||||||
|
{
|
||||||
|
if($Pref::Server::ND::PlayMenuSounds)
|
||||||
|
%client.play2d(lightOffSound);
|
||||||
|
|
||||||
|
%client.ndSetMode(NDM_StackSelect);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Prev Seat
|
||||||
|
function NDM_BoxSelect::onPrevSeat(%this, %client)
|
||||||
|
{
|
||||||
|
%client.ndLimited = !%client.ndLimited;
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
|
||||||
|
if($Pref::Server::ND::PlayMenuSounds)
|
||||||
|
%client.play2d(%client.ndLimited ? lightOnSound : lightOffSound);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Shift Brick
|
||||||
|
function NDM_BoxSelect::onShiftBrick(%this, %client, %x, %y, %z)
|
||||||
|
{
|
||||||
|
if(!isObject(%client.ndSelectionBox))
|
||||||
|
return;
|
||||||
|
|
||||||
|
//If we have a selection, enter plant mode!
|
||||||
|
if(%client.ndSelectionAvailable)
|
||||||
|
{
|
||||||
|
%client.ndSetMode(NDM_PlantCopy);
|
||||||
|
NDM_PlantCopy.onShiftBrick(%client, %x, %y, %z);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Move the corner
|
||||||
|
switch(getAngleIDFromPlayer(%client.getControlObject()))
|
||||||
|
{
|
||||||
|
case 0: %newX = %x; %newY = %y;
|
||||||
|
case 1: %newX = -%y; %newY = %x;
|
||||||
|
case 2: %newX = -%x; %newY = -%y;
|
||||||
|
case 3: %newX = %y; %newY = -%x;
|
||||||
|
}
|
||||||
|
|
||||||
|
%newX = mFloor(%newX) / 2;
|
||||||
|
%newY = mFloor(%newY) / 2;
|
||||||
|
%z = mFloor(%z ) / 5;
|
||||||
|
|
||||||
|
if(!%client.ndMultiSelect)
|
||||||
|
{
|
||||||
|
if(%client.isAdmin)
|
||||||
|
%limit = $Pref::Server::ND::MaxBoxSizeAdmin;
|
||||||
|
else
|
||||||
|
%limit = $Pref::Server::ND::MaxBoxSizePlayer;
|
||||||
|
|
||||||
|
if(%client.ndSelectionBox.shiftCorner(%newX SPC %newY SPC %z, %limit))
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Oops!\n<font:Verdana:17>" @
|
||||||
|
"\c6Your selection box is limited to \c3" @ mFloor(%limit * 2) @ " \c6studs.", 5);
|
||||||
|
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%client.ndSelectionBox.shift(%newX SPC %newY SPC %z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Super Shift Brick
|
||||||
|
function NDM_BoxSelect::onSuperShiftBrick(%this, %client, %x, %y, %z)
|
||||||
|
{
|
||||||
|
//If we have a selection, enter plant mode!
|
||||||
|
if(%client.ndSelectionAvailable)
|
||||||
|
{
|
||||||
|
%client.ndSetMode(NDM_PlantCopy);
|
||||||
|
NDM_PlantCopy.onSuperShiftBrick(%client, %x, %y, %z);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%this.onShiftBrick(%client, %x * 8, %y * 8, %z * 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Rotate Brick
|
||||||
|
function NDM_BoxSelect::onRotateBrick(%this, %client, %direction)
|
||||||
|
{
|
||||||
|
if(!isObject(%client.ndSelectionBox))
|
||||||
|
return;
|
||||||
|
|
||||||
|
//If we have a selection, enter plant mode!
|
||||||
|
if(%client.ndSelectionAvailable)
|
||||||
|
{
|
||||||
|
%client.ndSetMode(NDM_PlantCopy);
|
||||||
|
NDM_PlantCopy.onRotateBrick(%client, %direction);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!%client.ndMultiSelect)
|
||||||
|
%client.ndSelectionBox.switchCorner();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%client.ndSelectionBox.rotate(%direction);
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Plant Brick
|
||||||
|
function NDM_BoxSelect::onPlantBrick(%this, %client)
|
||||||
|
{
|
||||||
|
if(!isObject(%client.ndSelectionBox))
|
||||||
|
return;
|
||||||
|
|
||||||
|
//If we have a selection, enter plant mode!
|
||||||
|
if(%client.ndSelectionAvailable)
|
||||||
|
{
|
||||||
|
%client.ndSetMode(NDM_PlantCopy);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check timeout
|
||||||
|
if(!%client.isAdmin && %client.ndLastSelectTime + ($Pref::Server::ND::SelectTimeoutMS / 1000) > $Sim::Time)
|
||||||
|
{
|
||||||
|
%remain = mCeil(%client.ndLastSelectTime + ($Pref::Server::ND::SelectTimeoutMS / 1000) - $Sim::Time);
|
||||||
|
|
||||||
|
if(%remain != 1)
|
||||||
|
%s = "s";
|
||||||
|
|
||||||
|
messageClient(%client, 'MsgError', "");
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6You need to wait\c3 " @
|
||||||
|
%remain @ "\c6 second" @ %s @ " before selecting again!", 5);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%client.ndLastSelectTime = $Sim::Time;
|
||||||
|
|
||||||
|
//Prepare a selection to copy the bricks
|
||||||
|
if(isObject(%client.ndSelection))
|
||||||
|
%client.ndSelection.deleteData();
|
||||||
|
else
|
||||||
|
%client.ndSelection = ND_Selection(%client);
|
||||||
|
|
||||||
|
//Start selection
|
||||||
|
%box = %client.ndSelectionBox.getWorldBox();
|
||||||
|
|
||||||
|
%client.ndSetMode(NDM_BoxSelectProgress);
|
||||||
|
%client.ndSelection.startBoxSelection(%box, %client.ndLimited);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cancel Brick
|
||||||
|
function NDM_BoxSelect::onCancelBrick(%this, %client)
|
||||||
|
{
|
||||||
|
if(!isObject(%client.ndSelectionBox))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(%client.ndSelectionAvailable)
|
||||||
|
{
|
||||||
|
messageClient(%client, 'MsgError', "");
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Selection canceled! " @
|
||||||
|
"You can now edit the box again.", 5);
|
||||||
|
|
||||||
|
%client.ndSelectionAvailable = false;
|
||||||
|
%client.ndSelection.deleteData();
|
||||||
|
%client.ndSelectionBox.setNormalMode();
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isObject(%client.ndSelection))
|
||||||
|
%client.ndSelection.deleteData();
|
||||||
|
|
||||||
|
%client.ndSelectionBox.delete();
|
||||||
|
%client.ndSelectionAvailable = false;
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Copy Selection
|
||||||
|
function NDM_BoxSelect::onCopy(%this, %client)
|
||||||
|
{
|
||||||
|
%this.onPlantBrick(%client);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cut Selection
|
||||||
|
function NDM_BoxSelect::onCut(%this, %client)
|
||||||
|
{
|
||||||
|
if(!isObject(%client.ndSelectionBox))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(!%client.ndSelectionAvailable)
|
||||||
|
{
|
||||||
|
%this.onPlantBrick(%client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%client.ndSetMode(NDM_CutProgress);
|
||||||
|
%client.ndSelection.startCutting();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Supercut selection
|
||||||
|
function NDM_BoxSelect::onSuperCut(%this, %client)
|
||||||
|
{
|
||||||
|
if(!isObject(%client.ndSelectionBox))
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Prepare a selection to handle the callback
|
||||||
|
if(isObject(%client.ndSelection))
|
||||||
|
%client.ndSelection.deleteData();
|
||||||
|
else
|
||||||
|
%client.ndSelection = ND_Selection(%client);
|
||||||
|
|
||||||
|
if(!$ND::SimpleBrickTableCreated)
|
||||||
|
ndCreateSimpleBrickTable();
|
||||||
|
|
||||||
|
//Start supercut
|
||||||
|
%box = %client.ndSelectionBox.getWorldBox();
|
||||||
|
|
||||||
|
%client.ndSetMode(NDM_SuperCutProgress);
|
||||||
|
%client.ndSelection.startSuperCut(%box);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Create bottomprint for client
|
||||||
|
function NDM_BoxSelect::getBottomPrint(%this, %client)
|
||||||
|
{
|
||||||
|
if(isObject(%client.ndSelection) && %client.ndSelection.brickCount)
|
||||||
|
{
|
||||||
|
%count = %client.ndSelection.brickCount;
|
||||||
|
%title = "Selection Mode (\c3" @ %count @ "\c6 Brick" @ (%count > 1 ? "s)" : ")");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
%title = "Selection Mode";
|
||||||
|
|
||||||
|
%l0 = "Type: \c3Box \c6[Light]";
|
||||||
|
%l1 = "Limited: " @ (%client.ndLimited ? "\c3Yes" : "\c0No") @ " \c6[Prev Seat]";
|
||||||
|
|
||||||
|
if(isObject(%client.ndSelectionBox))
|
||||||
|
{
|
||||||
|
%size = %client.ndSelectionBox.getSize();
|
||||||
|
%x = mFloatLength(getWord(%size, 0) * 2, 0);
|
||||||
|
%y = mFloatLength(getWord(%size, 1) * 2, 0);
|
||||||
|
%z = mFloatLength(getWord(%size, 2) * 5, 0);
|
||||||
|
%l2 = "Size: \c3" @ %x @ "\c6 x \c3" @ %y @ "\c6 x \c3" @ %z @ "\c6 Plates";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isObject(%client.ndSelectionBox))
|
||||||
|
{
|
||||||
|
%r0 = "Click Brick: Place selection box";
|
||||||
|
%r1 = "";
|
||||||
|
%r2 = "";
|
||||||
|
}
|
||||||
|
else if(!%client.ndSelectionAvailable)
|
||||||
|
{
|
||||||
|
%r0 = "[Shift Brick]: Move corner";
|
||||||
|
%r1 = "[Rotate Brick]: Switch corner";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%r0 = "[Cancel Brick]: Adjust box";
|
||||||
|
%r1 = "[Plant Brick]: Duplicate";
|
||||||
|
}
|
||||||
|
|
||||||
|
return ndFormatMessage(%title, %l0, %r0, %l1, %r1, %l2, %r2);
|
||||||
|
}
|
59
classes/server/duplimode/boxselectprogress.cs
Normal file
59
classes/server/duplimode/boxselectprogress.cs
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Changing modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Kill this mode
|
||||||
|
function NDM_BoxSelectProgress::onKillMode(%this, %client)
|
||||||
|
{
|
||||||
|
//Destroy the selection
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
|
||||||
|
//Remove selection box
|
||||||
|
%client.ndSelectionBox.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Generic inputs
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Cancel Brick
|
||||||
|
function NDM_BoxSelectProgress::onCancelBrick(%this, %client)
|
||||||
|
{
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Selection canceled!", 4);
|
||||||
|
|
||||||
|
%client.ndSelection.cancelBoxSelection();
|
||||||
|
%client.ndSetMode(NDM_BoxSelect);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Create bottomprint for client
|
||||||
|
function NDM_BoxSelectProgress::getBottomPrint(%this, %client)
|
||||||
|
{
|
||||||
|
%qCount = %client.ndSelection.queueCount;
|
||||||
|
%bCount = %client.ndSelection.brickCount;
|
||||||
|
|
||||||
|
if(%bCount <= 0)
|
||||||
|
{
|
||||||
|
%curr = %client.ndSelection.currChunk + 1;
|
||||||
|
%num = %client.ndSelection.numChunks;
|
||||||
|
|
||||||
|
%percent = mFloor(%curr * 100 / %num);
|
||||||
|
%title = "Searching... (\c3" @ %percent @ "%\c6, \c3" @ %qCount @ "\c6 Bricks)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%percent = mFloor(%bCount * 100 / %qCount);
|
||||||
|
%title = "Processing... (\c3" @ %percent @ "%\c6)";
|
||||||
|
}
|
||||||
|
|
||||||
|
%l0 = "[Cancel Brick]: Cancel selection";
|
||||||
|
|
||||||
|
return ndFormatMessage(%title, %l0);
|
||||||
|
}
|
48
classes/server/duplimode/cutprogress.cs
Normal file
48
classes/server/duplimode/cutprogress.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Changing modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Switch away from this mode
|
||||||
|
function NDM_CutProgress::onChangeMode(%this, %client, %nextMode)
|
||||||
|
{
|
||||||
|
if(%nextMode != $NDM::PlantCopy)
|
||||||
|
%client.ndSelection.deleteData();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Kill this mode
|
||||||
|
function NDM_CutProgress::onKillMode(%this, %client)
|
||||||
|
{
|
||||||
|
//Destroy the selection
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Generic inputs
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Cancel Brick
|
||||||
|
function NDM_CutProgress::onCancelBrick(%this, %client)
|
||||||
|
{
|
||||||
|
%client.ndSelection.cancelCutting();
|
||||||
|
%client.ndSetMode(%client.ndLastSelectMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Create bottomprint for client
|
||||||
|
function NDM_CutProgress::getBottomPrint(%this, %client)
|
||||||
|
{
|
||||||
|
%count = %client.ndSelection.brickCount;
|
||||||
|
%percent = mFloor(%client.ndSelection.cutIndex * 100 / %count);
|
||||||
|
|
||||||
|
%title = "Cutting... (\c3" @ %percent @ "%\c6)";
|
||||||
|
%l0 = "[Cancel Brick]: Cancel cut";
|
||||||
|
|
||||||
|
return ndFormatMessage(%title, %l0);
|
||||||
|
}
|
128
classes/server/duplimode/fillcolor.cs
Normal file
128
classes/server/duplimode/fillcolor.cs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Changing modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Switch to this mode
|
||||||
|
function NDM_FillColor::onStartMode(%this, %client, %lastMode)
|
||||||
|
{
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
cancel(%client.ndToolSchedule);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Switch away from this mode
|
||||||
|
function NDM_FillColor::onChangeMode(%this, %client, %nextMode)
|
||||||
|
{
|
||||||
|
//Hide paint gui
|
||||||
|
if(%nextMode != $NDM::FillColorProgress)
|
||||||
|
{
|
||||||
|
%client.ndLastEquipTime = $Sim::Time;
|
||||||
|
|
||||||
|
if(%client.ndEquippedFromItem)
|
||||||
|
commandToClient(%client, 'setScrollMode', 2);
|
||||||
|
else
|
||||||
|
commandToClient(%client, 'setScrollMode', 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Kill this mode
|
||||||
|
function NDM_FillColor::onKillMode(%this, %client)
|
||||||
|
{
|
||||||
|
//Destroy the selection
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
|
||||||
|
//Remove the selection box
|
||||||
|
if(isObject(%client.ndSelectionBox))
|
||||||
|
%client.ndSelectionBox.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Generic inputs
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Plant Brick
|
||||||
|
function NDM_FillColor::onPlantBrick(%this, %client)
|
||||||
|
{
|
||||||
|
//Admin limit
|
||||||
|
if($Pref::Server::ND::PaintAdminOnly && !%client.isAdmin)
|
||||||
|
{
|
||||||
|
messageClient(%client, '', "\c6Paint Mode is admin only. Ask an admin for help.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Normal colors
|
||||||
|
if(%client.currentFxColor $= "")
|
||||||
|
{
|
||||||
|
%client.ndSetMode(NDM_FillColorProgress);
|
||||||
|
%client.ndSelection.startFillColor(0, %client.currentColor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Admin limit
|
||||||
|
if($Pref::Server::ND::PaintFxAdminOnly && !%client.isAdmin)
|
||||||
|
{
|
||||||
|
messageClient(%client, '', "\c6Paint Fx Mode is admin only. Ask an admin for help.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%client.ndSetMode(NDM_FillColorProgress);
|
||||||
|
|
||||||
|
if(%client.currentFxColor < 7)
|
||||||
|
%client.ndSelection.startFillColor(1, %client.currentFxColor);
|
||||||
|
else
|
||||||
|
%client.ndSelection.startFillColor(2, %client.currentFxColor - 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cancel Brick
|
||||||
|
function NDM_FillColor::onCancelBrick(%this, %client)
|
||||||
|
{
|
||||||
|
%client.ndSetMode(%client.ndLastSelectMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Create bottomprint for client
|
||||||
|
function NDM_FillColor::getBottomPrint(%this, %client)
|
||||||
|
{
|
||||||
|
%count = %client.ndSelection.brickCount;
|
||||||
|
%title = "Paint Mode (\c3" @ %count @ "\c6 Brick" @ (%count > 1 ? "s)" : ")");
|
||||||
|
|
||||||
|
if(%client.currentFxColor !$= "")
|
||||||
|
{
|
||||||
|
switch(%client.currentFxColor)
|
||||||
|
{
|
||||||
|
case 0: %color = "\c3Fx - None";
|
||||||
|
case 1: %color = "\c3Fx - Pearl";
|
||||||
|
case 2: %color = "\c3Fx - Chrome";
|
||||||
|
case 3: %color = "\c3Fx - Glow";
|
||||||
|
case 4: %color = "\c3Fx - Blink";
|
||||||
|
case 5: %color = "\c3Fx - Swirl";
|
||||||
|
case 6: %color = "\c3Fx - Rainbow";
|
||||||
|
case 7: %color = "\c3Fx - Stable";
|
||||||
|
case 8: %color = "\c3Fx - Undulo";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%color = "<font:impact:20>" @ ndGetPaintColorCode(%client.currentColor) @ "|||||<font:Verdana:16>\c3";
|
||||||
|
|
||||||
|
%alpha = mFloor(100 * getWord(getColorIdTable(%client.currentColor), 3));
|
||||||
|
|
||||||
|
if(%alpha != 100)
|
||||||
|
%color = %color SPC %alpha @ "%";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
%l0 = "Select paint can to chose color";
|
||||||
|
%l1 = "Color: " @ %color;
|
||||||
|
|
||||||
|
%r0 = "[Plant Brick]: Paint bricks";
|
||||||
|
%r1 = "[Cancel Brick]: Exit mode";
|
||||||
|
|
||||||
|
return ndFormatMessage(%title, %l0, %r0, %l1, %r1, %l2);
|
||||||
|
}
|
41
classes/server/duplimode/fillcolorprogress.cs
Normal file
41
classes/server/duplimode/fillcolorprogress.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Changing modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Kill this mode
|
||||||
|
function NDM_FillColorProgress::onKillMode(%this, %client)
|
||||||
|
{
|
||||||
|
//Destroy the selection
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Generic inputs
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Cancel Brick
|
||||||
|
function NDM_FillColorProgress::onCancelBrick(%this, %client)
|
||||||
|
{
|
||||||
|
%client.ndSelection.cancelFillColor();
|
||||||
|
%client.ndSetMode(NDM_FillColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Create bottomprint for client
|
||||||
|
function NDM_FillColorProgress::getBottomPrint(%this, %client)
|
||||||
|
{
|
||||||
|
%count = %client.ndSelection.brickCount;
|
||||||
|
%percent = mFloor(%client.ndSelection.paintIndex * 100 / %count);
|
||||||
|
|
||||||
|
%title = "Painting... (\c3" @ %percent @ "%\c6)";
|
||||||
|
%l0 = "[Cancel Brick]: Cancel painting";
|
||||||
|
|
||||||
|
return ndFormatMessage(%title, %l0);
|
||||||
|
}
|
76
classes/server/duplimode/loadprogress.cs
Normal file
76
classes/server/duplimode/loadprogress.cs
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Changing modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Switch to this mode
|
||||||
|
function NDM_LoadProgress::onStartMode(%this, %client, %lastMode)
|
||||||
|
{
|
||||||
|
//Prepare selection to load data into
|
||||||
|
if(isObject(%client.ndSelection))
|
||||||
|
%client.ndSelection.deleteData();
|
||||||
|
else
|
||||||
|
%client.ndSelection = ND_Selection(%client);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Kill this mode
|
||||||
|
function NDM_LoadProgress::onKillMode(%this, %client)
|
||||||
|
{
|
||||||
|
//Destroy selection
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Generic inputs
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Cancel Brick
|
||||||
|
function NDM_LoadProgress::onCancelBrick(%this, %client)
|
||||||
|
{
|
||||||
|
%client.ndSelection.cancelLoading();
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
|
||||||
|
%client.ndSetMode(%client.ndLastSelectMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Create bottomprint for client
|
||||||
|
function NDM_LoadProgress::getBottomPrint(%this, %client)
|
||||||
|
{
|
||||||
|
if(%client.ndSelection.loadStage == 0)
|
||||||
|
{
|
||||||
|
%count = %client.ndSelection.loadExpectedBrickCount;
|
||||||
|
|
||||||
|
if(%count != 0)
|
||||||
|
{
|
||||||
|
%percent = mFloor(%client.ndSelection.brickCount * 100 / %count);
|
||||||
|
|
||||||
|
%title = "Loading Bricks... (\c3" @ %percent @ "%\c6)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
%title = "Loading Bricks... (\c3" @ %client.ndSelection.brickCount @ "\c6 Bricks)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%count = %client.ndSelection.loadExpectedConnectionCount;
|
||||||
|
|
||||||
|
if(%count != 0)
|
||||||
|
{
|
||||||
|
%percent = mFloor(%client.ndSelection.connectionCount * 100 / %count);
|
||||||
|
|
||||||
|
%title = "Loading Connections... (\c3" @ %percent @ "%\c6)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
%title = "Loading Connections... (\c3" @ %client.ndSelection.connectionCount @ "\c6 Connections)";
|
||||||
|
}
|
||||||
|
|
||||||
|
%l0 = "[Cancel Brick]: Cancel loading";
|
||||||
|
|
||||||
|
return ndFormatMessage(%title, %l0);
|
||||||
|
}
|
268
classes/server/duplimode/plantcopy.cs
Normal file
268
classes/server/duplimode/plantcopy.cs
Normal file
@ -0,0 +1,268 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Changing modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Switch to this mode
|
||||||
|
function NDM_PlantCopy::onStartMode(%this, %client, %lastMode)
|
||||||
|
{
|
||||||
|
if(%lastMode == $NDM::StackSelect
|
||||||
|
|| %lastMode == $NDM::BoxSelect
|
||||||
|
|| %lastMode == $NDM::CutProgress
|
||||||
|
|| %lastMode == $NDM::LoadProgress)
|
||||||
|
{
|
||||||
|
%client.ndSelection.spawnGhostBricks(%client.ndSelection.rootPosition, 0);
|
||||||
|
%client.ndSelection.angleIdReference = getAngleIDFromPlayer(%client.getControlObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Switch away from this mode
|
||||||
|
function NDM_PlantCopy::onChangeMode(%this, %client, %nextMode)
|
||||||
|
{
|
||||||
|
if(%nextMode == $NDM::StackSelect || %nextMode == $NDM::BoxSelect)
|
||||||
|
{
|
||||||
|
%client.ndSelection.deleteData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Kill this mode
|
||||||
|
function NDM_PlantCopy::onKillMode(%this, %client)
|
||||||
|
{
|
||||||
|
//Destroy the selection
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Duplicator image callbacks
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Selecting an object with the duplicator
|
||||||
|
function NDM_PlantCopy::onSelectObject(%this, %client, %obj, %pos, %normal)
|
||||||
|
{
|
||||||
|
%this.moveBricksTo(%client, %pos, %normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Generic inputs
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Prev Seat
|
||||||
|
function NDM_PlantCopy::onPrevSeat(%this, %client)
|
||||||
|
{
|
||||||
|
%client.ndPivot = !%client.ndPivot;
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
|
||||||
|
if($Pref::Server::ND::PlayMenuSounds)
|
||||||
|
%client.play2d(%client.ndPivot ? lightOnSound : lightOffSound);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Shift Brick
|
||||||
|
function NDM_PlantCopy::onShiftBrick(%this, %client, %x, %y, %z)
|
||||||
|
{
|
||||||
|
switch(getAngleIDFromPlayer(%client.getControlObject()))
|
||||||
|
{
|
||||||
|
case 0: %newX = %x; %newY = %y;
|
||||||
|
case 1: %newX = -%y; %newY = %x;
|
||||||
|
case 2: %newX = -%x; %newY = -%y;
|
||||||
|
case 3: %newX = %y; %newY = -%x;
|
||||||
|
}
|
||||||
|
|
||||||
|
%client.ndSelection.shiftGhostBricks(%newX / 2 SPC %newY / 2 SPC %z / 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Super Shift Brick
|
||||||
|
function NDM_PlantCopy::onSuperShiftBrick(%this, %client, %x, %y, %z)
|
||||||
|
{
|
||||||
|
switch(getAngleIDFromPlayer(%client.getControlObject()))
|
||||||
|
{
|
||||||
|
case 0: %newX = %x; %newY = %y;
|
||||||
|
case 1: %newX = -%y; %newY = %x;
|
||||||
|
case 2: %newX = -%x; %newY = -%y;
|
||||||
|
case 3: %newX = %y; %newY = -%x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%client.ndPivot)
|
||||||
|
%box = %client.ndSelection.getGhostWorldBox();
|
||||||
|
else
|
||||||
|
%box = %client.ndSelection.ghostGroup.getObject(0).getWorldBox();
|
||||||
|
|
||||||
|
%newX *= (getWord(%box, 3) - getWord(%box, 0));
|
||||||
|
%newy *= (getWord(%box, 4) - getWord(%box, 1));
|
||||||
|
%z *= (getWord(%box, 5) - getWord(%box, 2));
|
||||||
|
|
||||||
|
%client.ndSelection.shiftGhostBricks(%newX SPC %newY SPC %z);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Rotate Brick
|
||||||
|
function NDM_PlantCopy::onRotateBrick(%this, %client, %direction)
|
||||||
|
{
|
||||||
|
%client.ndSelection.rotateGhostBricks(%direction, %client.ndPivot);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Plant Brick
|
||||||
|
function NDM_PlantCopy::onPlantBrick(%this, %client)
|
||||||
|
{
|
||||||
|
//Check force plant
|
||||||
|
if(%client.ndForcePlant)
|
||||||
|
{
|
||||||
|
if($Pref::Server::ND::FloatAdminOnly && !%client.isAdmin)
|
||||||
|
{
|
||||||
|
messageClient(%client, '', "\c6Force Plant has been disabled because it is admin only. Ask an admin for help.");
|
||||||
|
%client.ndForcePlant = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%this.conditionalPlant(%client, %client.ndForcePlant);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cancel Brick
|
||||||
|
function NDM_PlantCopy::onCancelBrick(%this, %client)
|
||||||
|
{
|
||||||
|
if(%client.ndEquipped)
|
||||||
|
%client.ndSetMode(%client.ndLastSelectMode);
|
||||||
|
else
|
||||||
|
%client.ndKillMode();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Paste Selection
|
||||||
|
function NDM_PlantCopy::onPaste(%this, %client)
|
||||||
|
{
|
||||||
|
%this.onPlantBrick(%client);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Create bottomprint for client
|
||||||
|
function NDM_PlantCopy::getBottomPrint(%this, %client)
|
||||||
|
{
|
||||||
|
%count = %client.ndSelection.brickCount;
|
||||||
|
|
||||||
|
%size = vectorSub(%client.ndSelection.maxSize, %client.ndSelection.minSize);
|
||||||
|
|
||||||
|
%x = mFloor(getWord(%size, 0) * 2);
|
||||||
|
%y = mFloor(getWord(%size, 1) * 2);
|
||||||
|
%z = mFloor(getWord(%size, 2) * 5);
|
||||||
|
|
||||||
|
if(%count == 1)
|
||||||
|
%title = "Plant Mode (\c31\c6 Brick)";
|
||||||
|
else if(%count <= $Pref::Server::ND::MaxGhostBricks)
|
||||||
|
%title = "Plant Mode (\c3" @ %count @ "\c6 Bricks)";
|
||||||
|
else
|
||||||
|
%title = "Plant Mode (\c3" @ %count @ "\c6 Bricks, \c3" @ mFloor($Pref::Server::ND::MaxGhostBricks * 100 / %count) @ "%\c6 Ghosted)";
|
||||||
|
|
||||||
|
%l0 = "Pivot: \c3" @ (%client.ndPivot ? "Whole Selection" : "Start Brick") @ "\c6 [Prev Seat]";
|
||||||
|
|
||||||
|
if(isObject(%client.ndSelection.targetGroup))
|
||||||
|
%l1 = "Planting as: \c3" @ %client.ndSelection.targetGroup.name;
|
||||||
|
else
|
||||||
|
%l1 = "Size: \c3" @ %x @ "\c6 x \c3" @ %y @ "\c6 x \c3" @ %z @ "\c6 Plates";
|
||||||
|
|
||||||
|
%r0 = "Use normal ghost brick controls";
|
||||||
|
%r1 = "[Cancel Brick] to exit plant mode";
|
||||||
|
|
||||||
|
return ndFormatMessage(%title, %l0, %r0, %l1, %r1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Functions
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Move the bricks to a specific location, like with the brick tool
|
||||||
|
function NDM_PlantCopy::moveBricksTo(%his, %client, %pos, %normal)
|
||||||
|
{
|
||||||
|
//Get half size of world box for offset
|
||||||
|
if(%client.ndPivot)
|
||||||
|
%box = %client.ndSelection.getGhostWorldBox();
|
||||||
|
else
|
||||||
|
%box = %client.ndSelection.ghostGroup.getObject(0).getWorldBox();
|
||||||
|
|
||||||
|
%halfSize = vectorScale(vectorSub(getWords(%box, 3, 5), getWords(%box, 0, 2)), 0.5);
|
||||||
|
|
||||||
|
//Point offset in correct direction based on normal
|
||||||
|
%offX = getWord(%halfSize, 0) * mFloatLength(getWord(%normal, 0), 0);
|
||||||
|
%offY = getWord(%halfSize, 1) * mFloatLength(getWord(%normal, 1), 0);
|
||||||
|
%offZ = getWord(%halfSize, 2) * mFloatLength(getWord(%normal, 2), 0);
|
||||||
|
%offset = %offX SPC %offY SPC %offZ;
|
||||||
|
|
||||||
|
//Get shift vector
|
||||||
|
%pos = vectorSub(vectorAdd(%pos, %offset), %client.ndSelection.ghostPosition);
|
||||||
|
|
||||||
|
if(%client.ndPivot)
|
||||||
|
{
|
||||||
|
%toCenter = %client.ndSelection.rootToCenter;
|
||||||
|
|
||||||
|
//Apply mirror
|
||||||
|
if(%client.ndSelection.ghostMirrorX)
|
||||||
|
%toCenter = -firstWord(%toCenter) SPC restWords(%toCenter);
|
||||||
|
else if(%client.ndSelection.ghostMirrorY)
|
||||||
|
%toCenter = getWord(%toCenter, 0) SPC -getWord(%toCenter, 1) SPC getWord(%toCenter, 2);
|
||||||
|
|
||||||
|
if(%client.ndSelection.ghostMirrorZ)
|
||||||
|
%toCenter = getWord(%toCenter, 0) SPC getWord(%toCenter, 1) SPC -getWord(%toCenter, 2);
|
||||||
|
|
||||||
|
%pos = vectorSub(%pos, ndRotateVector(%toCenter, %client.ndSelection.ghostAngleID));
|
||||||
|
}
|
||||||
|
|
||||||
|
%client.ndSelection.shiftGhostBricks(%pos);
|
||||||
|
|
||||||
|
//Offset required for New Brick Tool to display the tracer shape correctly
|
||||||
|
if(%client.ndPivot)
|
||||||
|
return vectorSub(%client.ndSelection.getGhostCenter(), %offset);
|
||||||
|
else
|
||||||
|
return vectorSub(%client.ndSelection.ghostGroup.getObject(0).getWorldBoxCenter(), %offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check time limit and attempt to plant bricks
|
||||||
|
function NDM_PlantCopy::conditionalPlant(%this, %client, %force)
|
||||||
|
{
|
||||||
|
//Check timeout
|
||||||
|
if(!%client.isAdmin && %client.ndLastPlantTime + ($Pref::Server::ND::PlantTimeoutMS / 1000) > $Sim::Time)
|
||||||
|
{
|
||||||
|
%remain = mCeil(%client.ndLastPlantTime + ($Pref::Server::ND::PlantTimeoutMS / 1000) - $Sim::Time);
|
||||||
|
|
||||||
|
if(%remain != 1)
|
||||||
|
%s = "s";
|
||||||
|
|
||||||
|
messageClient(%client, 'MsgError', "");
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6You need to wait\c3 " @ %remain @ "\c6 second" @ %s @ " before planting again!", 5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check too far distance
|
||||||
|
%offset = vectorSub(%client.ndSelection.getGhostCenter(), %client.getControlObject().position);
|
||||||
|
|
||||||
|
if(vectorLen(%offset) > $Pref::Server::TooFarDistance)
|
||||||
|
{
|
||||||
|
messageClient(%client, 'MsgError', "");
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6You can't plant so far away!", 5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Validate target group
|
||||||
|
if(isObject(%client.ndSelection.targetGroup) &&
|
||||||
|
getTrustLevel(%client, %client.ndSelection.targetGroup) < 1 &&
|
||||||
|
(!%client.isAdmin || !$Pref::Server::ND::AdminTrustBypass2))
|
||||||
|
{
|
||||||
|
messageClient(%client, '', "\c6You need build trust with \c3"
|
||||||
|
@ %client.ndSelection.targetGroup.name @ "\c6 to plant bricks in their group.");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%client.ndLastPlantTime = $Sim::Time;
|
||||||
|
|
||||||
|
%pos = %client.ndSelection.ghostPosition;
|
||||||
|
%ang = %client.ndSelection.ghostAngleID;
|
||||||
|
|
||||||
|
%client.ndSetMode(NDM_PlantCopyProgress);
|
||||||
|
%client.ndSelection.startPlant(%pos, %ang, %force);
|
||||||
|
}
|
62
classes/server/duplimode/plantcopyprogress.cs
Normal file
62
classes/server/duplimode/plantcopyprogress.cs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Changing modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Kill this mode
|
||||||
|
function NDM_PlantCopyProgress::onKillMode(%this, %client)
|
||||||
|
{
|
||||||
|
//Destroy the selection
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Generic inputs
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Cancel Brick
|
||||||
|
function NDM_PlantCopyProgress::onCancelBrick(%this, %client)
|
||||||
|
{
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Planting canceled!", 4);
|
||||||
|
|
||||||
|
%client.ndSelection.cancelPlanting();
|
||||||
|
%client.ndSetMode(NDM_PlantCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Create bottomprint for client
|
||||||
|
function NDM_PlantCopyProgress::getBottomPrint(%this, %client)
|
||||||
|
{
|
||||||
|
%qIndex = %client.ndSelection.plantQueueIndex;
|
||||||
|
%qCount = %client.ndSelection.plantQueueCount;
|
||||||
|
|
||||||
|
%count = %client.ndSelection.brickCount;
|
||||||
|
%planted = %client.ndSelection.plantSuccessCount;
|
||||||
|
|
||||||
|
if(%qIndex == %qCount)
|
||||||
|
{
|
||||||
|
//Searching for a brick
|
||||||
|
%pIndex = %client.ndSelection.plantSearchIndex;
|
||||||
|
%percent = mFloor(%client.ndSelection.plantSearchIndex * 100 / %count);
|
||||||
|
|
||||||
|
%title = "Finding Next Brick... (\c3" @ %percent @ "%\c6, \c3" @ %planted @ "\c6 planted)";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Planting bricks
|
||||||
|
%failed = %client.ndSelection.plantTrustFailCount + %client.ndSelection.plantBlockedFailCount;
|
||||||
|
%percent = mFloor(%planted * 100 / %count);
|
||||||
|
|
||||||
|
%title = "Planting... (\c3" @ %percent @ "%\c6, \c3" @ %failed @ "\c6 failed)";
|
||||||
|
}
|
||||||
|
|
||||||
|
%l0 = "[Cancel Brick]: Cancel planting";
|
||||||
|
|
||||||
|
return ndFormatMessage(%title, %l0);
|
||||||
|
}
|
43
classes/server/duplimode/saveprogress.cs
Normal file
43
classes/server/duplimode/saveprogress.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Changing modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Kill this mode
|
||||||
|
function NDM_SaveProgress::onKillMode(%this, %client)
|
||||||
|
{
|
||||||
|
//Destroy selection
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Generic inputs
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Cancel Brick
|
||||||
|
function NDM_SaveProgress::onCancelBrick(%this, %client)
|
||||||
|
{
|
||||||
|
%client.ndSelection.cancelSaving();
|
||||||
|
%client.ndSetMode(NDM_PlantCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Create bottomprint for client
|
||||||
|
function NDM_SaveProgress::getBottomPrint(%this, %client)
|
||||||
|
{
|
||||||
|
%count = %client.ndSelection.brickCount;
|
||||||
|
%index = %client.ndSelection.saveIndex / 2 + %client.ndSelection.saveStage * %count / 2;
|
||||||
|
|
||||||
|
%percent = mFloor(%index * 100 / %count);
|
||||||
|
|
||||||
|
%title = "Saving Selection... (\c3" @ %percent @ "%\c6)";
|
||||||
|
%l0 = "[Cancel Brick]: Cancel saving";
|
||||||
|
|
||||||
|
return ndFormatMessage(%title, %l0);
|
||||||
|
}
|
210
classes/server/duplimode/stackselect.cs
Normal file
210
classes/server/duplimode/stackselect.cs
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Changing modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Switch to this mode
|
||||||
|
function NDM_StackSelect::onStartMode(%this, %client, %lastMode)
|
||||||
|
{
|
||||||
|
%client.ndLastSelectMode = %this;
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Switch away from this mode
|
||||||
|
function NDM_StackSelect::onChangeMode(%this, %client, %nextMode)
|
||||||
|
{
|
||||||
|
if(%nextMode == $NDM::FillColor
|
||||||
|
|| %nextMode == $NDM::PlantCopy
|
||||||
|
|| %nextMode == $NDM::WrenchProgress)
|
||||||
|
{
|
||||||
|
//Start de-highlighting the bricks
|
||||||
|
%client.ndSelection.deHighlight();
|
||||||
|
}
|
||||||
|
|
||||||
|
//The transition to box select mode will be
|
||||||
|
//handled in NDM_BoxSelect::onStartMode
|
||||||
|
}
|
||||||
|
|
||||||
|
//Kill this mode
|
||||||
|
function NDM_StackSelect::onKillMode(%this, %client)
|
||||||
|
{
|
||||||
|
//Destroy selection
|
||||||
|
if(isObject(%client.ndSelection))
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Duplicator image callbacks
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Selecting an object with the duplicator
|
||||||
|
function NDM_StackSelect::onSelectObject(%this, %client, %obj, %pos, %normal)
|
||||||
|
{
|
||||||
|
if((%obj.getType() & $TypeMasks::FxBrickAlwaysObjectType) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Check timeout
|
||||||
|
if(!%client.isAdmin && %client.ndLastSelectTime + ($Pref::Server::ND::SelectTimeoutMS / 1000) > $Sim::Time)
|
||||||
|
{
|
||||||
|
%remain = mCeil(%client.ndLastSelectTime + ($Pref::Server::ND::SelectTimeoutMS / 1000) - $Sim::Time);
|
||||||
|
|
||||||
|
if(%remain != 1)
|
||||||
|
%s = "s";
|
||||||
|
|
||||||
|
messageClient(%client, 'MsgError', "");
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6You need to wait\c3 " @
|
||||||
|
%remain @ "\c6 second" @ %s @ " before selecting again!", 5);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%client.ndLastSelectTime = $Sim::Time;
|
||||||
|
|
||||||
|
if(!ndTrustCheckMessage(%obj, %client))
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Prepare selection to copy the bricks
|
||||||
|
if(!isObject(%client.ndSelection))
|
||||||
|
%client.ndSelection = ND_Selection(%client);
|
||||||
|
|
||||||
|
//Start selection
|
||||||
|
%client.ndSetMode(NDM_StackSelectProgress);
|
||||||
|
|
||||||
|
if(%client.ndMultiSelect)
|
||||||
|
%client.ndSelection.startStackSelectionAdditive(%obj, %client.ndDirection, %client.ndLimited);
|
||||||
|
else
|
||||||
|
%client.ndSelection.startStackSelection(%obj, %client.ndDirection, %client.ndLimited);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Generic inputs
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Light key
|
||||||
|
function NDM_StackSelect::onLight(%this, %client)
|
||||||
|
{
|
||||||
|
if($Pref::Server::ND::PlayMenuSounds)
|
||||||
|
%client.play2d(lightOnSound);
|
||||||
|
|
||||||
|
%client.ndSetMode(NDM_BoxSelect);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Next Seat
|
||||||
|
function NDM_StackSelect::onNextSeat(%this, %client)
|
||||||
|
{
|
||||||
|
%client.ndDirection = !%client.ndDirection;
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
|
||||||
|
if($Pref::Server::ND::PlayMenuSounds)
|
||||||
|
%client.play2d(%client.ndDirection ? lightOnSound : lightOffSound);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Prev Seat
|
||||||
|
function NDM_StackSelect::onPrevSeat(%this, %client)
|
||||||
|
{
|
||||||
|
%client.ndLimited = !%client.ndLimited;
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
|
||||||
|
if($Pref::Server::ND::PlayMenuSounds)
|
||||||
|
%client.play2d(%client.ndLimited ? lightOnSound : lightOffSound);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Shift Brick
|
||||||
|
function NDM_StackSelect::onShiftBrick(%this, %client, %x, %y, %z)
|
||||||
|
{
|
||||||
|
if(!isObject(%client.ndSelection) || !%client.ndSelection.brickCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Change to plant mode and apply the shift
|
||||||
|
%client.ndSetMode(NDM_PlantCopy);
|
||||||
|
NDM_PlantCopy.onShiftBrick(%client, %x, %y, %z);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Super Shift Brick
|
||||||
|
function NDM_StackSelect::onSuperShiftBrick(%this, %client, %x, %y, %z)
|
||||||
|
{
|
||||||
|
if(!isObject(%client.ndSelection) || !%client.ndSelection.brickCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Change to plant mode and apply the shift
|
||||||
|
%client.ndSetMode(NDM_PlantCopy);
|
||||||
|
NDM_PlantCopy.onSuperShiftBrick(%client, %x, %y, %z);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Rotate Brick
|
||||||
|
function NDM_StackSelect::onRotateBrick(%this, %client, %dir)
|
||||||
|
{
|
||||||
|
if(!isObject(%client.ndSelection) || !%client.ndSelection.brickCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Change to plant mode and apply the shift
|
||||||
|
%client.ndSetMode(NDM_PlantCopy);
|
||||||
|
NDM_PlantCopy.onRotateBrick(%client, %dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Plant Brick
|
||||||
|
function NDM_StackSelect::onPlantBrick(%this, %client)
|
||||||
|
{
|
||||||
|
if(!isObject(%client.ndSelection) || !%client.ndSelection.brickCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
%client.ndSetMode(NDM_PlantCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cancel Brick
|
||||||
|
function NDM_StackSelect::onCancelBrick(%this, %client)
|
||||||
|
{
|
||||||
|
if(isObject(%client.ndSelection))
|
||||||
|
%client.ndSelection.deleteData();
|
||||||
|
|
||||||
|
%client.ndUpdateBottomPrint();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Copy Selection
|
||||||
|
function NDM_StackSelect::onCopy(%this, %client)
|
||||||
|
{
|
||||||
|
%this.onPlantBrick(%client);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cut Selection
|
||||||
|
function NDM_StackSelect::onCut(%this, %client)
|
||||||
|
{
|
||||||
|
if(!isObject(%client.ndSelection) || !%client.ndSelection.brickCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
%client.ndSetMode(NDM_CutProgress);
|
||||||
|
%client.ndSelection.startCutting();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Create bottomprint for client
|
||||||
|
function NDM_StackSelect::getBottomPrint(%this, %client)
|
||||||
|
{
|
||||||
|
if(!isObject(%client.ndSelection) || !%client.ndSelection.brickCount)
|
||||||
|
{
|
||||||
|
%title = "Selection Mode";
|
||||||
|
%r0 = "Click Brick: Select stack " @ (%client.ndDirection ? "up" : "down");
|
||||||
|
%r1 = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%count = %client.ndSelection.brickCount;
|
||||||
|
|
||||||
|
%title = "Selection Mode (\c3" @ %count @ "\c6 Brick" @ (%count > 1 ? "s)" : ")");
|
||||||
|
%r0 = "Ctrl-Click Brick: Multiselect";
|
||||||
|
%r1 = "[Plant Brick]: Duplicate";
|
||||||
|
}
|
||||||
|
|
||||||
|
%l0 = "Type: \c3" @ (%client.ndMultiSelect ? "Multi-" : "") @ "Stack \c6[Light]";
|
||||||
|
%l1 = "Limited: " @ (%client.ndLimited ? "\c3Yes" : "\c0No") @ " \c6[Prev Seat]";
|
||||||
|
%l2 = "Direction: \c3" @ (%client.ndDirection ? "Up" : "Down") @ " \c6[Next Seat]";
|
||||||
|
|
||||||
|
return ndFormatMessage(%title, %l0, %r0, %l1, %r1, %l2);
|
||||||
|
}
|
43
classes/server/duplimode/stackselectprogress.cs
Normal file
43
classes/server/duplimode/stackselectprogress.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Changing modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Kill this mode
|
||||||
|
function NDM_StackSelectProgress::onKillMode(%this, %client)
|
||||||
|
{
|
||||||
|
//Destroy the selection
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Generic inputs
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Cancel Brick
|
||||||
|
function NDM_StackSelectProgress::onCancelBrick(%this, %client)
|
||||||
|
{
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Selection canceled!", 4);
|
||||||
|
|
||||||
|
%client.ndSelection.cancelStackSelection();
|
||||||
|
%client.ndSetMode(NDM_StackSelect);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Create bottomprint for client
|
||||||
|
function NDM_StackSelectProgress::getBottomPrint(%this, %client)
|
||||||
|
{
|
||||||
|
%count = %client.ndSelection.brickCount;
|
||||||
|
%qCount = %client.ndSelection.queueCount - %count;
|
||||||
|
|
||||||
|
%title = "Selecting... (\c3" @ %count @ "\c6 Bricks, \c3" @ %qCount @ "\c6 in Queue)";
|
||||||
|
%l0 = "[Cancel Brick]: Cancel selection";
|
||||||
|
|
||||||
|
return ndFormatMessage(%title, %l0);
|
||||||
|
}
|
50
classes/server/duplimode/supercutprogress.cs
Normal file
50
classes/server/duplimode/supercutprogress.cs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Changing modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Kill this mode
|
||||||
|
function NDM_SuperCutProgress::onKillMode(%this, %client)
|
||||||
|
{
|
||||||
|
//Destroy the selection
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
|
||||||
|
//Remove selection box
|
||||||
|
%client.ndSelectionBox.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Generic inputs
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Cancel Brick
|
||||||
|
function NDM_SuperCutProgress::onCancelBrick(%this, %client)
|
||||||
|
{
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Supercut canceled!", 4);
|
||||||
|
|
||||||
|
%client.ndSelection.cancelSuperCut();
|
||||||
|
%client.ndSetMode(NDM_BoxSelect);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Create bottomprint for client
|
||||||
|
function NDM_SuperCutProgress::getBottomPrint(%this, %client)
|
||||||
|
{
|
||||||
|
%curr = %client.ndSelection.currChunk + 1;
|
||||||
|
%num = %client.ndSelection.numChunks;
|
||||||
|
|
||||||
|
%percent = mFloor(%curr * 100 / %num);
|
||||||
|
%deleted = %client.ndSelection.superCutCount;
|
||||||
|
%planted = %client.ndSelection.superCutPlacedCount;
|
||||||
|
|
||||||
|
%title = "Supercut in progress... (\c3" @ %percent @ "%\c6, \c3" @ %deleted @ "\c6 deleted, \c3" @ %planted @ "\c6 planted)";
|
||||||
|
%l0 = "[Cancel Brick]: Cancel supercut";
|
||||||
|
|
||||||
|
return ndFormatMessage(%title, %l0);
|
||||||
|
}
|
45
classes/server/duplimode/wrenchprogress.cs
Normal file
45
classes/server/duplimode/wrenchprogress.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Changing modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Kill this mode
|
||||||
|
function NDM_WrenchProgress::onKillMode(%this, %client)
|
||||||
|
{
|
||||||
|
//Destroy the selection
|
||||||
|
%client.ndSelection.delete();
|
||||||
|
|
||||||
|
//Remove the selection box
|
||||||
|
if(isObject(%client.ndSelectionBox))
|
||||||
|
%client.ndSelectionBox.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Generic inputs
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Cancel Brick
|
||||||
|
function NDM_WrenchProgress::onCancelBrick(%this, %client)
|
||||||
|
{
|
||||||
|
%client.ndSelection.cancelFillWrench();
|
||||||
|
%client.ndSetMode(%client.ndLastSelectMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Interface
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Create bottomprint for client
|
||||||
|
function NDM_WrenchProgress::getBottomPrint(%this, %client)
|
||||||
|
{
|
||||||
|
%count = %client.ndSelection.brickCount;
|
||||||
|
%percent = mFloor(%client.ndSelection.wrenchIndex * 100 / %count);
|
||||||
|
|
||||||
|
%title = "Applying... (\c3" @ %percent @ "%\c6)";
|
||||||
|
%l0 = "[Cancel Brick]: Cancel";
|
||||||
|
|
||||||
|
return ndFormatMessage(%title, %l0);
|
||||||
|
}
|
38
classes/server/ghostgroup.cs
Normal file
38
classes/server/ghostgroup.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// Deletes large numbers of ghost bricks without causing lag.
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Create a new ghost group
|
||||||
|
function ND_GhostGroup()
|
||||||
|
{
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
%this = new ScriptGroup(ND_GhostGroup)
|
||||||
|
);
|
||||||
|
|
||||||
|
return %this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Delete some of the bricks in this group
|
||||||
|
function ND_GhostGroup::tickDelete(%this)
|
||||||
|
{
|
||||||
|
%max = $Pref::Server::ND::ProcessPerTick;
|
||||||
|
%bricks = getBrickCount();
|
||||||
|
|
||||||
|
//Deleting objects causes increasing lag with more bricks in total
|
||||||
|
if(%bricks > 450000)
|
||||||
|
%max /= 6;
|
||||||
|
else if(%bricks > 300000)
|
||||||
|
%max /= 4;
|
||||||
|
else if(%bricks > 150000)
|
||||||
|
%max /= 2;
|
||||||
|
|
||||||
|
if(%this.getCount() <= %max)
|
||||||
|
{
|
||||||
|
%this.delete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(%i = 0; %i < %max; %i++)
|
||||||
|
%this.getObject(0).delete();
|
||||||
|
|
||||||
|
%this.schedule(30, tickDelete);
|
||||||
|
}
|
112
classes/server/highlightbox.cs
Normal file
112
classes/server/highlightbox.cs
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// Resizable highlight box to visualize the size of the selection.
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Create a new highlight box
|
||||||
|
function ND_HighlightBox()
|
||||||
|
{
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
%this = new ScriptObject(ND_HighlightBox)
|
||||||
|
);
|
||||||
|
|
||||||
|
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.color = "1 0.84 0 0.99";
|
||||||
|
%this.applyColors();
|
||||||
|
|
||||||
|
return %this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Destroy static shapes when highlight box is removed
|
||||||
|
function ND_HighlightBox::onRemove(%this)
|
||||||
|
{
|
||||||
|
for(%i = 0; %i < 4; %i++)
|
||||||
|
{
|
||||||
|
%this.border_x[%i].delete();
|
||||||
|
%this.border_y[%i].delete();
|
||||||
|
%this.border_z[%i].delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Apply color changes to the highlight box
|
||||||
|
function ND_HighlightBox::applyColors(%this)
|
||||||
|
{
|
||||||
|
for(%i = 0; %i < 4; %i++)
|
||||||
|
{
|
||||||
|
%this.border_x[%i].setNodeColor("ALL", %this.color);
|
||||||
|
%this.border_y[%i].setNodeColor("ALL", %this.color);
|
||||||
|
%this.border_z[%i].setNodeColor("ALL", %this.color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Return current size of highlight box
|
||||||
|
function ND_HighlightBox::getSize(%this)
|
||||||
|
{
|
||||||
|
return %this.point1 SPC %this.point2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Resize the highlight box
|
||||||
|
function ND_HighlightBox::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 = %x2 - %x1;
|
||||||
|
%len_y = %y2 - %y1;
|
||||||
|
%len_z = %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.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);
|
||||||
|
|
||||||
|
%maxLen = getMax(getMax(%len_x, %len_y), %len_z);
|
||||||
|
%width = (7 / 1280) * %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);
|
||||||
|
}
|
||||||
|
}
|
4494
classes/server/selection.cs
Normal file
4494
classes/server/selection.cs
Normal file
File diff suppressed because it is too large
Load Diff
496
classes/server/selectionbox.cs
Normal file
496
classes/server/selectionbox.cs
Normal file
@ -0,0 +1,496 @@
|
|||||||
|
// 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;
|
||||||
|
}
|
75
classes/server/undogrouppaint.cs
Normal file
75
classes/server/undogrouppaint.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Delete this undo group
|
||||||
|
function ND_UndoGroupPaint::onRemove(%this)
|
||||||
|
{
|
||||||
|
if(%this.brickCount)
|
||||||
|
deleteVariables("$NU" @ %this.client @ "_" @ %this @ "_*");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Start undo paint
|
||||||
|
function ND_UndoGroupPaint::ndStartUndo(%this, %client)
|
||||||
|
{
|
||||||
|
%client.ndUndoInProgress = true;
|
||||||
|
%client.ndLastMessageTime = $Sim::Time;
|
||||||
|
%this.ndTickUndo(%this.paintType, 0, %client);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Tick undo paint
|
||||||
|
function ND_UndoGroupPaint::ndTickUndo(%this, %mode, %start, %client)
|
||||||
|
{
|
||||||
|
%end = %start + $Pref::Server::ND::ProcessPerTick;
|
||||||
|
|
||||||
|
if(%end > %this.brickCount)
|
||||||
|
%end = %this.brickCount;
|
||||||
|
|
||||||
|
for(%i = %start; %i < %end; %i++)
|
||||||
|
{
|
||||||
|
%brick = $NU[%client, %this, "B", %i];
|
||||||
|
|
||||||
|
if(!isObject(%brick))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
%colorID = $NU[%client, %this, "V", %i];
|
||||||
|
|
||||||
|
switch(%mode)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
//Check whether brick is highlighted
|
||||||
|
%brick.setColor(%colorID);
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
//Check whether brick is highlighted
|
||||||
|
if($NDHN[%brick])
|
||||||
|
$NDHF[%brick] = %colorID;
|
||||||
|
else
|
||||||
|
%brick.setColorFx(%colorID);
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
%brick.setShapeFx(%colorID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//If undo is taking long, tell the client how far we get
|
||||||
|
if(%client.ndLastMessageTime + 0.1 < $Sim::Time)
|
||||||
|
{
|
||||||
|
%client.ndLastMessageTime = $Sim::Time;
|
||||||
|
|
||||||
|
%percent = mFloor(%end * 100 / %this.brickCount);
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Undo in progress...\n<font:Verdana:17>\c3" @ %percent @ "%\c6 finished.", 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%end >= %this.brickcount)
|
||||||
|
{
|
||||||
|
%this.delete();
|
||||||
|
%client.ndUndoInProgress = false;
|
||||||
|
|
||||||
|
if(%start != 0)
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Undo finished.", 2);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%this.schedule(30, ndTickUndo, %mode, %end, %client);
|
||||||
|
}
|
61
classes/server/undogroupplant.cs
Normal file
61
classes/server/undogroupplant.cs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Start undo bricks
|
||||||
|
function SimSet::ndStartUndo(%this, %client)
|
||||||
|
{
|
||||||
|
if(!%this.brickCount)
|
||||||
|
{
|
||||||
|
%this.delete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%client.ndUndoInProgress = true;
|
||||||
|
%client.ndLastMessageTime = $Sim::Time;
|
||||||
|
%this.ndTickUndo(%this.brickCount, %client);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Tick undo bricks
|
||||||
|
function SimSet::ndTickUndo(%this, %count, %client)
|
||||||
|
{
|
||||||
|
if(%count > %this.getCount())
|
||||||
|
%start = %this.getCount();
|
||||||
|
else
|
||||||
|
%start = %count;
|
||||||
|
|
||||||
|
if(%start > $Pref::Server::ND::ProcessPerTick)
|
||||||
|
%end = %start - $Pref::Server::ND::ProcessPerTick;
|
||||||
|
else
|
||||||
|
%end = 0;
|
||||||
|
|
||||||
|
for(%i = %start - 1; %i >= %end; %i--)
|
||||||
|
{
|
||||||
|
%brick = %this.getObject(%i);
|
||||||
|
%brick.killBrick();
|
||||||
|
|
||||||
|
if(%start > 1024)
|
||||||
|
%brick.delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
//If undo is taking long, tell the client how far we get
|
||||||
|
if(%client.ndLastMessageTime + 0.1 < $Sim::Time)
|
||||||
|
{
|
||||||
|
%client.ndLastMessageTime = $Sim::Time;
|
||||||
|
|
||||||
|
%percent = mFloor(100 - (%end * 100 / %this.brickCount));
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Undo in progress...\n<font:Verdana:17>\c3" @ %percent @ "%\c6 finished.", 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%end <= 0)
|
||||||
|
{
|
||||||
|
%this.delete();
|
||||||
|
%client.ndUndoInProgress = false;
|
||||||
|
|
||||||
|
if(%start != 0)
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Undo finished.", 2);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%this.schedule(30, ndTickUndo, %end, %client);
|
||||||
|
}
|
197
classes/server/undogroupwrench.cs
Normal file
197
classes/server/undogroupwrench.cs
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Delete this undo group
|
||||||
|
function ND_UndoGroupWrench::onRemove(%this)
|
||||||
|
{
|
||||||
|
if(%this.brickCount)
|
||||||
|
deleteVariables("$NU" @ %this.client @ "_" @ %this @ "_*");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Start undo wrench
|
||||||
|
function ND_UndoGroupWrench::ndStartUndo(%this, %client)
|
||||||
|
{
|
||||||
|
%client.ndUndoInProgress = true;
|
||||||
|
%client.ndLastMessageTime = $Sim::Time;
|
||||||
|
%this.ndTickUndo(0, %client);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Tick undo wrench
|
||||||
|
function ND_UndoGroupWrench::ndTickUndo(%this, %start, %client)
|
||||||
|
{
|
||||||
|
%end = %start + $Pref::Server::ND::ProcessPerTick;
|
||||||
|
|
||||||
|
if(%end > %this.brickCount)
|
||||||
|
%end = %this.brickCount;
|
||||||
|
|
||||||
|
setCurrentQuotaObject(getQuotaObjectFromClient(%client));
|
||||||
|
|
||||||
|
%fillWrenchName = %this.fillWrenchName;
|
||||||
|
%fillWrenchLight = %this.fillWrenchLight;
|
||||||
|
%fillWrenchEmitter = %this.fillWrenchEmitter;
|
||||||
|
%fillWrenchEmitterDir = %this.fillWrenchEmitterDir;
|
||||||
|
%fillWrenchItem = %this.fillWrenchItem;
|
||||||
|
%fillWrenchItemPos = %this.fillWrenchItemPos;
|
||||||
|
%fillWrenchItemDir = %this.fillWrenchItemDir;
|
||||||
|
%fillWrenchItemTime = %this.fillWrenchItemTime;
|
||||||
|
%fillWrenchRaycasting = %this.fillWrenchRaycasting;
|
||||||
|
%fillWrenchCollision = %this.fillWrenchCollision;
|
||||||
|
%fillWrenchRendering = %this.fillWrenchRendering;
|
||||||
|
|
||||||
|
for(%i = %start; %i < %end; %i++)
|
||||||
|
{
|
||||||
|
%brick = $NU[%client, %this, "B", %i];
|
||||||
|
|
||||||
|
if(!isObject(%brick))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//Revert wrench settings
|
||||||
|
if(%fillWrenchName)
|
||||||
|
{
|
||||||
|
%curr = getSubStr(%brick.getName(), 1, 254);
|
||||||
|
%fillWrenchNameValue = $NU[%client, %this, "N", %i];
|
||||||
|
|
||||||
|
if(%curr !$= %fillWrenchNameValue)
|
||||||
|
%brick.setNTObjectName(%fillWrenchNameValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fillWrenchLight)
|
||||||
|
{
|
||||||
|
if(%tmp = %brick.light | 0)
|
||||||
|
%curr = %tmp.getDatablock();
|
||||||
|
else
|
||||||
|
%curr = 0;
|
||||||
|
|
||||||
|
%fillWrenchLightValue = $NU[%client, %this, "LDB", %i];
|
||||||
|
|
||||||
|
if(%curr != %fillWrenchLightValue)
|
||||||
|
%brick.setLight(%fillWrenchLightValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fillWrenchEmitter)
|
||||||
|
{
|
||||||
|
if(%tmp = %brick.emitter | 0)
|
||||||
|
%curr = %tmp.getEmitterDatablock();
|
||||||
|
else if(%tmp = %brick.oldEmitterDB | 0)
|
||||||
|
%curr = %tmp;
|
||||||
|
else
|
||||||
|
%curr = 0;
|
||||||
|
|
||||||
|
%fillWrenchEmitterValue = $NU[%client, %this, "EDB", %i];
|
||||||
|
|
||||||
|
if(%curr != %fillWrenchEmitterValue)
|
||||||
|
%brick.setEmitter(%fillWrenchEmitterValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fillWrenchEmitterDir)
|
||||||
|
{
|
||||||
|
%curr = %brick.emitterDirection;
|
||||||
|
%fillWrenchEmitterDirValue = $NU[%client, %this, "EDIR", %i];
|
||||||
|
|
||||||
|
if(%curr != %fillWrenchEmitterDirValue)
|
||||||
|
%brick.setEmitterDirection(%fillWrenchEmitterDirValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fillWrenchItem)
|
||||||
|
{
|
||||||
|
if(%tmp = %brick.item | 0)
|
||||||
|
%curr = %tmp.getDatablock();
|
||||||
|
else
|
||||||
|
%curr = 0;
|
||||||
|
|
||||||
|
%fillWrenchItemValue = $NU[%client, %this, "IDB", %i];
|
||||||
|
|
||||||
|
if(%curr != %fillWrenchItemValue)
|
||||||
|
%brick.setItem(%fillWrenchItemValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fillWrenchItemPos)
|
||||||
|
{
|
||||||
|
%curr = %brick.itemPosition;
|
||||||
|
%fillWrenchItemPosValue = $NU[%client, %this, "IPOS", %i];
|
||||||
|
|
||||||
|
if(%curr != %fillWrenchItemPosValue)
|
||||||
|
%brick.setItemPosition(%fillWrenchItemPosValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fillWrenchItemDir)
|
||||||
|
{
|
||||||
|
%curr = %brick.itemPosition;
|
||||||
|
%fillWrenchItemDirValue = $NU[%client, %this, "IDIR", %i];
|
||||||
|
|
||||||
|
if(%curr != %fillWrenchItemDirValue)
|
||||||
|
%brick.setItemDirection(%fillWrenchItemDirValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fillWrenchItemTime)
|
||||||
|
{
|
||||||
|
%curr = %brick.itemRespawnTime;
|
||||||
|
%fillWrenchItemTimeValue = $NU[%client, %this, "IRT", %i];
|
||||||
|
|
||||||
|
if(%curr != %fillWrenchItemTimeValue)
|
||||||
|
%brick.setItemRespawnTime(%fillWrenchItemTimeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fillWrenchRaycasting)
|
||||||
|
{
|
||||||
|
%curr = %brick.isRaycasting();
|
||||||
|
%fillWrenchRaycastingValue = $NU[%client, %this, "RC", %i];
|
||||||
|
|
||||||
|
if(%curr != %fillWrenchRaycastingValue)
|
||||||
|
%brick.setRaycasting(%fillWrenchRaycastingValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fillWrenchCollision)
|
||||||
|
{
|
||||||
|
%curr = %brick.isColliding();
|
||||||
|
%fillWrenchCollisionValue = $NU[%client, %this, "C", %i];
|
||||||
|
|
||||||
|
if(%curr != %fillWrenchCollisionValue)
|
||||||
|
%brick.setColliding(%fillWrenchCollisionValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fillWrenchRendering)
|
||||||
|
{
|
||||||
|
%curr = %brick.isRendering();
|
||||||
|
%fillWrenchRenderingValue = $NU[%client, %this, "R", %i];
|
||||||
|
|
||||||
|
if(%curr != %fillWrenchRenderingValue)
|
||||||
|
{
|
||||||
|
//Copy emitter ...?
|
||||||
|
if(!%fillWrenchRenderingValue && (%tmp = %brick.emitter | 0))
|
||||||
|
%emitter = %tmp.getEmitterDatablock();
|
||||||
|
else
|
||||||
|
%emitter = 0;
|
||||||
|
|
||||||
|
%brick.setRendering(%fillWrenchRenderingValue);
|
||||||
|
|
||||||
|
if(!%fillWrenchRenderingValue && %emitter)
|
||||||
|
%brick.setEmitter(%emitter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clearCurrentQuotaObject();
|
||||||
|
|
||||||
|
//If undo is taking long, tell the client how far we get
|
||||||
|
if(%client.ndLastMessageTime + 0.1 < $Sim::Time)
|
||||||
|
{
|
||||||
|
%client.ndLastMessageTime = $Sim::Time;
|
||||||
|
|
||||||
|
%percent = mFloor(%end * 100 / %this.brickCount);
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Undo in progress...\n<font:Verdana:17>\c3" @ %percent @ "%\c6 finished.", 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%end >= %this.brickcount)
|
||||||
|
{
|
||||||
|
%this.delete();
|
||||||
|
%client.ndUndoInProgress = false;
|
||||||
|
|
||||||
|
if(%start != 0)
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Undo finished.", 2);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%this.schedule(30, ndTickUndo, %end, %client);
|
||||||
|
}
|
4
description.txt
Normal file
4
description.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Title: New Duplicator
|
||||||
|
Author: Zeblote (1163)
|
||||||
|
New lag-free duplicator with intelligent selection modes
|
||||||
|
Redo's mod v1: better dupsave listing and search, fill and supercut logic wires, V20 support, possibly some other stuff I forgot about
|
BIN
resources/server/black.png
Normal file
BIN
resources/server/black.png
Normal file
Binary file not shown.
BIN
resources/server/blank.png
Normal file
BIN
resources/server/blank.png
Normal file
Binary file not shown.
BIN
resources/server/blue.png
Normal file
BIN
resources/server/blue.png
Normal file
Binary file not shown.
BIN
resources/server/brickBOTTOMEDGE.png
Normal file
BIN
resources/server/brickBOTTOMEDGE.png
Normal file
Binary file not shown.
BIN
resources/server/brickBOTTOMLOOP.png
Normal file
BIN
resources/server/brickBOTTOMLOOP.png
Normal file
Binary file not shown.
BIN
resources/server/brickSIDE.png
Normal file
BIN
resources/server/brickSIDE.png
Normal file
Binary file not shown.
BIN
resources/server/brickTOP.png
Normal file
BIN
resources/server/brickTOP.png
Normal file
Binary file not shown.
BIN
resources/server/duplicator_brick.dts
Normal file
BIN
resources/server/duplicator_brick.dts
Normal file
Binary file not shown.
BIN
resources/server/duplicator_selection.dts
Normal file
BIN
resources/server/duplicator_selection.dts
Normal file
Binary file not shown.
BIN
resources/server/icon.png
Normal file
BIN
resources/server/icon.png
Normal file
Binary file not shown.
BIN
resources/server/selectionbox_border.dts
Normal file
BIN
resources/server/selectionbox_border.dts
Normal file
Binary file not shown.
BIN
resources/server/selectionbox_inner.dts
Normal file
BIN
resources/server/selectionbox_inner.dts
Normal file
Binary file not shown.
BIN
resources/server/selectionbox_outer.dts
Normal file
BIN
resources/server/selectionbox_outer.dts
Normal file
Binary file not shown.
BIN
resources/server/transparent.png
Normal file
BIN
resources/server/transparent.png
Normal file
Binary file not shown.
BIN
resources/server/white.png
Normal file
BIN
resources/server/white.png
Normal file
Binary file not shown.
225
scripts/common/bytetable.cs
Normal file
225
scripts/common/bytetable.cs
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
// Converts integers to characters and back. Mainly used by save transfer.
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Binary compression (file version, 241 allowed characters)
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Creates byte lookup table
|
||||||
|
function ndCreateByte241Table()
|
||||||
|
{
|
||||||
|
$ND::Byte241Lookup = "";
|
||||||
|
|
||||||
|
//This will map uints 0-241 to chars 15-255, starting after \r
|
||||||
|
for(%i = 15; %i < 256; %i++)
|
||||||
|
{
|
||||||
|
%char = collapseEscape("\\x" @
|
||||||
|
getSubStr("0123456789abcdef", (%i & 0xf0) >> 4, 1) @
|
||||||
|
getSubStr("0123456789abcdef", %i & 0x0f, 1));
|
||||||
|
|
||||||
|
$ND::Byte241ToChar[%i - 15] = %char;
|
||||||
|
$ND::Byte241Lookup = $ND::Byte241Lookup @ %char;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ND::Byte241TableCreated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Packs uint in single byte
|
||||||
|
function ndPack241_1(%num)
|
||||||
|
{
|
||||||
|
return $ND::Byte241ToChar[%num];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Packs uint in two bytes
|
||||||
|
function ndPack241_2(%num)
|
||||||
|
{
|
||||||
|
return $ND::Byte241ToChar[(%num / 241) | 0] @ $ND::Byte241ToChar[%num % 241];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Packs uint in three bytes
|
||||||
|
function ndPack241_3(%num)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
$ND::Byte241ToChar[(((%num / 241) | 0) / 241) | 0] @
|
||||||
|
$ND::Byte241ToChar[((%num / 241) | 0) % 241] @
|
||||||
|
$ND::Byte241ToChar[%num % 241];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Packs uint in four bytes
|
||||||
|
function ndPack241_4(%num)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
$ND::Byte241ToChar[(((((%num / 241) | 0) / 241) | 0) / 241) | 0] @
|
||||||
|
$ND::Byte241ToChar[((((%num / 241) | 0) / 241) | 0) % 241] @
|
||||||
|
$ND::Byte241ToChar[((%num / 241) | 0) % 241] @
|
||||||
|
$ND::Byte241ToChar[%num % 241];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Unpacks uint from single byte
|
||||||
|
function ndUnpack241_1(%subStr)
|
||||||
|
{
|
||||||
|
return strStr($ND::Byte241Lookup, %subStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Unpacks uint from two bytes
|
||||||
|
function ndUnpack241_2(%subStr)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
strStr($ND::Byte241Lookup, getSubStr(%subStr, 0, 1)) * 241 +
|
||||||
|
strStr($ND::Byte241Lookup, getSubStr(%subStr, 1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Unpacks uint from three bytes
|
||||||
|
function ndUnpack241_3(%subStr)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
((strStr($ND::Byte241Lookup, getSubStr(%subStr, 0, 1)) * 58081) | 0) +
|
||||||
|
strStr($ND::Byte241Lookup, getSubStr(%subStr, 1, 1)) * 241 +
|
||||||
|
strStr($ND::Byte241Lookup, getSubStr(%subStr, 2, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Unpacks uint from four bytes
|
||||||
|
function ndUnpack241_4(%subStr)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
((strStr($ND::Byte241Lookup, getSubStr(%subStr, 0, 1)) * 13997521) | 0) +
|
||||||
|
((strStr($ND::Byte241Lookup, getSubStr(%subStr, 1, 1)) * 58081) | 0) +
|
||||||
|
strStr($ND::Byte241Lookup, getSubStr(%subStr, 2, 1)) * 241 +
|
||||||
|
strStr($ND::Byte241Lookup, getSubStr(%subStr, 3, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Binary compression (command version, 255 allowed characters)
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Creates byte lookup table
|
||||||
|
function ndCreateByte255Table()
|
||||||
|
{
|
||||||
|
$ND::Byte255Lookup = "";
|
||||||
|
|
||||||
|
//This will map uints 0-254 to chars 1-255, starting after \x00
|
||||||
|
for(%i = 1; %i < 256; %i++)
|
||||||
|
{
|
||||||
|
%char = collapseEscape("\\x" @
|
||||||
|
getSubStr("0123456789abcdef", (%i & 0xf0) >> 4, 1) @
|
||||||
|
getSubStr("0123456789abcdef", %i & 0x0f, 1));
|
||||||
|
|
||||||
|
$ND::Byte255ToChar[%i - 1] = %char;
|
||||||
|
$ND::Byte255Lookup = $ND::Byte255Lookup @ %char;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ND::Byte255TableCreated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Packs uint in single byte
|
||||||
|
function ndPack255_1(%num)
|
||||||
|
{
|
||||||
|
return $ND::Byte255ToChar[%num];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Packs uint in two bytes
|
||||||
|
function ndPack255_2(%num)
|
||||||
|
{
|
||||||
|
return $ND::Byte255ToChar[(%num / 255) | 0] @ $ND::Byte255ToChar[%num % 255];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Packs uint in three bytes
|
||||||
|
function ndPack255_3(%num)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
$ND::Byte255ToChar[(((%num / 255) | 0) / 255) | 0] @
|
||||||
|
$ND::Byte255ToChar[((%num / 255) | 0) % 255] @
|
||||||
|
$ND::Byte255ToChar[%num % 255];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Packs uint in four bytes
|
||||||
|
function ndPack255_4(%num)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
$ND::Byte255ToChar[(((((%num / 255) | 0) / 255) | 0) / 255) | 0] @
|
||||||
|
$ND::Byte255ToChar[((((%num / 255) | 0) / 255) | 0) % 255] @
|
||||||
|
$ND::Byte255ToChar[((%num / 255) | 0) % 255] @
|
||||||
|
$ND::Byte255ToChar[%num % 255];
|
||||||
|
}
|
||||||
|
|
||||||
|
//Unpacks uint from single byte
|
||||||
|
function ndUnpack255_1(%subStr)
|
||||||
|
{
|
||||||
|
return strStr($ND::Byte255Lookup, %subStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Unpacks uint from two bytes
|
||||||
|
function ndUnpack255_2(%subStr)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
strStr($ND::Byte255Lookup, getSubStr(%subStr, 0, 1)) * 255 +
|
||||||
|
strStr($ND::Byte255Lookup, getSubStr(%subStr, 1, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Unpacks uint from three bytes
|
||||||
|
function ndUnpack255_3(%subStr)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
((strStr($ND::Byte255Lookup, getSubStr(%subStr, 0, 1)) * 65025) | 0) +
|
||||||
|
strStr($ND::Byte255Lookup, getSubStr(%subStr, 1, 1)) * 255 +
|
||||||
|
strStr($ND::Byte255Lookup, getSubStr(%subStr, 2, 1)) | 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Unpacks uint from four bytes
|
||||||
|
function ndUnpack255_4(%subStr)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
((strStr($ND::Byte255Lookup, getSubStr(%subStr, 0, 1)) * 16581375) | 0) +
|
||||||
|
((strStr($ND::Byte255Lookup, getSubStr(%subStr, 1, 1)) * 65025) | 0) +
|
||||||
|
strStr($ND::Byte255Lookup, getSubStr(%subStr, 2, 1)) * 255 +
|
||||||
|
strStr($ND::Byte255Lookup, getSubStr(%subStr, 3, 1)) | 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Some tests for the packing functions
|
||||||
|
function ndTestPack255()
|
||||||
|
{
|
||||||
|
echo("Testing 1 byte");
|
||||||
|
echo(ndUnpack255_1(ndPack255_1(0)) == 0);
|
||||||
|
echo(ndUnpack255_1(ndPack255_1(123)) == 123);
|
||||||
|
echo(ndUnpack255_1(ndPack255_1(231)) == 231);
|
||||||
|
echo(ndUnpack255_1(ndPack255_1(254)) == 254);
|
||||||
|
|
||||||
|
echo("Testing 2 byte");
|
||||||
|
echo(ndUnpack255_2(ndPack255_2(0)) == 0);
|
||||||
|
echo(ndUnpack255_2(ndPack255_2(123)) == 123);
|
||||||
|
echo(ndUnpack255_2(ndPack255_2(231)) == 231);
|
||||||
|
echo(ndUnpack255_2(ndPack255_2(254)) == 254);
|
||||||
|
echo(ndUnpack255_2(ndPack255_2(12345)) == 12345);
|
||||||
|
echo(ndUnpack255_2(ndPack255_2(32145)) == 32145);
|
||||||
|
echo(ndUnpack255_2(ndPack255_2(65024)) == 65024);
|
||||||
|
|
||||||
|
echo("Testing 3 byte");
|
||||||
|
echo(ndUnpack255_3(ndPack255_3(0)) == 0);
|
||||||
|
echo(ndUnpack255_3(ndPack255_3(123)) == 123);
|
||||||
|
echo(ndUnpack255_3(ndPack255_3(231)) == 231);
|
||||||
|
echo(ndUnpack255_3(ndPack255_3(254)) == 254);
|
||||||
|
echo(ndUnpack255_3(ndPack255_3(12345)) == 12345);
|
||||||
|
echo(ndUnpack255_3(ndPack255_3(32145)) == 32145);
|
||||||
|
echo(ndUnpack255_3(ndPack255_3(65024)) == 65024);
|
||||||
|
echo(ndUnpack255_3(ndPack255_3(11234567)) == 11234567);
|
||||||
|
echo(ndUnpack255_3(ndPack255_3(14132451)) == 14132451);
|
||||||
|
echo(ndUnpack255_3(ndPack255_3(16581374)) == 16581374);
|
||||||
|
|
||||||
|
echo("Testing 4 byte");
|
||||||
|
echo(ndUnpack255_4(ndPack255_4(0)) == 0);
|
||||||
|
echo(ndUnpack255_4(ndPack255_4(123)) == 123);
|
||||||
|
echo(ndUnpack255_4(ndPack255_4(231)) == 231);
|
||||||
|
echo(ndUnpack255_4(ndPack255_4(254)) == 254);
|
||||||
|
echo(ndUnpack255_4(ndPack255_4(12345)) == 12345);
|
||||||
|
echo(ndUnpack255_4(ndPack255_4(32145)) == 32145);
|
||||||
|
echo(ndUnpack255_4(ndPack255_4(65024)) == 65024);
|
||||||
|
echo(ndUnpack255_4(ndPack255_4(11234567)) == 11234567);
|
||||||
|
echo(ndUnpack255_4(ndPack255_4(14132451)) == 14132451);
|
||||||
|
echo(ndUnpack255_4(ndPack255_4(16581374)) == 16581374);
|
||||||
|
echo(ndUnpack255_4(ndPack255_4(1234567890)) == 1234567890);
|
||||||
|
|
||||||
|
//Appearantly tork uses uint and normal int randomly in
|
||||||
|
//seperate places so we can't use the full uint range
|
||||||
|
echo(ndUnpack255_4(ndPack255_4(2147483647)) == 2147483647);
|
||||||
|
echo(ndUnpack255_4(ndPack255_4(2147483648)) != 2147483648);
|
||||||
|
}
|
1151
scripts/server/commands.cs
Normal file
1151
scripts/server/commands.cs
Normal file
File diff suppressed because it is too large
Load Diff
344
scripts/server/datablocks.cs
Normal file
344
scripts/server/datablocks.cs
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
// Creates datablocks for the handheld items and the selection box.
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Basic golden duplicator
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Duplicator Item
|
||||||
|
datablock ItemData(ND_Item)
|
||||||
|
{
|
||||||
|
cameraMaxDist = 0.1;
|
||||||
|
canDrop = 1;
|
||||||
|
category = "Tools";
|
||||||
|
className = "Weapon";
|
||||||
|
density = 0.2;
|
||||||
|
doColorShift = false;
|
||||||
|
colorShiftColor = "1 0.84 0 1";
|
||||||
|
elasticity = 0.2;
|
||||||
|
emap = 1;
|
||||||
|
friction = 0.6;
|
||||||
|
iconName = $ND::ResourcePath @ "server/icon";
|
||||||
|
image = "ND_Image";
|
||||||
|
shapeFile = $ND::ResourcePath @ "server/duplicator_brick.dts";
|
||||||
|
uiName = "Duplicator";
|
||||||
|
};
|
||||||
|
|
||||||
|
//Particles for explosion
|
||||||
|
datablock ParticleData(ND_HitParticle)
|
||||||
|
{
|
||||||
|
colors[0] = "1 0.84 0 0.9";
|
||||||
|
colors[1] = "1 0.84 0 0.7";
|
||||||
|
colors[2] = "1 0.84 0 0.5";
|
||||||
|
gravityCoefficient = 0.7;
|
||||||
|
lifetimeMS = 600;
|
||||||
|
lifetimeVarianceMS = 200;
|
||||||
|
sizes[0] = 0.6;
|
||||||
|
sizes[1] = 0.4;
|
||||||
|
sizes[2] = 0.3;
|
||||||
|
spinRandomMax = 90;
|
||||||
|
spinRandomMin = -90;
|
||||||
|
textureName = "base/client/ui/brickIcons/2x2";
|
||||||
|
times[1] = 0.8;
|
||||||
|
times[2] = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Emitter for explosion
|
||||||
|
datablock ParticleEmitterData(ND_HitEmitter)
|
||||||
|
{
|
||||||
|
lifetimeMS = 20;
|
||||||
|
ejectionPeriodMS = 1;
|
||||||
|
periodVarianceMS = 0;
|
||||||
|
ejectionVelocity = 3;
|
||||||
|
ejectionOffset = 0.2;
|
||||||
|
particles = ND_HitParticle;
|
||||||
|
thetaMin = 20;
|
||||||
|
thetaMax = 80;
|
||||||
|
velocityVariance = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Explosion
|
||||||
|
datablock ExplosionData(ND_HitExplosion)
|
||||||
|
{
|
||||||
|
camShakeDuration = 0.5;
|
||||||
|
camShakeFreq = "1 1 1";
|
||||||
|
emitter[0] = ND_HitEmitter;
|
||||||
|
faceViewer = 1;
|
||||||
|
lifetimeMS = 180;
|
||||||
|
lightEndRadius = 0;
|
||||||
|
lightStartColor = "0 0 0 0";
|
||||||
|
lightStartRadius = 0;
|
||||||
|
shakeCamera = 1;
|
||||||
|
soundProfile = "wandHitSound";
|
||||||
|
};
|
||||||
|
|
||||||
|
//Projectile to make explosion
|
||||||
|
datablock ProjectileData(ND_HitProjectile)
|
||||||
|
{
|
||||||
|
bounceElasticity = 0;
|
||||||
|
bounceFriction = 0;
|
||||||
|
explodeOnDeath = 1;
|
||||||
|
explosion = ND_HitExplosion;
|
||||||
|
fadeDelay = 2;
|
||||||
|
gravityMod = 0;
|
||||||
|
lifetime = 0;
|
||||||
|
range = 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Swing particles
|
||||||
|
datablock ParticleData(ND_WaitParticle)
|
||||||
|
{
|
||||||
|
colors[0] = "1 0.84 0 0.9";
|
||||||
|
colors[1] = "1 0.84 0 0.7";
|
||||||
|
colors[2] = "1 0.84 0 0.5";
|
||||||
|
gravityCoefficient = -0.4;
|
||||||
|
dragCoefficient = 2;
|
||||||
|
lifetimeMS = 400;
|
||||||
|
lifetimeVarianceMS = 200;
|
||||||
|
sizes[0] = 0.5;
|
||||||
|
sizes[1] = 0.8;
|
||||||
|
sizes[2] = 0;
|
||||||
|
spinRandomMax = 0;
|
||||||
|
spinRandomMin = 0;
|
||||||
|
textureName = "base/client/ui/brickIcons/1x1";
|
||||||
|
times[1] = 0.5;
|
||||||
|
times[2] = 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Swing emitter
|
||||||
|
datablock ParticleEmitterData(ND_WaitEmitter)
|
||||||
|
{
|
||||||
|
lifetimeMS = 5000;
|
||||||
|
ejectionPeriodMS = 10;
|
||||||
|
periodVarianceMS = 0;
|
||||||
|
ejectionVelocity = 1;
|
||||||
|
ejectionOffset = 0.01;
|
||||||
|
particles = ND_WaitParticle;
|
||||||
|
thetaMin = 20;
|
||||||
|
thetaMax = 80;
|
||||||
|
velocityVariance = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Spin particles
|
||||||
|
datablock ParticleData(ND_SpinParticle : ND_WaitParticle)
|
||||||
|
{
|
||||||
|
colors[0] = "1 0.65 0 0.9";
|
||||||
|
colors[1] = "1 0.65 0 0.7";
|
||||||
|
colors[2] = "1 0.65 0 0.5";
|
||||||
|
gravityCoefficient = 0;
|
||||||
|
sizes[0] = 0.3;
|
||||||
|
sizes[1] = 0.5;
|
||||||
|
sizes[2] = 0;
|
||||||
|
textureName = "base/client/ui/brickIcons/1x1";
|
||||||
|
};
|
||||||
|
|
||||||
|
//Spin emitter
|
||||||
|
datablock ParticleEmitterData(ND_SpinEmitter : ND_WaitEmitter)
|
||||||
|
{
|
||||||
|
particles = ND_SpinParticle;
|
||||||
|
ejectionPeriodMS = 15;
|
||||||
|
thetaMin = 40;
|
||||||
|
thetaMax = 140;
|
||||||
|
ejectionVelocity = 2;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Duplicator image
|
||||||
|
datablock ShapeBaseImageData(ND_Image)
|
||||||
|
{
|
||||||
|
shapeFile = $ND::ResourcePath @ "server/duplicator_brick.dts";
|
||||||
|
className = "WeaponImage";
|
||||||
|
emap = true;
|
||||||
|
mountPoint = 0;
|
||||||
|
offset = "0 0 0";
|
||||||
|
eyeOffset = "0.7 1.4 -0.9";
|
||||||
|
armReady = true;
|
||||||
|
showBricks = true;
|
||||||
|
doColorShift = true;
|
||||||
|
colorShiftColor = "1 0.84 0 1";
|
||||||
|
item = ND_Item;
|
||||||
|
projectile = ND_HitProjectile;
|
||||||
|
loaded = false;
|
||||||
|
|
||||||
|
//Image states
|
||||||
|
stateName[0] = "Activate";
|
||||||
|
stateSpinThread[0] = "Stop";
|
||||||
|
stateTimeoutValue[0] = 0;
|
||||||
|
stateAllowImageChange[0] = false;
|
||||||
|
stateTransitionOnTimeout[0] = "Idle";
|
||||||
|
|
||||||
|
stateName[1] = "Idle";
|
||||||
|
stateSpinThread[1] = "Stop";
|
||||||
|
stateAllowImageChange[1] = true;
|
||||||
|
stateTransitionOnNotLoaded[1] = "StartSpinning";
|
||||||
|
stateTransitionOnTriggerDown[1] = "PreFire";
|
||||||
|
|
||||||
|
stateName[2] = "PreFire";
|
||||||
|
stateScript[2] = "onPreFire";
|
||||||
|
stateTimeoutValue[2] = 0.01;
|
||||||
|
stateAllowImageChange[2] = false;
|
||||||
|
stateTransitionOnTimeout[2] = "Fire";
|
||||||
|
|
||||||
|
stateName[3] = "Fire";
|
||||||
|
stateFire[3] = true;
|
||||||
|
stateScript[3] = "onFire";
|
||||||
|
stateEmitter[3] = ND_WaitEmitter;
|
||||||
|
stateSequence[3] = "swing";
|
||||||
|
stateEmitterNode[3] = "muzzlePoint";
|
||||||
|
stateEmitterTime[3] = 0.01;
|
||||||
|
stateTimeoutValue[3] = 0.01;
|
||||||
|
stateWaitForTimeout[3] = true;
|
||||||
|
stateAllowImageChange[3] = false;
|
||||||
|
stateTransitionOnTimeout[3] = "CheckFire";
|
||||||
|
|
||||||
|
stateName[4] = "CheckFire";
|
||||||
|
stateSpinThread[4] = "Stop";
|
||||||
|
stateTransitionOnNotLoaded[4] = "StartSpinning_TDown";
|
||||||
|
stateTransitionOnTriggerUp[4] = "Idle";
|
||||||
|
|
||||||
|
//Spinning states (from idle)
|
||||||
|
stateName[5] = "StartSpinning";
|
||||||
|
stateSpinThread[5] = "SpinUp";
|
||||||
|
stateTimeoutValue[5] = 0.25;
|
||||||
|
stateTransitionOnTimeout[5] = "IdleSpinning";
|
||||||
|
|
||||||
|
stateName[6] = "IdleSpinning";
|
||||||
|
stateEmitter[6] = ND_SpinEmitter;
|
||||||
|
stateSpinThread[6] = "FullSpeed";
|
||||||
|
stateEmitterNode[6] = "muzzlePoint";
|
||||||
|
stateEmitterTime[6] = 0.35;
|
||||||
|
stateTimeoutValue[6] = 0.35;
|
||||||
|
stateTransitionOnLoaded[6] = "StopSpinning";
|
||||||
|
stateTransitionOnTimeout[6] = "IdleSpinning";
|
||||||
|
|
||||||
|
stateName[7] = "StopSpinning";
|
||||||
|
stateSpinThread[7] = "SpinDown";
|
||||||
|
stateTimeoutValue[7] = 0.25;
|
||||||
|
stateTransitionOnTimeout[7] = "Idle";
|
||||||
|
|
||||||
|
//Spinning states (from checkfire, trigger is still down)
|
||||||
|
stateName[8] = "StartSpinning_TDown";
|
||||||
|
stateSpinThread[8] = "SpinUp";
|
||||||
|
stateTimeoutValue[8] = 0.25;
|
||||||
|
stateTransitionOnTimeout[8] = "IdleSpinning_TDown";
|
||||||
|
|
||||||
|
stateName[9] = "IdleSpinning_TDown";
|
||||||
|
stateEmitter[9] = ND_SpinEmitter;
|
||||||
|
stateSpinThread[9] = "FullSpeed";
|
||||||
|
stateEmitterNode[9] = "muzzlePoint_TDown";
|
||||||
|
stateEmitterTime[9] = 0.4;
|
||||||
|
stateTimeoutValue[9] = 0.4;
|
||||||
|
stateTransitionOnLoaded[9] = "StopSpinning_TDown";
|
||||||
|
stateTransitionOnTimeout[9] = "IdleSpinning_TDown";
|
||||||
|
|
||||||
|
stateName[10] = "StopSpinning_TDown";
|
||||||
|
stateSpinThread[10] = "SpinDown";
|
||||||
|
stateTimeoutValue[10] = 0.25;
|
||||||
|
stateTransitionOnTimeout[10] = "CheckFire";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//Spinning selection box for box mode
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Duplicator image
|
||||||
|
datablock ShapeBaseImageData(ND_Image_Box : ND_Image)
|
||||||
|
{
|
||||||
|
shapeFile = $ND::ResourcePath @ "server/duplicator_selection.dts";
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//Blue duplicator for plant mode
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Particles for explosion
|
||||||
|
datablock ParticleData(ND_HitParticle_Blue : ND_HitParticle)
|
||||||
|
{
|
||||||
|
colors[0] = "0 0.25 1 0.9";
|
||||||
|
colors[1] = "0 0.25 1 0.7";
|
||||||
|
colors[2] = "0 0.25 1 0.5";
|
||||||
|
};
|
||||||
|
|
||||||
|
//Emitter for explosion
|
||||||
|
datablock ParticleEmitterData(ND_HitEmitter_Blue : ND_HitEmitter)
|
||||||
|
{
|
||||||
|
particles = ND_HitParticle_Blue;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Explosion
|
||||||
|
datablock ExplosionData(ND_HitExplosion_Blue : ND_HitExplosion)
|
||||||
|
{
|
||||||
|
emitter[0] = ND_HitEmitter_Blue;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Projectile to make explosion
|
||||||
|
datablock ProjectileData(ND_HitProjectile_Blue : ND_HitProjectile)
|
||||||
|
{
|
||||||
|
explosion = ND_HitExplosion_Blue;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Swing particles
|
||||||
|
datablock ParticleData(ND_WaitParticle_Blue : ND_WaitParticle)
|
||||||
|
{
|
||||||
|
colors[0] = "0 0.25 1 0.9";
|
||||||
|
colors[1] = "0 0.25 1 0.7";
|
||||||
|
colors[2] = "0 0.25 1 0.5";
|
||||||
|
};
|
||||||
|
|
||||||
|
//Swing emitter
|
||||||
|
datablock ParticleEmitterData(ND_WaitEmitter_Blue : ND_WaitEmitter)
|
||||||
|
{
|
||||||
|
particles = ND_WaitParticle_Blue;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Spin particles
|
||||||
|
datablock ParticleData(ND_SpinParticle_Blue : ND_SpinParticle)
|
||||||
|
{
|
||||||
|
colors[0] = "0 0.25 0.75 0.9";
|
||||||
|
colors[1] = "0 0.25 0.75 0.7";
|
||||||
|
colors[2] = "0 0.25 0.75 0.5";
|
||||||
|
};
|
||||||
|
|
||||||
|
//Spin emitter
|
||||||
|
datablock ParticleEmitterData(ND_SpinEmitter_Blue : ND_SpinEmitter)
|
||||||
|
{
|
||||||
|
particles = ND_SpinParticle_Blue;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Duplicator image
|
||||||
|
datablock ShapeBaseImageData(ND_Image_Blue : ND_Image)
|
||||||
|
{
|
||||||
|
colorShiftColor = "0 0.25 1 1";
|
||||||
|
projectile = ND_HitProjectile_Blue;
|
||||||
|
|
||||||
|
//Image states
|
||||||
|
stateEmitter[3] = ND_WaitEmitter_Blue;
|
||||||
|
stateEmitter[6] = ND_SpinEmitter_Blue;
|
||||||
|
stateEmitter[9] = ND_SpinEmitter_Blue;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//Resizable selection and highlight box
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Transparent box to visualize bricks intersecting selection box
|
||||||
|
datablock StaticShapeData(ND_SelectionBoxOuter)
|
||||||
|
{
|
||||||
|
shapeFile = $ND::ResourcePath @ "server/selectionbox_outer.dts";
|
||||||
|
};
|
||||||
|
|
||||||
|
//Inside box (inverted normals) to visualize backfaces
|
||||||
|
datablock StaticShapeData(ND_SelectionBoxInner)
|
||||||
|
{
|
||||||
|
shapeFile = $ND::ResourcePath @ "server/selectionbox_inner.dts";
|
||||||
|
};
|
||||||
|
|
||||||
|
//Small box to create solid edges
|
||||||
|
datablock StaticShapeData(ND_SelectionBoxBorder)
|
||||||
|
{
|
||||||
|
shapeFile = $ND::ResourcePath @ "server/selectionbox_border.dts";
|
||||||
|
};
|
||||||
|
|
||||||
|
//Empty shape to hold shapename
|
||||||
|
datablock StaticShapeData(ND_SelectionBoxShapeName)
|
||||||
|
{
|
||||||
|
shapeFile = "base/data/shapes/empty.dts";
|
||||||
|
};
|
734
scripts/server/functions.cs
Normal file
734
scripts/server/functions.cs
Normal file
@ -0,0 +1,734 @@
|
|||||||
|
// This file should not exist. Fix later...
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Math functions
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Rotate vector around +Z in 90 degree steps
|
||||||
|
function ndRotateVector(%vector, %steps)
|
||||||
|
{
|
||||||
|
switch(%steps % 4)
|
||||||
|
{
|
||||||
|
case 0: return %vector;
|
||||||
|
case 1: return getWord(%vector, 1) SPC -getWord(%vector, 0) SPC getWord(%vector, 2);
|
||||||
|
case 2: return -getWord(%vector, 0) SPC -getWord(%vector, 1) SPC getWord(%vector, 2);
|
||||||
|
case 3: return -getWord(%vector, 1) SPC getWord(%vector, 0) SPC getWord(%vector, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Rotate and mirror a direction
|
||||||
|
function ndTransformDirection(%dir, %steps, %mirrX, %mirrY, %mirrZ)
|
||||||
|
{
|
||||||
|
if(%dir > 1)
|
||||||
|
{
|
||||||
|
if(%mirrX && %dir % 2 == 1
|
||||||
|
|| %mirrY && %dir % 2 == 0)
|
||||||
|
%dir += 2;
|
||||||
|
|
||||||
|
%dir = (%dir + %steps - 2) % 4 + 2;
|
||||||
|
}
|
||||||
|
else if(%mirrZ)
|
||||||
|
%dir = !%dir;
|
||||||
|
|
||||||
|
return %dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the closest paint color to an rgb value
|
||||||
|
function ndGetClosestColorID(%rgb)
|
||||||
|
{
|
||||||
|
//Set initial value
|
||||||
|
%best = 0;
|
||||||
|
%bestDiff = 999999;
|
||||||
|
|
||||||
|
for(%i = 0; %i < 64; %i++)
|
||||||
|
{
|
||||||
|
%color = getColorI(getColorIdTable(%i));
|
||||||
|
|
||||||
|
%diff = vectorLen(vectorSub(%rgb, %color));
|
||||||
|
|
||||||
|
if(getWord(%color, 3) != 255)
|
||||||
|
%diff += 1000;
|
||||||
|
|
||||||
|
if(%diff < %bestDiff)
|
||||||
|
{
|
||||||
|
%best = %i;
|
||||||
|
%bestDiff = %diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return %best;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get the closest paint color to an rgba value
|
||||||
|
function ndGetClosestColorID2(%rgba)
|
||||||
|
{
|
||||||
|
%rgb = getWords(%rgba, 0, 2);
|
||||||
|
%a = getWord(%rgba, 3);
|
||||||
|
|
||||||
|
//Set initial value
|
||||||
|
%best = 0;
|
||||||
|
%bestDiff = 999999;
|
||||||
|
|
||||||
|
for(%i = 0; %i < 64; %i++)
|
||||||
|
{
|
||||||
|
%color = getColorI(getColorIdTable(%i));
|
||||||
|
%alpha = getWord(%color, 3);
|
||||||
|
|
||||||
|
%diff = vectorLen(vectorSub(%rgb, %color));
|
||||||
|
|
||||||
|
if((%alpha > 254) != (%a > 254))
|
||||||
|
%diff += 1000;
|
||||||
|
else
|
||||||
|
%diff += mAbs(%alpha - %a) * 0.5;
|
||||||
|
|
||||||
|
if(%diff < %bestDiff)
|
||||||
|
{
|
||||||
|
%best = %i;
|
||||||
|
%bestDiff = %diff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return %best;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Convert a paint color to a <color:xxxxxx> code
|
||||||
|
function ndGetPaintColorCode(%id)
|
||||||
|
{
|
||||||
|
%rgb = getColorI(getColorIdTable(%id));
|
||||||
|
%chars = "0123456789abcdef";
|
||||||
|
|
||||||
|
%r = getWord(%rgb, 0);
|
||||||
|
%g = getWord(%rgb, 1);
|
||||||
|
%b = getWord(%rgb, 2);
|
||||||
|
|
||||||
|
%r1 = getSubStr(%chars, (%r / 16) | 0, 1);
|
||||||
|
%r2 = getSubStr(%chars, %r % 16 , 1);
|
||||||
|
|
||||||
|
%g1 = getSubStr(%chars, (%g / 16) | 0, 1);
|
||||||
|
%g2 = getSubStr(%chars, %g % 16 , 1);
|
||||||
|
|
||||||
|
%b1 = getSubStr(%chars, (%b / 16) | 0, 1);
|
||||||
|
%b2 = getSubStr(%chars, %b % 16 , 1);
|
||||||
|
|
||||||
|
return "<color:" @ %r1 @ %r2 @ %g1 @ %g2 @ %b1 @ %b2 @ ">";
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get a plate world box from a raycast
|
||||||
|
function ndGetPlateBoxFromRayCast(%pos, %normal)
|
||||||
|
{
|
||||||
|
//Get half size of world box for offset
|
||||||
|
%halfSize = "0.25 0.25 0.1";
|
||||||
|
|
||||||
|
//Point offset in correct direction based on normal
|
||||||
|
%offX = getWord(%halfSize, 0) * mFloatLength(-getWord(%normal, 0), 0);
|
||||||
|
%offY = getWord(%halfSize, 1) * mFloatLength(-getWord(%normal, 1), 0);
|
||||||
|
%offZ = getWord(%halfSize, 2) * mFloatLength(-getWord(%normal, 2), 0);
|
||||||
|
%offset = %offX SPC %offY SPC %offZ;
|
||||||
|
|
||||||
|
//Get offset position
|
||||||
|
%newPos = vectorAdd(%pos, %offset);
|
||||||
|
|
||||||
|
//Get the plate box around the position
|
||||||
|
%x1 = mFloor(getWord(%newPos, 0) * 2) / 2;
|
||||||
|
%y1 = mFloor(getWord(%newPos, 1) * 2) / 2;
|
||||||
|
%z1 = mFloor(getWord(%newPos, 2) * 5) / 5;
|
||||||
|
|
||||||
|
%x2 = mCeil(getWord(%newPos, 0) * 2) / 2;
|
||||||
|
%y2 = mCeil(getWord(%newPos, 1) * 2) / 2;
|
||||||
|
%z2 = mCeil(getWord(%newPos, 2) * 5) / 5;
|
||||||
|
|
||||||
|
return %x1 SPC %y1 SPC %z1 SPC %x2 SPC %y2 SPC %z2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Trust checks
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Send a message if a client doesn't have select trust to a brick
|
||||||
|
function ndTrustCheckMessage(%obj, %client)
|
||||||
|
{
|
||||||
|
%group = %client.brickGroup.getId();
|
||||||
|
%bl_id = %client.bl_id;
|
||||||
|
%admin = %client.isAdmin;
|
||||||
|
|
||||||
|
if(ndTrustCheckSelect(%obj, %group, %bl_id, %admin))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(%obj.getGroup().bl_id == 888888 && !$Pref::Server::ND::SelectPublicBricks)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
messageClient(%client, 'MsgError', "");
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6You don't have enough trust to do that!", 5);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check whether a client has enough trust to select a brick
|
||||||
|
function ndTrustCheckSelect(%obj, %group2, %bl_id, %admin)
|
||||||
|
{
|
||||||
|
%group1 = %obj.getGroup();
|
||||||
|
|
||||||
|
//Client owns brick
|
||||||
|
if(%group1 == %group2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//Client owns stack
|
||||||
|
if(%obj.stackBL_ID == %bl_id)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//Client has trust to the brick
|
||||||
|
if(%group1.Trust[%bl_id] >= $Pref::Server::ND::TrustLimit)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//Client has trust to the stack of the brick
|
||||||
|
if(%group2.Trust[%obj.stackBL_ID] >= $Pref::Server::ND::TrustLimit)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//Client is admin
|
||||||
|
if(%admin && $Pref::Server::ND::AdminTrustBypass1)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//Client can duplicate public bricks
|
||||||
|
if(%group1.bl_id == 888888 && $Pref::Server::ND::SelectPublicBricks)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check whether a client has enough trust to modify a brick
|
||||||
|
function ndTrustCheckModify(%obj, %group2, %bl_id, %admin)
|
||||||
|
{
|
||||||
|
%group1 = %obj.getGroup();
|
||||||
|
|
||||||
|
//Client owns brick
|
||||||
|
if(%group1 == %group2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//Client owns stack
|
||||||
|
if(%obj.stackBL_ID == %bl_id)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//Client has trust to the brick
|
||||||
|
if(%group1.Trust[%bl_id] >= 2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//Client has trust to the stack of the brick
|
||||||
|
if(%group2.Trust[%obj.stackBL_ID] >= 2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
//Client is admin
|
||||||
|
if(%admin && $Pref::Server::ND::AdminTrustBypass2)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Fast check whether a client has enough trust to plant on a brick
|
||||||
|
function ndFastTrustCheck(%brick, %bl_id, %brickGroup)
|
||||||
|
{
|
||||||
|
%group = %brick.getGroup();
|
||||||
|
|
||||||
|
if(%group == %brickGroup)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(%group.Trust[%bl_id] > 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(%group.bl_id == 888888)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//General stuff
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Setup list of spawned clients
|
||||||
|
function ndUpdateSpawnedClientList()
|
||||||
|
{
|
||||||
|
$ND::NumSpawnedClients = 0;
|
||||||
|
|
||||||
|
for(%i = 0; %i < ClientGroup.getCount(); %i++)
|
||||||
|
{
|
||||||
|
%cl = ClientGroup.getObject(%i);
|
||||||
|
|
||||||
|
if(%cl.hasSpawnedOnce)
|
||||||
|
{
|
||||||
|
$ND::SpawnedClient[$ND::NumSpawnedClients] = %cl;
|
||||||
|
$ND::NumSpawnedClients++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Applies mirror effect to a single ghost brick
|
||||||
|
function FxDtsBrick::ndMirrorGhost(%brick, %client, %axis)
|
||||||
|
{
|
||||||
|
//Offset position
|
||||||
|
%bPos = %brick.position;
|
||||||
|
|
||||||
|
//Rotated local angle id
|
||||||
|
%bAngle = %brick.angleID;
|
||||||
|
|
||||||
|
//Apply mirror effects (ugh)
|
||||||
|
%datablock = %brick.getDatablock();
|
||||||
|
|
||||||
|
if(%axis == 0)
|
||||||
|
{
|
||||||
|
//Handle symmetries
|
||||||
|
switch($ND::Symmetry[%datablock])
|
||||||
|
{
|
||||||
|
//Asymmetric
|
||||||
|
case 0:
|
||||||
|
if(%db = $ND::SymmetryXDatablock[%datablock])
|
||||||
|
{
|
||||||
|
%datablock = %db;
|
||||||
|
%bAngle = (%bAngle + $ND::SymmetryXOffset[%datablock]) % 4;
|
||||||
|
|
||||||
|
//Pair is made on X, so apply mirror logic for X afterwards
|
||||||
|
if(%bAngle % 2 == 1)
|
||||||
|
%bAngle = (%bAngle + 2) % 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
messageClient(%client, '', "\c6Sorry, your ghost brick is asymmetric and cannot be mirrored.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Do nothing for fully symmetric
|
||||||
|
|
||||||
|
//X symmetric - rotate 180 degrees if brick is angled 90 or 270 degrees
|
||||||
|
case 2:
|
||||||
|
if(%bAngle % 2 == 1)
|
||||||
|
%bAngle = (%bAngle + 2) % 4;
|
||||||
|
|
||||||
|
//Y symmetric - rotate 180 degrees if brick is angled 0 or 180 degrees
|
||||||
|
case 3:
|
||||||
|
if(%bAngle % 2 == 0)
|
||||||
|
%bAngle = (%bAngle + 2) % 4;
|
||||||
|
|
||||||
|
//X+Y symmetric - rotate 90 degrees
|
||||||
|
case 4:
|
||||||
|
if(%bAngle % 2 == 0)
|
||||||
|
%bAngle = (%bAngle + 1) % 4;
|
||||||
|
else
|
||||||
|
%bAngle = (%bAngle + 3) % 4;
|
||||||
|
|
||||||
|
//X-Y symmetric - rotate -90 degrees
|
||||||
|
case 5:
|
||||||
|
if(%bAngle % 2 == 0)
|
||||||
|
%bAngle = (%bAngle + 3) % 4;
|
||||||
|
else
|
||||||
|
%bAngle = (%bAngle + 1) % 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(%axis == 1)
|
||||||
|
{
|
||||||
|
//Handle symmetries
|
||||||
|
switch($ND::Symmetry[%datablock])
|
||||||
|
{
|
||||||
|
//Asymmetric
|
||||||
|
case 0:
|
||||||
|
if(%db = $ND::SymmetryXDatablock[%datablock])
|
||||||
|
{
|
||||||
|
%datablock = %db;
|
||||||
|
%bAngle = (%bAngle + $ND::SymmetryXOffset[%datablock]) % 4;
|
||||||
|
|
||||||
|
//Pair is made on X, so apply mirror logic for X afterwards
|
||||||
|
if(%bAngle % 2 == 0)
|
||||||
|
%bAngle = (%bAngle + 2) % 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
messageClient(%client, '', "\c6Sorry, your ghost brick is asymmetric and cannot be mirrored.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Do nothing for fully symmetric
|
||||||
|
|
||||||
|
//X symmetric - rotate 180 degrees if brick is angled 90 or 270 degrees
|
||||||
|
case 2:
|
||||||
|
if(%bAngle % 2 == 0)
|
||||||
|
%bAngle = (%bAngle + 2) % 4;
|
||||||
|
|
||||||
|
//Y symmetric - rotate 180 degrees if brick is angled 0 or 180 degrees
|
||||||
|
case 3:
|
||||||
|
if(%bAngle % 2 == 1)
|
||||||
|
%bAngle = (%bAngle + 2) % 4;
|
||||||
|
|
||||||
|
//X+Y symmetric - rotate 90 degrees
|
||||||
|
case 4:
|
||||||
|
if(%bAngle % 2 == 1)
|
||||||
|
%bAngle = (%bAngle + 1) % 4;
|
||||||
|
else
|
||||||
|
%bAngle = (%bAngle + 3) % 4;
|
||||||
|
|
||||||
|
//X-Y symmetric - rotate -90 degrees
|
||||||
|
case 5:
|
||||||
|
if(%bAngle % 2 == 1)
|
||||||
|
%bAngle = (%bAngle + 3) % 4;
|
||||||
|
else
|
||||||
|
%bAngle = (%bAngle + 1) % 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Change datablock if asymmetric
|
||||||
|
if(!$ND::SymmetryZ[%datablock])
|
||||||
|
{
|
||||||
|
if(%db = $ND::SymmetryZDatablock[%datablock])
|
||||||
|
{
|
||||||
|
%datablock = %db;
|
||||||
|
%bAngle = (%bAngle + $ND::SymmetryZOffset[%datablock]) % 4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
messageClient(%client, '', "\c6Sorry, your ghost brick is not vertically symmetric and cannot be mirrored.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Apply datablock
|
||||||
|
if(%brick.getDatablock() != %datablock)
|
||||||
|
%brick.setDatablock(%datablock);
|
||||||
|
|
||||||
|
switch(%bAngle)
|
||||||
|
{
|
||||||
|
case 0: %bRot = "1 0 0 0";
|
||||||
|
case 1: %bRot = "0 0 1 1.5708";
|
||||||
|
case 2: %bRot = "0 0 1 3.14150";
|
||||||
|
case 3: %bRot = "0 0 -1 1.5708";
|
||||||
|
}
|
||||||
|
|
||||||
|
//Apply transform
|
||||||
|
%brick.setTransform(%bPos SPC %bRot);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Supercut helpers
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Creates simple brick lookup table
|
||||||
|
function ndCreateSimpleBrickTable()
|
||||||
|
{
|
||||||
|
deleteVariables("$ND::SimpleBrick*");
|
||||||
|
%max = getDatablockGroupSize();
|
||||||
|
|
||||||
|
%file = new FileObject();
|
||||||
|
%sorter = new GuiTextListCtrl();
|
||||||
|
|
||||||
|
for(%i = 0; %i < %max; %i++)
|
||||||
|
{
|
||||||
|
%db = getDatablock(%i);
|
||||||
|
|
||||||
|
if(%db.getClassName() $= "FxDtsBrickData")
|
||||||
|
{
|
||||||
|
//Skip unsuitable bricks
|
||||||
|
if((
|
||||||
|
%db.isWaterBrick
|
||||||
|
|| %db.hasPrint
|
||||||
|
|| %db.isSlyrBrick
|
||||||
|
|| %db.uiName $= ""
|
||||||
|
|| %db.ndDontUseForFill
|
||||||
|
|| %db.category $= "Special"
|
||||||
|
|| %db.isLogicGate
|
||||||
|
) && (
|
||||||
|
ndSubsetOfDatablock(%db)==$ND::SubsetDefault
|
||||||
|
)
|
||||||
|
){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
%db.ndSubset = ndSubsetOfDatablock(%db);
|
||||||
|
|
||||||
|
%file.openForRead(%db.brickFile);
|
||||||
|
%file.readLine();
|
||||||
|
|
||||||
|
//We only want simple bricks here
|
||||||
|
if(%file.readLine() $= "BRICK")
|
||||||
|
{
|
||||||
|
//Skip brick sizes that we already have
|
||||||
|
if(!$ND::SimpleBrickBlock[%db.brickSizeX, %db.brickSizeY, %db.BrickSizeZ, %db.ndSubset]){
|
||||||
|
%sorter.addRow(%db, %db.getVolume());
|
||||||
|
}
|
||||||
|
|
||||||
|
$ND::SimpleBrickBlock[%db.brickSizeX, %db.brickSizeY, %db.BrickSizeZ, %db.ndSubset] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
%file.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%file.delete();
|
||||||
|
|
||||||
|
//Sort the bricks by volume
|
||||||
|
%sorter.sortNumerical(0, 1);
|
||||||
|
|
||||||
|
//Copy sorted bricks to global variable array
|
||||||
|
$ND::SimpleBrickCount = %sorter.rowCount();
|
||||||
|
for(%i = 0; %i < $ND::SimpleBrickCount; %i++)
|
||||||
|
{
|
||||||
|
%db = %sorter.getRowId(%i);
|
||||||
|
%volume = %sorter.getRowText(%i);
|
||||||
|
|
||||||
|
$ND::SimpleBrick[%i] = %db;
|
||||||
|
$ND::SimpleBrickVolume[%i] = %volume;
|
||||||
|
|
||||||
|
$ND::SimpleBrickSubset[%i] = %db.ndSubset;
|
||||||
|
|
||||||
|
//Ensure X < Y in lookup table
|
||||||
|
if(%db.brickSizeX <= %db.brickSizeY)
|
||||||
|
{
|
||||||
|
$ND::SimpleBrickSizeX[%i] = %db.brickSizeX;
|
||||||
|
$ND::SimpleBrickSizeY[%i] = %db.brickSizeY;
|
||||||
|
$ND::SimpleBrickRotated[%i] = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$ND::SimpleBrickSizeX[%i] = %db.brickSizeY;
|
||||||
|
$ND::SimpleBrickSizeY[%i] = %db.brickSizeX;
|
||||||
|
$ND::SimpleBrickRotated[%i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ND::SimpleBrickSizeZ[%i] = %db.brickSizeZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
%sorter.delete();
|
||||||
|
$ND::SimpleBrickTableCreated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Find the largest (volume) brick that fits inside the area
|
||||||
|
function ndGetLargestBrickId(%x, %y, %z, %subset)
|
||||||
|
{
|
||||||
|
if(!$ND::SimpleBrickTableCreated)
|
||||||
|
ndCreateSimpleBrickTable();
|
||||||
|
|
||||||
|
%maxVolume = %x * %y * %z;
|
||||||
|
%start = $ND::SimpleBrickCount - 1;
|
||||||
|
|
||||||
|
if($ND::SimpleBrickVolume[%start] > %maxVolume)
|
||||||
|
{
|
||||||
|
//Use binary search to find the largest volume that
|
||||||
|
//is smaller or equal to the volume of the area
|
||||||
|
%bound1 = 0;
|
||||||
|
%bound2 = %start;
|
||||||
|
|
||||||
|
while(%bound1 < %bound2)
|
||||||
|
{
|
||||||
|
%i = mCeil((%bound1 + %bound2) / 2);
|
||||||
|
%volume = $ND::SimpleBrickVolume[%i];
|
||||||
|
|
||||||
|
if(%volume > %maxVolume)
|
||||||
|
{
|
||||||
|
%bound2 = %i - 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%volume <= %maxVolume)
|
||||||
|
{
|
||||||
|
%bound1 = %i + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%start = %bound2;
|
||||||
|
}
|
||||||
|
|
||||||
|
%bestIndex = -1;
|
||||||
|
|
||||||
|
//Go down the list until a brick fits on all 3 axis
|
||||||
|
for(%i = %start; %i >= 0; %i--)
|
||||||
|
{
|
||||||
|
if(
|
||||||
|
$ND::SimpleBrickSizeX[%i] <= %x
|
||||||
|
&& $ND::SimpleBrickSizeY[%i] <= %y
|
||||||
|
&& $ND::SimpleBrickSizeZ[%i] <= %z
|
||||||
|
&& $ND::SimpleBrickSubset[%i] == %subset
|
||||||
|
) {
|
||||||
|
return %i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Fill an area with bricks
|
||||||
|
function ndFillAreaWithBricks(%pos1, %pos2)
|
||||||
|
{
|
||||||
|
%pos1_x = getWord(%pos1, 0);
|
||||||
|
%pos1_y = getWord(%pos1, 1);
|
||||||
|
%pos1_z = getWord(%pos1, 2);
|
||||||
|
|
||||||
|
%pos2_x = getWord(%pos2, 0);
|
||||||
|
%pos2_y = getWord(%pos2, 1);
|
||||||
|
%pos2_z = getWord(%pos2, 2);
|
||||||
|
|
||||||
|
%size_x = %pos2_x - %pos1_x;
|
||||||
|
%size_y = %pos2_y - %pos1_y;
|
||||||
|
%size_z = %pos2_z - %pos1_z;
|
||||||
|
|
||||||
|
if(%size_x < 0.05 || %size_y < 0.05 || %size_z < 0.05)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(%size_x > %size_y)
|
||||||
|
{
|
||||||
|
%tmp = %size_y;
|
||||||
|
%size_y = %size_x;
|
||||||
|
%size_x = %tmp;
|
||||||
|
%rotated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
%brickId = ndGetLargestBrickId(%size_x * 2 + 0.05, %size_y * 2 + 0.05, %size_z * 5 + 0.02, $ND::FillBrickSubset);
|
||||||
|
|
||||||
|
if(!%rotated)
|
||||||
|
{
|
||||||
|
%pos3_x = %pos1_x + $ND::SimpleBrickSizeX[%brickId] / 2;
|
||||||
|
%pos3_y = %pos1_y + $ND::SimpleBrickSizeY[%brickId] / 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%pos3_x = %pos1_x + $ND::SimpleBrickSizeY[%brickId] / 2;
|
||||||
|
%pos3_y = %pos1_y + $ND::SimpleBrickSizeX[%brickId] / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
%pos3_z = %pos1_z + $ND::SimpleBrickSizeZ[%brickId] / 5;
|
||||||
|
%plantPos = (%pos1_x + %pos3_x) / 2 SPC (%pos1_y + %pos3_y) / 2 SPC (%pos1_z + %pos3_z) / 2;
|
||||||
|
|
||||||
|
if(!isObject($ND::SimpleBrick[%brickId]))
|
||||||
|
return;
|
||||||
|
|
||||||
|
%brick = new FxDTSBrick()
|
||||||
|
{
|
||||||
|
datablock = $ND::SimpleBrick[%brickId];
|
||||||
|
isPlanted = true;
|
||||||
|
client = $ND::FillBrickClient;
|
||||||
|
|
||||||
|
position = %plantPos;
|
||||||
|
rotation = (%rotated ^ $ND::SimpleBrickRotated[%brickId]) ? "0 0 1 90.0002" : "1 0 0 0";
|
||||||
|
angleID = %rotated;
|
||||||
|
|
||||||
|
colorID = $ND::FillBrickColorID;
|
||||||
|
colorFxID = $ND::FillBrickColorFxID;
|
||||||
|
shapeFxID = $ND::FillBrickShapeFxID;
|
||||||
|
|
||||||
|
printID = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
//This will call ::onLoadPlant instead of ::onPlant
|
||||||
|
%prev1 = $Server_LoadFileObj;
|
||||||
|
%prev2 = $LastLoadedBrick;
|
||||||
|
$Server_LoadFileObj = %brick;
|
||||||
|
$LastLoadedBrick = %brick;
|
||||||
|
|
||||||
|
//Add to brickgroup
|
||||||
|
$ND::FillBrickGroup.add(%brick);
|
||||||
|
|
||||||
|
//Attempt plant
|
||||||
|
%error = %brick.plant();
|
||||||
|
|
||||||
|
//Restore variable
|
||||||
|
$Server_LoadFileObj = %prev1;
|
||||||
|
$LastLoadedBrick = %prev2;
|
||||||
|
|
||||||
|
if(!%error || %error == 2)
|
||||||
|
{
|
||||||
|
//Set trusted
|
||||||
|
if(%brick.getNumDownBricks())
|
||||||
|
%brick.stackBL_ID = %brick.getDownBrick(0).stackBL_ID;
|
||||||
|
else if(%brick.getNumUpBricks())
|
||||||
|
%brick.stackBL_ID = %brick.getUpBrick(0).stackBL_ID;
|
||||||
|
else
|
||||||
|
%brick.stackBL_ID = $ND::FillBrickBL_ID;
|
||||||
|
|
||||||
|
%brick.trustCheckFinished();
|
||||||
|
|
||||||
|
%brick.setRendering($ND::FillBrickRendering);
|
||||||
|
%brick.setColliding($ND::FillBrickColliding);
|
||||||
|
%brick.setRayCasting($ND::FillBrickRayCasting);
|
||||||
|
|
||||||
|
//Instantly ghost the brick to all spawned clients (wow hacks)
|
||||||
|
for(%j = 0; %j < $ND::NumSpawnedClients; %j++)
|
||||||
|
{
|
||||||
|
%cl = $ND::SpawnedClient[%j];
|
||||||
|
%brick.scopeToClient(%cl);
|
||||||
|
%brick.clearScopeToClient(%cl);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ND::FillBrickCount++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
%brick.delete();
|
||||||
|
|
||||||
|
if((%pos3_x + 0.05) < %pos2_x)
|
||||||
|
ndFillAreaWithBricks(%pos3_x SPC %pos1_y SPC %pos1_z, %pos2_x SPC %pos2_y SPC %pos2_z);
|
||||||
|
|
||||||
|
if((%pos3_y + 0.05) < %pos2_y)
|
||||||
|
ndFillAreaWithBricks(%pos1_x SPC %pos3_y SPC %pos1_z, %pos3_x SPC %pos2_y SPC %pos2_z);
|
||||||
|
|
||||||
|
if((%pos3_z + 0.02) < %pos2_z)
|
||||||
|
ndFillAreaWithBricks(%pos1_x SPC %pos1_y SPC %pos3_z, %pos3_x SPC %pos3_y SPC %pos2_z);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Client finished supercut, now fill bricks
|
||||||
|
function GameConnection::doFillBricks(%this, %subset)
|
||||||
|
{
|
||||||
|
//Set variables for the fill brick function
|
||||||
|
$ND::FillBrickGroup = %this.brickGroup;
|
||||||
|
$ND::FillBrickClient = %this;
|
||||||
|
$ND::FillBrickBL_ID = %this.bl_id;
|
||||||
|
|
||||||
|
$ND::FillBrickColorID = %this.currentColor;
|
||||||
|
$ND::FillBrickColorFxID = 0;
|
||||||
|
$ND::FillBrickShapeFxID = 0;
|
||||||
|
|
||||||
|
$ND::FillBrickRendering = true;
|
||||||
|
$ND::FillBrickColliding = true;
|
||||||
|
$ND::FillBrickRayCasting = true;
|
||||||
|
|
||||||
|
$ND::FillBrickSubset = %subset;
|
||||||
|
|
||||||
|
%box = %this.ndSelectionBox.getWorldBox();
|
||||||
|
$ND::FillBrickCount = 0;
|
||||||
|
ndUpdateSpawnedClientList();
|
||||||
|
ndFillAreaWithBricks(getWords(%box, 0, 2), getWords(%box, 3, 5));
|
||||||
|
|
||||||
|
//%s = ($ND::FillBrickCount == 1 ? "" : "s");
|
||||||
|
//messageClient(%this, '', "\c6Filled in \c3" @ $ND::FillBrickCount @ "\c6 brick" @ %s);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ND::SubsetDefault = 0;
|
||||||
|
$ND::SubsetLogicWire = 1;
|
||||||
|
$ND::SubsetLogicBuffer = 2;
|
||||||
|
$ND::SubsetLogicBufferAl = 3;
|
||||||
|
$ND::SubsetLogicDff = 4;
|
||||||
|
$ND::SubsetLogicDffAl = 5;
|
||||||
|
$ND::SubsetLogicEnabler = 6;
|
||||||
|
$ND::SubsetLogicEnablerAl = 7;
|
||||||
|
|
||||||
|
// Which subset of fill bricks to use - normal or wire
|
||||||
|
function ndSubsetOfDatablock(%data){
|
||||||
|
if(%data.isLogic) {
|
||||||
|
if(%data.isLogicWire) {
|
||||||
|
return $ND::SubsetLogicWire;
|
||||||
|
} else if(strStr(%data.uiName, "Buffer") == 0) {
|
||||||
|
return (strStr(%data.uiName, "Active Low")==-1) ? $ND::SubsetLogicBuffer : $ND::SubsetLogicBufferAl;
|
||||||
|
} else if(strStr(%data.uiName, "D FlipFlop") == 0) {
|
||||||
|
return (strStr(%data.uiName, "Active Low")==-1) ? $ND::SubsetLogicDff : $ND::SubsetLogicDffAl;
|
||||||
|
}else if(strStr(%data.uiName, "Enabler") == 0) {
|
||||||
|
return (strStr(%data.uiName, "Active Low")==-1) ? $ND::SubsetLogicEnabler : $ND::SubsetLogicEnablerAl;
|
||||||
|
} else {
|
||||||
|
return $ND::SubsetDefault;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return $ND::SubsetDefault;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ndLookupSubsetName(%name) {
|
||||||
|
%subset = $ND::Subset[%name];
|
||||||
|
return (%subset !$= "") ? %subset : $ND::SubsetDefault;
|
||||||
|
}
|
71
scripts/server/handshake.cs
Normal file
71
scripts/server/handshake.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// Sends a handshake to new clients to obtain their duplicator version.
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
package NewDuplicator_Server
|
||||||
|
{
|
||||||
|
//Send handshake request to new client
|
||||||
|
function GameConnection::autoAdminCheck(%this)
|
||||||
|
{
|
||||||
|
%this.ndClient = false;
|
||||||
|
%this.ndVersion = "0.0.0";
|
||||||
|
|
||||||
|
commandToClient(%this, 'ndHandshake', $ND::Version);
|
||||||
|
return parent::autoAdminCheck(%this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Client responded, so he has new duplicator
|
||||||
|
function serverCmdNdHandshake(%this, %version)
|
||||||
|
{
|
||||||
|
cancel(%this.ndHandshakeTimeout);
|
||||||
|
|
||||||
|
%this.ndClient = true;
|
||||||
|
%this.ndVersion = %version;
|
||||||
|
|
||||||
|
//Inform client whether he has an outdated version
|
||||||
|
switch(ndCompareVersion($ND::Version, %version))
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
%m = "\c6Your version of the \c3New Duplicator\c6 is outdated! Some features might not work. ";
|
||||||
|
%m = %m @ "(Server Version: \c3" @ $ND::Version @ "\c6 | Your Version: \c0" @ %version @ "\c6)";
|
||||||
|
//messageClient(%this, '', %m);
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
//Hide this message on long-running dedicated servers
|
||||||
|
if($Sim::Time < 86400)
|
||||||
|
{
|
||||||
|
%m = "\c6Your version of the \c3New Duplicator\c6 is newer than the server's! Ask the host to update it! ";
|
||||||
|
%m = %m @ "(Server Version: \c0" @ $ND::Version @ "\c6 | Your Version: \c3" @ %version @ "\c6)";
|
||||||
|
//messageClient(%this, '', %m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Compares two version numbers (major.minor.patch)
|
||||||
|
function ndCompareVersion(%ver1, %ver2)
|
||||||
|
{
|
||||||
|
%ver1 = strReplace(%ver1, ".", " ");
|
||||||
|
%ver2 = strReplace(%ver2, ".", " ");
|
||||||
|
|
||||||
|
%count = getMax(getWordCount(%ver1), getWordCount(%ver2));
|
||||||
|
|
||||||
|
for(%i = 0; %i < %count; %i ++)
|
||||||
|
{
|
||||||
|
%v1 = getWord(%ver1, %i);
|
||||||
|
%v2 = getWord(%ver2, %i);
|
||||||
|
|
||||||
|
if(%v1 > %v2)
|
||||||
|
return 1;
|
||||||
|
else if(%v1 < %v2)
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send handshakes to all clients
|
||||||
|
function ndResendHandshakes()
|
||||||
|
{
|
||||||
|
for(%i = 0; %i < ClientGroup.getCount(); %i++)
|
||||||
|
commandToClient(ClientGroup.getObject(%i), 'ndHandshake', $ND::Version);
|
||||||
|
}
|
106
scripts/server/highlight.cs
Normal file
106
scripts/server/highlight.cs
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// Handles highlighting and de-highlighting large groups of bricks.
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Highlight group data $NDH::*
|
||||||
|
// $NDH::LastId : The id of the last created highlight group
|
||||||
|
// $NDH::Count : Total number of active highlight groups
|
||||||
|
//
|
||||||
|
// $NDHN[brick] : Number of groups a brick is in
|
||||||
|
// $NDHF[brick] : Original color fx of the brick
|
||||||
|
//
|
||||||
|
// $NDH[group] : Count of bricks in a group
|
||||||
|
// $NDH[group, i] : Brick in group at position i
|
||||||
|
|
||||||
|
//Reserve a highlight group id
|
||||||
|
function ndNewHighlightGroup()
|
||||||
|
{
|
||||||
|
//Increase group number
|
||||||
|
$NDH::LastId++;
|
||||||
|
$NDH::Count++;
|
||||||
|
|
||||||
|
//Set initial count
|
||||||
|
$NDH[$NDH::LastId] = 0;
|
||||||
|
|
||||||
|
//Assign free id
|
||||||
|
return $NDH::LastId;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Remove highlight group and clean up garbage variables
|
||||||
|
function ndRemoveHighlightGroup(%group)
|
||||||
|
{
|
||||||
|
//Don't delete groups that don't exist
|
||||||
|
if($NDH[%group] $= "")
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Lower group number
|
||||||
|
$NDH::Count--;
|
||||||
|
|
||||||
|
//Clear count to allow reuse of index
|
||||||
|
$NDH[%group] = "";
|
||||||
|
|
||||||
|
//Cancel schedules
|
||||||
|
cancel($NDHS[%group]);
|
||||||
|
|
||||||
|
//If this is the most recently created group, pretend it never existed
|
||||||
|
if($NDH::LastId == %group)
|
||||||
|
$NDH::LastId--;
|
||||||
|
|
||||||
|
//If this is the last highlight group, just delete ALL highlight variables
|
||||||
|
if($NDH::Count < 1)
|
||||||
|
deleteVariables("$NDH*");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add a brick to a highlight group
|
||||||
|
function ndHighlightBrick(%group, %brick)
|
||||||
|
{
|
||||||
|
//If brick is not highlighted, do that
|
||||||
|
if(!$NDHN[%brick])
|
||||||
|
{
|
||||||
|
$NDHF[%brick] = %brick.colorFxID;
|
||||||
|
%brick.setColorFx(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Increase group number of this brick
|
||||||
|
$NDHN[%brick]++;
|
||||||
|
|
||||||
|
//Add brick to highlight group
|
||||||
|
$NDH[%group, ($NDH[%group]++) - 1] = %brick;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Start de-highlighting bricks
|
||||||
|
function ndStartDeHighlight(%group)
|
||||||
|
{
|
||||||
|
//Don't do this if already de-highlighting
|
||||||
|
%t = getTimeRemaining($NDHS[%group]);
|
||||||
|
|
||||||
|
if(%t > 66 || %t == 0)
|
||||||
|
{
|
||||||
|
cancel($NDHS[%group]);
|
||||||
|
ndTickDeHighlight(%group, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Tick de-highlighting bricks
|
||||||
|
function ndTickDeHighlight(%group, %start)
|
||||||
|
{
|
||||||
|
%end = $NDH[%group];
|
||||||
|
|
||||||
|
if(%end - %start > $Pref::Server::ND::ProcessPerTick)
|
||||||
|
%end = %start + $Pref::Server::ND::ProcessPerTick;
|
||||||
|
else
|
||||||
|
%lastTick = true;
|
||||||
|
|
||||||
|
for(%i = %start; %i < %end; %i++)
|
||||||
|
{
|
||||||
|
%brick = $NDH[%group, %i];
|
||||||
|
|
||||||
|
//If the brick is in no more groups, de-highlight it
|
||||||
|
if(isObject(%brick) && !($NDHN[%brick]--))
|
||||||
|
%brick.setColorFx($NDHF[%brick]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!%lastTick)
|
||||||
|
$NDHS[%group] = schedule(30, 0, ndTickDeHighlight, %group, %end);
|
||||||
|
else
|
||||||
|
ndRemoveHighlightGroup(%group);
|
||||||
|
}
|
297
scripts/server/images.cs
Normal file
297
scripts/server/images.cs
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
// Handles interactions with the handheld duplicator item.
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Set which image a client should use
|
||||||
|
function GameConnection::ndSetImage(%this, %image)
|
||||||
|
{
|
||||||
|
%image = %image.getId();
|
||||||
|
|
||||||
|
if(%image != %this.ndImage)
|
||||||
|
{
|
||||||
|
%this.ndImage = %image;
|
||||||
|
|
||||||
|
if(%this.ndEquipped)
|
||||||
|
{
|
||||||
|
%this.ndIgnoreNextMount = true;
|
||||||
|
%this.player.schedule(0, updateArm, %image);
|
||||||
|
%this.player.schedule(0, mountImage, %image, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Mount the correct image when the item is equipped
|
||||||
|
function ND_Item::onUse(%this, %player, %slot)
|
||||||
|
{
|
||||||
|
%image = %player.client.ndImage;
|
||||||
|
|
||||||
|
if(!isObject(%image))
|
||||||
|
%image = ND_Image;
|
||||||
|
|
||||||
|
%player.updateArm(%image);
|
||||||
|
%player.mountImage(%image, 0);
|
||||||
|
%player.client.ndEquippedFromItem = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
package NewDuplicator_Server
|
||||||
|
{
|
||||||
|
//Start select mode when duplicator is equipped
|
||||||
|
function ND_Image::onMount(%this, %player, %slot)
|
||||||
|
{
|
||||||
|
parent::onMount(%this, %player, %slot);
|
||||||
|
%player.ndEquipped();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ND_Image_Blue::onMount(%this, %player, %slot)
|
||||||
|
{
|
||||||
|
parent::onMount(%this, %player, %slot);
|
||||||
|
%player.ndEquipped();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ND_Image_Box::onMount(%this, %player, %slot)
|
||||||
|
{
|
||||||
|
parent::onMount(%this, %player, %slot);
|
||||||
|
%player.ndEquipped();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cancel mode when duplicator is unequipped
|
||||||
|
function ND_Image::onUnMount(%this, %player, %slot)
|
||||||
|
{
|
||||||
|
parent::onUnMount(%this, %player, %slot);
|
||||||
|
%player.ndUnEquipped();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ND_Image_Blue::onUnMount(%this, %player, %slot)
|
||||||
|
{
|
||||||
|
parent::onUnMount(%this, %player, %slot);
|
||||||
|
%player.ndUnEquipped();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ND_Image_Box::onUnMount(%this, %player, %slot)
|
||||||
|
{
|
||||||
|
parent::onUnMount(%this, %player, %slot);
|
||||||
|
%player.ndUnEquipped();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Start the swinging animation
|
||||||
|
function ND_Image::onPreFire(%this, %player, %slot)
|
||||||
|
{
|
||||||
|
%player.playThread(2, shiftTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ND_Image_Blue::onPreFire(%this, %player, %slot)
|
||||||
|
{
|
||||||
|
%player.playThread(2, shiftTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
function ND_Image_Box::onPreFire(%this, %player, %slot)
|
||||||
|
{
|
||||||
|
%player.playThread(2, shiftTo);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Handle selecting things
|
||||||
|
function ND_Image::onFire(%this, %player, %slot)
|
||||||
|
{
|
||||||
|
%player.ndFired();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ND_Image_Blue::onFire(%this, %player, %slot)
|
||||||
|
{
|
||||||
|
%player.ndFired();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ND_Image_Box::onFire(%this, %player, %slot)
|
||||||
|
{
|
||||||
|
%player.ndFired();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Duplicator was equipped
|
||||||
|
function Player::ndEquipped(%this)
|
||||||
|
{
|
||||||
|
%client = %this.client;
|
||||||
|
|
||||||
|
if(%this.isHoleBot || %this.isSlayerBot || !isObject(%client))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(%client.ndIgnoreNextMount)
|
||||||
|
{
|
||||||
|
%client.ndIgnoreNextMount = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if($Pref::Server::ND::AdminOnly && !%client.isAdmin)
|
||||||
|
{
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Oops! The duplicator is admin only.", 5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%client.ndEquipped = true;
|
||||||
|
|
||||||
|
//Remove temp brick so it doesn't overlap the selection box
|
||||||
|
if(isObject(%this.tempBrick))
|
||||||
|
%this.tempBrick.delete();
|
||||||
|
|
||||||
|
//Should resume last used select mode
|
||||||
|
if(!%client.ndModeIndex)
|
||||||
|
%client.ndSetMode(%client.ndLastSelectMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Duplicator was unequipped
|
||||||
|
function Player::ndUnEquipped(%this)
|
||||||
|
{
|
||||||
|
%client = %this.client;
|
||||||
|
|
||||||
|
if(%this.isHoleBot || %this.isSlayerBot || !isObject(%client))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(%client.ndIgnoreNextMount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(%client.ndModeIndex && !%client.ndMode.allowUnMount)
|
||||||
|
%client.ndKillMode();
|
||||||
|
|
||||||
|
%client.ndEquipped = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Duplicator was fired
|
||||||
|
function Player::ndFired(%this)
|
||||||
|
{
|
||||||
|
%client = %this.client;
|
||||||
|
|
||||||
|
if(!isObject(%client) || !%client.ndModeIndex || !%client.ndMode.allowSelecting)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(isObject(%client.minigame) && !%client.minigame.enablebuilding)
|
||||||
|
{
|
||||||
|
commandToClient(%client, 'centerPrint', "<font:Verdana:20>\c6Oops! Building is disabled.", 5);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Support for Script_RaycastOffTools by Conan
|
||||||
|
if(%this.isRaycastTool)
|
||||||
|
%mask = $TypeMasks::FxBrickObjectType | $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType;
|
||||||
|
else
|
||||||
|
%mask = $TypeMasks::FxBrickAlwaysObjectType | $TypeMasks::TerrainObjectType | $TypeMasks::InteriorObjectType;
|
||||||
|
|
||||||
|
%start = %this.getEyePoint();
|
||||||
|
%dir = %this.getEyeVector();
|
||||||
|
|
||||||
|
//Octree::Raycast fails to detect close bricks (~1TU) with a long raycast, so we'll do 3.
|
||||||
|
//First a very short one of 1 TU to detect very close bricks, then a slightly longer one
|
||||||
|
//of 10 TU, and finally the long range one of 1000.
|
||||||
|
%len[0] = 1;
|
||||||
|
%len[1] = 10;
|
||||||
|
%len[2] = 1000;
|
||||||
|
|
||||||
|
for(%i = 0; %i < 3; %i++)
|
||||||
|
{
|
||||||
|
%end = vectorAdd(%start, vectorScale(%dir, %len[%i]));
|
||||||
|
%ray = containerRaycast(%start, %end, %mask, %this);
|
||||||
|
|
||||||
|
if(isObject(%obj = firstWord(%ray)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!isObject(%obj))
|
||||||
|
return;
|
||||||
|
|
||||||
|
%position = posFromRaycast(%ray);
|
||||||
|
%normal = normalFromRaycast(%ray);
|
||||||
|
|
||||||
|
//Can't directly spawn an explosion, must use a projectile
|
||||||
|
%data = %client.ndImage.projectile;
|
||||||
|
|
||||||
|
if(!isObject(%data))
|
||||||
|
%data = ND_HitProjectile;
|
||||||
|
|
||||||
|
%proj = new Projectile()
|
||||||
|
{
|
||||||
|
datablock = %data;
|
||||||
|
initialPosition = %position;
|
||||||
|
initialVelocity = %normal;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Pass on the selected object to the dupli mode
|
||||||
|
%client.ndMode.onSelectObject(%client, %obj, %position, %normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
package NewDuplicator_Server
|
||||||
|
{
|
||||||
|
//Automatically start the "ambient" animation on duplicator items
|
||||||
|
function ND_Item::onAdd(%this, %obj)
|
||||||
|
{
|
||||||
|
parent::onAdd(%this, %obj);
|
||||||
|
%obj.playThread(0, ambient);
|
||||||
|
|
||||||
|
//Fix colorshift bullshit
|
||||||
|
%obj.schedule(100, setNodeColor, "ALL", %this.colorShiftColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Prevent accidently unequipping the duplicator
|
||||||
|
function serverCmdUnUseTool(%client)
|
||||||
|
{
|
||||||
|
if(%client.ndLastEquipTime + 1.5 > $Sim::Time)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(%client.ndModeIndex == $NDM::StackSelect || %client.ndModeIndex == $NDM::BoxSelect)
|
||||||
|
{
|
||||||
|
%client.ndToolSchedule = %client.schedule(100, ndUnUseTool);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::serverCmdUnUseTool(%client);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Prevent creating ghost bricks in modes that allow un-mount
|
||||||
|
function BrickDeployProjectile::onCollision(%this, %obj, %col, %fade, %pos, %normal)
|
||||||
|
{
|
||||||
|
%client = %obj.client;
|
||||||
|
|
||||||
|
if(isObject(%client) && %client.ndModeIndex)
|
||||||
|
%client.ndMode.onSelectObject(%client, %col, %pos, %normal);
|
||||||
|
else
|
||||||
|
parent::onCollision(%this, %obj, %col, %fade, %pos, %normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Handle ghost brick movements from New Brick Tool
|
||||||
|
function placeNewGhostBrick(%client, %pos, %normal, %noOrient)
|
||||||
|
{
|
||||||
|
if(!isObject(%client) || !%client.ndModeIndex)
|
||||||
|
return parent::placeNewGhostBrick(%client, %pos, %normal, %noOrient);
|
||||||
|
|
||||||
|
if(%client.ndModeIndex == $NDM::PlantCopy)
|
||||||
|
{
|
||||||
|
if(!%noOrient)
|
||||||
|
{
|
||||||
|
%angleID = getAngleIDFromPlayer(%client.getControlObject()) - %client.ndSelection.angleIDReference;
|
||||||
|
%rotation = ((4 - %angleID) - %client.ndSelection.ghostAngleID) % 4;
|
||||||
|
|
||||||
|
if(%rotation != 0)
|
||||||
|
%client.ndSelection.rotateGhostBricks(%rotation, %client.ndPivot);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NDM_PlantCopy.moveBricksTo(%client, %pos, %normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
%client.ndMode.onSelectObject(%client, 0, %pos, %normal);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Fix for equipping paint can calling unUseTool
|
||||||
|
function GameConnection::ndUnUseTool(%this)
|
||||||
|
{
|
||||||
|
%player = %this.player;
|
||||||
|
|
||||||
|
if(%this.isTalking)
|
||||||
|
serverCmdStopTalking(%this);
|
||||||
|
|
||||||
|
if(!isObject(%player))
|
||||||
|
return;
|
||||||
|
|
||||||
|
%player.currTool = -1;
|
||||||
|
%this.currInv = -1;
|
||||||
|
%this.currInvSlot = -1;
|
||||||
|
|
||||||
|
%player.unmountImage(0);
|
||||||
|
%player.playThread(1, "root");
|
||||||
|
}
|
497
scripts/server/modes.cs
Normal file
497
scripts/server/modes.cs
Normal file
@ -0,0 +1,497 @@
|
|||||||
|
// Handles the duplicator state machine. Does not validate transitions!
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Base class for all duplicator modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
function NewDuplicatorMode::onStartMode(%this, %client, %lastMode){}
|
||||||
|
function NewDuplicatorMode::onChangeMode(%this, %client, %nextMode){}
|
||||||
|
function NewDuplicatorMode::onKillMode(%this, %client){}
|
||||||
|
|
||||||
|
function NewDuplicatorMode::onSelectObject(%this, %client, %obj, %pos, %normal){}
|
||||||
|
|
||||||
|
function NewDuplicatorMode::onLight(%this, %client){}
|
||||||
|
function NewDuplicatorMode::onNextSeat(%this, %client){}
|
||||||
|
function NewDuplicatorMode::onPrevSeat(%this, %client){}
|
||||||
|
function NewDuplicatorMode::onShiftBrick(%this, %client, %x, %y, %z){}
|
||||||
|
function NewDuplicatorMode::onSuperShiftBrick(%this, %client, %x, %y, %z){}
|
||||||
|
function NewDuplicatorMode::onRotateBrick(%this, %client, %direction){}
|
||||||
|
function NewDuplicatorMode::onPlantBrick(%this, %client){}
|
||||||
|
function NewDuplicatorMode::onCancelBrick(%this, %client){}
|
||||||
|
|
||||||
|
function NewDuplicatorMode::onCopy(%this, %client)
|
||||||
|
{
|
||||||
|
messageClient(%client, '', "\c6Copy can not be used in your current duplicator mode.");
|
||||||
|
}
|
||||||
|
|
||||||
|
function NewDuplicatorMode::onPaste(%this, %client)
|
||||||
|
{
|
||||||
|
messageClient(%client, '', "\c6Paste can not be used in your current duplicator mode.");
|
||||||
|
}
|
||||||
|
|
||||||
|
function NewDuplicatorMode::onCut(%this, %client)
|
||||||
|
{
|
||||||
|
messageClient(%client, '', "\c6Cut can not be used in your current duplicator mode.");
|
||||||
|
}
|
||||||
|
|
||||||
|
function NewDuplicatorMode::getBottomPrint(%this, %client){}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Registering duplicator modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Possible mode indices
|
||||||
|
$NDM::Disabled = 0;
|
||||||
|
$NDM::BoxSelect = 1;
|
||||||
|
$NDM::BoxSelectProgress = 2;
|
||||||
|
$NDM::CutProgress = 3;
|
||||||
|
$NDM::FillColor = 4;
|
||||||
|
$NDM::FillColorProgress = 5;
|
||||||
|
$NDM::StackSelect = 6;
|
||||||
|
$NDM::StackSelectProgress = 7;
|
||||||
|
$NDM::PlantCopy = 8;
|
||||||
|
$NDM::PlantCopyProgress = 9;
|
||||||
|
$NDM::WrenchProgress = 10;
|
||||||
|
$NDM::SaveProgress = 11;
|
||||||
|
$NDM::LoadProgress = 12;
|
||||||
|
$NDM::SuperCutProgress = 13;
|
||||||
|
|
||||||
|
//Create all the pseudo-classes to handle callbacks
|
||||||
|
function ndRegisterDuplicatorModes()
|
||||||
|
{
|
||||||
|
echo("ND: Registering duplicator modes");
|
||||||
|
|
||||||
|
//Disabled duplicator mode (does nothing)
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_Disabled)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::Disabled;
|
||||||
|
image = "ND_Image";
|
||||||
|
spin = false;
|
||||||
|
|
||||||
|
allowSelecting = false;
|
||||||
|
allowUnMount = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Box Select duplicator mode
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_BoxSelect)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::BoxSelect;
|
||||||
|
image = "ND_Image_Box";
|
||||||
|
spin = false;
|
||||||
|
|
||||||
|
allowSelecting = true;
|
||||||
|
allowUnMount = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Box Select Progress duplicator mode
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_BoxSelectProgress)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::BoxSelectProgress;
|
||||||
|
image = "ND_Image_Box";
|
||||||
|
spin = true;
|
||||||
|
|
||||||
|
allowSelecting = false;
|
||||||
|
allowUnMount = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Cut Progress duplicator mode
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_CutProgress)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::CutProgress;
|
||||||
|
image = "any";
|
||||||
|
spin = true;
|
||||||
|
|
||||||
|
allowSelecting = false;
|
||||||
|
allowUnMount = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Fill Color duplicator mode
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_FillColor)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::FillColor;
|
||||||
|
image = "any";
|
||||||
|
spin = false;
|
||||||
|
|
||||||
|
allowSelecting = false;
|
||||||
|
allowUnMount = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Fill Color Progress duplicator mode
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_FillColorProgress)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::FillColorProgress;
|
||||||
|
image = "any";
|
||||||
|
spin = true;
|
||||||
|
|
||||||
|
allowSelecting = false;
|
||||||
|
allowUnMount = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Plant Copy duplicator mode
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_PlantCopy)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::PlantCopy;
|
||||||
|
image = "ND_Image_Blue";
|
||||||
|
spin = false;
|
||||||
|
|
||||||
|
allowSelecting = true;
|
||||||
|
allowUnMount = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Plant Copy Progress duplicator mode
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_PlantCopyProgress)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::PlantCopyProgress;
|
||||||
|
image = "ND_Image_Blue";
|
||||||
|
spin = true;
|
||||||
|
|
||||||
|
allowSelecting = false;
|
||||||
|
allowUnMount = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Stack Select duplicator mode
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_StackSelect)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::StackSelect;
|
||||||
|
image = "ND_Image";
|
||||||
|
spin = false;
|
||||||
|
|
||||||
|
allowSelecting = true;
|
||||||
|
allowUnMount = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Stack Select Progress duplicator mode
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_StackSelectProgress)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::StackSelectProgress;
|
||||||
|
image = "ND_Image";
|
||||||
|
spin = true;
|
||||||
|
|
||||||
|
allowSelecting = false;
|
||||||
|
allowUnMount = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Wrench Progress duplicator mode
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_WrenchProgress)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::WrenchProgress;
|
||||||
|
image = "any";
|
||||||
|
spin = true;
|
||||||
|
|
||||||
|
allowSelecting = false;
|
||||||
|
allowUnMount = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Save Progress duplicator mode
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_SaveProgress)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::SaveProgress;
|
||||||
|
image = "any";
|
||||||
|
spin = true;
|
||||||
|
|
||||||
|
allowSelecting = false;
|
||||||
|
allowUnMount = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Load Progress duplicator mode
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_LoadProgress)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::LoadProgress;
|
||||||
|
image = "any";
|
||||||
|
spin = true;
|
||||||
|
|
||||||
|
allowSelecting = false;
|
||||||
|
allowUnMount = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//Supercut Progress duplicator mode
|
||||||
|
ND_ServerGroup.add(
|
||||||
|
new ScriptObject(NDM_SuperCutProgress)
|
||||||
|
{
|
||||||
|
class = "NewDuplicatorMode";
|
||||||
|
index = $NDM::SuperCutProgress;
|
||||||
|
image = "ND_Image_Box";
|
||||||
|
spin = true;
|
||||||
|
|
||||||
|
allowSelecting = false;
|
||||||
|
allowUnMount = false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
//If clients already exist, reset their modes
|
||||||
|
for(%i = 0; %i < ClientGroup.getCount(); %i++)
|
||||||
|
{
|
||||||
|
%cl = ClientGroup.getObject(%i);
|
||||||
|
|
||||||
|
%cl.ndPivot = true;
|
||||||
|
%cl.ndLimited = true;
|
||||||
|
%cl.ndDirection = true;
|
||||||
|
%cl.ndForcePlant = false;
|
||||||
|
|
||||||
|
%cl.ndImage = ND_Image.getId();
|
||||||
|
%cl.ndMode = NDM_Disabled;
|
||||||
|
%cl.ndModeIndex = $NDM::Disabled;
|
||||||
|
%cl.ndLastSelectMode = NDM_StackSelect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Switching modes
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Change duplication mode
|
||||||
|
function GameConnection::ndSetMode(%this, %newMode)
|
||||||
|
{
|
||||||
|
%oldMode = %this.ndMode;
|
||||||
|
|
||||||
|
if(%oldMode.index == %newMode.index)
|
||||||
|
return;
|
||||||
|
|
||||||
|
%this.ndMode = %newMode;
|
||||||
|
%this.ndModeIndex = %newMode.index;
|
||||||
|
|
||||||
|
%oldMode.onChangeMode(%this, %newMode.index);
|
||||||
|
%newMode.onStartMode(%this, %oldMode.index);
|
||||||
|
|
||||||
|
//Enable keybinds
|
||||||
|
if(!%oldMode.index)
|
||||||
|
{
|
||||||
|
commandToClient(%this, 'ndEnableKeybinds', true);
|
||||||
|
%client.ndMultiselect = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Change image
|
||||||
|
if(%newMode.image !$= "any")
|
||||||
|
%this.ndSetImage(nameToId(%newMode.image));
|
||||||
|
|
||||||
|
//Start or stop spinning
|
||||||
|
%this.player.setImageLoaded(0, !%newMode.spin);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Kill duplication mode
|
||||||
|
function GameConnection::ndKillMode(%this)
|
||||||
|
{
|
||||||
|
if(!%this.ndModeIndex)
|
||||||
|
return;
|
||||||
|
|
||||||
|
%this.ndMode.onKillMode(%this);
|
||||||
|
|
||||||
|
%this.ndMode = NDM_Disabled;
|
||||||
|
%this.ndModeIndex = $NDM::Disabled;
|
||||||
|
|
||||||
|
%this.ndUpdateBottomPrint();
|
||||||
|
|
||||||
|
//Disable keybinds
|
||||||
|
commandToClient(%this, 'ndEnableKeybinds', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Bottomprints
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
//Update the bottomprint
|
||||||
|
function GameConnection::ndUpdateBottomPrint(%this)
|
||||||
|
{
|
||||||
|
if(%this.ndModeIndex)
|
||||||
|
commandToClient(%this, 'bottomPrint', %this.ndMode.getBottomPrint(%this), 0, true);
|
||||||
|
else
|
||||||
|
commandToClient(%this, 'clearBottomPrint');
|
||||||
|
}
|
||||||
|
|
||||||
|
//Format bottomprint message with left and right justified text
|
||||||
|
function ndFormatMessage(%title, %l0, %r0, %l1, %r1, %l2, %r2)
|
||||||
|
{
|
||||||
|
%message = "<font:Arial:22>";
|
||||||
|
|
||||||
|
//Last used alignment, false = left | true = right
|
||||||
|
%align = false;
|
||||||
|
|
||||||
|
if(strStr("\c0\c1\c2\c3\c4\c5\c6\c7\c8\c9", getSubStr(%title, 0, 1)) < 0)
|
||||||
|
%message = %message @ "\c6";
|
||||||
|
|
||||||
|
%message = %message @ %title @ "\n<font:Verdana:16>";
|
||||||
|
|
||||||
|
for(%i = 0; strLen(%l[%i]) || strLen(%r[%i]); %i++)
|
||||||
|
{
|
||||||
|
if(strLen(%l[%i]))
|
||||||
|
{
|
||||||
|
if(%align)
|
||||||
|
%message = %message @ "<just:left>";
|
||||||
|
|
||||||
|
if(strStr("\c0\c1\c2\c3\c4\c5\c6\c7\c8\c9", getSubStr(%l[%i], 0, 1)) < 0)
|
||||||
|
%message = %message @ "\c6";
|
||||||
|
|
||||||
|
%message = %message @ %l[%i];
|
||||||
|
%align = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strLen(%r[%i]))
|
||||||
|
{
|
||||||
|
if(!%align)
|
||||||
|
%message = %message @ "<just:right>";
|
||||||
|
|
||||||
|
if(strStr("\c0\c1\c2\c3\c4\c5\c6\c7\c8\c9", getSubStr(%r[%i], 0, 1)) < 0)
|
||||||
|
%message = %message @ "\c6";
|
||||||
|
|
||||||
|
%message = %message @ %r[%i] @ " ";
|
||||||
|
%align = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
%message = %message @ "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return %message @ " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//Connecting, disconnecting, death
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
package NewDuplicator_Server
|
||||||
|
{
|
||||||
|
//Set initial variables on join
|
||||||
|
function GameConnection::onClientEnterGame(%this)
|
||||||
|
{
|
||||||
|
%this.ndPivot = true;
|
||||||
|
%this.ndLimited = true;
|
||||||
|
%this.ndDirection = true;
|
||||||
|
%this.ndForcePlant = false;
|
||||||
|
|
||||||
|
%this.ndImage = ND_Image.getId();
|
||||||
|
%this.ndMode = NDM_Disabled;
|
||||||
|
%this.ndModeIndex = $NDM::Disabled;
|
||||||
|
%this.ndLastSelectMode = NDM_StackSelect;
|
||||||
|
|
||||||
|
parent::onClientEnterGame(%this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Kill duplicator mode when a client leaves
|
||||||
|
function GameConnection::onClientLeaveGame(%this)
|
||||||
|
{
|
||||||
|
if(%this.ndModeIndex)
|
||||||
|
%this.ndKillMode(%this);
|
||||||
|
|
||||||
|
%this.ndEquipped = false;
|
||||||
|
|
||||||
|
//Remove from client lists of selections
|
||||||
|
for(%i = 0; %i < ND_ServerGroup.getCount(); %i++)
|
||||||
|
{
|
||||||
|
%obj = ND_ServerGroup.getObject(%i);
|
||||||
|
|
||||||
|
if(%obj.getName() $= "ND_Selection")
|
||||||
|
{
|
||||||
|
for(%j = 0; %j < %obj.numClients; %j++)
|
||||||
|
{
|
||||||
|
if($NS[%obj, "CL", %j] == %this.getId())
|
||||||
|
{
|
||||||
|
for(%k = %j; %k < (%obj.numClients - 1); %k++)
|
||||||
|
$NS[%obj, "CL", %k] = $NS[%obj, "CL", %k + 1];
|
||||||
|
|
||||||
|
%obj.numClients--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Delete undo groups
|
||||||
|
deleteVariables("$NU" @ %this @ "_*");
|
||||||
|
|
||||||
|
%stack = %this.undoStack;
|
||||||
|
%max = %stack.head;
|
||||||
|
|
||||||
|
if(%max < %stack.tail)
|
||||||
|
%max += %stack.size;
|
||||||
|
|
||||||
|
for(%i = %stack.tail; %i < %max; %i++)
|
||||||
|
{
|
||||||
|
%val = %stack.val[%i % %stack.size];
|
||||||
|
|
||||||
|
if(getFieldCount(%val) == 2)
|
||||||
|
{
|
||||||
|
%str = getField(%val, 1);
|
||||||
|
|
||||||
|
if(
|
||||||
|
%str $= "ND_PLANT"
|
||||||
|
|| %str $= "ND_PAINT"
|
||||||
|
|| %str $= "ND_WRENCH"
|
||||||
|
){
|
||||||
|
%group = getField(%val, 0);
|
||||||
|
|
||||||
|
if(isObject(%group))
|
||||||
|
{
|
||||||
|
%group.brickCount = 0;
|
||||||
|
%group.delete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::onClientLeaveGame(%this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Kill duplicator mode when a player dies
|
||||||
|
function GameConnection::onDeath(%this, %a, %b, %c, %d)
|
||||||
|
{
|
||||||
|
if(%this.ndModeIndex)
|
||||||
|
%this.ndKillMode(%this);
|
||||||
|
|
||||||
|
%this.ndEquipped = false;
|
||||||
|
|
||||||
|
parent::onDeath(%this, %a, %b, %c, %d);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Kill duplicator mode when a player is force respawned
|
||||||
|
function GameConnection::spawnPlayer(%this)
|
||||||
|
{
|
||||||
|
if(%this.ndModeIndex)
|
||||||
|
%this.ndKillMode(%this);
|
||||||
|
|
||||||
|
%this.ndEquipped = false;
|
||||||
|
|
||||||
|
parent::spawnPlayer(%this);
|
||||||
|
}
|
||||||
|
};
|
90
scripts/server/namedtargets.cs
Normal file
90
scripts/server/namedtargets.cs
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// Improved versions of setNTObjectName and clearNTObjectName with much
|
||||||
|
// higher performance. Required to fix lag when clearing named bricks.
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
function SimObject::setNTObjectName(%this, %name)
|
||||||
|
{
|
||||||
|
%this = %this.getId();
|
||||||
|
%name = getSafeVariableName(trim(%name));
|
||||||
|
|
||||||
|
if(%name $= "")
|
||||||
|
{
|
||||||
|
%this.clearNTObjectName();
|
||||||
|
%this.setName("");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Names must start with a _ to prevent overwriting real objects
|
||||||
|
if(getSubStr(%name, 0, 1) !$= "_")
|
||||||
|
%name = "_" @ %name;
|
||||||
|
|
||||||
|
if(%this.getName() $= %name)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(isObject(%name) && !(%name.getType() & $TypeMasks::FxBrickAlwaysObjectType))
|
||||||
|
{
|
||||||
|
error("ERROR: SimObject::setNTObjectName() - Non-Brick object named \"" @ %name @ "\" already exists!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%this.clearNTObjectName();
|
||||||
|
|
||||||
|
%group = %this.getGroup();
|
||||||
|
%count = %group.NTObjectCount[%name] | 0;
|
||||||
|
|
||||||
|
if(!%count)
|
||||||
|
%group.addNTName(%name);
|
||||||
|
|
||||||
|
//Add a reverse lookup to remove the name much faster
|
||||||
|
%group.NTObject[%name, %count] = %this;
|
||||||
|
%group.NTObjectIndex[%name, %this] = %count;
|
||||||
|
%group.NTObjectCount[%name] = %count + 1;
|
||||||
|
|
||||||
|
%this.setName(%name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function SimObject::clearNTObjectName(%this)
|
||||||
|
{
|
||||||
|
%this = %this.getId();
|
||||||
|
%group = %this.getGroup();
|
||||||
|
|
||||||
|
if(!isObject(%group))
|
||||||
|
return;
|
||||||
|
|
||||||
|
%oldName = %this.getName();
|
||||||
|
|
||||||
|
if(%oldName $= "")
|
||||||
|
return;
|
||||||
|
|
||||||
|
%index = %group.NTObjectIndex[%oldName, %this];
|
||||||
|
%count = %group.NTObjectCount[%oldName];
|
||||||
|
|
||||||
|
if(%group.NTObject[%oldName, %index] == %this)
|
||||||
|
{
|
||||||
|
//Reverse lookup works, use fast version
|
||||||
|
%lastObj = %group.NTObject[%oldName, %count - 1];
|
||||||
|
%group.NTObject[%oldName, %index] = %lastObj;
|
||||||
|
%group.NTObject[%oldName, %count - 1] = "";
|
||||||
|
%group.NTObjectIndex[%oldName, %lastObj] = %index;
|
||||||
|
%group.NTObjectIndex[%oldName, %this] = "";
|
||||||
|
%group.NTObjectCount[%oldName]--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Reverse lookup failed, use old and slow version
|
||||||
|
for(%i = 0; %i < %count; %i++)
|
||||||
|
{
|
||||||
|
if(%group.NTObject[%oldName, %i] == %this)
|
||||||
|
{
|
||||||
|
%group.NTObject[%oldName, %i] = %group.NTObject[%oldName, %count - 1];
|
||||||
|
%group.NTObject[%oldName, %count - 1] = "";
|
||||||
|
%group.NTObjectCount[%oldName]--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!%group.NTObjectCount[%oldName])
|
||||||
|
%group.removeNTName(%oldName);
|
||||||
|
}
|
||||||
|
|
212
scripts/server/prefs.cs
Normal file
212
scripts/server/prefs.cs
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
// Detects common services like RTB and registers perferences to them.
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
function ndRegisterPrefs()
|
||||||
|
{
|
||||||
|
//Glass prefs also set this variable so we don't need to add them seperately
|
||||||
|
if($RTB::Hooks::ServerControl)
|
||||||
|
ndRegisterPrefsToRtb();
|
||||||
|
else
|
||||||
|
ndExtendDefaultPrefValues();
|
||||||
|
|
||||||
|
ndDeleteOutdatedPrefs();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ndRegisterPrefsToRtb()
|
||||||
|
{
|
||||||
|
echo("ND: Registering RTB prefs");
|
||||||
|
%trustDropDown = "list None 0 Build 1 Full 2 Self 3";
|
||||||
|
|
||||||
|
//Limits
|
||||||
|
RTB_registerPref("Admin Only", "New Duplicator | Limits", "$Pref::Server::ND::AdminOnly", "bool", "Tool_NewDuplicator", false, false, false, "");
|
||||||
|
RTB_registerPref("Fill Paint Admin Only", "New Duplicator | Limits", "$Pref::Server::ND::PaintAdminOnly", "bool", "Tool_NewDuplicator", false, false, false, "");
|
||||||
|
RTB_registerPref("Fill Paint Fx Admin Only", "New Duplicator | Limits", "$Pref::Server::ND::PaintFxAdminOnly", "bool", "Tool_NewDuplicator", true, false, false, "");
|
||||||
|
RTB_registerPref("Fill Wrench Admin Only", "New Duplicator | Limits", "$Pref::Server::ND::WrenchAdminOnly", "bool", "Tool_NewDuplicator", true, false, false, "");
|
||||||
|
RTB_registerPref("Floating Bricks Admin Only", "New Duplicator | Limits", "$Pref::Server::ND::FloatAdminOnly", "bool", "Tool_NewDuplicator", true, false, false, "");
|
||||||
|
RTB_registerPref("Save Admin Only", "New Duplicator | Limits", "$Pref::Server::ND::SaveAdminOnly", "bool", "Tool_NewDuplicator", true, false, false, "");
|
||||||
|
RTB_registerPref("Load Admin Only", "New Duplicator | Limits", "$Pref::Server::ND::LoadAdminOnly", "bool", "Tool_NewDuplicator", false, false, false, "");
|
||||||
|
RTB_registerPref("Fill Bricks Admin Only", "New Duplicator | Limits", "$Pref::Server::ND::FillBricksAdminOnly", "bool", "Tool_NewDuplicator", true, false, false, "");
|
||||||
|
|
||||||
|
//Settings
|
||||||
|
RTB_RegisterPref("Trust Limit", "New Duplicator | Settings", "$Pref::Server::ND::TrustLimit", %trustDropDown, "Tool_NewDuplicator", 2, false, false, "");
|
||||||
|
RTB_RegisterPref("Admin Trust Bypass (Select)", "New Duplicator | Settings", "$Pref::Server::ND::AdminTrustBypass1", "bool", "Tool_NewDuplicator", true, false, false, "");
|
||||||
|
RTB_RegisterPref("Admin Trust Bypass (Edit)", "New Duplicator | Settings", "$Pref::Server::ND::AdminTrustBypass2", "bool", "Tool_NewDuplicator", false, false, false, "");
|
||||||
|
RTB_RegisterPref("Select Public Bricks", "New Duplicator | Settings", "$Pref::Server::ND::SelectPublicBricks", "bool", "Tool_NewDuplicator", true, false, false, "");
|
||||||
|
|
||||||
|
RTB_registerPref("Max Bricks (Admin)", "New Duplicator | Settings", "$Pref::Server::ND::MaxBricksAdmin", "int 1000 1000000", "Tool_NewDuplicator", 1000000, false, false, "");
|
||||||
|
RTB_registerPref("Max Bricks (Player)", "New Duplicator | Settings", "$Pref::Server::ND::MaxBricksPlayer", "int 1000 1000000", "Tool_NewDuplicator", 50000, false, false, "");
|
||||||
|
RTB_registerPref("Max Box Size (Admin)", "New Duplicator | Settings", "$Pref::Server::ND::MaxBoxSizeAdmin", "int 1 50000", "Tool_NewDuplicator", 1024, false, false, "");
|
||||||
|
RTB_registerPref("Max Box Size (Player)", "New Duplicator | Settings", "$Pref::Server::ND::MaxBoxSizePlayer", "int 1 50000", "Tool_NewDuplicator", 64, false, false, "");
|
||||||
|
|
||||||
|
RTB_registerPref("Selecting Timeout (Player)", "New Duplicator | Settings", "$Pref::Server::ND::SelectTimeoutMS", "int 0 5000", "Tool_NewDuplicator", 400, false, false, "");
|
||||||
|
RTB_registerPref("Planting Timeout (Player)", "New Duplicator | Settings", "$Pref::Server::ND::PlantTimeoutMS", "int 0 5000", "Tool_NewDuplicator", 400, false, false, "");
|
||||||
|
|
||||||
|
//Advanced
|
||||||
|
RTB_registerPref("Enable Menu Sounds", "New Duplicator | Advanced", "$Pref::Server::ND::PlayMenuSounds", "bool", "Tool_NewDuplicator", true, false, false, "");
|
||||||
|
RTB_registerPref("Max Ghost Bricks", "New Duplicator | Advanced", "$Pref::Server::ND::MaxGhostBricks", "int 1 50000", "Tool_NewDuplicator", 1500, false, false, "");
|
||||||
|
RTB_registerPref("Instant Ghost Bricks", "New Duplicator | Advanced", "$Pref::Server::ND::InstantGhostBricks", "int 1 50000", "Tool_NewDuplicator", 150, false, false, "");
|
||||||
|
RTB_registerPref("Scatter Ghost Bricks", "New Duplicator | Advanced", "$Pref::Server::ND::ScatterGhostBricks", "bool", "Tool_NewDuplicator", true, false, false, "");
|
||||||
|
RTB_registerPref("Process Bricks per Tick", "New Duplicator | Advanced", "$Pref::Server::ND::ProcessPerTick", "int 1 50000", "Tool_NewDuplicator", 300, false, false, "");
|
||||||
|
RTB_registerPref("Box Selection Chunk Size", "New Duplicator | Advanced", "$Pref::Server::ND::BoxSelectChunkDim", "int 1 50000", "Tool_NewDuplicator", 6, false, false, "");
|
||||||
|
RTB_registerPref("Create Sym Table on Start", "New Duplicator | Advanced", "$Pref::Server::ND::SymTableOnStart", "bool", "Tool_NewDuplicator", false, false, false, "");
|
||||||
|
|
||||||
|
//Restore default prefs
|
||||||
|
RTB_registerPref("Check to restore defaults", "New Duplicator | Reset Prefs", "$ND::RestoreDefaultPrefs", "bool", "Tool_NewDuplicator", false, false, false, "ndRestoreDefaultPrefs");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Callback function for "Reset Prefs"
|
||||||
|
function ndRestoreDefaultPrefs()
|
||||||
|
{
|
||||||
|
if($ND::RestoreDefaultPrefs)
|
||||||
|
ndApplyDefaultPrefValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ndExtendDefaultPrefValues()
|
||||||
|
{
|
||||||
|
echo("ND: Extending default pref values");
|
||||||
|
|
||||||
|
//Limits
|
||||||
|
if($Pref::Server::ND::AdminOnly $= "") $Pref::Server::ND::AdminOnly = false;
|
||||||
|
if($Pref::Server::ND::PaintAdminOnly $= "") $Pref::Server::ND::PaintAdminOnly = false;
|
||||||
|
if($Pref::Server::ND::PaintFxAdminOnly $= "") $Pref::Server::ND::PaintFxAdminOnly = true;
|
||||||
|
if($Pref::Server::ND::WrenchAdminOnly $= "") $Pref::Server::ND::WrenchAdminOnly = true;
|
||||||
|
if($Pref::Server::ND::FloatAdminOnly $= "") $Pref::Server::ND::FloatAdminOnly = true;
|
||||||
|
if($Pref::Server::ND::SaveAdminOnly $= "") $Pref::Server::ND::SaveAdminOnly = true;
|
||||||
|
if($Pref::Server::ND::LoadAdminOnly $= "") $Pref::Server::ND::LoadAdminOnly = false;
|
||||||
|
if($Pref::Server::ND::FillBricksAdminOnly $= "") $Pref::Server::ND::FillBricksAdminOnly = true;
|
||||||
|
|
||||||
|
//Settings
|
||||||
|
if($Pref::Server::ND::TrustLimit $= "") $Pref::Server::ND::TrustLimit = 2;
|
||||||
|
if($Pref::Server::ND::AdminTrustBypass1 $= "") $Pref::Server::ND::AdminTrustBypass1 = true;
|
||||||
|
if($Pref::Server::ND::AdminTrustBypass2 $= "") $Pref::Server::ND::AdminTrustBypass2 = false;
|
||||||
|
if($Pref::Server::ND::SelectPublicBricks $= "") $Pref::Server::ND::SelectPublicBricks = true;
|
||||||
|
|
||||||
|
if($Pref::Server::ND::MaxBricksAdmin $= "") $Pref::Server::ND::MaxBricksAdmin = 1000000;
|
||||||
|
if($Pref::Server::ND::MaxBricksPlayer $= "") $Pref::Server::ND::MaxBricksPlayer = 10000;
|
||||||
|
if($Pref::Server::ND::MaxBoxSizeAdmin $= "") $Pref::Server::ND::MaxBoxSizeAdmin = 1024;
|
||||||
|
if($Pref::Server::ND::MaxBoxSizePlayer $= "") $Pref::Server::ND::MaxBoxSizePlayer = 64;
|
||||||
|
|
||||||
|
if($Pref::Server::ND::SelectTimeoutMS $= "") $Pref::Server::ND::SelectTimeoutMS = 400;
|
||||||
|
if($Pref::Server::ND::PlantTimeoutMS $= "") $Pref::Server::ND::PlantTimeoutMS = 400;
|
||||||
|
|
||||||
|
//Advanced
|
||||||
|
if($Pref::Server::ND::PlayMenuSounds $= "") $Pref::Server::ND::PlayMenuSounds = true;
|
||||||
|
if($Pref::Server::ND::MaxGhostBricks $= "") $Pref::Server::ND::MaxGhostBricks = 1500;
|
||||||
|
if($Pref::Server::ND::InstantGhostBricks $= "") $Pref::Server::ND::InstantGhostBricks = 150;
|
||||||
|
if($Pref::Server::ND::ScatterGhostBricks $= "") $Pref::Server::ND::ScatterGhostBricks = true;
|
||||||
|
if($Pref::Server::ND::ProcessPerTick $= "") $Pref::Server::ND::ProcessPerTick = 300;
|
||||||
|
if($Pref::Server::ND::BoxSelectChunkDim $= "") $Pref::Server::ND::BoxSelectChunkDim = 6;
|
||||||
|
if($Pref::Server::ND::SymTableOnStart $= "") $Pref::Server::ND::SymTableOnStart = false;
|
||||||
|
|
||||||
|
//Always set this to false so we don't accidently reset the prefs
|
||||||
|
$ND::RestoreDefaultPrefs = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ndApplyDefaultPrefValues()
|
||||||
|
{
|
||||||
|
echo("ND: Applying default pref values");
|
||||||
|
messageAll('', "\c6(\c3New Duplicator\c6) \c6Prefs reset to default values.");
|
||||||
|
|
||||||
|
//Limits
|
||||||
|
$Pref::Server::ND::AdminOnly = false;
|
||||||
|
$Pref::Server::ND::PaintAdminOnly = false;
|
||||||
|
$Pref::Server::ND::PaintFxAdminOnly = true;
|
||||||
|
$Pref::Server::ND::WrenchAdminOnly = true;
|
||||||
|
$Pref::Server::ND::FloatAdminOnly = true;
|
||||||
|
$Pref::Server::ND::SaveAdminOnly = true;
|
||||||
|
$Pref::Server::ND::LoadAdminOnly = false;
|
||||||
|
$Pref::Server::ND::FillBricksAdminOnly = true;
|
||||||
|
|
||||||
|
//Settings
|
||||||
|
$Pref::Server::ND::TrustLimit = 2;
|
||||||
|
$Pref::Server::ND::AdminTrustBypass1 = true;
|
||||||
|
$Pref::Server::ND::AdminTrustBypass2 = false;
|
||||||
|
$Pref::Server::ND::SelectPublicBricks = true;
|
||||||
|
|
||||||
|
$Pref::Server::ND::MaxBricksAdmin = 1000000;
|
||||||
|
$Pref::Server::ND::MaxBricksPlayer = 10000;
|
||||||
|
$Pref::Server::ND::MaxBoxSizeAdmin = 1024;
|
||||||
|
$Pref::Server::ND::MaxBoxSizePlayer = 64;
|
||||||
|
|
||||||
|
$Pref::Server::ND::SelectTimeoutMS = 400;
|
||||||
|
$Pref::Server::ND::PlantTimeoutMS = 400;
|
||||||
|
|
||||||
|
//Advanced
|
||||||
|
$Pref::Server::ND::PlayMenuSounds = true;
|
||||||
|
$Pref::Server::ND::MaxGhostBricks = 1500;
|
||||||
|
$Pref::Server::ND::InstantGhostBricks = 150;
|
||||||
|
$Pref::Server::ND::ScatterGhostBricks = true;
|
||||||
|
$Pref::Server::ND::ProcessPerTick = 300;
|
||||||
|
$Pref::Server::ND::BoxSelectChunkDim = 6;
|
||||||
|
$Pref::Server::ND::SymTableOnStart = false;
|
||||||
|
|
||||||
|
//Always set this to false so we don't accidently reset the prefs
|
||||||
|
$ND::RestoreDefaultPrefs = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Erases outdated prefs from the config file
|
||||||
|
function ndDeleteOutdatedPrefs()
|
||||||
|
{
|
||||||
|
//Step 1: Copy all current prefs
|
||||||
|
//Limits
|
||||||
|
%adminOnly = $Pref::Server::ND::AdminOnly;
|
||||||
|
%paintAdminOnly = $Pref::Server::ND::PaintAdminOnly;
|
||||||
|
%paintFxAdminOnly = $Pref::Server::ND::PaintFxAdminOnly;
|
||||||
|
%wrenchAdminOnly = $Pref::Server::ND::WrenchAdminOnly;
|
||||||
|
%floatAdminOnly = $Pref::Server::ND::FloatAdminOnly;
|
||||||
|
%saveAdminOnly = $Pref::Server::ND::SaveAdminOnly;
|
||||||
|
%loadAdminOnly = $Pref::Server::ND::LoadAdminOnly;
|
||||||
|
%fillBricksAdminOnly = $Pref::Server::ND::FillBricksAdminOnly;
|
||||||
|
//Settings
|
||||||
|
%trustLimit = $Pref::Server::ND::TrustLimit;
|
||||||
|
%adminTrustBypass1 = $Pref::Server::ND::AdminTrustBypass1;
|
||||||
|
%adminTrustBypass2 = $Pref::Server::ND::AdminTrustBypass2;
|
||||||
|
%selectPublicBricks = $Pref::Server::ND::SelectPublicBricks;
|
||||||
|
%maxBricksAdmin = $Pref::Server::ND::MaxBricksAdmin;
|
||||||
|
%maxBricksPlayer = $Pref::Server::ND::MaxBricksPlayer;
|
||||||
|
%maxBoxSizeAdmin = $Pref::Server::ND::MaxBoxSizeAdmin;
|
||||||
|
%maxBoxSizePlayer = $Pref::Server::ND::MaxBoxSizePlayer;
|
||||||
|
%selectTimeoutMS = $Pref::Server::ND::SelectTimeoutMS;
|
||||||
|
%plantTimeoutMS = $Pref::Server::ND::PlantTimeoutMS;
|
||||||
|
//Advanced
|
||||||
|
%playMenuSounds = $Pref::Server::ND::PlayMenuSounds;
|
||||||
|
%maxGhostBricks = $Pref::Server::ND::MaxGhostBricks;
|
||||||
|
%instantGhostBricks = $Pref::Server::ND::InstantGhostBricks;
|
||||||
|
%scatterGhostBricks = $Pref::Server::ND::ScatterGhostBricks;
|
||||||
|
%processPerTick = $Pref::Server::ND::ProcessPerTick;
|
||||||
|
%boxSelectChunkDim = $Pref::Server::ND::BoxSelectChunkDim;
|
||||||
|
%symTableOnStart = $Pref::Server::ND::SymTableOnStart;
|
||||||
|
|
||||||
|
//Step 2: Delete everything
|
||||||
|
deleteVariables("$Pref::Server::ND::*");
|
||||||
|
|
||||||
|
//Step 3: Set current prefs again
|
||||||
|
//Limits
|
||||||
|
$Pref::Server::ND::AdminOnly = %adminOnly;
|
||||||
|
$Pref::Server::ND::PaintAdminOnly = %paintAdminOnly;
|
||||||
|
$Pref::Server::ND::PaintFxAdminOnly = %paintFxAdminOnly;
|
||||||
|
$Pref::Server::ND::WrenchAdminOnly = %wrenchAdminOnly;
|
||||||
|
$Pref::Server::ND::FloatAdminOnly = %floatAdminOnly;
|
||||||
|
$Pref::Server::ND::SaveAdminOnly = %saveAdminOnly;
|
||||||
|
$Pref::Server::ND::LoadAdminOnly = %loadAdminOnly;
|
||||||
|
$Pref::Server::ND::FillBricksAdminOnly = %fillBricksAdminOnl;
|
||||||
|
//Settings
|
||||||
|
$Pref::Server::ND::TrustLimit = %trustLimit;
|
||||||
|
$Pref::Server::ND::AdminTrustBypass1 = %adminTrustBypass1;
|
||||||
|
$Pref::Server::ND::AdminTrustBypass2 = %adminTrustBypass2;
|
||||||
|
$Pref::Server::ND::SelectPublicBricks = %selectPublicBricks;
|
||||||
|
$Pref::Server::ND::MaxBricksAdmin = %maxBricksAdmin;
|
||||||
|
$Pref::Server::ND::MaxBricksPlayer = %maxBricksPlayer;
|
||||||
|
$Pref::Server::ND::MaxBoxSizeAdmin = %maxBoxSizeAdmin;
|
||||||
|
$Pref::Server::ND::MaxBoxSizePlayer = %maxBoxSizePlayer;
|
||||||
|
$Pref::Server::ND::SelectTimeoutMS = %selectTimeoutMS;
|
||||||
|
$Pref::Server::ND::PlantTimeoutMS = %plantTimeoutMS;
|
||||||
|
//Advanced
|
||||||
|
$Pref::Server::ND::PlayMenuSounds = %playMenuSounds;
|
||||||
|
$Pref::Server::ND::MaxGhostBricks = %maxGhostBricks;
|
||||||
|
$Pref::Server::ND::InstantGhostBricks = %instantGhostBricks;
|
||||||
|
$Pref::Server::ND::ScatterGhostBricks = %scatterGhostBricks;
|
||||||
|
$Pref::Server::ND::ProcessPerTick = %processPerTick;
|
||||||
|
$Pref::Server::ND::BoxSelectChunkDim = %boxSelectChunkDim;
|
||||||
|
$Pref::Server::ND::SymTableOnStart = %symTableOnStart;
|
||||||
|
}
|
180
scripts/server/symmetrydefinitions.cs
Normal file
180
scripts/server/symmetrydefinitions.cs
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
// Manually sets up symmetry planes for certain bricks with bad geometry.
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Manual symmetry can be set using the following variables:
|
||||||
|
// $ND::ManualSymmetry[UIName] = {0 - 5}
|
||||||
|
// $ND::ManualSymmetryDB[UIName] = Other UIName
|
||||||
|
// $ND::ManualSymmetryOffset[UIName] = {0 - 3}
|
||||||
|
|
||||||
|
// $ND::ManualSymmetryZ[UIName] = {true, false}
|
||||||
|
// $ND::ManualSymmetryZDB[UIName] = Other UIName
|
||||||
|
// $ND::ManualSymmetryZOffset[UIName] = {0 - 3}
|
||||||
|
|
||||||
|
//Built-in Bricks
|
||||||
|
$ND::ManualSymmetryZ["1x1 Round"] = true;
|
||||||
|
$ND::ManualSymmetryZ["1x1F Round"] = true;
|
||||||
|
$ND::ManualSymmetryZ["Castle Wall"] = true;
|
||||||
|
$ND::ManualSymmetryZ["1x4x5 Window"] = true;
|
||||||
|
|
||||||
|
//Brick_V15
|
||||||
|
$ND::ManualSymmetry["1x4x2 Bars"] = 1;
|
||||||
|
$ND::ManualSymmetryZ["1x4x2 Bars"] = true;
|
||||||
|
|
||||||
|
//Brick_Treasure_Chest
|
||||||
|
$ND::ManualSymmetry["Treasure Chest"] = 2;
|
||||||
|
|
||||||
|
//Brick_Teledoor
|
||||||
|
$ND::ManualSymmetryZ["Teledoor"] = 1;
|
||||||
|
|
||||||
|
//Brick_Halloween
|
||||||
|
$ND::ManualSymmetry["Skull Cool Open"] = 2;
|
||||||
|
$ND::ManualSymmetry["Skull Cool"] = 2;
|
||||||
|
|
||||||
|
$ND::ManualSymmetry["Pumpkin"] = 3;
|
||||||
|
$ND::ManualSymmetry["Pumpkin_Face"] = 3;
|
||||||
|
$ND::ManualSymmetry["Pumpkin_Scared"] = 3;
|
||||||
|
$ND::ManualSymmetry["Pumpkin_Ascii"] = 3;
|
||||||
|
|
||||||
|
//Brick_PoleAdapters
|
||||||
|
$ND::ManualSymmetry["1x1x3 Pole"] = 1;
|
||||||
|
$ND::ManualSymmetry["1x1 Pole"] = 1;
|
||||||
|
$ND::ManualSymmetry["1x1F Pole"] = 1;
|
||||||
|
|
||||||
|
$ND::ManualSymmetry["1x1F Pole Plus"] = 2;
|
||||||
|
$ND::ManualSymmetry["1x1F Pole Corner"] = 5;
|
||||||
|
$ND::ManualSymmetry["1x1F Pole Corner up"] = 2;
|
||||||
|
$ND::ManualSymmetry["1x1F Pole Corner down"] = 2;
|
||||||
|
$ND::ManualSymmetry["1x1F Pole T"] = 5;
|
||||||
|
$ND::ManualSymmetry["1x1F Pole T up"] = 2;
|
||||||
|
$ND::ManualSymmetry["1x1F Pole T down"] = 2;
|
||||||
|
$ND::ManualSymmetry["1x1F Pole X Vert"] = 2;
|
||||||
|
$ND::ManualSymmetry["1x1F Pole X"] = 1;
|
||||||
|
|
||||||
|
$ND::ManualSymmetryZ["1x1F Pole Plus"] = true;
|
||||||
|
$ND::ManualSymmetryZ["1x1F Pole Corner"] = true;
|
||||||
|
$ND::ManualSymmetryZ["1x1F Pole Corner up"] = false;
|
||||||
|
$ND::ManualSymmetryZ["1x1F Pole Corner down"] = false;
|
||||||
|
$ND::ManualSymmetryZ["1x1F Pole T"] = true;
|
||||||
|
$ND::ManualSymmetryZ["1x1F Pole T up"] = false;
|
||||||
|
$ND::ManualSymmetryZ["1x1F Pole T down"] = false;
|
||||||
|
$ND::ManualSymmetryZ["1x1F Pole X Vert"] = true;
|
||||||
|
$ND::ManualSymmetryZ["1x1F Pole X"] = true;
|
||||||
|
|
||||||
|
$ND::ManualSymmetryZDB["1x1F Pole Corner up"] = "1x1F Pole Corner down";
|
||||||
|
$ND::ManualSymmetryZDB["1x1F Pole Corner down"] = "1x1F Pole Corner up";
|
||||||
|
$ND::ManualSymmetryZDB["1x1F Pole T up"] = "1x1F Pole T down";
|
||||||
|
$ND::ManualSymmetryZDB["1x1F Pole T down"] = "1x1F Pole T up";
|
||||||
|
|
||||||
|
$ND::ManualSymmetryZOffset["1x1F Pole Corner up"] = 0;
|
||||||
|
$ND::ManualSymmetryZOffset["1x1F Pole Corner down"] = 0;
|
||||||
|
$ND::ManualSymmetryZOffset["1x1F Pole T up"] = 0;
|
||||||
|
$ND::ManualSymmetryZOffset["1x1F Pole T down"] = 0;
|
||||||
|
|
||||||
|
//Brick_PoleDiagonals
|
||||||
|
$ND::ManualSymmetryZ["1x1f Horiz. Diag."] = true;
|
||||||
|
$ND::ManualSymmetryZ["2x2f Horiz. Diag."] = true;
|
||||||
|
$ND::ManualSymmetryZ["3x3f Horiz. Diag."] = true;
|
||||||
|
$ND::ManualSymmetryZ["4x4f Horiz. Diag."] = true;
|
||||||
|
$ND::ManualSymmetryZ["5x5f Horiz. Diag."] = true;
|
||||||
|
$ND::ManualSymmetryZ["6x6f Horiz. Diag."] = true;
|
||||||
|
|
||||||
|
$ND::ManualSymmetry["1x1 Vert. Diag. A"] = 2;
|
||||||
|
$ND::ManualSymmetry["2x2 Vert. Diag. A"] = 2;
|
||||||
|
$ND::ManualSymmetry["3x3 Vert. Diag. A"] = 2;
|
||||||
|
$ND::ManualSymmetry["4x4 Vert. Diag. A"] = 2;
|
||||||
|
$ND::ManualSymmetry["5x5 Vert. Diag. A"] = 2;
|
||||||
|
$ND::ManualSymmetry["6x6 Vert. Diag. A"] = 2;
|
||||||
|
$ND::ManualSymmetry["1x1 Vert. Diag. B"] = 2;
|
||||||
|
$ND::ManualSymmetry["2x2 Vert. Diag. B"] = 2;
|
||||||
|
$ND::ManualSymmetry["3x3 Vert. Diag. B"] = 2;
|
||||||
|
$ND::ManualSymmetry["4x4 Vert. Diag. B"] = 2;
|
||||||
|
$ND::ManualSymmetry["5x5 Vert. Diag. B"] = 2;
|
||||||
|
$ND::ManualSymmetry["6x6 Vert. Diag. B"] = 2;
|
||||||
|
|
||||||
|
$ND::ManualSymmetryZ["1x1 Vert. Diag. A"] = false;
|
||||||
|
$ND::ManualSymmetryZ["2x2 Vert. Diag. A"] = false;
|
||||||
|
$ND::ManualSymmetryZ["3x3 Vert. Diag. A"] = false;
|
||||||
|
$ND::ManualSymmetryZ["4x4 Vert. Diag. A"] = false;
|
||||||
|
$ND::ManualSymmetryZ["5x5 Vert. Diag. A"] = false;
|
||||||
|
$ND::ManualSymmetryZ["6x6 Vert. Diag. A"] = false;
|
||||||
|
$ND::ManualSymmetryZ["1x1 Vert. Diag. B"] = false;
|
||||||
|
$ND::ManualSymmetryZ["2x2 Vert. Diag. B"] = false;
|
||||||
|
$ND::ManualSymmetryZ["3x3 Vert. Diag. B"] = false;
|
||||||
|
$ND::ManualSymmetryZ["4x4 Vert. Diag. B"] = false;
|
||||||
|
$ND::ManualSymmetryZ["5x5 Vert. Diag. B"] = false;
|
||||||
|
$ND::ManualSymmetryZ["6x6 Vert. Diag. B"] = false;
|
||||||
|
|
||||||
|
$ND::ManualSymmetryZDB["1x1 Vert. Diag. A"] = "1x1 Vert. Diag. B";
|
||||||
|
$ND::ManualSymmetryZDB["2x2 Vert. Diag. A"] = "2x2 Vert. Diag. B";
|
||||||
|
$ND::ManualSymmetryZDB["3x3 Vert. Diag. A"] = "3x3 Vert. Diag. B";
|
||||||
|
$ND::ManualSymmetryZDB["4x4 Vert. Diag. A"] = "4x4 Vert. Diag. B";
|
||||||
|
$ND::ManualSymmetryZDB["5x5 Vert. Diag. A"] = "5x5 Vert. Diag. B";
|
||||||
|
$ND::ManualSymmetryZDB["6x6 Vert. Diag. A"] = "6x6 Vert. Diag. B";
|
||||||
|
$ND::ManualSymmetryZDB["1x1 Vert. Diag. B"] = "1x1 Vert. Diag. A";
|
||||||
|
$ND::ManualSymmetryZDB["2x2 Vert. Diag. B"] = "2x2 Vert. Diag. A";
|
||||||
|
$ND::ManualSymmetryZDB["3x3 Vert. Diag. B"] = "3x3 Vert. Diag. A";
|
||||||
|
$ND::ManualSymmetryZDB["4x4 Vert. Diag. B"] = "4x4 Vert. Diag. A";
|
||||||
|
$ND::ManualSymmetryZDB["5x5 Vert. Diag. B"] = "5x5 Vert. Diag. A";
|
||||||
|
$ND::ManualSymmetryZDB["6x6 Vert. Diag. B"] = "6x6 Vert. Diag. A";
|
||||||
|
|
||||||
|
$ND::ManualSymmetryZOffset["1x1 Vert. Diag. A"] = 2;
|
||||||
|
$ND::ManualSymmetryZOffset["2x2 Vert. Diag. A"] = 2;
|
||||||
|
$ND::ManualSymmetryZOffset["3x3 Vert. Diag. A"] = 2;
|
||||||
|
$ND::ManualSymmetryZOffset["4x4 Vert. Diag. A"] = 2;
|
||||||
|
$ND::ManualSymmetryZOffset["5x5 Vert. Diag. A"] = 2;
|
||||||
|
$ND::ManualSymmetryZOffset["6x6 Vert. Diag. A"] = 2;
|
||||||
|
$ND::ManualSymmetryZOffset["1x1 Vert. Diag. B"] = 2;
|
||||||
|
$ND::ManualSymmetryZOffset["2x2 Vert. Diag. B"] = 2;
|
||||||
|
$ND::ManualSymmetryZOffset["3x3 Vert. Diag. B"] = 2;
|
||||||
|
$ND::ManualSymmetryZOffset["4x4 Vert. Diag. B"] = 2;
|
||||||
|
$ND::ManualSymmetryZOffset["5x5 Vert. Diag. B"] = 2;
|
||||||
|
$ND::ManualSymmetryZOffset["6x6 Vert. Diag. B"] = 2;
|
||||||
|
|
||||||
|
//Brick_GrillPlate
|
||||||
|
$ND::ManualSymmetry["Grill Corner"] = 4;
|
||||||
|
|
||||||
|
//Brick_Bevel
|
||||||
|
$ND::ManualSymmetry["1x1F Beveled"] = 1;
|
||||||
|
$ND::ManualSymmetry["1x1FF Beveled"] = 1;
|
||||||
|
$ND::ManualSymmetry["1x2F Beveled"] = 1;
|
||||||
|
$ND::ManualSymmetry["1x2FF Beveled"] = 1;
|
||||||
|
$ND::ManualSymmetry["1x1 Beveled"] = 1;
|
||||||
|
$ND::ManualSymmetry["1x1x2 Beveled"] = 1;
|
||||||
|
$ND::ManualSymmetry["1x2 Beveled"] = 1;
|
||||||
|
$ND::ManualSymmetry["2x2F Beveled"] = 1;
|
||||||
|
$ND::ManualSymmetry["2x4F Beveled"] = 1;
|
||||||
|
$ND::ManualSymmetry["2x4FF Beveled"] = 1;
|
||||||
|
|
||||||
|
$ND::ManualSymmetryZ["1x1F Beveled"] = true;
|
||||||
|
$ND::ManualSymmetryZ["1x1FF Beveled"] = true;
|
||||||
|
$ND::ManualSymmetryZ["1x2F Beveled"] = true;
|
||||||
|
$ND::ManualSymmetryZ["1x2FF Beveled"] = true;
|
||||||
|
$ND::ManualSymmetryZ["1x1 Beveled"] = true;
|
||||||
|
$ND::ManualSymmetryZ["1x1x2 Beveled"] = true;
|
||||||
|
$ND::ManualSymmetryZ["1x2 Beveled"] = true;
|
||||||
|
$ND::ManualSymmetryZ["2x2F Beveled"] = true;
|
||||||
|
$ND::ManualSymmetryZ["2x4F Beveled"] = true;
|
||||||
|
$ND::ManualSymmetryZ["2x4FF Beveled"] = true;
|
||||||
|
|
||||||
|
//Brick_1RandomPack
|
||||||
|
$ND::ManualSymmetry["2x2x2 Octo Elbow Horz"] = 4;
|
||||||
|
|
||||||
|
$ND::ManualSymmetryZ["1x1 Octo"] = true;
|
||||||
|
$ND::ManualSymmetryZ["1x1x2 Octo"] = true;
|
||||||
|
$ND::ManualSymmetryZ["2x2x2 Octo T Horz"] = true;
|
||||||
|
$ND::ManualSymmetryZ["2x2x2 Octo Elbow Horz"] = true;
|
||||||
|
|
||||||
|
$ND::ManualSymmetryZ["2x3x2 Octo Offset"] = false;
|
||||||
|
$ND::ManualSymmetryZDB["2x3x2 Octo Offset"] = "2x3x2 Octo Offset";
|
||||||
|
$ND::ManualSymmetryZOffset["2x3x2 Octo Offset"] = 2;
|
||||||
|
|
||||||
|
//Brick_Fence
|
||||||
|
$ND::ManualSymmetry["1x4 Fence"] = 3;
|
||||||
|
|
||||||
|
//Brick_SmallBricks
|
||||||
|
$ND::ManualSymmetry["0.25x0.25 Corner"] = 4;
|
||||||
|
$ND::ManualSymmetry["0.25x0.25F Corner"] = 4;
|
||||||
|
$ND::ManualSymmetry["0.5x0.5 Corner"] = 4;
|
||||||
|
$ND::ManualSymmetry["0.5x0.5F Corner"] = 4;
|
||||||
|
$ND::ManualSymmetry["0.75x0.75 Corner"] = 4;
|
||||||
|
$ND::ManualSymmetry["0.75x0.75F Corner"] = 4;
|
692
scripts/server/symmetrytable.cs
Normal file
692
scripts/server/symmetrytable.cs
Normal file
@ -0,0 +1,692 @@
|
|||||||
|
// Analyzes brick geometry to detect common symmetry planes.
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
//Begin generating the symmetry table
|
||||||
|
function ndCreateSymmetryTable()
|
||||||
|
{
|
||||||
|
if($ND::SymmetryTableCreating)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//Tell everyone what is happening
|
||||||
|
messageAll('', "\c6(\c3New Duplicator\c6) \c6Creating brick symmetry table...");
|
||||||
|
|
||||||
|
//Make sure we have the uiname table for manual symmetry
|
||||||
|
if(!$UINameTableCreated)
|
||||||
|
createUINameTable();
|
||||||
|
|
||||||
|
//Delete previous data
|
||||||
|
deleteVariables("$ND::Symmetry*");
|
||||||
|
|
||||||
|
$ND::SymmetryTableCreated = false;
|
||||||
|
$ND::SymmetryTableCreating = true;
|
||||||
|
$ND::SymmetryTableStarted = getRealTime();
|
||||||
|
|
||||||
|
$NDT::SimpleCount = 0;
|
||||||
|
$NDT::MeshCount = 0;
|
||||||
|
|
||||||
|
$NDT::AsymXCountTotal = 0;
|
||||||
|
$NDT::AsymZCountTotal = 0;
|
||||||
|
|
||||||
|
echo("ND: Start building brick symmetry table...");
|
||||||
|
echo("==========================================================================");
|
||||||
|
|
||||||
|
ndTickCreateSymmetryTable(0, getDatablockGroupSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
//Process symmetry for 6 datablocks each tick
|
||||||
|
function ndTickCreateSymmetryTable(%lastIndex, %max)
|
||||||
|
{
|
||||||
|
%processed = 0;
|
||||||
|
%limit = $Server::Dedicated ? 400 : 200;
|
||||||
|
|
||||||
|
for(%i = %lastIndex; %i < %max; %i++)
|
||||||
|
{
|
||||||
|
%db = getDatablock(%i);
|
||||||
|
|
||||||
|
if(%db.getClassName() $= "FxDtsBrickData")
|
||||||
|
{
|
||||||
|
%processed += ndTestBrickSymmetry(%db);
|
||||||
|
|
||||||
|
if(%processed > %limit)
|
||||||
|
{
|
||||||
|
schedule(30, 0, ndTickCreateSymmetryTable, %i + 1, %max);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
%simple = $NDT::SimpleCount;
|
||||||
|
%mesh = $NDT::MeshCount;
|
||||||
|
|
||||||
|
%asymx = $NDT::AsymXCountTotal;
|
||||||
|
%asymz = $NDT::AsymZCountTotal;
|
||||||
|
|
||||||
|
echo("==========================================================================");
|
||||||
|
echo("ND: Finished basic symmetry tests: " @ %simple @ " simple, " @ %mesh @ " with mesh, " @ %asymx @ " asymmetric, " @ %asymz @ " z-asymmetric");
|
||||||
|
|
||||||
|
ndFindSymmetricPairs();
|
||||||
|
}
|
||||||
|
|
||||||
|
//Attempt to find symmetric pairs between asymmetric bricks
|
||||||
|
function ndFindSymmetricPairs()
|
||||||
|
{
|
||||||
|
echo("ND: Starting X symmetric pair search...");
|
||||||
|
echo("==========================================================================");
|
||||||
|
|
||||||
|
for(%i = 0; %i < $NDT::AsymXCountTotal; %i++)
|
||||||
|
{
|
||||||
|
%index = $NDT::AsymXBrick[%i];
|
||||||
|
|
||||||
|
if(!$NDT::SkipAsymX[%index])
|
||||||
|
ndFindSymmetricPairX(%index);
|
||||||
|
}
|
||||||
|
|
||||||
|
echo("==========================================================================");
|
||||||
|
echo("ND: Finished finding symmetric pairs");
|
||||||
|
echo("ND: Starting Z symmetric pair search...");
|
||||||
|
echo("==========================================================================");
|
||||||
|
|
||||||
|
for(%i = 0; %i < $NDT::AsymZCountTotal; %i++)
|
||||||
|
{
|
||||||
|
%index = $NDT::AsymZBrick[%i];
|
||||||
|
|
||||||
|
if(!$NDT::SkipAsymZ[%index])
|
||||||
|
ndFindSymmetricPairZ(%index);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Delete temporary arrays
|
||||||
|
deleteVariables("$NDT::*");
|
||||||
|
|
||||||
|
echo("==========================================================================");
|
||||||
|
echo("ND: Finished finding Z symmetric pairs");
|
||||||
|
echo("ND: Symmetry table complete in " @ (getRealTime() - $ND::SymmetryTableStarted) / 1000 @ " seconds");
|
||||||
|
|
||||||
|
$ND::SymmetryTableCreated = true;
|
||||||
|
$ND::SymmetryTableCreating = false;
|
||||||
|
|
||||||
|
//We're done!
|
||||||
|
%seconds = mFloatLength((getRealTime() - $ND::SymmetryTableStarted) / 1000, 0);
|
||||||
|
messageAll('', "\c6(\c3New Duplicator\c6) \c6Created brick symmetry table in " @ %seconds @ " seconds.");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Test symmetry of a single blb file
|
||||||
|
function ndTestBrickSymmetry(%datablock)
|
||||||
|
{
|
||||||
|
//Open blb file
|
||||||
|
%file = new FileObject();
|
||||||
|
%file.openForRead(%datablock.brickFile);
|
||||||
|
|
||||||
|
//Skip brick size - irrelevant
|
||||||
|
%file.readLine();
|
||||||
|
|
||||||
|
//Simple bricks are always fully symmetric
|
||||||
|
if(%file.readLine() $= "BRICK")
|
||||||
|
{
|
||||||
|
$NDT::SimpleCount++;
|
||||||
|
|
||||||
|
$ND::Symmetry[%datablock] = 1;
|
||||||
|
$ND::SymmetryZ[%datablock] = true;
|
||||||
|
|
||||||
|
%file.close();
|
||||||
|
%file.delete();
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Not simple, get mesh data index in temp arrays
|
||||||
|
%dbi = $NDT::MeshCount;
|
||||||
|
$NDT::MeshCount++;
|
||||||
|
|
||||||
|
//Load mesh from blb file
|
||||||
|
%faces = 0;
|
||||||
|
%points = 0;
|
||||||
|
|
||||||
|
while(!%file.isEOF())
|
||||||
|
{
|
||||||
|
//Find start of face
|
||||||
|
%line = %file.readLine();
|
||||||
|
|
||||||
|
if(getSubStr(%line, 0, 4) $= "TEX:")
|
||||||
|
{
|
||||||
|
%tex = trim(getSubStr(%line, 4, strLen(%line)));
|
||||||
|
|
||||||
|
//Top and bottom faces have different topology, skip
|
||||||
|
if(%tex $= "TOP" || %tex $= "BOTTOMLOOP" || %tex $= "BOTTOMEDGE")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//Add face
|
||||||
|
$NDT::FaceTexId[%dbi, %faces] = (%tex $= "SIDE" ? 0 : (%tex $= "RAMP" ? 1 : 2));
|
||||||
|
|
||||||
|
//Skip useless lines
|
||||||
|
while(trim(%file.readLine()) !$= "POSITION:") {}
|
||||||
|
|
||||||
|
//Add the 4 points
|
||||||
|
for(%i = 0; %i < 4; %i++)
|
||||||
|
{
|
||||||
|
//Read next line
|
||||||
|
%line = %file.readLine();
|
||||||
|
|
||||||
|
//Skip useless blank lines
|
||||||
|
while(!strLen(%line))
|
||||||
|
%line = %file.readLine();
|
||||||
|
|
||||||
|
//Remove formatting from point
|
||||||
|
%pos = vectorAdd(%line, "0 0 0");
|
||||||
|
|
||||||
|
//Round down two digits to fix float errors
|
||||||
|
%pos = mFloatLength(getWord(%pos, 0), 3) * 1.0
|
||||||
|
SPC mFloatLength(getWord(%pos, 1), 3) * 1.0
|
||||||
|
SPC mFloatLength(getWord(%pos, 2), 3) * 1.0;
|
||||||
|
|
||||||
|
//Get index of this point
|
||||||
|
if(!%ptIndex = $NDT::PtAtPosition[%dbi, %pos])
|
||||||
|
{
|
||||||
|
//Points array is 1-indexed so we can quickly test !PtAtPosition[...]
|
||||||
|
%points++;
|
||||||
|
%ptIndex = %points;
|
||||||
|
|
||||||
|
//Add new point to array
|
||||||
|
$NDT::PtPosition[%dbi, %points] = %pos;
|
||||||
|
$NDT::PtAtPosition[%dbi, %pos] = %points;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add face to point
|
||||||
|
if(!$NDT::PtInFace[%dbi, %faces, %ptIndex])
|
||||||
|
{
|
||||||
|
//Increase first then subtract 1 to get 0 the first time
|
||||||
|
%fIndex = $NDT::FacesAtPt[%dbi, %ptIndex]++ - 1;
|
||||||
|
$NDT::FaceAtPt[%dbi, %ptIndex, %fIndex] = %faces;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add point to face
|
||||||
|
$NDT::FacePt[%dbi, %faces, %i] = %ptIndex;
|
||||||
|
$NDT::PtInFace[%dbi, %faces, %ptIndex] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Added face
|
||||||
|
%faces++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$NDT::FaceCount[%dbi] = %faces;
|
||||||
|
$NDT::Datablock[%dbi] = %datablock;
|
||||||
|
|
||||||
|
%file.close();
|
||||||
|
%file.delete();
|
||||||
|
|
||||||
|
//Possible symmetries:
|
||||||
|
// 0: asymmetric
|
||||||
|
// 1: x & y
|
||||||
|
// 2: x
|
||||||
|
// 3: y
|
||||||
|
// 4: x+y
|
||||||
|
// 5: x-y
|
||||||
|
|
||||||
|
//We will test in the following order:
|
||||||
|
// X
|
||||||
|
// Y
|
||||||
|
// X+Y
|
||||||
|
// X-Y
|
||||||
|
// Z
|
||||||
|
|
||||||
|
//Check manual symmetry first
|
||||||
|
%sym = $ND::ManualSymmetry[%datablock.uiname];
|
||||||
|
|
||||||
|
if(%sym !$= "")
|
||||||
|
{
|
||||||
|
if(!%sym)
|
||||||
|
{
|
||||||
|
//Try to find the other brick
|
||||||
|
%otherdb = $UINameTable[$ND::ManualSymmetryDB[%datablock.uiname]];
|
||||||
|
%offset = $ND::ManualSymmetryOffset[%datablock.uiname];
|
||||||
|
|
||||||
|
//...
|
||||||
|
if(!isObject(%otherdb))
|
||||||
|
{
|
||||||
|
%otherdb = "";
|
||||||
|
%offset = 0;
|
||||||
|
echo("ND: " @ %datablock.uiname @ " has manual symmetry but the paired brick does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
$ND::SymmetryXDatablock[%datablock] = %otherdb;
|
||||||
|
$ND::SymmetryXOffset[%datablock] = %offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
%manualSym = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%failX = ndTestSelfSymmetry(%dbi, 0);
|
||||||
|
%failY = ndTestSelfSymmetry(%dbi, 1);
|
||||||
|
|
||||||
|
//Diagonals are only needed if the brick isn't symmetric to the axis
|
||||||
|
if(%failX && %failY)
|
||||||
|
%failXY = ndTestSelfSymmetry(%dbi, 3);
|
||||||
|
|
||||||
|
//One diagonal is enough, only test second if first one fails
|
||||||
|
if(%failXY)
|
||||||
|
%failYX = ndTestSelfSymmetry(%dbi, 4);
|
||||||
|
|
||||||
|
//X, Y symmetry
|
||||||
|
if(!%failX && !%failY)
|
||||||
|
%sym = 1;
|
||||||
|
else if(!%failX)
|
||||||
|
%sym = 2;
|
||||||
|
else if(!%failY)
|
||||||
|
%sym = 3;
|
||||||
|
else if(!%failXY)
|
||||||
|
%sym = 4;
|
||||||
|
else if(!%failYX)
|
||||||
|
%sym = 5;
|
||||||
|
else
|
||||||
|
%sym = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check manual symmetry first
|
||||||
|
%symZ = $ND::ManualSymmetryZ[%datablock.uiname];
|
||||||
|
|
||||||
|
//Z symmetry
|
||||||
|
if(%symZ !$= "")
|
||||||
|
{
|
||||||
|
if(!%symZ)
|
||||||
|
{
|
||||||
|
//Try to find the other brick
|
||||||
|
%otherdb = $UINameTable[$ND::ManualSymmetryZDB[%datablock.uiname]];
|
||||||
|
%offset = $ND::ManualSymmetryZOffset[%datablock.uiname];
|
||||||
|
|
||||||
|
//...
|
||||||
|
if(!isObject(%otherdb))
|
||||||
|
{
|
||||||
|
%otherdb = "";
|
||||||
|
%offset = 0;
|
||||||
|
echo("ND: " @ %datablock.uiname @ " has manual Z symmetry but the paired brick does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
$ND::SymmetryZDatablock[%datablock] = %otherdb;
|
||||||
|
$ND::SymmetryZOffset[%datablock] = %offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
%manualZSym = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
%symZ = !ndTestSelfSymmetry(%dbi, 2);
|
||||||
|
|
||||||
|
if(!%manualSym && !%sym)
|
||||||
|
{
|
||||||
|
//Add to lookup table of X-asymmetric bricks of this type
|
||||||
|
%bIndex = $NDT::AsymXCount[%faces, %symZ]++;
|
||||||
|
$NDT::AsymXBrick[%faces, %symZ, %bIndex] = %dbi;
|
||||||
|
|
||||||
|
//Add to list of asymmetric bricks
|
||||||
|
$NDT::AsymXBrick[$NDT::AsymXCountTotal] = %dbi;
|
||||||
|
$NDT::AsymXCountTotal++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!%manualZSym && !%symZ)
|
||||||
|
{
|
||||||
|
//Add to lookup table of Z-asymmetric bricks of this type
|
||||||
|
%bIndex = $NDT::AsymZCount[%faces, %sym]++;
|
||||||
|
$NDT::AsymZBrick[%faces, %sym, %bIndex] = %dbi;
|
||||||
|
|
||||||
|
//Add to list of Z-asymmetric bricks
|
||||||
|
$NDT::AsymZBrick[$NDT::AsymZCountTotal] = %dbi;
|
||||||
|
$NDT::AsymZCountTotal++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Save symmetries
|
||||||
|
$ND::Symmetry[%datablock] = %sym;
|
||||||
|
$ND::SymmetryZ[%datablock] = %symZ;
|
||||||
|
|
||||||
|
//Return processed faces
|
||||||
|
return %faces;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Find symmetric pair between two bricks on X axis
|
||||||
|
function ndFindSymmetricPairX(%dbi)
|
||||||
|
{
|
||||||
|
if($NDT::SkipAsymX[%dbi])
|
||||||
|
return;
|
||||||
|
|
||||||
|
%datablock = $NDT::Datablock[%dbi];
|
||||||
|
|
||||||
|
%zsym = $ND::SymmetryZ[%datablock];
|
||||||
|
%faces = $NDT::FaceCount[%dbi];
|
||||||
|
%count = $NDT::AsymXCount[%faces, %zsym];
|
||||||
|
|
||||||
|
//Only potential match is the brick itself - fail
|
||||||
|
if(%count == 1)
|
||||||
|
{
|
||||||
|
echo("ND: No X match for " @ %datablock.getName() @ " (" @ %datablock.category @ "/" @ %datablock.subCategory @ "/" @ %datablock.uiname @ ")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%off = -1;
|
||||||
|
$NDT::SkipAsymX[%dbi] = true;
|
||||||
|
|
||||||
|
for(%i = 1; %i <= %count; %i++)
|
||||||
|
{
|
||||||
|
%other = $NDT::AsymXBrick[%faces, %zsym, %i];
|
||||||
|
|
||||||
|
//Don't compare with bricks that already have a pair
|
||||||
|
if($NDT::SkipAsymX[%other])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//Test all 4 possible rotations
|
||||||
|
//Not using loop due to lack of goto command
|
||||||
|
if(!ndTestPairSymmetry(%dbi, %other, true, 0))
|
||||||
|
{
|
||||||
|
%off = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ndTestPairSymmetry(%dbi, %other, true, 1))
|
||||||
|
{
|
||||||
|
%off = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ndTestPairSymmetry(%dbi, %other, true, 2))
|
||||||
|
{
|
||||||
|
%off = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ndTestPairSymmetry(%dbi, %other, true, 3))
|
||||||
|
{
|
||||||
|
%off = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%off != -1)
|
||||||
|
{
|
||||||
|
%otherdb = $NDT::Datablock[%other];
|
||||||
|
|
||||||
|
//Save symmetry
|
||||||
|
$ND::SymmetryXDatablock[%datablock] = %otherdb;
|
||||||
|
$ND::SymmetryXOffset[%datablock] = %off;
|
||||||
|
|
||||||
|
$ND::SymmetryXDatablock[%otherdb] = %datablock;
|
||||||
|
$ND::SymmetryXOffset[%otherdb] = -%off;
|
||||||
|
|
||||||
|
//No need to process the other brick again
|
||||||
|
$NDT::SkipAsymX[%other] = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
echo("ND: No X match for " @ %datablock.getName() @ " (" @ %datablock.category @ "/" @ %datablock.subCategory @ "/" @ %datablock.uiname @ ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Find symmetric pair between two bricks on Z axis
|
||||||
|
function ndFindSymmetricPairZ(%dbi)
|
||||||
|
{
|
||||||
|
if($NDT::SkipAsymZ[%dbi])
|
||||||
|
return;
|
||||||
|
|
||||||
|
%datablock = $NDT::Datablock[%dbi];
|
||||||
|
|
||||||
|
%sym = $ND::Symmetry[%datablock];
|
||||||
|
%faces = $NDT::FaceCount[%dbi];
|
||||||
|
%count = $NDT::AsymZCount[%faces, %sym];
|
||||||
|
|
||||||
|
//Only potential match is the brick itself - fail
|
||||||
|
if(%count == 1)
|
||||||
|
{
|
||||||
|
echo("ND: No Z match for " @ %datablock.getName() @ " (" @ %datablock.category @ "/" @ %datablock.subCategory @ "/" @ %datablock.uiname @ ")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
%off = -1;
|
||||||
|
|
||||||
|
for(%i = 1; %i <= %count; %i++)
|
||||||
|
{
|
||||||
|
%other = $NDT::AsymZBrick[%faces, %sym, %i];
|
||||||
|
|
||||||
|
//Don't compare with bricks that already have a pair
|
||||||
|
if($NDT::SkipAsymZ[%other])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//Test all 4 possible rotations
|
||||||
|
//Not using loop due to lack of goto command
|
||||||
|
if(!ndTestPairSymmetry(%dbi, %other, false, 0))
|
||||||
|
{
|
||||||
|
%off = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ndTestPairSymmetry(%dbi, %other, false, 1))
|
||||||
|
{
|
||||||
|
%off = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ndTestPairSymmetry(%dbi, %other, false, 2))
|
||||||
|
{
|
||||||
|
%off = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!ndTestPairSymmetry(%dbi, %other, false, 3))
|
||||||
|
{
|
||||||
|
%off = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//It's possible for a brick to match itself rotated
|
||||||
|
//here, so only mark it after the search
|
||||||
|
$NDT::SkipAsymZ[%dbi] = true;
|
||||||
|
|
||||||
|
if(%off != -1)
|
||||||
|
{
|
||||||
|
%otherdb = $NDT::Datablock[%other];
|
||||||
|
|
||||||
|
//Save symmetry
|
||||||
|
$ND::SymmetryZDatablock[%datablock] = %otherdb;
|
||||||
|
$ND::SymmetryZOffset[%datablock] = %off;
|
||||||
|
|
||||||
|
$ND::SymmetryZDatablock[%otherdb] = %datablock;
|
||||||
|
$ND::SymmetryZOffset[%otherdb] = -%off;
|
||||||
|
|
||||||
|
//No need to process the other brick again
|
||||||
|
$NDT::SkipAsymZ[%other] = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
echo("ND: No Z match for " @ %datablock.getName() @ " (" @ %datablock.category @ "/" @ %datablock.subCategory @ "/" @ %datablock.uiname @ ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Test a mesh for a single symmetry plane in itself
|
||||||
|
function ndTestSelfSymmetry(%dbi, %plane)
|
||||||
|
{
|
||||||
|
%fail = false;
|
||||||
|
%faces = $NDT::FaceCount[%dbi];
|
||||||
|
|
||||||
|
for(%i = 0; %i < %faces; %i++)
|
||||||
|
{
|
||||||
|
//If this face was already used by another mirror, skip
|
||||||
|
if(%skipFace[%i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//Attempt to find the mirrored points
|
||||||
|
for(%j = 0; %j < 4; %j++)
|
||||||
|
{
|
||||||
|
%pt = $NDT::FacePt[%dbi, %i, %j];
|
||||||
|
|
||||||
|
//Do we already know the mirrored one?
|
||||||
|
if(%mirrPt[%pt])
|
||||||
|
{
|
||||||
|
%mirr[%j] = %mirrPt[%pt];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get position of point
|
||||||
|
%v = $NDT::PtPosition[%dbi, %pt];
|
||||||
|
|
||||||
|
//Get point at mirrored position based on plane
|
||||||
|
switch$(%plane)
|
||||||
|
{
|
||||||
|
//Flip X
|
||||||
|
case 0: %mirr = $NDT::PtAtPosition[%dbi, -firstWord(%v) SPC restWords(%v)];
|
||||||
|
//Flip Y
|
||||||
|
case 1: %mirr = $NDT::PtAtPosition[%dbi, getWord(%v, 0) SPC -getWord(%v, 1) SPC getWord(%v, 2)];
|
||||||
|
//Flip Z
|
||||||
|
case 2: %mirr = $NDT::PtAtPosition[%dbi, getWords(%v, 0, 1) SPC -getWord(%v, 2)];
|
||||||
|
//Mirror along X+Y
|
||||||
|
case 3: %mirr = $NDT::PtAtPosition[%dbi, -getWord(%v, 1) SPC -getWord(%v, 0) SPC getWord(%v, 2)];
|
||||||
|
//Mirror along X-Y
|
||||||
|
default: %mirr = $NDT::PtAtPosition[%dbi, getWord(%v, 1) SPC getWord(%v, 0) SPC getWord(%v, 2)];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%mirr)
|
||||||
|
{
|
||||||
|
%mirrPt[%pt] = %mirr;
|
||||||
|
%mirrPt[%mirr] = %pt;
|
||||||
|
|
||||||
|
%mirr[%j] = %mirr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%fail = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fail)
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Test whether the points have a common face
|
||||||
|
%fail = true;
|
||||||
|
%count = $NDT::FacesAtPt[%dbi, %mirr0];
|
||||||
|
|
||||||
|
for(%j = 0; %j < %count; %j++)
|
||||||
|
{
|
||||||
|
%potentialFace = $NDT::FaceAtPt[%dbi, %mirr0, %j];
|
||||||
|
|
||||||
|
//Mirrored face must have the same texture id
|
||||||
|
if($NDT::FaceTexId[%dbi, %i] != $NDT::FaceTexId[%dbi, %potentialFace])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//Check whether remaining points are in the face
|
||||||
|
if(!$NDT::PtInFace[%dbi, %potentialFace, %mirr1])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!$NDT::PtInFace[%dbi, %potentialFace, %mirr2])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!$NDT::PtInFace[%dbi, %potentialFace, %mirr3])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//We found a matching face!
|
||||||
|
%skipFace[%potentialFace] = true;
|
||||||
|
%fail = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fail)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return %fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Test X or Z symmetry between two meshes with rotation offset
|
||||||
|
function ndTestPairSymmetry(%dbi, %other, %plane, %rotation)
|
||||||
|
{
|
||||||
|
%fail = false;
|
||||||
|
%faces = $NDT::FaceCount[%dbi];
|
||||||
|
|
||||||
|
for(%i = 0; %i < %faces; %i++)
|
||||||
|
{
|
||||||
|
//Attempt to find the mirrored points
|
||||||
|
for(%j = 0; %j < 4; %j++)
|
||||||
|
{
|
||||||
|
%pt = $NDT::FacePt[%dbi, %i, %j];
|
||||||
|
|
||||||
|
//Do we already know the mirrored one?
|
||||||
|
if(%mirrPt[%pt])
|
||||||
|
{
|
||||||
|
%mirr[%j] = %mirrPt[%pt];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Get position of point
|
||||||
|
%v = $NDT::PtPosition[%dbi, %pt];
|
||||||
|
|
||||||
|
//true = X, false = Z
|
||||||
|
if(%plane)
|
||||||
|
{
|
||||||
|
//Get point at mirrored position based on rotation
|
||||||
|
switch(%rotation)
|
||||||
|
{
|
||||||
|
//Flip X
|
||||||
|
case 0: %mirr = $NDT::PtAtPosition[%other, -firstWord(%v) SPC restWords(%v)];
|
||||||
|
//Flip X, rotate 90
|
||||||
|
case 1: %mirr = $NDT::PtAtPosition[%other, getWord(%v, 1) SPC getWord(%v, 0) SPC getWord(%v, 2)];
|
||||||
|
//Flip X, rotate 180
|
||||||
|
case 2: %mirr = $NDT::PtAtPosition[%other, getWord(%v, 0) SPC -getWord(%v, 1) SPC getWord(%v, 2)];
|
||||||
|
//Flip X, rotate 270
|
||||||
|
default: %mirr = $NDT::PtAtPosition[%other, -getWord(%v, 1) SPC -getWord(%v, 0) SPC getWord(%v, 2)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Get point at mirrored position based on rotation
|
||||||
|
switch(%rotation)
|
||||||
|
{
|
||||||
|
//Flip Z
|
||||||
|
case 0: %mirr = $NDT::PtAtPosition[%other, getWord(%v, 0) SPC getWord(%v, 1) SPC -getWord(%v, 2)];
|
||||||
|
//Flip Z, rotate 90
|
||||||
|
case 1: %mirr = $NDT::PtAtPosition[%other, getWord(%v, 1) SPC -getWord(%v, 0) SPC -getWord(%v, 2)];
|
||||||
|
//Flip Z, rotate 180
|
||||||
|
case 2: %mirr = $NDT::PtAtPosition[%other, -getWord(%v, 0) SPC -getWord(%v, 1) SPC -getWord(%v, 2)];
|
||||||
|
//Flip Z, rotate 270
|
||||||
|
default: %mirr = $NDT::PtAtPosition[%other, -getWord(%v, 1) SPC getWord(%v, 0) SPC -getWord(%v, 2)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%mirr)
|
||||||
|
{
|
||||||
|
%mirrPt[%pt] = %mirr;
|
||||||
|
%mirr[%j] = %mirr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
%fail = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fail)
|
||||||
|
break;
|
||||||
|
|
||||||
|
//Test whether the points have a common face
|
||||||
|
%fail = true;
|
||||||
|
%count = $NDT::FacesAtPt[%other, %mirr0];
|
||||||
|
|
||||||
|
for(%j = 0; %j < %count; %j++)
|
||||||
|
{
|
||||||
|
%potentialFace = $NDT::FaceAtPt[%other, %mirr0, %j];
|
||||||
|
|
||||||
|
//Mirrored face must have the same texture id
|
||||||
|
if($NDT::FaceTexId[%dbi, %i] != $NDT::FaceTexId[%other, %potentialFace])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//Check whether remaining points are in the face
|
||||||
|
if(!$NDT::PtInFace[%other, %potentialFace, %mirr1])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!$NDT::PtInFace[%other, %potentialFace, %mirr2])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(!$NDT::PtInFace[%other, %potentialFace, %mirr3])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//We found a matching face!
|
||||||
|
%fail = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(%fail)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return %fail;
|
||||||
|
}
|
31
scripts/server/undo.cs
Normal file
31
scripts/server/undo.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Handles the undo stack for duplicator actions.
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
package NewDuplicator_Server
|
||||||
|
{
|
||||||
|
//Catch things falling off the end of the undo stack
|
||||||
|
function QueueSO::push(%obj, %val)
|
||||||
|
{
|
||||||
|
%lastVal = %obj.val[(%obj.head + 1) % %obj.size];
|
||||||
|
|
||||||
|
if(getFieldCount(%lastVal) == 2)
|
||||||
|
{
|
||||||
|
%str = getField(%lastVal, 1);
|
||||||
|
|
||||||
|
if(
|
||||||
|
%str $= "ND_PLANT"
|
||||||
|
|| %str $= "ND_PAINT"
|
||||||
|
|| %str $= "ND_WRENCH"
|
||||||
|
){
|
||||||
|
%qobj = getField(%lastVal, 0);
|
||||||
|
if(isObject(%qobj)){
|
||||||
|
%qobj.delete();
|
||||||
|
}else{
|
||||||
|
// talk("QueueSO::push(" @ %obj @ ", " @ %val @ ") - Nonexistent object " @ %qobj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::push(%obj, %val);
|
||||||
|
}
|
||||||
|
};
|
65
server.cs
Normal file
65
server.cs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
// Executes all required scripts and initializes the server side.
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
$ND::Version = "1.6.2";
|
||||||
|
|
||||||
|
$ND::FilePath = filePath($Con::File) @ "/";
|
||||||
|
$ND::ConfigPath = "config/NewDuplicator/";
|
||||||
|
|
||||||
|
$ND::ClassPath = $ND::FilePath @ "classes/";
|
||||||
|
$ND::ScriptPath = $ND::FilePath @ "scripts/";
|
||||||
|
$ND::ResourcePath = $ND::FilePath @ "resources/";
|
||||||
|
|
||||||
|
if(isObject(ND_ServerGroup))
|
||||||
|
ND_ServerGroup.delete();
|
||||||
|
|
||||||
|
new ScriptGroup(ND_ServerGroup);
|
||||||
|
|
||||||
|
exec($ND::ClassPath @ "server/ghostgroup.cs");
|
||||||
|
exec($ND::ClassPath @ "server/highlightbox.cs");
|
||||||
|
exec($ND::ClassPath @ "server/selection.cs");
|
||||||
|
exec($ND::ClassPath @ "server/selectionbox.cs");
|
||||||
|
exec($ND::ClassPath @ "server/undogrouppaint.cs");
|
||||||
|
exec($ND::ClassPath @ "server/undogroupplant.cs");
|
||||||
|
exec($ND::ClassPath @ "server/undogroupwrench.cs");
|
||||||
|
|
||||||
|
exec($ND::ClassPath @ "server/duplimode/boxselect.cs");
|
||||||
|
exec($ND::ClassPath @ "server/duplimode/boxselectprogress.cs");
|
||||||
|
exec($ND::ClassPath @ "server/duplimode/cutprogress.cs");
|
||||||
|
exec($ND::ClassPath @ "server/duplimode/fillcolor.cs");
|
||||||
|
exec($ND::ClassPath @ "server/duplimode/fillcolorprogress.cs");
|
||||||
|
exec($ND::ClassPath @ "server/duplimode/loadprogress.cs");
|
||||||
|
exec($ND::ClassPath @ "server/duplimode/plantcopy.cs");
|
||||||
|
exec($ND::ClassPath @ "server/duplimode/plantcopyprogress.cs");
|
||||||
|
exec($ND::ClassPath @ "server/duplimode/saveprogress.cs");
|
||||||
|
exec($ND::ClassPath @ "server/duplimode/stackselect.cs");
|
||||||
|
exec($ND::ClassPath @ "server/duplimode/stackselectprogress.cs");
|
||||||
|
exec($ND::ClassPath @ "server/duplimode/supercutprogress.cs");
|
||||||
|
exec($ND::ClassPath @ "server/duplimode/wrenchprogress.cs");
|
||||||
|
|
||||||
|
exec($ND::ScriptPath @ "common/bytetable.cs");
|
||||||
|
exec($ND::ScriptPath @ "server/commands.cs");
|
||||||
|
exec($ND::ScriptPath @ "server/datablocks.cs");
|
||||||
|
exec($ND::ScriptPath @ "server/functions.cs");
|
||||||
|
exec($ND::ScriptPath @ "server/handshake.cs");
|
||||||
|
exec($ND::ScriptPath @ "server/highlight.cs");
|
||||||
|
exec($ND::ScriptPath @ "server/images.cs");
|
||||||
|
exec($ND::ScriptPath @ "server/modes.cs");
|
||||||
|
exec($ND::ScriptPath @ "server/namedtargets.cs");
|
||||||
|
exec($ND::ScriptPath @ "server/prefs.cs");
|
||||||
|
exec($ND::ScriptPath @ "server/symmetrydefinitions.cs");
|
||||||
|
exec($ND::ScriptPath @ "server/symmetrytable.cs");
|
||||||
|
exec($ND::ScriptPath @ "server/undo.cs");
|
||||||
|
|
||||||
|
activatePackage(NewDuplicator_Server);
|
||||||
|
schedule(10, 0, activatePackage, NewDuplicator_Server_Final);
|
||||||
|
|
||||||
|
ndRegisterDuplicatorModes();
|
||||||
|
ndRegisterPrefs();
|
||||||
|
ndResendHandshakes();
|
||||||
|
|
||||||
|
if($Pref::Server::ND::SymTableOnStart && !$ND::SymmetryTableCreated){
|
||||||
|
schedule(10, 0, ndCreateSymmetryTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
exec("./v20fix.cs");
|
Loading…
x
Reference in New Issue
Block a user