ModernUO/Scripts/Items/Special/Solen Items/BallOfSummoning.cs
2018-09-14 12:56:58 -07:00

461 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using Server.Mobiles;
using Server.Targeting;
using Server.ContextMenus;
using Server.Network;
using Server.Regions;
using Server.Spells;
using Server.Spells.Ninjitsu;
namespace Server.Items
{
public class BallOfSummoning : Item, TranslocationItem
{
private int m_Charges;
private int m_Recharges;
private BaseCreature m_Pet;
private string m_PetName;
[CommandProperty( AccessLevel.GameMaster )]
public int Charges
{
get => m_Charges;
set
{
if ( value > MaxCharges )
m_Charges = MaxCharges;
else if ( value < 0 )
m_Charges = 0;
else
m_Charges = value;
InvalidateProperties();
}
}
[CommandProperty( AccessLevel.GameMaster )]
public int Recharges
{
get => m_Recharges;
set
{
if ( value > MaxRecharges )
m_Recharges = MaxRecharges;
else if ( value < 0 )
m_Recharges = 0;
else
m_Recharges = value;
InvalidateProperties();
}
}
[CommandProperty( AccessLevel.GameMaster )]
public int MaxCharges => 20;
[CommandProperty( AccessLevel.GameMaster )]
public int MaxRecharges => 255;
public string TranslocationItemName => "crystal ball of pet summoning";
[CommandProperty( AccessLevel.GameMaster )]
public BaseCreature Pet
{
get
{
if ( m_Pet != null && m_Pet.Deleted )
{
m_Pet = null;
InternalUpdatePetName();
}
return m_Pet;
}
set
{
m_Pet = value;
InternalUpdatePetName();
}
}
[CommandProperty( AccessLevel.GameMaster )]
public string PetName => m_PetName;
[Constructible]
public BallOfSummoning() : base( 0xE2E )
{
Weight = 10.0;
Light = LightType.Circle150;
m_Charges = Utility.RandomMinMax( 3, 9 );
m_PetName = "";
}
public override void AddNameProperty( ObjectPropertyList list )
{
list.Add( 1054131, m_Charges.ToString() + ( m_PetName.Length == 0 ? "\t " : "\t" + m_PetName ) ); // a crystal ball of pet summoning: [charges: ~1_charges~] : [linked pet: ~2_petName~]
}
public override void OnSingleClick( Mobile from )
{
LabelTo( from, 1054131, m_Charges.ToString() + ( m_PetName.Length == 0 ? "\t " : "\t" + m_PetName ) ); // a crystal ball of pet summoning: [charges: ~1_charges~] : [linked pet: ~2_petName~]
}
private delegate void BallCallback( Mobile from );
public override void GetContextMenuEntries( Mobile from, List<ContextMenuEntry> list )
{
base.GetContextMenuEntries( from, list );
if ( from.Alive && RootParent == from )
{
if ( Pet == null )
{
list.Add( new BallEntry( new BallCallback( LinkPet ), 6180 ) );
}
else
{
list.Add(new BallEntry(new BallCallback( CastSummonPet ), 6181 ));
list.Add( new BallEntry( new BallCallback( UpdatePetName ), 6183 ) );
list.Add( new BallEntry( new BallCallback( UnlinkPet ), 6182 ) );
}
}
}
private class BallEntry : ContextMenuEntry
{
private BallCallback m_Callback;
public BallEntry( BallCallback callback, int number ) : base( number, 2 )
{
m_Callback = callback;
}
public override void OnClick()
{
Mobile from = Owner.From;
if ( from.CheckAlive() )
m_Callback( from );
}
}
public override void OnDoubleClick( Mobile from )
{
if ( RootParent != from ) // TODO: Previous implementation allowed use on ground, without house protection checks. What is the correct behavior?
{
from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1042001 ); // That must be in your pack for you to use it.
return;
}
AnimalFormContext animalContext = AnimalForm.GetContext( from );
if ( Core.ML && animalContext != null )
{
from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1080073 ); // You cannot use a Crystal Ball of Pet Summoning while in animal form.
return;
}
if ( Pet == null )
{
LinkPet( from );
}
else
{
CastSummonPet( from );
}
}
public void LinkPet( Mobile from )
{
BaseCreature pet = Pet;
if ( Deleted || pet != null || RootParent != from )
return;
from.SendLocalizedMessage( 1054114 ); // Target your pet that you wish to link to this Crystal Ball of Pet Summoning.
from.Target = new PetLinkTarget( this );
}
private class PetLinkTarget : Target
{
private BallOfSummoning m_Ball;
public PetLinkTarget( BallOfSummoning ball ) : base( -1, false, TargetFlags.None )
{
m_Ball = ball;
}
protected override void OnTarget( Mobile from, object targeted )
{
if ( m_Ball.Deleted || m_Ball.Pet != null )
return;
if ( m_Ball.RootParent != from )
{
from.LocalOverheadMessage( MessageType.Regular, 0x3B2, 1042001 ); // That must be in your pack for you to use it.
}
else if ( targeted is BaseCreature creature )
{
if ( !creature.Controlled || creature.ControlMaster != from )
{
MessageHelper.SendLocalizedMessageTo( m_Ball, from, 1054117, 0x59 ); // You may only link your own pets to a Crystal Ball of Pet Summoning.
}
else if ( !creature.IsBonded )
{
MessageHelper.SendLocalizedMessageTo( m_Ball, from, 1054118, 0x59 ); // You must bond with your pet before it can be linked to a Crystal Ball of Pet Summoning.
}
else
{
MessageHelper.SendLocalizedMessageTo( m_Ball, from, 1054119, 0x59 ); // Your pet is now linked to this Crystal Ball of Pet Summoning.
m_Ball.Pet = creature;
}
}
else if ( targeted == m_Ball )
{
MessageHelper.SendLocalizedMessageTo( m_Ball, from, 1054115, 0x59 ); // The Crystal Ball of Pet Summoning cannot summon itself.
}
else
{
MessageHelper.SendLocalizedMessageTo( m_Ball, from, 1054116, 0x59 ); // Only pets can be linked to this Crystal Ball of Pet Summoning.
}
}
}
public void CastSummonPet( Mobile from )
{
BaseCreature pet = Pet;
if ( Deleted || pet == null || RootParent != from )
return;
if ( Charges == 0 )
{
SendLocalizedMessageTo( from, 1054122 ); // The Crystal Ball darkens. It must be charged before it can be used again.
}
else if ( pet is BaseMount mount && mount.Rider == from )
{
MessageHelper.SendLocalizedMessageTo( this, from, 1054124, 0x36 ); // The Crystal Ball fills with a yellow mist. Why would you summon your pet while riding it?
}
else if ( pet.Map == Map.Internal && ( !pet.IsStabled || (from.Followers + pet.ControlSlots) > from.FollowersMax ) )
{
MessageHelper.SendLocalizedMessageTo( this, from, 1054125, 0x5 ); // The Crystal Ball fills with a blue mist. Your pet is not responding to the summons.
}
else if ( ( !pet.Controlled || pet.ControlMaster != from ) && !from.Stabled.Contains( pet ) )
{
MessageHelper.SendLocalizedMessageTo( this, from, 1054126, 0x8FD ); // The Crystal Ball fills with a grey mist. You are not the owner of the pet you are attempting to summon.
}
else if ( !pet.IsBonded )
{
MessageHelper.SendLocalizedMessageTo( this, from, 1054127, 0x22 ); // The Crystal Ball fills with a red mist. You appear to have let your bond to your pet deteriorate.
}
else if ( from.Map == Map.Ilshenar || from.Region.IsPartOf( typeof( DungeonRegion ) ) || from.Region.IsPartOf( typeof( Jail ) ) || from.Region.IsPartOf( typeof( Engines.ConPVP.SafeZone ) ) )
{
from.Send( new AsciiMessage( Serial, ItemID, MessageType.Regular, 0x22, 3, "", "You cannot summon your pet to this location." ) );
}
else if ( Core.ML && from is PlayerMobile mobile && DateTime.UtcNow < mobile.LastPetBallTime.AddSeconds( 15.0 ) )
{
MessageHelper.SendLocalizedMessageTo( this, mobile, 1080072, 0x22 ); // You must wait a few seconds before you can summon your pet.
}
else
{
if ( Core.ML )
new PetSummoningSpell( this, from ).Cast();
else
SummonPet( from );
}
}
public void SummonPet( Mobile from )
{
BaseCreature pet = Pet;
if ( pet == null )
return;
Charges--;
if ( pet.IsStabled )
{
pet.SetControlMaster( from );
if ( pet.Summoned )
pet.SummonMaster = from;
pet.ControlTarget = from;
pet.ControlOrder = OrderType.Follow;
pet.IsStabled = false;
pet.StabledBy = null;
from.Stabled.Remove( pet );
if ( from is PlayerMobile mobile )
mobile.AutoStabled.Remove( pet );
}
pet.MoveToWorld( from.Location, from.Map );
MessageHelper.SendLocalizedMessageTo( this, from, 1054128, 0x43 ); // The Crystal Ball fills with a green mist. Your pet has been summoned.
if ( from is PlayerMobile playerMobile )
{
playerMobile.LastPetBallTime = DateTime.UtcNow;
}
}
public void UnlinkPet( Mobile from )
{
if ( !Deleted && Pet != null && RootParent == from )
{
Pet = null;
SendLocalizedMessageTo( from, 1054120 ); // This crystal ball is no longer linked to a pet.
}
}
public void UpdatePetName( Mobile from )
{
InternalUpdatePetName();
}
private void InternalUpdatePetName()
{
BaseCreature pet = Pet;
if ( pet == null )
m_PetName = "";
else
m_PetName = pet.Name;
InvalidateProperties();
}
public BallOfSummoning( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.WriteEncodedInt( (int) 1 ); // version
writer.WriteEncodedInt( (int) m_Recharges );
writer.WriteEncodedInt( (int) m_Charges );
writer.Write( (Mobile) Pet );
writer.Write( (string) m_PetName );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadEncodedInt();
switch ( version )
{
case 1:
{
m_Recharges = reader.ReadEncodedInt();
goto case 0;
}
case 0:
{
m_Charges = Math.Min( reader.ReadEncodedInt(), MaxCharges );
Pet = (BaseCreature) reader.ReadMobile();
m_PetName = reader.ReadString();
break;
}
}
}
private class PetSummoningSpell : Spell
{
private static SpellInfo m_Info = new SpellInfo( "Ball Of Summoning", "", 230 );
private BallOfSummoning m_Ball;
private Mobile m_Caster;
public PetSummoningSpell( BallOfSummoning ball, Mobile caster )
: base( caster, null, m_Info )
{
m_Caster = caster;
m_Ball = ball;
}
public override bool ClearHandsOnCast => false;
public override bool RevealOnCast => true;
public override TimeSpan GetCastRecovery()
{
return TimeSpan.Zero;
}
public override double CastDelayFastScalar => 0;
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 2.0 );
public override int GetMana()
{
return 0;
}
public override bool ConsumeReagents()
{
return true;
}
public override bool CheckFizzle()
{
return true;
}
private bool m_Stop;
public void Stop()
{
m_Stop = true;
Disturb( DisturbType.Hurt, false, false );
}
public override bool CheckDisturb( DisturbType type, bool checkFirst, bool resistable )
{
if ( type == DisturbType.EquipRequest || type == DisturbType.UseRequest/* || type == DisturbType.Hurt*/ )
return false;
return true;
}
public override void DoHurtFizzle()
{
if ( !m_Stop )
base.DoHurtFizzle();
}
public override void DoFizzle()
{
if ( !m_Stop )
base.DoFizzle();
}
public override void OnDisturb( DisturbType type, bool message )
{
if ( message && !m_Stop )
Caster.SendLocalizedMessage( 1080074 ); // You have been disrupted while attempting to summon your pet!
}
public override void OnCast()
{
m_Ball.SummonPet( m_Caster );
FinishSequence();
}
}
}
}