From f2894f2f7044582eb7becca4d5f4f2d0a39a4572 Mon Sep 17 00:00:00 2001 From: WarrentyExpired Date: Thu, 23 Jul 2026 11:54:29 -0400 Subject: [PATCH] #W# Creating rewards for quests. --- .../Items/Skill Items/Magical/PotionKeg.cs | 7 +- Scripts/Quests/Rewards/BottomlessPotionKeg.cs | 47 ++++++++ Scripts/Quests/Rewards/ClothingDye.cs | 104 +++++++++++++++++ Scripts/Quests/Rewards/HairDye.cs | 75 +++++++++++++ Scripts/Quests/Rewards/ScavagerCoin.cs | 105 ++++++++++++++++++ 5 files changed, 335 insertions(+), 3 deletions(-) create mode 100644 Scripts/Quests/Rewards/BottomlessPotionKeg.cs create mode 100644 Scripts/Quests/Rewards/ClothingDye.cs create mode 100644 Scripts/Quests/Rewards/HairDye.cs create mode 100644 Scripts/Quests/Rewards/ScavagerCoin.cs diff --git a/Scripts/Items/Skill Items/Magical/PotionKeg.cs b/Scripts/Items/Skill Items/Magical/PotionKeg.cs index 1f2bdba..df9f4e9 100644 --- a/Scripts/Items/Skill Items/Magical/PotionKeg.cs +++ b/Scripts/Items/Skill Items/Magical/PotionKeg.cs @@ -8,6 +8,7 @@ namespace Server.Items { private PotionEffect m_Type; private int m_Held; + public virtual int MaxCapacity { get { return 100; } } [CommandProperty( AccessLevel.GameMaster )] public int Held @@ -161,7 +162,7 @@ namespace Server.Items number = 502255; // The keg is about three quarters full. else if ( m_Held < 96 ) number = 502256; // The keg is very full. - else if ( m_Held < 100 ) + else if ( m_Held < MaxCapacity ) number = 502257; // The liquid is almost to the top of the keg. else number = 502258; // The keg is completely full. @@ -218,7 +219,7 @@ namespace Server.Items if ( item is BasePotion ) { BasePotion pot = (BasePotion)item; - int toHold = Math.Min( 100 - m_Held, pot.Amount ); + int toHold = Math.Min( MaxCapacity - m_Held, pot.Amount ); if ( toHold <= 0 ) @@ -341,4 +342,4 @@ namespace Server.Items TileData.ItemTable[0x1940].Height = 4; } } -} \ No newline at end of file +} diff --git a/Scripts/Quests/Rewards/BottomlessPotionKeg.cs b/Scripts/Quests/Rewards/BottomlessPotionKeg.cs new file mode 100644 index 0000000..5d19209 --- /dev/null +++ b/Scripts/Quests/Rewards/BottomlessPotionKeg.cs @@ -0,0 +1,47 @@ +using System; +using Server; +using Server.Items; + +namespace Server.Items +{ + public class BottomlessPotionKeg : PotionKeg + { + public override int MaxCapacity { get { return 500; } } + + [Constructable] + public BottomlessPotionKeg() : base() + { + Hue = 1161; // Glowing Blaze hue + } + + public override void GetProperties( ObjectPropertyList list ) + { + base.GetProperties( list ); + + list.Add( 1049644, "Bottomless (500 Max)" ); // Displays as: [ Bottomless (500 Max) ] + } + + public override void OnSingleClick( Mobile from ) + { + base.OnSingleClick( from ); + + this.LabelTo( from, "[Bottomless (500 Max)]" ); + } + + public BottomlessPotionKeg( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + } + } +} diff --git a/Scripts/Quests/Rewards/ClothingDye.cs b/Scripts/Quests/Rewards/ClothingDye.cs new file mode 100644 index 0000000..0dcda59 --- /dev/null +++ b/Scripts/Quests/Rewards/ClothingDye.cs @@ -0,0 +1,104 @@ +using System; +using Server; +using Server.Targeting; + +namespace Server.Items +{ + public class RareClothingDye : Item + { + private int m_DyeHue; + + [CommandProperty( AccessLevel.GameMaster )] + public int DyeHue + { + get { return m_DyeHue; } + set { m_DyeHue = value; InvalidateProperties(); } + } + + [Constructable] + public RareClothingDye() : this( Utility.RandomList( 1, 1150, 1154, 1157, 1161, 1166, 1175, 1254 ) ) + { + } + + [Constructable] + public RareClothingDye( int hue ) : base( 0xE27 ) // Round bottle graphic + { + Weight = 1.0; + m_DyeHue = hue; + Hue = m_DyeHue; + Name = "a vial of rare clothing dye"; + } + + public override void OnDoubleClick( Mobile from ) + { + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); + return; + } + + from.SendMessage( "Target the piece of clothing you wish to magically dye." ); + from.Target = new InternalTarget( this ); + } + + private class InternalTarget : Target + { + private RareClothingDye m_Dye; + + public InternalTarget( RareClothingDye dye ) : base( 1, false, TargetFlags.None ) + { + m_Dye = dye; + } + + protected override void OnTarget( Mobile from, object targeted ) + { + if ( m_Dye.Deleted ) return; + + if ( !m_Dye.IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); + return; + } + + if ( targeted is BaseClothing ) + { + BaseClothing clothing = (BaseClothing)targeted; + + // Ensure the player actually owns the item they are trying to dye + if ( !clothing.IsChildOf( from.Backpack ) && clothing.Parent != from ) + { + from.SendMessage( 33, "You must be holding or wearing that item to dye it." ); + return; + } + + clothing.Hue = m_Dye.DyeHue; + from.PlaySound( 0x23E ); + from.SendMessage( 63, "The magical dye seeps into the fabric, altering its color completely." ); + m_Dye.Delete(); + } + else + { + from.SendMessage( 33, "This magical dye will only adhere to fabrics and clothing." ); + } + } + } + + public RareClothingDye( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + writer.Write( (int) m_DyeHue ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_DyeHue = reader.ReadInt(); + } + } +} diff --git a/Scripts/Quests/Rewards/HairDye.cs b/Scripts/Quests/Rewards/HairDye.cs new file mode 100644 index 0000000..2cdb45d --- /dev/null +++ b/Scripts/Quests/Rewards/HairDye.cs @@ -0,0 +1,75 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class RareHairDye : Item + { + private int m_DyeHue; + + [CommandProperty( AccessLevel.GameMaster )] + public int DyeHue + { + get { return m_DyeHue; } + set { m_DyeHue = value; InvalidateProperties(); } + } + + [Constructable] + public RareHairDye() : this( Utility.RandomList( 1, 1150, 1154, 1157, 1161, 1166, 1175, 1254 ) ) + { + } + + [Constructable] + public RareHairDye( int hue ) : base( 0xE26 ) // Clear bottle graphic + { + Weight = 1.0; + m_DyeHue = hue; + Hue = m_DyeHue; // The bottle itself will display the rare color! + Name = "a vial of rare hair dye"; + } + + 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; + } + + if ( from.HairItemID == 0 && from.FacialHairItemID == 0 ) + { + from.SendMessage( 33, "You have no hair to dye!" ); + return; + } + + if ( from.HairItemID != 0 ) + from.HairHue = m_DyeHue; + + if ( from.FacialHairItemID != 0 ) + from.FacialHairHue = m_DyeHue; + + from.PlaySound( 0x246 ); // Magical splash sound + from.SendMessage( 63, "You wash your hair with the rare dye, permanently changing its color!" ); + this.Delete(); + } + + public RareHairDye( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + writer.Write( (int) m_DyeHue ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_DyeHue = reader.ReadInt(); + } + } +} diff --git a/Scripts/Quests/Rewards/ScavagerCoin.cs b/Scripts/Quests/Rewards/ScavagerCoin.cs new file mode 100644 index 0000000..82f55dd --- /dev/null +++ b/Scripts/Quests/Rewards/ScavagerCoin.cs @@ -0,0 +1,105 @@ +using System; +using Server; +using Server.Mobiles; + +namespace Server.Items +{ + public class ScavengersCoin : Item + { + private DateTime m_NextUse; + + [CommandProperty( AccessLevel.GameMaster )] + public DateTime NextUse + { + get { return m_NextUse; } + set { m_NextUse = value; } + } + + [Constructable] + public ScavengersCoin() : base( 0x1096 ) + { + Name = "Scavenger's Coin"; + Weight = 1.0; + Hue = 1175; // A shadowy charcoal hue to fit the stealth theme + } + + public override void OnDoubleClick( Mobile from ) + { + // 1. Must be in their backpack + if ( !IsChildOf( from.Backpack ) ) + { + from.SendLocalizedMessage( 1042001 ); // "That must be in your pack for you to use it." + return; + } + + if ( DateTime.UtcNow < m_NextUse ) + { + TimeSpan wait = m_NextUse - DateTime.UtcNow; + from.SendMessage( 33, String.Format( "You must wait {0} minutes and {1} seconds before using this again.", wait.Minutes, wait.Seconds ) ); + return; + } + SkillMod hideMod = new DefaultSkillMod( SkillName.Hiding, true, 100.0 ); + SkillMod stealthMod = new DefaultSkillMod( SkillName.Stealth, true, 100.0 ); + from.Hidden = true; + from.UseSkill( SkillName.Stealth ); + from.AddSkillMod( hideMod ); + from.AddSkillMod( stealthMod ); + m_NextUse = DateTime.UtcNow + TimeSpan.FromMinutes( 5 ); + + from.PlaySound( 0x3CA ); + from.FixedParticles( 0x376A, 9, 32, 5005, EffectLayer.Waist ); + from.SendMessage( 63, "You flip the coin and are enveloped in unnatural shadows for 60 seconds." ); + + new ScavengerTimer( from, hideMod, stealthMod ).Start(); + } + + // --- The Custom Countdown Timer --- + private class ScavengerTimer : Timer + { + private Mobile m_Mobile; + private SkillMod m_HideMod; + private SkillMod m_StealthMod; + + public ScavengerTimer( Mobile m, SkillMod hide, SkillMod stealth ) : base( TimeSpan.FromSeconds( 60 ) ) + { + m_Mobile = m; + m_HideMod = hide; + m_StealthMod = stealth; + + // Priority dictates how strictly the server keeps track of this timer on the main thread + Priority = TimerPriority.OneSecond; + } + + protected override void OnTick() + { + // When 60 seconds are up, this code fires + if ( m_Mobile != null ) + { + m_Mobile.RemoveSkillMod( m_HideMod ); + m_Mobile.RemoveSkillMod( m_StealthMod ); + m_Mobile.SendMessage( 33, "The magical shadows fade away, returning your skills to normal." ); + } + } + } + + public ScavengersCoin( Serial serial ) : base( serial ) + { + } + + public override void Serialize( GenericWriter writer ) + { + base.Serialize( writer ); + writer.Write( (int) 0 ); // version + + // We save the cooldown time so players can't just log out and back in to reset it + writer.Write( m_NextUse ); + } + + public override void Deserialize( GenericReader reader ) + { + base.Deserialize( reader ); + int version = reader.ReadInt(); + m_NextUse = reader.ReadDateTime(); + } + } +}