1156 lines
33 KiB
C#

// General server commands used to control the new duplicator.
// -------------------------------------------------------------------
//Information commands
///////////////////////////////////////////////////////////////////////////
//Shows version of blockland and the new duplicator
function serverCmdDupVersion(%client)
{
messageClient(%client, '', "\c6Blockland version: \c3r" @ getBuildNumber());
messageClient(%client, '', "\c6New duplicator version: \c3" @ $ND::Version);
if(%client.ndClient)
messageClient(%client, '', "\c6Your new duplicator version: \c3" @ %client.ndVersion);
else
messageClient(%client, '', "\c6You don't have the new duplicator installed");
}
//Shows versions of other clients
function serverCmdDupClients(%client)
{
messageClient(%client, '', "\c6New duplicator versions:");
%cnt = ClientGroup.getCount();
for(%i = 0; %i < %cnt; %i++)
{
%cl = ClientGroup.getObject(%i);
if(%cl.ndClient)
messageClient(%client, '', "\c3" @ %cl.name @ "\c6 has \c3" @ %cl.ndVersion);
}
}
//Shows list of commands
function serverCmdDupHelp(%client)
{
messageClient(%client, '', " ");
messageClient(%client, '', "\c6You can use the following commands with your new duplicator:");
messageClient(%client, '', "\c7--------------------------------------------------------------------------------");
messageClient(%client, '', "<tab:220>\c3/Duplicator\t\c6 Equip a new duplicator!");
messageClient(%client, '', "<font:Arial:8> ");
messageClient(%client, '', "<tab:220>\c3/ForcePlant\t\c6 Plant a selection in mid air; bricks can float.");
messageClient(%client, '', "<tab:220>\c3/ToggleForcePlant\t\c6 Enable force plant for normal planting, so you dont have to type it all the time.");
messageClient(%client, '', "<tab:220>\c3/PlantAs\c6 [\c3target\c6]\t\c6 Plant bricks in a different brick group. Target can be a name or blid.");
messageClient(%client, '', "<font:Arial:8> ");
messageClient(%client, '', "<tab:220>\c3/FillWrench\t\c6 Open the fill wrench gui to change settings on all selected bricks.");
messageClient(%client, '', "<font:Arial:8> ");
messageClient(%client, '', "<tab:220>\c3/MirrorX\t\c6 Mirror your ghost selection left/right on screen.");
messageClient(%client, '', "<tab:220>\c3/MirrorY\t\c6 Mirror your ghost selection front/back on screen.");
messageClient(%client, '', "<tab:220>\c3/MirrorZ\t\c6 Mirror your ghost selection up/down on screen.");
messageClient(%client, '', "<tab:220>\c3/MirErrors\t\c6 List potential mirror errors after planting a mirrored ghost selection.");
messageClient(%client, '', "<font:Arial:8> ");
messageClient(%client, '', "<tab:220>\c3/SuperCut\t\c6 Delete everything in your selection box, cutting bricks in half on its sides!");
messageClient(%client, '', "<tab:220>\c3/FillBricks\t\c6 First supercut, then completely fill your selection box with few bricks.");
messageClient(%client, '', "<font:Arial:8> ");
messageClient(%client, '', "<tab:220>\c3/SaveDup\c6 [\c3name\c6]\t\c6 Save your current selection to a file.");
messageClient(%client, '', "<tab:220>\c3/LoadDup\c6 [\c3name\c6]\t\c6 Load a selection from a file. Your current selection will be deleted.");
messageClient(%client, '', "<tab:220>\c3/AllDups\c6 [\c3filter\c6]\t\c6 Show all known saved duplications that match the filter. Leave blank to show all.");
messageClient(%client, '', "<font:Arial:8> ");
messageClient(%client, '', "<tab:220>\c3/DupVersion\t\c6 Show the duplicator and blockland versions running on the server.");
messageClient(%client, '', "<tab:220>\c3/DupClients\t\c6 Show the duplicator versions of other clients on the server.");
messageClient(%client, '', "\c7--------------------------------------------------------------------------------");
messageClient(%client, '', "\c6All of the commands can be shortened by just typing a \c3/\c6 and the capital letters!");
messageClient(%client, '', "\c6You might have to use \c3PageUp\c6/\c3PageDown\c6 to see all of them.");
messageClient(%client, '', " ");
}
//Alternative short commands
function serverCmdDV(%client){serverCmdDupVersion(%client);}
function serverCmdDC(%client){serverCmdDupClients(%client);}
function serverCmdDH(%client){serverCmdDupHelp(%client);}
//Equip commands
///////////////////////////////////////////////////////////////////////////
//Command to equip the new duplicator
function serverCmdNewDuplicator(%client)
{
//Check admin
if($Pref::Server::ND::AdminOnly && !%client.isAdmin)
{
messageClient(%client, '', "\c6The new duplicator is admin only. Ask an admin for help.");
return;
}
//Check minigame
if(isObject(%client.minigame) && !%client.minigame.enablebuilding)
{
messageClient(%client, '', "\c6You cannot use the new duplicator while building is disabled in your minigame.");
return;
}
//Check player
if(!isObject(%player = %client.player))
{
messageClient(%client, '', "\c6You must be spawned to equip the new duplicator.");
return;
}
//Hide brick selector and tool gui
%client.ndLastEquipTime = $Sim::Time;
commandToClient(%client, 'setScrollMode', 3);
//Give player a duplicator
%image = %client.ndImage;
if(!isObject(%image))
%image = ND_Image;
%player.updateArm(%image);
%player.mountImage(%image, 0);
%client.ndEquippedFromItem = false;
}
//Alternative commands to equip the new duplicator (override old duplicators)
package NewDuplicator_Server_Final
{
function serverCmdDuplicator(%client){serverCmdNewDuplicator(%client);}
function serverCmdDuplicato (%client){serverCmdNewDuplicator(%client);}
function serverCmdDuplicat (%client){serverCmdNewDuplicator(%client);}
function serverCmdDuplica (%client){serverCmdNewDuplicator(%client);}
function serverCmdDuplic (%client){serverCmdNewDuplicator(%client);}
function serverCmdDupli (%client){serverCmdNewDuplicator(%client);}
function serverCmdDupl (%client){serverCmdNewDuplicator(%client);}
function serverCmdDup (%client){serverCmdNewDuplicator(%client);}
function serverCmdDu (%client){serverCmdNewDuplicator(%client);}
function serverCmdD (%client){serverCmdNewDuplicator(%client);}
};
//Default keybind commands
///////////////////////////////////////////////////////////////////////////
package NewDuplicator_Server
{
//Light key (default: R)
function serverCmdLight(%client)
{
if(%client.ndModeIndex)
%client.ndMode.onLight(%client);
else
parent::serverCmdLight(%client);
}
//Next seat (default: .)
function serverCmdNextSeat(%client)
{
if(%client.ndModeIndex)
%client.ndMode.onNextSeat(%client);
else
parent::serverCmdNextSeat(%client);
}
//Previous seat (default: ,)
function serverCmdPrevSeat(%client)
{
if(%client.ndModeIndex)
%client.ndMode.onPrevSeat(%client);
else
parent::serverCmdPrevSeat(%client);
}
//Shifting the ghost brick (default: numpad 2468/13/5+)
function serverCmdShiftBrick(%client, %x, %y, %z)
{
if(%client.ndModeIndex)
%client.ndMode.onShiftBrick(%client, %x, %y, %z);
//Call parent to play animation
parent::serverCmdShiftBrick(%client, %x, %y, %z);
}
//Super-shifting the ghost brick (default: alt numpad 2468/5+)
function serverCmdSuperShiftBrick(%client, %x, %y, %z)
{
if(%client.ndModeIndex)
%client.ndMode.onSuperShiftBrick(%client, %x, %y, %z);
//Call parent to play animation
parent::serverCmdSuperShiftBrick(%client, %x, %y, %z);
}
//Rotating the ghost brick (default: numpad 79)
function serverCmdRotateBrick(%client, %direction)
{
if(%client.ndModeIndex)
%client.ndMode.onRotateBrick(%client, %direction);
//Call parent to play animation
parent::serverCmdRotateBrick(%client, %direction);
}
//Undo bricks (default: ctrl z)
function serverCmdUndoBrick(%client)
{
if(%client.ndUndoInProgress)
{
messageClient(%client, '', "\c6Please wait for the current undo task to finish.");
return;
}
//This really needs a better api.
//Wtf were you thinking, badspot?
%state = %client.undoStack.pop();
%type = getField(%state, 1);
if(
%type $= "ND_PLANT"
|| %type $= "ND_PAINT"
|| %type $= "ND_WRENCH"
){
%obj = getField(%state, 0);
if(isObject(%obj)){
if(%obj.brickCount > 10 && %client.ndUndoConfirm != %obj)
{
messageClient(%client, '', "\c6Next undo will affect \c3" @ %obj.brickCount @ "\c6 bricks. Press undo again to continue.");
%client.undoStack.push(%state);
%client.ndUndoConfirm = %obj;
return;
}
%obj.ndStartUndo(%client);
if(isObject(%client.player))
%client.player.playThread(3, "undo");
%client.ndUndoConfirm = 0;
}else{
talk("serverCmdUndoBrick(" @ %client.name @ ") - Nonexistent undo state " @ %state);
}
return;
}
%client.ndUndoConfirm = 0;
%client.undoStack.push(%state);
parent::serverCmdUndoBrick(%client);
}
};
package NewDuplicator_Server_Final
{
//Planting the ghost brick (default: numpad enter)
function serverCmdPlantBrick(%client)
{
if(%client.ndModeIndex)
%client.ndMode.onPlantBrick(%client);
else
parent::serverCmdPlantBrick(%client);
}
//Removing the ghost brick (default: numpad 0)
function serverCmdCancelBrick(%client)
{
if(%client.ndModeIndex)
%client.ndMode.onCancelBrick(%client);
else
parent::serverCmdCancelBrick(%client);
}
};
//Custom keybind commands
///////////////////////////////////////////////////////////////////////////
//Copy selection (ctrl c)
function serverCmdNdCopy(%client)
{
if(%client.ndModeIndex)
%client.ndMode.onCopy(%client);
}
//Paste selection (ctrl v)
function serverCmdNdPaste(%client)
{
if(%client.ndModeIndex)
%client.ndMode.onPaste(%client);
}
//Cut selection (ctrl x)
function serverCmdNdCut(%client)
{
if(%client.ndModeIndex)
%client.ndMode.onCut(%client);
}
//Cut selection
function serverCmdCut(%client)
{
serverCmdNdCut(%client);
}
//Supercut selection
function serverCmdSuperCut(%client)
{
if(%client.ndModeIndex != $NDM::BoxSelect)
{
messageClient(%client, '', "\c6Supercut can only be used on box selection mode.");
return;
}
if(!isObject(%client.ndSelectionBox))
{
messageClient(%client, '', "\c6Supercut can only be used with a selection box.");
return;
}
if(%client.ndSelectionAvailable)
{
messageClient(%client, '', "\c6Supercut can not be used with any bricks selected.");
return;
}
commandToClient(%client, 'messageBoxOkCancel', "New Duplicator | Supercut",
"Supercut is destructive and does\nNOT support undo at this time." @
"\n\nPlease make sure the box is correct,\nthen press OK below.",
'ndConfirmSuperCut');
}
//Confirm Supercut selection
function serverCmdNdConfirmSuperCut(%client)
{
if(%client.ndModeIndex != $NDM::BoxSelect)
{
messageClient(%client, '', "\c6Supercut can only be used on box selection mode.");
return;
}
if(!isObject(%client.ndSelectionBox))
{
messageClient(%client, '', "\c6Supercut can only be used with a selection box.");
return;
}
if(%client.ndSelectionAvailable)
{
messageClient(%client, '', "\c6Supercut can not be used with any bricks selected.");
return;
}
%client.NDFillBrickSubset = $ND::SubsetDefault;
%client.fillBricksAfterSuperCut = false;
%client.ndMode.onSuperCut(%client);
}
//Alternative short command
function serverCmdSC(%client){serverCmdSuperCut(%client);}
//Fill volume with bricks
function serverCmdFillBricks(%client, %conf, %subsetname)
{
if($Pref::Server::ND::FillBricksAdminOnly && !%client.isAdmin)
{
messageClient(%client, '', "\c6Fill Bricks is admin only. Ask an admin for help.");
return;
}
if(!isObject(%client.ndSelectionBox))
{
messageClient(%client, '', "\c6The fillBricks command can only be used with a selection box.");
return;
}
if(%client.ndSelectionAvailable)
{
messageClient(%client, '', "\c6The fillBricks command can not be used with any bricks selected.");
return;
}
if(!%client.ndSelectionBox.hasVolume())
{
messageClient(%client, '', "\c6The fillBricks command can only be used with a selection box that has a volume.");
return;
}
%client.NDFillBrickSubset = (%subsetname !$= "") ? ndLookupSubsetName(%subsetname) : $ND::SubsetDefault;
if(%conf) {
serverCmdNdConfirmFillBricks(%client, %subsetname);
} else {
commandToClient(%client, 'messageBoxOkCancel', "New Duplicator | /FillBricks",
"/FillBricks will first do a Supercut\nbefore placing bricks, to fix overlap." @
"\n\nSupercut is destructive and does\nNOT support undo at this time." @
"\n\nPlease make sure the box is correct,\nthen press OK below to continue.",
'ndConfirmFillBricks');
}
}
//Confirm fill volume with bricks
function serverCmdNdConfirmFillBricks(%client, %subsetname)
{
if($Pref::Server::ND::FillBricksAdminOnly && !%client.isAdmin)
{
messageClient(%client, '', "\c6Fill Bricks is admin only. Ask an admin for help.");
return;
}
if(!isObject(%client.ndSelectionBox))
{
messageClient(%client, '', "\c6The fillBricks command can only be used with a selection box.");
return;
}
if(%client.ndSelectionAvailable)
{
messageClient(%client, '', "\c6The fillBricks command can not be used with any bricks selected.");
return;
}
if(!%client.ndSelectionBox.hasVolume())
{
messageClient(%client, '', "\c6The fillBricks command can only be used with a selection box that has a volume.");
return;
}
%client.NDFillBrickSubset = (%subsetname !$= "") ?
ndLookupSubsetName(%subsetname) :
((%client.NDFillBrickSubset !$= "") ?
%client.NDFillBrickSubset :
$ND::SubsetDefault
)
;
%client.fillBricksAfterSuperCut = true;
%client.ndMode.onSuperCut(%client);
}
//Alternative short command
function serverCmdFB (%client, %conf) { serverCmdFillBricks(%client, %conf); }
function serverCmdFBW(%client, %conf) { serverCmdFillBricks(%client, %conf, "LogicWire"); }
//MultiSelect toggle (ctrl)
function serverCmdNdMultiSelect(%client, %bool)
{
%client.ndMultiSelect = !!%bool;
if(%client.ndModeIndex == $NDM::StackSelect || %client.ndModeIndex == $NDM::BoxSelect)
%client.ndUpdateBottomPrint();
}
//Mirror commands
///////////////////////////////////////////////////////////////////////////
//Mirror selection on X relative to player
function serverCmdMirrorX(%client)
{
if((getAngleIDFromPlayer(%client.getControlObject()) - %client.ndSelection.ghostAngleID) % 2 == 1)
%client.ndMirror(0);
else
%client.ndMirror(1);
}
//Mirror selection on Y relative to player
function serverCmdMirrorY(%client)
{
if((getAngleIDFromPlayer(%client.getControlObject()) - %client.ndSelection.ghostAngleID) % 2 == 1)
%client.ndMirror(1);
else
%client.ndMirror(0);
}
//Mirror selection on Z
function serverCmdMirrorZ(%client)
{
%client.ndMirror(2);
}
//Alternative short commands
function serverCmdMX(%client){serverCmdMirrorX(%client);}
function serverCmdMY(%client){serverCmdMirrorY(%client);}
function serverCmdMZ(%client){serverCmdMirrorZ(%client);}
//Attempt to mirror selection on axis
function GameConnection::ndMirror(%client, %axis)
{
//Make sure symmetry table is created
if(!$ND::SymmetryTableCreated)
{
if(!$ND::SymmetryTableCreating)
ndCreateSymmetryTable();
messageClient(%client, '', "\c6Please wait for the symmetry table to finish, then mirror again.");
return;
}
//If we're in plant mode, mirror the selection
if(isObject(%client.ndSelection) && %client.ndModeIndex == $NDM::PlantCopy)
{
%client.ndSelection.mirrorGhostBricks(%axis);
return;
}
//If we have a ghost brick, mirror that instead
if(isObject(%client.player) && isObject(%client.player.tempBrick))
{
%client.player.tempBrick.ndMirrorGhost(%client, %axis);
return;
}
//We didn't mirror anything
messageClient(%client, '', "\c6The mirror command can only be used in plant mode or with a ghost brick.");
}
//List potential mirror errors in last plant
function serverCmdMirErrors(%client)
{
%xerr = $NS[%client, "MXC"];
%zerr = $NS[%client, "MZC"];
if(%xerr)
{
messageClient(%client, '', " ");
messageClient(%client, '', "\c6These bricks are asymmetric and probably mirrored incorrectly:");
for(%i = 0; %i < %xerr; %i++)
{
%db = $NS[%client, "MXE", %i];
messageClient(%client, '', "\c7 -" @ %i + 1 @ "- \c6" @ %db.category @ "/" @ %db.subCategory @ "/" @ %db.uiName);
}
}
if(%zerr)
{
messageClient(%client, '', " ");
messageClient(%client, '', "\c6These bricks are not vertically symmetric and probably incorrect:");
for(%i = 0; %i < %zerr; %i++)
{
%db = $NS[%client, "MZE", %i];
messageClient(%client, '', "\c7 -" @ %i + 1 @ "- \c6" @ %db.category @ "/" @ %db.subCategory @ "/" @ %db.uiName);
}
}
if(!%xerr && !%zerr)
messageClient(%client, '', "\c6There were no mirror errors in your last plant attempt.");
}
//Alternative short command
function serverCmdME(%client){serverCmdMirErrors(%client);}
//Force plant
///////////////////////////////////////////////////////////////////////////
//Force plant one time
function serverCmdForcePlant(%client)
{
//Check mode
if(%client.ndModeIndex != $NDM::PlantCopy)
{
messageClient(%client, '', "\c6Force Plant can only be used in Plant Mode.");
return;
}
//Check admin
if($Pref::Server::ND::FloatAdminOnly && !%client.isAdmin)
{
messageClient(%client, '', "\c6Force Plant is admin only. Ask an admin for help.");
return;
}
NDM_PlantCopy.conditionalPlant(%client, true);
}
//Alternative short command
function serverCmdFP(%client){serverCmdForcePlant(%client);}
//Keep force plant enabled
function serverCmdToggleForcePlant(%client)
{
//Check admin
if($Pref::Server::ND::FloatAdminOnly && !%client.isAdmin)
{
messageClient(%client, '', "\c6Force Plant is admin only. Ask an admin for help.");
return;
}
%client.ndForcePlant = !%client.ndForcePlant;
if(%client.ndForcePlant)
messageClient(%client, '', "\c6Force Plant has been enabled. Use \c3/toggleForcePlant\c6 to disable it.");
else
messageClient(%client, '', "\c6Force Plant has been disabled. Use \c3/toggleForcePlant\c6 to enable it again.");
}
//Alternative short command
function serverCmdTFP(%client){serverCmdToggleForcePlant(%client);}
//Fill color
///////////////////////////////////////////////////////////////////////////
package NewDuplicator_Server
{
//Enable fill color mode or show the current color
function serverCmdUseSprayCan(%client, %index)
{
%mode = %client.ndModeIndex;
if(%mode == $NDM::StackSelect || %mode == $NDM::BoxSelect)
{
if(isObject(%client.ndSelection) && %client.ndSelection.brickCount)
{
%client.currentColor = %index;
%client.currentFxColor = "";
%client.ndSetMode(NDM_FillColor);
return;
}
}
else if(%mode == $NDM::FillColor || %client.ndModeIndex == $NDM::FillColorProgress)
{
%client.currentColor = %index;
%client.currentFxColor = "";
%client.ndUpdateBottomPrint();
return;
}
cancel(%client.ndToolSchedule);
parent::serverCmdUseSprayCan(%client, %index);
}
//Enable fill color mode or show the current color
function serverCmdUseFxCan(%client, %index)
{
%mode = %client.ndModeIndex;
if(%mode == $NDM::StackSelect || %mode == $NDM::BoxSelect)
{
if(isObject(%client.ndSelection) && %client.ndSelection.brickCount)
{
%client.currentFxColor = %index;
%client.ndSetMode(NDM_FillColor);
}
else
parent::serverCmdUseFxCan(%client, %index);
}
else if(%mode == $NDM::FillColor || %client.ndModeIndex == $NDM::FillColorProgress)
{
%client.currentFxColor = %index;
%client.ndUpdateBottomPrint();
}
else
parent::serverCmdUseFxCan(%client, %index);
}
};
//Fill wrench
///////////////////////////////////////////////////////////////////////////
//Open the fill wrench gui
function serverCmdFillWrench(%client)
{
//Check version
if(!%client.ndClient)
{
messageClient(%client, '', "\c6You need to have the new duplicator installed to use Fill Wrench.");
return;
}
if(ndCompareVersion("1.2.0", %client.ndVersion) == 1)
{
messageClient(%client, '', "\c6Your version of the new duplicator is too old to use Fill Wrench.");
return;
}
//Check admin
if($Pref::Server::ND::WrenchAdminOnly && !%client.isAdmin)
{
messageClient(%client, '', "\c6Fill Wrench is admin only. Ask an admin for help.");
return;
}
//Check mode
if(%client.ndModeIndex != $NDM::StackSelect && %client.ndModeIndex != $NDM::BoxSelect)
{
messageClient(%client, '', "\c6Fill Wrench can only be used in Selection Mode.");
return;
}
//Check selection
if(!isObject(%client.ndSelection) || !%client.ndSelection.brickCount)
{
messageClient(%client, '', "\c6Fill Wrench can only be used with a selection.");
return;
}
//Open fill wrench gui
commandToClient(%client, 'ndOpenWrenchGui');
}
//Short command
function serverCmdFW(%client) {serverCmdFillWrench(%client);}
//Send data from gui
function serverCmdNdStartFillWrench(%client, %data)
{
//Check admin
if($Pref::Server::ND::WrenchAdminOnly && !%client.isAdmin)
{
messageClient(%client, '', "\c6Fill Wrench is admin only. Ask an admin for help.");
return;
}
//Check mode
if(%client.ndModeIndex != $NDM::StackSelect && %client.ndModeIndex != $NDM::BoxSelect)
{
messageClient(%client, '', "\c6Fill Wrench can only be used in Selection Mode.");
return;
}
//Check selection
if(!isObject(%client.ndSelection) || !%client.ndSelection.brickCount)
{
messageClient(%client, '', "\c6Fill Wrench can only be used with a selection.");
return;
}
//Change mode
%client.ndSetMode(NDM_WrenchProgress);
%client.ndSelection.startFillWrench(%data);
}
//Saving and loading
///////////////////////////////////////////////////////////////////////////
package NewDuplicator_Server_Final
{
//Save current selection to file
function serverCmdSaveDup(%client, %f0, %f1, %f2, %f3, %f4, %f5, %f6, %f7)
{
//Check timeout
if(!%client.isAdmin && %client.ndLastSaveTime + 10 > $Sim::Time)
{
%remain = mCeil(%client.ndLastSaveTime + 10 - $Sim::Time);
if(%remain != 1)
%s = "s";
messageClient(%client, '', "\c6Please wait\c3 " @ %remain @ "\c6 second" @ %s @ " before saving again!");
return;
}
//Check admin
if($Pref::Server::ND::SaveAdminOnly && !%client.isAdmin)
{
messageClient(%client, '', "\c6Saving duplications is admin only. Ask an admin for help.");
return;
}
//Check mode
if(%client.ndModeIndex != $NDM::PlantCopy)
{
messageClient(%client, '', "\c6Saving duplications can only be used in Plant Mode.");
return;
}
//Filter file name
%allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ._-()";
%fileName = trim(%f0 SPC %f1 SPC %f2 SPC %f3 SPC %f4 SPC %f5 SPC %f6 SPC %f7);
%filePath = $ND::ConfigPath @ "Saves/" @ %fileName @ ".bls";
%filePath = strReplace(%filePath, ".bls.bls", ".bls");
for(%i = 0; %i < strLen(%fileName); %i++)
{
if(strStr(%allowed, getSubStr(%fileName, %i, 1)) == -1)
{
%forbidden = true;
break;
}
}
if(%forbidden || !strLen(%fileName) || strLen(%fileName) > 50)
{
messageClient(%client, '', "\c6Bad save name \"\c3" @ %fileName @ "\c6\", please try again.");
messageClient(%client, '', "\c6Only \c3a-z A-Z 0-9 ._-()\c6 and \c3space\c6 are allowed, with a max length of 50 characters.");
return;
}
//Check overwrite
if(isFile(%filePath) && %client.ndPotentialOverwrite !$= %fileName)
{
messageClient(%client, '', "\c6Save \"\c3" @ %fileName @ "\c6\" already exists. Repeat the command to overwrite.");
%client.ndPotentialOverwrite = %fileName;
return;
}
%client.ndPotentialOverwrite = "";
//Check writeable
if(!isWriteableFileName(%filePath))
{
messageClient(%client, '', "\c6File \"\c3" @ %fileName @ "\c6\" is not writeable. Ask the host for help.");
return;
}
messageClient(%client, '', "\c6Saving selection to \"\c3" @ %fileName @ "\c6\"...");
//Notify admins
if(!%client.isAdmin)
{
for(%i = 0; %i < ClientGroup.getCount(); %i++)
{
%cl = ClientGroup.getObject(%i);
if(%cl.isAdmin && %cl != %client)
messageClient(%cl, '', "\c3" @ %client.name @ "\c6 is saving duplication \"\c3" @ %fileName @ "\c6\"");
}
}
//Write log
echo("ND: " @ %client.name @ " (" @ %client.bl_id @ ") is saving duplication \"" @ %fileName @ "\"");
// Uncache saved file info
$ND::FileDate[%filePath] = "";
//Change mode
%client.ndSetMode(NDM_SaveProgress);
if(!%client.ndSelection.startSaving(%filePath))
{
messageClient(%client, '', "\c6Failed to write save \"\c3" @ %fileName @ "\c6\". Ask the host for help.");
%client.ndSetMode(NDM_PlantCopy);
}
}
//Load selection from file
function serverCmdLoadDup(%client, %f0, %f1, %f2, %f3, %f4, %f5, %f6, %f7)
{
//Check timeout
if(!%client.isAdmin && %client.ndLastLoadTime + 5 > $Sim::Time)
{
%remain = mCeil(%client.ndLastLoadTime + 5 - $Sim::Time);
if(%remain != 1)
%s = "s";
messageClient(%client, '', "\c6Please wait\c3 " @ %remain @ "\c6 second" @ %s @ " before loading again!");
return;
}
//Check admin
if($Pref::Server::ND::LoadAdminOnly && !%client.isAdmin)
{
messageClient(%client, '', "\c6Loading duplications is admin only. Ask an admin for help.");
return;
}
//Attempt to get a duplicator
if(!%client.ndEquipped)
{
serverCmdNewDuplicator(%client);
if(!%client.ndEquipped)
return;
}
//Check mode
%mode = %client.ndModeIndex;
if(%mode != $NDM::StackSelect && %mode != $NDM::BoxSelect && %mode != $NDM::PlantCopy)
{
messageClient(%client, '', "\c6Loading duplications can only be used in Plant or Selection Mode.");
return;
}
//Filter file name
%allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ._-()";
%fileName = trim(%f0 SPC %f1 SPC %f2 SPC %f3 SPC %f4 SPC %f5 SPC %f6 SPC %f7);
%filePath = $ND::ConfigPath @ "Saves/" @ %fileName @ ".bls";
%filePath = strReplace(%filePath, ".bls.bls", ".bls");
for(%i = 0; %i < strLen(%fileName); %i++)
{
if(strStr(%allowed, getSubStr(%fileName, %i, 1)) == -1)
{
%forbidden = true;
break;
}
}
if(%forbidden || !strLen(%fileName) || strLen(%fileName) > 50)
{
messageClient(%client, '', "\c6Bad save name \"\c3" @ %fileName @ "\c6\", please try again.");
messageClient(%client, '', "\c6Only \c3a-z A-Z 0-9 ._-()\c6 and \c3space\c6 are allowed, with a max length of 50 characters.");
return;
}
//Check if file exists
if(!isFile(%filePath))
{
messageClient(%client, '', "\c6Save \"\c3" @ %fileName @ "\c6\" does not exist, please try again.");
return;
}
messageClient(%client, '', "\c6Loading selection from \"\c3" @ %fileName @ "\c6\"...");
//Notify admins
if(!%client.isAdmin)
{
for(%i = 0; %i < ClientGroup.getCount(); %i++)
{
%cl = ClientGroup.getObject(%i);
if(%cl.isAdmin && %cl != %client)
messageClient(%cl, '', "\c3" @ %client.name @ "\c6 is loading duplication \"\c3" @ %fileName @ "\c6\"");
}
}
//Write log
echo("ND: " @ %client.name @ " (" @ %client.bl_id @ ") is loading duplication \"" @ %fileName @ "\"");
//Change mode
%client.ndSetMode(NDM_LoadProgress);
if(!%client.ndSelection.startLoading(%filePath))
{
messageClient(%client, '', "\c6Failed to read save \"\c3" @ %fileName @ "\c6\". Ask the host for help.");
%client.ndSetMode(%client.ndLastSelectMode);
}
}
};
function ND_SaveFileInfo(%filename) {
// Get date from file if not cached
if($ND::FileDate[%filename] $= "") {
%file = new FileObject();
%file.openForRead(%filename);
%file.readLine();
%file.readLine();
%dateline = %file.readLine();
%file.close();
%file.delete();
$ND::FileDate[%filename] = %dateline;
}
// Construct table line
%info = $ND::FileDate[%filename];
%info_aftername = getSubStr(%info, strStr(%info, " (")+2, strLen(%info));
%date = getSubStr(%info_aftername, strLen(%info_aftername)-17, 17);
%blid = getSubStr(%info_aftername, 0, strStr(%info_aftername, ")"));
%name = getSubStr(%info, 9, strStr(%info, " (") - 9);
// Fix date format for sorting
%sort = strReplace(strReplace(%date, "/", " "), ":", " ");
%sort = getWord(%sort, 2) SPC getWord(%sort, 0) SPC getWord(%sort, 1) SPC getWords(%sort, 3, 5) @ " ";
%namepart = fileBase(%filename);
%filetext = %sort @
"\c3" @ %namepart TAB
"\c3" @ %name TAB
"\c6" @ %blid TAB
"\c6" @ %date
;
return %filetext;
}
//Get list of all available dups
function serverCmdAllDups(%client, %pattern)
{
//Check admin
if($Pref::Server::ND::LoadAdminOnly && !%client.isAdmin)
{
messageClient(%client, '', "\c6Loading duplications is admin only. Ask an admin for help.");
return;
}
if(strLen(%pattern))
{
//Filter pattern
%allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._-()";
%pattern = trim(%pattern);
for(%i = 0; %i < strLen(%pattern); %i++)
{
if(strStr(%allowed, getSubStr(%pattern, %i, 1)) == -1)
{
messageClient(%client, '', "\c6Bad pattern \"\c3" @ %pattern @ "\c6\", please try again.");
messageClient(%client, '', "\c6Only \c3a-z A-Z 0-9 ._-()\c6 are allowed.");
return;
}
}
%p = $ND::ConfigPath @ "Saves/*" @ %pattern @ "*.bls";
} else {
%p = $ND::ConfigPath @ "Saves/*.bls";
}
//Get sorted list of files
%sort = new GuiTextListCtrl();
for(%filename = findFirstFile(%p); isFile(%filename); %filename = findNextFile(%p)) {
%info = ND_SaveFileInfo(%filename);
%sort.addRow(0, %info);
}
%fileCount = %sort.rowCount();
%sort.sort(0, true);
//Dump list to client
if(%fileCount)
{
%s = (%fileCount == 1) ? " is" : "s are";
if(strLen(%pattern))
messageClient(%client, '', "\c3" @ %fileCount @ "\c6 saved duplication" @ %s @ " available for filter \"\c3" @ %pattern @ "\c6\":");
else
messageClient(%client, '', "\c3" @ %fileCount @ "\c6 saved duplication" @ %s @ " available:");
%format = "<tab:400,550,650,750>";
if(%fileCount>0) {
messageClient(%client, '', %format @ "\c6Name\t\c6Saved By\t\c6BL_ID\t\c6Date");
}
for(%i = 0; %i < %fileCount; %i++) {
%text = %sort.getRowText(%i);
messageClient(%client, '', %format @ getSubStr(%text, 20, strLen(%text)));
}
}
else
{
if(strLen(%pattern))
messageClient(%client, '', "\c6No saved duplications are available for filter \"\c3" @ %pattern @ "\c6\".");
else
messageClient(%client, '', "\c6No saved duplications are available.");
}
%sort.delete();
messageClient(%client, '', "\c6Scroll using \c3PageUp\c6 and \c3PageDown\c6 if you can't see the whole list.");
}
//Alternative short commands
function serverCmdSD(%client, %f0, %f1, %f2, %f3, %f4, %f5, %f6, %f7) {serverCmdSaveDup(%client, %f0, %f1, %f2, %f3, %f4, %f5, %f6, %f7);}
function serverCmdLD(%client, %f0, %f1, %f2, %f3, %f4, %f5, %f6, %f7) {serverCmdLoadDup(%client, %f0, %f1, %f2, %f3, %f4, %f5, %f6, %f7);}
function serverCmdAD(%client, %pattern) {serverCmdAllDups(%client, %pattern);}
//Admin commands
///////////////////////////////////////////////////////////////////////////
//Cancel all active dups in case of spamming
function serverCmdClearDups(%client)
{
if(!%client.isAdmin)
{
messageClient(%client, '', "\c6Canceling all duplicators is admin only. Ask an admin for help.");
return;
}
messageAll('MsgClearBricks', "\c3" @ %client.getPlayerName() @ "\c0 canceled all duplicators.");
for(%i = 0; %i < ClientGroup.getCount(); %i++)
{
%cl = ClientGroup.getObject(%i);
if(%cl.ndModeIndex)
%cl.ndKillMode();
}
}
//Plant as a different brick group
function serverCmdPlantAs(%client, %t0, %t1, %t2, %t3, %t4)
{
//Check mode
if(%client.ndModeIndex != $NDM::PlantCopy)
{
messageClient(%client, '', "\c6This command can only be used in Plant Mode.");
return;
}
//Empty target to clear
if(!strLen(%t0))
{
messageClient(%client, '', "\c6Bricks will be planted in your own group!");
%client.ndSelection.targetGroup = "";
%client.ndSelection.targetBlid = "";
%client.ndUpdateBottomPrint();
return;
}
for(%i = 0; strLen(%t[%i]); %i++)
%target = %target SPC %t[%i];
//Attempt to find the brick group by name or blid
%target = trim(%target);
%targetClient = findClientByName(%target);
if(!isObject(%targetClient))
%targetClient = findClientByBL_ID(%target);
if(isObject(%targetClient))
%targetGroup = %targetClient.brickGroup;
else if((%target | 0) $= %target)
%targetGroup = nameToId("BrickGroup_" @ %target);
if(!isObject(%targetGroup))
{
messageClient(%client, '', "\c6No brick group was found for \"\c3" @ %target @ "\c6\".");
messageClient(%client, '', "\c6Bricks will be planted in your own group!");
%client.ndSelection.targetGroup = "";
%client.ndSelection.targetBlid = "";
%client.ndUpdateBottomPrint();
return;
}
//Check whether we have trust to the target group
if(getTrustLevel(%client, %targetGroup) < 1 &&
(!%client.isAdmin || !$Pref::Server::ND::AdminTrustBypass2))
{
messageClient(%client, '', "\c6You need build trust with \c3"
@ %targetGroup.name @ "\c6 to plant bricks in their group.");
%client.ndSelection.targetGroup = "";
%client.ndSelection.targetBlid = "";
%client.ndUpdateBottomPrint();
return;
}
//Should be good to go
%name = %targetGroup.name;
if(getSubStr(%name, strLen(%name) - 1, 1) $= "s")
messageClient(%client, '', "\c6Bricks will now be planted in \c3" @ %name @ "\c6' group!");
else
messageClient(%client, '', "\c6Bricks will now be planted in \c3" @ %name @ "\c6's group!");
%client.ndSelection.targetGroup = %targetGroup;
%client.ndSelection.targetBlid = %targetGroup.bl_id;
%client.ndUpdateBottomPrint();
}
//Alternative short command
function serverCmdPA(%client, %t0, %t1, %t2, %t3, %t4) {serverCmdPlantAs(%client, %t0, %t1, %t2, %t3, %t4);}