SepHighArcher.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. using System.Diagnostics;
  2. using System.Drawing;
  3. using System.Linq;
  4. using Server.MirDatabase;
  5. using Server.MirEnvir;
  6. using S = ServerPackets;
  7. namespace Server.MirObjects.Monsters
  8. {
  9. public class SepHighArcher : MonsterObject
  10. {
  11. public long FearTime, DecreaseMPTime;
  12. public byte AttackRange = 6;
  13. public bool Summoned;
  14. protected internal SepHighArcher(MonsterInfo info)
  15. : base(info)
  16. {
  17. }
  18. protected override bool InAttackRange()
  19. {
  20. return CurrentMap == Target.CurrentMap && Functions.InRange(CurrentLocation, Target.CurrentLocation, AttackRange);
  21. }
  22. protected override void Attack()
  23. {
  24. if (!Target.IsAttackTarget(this))
  25. {
  26. Target = null;
  27. return;
  28. }
  29. ShockTime = 0;
  30. ActionTime = Envir.Time + 300;
  31. AttackTime = Envir.Time + AttackSpeed;
  32. int damage = GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]);
  33. if (damage == 0) return;
  34. DelayedAction action;
  35. Direction = Functions.DirectionFromPoint(CurrentLocation, Target.CurrentLocation);
  36. int distance = Functions.MaxDistance(CurrentLocation, Target.CurrentLocation);
  37. int delay = distance * 50 + 500; //50 MS per Step
  38. if (Envir.Random.Next(3) == 0 && Functions.InRange(CurrentLocation, Target.CurrentLocation, 2))
  39. {
  40. Broadcast(new S.ObjectMagic { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, Spell = Spell.BackStep, TargetID = Target.ObjectID, Target = Target.CurrentLocation, Cast = true, Level = 3 });
  41. int travel = 0;
  42. bool blocked = false;
  43. int jumpDistance = 3;
  44. MirDirection jumpDir = Functions.ReverseDirection(Direction);
  45. Point location = CurrentLocation;
  46. for (int i = 0; i < jumpDistance; i++)
  47. {
  48. location = Functions.PointMove(location, jumpDir, 1);
  49. if (!CurrentMap.ValidPoint(location)) break;
  50. Cell cInfo = CurrentMap.GetCell(location);
  51. if (cInfo.Objects != null)
  52. for (int c = 0; c < cInfo.Objects.Count; c++)
  53. {
  54. MapObject ob = cInfo.Objects[c];
  55. if (!ob.Blocking) continue;
  56. blocked = true;
  57. if ((cInfo.Objects == null) || blocked) break;
  58. }
  59. if (blocked) break;
  60. travel++;
  61. }
  62. jumpDistance = travel;
  63. if (jumpDistance > 0)
  64. {
  65. for (int i = 0; i < jumpDistance; i++)
  66. {
  67. location = Functions.PointMove(CurrentLocation, jumpDir, 1);
  68. CurrentMap.GetCell(CurrentLocation).Remove(this);
  69. RemoveObjects(jumpDir, 1);
  70. CurrentLocation = location;
  71. CurrentMap.GetCell(CurrentLocation).Add(this);
  72. AddObjects(jumpDir, 1);
  73. }
  74. Broadcast(new S.ObjectBackStep { ObjectID = ObjectID, Direction = Direction, Location = location, Distance = jumpDistance });
  75. }
  76. return;
  77. }
  78. bool hasPoisonBuff = (Buffs.Where(x => x.Type == BuffType.PoisonShot).ToList().Count() > 0);
  79. if (hasPoisonBuff && Envir.Random.Next(2) == 0)
  80. {
  81. Broadcast(new S.ObjectMagic { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, Spell = Spell.CrippleShot, TargetID = Target.ObjectID, Target = Target.CurrentLocation, Cast = true, Level = 3 });
  82. PoisonTarget(Target, 5, 8, PoisonType.Green, 2000);
  83. if (hasPoisonBuff)
  84. {
  85. Point place = Target.CurrentLocation;
  86. for (int y = place.Y - 1; y <= place.Y + 1; y++)
  87. {
  88. if (y < 0) continue;
  89. if (y >= CurrentMap.Height) break;
  90. for (int x = place.X - 1; x <= place.X + 1; x++)
  91. {
  92. if (x < 0) continue;
  93. if (x >= CurrentMap.Width) break;
  94. Cell cell = CurrentMap.GetCell(x, y);
  95. if (!cell.Valid || cell.Objects == null) continue;
  96. for (int i = 0; i < cell.Objects.Count; i++)
  97. {
  98. MapObject targetob = cell.Objects[i];
  99. if (targetob.Race != ObjectType.Monster && targetob.Race != ObjectType.Player && targetob.Race != ObjectType.Hero) continue;
  100. if (targetob == null || !targetob.IsAttackTarget(this) || targetob.Node == null) continue;
  101. if (targetob.Dead) continue;
  102. targetob.Attacked(this, damage, DefenceType.MAC);
  103. targetob.ApplyPoison(new Poison
  104. {
  105. Duration = (Envir.Random.Next(1, 3) + 1) * 7,
  106. Owner = this,
  107. PType = PoisonType.Green,
  108. TickSpeed = 2000,
  109. Value = damage / 25 + 4,
  110. }, this);
  111. targetob.OperateTime = 0;
  112. RemoveBuff(BuffType.PoisonShot);
  113. }
  114. }
  115. }
  116. }
  117. return;
  118. }
  119. Broadcast(new S.ObjectMagic { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, Spell = Spell.PoisonShot, TargetID = Target.ObjectID, Target = Target.CurrentLocation, Cast = true, Level = 3 });
  120. if (Envir.Random.Next(10) <= 4)
  121. {
  122. if (!hasPoisonBuff)
  123. {
  124. Target.AddBuff(BuffType.PoisonShot, Target, Settings.Second * 10, new Stats());
  125. }
  126. }
  127. action = new DelayedAction(DelayedType.Damage, Envir.Time + delay, Target, damage, DefenceType.ACAgility);
  128. ActionList.Add(action);
  129. if (Target.Dead)
  130. FindTarget();
  131. }
  132. protected override void ProcessTarget()
  133. {
  134. if (Target == null || !CanAttack) return;
  135. if (!InAttackRange())
  136. {
  137. if (CurrentLocation == Target.CurrentLocation)
  138. {
  139. MirDirection direction = (MirDirection)Envir.Random.Next(8);
  140. int rotation = Envir.Random.Next(2) == 0 ? 1 : -1;
  141. for (int d = 0; d < 8; d++)
  142. {
  143. if (Walk(direction)) break;
  144. direction = Functions.ShiftDirection(direction, rotation);
  145. }
  146. }
  147. else
  148. MoveTo(Target.CurrentLocation);
  149. }
  150. if (!CanAttack) return;
  151. if (InAttackRange() && Envir.Time < FearTime)
  152. {
  153. Attack();
  154. return;
  155. }
  156. FearTime = Envir.Time + 5000;
  157. if (Envir.Time < ShockTime)
  158. {
  159. Target = null;
  160. return;
  161. }
  162. int dist = Functions.MaxDistance(CurrentLocation, Target.CurrentLocation);
  163. if (dist < AttackRange)
  164. {
  165. MirDirection dir = Functions.DirectionFromPoint(Target.CurrentLocation, CurrentLocation);
  166. if (Walk(dir)) return;
  167. switch (Envir.Random.Next(2)) //No favour
  168. {
  169. case 0:
  170. for (int i = 0; i < 7; i++)
  171. {
  172. dir = Functions.NextDir(dir);
  173. if (Walk(dir))
  174. return;
  175. }
  176. break;
  177. default:
  178. for (int i = 0; i < 7; i++)
  179. {
  180. dir = Functions.PreviousDir(dir);
  181. if (Walk(dir))
  182. return;
  183. }
  184. break;
  185. }
  186. }
  187. }
  188. public bool Walk(MirDirection dir, bool br = false)
  189. {
  190. if (!CanMove) return false;
  191. var temploc = Functions.PointMove(CurrentLocation, dir, 1);
  192. if (!CurrentMap.ValidPoint(temploc)) return false;
  193. var cell = CurrentMap.GetCell(temploc);
  194. if (cell.Objects != null)
  195. for (int i = 0; i < cell.Objects.Count; i++)
  196. {
  197. MapObject ob = cell.Objects[i];
  198. if (!ob.Blocking) continue;
  199. return false;
  200. }
  201. Point location = Functions.PointMove(CurrentLocation, dir, 2);
  202. if (!CurrentMap.ValidPoint(location)) return false;
  203. cell = CurrentMap.GetCell(location);
  204. bool isBreak = br;
  205. if (cell.Objects != null)
  206. for (int i = 0; i < cell.Objects.Count; i++)
  207. {
  208. MapObject ob = cell.Objects[i];
  209. if (!ob.Blocking) continue;
  210. isBreak = true;
  211. break;
  212. }
  213. if (isBreak)
  214. {
  215. location = Functions.PointMove(CurrentLocation, dir, 1);
  216. if (!CurrentMap.ValidPoint(location)) return false;
  217. cell = CurrentMap.GetCell(location);
  218. if (cell.Objects != null)
  219. for (int i = 0; i < cell.Objects.Count; i++)
  220. {
  221. MapObject ob = cell.Objects[i];
  222. if (!ob.Blocking) continue;
  223. return false;
  224. }
  225. }
  226. CurrentMap.GetCell(CurrentLocation).Remove(this);
  227. Direction = dir;
  228. RemoveObjects(dir, 1);
  229. CurrentLocation = location;
  230. CurrentMap.GetCell(CurrentLocation).Add(this);
  231. AddObjects(dir, 1);
  232. if (Hidden)
  233. {
  234. Hidden = false;
  235. for (int i = 0; i < Buffs.Count; i++)
  236. {
  237. if (Buffs[i].Type != BuffType.Hiding) continue;
  238. Buffs[i].ExpireTime = 0;
  239. break;
  240. }
  241. }
  242. CellTime = Envir.Time + 500;
  243. ActionTime = Envir.Time + 300;
  244. MoveTime = Envir.Time + MoveSpeed;
  245. if (MoveTime > AttackTime)
  246. AttackTime = MoveTime;
  247. InSafeZone = CurrentMap.GetSafeZone(CurrentLocation) != null;
  248. if (isBreak)
  249. Broadcast(new S.ObjectWalk { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  250. else
  251. Broadcast(new S.ObjectRun { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  252. cell = CurrentMap.GetCell(CurrentLocation);
  253. for (int i = 0; i < cell.Objects.Count; i++)
  254. {
  255. if (cell.Objects[i].Race != ObjectType.Spell) continue;
  256. SpellObject ob = (SpellObject)cell.Objects[i];
  257. ob.ProcessSpell(this);
  258. //break;
  259. }
  260. return true;
  261. }
  262. public override void Die()
  263. {
  264. if (Dead) return;
  265. HP = 0;
  266. Dead = true;
  267. DeadTime = 0;
  268. Broadcast(new S.ObjectDied { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, Type = (byte)(Master != null ? 1 : 0) });
  269. if (EXPOwner != null && Master == null && EXPOwner.Race == ObjectType.Player) EXPOwner.WinExp(Experience, Level);
  270. if (Respawn != null)
  271. Respawn.Count--;
  272. if (Master == null)
  273. Drop();
  274. Master = null;
  275. PoisonList.Clear();
  276. Envir.MonsterCount--;
  277. if (CurrentMap != null)
  278. CurrentMap.MonsterCount--;
  279. }
  280. public override Packet GetInfo()
  281. {
  282. PlayerObject master = null;
  283. short weapon = -1;
  284. short armour = 0;
  285. byte wing = 0;
  286. if (Master != null && Master is PlayerObject) master = (PlayerObject)Master;
  287. if (master != null)
  288. {
  289. weapon = master.Looks_Weapon;
  290. armour = master.Looks_Armour;
  291. wing = master.Looks_Wings;
  292. }
  293. return new S.ObjectPlayer
  294. {
  295. ObjectID = ObjectID,
  296. Name = master != null ? master.Name : Name,
  297. NameColour = NameColour,
  298. Class = MirClass.Archer,
  299. Gender = master != null ? master.Gender : Envir.Random.Next(2) == 0 ? MirGender.Male : MirGender.Female,
  300. Location = CurrentLocation,
  301. Direction = Direction,
  302. Hair = master != null ? master.Hair : (byte)Envir.Random.Next(0, 5),
  303. Weapon = 218,
  304. Armour = 41,
  305. Light = master != null ? master.Light : Light,
  306. Poison = CurrentPoison,
  307. Dead = Dead,
  308. Hidden = Hidden,
  309. Effect = SpellEffect.None,
  310. WingEffect = wing,
  311. Extra = Summoned,
  312. TransformType = -1,
  313. };
  314. }
  315. }
  316. }