Map.cs 100 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592
  1. using System.Drawing;
  2. using Server.MirDatabase;
  3. using Server.MirObjects;
  4. using Shared;
  5. using S = ServerPackets;
  6. namespace Server.MirEnvir
  7. {
  8. public class Map
  9. {
  10. private static Envir Envir
  11. {
  12. get { return Envir.Main; }
  13. }
  14. protected static MessageQueue MessageQueue
  15. {
  16. get { return MessageQueue.Instance; }
  17. }
  18. public MapInfo Info;
  19. public int Thread = 0;
  20. public int Width, Height;
  21. public Cell[,] Cells;
  22. public List<Point> WalkableCells;
  23. public Door[,] DoorIndex;
  24. public List<Door> Doors = new List<Door>();
  25. public MineSpot[,] Mine;
  26. public long LightningTime, FireTime;
  27. public int MonsterCount;
  28. public List<NPCObject> NPCs = new List<NPCObject>();
  29. public List<SpellObject> Spells = new List<SpellObject>();
  30. public List<PlayerObject> Players = new List<PlayerObject>();
  31. public List<MapRespawn> Respawns = new List<MapRespawn>();
  32. public List<DelayedAction> ActionList = new List<DelayedAction>();
  33. public List<HeroObject> Heroes = new List<HeroObject>();
  34. public List<ConquestObject> Conquest = new List<ConquestObject>();
  35. public ConquestObject tempConquest;
  36. public Map(MapInfo info)
  37. {
  38. Info = info;
  39. Thread = Envir.Random.Next(Settings.ThreadLimit);
  40. }
  41. public Door AddDoor(byte DoorIndex, Point location)
  42. {
  43. DoorIndex = (byte)(DoorIndex & 0x7F);
  44. for (int i = 0; i < Doors.Count; i++)
  45. if (Doors[i].index == DoorIndex)
  46. return Doors[i];
  47. Door DoorInfo = new Door() { index = DoorIndex, Location = location };
  48. Doors.Add(DoorInfo);
  49. return DoorInfo;
  50. }
  51. public bool OpenDoor(byte DoorIndex)
  52. {
  53. for (int i = 0; i < Doors.Count; i++)
  54. if (Doors[i].index == DoorIndex)
  55. {
  56. Doors[i].DoorState = DoorState.Open;
  57. Doors[i].LastTick = Envir.Time;
  58. return true;
  59. }
  60. return false;
  61. }
  62. private byte FindType(byte[] input)
  63. {
  64. //c# custom map format
  65. if ((input[2] == 0x43) && (input[3] == 0x23))
  66. {
  67. return 100;
  68. }
  69. //wemade mir3 maps have no title they just start with blank bytes
  70. if (input[0] == 0)
  71. return 5;
  72. //shanda mir3 maps start with title: (C) SNDA, MIR3.
  73. if ((input[0] == 0x0F) && (input[5] == 0x53) && (input[14] == 0x33))
  74. return 6;
  75. //wemades antihack map (laby maps) title start with: Mir2 AntiHack
  76. if ((input[0] == 0x15) && (input[4] == 0x32) && (input[6] == 0x41) && (input[19] == 0x31))
  77. return 4;
  78. //wemades 2010 map format i guess title starts with: Map 2010 Ver 1.0
  79. if ((input[0] == 0x10) && (input[2] == 0x61) && (input[7] == 0x31) && (input[14] == 0x31))
  80. return 1;
  81. //shanda's 2012 format and one of shandas(wemades) older formats share same header info, only difference is the filesize
  82. if ((input[4] == 0x0F) || (input[4] == 0x03) && (input[18] == 0x0D) && (input[19] == 0x0A))
  83. {
  84. int W = input[0] + (input[1] << 8);
  85. int H = input[2] + (input[3] << 8);
  86. if (input.Length > (52 + (W * H * 14)))
  87. return 3;
  88. else
  89. return 2;
  90. }
  91. //3/4 heroes map format (myth/lifcos i guess)
  92. if ((input[0] == 0x0D) && (input[1] == 0x4C) && (input[7] == 0x20) && (input[11] == 0x6D))
  93. return 7;
  94. return 0;
  95. }
  96. private void LoadMapCellsv0(byte[] fileBytes)
  97. {
  98. int offSet = 0;
  99. Width = BitConverter.ToInt16(fileBytes, offSet);
  100. offSet += 2;
  101. Height = BitConverter.ToInt16(fileBytes, offSet);
  102. Cells = new Cell[Width, Height];
  103. DoorIndex = new Door[Width, Height];
  104. offSet = 52;
  105. for (int x = 0; x < Width; x++)
  106. for (int y = 0; y < Height; y++)
  107. {//total 12
  108. if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
  109. Cells[x, y] = Cell.HighWall; //Can Fire Over.
  110. offSet += 2;
  111. if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
  112. Cells[x, y] = Cell.LowWall; //Can't Fire Over.
  113. offSet += 2;
  114. if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
  115. Cells[x, y] = Cell.HighWall; //No Floor Tile.
  116. if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
  117. offSet += 4;
  118. if (fileBytes[offSet] > 0)
  119. DoorIndex[x, y] = AddDoor(fileBytes[offSet], new Point(x, y));
  120. offSet += 3;
  121. byte light = fileBytes[offSet++];
  122. if (light >= 100 && light <= 119)
  123. Cells[x, y].FishingAttribute = (sbyte)(light - 100);
  124. }
  125. }
  126. private void LoadMapCellsv1(byte[] fileBytes)
  127. {
  128. int offSet = 21;
  129. int w = BitConverter.ToInt16(fileBytes, offSet);
  130. offSet += 2;
  131. int xor = BitConverter.ToInt16(fileBytes, offSet);
  132. offSet += 2;
  133. int h = BitConverter.ToInt16(fileBytes, offSet);
  134. Width = w ^ xor;
  135. Height = h ^ xor;
  136. Cells = new Cell[Width, Height];
  137. DoorIndex = new Door[Width, Height];
  138. offSet = 54;
  139. for (int x = 0; x < Width; x++)
  140. for (int y = 0; y < Height; y++)
  141. {
  142. if (((BitConverter.ToInt32(fileBytes, offSet) ^ 0xAA38AA38) & 0x20000000) != 0)
  143. Cells[x, y] = Cell.HighWall; //Can Fire Over.
  144. offSet += 6;
  145. if (((BitConverter.ToInt16(fileBytes, offSet) ^ xor) & 0x8000) != 0)
  146. Cells[x, y] = Cell.LowWall; //No Floor Tile.
  147. if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
  148. offSet += 2;
  149. if (fileBytes[offSet] > 0)
  150. DoorIndex[x, y] = AddDoor(fileBytes[offSet], new Point(x, y));
  151. offSet += 5;
  152. byte light = fileBytes[offSet++];
  153. if (light >= 100 && light <= 119)
  154. Cells[x, y].FishingAttribute = (sbyte)(light - 100);
  155. offSet += 1;
  156. }
  157. }
  158. private void LoadMapCellsv2(byte[] fileBytes)
  159. {
  160. int offSet = 0;
  161. Width = BitConverter.ToInt16(fileBytes, offSet);
  162. offSet += 2;
  163. Height = BitConverter.ToInt16(fileBytes, offSet);
  164. Cells = new Cell[Width, Height];
  165. DoorIndex = new Door[Width, Height];
  166. offSet = 52;
  167. for (int x = 0; x < Width; x++)
  168. for (int y = 0; y < Height; y++)
  169. {//total 14
  170. if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
  171. Cells[x, y] = Cell.HighWall; //Can Fire Over.
  172. offSet += 2;
  173. if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
  174. Cells[x, y] = Cell.LowWall; //Can't Fire Over.
  175. offSet += 2;
  176. if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
  177. Cells[x, y] = Cell.HighWall; //No Floor Tile.
  178. if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
  179. offSet += 2;
  180. if (fileBytes[offSet] > 0)
  181. DoorIndex[x, y] = AddDoor(fileBytes[offSet], new Point(x, y));
  182. offSet += 5;
  183. byte light = fileBytes[offSet++];
  184. if (light >= 100 && light <= 119)
  185. Cells[x, y].FishingAttribute = (sbyte)(light - 100);
  186. offSet += 2;
  187. }
  188. }
  189. private void LoadMapCellsv3(byte[] fileBytes)
  190. {
  191. int offSet = 0;
  192. Width = BitConverter.ToInt16(fileBytes, offSet);
  193. offSet += 2;
  194. Height = BitConverter.ToInt16(fileBytes, offSet);
  195. Cells = new Cell[Width, Height];
  196. DoorIndex = new Door[Width, Height];
  197. offSet = 52;
  198. for (int x = 0; x < Width; x++)
  199. for (int y = 0; y < Height; y++)
  200. {//total 36
  201. if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
  202. Cells[x, y] = Cell.HighWall; //Can Fire Over.
  203. offSet += 2;
  204. if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
  205. Cells[x, y] = Cell.LowWall; //Can't Fire Over.
  206. offSet += 2;
  207. if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
  208. Cells[x, y] = Cell.HighWall; //No Floor Tile.
  209. if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
  210. offSet += 2;
  211. if (fileBytes[offSet] > 0)
  212. DoorIndex[x, y] = AddDoor(fileBytes[offSet], new Point(x, y));
  213. offSet += 12;
  214. byte light = fileBytes[offSet++];
  215. if (light >= 100 && light <= 119)
  216. Cells[x, y].FishingAttribute = (sbyte)(light - 100);
  217. offSet += 17;
  218. }
  219. }
  220. private void LoadMapCellsv4(byte[] fileBytes)
  221. {
  222. int offSet = 31;
  223. int w = BitConverter.ToInt16(fileBytes, offSet);
  224. offSet += 2;
  225. int xor = BitConverter.ToInt16(fileBytes, offSet);
  226. offSet += 2;
  227. int h = BitConverter.ToInt16(fileBytes, offSet);
  228. Width = w ^ xor;
  229. Height = h ^ xor;
  230. Cells = new Cell[Width, Height];
  231. DoorIndex = new Door[Width, Height];
  232. offSet = 64;
  233. for (int x = 0; x < Width; x++)
  234. for (int y = 0; y < Height; y++)
  235. {//total 12
  236. if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
  237. Cells[x, y] = Cell.HighWall; //Can Fire Over.
  238. offSet += 2;
  239. if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
  240. Cells[x, y] = Cell.LowWall; //Can't Fire Over.
  241. if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
  242. offSet += 4;
  243. if (fileBytes[offSet] > 0)
  244. DoorIndex[x, y] = AddDoor(fileBytes[offSet], new Point(x, y));
  245. offSet += 6;
  246. }
  247. }
  248. private void LoadMapCellsv5(byte[] fileBytes)
  249. {
  250. int offSet = 22;
  251. Width = BitConverter.ToInt16(fileBytes, offSet);
  252. offSet += 2;
  253. Height = BitConverter.ToInt16(fileBytes, offSet);
  254. Cells = new Cell[Width, Height];
  255. DoorIndex = new Door[Width, Height];
  256. offSet = 28 + (3 * ((Width / 2) + (Width % 2)) * (Height / 2));
  257. for (int x = 0; x < Width; x++)
  258. for (int y = 0; y < Height; y++)
  259. {//total 14
  260. if ((fileBytes[offSet] & 0x01) != 1)
  261. Cells[x, y] = Cell.HighWall;
  262. else if ((fileBytes[offSet] & 0x02) != 2)
  263. Cells[x, y] = Cell.LowWall;
  264. else
  265. Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
  266. offSet += 13;
  267. byte light = fileBytes[offSet++];
  268. if (light >= 100 && light <= 119)
  269. Cells[x, y].FishingAttribute = (sbyte)(light - 100);
  270. }
  271. }
  272. private void LoadMapCellsv6(byte[] fileBytes)
  273. {
  274. int offSet = 16;
  275. Width = BitConverter.ToInt16(fileBytes, offSet);
  276. offSet += 2;
  277. Height = BitConverter.ToInt16(fileBytes, offSet);
  278. Cells = new Cell[Width, Height];
  279. DoorIndex = new Door[Width, Height];
  280. offSet = 40;
  281. for (int x = 0; x < Width; x++)
  282. for (int y = 0; y < Height; y++)
  283. {//total 20
  284. if ((fileBytes[offSet] & 0x01) != 1)
  285. Cells[x, y] = Cell.HighWall;
  286. else if ((fileBytes[offSet] & 0x02) != 2)
  287. Cells[x, y] = Cell.LowWall;
  288. else
  289. Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
  290. offSet += 20;
  291. }
  292. }
  293. private void LoadMapCellsv7(byte[] fileBytes)
  294. {
  295. int offSet = 21;
  296. Width = BitConverter.ToInt16(fileBytes, offSet);
  297. offSet += 4;
  298. Height = BitConverter.ToInt16(fileBytes, offSet);
  299. Cells = new Cell[Width, Height];
  300. DoorIndex = new Door[Width, Height];
  301. offSet = 54;
  302. for (int x = 0; x < Width; x++)
  303. for (int y = 0; y < Height; y++)
  304. {//total 15
  305. if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
  306. Cells[x, y] = Cell.HighWall; //Can Fire Over.
  307. offSet += 6;
  308. if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
  309. Cells[x, y] = Cell.LowWall; //Can't Fire Over.
  310. //offSet += 2;
  311. if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
  312. offSet += 2;
  313. if (fileBytes[offSet] > 0)
  314. DoorIndex[x, y] = AddDoor(fileBytes[offSet], new Point(x, y));
  315. offSet += 4;
  316. byte light = fileBytes[offSet++];
  317. if (light >= 100 && light <= 119)
  318. Cells[x, y].FishingAttribute = (sbyte)(light - 100);
  319. offSet += 2;
  320. }
  321. }
  322. private void LoadMapCellsV100(byte[] Bytes)
  323. {
  324. int offset = 4;
  325. if ((Bytes[0] != 1) || (Bytes[1] != 0)) return;//only support version 1 atm
  326. Width = BitConverter.ToInt16(Bytes, offset);
  327. offset += 2;
  328. Height = BitConverter.ToInt16(Bytes, offset);
  329. Cells = new Cell[Width, Height];
  330. DoorIndex = new Door[Width, Height];
  331. offset = 8;
  332. for (int x = 0; x < Width; x++)
  333. for (int y = 0; y < Height; y++)
  334. {
  335. offset += 2;
  336. if ((BitConverter.ToInt32(Bytes, offset) & 0x20000000) != 0)
  337. Cells[x, y] = Cell.HighWall; //Can Fire Over.
  338. offset += 10;
  339. if ((BitConverter.ToInt16(Bytes, offset) & 0x8000) != 0)
  340. Cells[x, y] = Cell.LowWall; //Can't Fire Over.
  341. if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
  342. offset += 2;
  343. if (Bytes[offset] > 0)
  344. DoorIndex[x, y] = AddDoor(Bytes[offset], new Point(x, y));
  345. offset += 11;
  346. byte light = Bytes[offset++];
  347. if (light >= 100 && light <= 119)
  348. Cells[x, y].FishingAttribute = (sbyte)(light - 100);
  349. }
  350. }
  351. public bool Load()
  352. {
  353. try
  354. {
  355. string fileName = Path.Combine(Settings.MapPath, Info.FileName + ".map");
  356. if (File.Exists(fileName))
  357. {
  358. byte[] fileBytes = File.ReadAllBytes(fileName);
  359. switch(FindType(fileBytes))
  360. {
  361. case 0:
  362. LoadMapCellsv0(fileBytes);
  363. break;
  364. case 1:
  365. LoadMapCellsv1(fileBytes);
  366. break;
  367. case 2:
  368. LoadMapCellsv2(fileBytes);
  369. break;
  370. case 3:
  371. LoadMapCellsv3(fileBytes);
  372. break;
  373. case 4:
  374. LoadMapCellsv4(fileBytes);
  375. break;
  376. case 5:
  377. LoadMapCellsv5(fileBytes);
  378. break;
  379. case 6:
  380. LoadMapCellsv6(fileBytes);
  381. break;
  382. case 7:
  383. LoadMapCellsv7(fileBytes);
  384. break;
  385. case 100:
  386. LoadMapCellsV100(fileBytes);
  387. break;
  388. }
  389. GetWalkableCells();
  390. for (int i = 0; i < Info.Respawns.Count; i++)
  391. {
  392. MapRespawn info = new MapRespawn(Info.Respawns[i]);
  393. if (info.Monster == null) continue;
  394. info.Map = this;
  395. info.WalkableCells = WalkableCells.Where(x =>
  396. x.X <= info.Info.Location.X + info.Info.Spread &&
  397. x.X >= info.Info.Location.X - info.Info.Spread &&
  398. x.Y <= info.Info.Location.Y + info.Info.Spread &&
  399. x.Y >= info.Info.Location.Y - info.Info.Spread).ToList();
  400. Respawns.Add(info);
  401. if ((info.Info.SaveRespawnTime) && (info.Info.RespawnTicks != 0))
  402. Envir.SavedSpawns.Add(info);
  403. }
  404. for (int i = 0; i < Info.NPCs.Count; i++)
  405. {
  406. NPCInfo info = Info.NPCs[i];
  407. if (!ValidPoint(info.Location)) continue;
  408. AddObject(new NPCObject(info) { CurrentMap = this });
  409. }
  410. for (int i = 0; i < Info.SafeZones.Count; i++)
  411. CreateSafeZone(Info.SafeZones[i]);
  412. CreateMine();
  413. return true;
  414. }
  415. }
  416. catch (Exception ex)
  417. {
  418. MessageQueue.Enqueue(ex);
  419. }
  420. MessageQueue.Enqueue(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.FailedToLoadMap) + Info.Title);
  421. MessageQueue.Enqueue(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.Filename) + Info.FileName);
  422. return false;
  423. }
  424. public void GetWalkableCells()
  425. {
  426. if (WalkableCells == null)
  427. {
  428. WalkableCells = new List<Point>();
  429. for (int x = 0; x < Width; x++)
  430. for (int y = 0; y < Height; y++)
  431. if (Cells[x, y].Attribute == CellAttribute.Walk)
  432. WalkableCells.Add(new Point(x, y));
  433. }
  434. }
  435. private void CreateSafeZone(SafeZoneInfo info)
  436. {
  437. if (Settings.SafeZoneBorder)
  438. {
  439. for (int y = info.Location.Y - info.Size; y <= info.Location.Y + info.Size; y++)
  440. {
  441. if (y < 0) continue;
  442. if (y >= Height) break;
  443. for (int x = info.Location.X - info.Size; x <= info.Location.X + info.Size; x += Math.Abs(y - info.Location.Y) == info.Size ? 1 : info.Size * 2)
  444. {
  445. if (x < 0) continue;
  446. if (x >= Width) break;
  447. if (!Cells[x, y].Valid) continue;
  448. SpellObject spell = new SpellObject
  449. {
  450. ExpireTime = long.MaxValue,
  451. Spell = Spell.TrapHexagon,
  452. TickSpeed = int.MaxValue,
  453. CurrentLocation = new Point(x, y),
  454. CurrentMap = this,
  455. Decoration = true
  456. };
  457. Cells[x, y].Add(spell);
  458. spell.Spawned();
  459. }
  460. }
  461. }
  462. if (Settings.SafeZoneHealing)
  463. {
  464. for (int y = info.Location.Y - info.Size; y <= info.Location.Y + info.Size; y++)
  465. {
  466. if (y < 0) continue;
  467. if (y >= Height) break;
  468. for (int x = info.Location.X - info.Size; x <= info.Location.X + info.Size; x++)
  469. {
  470. if (x < 0) continue;
  471. if (x >= Width) break;
  472. if (!Cells[x, y].Valid) continue;
  473. SpellObject spell = new SpellObject
  474. {
  475. ExpireTime = long.MaxValue,
  476. Value = 25,
  477. TickSpeed = 2000,
  478. Spell = Spell.Healing,
  479. CurrentLocation = new Point(x, y),
  480. CurrentMap = this
  481. };
  482. Cells[x, y].Add(spell);
  483. spell.Spawned();
  484. }
  485. }
  486. }
  487. }
  488. private void CreateMine()
  489. {
  490. if ((Info.MineIndex == 0) && (Info.MineZones.Count == 0)) return;
  491. Mine = new MineSpot[Width, Height];
  492. for (int i = 0; i < Width; i++)
  493. for (int j = 0; j < Height; j++)
  494. Mine[i, j] = new MineSpot();
  495. if ((Info.MineIndex != 0) && (Settings.MineSetList.Count > Info.MineIndex - 1))
  496. {
  497. Settings.MineSetList[Info.MineIndex - 1].SetDrops(Envir.ItemInfoList);
  498. for (int i = 0; i < Width; i++)
  499. for (int j = 0; j < Height; j++)
  500. Mine[i,j].Mine = Settings.MineSetList[Info.MineIndex - 1];
  501. }
  502. if (Info.MineZones.Count > 0)
  503. {
  504. for (int i = 0; i < Info.MineZones.Count; i++)
  505. {
  506. MineZone Zone = Info.MineZones[i];
  507. if (Zone.Mine != 0)
  508. Settings.MineSetList[Zone.Mine - 1].SetDrops(Envir.ItemInfoList);
  509. if (Settings.MineSetList.Count < Zone.Mine) continue;
  510. for (int x = Zone.Location.X - Zone.Size; x < Zone.Location.X + Zone.Size; x++)
  511. for (int y = Zone.Location.Y - Zone.Size; y < Zone.Location.Y + Zone.Size; y++)
  512. {
  513. if ((x < 0) || (x >= Width) || (y < 0) || (y >= Height)) continue;
  514. if (Zone.Mine == 0)
  515. Mine[x, y].Mine = null;
  516. else
  517. Mine[x, y].Mine = Settings.MineSetList[Zone.Mine - 1];
  518. }
  519. }
  520. }
  521. }
  522. public Cell GetCell(Point location)
  523. {
  524. return Cells[location.X, location.Y];
  525. }
  526. public Cell GetCell(int x, int y)
  527. {
  528. return Cells[x, y];
  529. }
  530. public bool ValidPoint(Point location)
  531. {
  532. return location.X >= 0 && location.X < Width && location.Y >= 0 && location.Y < Height && GetCell(location).Valid;
  533. }
  534. public bool ValidPoint(int x, int y)
  535. {
  536. return x >= 0 && x < Width && y >= 0 && y < Height && GetCell(x, y).Valid;
  537. }
  538. public bool CheckDoorOpen(Point location)
  539. {
  540. if (DoorIndex[location.X, location.Y] == null) return true;
  541. if (DoorIndex[location.X, location.Y].DoorState != DoorState.Open) return false;
  542. return true;
  543. }
  544. public void Process()
  545. {
  546. ProcessRespawns();
  547. for (int i = 0; i < Doors.Count; i++)
  548. {
  549. if ((Doors[i].DoorState == DoorState.Open) && (Doors[i].LastTick + 5000 < Envir.Time))
  550. {
  551. Doors[i].DoorState = 0;
  552. Broadcast(new S.Opendoor() { DoorIndex = Doors[i].index, Close = true }, Doors[i].Location);
  553. }
  554. }
  555. if ((Info.Lightning) && Envir.Time > LightningTime)
  556. {
  557. LightningTime = Envir.Time + Envir.Random.Next(3000, 15000);
  558. for (int i = Players.Count - 1; i >= 0; i--)
  559. {
  560. PlayerObject player = Players[i];
  561. Point location;
  562. if (Envir.Random.Next(4) == 0)
  563. {
  564. location = player.CurrentLocation;
  565. }
  566. else
  567. location = new Point(player.CurrentLocation.X - 10 + Envir.Random.Next(20), player.CurrentLocation.Y - 10 + Envir.Random.Next(20));
  568. if (!ValidPoint(location)) continue;
  569. SpellObject lightning = new SpellObject
  570. {
  571. Spell = Spell.MapLightning,
  572. Value = Envir.Random.Next(Info.LightningDamage),
  573. ExpireTime = Envir.Time + (1000),
  574. TickSpeed = 500,
  575. Caster = null,
  576. CurrentLocation = location,
  577. CurrentMap = this,
  578. Direction = MirDirection.Up
  579. };
  580. AddObject(lightning);
  581. lightning.Spawned();
  582. }
  583. }
  584. if ((Info.Fire) && Envir.Time > FireTime)
  585. {
  586. FireTime = Envir.Time + Envir.Random.Next(3000, 15000);
  587. for (int i = Players.Count - 1; i >= 0; i--)
  588. {
  589. PlayerObject player = Players[i];
  590. Point location;
  591. if (Envir.Random.Next(4) == 0)
  592. {
  593. location = player.CurrentLocation;
  594. }
  595. else
  596. location = new Point(player.CurrentLocation.X - 10 + Envir.Random.Next(20), player.CurrentLocation.Y - 10 + Envir.Random.Next(20));
  597. if (!ValidPoint(location)) continue;
  598. SpellObject lightning = new SpellObject
  599. {
  600. Spell = Spell.MapLava,
  601. Value = Envir.Random.Next(Info.FireDamage),
  602. ExpireTime = Envir.Time + (1000),
  603. TickSpeed = 500,
  604. Caster = null,
  605. CurrentLocation = location,
  606. CurrentMap = this,
  607. Direction = MirDirection.Up
  608. };
  609. AddObject(lightning);
  610. lightning.Spawned();
  611. }
  612. }
  613. for (int i = 0; i < ActionList.Count; i++)
  614. {
  615. if (Envir.Time < ActionList[i].Time) continue;
  616. Process(ActionList[i]);
  617. ActionList.RemoveAt(i);
  618. }
  619. }
  620. private void ProcessRespawns()
  621. {
  622. bool Success = true;
  623. for (int i = 0; i < Respawns.Count; i++)
  624. {
  625. MapRespawn respawn = Respawns[i];
  626. if ((respawn.Info.RespawnTicks != 0) && (Envir.RespawnTick.CurrentTickcounter < respawn.NextSpawnTick)) continue;
  627. if ((respawn.Info.RespawnTicks == 0) && (Envir.Time < respawn.RespawnTime)) continue;
  628. if (respawn.Count < (respawn.Info.Count * Envir.SpawnMultiplier))
  629. {
  630. int count = (respawn.Info.Count * Envir.SpawnMultiplier) - respawn.Count;
  631. for (int c = 0; c < count; c++)
  632. Success = respawn.Spawn();
  633. }
  634. if (Success)
  635. {
  636. respawn.ErrorCount = 0;
  637. long delay = Math.Max(1, respawn.Info.Delay - respawn.Info.RandomDelay + Envir.Random.Next(respawn.Info.RandomDelay * 2));
  638. respawn.RespawnTime = Envir.Time + (delay * Settings.Minute);
  639. if (respawn.Info.RespawnTicks != 0)
  640. {
  641. respawn.NextSpawnTick = Envir.RespawnTick.CurrentTickcounter + (ulong)respawn.Info.RespawnTicks;
  642. if (respawn.NextSpawnTick > long.MaxValue)//since nextspawntick is ulong this simple thing allows an easy way of preventing the counter from overflowing
  643. respawn.NextSpawnTick -= long.MaxValue;
  644. }
  645. }
  646. else
  647. {
  648. respawn.RespawnTime = Envir.Time + 1 * Settings.Minute; // each time it fails to spawn, give it a 1 minute cooldown
  649. if (respawn.ErrorCount < 5)
  650. respawn.ErrorCount++;
  651. else
  652. {
  653. if (respawn.ErrorCount == 5)
  654. {
  655. respawn.ErrorCount++;
  656. Logger.GetLogger(LogType.Spawn).Info($"Failed to spawn: " +
  657. $"mapindex: {respawn.Map.Info.Index}, " +
  658. $"mob info: index: {respawn.Info.MonsterIndex}, " +
  659. $"name: {respawn.Monster.Name}, " +
  660. $"spawncoords ({respawn.Info.Location.X}:{respawn.Info.Location.Y}), " +
  661. $"range {respawn.Info.Spread}");
  662. }
  663. }
  664. }
  665. }
  666. }
  667. public void Process(DelayedAction action)
  668. {
  669. switch (action.Type)
  670. {
  671. case DelayedType.Magic:
  672. CompleteMagic(action.Params);
  673. break;
  674. case DelayedType.Spawn:
  675. MapObject obj = (MapObject)action.Params[0];
  676. switch(obj.Race)
  677. {
  678. case ObjectType.Monster:
  679. {
  680. MonsterObject mob = (MonsterObject)action.Params[0];
  681. mob.Spawn(this, (Point)action.Params[1]);
  682. if (action.Params.Length > 2) ((MonsterObject)action.Params[2]).SlaveList.Add(mob);
  683. }
  684. break;
  685. case ObjectType.Spell:
  686. {
  687. SpellObject spell = (SpellObject)action.Params[0];
  688. AddObject(spell);
  689. spell.Spawned();
  690. }
  691. break;
  692. }
  693. break;
  694. }
  695. }
  696. /**
  697. * return the coordinates of effect coordinates within an n x n square (n should be odd number. i.e. 3x3, 5x5, 7x7)
  698. * then use GetCell() in Map.cs to retrive real objects
  699. * default 3x3
  700. */
  701. public static List<Point> GetPointsInEffectiveSquare(Point location, int mapWidth, int mapHeight, int squareEdgeLength = 3)
  702. {
  703. var pointsWithinTheMap = new List<Point>();
  704. int fallBackSpread = 1;
  705. int spread;
  706. if (squareEdgeLength > 1)
  707. {
  708. spread = (int)((squareEdgeLength - 1) / 2);
  709. } else
  710. {
  711. spread = fallBackSpread; // 3x3
  712. }
  713. for (int y = location.Y - spread; y <= location.Y + spread; y++)
  714. {
  715. if (y < 0) continue;
  716. if (y >= mapHeight) break;
  717. for (int x = location.X - spread; x <= location.X + spread; x++)
  718. {
  719. if (x < 0) continue;
  720. if (x >= mapWidth) break;
  721. pointsWithinTheMap.Add(new Point(x, y));
  722. }
  723. }
  724. return pointsWithinTheMap;
  725. }
  726. private void CompleteMagic(IList<object> data)
  727. {
  728. bool train = false;
  729. HumanObject player = (HumanObject)data[0];
  730. UserMagic magic = (UserMagic)data[1];
  731. if (player == null || player.Info == null || player.Node == null) return;
  732. int value, value2;
  733. Point location;
  734. Cell cell;
  735. MirDirection dir;
  736. MonsterObject monster;
  737. Point front;
  738. switch (magic.Spell)
  739. {
  740. #region HellFire
  741. case Spell.HellFire:
  742. value = (int)data[2];
  743. dir = (MirDirection)data[4];
  744. location = Functions.PointMove((Point)data[3], dir, 1);
  745. int count = (int)data[5] - 1;
  746. if (!ValidPoint(location)) return;
  747. if (count > 0)
  748. {
  749. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 100, player, magic, value, location, dir, count);
  750. ActionList.Add(action);
  751. }
  752. cell = GetCell(location);
  753. if (cell.Objects == null) return;
  754. for (int i = 0; i < cell.Objects.Count; i++)
  755. {
  756. MapObject target = cell.Objects[i];
  757. switch (target.Race)
  758. {
  759. case ObjectType.Monster:
  760. case ObjectType.Player:
  761. //Only targets
  762. if (target.IsAttackTarget(player))
  763. {
  764. if (target.Attacked(player, value, DefenceType.MAC, false) > 0)
  765. train = true;
  766. break;
  767. }
  768. break;
  769. }
  770. }
  771. break;
  772. #endregion
  773. #region SummonSkeleton, SummonShinsu, SummonHolyDeva, ArcherSummons
  774. case Spell.SummonSkeleton:
  775. case Spell.SummonShinsu:
  776. case Spell.SummonHolyDeva:
  777. case Spell.SummonVampire:
  778. case Spell.SummonToad:
  779. case Spell.SummonSnakes:
  780. monster = (MonsterObject)data[2];
  781. front = (Point)data[3];
  782. if (monster.Master.Dead) return;
  783. if (ValidPoint(front))
  784. monster.Spawn(this, front);
  785. else
  786. monster.Spawn(player.CurrentMap, player.CurrentLocation);
  787. monster.Master.Pets.Add(monster);
  788. break;
  789. case Spell.Stonetrap:
  790. monster = (MonsterObject)data[2];
  791. front = (Point)data[3];
  792. if (monster.Master.Dead) return;
  793. if (ValidPoint(front))
  794. monster.Spawn(this, front);
  795. else
  796. monster.Spawn(player.CurrentMap, player.CurrentLocation);
  797. monster.Master.Pets.Add(monster);
  798. break;
  799. #endregion
  800. #region FireBang, IceStorm
  801. case Spell.IceStorm:
  802. case Spell.FireBang:
  803. value = (int)data[2];
  804. location = (Point)data[3];
  805. for (int y = location.Y - 1; y <= location.Y + 1; y++)
  806. {
  807. if (y < 0) continue;
  808. if (y >= Height) break;
  809. for (int x = location.X - 1; x <= location.X + 1; x++)
  810. {
  811. if (x < 0) continue;
  812. if (x >= Width) break;
  813. cell = GetCell(x, y);
  814. if (!cell.Valid || cell.Objects == null) continue;
  815. for (int i = 0; i < cell.Objects.Count; i++)
  816. {
  817. MapObject target = cell.Objects[i];
  818. switch (target.Race)
  819. {
  820. case ObjectType.Monster:
  821. case ObjectType.Player:
  822. //Only targets
  823. if (target.IsAttackTarget(player))
  824. {
  825. if (target.Attacked(player, value, DefenceType.MAC, false) > 0)
  826. train = true;
  827. }
  828. break;
  829. }
  830. }
  831. }
  832. }
  833. break;
  834. #endregion
  835. #region MassHiding
  836. case Spell.MassHiding:
  837. value = (int)data[2];
  838. location = (Point)data[3];
  839. for (int y = location.Y - 1; y <= location.Y + 1; y++)
  840. {
  841. if (y < 0) continue;
  842. if (y >= Height) break;
  843. for (int x = location.X - 1; x <= location.X + 1; x++)
  844. {
  845. if (x < 0) continue;
  846. if (x >= Width) break;
  847. cell = GetCell(x, y);
  848. if (!cell.Valid || cell.Objects == null) continue;
  849. for (int i = 0; i < cell.Objects.Count; i++)
  850. {
  851. MapObject target = cell.Objects[i];
  852. if (target.Node == null) continue;
  853. switch (target.Race)
  854. {
  855. case ObjectType.Monster:
  856. case ObjectType.Player:
  857. //Only targets
  858. if (target.IsFriendlyTarget(player))
  859. {
  860. target.AddBuff(BuffType.Hiding, player, (Settings.Second * value), new Stats());
  861. target.OperateTime = 0;
  862. train = true;
  863. }
  864. break;
  865. }
  866. }
  867. }
  868. }
  869. break;
  870. #endregion
  871. #region SoulShield, BlessedArmour
  872. case Spell.SoulShield:
  873. case Spell.BlessedArmour:
  874. value = (int)data[2];
  875. location = (Point)data[3];
  876. BuffType type = magic.Spell == Spell.SoulShield ? BuffType.SoulShield : BuffType.BlessedArmour;
  877. for (int y = location.Y - 3; y <= location.Y + 3; y++)
  878. {
  879. if (y < 0) continue;
  880. if (y >= Height) break;
  881. for (int x = location.X - 3; x <= location.X + 3; x++)
  882. {
  883. if (x < 0) continue;
  884. if (x >= Width) break;
  885. cell = GetCell(x, y);
  886. if (!cell.Valid || cell.Objects == null) continue;
  887. for (int i = 0; i < cell.Objects.Count; i++)
  888. {
  889. MapObject target = cell.Objects[i];
  890. if (target.Node == null) continue;
  891. switch (target.Race)
  892. {
  893. case ObjectType.Monster:
  894. case ObjectType.Player:
  895. case ObjectType.Hero:
  896. //Only targets
  897. if (target.IsFriendlyTarget(player))
  898. {
  899. var stats = new Stats
  900. {
  901. [type == BuffType.SoulShield ? Stat.MaxMAC : Stat.MaxAC] = target.Level / 7 + 4
  902. };
  903. target.AddBuff(type, player, Settings.Second * value, stats);
  904. target.OperateTime = 0;
  905. train = true;
  906. }
  907. break;
  908. }
  909. }
  910. }
  911. }
  912. break;
  913. #endregion
  914. #region FireWall
  915. case Spell.FireWall:
  916. value = (int)data[2];
  917. location = (Point)data[3];
  918. int castId = 0;
  919. if (data.Count >= 5 && data[4] is int ci) castId = ci;
  920. player.LevelMagic(magic);
  921. if (ValidPoint(location))
  922. {
  923. cell = GetCell(location);
  924. bool cast = true;
  925. if (cell.Objects != null)
  926. for (int o = 0; o < cell.Objects.Count; o++)
  927. {
  928. MapObject target = cell.Objects[o];
  929. if (target.Race != ObjectType.Spell || ((SpellObject)target).Spell != Spell.FireWall) continue;
  930. cast = false;
  931. break;
  932. }
  933. if (cast)
  934. {
  935. SpellObject ob = new SpellObject
  936. {
  937. Spell = Spell.FireWall,
  938. Value = value,
  939. ExpireTime = Envir.Time + (10 + value / 2) * 1000,
  940. TickSpeed = 2000,
  941. Caster = player,
  942. CurrentLocation = location,
  943. CurrentMap = this,
  944. CastInstanceId = castId
  945. };
  946. AddObject(ob);
  947. ob.Spawned();
  948. }
  949. }
  950. dir = MirDirection.Up;
  951. for (int i = 0; i < 4; i++)
  952. {
  953. location = Functions.PointMove((Point)data[3], dir, 1);
  954. dir += 2;
  955. if (!ValidPoint(location)) continue;
  956. cell = GetCell(location);
  957. bool cast = true;
  958. if (cell.Objects != null)
  959. for (int o = 0; o < cell.Objects.Count; o++)
  960. {
  961. MapObject target = cell.Objects[o];
  962. if (target.Race != ObjectType.Spell || ((SpellObject)target).Spell != Spell.FireWall) continue;
  963. cast = false;
  964. break;
  965. }
  966. if (!cast) continue;
  967. SpellObject ob = new SpellObject
  968. {
  969. Spell = Spell.FireWall,
  970. Value = value,
  971. ExpireTime = Envir.Time + (10 + value / 2) * 1000,
  972. TickSpeed = 2000,
  973. Caster = player,
  974. CurrentLocation = location,
  975. CurrentMap = this,
  976. CastInstanceId = castId
  977. };
  978. AddObject(ob);
  979. ob.Spawned();
  980. }
  981. break;
  982. #endregion
  983. #region Lightning
  984. case Spell.Lightning:
  985. value = (int)data[2];
  986. location = (Point)data[3];
  987. dir = (MirDirection)data[4];
  988. for (int i = 0; i < 6; i++)
  989. {
  990. location = Functions.PointMove(location, dir, 1);
  991. if (!ValidPoint(location)) continue;
  992. cell = GetCell(location);
  993. if (cell.Objects == null) continue;
  994. for (int o = 0; o < cell.Objects.Count; o++)
  995. {
  996. MapObject target = cell.Objects[o];
  997. if (target.Race != ObjectType.Player && target.Race != ObjectType.Monster) continue;
  998. if (!target.IsAttackTarget(player)) continue;
  999. if (target.Attacked(player, value, DefenceType.MAC, false) > 0)
  1000. train = true;
  1001. break;
  1002. }
  1003. }
  1004. break;
  1005. #endregion
  1006. #region HeavenlySword
  1007. case Spell.HeavenlySword:
  1008. value = (int)data[2];
  1009. location = (Point)data[3];
  1010. dir = (MirDirection)data[4];
  1011. for (int i = 0; i < 3; i++)
  1012. {
  1013. location = Functions.PointMove(location, dir, 1);
  1014. if (!ValidPoint(location)) continue;
  1015. cell = GetCell(location);
  1016. if (cell.Objects == null) continue;
  1017. for (int o = 0; o < cell.Objects.Count; o++)
  1018. {
  1019. MapObject target = cell.Objects[o];
  1020. if (target.Race != ObjectType.Player && target.Race != ObjectType.Monster) continue;
  1021. if (!target.IsAttackTarget(player)) continue;
  1022. if (target.Attacked(player, value, DefenceType.MAC, false) > 0)
  1023. train = true;
  1024. break;
  1025. }
  1026. }
  1027. break;
  1028. #endregion
  1029. #region MassHealing
  1030. case Spell.MassHealing:
  1031. value = (int)data[2];
  1032. location = (Point)data[3];
  1033. for (int y = location.Y - 1; y <= location.Y + 1; y++)
  1034. {
  1035. if (y < 0) continue;
  1036. if (y >= Height) break;
  1037. for (int x = location.X - 1; x <= location.X + 1; x++)
  1038. {
  1039. if (x < 0) continue;
  1040. if (x >= Width) break;
  1041. cell = GetCell(x, y);
  1042. if (!cell.Valid || cell.Objects == null) continue;
  1043. for (int i = 0; i < cell.Objects.Count; i++)
  1044. {
  1045. MapObject target = cell.Objects[i];
  1046. switch (target.Race)
  1047. {
  1048. case ObjectType.Monster:
  1049. case ObjectType.Player:
  1050. case ObjectType.Hero:
  1051. //Only targets
  1052. if (target.IsFriendlyTarget(player))
  1053. {
  1054. if (target.Health >= target.MaxHealth) continue;
  1055. target.HealAmount = (ushort)Math.Min(ushort.MaxValue, target.HealAmount + value);
  1056. target.OperateTime = 0;
  1057. train = true;
  1058. }
  1059. break;
  1060. }
  1061. }
  1062. }
  1063. }
  1064. break;
  1065. #endregion
  1066. #region ThunderStorm
  1067. case Spell.ThunderStorm:
  1068. case Spell.FlameField:
  1069. case Spell.NapalmShot:
  1070. case Spell.StormEscape:
  1071. value = (int)data[2];
  1072. location = (Point)data[3];
  1073. for (int y = location.Y - 2; y <= location.Y + 2; y++)
  1074. {
  1075. if (y < 0) continue;
  1076. if (y >= Height) break;
  1077. for (int x = location.X - 2; x <= location.X + 2; x++)
  1078. {
  1079. if (x < 0) continue;
  1080. if (x >= Width) break;
  1081. cell = GetCell(x, y);
  1082. if (!cell.Valid || cell.Objects == null) continue;
  1083. for (int i = 0; i < cell.Objects.Count; i++)
  1084. {
  1085. MapObject target = cell.Objects[i];
  1086. switch (target.Race)
  1087. {
  1088. case ObjectType.Monster:
  1089. case ObjectType.Player:
  1090. //Only targets
  1091. if (!target.IsAttackTarget(player)) break;
  1092. target.Attacked(player, magic.Spell == Spell.ThunderStorm && !target.Undead ? value / 10 : value, DefenceType.MAC, false);
  1093. train = true;
  1094. break;
  1095. }
  1096. }
  1097. }
  1098. }
  1099. break;
  1100. #endregion
  1101. #region MoonMist
  1102. case Spell.MoonMist:
  1103. value = (int)data[2];
  1104. location = (Point)data[3];
  1105. for (int y = location.Y - 2; y <= location.Y + 2; y++)
  1106. {
  1107. if (y < 0) continue;
  1108. if (y >= Height) break;
  1109. for (int x = location.X - 2; x <= location.X + 2; x++)
  1110. {
  1111. if (x < 0) continue;
  1112. if (x >= Width) break;
  1113. cell = GetCell(x, y);
  1114. if (!cell.Valid || cell.Objects == null) continue;
  1115. for (int i = 0; i < cell.Objects.Count; i++)
  1116. {
  1117. MapObject target = cell.Objects[i];
  1118. switch (target.Race)
  1119. {
  1120. case ObjectType.Monster:
  1121. case ObjectType.Player:
  1122. //Only targets
  1123. if (!target.IsAttackTarget(player)) break;
  1124. if (target.Attacked(player, magic.Spell == Spell.ThunderStorm && !target.Undead ? value / 10 : value, DefenceType.AC, false) <= 0)
  1125. {
  1126. if (target.Undead)
  1127. {
  1128. target.ApplyPoison(new Poison { PType = PoisonType.Stun, Duration = magic.Level + 2, TickSpeed = 1000 }, player);
  1129. }
  1130. break;
  1131. }
  1132. train = true;
  1133. break;
  1134. }
  1135. }
  1136. }
  1137. }
  1138. break;
  1139. #endregion
  1140. #region LionRoar
  1141. case Spell.LionRoar:
  1142. location = (Point)data[2];
  1143. for (int y = location.Y - 2; y <= location.Y + 2; y++)
  1144. {
  1145. if (y < 0) continue;
  1146. if (y >= Height) break;
  1147. for (int x = location.X - 2; x <= location.X + 2; x++)
  1148. {
  1149. if (x < 0) continue;
  1150. if (x >= Width) break;
  1151. cell = GetCell(x, y);
  1152. if (!cell.Valid || cell.Objects == null) continue;
  1153. for (int i = 0; i < cell.Objects.Count; i++)
  1154. {
  1155. MapObject target = cell.Objects[i];
  1156. if (target.Race != ObjectType.Monster) continue;
  1157. //Only targets
  1158. if (!target.IsAttackTarget(player) || player.Level + 3 < target.Level) continue;
  1159. target.ApplyPoison(new Poison { PType = PoisonType.LRParalysis, Duration = magic.Level + 2, TickSpeed = 1000 }, player);
  1160. target.OperateTime = 0;
  1161. train = true;
  1162. }
  1163. }
  1164. }
  1165. break;
  1166. #endregion
  1167. #region PoisonCloud
  1168. case Spell.PoisonCloud:
  1169. value = (int)data[2];
  1170. location = (Point)data[3];
  1171. byte bonusdmg = (byte)data[4];
  1172. train = true;
  1173. bool show = true;
  1174. for (int y = location.Y - 1; y <= location.Y + 1; y++)
  1175. {
  1176. if (y < 0) continue;
  1177. if (y >= Height) break;
  1178. for (int x = location.X - 1; x <= location.X + 1; x++)
  1179. {
  1180. if (x < 0) continue;
  1181. if (x >= Width) break;
  1182. cell = GetCell(x, y);
  1183. if (!cell.Valid) continue;
  1184. bool cast = true;
  1185. if (cell.Objects != null)
  1186. for (int o = 0; o < cell.Objects.Count; o++)
  1187. {
  1188. MapObject target = cell.Objects[o];
  1189. if (target.Race != ObjectType.Spell || ((SpellObject)target).Spell != Spell.PoisonCloud) continue;
  1190. cast = false;
  1191. break;
  1192. }
  1193. if (!cast) continue;
  1194. SpellObject ob = new SpellObject
  1195. {
  1196. Spell = Spell.PoisonCloud,
  1197. Value = value,
  1198. BonusDmg = bonusdmg,
  1199. ExpireTime = Envir.Time + 6000,
  1200. TickSpeed = 1000,
  1201. Caster = player,
  1202. CurrentLocation = new Point(x, y),
  1203. CastLocation = location,
  1204. Show = show,
  1205. CurrentMap = this,
  1206. };
  1207. show = false;
  1208. AddObject(ob);
  1209. ob.Spawned();
  1210. }
  1211. }
  1212. break;
  1213. #endregion
  1214. #region IceThrust
  1215. case Spell.IceThrust:
  1216. {
  1217. location = (Point)data[2];
  1218. MirDirection direction = (MirDirection)data[3];
  1219. int nearDamage = (int)data[4];
  1220. int farDamage = (int)data[5];
  1221. int col = 3;
  1222. int row = 3;
  1223. Point[] loc = new Point[col]; //0 = left 1 = center 2 = right
  1224. loc[0] = Functions.PointMove(location, Functions.PreviousDir(direction), 1);
  1225. loc[1] = Functions.PointMove(location, direction, 1);
  1226. loc[2] = Functions.PointMove(location, Functions.NextDir(direction), 1);
  1227. for (int i = 0; i < col; i++)
  1228. {
  1229. Point startPoint = loc[i];
  1230. for (int j = 0; j < row; j++)
  1231. {
  1232. Point hitPoint = Functions.PointMove(startPoint, direction, j);
  1233. if (!ValidPoint(hitPoint)) continue;
  1234. cell = GetCell(hitPoint);
  1235. if (cell.Objects == null) continue;
  1236. for (int k = 0; k < cell.Objects.Count; k++)
  1237. {
  1238. MapObject target = cell.Objects[k];
  1239. switch (target.Race)
  1240. {
  1241. case ObjectType.Monster:
  1242. case ObjectType.Player:
  1243. if (target.IsAttackTarget(player))
  1244. {
  1245. //Only targets
  1246. if (target.Attacked(player, j <= 1 ? nearDamage : farDamage, DefenceType.MAC, false) > 0)
  1247. {
  1248. if (player.Level + (target.Race == ObjectType.Player ? 2 : 10) >= target.Level && Envir.Random.Next(target.Race == ObjectType.Player ? 100 : 20) <= magic.Level)
  1249. {
  1250. target.ApplyPoison(new Poison
  1251. {
  1252. Owner = player,
  1253. Duration = target.Race == ObjectType.Player ? 4 : 5 + Envir.Random.Next(5),
  1254. PType = PoisonType.Slow,
  1255. TickSpeed = 1000,
  1256. }, player);
  1257. target.OperateTime = 0;
  1258. }
  1259. if (player.Level + (target.Race == ObjectType.Player ? 2 : 10) >= target.Level && Envir.Random.Next(target.Race == ObjectType.Player ? 100 : 40) <= magic.Level)
  1260. {
  1261. target.ApplyPoison(new Poison
  1262. {
  1263. Owner = player,
  1264. Duration = target.Race == ObjectType.Player ? 2 : 5 + Envir.Random.Next(player.Stats[Stat.Freezing]),
  1265. PType = PoisonType.Frozen,
  1266. TickSpeed = 1000,
  1267. }, player);
  1268. target.OperateTime = 0;
  1269. }
  1270. train = true;
  1271. }
  1272. }
  1273. break;
  1274. }
  1275. }
  1276. }
  1277. }
  1278. }
  1279. break;
  1280. #endregion
  1281. #region SlashingBurst
  1282. case Spell.SlashingBurst:
  1283. value = (int)data[2];
  1284. location = (Point)data[3];
  1285. dir = (MirDirection)data[4];
  1286. count = (int)data[5];
  1287. for (int i = 0; i < count; i++)
  1288. {
  1289. location = Functions.PointMove(location, dir, 1);
  1290. if (!ValidPoint(location)) continue;
  1291. cell = GetCell(location);
  1292. if (cell.Objects == null) continue;
  1293. for (int o = 0; o < cell.Objects.Count; o++)
  1294. {
  1295. MapObject target = cell.Objects[o];
  1296. if (target.Race != ObjectType.Player && target.Race != ObjectType.Monster) continue;
  1297. if (!target.IsAttackTarget(player)) continue;
  1298. if (target.Attacked(player, value, DefenceType.AC, false) > 0)
  1299. train = true;
  1300. break;
  1301. }
  1302. }
  1303. break;
  1304. #endregion
  1305. #region Mirroring
  1306. case Spell.Mirroring:
  1307. monster = (MonsterObject)data[2];
  1308. front = (Point)data[3];
  1309. bool finish = (bool)data[4];
  1310. if (finish)
  1311. {
  1312. monster.Die();
  1313. return;
  1314. };
  1315. if (ValidPoint(front))
  1316. monster.Spawn(this, front);
  1317. else
  1318. monster.Spawn(player.CurrentMap, player.CurrentLocation);
  1319. break;
  1320. #endregion
  1321. #region Blizzard
  1322. case Spell.Blizzard:
  1323. value = (int)data[2];
  1324. location = (Point)data[3];
  1325. train = true;
  1326. show = true;
  1327. for (int y = location.Y - 2; y <= location.Y + 2; y++)
  1328. {
  1329. if (y < 0) continue;
  1330. if (y >= Height) break;
  1331. for (int x = location.X - 2; x <= location.X + 2; x++)
  1332. {
  1333. if (x < 0) continue;
  1334. if (x >= Width) break;
  1335. cell = GetCell(x, y);
  1336. if (!cell.Valid) continue;
  1337. bool cast = true;
  1338. if (cell.Objects != null)
  1339. for (int o = 0; o < cell.Objects.Count; o++)
  1340. {
  1341. MapObject target = cell.Objects[o];
  1342. if (target.Race != ObjectType.Spell || ((SpellObject) target).Spell != Spell.Blizzard) continue;
  1343. cast = false;
  1344. break;
  1345. }
  1346. if (!cast) continue;
  1347. SpellObject ob = new SpellObject
  1348. {
  1349. Spell = Spell.Blizzard,
  1350. Value = value,
  1351. ExpireTime = Envir.Time + 3000,
  1352. TickSpeed = 440,
  1353. Caster = player,
  1354. CurrentLocation = new Point(x, y),
  1355. CastLocation = location,
  1356. Show = show,
  1357. CurrentMap = this,
  1358. StartTime = Envir.Time + 800,
  1359. };
  1360. show = false;
  1361. AddObject(ob);
  1362. ob.Spawned();
  1363. }
  1364. }
  1365. break;
  1366. #endregion
  1367. #region MeteorStrike
  1368. case Spell.MeteorStrike:
  1369. value = (int)data[2];
  1370. location = (Point)data[3];
  1371. train = true;
  1372. show = true;
  1373. for (int y = location.Y - 2; y <= location.Y + 2; y++)
  1374. {
  1375. if (y < 0) continue;
  1376. if (y >= Height) break;
  1377. for (int x = location.X - 2; x <= location.X + 2; x++)
  1378. {
  1379. if (x < 0) continue;
  1380. if (x >= Width) break;
  1381. cell = GetCell(x, y);
  1382. if (!cell.Valid) continue;
  1383. bool cast = true;
  1384. if (cell.Objects != null)
  1385. for (int o = 0; o < cell.Objects.Count; o++)
  1386. {
  1387. MapObject target = cell.Objects[o];
  1388. if (target.Race != ObjectType.Spell || ((SpellObject)target).Spell != Spell.MeteorStrike) continue;
  1389. cast = false;
  1390. break;
  1391. }
  1392. if (!cast) continue;
  1393. SpellObject ob = new SpellObject
  1394. {
  1395. Spell = Spell.MeteorStrike,
  1396. Value = value,
  1397. ExpireTime = Envir.Time + 3000,
  1398. TickSpeed = 440,
  1399. Caster = player,
  1400. CurrentLocation = new Point(x, y),
  1401. CastLocation = location,
  1402. Show = show,
  1403. CurrentMap = this,
  1404. StartTime = Envir.Time + 800,
  1405. };
  1406. show = false;
  1407. AddObject(ob);
  1408. ob.Spawned();
  1409. }
  1410. }
  1411. break;
  1412. #endregion
  1413. #region TrapHexagon
  1414. case Spell.TrapHexagon:
  1415. value = (int)data[2];
  1416. location = (Point)data[3];
  1417. MonsterObject centerTarget = null;
  1418. for (int y = location.Y - 1; y <= location.Y + 1; y++)
  1419. {
  1420. if (y < 0) continue;
  1421. if (y >= Height) break;
  1422. for (int x = location.X - 1; x <= location.X + 1; x++)
  1423. {
  1424. if (x < 0) continue;
  1425. if (x >= Width) break;
  1426. cell = GetCell(x, y);
  1427. if (!cell.Valid || cell.Objects == null) continue;
  1428. for (int i = 0; i < cell.Objects.Count; i++)
  1429. {
  1430. MapObject target = cell.Objects[i];
  1431. if (y == location.Y && x == location.X && target.Race == ObjectType.Monster)
  1432. {
  1433. centerTarget = (MonsterObject)target;
  1434. }
  1435. switch (target.Race)
  1436. {
  1437. case ObjectType.Monster:
  1438. if (target == null || !target.IsAttackTarget(player) || target.Node == null || target.Level > player.Level + 2) continue;
  1439. MonsterObject mobTarget = (MonsterObject)target;
  1440. if (centerTarget == null) centerTarget = mobTarget;
  1441. mobTarget.ShockTime = Envir.Time + value;
  1442. mobTarget.Target = null;
  1443. break;
  1444. }
  1445. }
  1446. }
  1447. }
  1448. if (centerTarget == null) return;
  1449. for (byte i = 0; i < 8; i += 2)
  1450. {
  1451. Point startpoint = Functions.PointMove(location, (MirDirection)i, 2);
  1452. for (byte j = 0; j <= 4; j += 4)
  1453. {
  1454. MirDirection spawndirection = i == 0 || i == 4 ? MirDirection.Right : MirDirection.Up;
  1455. Point spawnpoint = Functions.PointMove(startpoint, spawndirection + j, 1);
  1456. if (spawnpoint.X <= 0 || spawnpoint.X > centerTarget.CurrentMap.Width) continue;
  1457. if (spawnpoint.Y <= 0 || spawnpoint.Y > centerTarget.CurrentMap.Height) continue;
  1458. SpellObject ob = new SpellObject
  1459. {
  1460. Spell = Spell.TrapHexagon,
  1461. ExpireTime = Envir.Time + value,
  1462. TickSpeed = 100,
  1463. Caster = player,
  1464. CurrentLocation = spawnpoint,
  1465. CastLocation = location,
  1466. CurrentMap = centerTarget.CurrentMap,
  1467. Target = centerTarget,
  1468. };
  1469. centerTarget.CurrentMap.AddObject(ob);
  1470. ob.Spawned();
  1471. }
  1472. }
  1473. train = true;
  1474. break;
  1475. #endregion
  1476. #region Curse
  1477. case Spell.Curse:
  1478. value = (int)data[2];
  1479. location = (Point)data[3];
  1480. value2 = (int)data[4];
  1481. for (int y = location.Y - 3; y <= location.Y + 3; y++)
  1482. {
  1483. if (y < 0) continue;
  1484. if (y >= Height) break;
  1485. for (int x = location.X - 3; x <= location.X + 3; x++)
  1486. {
  1487. if (x < 0) continue;
  1488. if (x >= Width) break;
  1489. cell = GetCell(x, y);
  1490. if (!cell.Valid || cell.Objects == null) continue;
  1491. for (int i = 0; i < cell.Objects.Count; i++)
  1492. {
  1493. MapObject target = cell.Objects[i];
  1494. if (target.Node == null) continue;
  1495. switch (target.Race)
  1496. {
  1497. case ObjectType.Monster:
  1498. case ObjectType.Player:
  1499. if (Envir.Random.Next(10) >= 4) continue;
  1500. //Only targets
  1501. if (target.IsAttackTarget(player))
  1502. {
  1503. target.ApplyPoison(new Poison { PType = PoisonType.Slow, Duration = value, TickSpeed = 1000, Value = value2, Owner = player }, player);
  1504. var stats = new Stats
  1505. {
  1506. [Stat.MaxDCRatePercent] = value2 * -1,
  1507. [Stat.MaxMCRatePercent] = value2 * -1,
  1508. [Stat.MaxSCRatePercent] = value2 * -1,
  1509. [Stat.AttackSpeedRatePercent] = target.Race == ObjectType.Player ? value2 * -1 : 0
  1510. };
  1511. target.AddBuff(BuffType.Curse, player, Settings.Second * value, stats);
  1512. target.OperateTime = 0;
  1513. train = true;
  1514. }
  1515. break;
  1516. }
  1517. }
  1518. }
  1519. }
  1520. break;
  1521. #endregion
  1522. #region ExplosiveTrap
  1523. case Spell.ExplosiveTrap:
  1524. value = (int)data[2];
  1525. front = (Point)data[3];
  1526. int trapID = (int)data[4];
  1527. if (ValidPoint(front))
  1528. {
  1529. cell = GetCell(front);
  1530. bool cast = true;
  1531. if (cell.Objects != null)
  1532. for (int o = 0; o < cell.Objects.Count; o++)
  1533. {
  1534. MapObject target = cell.Objects[o];
  1535. if (target.Race != ObjectType.Spell || (((SpellObject)target).Spell != Spell.FireWall && ((SpellObject)target).Spell != Spell.ExplosiveTrap)) continue;
  1536. cast = false;
  1537. break;
  1538. }
  1539. if (cast)
  1540. {
  1541. player.LevelMagic(magic);
  1542. System.Drawing.Point[] traps = new Point[3];
  1543. traps[0] = front;
  1544. traps[1] = Functions.Left(front, player.Direction);
  1545. traps[2] = Functions.Right(front, player.Direction);
  1546. for (int i = 0; i <= 2; i++)
  1547. {
  1548. bool skip = false;
  1549. //for the extra spots make sure to not overlap new traps with old ones since it creates invisible double/tripple /... trap spots
  1550. if (i > 0)
  1551. {
  1552. cell = GetCell(traps[i]);
  1553. if (cell.Objects != null)
  1554. for (int o = 0; o < cell.Objects.Count; o++)
  1555. {
  1556. MapObject target = cell.Objects[o];
  1557. if (target.Race != ObjectType.Spell || (((SpellObject)target).Spell != Spell.FireWall && ((SpellObject)target).Spell != Spell.ExplosiveTrap)) continue;
  1558. skip = true;
  1559. break;
  1560. }
  1561. }
  1562. if (skip) continue;
  1563. SpellObject ob = new SpellObject
  1564. {
  1565. Spell = Spell.ExplosiveTrap,
  1566. Value = value,
  1567. ExpireTime = Envir.Time + (10 + value / 2) * 1000,
  1568. TickSpeed = 500,
  1569. Caster = player,
  1570. CurrentLocation = traps[i],
  1571. CurrentMap = this,
  1572. ExplosiveTrapID = trapID,
  1573. ExplosiveTrapCount = i
  1574. };
  1575. AddObject(ob);
  1576. ob.Spawned();
  1577. }
  1578. }
  1579. }
  1580. break;
  1581. #endregion
  1582. #region Plague
  1583. case Spell.Plague:
  1584. // DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, this, magic, magic.GetDamage(GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC])), location, pType);
  1585. // (int)data[2] === magic.GetDamage(GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]))
  1586. // (Point)data[3] === location
  1587. // (PoisonType)data[4] === pType
  1588. value = (int)data[2];
  1589. location = (Point)data[3];
  1590. // the skill affect a 3x3 square
  1591. var points= GetPointsInEffectiveSquare(location, Width, Height, 3);
  1592. foreach (var point in points)
  1593. {
  1594. cell = GetCell(point.X, point.Y);
  1595. if (!cell.Valid || cell.Objects == null) continue;
  1596. for (int i = 0; i < cell.Objects.Count; i++)
  1597. {
  1598. MapObject target = cell.Objects[i];
  1599. switch (target.Race)
  1600. {
  1601. case ObjectType.Monster:
  1602. case ObjectType.Player:
  1603. //Only targets
  1604. if (target.IsAttackTarget(player))
  1605. {
  1606. int chance = Envir.Random.Next(15);
  1607. PoisonType poison;
  1608. if (new int[] { 0, 1, 2 }.Contains(chance)) //3 in 15 chances it'll slow
  1609. poison = PoisonType.Slow;
  1610. else if (new int[] { 3, 4 }.Contains(chance)) //2 in 15 chances it'll freeze
  1611. poison = PoisonType.Frozen;
  1612. else if (new int[] { 5, 6, 7, 8, 9 }.Contains(chance)) //5 in 15 chances it'll red/green
  1613. // (whatever type of poison player is holding)
  1614. poison = (PoisonType)data[4];
  1615. else //5 in 15 chances it'll do nothing
  1616. poison = PoisonType.None;
  1617. int tempValue = 0;
  1618. if (poison == PoisonType.Red)
  1619. {
  1620. tempValue = value / 15 + magic.Level + 1;
  1621. }
  1622. else
  1623. {
  1624. tempValue = value + (magic.Level + 1) * 2;
  1625. }
  1626. if (poison != PoisonType.None)
  1627. {
  1628. target.ApplyPoison(new Poison { PType = poison, Duration = (2 * (magic.Level + 1)) + (value / 10), TickSpeed = 1000, Value = tempValue, Owner = player }, player, false, true);
  1629. }
  1630. if (target.Race == ObjectType.Player)
  1631. {
  1632. PlayerObject tempOb = (PlayerObject)target;
  1633. tempOb.ChangeMP(-tempValue);
  1634. }
  1635. target.Attacked(player, player.Stats[Stat.MaxSC] * 2, DefenceType.MAC, true);
  1636. train = true;
  1637. }
  1638. break;
  1639. }
  1640. }
  1641. }
  1642. break;
  1643. #endregion
  1644. #region Trap
  1645. case Spell.Trap:
  1646. value = (int)data[2];
  1647. //location = (Point)data[3];
  1648. MapObject originalTarget = (MapObject)data[3];
  1649. location = originalTarget.CurrentLocation;
  1650. MonsterObject selectTarget = null;
  1651. if (!ValidPoint(location)) break;
  1652. cell = GetCell(location);
  1653. if (!cell.Valid || cell.Objects == null) break;
  1654. for (int i = 0; i < cell.Objects.Count; i++)
  1655. {
  1656. MapObject target = cell.Objects[i];
  1657. if (target.Race == ObjectType.Monster)
  1658. {
  1659. selectTarget = (MonsterObject)target;
  1660. if (selectTarget == null || !selectTarget.IsAttackTarget(player) || selectTarget.Node == null || selectTarget.Level >= player.Level + 2) continue;
  1661. selectTarget.ShockTime = Envir.Time + value;
  1662. selectTarget.Target = null;
  1663. break;
  1664. }
  1665. }
  1666. if (selectTarget == null) return;
  1667. if (location.X <= 0 || location.X > selectTarget.CurrentMap.Width) break;
  1668. if (location.Y <= 0 || location.Y > selectTarget.CurrentMap.Height) break;
  1669. SpellObject spellOb = new SpellObject
  1670. {
  1671. Spell = Spell.Trap,
  1672. ExpireTime = Envir.Time + value,
  1673. TickSpeed = 100,
  1674. Caster = player,
  1675. CurrentLocation = location,
  1676. CastLocation = location,
  1677. CurrentMap = selectTarget.CurrentMap,
  1678. Target = selectTarget,
  1679. };
  1680. selectTarget.CurrentMap.AddObject(spellOb);
  1681. spellOb.Spawned();
  1682. train = true;
  1683. break;
  1684. #endregion
  1685. #region OneWithNature
  1686. case Spell.OneWithNature:
  1687. value = (int)data[2];
  1688. location = (Point)data[3];
  1689. bool hasVampBuff = (player.Buffs.Any(ex => ex.Type == BuffType.VampireShot));
  1690. bool hasPoisonBuff = (player.Buffs.Any(ex => ex.Type == BuffType.PoisonShot));
  1691. for (int y = location.Y - 2; y <= location.Y + 2; y++)
  1692. {
  1693. if (y < 0) continue;
  1694. if (y >= Height) break;
  1695. for (int x = location.X - 2; x <= location.X + 2; x++)
  1696. {
  1697. if (x < 0) continue;
  1698. if (x >= Width) break;
  1699. cell = GetCell(x, y);
  1700. if (!cell.Valid || cell.Objects == null) continue;
  1701. for (int i = 0; i < cell.Objects.Count; i++)
  1702. {
  1703. MapObject target = cell.Objects[i];
  1704. switch (target.Race)
  1705. {
  1706. case ObjectType.Monster:
  1707. case ObjectType.Player:
  1708. //Only targets
  1709. if (!target.IsAttackTarget(player) || target.Dead) break;
  1710. //knockback
  1711. //int distance = 1 + Math.Max(0, magic.Level - 1) + Envir.Random.Next(2);
  1712. //dir = Functions.DirectionFromPoint(location, target.CurrentLocation);
  1713. //if(target.Level < player.Level)
  1714. // target.Pushed(player, dir, distance);// <--crashes server somehow?
  1715. if (target.Attacked(player, value, DefenceType.MAC, false) <= 0) break;
  1716. if (hasVampBuff)//Vampire Effect
  1717. {
  1718. if (player.VampAmount == 0) player.VampTime = Envir.Time + 1000;
  1719. player.VampAmount += (ushort)(value * (magic.Level + 1) * 0.25F);
  1720. }
  1721. if (hasPoisonBuff)//Poison Effect
  1722. {
  1723. target.ApplyPoison(new Poison
  1724. {
  1725. Duration = (value * 2) + (magic.Level + 1) * 7,
  1726. Owner = player,
  1727. PType = PoisonType.Green,
  1728. TickSpeed = 2000,
  1729. Value = value / 15 + magic.Level + 1 + Envir.Random.Next(player.Stats[Stat.PoisonAttack])
  1730. }, player);
  1731. target.OperateTime = 0;
  1732. }
  1733. train = true;
  1734. break;
  1735. }
  1736. }
  1737. }
  1738. }
  1739. if (hasVampBuff)
  1740. {
  1741. //Expire
  1742. player.AddBuff(BuffType.VampireShot, player, Settings.Second * 1, new Stats());
  1743. }
  1744. if (hasPoisonBuff)
  1745. {
  1746. //Expire
  1747. player.AddBuff(BuffType.PoisonShot, player, Settings.Second * 1, new Stats());
  1748. }
  1749. break;
  1750. #endregion
  1751. #region Portal
  1752. case Spell.Portal:
  1753. value = (int)data[2];
  1754. location = (Point)data[3];
  1755. value2 = (int)data[4];
  1756. spellOb = new SpellObject
  1757. {
  1758. Spell = Spell.Portal,
  1759. Value = value2,
  1760. ExpireTime = Envir.Time + value * 1000,
  1761. TickSpeed = 2000,
  1762. Caster = player,
  1763. CurrentLocation = location,
  1764. CurrentMap = this,
  1765. };
  1766. AddObject(spellOb);
  1767. spellOb.Spawned();
  1768. train = true;
  1769. break;
  1770. #endregion
  1771. #region DelayedExplosion
  1772. case Spell.DelayedExplosion:
  1773. value = (int)data[2];
  1774. location = (Point)data[3];
  1775. for (int y = location.Y - 1; y <= location.Y + 1; y++)
  1776. {
  1777. if (y < 0) continue;
  1778. if (y >= Height) break;
  1779. for (int x = location.X - 1; x <= location.X + 1; x++)
  1780. {
  1781. if (x < 0) continue;
  1782. if (x >= Width) break;
  1783. cell = GetCell(x, y);
  1784. if (!cell.Valid || cell.Objects == null) continue;
  1785. for (int i = 0; i < cell.Objects.Count; i++)
  1786. {
  1787. MapObject target = cell.Objects[i];
  1788. switch (target.Race)
  1789. {
  1790. case ObjectType.Monster:
  1791. case ObjectType.Player:
  1792. //Only targets
  1793. if (target.IsAttackTarget(player))
  1794. {
  1795. if (target.Attacked(player, value, DefenceType.MAC, false) > 0)
  1796. train = false;//wouldnt want to make the skill give twice the points
  1797. }
  1798. break;
  1799. }
  1800. }
  1801. }
  1802. }
  1803. break;
  1804. #endregion
  1805. #region BattleCry
  1806. case Spell.BattleCry:
  1807. location = (Point)data[2];
  1808. int startX = Math.Max(location.X - 2, 0);
  1809. int endX = Math.Min(location.X + 2, Width - 1);
  1810. int startY = Math.Max(location.Y - 2, 0);
  1811. int endY = Math.Min(location.Y + 2, Height - 1);
  1812. int randomValue = Envir.Random.Next(100);
  1813. for (int y = startY; y <= endY; y++)
  1814. {
  1815. for (int x = startX; x <= endX; x++)
  1816. {
  1817. cell = GetCell(x, y);
  1818. if (!cell.Valid || cell.Objects == null || cell.Objects.Count == 0) continue;
  1819. foreach (var target in cell.Objects)
  1820. {
  1821. if (target.Race != ObjectType.Monster) continue;
  1822. int threshold = magic.Level switch
  1823. {
  1824. 0 => 90, // 90% chance of failure (10% success)
  1825. 1 => 70, // 70% chance of failure (30% success)
  1826. 2 => 50, // 50% chance of failure (50% success)
  1827. 3 => 30, // 30% chance of failure (70% success)
  1828. _ => 100 // Default case, should not occur
  1829. };
  1830. if (randomValue > threshold) continue;
  1831. if (((MonsterObject)target).Info.CoolEye == 100) continue;
  1832. target.Target = player;
  1833. target.OperateTime = 0;
  1834. train = true;
  1835. }
  1836. }
  1837. }
  1838. break;
  1839. #endregion
  1840. #region HealingCircle
  1841. case Spell.HealingCircle:
  1842. value = (int)data[2];
  1843. location = (Point)data[3];
  1844. train = true;
  1845. show = true;
  1846. for (int y = location.Y - 1; y <= location.Y + 1; y++)
  1847. {
  1848. if (y < 0) continue;
  1849. if (y >= Height) break;
  1850. for (int x = location.X - 1; x <= location.X + 1; x++)
  1851. {
  1852. if (x < 0) continue;
  1853. if (x >= Width) break;
  1854. cell = GetCell(x, y);
  1855. if (!cell.Valid) continue;
  1856. bool cast = true;
  1857. if (cell.Objects != null)
  1858. for (int o = 0; o < cell.Objects.Count; o++)
  1859. {
  1860. MapObject target = cell.Objects[o];
  1861. if (target.Race != ObjectType.Spell || ((SpellObject)target).Spell != Spell.HealingCircle) continue;
  1862. cast = false;
  1863. break;
  1864. }
  1865. if (!cast) continue;
  1866. SpellObject ob = new SpellObject
  1867. {
  1868. Spell = Spell.HealingCircle,
  1869. Value = value,
  1870. ExpireTime = Envir.Time + (10000) + (5000 * magic.Level),
  1871. TickSpeed = 400,
  1872. Caster = player,
  1873. CurrentLocation = new Point(x, y),
  1874. CastLocation = location,
  1875. Show = show,
  1876. CurrentMap = this,
  1877. };
  1878. show = false;
  1879. AddObject(ob);
  1880. ob.Spawned();
  1881. }
  1882. }
  1883. break;
  1884. #endregion
  1885. }
  1886. if (train)
  1887. player.LevelMagic(magic);
  1888. }
  1889. public void AddObject(MapObject ob)
  1890. {
  1891. if (ob.Race == ObjectType.Player)
  1892. {
  1893. Players.Add((PlayerObject)ob);
  1894. }
  1895. if (ob.Race == ObjectType.Merchant) NPCs.Add((NPCObject)ob);
  1896. if (ob.Race == ObjectType.Spell) Spells.Add((SpellObject)ob);
  1897. if (ob.Race == ObjectType.Hero) Heroes.Add((HeroObject)ob);
  1898. GetCell(ob.CurrentLocation).Add(ob);
  1899. }
  1900. public void RemoveObject(MapObject ob)
  1901. {
  1902. if (ob.Race == ObjectType.Player) Players.Remove((PlayerObject)ob);
  1903. if (ob.Race == ObjectType.Merchant) NPCs.Remove((NPCObject)ob);
  1904. if (ob.Race == ObjectType.Spell) Spells.Remove((SpellObject)ob);
  1905. if (ob.Race == ObjectType.Hero) Heroes.Remove((HeroObject)ob);
  1906. GetCell(ob.CurrentLocation).Remove(ob);
  1907. }
  1908. public SafeZoneInfo GetSafeZone(Point location)
  1909. {
  1910. for (int i = 0; i < Info.SafeZones.Count; i++)
  1911. {
  1912. SafeZoneInfo szi = Info.SafeZones[i];
  1913. if (Functions.InRange(szi.Location, location, szi.Size))
  1914. return szi;
  1915. }
  1916. return null;
  1917. }
  1918. public List<SpellObject> GetSpellObjects(Spell spell ,MapObject caster)
  1919. {
  1920. List<SpellObject> spellObjects = new List<SpellObject>();
  1921. for (int i = 0; i < Spells.Count; i++)
  1922. {
  1923. if (spell != Spells[i].Spell) continue;
  1924. if (caster != null && Spells[i].Caster != caster) continue;
  1925. spellObjects.Add(Spells[i]);
  1926. }
  1927. return spellObjects;
  1928. }
  1929. public ConquestObject GetConquest(Point location)
  1930. {
  1931. for (int i = 0; i < Conquest.Count; i++)
  1932. {
  1933. ConquestObject swi = Conquest[i];
  1934. if ((swi.Info.FullMap || Functions.InRange(swi.Info.Location, location, swi.Info.Size)) && swi.WarIsOn)
  1935. return swi;
  1936. }
  1937. return null;
  1938. }
  1939. //public ConquestObject GetInnerConquest(Map map, Point location)
  1940. //{
  1941. // for (int i = 0; i < Conquest.Count; i++)
  1942. // {
  1943. // ConquestObject swi = Conquest[i];
  1944. // if (map.Info.Index != swi.Info.MapIndex) continue;
  1945. // if (Functions.InRange(swi.Info.KingLocation, location, swi.Info.KingSize) && swi.WarIsOn)
  1946. // return swi;
  1947. // }
  1948. // return null;
  1949. //}
  1950. public void Broadcast(Packet p, Point location)
  1951. {
  1952. if (p == null) return;
  1953. for (int i = Players.Count - 1; i >= 0; i--)
  1954. {
  1955. PlayerObject player = Players[i];
  1956. if (Functions.InRange(location, player.CurrentLocation, Globals.DataRange))
  1957. player.Enqueue(p);
  1958. }
  1959. }
  1960. public void BroadcastNPC(Packet p, Point location)
  1961. {
  1962. if (p == null) return;
  1963. for (int i = Players.Count - 1; i >= 0; i--)
  1964. {
  1965. PlayerObject player = Players[i];
  1966. if (Functions.InRange(location, player.CurrentLocation, Globals.DataRange))
  1967. player.Enqueue(p);
  1968. }
  1969. }
  1970. public void Broadcast(Packet p, Point location, PlayerObject Player)
  1971. {
  1972. if (p == null) return;
  1973. if (Functions.InRange(location, Player.CurrentLocation, Globals.DataRange))
  1974. {
  1975. Player.Enqueue(p);
  1976. }
  1977. }
  1978. }
  1979. public class Cell
  1980. {
  1981. public static Cell LowWall { get { return new Cell { Attribute = CellAttribute.LowWall }; } }
  1982. public static Cell HighWall { get { return new Cell { Attribute = CellAttribute.HighWall }; } }
  1983. public bool Valid
  1984. {
  1985. get { return Attribute == CellAttribute.Walk; }
  1986. }
  1987. public List<MapObject> Objects = new List<MapObject>();
  1988. public CellAttribute Attribute;
  1989. public sbyte FishingAttribute = -1;
  1990. public void Add(MapObject mapObject)
  1991. {
  1992. if (mapObject == null)
  1993. {
  1994. ReportCellIssue("Attempted to add a null MapObject to a Cell.");
  1995. return;
  1996. }
  1997. if (Objects.Contains(mapObject))
  1998. {
  1999. ReportCellIssue($"Duplicate MapObject add detected for ObjectID {mapObject.ObjectID}.");
  2000. return;
  2001. }
  2002. Objects.Add(mapObject);
  2003. }
  2004. public void Remove(MapObject mapObject)
  2005. {
  2006. if (mapObject == null)
  2007. {
  2008. ReportCellIssue("Attempted to remove a null MapObject from a Cell.");
  2009. return;
  2010. }
  2011. if (!Objects.Remove(mapObject))
  2012. {
  2013. ReportCellIssue($"Failed to remove MapObject {mapObject.ObjectID} from Cell collection.");
  2014. }
  2015. // DO NOT set Objects = null; keep the list to avoid re-alloc
  2016. }
  2017. private static void ReportCellIssue(string message)
  2018. {
  2019. try
  2020. {
  2021. throw new System.InvalidOperationException(message);
  2022. }
  2023. catch (System.Exception ex)
  2024. {
  2025. MessageQueue.Instance.Enqueue(ex);
  2026. }
  2027. }
  2028. }
  2029. public class MapRespawn
  2030. {
  2031. protected static Envir Envir
  2032. {
  2033. get { return Envir.Main; }
  2034. }
  2035. public RespawnInfo Info;
  2036. public MonsterInfo Monster;
  2037. public Map Map;
  2038. public int Count;
  2039. public long RespawnTime;
  2040. public ulong NextSpawnTick;
  2041. public byte ErrorCount = 0;
  2042. public List<RouteInfo> Route;
  2043. public List<Point> WalkableCells;
  2044. public MapRespawn(RespawnInfo info)
  2045. {
  2046. Info = info;
  2047. Monster = Envir.GetMonsterInfo(info.MonsterIndex);
  2048. LoadRoutes();
  2049. }
  2050. public bool Spawn()
  2051. {
  2052. MonsterObject ob = MonsterObject.GetMonster(Monster);
  2053. if (ob == null) return true;
  2054. MonsterType type = Settings.MonsterRarityEnabled
  2055. ? MonsterRarityData.Roll(RandomProvider.GetThreadRandom())
  2056. : MonsterType.Normal;
  2057. ob.SetMonsterType(type);
  2058. return ob.Spawn(this);
  2059. }
  2060. public void LoadRoutes()
  2061. {
  2062. Route = new List<RouteInfo>();
  2063. if (string.IsNullOrEmpty(Info.RoutePath)) return;
  2064. string fileName = Path.Combine(Settings.RoutePath, Info.RoutePath + ".txt");
  2065. if (!File.Exists(fileName)) return;
  2066. List<string> lines = File.ReadAllLines(fileName).ToList();
  2067. foreach (string line in lines)
  2068. {
  2069. RouteInfo info = RouteInfo.FromText(line);
  2070. if (info == null) continue;
  2071. Route.Add(info);
  2072. }
  2073. }
  2074. }
  2075. }