#W# Bosses: Working on Dungeon Bosses. Added some reward drops to increase stat/skill/totalskill cap.
This commit is contained in:
parent
00c25cd506
commit
69a2b8772b
11 changed files with 406 additions and 3 deletions
|
|
@ -23,4 +23,11 @@ CentrED Stuff
|
||||||
Dungeon Bosses
|
Dungeon Bosses
|
||||||
- Dungeon Arenas
|
- Dungeon Arenas
|
||||||
- Duneon Arenas Region
|
- Duneon Arenas Region
|
||||||
|
|
||||||
Skills
|
Skills
|
||||||
|
|
||||||
|
PortalSpawners
|
||||||
|
- Need to spawn (regon spawner?)
|
||||||
|
- Need to add more mobs.
|
||||||
|
|
||||||
|
Random Citizens
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ namespace Server.Custom.Events
|
||||||
private bool _triggered;
|
private bool _triggered;
|
||||||
|
|
||||||
[Constructible]
|
[Constructible]
|
||||||
public PortalSpawner() : base(0x0F6C)
|
public PortalSpawner() : base(0xFF93)
|
||||||
{
|
{
|
||||||
Name = "a horrific tear";
|
Name = "a horrific tear";
|
||||||
Hue = 1157;
|
Hue = 1157;
|
||||||
|
|
@ -24,6 +24,28 @@ namespace Server.Custom.Events
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _zAdjusted;
|
||||||
|
|
||||||
|
public override void OnMapChange()
|
||||||
|
{
|
||||||
|
base.OnMapChange();
|
||||||
|
|
||||||
|
// Now it checks the moment it officially enters the world
|
||||||
|
if (!_zAdjusted && Map != null && Map != Map.Internal)
|
||||||
|
{
|
||||||
|
_zAdjusted = true;
|
||||||
|
|
||||||
|
// Wait one tick for the spawner to finish snapping it to the floor
|
||||||
|
Timer.DelayCall(TimeSpan.Zero, () =>
|
||||||
|
{
|
||||||
|
if (!Deleted)
|
||||||
|
{
|
||||||
|
Z += 5; // Adjust as needed
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override bool HandlesOnMovement => true;
|
public override bool HandlesOnMovement => true;
|
||||||
|
|
||||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||||
|
|
|
||||||
59
Projects/UOContent/Items/Custom/CrystalOfFortitude.cs
Normal file
59
Projects/UOContent/Items/Custom/CrystalOfFortitude.cs
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
using System;
|
||||||
|
using Server;
|
||||||
|
using Server.Mobiles;
|
||||||
|
using ModernUO.Serialization;
|
||||||
|
|
||||||
|
namespace Server.Items
|
||||||
|
{
|
||||||
|
[SerializationGenerator(0)]
|
||||||
|
public partial class CrystalOfFortitude : Item
|
||||||
|
{
|
||||||
|
[Constructible]
|
||||||
|
public CrystalOfFortitude() : base(0x1F19) // Matching crystal graphic
|
||||||
|
{
|
||||||
|
Name = "a crystalline shard of fortitude";
|
||||||
|
Hue = 0x21; // A deep, vibrant red hue to represent physical stats
|
||||||
|
Weight = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnDoubleClick(Mobile from)
|
||||||
|
{
|
||||||
|
if (!IsChildOf(from.Backpack))
|
||||||
|
{
|
||||||
|
from.SendLocalizedMessage(1042001); // "That must be in your pack for you to use it."
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard stats are handled as simple integers (unlike skills which use tenths)
|
||||||
|
int maxCap = 250;
|
||||||
|
int capIncrease = 1;
|
||||||
|
|
||||||
|
if (from.StatCap >= maxCap)
|
||||||
|
{
|
||||||
|
from.SendMessage(38, "Your physical form cannot be pushed any further. You are already at the absolute maximum stat cap.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the permanent stat cap increase
|
||||||
|
from.StatCap += capIncrease;
|
||||||
|
|
||||||
|
// Failsafe in case a GM accidentally sets them too high
|
||||||
|
if (from.StatCap > maxCap)
|
||||||
|
{
|
||||||
|
from.StatCap = maxCap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Theatrical effects
|
||||||
|
from.SendMessage(0x21, "The crystal shatters, surging through your veins! Your total stat cap has permanently increased by 1.");
|
||||||
|
from.PlaySound(0x1F8);
|
||||||
|
from.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist);
|
||||||
|
|
||||||
|
// Destroy the item
|
||||||
|
Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CrystalOfFortitude(Serial serial) : base(serial)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
Projects/UOContent/Items/Custom/CrystalOfInsight.cs
Normal file
60
Projects/UOContent/Items/Custom/CrystalOfInsight.cs
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
using System;
|
||||||
|
using Server;
|
||||||
|
using Server.Mobiles;
|
||||||
|
using ModernUO.Serialization;
|
||||||
|
|
||||||
|
namespace Server.Items
|
||||||
|
{
|
||||||
|
[SerializationGenerator(0)]
|
||||||
|
public partial class CrystalOfInsight : Item
|
||||||
|
{
|
||||||
|
[Constructible]
|
||||||
|
public CrystalOfInsight() : base(0x1F19) // A cool crystal/gem graphic
|
||||||
|
{
|
||||||
|
Name = "a crystalline shard of insight";
|
||||||
|
Hue = 0x47E; // Matches the Diamond Core stance hue
|
||||||
|
Weight = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnDoubleClick(Mobile from)
|
||||||
|
{
|
||||||
|
// Security check: Must be in the player's main backpack to use
|
||||||
|
if (!IsChildOf(from.Backpack))
|
||||||
|
{
|
||||||
|
from.SendLocalizedMessage(1042001); // "That must be in your pack for you to use it."
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// In UO integer logic, 720.0 is 7200, and 1.0 is 10
|
||||||
|
int maxCap = 7200;
|
||||||
|
int capIncrease = 10;
|
||||||
|
|
||||||
|
if (from.SkillsCap >= maxCap)
|
||||||
|
{
|
||||||
|
from.SendMessage(38, "Your mind cannot expand any further. You are already at the absolute maximum skill cap.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the permanent increase
|
||||||
|
from.SkillsCap += capIncrease;
|
||||||
|
|
||||||
|
// Failsafe: If they somehow used a +1.0 item while at 719.5, hard-cap it at exactly 720.0
|
||||||
|
if (from.SkillsCap > maxCap)
|
||||||
|
{
|
||||||
|
from.SkillsCap = maxCap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Theatrical effects to make the reward feel powerful
|
||||||
|
from.SendMessage(0x47E, "The crystal shatters in your hands, expanding your mind! Your total skill cap has permanently increased by 1.0.");
|
||||||
|
from.PlaySound(0x1F8); // Shatter sound (same as the Titan's stance shift)
|
||||||
|
from.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist); // Sparkle effect around the player
|
||||||
|
|
||||||
|
// Destroy the item now that it has been consumed
|
||||||
|
Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CrystalOfInsight(Serial serial) : base(serial)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
100
Projects/UOContent/Items/Custom/CrystalOfKnowledge.cs
Normal file
100
Projects/UOContent/Items/Custom/CrystalOfKnowledge.cs
Normal file
|
|
@ -0,0 +1,100 @@
|
||||||
|
using System;
|
||||||
|
using Server;
|
||||||
|
using Server.Mobiles;
|
||||||
|
|
||||||
|
namespace Server.Items
|
||||||
|
{
|
||||||
|
public class CrystalOfKnowledge : Item
|
||||||
|
{
|
||||||
|
private SkillName _Skill;
|
||||||
|
|
||||||
|
[CommandProperty(AccessLevel.GameMaster)]
|
||||||
|
public SkillName Skill
|
||||||
|
{
|
||||||
|
get => _Skill;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_Skill = value;
|
||||||
|
UpdateName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Constructible]
|
||||||
|
public CrystalOfKnowledge() : this((SkillName)Utility.Random(SkillInfo.Table.Length))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Constructible]
|
||||||
|
public CrystalOfKnowledge(SkillName skill) : base(0x1F19)
|
||||||
|
{
|
||||||
|
_Skill = skill;
|
||||||
|
Hue = 0x501;
|
||||||
|
Weight = 1.0;
|
||||||
|
UpdateName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateName()
|
||||||
|
{
|
||||||
|
Name = $"a minor shard of {_Skill}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnDoubleClick(Mobile from)
|
||||||
|
{
|
||||||
|
if (!IsChildOf(from.Backpack))
|
||||||
|
{
|
||||||
|
from.SendLocalizedMessage(1042001);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Skill targetSkill = from.Skills[_Skill];
|
||||||
|
|
||||||
|
if (targetSkill == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int maxCap = 120;
|
||||||
|
int capIncrease = 1;
|
||||||
|
|
||||||
|
if (targetSkill.Cap >= maxCap)
|
||||||
|
{
|
||||||
|
from.SendMessage(38, $"Your mastery of {_Skill} is already at its absolute limit.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetSkill.Cap += capIncrease;
|
||||||
|
|
||||||
|
if (targetSkill.Cap > maxCap)
|
||||||
|
{
|
||||||
|
targetSkill.Cap = maxCap;
|
||||||
|
}
|
||||||
|
|
||||||
|
from.SendMessage(0x501, $"The shard dissolves, permanently increasing your {_Skill} cap by 1.0!");
|
||||||
|
from.PlaySound(0x243);
|
||||||
|
from.FixedParticles(0x373A, 10, 15, 5012, EffectLayer.Waist);
|
||||||
|
|
||||||
|
Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CrystalOfKnowledge(Serial serial) : base(serial)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- ModernUO Manual Serialization ---
|
||||||
|
public override void Serialize(IGenericWriter writer)
|
||||||
|
{
|
||||||
|
base.Serialize(writer);
|
||||||
|
writer.Write(0); // Version
|
||||||
|
|
||||||
|
// Save the specific skill ID to the hard drive
|
||||||
|
writer.Write((int)_Skill);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Deserialize(IGenericReader reader)
|
||||||
|
{
|
||||||
|
base.Deserialize(reader);
|
||||||
|
int version = reader.ReadInt();
|
||||||
|
|
||||||
|
// Load the specific skill ID back when the server boots
|
||||||
|
_Skill = (SkillName)reader.ReadInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ namespace Server.Custom.Dungeons
|
||||||
{
|
{
|
||||||
public override Type SummonItem => typeof(PulsingBloodClot);
|
public override Type SummonItem => typeof(PulsingBloodClot);
|
||||||
|
|
||||||
public override Type BossType => typeof(BloodstoneTitan);
|
public override Type BossType => typeof(CrystallineTitan);
|
||||||
|
|
||||||
[Constructible]
|
[Constructible]
|
||||||
public ShameAlter() : base(0xFFBD)
|
public ShameAlter() : base(0xFFBD)
|
||||||
|
|
@ -0,0 +1,153 @@
|
||||||
|
using System;
|
||||||
|
using Server;
|
||||||
|
using Server.Items;
|
||||||
|
using Server.Network;
|
||||||
|
using ModernUO.Serialization;
|
||||||
|
|
||||||
|
namespace Server.Mobiles
|
||||||
|
{
|
||||||
|
[SerializationGenerator(0, false)]
|
||||||
|
public partial class CrystallineTitan : BaseCreature
|
||||||
|
{
|
||||||
|
private DateTime _NextStanceChange;
|
||||||
|
private TitanStance _CurrentStance;
|
||||||
|
|
||||||
|
private enum TitanStance
|
||||||
|
{
|
||||||
|
Normal,
|
||||||
|
DiamondCore,
|
||||||
|
Shattered
|
||||||
|
}
|
||||||
|
|
||||||
|
[Constructible]
|
||||||
|
public CrystallineTitan() : base(AIType.AI_Melee, FightMode.Closest)
|
||||||
|
{
|
||||||
|
Name = "The Crystalline Titan";
|
||||||
|
Body = 1109;
|
||||||
|
BaseSoundID = 0x127;
|
||||||
|
|
||||||
|
SetStr(800, 1000);
|
||||||
|
SetDex(120, 150);
|
||||||
|
SetInt(100, 150);
|
||||||
|
SetHits(15000, 20000);
|
||||||
|
|
||||||
|
SetSkill(SkillName.Tactics, 100.0, 120.0);
|
||||||
|
SetSkill(SkillName.Wrestling, 100.0, 120.0);
|
||||||
|
SetSkill(SkillName.MagicResist, 120.0, 150.0);
|
||||||
|
SetSkill(SkillName.Anatomy, 100.0, 120.0);
|
||||||
|
|
||||||
|
Fame = 25000;
|
||||||
|
Karma = -25000;
|
||||||
|
VirtualArmor = 80;
|
||||||
|
|
||||||
|
// Start in the normal stance to show off the raw graphic
|
||||||
|
EnterNormal();
|
||||||
|
|
||||||
|
// Give players 30 seconds of normal combat before the first special phase triggers
|
||||||
|
_NextStanceChange = DateTime.UtcNow + TimeSpan.FromSeconds(30);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnThink()
|
||||||
|
{
|
||||||
|
base.OnThink();
|
||||||
|
|
||||||
|
if (Deleted || !Alive || Combatant == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Trigger the swap every 30 seconds while fighting
|
||||||
|
if (DateTime.UtcNow > _NextStanceChange)
|
||||||
|
{
|
||||||
|
// Reset the clock immediately so OnThink doesn't loop
|
||||||
|
_NextStanceChange = DateTime.UtcNow + TimeSpan.FromSeconds(30);
|
||||||
|
|
||||||
|
if (_CurrentStance == TitanStance.DiamondCore || _CurrentStance == TitanStance.Shattered)
|
||||||
|
{
|
||||||
|
SpeechHue = 0x3B2;
|
||||||
|
Say("*The Titan's crystals begin to stabilize...*");
|
||||||
|
|
||||||
|
// Wait 2 seconds, then execute the stat/hue change
|
||||||
|
Timer.DelayCall(TimeSpan.FromSeconds(2.0), () => { if (Alive && !Deleted) EnterNormal(); });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Utility.RandomBool())
|
||||||
|
{
|
||||||
|
SpeechHue = 0x47E;
|
||||||
|
Say("*The Titan braces itself as its shell begins to harden!*");
|
||||||
|
|
||||||
|
Timer.DelayCall(TimeSpan.FromSeconds(2.0), () => { if (Alive && !Deleted) EnterDiamondCore(); });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SpeechHue = 0x22;
|
||||||
|
Say("*The Titan's crystals throb with unstable, violent energy!*");
|
||||||
|
|
||||||
|
Timer.DelayCall(TimeSpan.FromSeconds(2.0), () => { if (Alive && !Deleted) EnterShattered(); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnterNormal()
|
||||||
|
{
|
||||||
|
_CurrentStance = TitanStance.Normal;
|
||||||
|
Hue = 0;
|
||||||
|
|
||||||
|
SetResistance(ResistanceType.Physical, 50, 60);
|
||||||
|
SetResistance(ResistanceType.Energy, 50, 60);
|
||||||
|
SetResistance(ResistanceType.Fire, 50, 60);
|
||||||
|
SetResistance(ResistanceType.Cold, 50, 60);
|
||||||
|
SetResistance(ResistanceType.Poison, 60, 70);
|
||||||
|
|
||||||
|
SetDamage(30, 45);
|
||||||
|
|
||||||
|
PlaySound(0x11F); // Deep rumble sound as the hue shifts
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnterDiamondCore()
|
||||||
|
{
|
||||||
|
_CurrentStance = TitanStance.DiamondCore;
|
||||||
|
Hue = 0x47E;
|
||||||
|
|
||||||
|
SetResistance(ResistanceType.Physical, 80, 90);
|
||||||
|
SetResistance(ResistanceType.Energy, 70, 80);
|
||||||
|
SetResistance(ResistanceType.Fire, 60, 70);
|
||||||
|
SetResistance(ResistanceType.Cold, 60, 70);
|
||||||
|
SetResistance(ResistanceType.Poison, 100, 100);
|
||||||
|
|
||||||
|
SetDamage(15, 25);
|
||||||
|
|
||||||
|
PlaySound(0x1E5); // Hardening/magic sound as the hue shifts
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnterShattered()
|
||||||
|
{
|
||||||
|
_CurrentStance = TitanStance.Shattered;
|
||||||
|
Hue = 0x86;
|
||||||
|
|
||||||
|
SetResistance(ResistanceType.Physical, 30, 40);
|
||||||
|
SetResistance(ResistanceType.Energy, 30, 40);
|
||||||
|
SetResistance(ResistanceType.Fire, 30, 40);
|
||||||
|
SetResistance(ResistanceType.Cold, 30, 40);
|
||||||
|
|
||||||
|
SetDamage(45, 65);
|
||||||
|
|
||||||
|
PlaySound(0x1F8); // Shattering explosion sound as the hue shifts
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Boss Immunities ---
|
||||||
|
public override bool AutoDispel => true;
|
||||||
|
public override bool BardImmune => true;
|
||||||
|
public override bool Uncalmable => true;
|
||||||
|
public override Poison PoisonImmune => Poison.Lethal;
|
||||||
|
|
||||||
|
public override void GenerateLoot()
|
||||||
|
{
|
||||||
|
AddLoot(LootPack.SuperBoss, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CrystallineTitan(Serial serial) : base(serial)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
Run.sh
4
Run.sh
|
|
@ -9,5 +9,7 @@ else
|
||||||
echo "________________________________"
|
echo "________________________________"
|
||||||
echo "| Starting Server...."
|
echo "| Starting Server...."
|
||||||
echo "--------------------------------"
|
echo "--------------------------------"
|
||||||
dotnet publish Projects/Application/Application.csproj -c Release -r linux-x64 --self-contained=false && dotnet ./Distribution/ModernUO.dll
|
#dotnet publish Projects/Application/Application.csproj -c Release -r linux-x64 --self-contained=false &&
|
||||||
|
#sleep 2 &&
|
||||||
|
dotnet ./Distribution/ModernUO.dll
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue