ModernUO/Projects/UOContent/Commands/Generic/Commands/DesignInsert.cs
Kamron Batman fffda53263
fix: Adds command help, webpage, and fixes issues with other commands (#1669)
### Summary

- Fixes `[AdvancedSearch` being accessible by players 😱 
- Adds `[GenCommands` to generate the same commands html page on https://muo.gg/commands.
- Fixes `[helpinfo` so all commands properly show up!

> [!WARNING]  
> ### Developer Warning:
> Commands must now be registered in the `Configure` bootup phase.
> If a command is not registered early enough, it may not be available to systems like [helpinfo
> that cache their information.

> [!NOTE]  
> ### Developer Note:
> Various commands related to generating content have been changed to _Developer_ and above access level.

### Screenshots
<img width="673" alt="image" src="https://github.com/modernuo/ModernUO/assets/3953314/b105b5c9-5eb4-4ace-93ff-1bfb31e7132f">

<img width="547" alt="image" src="https://github.com/modernuo/ModernUO/assets/3953314/e97487e8-47a5-4aa7-89cc-9fe3deda584d">
2024-02-10 00:19:19 -08:00

224 lines
7.5 KiB
C#

using System.Collections.Generic;
using Server.Gumps;
using Server.Items;
using Server.Multis;
using Server.Targeting;
namespace Server.Commands.Generic
{
public class DesignInsertCommand : BaseCommand
{
public enum DesignInsertResult
{
Valid,
InvalidItem,
NotInHouse,
OutsideHouseBounds
}
public DesignInsertCommand()
{
AccessLevel = AccessLevel.GameMaster;
Supports = CommandSupport.Single | CommandSupport.Area;
Commands = new[] { "DesignInsert" };
ObjectTypes = ObjectTypes.Items;
Usage = "DesignInsert [allItems=false]";
Description = "Inserts multiple targeted items into a customizable house's design.";
}
public static void Configure()
{
TargetCommands.Register(new DesignInsertCommand());
}
public static DesignInsertResult ProcessInsert(Item item, bool staticsOnly, out HouseFoundation house)
{
house = null;
if (item is null or BaseMulti or HouseSign || staticsOnly && item is not Static)
{
return DesignInsertResult.InvalidItem;
}
house = BaseHouse.FindHouseAt(item) as HouseFoundation;
if (house == null)
{
return DesignInsertResult.NotInHouse;
}
var x = item.X - house.X;
var y = item.Y - house.Y;
var z = item.Z - house.Z;
if (!TryInsertIntoState(house.CurrentState, item.ItemID, x, y, z))
{
return DesignInsertResult.OutsideHouseBounds;
}
TryInsertIntoState(house.DesignState, item.ItemID, x, y, z);
item.Delete();
return DesignInsertResult.Valid;
}
private static bool TryInsertIntoState(DesignState state, int itemID, int x, int y, int z)
{
var mcl = state.Components;
if (x < mcl.Min.X || y < mcl.Min.Y || x > mcl.Max.X || y > mcl.Max.Y)
{
return false;
}
mcl.Add(itemID, x, y, z);
state.OnRevised();
return true;
}
public override void Execute(CommandEventArgs e, object obj)
{
Target t = new DesignInsertTarget(new List<HouseFoundation>(), e.Length < 1 || !e.GetBoolean(0));
t.Invoke(e.Mobile, obj);
}
public override void ExecuteList(CommandEventArgs e, List<object> list)
{
var from = e.Mobile;
from.SendGump(
new WarningGump(
1060637,
30720,
$"You are about to insert {list.Count} objects. This cannot be undone without a full server revert.<br><br>Continue?",
0xFFC000,
420,
280,
okay => OnConfirmCallback(from, okay, list, e.Length < 1 || !e.GetBoolean(0))
)
);
AddResponse("Awaiting confirmation...");
}
private void OnConfirmCallback(Mobile from, bool okay, List<object> list, bool staticsOnly)
{
var flushToLog = false;
if (okay)
{
var foundations = new List<HouseFoundation>();
flushToLog = list.Count > 20;
for (var i = 0; i < list.Count; ++i)
{
var result = ProcessInsert(list[i] as Item, staticsOnly, out var house);
switch (result)
{
case DesignInsertResult.Valid:
{
AddResponse("The item has been inserted into the house design.");
if (!foundations.Contains(house))
{
foundations.Add(house);
}
break;
}
case DesignInsertResult.InvalidItem:
{
LogFailure("That cannot be inserted.");
break;
}
case DesignInsertResult.NotInHouse:
case DesignInsertResult.OutsideHouseBounds:
{
LogFailure("That item is not inside a customizable house.");
break;
}
}
}
foreach (var house in foundations)
{
house.Delta(ItemDelta.Update);
}
}
else
{
AddResponse("Command aborted.");
}
Flush(from, flushToLog);
}
private class DesignInsertTarget : Target
{
private readonly List<HouseFoundation> m_Foundations;
private readonly bool m_StaticsOnly;
public DesignInsertTarget(List<HouseFoundation> foundations, bool staticsOnly)
: base(-1, false, TargetFlags.None)
{
m_Foundations = foundations;
m_StaticsOnly = staticsOnly;
}
protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType)
{
if (m_Foundations.Count != 0)
{
from.SendMessage("Your changes have been committed. Updating...");
foreach (var house in m_Foundations)
{
house.Delta(ItemDelta.Update);
}
}
}
protected override void OnTarget(Mobile from, object obj)
{
var result = ProcessInsert(obj as Item, m_StaticsOnly, out var house);
switch (result)
{
case DesignInsertResult.Valid:
{
if (m_Foundations.Count == 0)
{
from.SendMessage(
"The item has been inserted into the house design. Press ESC when you are finished."
);
}
else
{
from.SendMessage("The item has been inserted into the house design.");
}
if (!m_Foundations.Contains(house))
{
m_Foundations.Add(house);
}
break;
}
case DesignInsertResult.InvalidItem:
{
from.SendMessage("That cannot be inserted. Try again.");
break;
}
case DesignInsertResult.NotInHouse:
case DesignInsertResult.OutsideHouseBounds:
{
from.SendMessage("That item is not inside a customizable house. Try again.");
break;
}
}
from.Target = new DesignInsertTarget(m_Foundations, m_StaticsOnly);
}
}
}
}