Plant gump issues

http://jira.runuo.com/browse/RUNUO-12

House decay stages should pass at random intervals
http://jira.runuo.com/browse/RUNUO-113

Nature's Fury cast issues
http://jira.runuo.com/browse/RUNUO-114

Animal Form inaccuracies and issue with Talisman of the Fey
http://jira.runuo.com/browse/RUNUO-115

BaseWaterContainer fill messages and behavior
http://jira.runuo.com/browse/RUNUO-116

AdminGump filter for accounts owning houses
http://jira.runuo.com/browse/RUNUO-118

Seeds should be stackable
http://jira.runuo.com/browse/RUNUO-119

Typo in case of a jailbreak
http://jira.runuo.com/browse/RUNUO-120

Prevent creation of invalid account names
http://jira.runuo.com/browse/RUNUO-121
This commit is contained in:
eos 2012-01-01 03:34:02 +00:00
parent d2f79e93ea
commit 4cba2c8d56
18 changed files with 440 additions and 137 deletions

View file

@ -251,17 +251,31 @@ namespace Server.Misc
return m_IPTable;
}
}
}
private static readonly char[] m_ForbiddenChars = new char[]
{
'<', '>', ':', '"', '/', '\\', '|', '?', '*'
};
private static bool IsForbiddenChar( char c )
{
for ( int i = 0; i < m_ForbiddenChars.Length; ++i )
if ( c == m_ForbiddenChars[i] )
return true;
return false;
}
private static Account CreateAccount( NetState state, string un, string pw )
{
if ( un.Length == 0 || pw.Length == 0 )
return null;
bool isSafe = true;
bool isSafe = !( un.StartsWith( " " ) || un.EndsWith( " " ) || un.EndsWith( "." ) );
for ( int i = 0; isSafe && i < un.Length; ++i )
isSafe = ( un[i] >= 0x20 && un[i] < 0x80 );
isSafe = ( un[i] >= 0x20 && un[i] < 0x80 && !IsForbiddenChar( un[i] ) );
for ( int i = 0; isSafe && i < pw.Length; ++i )
isSafe = ( pw[i] >= 0x20 && pw[i] < 0x80 );

View file

@ -233,7 +233,7 @@ namespace Server.Engines.Help
}
else if ( from.Region.IsPartOf( typeof( Server.Regions.Jail ) ) )
{
from.SendLocalizedMessage( 1041530, "", 0x35 ); // You'll need a better jailbreak plan then that!
from.SendLocalizedMessage( 1114345, "", 0x35 ); // You'll need a better jailbreak plan than that!
}
else if ( Factions.Sigil.ExistsOn( from ) )
{
@ -290,7 +290,7 @@ namespace Server.Engines.Help
{
if ( from.Region.IsPartOf( typeof( Regions.Jail ) ) )
{
from.SendLocalizedMessage( 1041530, "", 0x35 ); // You'll need a better jailbreak plan then that!
from.SendLocalizedMessage( 1114345, "", 0x35 ); // You'll need a better jailbreak plan than that!
}
else if ( from.Region.IsPartOf( "Haven Island" ) )
{

View file

@ -44,19 +44,19 @@ namespace Server.Engines.Plants
AddPlusMinus( 196, 67, system.Water );
AddButton( 209, 91, 0xD4, 0xD4, 7, GumpButtonType.Reply, 0 ); // Poison potion
AddItem( 197, 91, 0xF0A );
AddItem( 201, 91, 0xF0A );
AddLevel( 196, 91, system.PoisonPotion );
AddButton( 209, 115, 0xD4, 0xD4, 8, GumpButtonType.Reply, 0 ); // Cure potion
AddItem( 192, 115, 0xF07 );
AddItem( 201, 115, 0xF07 );
AddLevel( 196, 115, system.CurePotion );
AddButton( 209, 139, 0xD4, 0xD4, 9, GumpButtonType.Reply, 0 ); // Heal potion
AddItem( 190, 139, 0xF0C );
AddItem( 201, 139, 0xF0C );
AddLevel( 196, 139, system.HealPotion );
AddButton( 209, 163, 0xD4, 0xD4, 10, GumpButtonType.Reply, 0 ); // Strength potion
AddItem( 193, 163, 0xF09 );
AddItem( 201, 163, 0xF09 );
AddLevel( 196, 163, system.StrengthPotion );
AddImage( 48, 47, 0xD2 );
@ -317,6 +317,8 @@ namespace Server.Engines.Plants
from.SendLocalizedMessage( 1060808, "#" + m_Plant.GetLocalizedPlantStatus().ToString() ); // Target the container you wish to use to water the ~1_val~.
}
from.SendGump( new MainPlantGump( m_Plant ) );
break;
}
case 7: // Poison potion

View file

@ -386,7 +386,7 @@ namespace Server.Engines.Plants
m_PlantHue = seed.PlantHue;
m_ShowType = seed.ShowType;
seed.Delete();
seed.Consume();
PlantStatus = PlantStatus.Seed;

View file

@ -25,6 +25,9 @@ namespace Server.Engines.Plants
{
if ( !m_Plant.Deleted && m_Plant.PlantStatus < PlantStatus.DecorativePlant && from.InRange( m_Plant.GetWorldLocation(), 3 ) && m_Plant.IsUsableBy( from ) )
{
if ( from.HasGump( typeof( MainPlantGump ) ) )
from.CloseGump( typeof( MainPlantGump ) );
from.SendGump( new MainPlantGump( m_Plant ) );
}
}

View file

@ -1,4 +1,5 @@
using System;
using System.Text;
using Server;
using Server.Targeting;
@ -76,6 +77,7 @@ namespace Server.Engines.Plants
public Seed( PlantType plantType, PlantHue plantHue, bool showType ) : base( 0xDCF )
{
Weight = 1.0;
Stackable = Core.SA;
m_PlantType = plantType;
m_PlantHue = plantHue;
@ -90,7 +92,7 @@ namespace Server.Engines.Plants
public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } }
public override void AddNameProperty( ObjectPropertyList list )
private int GetLabel( out string args )
{
PlantHueInfo hueInfo = PlantHueInfo.GetInfo( m_PlantHue );
@ -98,30 +100,50 @@ namespace Server.Engines.Plants
if ( title == 0 ) // Not a bonsai
title = hueInfo.Name;
int label;
if ( Amount == 1 )
label = m_ShowType ? 1061917 : 1060838; // ~1_COLOR~ ~2_TYPE~ seed : ~1_val~ seed
else
label = m_ShowType ? 1113492 : 1113490; // ~1_amount~ ~2_color~ ~3_type~ seeds : ~1_amount~ ~2_val~ seeds
if ( hueInfo.IsBright() )
++label;
StringBuilder ab = new StringBuilder();
if ( Amount != 1 )
{
ab.Append( Amount );
ab.Append( '\t' );
}
ab.Append( '#' );
ab.Append( title );
if ( m_ShowType )
{
PlantTypeInfo typeInfo = PlantTypeInfo.GetInfo( m_PlantType );
list.Add( hueInfo.IsBright() ? 1061918 : 1061917, String.Concat( "#", title.ToString(), "\t#", typeInfo.Name.ToString() ) ); // [bright] ~1_COLOR~ ~2_TYPE~ seed
}
else
{
list.Add( hueInfo.IsBright() ? 1060839 : 1060838, String.Concat( "#", title.ToString() ) ); // [bright] ~1_val~ seed
ab.Append( "\t#" );
ab.Append( typeInfo.Name );
}
args = ab.ToString();
return label;
}
public override void OnSingleClick ( Mobile from )
public override void AddNameProperty( ObjectPropertyList list )
{
PlantHueInfo hueInfo = PlantHueInfo.GetInfo( m_PlantHue );
string args;
list.Add( GetLabel( out args ), args );
}
if ( m_ShowType )
{
PlantTypeInfo typeInfo = PlantTypeInfo.GetInfo( m_PlantType );
LabelTo( from, hueInfo.IsBright() ? 1061918 : 1061917, String.Concat( "#", hueInfo.Name.ToString(), "\t#", typeInfo.Name.ToString() ) ); // [bright] ~1_COLOR~ ~2_TYPE~ seed
}
else
{
LabelTo( from, hueInfo.IsBright() ? 1060839 : 1060838, String.Concat( "#", hueInfo.Name.ToString() ) ); // [bright] ~1_val~ seed
}
public override void OnSingleClick( Mobile from )
{
string args;
LabelTo( from, GetLabel( out args ), args );
}
public override void OnDoubleClick( Mobile from )
@ -136,6 +158,31 @@ namespace Server.Engines.Plants
LabelTo( from, 1061916 ); // Choose a bowl of dirt to plant this seed in.
}
public override bool StackWith( Mobile from, Item dropped, bool playSound )
{
if ( dropped is Seed )
{
Seed other = (Seed)dropped;
if ( other.PlantType == m_PlantType && other.PlantHue == m_PlantHue && other.ShowType == m_ShowType )
return base.StackWith( from, dropped, playSound );
}
return false;
}
public override void OnAfterDuped( Item newItem )
{
Seed newSeed = newItem as Seed;
if ( newSeed == null )
return;
newSeed.PlantType = m_PlantType;
newSeed.PlantHue = m_PlantHue;
newSeed.ShowType = m_ShowType;
}
private class InternalTarget : Target
{
private Seed m_Seed;
@ -178,7 +225,7 @@ namespace Server.Engines.Plants
{
base.Serialize( writer );
writer.Write( (int) 0 ); // version
writer.Write( (int) 1 ); // version
writer.Write( (int) m_PlantType );
writer.Write( (int) m_PlantHue );
@ -197,6 +244,9 @@ namespace Server.Engines.Plants
if ( Weight != 1.0 )
Weight = 1.0;
if ( version < 1 )
Stackable = Core.SA;
}
}
}

View file

@ -174,7 +174,7 @@ namespace Server.Engines.Quests
{
if ( m.Region.IsPartOf( typeof( Regions.Jail ) ) )
{
m.SendLocalizedMessage( 1042632 ); // You'll need a better jailbreak plan then that!
m.SendLocalizedMessage( 1114345 ); // You'll need a better jailbreak plan than that!
}
else if ( m == m_Caster )
{

View file

@ -10,6 +10,7 @@ using Server.Prompts;
using Server.Network;
using Server.Accounting;
using Server.Commands;
using Server.Multis;
namespace Server.Gumps
{
@ -756,7 +757,8 @@ namespace Server.Gumps
AddButtonLabeled( 10, 390, GetButtonID( 5, 27 ), "Ban marked" );
AddButtonLabeled( 10, 410, GetButtonID( 5, 28 ), "Delete marked" );
AddButtonLabeled( 210, 400, GetButtonID( 5, 29 ), "Mark all" );
AddButtonLabeled( 210, 390, GetButtonID( 5, 29 ), "Mark all" );
AddButtonLabeled( 210, 410, GetButtonID( 5, 33 ), "Unmark house owners" );
}
for ( int i = 0, index = (listPage * 12); i < 12 && index >= 0 && index < m_List.Count; ++i, ++index )
@ -2383,6 +2385,32 @@ namespace Server.Gumps
break;
}
case 33: // Unmark house owners
{
ArrayList list = m_List;
ArrayList rads = m_State as ArrayList;
if ( list == null || rads == null )
break;
ArrayList newRads = new ArrayList();
foreach ( Account acct in rads )
{
bool hasHouse = false;
for ( int i = 0; i < acct.Length && !hasHouse; ++i )
if ( acct[i] != null && BaseHouse.HasHouse( acct[i] ) )
hasHouse = true;
if ( !hasHouse )
newRads.Add( acct );
}
from.SendGump( new AdminGump( from, AdminGumpPage.Accounts, m_ListPage, m_List, null, newRads ) );
break;
}
default:
{
index -= 50;

View file

@ -741,14 +741,14 @@ namespace Server.Items
{
BaseWaterContainer bwc = targ as BaseWaterContainer;
if( Quantity == 0 || ( this.Content == BeverageType.Water && !this.IsFull ) )
if( Quantity == 0 || ( Content == BeverageType.Water && !IsFull ) )
{
int I_Need = Math.Min( ( MaxQuantity - Quantity ), bwc.Quantity );
int iNeed = Math.Min( ( MaxQuantity - Quantity ), bwc.Quantity );
if( ( I_Need > 0 ) && !bwc.IsEmpty && !IsFull )
if( iNeed > 0 && !bwc.IsEmpty && !IsFull )
{
bwc.Quantity -= I_Need;
Quantity += I_Need;
bwc.Quantity -= iNeed;
Quantity += iNeed;
Content = BeverageType.Water;
from.PlaySound( 0x4E );
@ -1026,15 +1026,23 @@ namespace Server.Items
else if( targ is BaseWaterContainer )
{
BaseWaterContainer bwc = targ as BaseWaterContainer;
if( ( !this.IsEmpty || this.Content == BeverageType.Water ) && bwc.Items.Count == 0 )
if( Content != BeverageType.Water )
{
int It_Needs = Math.Min( ( bwc.MaxQuantity - bwc.Quantity ), Quantity );
from.SendLocalizedMessage( 500842 ); // Can't pour that in there.
}
else if( bwc.Items.Count != 0 )
{
from.SendLocalizedMessage( 500841 ); // That has something in it.
}
else
{
int itNeeds = Math.Min( ( bwc.MaxQuantity - bwc.Quantity ), Quantity );
if( It_Needs > 0 && ( !IsEmpty && !bwc.IsFull ) )
if( itNeeds > 0 )
{
bwc.Quantity += It_Needs;
Quantity -= It_Needs;
bwc.Quantity += itNeeds;
Quantity -= itNeeds;
from.PlaySound( 0x4E );
}

View file

@ -31,6 +31,14 @@
ItemID = ( IsEmpty ) ? voidItem_ID : fullItem_ID;
if( !IsEmpty )
{
IEntity rootParent = RootParentEntity;
if( rootParent != null && rootParent.Map != null && rootParent.Map != Map.Internal )
MoveToWorld( rootParent.Location, rootParent.Map );
}
InvalidateProperties();
}
}

View file

@ -306,7 +306,7 @@ namespace Server.Items
}
else if ( from.Region.IsPartOf( typeof( Server.Regions.Jail ) ) )
{
from.SendLocalizedMessage( 1041530, "", 0x35 ); // You'll need a better jailbreak plan then that!
from.SendLocalizedMessage( 1114345, "", 0x35 ); // You'll need a better jailbreak plan than that!
return false;
}
else if ( boundRoot.Region.IsPartOf( typeof( Server.Regions.Jail ) ) )

View file

@ -24,6 +24,34 @@ namespace Server.Multis
public static int MaxFriends { get { return !Core.AOS ? 50 : 140; } }
public static int MaxBans { get { return !Core.AOS ? 50 : 140; } }
#region Dynamic decay system
private DecayLevel m_CurrentStage;
private DateTime m_NextDecayStage;
[CommandProperty( AccessLevel.GameMaster )]
public DateTime NextDecayStage
{
get { return m_NextDecayStage; }
set { m_NextDecayStage = value; }
}
public void ResetDynamicDecay()
{
m_CurrentStage = DecayLevel.Ageless;
m_NextDecayStage = DateTime.MinValue;
}
public void SetDynamicDecay( DecayLevel level )
{
m_CurrentStage = level;
if ( DynamicDecay.Decays( level ) )
m_NextDecayStage = DateTime.Now + DynamicDecay.GetRandomDuration( level );
else
m_NextDecayStage = DateTime.MinValue;
}
#endregion
public const bool DecayEnabled = true;
public static void Decay_OnTick()
@ -128,37 +156,73 @@ namespace Server.Multis
}
}
private DecayLevel m_LastDecayLevel;
[CommandProperty( AccessLevel.GameMaster )]
public virtual DecayLevel DecayLevel
{
get
{
DecayLevel result;
if ( !CanDecay )
{
if ( DynamicDecay.Enabled )
ResetDynamicDecay();
m_LastRefreshed = DateTime.Now;
return DecayLevel.Ageless;
result = DecayLevel.Ageless;
}
else if ( DynamicDecay.Enabled )
{
DecayLevel stage = m_CurrentStage;
if ( stage == DecayLevel.Ageless || ( DynamicDecay.Decays( stage ) && m_NextDecayStage <= DateTime.Now ) )
SetDynamicDecay( ++stage );
if ( stage == DecayLevel.Collapsed && ( HasRentedVendors || VendorInventories.Count > 0 ) )
result = DecayLevel.DemolitionPending;
else
result = stage;
}
else
{
result = GetOldDecayLevel();
}
TimeSpan timeAfterRefresh = DateTime.Now - m_LastRefreshed;
int percent = (int) ((timeAfterRefresh.Ticks * 1000) / DecayPeriod.Ticks);
if ( result != m_LastDecayLevel )
{
m_LastDecayLevel = result;
if ( percent >= 1000 ) // 100.0%
return ( HasRentedVendors || VendorInventories.Count > 0 ) ? DecayLevel.DemolitionPending : DecayLevel.Collapsed;
else if ( percent >= 950 ) // 95.0% - 99.9%
return DecayLevel.IDOC;
else if ( percent >= 750 ) // 75.0% - 94.9%
return DecayLevel.Greatly;
else if ( percent >= 500 ) // 50.0% - 74.9%
return DecayLevel.Fairly;
else if ( percent >= 250 ) // 25.0% - 49.9%
return DecayLevel.Somewhat;
else if ( percent >= 005 ) // 00.5% - 24.9%
return DecayLevel.Slightly;
if ( m_Sign != null && !m_Sign.GettingProperties )
m_Sign.InvalidateProperties();
}
return DecayLevel.LikeNew;
return result;
}
}
public DecayLevel GetOldDecayLevel()
{
TimeSpan timeAfterRefresh = DateTime.Now - m_LastRefreshed;
int percent = (int) ((timeAfterRefresh.Ticks * 1000) / DecayPeriod.Ticks);
if ( percent >= 1000 ) // 100.0%
return ( HasRentedVendors || VendorInventories.Count > 0 ) ? DecayLevel.DemolitionPending : DecayLevel.Collapsed;
else if ( percent >= 950 ) // 95.0% - 99.9%
return DecayLevel.IDOC;
else if ( percent >= 750 ) // 75.0% - 94.9%
return DecayLevel.Greatly;
else if ( percent >= 500 ) // 50.0% - 74.9%
return DecayLevel.Fairly;
else if ( percent >= 250 ) // 25.0% - 49.9%
return DecayLevel.Somewhat;
else if ( percent >= 005 ) // 00.5% - 24.9%
return DecayLevel.Slightly;
return DecayLevel.LikeNew;
}
public virtual bool RefreshDecay()
{
if ( DecayType == DecayType.Condemned )
@ -168,6 +232,12 @@ namespace Server.Multis
m_LastRefreshed = DateTime.Now;
if ( DynamicDecay.Enabled )
ResetDynamicDecay();
if ( m_Sign != null )
m_Sign.InvalidateProperties();
return ( oldLevel > DecayLevel.LikeNew );
}
@ -2336,7 +2406,17 @@ namespace Server.Multis
{
base.Serialize( writer );
writer.Write( (int) 14 ); // version
writer.Write( (int) 15 ); // version
if ( !DynamicDecay.Enabled )
{
writer.Write( (int) -1 );
}
else
{
writer.Write( (int) m_CurrentStage );
writer.Write( m_NextDecayStage );
}
writer.Write( (Point3D) m_RelativeBanLocation );
@ -2434,9 +2514,23 @@ namespace Server.Multis
int version = reader.ReadInt();
int count;
bool loadedDynamicDecay = false;
switch ( version )
{
case 15:
{
int stage = reader.ReadInt();
if ( stage != -1 )
{
m_CurrentStage = (DecayLevel)stage;
m_NextDecayStage = reader.ReadDateTime();
loadedDynamicDecay = true;
}
goto case 14;
}
case 14:
{
m_RelativeBanLocation = reader.ReadPoint3D();
@ -2631,6 +2725,16 @@ namespace Server.Multis
if ( version < 11 )
m_LastRefreshed = DateTime.Now + TimeSpan.FromHours( 24 * Utility.RandomDouble() );
if ( DynamicDecay.Enabled && !loadedDynamicDecay )
{
DecayLevel old = GetOldDecayLevel();
if ( old == DecayLevel.DemolitionPending )
old = DecayLevel.Collapsed;
SetDynamicDecay( old );
}
if ( !CheckDecay() )
{
if ( RelocatedEntities.Count > 0 )
@ -2788,7 +2892,11 @@ namespace Server.Multis
{
get
{
return m_Region.GoLocation;
if ( m_Region != null )
return m_Region.GoLocation;
Point3D rel = m_RelativeBanLocation;
return new Point3D( this.X + rel.X, this.Y + rel.Y, this.Z + rel.Z );
}
set
{
@ -2806,7 +2914,9 @@ namespace Server.Multis
set
{
m_RelativeBanLocation = value;
m_Region.GoLocation = new Point3D( this.X + value.X, this.Y + value.Y, this.Z + value.Z );
if ( m_Region != null )
m_Region.GoLocation = new Point3D( this.X + value.X, this.Y + value.Y, this.Z + value.Z );
}
}

View file

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using Server;
namespace Server.Multis
{
public class DynamicDecay
{
public static bool Enabled { get { return Core.ML; } }
private static Dictionary<DecayLevel, DecayStageInfo> m_Stages;
static DynamicDecay()
{
m_Stages = new Dictionary<DecayLevel, DecayStageInfo>();
Register( DecayLevel.LikeNew, TimeSpan.FromHours( 1 ), TimeSpan.FromHours( 1 ) );
Register( DecayLevel.Slightly, TimeSpan.FromDays( 1 ), TimeSpan.FromDays( 2 ) );
Register( DecayLevel.Somewhat, TimeSpan.FromDays( 1 ), TimeSpan.FromDays( 2 ) );
Register( DecayLevel.Fairly, TimeSpan.FromDays( 1 ), TimeSpan.FromDays( 2 ) );
Register( DecayLevel.Greatly, TimeSpan.FromDays( 1 ), TimeSpan.FromDays( 2 ) );
Register( DecayLevel.IDOC, TimeSpan.FromHours( 12 ), TimeSpan.FromHours( 24 ) );
}
public static void Register( DecayLevel level, TimeSpan min, TimeSpan max )
{
DecayStageInfo info = new DecayStageInfo( min, max );
if ( m_Stages.ContainsKey( level ) )
m_Stages[level] = info;
else
m_Stages.Add( level, info );
}
public static bool Decays( DecayLevel level )
{
return m_Stages.ContainsKey( level );
}
public static TimeSpan GetRandomDuration( DecayLevel level )
{
if ( !m_Stages.ContainsKey( level ) )
return TimeSpan.Zero;
DecayStageInfo info = m_Stages[level];
long min = info.MinDuration.Ticks;
long max = info.MaxDuration.Ticks;
return TimeSpan.FromTicks( min + (long)( Utility.RandomDouble() * ( max - min ) ) );
}
}
public class DecayStageInfo
{
private TimeSpan m_MinDuration;
private TimeSpan m_MaxDuration;
public TimeSpan MinDuration
{
get { return m_MinDuration; }
}
public TimeSpan MaxDuration
{
get { return m_MaxDuration; }
}
public DecayStageInfo( TimeSpan min, TimeSpan max )
{
m_MinDuration = min;
m_MaxDuration = max;
}
}
}

View file

@ -71,6 +71,13 @@ namespace Server.Multis
public override bool ForceShowProperties{ get{ return ObjectPropertyList.Enabled; } }
private bool m_GettingProperties;
public bool GettingProperties
{
get { return m_GettingProperties; }
}
public override void GetProperties( ObjectPropertyList list )
{
base.GetProperties( list );
@ -82,7 +89,9 @@ namespace Server.Multis
{
list.Add( m_Owner.Public ? 1061641 : 1061642 ); // This House is Open to the Public : This is a Private Home
m_GettingProperties = true;
DecayLevel level = m_Owner.DecayLevel;
m_GettingProperties = false;
if ( level == DecayLevel.DemolitionPending )
{

View file

@ -609,7 +609,7 @@ namespace Server.Spells
if( caster != null && caster.AccessLevel == AccessLevel.Player && caster.Region.IsPartOf( typeof( Regions.Jail ) ) )
{
caster.SendLocalizedMessage( 1042632 ); // You'll need a better jailbreak plan then that!
caster.SendLocalizedMessage( 1114345 ); // You'll need a better jailbreak plan than that!
return false;
}

View file

@ -69,11 +69,19 @@ namespace Server.Spells.Ninjitsu
return false;
}
private bool CasterIsMoving()
{
return (DateTime.Now - Caster.LastMoveTime <= Caster.ComputeMovementSpeed(Caster.Direction));
}
private bool m_WasMoving;
public override void OnBeginCast()
{
base.OnBeginCast();
Caster.FixedEffect(0x37C4, 10, 14, 4, 3);
m_WasMoving = CasterIsMoving();
}
public override bool CheckFizzle()
@ -112,7 +120,9 @@ namespace Server.Spells.Ninjitsu
}
else if (Caster is PlayerMobile)
{
if (GetLastAnimalForm(Caster) == -1 || DateTime.Now - Caster.LastMoveTime > Caster.ComputeMovementSpeed(Caster.Direction))
bool skipGump = (m_WasMoving || CasterIsMoving());
if (GetLastAnimalForm(Caster) == -1 || !skipGump)
{
Caster.CloseGump(typeof(AnimalFormGump));
Caster.SendGump(new AnimalFormGump(Caster, m_Entries, this));
@ -120,17 +130,27 @@ namespace Server.Spells.Ninjitsu
else
{
if (Morph(Caster, GetLastAnimalForm(Caster)) == MorphResult.Fail)
{
DoFizzle();
}
else
{
Caster.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist);
Caster.Mana -= mana;
}
}
}
else
{
if (Morph(Caster, GetLastAnimalForm(Caster)) == MorphResult.Fail)
{
DoFizzle();
}
else
{
Caster.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist);
Caster.Mana -= mana;
}
}
}
@ -189,12 +209,13 @@ namespace Server.Spells.Ninjitsu
m.CheckSkill(SkillName.Ninjitsu, 0.0, 37.5);
if (!BaseFormTalisman.EntryEnabled(m, entry.Type))
return MorphResult.Success; // Still consumes mana, just no effect
BaseMount.Dismount(m);
m.BodyMod = entry.BodyMod;
if (entry.HueMod > 0)
m.HueMod = entry.HueMod;
m.HueMod = entry.HueMod;
if (entry.SpeedBoost)
m.Send(SpeedControl.MountSpeed);
@ -461,6 +482,7 @@ namespace Server.Spells.Ninjitsu
}
else
{
m_Caster.FixedParticles(0x3728, 10, 13, 2023, EffectLayer.Waist);
m_Caster.Mana -= mana;
}
}

View file

@ -17,23 +17,10 @@ namespace Server.Mobiles
public override bool AlwaysMurderer { get { return true; } }
private Mobile m_Target;
public override Mobile ConstantFocus { get { return m_Target; } }
public override void OnThink()
{
if( m_Target != null && (!m_Target.Alive || m_Target.Deleted || !InRange( m_Target, 24 ) || !CanSee( m_Target )) )
m_Target = null; //Go kill other stuffs
base.OnThink();
}
[Constructable]
public NatureFury( Mobile target )
public NatureFury()
: base( AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4 )
{
m_Target = target;
Name = "a nature's fury";
Body = 0x33;
Hue = 0x4001;
@ -62,12 +49,6 @@ namespace Server.Mobiles
ControlSlots = 1;
}
[Constructable]
public NatureFury()
: this( null ) //Null makes it act like any other mob
{
}
public override void MoveToWorld( Point3D loc, Map map )
{
base.MoveToWorld( loc, map );

View file

@ -1,7 +1,7 @@
using System;
using Server.Mobiles;
using Server.Targeting;
using Server.Multis;
using Server.Regions;
namespace Server.Spells.Spellweaving
{
@ -23,26 +23,12 @@ namespace Server.Spells.Spellweaving
{
}
private bool m_MobileTarg;
public override int GetMana()
{
int mana = base.GetMana();
if( m_MobileTarg )
mana *= 2;
return mana;
}
public override bool CheckCast()
{
if( !base.CheckCast() )
if ( !base.CheckCast() )
return false;
if( (Caster.Followers + 1) > Caster.FollowersMax )
if ( ( Caster.Followers + 1 ) > Caster.FollowersMax )
{
Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature.
return false;
@ -58,46 +44,29 @@ namespace Server.Spells.Spellweaving
public void Target( IPoint3D point )
{
//What happens if you cast it on yourself? OSI ANSWER: You're an idiot for wasting the mana, and it'll just look for another target.
Mobile m = point as Mobile;
Point3D p = new Point3D( point );
Map map = Caster.Map;
m_MobileTarg = (m != null);
if ( map == null )
return;
BaseHouse house = BaseHouse.FindHouseAt( p, map, 0 );
if ( house != null)
if ( !house.IsFriend ( Caster ) )
return;
if (m != null) //say "Target can not be seen" if you target directly a mobile, like in OSI
{
Caster.SendLocalizedMessage( 500237 ); // Target can not be seen.
}
else if ( map == null || !map.CanSpawnMobile( p.X, p.Y, p.Z ) )
HouseRegion r = Region.Find( p, map ).GetRegion( typeof( HouseRegion ) ) as HouseRegion;
if ( r != null && r.House != null && !r.House.IsFriend( Caster ) )
return;
if ( !map.CanSpawnMobile( p.X, p.Y, p.Z ) )
{
Caster.SendLocalizedMessage( 501942 ); // That location is blocked.
}
else if( SpellHelper.CheckTown( p, Caster ) && (m_MobileTarg ? CheckHSequence( m ) : CheckSequence()) )
else if ( SpellHelper.CheckTown( p, Caster ) && CheckSequence() )
{
TimeSpan duration = TimeSpan.FromSeconds( Caster.Skills.Spellweaving.Value/24 + 25 + FocusLevel*2 );
TimeSpan duration = TimeSpan.FromSeconds( Caster.Skills.Spellweaving.Value / 24 + 25 + FocusLevel * 2 );
if( m == Caster )
m = null;
NatureFury nf = new NatureFury();
BaseCreature.Summon( nf, false, Caster, p, 0x5CB, duration );
NatureFury nf = new NatureFury( m );
BaseCreature.Summon( nf, false, Caster, p , 0x5CB, duration );
Timer t = null;
t = Timer.DelayCall( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 5.0 ), delegate
{
if( !nf.Alive || nf.Deleted || nf.DamageMin > 20 ) //sanity
t.Stop();
nf.DamageMin++;
nf.DamageMax++;
} );
new InternalTimer( nf ).Start();
}
FinishSequence();
@ -107,22 +76,47 @@ namespace Server.Spells.Spellweaving
{
private NatureFurySpell m_Owner;
public InternalTarget( NatureFurySpell owner ) : base( 10, true, TargetFlags.None )
public InternalTarget( NatureFurySpell owner )
: base( 10, true, TargetFlags.None )
{
m_Owner = owner;
CheckLOS = true;
}
protected override void OnTarget( Mobile from, object o )
{
if( o is IPoint3D )
if ( o is IPoint3D )
m_Owner.Target( (IPoint3D)o );
}
protected override void OnTargetFinish( Mobile from )
{
if( m_Owner != null )
if ( m_Owner != null )
m_Owner.FinishSequence();
}
}
private class InternalTimer : Timer
{
private NatureFury m_NatureFury;
public InternalTimer( NatureFury nf )
: base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 5.0 ) )
{
m_NatureFury = nf;
}
protected override void OnTick()
{
if ( m_NatureFury.Deleted || !m_NatureFury.Alive || m_NatureFury.DamageMin > 20 )
{
Stop();
}
else
{
++m_NatureFury.DamageMin;
++m_NatureFury.DamageMax;
}
}
}
}
}