MonsterObject.cs 140 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870
  1. using System;
  2. using System.Drawing;
  3. using Server.MirDatabase;
  4. using Server.MirEnvir;
  5. using Server.MirObjects.Monsters;
  6. using System.Diagnostics.Eventing.Reader;
  7. using Shared;
  8. using S = ServerPackets;
  9. namespace Server.MirObjects
  10. {
  11. public class MonsterObject : MapObject
  12. {
  13. public static MonsterObject GetMonster(MonsterInfo info)
  14. {
  15. if (info == null) return null;
  16. switch (info.AI)
  17. {
  18. case 1:
  19. case 2:
  20. return new Deer(info);
  21. case 3:
  22. return new Tree(info);
  23. case 4:
  24. //Common AI: 1 Line Attack with Poison
  25. return new SpittingSpider(info);
  26. case 5:
  27. return new CannibalPlant(info);
  28. case 6:
  29. return new Guard(info);
  30. case 7:
  31. return new CaveMaggot(info);
  32. case 8:
  33. //Common AI: 1 Range Projectile Attack with Fear
  34. return new AxeSkeleton(info);
  35. case 9:
  36. return new HarvestMonster(info);
  37. case 10:
  38. //Common AI: 1 Magic Attack
  39. return new FlamingWooma(info);
  40. case 11:
  41. return new WoomaTaurus(info);
  42. case 12:
  43. return new BugBagMaggot(info);
  44. case 13:
  45. return new RedMoonEvil(info);
  46. case 14:
  47. return new EvilCentipede(info);
  48. case 15:
  49. return new ZumaMonster(info);
  50. case 16:
  51. return new RedThunderZuma(info);
  52. case 17:
  53. return new ZumaTaurus(info);
  54. case 18:
  55. return new Shinsu(info);
  56. case 19:
  57. return new KingScorpion(info);
  58. case 20:
  59. return new DarkDevil(info);
  60. case 21:
  61. return new IncarnatedGhoul(info);
  62. case 22:
  63. return new IncarnatedZT(info);
  64. case 23:
  65. return new BoneFamiliar(info);
  66. case 24:
  67. return new DigOutZombie(info);
  68. case 25:
  69. return new RevivingZombie(info);
  70. case 26:
  71. return new ShamanZombie(info);
  72. case 27:
  73. return new Khazard(info);
  74. case 28:
  75. return new ToxicGhoul(info);
  76. case 29:
  77. //Common AI: 1 Line Attack
  78. return new BoneSpearman(info);
  79. case 30:
  80. return new BoneLord(info);
  81. case 31:
  82. //Common AI: 2 Magic Attacks, 1 Close, 1 Range
  83. return new RightGuard(info);
  84. case 32:
  85. //Common AI: 2 Magic Attacks, 1 Close, 1 Range Projectile
  86. return new LeftGuard(info);
  87. case 33:
  88. return new MinotaurKing(info);
  89. case 34:
  90. return new FrostTiger(info); //Effect 0/1
  91. case 35:
  92. //Common AI: 1 Line Attack
  93. return new SandWorm(info);
  94. case 36:
  95. return new Yimoogi(info);
  96. case 37:
  97. return new CrystalSpider(info);
  98. case 38:
  99. return new HolyDeva(info);
  100. case 39:
  101. return new RootSpider(info);
  102. case 40:
  103. return new BombSpider(info);
  104. case 41:
  105. case 42:
  106. return new YinDevilNode(info);
  107. case 43:
  108. return new OmaKing(info);
  109. case 44:
  110. //Common AI: 2 Attacks, 1 Close, 1 Line Attack
  111. return new BlackFoxman(info);
  112. case 45:
  113. return new RedFoxman(info);
  114. case 46:
  115. return new WhiteFoxman(info);
  116. case 47:
  117. return new TrapRock(info);
  118. case 48:
  119. return new GuardianRock(info);
  120. case 49:
  121. return new ThunderElement(info);
  122. case 50:
  123. return new GreatFoxSpirit(info);
  124. case 51:
  125. //Common AI: 2 Physical Attacks, 1 Close, 1 Range
  126. return new HedgeKekTal(info);
  127. case 52:
  128. return new EvilMir(info);
  129. case 53:
  130. return new EvilMirBody(info);
  131. case 54:
  132. return new DragonStatue(info);
  133. case 55:
  134. return new HumanWizard(info);
  135. case 56:
  136. return new Trainer(info);
  137. case 57:
  138. return new TownArcher(info);
  139. case 58:
  140. return new Guard(info);
  141. case 59:
  142. return new HumanAssassin(info);
  143. case 60:
  144. return new VampireSpider(info); //TODO - Clean up
  145. case 61:
  146. return new SpittingToad(info);
  147. case 62:
  148. return new SnakeTotem(info);
  149. case 63:
  150. return new CharmedSnake(info);
  151. case 64:
  152. return new IntelligentCreatureObject(info);
  153. case 65:
  154. //Common AI: 2 Close attacks with WeakerTeleport
  155. return new MutatedManworm(info);
  156. case 66:
  157. //Common AI: 2 Close Attacks
  158. return new CrazyManworm(info);
  159. case 67:
  160. return new DarkDevourer(info);
  161. case 68:
  162. return new Football(info);
  163. case 69:
  164. return new PoisonHugger(info);
  165. case 70:
  166. return new Hugger(info);
  167. case 71:
  168. return new Behemoth(info);
  169. case 72:
  170. return new FinialTurtle(info);
  171. case 73:
  172. return new TurtleKing(info);
  173. case 74:
  174. return new LightTurtle(info);
  175. case 75:
  176. return new WitchDoctor(info);
  177. case 76:
  178. //Common AI: 2 Close Attacks, 1 Normal, 1 Halfmoon
  179. return new HellSlasher(info);
  180. case 77:
  181. //Common AI: 2 Close Attacks, 1 Normal, 1 Fullmoon
  182. return new HellPirate(info);
  183. case 78:
  184. return new HellCannibal(info);
  185. case 79:
  186. return new HellKeeper(info);
  187. case 80:
  188. return new ConquestArcher(info);
  189. case 81:
  190. return new Gate(info);
  191. case 82:
  192. return new Wall(info);
  193. case 83:
  194. return new Tornado(info);
  195. case 84:
  196. return new WingedTigerLord(info);
  197. case 85:
  198. return new FlamingMutant(info);
  199. case 86:
  200. return new ManectricClaw(info);
  201. case 87:
  202. return new ManectricBlest(info);
  203. case 88:
  204. return new ManectricKing(info);
  205. case 89:
  206. return new IcePillar(info);
  207. case 90:
  208. return new TrollBomber(info);
  209. case 91:
  210. return new TrollKing(info);
  211. case 92:
  212. //Common AI: 2 Attacks with Fear, 1 Normal, 1 Long Line
  213. return new FlameSpear(info);
  214. case 93:
  215. //Common AI: 2 Magic Attacks with Fear, 1 Close, 1 Range AOE
  216. return new FlameMage(info);
  217. case 94:
  218. //Common AI: 2 Magic Attacks with Fear, 1 Close, 1 Close AOE
  219. return new FlameScythe(info);
  220. case 95:
  221. return new FlameAssassin(info);
  222. case 96:
  223. return new FlameQueen(info);
  224. case 97:
  225. return new HellKnight(info);
  226. case 98:
  227. return new HellLord(info);
  228. case 99:
  229. return new HellBomb(info);
  230. case 100:
  231. //Common AI: 1 Magic Line Attack with Poison
  232. return new VenomSpider(info);
  233. case 101:
  234. return new AncientBringer(info);
  235. case 102:
  236. return new IceGuard(info);
  237. case 103:
  238. return new ElementGuard(info);
  239. case 104:
  240. return new DemonGuard(info);
  241. case 105:
  242. return new KingGuard(info);
  243. case 106:
  244. return new DeathCrawler(info);
  245. case 107:
  246. //Common AI: 2 Magic Attacks with Rush, 1 Close, 1 Range
  247. return new BurningZombie(info);
  248. case 108:
  249. return new MudZombie(info);
  250. case 109:
  251. return new HardenRhino(info);
  252. case 110:
  253. return new DemonWolf(info); //Effect 0/1
  254. case 111:
  255. return new WhiteMammoth(info);
  256. case 112:
  257. //Common AI: 2 Close attacks
  258. return new DarkBeast(info); //Effect 0/1
  259. case 113:
  260. return new ArcherGuard(info);
  261. case 114:
  262. //Common AI: 1 Close attack with WeakerTeleport
  263. return new Mandrill(info);
  264. case 115:
  265. return new SandSnail(info);
  266. case 116:
  267. return new BlackHammerCat(info);
  268. case 117:
  269. return new StrayCat(info);
  270. case 118:
  271. return new CatShaman(info);
  272. case 119:
  273. return new Jar1(info);
  274. case 120:
  275. return new Jar2(info);
  276. case 121:
  277. return new SeedingsGeneral(info);
  278. case 122:
  279. return new RestlessJar(info);
  280. case 123:
  281. return new GeneralMeowMeow(info);
  282. case 124:
  283. return new Armadillo(info);
  284. case 125:
  285. return new ArmadilloElder(info);
  286. case 126:
  287. return new TucsonMage(info);
  288. case 127:
  289. return new TucsonWarrior(info);
  290. case 128:
  291. return new TucsonEgg(info); //Effect 0/1
  292. case 129:
  293. return new SwampWarrior(info);
  294. case 130:
  295. return new CannibalTentacles(info);
  296. case 131:
  297. return new TucsonGeneral(info);
  298. case 132:
  299. return new GasToad(info);
  300. case 133:
  301. return new Mantis(info);
  302. case 134:
  303. return new AssassinBird(info);
  304. case 135:
  305. return new StoningStatue(info);
  306. case 136:
  307. return new FlyingStatue(info);
  308. case 137:
  309. return new RhinoPriest(info);
  310. case 138:
  311. return new ElephantMan(info);
  312. case 139:
  313. return new StoneGolem(info);
  314. case 140:
  315. return new EarthGolem(info);
  316. case 141:
  317. return new TreeGuardian(info);
  318. case 142:
  319. return new TreeQueen(info);
  320. case 143:
  321. return new PeacockSpider(info);
  322. case 144:
  323. return new OmaCannibal(info);
  324. case 145:
  325. //Common AI: 2 Attacks, 1 Close, 1 Close AOE
  326. return new OmaBlest(info);
  327. case 146:
  328. //Common AI: 1 Halfmoon Attack
  329. return new OmaSlasher(info);
  330. case 147:
  331. return new OmaMage(info);
  332. case 148:
  333. return new OmaWitchDoctor(info);
  334. case 149:
  335. return new PowerBead(info); //Effect 0/1/2
  336. case 150:
  337. return new DarkOmaKing(info);
  338. case 151:
  339. return new CaveStatue(info);
  340. case 152:
  341. return new PlagueCrab(info);
  342. case 153:
  343. return new CreeperPlant(info);
  344. case 154:
  345. return new Nadz(info);
  346. case 155:
  347. return new AvengingSpirit(info);
  348. case 156:
  349. return new AvengingWarrior(info);
  350. case 157:
  351. return new AxePlant(info);
  352. case 158:
  353. //Common AI: None With Attack On Death
  354. return new WoodBox(info);
  355. case 159:
  356. return new DarkCaptain(info);
  357. case 160:
  358. //Common AI: 1 Range Attack with Fear
  359. return new BlueSoul(info);
  360. case 161:
  361. return new SackWarrior(info);
  362. case 162:
  363. return new KingHydrax(info);
  364. case 163:
  365. return new HornedMage(info);
  366. case 164:
  367. return new HornedArcher(info); //Effect 0/1
  368. case 165:
  369. return new HornedWarrior(info);
  370. case 166:
  371. return new FloatingRock(info);
  372. case 167:
  373. return new ScalyBeast(info);
  374. case 168:
  375. return new WereTiger(info);
  376. case 169:
  377. return new HornedSorceror(info);
  378. case 170:
  379. return new BoulderSpirit(info);
  380. case 171:
  381. return new HornedCommander(info);
  382. //case 172: MoonSunLightningStone
  383. case 173:
  384. return new TurtleGrass(info);
  385. case 174:
  386. return new ManTree(info);
  387. case 175:
  388. return new ChieftainArcher(info);
  389. //case 176: ChieftainSword
  390. case 177:
  391. return new FrozenKnight(info);
  392. case 178:
  393. return new IcePhantom(info); //TODO
  394. case 179:
  395. return new SnowWolf(info);
  396. case 180:
  397. return new SnowWolfKing(info);
  398. case 181:
  399. return new WaterDragon(info);
  400. case 182:
  401. return new BlackTortoise(info);
  402. //case 183: Manticore
  403. case 184:
  404. return new DragonWarrior(info); //TODO
  405. //case 185: DragonArcher
  406. case 186:
  407. return new Kirin(info);
  408. case 187:
  409. return new FrozenMiner(info);
  410. case 188:
  411. return new FrozenAxeman(info);
  412. case 189:
  413. return new FrozenMagician(info);
  414. case 190:
  415. return new SnowYeti(info);
  416. case 191:
  417. return new IceCrystalSoldier(info);
  418. case 192:
  419. return new DarkWraith(info);
  420. //case 193: CrystalBeast
  421. //case 194: RedOrb
  422. //case 195: FatalLotus
  423. case 196:
  424. return new AntCommander(info);
  425. // Sanjian
  426. case 197:
  427. return new GlacierSnail(info);
  428. case 198:
  429. return new FurbolgWarrior(info);
  430. case 199:
  431. return new FurbolgArcher(info);
  432. case 200:
  433. return new FurbolgCommander(info);
  434. case 201:
  435. return new FurbolgGuard(info);
  436. case 202:
  437. return new GlacierBeast(info);
  438. case 203:
  439. return new GlacierWarrior(info);
  440. case 210:
  441. return new HoodedSummonerScrolls(info);
  442. case 211:
  443. return new HoodedSummoner(info);
  444. case 212:
  445. return new PurpleFaeFlower(info);
  446. case 213:
  447. return new Siege(info); //TODO
  448. case 214:
  449. return new SepWarrior(info); //TODO
  450. case 215:
  451. return new SepWizard(info); //TODO
  452. case 216:
  453. return new SepTaoist(info); //TODO
  454. case 217:
  455. return new SepAssassin(info); //TODO
  456. case 218:
  457. return new SepArcher(info); //TODO
  458. case 219:
  459. return new SepHighWarrior(info); //TODO
  460. case 220:
  461. return new SepHighWizard(info); //TODO
  462. case 221:
  463. return new SepHighTaoist(info); //TODO
  464. case 222:
  465. return new SepHighAssassin(info); //TODO
  466. case 223:
  467. return new SepHighArcher(info); //TODO
  468. case 255://Skill
  469. return new StoneTrap(info);
  470. default:
  471. return new MonsterObject(info);
  472. }
  473. }
  474. public override ObjectType Race
  475. {
  476. get { return ObjectType.Monster; }
  477. }
  478. public virtual bool IgnoresNoPetRestriction => false;
  479. public MonsterInfo Info;
  480. public MapRespawn Respawn;
  481. public MonsterType MonsterType { get; private set; } = MonsterType.Normal;
  482. private long NextRecallTime;
  483. public override string Name
  484. {
  485. get
  486. {
  487. return Master == null ? Info.GameName : string.Format("{0}({1})", Info.GameName, Master.Name);
  488. }
  489. set { throw new NotSupportedException(); }
  490. }
  491. public override int CurrentMapIndex { get; set; }
  492. public override Point CurrentLocation { get; set; }
  493. public override sealed MirDirection Direction { get; set; }
  494. public override ushort Level
  495. {
  496. get { return Info.Level; }
  497. set { throw new NotSupportedException(); }
  498. }
  499. public override sealed AttackMode AMode
  500. {
  501. get
  502. {
  503. return base.AMode;
  504. }
  505. set
  506. {
  507. base.AMode = value;
  508. }
  509. }
  510. public override sealed PetMode PMode
  511. {
  512. get
  513. {
  514. return base.PMode;
  515. }
  516. set
  517. {
  518. base.PMode = value;
  519. }
  520. }
  521. public override int Health
  522. {
  523. get { return HP; }
  524. }
  525. public override int MaxHealth
  526. {
  527. get { return Stats[Stat.HP]; }
  528. }
  529. public int HealthPercent
  530. {
  531. get
  532. {
  533. return (Health * 100) / MaxHealth;
  534. }
  535. }
  536. public int HP;
  537. public ushort MoveSpeed;
  538. public virtual uint Experience
  539. {
  540. get
  541. {
  542. MonsterRarityProfile profile = GetRarityProfile();
  543. double scaled = Info.Experience * profile.ExpMultiplier;
  544. if (scaled <= 0) return 0;
  545. if (scaled > uint.MaxValue) return uint.MaxValue;
  546. return (uint)Math.Round(scaled);
  547. }
  548. }
  549. public int DeadDelay
  550. {
  551. get
  552. {
  553. switch (Info.AI)
  554. {
  555. case 64:
  556. return 0;
  557. case 81:
  558. case 82:
  559. return int.MaxValue;
  560. case 252:
  561. return 5000;
  562. default:
  563. return 180000;
  564. }
  565. }
  566. }
  567. public const int RegenDelay = 10000, EXPOwnerDelay = 5000, AloneDelay = 3000, SearchDelay = 3000, RoamDelay = 1000, HealDelay = 600, RevivalDelay = 2000;
  568. public long ActionTime, MoveTime, AttackTime, RegenTime, DeadTime, AloneTime, SearchTime, RoamTime, HealTime;
  569. public long ShockTime, RageTime, HallucinationTime;
  570. public bool BindingShotCenter, PoisonStopRegen = true;
  571. protected bool Alone = false, Stacking = false;
  572. public byte PetLevel;
  573. public uint PetExperience;
  574. public byte MaxPetLevel;
  575. public long TameTime;
  576. public bool DieNextTurn;
  577. public int RoutePoint;
  578. public bool Waiting;
  579. public bool GMMade;
  580. public bool Frozen;
  581. public List<MonsterObject> SlaveList = new List<MonsterObject>();
  582. public List<RouteInfo> Route = new List<RouteInfo>();
  583. public override bool Blocking
  584. {
  585. get
  586. {
  587. return !Dead;
  588. }
  589. }
  590. protected virtual bool CanRegen
  591. {
  592. get { return Envir.Time >= RegenTime; }
  593. }
  594. protected virtual bool CanMove
  595. {
  596. get
  597. {
  598. return
  599. !Dead &&
  600. Envir.Time > MoveTime &&
  601. Envir.Time > ActionTime &&
  602. Envir.Time > ShockTime &&
  603. (Master == null || Master.PMode == PetMode.MoveOnly || Master.PMode == PetMode.Both || Master.PMode == PetMode.FocusMasterTarget) &&
  604. !CurrentPoison.HasFlag(PoisonType.Paralysis) &&
  605. !CurrentPoison.HasFlag(PoisonType.LRParalysis) &&
  606. !CurrentPoison.HasFlag(PoisonType.Frozen) &&
  607. (!CurrentPoison.HasFlag(PoisonType.Stun) || (Info.Light == 10 || Info.Light == 5));
  608. }
  609. }
  610. protected virtual bool CanAttack
  611. {
  612. get
  613. {
  614. return
  615. !Dead &&
  616. Envir.Time > AttackTime &&
  617. Envir.Time > ActionTime &&
  618. (Master == null || Master.PMode == PetMode.AttackOnly || Master.PMode == PetMode.Both || Master.PMode == PetMode.FocusMasterTarget) &&
  619. !CurrentPoison.HasFlag(PoisonType.Paralysis) &&
  620. !CurrentPoison.HasFlag(PoisonType.LRParalysis) &&
  621. !CurrentPoison.HasFlag(PoisonType.Dazed) &&
  622. !CurrentPoison.HasFlag(PoisonType.Frozen) &&
  623. (!CurrentPoison.HasFlag(PoisonType.Stun) || (Info.Light == 10 || Info.Light == 5));
  624. }
  625. }
  626. protected internal MonsterObject(MonsterInfo info)
  627. {
  628. Info = info;
  629. Stats = new Stats();
  630. Undead = Info.Undead;
  631. AutoRev = info.AutoRev;
  632. CoolEye = info.CoolEye > Envir.Random.Next(100);
  633. Direction = (MirDirection)Envir.Random.Next(8);
  634. AMode = AttackMode.All;
  635. PMode = PetMode.Both;
  636. RegenTime = Envir.Random.Next(RegenDelay) + Envir.Time;
  637. SearchTime = Envir.Random.Next(SearchDelay) + Envir.Time;
  638. RoamTime = Envir.Random.Next(RoamDelay) + Envir.Time;
  639. }
  640. public void SetMonsterType(MonsterType type)
  641. {
  642. MonsterType = type;
  643. }
  644. public bool Spawn(Map temp, Point location)
  645. {
  646. if (!temp.ValidPoint(location)) return false;
  647. CurrentMap = temp;
  648. CurrentLocation = location;
  649. CurrentMap.AddObject(this);
  650. RefreshAll();
  651. SetHP(Stats[Stat.HP]);
  652. Spawned();
  653. Envir.MonsterCount++;
  654. CurrentMap.MonsterCount++;
  655. return true;
  656. }
  657. public bool Spawn(MapRespawn respawn)
  658. {
  659. Respawn = respawn;
  660. if (Respawn.Map == null) return false;
  661. if (Respawn.WalkableCells == null || Respawn.WalkableCells.Count == 0) return false;
  662. var spawnPoint = Respawn.WalkableCells[Envir.Random.Next(Respawn.WalkableCells.Count)];
  663. CurrentLocation = spawnPoint;
  664. respawn.Map.AddObject(this);
  665. CurrentMap = respawn.Map;
  666. if (Respawn.Route.Count > 0)
  667. Route.AddRange(Respawn.Route);
  668. RefreshAll();
  669. SetHP(Stats[Stat.HP]);
  670. Spawned();
  671. Respawn.Count++;
  672. respawn.Map.MonsterCount++;
  673. Envir.MonsterCount++;
  674. return true;
  675. }
  676. public override void Spawned()
  677. {
  678. ActionTime = Envir.Time + 2000;
  679. if (Info.HasSpawnScript && (Envir.MonsterNPC != null))
  680. {
  681. Envir.MonsterNPC.Call(this,string.Format("[@_SPAWN({0})]",Info.Index));
  682. }
  683. base.Spawned();
  684. }
  685. protected virtual void RefreshBase()
  686. {
  687. Stats.Clear();
  688. Stats.Add(Info.Stats);
  689. ApplyMonsterTypeBonuses();
  690. MoveSpeed = Info.MoveSpeed;
  691. AttackSpeed = Info.AttackSpeed;
  692. }
  693. protected virtual void ApplyMonsterTypeBonuses()
  694. {
  695. if (MonsterType == MonsterType.Normal) return;
  696. MonsterRarityProfile profile = GetRarityProfile();
  697. ScaleStat(Stat.HP, profile.HpMultiplier);
  698. ScaleStat(Stat.MinAC, profile.DefenseMultiplier);
  699. ScaleStat(Stat.MaxAC, profile.DefenseMultiplier);
  700. ScaleStat(Stat.MinMAC, profile.DefenseMultiplier);
  701. ScaleStat(Stat.MaxMAC, profile.DefenseMultiplier);
  702. ScaleStat(Stat.MinDC, profile.DamageMultiplier);
  703. ScaleStat(Stat.MaxDC, profile.DamageMultiplier);
  704. ScaleStat(Stat.MinMC, profile.DamageMultiplier);
  705. ScaleStat(Stat.MaxMC, profile.DamageMultiplier);
  706. ScaleStat(Stat.MinSC, profile.DamageMultiplier);
  707. ScaleStat(Stat.MaxSC, profile.DamageMultiplier);
  708. }
  709. protected void ScaleStat(Stat stat, double multiplier)
  710. {
  711. if (Math.Abs(multiplier - 1D) < double.Epsilon) return;
  712. int value = Stats[stat];
  713. if (value == 0) return;
  714. double scaled = value * multiplier;
  715. if (stat == Stat.HP)
  716. Stats[stat] = Math.Max(1, (int)Math.Round(scaled));
  717. else
  718. Stats[stat] = (int)Math.Round(scaled);
  719. }
  720. protected MonsterRarityProfile GetRarityProfile()
  721. {
  722. return MonsterRarityData.GetProfile(MonsterType);
  723. }
  724. protected uint ApplyGoldModifier(uint amount)
  725. {
  726. if (amount == 0) return 0;
  727. MonsterRarityProfile profile = GetRarityProfile();
  728. double scaled = amount * profile.GoldMultiplier;
  729. if (scaled <= 0) return 0;
  730. if (scaled > uint.MaxValue) return uint.MaxValue;
  731. return (uint)Math.Round(scaled);
  732. }
  733. public virtual void RefreshAll()
  734. {
  735. RefreshBase();
  736. Stats[Stat.HP] += PetLevel * 20;
  737. Stats[Stat.MinAC] += PetLevel * 2;
  738. Stats[Stat.MaxAC] += PetLevel * 2;
  739. Stats[Stat.MinMAC] += PetLevel * 2;
  740. Stats[Stat.MaxMAC] += PetLevel * 2;
  741. Stats[Stat.MinDC] += PetLevel;
  742. Stats[Stat.MaxDC] += PetLevel;
  743. if (Info.Name == Settings.SkeletonName || Info.Name == Settings.ShinsuName || Info.Name == Settings.AngelName)
  744. {
  745. MoveSpeed = (ushort)Math.Min(ushort.MaxValue, (Math.Max(ushort.MinValue, MoveSpeed - MaxPetLevel * 130)));
  746. AttackSpeed = (ushort)Math.Min(ushort.MaxValue, (Math.Max(ushort.MinValue, AttackSpeed - MaxPetLevel * 70)));
  747. }
  748. if (MoveSpeed < 400) MoveSpeed = 400;
  749. if (AttackSpeed < 400) AttackSpeed = 400;
  750. RefreshBuffs();
  751. }
  752. protected virtual void RefreshBuffs()
  753. {
  754. for (int i = 0; i < Buffs.Count; i++)
  755. {
  756. Buff buff = Buffs[i];
  757. Stats.Add(buff.Stats);
  758. switch (buff.Type)
  759. {
  760. case BuffType.SwiftFeet:
  761. MoveSpeed = (ushort)Math.Max(ushort.MinValue, MoveSpeed + 100);
  762. break;
  763. }
  764. }
  765. }
  766. public virtual void RefreshNameColour(bool send = true)
  767. {
  768. if (ShockTime < Envir.Time) BindingShotCenter = false;
  769. Color colour = Color.White;
  770. if (Master != null)
  771. {
  772. switch (PetLevel)
  773. {
  774. case 1:
  775. colour = Color.Aqua;
  776. break;
  777. case 2:
  778. colour = Color.Aquamarine;
  779. break;
  780. case 3:
  781. colour = Color.LightSeaGreen;
  782. break;
  783. case 4:
  784. colour = Color.SlateBlue;
  785. break;
  786. case 5:
  787. colour = Color.SteelBlue;
  788. break;
  789. case 6:
  790. colour = Color.Blue;
  791. break;
  792. case 7:
  793. colour = Color.Navy;
  794. break;
  795. }
  796. }
  797. else if (MonsterType != MonsterType.Normal)
  798. {
  799. colour = GetRarityProfile().NameColour;
  800. }
  801. if (Envir.Time < ShockTime)
  802. colour = Color.Peru;
  803. else if (Envir.Time < RageTime)
  804. colour = Color.Red;
  805. else if (Envir.Time < HallucinationTime)
  806. colour = Color.MediumOrchid;
  807. if (colour == NameColour || !send) return;
  808. NameColour = colour;
  809. Broadcast(new S.ObjectColourChanged { ObjectID = ObjectID, NameColour = NameColour });
  810. }
  811. public void SetHP(int amount)
  812. {
  813. if (HP == amount) return;
  814. HP = amount <= Stats[Stat.HP] ? amount : Stats[Stat.HP];
  815. if (!Dead && HP == 0) Die();
  816. // HealthChanged = true;
  817. BroadcastHealthChange();
  818. }
  819. public virtual void ChangeHP(int amount)
  820. {
  821. if (HP + amount > Stats[Stat.HP])
  822. amount = Stats[Stat.HP] - HP;
  823. if (amount == 0) return;
  824. HP += amount;
  825. if (HP < 0) HP = 0;
  826. if (!Dead && HP == 0) Die();
  827. // HealthChanged = true;
  828. BroadcastHealthChange();
  829. }
  830. //use this so you can have mobs take no/reduced poison damage
  831. public virtual void PoisonDamage(int amount, MapObject Attacker)
  832. {
  833. ChangeHP(amount);
  834. }
  835. public override bool Teleport(Map temp, Point location, bool effects = true, byte effectnumber = 0)
  836. {
  837. if (temp == null || !temp.ValidPoint(location)) return false;
  838. CurrentMap.RemoveObject(this);
  839. if (effects) Broadcast(new S.ObjectTeleportOut { ObjectID = ObjectID, Type = effectnumber });
  840. Broadcast(new S.ObjectRemove { ObjectID = ObjectID });
  841. CurrentMap.MonsterCount--;
  842. CurrentMap = temp;
  843. CurrentLocation = location;
  844. CurrentMap.MonsterCount++;
  845. InTrapRock = false;
  846. CurrentMap.AddObject(this);
  847. BroadcastInfo();
  848. if (effects) Broadcast(new S.ObjectTeleportIn { ObjectID = ObjectID, Type = effectnumber });
  849. BroadcastHealthChange();
  850. return true;
  851. }
  852. public override void Die()
  853. {
  854. if (Dead) return;
  855. HP = 0;
  856. Dead = true;
  857. DeadTime = Envir.Time + DeadDelay;
  858. Broadcast(new S.ObjectDied { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  859. if (Info.HasDieScript && (Envir.MonsterNPC != null))
  860. {
  861. Envir.MonsterNPC.Call(this, string.Format("[@_DIE({0})]", Info.Index));
  862. }
  863. if (EXPOwner != null && EXPOwner.Node != null && Master == null && (EXPOwner.Race == ObjectType.Player || EXPOwner.Race == ObjectType.Hero))
  864. {
  865. EXPOwner.WinExp(Experience, Level);
  866. if (EXPOwner.Race != ObjectType.Hero)
  867. {
  868. PlayerObject playerObj = (PlayerObject)EXPOwner;
  869. playerObj.CheckGroupQuestKill(Info);
  870. }
  871. }
  872. if (Respawn != null)
  873. Respawn.Count--;
  874. if (Master == null && EXPOwner != null)
  875. Drop();
  876. Master = null;
  877. PoisonList.Clear();
  878. Envir.MonsterCount--;
  879. if (CurrentMap != null)
  880. CurrentMap.MonsterCount--;
  881. }
  882. public MapObject GetAttacker(MapObject attacker)
  883. {
  884. return attacker switch
  885. {
  886. HeroObject hero => hero.Owner,
  887. _ => attacker
  888. };
  889. }
  890. public void Revive(int hp, bool effect)
  891. {
  892. if (!Dead) return;
  893. SetHP(hp);
  894. Dead = false;
  895. ActionTime = Envir.Time + RevivalDelay;
  896. Broadcast(new S.ObjectRevived { ObjectID = ObjectID, Effect = effect });
  897. if (Respawn != null)
  898. Respawn.Count++;
  899. Envir.MonsterCount++;
  900. CurrentMap.MonsterCount++;
  901. }
  902. public override int Pushed(MapObject pusher, MirDirection dir, int distance)
  903. {
  904. if (!Info.CanPush) return 0;
  905. //if (!CanMove) return 0; //stops mobs that can't move (like cannibalplants) from being pushed
  906. int result = 0;
  907. MirDirection reverse = Functions.ReverseDirection(dir);
  908. for (int i = 0; i < distance; i++)
  909. {
  910. Point location = Functions.PointMove(CurrentLocation, dir, 1);
  911. if (!CurrentMap.ValidPoint(location)) return result;
  912. Cell cell = CurrentMap.GetCell(location);
  913. bool stop = false;
  914. if (cell.Objects != null)
  915. for (int c = 0; c < cell.Objects.Count; c++)
  916. {
  917. MapObject ob = cell.Objects[c];
  918. if (!ob.Blocking) continue;
  919. stop = true;
  920. }
  921. if (stop) break;
  922. CurrentMap.GetCell(CurrentLocation).Remove(this);
  923. Direction = reverse;
  924. RemoveObjects(dir, 1);
  925. CurrentLocation = location;
  926. CurrentMap.GetCell(CurrentLocation).Add(this);
  927. AddObjects(dir, 1);
  928. Broadcast(new S.ObjectPushed { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  929. result++;
  930. }
  931. ActionTime = Envir.Time + 300 * result;
  932. MoveTime = Envir.Time + 500 * result;
  933. if (result > 0)
  934. {
  935. Cell cell = CurrentMap.GetCell(CurrentLocation);
  936. for (int i = 0; i < cell.Objects.Count; i++)
  937. {
  938. if (cell.Objects[i].Race != ObjectType.Spell) continue;
  939. SpellObject ob = (SpellObject)cell.Objects[i];
  940. ob.ProcessSpell(this);
  941. //break;
  942. }
  943. }
  944. return result;
  945. }
  946. protected virtual void Drop()
  947. {
  948. if (CurrentMap.Info.NoDropMonster)
  949. return;
  950. MonsterRarityProfile profile = GetRarityProfile();
  951. int ownerItemBonus = EXPOwner?.Stats[Stat.ItemDropRatePercent] ?? 0;
  952. int ownerGoldBonus = EXPOwner?.Stats[Stat.GoldDropRatePercent] ?? 0;
  953. int totalItemBonus = ownerItemBonus + profile.ItemDropBonusPercent;
  954. int totalGoldBonus = ownerGoldBonus + profile.GoldDropBonusPercent;
  955. for (int i = 0; i < Info.Drops.Count; i++)
  956. {
  957. DropInfo drop = Info.Drops[i];
  958. var reward = drop.AttemptDrop(totalItemBonus, totalGoldBonus);
  959. if (reward != null)
  960. {
  961. uint scaledGold = ApplyGoldModifier(reward.Gold);
  962. if (scaledGold > 0)
  963. {
  964. DropGold(scaledGold);
  965. }
  966. foreach (var dropItem in reward.Items)
  967. {
  968. UserItem item = Envir.CreateDropItem(dropItem);
  969. if (item == null) continue;
  970. if (GMMade)
  971. {
  972. item.GMMade = true;
  973. }
  974. if (EXPOwner != null && EXPOwner.Race == ObjectType.Player)
  975. {
  976. PlayerObject ob = (PlayerObject)EXPOwner;
  977. if (ob.CheckGroupQuestItem(item))
  978. {
  979. continue;
  980. }
  981. }
  982. if (drop.QuestRequired) continue;
  983. if (!DropItem(item)) return;
  984. }
  985. }
  986. }
  987. }
  988. protected virtual bool DropItem(UserItem item)
  989. {
  990. if (CurrentMap.Info.NoDropMonster)
  991. return false;
  992. ItemObject ob = new ItemObject(this, item)
  993. {
  994. Owner = EXPOwner,
  995. OwnerTime = Envir.Time + Settings.Minute,
  996. };
  997. if (!item.Info.GlobalDropNotify)
  998. return ob.Drop(Settings.DropRange);
  999. foreach (var player in Envir.Players)
  1000. {
  1001. player.ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.PlayerHasDroppedItem), Name, item.FriendlyName), ChatType.System2);
  1002. }
  1003. return ob.Drop(Settings.DropRange);
  1004. }
  1005. protected virtual bool DropGold(uint gold)
  1006. {
  1007. if (EXPOwner != null && EXPOwner.CanGainGold(gold) && !Settings.DropGold)
  1008. {
  1009. EXPOwner.WinGold(gold);
  1010. return true;
  1011. }
  1012. uint count = gold / Settings.MaxDropGold == 0 ? 1 : gold / Settings.MaxDropGold + 1;
  1013. for (int i = 0; i < count; i++)
  1014. {
  1015. ItemObject ob = new ItemObject(this, i != count - 1 ? Settings.MaxDropGold : gold % Settings.MaxDropGold)
  1016. {
  1017. Owner = EXPOwner,
  1018. OwnerTime = Envir.Time + Settings.Minute,
  1019. };
  1020. ob.Drop(Settings.DropRange);
  1021. }
  1022. return true;
  1023. }
  1024. public override void Process()
  1025. {
  1026. base.Process();
  1027. RefreshNameColour();
  1028. if (Target != null && (Target.CurrentMap != CurrentMap || !Target.IsAttackTarget(this) || !Functions.InRange(CurrentLocation, Target.CurrentLocation, Globals.DataRange)))
  1029. Target = null;
  1030. for (int i = SlaveList.Count - 1; i >= 0; i--)
  1031. if (SlaveList[i].Dead || SlaveList[i].Node == null)
  1032. SlaveList.RemoveAt(i);
  1033. if (Dead && Envir.Time >= DeadTime)
  1034. {
  1035. CurrentMap.RemoveObject(this);
  1036. if (Master != null)
  1037. {
  1038. Master.Pets.Remove(this);
  1039. Master = null;
  1040. }
  1041. Despawn();
  1042. return;
  1043. }
  1044. if (Master != null && TameTime > 0 && Envir.Time >= TameTime)
  1045. {
  1046. Master.Pets.Remove(this);
  1047. Master = null;
  1048. Broadcast(new S.ObjectName { ObjectID = ObjectID, Name = Name });
  1049. }
  1050. ProcessAI();
  1051. ProcessBuffs();
  1052. ProcessRegen();
  1053. ProcessPoison();
  1054. }
  1055. public override void SetOperateTime()
  1056. {
  1057. long time = Envir.Time + 2000;
  1058. if (AloneTime < time && AloneTime > Envir.Time)
  1059. time = AloneTime;
  1060. if (DeadTime < time && DeadTime > Envir.Time)
  1061. time = DeadTime;
  1062. if (OwnerTime < time && OwnerTime > Envir.Time)
  1063. time = OwnerTime;
  1064. if (ExpireTime < time && ExpireTime > Envir.Time)
  1065. time = ExpireTime;
  1066. if (PKPointTime < time && PKPointTime > Envir.Time)
  1067. time = PKPointTime;
  1068. if (LastHitTime < time && LastHitTime > Envir.Time)
  1069. time = LastHitTime;
  1070. if (EXPOwnerTime < time && EXPOwnerTime > Envir.Time)
  1071. time = EXPOwnerTime;
  1072. if (SearchTime < time && SearchTime > Envir.Time)
  1073. time = SearchTime;
  1074. if (RoamTime < time && RoamTime > Envir.Time)
  1075. time = RoamTime;
  1076. if (ShockTime < time && ShockTime > Envir.Time)
  1077. time = ShockTime;
  1078. if (RegenTime < time && RegenTime > Envir.Time && Health < MaxHealth)
  1079. time = RegenTime;
  1080. if (RageTime < time && RageTime > Envir.Time)
  1081. time = RageTime;
  1082. if (HallucinationTime < time && HallucinationTime > Envir.Time)
  1083. time = HallucinationTime;
  1084. if (ActionTime < time && ActionTime > Envir.Time)
  1085. time = ActionTime;
  1086. if (MoveTime < time && MoveTime > Envir.Time)
  1087. time = MoveTime;
  1088. if (AttackTime < time && AttackTime > Envir.Time)
  1089. time = AttackTime;
  1090. if (HealTime < time && HealTime > Envir.Time && HealAmount > 0)
  1091. time = HealTime;
  1092. if (BrownTime < time && BrownTime > Envir.Time)
  1093. time = BrownTime;
  1094. for (int i = 0; i < ActionList.Count; i++)
  1095. {
  1096. if (ActionList[i].Time >= time && ActionList[i].Time > Envir.Time) continue;
  1097. time = ActionList[i].Time;
  1098. }
  1099. for (int i = 0; i < PoisonList.Count; i++)
  1100. {
  1101. if (PoisonList[i].TickTime >= time && PoisonList[i].TickTime > Envir.Time) continue;
  1102. time = PoisonList[i].TickTime;
  1103. }
  1104. for (int i = 0; i < Buffs.Count; i++)
  1105. {
  1106. if (Buffs[i].NextTime >= time && Buffs[i].NextTime > Envir.Time) continue;
  1107. time = Buffs[i].NextTime;
  1108. }
  1109. if (OperateTime <= Envir.Time || time < OperateTime)
  1110. OperateTime = time;
  1111. }
  1112. public override void Process(DelayedAction action)
  1113. {
  1114. switch (action.Type)
  1115. {
  1116. case DelayedType.Damage:
  1117. CompleteAttack(action.Params);
  1118. break;
  1119. case DelayedType.RangeDamage:
  1120. CompleteRangeAttack(action.Params);
  1121. break;
  1122. case DelayedType.Die:
  1123. CompleteDeath(action.Params);
  1124. break;
  1125. case DelayedType.Recall:
  1126. PetRecall();
  1127. break;
  1128. case DelayedType.SpellEffect:
  1129. CompleteSpellEffect(action.Params);
  1130. break;
  1131. }
  1132. }
  1133. public void PetRecall()
  1134. {
  1135. if (Master == null || Master.CurrentMap == null) return;
  1136. // Prevent pet from warping into NoPets maps (unless exempt e.g. pickup pets)
  1137. if (Master.CurrentMap.Info.NoPets && !IgnoresNoPetRestriction)
  1138. {
  1139. Master.ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.CannotFollowIntoMapWaitHere, Name), ChatType.System);
  1140. Frozen = true;
  1141. Target = null;
  1142. PMode = PetMode.None;
  1143. Broadcast(new S.ObjectTurn
  1144. {
  1145. Direction = Direction,
  1146. Location = CurrentLocation
  1147. });
  1148. return;
  1149. }
  1150. bool wasFrozen = Frozen;
  1151. // Restore pet state
  1152. Frozen = false;
  1153. Target = null;
  1154. PMode = PetMode.Both;
  1155. // Only teleport if needed
  1156. if (CurrentMap != Master.CurrentMap)
  1157. {
  1158. if (!Teleport(Master.CurrentMap, Master.Back))
  1159. Teleport(Master.CurrentMap, Master.CurrentLocation);
  1160. // Only show message if returning from frozen/waiting state
  1161. if (wasFrozen)
  1162. {
  1163. Master.ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.HasReturnedToYourSide,Name), ChatType.System);
  1164. }
  1165. }
  1166. }
  1167. protected virtual void CompleteAttack(IList<object> data)
  1168. {
  1169. MapObject target = (MapObject)data[0];
  1170. int damage = (int)data[1];
  1171. DefenceType defence = (DefenceType)data[2];
  1172. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null) return;
  1173. target.Attacked(this, damage, defence);
  1174. }
  1175. protected virtual void CompleteRangeAttack(IList<object> data)
  1176. {
  1177. MapObject target = (MapObject)data[0];
  1178. int damage = (int)data[1];
  1179. DefenceType defence = (DefenceType)data[2];
  1180. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null) return;
  1181. target.Attacked(this, damage, defence);
  1182. }
  1183. protected virtual void CompleteDeath(IList<object> data)
  1184. {
  1185. throw new NotImplementedException();
  1186. }
  1187. protected virtual void CompleteSpellEffect(IList<object> data)
  1188. {
  1189. MapObject target = (MapObject)data[0];
  1190. SpellEffect effect = (SpellEffect)data[1];
  1191. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null) return;
  1192. S.ObjectEffect p = new S.ObjectEffect { ObjectID = target.ObjectID, Effect = effect };
  1193. CurrentMap.Broadcast(p, target.CurrentLocation);
  1194. }
  1195. protected virtual void ProcessRegen()
  1196. {
  1197. if (Dead) return;
  1198. int healthRegen = 0;
  1199. if (CanRegen)
  1200. {
  1201. RegenTime = Envir.Time + RegenDelay;
  1202. if (HP < Stats[Stat.HP])
  1203. healthRegen += (int)(Stats[Stat.HP] * 0.022F) + 1;
  1204. }
  1205. if (Envir.Time > HealTime)
  1206. {
  1207. HealTime = Envir.Time + HealDelay;
  1208. if (HealAmount > 5)
  1209. {
  1210. healthRegen += 5;
  1211. HealAmount -= 5;
  1212. }
  1213. else
  1214. {
  1215. healthRegen += HealAmount;
  1216. HealAmount = 0;
  1217. }
  1218. }
  1219. if (healthRegen > 0)
  1220. {
  1221. ChangeHP(healthRegen);
  1222. BroadcastDamageIndicator(DamageType.Hit, healthRegen);
  1223. }
  1224. if (HP == Stats[Stat.HP]) HealAmount = 0;
  1225. }
  1226. protected virtual void ProcessPoison()
  1227. {
  1228. PoisonType type = PoisonType.None;
  1229. ArmourRate = 1F;
  1230. DamageRate = 1F;
  1231. for (int i = PoisonList.Count - 1; i >= 0; i--)
  1232. {
  1233. if (Dead) return;
  1234. Poison poison = PoisonList[i];
  1235. if (poison.Owner != null && poison.Owner.Node == null)
  1236. {
  1237. if (poison.PType == PoisonType.Slow)
  1238. {
  1239. MoveSpeed = Info.MoveSpeed;
  1240. AttackSpeed = Info.AttackSpeed;
  1241. AttackTime = Envir.Time + AttackSpeed;
  1242. }
  1243. PoisonList.RemoveAt(i);
  1244. continue;
  1245. }
  1246. if (Envir.Time > poison.TickTime)
  1247. {
  1248. poison.Time++;
  1249. poison.TickTime = Envir.Time + poison.TickSpeed;
  1250. if (poison.Time >= poison.Duration)
  1251. {
  1252. if (poison.PType == PoisonType.Slow)
  1253. {
  1254. MoveSpeed = Info.MoveSpeed;
  1255. AttackSpeed = Info.AttackSpeed;
  1256. AttackTime = Envir.Time + AttackSpeed;
  1257. }
  1258. PoisonList.RemoveAt(i);
  1259. continue;
  1260. }
  1261. if (poison.PType == PoisonType.Green || poison.PType == PoisonType.Bleeding)
  1262. {
  1263. if (EXPOwner == null || EXPOwner.Dead)
  1264. {
  1265. EXPOwner = poison.Owner;
  1266. EXPOwnerTime = Envir.Time + EXPOwnerDelay;
  1267. }
  1268. else if (EXPOwner == poison.Owner)
  1269. EXPOwnerTime = Envir.Time + EXPOwnerDelay;
  1270. if (poison.PType == PoisonType.Bleeding)
  1271. {
  1272. Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.Bleeding, EffectType = 0 });
  1273. }
  1274. //ChangeHP(-poison.Value);
  1275. PoisonDamage(-poison.Value, poison.Owner);
  1276. BroadcastDamageIndicator(DamageType.Hit, -poison.Value);
  1277. if (PoisonStopRegen)
  1278. RegenTime = Envir.Time + RegenDelay;
  1279. if (poison.Owner != null && Target == null)
  1280. Target = poison.Owner;
  1281. }
  1282. if (poison.PType == PoisonType.DelayedExplosion)
  1283. {
  1284. if (Envir.Time > ExplosionInflictedTime) ExplosionInflictedStage++;
  1285. if (!ProcessDelayedExplosion(poison))
  1286. {
  1287. ExplosionInflictedStage = 0;
  1288. ExplosionInflictedTime = 0;
  1289. if (Dead) break; //temp to stop crashing
  1290. PoisonList.RemoveAt(i);
  1291. continue;
  1292. }
  1293. }
  1294. }
  1295. switch (poison.PType)
  1296. {
  1297. case PoisonType.Red:
  1298. ArmourRate -= 0.5F;
  1299. break;
  1300. case PoisonType.Stun:
  1301. DamageRate += 0.5F;
  1302. break;
  1303. case PoisonType.Blindness:
  1304. break;
  1305. case PoisonType.Slow:
  1306. MoveSpeed = (ushort)Math.Min(3500, MoveSpeed + 100);
  1307. AttackSpeed = (ushort)Math.Min(3500, AttackSpeed + 100);
  1308. if (poison.Time >= poison.Duration)
  1309. {
  1310. MoveSpeed = Info.MoveSpeed;
  1311. AttackSpeed = Info.AttackSpeed;
  1312. //Reset the Attack time
  1313. AttackTime = Envir.Time + AttackSpeed;
  1314. }
  1315. break;
  1316. }
  1317. type |= poison.PType;
  1318. /*
  1319. if ((int)type < (int)poison.PType)
  1320. type = poison.PType;
  1321. */
  1322. }
  1323. if (type == CurrentPoison) return;
  1324. CurrentPoison = type;
  1325. Broadcast(new S.ObjectPoisoned { ObjectID = ObjectID, Poison = type });
  1326. }
  1327. private bool ProcessDelayedExplosion(Poison poison)
  1328. {
  1329. if (Dead) return false;
  1330. if (ExplosionInflictedStage == 0)
  1331. {
  1332. Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.DelayedExplosion, EffectType = 0 });
  1333. return true;
  1334. }
  1335. if (ExplosionInflictedStage == 1)
  1336. {
  1337. if (Envir.Time > ExplosionInflictedTime)
  1338. ExplosionInflictedTime = poison.TickTime + 3000;
  1339. Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.DelayedExplosion, EffectType = 1 });
  1340. return true;
  1341. }
  1342. if (ExplosionInflictedStage == 2)
  1343. {
  1344. Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.DelayedExplosion, EffectType = 2 });
  1345. if (poison.Owner != null)
  1346. {
  1347. switch (poison.Owner.Race)
  1348. {
  1349. case ObjectType.Player:
  1350. PlayerObject caster = (PlayerObject)poison.Owner;
  1351. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time, poison.Owner, caster.GetMagic(Spell.DelayedExplosion), poison.Value, this.CurrentLocation);
  1352. CurrentMap.ActionList.Add(action);
  1353. //Attacked((PlayerObject)poison.Owner, poison.Value, DefenceType.MAC, false);
  1354. break;
  1355. case ObjectType.Monster://this is in place so it could be used by mobs if one day someone chooses to
  1356. Attacked((MonsterObject)poison.Owner, poison.Value, DefenceType.MAC);
  1357. break;
  1358. }
  1359. LastHitter = poison.Owner;
  1360. }
  1361. return false;
  1362. }
  1363. return false;
  1364. }
  1365. private void ProcessBuffs()
  1366. {
  1367. bool refresh = false;
  1368. for (int i = Buffs.Count - 1; i >= 0; i--)
  1369. {
  1370. Buff buff = Buffs[i];
  1371. if (buff.NextTime > Envir.Time) continue;
  1372. if (!buff.Paused && buff.StackType != BuffStackType.Infinite)
  1373. {
  1374. var change = Envir.Time - buff.LastTime;
  1375. buff.ExpireTime -= change;
  1376. }
  1377. buff.LastTime = Envir.Time;
  1378. buff.NextTime = Envir.Time + 1000;
  1379. if ((buff.ExpireTime > 0 || buff.StackType == BuffStackType.Infinite) && !buff.FlagForRemoval) continue;
  1380. Buffs.RemoveAt(i);
  1381. if (buff.Info.Visible)
  1382. {
  1383. Broadcast(new S.RemoveBuff { Type = buff.Type, ObjectID = ObjectID });
  1384. }
  1385. switch (buff.Type)
  1386. {
  1387. case BuffType.Hiding:
  1388. case BuffType.MoonLight:
  1389. case BuffType.DarkBody:
  1390. if (!HasAnyBuffs(buff.Type, BuffType.ClearRing, BuffType.Hiding, BuffType.MoonLight, BuffType.DarkBody))
  1391. {
  1392. Hidden = false;
  1393. }
  1394. if (buff.Type == BuffType.MoonLight || buff.Type == BuffType.DarkBody)
  1395. {
  1396. if (!HasAnyBuffs(buff.Type, BuffType.MoonLight, BuffType.DarkBody))
  1397. {
  1398. Sneaking = false;
  1399. }
  1400. break;
  1401. }
  1402. break;
  1403. }
  1404. ProcessBuffEnd(buff);
  1405. refresh = true;
  1406. }
  1407. if (refresh) RefreshAll();
  1408. }
  1409. protected virtual void ProcessBuffEnd(Buff buff)
  1410. {
  1411. }
  1412. protected virtual void ProcessAI()
  1413. {
  1414. if (Dead) return;
  1415. if (DieNextTurn)
  1416. {
  1417. Die();
  1418. return;
  1419. }
  1420. if (Master != null && Master.CurrentMap != null)
  1421. {
  1422. bool masterAllowsPets = !Master.CurrentMap.Info.NoPets || IgnoresNoPetRestriction;
  1423. bool needsRecall = CurrentMap != Master.CurrentMap;
  1424. // If frozen AND on different map AND master allows pets — force recall
  1425. if (Frozen && needsRecall && masterAllowsPets)
  1426. {
  1427. PetRecall();
  1428. return;
  1429. }
  1430. // If frozen but already on correct map — unfreeze
  1431. if (Frozen && !needsRecall && masterAllowsPets)
  1432. {
  1433. Frozen = false;
  1434. PMode = PetMode.Both;
  1435. }
  1436. }
  1437. // Still frozen = do nothing
  1438. if (Frozen) return;
  1439. if (Master != null)
  1440. {
  1441. PetMode mode = Master.PMode;
  1442. Map masterMap = Master.CurrentMap;
  1443. Point masterLocation = Master.CurrentLocation;
  1444. if ((mode == PetMode.Both || mode == PetMode.MoveOnly || mode == PetMode.FocusMasterTarget)
  1445. && masterMap != null)
  1446. {
  1447. if (!Functions.InRange(CurrentLocation, masterLocation, Globals.DataRange) || CurrentMap != masterMap)
  1448. PetRecall();
  1449. }
  1450. if (mode == PetMode.MoveOnly || mode == PetMode.None)
  1451. {
  1452. Target = null;
  1453. }
  1454. }
  1455. CheckAlone();
  1456. if (!Alone || Settings.MonsterProcessWhenAlone)
  1457. {
  1458. ProcessStacking();
  1459. ProcessSearch();
  1460. ProcessRoam();
  1461. ProcessTarget();
  1462. }
  1463. }
  1464. protected virtual void CheckAlone()
  1465. {
  1466. if (Envir.Time < AloneTime) return;
  1467. AloneTime = Envir.Time + AloneDelay;
  1468. if (Route.Count > 0)
  1469. {
  1470. Alone = false;
  1471. return;
  1472. }
  1473. if (CurrentMap.Players.Count == 0)
  1474. {
  1475. Alone = true;
  1476. return;
  1477. }
  1478. for (int i = 0; i < CurrentMap.Players.Count; i++)
  1479. {
  1480. if (Functions.InRange(CurrentLocation, CurrentMap.Players[i].CurrentLocation, Globals.DataRange * 2))
  1481. {
  1482. Alone = false;
  1483. return;
  1484. }
  1485. }
  1486. Alone = true;
  1487. }
  1488. protected virtual void ProcessStacking()
  1489. {
  1490. //Stacking or Infront of master - Move
  1491. Stacking = CheckStacked();
  1492. if (CanMove && ((Master != null && Master.Front == CurrentLocation) || Stacking))
  1493. {
  1494. //Walk Randomly
  1495. if (!Walk(Direction))
  1496. {
  1497. MirDirection dir = Direction;
  1498. switch (Envir.Random.Next(3)) // favour Clockwise
  1499. {
  1500. case 0:
  1501. for (int i = 0; i < 7; i++)
  1502. {
  1503. dir = Functions.NextDir(dir);
  1504. if (Walk(dir))
  1505. break;
  1506. }
  1507. break;
  1508. default:
  1509. for (int i = 0; i < 7; i++)
  1510. {
  1511. dir = Functions.PreviousDir(dir);
  1512. if (Walk(dir))
  1513. break;
  1514. }
  1515. break;
  1516. }
  1517. }
  1518. return;
  1519. }
  1520. }
  1521. protected virtual void ProcessSearch()
  1522. {
  1523. if (Envir.Time < SearchTime) return;
  1524. if (Master != null && (Master.PMode == PetMode.MoveOnly || Master.PMode == PetMode.None || Master.PMode == PetMode.FocusMasterTarget)) return;
  1525. SearchTime = Envir.Time + SearchDelay;
  1526. if (Target == null || Envir.Random.Next(3) == 0)
  1527. FindTarget();
  1528. }
  1529. protected virtual void ProcessRoam()
  1530. {
  1531. if (Target != null || Envir.Time < RoamTime) return;
  1532. if (ProcessRoute()) return;
  1533. if (Master != null)
  1534. {
  1535. MoveTo(Master.Back);
  1536. return;
  1537. }
  1538. RoamTime = Envir.Time + RoamDelay;
  1539. if (Envir.Random.Next(10) != 0) return;
  1540. switch (Envir.Random.Next(3)) //Face Walk
  1541. {
  1542. case 0:
  1543. Turn((MirDirection)Envir.Random.Next(8));
  1544. break;
  1545. default:
  1546. Walk(Direction);
  1547. break;
  1548. }
  1549. }
  1550. protected virtual void ProcessTarget()
  1551. {
  1552. if (Target == null || !CanAttack) return;
  1553. if (InAttackRange())
  1554. {
  1555. Attack();
  1556. if (Target != null && Target.Dead)
  1557. {
  1558. FindTarget();
  1559. }
  1560. return;
  1561. }
  1562. if (Envir.Time < ShockTime)
  1563. {
  1564. Target = null;
  1565. return;
  1566. }
  1567. if (Settings.MonsterRecallEnabled && Info.CanRecall && TryRecallToTarget())
  1568. {
  1569. return;
  1570. }
  1571. MoveTo(Target.CurrentLocation);
  1572. }
  1573. protected virtual bool TryRecallToTarget()
  1574. {
  1575. if (Target == null || Target.CurrentMap == null) return false;
  1576. int recallRange = Math.Max(1, Settings.MonsterRecallRange);
  1577. int recallCooldown = Math.Max(0, Settings.MonsterRecallCooldown);
  1578. if (Envir.Time < NextRecallTime) return false;
  1579. bool needsRecall = Target.CurrentMap != CurrentMap ||
  1580. !Functions.InRange(CurrentLocation, Target.CurrentLocation, recallRange);
  1581. if (!needsRecall) return false;
  1582. Point destination = FindRecallPoint(Target.CurrentMap, Target.CurrentLocation);
  1583. if (!Target.CurrentMap.ValidPoint(destination)) return false;
  1584. if (!Teleport(Target.CurrentMap, destination, true))
  1585. return false;
  1586. NextRecallTime = Envir.Time + recallCooldown;
  1587. ActionTime = Envir.Time + 1000;
  1588. return true;
  1589. }
  1590. protected virtual Point FindRecallPoint(Map map, Point targetLocation)
  1591. {
  1592. if (map.ValidPoint(targetLocation)) return targetLocation;
  1593. for (int i = 0; i < 8; i++)
  1594. {
  1595. Point point = Functions.PointMove(targetLocation, (MirDirection)i, 1);
  1596. if (map.ValidPoint(point))
  1597. return point;
  1598. }
  1599. return targetLocation;
  1600. }
  1601. protected virtual bool InAttackRange()
  1602. {
  1603. if (Target.CurrentMap != CurrentMap) return false;
  1604. return Target.CurrentLocation != CurrentLocation && Functions.InRange(CurrentLocation, Target.CurrentLocation, 1);
  1605. }
  1606. protected virtual void FindTarget()
  1607. {
  1608. Map Current = CurrentMap;
  1609. for (int d = 0; d <= Info.ViewRange; d++)
  1610. {
  1611. for (int y = CurrentLocation.Y - d; y <= CurrentLocation.Y + d; y++)
  1612. {
  1613. if (y < 0) continue;
  1614. if (y >= Current.Height) break;
  1615. for (int x = CurrentLocation.X - d; x <= CurrentLocation.X + d; x += Math.Abs(y - CurrentLocation.Y) == d ? 1 : d * 2)
  1616. {
  1617. if (x < 0) continue;
  1618. if (x >= Current.Width) break;
  1619. Cell cell = Current.Cells[x, y];
  1620. if (cell.Objects == null || !cell.Valid) continue;
  1621. for (int i = 0; i < cell.Objects.Count; i++)
  1622. {
  1623. MapObject ob = cell.Objects[i];
  1624. switch (ob.Race)
  1625. {
  1626. case ObjectType.Monster:
  1627. case ObjectType.Hero:
  1628. if (!ob.IsAttackTarget(this)) continue;
  1629. if (ob.Hidden && (!CoolEye || Level < ob.Level)) continue;
  1630. if (this is TrapRock && ob.InTrapRock) continue;
  1631. if (ob.Race == ObjectType.Monster &&
  1632. ob is StoneTrap)
  1633. {
  1634. if (Target is null ||
  1635. (Target is not null &&
  1636. Target is not StoneTrap))
  1637. {
  1638. Target = ob;
  1639. }
  1640. return;
  1641. }
  1642. else
  1643. {
  1644. Target ??= ob;
  1645. }
  1646. continue;
  1647. case ObjectType.Player:
  1648. if (Target != null)
  1649. {
  1650. continue;
  1651. }
  1652. PlayerObject playerob = (PlayerObject)ob;
  1653. if (!ob.IsAttackTarget(this)) continue;
  1654. if (playerob.GMGameMaster || ob.Hidden && (!CoolEye || Level < ob.Level) || Envir.Time < HallucinationTime) continue;
  1655. Target = ob;
  1656. if (Master != null)
  1657. {
  1658. for (int j = 0; j < playerob.Pets.Count; j++)
  1659. {
  1660. MonsterObject pet = playerob.Pets[j];
  1661. if (!pet.IsAttackTarget(this)) continue;
  1662. Target = pet;
  1663. break;
  1664. }
  1665. }
  1666. continue;
  1667. default:
  1668. continue;
  1669. }
  1670. }
  1671. }
  1672. }
  1673. }
  1674. }
  1675. protected virtual bool ProcessRoute()
  1676. {
  1677. if (Route.Count < 1) return false;
  1678. RoamTime = Envir.Time + 500;
  1679. if (CurrentLocation == Route[RoutePoint].Location)
  1680. {
  1681. if (Route[RoutePoint].Delay > 0 && !Waiting)
  1682. {
  1683. Waiting = true;
  1684. RoamTime = Envir.Time + RoamDelay + Route[RoutePoint].Delay;
  1685. return true;
  1686. }
  1687. Waiting = false;
  1688. RoutePoint++;
  1689. }
  1690. if (RoutePoint > Route.Count - 1) RoutePoint = 0;
  1691. if (!CurrentMap.ValidPoint(Route[RoutePoint].Location)) return true;
  1692. MoveTo(Route[RoutePoint].Location);
  1693. return true;
  1694. }
  1695. protected virtual void MoveTo(Point location)
  1696. {
  1697. if (CurrentLocation == location) return;
  1698. bool inRange = Functions.InRange(location, CurrentLocation, 1);
  1699. if (inRange)
  1700. {
  1701. if (!CurrentMap.ValidPoint(location)) return;
  1702. Cell cell = CurrentMap.GetCell(location);
  1703. if (cell.Objects != null)
  1704. for (int i = 0; i < cell.Objects.Count; i++)
  1705. {
  1706. MapObject ob = cell.Objects[i];
  1707. if (!ob.Blocking) continue;
  1708. return;
  1709. }
  1710. }
  1711. MirDirection dir = Functions.DirectionFromPoint(CurrentLocation, location);
  1712. if (Walk(dir)) return;
  1713. switch (Envir.Random.Next(2)) //No favour
  1714. {
  1715. case 0:
  1716. for (int i = 0; i < 7; i++)
  1717. {
  1718. dir = Functions.NextDir(dir);
  1719. if (Walk(dir))
  1720. return;
  1721. }
  1722. break;
  1723. default:
  1724. for (int i = 0; i < 7; i++)
  1725. {
  1726. dir = Functions.PreviousDir(dir);
  1727. if (Walk(dir))
  1728. return;
  1729. }
  1730. break;
  1731. }
  1732. }
  1733. public virtual void Turn(MirDirection dir)
  1734. {
  1735. if (!CanMove) return;
  1736. Direction = dir;
  1737. InSafeZone = CurrentMap.GetSafeZone(CurrentLocation) != null;
  1738. Cell cell = CurrentMap.GetCell(CurrentLocation);
  1739. for (int i = 0; i < cell.Objects.Count; i++)
  1740. {
  1741. if (cell.Objects[i].Race != ObjectType.Spell) continue;
  1742. SpellObject ob = (SpellObject)cell.Objects[i];
  1743. ob.ProcessSpell(this);
  1744. //break;
  1745. }
  1746. Broadcast(new S.ObjectTurn { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  1747. }
  1748. public virtual bool Walk(MirDirection dir)
  1749. {
  1750. if (!CanMove) return false;
  1751. Point location = Functions.PointMove(CurrentLocation, dir, 1);
  1752. if (!CurrentMap.ValidPoint(location)) return false;
  1753. Cell cell = CurrentMap.GetCell(location);
  1754. if (cell.Objects != null)
  1755. for (int i = 0; i < cell.Objects.Count; i++)
  1756. {
  1757. MapObject ob = cell.Objects[i];
  1758. if (!ob.Blocking || Race == ObjectType.Creature) continue;
  1759. return false;
  1760. }
  1761. CurrentMap.GetCell(CurrentLocation).Remove(this);
  1762. Direction = dir;
  1763. RemoveObjects(dir, 1);
  1764. CurrentLocation = location;
  1765. CurrentMap.GetCell(CurrentLocation).Add(this);
  1766. AddObjects(dir, 1);
  1767. if (Hidden)
  1768. {
  1769. RemoveBuff(BuffType.Hiding);
  1770. }
  1771. CellTime = Envir.Time + 500;
  1772. ActionTime = Envir.Time + 300;
  1773. MoveTime = Envir.Time + MoveSpeed;
  1774. if (MoveTime > AttackTime)
  1775. AttackTime = MoveTime;
  1776. InSafeZone = CurrentMap.GetSafeZone(CurrentLocation) != null;
  1777. Broadcast(new S.ObjectWalk { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  1778. cell = CurrentMap.GetCell(CurrentLocation);
  1779. for (int i = 0; i < cell.Objects.Count; i++)
  1780. {
  1781. if (cell.Objects[i].Race != ObjectType.Spell) continue;
  1782. SpellObject ob = (SpellObject)cell.Objects[i];
  1783. ob.ProcessSpell(this);
  1784. //break;
  1785. }
  1786. return true;
  1787. }
  1788. protected virtual void Attack()
  1789. {
  1790. if (BindingShotCenter) ReleaseBindingShot();
  1791. ShockTime = 0;
  1792. if (!Target.IsAttackTarget(this))
  1793. {
  1794. Target = null;
  1795. return;
  1796. }
  1797. Direction = Functions.DirectionFromPoint(CurrentLocation, Target.CurrentLocation);
  1798. Broadcast(new S.ObjectAttack { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  1799. ActionTime = Envir.Time + 300;
  1800. AttackTime = Envir.Time + AttackSpeed;
  1801. int damage = GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]);
  1802. if (damage == 0) return;
  1803. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + 300, Target, damage, DefenceType.ACAgility);
  1804. ActionList.Add(action);
  1805. }
  1806. public void ReleaseBindingShot()
  1807. {
  1808. if (!BindingShotCenter) return;
  1809. ShockTime = 0;
  1810. Broadcast(GetInfo());//update clients in range (remove effect)
  1811. BindingShotCenter = false;
  1812. //the centertarget is escaped so make all shocked mobs awake (3x3 from center)
  1813. Point place = CurrentLocation;
  1814. for (int y = place.Y - 1; y <= place.Y + 1; y++)
  1815. {
  1816. if (y < 0) continue;
  1817. if (y >= CurrentMap.Height) break;
  1818. for (int x = place.X - 1; x <= place.X + 1; x++)
  1819. {
  1820. if (x < 0) continue;
  1821. if (x >= CurrentMap.Width) break;
  1822. Cell cell = CurrentMap.GetCell(x, y);
  1823. if (!cell.Valid || cell.Objects == null) continue;
  1824. for (int i = 0; i < cell.Objects.Count; i++)
  1825. {
  1826. MapObject targetob = cell.Objects[i];
  1827. if (targetob == null || targetob.Node == null || targetob.Race != ObjectType.Monster) continue;
  1828. if (((MonsterObject)targetob).ShockTime == 0) continue;
  1829. //each centerTarget has its own effect which needs to be cleared when no longer shocked
  1830. if (((MonsterObject)targetob).BindingShotCenter) ((MonsterObject)targetob).ReleaseBindingShot();
  1831. else ((MonsterObject)targetob).ShockTime = 0;
  1832. break;
  1833. }
  1834. }
  1835. }
  1836. }
  1837. public bool FindNearby(int distance)
  1838. {
  1839. for (int d = 0; d <= distance; d++)
  1840. {
  1841. for (int y = CurrentLocation.Y - d; y <= CurrentLocation.Y + d; y++)
  1842. {
  1843. if (y < 0) continue;
  1844. if (y >= CurrentMap.Height) break;
  1845. for (int x = CurrentLocation.X - d; x <= CurrentLocation.X + d; x += Math.Abs(y - CurrentLocation.Y) == d ? 1 : d * 2)
  1846. {
  1847. if (x < 0) continue;
  1848. if (x >= CurrentMap.Width) break;
  1849. if (!CurrentMap.ValidPoint(x, y)) continue;
  1850. Cell cell = CurrentMap.GetCell(x, y);
  1851. if (cell.Objects == null) continue;
  1852. for (int i = 0; i < cell.Objects.Count; i++)
  1853. {
  1854. MapObject ob = cell.Objects[i];
  1855. switch (ob.Race)
  1856. {
  1857. case ObjectType.Monster:
  1858. case ObjectType.Player:
  1859. case ObjectType.Hero:
  1860. if (!ob.IsAttackTarget(this)) continue;
  1861. if (ob.Hidden && (!CoolEye || Level < ob.Level)) continue;
  1862. if (ob.Race == ObjectType.Player)
  1863. {
  1864. PlayerObject player = ((PlayerObject)ob);
  1865. if (player.GMGameMaster) continue;
  1866. }
  1867. return true;
  1868. default:
  1869. continue;
  1870. }
  1871. }
  1872. }
  1873. }
  1874. }
  1875. return false;
  1876. }
  1877. public bool FindFriendsNearby(int distance)
  1878. {
  1879. for (int d = 0; d <= distance; d++)
  1880. {
  1881. for (int y = CurrentLocation.Y - d; y <= CurrentLocation.Y + d; y++)
  1882. {
  1883. if (y < 0) continue;
  1884. if (y >= CurrentMap.Height) break;
  1885. for (int x = CurrentLocation.X - d; x <= CurrentLocation.X + d; x += Math.Abs(y - CurrentLocation.Y) == d ? 1 : d * 2)
  1886. {
  1887. if (x < 0) continue;
  1888. if (x >= CurrentMap.Width) break;
  1889. if (!CurrentMap.ValidPoint(x, y)) continue;
  1890. Cell cell = CurrentMap.GetCell(x, y);
  1891. if (cell.Objects == null) continue;
  1892. for (int i = 0; i < cell.Objects.Count; i++)
  1893. {
  1894. MapObject ob = cell.Objects[i];
  1895. switch (ob.Race)
  1896. {
  1897. case ObjectType.Monster:
  1898. case ObjectType.Player:
  1899. case ObjectType.Hero:
  1900. if (ob == this || ob.Dead) continue;
  1901. if (ob.IsAttackTarget(this)) continue;
  1902. if (ob.Race == ObjectType.Player)
  1903. {
  1904. PlayerObject player = ((PlayerObject)ob);
  1905. if (player.GMGameMaster) continue;
  1906. }
  1907. return true;
  1908. default:
  1909. continue;
  1910. }
  1911. }
  1912. }
  1913. }
  1914. }
  1915. return false;
  1916. }
  1917. protected List<MapObject> FindAllFriends(int dist, Point location, bool needSight = true, bool ownAI = true)
  1918. {
  1919. List<MapObject> targets = new List<MapObject>();
  1920. for (int d = 0; d <= dist; d++)
  1921. {
  1922. for (int y = location.Y - d; y <= location.Y + d; y++)
  1923. {
  1924. if (y < 0) continue;
  1925. if (y >= CurrentMap.Height) break;
  1926. for (int x = location.X - d; x <= location.X + d; x += Math.Abs(y - location.Y) == d ? 1 : d * 2)
  1927. {
  1928. if (x < 0) continue;
  1929. if (x >= CurrentMap.Width) break;
  1930. Cell cell = CurrentMap.GetCell(x, y);
  1931. if (!cell.Valid || cell.Objects == null) continue;
  1932. for (int i = 0; i < cell.Objects.Count; i++)
  1933. {
  1934. MapObject ob = cell.Objects[i];
  1935. if (ob == this) continue;
  1936. switch (ob.Race)
  1937. {
  1938. case ObjectType.Monster:
  1939. case ObjectType.Player:
  1940. case ObjectType.Hero:
  1941. if (ob.Dead) continue;
  1942. if (!ownAI && ob.Race == ObjectType.Monster && ((MonsterObject)ob).Info.AI == Info.AI) continue;
  1943. if (!ob.IsFriendlyTarget(this)) continue;
  1944. if (ob.Master != Master) continue;
  1945. if (ob.Hidden && (!CoolEye || Level < ob.Level) && needSight) continue;
  1946. targets.Add(ob);
  1947. continue;
  1948. default:
  1949. continue;
  1950. }
  1951. }
  1952. }
  1953. }
  1954. }
  1955. return targets;
  1956. }
  1957. public List<MapObject> FindAllNearby(int dist, Point location, bool needSight = true)
  1958. {
  1959. List<MapObject> targets = new List<MapObject>();
  1960. for (int d = 0; d <= dist; d++)
  1961. {
  1962. for (int y = location.Y - d; y <= location.Y + d; y++)
  1963. {
  1964. if (y < 0) continue;
  1965. if (y >= CurrentMap.Height) break;
  1966. for (int x = location.X - d; x <= location.X + d; x += Math.Abs(y - location.Y) == d ? 1 : d * 2)
  1967. {
  1968. if (x < 0) continue;
  1969. if (x >= CurrentMap.Width) break;
  1970. Cell cell = CurrentMap.GetCell(x, y);
  1971. if (!cell.Valid || cell.Objects == null) continue;
  1972. for (int i = 0; i < cell.Objects.Count; i++)
  1973. {
  1974. MapObject ob = cell.Objects[i];
  1975. switch (ob.Race)
  1976. {
  1977. case ObjectType.Monster:
  1978. case ObjectType.Player:
  1979. case ObjectType.Hero:
  1980. targets.Add(ob);
  1981. continue;
  1982. default:
  1983. continue;
  1984. }
  1985. }
  1986. }
  1987. }
  1988. }
  1989. return targets;
  1990. }
  1991. protected List<MapObject> FindAllTargets(int dist, Point location, bool needSight = true)
  1992. {
  1993. List<MapObject> targets = new List<MapObject>();
  1994. for (int d = 0; d <= dist; d++)
  1995. {
  1996. for (int y = location.Y - d; y <= location.Y + d; y++)
  1997. {
  1998. if (y < 0) continue;
  1999. if (y >= CurrentMap.Height) break;
  2000. for (int x = location.X - d; x <= location.X + d; x += Math.Abs(y - location.Y) == d ? 1 : d * 2)
  2001. {
  2002. if (x < 0) continue;
  2003. if (x >= CurrentMap.Width) break;
  2004. Cell cell = CurrentMap.GetCell(x, y);
  2005. if (!cell.Valid || cell.Objects == null) continue;
  2006. for (int i = 0; i < cell.Objects.Count; i++)
  2007. {
  2008. MapObject ob = cell.Objects[i];
  2009. switch (ob.Race)
  2010. {
  2011. case ObjectType.Monster:
  2012. case ObjectType.Player:
  2013. case ObjectType.Hero:
  2014. if (!ob.IsAttackTarget(this)) continue;
  2015. if (ob.Hidden && (!CoolEye || Level < ob.Level) && needSight) continue;
  2016. if (ob.Race == ObjectType.Player)
  2017. {
  2018. PlayerObject player = ((PlayerObject)ob);
  2019. if (player.GMGameMaster) continue;
  2020. }
  2021. targets.Add(ob);
  2022. continue;
  2023. default:
  2024. continue;
  2025. }
  2026. }
  2027. }
  2028. }
  2029. }
  2030. return targets;
  2031. }
  2032. public override bool IsAttackTarget(HumanObject attacker)
  2033. {
  2034. if (attacker == null || attacker.Node == null) return false;
  2035. if (Dead) return false;
  2036. if (Master == null) return true;
  2037. if (attacker.Race == ObjectType.Hero)
  2038. attacker = ((HeroObject)attacker).Owner;
  2039. if (attacker.AMode == AttackMode.Peace) return false;
  2040. if (Master == attacker) return attacker.AMode == AttackMode.All;
  2041. if (Master.Race == ObjectType.Player && (attacker.InSafeZone || InSafeZone)) return false;
  2042. switch (attacker.AMode)
  2043. {
  2044. case AttackMode.Group:
  2045. return Master.GroupMembers == null || !Master.GroupMembers.Contains(attacker);
  2046. case AttackMode.Guild:
  2047. {
  2048. if (!(Master is PlayerObject)) return false;
  2049. PlayerObject master = (PlayerObject)Master;
  2050. return master.MyGuild == null || master.MyGuild != attacker.MyGuild;
  2051. }
  2052. case AttackMode.EnemyGuild:
  2053. {
  2054. if (!(Master is PlayerObject)) return false;
  2055. PlayerObject master = (PlayerObject)Master;
  2056. return (master.MyGuild != null && attacker.MyGuild != null) && master.MyGuild.IsEnemy(attacker.MyGuild);
  2057. }
  2058. case AttackMode.RedBrown:
  2059. return Master.PKPoints >= 200 || Envir.Time < Master.BrownTime;
  2060. default:
  2061. return true;
  2062. }
  2063. }
  2064. public override bool IsAttackTarget(MonsterObject attacker)
  2065. {
  2066. if (attacker == null || attacker.Node == null) return false;
  2067. if (Dead || attacker == this) return false;
  2068. if (attacker.Race == ObjectType.Creature) return false;
  2069. if (attacker.Info.AI == 6 || attacker.Info.AI == 113) // Guard
  2070. {
  2071. if (Info.AI != 1 && Info.AI != 2 && Info.AI != 3 && (Master == null || Master.PKPoints >= 200)) //Not Dear/Hen/Tree/Pets or Red Master
  2072. return true;
  2073. }
  2074. else if (attacker.Info.AI == 58) // Tao Guard - attacks Pets
  2075. {
  2076. if (Info.AI != 1 && Info.AI != 2 && Info.AI != 3 && (Master == null || Master.AMode != AttackMode.Peace)) //Not Dear/Hen/Tree or Peaceful Master
  2077. return true;
  2078. }
  2079. else if (Master != null) //Pet Attacked
  2080. {
  2081. if (attacker.Master == null) //Wild Monster
  2082. return true;
  2083. //Pet Vs Pet
  2084. if (Master == attacker.Master)
  2085. return false;
  2086. if (Envir.Time < ShockTime) //Shocked
  2087. return false;
  2088. if (Master.Race == ObjectType.Player && attacker.Master.Race == ObjectType.Player && (Master.InSafeZone || attacker.Master.InSafeZone)) return false;
  2089. switch (attacker.Master.AMode)
  2090. {
  2091. case AttackMode.Group:
  2092. if (Master.GroupMembers != null && Master.GroupMembers.Contains((PlayerObject)attacker.Master)) return false;
  2093. break;
  2094. case AttackMode.Guild:
  2095. break;
  2096. case AttackMode.EnemyGuild:
  2097. break;
  2098. case AttackMode.RedBrown:
  2099. if (attacker.Master.PKPoints < 200 || Envir.Time > attacker.Master.BrownTime) return false;
  2100. break;
  2101. case AttackMode.Peace:
  2102. return false;
  2103. }
  2104. for (int i = 0; i < Master.Pets.Count; i++)
  2105. if (Master.Pets[i].EXPOwner == attacker.Master) return true;
  2106. for (int i = 0; i < attacker.Master.Pets.Count; i++)
  2107. {
  2108. MonsterObject ob = attacker.Master.Pets[i];
  2109. if (ob == Target || ob.Target == this) return true;
  2110. }
  2111. return Master.LastHitter == attacker.Master;
  2112. }
  2113. else if (attacker.Master != null) //Pet Attacking Wild Monster
  2114. {
  2115. if (Envir.Time < ShockTime) //Shocked
  2116. return false;
  2117. for (int i = 0; i < attacker.Master.Pets.Count; i++)
  2118. {
  2119. MonsterObject ob = attacker.Master.Pets[i];
  2120. if (ob == Target || ob.Target == this) return true;
  2121. }
  2122. if (Target == attacker.Master)
  2123. return true;
  2124. }
  2125. if (Envir.Time < attacker.HallucinationTime) return true;
  2126. return Envir.Time < attacker.RageTime;
  2127. }
  2128. public override bool IsFriendlyTarget(HumanObject ally)
  2129. {
  2130. if (Master == null) return false;
  2131. if (Master == ally) return true;
  2132. switch (ally.AMode)
  2133. {
  2134. case AttackMode.Group:
  2135. return Master.GroupMembers != null && Master.GroupMembers.Contains(ally);
  2136. case AttackMode.Guild:
  2137. return false;
  2138. case AttackMode.EnemyGuild:
  2139. return true;
  2140. case AttackMode.RedBrown:
  2141. return Master.PKPoints < 200 & Envir.Time > Master.BrownTime;
  2142. }
  2143. return true;
  2144. }
  2145. public override bool IsFriendlyTarget(MonsterObject ally)
  2146. {
  2147. if (Master != null) return false;
  2148. if (ally.Race != ObjectType.Monster) return false;
  2149. if (ally.Master != null) return false;
  2150. return true;
  2151. }
  2152. public override int Attacked(HumanObject attacker, int damage, DefenceType type = DefenceType.ACAgility, bool damageWeapon = true)
  2153. {
  2154. if (Target == null && attacker.IsAttackTarget(this))
  2155. {
  2156. Target = attacker;
  2157. }
  2158. var armour = GetArmour(type, attacker, out bool hit);
  2159. if (!hit)
  2160. return 0;
  2161. armour = (int)Math.Max(int.MinValue, (Math.Min(int.MaxValue, (decimal)(armour * ArmourRate))));
  2162. damage = (int)Math.Max(int.MinValue, (Math.Min(int.MaxValue, (decimal)(damage * DamageRate))));
  2163. if (damageWeapon)
  2164. attacker.DamageWeapon();
  2165. damage += attacker.Stats[Stat.AttackBonus];
  2166. if (armour >= damage)
  2167. {
  2168. BroadcastDamageIndicator(DamageType.Miss);
  2169. return 0;
  2170. }
  2171. if (Envir.Random.Next(100) < (attacker.Stats[Stat.CriticalRate] * Settings.CriticalRateWeight))
  2172. {
  2173. Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.Critical });
  2174. damage = Math.Min(int.MaxValue, damage + (int)Math.Floor(damage * (((double)attacker.Stats[Stat.CriticalDamage] / (double)Settings.CriticalDamageWeight) * 10)));
  2175. BroadcastDamageIndicator(DamageType.Critical);
  2176. }
  2177. if (Target != this && attacker.IsAttackTarget(this))
  2178. {
  2179. if (attacker.Info.MentalState == 2)
  2180. {
  2181. if (Functions.MaxDistance(CurrentLocation, attacker.CurrentLocation) < (8 - attacker.Info.MentalStateLvl))
  2182. Target = attacker;
  2183. }
  2184. else
  2185. Target = attacker;
  2186. }
  2187. if (BindingShotCenter) ReleaseBindingShot();
  2188. ShockTime = 0;
  2189. for (int i = PoisonList.Count - 1; i >= 0; i--)
  2190. {
  2191. if (PoisonList[i].PType != PoisonType.LRParalysis) continue;
  2192. PoisonList.RemoveAt(i);
  2193. OperateTime = 0;
  2194. }
  2195. if (Master != null && Master != attacker && (Master.Race != ObjectType.Hero || Master.Race == ObjectType.Hero && attacker != ((HeroObject)Master).Owner))
  2196. if (Envir.Time > Master.BrownTime && Master.PKPoints < 200)
  2197. attacker.BrownTime = Envir.Time + Settings.Minute;
  2198. if (EXPOwner == null || EXPOwner.Dead)
  2199. {
  2200. EXPOwner = GetAttacker(attacker);
  2201. }
  2202. if (EXPOwner == attacker)
  2203. EXPOwnerTime = Envir.Time + EXPOwnerDelay;
  2204. ushort levelOffset = (ushort)(Level > attacker.Level ? 0 : Math.Min(10, attacker.Level - Level));
  2205. ApplyNegativeEffects(attacker, type, levelOffset);
  2206. Broadcast(new S.ObjectStruck { ObjectID = ObjectID, AttackerID = attacker.ObjectID, Direction = Direction, Location = CurrentLocation });
  2207. if (attacker.Stats[Stat.HPDrainRatePercent] > 0 && damageWeapon)
  2208. {
  2209. attacker.HpDrain += Math.Max(0, ((float)(damage - armour) / 100) * attacker.Stats[Stat.HPDrainRatePercent]);
  2210. if (attacker.HpDrain > 2)
  2211. {
  2212. int hpGain = (int)Math.Floor(attacker.HpDrain);
  2213. attacker.ChangeHP(hpGain);
  2214. attacker.HpDrain -= hpGain;
  2215. }
  2216. }
  2217. attacker.GatherElement();
  2218. if (attacker.Info.Mentor != 0 && attacker.Info.IsMentor)
  2219. {
  2220. if (attacker.HasBuff(BuffType.Mentor, out _))
  2221. {
  2222. CharacterInfo mentee = Envir.GetCharacterInfo(attacker.Info.Mentor);
  2223. PlayerObject player = Envir.GetPlayer(mentee.Name);
  2224. if (player != null && player.CurrentMap == attacker.CurrentMap && Functions.InRange(player.CurrentLocation, attacker.CurrentLocation, Globals.DataRange) && !player.Dead)
  2225. {
  2226. if (GroupMembers != null && GroupMembers.Contains(player))
  2227. damage += (int)Math.Round((double)(damage * attacker.Stats[Stat.MentorDamageRatePercent]) / 100);
  2228. }
  2229. }
  2230. }
  2231. if (Master != null && Master != attacker && Master.Race == ObjectType.Player && Envir.Time > Master.BrownTime && Master.PKPoints < 200 && !((PlayerObject)Master).AtWar(attacker))
  2232. {
  2233. attacker.BrownTime = Envir.Time + Settings.Minute;
  2234. }
  2235. for (int i = 0; i < attacker.Pets.Count; i++)
  2236. {
  2237. MonsterObject ob = attacker.Pets[i];
  2238. if (IsAttackTarget(ob) && (ob.Target == null)) ob.Target = this;
  2239. }
  2240. BroadcastDamageIndicator(DamageType.Hit, armour - damage);
  2241. ChangeHP(armour - damage);
  2242. return damage - armour;
  2243. }
  2244. public override int Attacked(MonsterObject attacker, int damage, DefenceType type = DefenceType.ACAgility)
  2245. {
  2246. if (Target == null && attacker.IsAttackTarget(this))
  2247. Target = attacker;
  2248. var armour = GetArmour(type, attacker, out bool hit);
  2249. if (!hit)
  2250. return 0;
  2251. armour = (int)Math.Max(int.MinValue, (Math.Min(int.MaxValue, (decimal)(armour * ArmourRate))));
  2252. damage = (int)Math.Max(int.MinValue, (Math.Min(int.MaxValue, (decimal)(damage * DamageRate))));
  2253. if (armour >= damage)
  2254. {
  2255. BroadcastDamageIndicator(DamageType.Miss);
  2256. return 0;
  2257. }
  2258. if (Target != this && attacker.IsAttackTarget(this))
  2259. Target = attacker;
  2260. if (BindingShotCenter) ReleaseBindingShot();
  2261. ShockTime = 0;
  2262. for (int i = PoisonList.Count - 1; i >= 0; i--)
  2263. {
  2264. if (PoisonList[i].PType != PoisonType.LRParalysis) continue;
  2265. PoisonList.RemoveAt(i);
  2266. OperateTime = 0;
  2267. }
  2268. if (attacker.Info.AI == 6 || attacker.Info.AI == 58 || attacker.Info.AI == 113)
  2269. EXPOwner = null;
  2270. else if (attacker.Master != null)
  2271. {
  2272. if (attacker.CurrentMap != attacker.Master.CurrentMap || !Functions.InRange(attacker.CurrentLocation, attacker.Master.CurrentLocation, Globals.DataRange))
  2273. EXPOwner = null;
  2274. else
  2275. {
  2276. if (EXPOwner == null || EXPOwner.Dead)
  2277. EXPOwner = attacker.Master switch
  2278. {
  2279. HeroObject hero => hero.Owner,
  2280. _ => attacker.Master
  2281. };
  2282. if (EXPOwner == attacker.Master)
  2283. EXPOwnerTime = Envir.Time + EXPOwnerDelay;
  2284. }
  2285. }
  2286. Broadcast(new S.ObjectStruck { ObjectID = ObjectID, AttackerID = attacker.ObjectID, Direction = Direction, Location = CurrentLocation });
  2287. BroadcastDamageIndicator(DamageType.Hit, armour - damage);
  2288. ChangeHP(armour - damage);
  2289. return damage - armour;
  2290. }
  2291. public override int Struck(int damage, DefenceType type = DefenceType.ACAgility)
  2292. {
  2293. int armour = 0;
  2294. switch (type)
  2295. {
  2296. case DefenceType.ACAgility:
  2297. armour = GetAttackPower(Stats[Stat.MinAC], Stats[Stat.MaxAC]);
  2298. break;
  2299. case DefenceType.AC:
  2300. armour = GetAttackPower(Stats[Stat.MinAC], Stats[Stat.MaxAC]);
  2301. break;
  2302. case DefenceType.MACAgility:
  2303. armour = GetAttackPower(Stats[Stat.MinMAC], Stats[Stat.MaxMAC]);
  2304. break;
  2305. case DefenceType.MAC:
  2306. armour = GetAttackPower(Stats[Stat.MinMAC], Stats[Stat.MaxMAC]);
  2307. break;
  2308. case DefenceType.Agility:
  2309. break;
  2310. }
  2311. armour = (int)Math.Max(int.MinValue, (Math.Min(int.MaxValue, (decimal)(armour * ArmourRate))));
  2312. damage = (int)Math.Max(int.MinValue, (Math.Min(int.MaxValue, (decimal)(damage * DamageRate))));
  2313. if (armour >= damage) return 0;
  2314. Broadcast(new S.ObjectStruck { ObjectID = ObjectID, AttackerID = 0, Direction = Direction, Location = CurrentLocation });
  2315. ChangeHP(armour - damage);
  2316. return damage - armour;
  2317. }
  2318. public override void ApplyPoison(Poison p, MapObject Caster = null, bool NoResist = false, bool ignoreDefence = true)
  2319. {
  2320. if (p.Owner != null && p.Owner.IsAttackTarget(this) && Target == null)
  2321. Target = p.Owner;
  2322. if (Master != null && p.Owner != null && p.Owner.Race == ObjectType.Player && p.Owner != Master)
  2323. {
  2324. if (Envir.Time > Master.BrownTime && Master.PKPoints < 200)
  2325. p.Owner.BrownTime = Envir.Time + Settings.Minute;
  2326. }
  2327. if (!ignoreDefence && (p.PType == PoisonType.Green))
  2328. {
  2329. int armour = GetAttackPower(Stats[Stat.MinMAC], Stats[Stat.MaxMAC]);
  2330. if (p.Value < armour)
  2331. p.PType = PoisonType.None;
  2332. else
  2333. p.Value -= armour;
  2334. }
  2335. if (p.PType == PoisonType.None) return;
  2336. for (int i = 0; i < PoisonList.Count; i++)
  2337. {
  2338. if (PoisonList[i].PType != p.PType) continue;
  2339. if ((PoisonList[i].PType == PoisonType.Green) && (PoisonList[i].Value > p.Value)) return;//cant cast weak poison to cancel out strong poison
  2340. if ((PoisonList[i].PType != PoisonType.Green) && ((PoisonList[i].Duration - PoisonList[i].Time) > p.Duration)) return;//cant cast 1 second poison to make a 1minute poison go away!
  2341. if (p.PType == PoisonType.DelayedExplosion) return;
  2342. if ((PoisonList[i].PType == PoisonType.Frozen) || (PoisonList[i].PType == PoisonType.Slow) || (PoisonList[i].PType == PoisonType.Paralysis)|| (PoisonList[i].PType == PoisonType.LRParalysis)) return;//prevents mobs from being perma frozen/slowed
  2343. PoisonList[i] = p;
  2344. return;
  2345. }
  2346. if (p.PType == PoisonType.DelayedExplosion)
  2347. {
  2348. ExplosionInflictedTime = Envir.Time + 4000;
  2349. Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.DelayedExplosion });
  2350. }
  2351. else if (p.PType == PoisonType.Dazed)
  2352. {
  2353. Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.Stunned, Time = (uint)(p.Duration * p.TickSpeed) });
  2354. }
  2355. else if (p.PType == PoisonType.Blindness)
  2356. {
  2357. var stats = new Stats
  2358. {
  2359. [Stat.Accuracy] = p.Value * -1
  2360. };
  2361. AddBuff(BuffType.Blindness, Caster, (int)(p.Duration * p.TickSpeed), stats);
  2362. }
  2363. PoisonList.Add(p);
  2364. }
  2365. public override Buff AddBuff(BuffType type, MapObject owner, int duration, Stats stats, bool refreshStats = true, bool updateOnly = false, params int[] values)
  2366. {
  2367. Buff b = base.AddBuff(type, owner, duration, stats, refreshStats, updateOnly, values);
  2368. var packet = new S.AddBuff
  2369. {
  2370. Buff = b.ToClientBuff(),
  2371. };
  2372. if (b.Info.Visible) Broadcast(packet);
  2373. if (refreshStats)
  2374. {
  2375. RefreshAll();
  2376. }
  2377. return b;
  2378. }
  2379. public override Packet GetInfo()
  2380. {
  2381. return new S.ObjectMonster
  2382. {
  2383. ObjectID = ObjectID,
  2384. Name = Name,
  2385. NameColour = NameColour,
  2386. Location = CurrentLocation,
  2387. Image = Info.Image,
  2388. Direction = Direction,
  2389. Effect = Info.Effect,
  2390. AI = Info.AI,
  2391. Light = Info.Light,
  2392. Dead = Dead,
  2393. Skeleton = Harvested,
  2394. Poison = CurrentPoison,
  2395. Hidden = Hidden,
  2396. ShockTime = (ShockTime > 0 ? ShockTime - Envir.Time : 0),
  2397. BindingShotCenter = BindingShotCenter,
  2398. Buffs = Buffs.Where(d => d.Info.Visible).Select(e => e.Type).ToList(),
  2399. MasterObjectId = Master?.ObjectID ?? 0,
  2400. Rarity= MonsterType
  2401. };
  2402. }
  2403. public override void ReceiveChat(string text, ChatType type)
  2404. {
  2405. throw new NotSupportedException();
  2406. }
  2407. public void RemoveObjects(MirDirection dir, int count)
  2408. {
  2409. switch (dir)
  2410. {
  2411. case MirDirection.Up:
  2412. //Bottom Block
  2413. for (int a = 0; a < count; a++)
  2414. {
  2415. int y = CurrentLocation.Y + Globals.DataRange - a;
  2416. if (y < 0 || y >= CurrentMap.Height) continue;
  2417. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  2418. {
  2419. int x = CurrentLocation.X + b;
  2420. if (x < 0 || x >= CurrentMap.Width) continue;
  2421. Cell cell = CurrentMap.GetCell(x, y);
  2422. if (!cell.Valid || cell.Objects == null) continue;
  2423. for (int i = 0; i < cell.Objects.Count; i++)
  2424. {
  2425. MapObject ob = cell.Objects[i];
  2426. if (ob.Race != ObjectType.Player) continue;
  2427. ob.Remove(this);
  2428. }
  2429. }
  2430. }
  2431. break;
  2432. case MirDirection.UpRight:
  2433. //Bottom Block
  2434. for (int a = 0; a < count; a++)
  2435. {
  2436. int y = CurrentLocation.Y + Globals.DataRange - a;
  2437. if (y < 0 || y >= CurrentMap.Height) continue;
  2438. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  2439. {
  2440. int x = CurrentLocation.X + b;
  2441. if (x < 0 || x >= CurrentMap.Width) continue;
  2442. Cell cell = CurrentMap.GetCell(x, y);
  2443. if (!cell.Valid || cell.Objects == null) continue;
  2444. for (int i = 0; i < cell.Objects.Count; i++)
  2445. {
  2446. MapObject ob = cell.Objects[i];
  2447. if (ob.Race != ObjectType.Player) continue;
  2448. ob.Remove(this);
  2449. }
  2450. }
  2451. }
  2452. //Left Block
  2453. for (int a = -Globals.DataRange; a <= Globals.DataRange - count; a++)
  2454. {
  2455. int y = CurrentLocation.Y + a;
  2456. if (y < 0 || y >= CurrentMap.Height) continue;
  2457. for (int b = 0; b < count; b++)
  2458. {
  2459. int x = CurrentLocation.X - Globals.DataRange + b;
  2460. if (x < 0 || x >= CurrentMap.Width) continue;
  2461. Cell cell = CurrentMap.GetCell(x, y);
  2462. if (!cell.Valid || cell.Objects == null) continue;
  2463. for (int i = 0; i < cell.Objects.Count; i++)
  2464. {
  2465. MapObject ob = cell.Objects[i];
  2466. if (ob.Race != ObjectType.Player) continue;
  2467. ob.Remove(this);
  2468. }
  2469. }
  2470. }
  2471. break;
  2472. case MirDirection.Right:
  2473. //Left Block
  2474. for (int a = -Globals.DataRange; a <= Globals.DataRange; a++)
  2475. {
  2476. int y = CurrentLocation.Y + a;
  2477. if (y < 0 || y >= CurrentMap.Height) continue;
  2478. for (int b = 0; b < count; b++)
  2479. {
  2480. int x = CurrentLocation.X - Globals.DataRange + b;
  2481. if (x < 0 || x >= CurrentMap.Width) continue;
  2482. Cell cell = CurrentMap.GetCell(x, y);
  2483. if (!cell.Valid || cell.Objects == null) continue;
  2484. for (int i = 0; i < cell.Objects.Count; i++)
  2485. {
  2486. MapObject ob = cell.Objects[i];
  2487. if (ob.Race != ObjectType.Player) continue;
  2488. ob.Remove(this);
  2489. }
  2490. }
  2491. }
  2492. break;
  2493. case MirDirection.DownRight:
  2494. //Top Block
  2495. for (int a = 0; a < count; a++)
  2496. {
  2497. int y = CurrentLocation.Y - Globals.DataRange + a;
  2498. if (y < 0 || y >= CurrentMap.Height) continue;
  2499. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  2500. {
  2501. int x = CurrentLocation.X + b;
  2502. if (x < 0 || x >= CurrentMap.Width) continue;
  2503. Cell cell = CurrentMap.GetCell(x, y);
  2504. if (!cell.Valid || cell.Objects == null) continue;
  2505. for (int i = 0; i < cell.Objects.Count; i++)
  2506. {
  2507. MapObject ob = cell.Objects[i];
  2508. if (ob.Race != ObjectType.Player) continue;
  2509. ob.Remove(this);
  2510. }
  2511. }
  2512. }
  2513. //Left Block
  2514. for (int a = -Globals.DataRange + count; a <= Globals.DataRange; a++)
  2515. {
  2516. int y = CurrentLocation.Y + a;
  2517. if (y < 0 || y >= CurrentMap.Height) continue;
  2518. for (int b = 0; b < count; b++)
  2519. {
  2520. int x = CurrentLocation.X - Globals.DataRange + b;
  2521. if (x < 0 || x >= CurrentMap.Width) continue;
  2522. Cell cell = CurrentMap.GetCell(x, y);
  2523. if (!cell.Valid || cell.Objects == null) continue;
  2524. for (int i = 0; i < cell.Objects.Count; i++)
  2525. {
  2526. MapObject ob = cell.Objects[i];
  2527. if (ob.Race != ObjectType.Player) continue;
  2528. ob.Remove(this);
  2529. }
  2530. }
  2531. }
  2532. break;
  2533. case MirDirection.Down:
  2534. for (int a = 0; a < count; a++)
  2535. {
  2536. int y = CurrentLocation.Y - Globals.DataRange + a;
  2537. if (y < 0 || y >= CurrentMap.Height) continue;
  2538. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  2539. {
  2540. int x = CurrentLocation.X + b;
  2541. if (x < 0 || x >= CurrentMap.Width) continue;
  2542. Cell cell = CurrentMap.GetCell(x, y);
  2543. if (!cell.Valid || cell.Objects == null) continue;
  2544. for (int i = 0; i < cell.Objects.Count; i++)
  2545. {
  2546. MapObject ob = cell.Objects[i];
  2547. if (ob.Race != ObjectType.Player) continue;
  2548. ob.Remove(this);
  2549. }
  2550. }
  2551. }
  2552. break;
  2553. case MirDirection.DownLeft:
  2554. //Top Block
  2555. for (int a = 0; a < count; a++)
  2556. {
  2557. int y = CurrentLocation.Y - Globals.DataRange + a;
  2558. if (y < 0 || y >= CurrentMap.Height) continue;
  2559. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  2560. {
  2561. int x = CurrentLocation.X + b;
  2562. if (x < 0 || x >= CurrentMap.Width) continue;
  2563. Cell cell = CurrentMap.GetCell(x, y);
  2564. if (!cell.Valid || cell.Objects == null) continue;
  2565. for (int i = 0; i < cell.Objects.Count; i++)
  2566. {
  2567. MapObject ob = cell.Objects[i];
  2568. if (ob.Race != ObjectType.Player) continue;
  2569. ob.Remove(this);
  2570. }
  2571. }
  2572. }
  2573. //Right Block
  2574. for (int a = -Globals.DataRange + count; a <= Globals.DataRange; a++)
  2575. {
  2576. int y = CurrentLocation.Y + a;
  2577. if (y < 0 || y >= CurrentMap.Height) continue;
  2578. for (int b = 0; b < count; b++)
  2579. {
  2580. int x = CurrentLocation.X + Globals.DataRange - b;
  2581. if (x < 0 || x >= CurrentMap.Width) continue;
  2582. Cell cell = CurrentMap.GetCell(x, y);
  2583. if (!cell.Valid || cell.Objects == null) continue;
  2584. for (int i = 0; i < cell.Objects.Count; i++)
  2585. {
  2586. MapObject ob = cell.Objects[i];
  2587. if (ob.Race != ObjectType.Player) continue;
  2588. ob.Remove(this);
  2589. }
  2590. }
  2591. }
  2592. break;
  2593. case MirDirection.Left:
  2594. for (int a = -Globals.DataRange; a <= Globals.DataRange; a++)
  2595. {
  2596. int y = CurrentLocation.Y + a;
  2597. if (y < 0 || y >= CurrentMap.Height) continue;
  2598. for (int b = 0; b < count; b++)
  2599. {
  2600. int x = CurrentLocation.X + Globals.DataRange - b;
  2601. if (x < 0 || x >= CurrentMap.Width) continue;
  2602. Cell cell = CurrentMap.GetCell(x, y);
  2603. if (!cell.Valid || cell.Objects == null) continue;
  2604. for (int i = 0; i < cell.Objects.Count; i++)
  2605. {
  2606. MapObject ob = cell.Objects[i];
  2607. if (ob.Race != ObjectType.Player) continue;
  2608. ob.Remove(this);
  2609. }
  2610. }
  2611. }
  2612. break;
  2613. case MirDirection.UpLeft:
  2614. //Bottom Block
  2615. for (int a = 0; a < count; a++)
  2616. {
  2617. int y = CurrentLocation.Y + Globals.DataRange - a;
  2618. if (y < 0 || y >= CurrentMap.Height) continue;
  2619. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  2620. {
  2621. int x = CurrentLocation.X + b;
  2622. if (x < 0 || x >= CurrentMap.Width) continue;
  2623. if (x < 0 || x >= CurrentMap.Width) continue;
  2624. Cell cell = CurrentMap.GetCell(x, y);
  2625. if (!cell.Valid || cell.Objects == null) continue;
  2626. for (int i = 0; i < cell.Objects.Count; i++)
  2627. {
  2628. MapObject ob = cell.Objects[i];
  2629. if (ob.Race != ObjectType.Player) continue;
  2630. ob.Remove(this);
  2631. }
  2632. }
  2633. }
  2634. //Right Block
  2635. for (int a = -Globals.DataRange; a <= Globals.DataRange - count; a++)
  2636. {
  2637. int y = CurrentLocation.Y + a;
  2638. if (y < 0 || y >= CurrentMap.Height) continue;
  2639. for (int b = 0; b < count; b++)
  2640. {
  2641. int x = CurrentLocation.X + Globals.DataRange - b;
  2642. if (x < 0 || x >= CurrentMap.Width) continue;
  2643. Cell cell = CurrentMap.GetCell(x, y);
  2644. if (!cell.Valid || cell.Objects == null) continue;
  2645. for (int i = 0; i < cell.Objects.Count; i++)
  2646. {
  2647. MapObject ob = cell.Objects[i];
  2648. if (ob.Race != ObjectType.Player) continue;
  2649. ob.Remove(this);
  2650. }
  2651. }
  2652. }
  2653. break;
  2654. }
  2655. }
  2656. public void AddObjects(MirDirection dir, int count)
  2657. {
  2658. switch (dir)
  2659. {
  2660. case MirDirection.Up:
  2661. for (int a = 0; a < count; a++)
  2662. {
  2663. int y = CurrentLocation.Y - Globals.DataRange + a;
  2664. if (y < 0 || y >= CurrentMap.Height) continue;
  2665. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  2666. {
  2667. int x = CurrentLocation.X + b;
  2668. if (x < 0 || x >= CurrentMap.Width) continue;
  2669. Cell cell = CurrentMap.GetCell(x, y);
  2670. if (!cell.Valid || cell.Objects == null) continue;
  2671. for (int i = 0; i < cell.Objects.Count; i++)
  2672. {
  2673. MapObject ob = cell.Objects[i];
  2674. if (ob.Race != ObjectType.Player) continue;
  2675. ob.Add(this);
  2676. }
  2677. }
  2678. }
  2679. break;
  2680. case MirDirection.UpRight:
  2681. //Top Block
  2682. for (int a = 0; a < count; a++)
  2683. {
  2684. int y = CurrentLocation.Y - Globals.DataRange + a;
  2685. if (y < 0 || y >= CurrentMap.Height) continue;
  2686. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  2687. {
  2688. int x = CurrentLocation.X + b;
  2689. if (x < 0 || x >= CurrentMap.Width) continue;
  2690. Cell cell = CurrentMap.GetCell(x, y);
  2691. if (!cell.Valid || cell.Objects == null) continue;
  2692. for (int i = 0; i < cell.Objects.Count; i++)
  2693. {
  2694. MapObject ob = cell.Objects[i];
  2695. if (ob.Race != ObjectType.Player) continue;
  2696. ob.Add(this);
  2697. }
  2698. }
  2699. }
  2700. //Right Block
  2701. for (int a = -Globals.DataRange + count; a <= Globals.DataRange; a++)
  2702. {
  2703. int y = CurrentLocation.Y + a;
  2704. if (y < 0 || y >= CurrentMap.Height) continue;
  2705. for (int b = 0; b < count; b++)
  2706. {
  2707. int x = CurrentLocation.X + Globals.DataRange - b;
  2708. if (x < 0 || x >= CurrentMap.Width) continue;
  2709. Cell cell = CurrentMap.GetCell(x, y);
  2710. if (!cell.Valid || cell.Objects == null) continue;
  2711. for (int i = 0; i < cell.Objects.Count; i++)
  2712. {
  2713. MapObject ob = cell.Objects[i];
  2714. if (ob.Race != ObjectType.Player) continue;
  2715. ob.Add(this);
  2716. }
  2717. }
  2718. }
  2719. break;
  2720. case MirDirection.Right:
  2721. for (int a = -Globals.DataRange; a <= Globals.DataRange; a++)
  2722. {
  2723. int y = CurrentLocation.Y + a;
  2724. if (y < 0 || y >= CurrentMap.Height) continue;
  2725. for (int b = 0; b < count; b++)
  2726. {
  2727. int x = CurrentLocation.X + Globals.DataRange - b;
  2728. if (x < 0 || x >= CurrentMap.Width) continue;
  2729. Cell cell = CurrentMap.GetCell(x, y);
  2730. if (!cell.Valid || cell.Objects == null) continue;
  2731. for (int i = 0; i < cell.Objects.Count; i++)
  2732. {
  2733. MapObject ob = cell.Objects[i];
  2734. if (ob.Race != ObjectType.Player) continue;
  2735. ob.Add(this);
  2736. }
  2737. }
  2738. }
  2739. break;
  2740. case MirDirection.DownRight:
  2741. //Bottom Block
  2742. for (int a = 0; a < count; a++)
  2743. {
  2744. int y = CurrentLocation.Y + Globals.DataRange - a;
  2745. if (y < 0 || y >= CurrentMap.Height) continue;
  2746. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  2747. {
  2748. int x = CurrentLocation.X + b;
  2749. if (x < 0 || x >= CurrentMap.Width) continue;
  2750. Cell cell = CurrentMap.GetCell(x, y);
  2751. if (!cell.Valid || cell.Objects == null) continue;
  2752. for (int i = 0; i < cell.Objects.Count; i++)
  2753. {
  2754. MapObject ob = cell.Objects[i];
  2755. if (ob.Race != ObjectType.Player) continue;
  2756. ob.Add(this);
  2757. }
  2758. }
  2759. }
  2760. //Right Block
  2761. for (int a = -Globals.DataRange; a <= Globals.DataRange - count; a++)
  2762. {
  2763. int y = CurrentLocation.Y + a;
  2764. if (y < 0 || y >= CurrentMap.Height) continue;
  2765. for (int b = 0; b < count; b++)
  2766. {
  2767. int x = CurrentLocation.X + Globals.DataRange - b;
  2768. if (x < 0 || x >= CurrentMap.Width) continue;
  2769. Cell cell = CurrentMap.GetCell(x, y);
  2770. if (!cell.Valid || cell.Objects == null) continue;
  2771. for (int i = 0; i < cell.Objects.Count; i++)
  2772. {
  2773. MapObject ob = cell.Objects[i];
  2774. if (ob.Race != ObjectType.Player) continue;
  2775. ob.Add(this);
  2776. }
  2777. }
  2778. }
  2779. break;
  2780. case MirDirection.Down:
  2781. //Bottom Block
  2782. for (int a = 0; a < count; a++)
  2783. {
  2784. int y = CurrentLocation.Y + Globals.DataRange - a;
  2785. if (y < 0 || y >= CurrentMap.Height) continue;
  2786. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  2787. {
  2788. int x = CurrentLocation.X + b;
  2789. if (x < 0 || x >= CurrentMap.Width) continue;
  2790. Cell cell = CurrentMap.GetCell(x, y);
  2791. if (!cell.Valid || cell.Objects == null) continue;
  2792. for (int i = 0; i < cell.Objects.Count; i++)
  2793. {
  2794. MapObject ob = cell.Objects[i];
  2795. if (ob.Race != ObjectType.Player) continue;
  2796. ob.Add(this);
  2797. }
  2798. }
  2799. }
  2800. break;
  2801. case MirDirection.DownLeft:
  2802. //Bottom Block
  2803. for (int a = 0; a < count; a++)
  2804. {
  2805. int y = CurrentLocation.Y + Globals.DataRange - a;
  2806. if (y < 0 || y >= CurrentMap.Height) continue;
  2807. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  2808. {
  2809. int x = CurrentLocation.X + b;
  2810. if (x < 0 || x >= CurrentMap.Width) continue;
  2811. Cell cell = CurrentMap.GetCell(x, y);
  2812. if (!cell.Valid || cell.Objects == null) continue;
  2813. for (int i = 0; i < cell.Objects.Count; i++)
  2814. {
  2815. MapObject ob = cell.Objects[i];
  2816. if (ob.Race != ObjectType.Player) continue;
  2817. ob.Add(this);
  2818. }
  2819. }
  2820. }
  2821. //Left Block
  2822. for (int a = -Globals.DataRange; a <= Globals.DataRange - count; a++)
  2823. {
  2824. int y = CurrentLocation.Y + a;
  2825. if (y < 0 || y >= CurrentMap.Height) continue;
  2826. for (int b = 0; b < count; b++)
  2827. {
  2828. int x = CurrentLocation.X - Globals.DataRange + b;
  2829. if (x < 0 || x >= CurrentMap.Width) continue;
  2830. Cell cell = CurrentMap.GetCell(x, y);
  2831. if (!cell.Valid || cell.Objects == null) continue;
  2832. for (int i = 0; i < cell.Objects.Count; i++)
  2833. {
  2834. MapObject ob = cell.Objects[i];
  2835. if (ob.Race != ObjectType.Player) continue;
  2836. ob.Add(this);
  2837. }
  2838. }
  2839. }
  2840. break;
  2841. case MirDirection.Left:
  2842. //Left Block
  2843. for (int a = -Globals.DataRange; a <= Globals.DataRange; a++)
  2844. {
  2845. int y = CurrentLocation.Y + a;
  2846. if (y < 0 || y >= CurrentMap.Height) continue;
  2847. for (int b = 0; b < count; b++)
  2848. {
  2849. int x = CurrentLocation.X - Globals.DataRange + b;
  2850. if (x < 0 || x >= CurrentMap.Width) continue;
  2851. Cell cell = CurrentMap.GetCell(x, y);
  2852. if (!cell.Valid || cell.Objects == null) continue;
  2853. for (int i = 0; i < cell.Objects.Count; i++)
  2854. {
  2855. MapObject ob = cell.Objects[i];
  2856. if (ob.Race != ObjectType.Player) continue;
  2857. ob.Add(this);
  2858. }
  2859. }
  2860. }
  2861. break;
  2862. case MirDirection.UpLeft:
  2863. //Top Block
  2864. for (int a = 0; a < count; a++)
  2865. {
  2866. int y = CurrentLocation.Y - Globals.DataRange + a;
  2867. if (y < 0 || y >= CurrentMap.Height) continue;
  2868. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  2869. {
  2870. int x = CurrentLocation.X + b;
  2871. if (x < 0 || x >= CurrentMap.Width) continue;
  2872. Cell cell = CurrentMap.GetCell(x, y);
  2873. if (!cell.Valid || cell.Objects == null) continue;
  2874. for (int i = 0; i < cell.Objects.Count; i++)
  2875. {
  2876. MapObject ob = cell.Objects[i];
  2877. if (ob.Race != ObjectType.Player) continue;
  2878. ob.Add(this);
  2879. }
  2880. }
  2881. }
  2882. //Left Block
  2883. for (int a = -Globals.DataRange + count; a <= Globals.DataRange; a++)
  2884. {
  2885. int y = CurrentLocation.Y + a;
  2886. if (y < 0 || y >= CurrentMap.Height) continue;
  2887. for (int b = 0; b < count; b++)
  2888. {
  2889. int x = CurrentLocation.X - Globals.DataRange + b;
  2890. if (x < 0 || x >= CurrentMap.Width) continue;
  2891. Cell cell = CurrentMap.GetCell(x, y);
  2892. if (!cell.Valid || cell.Objects == null) continue;
  2893. for (int i = 0; i < cell.Objects.Count; i++)
  2894. {
  2895. MapObject ob = cell.Objects[i];
  2896. if (ob.Race != ObjectType.Player) continue;
  2897. ob.Add(this);
  2898. }
  2899. }
  2900. }
  2901. break;
  2902. }
  2903. }
  2904. public override void Add(HumanObject player)
  2905. {
  2906. player.Enqueue(GetInfo());
  2907. SendHealth(player);
  2908. }
  2909. public override void SendHealth(HumanObject player)
  2910. {
  2911. if (!player.IsMember(Master) && !(player.IsMember(EXPOwner) && AutoRev) && Envir.Time > RevTime) return;
  2912. byte time = Math.Min(byte.MaxValue, (byte)Math.Max(5, (RevTime - Envir.Time) / 1000));
  2913. player.Enqueue(new S.ObjectHealth { ObjectID = ObjectID, Percent = PercentHealth, Expire = time });
  2914. }
  2915. public void PetExp(uint amount)
  2916. {
  2917. if (PetLevel >= MaxPetLevel) return;
  2918. if (Info.Name == Settings.SkeletonName || Info.Name == Settings.ShinsuName || Info.Name == Settings.AngelName)
  2919. amount *= 3;
  2920. PetExperience += amount;
  2921. if (PetExperience < (PetLevel + 1) * 20000) return;
  2922. PetExperience = (uint)(PetExperience - ((PetLevel + 1) * 20000));
  2923. PetLevel++;
  2924. RefreshAll();
  2925. OperateTime = 0;
  2926. BroadcastHealthChange();
  2927. }
  2928. public override void Despawn()
  2929. {
  2930. SlaveList.Clear();
  2931. base.Despawn();
  2932. }
  2933. // MONSTER AI ATTACKS \\\
  2934. protected virtual void PoisonTarget(MapObject target, int chanceToPoison, long poisonDuration, PoisonType poison, long poisonTickSpeed = 1000, bool noResist = false, bool ignoreDefence = true)
  2935. {
  2936. int value = GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]);
  2937. if (Envir.Random.Next(Settings.PoisonResistWeight) >= target.Stats[Stat.PoisonResist])
  2938. {
  2939. if (Envir.Random.Next(chanceToPoison) == 0)
  2940. {
  2941. target.ApplyPoison(new Poison { Owner = this, Duration = poisonDuration, PType = poison, Value = value, TickSpeed = poisonTickSpeed }, this, noResist, ignoreDefence);
  2942. }
  2943. }
  2944. }
  2945. protected virtual void TriangleAttack(int damage, int distance, int limitWidth = -1, int additionalDelay = 500, DefenceType defenceType = DefenceType.ACAgility, bool push = false)
  2946. {
  2947. List<Point> points = new List<Point>();
  2948. for (int i = 1; i <= distance; i++)
  2949. {
  2950. Point target = Functions.PointMove(CurrentLocation, Direction, i);
  2951. if (!CurrentMap.ValidPoint(target)) continue;
  2952. points.Add(target);
  2953. if (distance > 1)
  2954. {
  2955. Point left = target;
  2956. Point right = target;
  2957. var offset = i - 1;
  2958. for (int l = 1; l <= offset; l++)
  2959. {
  2960. if (limitWidth > -1 && l > limitWidth) break;
  2961. left = Functions.Left(left, Direction);
  2962. if (!CurrentMap.ValidPoint(left)) continue;
  2963. points.Add(left);
  2964. }
  2965. for (int r = 1; r <= offset; r++)
  2966. {
  2967. if (limitWidth > -1 && r > limitWidth) break;
  2968. right = Functions.Right(right, Direction);
  2969. if (!CurrentMap.ValidPoint(right)) continue;
  2970. points.Add(right);
  2971. }
  2972. }
  2973. }
  2974. foreach (var point in points)
  2975. {
  2976. Cell cell = CurrentMap.GetCell(point);
  2977. if (cell.Objects == null) continue;
  2978. for (int o = 0; o < cell.Objects.Count; o++)
  2979. {
  2980. MapObject ob = cell.Objects[o];
  2981. if (ob.Race == ObjectType.Monster || ob.Race == ObjectType.Player || ob.Race == ObjectType.Hero)
  2982. {
  2983. if (!ob.IsAttackTarget(this)) continue;
  2984. if (push)
  2985. {
  2986. var dir = Functions.DirectionFromPoint(CurrentLocation, ob.CurrentLocation);
  2987. ob.Pushed(this, dir, distance - 1);
  2988. }
  2989. int delay = Functions.MaxDistance(CurrentLocation, ob.CurrentLocation) * 50 + additionalDelay; //50 MS per Step
  2990. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + delay, ob, damage, defenceType);
  2991. ActionList.Add(action);
  2992. }
  2993. else continue;
  2994. break;
  2995. }
  2996. }
  2997. }
  2998. protected virtual void LineAttack(int damage, int distance, int additionalDelay = 500, DefenceType defenceType = DefenceType.ACAgility, bool push = false)
  2999. {
  3000. for (int i = 1; i <= distance; i++)
  3001. {
  3002. Point target = Functions.PointMove(CurrentLocation, Direction, i);
  3003. if (!CurrentMap.ValidPoint(target)) continue;
  3004. Cell cell = CurrentMap.GetCell(target);
  3005. if (cell.Objects == null) continue;
  3006. for (int o = 0; o < cell.Objects.Count; o++)
  3007. {
  3008. MapObject ob = cell.Objects[o];
  3009. if (ob.Race == ObjectType.Monster || ob.Race == ObjectType.Player || ob.Race == ObjectType.Hero)
  3010. {
  3011. if (!ob.IsAttackTarget(this)) continue;
  3012. if (push)
  3013. {
  3014. ob.Pushed(this, Direction, distance - 1);
  3015. }
  3016. int delay = Functions.MaxDistance(CurrentLocation, ob.CurrentLocation) * 50 + additionalDelay; //50 MS per Step
  3017. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + delay, ob, damage, defenceType);
  3018. ActionList.Add(action);
  3019. }
  3020. else continue;
  3021. break;
  3022. }
  3023. }
  3024. }
  3025. protected virtual void WideLineAttack(int damage, int distance, int additionalDelay = 500, DefenceType defenceType = DefenceType.ACAgility, bool push = false, int width = 3)
  3026. {
  3027. if (width <= 2)
  3028. {
  3029. width = 3;
  3030. }
  3031. var even = width % 2 == 0;
  3032. if (even)
  3033. {
  3034. width--;
  3035. }
  3036. var startPoints = new List<Point>
  3037. {
  3038. CurrentLocation
  3039. };
  3040. var half = (width - 1) / 2;
  3041. var leftLoc = CurrentLocation;
  3042. var rightLoc = CurrentLocation;
  3043. for (int j = 0; j < half; j++)
  3044. {
  3045. leftLoc = Functions.Left(leftLoc, Direction);
  3046. rightLoc = Functions.Right(rightLoc, Direction);
  3047. startPoints.Add(leftLoc);
  3048. startPoints.Add(rightLoc);
  3049. }
  3050. for (int j = 0; j < startPoints.Count; j++)
  3051. {
  3052. var point = startPoints[j];
  3053. for (int i = 1; i <= distance; i++)
  3054. {
  3055. Point target = Functions.PointMove(point, Direction, i);
  3056. if (!CurrentMap.ValidPoint(target)) continue;
  3057. Cell cell = CurrentMap.GetCell(target);
  3058. if (cell.Objects == null) continue;
  3059. for (int o = 0; o < cell.Objects.Count; o++)
  3060. {
  3061. MapObject ob = cell.Objects[o];
  3062. if (ob.Race == ObjectType.Monster || ob.Race == ObjectType.Player || ob.Race == ObjectType.Hero)
  3063. {
  3064. if (!ob.IsAttackTarget(this)) continue;
  3065. if (push)
  3066. {
  3067. ob.Pushed(this, Direction, distance - 1);
  3068. }
  3069. int delay = Functions.MaxDistance(CurrentLocation, ob.CurrentLocation) * 50 + additionalDelay; //50 MS per Step
  3070. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + delay, ob, damage, defenceType);
  3071. ActionList.Add(action);
  3072. }
  3073. else continue;
  3074. break;
  3075. }
  3076. }
  3077. }
  3078. }
  3079. protected virtual void HalfmoonAttack(int damage, int delay = 500, DefenceType defenceType = DefenceType.ACAgility)
  3080. {
  3081. MirDirection dir = Functions.PreviousDir(Direction);
  3082. for (int i = 0; i < 4; i++)
  3083. {
  3084. Point target = Functions.PointMove(CurrentLocation, dir, 1);
  3085. dir = Functions.NextDir(dir);
  3086. if (!CurrentMap.ValidPoint(target)) continue;
  3087. Cell cell = CurrentMap.GetCell(target);
  3088. if (cell.Objects == null) continue;
  3089. for (int o = 0; o < cell.Objects.Count; o++)
  3090. {
  3091. MapObject ob = cell.Objects[o];
  3092. if (ob.Race != ObjectType.Player && ob.Race != ObjectType.Monster && ob.Race != ObjectType.Hero) continue;
  3093. if (!ob.IsAttackTarget(this)) continue;
  3094. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + delay, ob, damage, defenceType);
  3095. ActionList.Add(action);
  3096. break;
  3097. }
  3098. }
  3099. }
  3100. // Sanjian
  3101. protected virtual void ThreeQuarterMoonAttack(int damage, int delay = 500, DefenceType defenceType = DefenceType.ACAgility)
  3102. {
  3103. MirDirection dir = Functions.PreviousDir(Direction);
  3104. for (int i = 0; i < 6; i++)
  3105. {
  3106. Point target = Functions.PointMove(CurrentLocation, dir, 1);
  3107. dir = Functions.NextDir(dir);
  3108. if (!CurrentMap.ValidPoint(target)) continue;
  3109. Cell cell = CurrentMap.GetCell(target);
  3110. if (cell.Objects == null) continue;
  3111. for (int o = 0; o < cell.Objects.Count; o++)
  3112. {
  3113. MapObject ob = cell.Objects[o];
  3114. if (ob.Race != ObjectType.Player && ob.Race != ObjectType.Monster && ob.Race != ObjectType.Hero) continue;
  3115. if (!ob.IsAttackTarget(this)) continue;
  3116. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + delay, ob, damage, defenceType);
  3117. ActionList.Add(action);
  3118. break;
  3119. }
  3120. }
  3121. }
  3122. protected virtual void JumpBack(int distance)
  3123. {
  3124. MirDirection jumpDir = Functions.ReverseDirection(Direction);
  3125. Point location = new Point();
  3126. for (int i = 0; i < distance; i++)
  3127. {
  3128. location = Functions.PointMove(CurrentLocation, jumpDir, 1);
  3129. if (!CurrentMap.ValidPoint(location)) return;
  3130. }
  3131. for (int i = 0; i < distance; i++)
  3132. {
  3133. location = Functions.PointMove(CurrentLocation, jumpDir, 1);
  3134. CurrentMap.GetCell(CurrentLocation).Remove(this);
  3135. RemoveObjects(jumpDir, 1);
  3136. CurrentLocation = location;
  3137. CurrentMap.GetCell(CurrentLocation).Add(this);
  3138. AddObjects(jumpDir, 1);
  3139. }
  3140. Broadcast(new S.ObjectBackStep { ObjectID = ObjectID, Direction = Direction, Location = location, Distance = distance });
  3141. }
  3142. protected virtual void FullmoonAttack(int damage, int delay = 500, DefenceType defenceType = DefenceType.ACAgility, int pushDistance = -1, int distance = 1)
  3143. {
  3144. MirDirection dir = Direction;
  3145. bool pushed = false;
  3146. for (int j = 1; j <= distance; j++)
  3147. {
  3148. for (int i = 0; i < 8; i++)
  3149. {
  3150. dir = Functions.NextDir(dir);
  3151. Point point = Functions.PointMove(CurrentLocation, dir, j);
  3152. if (!CurrentMap.ValidPoint(point)) continue;
  3153. Cell cell = CurrentMap.GetCell(point);
  3154. if (cell.Objects == null) continue;
  3155. for (int o = 0; o < cell.Objects.Count; o++)
  3156. {
  3157. MapObject ob = cell.Objects[o];
  3158. if (ob.Race != ObjectType.Player && ob.Race != ObjectType.Monster && ob.Race != ObjectType.Hero) continue;
  3159. if (!ob.IsAttackTarget(this)) continue;
  3160. if (pushDistance > 0 && !pushed)
  3161. {
  3162. ob.Pushed(this, Direction, pushDistance);
  3163. pushed = true;
  3164. }
  3165. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + delay, ob, damage, defenceType);
  3166. ActionList.Add(action);
  3167. break;
  3168. }
  3169. }
  3170. }
  3171. }
  3172. protected virtual void ProjectileAttack(int damage, DefenceType type = DefenceType.ACAgility, int additionalDelay = 500)
  3173. {
  3174. int delay = Functions.MaxDistance(CurrentLocation, Target.CurrentLocation) * 50 + additionalDelay;
  3175. DelayedAction action = new DelayedAction(DelayedType.RangeDamage, Envir.Time + delay, Target, damage, type);
  3176. ActionList.Add(action);
  3177. }
  3178. protected virtual void SinglePushAttack(int damage, DefenceType type = DefenceType.AC, int delay = 500, int pushDistance = 3)
  3179. {
  3180. //Repulsion - (utilises DelayedAction so player is hit at end of push)
  3181. //need to put Damage Stats (DC/MC/SC) on mob for it to push
  3182. int levelGap = 5;
  3183. int mobLevel = this.Level;
  3184. int targetLevel = Target.Level;
  3185. if ((targetLevel <= mobLevel + levelGap))
  3186. {
  3187. if (Target.Pushed(this, Functions.DirectionFromPoint(CurrentLocation, Target.CurrentLocation), pushDistance) > 0)
  3188. {
  3189. AttackTime = Envir.Time + AttackSpeed + 300;
  3190. if (damage == 0) return;
  3191. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + delay, Target, damage, type);
  3192. ActionList.Add(action);
  3193. }
  3194. else
  3195. {
  3196. if (damage == 0) return;
  3197. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + delay, Target, damage, type);
  3198. ActionList.Add(action);
  3199. }
  3200. }
  3201. }
  3202. }
  3203. }