Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions src/ZoneServer/Commands/ChatCommands.Handlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
using Yggdrasil.Network.Communication;
using Yggdrasil.Util;
using Yggdrasil.Util.Commands;
using Melia.Zone.World.Maps;
using Melia.Zone.World.Spawning;

namespace Melia.Zone.Commands
{
Expand Down Expand Up @@ -72,6 +74,7 @@ public ChatCommands()
this.Add("iteminfo", "<name>", "Displays information about an item.", this.HandleItemInfo);
this.Add("monsterinfo", "<name>", "Displays information about a monster.", this.HandleMonsterInfo);
this.Add("whodrops", "<name>", "Finds monsters that drop a given item", this.HandleWhoDrops);
this.Add("whereis", "<name>", "Finds the maps where a monster spawns.", this.HandleWhereIs);
this.Add("go", "<destination>", "Warps to certain pre-defined destinations.", this.HandleGo);
this.Add("goto", "<team name>", "Warps to another character.", this.HandleGoTo);
this.Add("recall", "<team name>", "Warps another character back.", this.HandleRecall);
Expand Down Expand Up @@ -1127,6 +1130,106 @@ private CommandResult HandleWhoDrops(Character sender, Character target, string
return CommandResult.Okay;
}


/// <summary>
/// Finds the maps where a monster respawns
/// </summary>
/// <param name="sender"></param>
/// <param name="target"></param>
/// <param name="message"></param>
/// <param name="command"></param>
/// <param name="args"></param>
/// <returns></returns>
private CommandResult HandleWhereIs(Character sender, Character target, string message, string commandName, Arguments args)
{
if (args.Count == 0)
return CommandResult.InvalidArgument;

var search = string.Join(" ", args.GetAll()).ToLower();

// Find the monster data that matches the search term
var monsters = ZoneServer.Instance.Data.MonsterDb.FindAllPreferExact(search);
if (monsters.Count == 0)
{
sender.ServerMessage(Localization.Get("No monsters found for '{0}'."), search);
return CommandResult.Okay;
}

// Get all spawners in the world
var spawners = ZoneServer.Instance.World.GetSpawners()
.OfType<MonsterSpawner>();

var results = new List<(MonsterData Monster, Map Map, MonsterSpawner Spawner)>();

foreach (var monster in monsters)
{
// Find all spawners that spawn this monster
foreach (var spawner in spawners)
{
if (spawner is MonsterSpawner monsterSpawner)
{
// Skip if this spawner doesn't spawn our monster
if (!ZoneServer.Instance.Data.MonsterDb.TryFind(monsterSpawner.MonsterData.Id, out var spawnerMonster) ||
spawnerMonster.Id != monster.Id)
continue;

// Get the map from the spawn areas
if (!ZoneServer.Instance.World.TryGetSpawnAreas(spawner.SpawnPointsIdent, out var spawnAreas))
continue;

foreach (var area in spawnAreas.GetAll())
{
if (!ZoneServer.Instance.World.TryGetMap(area.Map.Id, out var map))
continue;

results.Add((monster, map, monsterSpawner));
}
}
}
}

if (results.Count == 0)
{
sender.ServerMessage(Localization.Get("No spawn locations found for '{0}'."), search);
return CommandResult.Okay;
}

// Order results by map name
results = results.OrderBy(x => x.Map.ClassName).ToList();

// Display results
foreach (var result in results)
{
var spawner = result.Spawner;
var respawnInfo = "";

// Add respawn time info if it exists
if (spawner.MinRespawnDelay != TimeSpan.Zero || spawner.MaxRespawnDelay != TimeSpan.Zero)
{
if (spawner.MinRespawnDelay == spawner.MaxRespawnDelay)
respawnInfo = $" [Delay: {spawner.MinRespawnDelay.TotalSeconds:0}s]";
else
respawnInfo = $" [Delay: {spawner.MinRespawnDelay.TotalSeconds:0}s~{spawner.MaxRespawnDelay.TotalSeconds:0}s]";
}

var response = string.Format(
"{0} ({1}) - {2} ({3}) - Quantity: {4}~{5}{6}",
result.Monster.Name,
result.Monster.ClassName,
result.Map?.Data?.Name ?? "Unknown",
result.Map.ClassName,
spawner.MinAmount,
spawner.MaxAmount,
respawnInfo
);

sender.ServerMessage(response);
}

return CommandResult.Okay;
}


/// <summary>
/// Warps target to a pre-defined location.
/// </summary>
Expand Down
5 changes: 5 additions & 0 deletions src/ZoneServer/World/Spawning/MonsterSpawner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ public class MonsterSpawner : IUpdateable
/// </summary>
public int FlexAmount { get; private set; }

/// <summary>
/// Returns the monster data currently being used for this spawner.
/// </summary>
public MonsterData MonsterData { get { return _monsterData; } }

/// <summary>
/// Returns the amount of monsters currently spawned.
/// </summary>
Expand Down
3 changes: 3 additions & 0 deletions system/conf/commands.conf
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ monsterinfo : 50,-1
// Searches for monsters that drop a given item
whodrops : 50,-1

// Searches for spawns of monsters in any maps
whereis: 50,-1

// Warps player to pre-defined destinations
go : 50,50

Expand Down