#W# Citizens: Added more monster types and more custom dialog.

This commit is contained in:
WarrentyExpired 2026-11-02 11:23:21 -05:00
parent 75243a4f13
commit 488fa12039
9 changed files with 155 additions and 72 deletions

View file

@ -606,5 +606,11 @@
"Naranoth", "Lauralare", "Olthonis", "Roth", "Camalanth", "Spath", "Halzanth", "Hrontr", "Takhansa",
"Santega", "Lant", "Weth"
]
},
{
"type": "ghost",
"names": [
"Omen", "the Lost", "Aldous", "Alistair", "Eleanor", "Gideon", "the Pale"
]
}
]

View file

@ -1,3 +1,4 @@
#MirePort
2 3025 358 1241 -1 Mireport Architect
2 2981 350 1276 0 Mireport Tailors
2 2983 353 1286 0 Mireport Tinkers
@ -16,3 +17,10 @@
2 2997 425 1336 0 Mireport Shipwrights
2 2994 415 1341 0 Mireport Mapmakers
2 3059 412 1350 1 Mireport Fishermen
#Stonehllow
2 2996 758 1212 -5 Stonehollow Inn and Tavern
2 2986 821 1228 -4 Stonehollow Blacksmith
2 3007 733 1248 -4 Stonehollow Weaponsmith
2 3054 805 1262 -4 Stonehollow Miners House
2 2987 745 1289 -4 Stonehollow Healers
2 3024 800 1300 -4 Stonehollow House

View file

@ -25,7 +25,7 @@ Dungeon Bosses
- Duneon Arenas Region
Skills
Signs
PortalSpawners
- Need to spawn (regon spawner?)
- Need to add more mobs.

View file

@ -59,7 +59,7 @@ namespace Server.Custom.CitizenSpawns
}
}
private static readonly Type[] Citizens = new Type[] { typeof(Citizen) };
private static readonly Type[] Citizens = new Type[] { typeof(Citizen), typeof(MonsterCitizen) };
public static Terrain GetTerrain(Map map, Point3D location, int x, int y)
{

View file

@ -1,65 +0,0 @@
using System;
using Server;
using Server.Mobiles;
using ModernUO.Serialization;
namespace Server.Mobiles
{
[SerializationGenerator(0, false)]
public partial class FriendlyTownMonster : BaseCreature
{
private DateTime _NextChatter;
public override bool InitialInnocent => true;
[Constructible]
public FriendlyTownMonster() : base(AIType.AI_Animal, FightMode.None)
{
Name = NameList.RandomName("orc");
Title = "the civilized";
Body = Utility.RandomList(17, 1075, 1072);
BaseSoundID = 0x45A;
Karma = 1000;
Fame = 1000;
_NextChatter = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(10, 20));
}
public override void OnThink()
{
base.OnThink();
if (Deleted) return;
if (DateTime.UtcNow > _NextChatter)
{
bool playerNearby = false;
foreach (Mobile m in GetMobilesInRange(8))
{
if (m != null && m.Player && m.Alive)
{
playerNearby = true;
break;
}
}
if (playerNearby)
{
string[] lines = {
"*grunts amicably*",
"Me like town. No heroes trying to stab me.",
"Guards no chase me here.",
"You have shiny coins for trading?"
};
Say(lines[Utility.Random(lines.Length)]);
}
_NextChatter = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(30, 60));
}
}
public override bool IsHarmfulCriminal(Mobile target) => true;
public FriendlyTownMonster(Serial serial) : base(serial)
{
}
}
}

View file

@ -3,7 +3,7 @@ using Server;
namespace Server.Mobiles
{
public class GatheringMonster : FriendlyTownMonster
public class GatheringMonster : MonsterCitizen
{
private Direction _GatherDirection;

View file

@ -0,0 +1,122 @@
using System;
using Server;
using Server.Mobiles;
using ModernUO.Serialization;
namespace Server.Mobiles
{
[SerializationGenerator(0, false)]
public partial class MonsterCitizen : BaseCreature
{
private DateTime _NextChatter;
public override bool InitialInnocent => true;
private static readonly (int Body, string NameList, int SoundID)[] MonsterProfiles =
{
(17, "orc", 0x45A), // Orc
(1077, "ratman", 437), // Ratman
(35, "lizardman", 417), // Lizardman 1
(36, "lizardman", 417), // Lizardman 2
(4, "gargoyle vendor", 372), // Gargoyle
(7, "orc", 0x45A), // Orc Captain
(26, "ghost", 0x482) // Civilized Shade
};
[Constructible]
public MonsterCitizen() : base(AIType.AI_Animal, FightMode.None)
{
Title = "the civilized";
var profile = MonsterProfiles[Utility.Random(MonsterProfiles.Length)];
Body = profile.Body;
Name = NameList.RandomName(profile.NameList);
BaseSoundID = profile.SoundID;
Karma = 1000;
Fame = 1000;
_NextChatter = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(10, 20));
}
public override void OnThink()
{
base.OnThink();
if (Deleted) return;
if (DateTime.UtcNow > _NextChatter)
{
bool playerNearby = false;
foreach (Mobile m in GetMobilesInRange(8))
{
if (m != null && m.Player && m.Alive)
{
playerNearby = true;
break;
}
}
if (playerNearby)
{
// Fetch the correct lines based on their current body type
string[] lines = GetChatterLines();
Say(lines[Utility.Random(lines.Length)]);
}
_NextChatter = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(30, 60));
}
}
// --- NEW: Helper method to organize dialogue by body ID ---
private string[] GetChatterLines()
{
switch ((int)Body)
{
case 17: // Orc
case 7: // Orc Captain
return new string[] {
"*grunts amicably*",
"Me like town. No heroes trying to stab me.",
"Guards no chase me here.",
"You have shiny coins for trading?"
};
case 1077: // Ratman
return new string[] {
"*sniffs the air*",
"Squeak! The cheese here is much better.",
"Shiny things... you have shiny things?",
"No traps in this town, yes-yes."
};
case 35: // Lizardman 1
case 36: // Lizardman 2
return new string[] {
"*hisses softly*",
"Sun feels warm on scales here.",
"Swamp is cold. Town is good.",
"Sssstay a while."
};
case 4: // Gargoyle
return new string[] {
"To seek knowledge is the path of wisdom.",
"The humans here are... tolerable.",
"Order must be maintained.",
"Do you require my assistance?"
};
case 26: // Ghost
return new string[] {
"*wails softly*",
"So cold... but peaceful.",
"Do you remember the old days?",
"I just watch the living scurry about."
};
default:
return new string[] {
"Lovely weather we're having today.",
"Just another quiet day in town."
};
}
}
public override bool IsHarmfulCriminal(Mobile target) => true;
public MonsterCitizen(Serial serial) : base(serial)
{
}
}
}

View file

@ -50,10 +50,10 @@ namespace Server.Items
}
_Attendees.Clear();
Mobile east = new GatheringCitizen();
Mobile south = new GatheringCitizen();
Mobile west = new GatheringMonster();
Mobile north = new GatheringMonster();
Mobile east = RandomAttendee();
Mobile south = RandomAttendee();
Mobile west = RandomAttendee();
Mobile north = RandomAttendee();
PlaceAndFace(east, Location.X + 3, Location.Y, Location.Z, Direction.West);
PlaceAndFace(west, Location.X - 3, Location.Y, Location.Z, Direction.East);
@ -61,6 +61,18 @@ namespace Server.Items
PlaceAndFace(north, Location.X, Location.Y - 3, Location.Z, Direction.South);
}
private Mobile RandomAttendee()
{
if (Utility.RandomBool())
{
return new GatheringCitizen();
}
else
{
return new GatheringMonster();
}
}
private void PlaceAndFace(Mobile m, int x, int y, int z, Direction facing)
{
m.MoveToWorld(new Point3D(x, y, z), Map);