HumanAssassin.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  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 HumanAssassin : MonsterObject
  8. {
  9. public byte AttackRange = 1;
  10. public int AttackDamage = 0;
  11. public bool Summoned;
  12. public long ExplosionTime;
  13. protected internal HumanAssassin(MonsterInfo info)
  14. : base(info)
  15. {
  16. ExplosionTime = Envir.Time + 1000 * 10;
  17. Summoned = true;
  18. }
  19. protected override void RefreshBase()
  20. {
  21. if (Master != null)
  22. {
  23. Stats.Clear();
  24. Stats.Add(Master.Stats);
  25. Stats[Stat.HP] = 1500;
  26. MoveSpeed = 100;
  27. AttackSpeed = Master.AttackSpeed;
  28. }
  29. }
  30. public override void RefreshAll()
  31. {
  32. RefreshBase();
  33. Stats[Stat.HP] += PetLevel * 20;
  34. Stats[Stat.MinAC] += PetLevel * 2;
  35. Stats[Stat.MaxAC] += PetLevel * 2;
  36. Stats[Stat.MinMAC] += PetLevel * 2;
  37. Stats[Stat.MaxMAC] += PetLevel * 2;
  38. Stats[Stat.MinDC] += PetLevel;
  39. Stats[Stat.MaxDC] += PetLevel;
  40. if (MoveSpeed < 100) MoveSpeed = 100;
  41. if (AttackSpeed < 100) AttackSpeed = 100;
  42. RefreshBuffs();
  43. }
  44. public override bool Walk(MirDirection dir)
  45. {
  46. if (!CanMove) return false;
  47. Point location = Functions.PointMove(CurrentLocation, dir, 2);
  48. if (!CurrentMap.ValidPoint(location)) return false;
  49. Cell cell = CurrentMap.GetCell(location);
  50. bool isBreak = false;
  51. if (cell.Objects != null)
  52. for (int i = 0; i < cell.Objects.Count; i++)
  53. {
  54. MapObject ob = cell.Objects[i];
  55. if (!ob.Blocking) continue;
  56. isBreak = true;
  57. break;
  58. }
  59. if (isBreak)
  60. {
  61. location = Functions.PointMove(CurrentLocation, dir, 1);
  62. if (!CurrentMap.ValidPoint(location)) return false;
  63. cell = CurrentMap.GetCell(location);
  64. if (cell.Objects != null)
  65. for (int i = 0; i < cell.Objects.Count; i++)
  66. {
  67. MapObject ob = cell.Objects[i];
  68. if (!ob.Blocking) continue;
  69. return false;
  70. }
  71. }
  72. CurrentMap.GetCell(CurrentLocation).Remove(this);
  73. Direction = dir;
  74. RemoveObjects(dir, 1);
  75. CurrentLocation = location;
  76. CurrentMap.GetCell(CurrentLocation).Add(this);
  77. AddObjects(dir, 1);
  78. if (Hidden)
  79. {
  80. RemoveBuff(BuffType.Hiding);
  81. }
  82. CellTime = Envir.Time + 500;
  83. ActionTime = Envir.Time + 300;
  84. MoveTime = Envir.Time + MoveSpeed;
  85. if (MoveTime > AttackTime)
  86. AttackTime = MoveTime;
  87. InSafeZone = CurrentMap.GetSafeZone(CurrentLocation) != null;
  88. if (isBreak)
  89. Broadcast(new S.ObjectWalk { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  90. else
  91. Broadcast(new S.ObjectRun { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  92. cell = CurrentMap.GetCell(CurrentLocation);
  93. for (int i = 0; i < cell.Objects.Count; i++)
  94. {
  95. if (cell.Objects[i].Race != ObjectType.Spell) continue;
  96. SpellObject ob = (SpellObject)cell.Objects[i];
  97. ob.ProcessSpell(this);
  98. //break;
  99. }
  100. return true;
  101. }
  102. protected override bool InAttackRange()
  103. {
  104. return CurrentMap == Target.CurrentMap && Functions.InRange(CurrentLocation, Target.CurrentLocation, AttackRange);
  105. }
  106. protected override void ProcessAI()
  107. {
  108. if (Dead) return;
  109. ProcessSearch();
  110. ProcessTarget();
  111. if (Master != null && Master is PlayerObject)
  112. {
  113. if (Envir.Time > ExplosionTime) Die();
  114. }
  115. }
  116. protected override void ProcessSearch()
  117. {
  118. if (Envir.Time < SearchTime) return;
  119. SearchTime = Envir.Time + SearchDelay;
  120. //Stacking or Infront of master - Move
  121. bool stacking = false;
  122. Cell cell = CurrentMap.GetCell(CurrentLocation);
  123. if (cell.Objects != null)
  124. for (int i = 0; i < cell.Objects.Count; i++)
  125. {
  126. MapObject ob = cell.Objects[i];
  127. if (ob == this || !ob.Blocking) continue;
  128. stacking = true;
  129. break;
  130. }
  131. if (CanMove && stacking)
  132. {
  133. //Walk Randomly
  134. if (!Walk(Direction))
  135. {
  136. MirDirection dir = Direction;
  137. switch (Envir.Random.Next(3)) // favour Clockwise
  138. {
  139. case 0:
  140. for (int i = 0; i < 7; i++)
  141. {
  142. dir = Functions.NextDir(dir);
  143. if (Walk(dir))
  144. break;
  145. }
  146. break;
  147. default:
  148. for (int i = 0; i < 7; i++)
  149. {
  150. dir = Functions.PreviousDir(dir);
  151. if (Walk(dir))
  152. break;
  153. }
  154. break;
  155. }
  156. }
  157. }
  158. if (Target == null || Envir.Random.Next(3) == 0)
  159. FindTarget();
  160. }
  161. protected override void ProcessTarget()
  162. {
  163. if (Target == null || !CanAttack) return;
  164. if (InAttackRange())
  165. {
  166. Attack();
  167. return;
  168. }
  169. if (Envir.Time < ShockTime)
  170. {
  171. Target = null;
  172. return;
  173. }
  174. int dist = Functions.MaxDistance(CurrentLocation, Target.CurrentLocation);
  175. if (dist >= AttackRange)
  176. MoveTo(Target.CurrentLocation);
  177. }
  178. protected override void Attack()
  179. {
  180. if (AttackDamage >= 500)
  181. {
  182. Die();
  183. return;
  184. }
  185. ShockTime = 0;
  186. if (!Target.IsAttackTarget(this))
  187. {
  188. Target = null;
  189. return;
  190. }
  191. Direction = Functions.DirectionFromPoint(CurrentLocation, Target.CurrentLocation);
  192. Broadcast(new S.ObjectAttack { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  193. ActionTime = Envir.Time + 300;
  194. AttackTime = Envir.Time + AttackSpeed;
  195. int damage = GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]);
  196. AttackDamage += damage;
  197. if (damage == 0) return;
  198. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + 300, Target, damage, DefenceType.ACAgility);
  199. ActionList.Add(action);
  200. }
  201. public override void Spawned()
  202. {
  203. base.Spawned();
  204. Summoned = false;
  205. }
  206. public override void Die()
  207. {
  208. if (Dead) return;
  209. ExplosionDie();
  210. HP = 0;
  211. Dead = true;
  212. //DeadTime = Envir.Time + DeadDelay;
  213. DeadTime = 0;
  214. Broadcast(new S.ObjectDied { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, Type = (byte)2 });
  215. if (EXPOwner != null && EXPOwner.Node != null && Master == null && EXPOwner.Race == ObjectType.Player) EXPOwner.WinExp(Experience);
  216. if (Respawn != null)
  217. Respawn.Count--;
  218. Master = null;
  219. PoisonList.Clear();
  220. Envir.MonsterCount--;
  221. if (CurrentMap != null)
  222. CurrentMap.MonsterCount--;
  223. }
  224. private void ExplosionDie()
  225. {
  226. int criticalDamage = Envir.Random.Next(0, 100) <= Stats[Stat.Accuracy] ? Stats[Stat.MaxDC] * 2 : Stats[Stat.MinDC] * 2;
  227. int damage = (Stats[Stat.MinDC] / 5 + 4 * (Level / 20)) * criticalDamage / 20 + Stats[Stat.MaxDC];
  228. for (int i = 0; i < 16; i++)
  229. {
  230. MirDirection dir = (MirDirection)(i % 8);
  231. Point hitPoint = Functions.PointMove(CurrentLocation, dir, (i / 8 + 1));
  232. if (!CurrentMap.ValidPoint(hitPoint)) continue;
  233. Cell cell = CurrentMap.GetCell(hitPoint);
  234. if (cell.Objects == null) continue;
  235. for (int j = 0; j < cell.Objects.Count; j++)
  236. {
  237. MapObject target = cell.Objects[j];
  238. switch (target.Race)
  239. {
  240. case ObjectType.Monster:
  241. case ObjectType.Player:
  242. //Only targets
  243. if (Master is HumanObject humanOb && target.IsAttackTarget(humanOb))
  244. {
  245. target.Attacked(humanOb, damage, DefenceType.AC, false);
  246. }
  247. break;
  248. }
  249. }
  250. }
  251. }
  252. public override Packet GetInfo()
  253. {
  254. PlayerObject master = null;
  255. short weapon = -1;
  256. short armour = 0;
  257. byte wing = 0;
  258. if (Master != null && Master is PlayerObject)
  259. master = (PlayerObject)Master;
  260. if (master != null)
  261. {
  262. weapon = master.Looks_Weapon;
  263. armour = master.Looks_Armour;
  264. wing = master.Looks_Wings;
  265. }
  266. return new S.ObjectPlayer
  267. {
  268. ObjectID = ObjectID,
  269. Name = master != null ? master.Name : Name,
  270. NameColour = NameColour,
  271. Class = master != null ? master.Class : MirClass.Assassin,
  272. Gender = master != null ? master.Gender : MirGender.Male,
  273. Location = CurrentLocation,
  274. Direction = Direction,
  275. Hair = master != null ? master.Hair : (byte)0,
  276. Weapon = weapon,
  277. Armour = armour,
  278. Light = master != null ? master.Light : Light,
  279. Poison = CurrentPoison,
  280. Dead = Dead,
  281. Hidden = Hidden,
  282. Effect = SpellEffect.None,
  283. WingEffect = wing,
  284. Extra = false,
  285. TransformType = -1
  286. };
  287. }
  288. }
  289. }