Fixes to bola: thrower+target dismount time is equal, Core.ML is 10s, 4 sec delay from throw to hit victim, dismount info moved to playermobile rather than mount, to prevent exploit.

This commit is contained in:
xavier 2013-01-12 23:56:40 +00:00
parent 48e08198fe
commit 2120f4fb5b
5 changed files with 208 additions and 176 deletions

View file

@ -1,50 +1,53 @@
using System;
using System.Collections;
using Server;
using Server.Mobiles;
using Server.Network;
using Server.Targeting;
using System;
namespace Server.Items
{
public class Bola : Item
{
[Constructable]
public Bola() : this( 1 )
public Bola()
: this( 1 )
{
}
[Constructable]
public Bola( int amount ) : base( 0x26AC )
public Bola( int amount )
: base( 0x26AC )
{
Weight = 4.0;
Stackable = true;
Amount = amount;
}
public static TimeSpan BolaRecoveryTime { get { return TimeSpan.FromSeconds( Core.ML ? 10 : 3 ); } }
public override void OnDoubleClick( Mobile from )
{
if ( !IsChildOf( from.Backpack ) )
if( !IsChildOf( from.Backpack ) )
{
from.SendLocalizedMessage( 1040019 ); // The bola must be in your pack to use it.
}
else if ( !from.CanBeginAction( typeof( Bola ) ) )
else if( !from.CanBeginAction( typeof( Bola ) ) )
{
from.SendLocalizedMessage( 1049624 ); // You have to wait a few moments before you can use another bola!
}
else if ( from.Target is BolaTarget )
else if( from.Target is BolaTarget )
{
from.SendLocalizedMessage( 1049631 ); // This bola is already being used.
}
else if ( !Core.AOS && (from.FindItemOnLayer( Layer.OneHanded ) != null || from.FindItemOnLayer( Layer.TwoHanded ) != null) )
else if( !Core.AOS && ( from.FindItemOnLayer( Layer.OneHanded ) != null || from.FindItemOnLayer( Layer.TwoHanded ) != null ) )
{
from.SendLocalizedMessage( 1040015 ); // Your hands must be free to use this
}
else if ( from.Mounted )
else if( from.Mounted )
{
from.SendLocalizedMessage( 1040016 ); // You cannot use this while riding a mount
}
else if ( Server.Spells.Ninjitsu.AnimalForm.UnderTransformation( from ) )
else if( Server.Spells.Ninjitsu.AnimalForm.UnderTransformation( from ) )
{
from.SendLocalizedMessage( 1070902 ); // You can't use this while in an animal form!
}
@ -52,14 +55,15 @@ namespace Server.Items
{
EtherealMount.StopMounting( from );
if ( Core.AOS ) {
if( Core.AOS )
{
Item one = from.FindItemOnLayer( Layer.OneHanded );
Item two = from.FindItemOnLayer( Layer.TwoHanded );
if ( one != null )
if( one != null )
from.AddToBackpack( one );
if ( two != null )
if( two != null )
from.AddToBackpack( two );
}
@ -69,105 +73,126 @@ namespace Server.Items
}
}
private static void ReleaseBolaLock( object state )
{
((Mobile)state).EndAction( typeof( Bola ) );
}
private static void FinishThrow( object state )
{
object[] states = (object[])state;
object[] states = ( object[] )state;
Mobile from = (Mobile)states[0];
Mobile to = (Mobile)states[1];
Mobile from = ( Mobile )states[ 0 ];
Mobile to = ( Mobile )states[ 1 ];
if ( Core.AOS )
Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerStateCallback( ReleaseBolaLock ), from );
if( Core.AOS )
new Bola().MoveToWorld( to.Location, to.Map );
to.Damage( 1, from );
if ( to is ChaosDragoon || to is ChaosDragoonElite )
if( to is ChaosDragoon || to is ChaosDragoonElite )
{
from.SendLocalizedMessage( 1042047 ); // You fail to knock the rider from its mount.
}
else
{
if( from.InRange( to.Location, 8 ) && ( to.Map == from.Map ) && ( to.Map != Map.Internal ) )
{
IMount mt = to.Mount;
IMount mt = to.Mount;
if ( mt != null && !( to is ChaosDragoon || to is ChaosDragoonElite ) )
mt.Rider = null;
if( mt != null )
{
mt.Rider = null;
}
to.SendLocalizedMessage( 1040023 ); // You have been knocked off of your mount!
from.Direction = from.GetDirectionTo( to );
from.Animate( 11, 5, 1, true, false, 0 );
BaseMount.SetMountPrevention( to, BlockMountType.Dazed, TimeSpan.FromSeconds( 3.0 ) );
from.MovingEffect( to, 0x26AC, 10, 0, false, false );
Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerStateCallback( ReleaseBolaLock ), from );
from.DoHarmful( to );
to.SendLocalizedMessage( 1040023 ); // You have been knocked off of your mount!
if( to is PlayerMobile )
{
( to as PlayerMobile ).AddMountBlock( BlockMountType.Dazed, BolaRecoveryTime );
}
if( from is PlayerMobile )
{
( from as PlayerMobile ).AddMountBlock( BlockMountType.BolaRecovery, BolaRecoveryTime ); // TODO validate durations
}
}
else
{
from.SendLocalizedMessage( 1042060 ); //You cannot see that target!
}
}
}
private static void ReleaseBolaLock( object state )
{
( ( Mobile )state ).EndAction( typeof( Bola ) );
}
private class BolaTarget : Target
{
private Bola m_Bola;
public BolaTarget( Bola bola ) : base( 8, false, TargetFlags.Harmful )
public BolaTarget( Bola bola )
: base( 8, false, TargetFlags.Harmful )
{
m_Bola = bola;
}
protected override void OnTarget( Mobile from, object obj )
{
if ( m_Bola.Deleted )
if( m_Bola.Deleted )
return;
if ( obj is Mobile )
if( obj is Mobile )
{
Mobile to = (Mobile)obj;
Mobile to = ( Mobile )obj;
if ( !m_Bola.IsChildOf( from.Backpack ) )
if( !m_Bola.IsChildOf( from.Backpack ) )
{
from.SendLocalizedMessage( 1040019 ); // The bola must be in your pack to use it.
}
else if ( !Core.AOS && (from.FindItemOnLayer( Layer.OneHanded ) != null || from.FindItemOnLayer( Layer.TwoHanded ) != null) )
else if( !Core.AOS && ( from.FindItemOnLayer( Layer.OneHanded ) != null || from.FindItemOnLayer( Layer.TwoHanded ) != null ) )
{
from.SendLocalizedMessage( 1040015 ); // Your hands must be free to use this
}
else if ( from.Mounted )
else if( from.Mounted )
{
from.SendLocalizedMessage( 1040016 ); // You cannot use this while riding a mount
}
else if ( Server.Spells.Ninjitsu.AnimalForm.UnderTransformation( from ) )
else if( Server.Spells.Ninjitsu.AnimalForm.UnderTransformation( from ) )
{
from.SendLocalizedMessage( 1070902 ); // You can't use this while in an animal form!
}
else if ( !to.Mounted )
else if( !to.Mounted )
{
from.SendLocalizedMessage( 1049628 ); // You have no reason to throw a bola at that.
}
else if ( !from.CanBeHarmful( to ) )
else if( !from.CanBeHarmful( to ) )
{
}
else if ( from.BeginAction( typeof( Bola ) ) )
else if( from.BeginAction( typeof( Bola ) ) )
{
EtherealMount.StopMounting( from );
if ( Core.AOS ) {
if( Core.AOS )
{
Item one = from.FindItemOnLayer( Layer.OneHanded );
Item two = from.FindItemOnLayer( Layer.TwoHanded );
if ( one != null )
if( one != null )
from.AddToBackpack( one );
if ( two != null )
if( two != null )
from.AddToBackpack( two );
}
from.DoHarmful( to );
if ( Core.AOS )
BaseMount.SetMountPrevention( from, BlockMountType.BolaRecovery, TimeSpan.FromSeconds( 3.0 ) );
m_Bola.Consume();
from.Direction = from.GetDirectionTo( to );
from.Animate( 11, 5, 1, true, false, 0 );
from.MovingEffect( to, 0x26AC, 10, 0, false, false );
Timer.DelayCall( TimeSpan.FromSeconds( 0.5 ), new TimerStateCallback( FinishThrow ), new object[]{ from, to } );
Timer.DelayCall( TimeSpan.FromSeconds( Core.ML ? 4 : .5 ), new TimerStateCallback( FinishThrow ), new object[] { from, to } );
}
else
{
@ -181,7 +206,8 @@ namespace Server.Items
}
}
public Bola( Serial serial ) : base( serial )
public Bola( Serial serial )
: base( serial )
{
}
@ -189,7 +215,7 @@ namespace Server.Items
{
base.Serialize( writer );
writer.Write( (int) 0 );
writer.Write( ( int )0 );
}
public override void Deserialize( GenericReader reader )
@ -199,4 +225,5 @@ namespace Server.Items
int version = reader.ReadInt();
}
}
}
}

View file

@ -31,8 +31,7 @@ namespace Server.Items
return true;
}
public static readonly TimeSpan DefenderRemountDelay = TimeSpan.FromSeconds( 10.0 ); // TODO: Taken from bola script, needs to be verified
public static readonly TimeSpan AttackerRemountDelay = TimeSpan.FromSeconds( 3.0 );
public static readonly TimeSpan RemountDelay = TimeSpan.FromSeconds( 10.0 );
public override void OnHit( Mobile attacker, Mobile defender, int damage )
{
@ -73,16 +72,26 @@ namespace Server.Items
defender.PlaySound( 0x140 );
defender.FixedParticles( 0x3728, 10, 15, 9955, EffectLayer.Waist );
mount.Rider = null;
BaseMount.SetMountPrevention( defender, BlockMountType.Dazed, DefenderRemountDelay );
if( Core.ML && attacker is BaseCreature && ((BaseCreature)attacker).ControlMaster != null )
if( defender is PlayerMobile )
{
BaseMount.SetMountPrevention( ((BaseCreature)attacker).ControlMaster, BlockMountType.DismountRecovery, AttackerRemountDelay );
( defender as PlayerMobile ).AddMountBlock( BlockMountType.Dazed, RemountDelay );
}
else
if( attacker is PlayerMobile )
{
BaseMount.SetMountPrevention( attacker, BlockMountType.DismountRecovery, AttackerRemountDelay );
( attacker as PlayerMobile ).AddMountBlock( BlockMountType.DismountRecovery, RemountDelay );
}
else if( Core.ML && attacker is BaseCreature )
{
BaseCreature bc = attacker as BaseCreature;
if( bc.ControlMaster is PlayerMobile )
{
PlayerMobile pm = bc.ControlMaster as PlayerMobile;
pm.AddMountBlock( BlockMountType.DismountRecovery, RemountDelay );
}
}
if ( !attacker.Mounted )

View file

@ -32,22 +32,6 @@ namespace Server.Mobiles
m_InternalItem = new MountItem( this, itemID );
}
public BaseMount( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 1 ); // version
writer.Write( m_NextMountAbility );
writer.Write( m_Rider );
writer.Write( m_InternalItem );
}
[Hue, CommandProperty( AccessLevel.GameMaster )]
public override int Hue
{
@ -88,6 +72,23 @@ namespace Server.Mobiles
base.OnDelete();
}
public BaseMount( Serial serial )
: base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( ( int )1 ); // version
writer.Write( m_NextMountAbility );
writer.Write( m_Rider );
writer.Write( m_InternalItem );
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
@ -134,7 +135,7 @@ namespace Server.Mobiles
return;
}
if ( !CheckMountAllowed( from, true ) )
if ( !CheckMountAllowed( from ) )
return;
if ( from.Mounted )
@ -262,97 +263,22 @@ namespace Server.Mobiles
}
}
private class BlockEntry
// 1040024 You are still too dazed from being knocked off your mount to ride!
// 1062910 You cannot mount while recovering from a bola throw.
// 1070859 You cannot mount while recovering from a dismount special maneuver.
public static bool CheckMountAllowed( Mobile mob )
{
public BlockMountType m_Type;
public DateTime m_Expiration;
bool result = true;
public bool IsExpired{ get{ return ( DateTime.Now >= m_Expiration ); } }
public BlockEntry( BlockMountType type, DateTime expiration )
if( ( mob is PlayerMobile ) && ( mob as PlayerMobile ).BlockReason != BlockMountType.None )
{
m_Type = type;
m_Expiration = expiration;
}
}
mob.SendLocalizedMessage( ( int )( mob as PlayerMobile ).BlockReason );
private static Hashtable m_Table = new Hashtable();
public static void SetMountPrevention( Mobile mob, BlockMountType type, TimeSpan duration )
{
if ( mob == null )
return;
DateTime expiration = DateTime.Now + duration;
BlockEntry entry = m_Table[mob] as BlockEntry;
if ( entry != null )
{
entry.m_Type = type;
entry.m_Expiration = expiration;
}
else
{
m_Table[mob] = entry = new BlockEntry( type, expiration );
}
}
public static void ClearMountPrevention( Mobile mob )
{
if ( mob != null )
m_Table.Remove( mob );
}
public static BlockMountType GetMountPrevention( Mobile mob )
{
if ( mob == null )
return BlockMountType.None;
BlockEntry entry = m_Table[mob] as BlockEntry;
if ( entry == null )
return BlockMountType.None;
if ( entry.IsExpired )
{
m_Table.Remove( mob );
return BlockMountType.None;
result = false;
}
return entry.m_Type;
}
public static bool CheckMountAllowed( Mobile mob, bool message )
{
BlockMountType type = GetMountPrevention( mob );
if ( type == BlockMountType.None )
return true;
if ( message )
{
switch ( type )
{
case BlockMountType.Dazed:
{
mob.SendLocalizedMessage( 1040024 ); // You are still too dazed from being knocked off your mount to ride!
break;
}
case BlockMountType.BolaRecovery:
{
mob.SendLocalizedMessage( 1062910 ); // You cannot mount while recovering from a bola throw.
break;
}
case BlockMountType.DismountRecovery:
{
mob.SendLocalizedMessage( 1070859 ); // You cannot mount while recovering from a dismount special maneuver.
break;
}
}
}
return false;
return result;
}
public virtual void OnRiderDamaged( int amount, Mobile from, bool willKill )
@ -451,12 +377,5 @@ namespace Server.Mobiles
}
}
}
}
public enum BlockMountType
{
None = -1,
Dazed,
BolaRecovery,
DismountRecovery
}
}

View file

@ -133,7 +133,7 @@ namespace Server.Mobiles
// CheckIsUsableBy sends the message
return false;
}
else if( !BaseMount.CheckMountAllowed( from, true ) )
else if( !BaseMount.CheckMountAllowed( from ) )
{
// CheckMountAllowed sends the message
return false;

View file

@ -71,6 +71,15 @@ namespace Server.Mobiles
Red,
Black
}
public enum BlockMountType
{
None = -1,
Dazed = 1040024,
BolaRecovery = 1062910,
DismountRecovery = 1070859
}
#endregion
public partial class PlayerMobile : Mobile, IHonorTarget
@ -657,6 +666,74 @@ namespace Server.Mobiles
}
}
private List<MountBlock> m_Blocks;
public BlockMountType BlockReason { get { return ( CheckList() ) ? m_Blocks[ 0 ].type : BlockMountType.None; } }
private class MountBlock
{
public BlockMountType type;
public Timer m_Timer;
public MountBlock( TimeSpan duration, BlockMountType Type, List<MountBlock> list )
{
type = Type;
m_Timer = Timer.DelayCall( duration, new TimerStateCallback<List<MountBlock>>( RemoveBlock ), list );
}
private void RemoveBlock( List<MountBlock> list )
{
if( list != null )
{
list.Remove( this );
}
}
}
public void AddMountBlock( BlockMountType type, TimeSpan duration )
{
CheckList();
m_Blocks.Add( new MountBlock( duration, type, m_Blocks ) );
IMount mount = this.Mount;
if( mount != null )
{
mount.Rider = null;
}
}
private bool CheckList()
{
if( m_Blocks == null )
{
m_Blocks = new List<MountBlock>();
}
else if( m_Blocks.Count > 0 )
{
List<MountBlock> toRemove = new List<MountBlock>();
int count = m_Blocks.Count;
for( int i = 0; i < count; i++ )
{
if( !m_Blocks[ i ].m_Timer.Running )
{
toRemove.Add( m_Blocks[ i ] );
}
}
foreach( MountBlock block in toRemove )
{
m_Blocks.Remove( block );
}
}
return m_Blocks.Count > 0;
}
public override void OnSkillInvalidated( Skill skill )
{
if ( Core.AOS && skill.SkillName == SkillName.MagicResist )