TreeQueen.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. using System.Drawing;
  2. using Server.MirDatabase;
  3. using Server.MirEnvir;
  4. using S = ServerPackets;
  5. namespace Server.MirObjects.Monsters
  6. {
  7. public class TreeQueen : MonsterObject
  8. {
  9. protected override bool CanMove { get { return false; } }
  10. protected override bool CanRegen { get { return false; } }
  11. private readonly int _rootSpreadMin = 5;
  12. private readonly int _rootSpreadMax = 15;
  13. private readonly int _rootCount = 5;
  14. private long _rootSpawnTime;
  15. private readonly int _groundrootSpread = 5;
  16. private long _groundRootSpawnTime;
  17. private readonly int _nearMultiplier = 4;
  18. private bool _notNear = true;
  19. protected internal TreeQueen(MonsterInfo info)
  20. : base(info)
  21. {
  22. Direction = MirDirection.Up;
  23. }
  24. protected override bool InAttackRange()
  25. {
  26. return Target.CurrentMap == CurrentMap;
  27. }
  28. public override void Turn(MirDirection dir) { }
  29. public override bool Walk(MirDirection dir) { return false; }
  30. public override int Attacked(MonsterObject attacker, int damage, DefenceType type = DefenceType.ACAgility)
  31. {
  32. return base.Attacked(attacker, damage, type);
  33. }
  34. public override int Attacked(HumanObject attacker, int damage, DefenceType type = DefenceType.ACAgility, bool damageWeapon = true)
  35. {
  36. return base.Attacked(attacker, damage, type, damageWeapon);
  37. }
  38. public override void ApplyPoison(Poison p, MapObject Caster = null, bool NoResist = false, bool ignoreDefence = true)
  39. {
  40. }
  41. protected override void Attack()
  42. {
  43. if (!Target.IsAttackTarget(this))
  44. {
  45. Target = null;
  46. return;
  47. }
  48. ShockTime = 0;
  49. ActionTime = Envir.Time + 500;
  50. AttackTime = Envir.Time + AttackSpeed;
  51. bool ranged = CurrentLocation == Target.CurrentLocation || !Functions.InRange(CurrentLocation, Target.CurrentLocation, 2);
  52. if (!ranged)
  53. {
  54. _notNear = false;
  55. if (Envir.Random.Next(2) > 0)
  56. {
  57. // Fire Bombardment Spell
  58. Broadcast(new S.ObjectAttack { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, Type = 0 });
  59. int damage = GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]);
  60. if (damage == 0) return;
  61. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + 500, Target, damage, DefenceType.MACAgility, true, false);
  62. ActionList.Add(action);
  63. }
  64. else
  65. {
  66. // Push Attack
  67. Broadcast(new S.ObjectAttack { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, Type = 1 });
  68. int damage = GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]);
  69. if (damage == 0) return;
  70. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + 500, Target, damage, DefenceType.MACAgility, false, true);
  71. ActionList.Add(action);
  72. }
  73. }
  74. else
  75. {
  76. _notNear = true;
  77. }
  78. }
  79. protected override void CompleteAttack(IList<object> data)
  80. {
  81. MapObject target = (MapObject)data[0];
  82. int damage = (int)data[1];
  83. DefenceType defence = (DefenceType)data[2];
  84. bool fireBombardment = (bool)data[3];
  85. bool pushAttack = (bool)data[4];
  86. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null) return;
  87. if (fireBombardment)
  88. {
  89. List<MapObject> targets = FindAllTargets(3, CurrentLocation);
  90. if (targets.Count == 0) return;
  91. for (int i = 0; i < targets.Count; i++)
  92. {
  93. targets[i].Attacked(this, damage, defence);
  94. }
  95. }
  96. if (pushAttack)
  97. {
  98. List<MapObject> targets = FindAllTargets(1, CurrentLocation);
  99. if (targets.Count == 0) return;
  100. for (int i = 0; i < targets.Count; i++)
  101. {
  102. targets[i].Pushed(this, Functions.DirectionFromPoint(CurrentLocation, targets[i].CurrentLocation), 5);
  103. }
  104. }
  105. }
  106. private void SpawnRoots()
  107. {
  108. if (Dead) return;
  109. int count = Envir.Random.Next(1, _rootCount);
  110. int distance = Envir.Random.Next(_rootSpreadMin, _rootSpreadMax);
  111. for (int j = 0; j < CurrentMap.Players.Count; j++)
  112. {
  113. Point playerLocation = CurrentMap.Players[j].CurrentLocation;
  114. bool hit = false;
  115. for (int i = 0; i < count; i++)
  116. {
  117. Point location = new Point(playerLocation.X + Envir.Random.Next(-distance, distance + 1),
  118. playerLocation.Y + Envir.Random.Next(-distance, distance + 1));
  119. if (Envir.Random.Next(3) == 0)
  120. {
  121. location = playerLocation;
  122. hit = true;
  123. }
  124. if (!CurrentMap.ValidPoint(location)) continue;
  125. var start = Envir.Random.Next(2000);
  126. SpellObject spellObj = new SpellObject
  127. {
  128. Spell = Spell.TreeQueenRoot,
  129. Value = Envir.Random.Next(Envir.Random.Next(Stats[Stat.MinMC], Stats[Stat.MaxMC])),
  130. ExpireTime = Envir.Time + 1500 + start,
  131. TickSpeed = 2000,
  132. Caster = this,
  133. CurrentLocation = location,
  134. CurrentMap = CurrentMap,
  135. Direction = MirDirection.Up
  136. };
  137. DelayedAction action = new DelayedAction(DelayedType.Spawn, Envir.Time + start, spellObj);
  138. CurrentMap.ActionList.Add(action);
  139. if (hit)
  140. {
  141. break;
  142. }
  143. }
  144. }
  145. }
  146. private void SpawnMassRoots()
  147. {
  148. if (Dead) return;
  149. var count = CurrentMap.Players.Count;
  150. if (count == 0) return;
  151. var target = CurrentMap.Players[Envir.Random.Next(count)];
  152. var location = target.CurrentLocation;
  153. Broadcast(new S.ObjectRangeAttack { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, TargetID = target.ObjectID, Type = 1 });
  154. for (int y = location.Y - 3; y <= location.Y + 3; y++)
  155. {
  156. if (y < 0) continue;
  157. if (y >= CurrentMap.Height) break;
  158. for (int x = location.X - 3; x <= location.X + 3; x++)
  159. {
  160. if (x < 0) continue;
  161. if (x >= CurrentMap.Width) break;
  162. if (x == CurrentLocation.X && y == CurrentLocation.Y) continue;
  163. var cell = CurrentMap.GetCell(x, y);
  164. if (!cell.Valid) continue;
  165. int damage = GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]);
  166. var start = 500;
  167. SpellObject ob = new SpellObject
  168. {
  169. Spell = Spell.TreeQueenMassRoots,
  170. Value = damage,
  171. ExpireTime = Envir.Time + 1500 + start,
  172. TickSpeed = 1000,
  173. CurrentLocation = new Point(x, y),
  174. CastLocation = location,
  175. Show = location.X == x && location.Y == y,
  176. CurrentMap = CurrentMap,
  177. Caster = this
  178. };
  179. DelayedAction action = new DelayedAction(DelayedType.Spawn, Envir.Time + start, ob);
  180. CurrentMap.ActionList.Add(action);
  181. }
  182. }
  183. }
  184. private void SpawnGroundRoots()
  185. {
  186. if (Dead) return;
  187. for (int i = 0; i < CurrentMap.Players.Count; i++)
  188. {
  189. Point location = new Point(CurrentLocation.X + Envir.Random.Next(-_groundrootSpread, _groundrootSpread + 1),
  190. CurrentLocation.Y + Envir.Random.Next(-_groundrootSpread, _groundrootSpread + 1));
  191. for (int y = location.Y - 2; y <= location.Y + 2; y++)
  192. {
  193. if (y < 0) continue;
  194. if (y >= CurrentMap.Height) break;
  195. for (int x = location.X - 2; x <= location.X + 2; x++)
  196. {
  197. if (x < 0) continue;
  198. if (x >= CurrentMap.Width) break;
  199. if (x == CurrentLocation.X && y == CurrentLocation.Y) continue;
  200. var cell = CurrentMap.GetCell(x, y);
  201. if (!cell.Valid) continue;
  202. int damage = GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]);
  203. var start = Envir.Random.Next(4000);
  204. SpellObject ob = new SpellObject
  205. {
  206. Spell = Spell.TreeQueenGroundRoots,
  207. Value = damage,
  208. ExpireTime = Envir.Time + 900 + start,
  209. TickSpeed = 1000,
  210. CurrentLocation = new Point(x, y),
  211. CastLocation = location,
  212. Show = location.X == x && location.Y == y,
  213. CurrentMap = CurrentMap,
  214. Caster = this
  215. };
  216. DelayedAction action = new DelayedAction(DelayedType.Spawn, Envir.Time + start, ob);
  217. CurrentMap.ActionList.Add(action);
  218. }
  219. }
  220. }
  221. }
  222. public override void Spawned()
  223. {
  224. // Begin timers (stops players from being bombarded with attacks when they enter the room / map).
  225. _rootSpawnTime = Envir.Time + (Settings.Second * 5);
  226. _groundRootSpawnTime = Envir.Time + (Settings.Second * 15);
  227. base.Spawned();
  228. }
  229. protected override void ProcessTarget()
  230. {
  231. if (CurrentMap.Players.Count == 0) return;
  232. if (Envir.Time > _rootSpawnTime)
  233. {
  234. if (Envir.Random.Next(4) > 0)
  235. {
  236. SpawnRoots();
  237. }
  238. else
  239. {
  240. SpawnMassRoots();
  241. }
  242. var next = Envir.Random.Next(1, 4);
  243. _rootSpawnTime = Envir.Time + (Settings.Second * (_notNear ? next : next * _nearMultiplier));
  244. }
  245. if (Envir.Time > _groundRootSpawnTime)
  246. {
  247. SpawnGroundRoots();
  248. var next = Envir.Random.Next(2, 3);
  249. _groundRootSpawnTime = Envir.Time + (Settings.Second * (_notNear ? next : next * _nearMultiplier));
  250. }
  251. if (Target == null || !CanAttack) return;
  252. if (InAttackRange() && CanAttack)
  253. {
  254. Attack();
  255. return;
  256. }
  257. }
  258. }
  259. }