| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592 |
- using System.Drawing;
- using Server.MirDatabase;
- using Server.MirObjects;
- using Shared;
- using S = ServerPackets;
- namespace Server.MirEnvir
- {
- public class Map
- {
- private static Envir Envir
- {
- get { return Envir.Main; }
- }
- protected static MessageQueue MessageQueue
- {
- get { return MessageQueue.Instance; }
- }
- public MapInfo Info;
- public int Thread = 0;
- public int Width, Height;
- public Cell[,] Cells;
- public List<Point> WalkableCells;
- public Door[,] DoorIndex;
- public List<Door> Doors = new List<Door>();
- public MineSpot[,] Mine;
- public long LightningTime, FireTime;
- public int MonsterCount;
- public List<NPCObject> NPCs = new List<NPCObject>();
- public List<SpellObject> Spells = new List<SpellObject>();
- public List<PlayerObject> Players = new List<PlayerObject>();
- public List<MapRespawn> Respawns = new List<MapRespawn>();
- public List<DelayedAction> ActionList = new List<DelayedAction>();
- public List<HeroObject> Heroes = new List<HeroObject>();
- public List<ConquestObject> Conquest = new List<ConquestObject>();
- public ConquestObject tempConquest;
- public Map(MapInfo info)
- {
- Info = info;
- Thread = Envir.Random.Next(Settings.ThreadLimit);
- }
- public Door AddDoor(byte DoorIndex, Point location)
- {
- DoorIndex = (byte)(DoorIndex & 0x7F);
- for (int i = 0; i < Doors.Count; i++)
- if (Doors[i].index == DoorIndex)
- return Doors[i];
- Door DoorInfo = new Door() { index = DoorIndex, Location = location };
- Doors.Add(DoorInfo);
- return DoorInfo;
- }
-
- public bool OpenDoor(byte DoorIndex)
- {
- for (int i = 0; i < Doors.Count; i++)
- if (Doors[i].index == DoorIndex)
- {
- Doors[i].DoorState = DoorState.Open;
- Doors[i].LastTick = Envir.Time;
- return true;
- }
- return false;
- }
- private byte FindType(byte[] input)
- {
- //c# custom map format
- if ((input[2] == 0x43) && (input[3] == 0x23))
- {
- return 100;
- }
- //wemade mir3 maps have no title they just start with blank bytes
- if (input[0] == 0)
- return 5;
- //shanda mir3 maps start with title: (C) SNDA, MIR3.
- if ((input[0] == 0x0F) && (input[5] == 0x53) && (input[14] == 0x33))
- return 6;
- //wemades antihack map (laby maps) title start with: Mir2 AntiHack
- if ((input[0] == 0x15) && (input[4] == 0x32) && (input[6] == 0x41) && (input[19] == 0x31))
- return 4;
- //wemades 2010 map format i guess title starts with: Map 2010 Ver 1.0
- if ((input[0] == 0x10) && (input[2] == 0x61) && (input[7] == 0x31) && (input[14] == 0x31))
- return 1;
- //shanda's 2012 format and one of shandas(wemades) older formats share same header info, only difference is the filesize
- if ((input[4] == 0x0F) || (input[4] == 0x03) && (input[18] == 0x0D) && (input[19] == 0x0A))
- {
- int W = input[0] + (input[1] << 8);
- int H = input[2] + (input[3] << 8);
- if (input.Length > (52 + (W * H * 14)))
- return 3;
- else
- return 2;
- }
- //3/4 heroes map format (myth/lifcos i guess)
- if ((input[0] == 0x0D) && (input[1] == 0x4C) && (input[7] == 0x20) && (input[11] == 0x6D))
- return 7;
- return 0;
- }
- private void LoadMapCellsv0(byte[] fileBytes)
- {
- int offSet = 0;
- Width = BitConverter.ToInt16(fileBytes, offSet);
- offSet += 2;
- Height = BitConverter.ToInt16(fileBytes, offSet);
- Cells = new Cell[Width, Height];
- DoorIndex = new Door[Width, Height];
- offSet = 52;
- for (int x = 0; x < Width; x++)
- for (int y = 0; y < Height; y++)
- {//total 12
- if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
- Cells[x, y] = Cell.HighWall; //Can Fire Over.
- offSet += 2;
- if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
- Cells[x, y] = Cell.LowWall; //Can't Fire Over.
- offSet += 2;
- if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
- Cells[x, y] = Cell.HighWall; //No Floor Tile.
- if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
- offSet += 4;
- if (fileBytes[offSet] > 0)
- DoorIndex[x, y] = AddDoor(fileBytes[offSet], new Point(x, y));
- offSet += 3;
- byte light = fileBytes[offSet++];
- if (light >= 100 && light <= 119)
- Cells[x, y].FishingAttribute = (sbyte)(light - 100);
- }
- }
-
- private void LoadMapCellsv1(byte[] fileBytes)
- {
- int offSet = 21;
- int w = BitConverter.ToInt16(fileBytes, offSet);
- offSet += 2;
- int xor = BitConverter.ToInt16(fileBytes, offSet);
- offSet += 2;
- int h = BitConverter.ToInt16(fileBytes, offSet);
- Width = w ^ xor;
- Height = h ^ xor;
- Cells = new Cell[Width, Height];
- DoorIndex = new Door[Width, Height];
- offSet = 54;
- for (int x = 0; x < Width; x++)
- for (int y = 0; y < Height; y++)
- {
- if (((BitConverter.ToInt32(fileBytes, offSet) ^ 0xAA38AA38) & 0x20000000) != 0)
- Cells[x, y] = Cell.HighWall; //Can Fire Over.
- offSet += 6;
- if (((BitConverter.ToInt16(fileBytes, offSet) ^ xor) & 0x8000) != 0)
- Cells[x, y] = Cell.LowWall; //No Floor Tile.
- if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
- offSet += 2;
- if (fileBytes[offSet] > 0)
- DoorIndex[x, y] = AddDoor(fileBytes[offSet], new Point(x, y));
- offSet += 5;
- byte light = fileBytes[offSet++];
- if (light >= 100 && light <= 119)
- Cells[x, y].FishingAttribute = (sbyte)(light - 100);
- offSet += 1;
- }
- }
- private void LoadMapCellsv2(byte[] fileBytes)
- {
- int offSet = 0;
- Width = BitConverter.ToInt16(fileBytes, offSet);
- offSet += 2;
- Height = BitConverter.ToInt16(fileBytes, offSet);
- Cells = new Cell[Width, Height];
- DoorIndex = new Door[Width, Height];
- offSet = 52;
- for (int x = 0; x < Width; x++)
- for (int y = 0; y < Height; y++)
- {//total 14
- if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
- Cells[x, y] = Cell.HighWall; //Can Fire Over.
- offSet += 2;
- if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
- Cells[x, y] = Cell.LowWall; //Can't Fire Over.
- offSet += 2;
- if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
- Cells[x, y] = Cell.HighWall; //No Floor Tile.
- if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
- offSet += 2;
- if (fileBytes[offSet] > 0)
- DoorIndex[x, y] = AddDoor(fileBytes[offSet], new Point(x, y));
- offSet += 5;
- byte light = fileBytes[offSet++];
- if (light >= 100 && light <= 119)
- Cells[x, y].FishingAttribute = (sbyte)(light - 100);
- offSet += 2;
- }
- }
- private void LoadMapCellsv3(byte[] fileBytes)
- {
- int offSet = 0;
- Width = BitConverter.ToInt16(fileBytes, offSet);
- offSet += 2;
- Height = BitConverter.ToInt16(fileBytes, offSet);
- Cells = new Cell[Width, Height];
- DoorIndex = new Door[Width, Height];
- offSet = 52;
- for (int x = 0; x < Width; x++)
- for (int y = 0; y < Height; y++)
- {//total 36
- if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
- Cells[x, y] = Cell.HighWall; //Can Fire Over.
- offSet += 2;
- if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
- Cells[x, y] = Cell.LowWall; //Can't Fire Over.
- offSet += 2;
- if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
- Cells[x, y] = Cell.HighWall; //No Floor Tile.
- if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
- offSet += 2;
- if (fileBytes[offSet] > 0)
- DoorIndex[x, y] = AddDoor(fileBytes[offSet], new Point(x, y));
- offSet += 12;
- byte light = fileBytes[offSet++];
- if (light >= 100 && light <= 119)
- Cells[x, y].FishingAttribute = (sbyte)(light - 100);
- offSet += 17;
- }
- }
- private void LoadMapCellsv4(byte[] fileBytes)
- {
- int offSet = 31;
- int w = BitConverter.ToInt16(fileBytes, offSet);
- offSet += 2;
- int xor = BitConverter.ToInt16(fileBytes, offSet);
- offSet += 2;
- int h = BitConverter.ToInt16(fileBytes, offSet);
- Width = w ^ xor;
- Height = h ^ xor;
- Cells = new Cell[Width, Height];
- DoorIndex = new Door[Width, Height];
- offSet = 64;
- for (int x = 0; x < Width; x++)
- for (int y = 0; y < Height; y++)
- {//total 12
- if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
- Cells[x, y] = Cell.HighWall; //Can Fire Over.
- offSet += 2;
- if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
- Cells[x, y] = Cell.LowWall; //Can't Fire Over.
- if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
- offSet += 4;
- if (fileBytes[offSet] > 0)
- DoorIndex[x, y] = AddDoor(fileBytes[offSet], new Point(x, y));
- offSet += 6;
- }
- }
- private void LoadMapCellsv5(byte[] fileBytes)
- {
- int offSet = 22;
- Width = BitConverter.ToInt16(fileBytes, offSet);
- offSet += 2;
- Height = BitConverter.ToInt16(fileBytes, offSet);
- Cells = new Cell[Width, Height];
- DoorIndex = new Door[Width, Height];
- offSet = 28 + (3 * ((Width / 2) + (Width % 2)) * (Height / 2));
- for (int x = 0; x < Width; x++)
- for (int y = 0; y < Height; y++)
- {//total 14
- if ((fileBytes[offSet] & 0x01) != 1)
- Cells[x, y] = Cell.HighWall;
- else if ((fileBytes[offSet] & 0x02) != 2)
- Cells[x, y] = Cell.LowWall;
- else
- Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
- offSet += 13;
- byte light = fileBytes[offSet++];
- if (light >= 100 && light <= 119)
- Cells[x, y].FishingAttribute = (sbyte)(light - 100);
- }
- }
- private void LoadMapCellsv6(byte[] fileBytes)
- {
- int offSet = 16;
- Width = BitConverter.ToInt16(fileBytes, offSet);
- offSet += 2;
- Height = BitConverter.ToInt16(fileBytes, offSet);
- Cells = new Cell[Width, Height];
- DoorIndex = new Door[Width, Height];
- offSet = 40;
- for (int x = 0; x < Width; x++)
- for (int y = 0; y < Height; y++)
- {//total 20
- if ((fileBytes[offSet] & 0x01) != 1)
- Cells[x, y] = Cell.HighWall;
- else if ((fileBytes[offSet] & 0x02) != 2)
- Cells[x, y] = Cell.LowWall;
- else
- Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
- offSet += 20;
- }
- }
- private void LoadMapCellsv7(byte[] fileBytes)
- {
- int offSet = 21;
- Width = BitConverter.ToInt16(fileBytes, offSet);
- offSet += 4;
- Height = BitConverter.ToInt16(fileBytes, offSet);
- Cells = new Cell[Width, Height];
- DoorIndex = new Door[Width, Height];
- offSet = 54;
- for (int x = 0; x < Width; x++)
- for (int y = 0; y < Height; y++)
- {//total 15
- if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
- Cells[x, y] = Cell.HighWall; //Can Fire Over.
- offSet += 6;
- if ((BitConverter.ToInt16(fileBytes, offSet) & 0x8000) != 0)
- Cells[x, y] = Cell.LowWall; //Can't Fire Over.
- //offSet += 2;
- if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
- offSet += 2;
- if (fileBytes[offSet] > 0)
- DoorIndex[x, y] = AddDoor(fileBytes[offSet], new Point(x, y));
- offSet += 4;
- byte light = fileBytes[offSet++];
- if (light >= 100 && light <= 119)
- Cells[x, y].FishingAttribute = (sbyte)(light - 100);
- offSet += 2;
- }
- }
- private void LoadMapCellsV100(byte[] Bytes)
- {
- int offset = 4;
- if ((Bytes[0] != 1) || (Bytes[1] != 0)) return;//only support version 1 atm
- Width = BitConverter.ToInt16(Bytes, offset);
- offset += 2;
- Height = BitConverter.ToInt16(Bytes, offset);
- Cells = new Cell[Width, Height];
- DoorIndex = new Door[Width, Height];
- offset = 8;
- for (int x = 0; x < Width; x++)
- for (int y = 0; y < Height; y++)
- {
- offset += 2;
- if ((BitConverter.ToInt32(Bytes, offset) & 0x20000000) != 0)
- Cells[x, y] = Cell.HighWall; //Can Fire Over.
- offset += 10;
- if ((BitConverter.ToInt16(Bytes, offset) & 0x8000) != 0)
- Cells[x, y] = Cell.LowWall; //Can't Fire Over.
- if (Cells[x, y] == null) Cells[x, y] = new Cell { Attribute = CellAttribute.Walk };
- offset += 2;
- if (Bytes[offset] > 0)
- DoorIndex[x, y] = AddDoor(Bytes[offset], new Point(x, y));
- offset += 11;
- byte light = Bytes[offset++];
- if (light >= 100 && light <= 119)
- Cells[x, y].FishingAttribute = (sbyte)(light - 100);
- }
-
- }
- public bool Load()
- {
- try
- {
- string fileName = Path.Combine(Settings.MapPath, Info.FileName + ".map");
- if (File.Exists(fileName))
- {
- byte[] fileBytes = File.ReadAllBytes(fileName);
- switch(FindType(fileBytes))
- {
- case 0:
- LoadMapCellsv0(fileBytes);
- break;
- case 1:
- LoadMapCellsv1(fileBytes);
- break;
- case 2:
- LoadMapCellsv2(fileBytes);
- break;
- case 3:
- LoadMapCellsv3(fileBytes);
- break;
- case 4:
- LoadMapCellsv4(fileBytes);
- break;
- case 5:
- LoadMapCellsv5(fileBytes);
- break;
- case 6:
- LoadMapCellsv6(fileBytes);
- break;
- case 7:
- LoadMapCellsv7(fileBytes);
- break;
- case 100:
- LoadMapCellsV100(fileBytes);
- break;
- }
- GetWalkableCells();
-
- for (int i = 0; i < Info.Respawns.Count; i++)
- {
- MapRespawn info = new MapRespawn(Info.Respawns[i]);
- if (info.Monster == null) continue;
- info.Map = this;
- info.WalkableCells = WalkableCells.Where(x =>
- x.X <= info.Info.Location.X + info.Info.Spread &&
- x.X >= info.Info.Location.X - info.Info.Spread &&
- x.Y <= info.Info.Location.Y + info.Info.Spread &&
- x.Y >= info.Info.Location.Y - info.Info.Spread).ToList();
- Respawns.Add(info);
- if ((info.Info.SaveRespawnTime) && (info.Info.RespawnTicks != 0))
- Envir.SavedSpawns.Add(info);
- }
- for (int i = 0; i < Info.NPCs.Count; i++)
- {
- NPCInfo info = Info.NPCs[i];
- if (!ValidPoint(info.Location)) continue;
- AddObject(new NPCObject(info) { CurrentMap = this });
- }
- for (int i = 0; i < Info.SafeZones.Count; i++)
- CreateSafeZone(Info.SafeZones[i]);
- CreateMine();
- return true;
- }
- }
- catch (Exception ex)
- {
- MessageQueue.Enqueue(ex);
- }
- MessageQueue.Enqueue(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.FailedToLoadMap) + Info.Title);
- MessageQueue.Enqueue(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.Filename) + Info.FileName);
- return false;
- }
- public void GetWalkableCells()
- {
- if (WalkableCells == null)
- {
- WalkableCells = new List<Point>();
- for (int x = 0; x < Width; x++)
- for (int y = 0; y < Height; y++)
- if (Cells[x, y].Attribute == CellAttribute.Walk)
- WalkableCells.Add(new Point(x, y));
- }
- }
- private void CreateSafeZone(SafeZoneInfo info)
- {
- if (Settings.SafeZoneBorder)
- {
- for (int y = info.Location.Y - info.Size; y <= info.Location.Y + info.Size; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = info.Location.X - info.Size; x <= info.Location.X + info.Size; x += Math.Abs(y - info.Location.Y) == info.Size ? 1 : info.Size * 2)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- if (!Cells[x, y].Valid) continue;
- SpellObject spell = new SpellObject
- {
- ExpireTime = long.MaxValue,
- Spell = Spell.TrapHexagon,
- TickSpeed = int.MaxValue,
- CurrentLocation = new Point(x, y),
- CurrentMap = this,
- Decoration = true
- };
- Cells[x, y].Add(spell);
- spell.Spawned();
- }
- }
- }
- if (Settings.SafeZoneHealing)
- {
- for (int y = info.Location.Y - info.Size; y <= info.Location.Y + info.Size; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = info.Location.X - info.Size; x <= info.Location.X + info.Size; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- if (!Cells[x, y].Valid) continue;
- SpellObject spell = new SpellObject
- {
- ExpireTime = long.MaxValue,
- Value = 25,
- TickSpeed = 2000,
- Spell = Spell.Healing,
- CurrentLocation = new Point(x, y),
- CurrentMap = this
- };
- Cells[x, y].Add(spell);
- spell.Spawned();
- }
- }
- }
- }
- private void CreateMine()
- {
- if ((Info.MineIndex == 0) && (Info.MineZones.Count == 0)) return;
- Mine = new MineSpot[Width, Height];
- for (int i = 0; i < Width; i++)
- for (int j = 0; j < Height; j++)
- Mine[i, j] = new MineSpot();
- if ((Info.MineIndex != 0) && (Settings.MineSetList.Count > Info.MineIndex - 1))
- {
- Settings.MineSetList[Info.MineIndex - 1].SetDrops(Envir.ItemInfoList);
- for (int i = 0; i < Width; i++)
- for (int j = 0; j < Height; j++)
- Mine[i,j].Mine = Settings.MineSetList[Info.MineIndex - 1];
- }
- if (Info.MineZones.Count > 0)
- {
- for (int i = 0; i < Info.MineZones.Count; i++)
- {
- MineZone Zone = Info.MineZones[i];
- if (Zone.Mine != 0)
- Settings.MineSetList[Zone.Mine - 1].SetDrops(Envir.ItemInfoList);
- if (Settings.MineSetList.Count < Zone.Mine) continue;
- for (int x = Zone.Location.X - Zone.Size; x < Zone.Location.X + Zone.Size; x++)
- for (int y = Zone.Location.Y - Zone.Size; y < Zone.Location.Y + Zone.Size; y++)
- {
- if ((x < 0) || (x >= Width) || (y < 0) || (y >= Height)) continue;
- if (Zone.Mine == 0)
- Mine[x, y].Mine = null;
- else
- Mine[x, y].Mine = Settings.MineSetList[Zone.Mine - 1];
- }
- }
- }
- }
- public Cell GetCell(Point location)
- {
- return Cells[location.X, location.Y];
- }
- public Cell GetCell(int x, int y)
- {
- return Cells[x, y];
- }
- public bool ValidPoint(Point location)
- {
- return location.X >= 0 && location.X < Width && location.Y >= 0 && location.Y < Height && GetCell(location).Valid;
- }
- public bool ValidPoint(int x, int y)
- {
- return x >= 0 && x < Width && y >= 0 && y < Height && GetCell(x, y).Valid;
- }
- public bool CheckDoorOpen(Point location)
- {
- if (DoorIndex[location.X, location.Y] == null) return true;
- if (DoorIndex[location.X, location.Y].DoorState != DoorState.Open) return false;
- return true;
- }
- public void Process()
- {
- ProcessRespawns();
- for (int i = 0; i < Doors.Count; i++)
- {
- if ((Doors[i].DoorState == DoorState.Open) && (Doors[i].LastTick + 5000 < Envir.Time))
- {
- Doors[i].DoorState = 0;
- Broadcast(new S.Opendoor() { DoorIndex = Doors[i].index, Close = true }, Doors[i].Location);
- }
- }
- if ((Info.Lightning) && Envir.Time > LightningTime)
- {
- LightningTime = Envir.Time + Envir.Random.Next(3000, 15000);
- for (int i = Players.Count - 1; i >= 0; i--)
- {
- PlayerObject player = Players[i];
- Point location;
- if (Envir.Random.Next(4) == 0)
- {
- location = player.CurrentLocation;
- }
- else
- location = new Point(player.CurrentLocation.X - 10 + Envir.Random.Next(20), player.CurrentLocation.Y - 10 + Envir.Random.Next(20));
- if (!ValidPoint(location)) continue;
- SpellObject lightning = new SpellObject
- {
- Spell = Spell.MapLightning,
- Value = Envir.Random.Next(Info.LightningDamage),
- ExpireTime = Envir.Time + (1000),
- TickSpeed = 500,
- Caster = null,
- CurrentLocation = location,
- CurrentMap = this,
- Direction = MirDirection.Up
- };
- AddObject(lightning);
- lightning.Spawned();
- }
- }
- if ((Info.Fire) && Envir.Time > FireTime)
- {
- FireTime = Envir.Time + Envir.Random.Next(3000, 15000);
- for (int i = Players.Count - 1; i >= 0; i--)
- {
- PlayerObject player = Players[i];
- Point location;
- if (Envir.Random.Next(4) == 0)
- {
- location = player.CurrentLocation;
- }
- else
- location = new Point(player.CurrentLocation.X - 10 + Envir.Random.Next(20), player.CurrentLocation.Y - 10 + Envir.Random.Next(20));
- if (!ValidPoint(location)) continue;
- SpellObject lightning = new SpellObject
- {
- Spell = Spell.MapLava,
- Value = Envir.Random.Next(Info.FireDamage),
- ExpireTime = Envir.Time + (1000),
- TickSpeed = 500,
- Caster = null,
- CurrentLocation = location,
- CurrentMap = this,
- Direction = MirDirection.Up
- };
- AddObject(lightning);
- lightning.Spawned();
- }
- }
- for (int i = 0; i < ActionList.Count; i++)
- {
- if (Envir.Time < ActionList[i].Time) continue;
- Process(ActionList[i]);
- ActionList.RemoveAt(i);
- }
- }
- private void ProcessRespawns()
- {
- bool Success = true;
- for (int i = 0; i < Respawns.Count; i++)
- {
- MapRespawn respawn = Respawns[i];
- if ((respawn.Info.RespawnTicks != 0) && (Envir.RespawnTick.CurrentTickcounter < respawn.NextSpawnTick)) continue;
- if ((respawn.Info.RespawnTicks == 0) && (Envir.Time < respawn.RespawnTime)) continue;
- if (respawn.Count < (respawn.Info.Count * Envir.SpawnMultiplier))
- {
- int count = (respawn.Info.Count * Envir.SpawnMultiplier) - respawn.Count;
- for (int c = 0; c < count; c++)
- Success = respawn.Spawn();
- }
- if (Success)
- {
- respawn.ErrorCount = 0;
- long delay = Math.Max(1, respawn.Info.Delay - respawn.Info.RandomDelay + Envir.Random.Next(respawn.Info.RandomDelay * 2));
- respawn.RespawnTime = Envir.Time + (delay * Settings.Minute);
- if (respawn.Info.RespawnTicks != 0)
- {
- respawn.NextSpawnTick = Envir.RespawnTick.CurrentTickcounter + (ulong)respawn.Info.RespawnTicks;
- if (respawn.NextSpawnTick > long.MaxValue)//since nextspawntick is ulong this simple thing allows an easy way of preventing the counter from overflowing
- respawn.NextSpawnTick -= long.MaxValue;
- }
- }
- else
- {
- respawn.RespawnTime = Envir.Time + 1 * Settings.Minute; // each time it fails to spawn, give it a 1 minute cooldown
- if (respawn.ErrorCount < 5)
- respawn.ErrorCount++;
- else
- {
- if (respawn.ErrorCount == 5)
- {
- respawn.ErrorCount++;
- Logger.GetLogger(LogType.Spawn).Info($"Failed to spawn: " +
- $"mapindex: {respawn.Map.Info.Index}, " +
- $"mob info: index: {respawn.Info.MonsterIndex}, " +
- $"name: {respawn.Monster.Name}, " +
- $"spawncoords ({respawn.Info.Location.X}:{respawn.Info.Location.Y}), " +
- $"range {respawn.Info.Spread}");
- }
- }
- }
- }
- }
- public void Process(DelayedAction action)
- {
- switch (action.Type)
- {
- case DelayedType.Magic:
- CompleteMagic(action.Params);
- break;
- case DelayedType.Spawn:
- MapObject obj = (MapObject)action.Params[0];
- switch(obj.Race)
- {
- case ObjectType.Monster:
- {
- MonsterObject mob = (MonsterObject)action.Params[0];
- mob.Spawn(this, (Point)action.Params[1]);
- if (action.Params.Length > 2) ((MonsterObject)action.Params[2]).SlaveList.Add(mob);
- }
- break;
- case ObjectType.Spell:
- {
- SpellObject spell = (SpellObject)action.Params[0];
- AddObject(spell);
- spell.Spawned();
- }
- break;
- }
- break;
- }
- }
- /**
- * return the coordinates of effect coordinates within an n x n square (n should be odd number. i.e. 3x3, 5x5, 7x7)
- * then use GetCell() in Map.cs to retrive real objects
- * default 3x3
- */
- public static List<Point> GetPointsInEffectiveSquare(Point location, int mapWidth, int mapHeight, int squareEdgeLength = 3)
- {
- var pointsWithinTheMap = new List<Point>();
- int fallBackSpread = 1;
- int spread;
- if (squareEdgeLength > 1)
- {
- spread = (int)((squareEdgeLength - 1) / 2);
- } else
- {
- spread = fallBackSpread; // 3x3
- }
- for (int y = location.Y - spread; y <= location.Y + spread; y++)
- {
- if (y < 0) continue;
- if (y >= mapHeight) break;
- for (int x = location.X - spread; x <= location.X + spread; x++)
- {
- if (x < 0) continue;
- if (x >= mapWidth) break;
- pointsWithinTheMap.Add(new Point(x, y));
- }
- }
- return pointsWithinTheMap;
- }
- private void CompleteMagic(IList<object> data)
- {
- bool train = false;
- HumanObject player = (HumanObject)data[0];
- UserMagic magic = (UserMagic)data[1];
- if (player == null || player.Info == null || player.Node == null) return;
- int value, value2;
- Point location;
- Cell cell;
- MirDirection dir;
- MonsterObject monster;
- Point front;
- switch (magic.Spell)
- {
- #region HellFire
- case Spell.HellFire:
- value = (int)data[2];
- dir = (MirDirection)data[4];
- location = Functions.PointMove((Point)data[3], dir, 1);
- int count = (int)data[5] - 1;
- if (!ValidPoint(location)) return;
- if (count > 0)
- {
- DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 100, player, magic, value, location, dir, count);
- ActionList.Add(action);
- }
- cell = GetCell(location);
- if (cell.Objects == null) return;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- switch (target.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Player:
- //Only targets
- if (target.IsAttackTarget(player))
- {
- if (target.Attacked(player, value, DefenceType.MAC, false) > 0)
- train = true;
- break;
- }
- break;
- }
- }
- break;
- #endregion
- #region SummonSkeleton, SummonShinsu, SummonHolyDeva, ArcherSummons
- case Spell.SummonSkeleton:
- case Spell.SummonShinsu:
- case Spell.SummonHolyDeva:
- case Spell.SummonVampire:
- case Spell.SummonToad:
- case Spell.SummonSnakes:
- monster = (MonsterObject)data[2];
- front = (Point)data[3];
- if (monster.Master.Dead) return;
- if (ValidPoint(front))
- monster.Spawn(this, front);
- else
- monster.Spawn(player.CurrentMap, player.CurrentLocation);
- monster.Master.Pets.Add(monster);
- break;
- case Spell.Stonetrap:
- monster = (MonsterObject)data[2];
- front = (Point)data[3];
- if (monster.Master.Dead) return;
- if (ValidPoint(front))
- monster.Spawn(this, front);
- else
- monster.Spawn(player.CurrentMap, player.CurrentLocation);
- monster.Master.Pets.Add(monster);
- break;
- #endregion
- #region FireBang, IceStorm
- case Spell.IceStorm:
- case Spell.FireBang:
- value = (int)data[2];
- location = (Point)data[3];
- for (int y = location.Y - 1; y <= location.Y + 1; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 1; x <= location.X + 1; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- switch (target.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Player:
- //Only targets
- if (target.IsAttackTarget(player))
- {
- if (target.Attacked(player, value, DefenceType.MAC, false) > 0)
- train = true;
- }
- break;
- }
- }
- }
- }
- break;
- #endregion
- #region MassHiding
- case Spell.MassHiding:
- value = (int)data[2];
- location = (Point)data[3];
- for (int y = location.Y - 1; y <= location.Y + 1; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 1; x <= location.X + 1; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- if (target.Node == null) continue;
- switch (target.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Player:
- //Only targets
- if (target.IsFriendlyTarget(player))
- {
- target.AddBuff(BuffType.Hiding, player, (Settings.Second * value), new Stats());
- target.OperateTime = 0;
- train = true;
- }
- break;
- }
- }
- }
- }
- break;
- #endregion
- #region SoulShield, BlessedArmour
- case Spell.SoulShield:
- case Spell.BlessedArmour:
- value = (int)data[2];
- location = (Point)data[3];
- BuffType type = magic.Spell == Spell.SoulShield ? BuffType.SoulShield : BuffType.BlessedArmour;
- for (int y = location.Y - 3; y <= location.Y + 3; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 3; x <= location.X + 3; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- if (target.Node == null) continue;
- switch (target.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Player:
- case ObjectType.Hero:
- //Only targets
- if (target.IsFriendlyTarget(player))
- {
- var stats = new Stats
- {
- [type == BuffType.SoulShield ? Stat.MaxMAC : Stat.MaxAC] = target.Level / 7 + 4
- };
- target.AddBuff(type, player, Settings.Second * value, stats);
- target.OperateTime = 0;
- train = true;
- }
- break;
- }
- }
- }
- }
- break;
- #endregion
- #region FireWall
- case Spell.FireWall:
- value = (int)data[2];
- location = (Point)data[3];
- int castId = 0;
- if (data.Count >= 5 && data[4] is int ci) castId = ci;
- player.LevelMagic(magic);
- if (ValidPoint(location))
- {
- cell = GetCell(location);
- bool cast = true;
- if (cell.Objects != null)
- for (int o = 0; o < cell.Objects.Count; o++)
- {
- MapObject target = cell.Objects[o];
- if (target.Race != ObjectType.Spell || ((SpellObject)target).Spell != Spell.FireWall) continue;
- cast = false;
- break;
- }
- if (cast)
- {
- SpellObject ob = new SpellObject
- {
- Spell = Spell.FireWall,
- Value = value,
- ExpireTime = Envir.Time + (10 + value / 2) * 1000,
- TickSpeed = 2000,
- Caster = player,
- CurrentLocation = location,
- CurrentMap = this,
- CastInstanceId = castId
- };
- AddObject(ob);
- ob.Spawned();
- }
- }
- dir = MirDirection.Up;
- for (int i = 0; i < 4; i++)
- {
- location = Functions.PointMove((Point)data[3], dir, 1);
- dir += 2;
- if (!ValidPoint(location)) continue;
- cell = GetCell(location);
- bool cast = true;
- if (cell.Objects != null)
- for (int o = 0; o < cell.Objects.Count; o++)
- {
- MapObject target = cell.Objects[o];
- if (target.Race != ObjectType.Spell || ((SpellObject)target).Spell != Spell.FireWall) continue;
- cast = false;
- break;
- }
- if (!cast) continue;
- SpellObject ob = new SpellObject
- {
- Spell = Spell.FireWall,
- Value = value,
- ExpireTime = Envir.Time + (10 + value / 2) * 1000,
- TickSpeed = 2000,
- Caster = player,
- CurrentLocation = location,
- CurrentMap = this,
- CastInstanceId = castId
- };
- AddObject(ob);
- ob.Spawned();
- }
- break;
- #endregion
- #region Lightning
- case Spell.Lightning:
- value = (int)data[2];
- location = (Point)data[3];
- dir = (MirDirection)data[4];
- for (int i = 0; i < 6; i++)
- {
- location = Functions.PointMove(location, dir, 1);
- if (!ValidPoint(location)) continue;
- cell = GetCell(location);
- if (cell.Objects == null) continue;
- for (int o = 0; o < cell.Objects.Count; o++)
- {
- MapObject target = cell.Objects[o];
- if (target.Race != ObjectType.Player && target.Race != ObjectType.Monster) continue;
- if (!target.IsAttackTarget(player)) continue;
- if (target.Attacked(player, value, DefenceType.MAC, false) > 0)
- train = true;
- break;
- }
- }
- break;
- #endregion
- #region HeavenlySword
- case Spell.HeavenlySword:
- value = (int)data[2];
- location = (Point)data[3];
- dir = (MirDirection)data[4];
- for (int i = 0; i < 3; i++)
- {
- location = Functions.PointMove(location, dir, 1);
- if (!ValidPoint(location)) continue;
- cell = GetCell(location);
- if (cell.Objects == null) continue;
- for (int o = 0; o < cell.Objects.Count; o++)
- {
- MapObject target = cell.Objects[o];
- if (target.Race != ObjectType.Player && target.Race != ObjectType.Monster) continue;
- if (!target.IsAttackTarget(player)) continue;
- if (target.Attacked(player, value, DefenceType.MAC, false) > 0)
- train = true;
- break;
- }
- }
- break;
- #endregion
- #region MassHealing
- case Spell.MassHealing:
- value = (int)data[2];
- location = (Point)data[3];
- for (int y = location.Y - 1; y <= location.Y + 1; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 1; x <= location.X + 1; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- switch (target.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Player:
- case ObjectType.Hero:
- //Only targets
- if (target.IsFriendlyTarget(player))
- {
- if (target.Health >= target.MaxHealth) continue;
- target.HealAmount = (ushort)Math.Min(ushort.MaxValue, target.HealAmount + value);
- target.OperateTime = 0;
- train = true;
- }
- break;
- }
- }
- }
- }
- break;
- #endregion
- #region ThunderStorm
- case Spell.ThunderStorm:
- case Spell.FlameField:
- case Spell.NapalmShot:
- case Spell.StormEscape:
- value = (int)data[2];
- location = (Point)data[3];
- for (int y = location.Y - 2; y <= location.Y + 2; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 2; x <= location.X + 2; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- switch (target.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Player:
- //Only targets
- if (!target.IsAttackTarget(player)) break;
- target.Attacked(player, magic.Spell == Spell.ThunderStorm && !target.Undead ? value / 10 : value, DefenceType.MAC, false);
- train = true;
- break;
- }
- }
- }
- }
- break;
- #endregion
- #region MoonMist
- case Spell.MoonMist:
- value = (int)data[2];
- location = (Point)data[3];
- for (int y = location.Y - 2; y <= location.Y + 2; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 2; x <= location.X + 2; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- switch (target.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Player:
- //Only targets
- if (!target.IsAttackTarget(player)) break;
- if (target.Attacked(player, magic.Spell == Spell.ThunderStorm && !target.Undead ? value / 10 : value, DefenceType.AC, false) <= 0)
- {
- if (target.Undead)
- {
- target.ApplyPoison(new Poison { PType = PoisonType.Stun, Duration = magic.Level + 2, TickSpeed = 1000 }, player);
- }
- break;
- }
- train = true;
- break;
- }
- }
- }
- }
- break;
- #endregion
- #region LionRoar
- case Spell.LionRoar:
- location = (Point)data[2];
- for (int y = location.Y - 2; y <= location.Y + 2; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 2; x <= location.X + 2; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- if (target.Race != ObjectType.Monster) continue;
- //Only targets
- if (!target.IsAttackTarget(player) || player.Level + 3 < target.Level) continue;
- target.ApplyPoison(new Poison { PType = PoisonType.LRParalysis, Duration = magic.Level + 2, TickSpeed = 1000 }, player);
- target.OperateTime = 0;
- train = true;
- }
- }
- }
- break;
- #endregion
- #region PoisonCloud
- case Spell.PoisonCloud:
- value = (int)data[2];
- location = (Point)data[3];
- byte bonusdmg = (byte)data[4];
- train = true;
- bool show = true;
- for (int y = location.Y - 1; y <= location.Y + 1; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 1; x <= location.X + 1; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid) continue;
- bool cast = true;
- if (cell.Objects != null)
- for (int o = 0; o < cell.Objects.Count; o++)
- {
- MapObject target = cell.Objects[o];
- if (target.Race != ObjectType.Spell || ((SpellObject)target).Spell != Spell.PoisonCloud) continue;
- cast = false;
- break;
- }
- if (!cast) continue;
- SpellObject ob = new SpellObject
- {
- Spell = Spell.PoisonCloud,
- Value = value,
- BonusDmg = bonusdmg,
- ExpireTime = Envir.Time + 6000,
- TickSpeed = 1000,
- Caster = player,
- CurrentLocation = new Point(x, y),
- CastLocation = location,
- Show = show,
- CurrentMap = this,
- };
- show = false;
- AddObject(ob);
- ob.Spawned();
- }
- }
- break;
- #endregion
- #region IceThrust
- case Spell.IceThrust:
- {
- location = (Point)data[2];
- MirDirection direction = (MirDirection)data[3];
- int nearDamage = (int)data[4];
- int farDamage = (int)data[5];
- int col = 3;
- int row = 3;
- Point[] loc = new Point[col]; //0 = left 1 = center 2 = right
- loc[0] = Functions.PointMove(location, Functions.PreviousDir(direction), 1);
- loc[1] = Functions.PointMove(location, direction, 1);
- loc[2] = Functions.PointMove(location, Functions.NextDir(direction), 1);
- for (int i = 0; i < col; i++)
- {
- Point startPoint = loc[i];
- for (int j = 0; j < row; j++)
- {
- Point hitPoint = Functions.PointMove(startPoint, direction, j);
- if (!ValidPoint(hitPoint)) continue;
- cell = GetCell(hitPoint);
- if (cell.Objects == null) continue;
- for (int k = 0; k < cell.Objects.Count; k++)
- {
- MapObject target = cell.Objects[k];
- switch (target.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Player:
- if (target.IsAttackTarget(player))
- {
- //Only targets
- if (target.Attacked(player, j <= 1 ? nearDamage : farDamage, DefenceType.MAC, false) > 0)
- {
- if (player.Level + (target.Race == ObjectType.Player ? 2 : 10) >= target.Level && Envir.Random.Next(target.Race == ObjectType.Player ? 100 : 20) <= magic.Level)
- {
- target.ApplyPoison(new Poison
- {
- Owner = player,
- Duration = target.Race == ObjectType.Player ? 4 : 5 + Envir.Random.Next(5),
- PType = PoisonType.Slow,
- TickSpeed = 1000,
- }, player);
- target.OperateTime = 0;
- }
- if (player.Level + (target.Race == ObjectType.Player ? 2 : 10) >= target.Level && Envir.Random.Next(target.Race == ObjectType.Player ? 100 : 40) <= magic.Level)
- {
- target.ApplyPoison(new Poison
- {
- Owner = player,
- Duration = target.Race == ObjectType.Player ? 2 : 5 + Envir.Random.Next(player.Stats[Stat.Freezing]),
- PType = PoisonType.Frozen,
- TickSpeed = 1000,
- }, player);
- target.OperateTime = 0;
- }
- train = true;
- }
- }
- break;
- }
- }
- }
- }
- }
- break;
- #endregion
- #region SlashingBurst
- case Spell.SlashingBurst:
- value = (int)data[2];
- location = (Point)data[3];
- dir = (MirDirection)data[4];
- count = (int)data[5];
- for (int i = 0; i < count; i++)
- {
- location = Functions.PointMove(location, dir, 1);
- if (!ValidPoint(location)) continue;
- cell = GetCell(location);
- if (cell.Objects == null) continue;
- for (int o = 0; o < cell.Objects.Count; o++)
- {
- MapObject target = cell.Objects[o];
- if (target.Race != ObjectType.Player && target.Race != ObjectType.Monster) continue;
- if (!target.IsAttackTarget(player)) continue;
- if (target.Attacked(player, value, DefenceType.AC, false) > 0)
- train = true;
- break;
- }
- }
- break;
- #endregion
- #region Mirroring
- case Spell.Mirroring:
- monster = (MonsterObject)data[2];
- front = (Point)data[3];
- bool finish = (bool)data[4];
- if (finish)
- {
- monster.Die();
- return;
- };
- if (ValidPoint(front))
- monster.Spawn(this, front);
- else
- monster.Spawn(player.CurrentMap, player.CurrentLocation);
- break;
- #endregion
- #region Blizzard
- case Spell.Blizzard:
- value = (int)data[2];
- location = (Point)data[3];
- train = true;
- show = true;
- for (int y = location.Y - 2; y <= location.Y + 2; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 2; x <= location.X + 2; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid) continue;
- bool cast = true;
- if (cell.Objects != null)
- for (int o = 0; o < cell.Objects.Count; o++)
- {
- MapObject target = cell.Objects[o];
- if (target.Race != ObjectType.Spell || ((SpellObject) target).Spell != Spell.Blizzard) continue;
- cast = false;
- break;
- }
- if (!cast) continue;
- SpellObject ob = new SpellObject
- {
- Spell = Spell.Blizzard,
- Value = value,
- ExpireTime = Envir.Time + 3000,
- TickSpeed = 440,
- Caster = player,
- CurrentLocation = new Point(x, y),
- CastLocation = location,
- Show = show,
- CurrentMap = this,
- StartTime = Envir.Time + 800,
- };
- show = false;
- AddObject(ob);
- ob.Spawned();
- }
- }
- break;
- #endregion
- #region MeteorStrike
- case Spell.MeteorStrike:
- value = (int)data[2];
- location = (Point)data[3];
- train = true;
- show = true;
- for (int y = location.Y - 2; y <= location.Y + 2; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 2; x <= location.X + 2; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid) continue;
- bool cast = true;
- if (cell.Objects != null)
- for (int o = 0; o < cell.Objects.Count; o++)
- {
- MapObject target = cell.Objects[o];
- if (target.Race != ObjectType.Spell || ((SpellObject)target).Spell != Spell.MeteorStrike) continue;
- cast = false;
- break;
- }
- if (!cast) continue;
- SpellObject ob = new SpellObject
- {
- Spell = Spell.MeteorStrike,
- Value = value,
- ExpireTime = Envir.Time + 3000,
- TickSpeed = 440,
- Caster = player,
- CurrentLocation = new Point(x, y),
- CastLocation = location,
- Show = show,
- CurrentMap = this,
- StartTime = Envir.Time + 800,
- };
- show = false;
- AddObject(ob);
- ob.Spawned();
- }
- }
- break;
- #endregion
- #region TrapHexagon
- case Spell.TrapHexagon:
- value = (int)data[2];
- location = (Point)data[3];
- MonsterObject centerTarget = null;
- for (int y = location.Y - 1; y <= location.Y + 1; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 1; x <= location.X + 1; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- if (y == location.Y && x == location.X && target.Race == ObjectType.Monster)
- {
- centerTarget = (MonsterObject)target;
- }
-
- switch (target.Race)
- {
- case ObjectType.Monster:
- if (target == null || !target.IsAttackTarget(player) || target.Node == null || target.Level > player.Level + 2) continue;
- MonsterObject mobTarget = (MonsterObject)target;
- if (centerTarget == null) centerTarget = mobTarget;
- mobTarget.ShockTime = Envir.Time + value;
- mobTarget.Target = null;
- break;
- }
- }
- }
- }
- if (centerTarget == null) return;
- for (byte i = 0; i < 8; i += 2)
- {
- Point startpoint = Functions.PointMove(location, (MirDirection)i, 2);
- for (byte j = 0; j <= 4; j += 4)
- {
- MirDirection spawndirection = i == 0 || i == 4 ? MirDirection.Right : MirDirection.Up;
- Point spawnpoint = Functions.PointMove(startpoint, spawndirection + j, 1);
- if (spawnpoint.X <= 0 || spawnpoint.X > centerTarget.CurrentMap.Width) continue;
- if (spawnpoint.Y <= 0 || spawnpoint.Y > centerTarget.CurrentMap.Height) continue;
- SpellObject ob = new SpellObject
- {
- Spell = Spell.TrapHexagon,
- ExpireTime = Envir.Time + value,
- TickSpeed = 100,
- Caster = player,
- CurrentLocation = spawnpoint,
- CastLocation = location,
- CurrentMap = centerTarget.CurrentMap,
- Target = centerTarget,
- };
- centerTarget.CurrentMap.AddObject(ob);
- ob.Spawned();
- }
- }
- train = true;
- break;
- #endregion
- #region Curse
- case Spell.Curse:
- value = (int)data[2];
- location = (Point)data[3];
- value2 = (int)data[4];
- for (int y = location.Y - 3; y <= location.Y + 3; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 3; x <= location.X + 3; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- if (target.Node == null) continue;
- switch (target.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Player:
- if (Envir.Random.Next(10) >= 4) continue;
- //Only targets
- if (target.IsAttackTarget(player))
- {
- target.ApplyPoison(new Poison { PType = PoisonType.Slow, Duration = value, TickSpeed = 1000, Value = value2, Owner = player }, player);
- var stats = new Stats
- {
- [Stat.MaxDCRatePercent] = value2 * -1,
- [Stat.MaxMCRatePercent] = value2 * -1,
- [Stat.MaxSCRatePercent] = value2 * -1,
- [Stat.AttackSpeedRatePercent] = target.Race == ObjectType.Player ? value2 * -1 : 0
- };
- target.AddBuff(BuffType.Curse, player, Settings.Second * value, stats);
- target.OperateTime = 0;
- train = true;
- }
- break;
- }
- }
- }
- }
- break;
- #endregion
- #region ExplosiveTrap
- case Spell.ExplosiveTrap:
- value = (int)data[2];
- front = (Point)data[3];
- int trapID = (int)data[4];
- if (ValidPoint(front))
- {
- cell = GetCell(front);
- bool cast = true;
- if (cell.Objects != null)
- for (int o = 0; o < cell.Objects.Count; o++)
- {
- MapObject target = cell.Objects[o];
- if (target.Race != ObjectType.Spell || (((SpellObject)target).Spell != Spell.FireWall && ((SpellObject)target).Spell != Spell.ExplosiveTrap)) continue;
- cast = false;
- break;
- }
- if (cast)
- {
- player.LevelMagic(magic);
- System.Drawing.Point[] traps = new Point[3];
- traps[0] = front;
- traps[1] = Functions.Left(front, player.Direction);
- traps[2] = Functions.Right(front, player.Direction);
- for (int i = 0; i <= 2; i++)
- {
- bool skip = false;
- //for the extra spots make sure to not overlap new traps with old ones since it creates invisible double/tripple /... trap spots
- if (i > 0)
- {
- cell = GetCell(traps[i]);
- if (cell.Objects != null)
- for (int o = 0; o < cell.Objects.Count; o++)
- {
- MapObject target = cell.Objects[o];
- if (target.Race != ObjectType.Spell || (((SpellObject)target).Spell != Spell.FireWall && ((SpellObject)target).Spell != Spell.ExplosiveTrap)) continue;
- skip = true;
- break;
- }
- }
- if (skip) continue;
- SpellObject ob = new SpellObject
- {
- Spell = Spell.ExplosiveTrap,
- Value = value,
- ExpireTime = Envir.Time + (10 + value / 2) * 1000,
- TickSpeed = 500,
- Caster = player,
- CurrentLocation = traps[i],
- CurrentMap = this,
- ExplosiveTrapID = trapID,
- ExplosiveTrapCount = i
- };
- AddObject(ob);
- ob.Spawned();
- }
- }
- }
- break;
- #endregion
- #region Plague
- case Spell.Plague:
- // DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, this, magic, magic.GetDamage(GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC])), location, pType);
- // (int)data[2] === magic.GetDamage(GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]))
- // (Point)data[3] === location
- // (PoisonType)data[4] === pType
- value = (int)data[2];
- location = (Point)data[3];
- // the skill affect a 3x3 square
- var points= GetPointsInEffectiveSquare(location, Width, Height, 3);
- foreach (var point in points)
- {
- cell = GetCell(point.X, point.Y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- switch (target.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Player:
- //Only targets
- if (target.IsAttackTarget(player))
- {
- int chance = Envir.Random.Next(15);
- PoisonType poison;
- if (new int[] { 0, 1, 2 }.Contains(chance)) //3 in 15 chances it'll slow
- poison = PoisonType.Slow;
- else if (new int[] { 3, 4 }.Contains(chance)) //2 in 15 chances it'll freeze
- poison = PoisonType.Frozen;
- else if (new int[] { 5, 6, 7, 8, 9 }.Contains(chance)) //5 in 15 chances it'll red/green
- // (whatever type of poison player is holding)
- poison = (PoisonType)data[4];
- else //5 in 15 chances it'll do nothing
- poison = PoisonType.None;
- int tempValue = 0;
- if (poison == PoisonType.Red)
- {
- tempValue = value / 15 + magic.Level + 1;
- }
- else
- {
- tempValue = value + (magic.Level + 1) * 2;
- }
- if (poison != PoisonType.None)
- {
- target.ApplyPoison(new Poison { PType = poison, Duration = (2 * (magic.Level + 1)) + (value / 10), TickSpeed = 1000, Value = tempValue, Owner = player }, player, false, true);
- }
- if (target.Race == ObjectType.Player)
- {
- PlayerObject tempOb = (PlayerObject)target;
- tempOb.ChangeMP(-tempValue);
- }
- target.Attacked(player, player.Stats[Stat.MaxSC] * 2, DefenceType.MAC, true);
- train = true;
- }
- break;
- }
- }
- }
- break;
- #endregion
- #region Trap
- case Spell.Trap:
- value = (int)data[2];
- //location = (Point)data[3];
- MapObject originalTarget = (MapObject)data[3];
- location = originalTarget.CurrentLocation;
- MonsterObject selectTarget = null;
- if (!ValidPoint(location)) break;
- cell = GetCell(location);
- if (!cell.Valid || cell.Objects == null) break;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- if (target.Race == ObjectType.Monster)
- {
- selectTarget = (MonsterObject)target;
- if (selectTarget == null || !selectTarget.IsAttackTarget(player) || selectTarget.Node == null || selectTarget.Level >= player.Level + 2) continue;
- selectTarget.ShockTime = Envir.Time + value;
- selectTarget.Target = null;
- break;
- }
- }
- if (selectTarget == null) return;
- if (location.X <= 0 || location.X > selectTarget.CurrentMap.Width) break;
- if (location.Y <= 0 || location.Y > selectTarget.CurrentMap.Height) break;
- SpellObject spellOb = new SpellObject
- {
- Spell = Spell.Trap,
- ExpireTime = Envir.Time + value,
- TickSpeed = 100,
- Caster = player,
- CurrentLocation = location,
- CastLocation = location,
- CurrentMap = selectTarget.CurrentMap,
- Target = selectTarget,
- };
- selectTarget.CurrentMap.AddObject(spellOb);
- spellOb.Spawned();
- train = true;
- break;
- #endregion
- #region OneWithNature
- case Spell.OneWithNature:
- value = (int)data[2];
- location = (Point)data[3];
- bool hasVampBuff = (player.Buffs.Any(ex => ex.Type == BuffType.VampireShot));
- bool hasPoisonBuff = (player.Buffs.Any(ex => ex.Type == BuffType.PoisonShot));
- for (int y = location.Y - 2; y <= location.Y + 2; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 2; x <= location.X + 2; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- switch (target.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Player:
- //Only targets
- if (!target.IsAttackTarget(player) || target.Dead) break;
- //knockback
- //int distance = 1 + Math.Max(0, magic.Level - 1) + Envir.Random.Next(2);
- //dir = Functions.DirectionFromPoint(location, target.CurrentLocation);
- //if(target.Level < player.Level)
- // target.Pushed(player, dir, distance);// <--crashes server somehow?
- if (target.Attacked(player, value, DefenceType.MAC, false) <= 0) break;
- if (hasVampBuff)//Vampire Effect
- {
- if (player.VampAmount == 0) player.VampTime = Envir.Time + 1000;
- player.VampAmount += (ushort)(value * (magic.Level + 1) * 0.25F);
- }
- if (hasPoisonBuff)//Poison Effect
- {
- target.ApplyPoison(new Poison
- {
- Duration = (value * 2) + (magic.Level + 1) * 7,
- Owner = player,
- PType = PoisonType.Green,
- TickSpeed = 2000,
- Value = value / 15 + magic.Level + 1 + Envir.Random.Next(player.Stats[Stat.PoisonAttack])
- }, player);
- target.OperateTime = 0;
- }
- train = true;
- break;
- }
- }
- }
- }
- if (hasVampBuff)
- {
- //Expire
- player.AddBuff(BuffType.VampireShot, player, Settings.Second * 1, new Stats());
- }
- if (hasPoisonBuff)
- {
- //Expire
- player.AddBuff(BuffType.PoisonShot, player, Settings.Second * 1, new Stats());
- }
- break;
- #endregion
- #region Portal
- case Spell.Portal:
- value = (int)data[2];
- location = (Point)data[3];
- value2 = (int)data[4];
- spellOb = new SpellObject
- {
- Spell = Spell.Portal,
- Value = value2,
- ExpireTime = Envir.Time + value * 1000,
- TickSpeed = 2000,
- Caster = player,
- CurrentLocation = location,
- CurrentMap = this,
- };
- AddObject(spellOb);
- spellOb.Spawned();
- train = true;
- break;
- #endregion
- #region DelayedExplosion
- case Spell.DelayedExplosion:
- value = (int)data[2];
- location = (Point)data[3];
- for (int y = location.Y - 1; y <= location.Y + 1; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 1; x <= location.X + 1; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid || cell.Objects == null) continue;
- for (int i = 0; i < cell.Objects.Count; i++)
- {
- MapObject target = cell.Objects[i];
- switch (target.Race)
- {
- case ObjectType.Monster:
- case ObjectType.Player:
- //Only targets
- if (target.IsAttackTarget(player))
- {
- if (target.Attacked(player, value, DefenceType.MAC, false) > 0)
- train = false;//wouldnt want to make the skill give twice the points
- }
- break;
- }
- }
- }
- }
- break;
- #endregion
- #region BattleCry
- case Spell.BattleCry:
- location = (Point)data[2];
- int startX = Math.Max(location.X - 2, 0);
- int endX = Math.Min(location.X + 2, Width - 1);
- int startY = Math.Max(location.Y - 2, 0);
- int endY = Math.Min(location.Y + 2, Height - 1);
- int randomValue = Envir.Random.Next(100);
- for (int y = startY; y <= endY; y++)
- {
- for (int x = startX; x <= endX; x++)
- {
- cell = GetCell(x, y);
- if (!cell.Valid || cell.Objects == null || cell.Objects.Count == 0) continue;
- foreach (var target in cell.Objects)
- {
- if (target.Race != ObjectType.Monster) continue;
- int threshold = magic.Level switch
- {
- 0 => 90, // 90% chance of failure (10% success)
- 1 => 70, // 70% chance of failure (30% success)
- 2 => 50, // 50% chance of failure (50% success)
- 3 => 30, // 30% chance of failure (70% success)
- _ => 100 // Default case, should not occur
- };
- if (randomValue > threshold) continue;
- if (((MonsterObject)target).Info.CoolEye == 100) continue;
- target.Target = player;
- target.OperateTime = 0;
- train = true;
- }
- }
- }
- break;
- #endregion
- #region HealingCircle
- case Spell.HealingCircle:
- value = (int)data[2];
- location = (Point)data[3];
- train = true;
- show = true;
- for (int y = location.Y - 1; y <= location.Y + 1; y++)
- {
- if (y < 0) continue;
- if (y >= Height) break;
- for (int x = location.X - 1; x <= location.X + 1; x++)
- {
- if (x < 0) continue;
- if (x >= Width) break;
- cell = GetCell(x, y);
- if (!cell.Valid) continue;
- bool cast = true;
- if (cell.Objects != null)
- for (int o = 0; o < cell.Objects.Count; o++)
- {
- MapObject target = cell.Objects[o];
- if (target.Race != ObjectType.Spell || ((SpellObject)target).Spell != Spell.HealingCircle) continue;
- cast = false;
- break;
- }
- if (!cast) continue;
- SpellObject ob = new SpellObject
- {
- Spell = Spell.HealingCircle,
- Value = value,
- ExpireTime = Envir.Time + (10000) + (5000 * magic.Level),
- TickSpeed = 400,
- Caster = player,
- CurrentLocation = new Point(x, y),
- CastLocation = location,
- Show = show,
- CurrentMap = this,
- };
- show = false;
- AddObject(ob);
- ob.Spawned();
- }
- }
- break;
- #endregion
- }
- if (train)
- player.LevelMagic(magic);
- }
- public void AddObject(MapObject ob)
- {
- if (ob.Race == ObjectType.Player)
- {
- Players.Add((PlayerObject)ob);
- }
- if (ob.Race == ObjectType.Merchant) NPCs.Add((NPCObject)ob);
- if (ob.Race == ObjectType.Spell) Spells.Add((SpellObject)ob);
- if (ob.Race == ObjectType.Hero) Heroes.Add((HeroObject)ob);
- GetCell(ob.CurrentLocation).Add(ob);
- }
- public void RemoveObject(MapObject ob)
- {
- if (ob.Race == ObjectType.Player) Players.Remove((PlayerObject)ob);
- if (ob.Race == ObjectType.Merchant) NPCs.Remove((NPCObject)ob);
- if (ob.Race == ObjectType.Spell) Spells.Remove((SpellObject)ob);
- if (ob.Race == ObjectType.Hero) Heroes.Remove((HeroObject)ob);
- GetCell(ob.CurrentLocation).Remove(ob);
- }
- public SafeZoneInfo GetSafeZone(Point location)
- {
- for (int i = 0; i < Info.SafeZones.Count; i++)
- {
- SafeZoneInfo szi = Info.SafeZones[i];
- if (Functions.InRange(szi.Location, location, szi.Size))
- return szi;
- }
- return null;
- }
- public List<SpellObject> GetSpellObjects(Spell spell ,MapObject caster)
- {
- List<SpellObject> spellObjects = new List<SpellObject>();
- for (int i = 0; i < Spells.Count; i++)
- {
- if (spell != Spells[i].Spell) continue;
- if (caster != null && Spells[i].Caster != caster) continue;
- spellObjects.Add(Spells[i]);
- }
- return spellObjects;
- }
- public ConquestObject GetConquest(Point location)
- {
- for (int i = 0; i < Conquest.Count; i++)
- {
- ConquestObject swi = Conquest[i];
- if ((swi.Info.FullMap || Functions.InRange(swi.Info.Location, location, swi.Info.Size)) && swi.WarIsOn)
- return swi;
- }
- return null;
- }
- //public ConquestObject GetInnerConquest(Map map, Point location)
- //{
- // for (int i = 0; i < Conquest.Count; i++)
- // {
- // ConquestObject swi = Conquest[i];
- // if (map.Info.Index != swi.Info.MapIndex) continue;
- // if (Functions.InRange(swi.Info.KingLocation, location, swi.Info.KingSize) && swi.WarIsOn)
- // return swi;
- // }
- // return null;
- //}
- public void Broadcast(Packet p, Point location)
- {
- if (p == null) return;
- for (int i = Players.Count - 1; i >= 0; i--)
- {
- PlayerObject player = Players[i];
- if (Functions.InRange(location, player.CurrentLocation, Globals.DataRange))
- player.Enqueue(p);
- }
- }
- public void BroadcastNPC(Packet p, Point location)
- {
- if (p == null) return;
- for (int i = Players.Count - 1; i >= 0; i--)
- {
- PlayerObject player = Players[i];
- if (Functions.InRange(location, player.CurrentLocation, Globals.DataRange))
- player.Enqueue(p);
- }
- }
- public void Broadcast(Packet p, Point location, PlayerObject Player)
- {
- if (p == null) return;
- if (Functions.InRange(location, Player.CurrentLocation, Globals.DataRange))
- {
- Player.Enqueue(p);
- }
- }
- }
- public class Cell
- {
- public static Cell LowWall { get { return new Cell { Attribute = CellAttribute.LowWall }; } }
- public static Cell HighWall { get { return new Cell { Attribute = CellAttribute.HighWall }; } }
- public bool Valid
- {
- get { return Attribute == CellAttribute.Walk; }
- }
- public List<MapObject> Objects = new List<MapObject>();
- public CellAttribute Attribute;
- public sbyte FishingAttribute = -1;
- public void Add(MapObject mapObject)
- {
- if (mapObject == null)
- {
- ReportCellIssue("Attempted to add a null MapObject to a Cell.");
- return;
- }
- if (Objects.Contains(mapObject))
- {
- ReportCellIssue($"Duplicate MapObject add detected for ObjectID {mapObject.ObjectID}.");
- return;
- }
- Objects.Add(mapObject);
- }
- public void Remove(MapObject mapObject)
- {
- if (mapObject == null)
- {
- ReportCellIssue("Attempted to remove a null MapObject from a Cell.");
- return;
- }
- if (!Objects.Remove(mapObject))
- {
- ReportCellIssue($"Failed to remove MapObject {mapObject.ObjectID} from Cell collection.");
- }
- // DO NOT set Objects = null; keep the list to avoid re-alloc
- }
- private static void ReportCellIssue(string message)
- {
- try
- {
- throw new System.InvalidOperationException(message);
- }
- catch (System.Exception ex)
- {
- MessageQueue.Instance.Enqueue(ex);
- }
- }
- }
- public class MapRespawn
- {
- protected static Envir Envir
- {
- get { return Envir.Main; }
- }
- public RespawnInfo Info;
- public MonsterInfo Monster;
- public Map Map;
- public int Count;
- public long RespawnTime;
- public ulong NextSpawnTick;
- public byte ErrorCount = 0;
- public List<RouteInfo> Route;
- public List<Point> WalkableCells;
- public MapRespawn(RespawnInfo info)
- {
- Info = info;
- Monster = Envir.GetMonsterInfo(info.MonsterIndex);
- LoadRoutes();
- }
- public bool Spawn()
- {
- MonsterObject ob = MonsterObject.GetMonster(Monster);
- if (ob == null) return true;
- MonsterType type = Settings.MonsterRarityEnabled
- ? MonsterRarityData.Roll(RandomProvider.GetThreadRandom())
- : MonsterType.Normal;
- ob.SetMonsterType(type);
- return ob.Spawn(this);
- }
- public void LoadRoutes()
- {
- Route = new List<RouteInfo>();
- if (string.IsNullOrEmpty(Info.RoutePath)) return;
- string fileName = Path.Combine(Settings.RoutePath, Info.RoutePath + ".txt");
- if (!File.Exists(fileName)) return;
- List<string> lines = File.ReadAllLines(fileName).ToList();
- foreach (string line in lines)
- {
- RouteInfo info = RouteInfo.FromText(line);
- if (info == null) continue;
- Route.Add(info);
- }
- }
- }
- }
|