using Server;
using Server.Items;
using Server.Mobiles;
using Server.Network;
using Server.Spells;
using System;
using System.Collections;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
namespace Viront.Customs.SkeetShooter
{
//based off Server.Items.Bow
[FlipableAttribute(0x13B2, 0x13B1)]
public class SkeetShooter : BaseRanged
{
private int _maxSkeetRange = 15;
[CommandProperty(AccessLevel.GameMaster)]
public int MaxSkeetRange { get { return _maxSkeetRange; } set { _maxSkeetRange = value; } }
public override string DefaultName { get { return "Skeet Shooter"; } }
public override int Hue { get { return 11; } }
public override int EffectID{ get{ return 0xF42; } }
public override Type AmmoType{ get{ return typeof( Arrow ); } }
public override Item Ammo{ get{ return new Arrow(); } }
public override WeaponAbility PrimaryAbility{ get{ return WeaponAbility.ParalyzingBlow; } }
public override WeaponAbility SecondaryAbility{ get{ return WeaponAbility.MortalStrike; } }
public override int AosStrengthReq{ get{ return 30; } }
public override int AosMinDamage{ get{ return Core.ML ? 15 : 16; } }
public override int AosMaxDamage{ get{ return Core.ML ? 19 : 18; } }
public override int AosSpeed{ get{ return 25; } }
public override float MlSpeed{ get{ return 4.25f; } }
public override int OldStrengthReq{ get{ return 20; } }
public override int OldMinDamage{ get{ return 9; } }
public override int OldMaxDamage{ get{ return 41; } }
public override int OldSpeed{ get{ return 20; } }
public override int DefMaxRange{ get{ return 10; } }
public override int InitMinHits{ get{ return 31; } }
public override int InitMaxHits{ get{ return 60; } }
public override WeaponAnimation DefAnimation{ get{ return WeaponAnimation.ShootBow; } }
[Constructable]
public SkeetShooter() : base( 0x13B2 )
{
Weight = 6.0;
Layer = Layer.TwoHanded;
}
public SkeetShooter(Serial serial)
: base(serial)
{
}
private bool ConsumeSkeetAmmo(Mobile from, BaseSkeetItem to)
{
if (from.Player)
{
BaseQuiver quiver = from.FindItemOnLayer(Layer.Cloak) as BaseQuiver;
Container pack = from.Backpack;
if (quiver == null || Utility.Random(100) >= quiver.LowerAmmoCost)
{
// consume ammo
if (quiver != null && quiver.ConsumeTotal(AmmoType, 1))
quiver.InvalidateWeight();
else if (pack == null || !pack.ConsumeTotal(AmmoType, 1))
return false;
}
else if (quiver.FindItemByType(AmmoType) == null && (pack == null || pack.FindItemByType(AmmoType) == null))
{
// lower ammo cost should not work when we have no ammo at all
return false;
}
}
from.MovingEffect(to, EffectID, 18, 1, false, false);//play shoot affect
return true;
}
public override void OnDoubleClick(Mobile from)
{
//todo: check facing direction and require user face the target
//todo: change facing direction
//todo: target originating range check should depend on how much time elapses (t=0 originating, t=MAX destination, t=MAX/2 mid point between)
if (Parent != from)
{
from.SendLocalizedMessage(502641); // You must equip this item to use it.
return;
}
if (!from.CanBeginAction(typeof(SkeetShooter)))
{
from.SendLocalizedMessage(501789); // You must wait before trying again.
return;
}
Map map = from.Map;
Point3D worldLoc = GetWorldLocation();
IPooledEnumerable eable = map.GetItemsInRange( worldLoc, this.MaxSkeetRange );
BaseSkeetItem itemToHit = null;
foreach (object o in eable)
{
if (o is BaseSkeetItem)
{
var ih = (BaseSkeetItem)o;
if (!ih.Deleted && ih.Fired && !ih.HasBeenHit && from.InLOS(ih))
{
itemToHit = ih;
break;
}
}
}
eable.Free();
if(itemToHit == null)
{
from.SendMessage("No skeet targets to shoot!");
return;
}
if (!ConsumeSkeetAmmo(from, itemToHit))
{
from.SendMessage("You don't have enough ammo to do that!");
return;
}
PlaySwingAnimation(from);
if (!SkeetCheckHit(from))
{
OnSkeetMiss(from, itemToHit);
return;
}
OnSkeetHit(from, itemToHit);
}
private void OnSkeetHit(Mobile from, BaseSkeetItem itemToHit)
{
itemToHit.TakeHit(from);
from.PublicOverheadMessage(MessageType.Emote, 0x3B2, true, "*hits the skeet target*");
}
private void OnSkeetMiss(Mobile from, BaseSkeetItem itemToHit)
{
from.SendMessage("You miss the skeet target!");
if (from.Player && 0.4 >= Utility.RandomDouble())
{
//todo: what is this SE RecoverableAmmo code for?
//if (Core.SE)
//{
// PlayerMobile p = from as PlayerMobile;
// if (p != null)
// {
// Type ammo = AmmoType;
// if (p.RecoverableAmmo.ContainsKey(ammo))
// p.RecoverableAmmo[ammo]++;
// else
// p.RecoverableAmmo.Add(ammo, 1);
// }
//}
//else
//{
Ammo.MoveToWorld(new Point3D(itemToHit.X + Utility.RandomMinMax(-1, 1), itemToHit.Y + Utility.RandomMinMax(-1, 1), itemToHit.Z), itemToHit.Map);
//}
}
}
public virtual bool SkeetCheckHit(Mobile attacker)
{
Skill atkSkill = attacker.Skills[Skill];
double atkValue = attacker.Skills[GetUsedSkill(attacker, true)].Value;
double ourValue = 0;
//todo: bonus does not seem to be working correctly
int bonus = GetHitChanceBonus();
if (Core.AOS)
{
if (atkValue <= -20.0)
atkValue = -19.9;
bonus += AosAttributes.GetValue(attacker, AosAttribute.AttackChance);
if (Server.Spells.Chivalry.DivineFurySpell.UnderEffect(attacker))
bonus += 10; // attacker gets 10% bonus when they're under divine fury
if (HitLower.IsUnderAttackEffect(attacker))
bonus -= 25; // Under Hit Lower Attack effect -> 25% malus
WeaponAbility ability = WeaponAbility.GetCurrentAbility(attacker);
if (ability != null)
bonus += ability.AccuracyBonus;
SpecialMove move = SpecialMove.GetCurrentMove(attacker);
if (move != null)
bonus += move.GetAccuracyBonus(attacker);
// Max Hit Chance Increase = 45%
if (bonus > 45)
bonus = 45;
ourValue = atkValue;
}
else
{
if (atkValue <= -50.0)
atkValue = -49.9;
ourValue = (atkValue + 50.0);
}
double chance = ourValue / 100;
chance *= 1.0 + ((double)bonus / 100);
if (Core.AOS && chance < 0.02)
chance = 0.02;
return attacker.CheckSkill(atkSkill.SkillName, chance);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
writer.Write((int)_maxSkeetRange);
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
switch (version)
{
case 0:
_maxSkeetRange = reader.ReadInt();
break;
}
}
}
}