HumanObject.cs 336 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675
  1. using System.Drawing;
  2. using Server.MirDatabase;
  3. using Server.MirEnvir;
  4. using Server.MirNetwork;
  5. using Server.MirObjects.Monsters;
  6. using System.Numerics;
  7. using S = ServerPackets;
  8. namespace Server.MirObjects
  9. {
  10. public class HumanObject : MapObject
  11. {
  12. public override ObjectType Race
  13. {
  14. get { return ObjectType.Player; }
  15. }
  16. public CharacterInfo Info;
  17. protected MirConnection connection;
  18. public virtual MirConnection Connection
  19. {
  20. get { return connection; }
  21. set { connection = value; }
  22. }
  23. public override string Name
  24. {
  25. get { return Info.Name; }
  26. set { /*Check if Name exists.*/ }
  27. }
  28. public override int CurrentMapIndex
  29. {
  30. get { return Info.CurrentMapIndex; }
  31. set { Info.CurrentMapIndex = value; }
  32. }
  33. public override Point CurrentLocation
  34. {
  35. get { return Info.CurrentLocation; }
  36. set { Info.CurrentLocation = value; }
  37. }
  38. public override MirDirection Direction
  39. {
  40. get { return Info.Direction; }
  41. set { Info.Direction = value; }
  42. }
  43. public override ushort Level
  44. {
  45. get { return Info.Level; }
  46. set { Info.Level = value; }
  47. }
  48. public override int Health
  49. {
  50. get { return HP; }
  51. }
  52. public override int MaxHealth
  53. {
  54. get { return Stats[Stat.HP]; }
  55. }
  56. public int HP
  57. {
  58. get { return Info.HP; }
  59. set { Info.HP = value; }
  60. }
  61. public int MP
  62. {
  63. get { return Info.MP; }
  64. set { Info.MP = value; }
  65. }
  66. public override AttackMode AMode
  67. {
  68. get { return Info.AMode; }
  69. set { Info.AMode = value; }
  70. }
  71. public override PetMode PMode
  72. {
  73. get { return Info.PMode; }
  74. set { Info.PMode = value; }
  75. }
  76. public long Experience
  77. {
  78. set { Info.Experience = value; }
  79. get { return Info.Experience; }
  80. }
  81. public long MaxExperience;
  82. public byte Hair
  83. {
  84. get { return Info.Hair; }
  85. set { Info.Hair = value; }
  86. }
  87. public MirClass Class
  88. {
  89. get { return Info.Class; }
  90. }
  91. public MirGender Gender
  92. {
  93. get { return Info.Gender; }
  94. }
  95. public override List<Buff> Buffs
  96. {
  97. get { return Info.Buffs; }
  98. set { Info.Buffs = value; }
  99. }
  100. public override List<Poison> PoisonList
  101. {
  102. get { return Info.Poisons; }
  103. set { Info.Poisons = value; }
  104. }
  105. public bool RidingMount;
  106. public MountInfo Mount
  107. {
  108. get { return Info.Mount; }
  109. }
  110. public Reporting Report;
  111. public virtual bool CanMove
  112. {
  113. get
  114. {
  115. return !Dead && Envir.Time >= ActionTime && !CurrentPoison.HasFlag(PoisonType.Paralysis) && !CurrentPoison.HasFlag(PoisonType.LRParalysis) && !CurrentPoison.HasFlag(PoisonType.Frozen);
  116. }
  117. }
  118. public virtual bool CanWalk
  119. {
  120. get
  121. {
  122. return !Dead && Envir.Time >= ActionTime && !InTrapRock && !CurrentPoison.HasFlag(PoisonType.Paralysis) && !CurrentPoison.HasFlag(PoisonType.LRParalysis) && !CurrentPoison.HasFlag(PoisonType.Frozen);
  123. }
  124. }
  125. public virtual bool CanRun
  126. {
  127. get
  128. {
  129. return !Dead && Envir.Time >= ActionTime && (_stepCounter > 0 || FastRun) && (!Sneaking || ActiveSwiftFeet) && CurrentBagWeight <= Stats[Stat.BagWeight] && !CurrentPoison.HasFlag(PoisonType.Paralysis) && !CurrentPoison.HasFlag(PoisonType.LRParalysis) && !CurrentPoison.HasFlag(PoisonType.Frozen);
  130. }
  131. }
  132. public virtual bool CanAttack
  133. {
  134. get
  135. {
  136. return !Dead && Envir.Time >= ActionTime && Envir.Time >= AttackTime && !CurrentPoison.HasFlag(PoisonType.Paralysis) && !CurrentPoison.HasFlag(PoisonType.LRParalysis) && !CurrentPoison.HasFlag(PoisonType.Frozen) && !CurrentPoison.HasFlag(PoisonType.Dazed) && Mount.CanAttack;
  137. }
  138. }
  139. public bool CanRegen
  140. {
  141. get
  142. {
  143. return Envir.Time >= RegenTime;
  144. }
  145. }
  146. protected virtual bool CanCast
  147. {
  148. get
  149. {
  150. return !Dead && Envir.Time >= ActionTime && Envir.Time >= SpellTime && !CurrentPoison.HasFlag(PoisonType.Stun) && !CurrentPoison.HasFlag(PoisonType.Dazed) &&
  151. !CurrentPoison.HasFlag(PoisonType.Paralysis) && !CurrentPoison.HasFlag(PoisonType.Frozen) && Mount.CanAttack;
  152. }
  153. }
  154. protected bool CheckCellTime = true;
  155. public short TransformType;
  156. public short Looks_Armour = 0, Looks_Weapon = -1, Looks_WeaponEffect = 0;
  157. public byte Looks_Wings = 0;
  158. public int CurrentHandWeight,
  159. CurrentWearWeight,
  160. CurrentBagWeight;
  161. public bool HasElemental;
  162. public int ElementsLevel;
  163. public bool Stacking;
  164. public bool IsGM, GMNeverDie, GMGameMaster;
  165. public bool HasUpdatedBaseStats = true;
  166. public virtual int PotionBeltMinimum => 0;
  167. public virtual int PotionBeltMaximum => 4;
  168. public virtual int AmuletBeltMinimum => 4;
  169. public virtual int AmuletBeltMaximum => 6;
  170. public virtual int BeltSize => 6;
  171. public LevelEffects LevelEffects = LevelEffects.None;
  172. public const long LoyaltyDelay = 1000, ItemExpireDelay = 60000, DuraDelay = 10000, RegenDelay = 10000, PotDelay = 200, HealDelay = 600, VampDelay = 500, MoveDelay = 600;
  173. public long StruckTime, RunTime, ActionTime, AttackTime, RegenTime, SpellTime, StackingTime, IncreaseLoyaltyTime, ItemExpireTime, TorchTime, DuraTime, PotTime, HealTime, VampTime, LogTime, DecreaseLoyaltyTime, SearchTime;
  174. protected int _stepCounter, _runCounter;
  175. private GuildObject myGuild = null;
  176. public virtual GuildObject MyGuild
  177. {
  178. get { return myGuild; }
  179. set { myGuild = value; }
  180. }
  181. public GuildRank MyGuildRank = null;
  182. public IntelligentCreatureType SummonedCreatureType = IntelligentCreatureType.None;
  183. public bool CreatureSummoned;
  184. public SpecialItemMode SpecialMode;
  185. public List<ItemSets> ItemSets = new List<ItemSets>();
  186. public List<EquipmentSlot> MirSet = new List<EquipmentSlot>();
  187. public bool FatalSword, Slaying, TwinDrakeBlade, FlamingSword, MPEater, Hemorrhage, CounterAttack;
  188. public int MPEaterCount, HemorrhageAttackCount;
  189. public long FlamingSwordTime, CounterAttackTime;
  190. public bool ActiveBlizzard, ActiveReincarnation, ActiveSwiftFeet, ReincarnationReady;
  191. public HumanObject ReincarnationTarget, ReincarnationHost;
  192. public long ReincarnationExpireTime;
  193. public long LastRevivalTime;
  194. public float HpDrain = 0;
  195. public bool UnlockCurse = false;
  196. public bool FastRun = false;
  197. public bool CanGainExp = true;
  198. private int _fireWallCastSeq = 0;
  199. public override bool Blocking
  200. {
  201. get
  202. {
  203. return !Dead && !Observer;
  204. }
  205. }
  206. public HumanObject() { }
  207. public HumanObject(CharacterInfo info, MirConnection connection)
  208. {
  209. Load(info, connection);
  210. }
  211. protected virtual void Load(CharacterInfo info, MirConnection connection) { }
  212. protected virtual void NewCharacter()
  213. {
  214. Level = 1;
  215. Hair = (byte)Envir.Random.Next(0, 9);
  216. for (int i = 0; i < Envir.StartItems.Count; i++)
  217. {
  218. ItemInfo info = Envir.StartItems[i];
  219. if (!CorrectStartItem(info)) continue;
  220. AddItem(Envir.CreateFreshItem(info));
  221. }
  222. }
  223. public long GetDelayTime(long original)
  224. {
  225. if (CurrentPoison.HasFlag(PoisonType.Slow))
  226. {
  227. return original * 2;
  228. }
  229. return original;
  230. }
  231. public override void Process()
  232. {
  233. if ((Race == ObjectType.Player && Connection == null) || Node == null || Info == null) return;
  234. if (CellTime + 700 < Envir.Time) _stepCounter = 0;
  235. if (Sneaking) CheckSneakRadius();
  236. if (FlamingSword && Envir.Time >= FlamingSwordTime)
  237. {
  238. FlamingSword = false;
  239. Enqueue(new S.SpellToggle { ObjectID = ObjectID, Spell = Spell.FlamingSword, CanUse = false });
  240. }
  241. if (CounterAttack && Envir.Time >= CounterAttackTime)
  242. {
  243. CounterAttack = false;
  244. }
  245. if (ReincarnationReady && Envir.Time >= ReincarnationExpireTime)
  246. {
  247. ReincarnationReady = false;
  248. ActiveReincarnation = false;
  249. ReincarnationTarget = null;
  250. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.ReincarnationFailed), ChatType.System);
  251. }
  252. if ((ReincarnationReady || ActiveReincarnation) && (ReincarnationTarget == null || !ReincarnationTarget.Dead))
  253. {
  254. ReincarnationReady = false;
  255. ActiveReincarnation = false;
  256. ReincarnationTarget = null;
  257. }
  258. if (Envir.Time > RunTime && _runCounter > 0)
  259. {
  260. RunTime = Envir.Time + 1500;
  261. _runCounter--;
  262. }
  263. if (Stacking && Envir.Time > StackingTime)
  264. {
  265. Stacking = false;
  266. for (int i = 0; i < 8; i++)
  267. {
  268. if (Pushed(this, (MirDirection)i, 1) == 1) break;
  269. }
  270. }
  271. if (Mount.HasMount && Envir.Time > IncreaseLoyaltyTime)
  272. {
  273. IncreaseLoyaltyTime = Envir.Time + (LoyaltyDelay * 60);
  274. IncreaseMountLoyalty(1);
  275. }
  276. if (Envir.Time > ItemExpireTime)
  277. {
  278. ItemExpireTime = Envir.Time + ItemExpireDelay;
  279. ProcessItems();
  280. }
  281. for (int i = Pets.Count() - 1; i >= 0; i--)
  282. {
  283. MonsterObject pet = Pets[i];
  284. if (pet.Dead) Pets.Remove(pet);
  285. }
  286. ProcessBuffs();
  287. ProcessRegen();
  288. ProcessPoison();
  289. UserItem item;
  290. if (Envir.Time > TorchTime)
  291. {
  292. TorchTime = Envir.Time + 10000;
  293. item = Info.Equipment[(int)EquipmentSlot.Torch];
  294. if (item != null)
  295. {
  296. DamageItem(item, 5);
  297. if (item.CurrentDura == 0)
  298. {
  299. Info.Equipment[(int)EquipmentSlot.Torch] = null;
  300. Enqueue(new S.DeleteItem { UniqueID = item.UniqueID, Count = item.Count });
  301. RefreshStats();
  302. }
  303. }
  304. }
  305. if (Envir.Time > DuraTime)
  306. {
  307. DuraTime = Envir.Time + DuraDelay;
  308. for (int i = 0; i < Info.Equipment.Length; i++)
  309. {
  310. item = Info.Equipment[i];
  311. if (item == null || !item.DuraChanged) continue; // || item.Info.Type == ItemType.Mount
  312. item.DuraChanged = false;
  313. Enqueue(new S.DuraChanged { UniqueID = item.UniqueID, CurrentDura = item.CurrentDura });
  314. }
  315. }
  316. base.Process();
  317. RefreshNameColour();
  318. }
  319. public override void OnSafeZoneChanged()
  320. {
  321. base.OnSafeZoneChanged();
  322. bool needsUpdate = false;
  323. for (int i = 0; i < Buffs.Count; i++)
  324. {
  325. if (Buffs[i].ObjectID == 0) continue;
  326. if (!Buffs[i].Properties.HasFlag(BuffProperty.PauseInSafeZone)) continue;
  327. needsUpdate = true;
  328. if (InSafeZone)
  329. {
  330. PauseBuff(Buffs[i]);
  331. }
  332. else
  333. {
  334. UnpauseBuff(Buffs[i]);
  335. }
  336. }
  337. if (needsUpdate)
  338. {
  339. RefreshStats();
  340. }
  341. }
  342. public override void SetOperateTime()
  343. {
  344. OperateTime = Envir.Time;
  345. }
  346. public override void Die() { }
  347. protected virtual void ProcessBuffs()
  348. {
  349. bool refresh = false;
  350. bool clearRing = false, skill = false, gm = false, mentor = false, lover = false;
  351. for (int i = Buffs.Count - 1; i >= 0; i--)
  352. {
  353. Buff buff = Buffs[i];
  354. switch (buff.Type)
  355. {
  356. case BuffType.Concentration:
  357. if (buff.Get<bool>("Interrupted") && buff.Get<long>("InterruptTime") <= Envir.Time)
  358. {
  359. buff.Set("Interrupted", false);
  360. buff.Set("InterruptTime", (long)0);
  361. UpdateConcentration(true, false);
  362. }
  363. break;
  364. case BuffType.ClearRing:
  365. clearRing = true;
  366. if (!SpecialMode.HasFlag(SpecialItemMode.ClearRing)) buff.FlagForRemoval = true;
  367. break;
  368. case BuffType.Skill:
  369. skill = true;
  370. if (!SpecialMode.HasFlag(SpecialItemMode.Skill)) buff.FlagForRemoval = true;
  371. break;
  372. case BuffType.GameMaster:
  373. gm = true;
  374. if (!IsGM) buff.FlagForRemoval = true;
  375. break;
  376. case BuffType.Mentor:
  377. case BuffType.Mentee:
  378. mentor = true;
  379. if (Info.Mentor == 0) buff.FlagForRemoval = true;
  380. break;
  381. case BuffType.Lover:
  382. lover = true;
  383. if (Info.Married == 0) buff.FlagForRemoval = true;
  384. break;
  385. }
  386. if (buff.NextTime > Envir.Time) continue;
  387. if (!buff.Paused && buff.StackType != BuffStackType.Infinite)
  388. {
  389. var change = Envir.Time - buff.LastTime;
  390. buff.ExpireTime -= change;
  391. }
  392. buff.LastTime = Envir.Time;
  393. buff.NextTime = Envir.Time + 1000;
  394. if ((buff.ExpireTime > 0 || buff.StackType == BuffStackType.Infinite) && !buff.FlagForRemoval) continue;
  395. Buffs.RemoveAt(i);
  396. Enqueue(new S.RemoveBuff { Type = buff.Type, ObjectID = ObjectID });
  397. if (buff.Info.Visible)
  398. {
  399. Broadcast(new S.RemoveBuff { Type = buff.Type, ObjectID = ObjectID });
  400. }
  401. switch (buff.Type)
  402. {
  403. case BuffType.Hiding:
  404. case BuffType.MoonLight:
  405. case BuffType.DarkBody:
  406. case BuffType.ClearRing:
  407. if (!HasAnyBuffs(buff.Type, BuffType.ClearRing, BuffType.Hiding, BuffType.MoonLight, BuffType.DarkBody))
  408. {
  409. Hidden = false;
  410. }
  411. if (buff.Type == BuffType.MoonLight || buff.Type == BuffType.DarkBody)
  412. {
  413. if (!HasAnyBuffs(buff.Type, BuffType.MoonLight, BuffType.DarkBody))
  414. {
  415. Sneaking = false;
  416. }
  417. break;
  418. }
  419. break;
  420. case BuffType.Concentration:
  421. UpdateConcentration(false, false);
  422. break;
  423. case BuffType.SwiftFeet:
  424. ActiveSwiftFeet = false;
  425. break;
  426. case BuffType.MagicShield:
  427. CurrentMap.Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.MagicShieldDown }, CurrentLocation);
  428. break;
  429. case BuffType.ElementalBarrier:
  430. CurrentMap.Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.ElementalBarrierDown }, CurrentLocation);
  431. break;
  432. }
  433. refresh = true;
  434. }
  435. if (IsGM && !gm)
  436. {
  437. UpdateGMBuff();
  438. }
  439. if (SpecialMode.HasFlag(SpecialItemMode.ClearRing) && !clearRing)
  440. {
  441. AddBuff(BuffType.ClearRing, this, 0, new Stats());
  442. }
  443. if (SpecialMode.HasFlag(SpecialItemMode.Skill) && !skill)
  444. {
  445. AddBuff(BuffType.Skill, this, 0, new Stats { [Stat.SkillGainMultiplier] = 3 }, false);
  446. }
  447. if (Info.Mentor != 0 && !mentor)
  448. {
  449. CharacterInfo partnerC = Envir.GetCharacterInfo(Info.Mentor);
  450. PlayerObject partnerP = partnerC != null ? Envir.GetPlayer(partnerC.Name) : null;
  451. if (partnerP != null)
  452. {
  453. if (Info.IsMentor)
  454. {
  455. AddBuff(BuffType.Mentor, partnerP, 0, new Stats { [Stat.MentorDamageRatePercent] = Settings.MentorDamageBoost });
  456. }
  457. else
  458. {
  459. AddBuff(BuffType.Mentee, partnerP, 0, new Stats { [Stat.MentorExpRatePercent] = Settings.MentorExpBoost });
  460. }
  461. }
  462. }
  463. if (Info.Married != 0 && !lover)
  464. {
  465. CharacterInfo loverC = Envir.GetCharacterInfo(Info.Married);
  466. PlayerObject loverP = loverC != null ? Envir.GetPlayer(loverC.Name) : null;
  467. if (loverP != null)
  468. {
  469. AddBuff(BuffType.Lover, loverP, 0, new Stats { [Stat.LoverExpRatePercent] = Settings.LoverEXPBonus });
  470. }
  471. }
  472. if (MyGuild != null && MyGuild.Name == Settings.NewbieGuild && Settings.NewbieGuildBuffEnabled == true)
  473. {
  474. AddBuff(BuffType.Newbie, this, 0, new Stats { [Stat.ExpRatePercent] = Settings.NewbieGuildExpBuff });
  475. }
  476. if (refresh)
  477. {
  478. RefreshStats();
  479. }
  480. }
  481. private void ProcessRegen()
  482. {
  483. if (Dead) return;
  484. int healthRegen = 0, manaRegen = 0;
  485. if (CanRegen)
  486. {
  487. RegenTime = Envir.Time + RegenDelay;
  488. if (HP < Stats[Stat.HP])
  489. {
  490. healthRegen += (int)(Stats[Stat.HP] * 0.03F) + 1;
  491. healthRegen += (int)(healthRegen * ((double)Stats[Stat.HealthRecovery] / Settings.HealthRegenWeight));
  492. }
  493. if (MP < Stats[Stat.MP])
  494. {
  495. manaRegen += (int)(Stats[Stat.MP] * 0.03F) + 1;
  496. manaRegen += (int)(manaRegen * ((double)Stats[Stat.SpellRecovery] / Settings.ManaRegenWeight));
  497. }
  498. }
  499. if (Envir.Time > PotTime)
  500. {
  501. //PotTime = Envir.Time + Math.Max(50,Math.Min(PotDelay, 600 - (Level * 10)));
  502. PotTime = Envir.Time + PotDelay;
  503. int PerTickRegen = 5 + (Level / 10);
  504. if (PotHealthAmount > PerTickRegen)
  505. {
  506. healthRegen += PerTickRegen;
  507. PotHealthAmount -= (ushort)PerTickRegen;
  508. }
  509. else
  510. {
  511. healthRegen += PotHealthAmount;
  512. PotHealthAmount = 0;
  513. }
  514. if (PotManaAmount > PerTickRegen)
  515. {
  516. manaRegen += PerTickRegen;
  517. PotManaAmount -= (ushort)PerTickRegen;
  518. }
  519. else
  520. {
  521. manaRegen += PotManaAmount;
  522. PotManaAmount = 0;
  523. }
  524. }
  525. if (Envir.Time > HealTime)
  526. {
  527. HealTime = Envir.Time + HealDelay;
  528. int incHeal = (Level / 10) + (HealAmount / 10);
  529. if (HealAmount > (5 + incHeal))
  530. {
  531. healthRegen += (5 + incHeal);
  532. HealAmount -= (ushort)Math.Min(HealAmount, 5 + incHeal);
  533. }
  534. else
  535. {
  536. healthRegen += HealAmount;
  537. HealAmount = 0;
  538. }
  539. }
  540. if (Envir.Time > VampTime)
  541. {
  542. VampTime = Envir.Time + VampDelay;
  543. if (VampAmount > 10)
  544. {
  545. healthRegen += 10;
  546. VampAmount -= 10;
  547. }
  548. else
  549. {
  550. healthRegen += VampAmount;
  551. VampAmount = 0;
  552. }
  553. }
  554. if (healthRegen > 0)
  555. {
  556. ChangeHP(healthRegen);
  557. BroadcastDamageIndicator(DamageType.Hit, healthRegen);
  558. }
  559. if (HP == Stats[Stat.HP])
  560. {
  561. PotHealthAmount = 0;
  562. HealAmount = 0;
  563. }
  564. if (manaRegen > 0) ChangeMP(manaRegen);
  565. if (MP == Stats[Stat.MP]) PotManaAmount = 0;
  566. }
  567. private void ProcessPoison()
  568. {
  569. PoisonType type = PoisonType.None;
  570. ArmourRate = 1F;
  571. DamageRate = 1F;
  572. for (int i = PoisonList.Count - 1; i >= 0; i--)
  573. {
  574. if (Dead) return;
  575. Poison poison = PoisonList[i];
  576. if (poison.Owner != null && poison.Owner.Node == null)
  577. {
  578. PoisonList.RemoveAt(i);
  579. continue;
  580. }
  581. if (Envir.Time > poison.TickTime)
  582. {
  583. poison.Time++;
  584. poison.TickTime = Envir.Time + poison.TickSpeed;
  585. if (poison.Time >= poison.Duration)
  586. {
  587. PoisonList.RemoveAt(i);
  588. }
  589. if (poison.PType == PoisonType.Green || poison.PType == PoisonType.Bleeding)
  590. {
  591. LastHitter = poison.Owner;
  592. LastHitTime = Envir.Time + 10000;
  593. if (poison.PType == PoisonType.Bleeding)
  594. {
  595. Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.Bleeding, EffectType = 0 });
  596. }
  597. PoisonDamage(-poison.Value, poison.Owner);
  598. BroadcastDamageIndicator(DamageType.Hit, -poison.Value);
  599. if (Dead) break;
  600. RegenTime = Envir.Time + RegenDelay;
  601. }
  602. if (poison.PType == PoisonType.DelayedExplosion)
  603. {
  604. if (Envir.Time > ExplosionInflictedTime) ExplosionInflictedStage++;
  605. if (!ProcessDelayedExplosion(poison))
  606. {
  607. if (Dead) break;
  608. ExplosionInflictedStage = 0;
  609. ExplosionInflictedTime = 0;
  610. PoisonList.RemoveAt(i);
  611. continue;
  612. }
  613. }
  614. }
  615. switch (poison.PType)
  616. {
  617. case PoisonType.Red:
  618. ArmourRate -= 0.10F;
  619. break;
  620. case PoisonType.Stun:
  621. DamageRate += 0.20F;
  622. break;
  623. case PoisonType.Blindness:
  624. break;
  625. }
  626. type |= poison.PType;
  627. }
  628. if (type == CurrentPoison) return;
  629. Enqueue(new S.Poisoned { Poison = type });
  630. Broadcast(new S.ObjectPoisoned { ObjectID = ObjectID, Poison = type });
  631. CurrentPoison = type;
  632. }
  633. private bool ProcessDelayedExplosion(Poison poison)
  634. {
  635. if (Dead) return false;
  636. if (ExplosionInflictedStage == 0)
  637. {
  638. Enqueue(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.DelayedExplosion, EffectType = 0 });
  639. Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.DelayedExplosion, EffectType = 0 });
  640. return true;
  641. }
  642. if (ExplosionInflictedStage == 1)
  643. {
  644. if (Envir.Time > ExplosionInflictedTime)
  645. ExplosionInflictedTime = poison.TickTime + 3000;
  646. Enqueue(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.DelayedExplosion, EffectType = 1 });
  647. Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.DelayedExplosion, EffectType = 1 });
  648. return true;
  649. }
  650. if (ExplosionInflictedStage == 2)
  651. {
  652. Enqueue(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.DelayedExplosion, EffectType = 2 });
  653. Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.DelayedExplosion, EffectType = 2 });
  654. if (poison.Owner != null)
  655. {
  656. switch (poison.Owner.Race)
  657. {
  658. case ObjectType.Player:
  659. PlayerObject caster = (PlayerObject)poison.Owner;
  660. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time, poison.Owner, caster.GetMagic(Spell.DelayedExplosion), poison.Value, this.CurrentLocation);
  661. CurrentMap.ActionList.Add(action);
  662. break;
  663. case ObjectType.Monster://this is in place so it could be used by mobs if one day someone chooses to
  664. Attacked((MonsterObject)poison.Owner, poison.Value, DefenceType.MAC);
  665. break;
  666. }
  667. LastHitter = poison.Owner;
  668. }
  669. return false;
  670. }
  671. return false;
  672. }
  673. private void ProcessItems()
  674. {
  675. for (var i = 0; i < Info.Inventory.Length; i++)
  676. {
  677. var item = Info.Inventory[i];
  678. if (item?.ExpireInfo?.ExpiryDate <= Envir.Now)
  679. {
  680. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.ItemHasExpiredFromInventory), item.Info.FriendlyName), ChatType.Hint);
  681. Enqueue(new S.DeleteItem { UniqueID = item.UniqueID, Count = item.Count });
  682. Info.Inventory[i] = null;
  683. continue;
  684. }
  685. if (item?.RentalInformation?.RentalLocked == true && item?.RentalInformation?.ExpiryDate <= Envir.Now)
  686. {
  687. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.RentalLockRemovedFrom), item.Info.FriendlyName), ChatType.Hint);
  688. item.RentalInformation = null;
  689. }
  690. }
  691. for (var i = 0; i < Info.Equipment.Length; i++)
  692. {
  693. var item = Info.Equipment[i];
  694. if (item?.ExpireInfo?.ExpiryDate <= Envir.Now)
  695. {
  696. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.EquipmentExpired), item.Info.FriendlyName), ChatType.Hint);
  697. Enqueue(new S.DeleteItem { UniqueID = item.UniqueID, Count = item.Count });
  698. Info.Equipment[i] = null;
  699. continue;
  700. }
  701. if (item?.RentalInformation?.RentalLocked == true && item?.RentalInformation?.ExpiryDate <= Envir.Now)
  702. {
  703. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.RentalLockRemovedFrom), item.Info.FriendlyName), ChatType.Hint);
  704. item.RentalInformation = null;
  705. }
  706. }
  707. if (Info.AccountInfo == null) return;
  708. for (int i = 0; i < Info.AccountInfo.Storage.Length; i++)
  709. {
  710. var item = Info.AccountInfo.Storage[i];
  711. if (item?.ExpireInfo?.ExpiryDate <= Envir.Now)
  712. {
  713. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.ItemExpiredFromStorage), item.Info.FriendlyName), ChatType.Hint);
  714. Enqueue(new S.DeleteItem { UniqueID = item.UniqueID, Count = item.Count });
  715. Info.AccountInfo.Storage[i] = null;
  716. continue;
  717. }
  718. }
  719. }
  720. public override void Process(DelayedAction action)
  721. {
  722. }
  723. protected void UpdateGMBuff()
  724. {
  725. if (!IsGM) return;
  726. GMOptions options = GMOptions.None;
  727. if (GMGameMaster) options |= GMOptions.GameMaster;
  728. if (GMNeverDie) options |= GMOptions.Superman;
  729. if (Observer) options |= GMOptions.Observer;
  730. AddBuff(BuffType.GameMaster, this, 0, null, false, values: (byte)options);
  731. }
  732. public virtual void LevelUp()
  733. {
  734. RefreshStats();
  735. SetHP(Stats[Stat.HP]);
  736. SetMP(Stats[Stat.MP]);
  737. Broadcast(new S.ObjectLeveled { ObjectID = ObjectID });
  738. }
  739. public virtual Color GetNameColour(HumanObject human)
  740. {
  741. return NameColour;
  742. }
  743. public virtual void RefreshNameColour() { }
  744. protected void SetHP(int amount)
  745. {
  746. if (HP == amount) return;
  747. HP = amount <= Stats[Stat.HP] ? amount : Stats[Stat.HP];
  748. HP = GMNeverDie ? Stats[Stat.HP] : HP;
  749. if (!Dead && HP == 0) Die();
  750. //HealthChanged = true;
  751. SendHealthChanged();
  752. }
  753. protected virtual void SendHealthChanged()
  754. {
  755. Enqueue(new S.HealthChanged { HP = HP, MP = MP });
  756. BroadcastHealthChange();
  757. }
  758. protected void SetMP(int amount)
  759. {
  760. if (MP == amount) return;
  761. //was info.MP
  762. MP = amount <= Stats[Stat.MP] ? amount : Stats[Stat.MP];
  763. MP = GMNeverDie ? Stats[Stat.MP] : MP;
  764. // HealthChanged = true;
  765. SendHealthChanged();
  766. }
  767. public void ChangeHP(int amount)
  768. {
  769. if (SpecialMode.HasFlag(SpecialItemMode.Protection) && MP > 0 && amount < 0)
  770. {
  771. ChangeMP(amount);
  772. return;
  773. }
  774. if (HP + amount > Stats[Stat.HP])
  775. amount = Stats[Stat.HP] - HP;
  776. if (amount == 0) return;
  777. HP += amount;
  778. HP = GMNeverDie ? Stats[Stat.HP] : HP;
  779. if (HP < 0) HP = 0;
  780. if (!Dead && HP == 0) Die();
  781. // HealthChanged = true;
  782. SendHealthChanged();
  783. }
  784. public void PoisonDamage(int amount, MapObject Attacker)
  785. {
  786. ChangeHP(amount);
  787. }
  788. public void ChangeMP(int amount)
  789. {
  790. if (MP + amount > Stats[Stat.MP])
  791. amount = Stats[Stat.MP] - MP;
  792. if (amount == 0) return;
  793. MP += amount;
  794. MP = GMNeverDie ? Stats[Stat.MP] : MP;
  795. if (MP < 0) MP = 0;
  796. // HealthChanged = true;
  797. SendHealthChanged();
  798. }
  799. public void GetMinePayout(MineSet Mine)
  800. {
  801. if ((Mine.Drops == null) || (Mine.Drops.Count == 0)) return;
  802. if (FreeSpace(Info.Inventory) == 0) return;
  803. byte Slot = (byte)Envir.Random.Next(Mine.TotalSlots);
  804. for (int i = 0; i < Mine.Drops.Count; i++)
  805. {
  806. MineDrop Drop = Mine.Drops[i];
  807. if ((Drop.MinSlot <= Slot) && (Drop.MaxSlot >= Slot) && (Drop.Item != null))
  808. {
  809. var info = Envir.GetItemInfo(Drop.Item.Index);
  810. UserItem item = Envir.CreateDropItem(info);
  811. if (item.Info.Type == ItemType.Ore)
  812. {
  813. item.CurrentDura = (ushort)Math.Min(ushort.MaxValue, (Drop.MinDura + Envir.Random.Next(Math.Max(0, Drop.MaxDura - Drop.MinDura))) * 1000);
  814. if ((Drop.BonusChance > 0) && (Envir.Random.Next(100) <= Drop.BonusChance))
  815. item.CurrentDura = (ushort)Math.Min(ushort.MaxValue, item.CurrentDura + (Envir.Random.Next(Drop.MaxBonusDura) * 1000));
  816. }
  817. if (CheckGroupQuestItem(item)) continue;
  818. if (CanGainItem(item))
  819. {
  820. GainItem(item);
  821. Report.ItemChanged(item, item.Count, 2);
  822. }
  823. return;
  824. }
  825. }
  826. }
  827. public virtual bool CheckGroupQuestItem(UserItem item, bool gainItem = true)
  828. {
  829. return false;
  830. }
  831. protected bool TryLuckWeapon()
  832. {
  833. var item = Info.Equipment[(int)EquipmentSlot.Weapon];
  834. if (item == null || item.AddedStats[Stat.Luck] >= 7)
  835. return false;
  836. if (item.Info.Bind.HasFlag(BindMode.DontUpgrade))
  837. return false;
  838. if (item.RentalInformation != null && item.RentalInformation.BindingFlags.HasFlag(BindMode.DontUpgrade))
  839. return false;
  840. string message = String.Empty;
  841. ChatType chatType;
  842. if (item.AddedStats[Stat.Luck] > (Settings.MaxLuck * -1) && Envir.Random.Next(20) == 0)
  843. {
  844. Stats[Stat.Luck]--;
  845. item.AddedStats[Stat.Luck]--;
  846. Enqueue(new S.RefreshItem { Item = item });
  847. message = GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.WeaponCurse);
  848. chatType = ChatType.System;
  849. }
  850. else if (item.AddedStats[Stat.Luck] <= 0 || Envir.Random.Next(10 * item.GetTotal(Stat.Luck)) == 0)
  851. {
  852. Stats[Stat.Luck]++;
  853. item.AddedStats[Stat.Luck]++;
  854. Enqueue(new S.RefreshItem { Item = item });
  855. message = GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.WeaponLuck);
  856. chatType = ChatType.Hint;
  857. }
  858. else
  859. {
  860. message = GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.WeaponNoEffect);
  861. chatType = ChatType.Hint;
  862. }
  863. if (this is HeroObject hero)
  864. {
  865. if (message == GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.WeaponCurse) ||
  866. message == GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.WeaponLuck))
  867. {
  868. hero.Owner.Enqueue(new S.RefreshItem { Item = item });
  869. }
  870. hero.Owner.ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.HeroOwnerReceiveChat), hero.Name, message), chatType);
  871. }
  872. else
  873. {
  874. ReceiveChat(message, chatType);
  875. }
  876. return true;
  877. }
  878. protected bool CanUseItem(UserItem item)
  879. {
  880. if (item == null) return false;
  881. switch (Gender)
  882. {
  883. case MirGender.Male:
  884. if (!item.Info.RequiredGender.HasFlag(RequiredGender.Male))
  885. {
  886. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.NotFemale), ChatType.System);
  887. return false;
  888. }
  889. break;
  890. case MirGender.Female:
  891. if (!item.Info.RequiredGender.HasFlag(RequiredGender.Female))
  892. {
  893. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.NotMale), ChatType.System);
  894. return false;
  895. }
  896. break;
  897. }
  898. switch (Class)
  899. {
  900. case MirClass.Warrior:
  901. if (!item.Info.RequiredClass.HasFlag(RequiredClass.Warrior))
  902. {
  903. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.WarriorsCannotUseItem), ChatType.System);
  904. return false;
  905. }
  906. break;
  907. case MirClass.Wizard:
  908. if (!item.Info.RequiredClass.HasFlag(RequiredClass.Wizard))
  909. {
  910. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.WizardsCannotUseItem), ChatType.System);
  911. return false;
  912. }
  913. break;
  914. case MirClass.Taoist:
  915. if (!item.Info.RequiredClass.HasFlag(RequiredClass.Taoist))
  916. {
  917. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.TaoistsCannotUseItem), ChatType.System);
  918. return false;
  919. }
  920. break;
  921. case MirClass.Assassin:
  922. if (!item.Info.RequiredClass.HasFlag(RequiredClass.Assassin))
  923. {
  924. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.AssassinsCannotUseItem), ChatType.System);
  925. return false;
  926. }
  927. break;
  928. case MirClass.Archer:
  929. if (!item.Info.RequiredClass.HasFlag(RequiredClass.Archer))
  930. {
  931. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.ArchersCannotUseItem), ChatType.System);
  932. return false;
  933. }
  934. break;
  935. }
  936. switch (item.Info.RequiredType)
  937. {
  938. case RequiredType.Level:
  939. if (Level < item.Info.RequiredAmount)
  940. {
  941. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.LowLevel), ChatType.System);
  942. return false;
  943. }
  944. break;
  945. case RequiredType.MaxAC:
  946. if (Stats[Stat.MaxAC] < item.Info.RequiredAmount)
  947. {
  948. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouNotEnoughAC), ChatType.System);
  949. return false;
  950. }
  951. break;
  952. case RequiredType.MaxMAC:
  953. if (Stats[Stat.MaxMAC] < item.Info.RequiredAmount)
  954. {
  955. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouNotEnoughMAC), ChatType.System);
  956. return false;
  957. }
  958. break;
  959. case RequiredType.MaxDC:
  960. if (Stats[Stat.MaxDC] < item.Info.RequiredAmount)
  961. {
  962. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.LowDC), ChatType.System);
  963. return false;
  964. }
  965. break;
  966. case RequiredType.MaxMC:
  967. if (Stats[Stat.MaxMC] < item.Info.RequiredAmount)
  968. {
  969. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.LowMC), ChatType.System);
  970. return false;
  971. }
  972. break;
  973. case RequiredType.MaxSC:
  974. if (Stats[Stat.MaxSC] < item.Info.RequiredAmount)
  975. {
  976. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.LowSC), ChatType.System);
  977. return false;
  978. }
  979. break;
  980. case RequiredType.MaxLevel:
  981. if (Level > item.Info.RequiredAmount)
  982. {
  983. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouExceededMaxLevel), ChatType.System);
  984. return false;
  985. }
  986. break;
  987. case RequiredType.MinAC:
  988. if (Stats[Stat.MinAC] < item.Info.RequiredAmount)
  989. {
  990. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouNoBaseAC), ChatType.System);
  991. return false;
  992. }
  993. break;
  994. case RequiredType.MinMAC:
  995. if (Stats[Stat.MinMAC] < item.Info.RequiredAmount)
  996. {
  997. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouNoBaseMAC), ChatType.System);
  998. return false;
  999. }
  1000. break;
  1001. case RequiredType.MinDC:
  1002. if (Stats[Stat.MinDC] < item.Info.RequiredAmount)
  1003. {
  1004. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouNoBaseDC), ChatType.System);
  1005. return false;
  1006. }
  1007. break;
  1008. case RequiredType.MinMC:
  1009. if (Stats[Stat.MinMC] < item.Info.RequiredAmount)
  1010. {
  1011. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouNoBaseMC), ChatType.System);
  1012. return false;
  1013. }
  1014. break;
  1015. case RequiredType.MinSC:
  1016. if (Stats[Stat.MinSC] < item.Info.RequiredAmount)
  1017. {
  1018. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouNoBaseSC), ChatType.System);
  1019. return false;
  1020. }
  1021. break;
  1022. }
  1023. switch (item.Info.Type)
  1024. {
  1025. case ItemType.Scroll:
  1026. switch (item.Info.Shape)
  1027. {
  1028. case 0:
  1029. if (CurrentMap.Info.NoEscape)
  1030. {
  1031. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.CanNotDungeon), ChatType.System);
  1032. return false;
  1033. }
  1034. break;
  1035. case 1:
  1036. if (CurrentMap.Info.NoTownTeleport)
  1037. {
  1038. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.NoTownTeleport), ChatType.System);
  1039. return false;
  1040. }
  1041. break;
  1042. case 2:
  1043. if (CurrentMap.Info.NoRandom)
  1044. {
  1045. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.CanNotRandom), ChatType.System);
  1046. return false;
  1047. }
  1048. break;
  1049. case 6:
  1050. if (!Dead)
  1051. {
  1052. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.CannotResurrection), ChatType.Hint);
  1053. return false;
  1054. }
  1055. break;
  1056. case 10:
  1057. {
  1058. int skillId = item.Info.Effect;
  1059. if (MyGuild == null)
  1060. {
  1061. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouMustBeInGuildToUseSkill), ChatType.Hint);
  1062. return false;
  1063. }
  1064. if (MyGuildRank != MyGuild.Ranks[0])
  1065. {
  1066. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouMustBeGuildLeaderToUseSkill), ChatType.Hint);
  1067. return false;
  1068. }
  1069. GuildBuffInfo buffInfo = Envir.FindGuildBuffInfo(skillId);
  1070. if (buffInfo == null) return false;
  1071. if (MyGuild.BuffList.Any(e => e.Info.Id == skillId))
  1072. {
  1073. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YourGuildAlreadyHasSkill), ChatType.Hint);
  1074. return false;
  1075. }
  1076. }
  1077. break;
  1078. }
  1079. break;
  1080. case ItemType.Potion:
  1081. if (CurrentMap.Info.NoDrug)
  1082. {
  1083. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouCannotUsePotionsHere), ChatType.System);
  1084. return false;
  1085. }
  1086. break;
  1087. case ItemType.Book:
  1088. if (Info.Magics.Any(t => t.Spell == (Spell)item.Info.Shape))
  1089. {
  1090. return false;
  1091. }
  1092. break;
  1093. case ItemType.Saddle:
  1094. case ItemType.Ribbon:
  1095. case ItemType.Bells:
  1096. case ItemType.Mask:
  1097. case ItemType.Reins:
  1098. if (Info.Equipment[(int)EquipmentSlot.Mount] == null)
  1099. {
  1100. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.CanOnlyUseWithMount), ChatType.System);
  1101. return false;
  1102. }
  1103. break;
  1104. case ItemType.Hook:
  1105. case ItemType.Float:
  1106. case ItemType.Bait:
  1107. case ItemType.Finder:
  1108. case ItemType.Reel:
  1109. if (Info.Equipment[(int)EquipmentSlot.Weapon] == null || !Info.Equipment[(int)EquipmentSlot.Weapon].Info.IsFishingRod)
  1110. {
  1111. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.CanOnlyUseWithFishingRod), ChatType.System);
  1112. return false;
  1113. }
  1114. break;
  1115. case ItemType.Socket:
  1116. break;
  1117. case ItemType.Pets:
  1118. switch (item.Info.Shape)
  1119. {
  1120. case 20://mirror rename creature
  1121. if (Info.IntelligentCreatures.Count == 0) return false;
  1122. break;
  1123. case 21://creature stone
  1124. break;
  1125. case 22://nuts maintain food levels
  1126. if (!CreatureSummoned)
  1127. {
  1128. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.CanUseWithSummonedCreature), ChatType.System);
  1129. return false;
  1130. }
  1131. break;
  1132. case 23://basic creature food
  1133. if (!CreatureSummoned)
  1134. {
  1135. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.CanUseWithSummonedCreature), ChatType.System);
  1136. return false;
  1137. }
  1138. else
  1139. {
  1140. for (int i = 0; i < Pets.Count; i++)
  1141. {
  1142. if (Pets[i].Race != ObjectType.Creature) continue;
  1143. var pet = (IntelligentCreatureObject)Pets[i];
  1144. if (pet.PetType != SummonedCreatureType) continue;
  1145. if (pet.Fullness > 9900)
  1146. {
  1147. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.PetIsNotHungry), pet.Name), ChatType.System);
  1148. return false;
  1149. }
  1150. return true;
  1151. }
  1152. return false;
  1153. }
  1154. case 24://wonderpill vitalize creature
  1155. if (!CreatureSummoned)
  1156. {
  1157. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.CanUseWithSummonedCreature), ChatType.System);
  1158. return false;
  1159. }
  1160. else
  1161. {
  1162. for (int i = 0; i < Pets.Count; i++)
  1163. {
  1164. if (Pets[i].Race != ObjectType.Creature) continue;
  1165. var pet = (IntelligentCreatureObject)Pets[i];
  1166. if (pet.PetType != SummonedCreatureType) continue;
  1167. if (pet.Fullness > 0)
  1168. {
  1169. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.PetDoesNotNeedVitalize), pet.Name), ChatType.System);
  1170. return false;
  1171. }
  1172. return true;
  1173. }
  1174. return false;
  1175. }
  1176. case 25://Strongbox
  1177. break;
  1178. case 26://Wonderdrugs
  1179. break;
  1180. case 27://Fortunecookies
  1181. break;
  1182. }
  1183. break;
  1184. }
  1185. if (RidingMount && item.Info.Type != ItemType.Scroll && item.Info.Type != ItemType.Potion)
  1186. {
  1187. return false;
  1188. }
  1189. return true;
  1190. }
  1191. public virtual void UseItem(ulong id) { }
  1192. protected void ConsumeItem(UserItem item, byte cost)
  1193. {
  1194. item.Count -= cost;
  1195. Enqueue(new S.DeleteItem { UniqueID = item.UniqueID, Count = cost });
  1196. if (item.Count != 0) return;
  1197. for (int i = 0; i < Info.Equipment.Length; i++)
  1198. {
  1199. if (Info.Equipment[i] != null && Info.Equipment[i].Slots.Length > 0)
  1200. {
  1201. for (int j = 0; j < Info.Equipment[i].Slots.Length; j++)
  1202. {
  1203. if (Info.Equipment[i].Slots[j] != item) continue;
  1204. Info.Equipment[i].Slots[j] = null;
  1205. return;
  1206. }
  1207. }
  1208. if (Info.Equipment[i] != item) continue;
  1209. Info.Equipment[i] = null;
  1210. return;
  1211. }
  1212. for (int i = 0; i < Info.Inventory.Length; i++)
  1213. {
  1214. if (Info.Inventory[i] != item) continue;
  1215. Info.Inventory[i] = null;
  1216. return;
  1217. }
  1218. //Item not found
  1219. }
  1220. protected bool DropItem(UserItem item, int range = 1, bool DeathDrop = false)
  1221. {
  1222. ItemObject ob = new ItemObject(this, item, DeathDrop);
  1223. if (!ob.Drop(range)) return false;
  1224. if (item.Info.Type == ItemType.Meat)
  1225. item.CurrentDura = (ushort)Math.Max(0, item.CurrentDura - 2000);
  1226. return true;
  1227. }
  1228. protected void DeathDrop(MapObject killer)
  1229. {
  1230. var pkbodydrop = true;
  1231. if (CurrentMap.Info.NoDropPlayer && (Race == ObjectType.Player || Race == ObjectType.Hero))
  1232. return;
  1233. if ((killer == null) || ((pkbodydrop) || (killer.Race != ObjectType.Player) || killer.Race != ObjectType.Hero))
  1234. {
  1235. for (var i = 0; i < Info.Equipment.Length; i++)
  1236. {
  1237. var item = Info.Equipment[i];
  1238. if (item == null)
  1239. continue;
  1240. if (item.Info.Bind.HasFlag(BindMode.DontDeathdrop))
  1241. continue;
  1242. // TODO: Check this.
  1243. if (item.WeddingRing != -1 && Info.Equipment[(int)EquipmentSlot.RingL].UniqueID == item.UniqueID)
  1244. continue;
  1245. if (item.SealedInfo != null && item.SealedInfo.ExpiryDate > Envir.Now)
  1246. continue;
  1247. if (((killer == null) || ((killer != null) && ((killer.Race != ObjectType.Player) || (killer.Race != ObjectType.Hero)))))
  1248. {
  1249. if (item.Info.Bind.HasFlag(BindMode.BreakOnDeath))
  1250. {
  1251. Info.Equipment[i] = null;
  1252. Enqueue(new S.DeleteItem { UniqueID = item.UniqueID, Count = item.Count });
  1253. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.YourItemShatteredUponDeath), item.FriendlyName), ChatType.System2);
  1254. Report?.ItemChanged(item, item.Count, 1);
  1255. }
  1256. }
  1257. if (ItemSets.Any(set => set.Set == ItemSet.Spirit && !set.SetComplete))
  1258. {
  1259. if (item.Info.Set == ItemSet.Spirit)
  1260. {
  1261. Info.Equipment[i] = null;
  1262. Enqueue(new S.DeleteItem { UniqueID = item.UniqueID, Count = item.Count });
  1263. Report?.ItemChanged(item, item.Count, 1);
  1264. }
  1265. }
  1266. if (item.Count > 1)
  1267. {
  1268. var percent = Envir.RandomomRange(10, 8);
  1269. var count = (ushort)Math.Ceiling(item.Count / 10F * percent);
  1270. if (count > item.Count)
  1271. throw new ArgumentOutOfRangeException();
  1272. var temp2 = Envir.CreateFreshItem(item.Info);
  1273. temp2.Count = count;
  1274. if (!DropItem(temp2, Settings.DropRange, true))
  1275. continue;
  1276. if (count == item.Count)
  1277. Info.Equipment[i] = null;
  1278. Enqueue(new S.DeleteItem { UniqueID = item.UniqueID, Count = count });
  1279. item.Count -= count;
  1280. Report?.ItemChanged(item, count, 1);
  1281. }
  1282. else if (Envir.Random.Next(30) == 0)
  1283. {
  1284. if (Envir.ReturnRentalItem(item, item.RentalInformation?.OwnerName, Info))
  1285. {
  1286. Info.Equipment[i] = null;
  1287. Enqueue(new S.DeleteItem { UniqueID = item.UniqueID, Count = item.Count });
  1288. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.YouDiedItemReturnedOwner), item.Info.FriendlyName), ChatType.Hint);
  1289. Report?.ItemMailed(item, 1, 1);
  1290. continue;
  1291. }
  1292. if (!DropItem(item, Settings.DropRange, true))
  1293. {
  1294. continue;
  1295. }
  1296. if (item.Info.GlobalDropNotify)
  1297. {
  1298. foreach (var player in Envir.Players)
  1299. {
  1300. player.ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.PlayerHasDroppedItem), Name, item.FriendlyName), ChatType.System2);
  1301. }
  1302. }
  1303. Info.Equipment[i] = null;
  1304. Enqueue(new S.DeleteItem { UniqueID = item.UniqueID, Count = item.Count });
  1305. Report?.ItemChanged(item, item.Count, 1);
  1306. }
  1307. }
  1308. }
  1309. for (var i = 0; i < Info.Inventory.Length; i++)
  1310. {
  1311. var item = Info.Inventory[i];
  1312. if (item == null)
  1313. continue;
  1314. if (item.Info.Bind.HasFlag(BindMode.DontDeathdrop))
  1315. continue;
  1316. if (item.WeddingRing != -1)
  1317. continue;
  1318. if (item.SealedInfo != null && item.SealedInfo.ExpiryDate > Envir.Now)
  1319. continue;
  1320. if (item.Count > 1)
  1321. {
  1322. var percent = Envir.RandomomRange(10, 8);
  1323. if (percent == 0)
  1324. continue;
  1325. var count = (ushort)Math.Ceiling(item.Count / 10F * percent);
  1326. if (count > item.Count)
  1327. throw new ArgumentOutOfRangeException();
  1328. var temp2 = Envir.CreateFreshItem(item.Info);
  1329. temp2.Count = count;
  1330. if (!DropItem(temp2, Settings.DropRange, true))
  1331. continue;
  1332. if (count == item.Count)
  1333. Info.Inventory[i] = null;
  1334. Enqueue(new S.DeleteItem { UniqueID = item.UniqueID, Count = count });
  1335. item.Count -= count;
  1336. Report?.ItemChanged(item, count, 1);
  1337. }
  1338. else if (Envir.Random.Next(10) == 0)
  1339. {
  1340. if (Envir.ReturnRentalItem(item, item.RentalInformation?.OwnerName, Info))
  1341. {
  1342. Info.Inventory[i] = null;
  1343. Enqueue(new S.DeleteItem { UniqueID = item.UniqueID, Count = item.Count });
  1344. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.PlayerDiedItemReturnedOwner), item.Info), ChatType.Hint);
  1345. Report?.ItemMailed(item, 1, 1);
  1346. continue;
  1347. }
  1348. if (!DropItem(item, Settings.DropRange, true))
  1349. continue;
  1350. if (item.Info.GlobalDropNotify)
  1351. foreach (var player in Envir.Players)
  1352. {
  1353. player.ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.PlayerHasDroppedItem), Name, item.FriendlyName), ChatType.System2);;
  1354. }
  1355. Info.Inventory[i] = null;
  1356. Enqueue(new S.DeleteItem { UniqueID = item.UniqueID, Count = item.Count });
  1357. Report?.ItemChanged(item, item.Count, 1);
  1358. }
  1359. }
  1360. RefreshStats();
  1361. }
  1362. protected static int FreeSpace(IList<UserItem> array)
  1363. {
  1364. int count = 0;
  1365. for (int i = 0; i < array.Count; i++)
  1366. if (array[i] == null) count++;
  1367. return count;
  1368. }
  1369. protected void AddItem(UserItem item)
  1370. {
  1371. if (item.Info.StackSize > 1) //Stackable
  1372. {
  1373. for (int i = 0; i < Info.Inventory.Length; i++)
  1374. {
  1375. UserItem temp = Info.Inventory[i];
  1376. if (temp == null || item.Info != temp.Info || temp.Count >= temp.Info.StackSize) continue;
  1377. if (item.Count + temp.Count <= temp.Info.StackSize)
  1378. {
  1379. temp.Count += item.Count;
  1380. return;
  1381. }
  1382. item.Count -= (ushort)(temp.Info.StackSize - temp.Count);
  1383. temp.Count = temp.Info.StackSize;
  1384. }
  1385. }
  1386. if (item.Info.Type == ItemType.Potion || item.Info.Type == ItemType.Scroll || (item.Info.Type == ItemType.Script && item.Info.Effect == 1))
  1387. {
  1388. for (int i = PotionBeltMinimum; i < PotionBeltMaximum; i++)
  1389. {
  1390. if (Info.Inventory[i] != null) continue;
  1391. Info.Inventory[i] = item;
  1392. return;
  1393. }
  1394. }
  1395. else if (item.Info.Type == ItemType.Amulet)
  1396. {
  1397. for (int i = AmuletBeltMinimum; i < AmuletBeltMaximum; i++)
  1398. {
  1399. if (Info.Inventory[i] != null) continue;
  1400. Info.Inventory[i] = item;
  1401. return;
  1402. }
  1403. }
  1404. else
  1405. {
  1406. for (int i = BeltSize; i < Info.Inventory.Length; i++)
  1407. {
  1408. if (Info.Inventory[i] != null) continue;
  1409. Info.Inventory[i] = item;
  1410. return;
  1411. }
  1412. }
  1413. for (int i = 0; i < Info.Inventory.Length; i++)
  1414. {
  1415. if (Info.Inventory[i] != null) continue;
  1416. Info.Inventory[i] = item;
  1417. return;
  1418. }
  1419. }
  1420. protected bool CorrectStartItem(ItemInfo info)
  1421. {
  1422. switch (Class)
  1423. {
  1424. case MirClass.Warrior:
  1425. if (!info.RequiredClass.HasFlag(RequiredClass.Warrior)) return false;
  1426. break;
  1427. case MirClass.Wizard:
  1428. if (!info.RequiredClass.HasFlag(RequiredClass.Wizard)) return false;
  1429. break;
  1430. case MirClass.Taoist:
  1431. if (!info.RequiredClass.HasFlag(RequiredClass.Taoist)) return false;
  1432. break;
  1433. case MirClass.Assassin:
  1434. if (!info.RequiredClass.HasFlag(RequiredClass.Assassin)) return false;
  1435. break;
  1436. case MirClass.Archer:
  1437. if (!info.RequiredClass.HasFlag(RequiredClass.Archer)) return false;
  1438. break;
  1439. default:
  1440. return false;
  1441. }
  1442. switch (Gender)
  1443. {
  1444. case MirGender.Male:
  1445. if (!info.RequiredGender.HasFlag(RequiredGender.Male)) return false;
  1446. break;
  1447. case MirGender.Female:
  1448. if (!info.RequiredGender.HasFlag(RequiredGender.Female)) return false;
  1449. break;
  1450. default:
  1451. return false;
  1452. }
  1453. return true;
  1454. }
  1455. public void CheckItemInfo(ItemInfo info, bool dontLoop = false)
  1456. {
  1457. Connection.CheckItemInfo(info, dontLoop);
  1458. }
  1459. public void CheckItem(UserItem item)
  1460. {
  1461. Connection.CheckItem(item);
  1462. }
  1463. public void SetLevelEffects()
  1464. {
  1465. LevelEffects = LevelEffects.None;
  1466. if (Info.Flags[990]) LevelEffects |= LevelEffects.Mist;
  1467. if (Info.Flags[991]) LevelEffects |= LevelEffects.RedDragon;
  1468. if (Info.Flags[992]) LevelEffects |= LevelEffects.BlueDragon;
  1469. if (Info.Flags[993]) LevelEffects |= LevelEffects.Rebirth1;
  1470. if (Info.Flags[994]) LevelEffects |= LevelEffects.Rebirth2;
  1471. if (Info.Flags[995]) LevelEffects |= LevelEffects.Rebirth3;
  1472. if (Info.Flags[996]) LevelEffects |= LevelEffects.NewBlue;
  1473. if (Info.Flags[997]) LevelEffects |= LevelEffects.YellowDragon;
  1474. if (Info.Flags[998]) LevelEffects |= LevelEffects.Phoenix;
  1475. }
  1476. public virtual void Revive(int hp, bool effect)
  1477. {
  1478. if (!Dead) return;
  1479. Dead = false;
  1480. SetHP(hp);
  1481. CurrentMap.RemoveObject(this);
  1482. Broadcast(new S.ObjectRemove { ObjectID = ObjectID });
  1483. CurrentMap = CurrentMap;
  1484. CurrentLocation = CurrentLocation;
  1485. CurrentMap.AddObject(this);
  1486. Enqueue(new S.MapChanged
  1487. {
  1488. MapIndex = CurrentMap.Info.Index,
  1489. FileName = CurrentMap.Info.FileName,
  1490. Title = CurrentMap.Info.Title,
  1491. Weather = CurrentMap.Info.WeatherParticles,
  1492. MiniMap = CurrentMap.Info.MiniMap,
  1493. BigMap = CurrentMap.Info.BigMap,
  1494. Lights = CurrentMap.Info.Light,
  1495. Location = CurrentLocation,
  1496. Direction = Direction,
  1497. MapDarkLight = CurrentMap.Info.MapDarkLight,
  1498. Music = CurrentMap.Info.Music
  1499. });
  1500. Enqueue(new S.Revived());
  1501. Broadcast(new S.ObjectRevived { ObjectID = ObjectID, Effect = effect });
  1502. }
  1503. protected virtual void SendBaseStats()
  1504. {
  1505. Enqueue(new S.BaseStatsInfo { Stats = Settings.ClassBaseStats[(byte)Class] });
  1506. }
  1507. #region Refresh Stats
  1508. public void RefreshStats()
  1509. {
  1510. if (HasUpdatedBaseStats == false)
  1511. {
  1512. SendBaseStats();
  1513. HasUpdatedBaseStats = true;
  1514. }
  1515. Stats.Clear();
  1516. RefreshLevelStats();
  1517. RefreshBagWeight();
  1518. RefreshEquipmentStats();
  1519. RefreshItemSetStats();
  1520. RefreshMirSetStats();
  1521. RefreshSkills();
  1522. RefreshBuffs();
  1523. RefreshGuildBuffs();
  1524. //Add any rate percent changes
  1525. Stats[Stat.HP] += (Stats[Stat.HP] * Stats[Stat.HPRatePercent]) / 100;
  1526. Stats[Stat.MP] += (Stats[Stat.MP] * Stats[Stat.MPRatePercent]) / 100;
  1527. Stats[Stat.MaxAC] += (Stats[Stat.MaxAC] * Stats[Stat.MaxACRatePercent]) / 100;
  1528. Stats[Stat.MaxMAC] += (Stats[Stat.MaxMAC] * Stats[Stat.MaxMACRatePercent]) / 100;
  1529. Stats[Stat.MaxDC] += (Stats[Stat.MaxDC] * Stats[Stat.MaxDCRatePercent]) / 100;
  1530. Stats[Stat.MaxMC] += (Stats[Stat.MaxMC] * Stats[Stat.MaxMCRatePercent]) / 100;
  1531. Stats[Stat.MaxSC] += (Stats[Stat.MaxSC] * Stats[Stat.MaxSCRatePercent]) / 100;
  1532. Stats[Stat.AttackSpeed] += (Stats[Stat.AttackSpeed] * Stats[Stat.AttackSpeedRatePercent]) / 100;
  1533. RefreshStatCaps();
  1534. if (HP > Stats[Stat.HP]) SetHP(Stats[Stat.HP]);
  1535. if (MP > Stats[Stat.MP]) SetMP(Stats[Stat.MP]);
  1536. AttackSpeed = 1400 - ((Stats[Stat.AttackSpeed] * 60) + Math.Min(370, (Level * 14)));
  1537. if (AttackSpeed < 550) AttackSpeed = 550;
  1538. }
  1539. public virtual void RefreshGuildBuffs() { }
  1540. public virtual void RefreshMaxExperience() { }
  1541. protected virtual void RefreshLevelStats()
  1542. {
  1543. RefreshMaxExperience();
  1544. foreach (var stat in Settings.ClassBaseStats[(byte)Class].Stats)
  1545. {
  1546. Stats[stat.Type] = stat.Calculate(Class, Level);
  1547. }
  1548. }
  1549. public void RefreshBagWeight()
  1550. {
  1551. CurrentBagWeight = 0;
  1552. for (int i = 0; i < Info.Inventory.Length; i++)
  1553. {
  1554. UserItem item = Info.Inventory[i];
  1555. if (item != null)
  1556. {
  1557. CurrentBagWeight += item.Weight;
  1558. }
  1559. }
  1560. }
  1561. private void RefreshEquipmentStats()
  1562. {
  1563. short OldLooks_Weapon = Looks_Weapon;
  1564. short OldLooks_WeaponEffect = Looks_WeaponEffect;
  1565. short OldLooks_Armour = Looks_Armour;
  1566. short Old_MountType = Mount.MountType;
  1567. byte OldLooks_Wings = Looks_Wings;
  1568. byte OldLight = Light;
  1569. Looks_Armour = 0;
  1570. Looks_Weapon = -1;
  1571. Looks_WeaponEffect = 0;
  1572. Looks_Wings = 0;
  1573. Light = 0;
  1574. CurrentWearWeight = 0;
  1575. CurrentHandWeight = 0;
  1576. Mount.MountType = -1;
  1577. SpecialMode = SpecialItemMode.None;
  1578. FastRun = false;
  1579. Stats[Stat.SkillGainMultiplier] = 1;
  1580. var skillsToAdd = new List<string>();
  1581. var skillsToRemove = new List<string> { Settings.HealRing, Settings.FireRing, Settings.BlinkSkill };
  1582. ItemSets.Clear();
  1583. MirSet.Clear();
  1584. for (int i = 0; i < Info.Equipment.Length; i++)
  1585. {
  1586. UserItem temp = Info.Equipment[i];
  1587. if (temp == null) continue;
  1588. ItemInfo realItem = Functions.GetRealItem(temp.Info, Info.Level, Info.Class, Envir.ItemInfoList);
  1589. if (realItem.Type == ItemType.Weapon || realItem.Type == ItemType.Torch)
  1590. CurrentHandWeight = (int)Math.Min(int.MaxValue, CurrentHandWeight + temp.Weight);
  1591. else
  1592. CurrentWearWeight = (int)Math.Min(int.MaxValue, CurrentWearWeight + temp.Weight);
  1593. if (temp.CurrentDura == 0 && temp.Info.Durability > 0) continue;
  1594. if (realItem.Type == ItemType.Armour)
  1595. {
  1596. Looks_Armour = realItem.Shape;
  1597. Looks_Wings = realItem.Effect;
  1598. }
  1599. if (realItem.Type == ItemType.Weapon)
  1600. {
  1601. Looks_Weapon = realItem.Shape;
  1602. Looks_WeaponEffect = realItem.Effect;
  1603. }
  1604. if (realItem.Type == ItemType.Mount)
  1605. {
  1606. Mount.MountType = realItem.Shape;
  1607. //RealItem.Effect;
  1608. }
  1609. if (temp.Info.IsFishingRod) continue;
  1610. Stats.Add(realItem.Stats);
  1611. Stats.Add(temp.AddedStats);
  1612. Stats[Stat.MinAC] += temp.Awake.GetAC();
  1613. Stats[Stat.MaxAC] += temp.Awake.GetAC();
  1614. Stats[Stat.MinMAC] += temp.Awake.GetMAC();
  1615. Stats[Stat.MaxMAC] += temp.Awake.GetMAC();
  1616. Stats[Stat.MinDC] += temp.Awake.GetDC();
  1617. Stats[Stat.MaxDC] += temp.Awake.GetDC();
  1618. Stats[Stat.MinMC] += temp.Awake.GetMC();
  1619. Stats[Stat.MaxMC] += temp.Awake.GetMC();
  1620. Stats[Stat.MinSC] += temp.Awake.GetSC();
  1621. Stats[Stat.MaxSC] += temp.Awake.GetSC();
  1622. Stats[Stat.HP] += temp.Awake.GetHPMP();
  1623. Stats[Stat.MP] += temp.Awake.GetHPMP();
  1624. if (realItem.Light > Light) Light = realItem.Light;
  1625. if (realItem.Unique != SpecialItemMode.None)
  1626. {
  1627. SpecialMode |= realItem.Unique;
  1628. if (realItem.Unique.HasFlag(SpecialItemMode.Flame)) skillsToAdd.Add(Settings.FireRing);
  1629. if (realItem.Unique.HasFlag(SpecialItemMode.Healing)) skillsToAdd.Add(Settings.HealRing);
  1630. if (realItem.Unique.HasFlag(SpecialItemMode.Blink)) skillsToAdd.Add(Settings.BlinkSkill);
  1631. }
  1632. if (realItem.CanFastRun)
  1633. {
  1634. FastRun = true;
  1635. }
  1636. RefreshSocketStats(temp, skillsToAdd);
  1637. if (realItem.Set == ItemSet.None) continue;
  1638. ItemSets itemSet = ItemSets.Where(set => set.Set == realItem.Set && !set.Type.Contains(realItem.Type) && !set.SetComplete).FirstOrDefault();
  1639. if (itemSet != null)
  1640. {
  1641. itemSet.Type.Add(realItem.Type);
  1642. itemSet.Count++;
  1643. }
  1644. else
  1645. {
  1646. ItemSets.Add(new ItemSets { Count = 1, Set = realItem.Set, Type = new List<ItemType> { realItem.Type } });
  1647. }
  1648. //Mir Set
  1649. if (realItem.Set == ItemSet.Mir)
  1650. {
  1651. if (!MirSet.Contains((EquipmentSlot)i))
  1652. {
  1653. MirSet.Add((EquipmentSlot)i);
  1654. }
  1655. }
  1656. }
  1657. AddTempSkills(skillsToAdd);
  1658. RemoveTempSkills(skillsToRemove.Except(skillsToAdd));
  1659. if (SpecialMode.HasFlag(SpecialItemMode.Muscle))
  1660. {
  1661. Stats[Stat.BagWeight] = Stats[Stat.BagWeight] * 2;
  1662. Stats[Stat.WearWeight] = Stats[Stat.WearWeight] * 2;
  1663. Stats[Stat.HandWeight] = Stats[Stat.HandWeight] * 2;
  1664. }
  1665. if ((OldLooks_Armour != Looks_Armour) || (OldLooks_Weapon != Looks_Weapon) || (OldLooks_WeaponEffect != Looks_WeaponEffect) || (OldLooks_Wings != Looks_Wings) || (OldLight != Light))
  1666. {
  1667. UpdateLooks(OldLooks_Weapon);
  1668. }
  1669. if (Old_MountType != Mount.MountType)
  1670. {
  1671. RefreshMount(false);
  1672. }
  1673. }
  1674. private void RefreshSocketStats(UserItem equipItem, List<string> skillsToAdd)
  1675. {
  1676. if (equipItem == null) return;
  1677. if (equipItem.Info.Type == ItemType.Weapon && equipItem.Info.IsFishingRod)
  1678. {
  1679. return;
  1680. }
  1681. if (equipItem.Info.Type == ItemType.Mount && !RidingMount)
  1682. {
  1683. return;
  1684. }
  1685. for (int j = 0; j < equipItem.Slots.Length; j++)
  1686. {
  1687. UserItem temp = equipItem.Slots[j];
  1688. if (temp == null) continue;
  1689. ItemInfo RealItem = Functions.GetRealItem(temp.Info, Info.Level, Info.Class, Envir.ItemInfoList);
  1690. if (RealItem.Type == ItemType.Weapon || RealItem.Type == ItemType.Torch)
  1691. CurrentHandWeight = (int)Math.Min(int.MaxValue, CurrentHandWeight + temp.Weight);
  1692. else
  1693. CurrentWearWeight = (int)Math.Min(int.MaxValue, CurrentWearWeight + temp.Weight);
  1694. if (temp.CurrentDura == 0 && temp.Info.Durability > 0) continue;
  1695. Stats.Add(RealItem.Stats);
  1696. Stats.Add(temp.AddedStats);
  1697. if (RealItem.Light > Light) Light = RealItem.Light;
  1698. if (RealItem.Unique != SpecialItemMode.None)
  1699. {
  1700. SpecialMode |= RealItem.Unique;
  1701. if (RealItem.Unique.HasFlag(SpecialItemMode.Skill)) Stats[Stat.SkillGainMultiplier] = 3;
  1702. if (RealItem.Unique.HasFlag(SpecialItemMode.Flame)) skillsToAdd.Add(Settings.FireRing);
  1703. if (RealItem.Unique.HasFlag(SpecialItemMode.Healing)) skillsToAdd.Add(Settings.HealRing);
  1704. if (RealItem.Unique.HasFlag(SpecialItemMode.Blink)) skillsToAdd.Add(Settings.BlinkSkill);
  1705. }
  1706. }
  1707. //TODO - Add Socket bonuses
  1708. }
  1709. private void RefreshItemSetStats()
  1710. {
  1711. bool hasSmashSetBonus = false; // Flag for Smash set AttackSpeed bonus
  1712. bool hasPuritySetBonus = false; // Flag for Purity set Holy bonus
  1713. bool hasHwanDevilSetBonus = false; // Flag for HwanDevil set Weight bonuses
  1714. foreach (var s in ItemSets)
  1715. {
  1716. if ((s.Set == ItemSet.Smash) && (s.Type.Contains(ItemType.Ring)) && (s.Type.Contains(ItemType.Bracelet)))
  1717. {
  1718. if (!hasSmashSetBonus)
  1719. {
  1720. Stats[Stat.AttackSpeed] += 2;
  1721. hasSmashSetBonus = true;
  1722. }
  1723. }
  1724. if ((s.Set == ItemSet.Purity) && (s.Type.Contains(ItemType.Ring)) && (s.Type.Contains(ItemType.Bracelet)))
  1725. {
  1726. if (!hasPuritySetBonus)
  1727. {
  1728. Stats[Stat.Holy] += 3;
  1729. hasPuritySetBonus = true;
  1730. }
  1731. }
  1732. if ((s.Set == ItemSet.HwanDevil) && (s.Type.Contains(ItemType.Ring)) && (s.Type.Contains(ItemType.Bracelet)))
  1733. {
  1734. if (!hasHwanDevilSetBonus)
  1735. {
  1736. Stats[Stat.WearWeight] += 5;
  1737. Stats[Stat.BagWeight] += 20;
  1738. hasHwanDevilSetBonus = true;
  1739. }
  1740. }
  1741. if ((s.Set == ItemSet.DarkGhost) && (s.Type.Contains(ItemType.Necklace)) && (s.Type.Contains(ItemType.Bracelet)))
  1742. {
  1743. Stats[Stat.HP] += 25;
  1744. }
  1745. if (!s.SetComplete) continue;
  1746. switch (s.Set)
  1747. {
  1748. case ItemSet.Mundane:
  1749. Stats[Stat.HP] += 50;
  1750. break;
  1751. case ItemSet.NokChi:
  1752. Stats[Stat.MP] += 50;
  1753. break;
  1754. case ItemSet.TaoProtect:
  1755. Stats[Stat.HP] += 30;
  1756. Stats[Stat.MP] += 30;
  1757. break;
  1758. case ItemSet.RedOrchid:
  1759. Stats[Stat.Accuracy] += 2;
  1760. break;
  1761. case ItemSet.RedFlower:
  1762. Stats[Stat.HP] += 50;
  1763. Stats[Stat.MP] -= 50;
  1764. break;
  1765. case ItemSet.Smash:
  1766. Stats[Stat.MinDC] += 1;
  1767. Stats[Stat.MaxDC] += 3;
  1768. break;
  1769. case ItemSet.HwanDevil:
  1770. Stats[Stat.MinMC] += 1;
  1771. Stats[Stat.MaxMC] += 2;
  1772. break;
  1773. case ItemSet.Purity:
  1774. Stats[Stat.MinSC] += 1;
  1775. Stats[Stat.MaxSC] += 2;
  1776. break;
  1777. case ItemSet.FiveString:
  1778. Stats[Stat.HP] += (int)(((double)Stats[Stat.HP] / 100) * 30);
  1779. Stats[Stat.MinAC] += 2;
  1780. Stats[Stat.MaxAC] += 2;
  1781. break;
  1782. case ItemSet.Spirit:
  1783. Stats[Stat.MinDC] += 2;
  1784. Stats[Stat.MaxDC] += 5;
  1785. Stats[Stat.AttackSpeed] += 2;
  1786. break;
  1787. case ItemSet.Bone:
  1788. Stats[Stat.MaxAC] += 2;
  1789. Stats[Stat.MaxMC] += 1;
  1790. Stats[Stat.MaxSC] += 1;
  1791. break;
  1792. case ItemSet.Bug:
  1793. Stats[Stat.MaxDC] += 1;
  1794. Stats[Stat.MaxMC] += 1;
  1795. Stats[Stat.MaxSC] += 1;
  1796. Stats[Stat.MaxMAC] += 1;
  1797. Stats[Stat.PoisonResist] += 1;
  1798. break;
  1799. case ItemSet.WhiteGold:
  1800. Stats[Stat.MaxDC] += 2;
  1801. Stats[Stat.MaxAC] += 2;
  1802. break;
  1803. case ItemSet.WhiteGoldH:
  1804. Stats[Stat.MaxDC] += 3;
  1805. Stats[Stat.HP] += 30;
  1806. Stats[Stat.AttackSpeed] += 2;
  1807. break;
  1808. case ItemSet.RedJade:
  1809. Stats[Stat.MaxMC] += 2;
  1810. Stats[Stat.MaxMAC] += 2;
  1811. break;
  1812. case ItemSet.RedJadeH:
  1813. Stats[Stat.MaxMC] += 2;
  1814. Stats[Stat.MP] += 40;
  1815. Stats[Stat.Agility] += 2;
  1816. break;
  1817. case ItemSet.Nephrite:
  1818. Stats[Stat.MaxSC] += 2;
  1819. Stats[Stat.MaxAC] += 1;
  1820. Stats[Stat.MaxMAC] += 1;
  1821. break;
  1822. case ItemSet.NephriteH:
  1823. Stats[Stat.MaxSC] += 2;
  1824. Stats[Stat.HP] += 15;
  1825. Stats[Stat.MP] += 20;
  1826. Stats[Stat.Holy] += 1;
  1827. Stats[Stat.Accuracy] += 1;
  1828. break;
  1829. case ItemSet.Whisker1:
  1830. Stats[Stat.MaxDC] += 1;
  1831. Stats[Stat.BagWeight] += 25;
  1832. break;
  1833. case ItemSet.Whisker2:
  1834. Stats[Stat.MaxMC] += 1;
  1835. Stats[Stat.BagWeight] += 17;
  1836. break;
  1837. case ItemSet.Whisker3:
  1838. Stats[Stat.MaxSC] += 1;
  1839. Stats[Stat.BagWeight] += 17;
  1840. break;
  1841. case ItemSet.Whisker4:
  1842. Stats[Stat.MaxDC] += 1;
  1843. Stats[Stat.BagWeight] += 20;
  1844. break;
  1845. case ItemSet.Whisker5:
  1846. Stats[Stat.MaxDC] += 1;
  1847. Stats[Stat.BagWeight] += 17;
  1848. break;
  1849. case ItemSet.Hyeolryong:
  1850. Stats[Stat.MaxSC] += 2;
  1851. Stats[Stat.HP] += 15;
  1852. Stats[Stat.MP] += 20;
  1853. Stats[Stat.Holy] += 1;
  1854. Stats[Stat.Accuracy] += 1;
  1855. break;
  1856. case ItemSet.Monitor:
  1857. Stats[Stat.MagicResist] += 1;
  1858. Stats[Stat.PoisonResist] += 1;
  1859. break;
  1860. case ItemSet.Oppressive:
  1861. Stats[Stat.MaxAC] += 1;
  1862. Stats[Stat.Agility] += 1;
  1863. break;
  1864. case ItemSet.BlueFrost:
  1865. Stats[Stat.MinDC] += 1;
  1866. Stats[Stat.MaxDC] += 1;
  1867. Stats[Stat.MinMC] += 1;
  1868. Stats[Stat.MaxMC] += 1;
  1869. Stats[Stat.HandWeight] += 1;
  1870. Stats[Stat.WearWeight] += 2;
  1871. break;
  1872. case ItemSet.BlueFrostH:
  1873. Stats[Stat.MinDC] += 1;
  1874. Stats[Stat.MaxDC] += 2;
  1875. Stats[Stat.MaxMC] += 2;
  1876. Stats[Stat.Accuracy] += 1;
  1877. Stats[Stat.HP] += 50;
  1878. break;
  1879. case ItemSet.DarkGhost:
  1880. Stats[Stat.MP] += 25;
  1881. Stats[Stat.AttackSpeed] += 2;
  1882. break;
  1883. }
  1884. }
  1885. }
  1886. private void RefreshMirSetStats()
  1887. {
  1888. if (MirSet.Count() == 10)
  1889. {
  1890. Stats[Stat.MaxAC] += 1;
  1891. Stats[Stat.MaxMAC] += 1;
  1892. Stats[Stat.BagWeight] += 70;
  1893. Stats[Stat.Luck] += 2;
  1894. Stats[Stat.AttackSpeed] += 2;
  1895. Stats[Stat.HP] += 70;
  1896. Stats[Stat.MP] += 80;
  1897. Stats[Stat.MagicResist] += 6;
  1898. Stats[Stat.PoisonResist] += 6;
  1899. }
  1900. if (MirSet.Contains(EquipmentSlot.RingL) && MirSet.Contains(EquipmentSlot.RingR))
  1901. {
  1902. Stats[Stat.MaxMAC] += 1;
  1903. Stats[Stat.MaxAC] += 1;
  1904. }
  1905. if (MirSet.Contains(EquipmentSlot.BraceletL) && MirSet.Contains(EquipmentSlot.BraceletR))
  1906. {
  1907. Stats[Stat.MinAC] += 1;
  1908. Stats[Stat.MinMAC] += 1;
  1909. }
  1910. if ((MirSet.Contains(EquipmentSlot.RingL) | MirSet.Contains(EquipmentSlot.RingR)) && (MirSet.Contains(EquipmentSlot.BraceletL) | MirSet.Contains(EquipmentSlot.BraceletR)) && MirSet.Contains(EquipmentSlot.Necklace))
  1911. {
  1912. Stats[Stat.MaxMAC] += 1;
  1913. Stats[Stat.MaxAC] += 1;
  1914. Stats[Stat.BagWeight] += 30;
  1915. Stats[Stat.WearWeight] += 17;
  1916. }
  1917. if (MirSet.Contains(EquipmentSlot.RingL) && MirSet.Contains(EquipmentSlot.RingR) && MirSet.Contains(EquipmentSlot.BraceletL) && MirSet.Contains(EquipmentSlot.BraceletR) && MirSet.Contains(EquipmentSlot.Necklace))
  1918. {
  1919. Stats[Stat.MaxMAC] += 1;
  1920. Stats[Stat.MaxAC] += 1;
  1921. Stats[Stat.BagWeight] += 20;
  1922. Stats[Stat.WearWeight] += 10;
  1923. }
  1924. if (MirSet.Contains(EquipmentSlot.Armour) && MirSet.Contains(EquipmentSlot.Helmet) && MirSet.Contains(EquipmentSlot.Weapon))
  1925. {
  1926. Stats[Stat.MaxDC] += 2;
  1927. Stats[Stat.MaxMC] += 1;
  1928. Stats[Stat.MaxSC] += 1;
  1929. Stats[Stat.Agility] += 1;
  1930. }
  1931. if (MirSet.Contains(EquipmentSlot.Armour) && MirSet.Contains(EquipmentSlot.Boots) && MirSet.Contains(EquipmentSlot.Belt))
  1932. {
  1933. Stats[Stat.MaxDC] += 1;
  1934. Stats[Stat.MaxMC] += 1;
  1935. Stats[Stat.MaxSC] += 1;
  1936. Stats[Stat.HandWeight] += 17;
  1937. }
  1938. if (MirSet.Contains(EquipmentSlot.Armour) && MirSet.Contains(EquipmentSlot.Boots) && MirSet.Contains(EquipmentSlot.Belt) && MirSet.Contains(EquipmentSlot.Helmet) && MirSet.Contains(EquipmentSlot.Weapon))
  1939. {
  1940. Stats[Stat.MinDC] += 1;
  1941. Stats[Stat.MaxDC] += 1;
  1942. Stats[Stat.MinMC] += 1;
  1943. Stats[Stat.MaxMC] += 1;
  1944. Stats[Stat.MinSC] += 1;
  1945. Stats[Stat.MaxSC] += 1;
  1946. Stats[Stat.HandWeight] += 17;
  1947. }
  1948. }
  1949. public void RefreshStatCaps()
  1950. {
  1951. foreach (var cap in Settings.ClassBaseStats[(byte)Class].Caps.Values)
  1952. {
  1953. Stats[cap.Key] = Math.Min(cap.Value, Stats[cap.Key]);
  1954. }
  1955. Stats[Stat.HP] = Math.Max(0, Stats[Stat.HP]);
  1956. Stats[Stat.MP] = Math.Max(0, Stats[Stat.MP]);
  1957. Stats[Stat.MinAC] = Math.Max(0, Stats[Stat.MinAC]);
  1958. Stats[Stat.MaxAC] = Math.Max(0, Stats[Stat.MaxAC]);
  1959. Stats[Stat.MinMAC] = Math.Max(0, Stats[Stat.MinMAC]);
  1960. Stats[Stat.MaxMAC] = Math.Max(0, Stats[Stat.MaxMAC]);
  1961. Stats[Stat.MinDC] = Math.Max(0, Stats[Stat.MinDC]);
  1962. Stats[Stat.MaxDC] = Math.Max(0, Stats[Stat.MaxDC]);
  1963. Stats[Stat.MinMC] = Math.Max(0, Stats[Stat.MinMC]);
  1964. Stats[Stat.MaxMC] = Math.Max(0, Stats[Stat.MaxMC]);
  1965. Stats[Stat.MinSC] = Math.Max(0, Stats[Stat.MinSC]);
  1966. Stats[Stat.MaxSC] = Math.Max(0, Stats[Stat.MaxSC]);
  1967. Stats[Stat.MinDC] = Math.Min(Stats[Stat.MinDC], Stats[Stat.MaxDC]);
  1968. Stats[Stat.MinMC] = Math.Min(Stats[Stat.MinMC], Stats[Stat.MaxMC]);
  1969. Stats[Stat.MinSC] = Math.Min(Stats[Stat.MinSC], Stats[Stat.MaxSC]);
  1970. }
  1971. #endregion
  1972. private void AddTempSkills(IEnumerable<string> skillsToAdd)
  1973. {
  1974. foreach (var skill in skillsToAdd)
  1975. {
  1976. Spell spelltype;
  1977. bool hasSkill = false;
  1978. if (!Enum.TryParse(skill, out spelltype)) return;
  1979. for (var i = Info.Magics.Count - 1; i >= 0; i--)
  1980. if (Info.Magics[i].Spell == spelltype) hasSkill = true;
  1981. if (hasSkill) continue;
  1982. var magic = new UserMagic(spelltype) { IsTempSpell = true };
  1983. Info.Magics.Add(magic);
  1984. SendMagicInfo(magic);
  1985. }
  1986. }
  1987. public virtual void SendMagicInfo(UserMagic magic)
  1988. {
  1989. Enqueue(magic.GetInfo(false));
  1990. }
  1991. private void RemoveTempSkills(IEnumerable<string> skillsToRemove)
  1992. {
  1993. foreach (var skill in skillsToRemove)
  1994. {
  1995. if (!Enum.TryParse(skill, out Spell spelltype)) return;
  1996. for (var i = Info.Magics.Count - 1; i >= 0; i--)
  1997. {
  1998. if (!Info.Magics[i].IsTempSpell || Info.Magics[i].Spell != spelltype) continue;
  1999. Info.Magics.RemoveAt(i);
  2000. Enqueue(new S.RemoveMagic { PlaceId = i });
  2001. }
  2002. }
  2003. }
  2004. private void RefreshSkills()
  2005. {
  2006. int[] spiritSwordLvPlus = { 0, 3, 5, 8 };
  2007. int[] slayingLvPlus = { 5, 6, 7, 8 };
  2008. for (int i = 0; i < Info.Magics.Count; i++)
  2009. {
  2010. UserMagic magic = Info.Magics[i];
  2011. switch (magic.Spell)
  2012. {
  2013. case Spell.Fencing:
  2014. Stats[Stat.Accuracy] += magic.Level * 3;
  2015. // Stats[Stat.MaxAC] += (magic.Level + 1) * 3;
  2016. break;
  2017. // case Spell.FatalSword:
  2018. case Spell.Slaying:
  2019. Stats[Stat.Accuracy] += magic.Level;
  2020. Stats[Stat.MaxDC] += slayingLvPlus[magic.Level];
  2021. break;
  2022. case Spell.SpiritSword:
  2023. Stats[Stat.Accuracy] += spiritSwordLvPlus[magic.Level];
  2024. // Stats[Stat.Accuracy] += magic.Level;
  2025. // Stats[Stat.MaxDC] += (int)(Stats[Stat.MaxSC] * (magic.Level + 1) * 0.1F);
  2026. break;
  2027. }
  2028. }
  2029. }
  2030. private void RefreshBuffs()
  2031. {
  2032. short Old_TransformType = TransformType;
  2033. TransformType = -1;
  2034. for (int i = 0; i < Buffs.Count; i++)
  2035. {
  2036. Buff buff = Buffs[i];
  2037. if (buff.Paused) continue;
  2038. Stats.Add(buff.Stats);
  2039. if (buff.Values != null && buff.Values.Length > 0)
  2040. {
  2041. switch (buff.Type)
  2042. {
  2043. case BuffType.Transform:
  2044. TransformType = (short)buff.Values[0];
  2045. FastRun = true;
  2046. break;
  2047. }
  2048. }
  2049. }
  2050. if (Old_TransformType != TransformType)
  2051. {
  2052. Broadcast(new S.TransformUpdate { ObjectID = ObjectID, TransformType = TransformType });
  2053. }
  2054. }
  2055. public void BroadcastColourChange()
  2056. {
  2057. if (CurrentMap == null) return;
  2058. for (int i = CurrentMap.Players.Count - 1; i >= 0; i--)
  2059. {
  2060. PlayerObject player = CurrentMap.Players[i];
  2061. if (player == this) continue;
  2062. if (Functions.InRange(CurrentLocation, player.CurrentLocation, Globals.DataRange))
  2063. player.Enqueue(new S.ObjectColourChanged { ObjectID = ObjectID, NameColour = player.GetNameColour(this) });
  2064. }
  2065. }
  2066. public virtual void GainExp(uint amount) { }
  2067. public int ReduceExp(uint amount, uint targetLevel)
  2068. {
  2069. int expPoint;
  2070. if (Level < targetLevel + 10 || !Settings.ExpMobLevelDifference)
  2071. {
  2072. expPoint = (int)amount;
  2073. }
  2074. else
  2075. {
  2076. expPoint = (int)amount - (int)Math.Round(Math.Max(amount / 15, 1) * ((double)Level - (targetLevel + 10)));
  2077. }
  2078. if (expPoint <= 0) expPoint = 1;
  2079. return expPoint;
  2080. }
  2081. public override void BroadcastInfo()
  2082. {
  2083. Packet p;
  2084. if (CurrentMap == null) return;
  2085. for (int i = CurrentMap.Players.Count - 1; i >= 0; i--)
  2086. {
  2087. PlayerObject player = CurrentMap.Players[i];
  2088. if (player == this) continue;
  2089. if (Functions.InRange(CurrentLocation, player.CurrentLocation, Globals.DataRange))
  2090. {
  2091. p = GetInfoEx(player);
  2092. if (p != null)
  2093. player.Enqueue(p);
  2094. }
  2095. }
  2096. }
  2097. public virtual bool CheckMovement(Point location)
  2098. {
  2099. return false;
  2100. }
  2101. public bool Walk(MirDirection dir)
  2102. {
  2103. if (!CanMove || !CanWalk)
  2104. {
  2105. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2106. return false;
  2107. }
  2108. Point location = Functions.PointMove(CurrentLocation, dir, 1);
  2109. if (!CurrentMap.ValidPoint(location))
  2110. {
  2111. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2112. return false;
  2113. }
  2114. if (!CurrentMap.CheckDoorOpen(location))
  2115. {
  2116. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2117. return false;
  2118. }
  2119. Cell cell = CurrentMap.GetCell(location);
  2120. if (cell.Objects != null)
  2121. {
  2122. for (int i = 0; i < cell.Objects.Count; i++)
  2123. {
  2124. MapObject ob = cell.Objects[i];
  2125. if (ob.Race == ObjectType.Merchant && Race == ObjectType.Player)
  2126. {
  2127. NPCObject NPC = (NPCObject)ob;
  2128. if (!NPC.Visible || !NPC.VisibleLog[Info.Index]) continue;
  2129. }
  2130. else
  2131. {
  2132. if (!ob.Blocking || (CheckCellTime && ob.CellTime >= Envir.Time)) continue;
  2133. }
  2134. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2135. return false;
  2136. }
  2137. }
  2138. if (HasBuff(BuffType.Concentration, out Buff concentration))
  2139. {
  2140. concentration.Set("InterruptTime", Envir.Time + (Settings.Second * 3));
  2141. if (!concentration.Get<bool>("Interrupted"))
  2142. {
  2143. concentration.Set("Interrupted", true);
  2144. UpdateConcentration(true, true);
  2145. }
  2146. }
  2147. if (Hidden)
  2148. {
  2149. RemoveBuff(BuffType.Hiding);
  2150. }
  2151. Direction = dir;
  2152. if (CheckMovement(location)) return false;
  2153. CurrentMap.GetCell(CurrentLocation).Remove(this);
  2154. RemoveObjects(dir, 1);
  2155. CurrentLocation = location;
  2156. var dstCell = CurrentMap.GetCell(CurrentLocation);
  2157. dstCell.Add(this);
  2158. AddObjects(dir, 1);
  2159. _stepCounter++;
  2160. SafeZoneInfo szi = CurrentMap.GetSafeZone(CurrentLocation);
  2161. if (szi != null)
  2162. {
  2163. SetBindSafeZone(szi);
  2164. InSafeZone = true;
  2165. }
  2166. else
  2167. InSafeZone = false;
  2168. if (RidingMount) DecreaseMountLoyalty(1);
  2169. Moved();
  2170. CellTime = Envir.Time + 500;
  2171. ActionTime = Envir.Time + GetDelayTime(MoveDelay);
  2172. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2173. Broadcast(new S.ObjectWalk { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  2174. GetPlayerLocation();
  2175. cell = CurrentMap.GetCell(CurrentLocation);
  2176. if (cell.Objects != null)
  2177. {
  2178. for (int i = 0; i < cell.Objects.Count; i++)
  2179. {
  2180. if (cell.Objects[i].Race != ObjectType.Spell) continue;
  2181. SpellObject ob = (SpellObject)cell.Objects[i];
  2182. ob.ProcessSpell(this);
  2183. }
  2184. }
  2185. return true;
  2186. }
  2187. public bool Run(MirDirection dir)
  2188. {
  2189. if (CurrentBagWeight > Stats[Stat.BagWeight])
  2190. {
  2191. Walk(dir);
  2192. }
  2193. var steps = RidingMount || ActiveSwiftFeet && !Sneaking ? 3 : 2;
  2194. if (!CanMove || !CanWalk || !CanRun)
  2195. {
  2196. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2197. return false;
  2198. }
  2199. if (HasBuff(BuffType.Concentration, out Buff concentration))
  2200. {
  2201. concentration.Set("InterruptTime", Envir.Time + (Settings.Second * 3));
  2202. if (!concentration.Get<bool>("Interrupted"))
  2203. {
  2204. concentration.Set("Interrupted", true);
  2205. UpdateConcentration(true, true);
  2206. }
  2207. }
  2208. if (Hidden && !Sneaking)
  2209. {
  2210. RemoveBuff(BuffType.Hiding);
  2211. RemoveBuff(BuffType.MoonLight);
  2212. RemoveBuff(BuffType.DarkBody);
  2213. }
  2214. Moved();
  2215. Direction = dir;
  2216. Point location = Functions.PointMove(CurrentLocation, dir, 1);
  2217. for (int j = 1; j <= steps; j++)
  2218. {
  2219. location = Functions.PointMove(CurrentLocation, dir, j);
  2220. if (!CurrentMap.ValidPoint(location))
  2221. {
  2222. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2223. return false;
  2224. }
  2225. if (!CurrentMap.CheckDoorOpen(location))
  2226. {
  2227. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2228. return false;
  2229. }
  2230. Cell cell = CurrentMap.GetCell(location);
  2231. if (cell.Objects != null)
  2232. {
  2233. for (int i = 0; i < cell.Objects.Count; i++)
  2234. {
  2235. MapObject ob = cell.Objects[i];
  2236. if (ob.Race == ObjectType.Merchant && Race == ObjectType.Player)
  2237. {
  2238. NPCObject NPC = (NPCObject)ob;
  2239. if (!NPC.Visible || !NPC.VisibleLog[Info.Index]) continue;
  2240. }
  2241. else
  2242. if (!ob.Blocking || (CheckCellTime && ob.CellTime >= Envir.Time)) continue;
  2243. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2244. return false;
  2245. }
  2246. }
  2247. if (CheckMovement(location)) return false;
  2248. }
  2249. Enqueue(new S.UserLocation { Direction = dir, Location = location });
  2250. Broadcast(new S.ObjectRun { ObjectID = ObjectID, Direction = dir, Location = location });
  2251. if (RidingMount && !Sneaking)
  2252. {
  2253. DecreaseMountLoyalty(2);
  2254. }
  2255. Direction = dir;
  2256. CurrentMap.GetCell(CurrentLocation).Remove(this);
  2257. RemoveObjects(dir, steps);
  2258. Point OldLocation = CurrentLocation;
  2259. CurrentLocation = location;
  2260. CurrentMap.GetCell(CurrentLocation).Add(this);
  2261. AddObjects(dir, steps);
  2262. SafeZoneInfo szi = CurrentMap.GetSafeZone(CurrentLocation);
  2263. if (szi != null)
  2264. {
  2265. SetBindSafeZone(szi);
  2266. InSafeZone = true;
  2267. }
  2268. else
  2269. InSafeZone = false;
  2270. CellTime = Envir.Time + 500;
  2271. ActionTime = Envir.Time + GetDelayTime(MoveDelay);
  2272. if (!RidingMount)
  2273. _runCounter++;
  2274. if (_runCounter > 10)
  2275. {
  2276. _runCounter -= 8;
  2277. ChangeHP(-1);
  2278. }
  2279. GetPlayerLocation();
  2280. for (int j = 1; j <= steps; j++)
  2281. {
  2282. location = Functions.PointMove(OldLocation, dir, j);
  2283. Cell cell = CurrentMap.GetCell(location);
  2284. if (cell.Objects == null) continue;
  2285. for (int i = 0; i < cell.Objects.Count; i++)
  2286. {
  2287. if (cell.Objects[i].Race != ObjectType.Spell) continue;
  2288. SpellObject ob = (SpellObject)cell.Objects[i];
  2289. ob.ProcessSpell(this);
  2290. //break;
  2291. }
  2292. }
  2293. return true;
  2294. }
  2295. protected virtual void Moved()
  2296. {
  2297. }
  2298. public override int Pushed(MapObject pusher, MirDirection dir, int distance)
  2299. {
  2300. int result = 0;
  2301. MirDirection reverse = Functions.ReverseDirection(dir);
  2302. Cell cell;
  2303. for (int i = 0; i < distance; i++)
  2304. {
  2305. Point location = Functions.PointMove(CurrentLocation, dir, 1);
  2306. if (!CurrentMap.ValidPoint(location)) return result;
  2307. cell = CurrentMap.GetCell(location);
  2308. bool stop = false;
  2309. if (cell.Objects != null)
  2310. for (int c = 0; c < cell.Objects.Count; c++)
  2311. {
  2312. MapObject ob = cell.Objects[c];
  2313. if (!ob.Blocking) continue;
  2314. stop = true;
  2315. }
  2316. if (stop) break;
  2317. CurrentMap.GetCell(CurrentLocation).Remove(this);
  2318. Direction = reverse;
  2319. RemoveObjects(dir, 1);
  2320. CurrentLocation = location;
  2321. CurrentMap.GetCell(CurrentLocation).Add(this);
  2322. AddObjects(dir, 1);
  2323. Moved();
  2324. Enqueue(new S.Pushed { Direction = Direction, Location = CurrentLocation });
  2325. Broadcast(new S.ObjectPushed { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  2326. GetPlayerLocation();
  2327. result++;
  2328. }
  2329. if (result > 0)
  2330. {
  2331. if (HasBuff(BuffType.Concentration, out Buff concentration))
  2332. {
  2333. concentration.Set("InterruptTime", Envir.Time + (Settings.Second * 3));
  2334. if (!concentration.Get<bool>("Interrupted"))
  2335. {
  2336. concentration.Set("Interrupted", true);
  2337. UpdateConcentration(true, true);
  2338. }
  2339. }
  2340. cell = CurrentMap.GetCell(CurrentLocation);
  2341. for (int i = 0; i < cell.Objects.Count; i++)
  2342. {
  2343. if (cell.Objects[i].Race != ObjectType.Spell) continue;
  2344. SpellObject ob = (SpellObject)cell.Objects[i];
  2345. ob.ProcessSpell(this);
  2346. //break;
  2347. }
  2348. SafeZoneInfo szi = CurrentMap.GetSafeZone(CurrentLocation);
  2349. if (szi != null)
  2350. {
  2351. SetBindSafeZone(szi);
  2352. InSafeZone = true;
  2353. }
  2354. else
  2355. InSafeZone = false;
  2356. }
  2357. ActionTime = Envir.Time + 500;
  2358. return result;
  2359. }
  2360. public void GetPlayerLocation()
  2361. {
  2362. if (GroupMembers == null) return;
  2363. for (int i = 0; i < GroupMembers.Count; i++)
  2364. {
  2365. PlayerObject member = GroupMembers[i];
  2366. if (member.CurrentMap.Info.BigMap <= 0) continue;
  2367. member.Enqueue(new S.SendMemberLocation { MemberName = Name, MemberLocation = CurrentLocation });
  2368. Enqueue(new S.SendMemberLocation { MemberName = member.Name, MemberLocation = member.CurrentLocation });
  2369. }
  2370. Enqueue(new S.SendMemberLocation { MemberName = Name, MemberLocation = CurrentLocation });
  2371. }
  2372. public void RangeAttack(MirDirection dir, Point location, uint targetID)
  2373. {
  2374. LogTime = Envir.Time + Globals.LogDelay;
  2375. if (Info.Equipment[(int)EquipmentSlot.Weapon] == null) return;
  2376. ItemInfo RealItem = Functions.GetRealItem(Info.Equipment[(int)EquipmentSlot.Weapon].Info, Info.Level, Info.Class, Envir.ItemInfoList);
  2377. if ((RealItem.Shape / Globals.ClassWeaponCount) != 2) return;
  2378. if (Functions.InRange(CurrentLocation, location, Globals.MaxAttackRange) == false) return;
  2379. MapObject target = null;
  2380. if (targetID == ObjectID)
  2381. target = this;
  2382. else if (targetID > 0)
  2383. target = FindObject(targetID, 10);
  2384. if (target != null && target.Dead) return;
  2385. if (target != null && target.Race != ObjectType.Monster && target.Race != ObjectType.Player && target.Race != ObjectType.Hero) return;
  2386. if (target != null && !target.Dead && target.IsAttackTarget(this) && !target.IsFriendlyTarget(this))
  2387. {
  2388. if (this is PlayerObject player &&
  2389. player.PMode == PetMode.FocusMasterTarget)
  2390. {
  2391. foreach (MonsterObject pet in player.Pets)
  2392. {
  2393. if (pet.Race != ObjectType.Creature)
  2394. {
  2395. pet.Target = target;
  2396. }
  2397. }
  2398. if (player.HeroSpawned &&
  2399. !player.Hero.Dead)
  2400. {
  2401. player.Hero.Target = target;
  2402. }
  2403. }
  2404. }
  2405. Direction = dir;
  2406. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2407. UserMagic magic;
  2408. Spell spell = Spell.None;
  2409. bool focus = false;
  2410. if (target != null && !CanFly(target.CurrentLocation) && (Info.MentalState != 1))
  2411. {
  2412. target = null;
  2413. targetID = 0;
  2414. }
  2415. if (target != null)
  2416. {
  2417. magic = GetMagic(Spell.Focus);
  2418. if (magic != null && Envir.Random.Next(5) <= magic.Level)
  2419. {
  2420. focus = true;
  2421. LevelMagic(magic);
  2422. spell = Spell.Focus;
  2423. }
  2424. int distance = Functions.MaxDistance(CurrentLocation, target.CurrentLocation);
  2425. int damage = GetRangeAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC], distance);
  2426. damage = ApplyArcherState(damage);
  2427. int chanceToHit = (100 + Settings.RangeAccuracyBonus - ((100 / Globals.MaxAttackRange) * distance)) * (focus ? 2 : 1);
  2428. if (chanceToHit < 0) chanceToHit = 0;
  2429. int delay = Functions.MaxDistance(CurrentLocation, target.CurrentLocation) * 50 + 500 + 50; //50 MS per Step
  2430. if (Envir.Random.Next(100) < chanceToHit)
  2431. {
  2432. if (target.CurrentLocation != location)
  2433. location = target.CurrentLocation;
  2434. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + delay, target, damage, DefenceType.ACAgility, true);
  2435. ActionList.Add(action);
  2436. }
  2437. else
  2438. {
  2439. DelayedAction action = new DelayedAction(DelayedType.DamageIndicator, Envir.Time + delay, target, DamageType.Miss);
  2440. ActionList.Add(action);
  2441. }
  2442. }
  2443. else
  2444. targetID = 0;
  2445. Enqueue(new S.RangeAttack { TargetID = targetID, Target = location, Spell = spell });
  2446. Broadcast(new S.ObjectRangeAttack { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, TargetID = targetID, Target = location, Spell = spell });
  2447. AttackTime = Envir.Time + AttackSpeed;
  2448. ActionTime = Envir.Time + 550;
  2449. RegenTime = Envir.Time + RegenDelay;
  2450. }
  2451. public void Attack(MirDirection dir, Spell spell)
  2452. {
  2453. LogTime = Envir.Time + Globals.LogDelay;
  2454. bool Mined = false;
  2455. bool MoonLightAttack = false;
  2456. bool DarkBodyAttack = false;
  2457. if (!CanAttack)
  2458. {
  2459. switch (spell)
  2460. {
  2461. case Spell.Slaying:
  2462. Slaying = false;
  2463. break;
  2464. }
  2465. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2466. return;
  2467. }
  2468. if (Hidden)
  2469. {
  2470. for (int i = 0; i < Buffs.Count; i++)
  2471. {
  2472. switch (Buffs[i].Type)
  2473. {
  2474. case BuffType.MoonLight:
  2475. MoonLightAttack = true;
  2476. break;
  2477. case BuffType.DarkBody:
  2478. DarkBodyAttack = true;
  2479. break;
  2480. }
  2481. }
  2482. RemoveBuff(BuffType.MoonLight);
  2483. RemoveBuff(BuffType.DarkBody);
  2484. }
  2485. byte level = 0;
  2486. UserMagic magic;
  2487. if (RidingMount)
  2488. {
  2489. spell = Spell.None;
  2490. }
  2491. switch (spell)
  2492. {
  2493. case Spell.Slaying:
  2494. if (!Slaying)
  2495. spell = Spell.None;
  2496. else
  2497. {
  2498. magic = GetMagic(Spell.Slaying);
  2499. level = magic.Level;
  2500. }
  2501. Slaying = false;
  2502. break;
  2503. case Spell.DoubleSlash:
  2504. magic = GetMagic(spell);
  2505. if (magic == null || magic.Info.BaseCost + (magic.Level * magic.Info.LevelCost) > MP)
  2506. {
  2507. spell = Spell.None;
  2508. break;
  2509. }
  2510. level = magic.Level;
  2511. ChangeMP(-(magic.Info.BaseCost + magic.Level * magic.Info.LevelCost));
  2512. break;
  2513. case Spell.Thrusting:
  2514. case Spell.FlamingSword:
  2515. magic = GetMagic(spell);
  2516. if ((magic == null) || (!FlamingSword && (spell == Spell.FlamingSword)))
  2517. {
  2518. spell = Spell.None;
  2519. break;
  2520. }
  2521. level = magic.Level;
  2522. break;
  2523. case Spell.HalfMoon:
  2524. case Spell.CrossHalfMoon:
  2525. magic = GetMagic(spell);
  2526. if (magic == null || magic.Info.BaseCost + (magic.Level * magic.Info.LevelCost) > MP)
  2527. {
  2528. spell = Spell.None;
  2529. break;
  2530. }
  2531. level = magic.Level;
  2532. ChangeMP(-(magic.Info.BaseCost + magic.Level * magic.Info.LevelCost));
  2533. break;
  2534. case Spell.TwinDrakeBlade:
  2535. magic = GetMagic(spell);
  2536. if (!TwinDrakeBlade || magic == null || magic.Info.BaseCost + magic.Level * magic.Info.LevelCost > MP)
  2537. {
  2538. spell = Spell.None;
  2539. break;
  2540. }
  2541. level = magic.Level;
  2542. ChangeMP(-(magic.Info.BaseCost + magic.Level * magic.Info.LevelCost));
  2543. break;
  2544. default:
  2545. spell = Spell.None;
  2546. break;
  2547. }
  2548. if (!Slaying)
  2549. {
  2550. magic = GetMagic(Spell.Slaying);
  2551. if (magic != null && Envir.Random.Next(12) <= magic.Level)
  2552. {
  2553. Slaying = true;
  2554. Enqueue(new S.SpellToggle { ObjectID = ObjectID, Spell = Spell.Slaying, CanUse = Slaying });
  2555. }
  2556. }
  2557. Direction = dir;
  2558. if (RidingMount) DecreaseMountLoyalty(3);
  2559. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2560. Broadcast(new S.ObjectAttack { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, Spell = spell, Level = level });
  2561. AttackTime = Envir.Time + AttackSpeed;
  2562. ActionTime = Envir.Time + 550;
  2563. RegenTime = Envir.Time + RegenDelay;
  2564. Point target = Functions.PointMove(CurrentLocation, dir, 1);
  2565. //damabeBase = the original damage from your gear (+ bonus from moonlight and darkbody)
  2566. int damageBase = GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]);
  2567. //damageFinal = the damage you're gonna do with skills added
  2568. int damageFinal;
  2569. if (MoonLightAttack || DarkBodyAttack)
  2570. {
  2571. magic = MoonLightAttack ? GetMagic(Spell.MoonLight) : GetMagic(Spell.DarkBody);
  2572. if (magic != null)
  2573. {
  2574. damageBase += magic.GetPower();
  2575. }
  2576. }
  2577. if (!CurrentMap.ValidPoint(target))
  2578. {
  2579. switch (spell)
  2580. {
  2581. case Spell.Thrusting:
  2582. goto Thrusting;
  2583. case Spell.HalfMoon:
  2584. goto HalfMoon;
  2585. case Spell.CrossHalfMoon:
  2586. goto CrossHalfMoon;
  2587. case Spell.None:
  2588. Mined = true;
  2589. goto Mining;
  2590. }
  2591. return;
  2592. }
  2593. Cell cell = CurrentMap.GetCell(target);
  2594. if (cell.Objects == null)
  2595. {
  2596. switch (spell)
  2597. {
  2598. case Spell.Thrusting:
  2599. goto Thrusting;
  2600. case Spell.HalfMoon:
  2601. goto HalfMoon;
  2602. case Spell.CrossHalfMoon:
  2603. goto CrossHalfMoon;
  2604. }
  2605. return;
  2606. }
  2607. damageFinal = damageBase;//incase we're not using skills
  2608. for (int i = 0; i < cell.Objects.Count; i++)
  2609. {
  2610. MapObject ob = cell.Objects[i];
  2611. if (ob.Race != ObjectType.Player && ob.Race != ObjectType.Monster && ob.Race != ObjectType.Hero) continue;
  2612. if (!ob.IsAttackTarget(this)) continue;
  2613. if (ob != null && !ob.Dead && ob.IsAttackTarget(this) && !ob.IsFriendlyTarget(this))
  2614. {
  2615. if (this is PlayerObject player &&
  2616. player.PMode == PetMode.FocusMasterTarget)
  2617. {
  2618. foreach (MonsterObject pet in player.Pets)
  2619. {
  2620. if (pet.Race != ObjectType.Creature)
  2621. {
  2622. pet.Target = ob;
  2623. }
  2624. }
  2625. if (player.HeroSpawned &&
  2626. !player.Hero.Dead)
  2627. {
  2628. player.Hero.Target = ob;
  2629. }
  2630. }
  2631. }
  2632. //Only undead targets
  2633. if (ob.Undead)
  2634. {
  2635. damageBase = Math.Min(int.MaxValue, damageBase + Stats[Stat.Holy]);
  2636. damageFinal = damageBase;//incase we're not using skills
  2637. }
  2638. #region FatalSword
  2639. magic = GetMagic(Spell.FatalSword);
  2640. DefenceType defence = DefenceType.ACAgility;
  2641. if (magic != null)
  2642. {
  2643. if (!FatalSword && Envir.Random.Next(10) == 0)
  2644. FatalSword = true;
  2645. if (FatalSword)
  2646. damageBase = magic.GetDamage(damageBase);
  2647. }
  2648. #endregion
  2649. #region MPEater
  2650. magic = GetMagic(Spell.MPEater);
  2651. if (magic != null)
  2652. {
  2653. int baseCount = 1 + Stats[Stat.Accuracy] / 2;
  2654. int maxCount = baseCount + magic.Level * 5;
  2655. MPEaterCount += Envir.Random.Next(baseCount, maxCount);
  2656. if (MPEater)
  2657. {
  2658. LevelMagic(magic);
  2659. damageFinal = magic.GetDamage(damageBase);
  2660. defence = DefenceType.ACAgility;
  2661. S.ObjectEffect p = new S.ObjectEffect { ObjectID = ob.ObjectID, Effect = SpellEffect.MPEater, EffectType = ObjectID };
  2662. CurrentMap.Broadcast(p, ob.CurrentLocation);
  2663. int addMp = 5 * (magic.Level + Stats[Stat.Accuracy] / 4);
  2664. if (ob.Race == ObjectType.Player)
  2665. {
  2666. ((PlayerObject)ob).ChangeMP(-addMp);
  2667. }
  2668. ChangeMP(addMp);
  2669. MPEaterCount = 0;
  2670. MPEater = false;
  2671. }
  2672. else if (!MPEater && 100 <= MPEaterCount) MPEater = true;
  2673. }
  2674. #endregion
  2675. #region Hemorrhage
  2676. magic = GetMagic(Spell.Hemorrhage);
  2677. if (magic != null)
  2678. {
  2679. HemorrhageAttackCount += Envir.Random.Next(1, 1 + magic.Level * 2);
  2680. if (Hemorrhage)
  2681. {
  2682. damageFinal = magic.GetDamage(damageBase);
  2683. LevelMagic(magic);
  2684. S.ObjectEffect ef = new S.ObjectEffect { ObjectID = ob.ObjectID, Effect = SpellEffect.Hemorrhage };
  2685. CurrentMap.Broadcast(ef, ob.CurrentLocation);
  2686. if (ob == null || ob.Node == null) continue;
  2687. long calcDuration = magic.Level * 2 + Stats[Stat.Luck] / 6;
  2688. ob.ApplyPoison(new Poison
  2689. {
  2690. Duration = (calcDuration <= 0) ? 1 : calcDuration,
  2691. Owner = this,
  2692. PType = PoisonType.Bleeding,
  2693. TickSpeed = 1000,
  2694. Value = Stats[Stat.MaxDC] + 1
  2695. }, this);
  2696. ob.OperateTime = 0;
  2697. HemorrhageAttackCount = 0;
  2698. Hemorrhage = false;
  2699. }
  2700. else if (!Hemorrhage && 55 <= HemorrhageAttackCount) Hemorrhage = true;
  2701. }
  2702. #endregion
  2703. DelayedAction action;
  2704. switch (spell)
  2705. {
  2706. case Spell.Slaying:
  2707. magic = GetMagic(Spell.Slaying);
  2708. damageFinal = magic.GetDamage(damageBase);
  2709. LevelMagic(magic);
  2710. break;
  2711. case Spell.DoubleSlash:
  2712. magic = GetMagic(Spell.DoubleSlash);
  2713. damageFinal = magic.GetDamage(damageBase);
  2714. if (defence == DefenceType.ACAgility) defence = DefenceType.MACAgility;
  2715. action = new DelayedAction(DelayedType.Damage, Envir.Time + 400, ob, damageFinal, DefenceType.Agility, false);
  2716. ActionList.Add(action);
  2717. LevelMagic(magic);
  2718. break;
  2719. case Spell.Thrusting:
  2720. magic = GetMagic(Spell.Thrusting);
  2721. LevelMagic(magic);
  2722. break;
  2723. case Spell.HalfMoon:
  2724. magic = GetMagic(Spell.HalfMoon);
  2725. LevelMagic(magic);
  2726. break;
  2727. case Spell.CrossHalfMoon:
  2728. magic = GetMagic(Spell.CrossHalfMoon);
  2729. LevelMagic(magic);
  2730. break;
  2731. case Spell.TwinDrakeBlade:
  2732. magic = GetMagic(Spell.TwinDrakeBlade);
  2733. damageFinal = magic.GetDamage(damageBase);
  2734. TwinDrakeBlade = false;
  2735. action = new DelayedAction(DelayedType.Damage, Envir.Time + 400,
  2736. ob, //Object (Target)
  2737. damageFinal, //Damage
  2738. DefenceType.Agility, //Defence to target
  2739. false, //Damage Weapon
  2740. magic, //Magic
  2741. true); //Final hit
  2742. ActionList.Add(action);
  2743. LevelMagic(magic);
  2744. break;
  2745. case Spell.FlamingSword:
  2746. magic = GetMagic(Spell.FlamingSword);
  2747. damageFinal = magic.GetDamage(damageBase);
  2748. FlamingSword = false;
  2749. defence = DefenceType.AC;
  2750. //action = new DelayedAction(DelayedType.Damage, Envir.Time + 400, ob, damage, DefenceType.Agility, true);
  2751. //ActionList.Add(action);
  2752. LevelMagic(magic);
  2753. break;
  2754. }
  2755. //if (ob.Attacked(this, damage, defence) <= 0) break;
  2756. action = new DelayedAction(DelayedType.Damage, Envir.Time + 300, ob, damageFinal, defence, true);
  2757. ActionList.Add(action);
  2758. break;
  2759. }
  2760. Thrusting:
  2761. if (spell == Spell.Thrusting)
  2762. {
  2763. target = Functions.PointMove(target, dir, 1);
  2764. if (!CurrentMap.ValidPoint(target)) return;
  2765. cell = CurrentMap.GetCell(target);
  2766. if (cell.Objects == null) return;
  2767. for (int i = 0; i < cell.Objects.Count; i++)
  2768. {
  2769. MapObject ob = cell.Objects[i];
  2770. if (ob.Race != ObjectType.Player && ob.Race != ObjectType.Monster && ob.Race != ObjectType.Hero) continue;
  2771. if (!ob.IsAttackTarget(this)) continue;
  2772. magic = GetMagic(spell);
  2773. damageFinal = magic.GetDamage(damageBase);
  2774. ob.Attacked(this, damageFinal,
  2775. ob is MonsterObject monster && (monster.Info.AI == 49) ? DefenceType.Repulsion : DefenceType.Agility,
  2776. false);
  2777. break;
  2778. }
  2779. }
  2780. HalfMoon:
  2781. if (spell == Spell.HalfMoon)
  2782. {
  2783. dir = Functions.PreviousDir(dir);
  2784. magic = GetMagic(spell);
  2785. damageFinal = magic.GetDamage(damageBase);
  2786. for (int i = 0; i < 4; i++)
  2787. {
  2788. target = Functions.PointMove(CurrentLocation, dir, 1);
  2789. dir = Functions.NextDir(dir);
  2790. if (target == Front) continue;
  2791. if (!CurrentMap.ValidPoint(target)) continue;
  2792. cell = CurrentMap.GetCell(target);
  2793. if (cell.Objects == null) continue;
  2794. for (int o = 0; o < cell.Objects.Count; o++)
  2795. {
  2796. MapObject ob = cell.Objects[o];
  2797. if (ob.Race != ObjectType.Player && ob.Race != ObjectType.Monster) continue;
  2798. if (!ob.IsAttackTarget(this)) continue;
  2799. ob.Attacked(this, damageFinal, DefenceType.Agility, false);
  2800. break;
  2801. }
  2802. }
  2803. }
  2804. CrossHalfMoon:
  2805. if (spell == Spell.CrossHalfMoon)
  2806. {
  2807. magic = GetMagic(spell);
  2808. damageFinal = magic.GetDamage(damageBase);
  2809. for (int i = 0; i < 8; i++)
  2810. {
  2811. target = Functions.PointMove(CurrentLocation, dir, 1);
  2812. dir = Functions.NextDir(dir);
  2813. if (target == Front) continue;
  2814. if (!CurrentMap.ValidPoint(target)) continue;
  2815. cell = CurrentMap.GetCell(target);
  2816. if (cell.Objects == null) continue;
  2817. for (int o = 0; o < cell.Objects.Count; o++)
  2818. {
  2819. MapObject ob = cell.Objects[o];
  2820. if (ob.Race != ObjectType.Player && ob.Race != ObjectType.Monster) continue;
  2821. if (!ob.IsAttackTarget(this)) continue;
  2822. ob.Attacked(this, damageFinal, DefenceType.Agility, false);
  2823. break;
  2824. }
  2825. }
  2826. }
  2827. Mining:
  2828. if (Mined)
  2829. {
  2830. if (Info.Equipment[(int)EquipmentSlot.Weapon] == null) return;
  2831. if (!Info.Equipment[(int)EquipmentSlot.Weapon].Info.CanMine) return;
  2832. if (Info.Equipment[(int)EquipmentSlot.Weapon].CurrentDura <= 0)//Stop dura 0 working. use below if you wish to break the item.
  2833. /*{
  2834. Enqueue(new S.DeleteItem { UniqueID = Info.Equipment[(int)EquipmentSlot.Weapon].UniqueID, Count = Info.Equipment[(int)EquipmentSlot.Weapon].Count });
  2835. Info.Equipment[(int)EquipmentSlot.Weapon] = null;
  2836. RefreshStats();*/
  2837. return;
  2838. /*}*/
  2839. if (CurrentMap.Mine == null) return;
  2840. MineSpot Mine = CurrentMap.Mine[target.X, target.Y];
  2841. if ((Mine == null) || (Mine.Mine == null)) return;
  2842. if (Mine.StonesLeft > 0)
  2843. {
  2844. Mine.StonesLeft--;
  2845. if (Envir.Random.Next(100) < (Mine.Mine.HitRate + (Info.Equipment[(int)EquipmentSlot.Weapon].GetTotal(Stat.Accuracy)) * 10))
  2846. {
  2847. //create some rubble on the floor (or increase whats there)
  2848. SpellObject Rubble = null;
  2849. Cell minecell = CurrentMap.GetCell(CurrentLocation);
  2850. for (int i = 0; i < minecell.Objects.Count; i++)
  2851. {
  2852. if (minecell.Objects[i].Race != ObjectType.Spell) continue;
  2853. SpellObject ob = (SpellObject)minecell.Objects[i];
  2854. if (ob.Spell != Spell.Rubble) continue;
  2855. Rubble = ob;
  2856. Rubble.ExpireTime = Envir.Time + (5 * 60 * 1000);
  2857. break;
  2858. }
  2859. if (Rubble == null)
  2860. {
  2861. Rubble = new SpellObject
  2862. {
  2863. Spell = Spell.Rubble,
  2864. Value = 1,
  2865. ExpireTime = Envir.Time + (5 * 60 * 1000),
  2866. TickSpeed = 2000,
  2867. Caster = null,
  2868. CurrentLocation = CurrentLocation,
  2869. CurrentMap = this.CurrentMap,
  2870. Direction = MirDirection.Up
  2871. };
  2872. CurrentMap.AddObject(Rubble);
  2873. Rubble.Spawned();
  2874. }
  2875. if (Rubble != null)
  2876. {
  2877. ActionList.Add(new DelayedAction(DelayedType.Mine, Envir.Time + 400, Rubble));
  2878. }
  2879. //check if we get a payout
  2880. if (Envir.Random.Next(100) < (Mine.Mine.DropRate + Stats[Stat.MineRatePercent]))
  2881. {
  2882. GetMinePayout(Mine.Mine);
  2883. }
  2884. DamageItem(Info.Equipment[(int)EquipmentSlot.Weapon], 5 + Envir.Random.Next(15));
  2885. }
  2886. }
  2887. else
  2888. {
  2889. if (Envir.Time > Mine.LastRegenTick)
  2890. {
  2891. Mine.LastRegenTick = Envir.Time + Mine.Mine.SpotRegenRate * 60 * 1000;
  2892. Mine.StonesLeft = (byte)Envir.Random.Next(Mine.Mine.MaxStones);
  2893. }
  2894. }
  2895. }
  2896. }
  2897. public virtual bool TryMagic()
  2898. {
  2899. return !Dead && Envir.Time >= ActionTime || Envir.Time >= SpellTime;
  2900. }
  2901. public virtual void BeginMagic(Spell spell, MirDirection dir, uint targetID, Point location, Boolean spellTargetLock = false)
  2902. {
  2903. Magic(spell, dir, targetID, location, spellTargetLock);
  2904. }
  2905. public int MagicCost(UserMagic magic)
  2906. {
  2907. int cost = magic.Info.BaseCost + magic.Info.LevelCost * magic.Level;
  2908. Spell spell = magic.Spell;
  2909. if (spell == Spell.Teleport || spell == Spell.Blink || spell == Spell.StormEscape)
  2910. {
  2911. if (Stats[Stat.TeleportManaPenaltyPercent] > 0)
  2912. {
  2913. cost += (cost * Stats[Stat.TeleportManaPenaltyPercent]) / 100;
  2914. }
  2915. }
  2916. if (Stats[Stat.ManaPenaltyPercent] > 0)
  2917. {
  2918. cost += (cost * Stats[Stat.ManaPenaltyPercent]) / 100;
  2919. }
  2920. if (spell == Spell.Plague)
  2921. {
  2922. cost = Stats[Stat.MaxSC] + Stats[Stat.MinSC];
  2923. }
  2924. return cost;
  2925. }
  2926. public virtual MapObject DefaultMagicTarget => this;
  2927. public void Magic(Spell spell, MirDirection dir, uint targetID, Point location, bool spellTargetLock = false)
  2928. {
  2929. if (!CanCast)
  2930. {
  2931. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2932. return;
  2933. }
  2934. UserMagic magic = GetMagic(spell);
  2935. if (magic == null)
  2936. {
  2937. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2938. return;
  2939. }
  2940. if ((location.X != 0) && (location.Y != 0) && magic.Info.Range != 0 && Functions.InRange(CurrentLocation, location, magic.Info.Range) == false) return;
  2941. if (Hidden)
  2942. {
  2943. RemoveBuff(BuffType.MoonLight);
  2944. RemoveBuff(BuffType.DarkBody);
  2945. }
  2946. AttackTime = Envir.Time + MoveDelay;
  2947. SpellTime = Envir.Time + 1800; //Spell Delay
  2948. if (spell != Spell.ShoulderDash)
  2949. {
  2950. ActionTime = Envir.Time + MoveDelay;
  2951. }
  2952. LogTime = Envir.Time + Globals.LogDelay;
  2953. long delay = magic.GetDelay();
  2954. if (magic != null && Envir.Time < (magic.CastTime + delay))
  2955. {
  2956. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2957. return;
  2958. }
  2959. int cost = MagicCost(magic);
  2960. if (cost > MP)
  2961. {
  2962. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2963. return;
  2964. }
  2965. RegenTime = Envir.Time + RegenDelay;
  2966. ChangeMP(-cost);
  2967. if (spell == Spell.ShoulderDash && Race == ObjectType.Hero)
  2968. dir = Direction;
  2969. Direction = dir;
  2970. if (spell != Spell.ShoulderDash && spell != Spell.BackStep && spell != Spell.FlashDash)
  2971. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  2972. MapObject target = null;
  2973. if (targetID == ObjectID)
  2974. {
  2975. target = this;
  2976. }
  2977. else if (targetID > 0)
  2978. {
  2979. target = FindObject(targetID, 10);
  2980. }
  2981. if (target != null && target.Race != ObjectType.Monster && target.Race != ObjectType.Player && target.Race != ObjectType.Hero)
  2982. {
  2983. target = null;
  2984. }
  2985. if (target != null && !target.Dead && target.IsAttackTarget(this) && !target.IsFriendlyTarget(this))
  2986. {
  2987. if (this is PlayerObject player &&
  2988. player.PMode == PetMode.FocusMasterTarget)
  2989. {
  2990. foreach (MonsterObject pet in player.Pets)
  2991. {
  2992. if (pet.Race != ObjectType.Creature)
  2993. {
  2994. pet.Target = target;
  2995. }
  2996. }
  2997. if (player.HeroSpawned &&
  2998. !player.Hero.Dead)
  2999. {
  3000. player.Hero.Target = target;
  3001. }
  3002. }
  3003. }
  3004. bool cast = true;
  3005. byte level = magic.Level;
  3006. switch (spell)
  3007. {
  3008. case Spell.FireBall:
  3009. case Spell.GreatFireBall:
  3010. case Spell.FrostCrunch:
  3011. if (!Fireball(target, magic)) targetID = 0;
  3012. break;
  3013. case Spell.Healing:
  3014. if (target == null)
  3015. {
  3016. target = DefaultMagicTarget;
  3017. targetID = ObjectID;
  3018. }
  3019. Healing(target, magic);
  3020. break;
  3021. case Spell.Repulsion:
  3022. case Spell.EnergyRepulsor:
  3023. case Spell.FireBurst:
  3024. Repulsion(magic);
  3025. break;
  3026. case Spell.ElectricShock:
  3027. ActionList.Add(new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, target as MonsterObject));
  3028. break;
  3029. case Spell.Poisoning:
  3030. if (!Poisoning(target, magic)) cast = false;
  3031. break;
  3032. case Spell.HellFire:
  3033. HellFire(magic);
  3034. break;
  3035. case Spell.ThunderBolt:
  3036. ThunderBolt(target, magic);
  3037. break;
  3038. case Spell.SoulFireBall:
  3039. if (!SoulFireball(target, magic, out cast)) targetID = 0;
  3040. break;
  3041. case Spell.SummonSkeleton:
  3042. SummonSkeleton(magic);
  3043. break;
  3044. case Spell.Teleport:
  3045. case Spell.Blink:
  3046. ActionList.Add(new DelayedAction(DelayedType.Magic, Envir.Time + 200, magic, location));
  3047. break;
  3048. case Spell.Hiding:
  3049. Hiding(magic);
  3050. break;
  3051. case Spell.Haste:
  3052. case Spell.LightBody:
  3053. ActionList.Add(new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic));
  3054. break;
  3055. case Spell.Fury:
  3056. FurySpell(magic, out cast);
  3057. break;
  3058. case Spell.ImmortalSkin:
  3059. ImmortalSkin(magic, out cast);
  3060. break;
  3061. case Spell.FireBang:
  3062. case Spell.IceStorm:
  3063. FireBang(magic, spellTargetLock ? (target != null ? target.CurrentLocation : location) : location);
  3064. break;
  3065. case Spell.MassHiding:
  3066. MassHiding(magic, spellTargetLock ? (target != null ? target.CurrentLocation : location) : location, out cast);
  3067. break;
  3068. case Spell.SoulShield:
  3069. case Spell.BlessedArmour:
  3070. SoulShield(magic, spellTargetLock ? (target != null ? target.CurrentLocation : location) : location, out cast);
  3071. break;
  3072. case Spell.FireWall:
  3073. FireWall(magic, spellTargetLock ? (target != null ? target.CurrentLocation : location) : location);
  3074. break;
  3075. case Spell.Lightning:
  3076. Lightning(magic);
  3077. break;
  3078. case Spell.HeavenlySword:
  3079. HeavenlySword(magic);
  3080. break;
  3081. case Spell.MassHealing:
  3082. MassHealing(magic, spellTargetLock ? (target != null ? target.CurrentLocation : location) : location);
  3083. break;
  3084. case Spell.ShoulderDash:
  3085. ShoulderDash(magic);
  3086. return;
  3087. case Spell.ThunderStorm:
  3088. case Spell.FlameField:
  3089. case Spell.StormEscape:
  3090. ThunderStorm(magic);
  3091. if (spell == Spell.FlameField)
  3092. SpellTime = Envir.Time + 2500; //Spell Delay
  3093. if (spell == Spell.StormEscape)
  3094. //Start teleport.
  3095. ActionList.Add(new DelayedAction(DelayedType.Magic, Envir.Time + 750, magic, location));
  3096. break;
  3097. case Spell.MagicShield:
  3098. ActionList.Add(new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, magic.GetPower(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]) + 15)));
  3099. break;
  3100. case Spell.FlameDisruptor:
  3101. FlameDisruptor(target, magic);
  3102. break;
  3103. case Spell.TurnUndead:
  3104. TurnUndead(target, magic);
  3105. break;
  3106. case Spell.MagicBooster:
  3107. MagicBooster(magic);
  3108. break;
  3109. case Spell.Vampirism:
  3110. Vampirism(target, magic);
  3111. break;
  3112. case Spell.SummonShinsu:
  3113. SummonShinsu(magic);
  3114. break;
  3115. case Spell.Purification:
  3116. if (target == null)
  3117. {
  3118. target = DefaultMagicTarget;
  3119. targetID = ObjectID;
  3120. }
  3121. Purification(target, magic);
  3122. break;
  3123. case Spell.LionRoar:
  3124. case Spell.BattleCry:
  3125. CurrentMap.ActionList.Add(new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, CurrentLocation));
  3126. break;
  3127. case Spell.Revelation:
  3128. Revelation(target, magic);
  3129. break;
  3130. case Spell.PoisonCloud:
  3131. PoisonCloud(magic, location, out cast);
  3132. break;
  3133. case Spell.Entrapment:
  3134. Entrapment(target, magic);
  3135. break;
  3136. case Spell.BladeAvalanche:
  3137. BladeAvalanche(magic);
  3138. break;
  3139. case Spell.SlashingBurst:
  3140. ActionList.Add(new DelayedAction(DelayedType.Magic, Envir.Time + 300, magic));
  3141. break;
  3142. case Spell.Rage:
  3143. Rage(magic);
  3144. break;
  3145. case Spell.Mirroring:
  3146. Mirroring(magic);
  3147. break;
  3148. case Spell.Blizzard:
  3149. Blizzard(magic, spellTargetLock ? (target != null ? target.CurrentLocation : location) : location, out cast);
  3150. break;
  3151. case Spell.MeteorStrike:
  3152. MeteorStrike(magic, spellTargetLock ? (target != null ? target.CurrentLocation : location) : location, out cast);
  3153. break;
  3154. case Spell.IceThrust:
  3155. IceThrust(magic);
  3156. break;
  3157. case Spell.ProtectionField:
  3158. ProtectionField(magic);
  3159. break;
  3160. case Spell.PetEnhancer:
  3161. PetEnhancer(target, magic, out cast);
  3162. break;
  3163. case Spell.TrapHexagon:
  3164. TrapHexagon(magic, spellTargetLock ? (target != null ? target.CurrentLocation : location) : location, out cast);
  3165. break;
  3166. case Spell.Reincarnation:
  3167. if (!CurrentMap.Info.NoReincarnation)
  3168. Reincarnation(magic, target == null ? null : target as PlayerObject, out cast);
  3169. break;
  3170. case Spell.Curse:
  3171. Curse(magic, spellTargetLock ? (target != null ? target.CurrentLocation : location) : location, out cast);
  3172. break;
  3173. case Spell.SummonHolyDeva:
  3174. SummonHolyDeva(magic);
  3175. break;
  3176. case Spell.Hallucination:
  3177. Hallucination(target, magic);
  3178. break;
  3179. case Spell.EnergyShield:
  3180. EnergyShield(target, magic, out cast);
  3181. break;
  3182. case Spell.UltimateEnhancer:
  3183. UltimateEnhancer(target, magic, out cast);
  3184. break;
  3185. case Spell.Plague:
  3186. Plague(magic, spellTargetLock ? (target != null ? target.CurrentLocation : location) : location, out cast);
  3187. break;
  3188. case Spell.SwiftFeet:
  3189. SwiftFeet(magic, out cast);
  3190. break;
  3191. case Spell.MoonLight:
  3192. MoonLight(magic);
  3193. break;
  3194. case Spell.Trap:
  3195. Trap(magic, target, out cast);
  3196. break;
  3197. case Spell.CatTongue:
  3198. CatTongue(target, magic);
  3199. break;
  3200. case Spell.PoisonSword:
  3201. PoisonSword(magic);
  3202. break;
  3203. case Spell.DarkBody:
  3204. DarkBody(target, magic);
  3205. break;
  3206. case Spell.FlashDash:
  3207. FlashDash(magic);
  3208. return;
  3209. case Spell.CrescentSlash:
  3210. CrescentSlash(magic);
  3211. break;
  3212. case Spell.StraightShot:
  3213. if (!StraightShot(target, magic)) targetID = 0;
  3214. break;
  3215. case Spell.DoubleShot:
  3216. if (!DoubleShot(target, magic)) targetID = 0;
  3217. break;
  3218. case Spell.BackStep:
  3219. BackStep(magic);
  3220. return;
  3221. case Spell.ExplosiveTrap:
  3222. ExplosiveTrap(magic, Front);
  3223. break;
  3224. case Spell.DelayedExplosion:
  3225. if (!DelayedExplosion(target, magic)) targetID = 0;
  3226. break;
  3227. case Spell.Concentration:
  3228. Concentration(magic);
  3229. break;
  3230. case Spell.ElementalShot:
  3231. if (!ElementalShot(target, magic)) targetID = 0;
  3232. break;
  3233. case Spell.ElementalBarrier:
  3234. ActionList.Add(new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, magic.GetPower(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]))));
  3235. break;
  3236. case Spell.BindingShot:
  3237. BindingShot(magic, target, out cast);
  3238. break;
  3239. case Spell.SummonVampire:
  3240. case Spell.SummonToad:
  3241. case Spell.SummonSnakes:
  3242. ArcherSummon(magic, target, location);
  3243. break;
  3244. case Spell.Stonetrap:
  3245. ArcherSummonStone(magic, spellTargetLock ? (target != null ? target.CurrentLocation : location) : location, out cast);
  3246. break;
  3247. case Spell.VampireShot:
  3248. case Spell.PoisonShot:
  3249. case Spell.CrippleShot:
  3250. SpecialArrowShot(target, magic);
  3251. break;
  3252. case Spell.NapalmShot:
  3253. NapalmShot(target, magic);
  3254. break;
  3255. case Spell.OneWithNature:
  3256. OneWithNature(target, magic);
  3257. break;
  3258. case Spell.MoonMist:
  3259. MoonMist(magic);
  3260. break;
  3261. case Spell.HealingCircle:
  3262. HealingCircle(magic, spellTargetLock ? (target != null ? target.CurrentLocation : location) : location);
  3263. break;
  3264. //Custom Spells
  3265. case Spell.Portal:
  3266. Portal(magic, location, out cast);
  3267. break;
  3268. case Spell.MeteorShower:
  3269. if (!MeteorShower(target, magic)) targetID = 0;
  3270. return;
  3271. case Spell.FireBounce:
  3272. if (!FireBounce(target, magic, this)) targetID = 0;
  3273. break;
  3274. default:
  3275. cast = false;
  3276. break;
  3277. }
  3278. if (cast)
  3279. {
  3280. magic.CastTime = Envir.Time;
  3281. }
  3282. Enqueue(new S.Magic { Spell = spell, TargetID = targetID, Target = location, Cast = cast, Level = level });
  3283. Broadcast(new S.ObjectMagic { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, Spell = spell, TargetID = targetID, Target = location, Cast = cast, Level = level });
  3284. }
  3285. #region Elemental System
  3286. private void Concentration(UserMagic magic)
  3287. {
  3288. int duration = 45 + (15 * magic.Level);
  3289. var buff = AddBuff(BuffType.Concentration, this, Settings.Second * duration, new Stats());
  3290. buff.Set("InterruptTime", (long)0);
  3291. buff.Set("Interrupted", false);
  3292. LevelMagic(magic);
  3293. OperateTime = 0;
  3294. UpdateConcentration(true, false);
  3295. }
  3296. public void UpdateConcentration(bool concentrating, bool interrupted)
  3297. {
  3298. Enqueue(new S.SetConcentration { ObjectID = ObjectID, Enabled = concentrating, Interrupted = interrupted });
  3299. Broadcast(new S.SetConcentration { ObjectID = ObjectID, Enabled = concentrating, Interrupted = interrupted });
  3300. }
  3301. private bool ElementalShot(MapObject target, UserMagic magic)
  3302. {
  3303. if (HasElemental)
  3304. {
  3305. if (target == null || !target.IsAttackTarget(this)) return false;
  3306. if ((Info.MentalState != 1) && !CanFly(target.CurrentLocation)) return false;
  3307. int orbPower = GetElementalOrbPower(false);//base power + orbpower
  3308. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]) + orbPower);
  3309. int delay = Functions.MaxDistance(CurrentLocation, target.CurrentLocation) * 50 + 500; //50 MS per Step
  3310. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, damage, target, target.CurrentLocation);
  3311. ActionList.Add(action);
  3312. }
  3313. else
  3314. {
  3315. ObtainElement(true);//gather orb through casting
  3316. LevelMagic(magic);
  3317. return false;
  3318. }
  3319. return true;
  3320. }
  3321. public void GatherElement()
  3322. {
  3323. UserMagic magic = GetMagic(Spell.Meditation);
  3324. if (magic == null) return;
  3325. int meditationLvl = magic.Level;
  3326. int concentrateChance = 0;
  3327. if (HasBuff(BuffType.Concentration, out Buff concentration) && !concentration.Get<bool>("Interrupted"))
  3328. {
  3329. magic = GetMagic(Spell.Concentration);
  3330. if (magic != null)
  3331. {
  3332. concentrateChance = magic.Level + 1;
  3333. }
  3334. }
  3335. if (meditationLvl >= 0)
  3336. {
  3337. int rnd = Envir.Random.Next(10);
  3338. if (rnd >= (8 - meditationLvl - concentrateChance))
  3339. {
  3340. ObtainElement(false);
  3341. LevelMagic(GetMagic(Spell.Meditation));
  3342. }
  3343. }
  3344. }
  3345. public void ObtainElement(bool cast)
  3346. {
  3347. int orbType = 0;
  3348. int meditateLevel = 0;
  3349. UserMagic spell = GetMagic(Spell.Meditation);
  3350. if (spell == null)
  3351. {
  3352. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.SkillRequiresMeditation), ChatType.System);
  3353. return;
  3354. }
  3355. meditateLevel = spell.Level;
  3356. int maxOrbs = (int)Settings.OrbsExpList[Settings.OrbsExpList.Count - 1];
  3357. if (cast)
  3358. {
  3359. ElementsLevel = (int)Settings.OrbsExpList[0];
  3360. orbType = 1;
  3361. if (Settings.GatherOrbsPerLevel)//Meditation Orbs per level
  3362. if (meditateLevel == 3)
  3363. {
  3364. Enqueue(new S.SetElemental { ObjectID = ObjectID, Enabled = true, Value = (uint)Settings.OrbsExpList[0], ElementType = 1, ExpLast = (uint)maxOrbs });
  3365. Broadcast(new S.SetElemental { ObjectID = ObjectID, Enabled = true, Casted = true, Value = (uint)Settings.OrbsExpList[0], ElementType = 1, ExpLast = (uint)maxOrbs });
  3366. ElementsLevel = (int)Settings.OrbsExpList[1];
  3367. orbType = 2;
  3368. }
  3369. HasElemental = true;
  3370. }
  3371. else
  3372. {
  3373. HasElemental = false;
  3374. ElementsLevel++;
  3375. if (Settings.GatherOrbsPerLevel)//Meditation Orbs per level
  3376. if (ElementsLevel > Settings.OrbsExpList[GetMagic(Spell.Meditation).Level])
  3377. {
  3378. HasElemental = true;
  3379. ElementsLevel = (int)Settings.OrbsExpList[GetMagic(Spell.Meditation).Level];
  3380. return;
  3381. }
  3382. if (ElementsLevel >= Settings.OrbsExpList[0]) HasElemental = true;
  3383. for (int i = 0; i <= Settings.OrbsExpList.Count - 1; i++)
  3384. {
  3385. if (Settings.OrbsExpList[i] != ElementsLevel) continue;
  3386. orbType = i + 1;
  3387. break;
  3388. }
  3389. }
  3390. Enqueue(new S.SetElemental { ObjectID = ObjectID, Enabled = HasElemental, Value = (uint)ElementsLevel, ElementType = (uint)orbType, ExpLast = (uint)maxOrbs });
  3391. Broadcast(new S.SetElemental { ObjectID = ObjectID, Enabled = HasElemental, Casted = cast, Value = (uint)ElementsLevel, ElementType = (uint)orbType, ExpLast = (uint)maxOrbs });
  3392. }
  3393. public int GetElementalOrbCount()
  3394. {
  3395. int OrbCount = 0;
  3396. for (int i = Settings.OrbsExpList.Count - 1; i >= 0; i--)
  3397. {
  3398. if (ElementsLevel >= Settings.OrbsExpList[i])
  3399. {
  3400. OrbCount = i + 1;
  3401. break;
  3402. }
  3403. }
  3404. return OrbCount;
  3405. }
  3406. public int GetElementalOrbPower(bool defensive)
  3407. {
  3408. if (!HasElemental) return 0;
  3409. if (defensive)
  3410. return (int)Settings.OrbsDefList[GetElementalOrbCount() - 1];
  3411. if (!defensive)
  3412. return (int)Settings.OrbsDmgList[GetElementalOrbCount() - 1];
  3413. return 0;
  3414. }
  3415. #endregion
  3416. #region Wizard Skills
  3417. private bool Fireball(MapObject target, UserMagic magic)
  3418. {
  3419. if (target == null || !target.IsAttackTarget(this) || !CanFly(target.CurrentLocation)) return false;
  3420. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  3421. int delay = Functions.MaxDistance(CurrentLocation, target.CurrentLocation) * 50 + 500; //50 MS per Step
  3422. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, damage, target, target.CurrentLocation);
  3423. ActionList.Add(action);
  3424. return true;
  3425. }
  3426. private void Repulsion(UserMagic magic)
  3427. {
  3428. bool result = false;
  3429. for (int d = 0; d <= 1; d++)
  3430. {
  3431. for (int y = CurrentLocation.Y - d; y <= CurrentLocation.Y + d; y++)
  3432. {
  3433. if (y < 0) continue;
  3434. if (y >= CurrentMap.Height) break;
  3435. for (int x = CurrentLocation.X - d; x <= CurrentLocation.X + d; x += Math.Abs(y - CurrentLocation.Y) == d ? 1 : d * 2)
  3436. {
  3437. if (x < 0) continue;
  3438. if (x >= CurrentMap.Width) break;
  3439. Cell cell = CurrentMap.GetCell(x, y);
  3440. if (!cell.Valid || cell.Objects == null) continue;
  3441. for (int i = 0; cell.Objects != null && i < cell.Objects.Count; i++)
  3442. {
  3443. MapObject ob = cell.Objects[i];
  3444. if (ob.Race != ObjectType.Monster && ob.Race != ObjectType.Player && ob.Race != ObjectType.Hero) continue;
  3445. if (!ob.IsAttackTarget(this) || ob.Level >= Level) continue;
  3446. if (Envir.Random.Next(20) >= 6 + magic.Level * 3 + Level - ob.Level) continue;
  3447. int distance = 1 + Math.Max(0, magic.Level - 1) + Envir.Random.Next(2);
  3448. MirDirection dir = Functions.DirectionFromPoint(CurrentLocation, ob.CurrentLocation);
  3449. if (ob.Pushed(this, dir, distance) == 0) continue;
  3450. if (ob.Race == ObjectType.Player)
  3451. {
  3452. SafeZoneInfo szi = CurrentMap.GetSafeZone(ob.CurrentLocation);
  3453. if (szi != null)
  3454. {
  3455. ((PlayerObject)ob).BindLocation = szi.Location;
  3456. ((PlayerObject)ob).BindMapIndex = CurrentMapIndex;
  3457. ob.InSafeZone = true;
  3458. }
  3459. else
  3460. ob.InSafeZone = false;
  3461. ob.Attacked(this, magic.GetDamage(0), DefenceType.None, false);
  3462. }
  3463. result = true;
  3464. }
  3465. }
  3466. }
  3467. }
  3468. if (result) LevelMagic(magic);
  3469. }
  3470. private void ElectricShock(MonsterObject target, UserMagic magic)
  3471. {
  3472. if (CurrentMap.Info.NoPets)
  3473. {
  3474. ReceiveChat("You cannot summon pets on this map.", ChatType.System);
  3475. return;
  3476. }
  3477. if (target == null || !target.IsAttackTarget(this)) return;
  3478. if (Envir.Random.Next(4 - magic.Level) > 0)
  3479. {
  3480. if (Envir.Random.Next(2) == 0) LevelMagic(magic);
  3481. return;
  3482. }
  3483. LevelMagic(magic);
  3484. if (target.Master == this)
  3485. {
  3486. target.ShockTime = Envir.Time + (magic.Level * 5 + 10) * 1000;
  3487. target.Target = null;
  3488. return;
  3489. }
  3490. if (Envir.Random.Next(2) > 0)
  3491. {
  3492. target.ShockTime = Envir.Time + (magic.Level * 5 + 10) * 1000;
  3493. target.Target = null;
  3494. return;
  3495. }
  3496. if (target.Level > Level + 2 || !target.Info.CanTame) return;
  3497. if (target.Info.IsBoss)
  3498. {
  3499. int limit = Settings.MaxBossTames;
  3500. if (limit <= 0) return;
  3501. int currentBossTames = Pets.Count(p => !p.Dead && p.Race != ObjectType.Creature && p.Info != null && p.Info.IsBoss);
  3502. if (currentBossTames >= limit) return;
  3503. }
  3504. if (Envir.Random.Next(Level + 20 + magic.Level * 5) <= target.Level + 10)
  3505. {
  3506. if (Envir.Random.Next(5) > 0 && target.Master == null)
  3507. {
  3508. target.RageTime = Envir.Time + (Envir.Random.Next(20) + 10) * 1000;
  3509. target.Target = null;
  3510. }
  3511. return;
  3512. }
  3513. var petBonus = Globals.MaxPets - 3;
  3514. if (Pets.Count(t => !t.Dead && t.Race != ObjectType.Creature) >= magic.Level + petBonus) return;
  3515. int rate = (int)(target.Stats[Stat.HP] / 100);
  3516. if (rate <= 2) rate = 2;
  3517. else rate *= 2;
  3518. if (Envir.Random.Next(rate) != 0) return;
  3519. //else if (Envir.Random.Next(20) == 0) target.Die();
  3520. if (target.Master != null)
  3521. {
  3522. target.SetHP(target.Stats[Stat.HP] / 10);
  3523. target.Master.Pets.Remove(target);
  3524. }
  3525. else if (target.Respawn != null)
  3526. {
  3527. target.Respawn.Count--;
  3528. Envir.MonsterCount--;
  3529. CurrentMap.MonsterCount--;
  3530. target.Respawn = null;
  3531. }
  3532. target.Master = this;
  3533. //target.HealthChanged = true;
  3534. target.BroadcastHealthChange();
  3535. Pets.Add(target);
  3536. target.Target = null;
  3537. target.RageTime = 0;
  3538. target.ShockTime = 0;
  3539. target.OperateTime = 0;
  3540. target.MaxPetLevel = (byte)(1 + magic.Level * 2);
  3541. if (!Settings.PetSave)
  3542. {
  3543. target.TameTime = Envir.Time + (Settings.Minute * 60);
  3544. }
  3545. target.Broadcast(new S.ObjectName { ObjectID = target.ObjectID, Name = target.Name });
  3546. }
  3547. private void HellFire(UserMagic magic)
  3548. {
  3549. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  3550. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damage, CurrentLocation, Direction, 4);
  3551. CurrentMap.ActionList.Add(action);
  3552. if (magic.Level != 3) return;
  3553. MirDirection dir = (MirDirection)(((int)Direction + 1) % 8);
  3554. action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damage, CurrentLocation, dir, 4);
  3555. CurrentMap.ActionList.Add(action);
  3556. dir = (MirDirection)(((int)Direction - 1 + 8) % 8);
  3557. action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damage, CurrentLocation, dir, 4);
  3558. CurrentMap.ActionList.Add(action);
  3559. }
  3560. private void ThunderBolt(MapObject target, UserMagic magic)
  3561. {
  3562. if (target == null || !target.IsAttackTarget(this)) return;
  3563. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  3564. if (target.Undead) damage = (int)(damage * 1.5F);
  3565. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, damage, target, target.CurrentLocation);
  3566. ActionList.Add(action);
  3567. }
  3568. private void Vampirism(MapObject target, UserMagic magic)
  3569. {
  3570. if (target == null || !target.IsAttackTarget(this)) return;
  3571. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  3572. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, damage, target);
  3573. ActionList.Add(action);
  3574. }
  3575. private void FireBang(UserMagic magic, Point location)
  3576. {
  3577. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  3578. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damage, location);
  3579. CurrentMap.ActionList.Add(action);
  3580. }
  3581. private void FireWall(UserMagic magic, Point location)
  3582. {
  3583. List<SpellObject> activeFireWalls = null;
  3584. if (CurrentMap.Info.FireWallLimit && CurrentMap.Info.FireWallCount > 0)
  3585. {
  3586. activeFireWalls = Envir
  3587. .GetObjects(CurrentMapIndex, ObjectType.Spell)
  3588. .OfType<SpellObject>()
  3589. .Where(so => so.Spell == Spell.FireWall && so.Caster == this)
  3590. .ToList();
  3591. var activeCasts = activeFireWalls
  3592. .Select(so => so.CastInstanceId)
  3593. .DefaultIfEmpty(0)
  3594. .Distinct()
  3595. .Count();
  3596. if (activeCasts >= CurrentMap.Info.FireWallCount)
  3597. {
  3598. if (!TryReplaceOldestFireWallCast(activeFireWalls))
  3599. {
  3600. ReceiveChat("Unable to recycle an existing FireWall. Please wait a moment.", ChatType.System);
  3601. return;
  3602. }
  3603. }
  3604. }
  3605. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  3606. int castId = ++_fireWallCastSeq;
  3607. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damage, location, castId);
  3608. CurrentMap.ActionList.Add(action);
  3609. }
  3610. private bool TryReplaceOldestFireWallCast(List<SpellObject> activeFireWalls)
  3611. {
  3612. if (activeFireWalls == null || activeFireWalls.Count == 0) return false;
  3613. var targetGroup = activeFireWalls
  3614. .GroupBy(so => so.CastInstanceId)
  3615. .OrderBy(g => g.Key == 0 ? int.MinValue : g.Key)
  3616. .FirstOrDefault();
  3617. if (targetGroup == null) return false;
  3618. foreach (var spell in targetGroup)
  3619. {
  3620. if (spell.CurrentMap != null)
  3621. {
  3622. spell.CurrentMap.RemoveObject(spell);
  3623. }
  3624. if (spell.Node != null)
  3625. {
  3626. spell.Despawn();
  3627. }
  3628. }
  3629. return true;
  3630. }
  3631. private void Lightning(UserMagic magic)
  3632. {
  3633. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  3634. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damage, CurrentLocation, Direction);
  3635. CurrentMap.ActionList.Add(action);
  3636. }
  3637. private void TurnUndead(MapObject target, UserMagic magic)
  3638. {
  3639. if(target != null &&
  3640. target.Race == ObjectType.Monster &&
  3641. target.Undead &&
  3642. target.IsAttackTarget(this))
  3643. {
  3644. // undead pet logic
  3645. if (target.Master is PlayerObject master)
  3646. {
  3647. if (master.PKPoints < 200 &&
  3648. (master.BrownTime == 0 &&
  3649. !master.AtWar(this)))
  3650. {
  3651. BrownTime = Envir.Time + Settings.Minute;
  3652. }
  3653. }
  3654. if (Envir.Random.Next(2) + Level - 1 <= target.Level)
  3655. {
  3656. target.Target = this;
  3657. return;
  3658. }
  3659. int dif = Level - target.Level + 15;
  3660. if (Envir.Random.Next(100) >= (magic.Level + 1 << 3) + dif)
  3661. {
  3662. target.Target = this;
  3663. return;
  3664. }
  3665. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, target);
  3666. ActionList.Add(action);
  3667. }
  3668. }
  3669. private void FlameDisruptor(MapObject target, UserMagic magic)
  3670. {
  3671. if (target == null || (target.Race != ObjectType.Player && target.Race != ObjectType.Monster) || !target.IsAttackTarget(this)) return;
  3672. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  3673. if (!target.Undead) damage = (int)(damage * 1.5F);
  3674. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, damage, target, target.CurrentLocation);
  3675. ActionList.Add(action);
  3676. }
  3677. private void ThunderStorm(UserMagic magic)
  3678. {
  3679. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  3680. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damage, CurrentLocation);
  3681. CurrentMap.ActionList.Add(action);
  3682. }
  3683. private void Mirroring(UserMagic magic)
  3684. {
  3685. if (CurrentMap.Info.NoPets)
  3686. {
  3687. ReceiveChat("You cannot summon pets on this map.", ChatType.System);
  3688. return;
  3689. }
  3690. MonsterObject monster;
  3691. DelayedAction action;
  3692. for (int i = 0; i < Pets.Count; i++)
  3693. {
  3694. monster = Pets[i];
  3695. if ((monster.Info.Name != Settings.CloneName) || monster.Dead) continue;
  3696. if (monster.Node == null) continue;
  3697. action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, monster, Front, true);
  3698. CurrentMap.ActionList.Add(action);
  3699. return;
  3700. }
  3701. MonsterInfo info = Envir.GetMonsterInfo(Settings.CloneName);
  3702. if (info == null) return;
  3703. LevelMagic(magic);
  3704. monster = MonsterObject.GetMonster(info);
  3705. monster.Master = this;
  3706. monster.ActionTime = Envir.Time + 1000;
  3707. monster.RefreshNameColour(false);
  3708. Pets.Add(monster);
  3709. action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, monster, Front, false);
  3710. CurrentMap.ActionList.Add(action);
  3711. }
  3712. private void Blizzard(UserMagic magic, Point location, out bool cast)
  3713. {
  3714. cast = false;
  3715. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  3716. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damage, location);
  3717. ActiveBlizzard = true;
  3718. CurrentMap.ActionList.Add(action);
  3719. cast = true;
  3720. }
  3721. private void MeteorStrike(UserMagic magic, Point location, out bool cast)
  3722. {
  3723. cast = false;
  3724. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  3725. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damage, location);
  3726. ActiveBlizzard = true;
  3727. CurrentMap.ActionList.Add(action);
  3728. cast = true;
  3729. }
  3730. private void IceThrust(UserMagic magic)
  3731. {
  3732. int damageBase = GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]);
  3733. if (Envir.Random.Next(100) < (1 + Stats[Stat.Luck]))
  3734. damageBase += damageBase;
  3735. int damageFinish = magic.GetDamage(damageBase);
  3736. Point location = Functions.PointMove(CurrentLocation, Direction, 1);
  3737. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 1500, this, magic, location, Direction, damageFinish, (int)(damageFinish * 0.6));
  3738. CurrentMap.ActionList.Add(action);
  3739. }
  3740. private void MagicBooster(UserMagic magic)
  3741. {
  3742. int bonus = 6 + magic.Level * 6;
  3743. ActionList.Add(new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, bonus));
  3744. }
  3745. #endregion
  3746. #region Taoist Skills
  3747. private void Healing(MapObject target, UserMagic magic)
  3748. {
  3749. if (target == null || !target.IsFriendlyTarget(this)) return;
  3750. int health = magic.GetDamage(GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]) * 2) + Level;
  3751. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, health, target);
  3752. ActionList.Add(action);
  3753. }
  3754. private bool Poisoning(MapObject target, UserMagic magic)
  3755. {
  3756. if (target == null || !target.IsAttackTarget(this)) return false;
  3757. UserItem item = GetPoison(1);
  3758. if (item == null) return false;
  3759. int power = magic.GetDamage(GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]));
  3760. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, power, target, item);
  3761. ActionList.Add(action);
  3762. ConsumeItem(item, 1);
  3763. return true;
  3764. }
  3765. private bool SoulFireball(MapObject target, UserMagic magic, out bool cast)
  3766. {
  3767. cast = false;
  3768. UserItem item = GetAmulet(1);
  3769. if (item == null) return false;
  3770. cast = true;
  3771. if (target == null || !target.IsAttackTarget(this) || !CanFly(target.CurrentLocation)) return false;
  3772. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]));
  3773. int delay = Functions.MaxDistance(CurrentLocation, target.CurrentLocation) * 50 + 500; //50 MS per Step
  3774. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, damage, target, target.CurrentLocation);
  3775. ActionList.Add(action);
  3776. ConsumeItem(item, 1);
  3777. return true;
  3778. }
  3779. private void SummonSkeleton(UserMagic magic)
  3780. {
  3781. if (CurrentMap.Info.NoPets)
  3782. {
  3783. ReceiveChat("You cannot summon pets on this map.", ChatType.System);
  3784. return;
  3785. }
  3786. MonsterObject monster;
  3787. for (int i = 0; i < Pets.Count; i++)
  3788. {
  3789. monster = Pets[i];
  3790. if ((monster.Info.Name != Settings.SkeletonName) || monster.Dead) continue;
  3791. if (monster.Node == null) continue;
  3792. monster.ActionList.Add(new DelayedAction(DelayedType.Recall, Envir.Time + 500));
  3793. return;
  3794. }
  3795. if (Pets.Count(x => x.Race == ObjectType.Monster) >= 2) return;
  3796. UserItem item = GetAmulet(1);
  3797. if (item == null) return;
  3798. MonsterInfo info = Envir.GetMonsterInfo(Settings.SkeletonName);
  3799. if (info == null) return;
  3800. LevelMagic(magic);
  3801. ConsumeItem(item, 1);
  3802. monster = MonsterObject.GetMonster(info);
  3803. monster.PetLevel = magic.Level;
  3804. monster.Master = this;
  3805. monster.MaxPetLevel = (byte)(4 + magic.Level);
  3806. monster.ActionTime = Envir.Time + 1000;
  3807. monster.RefreshNameColour(false);
  3808. //Pets.Add(monster);
  3809. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, monster, Front);
  3810. CurrentMap.ActionList.Add(action);
  3811. }
  3812. private void Purification(MapObject target, UserMagic magic)
  3813. {
  3814. if (target == null || !target.IsFriendlyTarget(this)) return;
  3815. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, target);
  3816. ActionList.Add(action);
  3817. }
  3818. private void SummonShinsu(UserMagic magic)
  3819. {
  3820. if (CurrentMap.Info.NoPets)
  3821. {
  3822. ReceiveChat("You cannot summon pets on this map.", ChatType.System);
  3823. return;
  3824. }
  3825. MonsterObject monster;
  3826. for (int i = 0; i < Pets.Count; i++)
  3827. {
  3828. monster = Pets[i];
  3829. if ((monster.Info.Name != Settings.ShinsuName) || monster.Dead) continue;
  3830. if (monster.Node == null) continue;
  3831. monster.ActionList.Add(new DelayedAction(DelayedType.Recall, Envir.Time + 500));
  3832. return;
  3833. }
  3834. if (Pets.Count(x => x.Race == ObjectType.Monster) >= 2) return;
  3835. UserItem item = GetAmulet(5);
  3836. if (item == null) return;
  3837. MonsterInfo info = Envir.GetMonsterInfo(Settings.ShinsuName);
  3838. if (info == null) return;
  3839. LevelMagic(magic);
  3840. ConsumeItem(item, 5);
  3841. monster = MonsterObject.GetMonster(info);
  3842. monster.PetLevel = magic.Level;
  3843. monster.Master = this;
  3844. monster.MaxPetLevel = (byte)(1 + magic.Level * 2);
  3845. monster.Direction = Direction;
  3846. monster.ActionTime = Envir.Time + 1000;
  3847. //Pets.Add(monster);
  3848. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, monster, Front);
  3849. CurrentMap.ActionList.Add(action);
  3850. }
  3851. private void Hiding(UserMagic magic)
  3852. {
  3853. UserItem item = GetAmulet(1);
  3854. if (item == null) return;
  3855. ConsumeItem(item, 1);
  3856. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]) + (magic.Level + 1) * 5);
  3857. ActionList.Add(action);
  3858. }
  3859. private void MassHiding(UserMagic magic, Point location, out bool cast)
  3860. {
  3861. cast = false;
  3862. UserItem item = GetAmulet(1);
  3863. if (item == null) return;
  3864. cast = true;
  3865. int delay = Functions.MaxDistance(CurrentLocation, location) * 50 + 500; //50 MS per Step
  3866. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, this, magic, GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]) / 2 + (magic.Level + 1) * 2, location);
  3867. CurrentMap.ActionList.Add(action);
  3868. }
  3869. private void SoulShield(UserMagic magic, Point location, out bool cast)
  3870. {
  3871. cast = false;
  3872. UserItem item = GetAmulet(1);
  3873. if (item == null) return;
  3874. cast = true;
  3875. int delay = Functions.MaxDistance(CurrentLocation, location) * 50 + 500; //50 MS per Step
  3876. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, this, magic, GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]) * 4 + (magic.Level + 1) * 50, location);
  3877. CurrentMap.ActionList.Add(action);
  3878. ConsumeItem(item, 1);
  3879. }
  3880. private void MassHealing(UserMagic magic, Point location)
  3881. {
  3882. int value = magic.GetDamage(GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]));
  3883. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, value, location);
  3884. CurrentMap.ActionList.Add(action);
  3885. }
  3886. private void Revelation(MapObject target, UserMagic magic)
  3887. {
  3888. if (target == null) return;
  3889. int value = GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]) + magic.GetPower();
  3890. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, value, target);
  3891. ActionList.Add(action);
  3892. }
  3893. private void PoisonCloud(UserMagic magic, Point location, out bool cast)
  3894. {
  3895. cast = false;
  3896. UserItem amulet = GetAmulet(5);
  3897. if (amulet == null) return;
  3898. UserItem poison = GetPoison(5, 1);
  3899. if (poison == null) return;
  3900. int delay = Functions.MaxDistance(CurrentLocation, location) * 50 + 500; //50 MS per Step
  3901. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]));
  3902. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, this, magic, damage, location, (byte)Envir.Random.Next(Stats[Stat.PoisonAttack]));
  3903. ConsumeItem(amulet, 5);
  3904. ConsumeItem(poison, 5);
  3905. CurrentMap.ActionList.Add(action);
  3906. cast = true;
  3907. }
  3908. private void MoonMist(UserMagic magic)
  3909. {
  3910. for (int i = 0; i < Buffs.Count; i++)
  3911. if (Buffs[i].Type == BuffType.MoonLight) return;
  3912. var time = GetAttackPower(Stats[Stat.MinAC], Stats[Stat.MaxAC]);
  3913. AddBuff(BuffType.MoonLight, this, (time + (magic.Level + 1) * 5) * 500, new Stats());
  3914. CurrentMap.Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.MoonMist }, CurrentLocation);
  3915. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]));
  3916. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damage, CurrentLocation, Direction);
  3917. CurrentMap.ActionList.Add(action);
  3918. LevelMagic(magic);
  3919. }
  3920. private bool CatTongue(MapObject target, UserMagic magic)
  3921. {
  3922. if (target == null || !target.IsAttackTarget(this) || !CanFly(target.CurrentLocation)) return false;
  3923. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]));
  3924. int delay = Functions.MaxDistance(CurrentLocation, target.CurrentLocation) * 50 + 500;
  3925. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, damage, target);
  3926. ActionList.Add(action);
  3927. return true;
  3928. }
  3929. private void TrapHexagon(UserMagic magic, Point location, out bool cast)
  3930. {
  3931. cast = false;
  3932. bool anyTargetsFound = false;
  3933. for (int x = location.X - 1; x <= location.X + 1; x++)
  3934. {
  3935. if (x < 0 || x >= CurrentMap.Width) continue;
  3936. for (int y = location.Y - 1; y < location.Y + 1; y++)
  3937. {
  3938. if (y < 0 || y >= CurrentMap.Height) continue;
  3939. if (!CurrentMap.ValidPoint(x, y)) continue;
  3940. var cell = CurrentMap.GetCell(x, y);
  3941. if (cell == null ||
  3942. cell.Objects == null ||
  3943. cell.Objects.Count <= 0) continue;
  3944. foreach (var target in cell.Objects)
  3945. {
  3946. switch (target.Race)
  3947. {
  3948. case ObjectType.Monster:
  3949. if (!target.IsAttackTarget(this)) continue;
  3950. if (target.Level > Level + 2) continue;
  3951. anyTargetsFound = true;
  3952. break;
  3953. }
  3954. }
  3955. }
  3956. }
  3957. if (!anyTargetsFound)
  3958. return;
  3959. UserItem item = GetAmulet(1);
  3960. //Point location = target.CurrentLocation;
  3961. if (item == null) return;
  3962. LevelMagic(magic);
  3963. uint duration = (uint)((magic.Level * 5 + 10) * 1000);
  3964. int value = (int)duration;
  3965. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, value, location);
  3966. CurrentMap.ActionList.Add(action);
  3967. ConsumeItem(item, 1);
  3968. cast = true;
  3969. }
  3970. private void Reincarnation(UserMagic magic, PlayerObject target, out bool cast)
  3971. {
  3972. cast = true;
  3973. if (target == null || !target.Dead) return;
  3974. // checks for amulet of revival
  3975. UserItem item = GetAmulet(1, 3);
  3976. if (item == null) return;
  3977. if (!ActiveReincarnation && !ReincarnationReady)
  3978. {
  3979. cast = false;
  3980. int CastTime = Math.Abs(((magic.Level + 1) * 1000) - 9000);
  3981. ExpireTime = Envir.Time + CastTime;
  3982. ReincarnationReady = true;
  3983. ActiveReincarnation = true;
  3984. ReincarnationTarget = target;
  3985. ReincarnationExpireTime = ExpireTime + 5000;
  3986. target.ReincarnationHost = this;
  3987. SpellObject ob = new SpellObject
  3988. {
  3989. Spell = Spell.Reincarnation,
  3990. ExpireTime = ExpireTime,
  3991. TickSpeed = 1000,
  3992. Caster = this,
  3993. CurrentLocation = CurrentLocation,
  3994. CastLocation = CurrentLocation,
  3995. Show = true,
  3996. CurrentMap = CurrentMap,
  3997. };
  3998. Packet p = new S.Chat { Message = GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.PlayerReviveTarget), Name, target.Name), Type = ChatType.Shout };
  3999. for (int i = 0; i < CurrentMap.Players.Count; i++)
  4000. {
  4001. if (!Functions.InRange(CurrentLocation, CurrentMap.Players[i].CurrentLocation, Globals.DataRange * 2)) continue;
  4002. CurrentMap.Players[i].Enqueue(p);
  4003. }
  4004. CurrentMap.AddObject(ob);
  4005. ob.Spawned();
  4006. ConsumeItem(item, 1);
  4007. // chance of failing Reincarnation when casting
  4008. if (Envir.Random.Next(30) > (1 + magic.Level) * 10)
  4009. {
  4010. return;
  4011. }
  4012. DelayedAction action = new DelayedAction(DelayedType.Magic, ExpireTime, magic);
  4013. ActionList.Add(action);
  4014. return;
  4015. }
  4016. return;
  4017. }
  4018. private void SummonHolyDeva(UserMagic magic)
  4019. {
  4020. if (CurrentMap.Info.NoPets)
  4021. {
  4022. ReceiveChat("You cannot summon pets on this map.", ChatType.System);
  4023. return;
  4024. }
  4025. MonsterObject monster;
  4026. for (int i = 0; i < Pets.Count; i++)
  4027. {
  4028. monster = Pets[i];
  4029. if ((monster.Info.Name != Settings.AngelName) || monster.Dead) continue;
  4030. if (monster.Node == null) continue;
  4031. monster.ActionList.Add(new DelayedAction(DelayedType.Recall, Envir.Time + 500));
  4032. return;
  4033. }
  4034. if (Pets.Count(x => x.Race == ObjectType.Monster) >= 2) return;
  4035. UserItem item = GetAmulet(2);
  4036. if (item == null) return;
  4037. MonsterInfo info = Envir.GetMonsterInfo(Settings.AngelName);
  4038. if (info == null) return;
  4039. LevelMagic(magic);
  4040. ConsumeItem(item, 2);
  4041. monster = MonsterObject.GetMonster(info);
  4042. monster.PetLevel = magic.Level;
  4043. monster.Master = this;
  4044. monster.MaxPetLevel = (byte)(1 + magic.Level * 2);
  4045. monster.Direction = Direction;
  4046. monster.ActionTime = Envir.Time + 1000;
  4047. //Pets.Add(monster);
  4048. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 1500, this, magic, monster, Front);
  4049. CurrentMap.ActionList.Add(action);
  4050. }
  4051. private void Hallucination(MapObject target, UserMagic magic)
  4052. {
  4053. if (target == null || target.Race != ObjectType.Monster || !target.IsAttackTarget(this)) return;
  4054. int damage = 0;
  4055. int delay = Functions.MaxDistance(CurrentLocation, target.CurrentLocation) * 50 + 500; //50 MS per Step
  4056. DelayedAction action = new DelayedAction(DelayedType.Magic, delay, magic, damage, target);
  4057. ActionList.Add(action);
  4058. }
  4059. private void EnergyShield(MapObject target, UserMagic magic, out bool cast)
  4060. {
  4061. cast = false;
  4062. if (target == null || target.Node == null || !target.IsFriendlyTarget(this)) target = this; //offical is only party target
  4063. int duration = 30 + 50 * magic.Level;
  4064. int power = magic.GetPower(GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]));
  4065. int chance = (10 - (Stats[Stat.Luck] / 3 + magic.Level + 1));
  4066. if (chance < 2) chance = 2;
  4067. var stats = new Stats
  4068. {
  4069. [Stat.EnergyShieldPercent] = (int)Math.Round((1 / (decimal)chance) * 100),
  4070. [Stat.EnergyShieldHPGain] = power
  4071. };
  4072. switch (target.Race)
  4073. {
  4074. case ObjectType.Player:
  4075. //Only targets
  4076. if (target.IsFriendlyTarget(this))
  4077. {
  4078. target.AddBuff(BuffType.EnergyShield, this, (Settings.Second * duration), stats);
  4079. target.OperateTime = 0;
  4080. LevelMagic(magic);
  4081. cast = true;
  4082. }
  4083. break;
  4084. }
  4085. }
  4086. private void UltimateEnhancer(MapObject target, UserMagic magic, out bool cast)
  4087. {
  4088. cast = false;
  4089. if (target == null || target.Node == null || !target.IsFriendlyTarget(this)) return;
  4090. UserItem item = GetAmulet(1);
  4091. if (item == null) return;
  4092. int expiretime = GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]) * 4 + (magic.Level + 1) * 50;
  4093. int value = Stats[Stat.MaxSC] >= 5 ? Math.Min(8, Stats[Stat.MaxSC] / 5) : 1;
  4094. switch (target.Race)
  4095. {
  4096. case ObjectType.Monster:
  4097. case ObjectType.Player:
  4098. case ObjectType.Hero:
  4099. //Only targets
  4100. if (target.IsFriendlyTarget(this))
  4101. {
  4102. var stats = new Stats();
  4103. if (target.Race == ObjectType.Monster || ((HumanObject)target).Class == MirClass.Warrior || ((HumanObject)target).Class == MirClass.Assassin)
  4104. {
  4105. stats[Stat.MaxDC] = value;
  4106. }
  4107. else if (((HumanObject)target).Class == MirClass.Wizard || ((HumanObject)target).Class == MirClass.Archer)
  4108. {
  4109. stats[Stat.MaxMC] = value;
  4110. }
  4111. else if (((HumanObject)target).Class == MirClass.Taoist)
  4112. {
  4113. stats[Stat.MaxSC] = value;
  4114. }
  4115. target.AddBuff(BuffType.UltimateEnhancer, this, Settings.Second * expiretime, stats);
  4116. target.OperateTime = 0;
  4117. LevelMagic(magic);
  4118. ConsumeItem(item, 1);
  4119. cast = true;
  4120. }
  4121. break;
  4122. }
  4123. }
  4124. private void Plague(UserMagic magic, Point location, out bool cast)
  4125. {
  4126. cast = false;
  4127. UserItem item = GetAmulet(1);
  4128. if (item == null) return;
  4129. cast = true;
  4130. int delay = Functions.MaxDistance(CurrentLocation, location) * 50 + 500; //50 MS per Step
  4131. PoisonType pType = PoisonType.None;
  4132. UserItem itemp = GetPoison(1, 1);
  4133. if (itemp != null)
  4134. pType = PoisonType.Green;
  4135. else
  4136. {
  4137. itemp = GetPoison(1, 2);
  4138. if (itemp != null)
  4139. pType = PoisonType.Red;
  4140. }
  4141. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, this, magic, magic.GetDamage(GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC])), location, pType);
  4142. CurrentMap.ActionList.Add(action);
  4143. ConsumeItem(item, 1);
  4144. if (itemp != null) ConsumeItem(itemp, 1);
  4145. }
  4146. private void Curse(UserMagic magic, Point location, out bool cast)
  4147. {
  4148. cast = false;
  4149. UserItem item = GetAmulet(1);
  4150. if (item == null) return;
  4151. cast = true;
  4152. ConsumeItem(item, 1);
  4153. if (Envir.Random.Next(10 - ((magic.Level + 1) * 2)) > 2) return;
  4154. int delay = Functions.MaxDistance(CurrentLocation, location) * 50 + 500; //50 MS per Step
  4155. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, this, magic, magic.GetDamage(GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC])), location, 1 + ((magic.Level + 1) * 2));
  4156. CurrentMap.ActionList.Add(action);
  4157. }
  4158. private void PetEnhancer(MapObject target, UserMagic magic, out bool cast)
  4159. {
  4160. cast = false;
  4161. if (target == null || target.Race != ObjectType.Monster || !target.IsFriendlyTarget(this)) return;
  4162. int duration = GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]) + magic.GetPower();
  4163. cast = true;
  4164. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, duration, target);
  4165. ActionList.Add(action);
  4166. }
  4167. #endregion
  4168. #region Warrior Skills
  4169. private void Entrapment(MapObject target, UserMagic magic)
  4170. {
  4171. if (target == null || !target.IsAttackTarget(this)) return;
  4172. int damage = 0;
  4173. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic, damage, target);
  4174. ActionList.Add(action);
  4175. }
  4176. private void BladeAvalanche(UserMagic magic)
  4177. {
  4178. int damageBase = GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]);
  4179. if (Envir.Random.Next(0, 100) <= (1 + Stats[Stat.Luck]))
  4180. damageBase += damageBase;//crit should do something like double dmg, not double max dc dmg!
  4181. int damageFinal = magic.GetDamage(damageBase);
  4182. int col = 3;
  4183. int row = 3;
  4184. Point[] loc = new Point[col]; //0 = left 1 = center 2 = right
  4185. loc[0] = Functions.PointMove(CurrentLocation, Functions.PreviousDir(Direction), 1);
  4186. loc[1] = Functions.PointMove(CurrentLocation, Direction, 1);
  4187. loc[2] = Functions.PointMove(CurrentLocation, Functions.NextDir(Direction), 1);
  4188. bool train = false;
  4189. for (int i = 0; i < col; i++)
  4190. {
  4191. Point startPoint = loc[i];
  4192. for (int j = 0; j < row; j++)
  4193. {
  4194. Point hitPoint = Functions.PointMove(startPoint, Direction, j);
  4195. if (!CurrentMap.ValidPoint(hitPoint)) continue;
  4196. Cell cell = CurrentMap.GetCell(hitPoint);
  4197. if (cell.Objects == null) continue;
  4198. for (int k = 0; k < cell.Objects.Count; k++)
  4199. {
  4200. MapObject target = cell.Objects[k];
  4201. switch (target.Race)
  4202. {
  4203. case ObjectType.Monster:
  4204. case ObjectType.Player:
  4205. case ObjectType.Hero:
  4206. //Only targets
  4207. if (target.IsAttackTarget(this))
  4208. {
  4209. if (target.Attacked(this, j <= 1 ? damageFinal : (int)(damageFinal * 0.6),
  4210. target is MonsterObject monster && (monster.Info.AI == 49) ? DefenceType.Repulsion : DefenceType.MAC,
  4211. false) > 0)
  4212. train = true;
  4213. }
  4214. break;
  4215. }
  4216. }
  4217. }
  4218. }
  4219. if (train)
  4220. LevelMagic(magic);
  4221. }
  4222. private void ProtectionField(UserMagic magic)
  4223. {
  4224. int duration = 45 + (15 * magic.Level);
  4225. int addValue = (int)Math.Round(Stats[Stat.MaxAC] * (0.2 + (0.03 * magic.Level)));
  4226. AddBuff(BuffType.ProtectionField, this, Settings.Second * duration, new Stats { [Stat.MaxAC] = addValue, [Stat.MinAC] = addValue });
  4227. OperateTime = 0;
  4228. LevelMagic(magic);
  4229. }
  4230. private void Rage(UserMagic magic)
  4231. {
  4232. int duration = 18 + (6 * magic.Level);
  4233. int addValue = (int)Math.Round(Stats[Stat.MaxDC] * (0.12 + (0.03 * magic.Level)));
  4234. AddBuff(BuffType.Rage, this, Settings.Second * duration, new Stats { [Stat.MaxDC] = addValue, [Stat.MinDC] = addValue });
  4235. OperateTime = 0;
  4236. LevelMagic(magic);
  4237. }
  4238. private void ShoulderDash(UserMagic magic)
  4239. {
  4240. if (InTrapRock || !CanWalk)
  4241. {
  4242. return;
  4243. }
  4244. Point _nextLocation;
  4245. MapObject _target = null;
  4246. bool _blocking = false;
  4247. bool _canDash = false;
  4248. int _cellsTravelled = 0;
  4249. int dist = Envir.Random.Next(2) + magic.Level + 2;
  4250. ActionTime = Envir.Time + MoveDelay;
  4251. for (int i = 0; i < dist; i++)
  4252. {
  4253. if (_blocking)
  4254. {
  4255. break;
  4256. }
  4257. _nextLocation = Functions.PointMove(CurrentLocation, Direction, 1);
  4258. if (!CurrentMap.ValidPoint(_nextLocation) || CurrentMap.GetSafeZone(_nextLocation) != null)
  4259. {
  4260. break;
  4261. }
  4262. // acquire target
  4263. if (i == 0)
  4264. {
  4265. Cell targetCell = CurrentMap.GetCell(_nextLocation);
  4266. if (targetCell.Objects != null)
  4267. {
  4268. int cellCnt = targetCell.Objects.Count;
  4269. for (int j = 0; j < cellCnt; j++)
  4270. {
  4271. MapObject ob = targetCell.Objects[j];
  4272. if ((ob.Race == ObjectType.Player ||
  4273. ob.Race == ObjectType.Monster ||
  4274. ob.Race == ObjectType.Hero) &&
  4275. ob.IsAttackTarget(this) &&
  4276. ob.Level < Level)
  4277. {
  4278. _target = ob;
  4279. break;
  4280. }
  4281. if(ob.Blocking)
  4282. {
  4283. _blocking = true;
  4284. break;
  4285. }
  4286. }
  4287. }
  4288. if (_blocking)
  4289. {
  4290. break;
  4291. }
  4292. }
  4293. // try to dash
  4294. Cell dashCell = CurrentMap.GetCell(_nextLocation);
  4295. _canDash = false;
  4296. if (_target == null)
  4297. {
  4298. if (dashCell.Objects != null)
  4299. {
  4300. int cellCnt = dashCell.Objects.Count;
  4301. for (int k = 0; k < cellCnt; k++)
  4302. {
  4303. MapObject ob = dashCell.Objects[k];
  4304. if (ob.Blocking)
  4305. {
  4306. _blocking = true;
  4307. break;
  4308. }
  4309. }
  4310. if(!_blocking)
  4311. {
  4312. _canDash = true;
  4313. }
  4314. }
  4315. else
  4316. {
  4317. _canDash = true;
  4318. }
  4319. }
  4320. else
  4321. {
  4322. // try to push
  4323. if (_target.Pushed(this, Direction, 1) == 0)
  4324. {
  4325. _blocking = true;
  4326. }
  4327. else
  4328. {
  4329. _canDash = true;
  4330. }
  4331. }
  4332. if (_canDash)
  4333. {
  4334. CurrentMap.GetCell(CurrentLocation).Remove(this);
  4335. RemoveObjects(Direction, 1);
  4336. Enqueue(new S.UserDash { Direction = Direction, Location = _nextLocation });
  4337. Broadcast(new S.ObjectDash { ObjectID = ObjectID, Direction = Direction, Location = _nextLocation });
  4338. CurrentMap.GetCell(_nextLocation).Add(this);
  4339. AddObjects(Direction, 1);
  4340. // dash interrupt
  4341. Cell cell = CurrentMap.GetCell(_nextLocation);
  4342. for (int l = 0; l < cell.Objects.Count; l++)
  4343. {
  4344. if (cell.Objects[l].Race == ObjectType.Spell)
  4345. {
  4346. SpellObject ob = (SpellObject)cell.Objects[l];
  4347. if (IsAttackTarget(ob.Caster))
  4348. {
  4349. switch (ob.Spell)
  4350. {
  4351. case Spell.FireWall:
  4352. if (Attacked((PlayerObject)ob.Caster, ob.Value, DefenceType.MAC, false) > 0)
  4353. {
  4354. _blocking = true;
  4355. }
  4356. break;
  4357. }
  4358. }
  4359. }
  4360. }
  4361. CurrentLocation = _nextLocation;
  4362. _cellsTravelled++;
  4363. }
  4364. }
  4365. if (_cellsTravelled == 0)
  4366. {
  4367. Enqueue(new S.UserDashFail { Direction = Direction, Location = CurrentLocation });
  4368. Broadcast(new S.ObjectDashFail { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  4369. if (InSafeZone)
  4370. {
  4371. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.NoPushingInSafezone), ChatType.System);
  4372. }
  4373. else
  4374. {
  4375. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.NotEnoughPushingPower), ChatType.System);
  4376. }
  4377. }
  4378. else
  4379. {
  4380. _target?.Attacked(this, magic.GetDamage(0), DefenceType.None, false);
  4381. LevelMagic(magic);
  4382. // Broadcast(new S.ObjectDash { ObjectID = ObjectID, Direction = Direction, Location = Front });
  4383. }
  4384. long now = Envir.Time;
  4385. magic.CastTime = now;
  4386. Enqueue(new S.MagicCast { Spell = magic.Spell });
  4387. CellTime = now + 500;
  4388. _stepCounter = 0;
  4389. }
  4390. private void SlashingBurst(UserMagic magic)
  4391. {
  4392. int damageBase = GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]);
  4393. int damageFinal = magic.GetDamage(damageBase);
  4394. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damageFinal, CurrentLocation, Direction, 1);
  4395. CurrentMap.ActionList.Add(action);
  4396. Point location = Functions.PointMove(CurrentLocation, Direction, 2);
  4397. if (!CurrentMap.ValidPoint(location)) return;
  4398. Cell cInfo = CurrentMap.GetCell(location);
  4399. bool blocked = false;
  4400. if (cInfo.Objects != null)
  4401. {
  4402. for (int c = 0; c < cInfo.Objects.Count; c++)
  4403. {
  4404. MapObject ob = cInfo.Objects[c];
  4405. if (!ob.Blocking) continue;
  4406. blocked = true;
  4407. if ((cInfo.Objects == null) || blocked) break;
  4408. }
  4409. }
  4410. if (blocked) return;
  4411. CurrentMap.GetCell(CurrentLocation).Remove(this);
  4412. Broadcast(new S.ObjectRemove { ObjectID = ObjectID });
  4413. RemoveObjects(Direction, 2);
  4414. CurrentLocation = location;
  4415. InTrapRock = false;
  4416. CurrentMap.GetCell(CurrentLocation).Add(this);
  4417. BroadcastInfo();
  4418. AddObjects(Direction, 2);
  4419. Enqueue(new S.UserLocation { Direction = Direction, Location = CurrentLocation });
  4420. }
  4421. private void FurySpell(UserMagic magic, out bool cast)
  4422. {
  4423. cast = true;
  4424. ActionList.Add(new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic));
  4425. }
  4426. private void ImmortalSkin(UserMagic magic, out bool cast)
  4427. {
  4428. cast = true;
  4429. ActionList.Add(new DelayedAction(DelayedType.Magic, Envir.Time + 500, magic));
  4430. }
  4431. private void CounterAttackCast(UserMagic magic, MapObject target)
  4432. {
  4433. if (target == null || magic == null) return;
  4434. if (CounterAttack == false) return;
  4435. int damageBase = GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]);
  4436. if (Envir.Random.Next(0, 100) <= Stats[Stat.Accuracy])
  4437. damageBase += damageBase;//crit should do something like double dmg, not double max dc dmg!
  4438. int damageFinal = magic.GetDamage(damageBase);
  4439. MirDirection dir = Functions.ReverseDirection(target.Direction);
  4440. Direction = dir;
  4441. if (Functions.InRange(CurrentLocation, target.CurrentLocation, 1) == false) return;
  4442. if (Envir.Random.Next(10) > magic.Level + 6) return;
  4443. Enqueue(new S.ObjectMagic { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, Spell = Spell.CounterAttack, TargetID = target.ObjectID, Target = target.CurrentLocation, Cast = true, Level = GetMagic(Spell.CounterAttack).Level, SelfBroadcast = true });
  4444. DelayedAction action = new DelayedAction(DelayedType.Damage, AttackTime, target, damageFinal, DefenceType.AC, true);
  4445. ActionList.Add(action);
  4446. LevelMagic(magic);
  4447. CounterAttack = false;
  4448. }
  4449. #endregion
  4450. #region Assassin Skills
  4451. private void HeavenlySword(UserMagic magic)
  4452. {
  4453. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]));
  4454. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damage, CurrentLocation, Direction);
  4455. CurrentMap.ActionList.Add(action);
  4456. }
  4457. private void SwiftFeet(UserMagic magic, out bool cast)
  4458. {
  4459. cast = true;
  4460. ActiveSwiftFeet = true;
  4461. AddBuff(BuffType.SwiftFeet, this, (Settings.Second * 25) + (magic.Level * 5000), new Stats(), true);
  4462. LevelMagic(magic);
  4463. }
  4464. private void MoonLight(UserMagic magic)
  4465. {
  4466. var time = GetAttackPower(Stats[Stat.MinAC], Stats[Stat.MaxAC]);
  4467. AddBuff(BuffType.MoonLight, this, (time + (magic.Level + 1) * 5) * 500, new Stats());
  4468. LevelMagic(magic);
  4469. }
  4470. private void Trap(UserMagic magic, MapObject target, out bool cast)
  4471. {
  4472. cast = false;
  4473. if (target == null || !target.IsAttackTarget(this) || !(target is MonsterObject)) return;
  4474. if (target.Level >= Level + 2) return;
  4475. LevelMagic(magic);
  4476. uint duration = 60000;
  4477. int value = (int)duration;
  4478. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, value, target);
  4479. CurrentMap.ActionList.Add(action);
  4480. cast = true;
  4481. }
  4482. private bool PoisonSword(UserMagic magic)
  4483. {
  4484. UserItem item = GetPoison(1);
  4485. if (item == null) return false;
  4486. Point hitPoint;
  4487. Cell cell;
  4488. MirDirection dir = Functions.PreviousDir(Direction);
  4489. int power = magic.GetDamage(GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]));
  4490. for (int i = 0; i < 5; i++)
  4491. {
  4492. hitPoint = Functions.PointMove(CurrentLocation, dir, 1);
  4493. dir = Functions.NextDir(dir);
  4494. if (!CurrentMap.ValidPoint(hitPoint)) continue;
  4495. cell = CurrentMap.GetCell(hitPoint);
  4496. if (cell.Objects == null) continue;
  4497. for (int o = 0; o < cell.Objects.Count; o++)
  4498. {
  4499. MapObject target = cell.Objects[o];
  4500. if (target.Race != ObjectType.Player && target.Race != ObjectType.Monster) continue;
  4501. if (target == null || !target.IsAttackTarget(this) || target.Node == null) continue;
  4502. target.ApplyPoison(new Poison
  4503. {
  4504. Duration = 3 + power / 10 + magic.Level * 3,
  4505. Owner = this,
  4506. PType = PoisonType.Green,
  4507. TickSpeed = 1000,
  4508. Value = power / 10 + magic.Level + 1 + Envir.Random.Next(Stats[Stat.PoisonAttack])
  4509. }, this);
  4510. target.OperateTime = 0;
  4511. break;
  4512. }
  4513. }
  4514. LevelMagic(magic);
  4515. ConsumeItem(item, 1);
  4516. return true;
  4517. }
  4518. private void DarkBody(MapObject target, UserMagic magic)
  4519. {
  4520. if (CurrentMap.Info.NoPets)
  4521. {
  4522. ReceiveChat("You cannot summon pets on this map.", ChatType.System);
  4523. return;
  4524. }
  4525. if (target == null) return;
  4526. MonsterObject monster;
  4527. for (int i = 0; i < Pets.Count; i++)
  4528. {
  4529. monster = Pets[i];
  4530. if ((monster.Info.Name != Settings.AssassinCloneName) || monster.Dead) continue;
  4531. if (monster.Node == null) continue;
  4532. monster.Die();
  4533. return;
  4534. }
  4535. MonsterInfo info = Envir.GetMonsterInfo(Settings.AssassinCloneName);
  4536. if (info == null) return;
  4537. monster = MonsterObject.GetMonster(info);
  4538. monster.Master = this;
  4539. monster.Direction = Direction;
  4540. monster.ActionTime = Envir.Time + 500;
  4541. monster.RefreshNameColour(false);
  4542. monster.Target = target;
  4543. Pets.Add(monster);
  4544. monster.Spawn(CurrentMap, CurrentLocation);
  4545. if (!HasBuff(BuffType.DarkBody, out _))
  4546. {
  4547. LevelMagic(magic);
  4548. }
  4549. var duration = (GetAttackPower(Stats[Stat.MinAC], Stats[Stat.MaxAC]) + (magic.Level + 1) * 5) * 500;
  4550. AddBuff(BuffType.DarkBody, this, duration, new Stats());
  4551. }
  4552. private void CrescentSlash(UserMagic magic)
  4553. {
  4554. int damageBase = GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC]);
  4555. if (Envir.Random.Next(0, 100) <= Stats[Stat.Accuracy])
  4556. damageBase += damageBase;//crit should do something like double dmg, not double max dc dmg!
  4557. int damageFinal = magic.GetDamage(damageBase);
  4558. MirDirection backDir = Functions.ReverseDirection(Direction);
  4559. MirDirection preBackDir = Functions.PreviousDir(backDir);
  4560. MirDirection nextBackDir = Functions.NextDir(backDir);
  4561. for (int i = 0; i < 8; i++)
  4562. {
  4563. MirDirection dir = (MirDirection)i;
  4564. Point hitPoint = Functions.PointMove(CurrentLocation, dir, 1);
  4565. if (dir != backDir && dir != preBackDir && dir != nextBackDir)
  4566. {
  4567. if (!CurrentMap.ValidPoint(hitPoint)) continue;
  4568. Cell cell = CurrentMap.GetCell(hitPoint);
  4569. if (cell.Objects == null) continue;
  4570. for (int j = 0; j < cell.Objects.Count; j++)
  4571. {
  4572. MapObject target = cell.Objects[j];
  4573. switch (target.Race)
  4574. {
  4575. case ObjectType.Monster:
  4576. case ObjectType.Player:
  4577. //Only targets
  4578. if (target.IsAttackTarget(this))
  4579. {
  4580. DelayedAction action = new DelayedAction(DelayedType.Damage, Envir.Time + AttackSpeed, target, damageFinal, DefenceType.AC, true);
  4581. ActionList.Add(action);
  4582. }
  4583. break;
  4584. }
  4585. }
  4586. LevelMagic(magic);
  4587. }
  4588. }
  4589. }
  4590. private void FlashDash(UserMagic magic)
  4591. {
  4592. bool success = false;
  4593. ActionTime = Envir.Time;
  4594. int travel = 0;
  4595. bool blocked = false;
  4596. int jumpDistance = (magic.Level <= 1) ? 0 : 1;//3 max
  4597. Point location = CurrentLocation;
  4598. for (int i = 0; i < jumpDistance; i++)
  4599. {
  4600. location = Functions.PointMove(location, Direction, 1);
  4601. if (!CurrentMap.ValidPoint(location)) break;
  4602. Cell cInfo = CurrentMap.GetCell(location);
  4603. if (cInfo.Objects != null)
  4604. {
  4605. for (int c = 0; c < cInfo.Objects.Count; c++)
  4606. {
  4607. MapObject ob = cInfo.Objects[c];
  4608. if (!ob.Blocking) continue;
  4609. blocked = true;
  4610. if ((cInfo.Objects == null) || blocked) break;
  4611. }
  4612. }
  4613. if (blocked) break;
  4614. travel++;
  4615. }
  4616. jumpDistance = travel;
  4617. if (jumpDistance > 0)
  4618. {
  4619. location = Functions.PointMove(CurrentLocation, Direction, jumpDistance);
  4620. CurrentMap.GetCell(CurrentLocation).Remove(this);
  4621. RemoveObjects(Direction, 1);
  4622. CurrentLocation = location;
  4623. CurrentMap.GetCell(CurrentLocation).Add(this);
  4624. AddObjects(Direction, 1);
  4625. Enqueue(new S.UserDashAttack { Direction = Direction, Location = location });
  4626. Broadcast(new S.ObjectDashAttack { ObjectID = ObjectID, Direction = Direction, Location = location, Distance = jumpDistance });
  4627. }
  4628. else
  4629. {
  4630. Broadcast(new S.ObjectAttack { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation });
  4631. }
  4632. if (travel == 0) location = CurrentLocation;
  4633. int attackDelay = (AttackSpeed - 120) <= 300 ? 300 : (AttackSpeed - 120);
  4634. AttackTime = Envir.Time + attackDelay;
  4635. SpellTime = Envir.Time + 300;
  4636. location = Functions.PointMove(location, Direction, 1);
  4637. if (CurrentMap.ValidPoint(location))
  4638. {
  4639. Cell cInfo = CurrentMap.GetCell(location);
  4640. if (cInfo.Objects != null)
  4641. {
  4642. for (int c = 0; c < cInfo.Objects.Count; c++)
  4643. {
  4644. MapObject ob = cInfo.Objects[c];
  4645. switch (ob.Race)
  4646. {
  4647. case ObjectType.Monster:
  4648. case ObjectType.Player:
  4649. //Only targets
  4650. if (ob.IsAttackTarget(this))
  4651. {
  4652. DelayedAction action = new DelayedAction(DelayedType.Damage, AttackTime, ob, magic.GetDamage(GetAttackPower(Stats[Stat.MinDC], Stats[Stat.MaxDC])), DefenceType.AC, true);
  4653. ActionList.Add(action);
  4654. success = true;
  4655. if ((((ob.Race != ObjectType.Player) || Settings.PvpCanResistPoison) && (Envir.Random.Next(Settings.PoisonAttackWeight) >= ob.Stats[Stat.PoisonResist])) && (Envir.Random.Next(15) <= magic.Level + 1))
  4656. {
  4657. DelayedAction pa = new DelayedAction(DelayedType.Poison, AttackTime, ob, PoisonType.Stun, SpellEffect.TwinDrakeBlade, magic.Level + 1, 1000);
  4658. ActionList.Add(pa);
  4659. }
  4660. }
  4661. break;
  4662. }
  4663. }
  4664. }
  4665. }
  4666. if (success) //technicaly this makes flashdash lvl when it casts rather then when it hits (it wont lvl if it's not hitting!)
  4667. LevelMagic(magic);
  4668. magic.CastTime = Envir.Time;
  4669. Enqueue(new S.MagicCast { Spell = magic.Spell });
  4670. }
  4671. #endregion
  4672. #region Archer Skills
  4673. private int ApplyArcherState(int damage)
  4674. {
  4675. UserMagic magic = GetMagic(Spell.MentalState);
  4676. if (magic != null)
  4677. {
  4678. LevelMagic(magic);
  4679. }
  4680. int dmgpenalty = 100;
  4681. switch (Info.MentalState)
  4682. {
  4683. case 1: //trickshot
  4684. dmgpenalty = 55 + (Info.MentalStateLvl * 5);
  4685. break;
  4686. case 2: //group attack
  4687. dmgpenalty = 80;
  4688. break;
  4689. }
  4690. return (damage * dmgpenalty) / 100;
  4691. }
  4692. private bool StraightShot(MapObject target, UserMagic magic)
  4693. {
  4694. if (target == null || !target.IsAttackTarget(this)) return false;
  4695. if ((Info.MentalState != 1) && !CanFly(target.CurrentLocation)) return false;
  4696. int distance = Functions.MaxDistance(CurrentLocation, target.CurrentLocation);
  4697. int damage = magic.GetDamage(GetRangeAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC], distance));
  4698. damage = ApplyArcherState(damage);
  4699. int delay = distance * 50 + 500; //50 MS per Step
  4700. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, damage, target, target.CurrentLocation);
  4701. ActionList.Add(action);
  4702. return true;
  4703. }
  4704. private bool DoubleShot(MapObject target, UserMagic magic)
  4705. {
  4706. if (target == null || !target.IsAttackTarget(this)) return false;
  4707. if ((Info.MentalState != 1) && !CanFly(target.CurrentLocation)) return false;
  4708. int distance = Functions.MaxDistance(CurrentLocation, target.CurrentLocation);
  4709. int damage = magic.GetDamage(GetRangeAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC], distance));
  4710. damage = ApplyArcherState(damage);
  4711. int delay = distance * 50 + 500; //50 MS per Step
  4712. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, damage, target, target.CurrentLocation);
  4713. ActionList.Add(action);
  4714. action = new DelayedAction(DelayedType.Magic, Envir.Time + delay + 50, magic, damage, target, target.CurrentLocation);
  4715. ActionList.Add(action);
  4716. return true;
  4717. }
  4718. private void BackStep(UserMagic magic)
  4719. {
  4720. ActionTime = Envir.Time;
  4721. if (!CanWalk) return;
  4722. int travel = 0;
  4723. bool blocked = false;
  4724. int jumpDistance = (magic.Level == 0) ? 1 : magic.Level;//3 max
  4725. MirDirection jumpDir = Functions.ReverseDirection(Direction);
  4726. Point location = CurrentLocation;
  4727. for (int i = 0; i < jumpDistance; i++)
  4728. {
  4729. location = Functions.PointMove(location, jumpDir, 1);
  4730. if (!CurrentMap.ValidPoint(location)) break;
  4731. Cell cInfo = CurrentMap.GetCell(location);
  4732. if (cInfo.Objects != null)
  4733. for (int c = 0; c < cInfo.Objects.Count; c++)
  4734. {
  4735. MapObject ob = cInfo.Objects[c];
  4736. if (!ob.Blocking) continue;
  4737. blocked = true;
  4738. if ((cInfo.Objects == null) || blocked) break;
  4739. }
  4740. if (blocked) break;
  4741. travel++;
  4742. }
  4743. jumpDistance = travel;
  4744. if (jumpDistance > 0)
  4745. {
  4746. for (int i = 0; i < jumpDistance; i++)
  4747. {
  4748. location = Functions.PointMove(CurrentLocation, jumpDir, 1);
  4749. CurrentMap.GetCell(CurrentLocation).Remove(this);
  4750. RemoveObjects(jumpDir, 1);
  4751. CurrentLocation = location;
  4752. CurrentMap.GetCell(CurrentLocation).Add(this);
  4753. AddObjects(jumpDir, 1);
  4754. }
  4755. Enqueue(new S.UserBackStep { Direction = Direction, Location = location });
  4756. Broadcast(new S.ObjectBackStep { ObjectID = ObjectID, Direction = Direction, Location = location, Distance = jumpDistance });
  4757. LevelMagic(magic);
  4758. }
  4759. else
  4760. {
  4761. Broadcast(new S.ObjectBackStep { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, Distance = jumpDistance });
  4762. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.NotEnoughJumpingPower), ChatType.System);
  4763. }
  4764. magic.CastTime = Envir.Time;
  4765. Enqueue(new S.MagicCast { Spell = magic.Spell });
  4766. CellTime = Envir.Time + 500;
  4767. }
  4768. private bool DelayedExplosion(MapObject target, UserMagic magic)
  4769. {
  4770. if (target == null || !target.IsAttackTarget(this) || !CanFly(target.CurrentLocation)) return false;
  4771. int power = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  4772. int delay = Functions.MaxDistance(CurrentLocation, target.CurrentLocation) * 50 + 500; //50 MS per Step
  4773. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, power, target, target.CurrentLocation);
  4774. ActionList.Add(action);
  4775. return true;
  4776. }
  4777. private void ExplosiveTrap(UserMagic magic, Point location)
  4778. {
  4779. int freeTrapSpot = -1;
  4780. var trapIDs = CurrentMap.GetSpellObjects(Spell.ExplosiveTrap, this).Select(x => x.ExplosiveTrapID).Distinct();
  4781. var max = magic.Level + 1;
  4782. if (trapIDs.Count() >= max) return;
  4783. for (int i = 0; i < max; i++)
  4784. {
  4785. if (!trapIDs.Contains(i))
  4786. {
  4787. freeTrapSpot = i;
  4788. break;
  4789. }
  4790. }
  4791. if (freeTrapSpot == -1) return;
  4792. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  4793. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damage, location, freeTrapSpot);
  4794. CurrentMap.ActionList.Add(action);
  4795. }
  4796. public void DoKnockback(MapObject target, UserMagic magic)//ElementalShot - knockback
  4797. {
  4798. Cell cell = CurrentMap.GetCell(target.CurrentLocation);
  4799. if (!cell.Valid || cell.Objects == null) return;
  4800. if (target.CurrentLocation.Y < 0 || target.CurrentLocation.Y >= CurrentMap.Height || target.CurrentLocation.X < 0 || target.CurrentLocation.X >= CurrentMap.Height) return;
  4801. if (target.Race != ObjectType.Monster && target.Race != ObjectType.Player && target.Race != ObjectType.Hero) return;
  4802. if (!target.IsAttackTarget(this) || target.Level >= Level) return;
  4803. if (Envir.Random.Next(20) >= 6 + magic.Level * 3 + ElementsLevel + Level - target.Level) return;
  4804. int distance = 1 + Math.Max(0, magic.Level - 1) + Envir.Random.Next(2);
  4805. MirDirection dir = Functions.DirectionFromPoint(CurrentLocation, target.CurrentLocation);
  4806. target.Pushed(this, dir, distance);
  4807. }
  4808. public void BindingShot(UserMagic magic, MapObject target, out bool cast)
  4809. {
  4810. cast = false;
  4811. if (target == null || !target.IsAttackTarget(this) || !(target is MonsterObject)) return;
  4812. if ((Info.MentalState != 1) && !CanFly(target.CurrentLocation)) return;
  4813. if (target.Level > Level + 2) return;
  4814. if (((MonsterObject)target).ShockTime >= Envir.Time) return;//Already shocked
  4815. uint duration = (uint)((magic.Level * 5 + 10) * 1000);
  4816. int value = (int)duration;
  4817. int delay = Functions.MaxDistance(CurrentLocation, target.CurrentLocation) * 50 + 500; //50 MS per Step
  4818. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, value, target, target.CurrentLocation);
  4819. ActionList.Add(action);
  4820. cast = true;
  4821. }
  4822. public void SpecialArrowShot(MapObject target, UserMagic magic)
  4823. {
  4824. if (target == null || !target.IsAttackTarget(this)) return;
  4825. if ((Info.MentalState != 1) && !CanFly(target.CurrentLocation)) return;
  4826. int distance = Functions.MaxDistance(CurrentLocation, target.CurrentLocation);
  4827. int damage = magic.GetDamage(GetRangeAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC], distance));
  4828. damage = ApplyArcherState(damage);
  4829. int delay = distance * 50 + 500; //50 MS per Step
  4830. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, damage, target, target.CurrentLocation);
  4831. ActionList.Add(action);
  4832. }
  4833. public void NapalmShot(MapObject target, UserMagic magic)
  4834. {
  4835. if (target == null || !target.IsAttackTarget(this)) return;
  4836. if ((Info.MentalState != 1) && !CanFly(target.CurrentLocation)) return;
  4837. int distance = Functions.MaxDistance(CurrentLocation, target.CurrentLocation);
  4838. int damage = magic.GetDamage(GetRangeAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC], distance));
  4839. damage = ApplyArcherState(damage);
  4840. int delay = distance * 50 + 500; //50 MS per Step
  4841. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, this, magic, damage, target.CurrentLocation);
  4842. CurrentMap.ActionList.Add(action);
  4843. }
  4844. public void ArcherSummon(UserMagic magic, MapObject target, Point location)
  4845. {
  4846. if (CurrentMap.Info.NoPets)
  4847. {
  4848. ReceiveChat("You cannot summon pets on this map.", ChatType.System);
  4849. return;
  4850. }
  4851. if (target != null && target.IsAttackTarget(this))
  4852. location = target.CurrentLocation;
  4853. if (!CanFly(location)) return;
  4854. uint duration = (uint)((magic.Level * 5 + 10) * 1000);
  4855. int value = (int)duration;
  4856. int delay = Functions.MaxDistance(CurrentLocation, location) * 50 + 500; //50 MS per Step
  4857. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, value, location, target);
  4858. ActionList.Add(action);
  4859. }
  4860. public void ArcherSummonStone(UserMagic magic, Point location, out bool cast)
  4861. {
  4862. cast = false;
  4863. if (CurrentMap.Info.NoPets)
  4864. {
  4865. ReceiveChat("You cannot summon pets on this map.", ChatType.System);
  4866. return;
  4867. }
  4868. if (!CurrentMap.ValidPoint(location) ||
  4869. !CanFly(location))
  4870. {
  4871. return;
  4872. }
  4873. if (Pets.Exists(x => x.Info.GameName == Settings.StoneName))
  4874. {
  4875. MonsterObject st = Pets.First(x => x.Info.GameName == Settings.StoneName);
  4876. if (!st.Dead)
  4877. {
  4878. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization((ServerTextKeys.OnlyOneActiveStoneAlive), Settings.StoneName), ChatType.Hint);
  4879. return;
  4880. }
  4881. }
  4882. int duration = (((magic.Level * 5) + 10) * 1000);
  4883. int delay = Functions.MaxDistance(CurrentLocation, location) * 50 + 500; //50 MS per Step
  4884. //
  4885. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, duration, location);
  4886. ActionList.Add(action);
  4887. cast = true;
  4888. }
  4889. public void OneWithNature(MapObject target, UserMagic magic)
  4890. {
  4891. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  4892. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, damage, CurrentLocation);
  4893. CurrentMap.ActionList.Add(action);
  4894. }
  4895. public void HealingCircle(UserMagic magic, Point location)
  4896. {
  4897. var damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinSC], Stats[Stat.MaxSC]));
  4898. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500 + 1200, this, magic, damage, location);
  4899. CurrentMap.ActionList.Add(action);
  4900. }
  4901. #endregion
  4902. #region Custom
  4903. private void Portal(UserMagic magic, Point location, out bool cast)
  4904. {
  4905. cast = false;
  4906. if (!CurrentMap.ValidPoint(location)) return;
  4907. var portalCount = Envir.Spells.Count(x => x.Spell == Spell.Portal && x.Caster == this);
  4908. if (portalCount == 2) return;
  4909. if (!CanFly(location)) return;
  4910. int duration = 30 + (magic.Level * 30);
  4911. int value = duration;
  4912. int passthroughCount = (magic.Level * 2) - 1;
  4913. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, value, location, passthroughCount);
  4914. CurrentMap.ActionList.Add(action);
  4915. cast = true;
  4916. }
  4917. private bool FireBounce(MapObject target, UserMagic magic, MapObject source, int bounce = -1)
  4918. {
  4919. if (target == null || !target.IsAttackTarget(this) || !source.CanFly(target.CurrentLocation) || bounce == 0) return false;
  4920. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  4921. int delay = Functions.MaxDistance(source.CurrentLocation, target.CurrentLocation) * 50; //50 MS per Step
  4922. if (bounce == -1)
  4923. {
  4924. bounce = magic.Level + 2;
  4925. delay += 500;
  4926. }
  4927. else
  4928. {
  4929. CurrentMap.Broadcast(new S.ObjectProjectile { Spell = magic.Info.Spell, Source = source.ObjectID, Destination = target.ObjectID }, source.CurrentLocation);
  4930. }
  4931. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, damage, target, target.CurrentLocation, bounce);
  4932. ActionList.Add(action);
  4933. return true;
  4934. }
  4935. private bool MeteorShower(MapObject target, UserMagic magic)
  4936. {
  4937. if (target == null || !target.IsAttackTarget(this) || !CanFly(target.CurrentLocation)) return false;
  4938. int damage = magic.GetDamage(GetAttackPower(Stats[Stat.MinMC], Stats[Stat.MaxMC]));
  4939. int delay = Functions.MaxDistance(CurrentLocation, target.CurrentLocation) * 50 + 500; //50 MS per Step
  4940. var targetIDs = new List<uint>();
  4941. if (target.Race == ObjectType.Monster)
  4942. {
  4943. List<MapObject> targets = ((MonsterObject)target).FindAllNearby(4, target.CurrentLocation);
  4944. int secondaryTargetCount = targets.Count > 3 ? 3 : targets.Count;
  4945. for (int i = 0; i < secondaryTargetCount; i++)
  4946. {
  4947. if (targets[i] == target || !targets[i].IsAttackTarget(this)) continue;
  4948. DelayedAction action2 = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, damage / 2, targets[i], targets[i].CurrentLocation);
  4949. ActionList.Add(action2);
  4950. targetIDs.Add(targets[i].ObjectID);
  4951. }
  4952. }
  4953. Broadcast(new S.ObjectMagic { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, Spell = magic.Info.Spell, TargetID = target.ObjectID, Target = target.CurrentLocation, Cast = true, Level = magic.Level, SecondaryTargetIDs = targetIDs });
  4954. Enqueue(new S.Magic { Spell = Spell.MeteorShower, TargetID = target.ObjectID, Target = target.CurrentLocation, Cast = true, Level = magic.Level, SecondaryTargetIDs = targetIDs });
  4955. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + delay, magic, damage, target, target.CurrentLocation);
  4956. ActionList.Add(action);
  4957. return true;
  4958. }
  4959. #endregion
  4960. private void CheckSneakRadius()
  4961. {
  4962. if (!Sneaking) return;
  4963. for (int y = CurrentLocation.Y - 3; y <= CurrentLocation.Y + 3; y++)
  4964. {
  4965. if (y < 0) continue;
  4966. if (y >= CurrentMap.Height) break;
  4967. for (int x = CurrentLocation.X - 3; x <= CurrentLocation.X + 3; x++)
  4968. {
  4969. if (x < 0) continue;
  4970. if (x >= CurrentMap.Width) break;
  4971. Cell cell = CurrentMap.GetCell(x, y);
  4972. if (!cell.Valid || cell.Objects == null) continue;
  4973. for (int i = 0; cell.Objects != null && i < cell.Objects.Count; i++)
  4974. {
  4975. MapObject ob = cell.Objects[i];
  4976. if ((ob.Race != ObjectType.Player) || ob == this) continue;
  4977. SneakingActive = false;
  4978. return;
  4979. }
  4980. }
  4981. }
  4982. SneakingActive = true;
  4983. }
  4984. protected void CompleteMagic(IList<object> data)
  4985. {
  4986. UserMagic magic = (UserMagic)data[0];
  4987. int value;
  4988. MapObject target;
  4989. Point targetLocation;
  4990. Point location;
  4991. MonsterObject monster;
  4992. switch (magic.Spell)
  4993. {
  4994. #region FireBall, GreatFireBall, ThunderBolt, SoulFireBall, FlameDisruptor
  4995. case Spell.FireBall:
  4996. case Spell.GreatFireBall:
  4997. case Spell.ThunderBolt:
  4998. case Spell.SoulFireBall:
  4999. case Spell.FlameDisruptor:
  5000. case Spell.StraightShot:
  5001. case Spell.DoubleShot:
  5002. case Spell.MeteorShower:
  5003. value = (int)data[1];
  5004. target = (MapObject)data[2];
  5005. targetLocation = (Point)data[3];
  5006. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null || !Functions.InRange(target.CurrentLocation, targetLocation, 2)) return;
  5007. if (target.Attacked(this, value, DefenceType.MAC, false) > 0) LevelMagic(magic);
  5008. break;
  5009. #endregion
  5010. #region FireBounce
  5011. case Spell.FireBounce:
  5012. value = (int)data[1];
  5013. target = (MapObject)data[2];
  5014. targetLocation = (Point)data[3];
  5015. int bounce = (int)data[4];
  5016. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null || !Functions.InRange(target.CurrentLocation, targetLocation, 2)) return;
  5017. if (target.Attacked(this, value, DefenceType.MAC, false) > 0) LevelMagic(magic);
  5018. if (target.Race == ObjectType.Monster)
  5019. {
  5020. var targets = ((MonsterObject)target).FindAllNearby(3, target.CurrentLocation).Where(x => x != target && x.IsAttackTarget(this) && target.CanFly(x.CurrentLocation)).ToList();
  5021. if (targets.Count > 0)
  5022. {
  5023. var nextTarget = targets[Envir.Random.Next(targets.Count)];
  5024. this.FireBounce(nextTarget, magic, target, --bounce);
  5025. }
  5026. }
  5027. break;
  5028. #endregion
  5029. #region FrostCrunch
  5030. case Spell.FrostCrunch:
  5031. value = (int)data[1];
  5032. target = (MapObject)data[2];
  5033. targetLocation = (Point)data[3];
  5034. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null || !Functions.InRange(target.CurrentLocation, targetLocation, 2)) return;
  5035. if (target.Attacked(this, value, DefenceType.MAC, false) > 0)
  5036. {
  5037. if (Level + (target.Race == ObjectType.Player ? 2 : 10) >= target.Level && Envir.Random.Next(target.Race == ObjectType.Player ? 100 : 20) <= magic.Level)
  5038. {
  5039. target.ApplyPoison(new Poison
  5040. {
  5041. Owner = this,
  5042. Duration = target.Race == ObjectType.Player ? 4 : 5 + Envir.Random.Next(5),
  5043. PType = PoisonType.Slow,
  5044. TickSpeed = 1000,
  5045. }, this);
  5046. target.OperateTime = 0;
  5047. }
  5048. if (Level + (target.Race == ObjectType.Player ? 2 : 10) >= target.Level && Envir.Random.Next(target.Race == ObjectType.Player ? 100 : 40) <= magic.Level)
  5049. {
  5050. target.ApplyPoison(new Poison
  5051. {
  5052. Owner = this,
  5053. Duration = target.Race == ObjectType.Player ? 2 : 5 + Envir.Random.Next(Stats[Stat.Freezing]),
  5054. PType = PoisonType.Frozen,
  5055. TickSpeed = 1000,
  5056. }, this);
  5057. target.OperateTime = 0;
  5058. }
  5059. LevelMagic(magic);
  5060. }
  5061. break;
  5062. #endregion
  5063. #region Vampirism
  5064. case Spell.Vampirism:
  5065. value = (int)data[1];
  5066. target = (MapObject)data[2];
  5067. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null) return;
  5068. value = target.Attacked(this, value, DefenceType.MAC, false);
  5069. if (value == 0) return;
  5070. LevelMagic(magic);
  5071. if (VampAmount == 0) VampTime = Envir.Time + 1000;
  5072. VampAmount += (ushort)(value * (magic.Level + 1) * 0.25F);
  5073. break;
  5074. #endregion
  5075. #region Healing
  5076. case Spell.Healing:
  5077. value = (int)data[1];
  5078. target = (MapObject)data[2];
  5079. if (target == null || !target.IsFriendlyTarget(this) || target.CurrentMap != CurrentMap || target.Node == null) return;
  5080. if (target.Health >= target.MaxHealth) return;
  5081. target.HealAmount = (ushort)Math.Min(ushort.MaxValue, target.HealAmount + value);
  5082. target.OperateTime = 0;
  5083. LevelMagic(magic);
  5084. break;
  5085. #endregion
  5086. #region ElectricShock
  5087. case Spell.ElectricShock:
  5088. monster = (MonsterObject)data[1];
  5089. if (monster == null || !monster.IsAttackTarget(this) || monster.CurrentMap != CurrentMap || monster.Node == null) return;
  5090. ElectricShock(monster, magic);
  5091. break;
  5092. #endregion
  5093. #region Poisoning
  5094. case Spell.Poisoning:
  5095. value = (int)data[1];
  5096. target = (MapObject)data[2];
  5097. UserItem item = (UserItem)data[3];
  5098. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null) return;
  5099. switch (item.Info.Shape)
  5100. {
  5101. case 1:
  5102. target.ApplyPoison(new Poison
  5103. {
  5104. Duration = (value * 2) + ((magic.Level + 1) * 7),
  5105. Owner = this,
  5106. PType = PoisonType.Green,
  5107. TickSpeed = 2000,
  5108. Value = value / 15 + magic.Level + 1 + Envir.Random.Next(Stats[Stat.PoisonAttack])
  5109. }, this);
  5110. break;
  5111. case 2:
  5112. target.ApplyPoison(new Poison
  5113. {
  5114. Duration = (value * 2) + (magic.Level + 1) * 7,
  5115. Owner = this,
  5116. PType = PoisonType.Red,
  5117. TickSpeed = 2000,
  5118. }, this);
  5119. break;
  5120. }
  5121. target.OperateTime = 0;
  5122. LevelMagic(magic);
  5123. break;
  5124. #endregion
  5125. #region StormEscape
  5126. case Spell.StormEscape:
  5127. location = (Point)data[1];
  5128. if (CurrentMap.Info.NoTeleport)
  5129. {
  5130. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouCannotTeleportOnMap), ChatType.System);
  5131. return;
  5132. }
  5133. if (!CurrentMap.ValidPoint(location) || Envir.Random.Next(4) >= magic.Level + 1 || !Teleport(CurrentMap, location, false)) return;
  5134. CurrentMap.Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.StormEscape }, CurrentLocation);
  5135. AddBuff(BuffType.TemporalFlux, this, Settings.Second * 30, new Stats { [Stat.TeleportManaPenaltyPercent] = 30 });
  5136. LevelMagic(magic);
  5137. break;
  5138. #endregion
  5139. #region Teleport
  5140. case Spell.Teleport:
  5141. if (CurrentMap.Info.NoTeleport)
  5142. {
  5143. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouCannotTeleportOnMap), ChatType.System);
  5144. return;
  5145. }
  5146. if (!MagicTeleport(magic))
  5147. return;
  5148. AddBuff(BuffType.TemporalFlux, this, Settings.Second * 30, new Stats { [Stat.TeleportManaPenaltyPercent] = 30 });
  5149. LevelMagic(magic);
  5150. break;
  5151. #endregion
  5152. #region Blink
  5153. case Spell.Blink:
  5154. {
  5155. location = (Point)data[1];
  5156. if (CurrentMap.Info.NoTeleport)
  5157. {
  5158. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouCannotTeleportOnMap), ChatType.System);
  5159. return;
  5160. }
  5161. if (Functions.InRange(CurrentLocation, location, magic.Info.Range) == false) return;
  5162. if (!CurrentMap.ValidPoint(location) || Envir.Random.Next(4) >= magic.Level + 1 || !Teleport(CurrentMap, location, false)) return;
  5163. CurrentMap.Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.Teleport }, CurrentLocation);
  5164. LevelMagic(magic);
  5165. AddBuff(BuffType.TemporalFlux, this, Settings.Second * 30, new Stats { [Stat.TeleportManaPenaltyPercent] = 30 });
  5166. }
  5167. break;
  5168. #endregion
  5169. #region Hiding
  5170. case Spell.Hiding:
  5171. {
  5172. value = (int)data[1];
  5173. AddBuff(BuffType.Hiding, this, Settings.Second * value, new Stats());
  5174. LevelMagic(magic);
  5175. }
  5176. break;
  5177. #endregion
  5178. #region Haste
  5179. case Spell.Haste:
  5180. {
  5181. AddBuff(BuffType.Haste, this, (Settings.Second * 25) + (Settings.Second * magic.Level * 15), new Stats { [Stat.AttackSpeed] = (magic.Level * 2) + 2 });
  5182. LevelMagic(magic);
  5183. }
  5184. break;
  5185. #endregion
  5186. #region Fury
  5187. case Spell.Fury:
  5188. {
  5189. AddBuff(BuffType.Fury, this, (Settings.Second * 60) + (magic.Level * 10000), new Stats { [Stat.AttackSpeed] = 4 });
  5190. LevelMagic(magic);
  5191. }
  5192. break;
  5193. #endregion
  5194. #region ImmortalSkin
  5195. case Spell.ImmortalSkin:
  5196. {
  5197. var stats = new Stats
  5198. {
  5199. [Stat.MaxDC] = (int)Math.Round(Stats[Stat.MaxDC] * (0.05 + (0.01 * magic.Level))) * -1,
  5200. [Stat.MaxAC] = (int)Math.Round(Stats[Stat.MaxAC] * (0.10 + (0.07 * magic.Level)))
  5201. };
  5202. AddBuff(BuffType.ImmortalSkin, this, (Settings.Second * 60) + (magic.Level * 1000), stats);
  5203. LevelMagic(magic);
  5204. }
  5205. break;
  5206. #endregion
  5207. #region LightBody
  5208. case Spell.LightBody:
  5209. {
  5210. AddBuff(BuffType.LightBody, this, (magic.Level + 1) * (Settings.Second * 30), new Stats { [Stat.Agility] = (magic.Level + 1) * 2 });
  5211. LevelMagic(magic);
  5212. }
  5213. break;
  5214. #endregion
  5215. #region MagicShield
  5216. case Spell.MagicShield:
  5217. {
  5218. if (HasBuff(BuffType.MagicShield, out _)) return;
  5219. LevelMagic(magic);
  5220. AddBuff(BuffType.MagicShield, this, Settings.Second * (int)data[1], new Stats { [Stat.DamageReductionPercent] = (magic.Level + 2) * 10 });
  5221. }
  5222. break;
  5223. #endregion
  5224. #region TurnUndead
  5225. case Spell.TurnUndead:
  5226. {
  5227. monster = (MonsterObject)data[1];
  5228. if (monster == null || !monster.IsAttackTarget(this) || monster.CurrentMap != CurrentMap || monster.Node == null) return;
  5229. monster.LastHitter = this;
  5230. monster.LastHitTime = Envir.Time + 5000;
  5231. monster.EXPOwner = this;
  5232. monster.EXPOwnerTime = Envir.Time + 5000;
  5233. monster.Die();
  5234. LevelMagic(magic);
  5235. }
  5236. break;
  5237. #endregion
  5238. #region MagicBooster
  5239. case Spell.MagicBooster:
  5240. {
  5241. var stats = new Stats
  5242. {
  5243. [Stat.MinMC] = (int)data[1],
  5244. [Stat.MaxMC] = (int)data[1],
  5245. [Stat.ManaPenaltyPercent] = 6 + magic.Level
  5246. };
  5247. AddBuff(BuffType.MagicBooster, this, Settings.Second * 60, stats, true);
  5248. LevelMagic(magic);
  5249. }
  5250. break;
  5251. #endregion
  5252. #region Purification
  5253. case Spell.Purification:
  5254. target = (MapObject)data[1];
  5255. if (target == null || !target.IsFriendlyTarget(this) || target.CurrentMap != CurrentMap || target.Node == null) return;
  5256. if (Envir.Random.Next(4) > magic.Level) return;
  5257. for (int i = 0; i < target.Buffs.Count; i++)
  5258. {
  5259. var buff = target.Buffs[i];
  5260. if (!buff.Properties.HasFlag(BuffProperty.Debuff)) continue;
  5261. target.RemoveBuff(buff.Type);
  5262. }
  5263. if (target.PoisonList.Any(x => x.PType == PoisonType.DelayedExplosion))
  5264. {
  5265. target.ExplosionInflictedTime = 0;
  5266. target.ExplosionInflictedStage = 0;
  5267. if (target.ObjectID == ObjectID)
  5268. {
  5269. Enqueue(new S.RemoveDelayedExplosion { ObjectID = target.ObjectID });
  5270. }
  5271. target.Broadcast(new S.RemoveDelayedExplosion { ObjectID = target.ObjectID });
  5272. }
  5273. target.PoisonList.Clear();
  5274. target.OperateTime = 0;
  5275. LevelMagic(magic);
  5276. break;
  5277. #endregion
  5278. #region Revelation
  5279. case Spell.Revelation:
  5280. value = (int)data[1];
  5281. target = (MapObject)data[2];
  5282. if (target == null || target.CurrentMap != CurrentMap || target.Node == null) return;
  5283. if (target.Race != ObjectType.Player && target.Race != ObjectType.Monster) return;
  5284. if (Envir.Random.Next(4) > magic.Level || Envir.Time < target.RevTime) return;
  5285. target.RevTime = Envir.Time + value * 1000;
  5286. target.OperateTime = 0;
  5287. target.BroadcastHealthChange();
  5288. LevelMagic(magic);
  5289. break;
  5290. #endregion
  5291. #region Reincarnation
  5292. case Spell.Reincarnation:
  5293. if (ReincarnationReady)
  5294. {
  5295. ReincarnationTarget.Enqueue(new S.RequestReincarnation { });
  5296. LevelMagic(magic);
  5297. }
  5298. break;
  5299. #endregion
  5300. #region Entrapment
  5301. case Spell.Entrapment:
  5302. value = (int)data[1];
  5303. target = (MapObject)data[2];
  5304. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null || target.Race != ObjectType.Monster ||
  5305. Functions.MaxDistance(CurrentLocation, target.CurrentLocation) > 7 || target.Level >= Level + 5 + Envir.Random.Next(8)) return;
  5306. MirDirection pulldirection = (MirDirection)((byte)(Direction - 4) % 8);
  5307. int pulldistance = 0;
  5308. if ((byte)pulldirection % 2 > 0)
  5309. pulldistance = Math.Max(0, Math.Min(Math.Abs(CurrentLocation.X - target.CurrentLocation.X), Math.Abs(CurrentLocation.Y - target.CurrentLocation.Y)));
  5310. else
  5311. pulldistance = pulldirection == MirDirection.Up || pulldirection == MirDirection.Down ? Math.Abs(CurrentLocation.Y - target.CurrentLocation.Y) - 2 : Math.Abs(CurrentLocation.X - target.CurrentLocation.X) - 2;
  5312. int levelgap = target.Race == ObjectType.Player ? Level - target.Level + 4 : Level - target.Level + 9;
  5313. if (Envir.Random.Next(30) >= ((magic.Level + 1) * 3) + levelgap) return;
  5314. int duration = target.Race == ObjectType.Player ? (int)Math.Round((magic.Level + 1) * 1.6) : (int)Math.Round((magic.Level + 1) * 0.8);
  5315. if (duration > 0) target.ApplyPoison(new Poison { PType = PoisonType.Paralysis, Duration = duration, TickSpeed = 1000 }, this);
  5316. CurrentMap.Broadcast(new S.ObjectEffect { ObjectID = target.ObjectID, Effect = SpellEffect.Entrapment }, target.CurrentLocation);
  5317. if (target.Pushed(this, pulldirection, pulldistance) > 0) LevelMagic(magic);
  5318. break;
  5319. #endregion
  5320. #region Hallucination
  5321. case Spell.Hallucination:
  5322. value = (int)data[1];
  5323. target = (MapObject)data[2];
  5324. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null ||
  5325. Functions.MaxDistance(CurrentLocation, target.CurrentLocation) > 7 || Envir.Random.Next(Level + 20 + magic.Level * 5) <= target.Level + 10) return;
  5326. item = GetAmulet(1);
  5327. if (item == null) return;
  5328. ((MonsterObject)target).HallucinationTime = Envir.Time + (Envir.Random.Next(20) + 10) * 1000;
  5329. target.Target = null;
  5330. ConsumeItem(item, 1);
  5331. LevelMagic(magic);
  5332. break;
  5333. #endregion
  5334. #region PetEnhancer
  5335. case Spell.PetEnhancer:
  5336. {
  5337. value = (int)data[1];
  5338. target = (MonsterObject)data[2];
  5339. if (target.Node == null) return;
  5340. int dcInc = 2 + target.Level * 2;
  5341. int acInc = 4 + target.Level;
  5342. var stats = new Stats
  5343. {
  5344. [Stat.MinDC] = dcInc,
  5345. [Stat.MaxDC] = dcInc,
  5346. [Stat.MinAC] = acInc,
  5347. [Stat.MaxAC] = acInc
  5348. };
  5349. target.AddBuff(BuffType.PetEnhancer, this, (Settings.Second * value), stats);
  5350. LevelMagic(magic);
  5351. }
  5352. break;
  5353. #endregion
  5354. #region CatTongue
  5355. case Spell.CatTongue:
  5356. value = (int)data[1];
  5357. target = (MapObject)data[2];
  5358. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null) return;
  5359. if (target.Attacked(this, value, DefenceType.AC, false) > 0)
  5360. {
  5361. int rnd = Envir.Random.Next(10);
  5362. if (rnd >= 8)
  5363. {
  5364. if (target.Race == ObjectType.Player && Settings.PvpCanFreeze)
  5365. target.ApplyPoison(new Poison { PType = PoisonType.Frozen, Duration = (magic.Level + 1) * 3, TickSpeed = 1000 }, this);
  5366. else
  5367. rnd -= 4;
  5368. }
  5369. if (rnd <= 4)
  5370. target.ApplyPoison(new Poison { PType = PoisonType.Stun, Duration = (magic.Level + 1) * 3, TickSpeed = 1000 }, this);
  5371. else if (rnd <= 7)
  5372. target.ApplyPoison(new Poison { PType = PoisonType.Slow, Duration = (magic.Level + 1) * 3, TickSpeed = 1000 }, this);
  5373. LevelMagic(magic);
  5374. }
  5375. break;
  5376. #endregion
  5377. #region ElementalBarrier, ElementalShot
  5378. case Spell.ElementalBarrier:
  5379. {
  5380. if (HasBuff(BuffType.ElementalBarrier, out _)) return;
  5381. if (!HasElemental)
  5382. {
  5383. ObtainElement(true);
  5384. LevelMagic(magic);
  5385. return;
  5386. }
  5387. int barrierPower = GetElementalOrbPower(true);//defensive orbpower
  5388. //destroy orbs
  5389. ElementsLevel = 0;
  5390. ObtainElement(false);
  5391. LevelMagic(magic);
  5392. AddBuff(BuffType.ElementalBarrier, this, Settings.Second * ((int)data[1] + barrierPower), new Stats { [Stat.DamageReductionPercent] = (magic.Level + 1) * 10 });
  5393. CurrentMap.Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.ElementalBarrierUp }, CurrentLocation);
  5394. }
  5395. break;
  5396. case Spell.ElementalShot:
  5397. value = (int)data[1];
  5398. target = (MapObject)data[2];
  5399. targetLocation = (Point)data[3];
  5400. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null || !Functions.InRange(target.CurrentLocation, targetLocation, 2))
  5401. {
  5402. //destroy orbs
  5403. ElementsLevel = 0;
  5404. ObtainElement(false);//update and send to client
  5405. return;
  5406. }
  5407. if (target.Attacked(this, value, DefenceType.MAC, false) > 0)
  5408. LevelMagic(magic);
  5409. DoKnockback(target, magic);//ElementalShot - Knockback
  5410. //destroy orbs
  5411. ElementsLevel = 0;
  5412. ObtainElement(false);//update and send to client
  5413. break;
  5414. #endregion
  5415. #region DelayedExplosion
  5416. case Spell.DelayedExplosion:
  5417. value = (int)data[1];
  5418. target = (MapObject)data[2];
  5419. targetLocation = (Point)data[3];
  5420. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null || !Functions.InRange(target.CurrentLocation, targetLocation, 2)) return;
  5421. if (target.Attacked(this, value, DefenceType.MAC, false) > 0) LevelMagic(magic);
  5422. target.ApplyPoison(new Poison
  5423. {
  5424. Duration = (value * 2) + (magic.Level + 1) * 7,
  5425. Owner = this,
  5426. PType = PoisonType.DelayedExplosion,
  5427. TickSpeed = 2000,
  5428. Value = value
  5429. }, this);
  5430. target.OperateTime = 0;
  5431. LevelMagic(magic);
  5432. break;
  5433. #endregion
  5434. #region BindingShot
  5435. case Spell.BindingShot:
  5436. value = (int)data[1];
  5437. target = (MapObject)data[2];
  5438. targetLocation = (Point)data[3];
  5439. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null || !Functions.InRange(target.CurrentLocation, targetLocation, 2)) return;
  5440. if (((MonsterObject)target).ShockTime >= Envir.Time) return;//Already shocked
  5441. Point place = target.CurrentLocation;
  5442. MonsterObject centerTarget = null;
  5443. for (int y = place.Y - 1; y <= place.Y + 1; y++)
  5444. {
  5445. if (y < 0) continue;
  5446. if (y >= CurrentMap.Height) break;
  5447. for (int x = place.X - 1; x <= place.X + 1; x++)
  5448. {
  5449. if (x < 0) continue;
  5450. if (x >= CurrentMap.Width) break;
  5451. Cell cell = CurrentMap.GetCell(x, y);
  5452. if (!cell.Valid || cell.Objects == null) continue;
  5453. for (int i = 0; i < cell.Objects.Count; i++)
  5454. {
  5455. MapObject targetob = cell.Objects[i];
  5456. if (y == place.Y && x == place.X && targetob.Race == ObjectType.Monster)
  5457. {
  5458. centerTarget = (MonsterObject)targetob;
  5459. }
  5460. switch (targetob.Race)
  5461. {
  5462. case ObjectType.Monster:
  5463. if (targetob == null || !targetob.IsAttackTarget(this) || targetob.Node == null || targetob.Level > this.Level + 2) continue;
  5464. MonsterObject mobTarget = (MonsterObject)targetob;
  5465. if (centerTarget == null) centerTarget = mobTarget;
  5466. mobTarget.ShockTime = Envir.Time + value;
  5467. mobTarget.Target = null;
  5468. break;
  5469. }
  5470. }
  5471. }
  5472. }
  5473. if (centerTarget == null) return;
  5474. //only the centertarget holds the effect
  5475. centerTarget.BindingShotCenter = true;
  5476. centerTarget.Broadcast(new S.SetBindingShot { ObjectID = centerTarget.ObjectID, Enabled = true, Value = value });
  5477. LevelMagic(magic);
  5478. break;
  5479. #endregion
  5480. #region VampireShot, PoisonShot, CrippleShot
  5481. case Spell.VampireShot:
  5482. case Spell.PoisonShot:
  5483. case Spell.CrippleShot:
  5484. value = (int)data[1];
  5485. target = (MapObject)data[2];
  5486. targetLocation = (Point)data[3];
  5487. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null || !Functions.InRange(target.CurrentLocation, targetLocation, 2)) return;
  5488. if (target.Attacked(this, value, DefenceType.MAC, false) == 0) return;
  5489. int buffTime = 5 + (5 * magic.Level);
  5490. bool hasVampBuff = HasBuff(BuffType.VampireShot, out _);
  5491. bool hasPoisonBuff = HasBuff(BuffType.PoisonShot, out _);
  5492. bool doVamp = false, doPoison = false;
  5493. if (magic.Spell == Spell.VampireShot)
  5494. {
  5495. doVamp = true;
  5496. if (!hasVampBuff && !hasPoisonBuff && (Envir.Random.Next(20) >= 8))//40% chance
  5497. {
  5498. AddBuff(BuffType.VampireShot, this, Settings.Second * buffTime, new Stats());
  5499. BroadcastInfo();
  5500. }
  5501. }
  5502. if (magic.Spell == Spell.PoisonShot)
  5503. {
  5504. doPoison = true;
  5505. if (!hasPoisonBuff && !hasVampBuff && (Envir.Random.Next(20) >= 8))//40% chance
  5506. {
  5507. AddBuff(BuffType.PoisonShot, this, Settings.Second * buffTime, new Stats());
  5508. BroadcastInfo();
  5509. }
  5510. }
  5511. if (magic.Spell == Spell.CrippleShot)
  5512. {
  5513. if (hasVampBuff || hasPoisonBuff)
  5514. {
  5515. place = target.CurrentLocation;
  5516. for (int y = place.Y - 1; y <= place.Y + 1; y++)
  5517. {
  5518. if (y < 0) continue;
  5519. if (y >= CurrentMap.Height) break;
  5520. for (int x = place.X - 1; x <= place.X + 1; x++)
  5521. {
  5522. if (x < 0) continue;
  5523. if (x >= CurrentMap.Width) break;
  5524. Cell cell = CurrentMap.GetCell(x, y);
  5525. if (!cell.Valid || cell.Objects == null) continue;
  5526. for (int i = 0; i < cell.Objects.Count; i++)
  5527. {
  5528. MapObject targetob = cell.Objects[i];
  5529. if (targetob.Race != ObjectType.Monster && targetob.Race != ObjectType.Player) continue;
  5530. if (targetob == null || !targetob.IsAttackTarget(this) || targetob.Node == null) continue;
  5531. if (targetob.Dead) continue;
  5532. if (hasVampBuff)//Vampire Effect
  5533. {
  5534. //cancel out buff
  5535. AddBuff(BuffType.VampireShot, this, 0, new Stats());
  5536. target.Attacked(this, value, DefenceType.MAC, false);
  5537. if (VampAmount == 0) VampTime = Envir.Time + Settings.Second;
  5538. VampAmount += (ushort)(value * (magic.Level + 1) * 0.25F);
  5539. }
  5540. if (hasPoisonBuff)//Poison Effect
  5541. {
  5542. //cancel out buff
  5543. AddBuff(BuffType.PoisonShot, this, 0, new Stats());
  5544. targetob.ApplyPoison(new Poison
  5545. {
  5546. Duration = (value * 2) + (magic.Level + 1) * 7,
  5547. Owner = this,
  5548. PType = PoisonType.Green,
  5549. TickSpeed = 2000,
  5550. Value = value / 25 + magic.Level + 1 + Envir.Random.Next(Stats[Stat.PoisonAttack])
  5551. }, this);
  5552. targetob.OperateTime = 0;
  5553. }
  5554. }
  5555. }
  5556. }
  5557. }
  5558. }
  5559. else
  5560. {
  5561. if (doVamp)//Vampire Effect
  5562. {
  5563. if (VampAmount == 0) VampTime = Envir.Time + 1000;
  5564. VampAmount += (ushort)(value * (magic.Level + 1) * 0.25F);
  5565. }
  5566. if (doPoison)//Poison Effect
  5567. {
  5568. target.ApplyPoison(new Poison
  5569. {
  5570. Duration = (value * 2) + (magic.Level + 1) * 7,
  5571. Owner = this,
  5572. PType = PoisonType.Green,
  5573. TickSpeed = 2000,
  5574. Value = value / 25 + magic.Level + 1 + Envir.Random.Next(Stats[Stat.PoisonAttack])
  5575. }, this);
  5576. target.OperateTime = 0;
  5577. }
  5578. }
  5579. LevelMagic(magic);
  5580. break;
  5581. #endregion
  5582. #region ArcherSummons
  5583. case Spell.SummonVampire:
  5584. case Spell.SummonToad:
  5585. case Spell.SummonSnakes:
  5586. value = (int)data[1];
  5587. location = (Point)data[2];
  5588. target = (MapObject)data[3];
  5589. int SummonType = 0;
  5590. switch (magic.Spell)
  5591. {
  5592. case Spell.SummonVampire:
  5593. SummonType = 1;
  5594. break;
  5595. case Spell.SummonToad:
  5596. SummonType = 2;
  5597. break;
  5598. case Spell.SummonSnakes:
  5599. SummonType = 3;
  5600. break;
  5601. }
  5602. if (SummonType == 0) return;
  5603. for (int i = 0; i < Pets.Count; i++)
  5604. {
  5605. monster = Pets[i];
  5606. if ((monster.Info.Name != (SummonType == 1 ? Settings.VampireName : (SummonType == 2 ? Settings.ToadName : Settings.SnakeTotemName))) || monster.Dead) continue;
  5607. if (monster.Node == null) continue;
  5608. monster.ActionList.Add(new DelayedAction(DelayedType.Recall, Envir.Time + 500, target));
  5609. monster.Target = target;
  5610. return;
  5611. }
  5612. if (Pets.Count(x => x.Race == ObjectType.Monster) >= 2) return;
  5613. //left it in for future summon amulets
  5614. //UserItem item = GetAmulet(5);
  5615. //if (item == null) return;
  5616. MonsterInfo info = Envir.GetMonsterInfo((SummonType == 1 ? Settings.VampireName : (SummonType == 2 ? Settings.ToadName : Settings.SnakeTotemName)));
  5617. if (info == null) return;
  5618. LevelMagic(magic);
  5619. //ConsumeItem(item, 5);
  5620. monster = MonsterObject.GetMonster(info);
  5621. monster.PetLevel = magic.Level;
  5622. monster.Master = this;
  5623. monster.MaxPetLevel = (byte)(1 + magic.Level * 2);
  5624. monster.Direction = Direction;
  5625. monster.ActionTime = Envir.Time + 1000;
  5626. monster.Target = target;
  5627. if (SummonType == 1)
  5628. ((Monsters.VampireSpider)monster).AliveTime = Envir.Time + ((magic.Level * 1500) + 15000);
  5629. if (SummonType == 2)
  5630. ((Monsters.SpittingToad)monster).AliveTime = Envir.Time + ((magic.Level * 2000) + 25000);
  5631. if (SummonType == 3)
  5632. ((Monsters.SnakeTotem)monster).AliveTime = Envir.Time + ((magic.Level * 1500) + 20000);
  5633. //Pets.Add(monster);
  5634. DelayedAction action = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, monster, location);
  5635. CurrentMap.ActionList.Add(action);
  5636. break;
  5637. case Spell.Stonetrap:
  5638. {
  5639. duration = (int)data[1];
  5640. location = (Point)data[2];
  5641. if (Pets.Where(x => x.Race == ObjectType.Monster).Count() >= magic.Level + 1) return;
  5642. MonsterInfo mInfo = Envir.GetMonsterInfo(Settings.StoneName);
  5643. if (mInfo == null) return;
  5644. LevelMagic(magic);
  5645. monster = MonsterObject.GetMonster(mInfo);
  5646. monster.Master = this;
  5647. monster.MaxPetLevel = (byte)(1 + magic.Level * 2);
  5648. monster.Direction = Direction;
  5649. monster.ActionTime = Envir.Time + 1000;
  5650. StoneTrap st = monster as StoneTrap;
  5651. st.DieTime = Envir.Time + duration;
  5652. DelayedAction act = new DelayedAction(DelayedType.Magic, Envir.Time + 500, this, magic, monster, location);
  5653. CurrentMap.ActionList.Add(act);
  5654. break;
  5655. }
  5656. #endregion
  5657. #region SlashingBurst
  5658. case Spell.SlashingBurst:
  5659. SlashingBurst(magic);
  5660. break;
  5661. #endregion
  5662. }
  5663. }
  5664. protected void CompleteMine(IList<object> data)
  5665. {
  5666. MapObject target = (MapObject)data[0];
  5667. if (target == null) return;
  5668. target.Broadcast(new S.MapEffect { Effect = SpellEffect.Mine, Location = target.CurrentLocation, Value = (byte)Direction });
  5669. //target.Broadcast(new S.ObjectEffect { ObjectID = target.ObjectID, Effect = SpellEffect.Mine });
  5670. if ((byte)target.Direction < 6)
  5671. target.Direction++;
  5672. target.Broadcast(target.GetInfo());
  5673. }
  5674. protected void CompleteAttack(IList<object> data)
  5675. {
  5676. MapObject target = (MapObject)data[0];
  5677. int damage = (int)data[1];
  5678. DefenceType defence = (DefenceType)data[2];
  5679. bool damageWeapon = (bool)data[3];
  5680. UserMagic userMagic = null;
  5681. bool finalHit = false;
  5682. if (data.Count >= 5)
  5683. userMagic = (UserMagic)data[4];
  5684. if (data.Count >= 6)
  5685. finalHit = (bool)data[5];
  5686. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null) return;
  5687. if (FatalSword)
  5688. defence = DefenceType.Agility;
  5689. if (target.Attacked(this, damage, defence, damageWeapon) <= 0) return;
  5690. if (FatalSword)
  5691. {
  5692. S.ObjectEffect p = new S.ObjectEffect { ObjectID = target.ObjectID, Effect = SpellEffect.FatalSword };
  5693. CurrentMap.Broadcast(p, target.CurrentLocation);
  5694. FatalSword = false;
  5695. var magic = GetMagic(Spell.FatalSword);
  5696. if (magic != null) LevelMagic(magic);
  5697. }
  5698. if (userMagic != null && finalHit)
  5699. {
  5700. if (userMagic.Spell == Spell.TwinDrakeBlade)
  5701. {
  5702. if ((((target.Race != ObjectType.Player) || Settings.PvpCanResistPoison) &&
  5703. (Envir.Random.Next(Settings.PoisonAttackWeight) >= target.Stats[Stat.PoisonResist])) &&
  5704. (target.Level < Level + 10 && Envir.Random.Next(target.Race == ObjectType.Player ? 40 : 20) <= userMagic.Level + 1))
  5705. {
  5706. target.ApplyPoison(new Poison { PType = PoisonType.Stun, Duration = target.Race == ObjectType.Player ? 2 : 2 + userMagic.Level, TickSpeed = 1000 }, this);
  5707. target.Broadcast(new S.ObjectEffect { ObjectID = target.ObjectID, Effect = SpellEffect.TwinDrakeBlade });
  5708. }
  5709. }
  5710. }
  5711. //Level Fencing / SpiritSword
  5712. foreach (UserMagic magic in Info.Magics)
  5713. {
  5714. switch (magic.Spell)
  5715. {
  5716. case Spell.Fencing:
  5717. case Spell.SpiritSword:
  5718. LevelMagic(magic);
  5719. break;
  5720. }
  5721. }
  5722. }
  5723. protected void CompleteDamageIndicator(IList<object> data)
  5724. {
  5725. MapObject target = (MapObject)data[0];
  5726. DamageType type = (DamageType)data[1];
  5727. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null) return;
  5728. target.BroadcastDamageIndicator(type);
  5729. }
  5730. protected void CompleteSpellEffect(IList<object> data)
  5731. {
  5732. MapObject target = (MapObject)data[0];
  5733. SpellEffect effect = (SpellEffect)data[1];
  5734. if (target == null || !target.IsAttackTarget(this) || target.CurrentMap != CurrentMap || target.Node == null) return;
  5735. S.ObjectEffect p = new S.ObjectEffect { ObjectID = target.ObjectID, Effect = effect };
  5736. CurrentMap.Broadcast(p, target.CurrentLocation);
  5737. }
  5738. protected void CompletePoison(IList<object> data)
  5739. {
  5740. MapObject target = (MapObject)data[0];
  5741. PoisonType pt = (PoisonType)data[1];
  5742. SpellEffect sp = (SpellEffect)data[2];
  5743. int duration = (int)data[3];
  5744. int tickSpeed = (int)data[4];
  5745. if (target == null) return;
  5746. target.ApplyPoison(new Poison { PType = pt, Duration = duration, TickSpeed = tickSpeed }, this);
  5747. target.Broadcast(new S.ObjectEffect { ObjectID = target.ObjectID, Effect = sp });
  5748. }
  5749. protected UserItem GetAmulet(int count, int shape = 0)
  5750. {
  5751. for (int i = 0; i < Info.Equipment.Length; i++)
  5752. {
  5753. UserItem item = Info.Equipment[i];
  5754. if (item != null && item.Info.Type == ItemType.Amulet && item.Info.Shape == shape && item.Count >= count)
  5755. return item;
  5756. }
  5757. return null;
  5758. }
  5759. protected UserItem GetPoison(int count, byte shape = 0)
  5760. {
  5761. for (int i = 0; i < Info.Equipment.Length; i++)
  5762. {
  5763. UserItem item = Info.Equipment[i];
  5764. if (item != null && item.Info.Type == ItemType.Amulet && item.Count >= count)
  5765. {
  5766. if (shape == 0)
  5767. {
  5768. if (item.Info.Shape == 1 || item.Info.Shape == 2)
  5769. return item;
  5770. }
  5771. else
  5772. {
  5773. if (item.Info.Shape == shape)
  5774. return item;
  5775. }
  5776. }
  5777. }
  5778. return null;
  5779. }
  5780. public UserMagic GetMagic(Spell spell)
  5781. {
  5782. for (int i = 0; i < Info.Magics.Count; i++)
  5783. {
  5784. UserMagic magic = Info.Magics[i];
  5785. if (magic.Spell != spell) continue;
  5786. return magic;
  5787. }
  5788. return null;
  5789. }
  5790. public void LevelMagic(UserMagic magic)
  5791. {
  5792. byte exp = (byte)(Envir.Random.Next(3) + 1);
  5793. if (Settings.MentorSkillBoost && Info.Mentor != 0 && Info.IsMentor)
  5794. {
  5795. if (HasBuff(BuffType.Mentee, out _))
  5796. {
  5797. CharacterInfo mentor = Envir.GetCharacterInfo(Info.Mentor);
  5798. PlayerObject player = Envir.GetPlayer(mentor.Name);
  5799. if (player.CurrentMap == CurrentMap && Functions.InRange(player.CurrentLocation, CurrentLocation, Globals.DataRange) && !player.Dead)
  5800. {
  5801. if (Stats[Stat.SkillGainMultiplier] == 1)
  5802. {
  5803. if (GroupMembers != null && GroupMembers.Contains(player))
  5804. exp *= 2;
  5805. }
  5806. }
  5807. }
  5808. }
  5809. exp *= (byte)Math.Min(byte.MaxValue, Stats[Stat.SkillGainMultiplier]);
  5810. if (Level == ushort.MaxValue) exp = byte.MaxValue;
  5811. int oldLevel = magic.Level;
  5812. switch (magic.Level)
  5813. {
  5814. case 0:
  5815. if (Level < magic.Info.Level1)
  5816. return;
  5817. magic.Experience += exp;
  5818. if (magic.Experience >= magic.Info.Need1)
  5819. {
  5820. magic.Level++;
  5821. magic.Experience = (ushort)(magic.Experience - magic.Info.Need1);
  5822. RefreshStats();
  5823. }
  5824. break;
  5825. case 1:
  5826. if (Level < magic.Info.Level2)
  5827. return;
  5828. magic.Experience += exp;
  5829. if (magic.Experience >= magic.Info.Need2)
  5830. {
  5831. magic.Level++;
  5832. magic.Experience = (ushort)(magic.Experience - magic.Info.Need2);
  5833. RefreshStats();
  5834. }
  5835. break;
  5836. case 2:
  5837. if (Level < magic.Info.Level3)
  5838. return;
  5839. magic.Experience += exp;
  5840. if (magic.Experience >= magic.Info.Need3)
  5841. {
  5842. magic.Level++;
  5843. magic.Experience = 0;
  5844. RefreshStats();
  5845. }
  5846. break;
  5847. default:
  5848. return;
  5849. }
  5850. if (oldLevel != magic.Level)
  5851. {
  5852. long delay = magic.GetDelay();
  5853. Enqueue(new S.MagicDelay { ObjectID = ObjectID, Spell = magic.Spell, Delay = delay });
  5854. }
  5855. Enqueue(new S.MagicLeveled { ObjectID = ObjectID, Spell = magic.Spell, Level = magic.Level, Experience = magic.Experience });
  5856. }
  5857. public virtual bool MagicTeleport(UserMagic magic)
  5858. {
  5859. return false;
  5860. }
  5861. public override bool Teleport(Map temp, Point location, bool effects = true, byte effectnumber = 0)
  5862. {
  5863. Map oldMap = CurrentMap;
  5864. Point oldLocation = CurrentLocation;
  5865. bool mapChanged = temp != oldMap;
  5866. if (!base.Teleport(temp, location, effects)) return false;
  5867. Enqueue(new S.MapChanged
  5868. {
  5869. MapIndex = CurrentMap.Info.Index,
  5870. FileName = CurrentMap.Info.FileName,
  5871. Title = CurrentMap.Info.Title,
  5872. Weather = CurrentMap.Info.WeatherParticles,
  5873. MiniMap = CurrentMap.Info.MiniMap,
  5874. BigMap = CurrentMap.Info.BigMap,
  5875. Lights = CurrentMap.Info.Light,
  5876. Location = CurrentLocation,
  5877. Direction = Direction,
  5878. MapDarkLight = CurrentMap.Info.MapDarkLight,
  5879. Music = CurrentMap.Info.Music
  5880. });
  5881. if (effects) Enqueue(new S.ObjectTeleportIn { ObjectID = ObjectID, Type = effectnumber });
  5882. if (RidingMount) RefreshMount();
  5883. if (ActiveBlizzard) ActiveBlizzard = false;
  5884. if (CheckStacked())
  5885. {
  5886. StackingTime = Envir.Time + 1000;
  5887. Stacking = true;
  5888. }
  5889. SafeZoneInfo szi = CurrentMap.GetSafeZone(CurrentLocation);
  5890. if (szi != null)
  5891. {
  5892. SetBindSafeZone(szi);
  5893. InSafeZone = true;
  5894. }
  5895. else
  5896. InSafeZone = false;
  5897. return true;
  5898. }
  5899. protected virtual void SetBindSafeZone(SafeZoneInfo szi) { }
  5900. public virtual bool AtWar(HumanObject attacker)
  5901. {
  5902. return false;
  5903. }
  5904. private Packet GetMountInfo()
  5905. {
  5906. return new S.MountUpdate
  5907. {
  5908. ObjectID = ObjectID,
  5909. RidingMount = RidingMount,
  5910. MountType = Mount.MountType
  5911. };
  5912. }
  5913. protected Packet GetUpdateInfo()
  5914. {
  5915. return new S.PlayerUpdate
  5916. {
  5917. ObjectID = ObjectID,
  5918. Weapon = Looks_Weapon,
  5919. WeaponEffect = Looks_WeaponEffect,
  5920. Armour = Looks_Armour,
  5921. Light = Light,
  5922. WingEffect = Looks_Wings
  5923. };
  5924. }
  5925. protected virtual void UpdateLooks(short OldLooks_Weapon)
  5926. {
  5927. Broadcast(GetUpdateInfo());
  5928. }
  5929. public Packet GetInfoEx(HumanObject player)
  5930. {
  5931. var p = (S.ObjectPlayer)GetInfo();
  5932. if (p != null)
  5933. {
  5934. p.NameColour = player.GetNameColour(this);
  5935. }
  5936. return p;
  5937. }
  5938. public override bool IsAttackTarget(HumanObject attacker)
  5939. {
  5940. return true;
  5941. }
  5942. public override bool IsAttackTarget(MonsterObject attacker)
  5943. {
  5944. return true;
  5945. }
  5946. public override bool IsFriendlyTarget(HumanObject ally)
  5947. {
  5948. return true;
  5949. }
  5950. public override bool IsFriendlyTarget(MonsterObject ally)
  5951. {
  5952. return true;
  5953. }
  5954. public override void ReceiveChat(string text, ChatType type) { }
  5955. public override Packet GetInfo() { return null; }
  5956. public override int Attacked(HumanObject attacker, int damage, DefenceType type = DefenceType.ACAgility, bool damageWeapon = true)
  5957. {
  5958. if (attacker.Race == ObjectType.Hero)
  5959. {
  5960. HeroObject heroAttacker = (HeroObject)attacker;
  5961. attacker = heroAttacker.Owner;
  5962. heroAttacker.Target = this;
  5963. }
  5964. var armour = GetArmour(type, attacker, out bool hit);
  5965. if (!hit)
  5966. {
  5967. return 0;
  5968. }
  5969. armour = (int)Math.Max(int.MinValue, (Math.Min(int.MaxValue, (decimal)(armour * ArmourRate))));
  5970. damage = (int)Math.Max(int.MinValue, (Math.Min(int.MaxValue, (decimal)(damage * DamageRate))));
  5971. if (damageWeapon)
  5972. attacker.DamageWeapon();
  5973. damage += attacker.Stats[Stat.AttackBonus];
  5974. if (Envir.Random.Next(100) < Stats[Stat.Reflect])
  5975. {
  5976. if (attacker.IsAttackTarget(this))
  5977. {
  5978. attacker.Attacked(this, damage, type, false);
  5979. CurrentMap.Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.Reflect }, CurrentLocation);
  5980. }
  5981. return 0;
  5982. }
  5983. //MagicShield, ElementalBarrier
  5984. if (Stats[Stat.DamageReductionPercent] > 0)
  5985. {
  5986. damage -= (damage * Stats[Stat.DamageReductionPercent]) / 100;
  5987. }
  5988. if (armour >= damage)
  5989. {
  5990. BroadcastDamageIndicator(DamageType.Miss);
  5991. return 0;
  5992. }
  5993. if (Hidden)
  5994. {
  5995. RemoveBuff(BuffType.MoonLight);
  5996. RemoveBuff(BuffType.DarkBody);
  5997. }
  5998. //EnergyShield
  5999. if (Stats[Stat.EnergyShieldPercent] > 0)
  6000. {
  6001. if (Envir.Random.Next(100) < Stats[Stat.EnergyShieldPercent])
  6002. {
  6003. if (HP + (Stats[Stat.EnergyShieldHPGain]) >= Stats[Stat.HP])
  6004. SetHP(Stats[Stat.HP]);
  6005. else
  6006. ChangeHP(Stats[Stat.EnergyShieldHPGain]);
  6007. }
  6008. }
  6009. if (Envir.Random.Next(100) < (attacker.Stats[Stat.CriticalRate] * Settings.CriticalRateWeight))
  6010. {
  6011. CurrentMap.Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.Critical }, CurrentLocation);
  6012. damage = Math.Min(int.MaxValue, damage + (int)Math.Floor(damage * (((double)attacker.Stats[Stat.CriticalDamage] / (double)Settings.CriticalDamageWeight) * 10)));
  6013. BroadcastDamageIndicator(DamageType.Critical);
  6014. }
  6015. if (HasBuff(BuffType.MagicShield, out Buff magicShield))
  6016. {
  6017. var duration = (int)Math.Min(int.MaxValue, magicShield.ExpireTime - ((damage - armour) * 60));
  6018. AddBuff(BuffType.MagicShield, this, duration, null);
  6019. }
  6020. if (HasBuff(BuffType.ElementalBarrier, out Buff elementalBarrier))
  6021. {
  6022. var duration = (int)Math.Min(int.MaxValue, elementalBarrier.ExpireTime - ((damage - armour) * 60));
  6023. AddBuff(BuffType.ElementalBarrier, this, duration, null);
  6024. }
  6025. if (attacker.Stats[Stat.HPDrainRatePercent] > 0 && damageWeapon)
  6026. {
  6027. attacker.HpDrain += Math.Max(0, ((float)(damage - armour) / 100) * attacker.Stats[Stat.HPDrainRatePercent]);
  6028. if (attacker.HpDrain > 2)
  6029. {
  6030. int HpGain = (int)Math.Floor(attacker.HpDrain);
  6031. attacker.ChangeHP(HpGain);
  6032. attacker.HpDrain -= HpGain;
  6033. }
  6034. }
  6035. for (int i = PoisonList.Count - 1; i >= 0; i--)
  6036. {
  6037. if (PoisonList[i].PType != PoisonType.LRParalysis) continue;
  6038. PoisonList.RemoveAt(i);
  6039. OperateTime = 0;
  6040. }
  6041. LastHitter = attacker;
  6042. LastHitTime = Envir.Time + 10000;
  6043. RegenTime = Envir.Time + RegenDelay;
  6044. LogTime = Envir.Time + Globals.LogDelay;
  6045. if (Envir.Time > BrownTime && PKPoints < 200 && !AtWar(attacker))
  6046. attacker.BrownTime = Envir.Time + Settings.Minute;
  6047. ushort LevelOffset = (byte)(Level > attacker.Level ? 0 : Math.Min(10, attacker.Level - Level));
  6048. ApplyNegativeEffects(attacker, type, LevelOffset);
  6049. attacker.GatherElement();
  6050. DamageDura();
  6051. ActiveBlizzard = false;
  6052. ActiveReincarnation = false;
  6053. CounterAttackCast(GetMagic(Spell.CounterAttack), LastHitter);
  6054. Enqueue(new S.Struck { AttackerID = attacker.ObjectID });
  6055. Broadcast(new S.ObjectStruck { ObjectID = ObjectID, AttackerID = attacker.ObjectID, Direction = Direction, Location = CurrentLocation });
  6056. BroadcastDamageIndicator(DamageType.Hit, armour - damage);
  6057. ChangeHP(armour - damage);
  6058. return damage - armour;
  6059. }
  6060. public override int Attacked(MonsterObject attacker, int damage, DefenceType type = DefenceType.ACAgility)
  6061. {
  6062. var armour = GetArmour(type, attacker, out bool hit);
  6063. if (!hit)
  6064. {
  6065. return 0;
  6066. }
  6067. if (Envir.Random.Next(100) < Stats[Stat.Reflect])
  6068. {
  6069. if (attacker.IsAttackTarget(this))
  6070. {
  6071. attacker.Attacked(this, damage, type, false);
  6072. CurrentMap.Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.Reflect }, CurrentLocation);
  6073. }
  6074. return 0;
  6075. }
  6076. armour = (int)Math.Max(int.MinValue, (Math.Min(int.MaxValue, (decimal)(armour * ArmourRate))));
  6077. damage = (int)Math.Max(int.MinValue, (Math.Min(int.MaxValue, (decimal)(damage * DamageRate))));
  6078. //MagicShield, ElementalBarrier
  6079. if (Stats[Stat.DamageReductionPercent] != 0)
  6080. {
  6081. damage -= (damage * Stats[Stat.DamageReductionPercent]) / 100;
  6082. }
  6083. if (armour >= damage)
  6084. {
  6085. BroadcastDamageIndicator(DamageType.Miss);
  6086. return 0;
  6087. }
  6088. if (Hidden)
  6089. {
  6090. RemoveBuff(BuffType.MoonLight);
  6091. RemoveBuff(BuffType.DarkBody);
  6092. }
  6093. if (Stats[Stat.EnergyShieldPercent] > 0)
  6094. {
  6095. if (Envir.Random.Next(100) < Stats[Stat.EnergyShieldPercent])
  6096. {
  6097. if (HP + (Stats[Stat.EnergyShieldHPGain]) >= Stats[Stat.HP])
  6098. SetHP(Stats[Stat.HP]);
  6099. else
  6100. ChangeHP(Stats[Stat.EnergyShieldHPGain]);
  6101. }
  6102. }
  6103. if (HasBuff(BuffType.MagicShield, out Buff magicShield))
  6104. {
  6105. var duration = (int)Math.Min(int.MaxValue, magicShield.ExpireTime - ((damage - armour) * 60));
  6106. AddBuff(BuffType.MagicShield, this, duration, null);
  6107. }
  6108. if (HasBuff(BuffType.ElementalBarrier, out Buff elementalBarrier))
  6109. {
  6110. var duration = (int)Math.Min(int.MaxValue, elementalBarrier.ExpireTime - ((damage - armour) * 60));
  6111. AddBuff(BuffType.ElementalBarrier, this, duration, null);
  6112. }
  6113. for (int i = PoisonList.Count - 1; i >= 0; i--)
  6114. {
  6115. if (PoisonList[i].PType != PoisonType.LRParalysis) continue;
  6116. PoisonList.RemoveAt(i);
  6117. OperateTime = 0;
  6118. }
  6119. LastHitter = attacker.Master ?? attacker;
  6120. LastHitTime = Envir.Time + 10000;
  6121. RegenTime = Envir.Time + RegenDelay;
  6122. LogTime = Envir.Time + Globals.LogDelay;
  6123. DamageDura();
  6124. ActiveBlizzard = false;
  6125. ActiveReincarnation = false;
  6126. CounterAttackCast(GetMagic(Spell.CounterAttack), LastHitter);
  6127. if (StruckTime < Envir.Time)
  6128. {
  6129. Enqueue(new S.Struck { AttackerID = attacker.ObjectID });
  6130. Broadcast(new S.ObjectStruck { ObjectID = ObjectID, AttackerID = attacker.ObjectID, Direction = Direction, Location = CurrentLocation });
  6131. StruckTime = Envir.Time + 500;
  6132. }
  6133. BroadcastDamageIndicator(DamageType.Hit, armour - damage);
  6134. ChangeHP(armour - damage);
  6135. return damage - armour;
  6136. }
  6137. public override int Struck(int damage, DefenceType type = DefenceType.ACAgility)
  6138. {
  6139. int armour = 0;
  6140. if (Hidden)
  6141. {
  6142. RemoveBuff(BuffType.MoonLight);
  6143. RemoveBuff(BuffType.DarkBody);
  6144. }
  6145. switch (type)
  6146. {
  6147. case DefenceType.ACAgility:
  6148. armour = GetAttackPower(Stats[Stat.MinAC], Stats[Stat.MaxAC]);
  6149. break;
  6150. case DefenceType.AC:
  6151. armour = GetAttackPower(Stats[Stat.MinAC], Stats[Stat.MaxAC]);
  6152. break;
  6153. case DefenceType.MACAgility:
  6154. armour = GetAttackPower(Stats[Stat.MinMAC], Stats[Stat.MaxMAC]);
  6155. break;
  6156. case DefenceType.MAC:
  6157. armour = GetAttackPower(Stats[Stat.MinMAC], Stats[Stat.MaxMAC]);
  6158. break;
  6159. case DefenceType.Agility:
  6160. break;
  6161. }
  6162. armour = (int)Math.Max(int.MinValue, (Math.Min(int.MaxValue, (decimal)(armour * ArmourRate))));
  6163. damage = (int)Math.Max(int.MinValue, (Math.Min(int.MaxValue, (decimal)(damage * DamageRate))));
  6164. //MagicShield, ElementalBarrier
  6165. if (Stats[Stat.DamageReductionPercent] != 0)
  6166. {
  6167. damage -= (damage * Stats[Stat.DamageReductionPercent]) / 100;
  6168. }
  6169. if (armour >= damage) return 0;
  6170. if (HasBuff(BuffType.MagicShield, out Buff magicShield))
  6171. {
  6172. var duration = (int)Math.Min(int.MaxValue, magicShield.ExpireTime - ((damage - armour) * 60));
  6173. AddBuff(BuffType.MagicShield, this, duration, null);
  6174. }
  6175. if (HasBuff(BuffType.ElementalBarrier, out Buff elementalBarrier))
  6176. {
  6177. var duration = (int)Math.Min(int.MaxValue, elementalBarrier.ExpireTime - ((damage - armour) * 60));
  6178. AddBuff(BuffType.ElementalBarrier, this, duration, null);
  6179. }
  6180. RegenTime = Envir.Time + RegenDelay;
  6181. LogTime = Envir.Time + Globals.LogDelay;
  6182. DamageDura();
  6183. ActiveBlizzard = false;
  6184. ActiveReincarnation = false;
  6185. Enqueue(new S.Struck { AttackerID = 0 });
  6186. Broadcast(new S.ObjectStruck { ObjectID = ObjectID, AttackerID = 0, Direction = Direction, Location = CurrentLocation });
  6187. ChangeHP(armour - damage);
  6188. return damage - armour;
  6189. }
  6190. public override void ApplyPoison(Poison p, MapObject Caster = null, bool NoResist = false, bool ignoreDefence = true)
  6191. {
  6192. if (Caster != null && !NoResist)
  6193. {
  6194. if (((Caster.Race != ObjectType.Player) || Settings.PvpCanResistPoison) && (Envir.Random.Next(Settings.PoisonResistWeight) < Stats[Stat.PoisonResist]))
  6195. {
  6196. return;
  6197. }
  6198. }
  6199. if (!ignoreDefence && (p.PType == PoisonType.Green))
  6200. {
  6201. int armour = GetAttackPower(Stats[Stat.MinMAC], Stats[Stat.MaxMAC]);
  6202. if (p.Value < armour)
  6203. p.PType = PoisonType.None;
  6204. else
  6205. p.Value -= armour;
  6206. }
  6207. if (p.Owner != null && p.Owner is PlayerObject player && Envir.Time > BrownTime && PKPoints < 200)
  6208. {
  6209. bool ownerBrowns = true;
  6210. if (player.MyGuild != null && MyGuild != null && MyGuild.IsAtWar() && MyGuild.IsEnemy(player.MyGuild))
  6211. ownerBrowns = false;
  6212. if (ownerBrowns && !player.WarZone)
  6213. p.Owner.BrownTime = Envir.Time + Settings.Minute;
  6214. }
  6215. if ((p.PType == PoisonType.Green) || (p.PType == PoisonType.Red)) p.Duration = Math.Max(0, p.Duration - Stats[Stat.PoisonRecovery]);
  6216. if (p.Duration == 0) return;
  6217. if (p.PType == PoisonType.None) return;
  6218. for (int i = 0; i < PoisonList.Count; i++)
  6219. {
  6220. if (PoisonList[i].PType != p.PType) continue;
  6221. if ((PoisonList[i].PType == PoisonType.Green) && (PoisonList[i].Value > p.Value)) return;//cant cast weak poison to cancel out strong poison
  6222. 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!
  6223. 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
  6224. if (p.PType == PoisonType.DelayedExplosion) return;
  6225. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.BeenPoisoned), ChatType.System2);
  6226. PoisonList[i] = p;
  6227. return;
  6228. }
  6229. switch (p.PType)
  6230. {
  6231. case PoisonType.DelayedExplosion:
  6232. {
  6233. ExplosionInflictedTime = Envir.Time + 4000;
  6234. Enqueue(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.DelayedExplosion });
  6235. Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.DelayedExplosion });
  6236. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouAreWalkingExplosive), ChatType.System);
  6237. }
  6238. break;
  6239. case PoisonType.Dazed:
  6240. {
  6241. Enqueue(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.Stunned, Time = (uint)(p.Duration * p.TickSpeed) });
  6242. Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.Stunned, Time = (uint)(p.Duration * p.TickSpeed) });
  6243. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.BeenPoisoned), ChatType.System2);
  6244. }
  6245. break;
  6246. case PoisonType.Blindness:
  6247. {
  6248. AddBuff(BuffType.Blindness, Caster, (int)(p.Duration * p.TickSpeed), new Stats { [Stat.Accuracy] = p.Value * -1 });
  6249. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.BeenPoisoned), ChatType.System2);
  6250. }
  6251. break;
  6252. default:
  6253. {
  6254. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.BeenPoisoned), ChatType.System2);
  6255. }
  6256. break;
  6257. }
  6258. PoisonList.Add(p);
  6259. }
  6260. public override Buff AddBuff(BuffType type, MapObject owner, int duration, Stats stats, bool refreshStats = true, bool updateOnly = false, params int[] values)
  6261. {
  6262. Buff b = base.AddBuff(type, owner, duration, stats, refreshStats, updateOnly, values);
  6263. switch (b.Type)
  6264. {
  6265. case BuffType.MagicShield:
  6266. CurrentMap.Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.MagicShieldUp }, CurrentLocation);
  6267. break;
  6268. case BuffType.ElementalBarrier:
  6269. CurrentMap.Broadcast(new S.ObjectEffect { ObjectID = ObjectID, Effect = SpellEffect.ElementalBarrierUp }, CurrentLocation);
  6270. break;
  6271. }
  6272. var packet = new S.AddBuff { Buff = b.ToClientBuff() };
  6273. Enqueue(packet);
  6274. if (b.Info.Visible)
  6275. {
  6276. Broadcast(packet);
  6277. }
  6278. if (refreshStats)
  6279. {
  6280. RefreshStats();
  6281. }
  6282. return b;
  6283. }
  6284. public override void PauseBuff(Buff b)
  6285. {
  6286. if (b.Paused) return;
  6287. base.PauseBuff(b);
  6288. Enqueue(new S.PauseBuff { Type = b.Type, ObjectID = ObjectID, Paused = true });
  6289. }
  6290. public override void UnpauseBuff(Buff b)
  6291. {
  6292. if (!b.Paused) return;
  6293. base.UnpauseBuff(b);
  6294. Enqueue(new S.PauseBuff { Type = b.Type, ObjectID = ObjectID, Paused = false });
  6295. }
  6296. protected int GetCurrentStatCount(UserItem gem, UserItem item)
  6297. {
  6298. if (gem.GetTotal(Stat.MaxDC) > 0)
  6299. return item.AddedStats[Stat.MaxDC];
  6300. else if (gem.GetTotal(Stat.MaxMC) > 0)
  6301. return item.AddedStats[Stat.MaxMC];
  6302. else if (gem.GetTotal(Stat.MaxSC) > 0)
  6303. return item.AddedStats[Stat.MaxSC];
  6304. else if (gem.GetTotal(Stat.MaxAC) > 0)
  6305. return item.AddedStats[Stat.MaxAC];
  6306. else if (gem.GetTotal(Stat.MaxMAC) > 0)
  6307. return item.AddedStats[Stat.MaxMAC];
  6308. else if ((gem.Info.Durability) > 0)
  6309. return item.Info.Durability > item.MaxDura ? 0 : ((item.MaxDura - item.Info.Durability) / 1000);
  6310. else if (gem.GetTotal(Stat.AttackSpeed) > 0)
  6311. return item.AddedStats[Stat.AttackSpeed];
  6312. else if (gem.GetTotal(Stat.Agility) > 0)
  6313. return item.AddedStats[Stat.Agility];
  6314. else if (gem.GetTotal(Stat.Accuracy) > 0)
  6315. return item.AddedStats[Stat.Accuracy];
  6316. else if (gem.GetTotal(Stat.PoisonAttack) > 0)
  6317. return item.AddedStats[Stat.PoisonAttack];
  6318. else if (gem.GetTotal(Stat.Freezing) > 0)
  6319. return item.AddedStats[Stat.Freezing];
  6320. else if (gem.GetTotal(Stat.MagicResist) > 0)
  6321. return item.AddedStats[Stat.MagicResist];
  6322. else if (gem.GetTotal(Stat.PoisonResist) > 0)
  6323. return item.AddedStats[Stat.PoisonResist];
  6324. else if (gem.GetTotal(Stat.Luck) > 0)
  6325. return item.AddedStats[Stat.Luck];
  6326. else if (gem.GetTotal(Stat.PoisonRecovery) > 0)
  6327. return item.AddedStats[Stat.PoisonRecovery];
  6328. else if (gem.GetTotal(Stat.HP) > 0)
  6329. return item.AddedStats[Stat.HP];
  6330. else if (gem.GetTotal(Stat.MP) > 0)
  6331. return item.AddedStats[Stat.MP];
  6332. else if (gem.GetTotal(Stat.HealthRecovery) > 0)
  6333. return item.AddedStats[Stat.HealthRecovery];
  6334. // Definitions are missing for these.
  6335. /*
  6336. else if ((gem.Info.HPrate) > 0)
  6337. return item.h
  6338. else if ((gem.Info.MPrate) > 0)
  6339. return
  6340. else if ((gem.Info.SpellRecovery) > 0)
  6341. return
  6342. else if ((gem.Info.Holy) > 0)
  6343. return
  6344. else if ((gem.Info.Strong + gem.Strong) > 0)
  6345. return
  6346. else if (gem.Info.HPrate > 0)
  6347. return
  6348. */
  6349. return 0;
  6350. }
  6351. public bool CanGainItem(UserItem item)
  6352. {
  6353. if (FreeSpace(Info.Inventory) > 0)
  6354. {
  6355. return true;
  6356. }
  6357. if (item.Info.Type == ItemType.Amulet)
  6358. {
  6359. ushort count = item.Count;
  6360. for (int i = 0; i < Info.Inventory.Length; i++)
  6361. {
  6362. UserItem bagItem = Info.Inventory[i];
  6363. if (bagItem == null || bagItem.Info != item.Info) continue;
  6364. if (bagItem.Count + count <= bagItem.Info.StackSize) return true;
  6365. count -= (ushort)(bagItem.Info.StackSize - bagItem.Count);
  6366. }
  6367. return false;
  6368. }
  6369. if (item.Info.StackSize > 1)
  6370. {
  6371. ushort count = item.Count;
  6372. for (int i = 0; i < Info.Inventory.Length; i++)
  6373. {
  6374. UserItem bagItem = Info.Inventory[i];
  6375. if (bagItem.Info != item.Info) continue;
  6376. if (bagItem.Count + count <= bagItem.Info.StackSize) return true;
  6377. count -= (ushort)(bagItem.Info.StackSize - bagItem.Count);
  6378. }
  6379. }
  6380. return false;
  6381. }
  6382. public bool CanGainItems(UserItem[] items)
  6383. {
  6384. int itemCount = items.Count(e => e != null);
  6385. ushort stackOffset = 0;
  6386. if (itemCount < 1) return true;
  6387. for (int i = 0; i < items.Length; i++)
  6388. {
  6389. if (items[i] == null) continue;
  6390. if (items[i].Info.StackSize > 1)
  6391. {
  6392. ushort count = items[i].Count;
  6393. for (int u = 0; u < Info.Inventory.Length; u++)
  6394. {
  6395. UserItem bagItem = Info.Inventory[u];
  6396. if (bagItem == null || bagItem.Info != items[i].Info) continue;
  6397. if (bagItem.Count + count > bagItem.Info.StackSize) stackOffset++;
  6398. break;
  6399. }
  6400. }
  6401. }
  6402. if (FreeSpace(Info.Inventory) < itemCount + stackOffset) return false;
  6403. return true;
  6404. }
  6405. public bool CanEquipItem(UserItem item, int slot)
  6406. {
  6407. switch ((EquipmentSlot)slot)
  6408. {
  6409. case EquipmentSlot.Weapon:
  6410. if (item.Info.Type != ItemType.Weapon)
  6411. return false;
  6412. break;
  6413. case EquipmentSlot.Armour:
  6414. if (item.Info.Type != ItemType.Armour)
  6415. return false;
  6416. break;
  6417. case EquipmentSlot.Helmet:
  6418. if (item.Info.Type != ItemType.Helmet)
  6419. return false;
  6420. break;
  6421. case EquipmentSlot.Torch:
  6422. if (item.Info.Type != ItemType.Torch)
  6423. return false;
  6424. break;
  6425. case EquipmentSlot.Necklace:
  6426. if (item.Info.Type != ItemType.Necklace)
  6427. return false;
  6428. break;
  6429. case EquipmentSlot.BraceletL:
  6430. if (item.Info.Type != ItemType.Bracelet)
  6431. return false;
  6432. break;
  6433. case EquipmentSlot.BraceletR:
  6434. if (item.Info.Type != ItemType.Bracelet && item.Info.Type != ItemType.Amulet)
  6435. return false;
  6436. break;
  6437. case EquipmentSlot.RingL:
  6438. case EquipmentSlot.RingR:
  6439. if (item.Info.Type != ItemType.Ring)
  6440. return false;
  6441. break;
  6442. case EquipmentSlot.Amulet:
  6443. if (item.Info.Type != ItemType.Amulet)// || item.Info.Shape == 0
  6444. return false;
  6445. break;
  6446. case EquipmentSlot.Boots:
  6447. if (item.Info.Type != ItemType.Boots)
  6448. return false;
  6449. break;
  6450. case EquipmentSlot.Belt:
  6451. if (item.Info.Type != ItemType.Belt)
  6452. return false;
  6453. break;
  6454. case EquipmentSlot.Stone:
  6455. if (item.Info.Type != ItemType.Stone)
  6456. return false;
  6457. break;
  6458. case EquipmentSlot.Mount:
  6459. if (item.Info.Type != ItemType.Mount)
  6460. return false;
  6461. break;
  6462. default:
  6463. return false;
  6464. }
  6465. switch (Gender)
  6466. {
  6467. case MirGender.Male:
  6468. if (!item.Info.RequiredGender.HasFlag(RequiredGender.Male))
  6469. return false;
  6470. break;
  6471. case MirGender.Female:
  6472. if (!item.Info.RequiredGender.HasFlag(RequiredGender.Female))
  6473. return false;
  6474. break;
  6475. }
  6476. switch (Class)
  6477. {
  6478. case MirClass.Warrior:
  6479. if (!item.Info.RequiredClass.HasFlag(RequiredClass.Warrior))
  6480. return false;
  6481. break;
  6482. case MirClass.Wizard:
  6483. if (!item.Info.RequiredClass.HasFlag(RequiredClass.Wizard))
  6484. return false;
  6485. break;
  6486. case MirClass.Taoist:
  6487. if (!item.Info.RequiredClass.HasFlag(RequiredClass.Taoist))
  6488. return false;
  6489. break;
  6490. case MirClass.Assassin:
  6491. if (!item.Info.RequiredClass.HasFlag(RequiredClass.Assassin))
  6492. return false;
  6493. break;
  6494. }
  6495. switch (item.Info.RequiredType)
  6496. {
  6497. case RequiredType.Level:
  6498. if (Level < item.Info.RequiredAmount)
  6499. return false;
  6500. break;
  6501. case RequiredType.MaxAC:
  6502. if (Stats[Stat.MaxAC] < item.Info.RequiredAmount)
  6503. return false;
  6504. break;
  6505. case RequiredType.MaxMAC:
  6506. if (Stats[Stat.MaxMAC] < item.Info.RequiredAmount)
  6507. return false;
  6508. break;
  6509. case RequiredType.MaxDC:
  6510. if (Stats[Stat.MaxDC] < item.Info.RequiredAmount)
  6511. return false;
  6512. break;
  6513. case RequiredType.MaxMC:
  6514. if (Stats[Stat.MaxMC] < item.Info.RequiredAmount)
  6515. return false;
  6516. break;
  6517. case RequiredType.MaxSC:
  6518. if (Stats[Stat.MaxSC] < item.Info.RequiredAmount)
  6519. return false;
  6520. break;
  6521. case RequiredType.MaxLevel:
  6522. if (Level > item.Info.RequiredAmount)
  6523. return false;
  6524. break;
  6525. case RequiredType.MinAC:
  6526. if (Stats[Stat.MinAC] < item.Info.RequiredAmount)
  6527. return false;
  6528. break;
  6529. case RequiredType.MinMAC:
  6530. if (Stats[Stat.MinMAC] < item.Info.RequiredAmount)
  6531. return false;
  6532. break;
  6533. case RequiredType.MinDC:
  6534. if (Stats[Stat.MinDC] < item.Info.RequiredAmount)
  6535. return false;
  6536. break;
  6537. case RequiredType.MinMC:
  6538. if (Stats[Stat.MinMC] < item.Info.RequiredAmount)
  6539. return false;
  6540. break;
  6541. case RequiredType.MinSC:
  6542. if (Stats[Stat.MinSC] < item.Info.RequiredAmount)
  6543. return false;
  6544. break;
  6545. }
  6546. if (item.Info.Type == ItemType.Weapon || item.Info.Type == ItemType.Torch)
  6547. {
  6548. if (item.Weight - (Info.Equipment[slot] != null ? Info.Equipment[slot].Weight : 0) + CurrentHandWeight > Stats[Stat.HandWeight])
  6549. return false;
  6550. }
  6551. else
  6552. if (item.Weight - (Info.Equipment[slot] != null ? Info.Equipment[slot].Weight : 0) + CurrentWearWeight > Stats[Stat.WearWeight])
  6553. return false;
  6554. if (RidingMount && item.Info.Type != ItemType.Torch)
  6555. {
  6556. return false;
  6557. }
  6558. return true;
  6559. }
  6560. public void GainItem(UserItem item)
  6561. {
  6562. //CheckItemInfo(item.Info);
  6563. CheckItem(item);
  6564. UserItem clonedItem = item.Clone();
  6565. Enqueue(new S.GainedItem { Item = clonedItem }); //Cloned because we are probably going to change the amount.
  6566. AddItem(item);
  6567. RefreshBagWeight();
  6568. }
  6569. private void DamageDura()
  6570. {
  6571. if (!SpecialMode.HasFlag(SpecialItemMode.NoDuraLoss))
  6572. for (int i = 0; i < Info.Equipment.Length; i++)
  6573. if (i != (int)EquipmentSlot.Weapon)
  6574. DamageItem(Info.Equipment[i], Envir.Random.Next(1) + 1);
  6575. }
  6576. public void DamageWeapon()
  6577. {
  6578. if (!SpecialMode.HasFlag(SpecialItemMode.NoDuraLoss))
  6579. DamageItem(Info.Equipment[(int)EquipmentSlot.Weapon], Envir.Random.Next(4) + 1);
  6580. }
  6581. public void DamageItem(UserItem item, int amount, bool isChanged = false)
  6582. {
  6583. if (item == null || item.CurrentDura == 0 || item.Info.Type == ItemType.Amulet) return;
  6584. if ((item.WeddingRing == Info.Married) && (Info.Equipment[(int)EquipmentSlot.RingL].UniqueID == item.UniqueID)) return;
  6585. if (item.GetTotal(Stat.Strong) > 0) amount = Math.Max(1, amount - item.GetTotal(Stat.Strong));
  6586. item.CurrentDura = (ushort)Math.Max(ushort.MinValue, item.CurrentDura - amount);
  6587. item.DuraChanged = true;
  6588. if (item.CurrentDura > 0 && isChanged != true) return;
  6589. Enqueue(new S.DuraChanged { UniqueID = item.UniqueID, CurrentDura = item.CurrentDura });
  6590. item.DuraChanged = false;
  6591. RefreshStats();
  6592. }
  6593. public void RemoveObjects(MirDirection dir, int count)
  6594. {
  6595. switch (dir)
  6596. {
  6597. case MirDirection.Up:
  6598. //Bottom Block
  6599. for (int a = 0; a < count; a++)
  6600. {
  6601. int y = CurrentLocation.Y + Globals.DataRange - a;
  6602. if (y < 0 || y >= CurrentMap.Height) continue;
  6603. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  6604. {
  6605. int x = CurrentLocation.X + b;
  6606. if (x < 0 || x >= CurrentMap.Width) continue;
  6607. Cell cell = CurrentMap.GetCell(x, y);
  6608. if (!cell.Valid || cell.Objects == null) continue;
  6609. for (int i = 0; i < cell.Objects.Count; i++)
  6610. {
  6611. MapObject ob = cell.Objects[i];
  6612. ob.Remove(this);
  6613. }
  6614. }
  6615. }
  6616. break;
  6617. case MirDirection.UpRight:
  6618. //Bottom Block
  6619. for (int a = 0; a < count; a++)
  6620. {
  6621. int y = CurrentLocation.Y + Globals.DataRange - a;
  6622. if (y < 0 || y >= CurrentMap.Height) continue;
  6623. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  6624. {
  6625. int x = CurrentLocation.X + b;
  6626. if (x < 0 || x >= CurrentMap.Width) continue;
  6627. Cell cell = CurrentMap.GetCell(x, y);
  6628. if (!cell.Valid || cell.Objects == null) continue;
  6629. for (int i = 0; i < cell.Objects.Count; i++)
  6630. {
  6631. MapObject ob = cell.Objects[i];
  6632. ob.Remove(this);
  6633. }
  6634. }
  6635. }
  6636. //Left Block
  6637. for (int a = -Globals.DataRange; a <= Globals.DataRange - count; a++)
  6638. {
  6639. int y = CurrentLocation.Y + a;
  6640. if (y < 0 || y >= CurrentMap.Height) continue;
  6641. for (int b = 0; b < count; b++)
  6642. {
  6643. int x = CurrentLocation.X - Globals.DataRange + b;
  6644. if (x < 0 || x >= CurrentMap.Width) continue;
  6645. Cell cell = CurrentMap.GetCell(x, y);
  6646. if (!cell.Valid || cell.Objects == null) continue;
  6647. for (int i = 0; i < cell.Objects.Count; i++)
  6648. {
  6649. MapObject ob = cell.Objects[i];
  6650. ob.Remove(this);
  6651. }
  6652. }
  6653. }
  6654. break;
  6655. case MirDirection.Right:
  6656. //Left Block
  6657. for (int a = -Globals.DataRange; a <= Globals.DataRange; a++)
  6658. {
  6659. int y = CurrentLocation.Y + a;
  6660. if (y < 0 || y >= CurrentMap.Height) continue;
  6661. for (int b = 0; b < count; b++)
  6662. {
  6663. int x = CurrentLocation.X - Globals.DataRange + b;
  6664. if (x < 0 || x >= CurrentMap.Width) continue;
  6665. Cell cell = CurrentMap.GetCell(x, y);
  6666. if (!cell.Valid || cell.Objects == null) continue;
  6667. for (int i = 0; i < cell.Objects.Count; i++)
  6668. {
  6669. MapObject ob = cell.Objects[i];
  6670. ob.Remove(this);
  6671. }
  6672. }
  6673. }
  6674. break;
  6675. case MirDirection.DownRight:
  6676. //Top Block
  6677. for (int a = 0; a < count; a++)
  6678. {
  6679. int y = CurrentLocation.Y - Globals.DataRange + a;
  6680. if (y < 0 || y >= CurrentMap.Height) continue;
  6681. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  6682. {
  6683. int x = CurrentLocation.X + b;
  6684. if (x < 0 || x >= CurrentMap.Width) continue;
  6685. Cell cell = CurrentMap.GetCell(x, y);
  6686. if (!cell.Valid || cell.Objects == null) continue;
  6687. for (int i = 0; i < cell.Objects.Count; i++)
  6688. {
  6689. MapObject ob = cell.Objects[i];
  6690. ob.Remove(this);
  6691. }
  6692. }
  6693. }
  6694. //Left Block
  6695. for (int a = -Globals.DataRange + count; a <= Globals.DataRange; a++)
  6696. {
  6697. int y = CurrentLocation.Y + a;
  6698. if (y < 0 || y >= CurrentMap.Height) continue;
  6699. for (int b = 0; b < count; b++)
  6700. {
  6701. int x = CurrentLocation.X - Globals.DataRange + b;
  6702. if (x < 0 || x >= CurrentMap.Width) continue;
  6703. Cell cell = CurrentMap.GetCell(x, y);
  6704. if (!cell.Valid || cell.Objects == null) continue;
  6705. for (int i = 0; i < cell.Objects.Count; i++)
  6706. {
  6707. MapObject ob = cell.Objects[i];
  6708. ob.Remove(this);
  6709. }
  6710. }
  6711. }
  6712. break;
  6713. case MirDirection.Down:
  6714. for (int a = 0; a < count; a++)
  6715. {
  6716. int y = CurrentLocation.Y - Globals.DataRange + a;
  6717. if (y < 0 || y >= CurrentMap.Height) continue;
  6718. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  6719. {
  6720. int x = CurrentLocation.X + b;
  6721. if (x < 0 || x >= CurrentMap.Width) continue;
  6722. Cell cell = CurrentMap.GetCell(x, y);
  6723. if (!cell.Valid || cell.Objects == null) continue;
  6724. for (int i = 0; i < cell.Objects.Count; i++)
  6725. {
  6726. MapObject ob = cell.Objects[i];
  6727. ob.Remove(this);
  6728. }
  6729. }
  6730. }
  6731. break;
  6732. case MirDirection.DownLeft:
  6733. //Top Block
  6734. for (int a = 0; a < count; a++)
  6735. {
  6736. int y = CurrentLocation.Y - Globals.DataRange + a;
  6737. if (y < 0 || y >= CurrentMap.Height) continue;
  6738. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  6739. {
  6740. int x = CurrentLocation.X + b;
  6741. if (x < 0 || x >= CurrentMap.Width) continue;
  6742. Cell cell = CurrentMap.GetCell(x, y);
  6743. if (!cell.Valid || cell.Objects == null) continue;
  6744. for (int i = 0; i < cell.Objects.Count; i++)
  6745. {
  6746. MapObject ob = cell.Objects[i];
  6747. ob.Remove(this);
  6748. }
  6749. }
  6750. }
  6751. //Right Block
  6752. for (int a = -Globals.DataRange + count; a <= Globals.DataRange; a++)
  6753. {
  6754. int y = CurrentLocation.Y + a;
  6755. if (y < 0 || y >= CurrentMap.Height) continue;
  6756. for (int b = 0; b < count; b++)
  6757. {
  6758. int x = CurrentLocation.X + Globals.DataRange - b;
  6759. if (x < 0 || x >= CurrentMap.Width) continue;
  6760. Cell cell = CurrentMap.GetCell(x, y);
  6761. if (!cell.Valid || cell.Objects == null) continue;
  6762. for (int i = 0; i < cell.Objects.Count; i++)
  6763. {
  6764. MapObject ob = cell.Objects[i];
  6765. ob.Remove(this);
  6766. }
  6767. }
  6768. }
  6769. break;
  6770. case MirDirection.Left:
  6771. for (int a = -Globals.DataRange; a <= Globals.DataRange; a++)
  6772. {
  6773. int y = CurrentLocation.Y + a;
  6774. if (y < 0 || y >= CurrentMap.Height) continue;
  6775. for (int b = 0; b < count; b++)
  6776. {
  6777. int x = CurrentLocation.X + Globals.DataRange - b;
  6778. if (x < 0 || x >= CurrentMap.Width) continue;
  6779. Cell cell = CurrentMap.GetCell(x, y);
  6780. if (!cell.Valid || cell.Objects == null) continue;
  6781. for (int i = 0; i < cell.Objects.Count; i++)
  6782. {
  6783. MapObject ob = cell.Objects[i];
  6784. ob.Remove(this);
  6785. }
  6786. }
  6787. }
  6788. break;
  6789. case MirDirection.UpLeft:
  6790. //Bottom Block
  6791. for (int a = 0; a < count; a++)
  6792. {
  6793. int y = CurrentLocation.Y + Globals.DataRange - a;
  6794. if (y < 0 || y >= CurrentMap.Height) continue;
  6795. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  6796. {
  6797. int x = CurrentLocation.X + b;
  6798. if (x < 0 || x >= CurrentMap.Width) continue;
  6799. Cell cell = CurrentMap.GetCell(x, y);
  6800. if (!cell.Valid || cell.Objects == null) continue;
  6801. for (int i = 0; i < cell.Objects.Count; i++)
  6802. {
  6803. MapObject ob = cell.Objects[i];
  6804. ob.Remove(this);
  6805. }
  6806. }
  6807. }
  6808. //Right Block
  6809. for (int a = -Globals.DataRange; a <= Globals.DataRange - count; a++)
  6810. {
  6811. int y = CurrentLocation.Y + a;
  6812. if (y < 0 || y >= CurrentMap.Height) continue;
  6813. for (int b = 0; b < count; b++)
  6814. {
  6815. int x = CurrentLocation.X + Globals.DataRange - b;
  6816. if (x < 0 || x >= CurrentMap.Width) continue;
  6817. Cell cell = CurrentMap.GetCell(x, y);
  6818. if (!cell.Valid || cell.Objects == null) continue;
  6819. for (int i = 0; i < cell.Objects.Count; i++)
  6820. {
  6821. MapObject ob = cell.Objects[i];
  6822. ob.Remove(this);
  6823. }
  6824. }
  6825. }
  6826. break;
  6827. }
  6828. }
  6829. public void AddObjects(MirDirection dir, int count)
  6830. {
  6831. switch (dir)
  6832. {
  6833. case MirDirection.Up:
  6834. for (int a = 0; a < count; a++)
  6835. {
  6836. int y = CurrentLocation.Y - Globals.DataRange + a;
  6837. if (y < 0 || y >= CurrentMap.Height) continue;
  6838. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  6839. {
  6840. int x = CurrentLocation.X + b;
  6841. if (x < 0 || x >= CurrentMap.Width) continue;
  6842. Cell cell = CurrentMap.GetCell(x, y);
  6843. if (!cell.Valid || cell.Objects == null) continue;
  6844. for (int i = 0; i < cell.Objects.Count; i++)
  6845. {
  6846. MapObject ob = cell.Objects[i];
  6847. ob.Add(this);
  6848. }
  6849. }
  6850. }
  6851. break;
  6852. case MirDirection.UpRight:
  6853. //Top Block
  6854. for (int a = 0; a < count; a++)
  6855. {
  6856. int y = CurrentLocation.Y - Globals.DataRange + a;
  6857. if (y < 0 || y >= CurrentMap.Height) continue;
  6858. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  6859. {
  6860. int x = CurrentLocation.X + b;
  6861. if (x < 0 || x >= CurrentMap.Width) continue;
  6862. Cell cell = CurrentMap.GetCell(x, y);
  6863. if (!cell.Valid || cell.Objects == null) continue;
  6864. for (int i = 0; i < cell.Objects.Count; i++)
  6865. {
  6866. MapObject ob = cell.Objects[i];
  6867. ob.Add(this);
  6868. }
  6869. }
  6870. }
  6871. //Right Block
  6872. for (int a = -Globals.DataRange + count; a <= Globals.DataRange; a++)
  6873. {
  6874. int y = CurrentLocation.Y + a;
  6875. if (y < 0 || y >= CurrentMap.Height) continue;
  6876. for (int b = 0; b < count; b++)
  6877. {
  6878. int x = CurrentLocation.X + Globals.DataRange - b;
  6879. if (x < 0 || x >= CurrentMap.Width) continue;
  6880. Cell cell = CurrentMap.GetCell(x, y);
  6881. if (!cell.Valid || cell.Objects == null) continue;
  6882. for (int i = 0; i < cell.Objects.Count; i++)
  6883. {
  6884. MapObject ob = cell.Objects[i];
  6885. ob.Add(this);
  6886. }
  6887. }
  6888. }
  6889. break;
  6890. case MirDirection.Right:
  6891. for (int a = -Globals.DataRange; a <= Globals.DataRange; a++)
  6892. {
  6893. int y = CurrentLocation.Y + a;
  6894. if (y < 0 || y >= CurrentMap.Height) continue;
  6895. for (int b = 0; b < count; b++)
  6896. {
  6897. int x = CurrentLocation.X + Globals.DataRange - b;
  6898. if (x < 0 || x >= CurrentMap.Width) continue;
  6899. Cell cell = CurrentMap.GetCell(x, y);
  6900. if (!cell.Valid || cell.Objects == null) continue;
  6901. for (int i = 0; i < cell.Objects.Count; i++)
  6902. {
  6903. MapObject ob = cell.Objects[i];
  6904. ob.Add(this);
  6905. }
  6906. }
  6907. }
  6908. break;
  6909. case MirDirection.DownRight:
  6910. //Bottom Block
  6911. for (int a = 0; a < count; a++)
  6912. {
  6913. int y = CurrentLocation.Y + Globals.DataRange - a;
  6914. if (y < 0 || y >= CurrentMap.Height) continue;
  6915. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  6916. {
  6917. int x = CurrentLocation.X + b;
  6918. if (x < 0 || x >= CurrentMap.Width) continue;
  6919. Cell cell = CurrentMap.GetCell(x, y);
  6920. if (!cell.Valid || cell.Objects == null) continue;
  6921. for (int i = 0; i < cell.Objects.Count; i++)
  6922. {
  6923. MapObject ob = cell.Objects[i];
  6924. ob.Add(this);
  6925. }
  6926. }
  6927. }
  6928. //Right Block
  6929. for (int a = -Globals.DataRange; a <= Globals.DataRange - count; a++)
  6930. {
  6931. int y = CurrentLocation.Y + a;
  6932. if (y < 0 || y >= CurrentMap.Height) continue;
  6933. for (int b = 0; b < count; b++)
  6934. {
  6935. int x = CurrentLocation.X + Globals.DataRange - b;
  6936. if (x < 0 || x >= CurrentMap.Width) continue;
  6937. Cell cell = CurrentMap.GetCell(x, y);
  6938. if (!cell.Valid || cell.Objects == null) continue;
  6939. for (int i = 0; i < cell.Objects.Count; i++)
  6940. {
  6941. MapObject ob = cell.Objects[i];
  6942. ob.Add(this);
  6943. }
  6944. }
  6945. }
  6946. break;
  6947. case MirDirection.Down:
  6948. //Bottom Block
  6949. for (int a = 0; a < count; a++)
  6950. {
  6951. int y = CurrentLocation.Y + Globals.DataRange - a;
  6952. if (y < 0 || y >= CurrentMap.Height) continue;
  6953. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  6954. {
  6955. int x = CurrentLocation.X + b;
  6956. if (x < 0 || x >= CurrentMap.Width) continue;
  6957. Cell cell = CurrentMap.GetCell(x, y);
  6958. if (!cell.Valid || cell.Objects == null) continue;
  6959. for (int i = 0; i < cell.Objects.Count; i++)
  6960. {
  6961. MapObject ob = cell.Objects[i];
  6962. ob.Add(this);
  6963. }
  6964. }
  6965. }
  6966. break;
  6967. case MirDirection.DownLeft:
  6968. //Bottom Block
  6969. for (int a = 0; a < count; a++)
  6970. {
  6971. int y = CurrentLocation.Y + Globals.DataRange - a;
  6972. if (y < 0 || y >= CurrentMap.Height) continue;
  6973. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  6974. {
  6975. int x = CurrentLocation.X + b;
  6976. if (x < 0 || x >= CurrentMap.Width) continue;
  6977. Cell cell = CurrentMap.GetCell(x, y);
  6978. if (!cell.Valid || cell.Objects == null) continue;
  6979. for (int i = 0; i < cell.Objects.Count; i++)
  6980. {
  6981. MapObject ob = cell.Objects[i];
  6982. ob.Add(this);
  6983. }
  6984. }
  6985. }
  6986. //Left Block
  6987. for (int a = -Globals.DataRange; a <= Globals.DataRange - count; a++)
  6988. {
  6989. int y = CurrentLocation.Y + a;
  6990. if (y < 0 || y >= CurrentMap.Height) continue;
  6991. for (int b = 0; b < count; b++)
  6992. {
  6993. int x = CurrentLocation.X - Globals.DataRange + b;
  6994. if (x < 0 || x >= CurrentMap.Width) continue;
  6995. Cell cell = CurrentMap.GetCell(x, y);
  6996. if (!cell.Valid || cell.Objects == null) continue;
  6997. for (int i = 0; i < cell.Objects.Count; i++)
  6998. {
  6999. MapObject ob = cell.Objects[i];
  7000. ob.Add(this);
  7001. }
  7002. }
  7003. }
  7004. break;
  7005. case MirDirection.Left:
  7006. //Left Block
  7007. for (int a = -Globals.DataRange; a <= Globals.DataRange; a++)
  7008. {
  7009. int y = CurrentLocation.Y + a;
  7010. if (y < 0 || y >= CurrentMap.Height) continue;
  7011. for (int b = 0; b < count; b++)
  7012. {
  7013. int x = CurrentLocation.X - Globals.DataRange + b;
  7014. if (x < 0 || x >= CurrentMap.Width) continue;
  7015. Cell cell = CurrentMap.GetCell(x, y);
  7016. if (!cell.Valid || cell.Objects == null) continue;
  7017. for (int i = 0; i < cell.Objects.Count; i++)
  7018. {
  7019. MapObject ob = cell.Objects[i];
  7020. ob.Add(this);
  7021. }
  7022. }
  7023. }
  7024. break;
  7025. case MirDirection.UpLeft:
  7026. //Top Block
  7027. for (int a = 0; a < count; a++)
  7028. {
  7029. int y = CurrentLocation.Y - Globals.DataRange + a;
  7030. if (y < 0 || y >= CurrentMap.Height) continue;
  7031. for (int b = -Globals.DataRange; b <= Globals.DataRange; b++)
  7032. {
  7033. int x = CurrentLocation.X + b;
  7034. if (x < 0 || x >= CurrentMap.Width) continue;
  7035. Cell cell = CurrentMap.GetCell(x, y);
  7036. if (!cell.Valid || cell.Objects == null) continue;
  7037. for (int i = 0; i < cell.Objects.Count; i++)
  7038. {
  7039. MapObject ob = cell.Objects[i];
  7040. ob.Add(this);
  7041. }
  7042. }
  7043. }
  7044. //Left Block
  7045. for (int a = -Globals.DataRange + count; a <= Globals.DataRange; a++)
  7046. {
  7047. int y = CurrentLocation.Y + a;
  7048. if (y < 0 || y >= CurrentMap.Height) continue;
  7049. for (int b = 0; b < count; b++)
  7050. {
  7051. int x = CurrentLocation.X - Globals.DataRange + b;
  7052. if (x < 0 || x >= CurrentMap.Width) continue;
  7053. Cell cell = CurrentMap.GetCell(x, y);
  7054. if (!cell.Valid || cell.Objects == null) continue;
  7055. for (int i = 0; i < cell.Objects.Count; i++)
  7056. {
  7057. MapObject ob = cell.Objects[i];
  7058. ob.Add(this);
  7059. }
  7060. }
  7061. }
  7062. break;
  7063. }
  7064. }
  7065. public override void Remove(HumanObject player)
  7066. {
  7067. if (player == this) return;
  7068. base.Remove(player);
  7069. Enqueue(new S.ObjectRemove { ObjectID = player.ObjectID });
  7070. }
  7071. public override void Add(HumanObject player)
  7072. {
  7073. if (player == this) return;
  7074. //base.Add(player);
  7075. Enqueue(player.GetInfoEx(this));
  7076. player.Enqueue(GetInfoEx(player));
  7077. player.SendHealth(this);
  7078. SendHealth(player);
  7079. }
  7080. public override void Remove(MonsterObject monster)
  7081. {
  7082. Enqueue(new S.ObjectRemove { ObjectID = monster.ObjectID });
  7083. }
  7084. public override void Add(MonsterObject monster)
  7085. {
  7086. Enqueue(monster.GetInfo());
  7087. monster.SendHealth(this);
  7088. }
  7089. public override void SendHealth(HumanObject player)
  7090. {
  7091. if (!player.IsMember(this) && Envir.Time > RevTime) return;
  7092. byte time = Math.Min(byte.MaxValue, (byte)Math.Max(5, (RevTime - Envir.Time) / 1000));
  7093. player.Enqueue(new S.ObjectHealth { ObjectID = ObjectID, Percent = PercentHealth, Expire = time });
  7094. }
  7095. protected virtual void CleanUp()
  7096. {
  7097. Connection.Player = null;
  7098. Info.Player = null;
  7099. Info.Mount = null;
  7100. Connection.CleanObservers();
  7101. Connection = null;
  7102. Info = null;
  7103. }
  7104. public virtual void Enqueue(Packet p)
  7105. {
  7106. if (Connection == null) return;
  7107. Connection.Enqueue(p);
  7108. //if (p != null) MessageQueue.EnqueueDebugging(((ServerPacketIds)p.Index).ToString());
  7109. }
  7110. public virtual void Enqueue(Packet p, MirConnection c)
  7111. {
  7112. if (c == null)
  7113. {
  7114. Enqueue(p);
  7115. return;
  7116. }
  7117. c.Enqueue(p);
  7118. }
  7119. public void SpellToggle(Spell spell, SpellToggleState state)
  7120. {
  7121. if (Dead) return;
  7122. UserMagic magic;
  7123. bool use = Convert.ToBoolean(state);
  7124. magic = GetMagic(spell);
  7125. if (magic == null) return;
  7126. int cost;
  7127. switch (spell)
  7128. {
  7129. case Spell.Thrusting:
  7130. Info.Thrusting = state == SpellToggleState.None ? !Info.Thrusting : use;
  7131. break;
  7132. case Spell.HalfMoon:
  7133. Info.HalfMoon = state == SpellToggleState.None ? !Info.HalfMoon : use;
  7134. break;
  7135. case Spell.CrossHalfMoon:
  7136. Info.CrossHalfMoon = state == SpellToggleState.None ? !Info.CrossHalfMoon : use;
  7137. break;
  7138. case Spell.DoubleSlash:
  7139. Info.DoubleSlash = state == SpellToggleState.None ? !Info.DoubleSlash : use;
  7140. break;
  7141. case Spell.TwinDrakeBlade:
  7142. if (TwinDrakeBlade) return;
  7143. magic = GetMagic(spell);
  7144. if (magic == null) return;
  7145. cost = magic.Info.BaseCost + magic.Level * magic.Info.LevelCost;
  7146. if (cost >= MP) return;
  7147. TwinDrakeBlade = true;
  7148. ChangeMP(-cost);
  7149. Enqueue(new S.ObjectMagic { ObjectID = ObjectID, Direction = Direction, Location = CurrentLocation, Spell = spell });
  7150. break;
  7151. case Spell.FlamingSword:
  7152. if (FlamingSword || Envir.Time < FlamingSwordTime) return;
  7153. magic = GetMagic(spell);
  7154. if (magic == null) return;
  7155. cost = magic.Info.BaseCost + magic.Level * magic.Info.LevelCost;
  7156. if (cost >= MP) return;
  7157. FlamingSword = true;
  7158. FlamingSwordTime = Envir.Time + 10000;
  7159. Enqueue(new S.SpellToggle { ObjectID = ObjectID, Spell = Spell.FlamingSword, CanUse = true });
  7160. ChangeMP(-cost);
  7161. break;
  7162. case Spell.CounterAttack:
  7163. if (CounterAttack || Envir.Time < CounterAttackTime) return;
  7164. magic = GetMagic(spell);
  7165. if (magic == null) return;
  7166. cost = magic.Info.BaseCost + magic.Level * magic.Info.LevelCost;
  7167. if (cost >= MP) return;
  7168. CounterAttack = true;
  7169. CounterAttackTime = Envir.Time + (Settings.Second * 7);
  7170. var stats = new Stats
  7171. {
  7172. [Stat.MinAC] = 11 + magic.Level * 3,
  7173. [Stat.MinMAC] = 11 + magic.Level * 3,
  7174. [Stat.MaxAC] = 11 + magic.Level * 3,
  7175. [Stat.MaxMAC] = 11 + magic.Level * 3,
  7176. };
  7177. AddBuff(BuffType.CounterAttack, this, Settings.Second * 7, stats);
  7178. ChangeMP(-cost);
  7179. break;
  7180. case Spell.MentalState:
  7181. Info.MentalState = (byte)((Info.MentalState + 1) % 3);
  7182. ShowMentalState();
  7183. break;
  7184. }
  7185. }
  7186. private void ShowMentalState()
  7187. {
  7188. switch (Info.MentalState)
  7189. {
  7190. case 0:
  7191. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.MentalstateAgressive), ChatType.Hint);
  7192. break;
  7193. case 1:
  7194. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.MentalstateTrickShot), ChatType.Hint);
  7195. break;
  7196. case 2:
  7197. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.MentalstateGroupMode), ChatType.Hint);
  7198. break;
  7199. }
  7200. AddBuff(BuffType.MentalState, this, 0, new Stats(), false, values: Info.MentalState);
  7201. }
  7202. #region Mounts
  7203. public void RefreshMount(bool refreshStats = true)
  7204. {
  7205. if (RidingMount)
  7206. {
  7207. if (Mount.MountType < 0)
  7208. {
  7209. RidingMount = false;
  7210. }
  7211. else if (!Mount.CanRide)
  7212. {
  7213. RidingMount = false;
  7214. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouMustHaveSaddle), ChatType.System);
  7215. }
  7216. else if (!Mount.CanMapRide)
  7217. {
  7218. RidingMount = false;
  7219. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouCannotRideOnMap), ChatType.System);
  7220. }
  7221. else if (!Mount.CanDungeonRide)
  7222. {
  7223. RidingMount = false;
  7224. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouCannotRideWithoutBridle), ChatType.System);
  7225. }
  7226. }
  7227. else
  7228. {
  7229. RidingMount = false;
  7230. }
  7231. if (refreshStats)
  7232. RefreshStats();
  7233. Broadcast(GetMountInfo());
  7234. Enqueue(GetMountInfo());
  7235. }
  7236. public void IncreaseMountLoyalty(int amount)
  7237. {
  7238. UserItem item = Info.Equipment[(int)EquipmentSlot.Mount];
  7239. if (item != null && item.CurrentDura < item.MaxDura)
  7240. {
  7241. item.CurrentDura = (ushort)Math.Min(item.MaxDura, item.CurrentDura + amount);
  7242. item.DuraChanged = false;
  7243. Enqueue(new S.ItemRepaired { UniqueID = item.UniqueID, MaxDura = item.MaxDura, CurrentDura = item.CurrentDura });
  7244. }
  7245. }
  7246. public void DecreaseMountLoyalty(int amount)
  7247. {
  7248. if (Envir.Time > DecreaseLoyaltyTime)
  7249. {
  7250. DecreaseLoyaltyTime = Envir.Time + (Mount.SlowLoyalty ? (LoyaltyDelay * 2) : LoyaltyDelay);
  7251. UserItem item = Info.Equipment[(int)EquipmentSlot.Mount];
  7252. if (item != null && item.CurrentDura > 0)
  7253. {
  7254. DamageItem(item, amount);
  7255. if (item.CurrentDura == 0)
  7256. {
  7257. RefreshMount();
  7258. }
  7259. }
  7260. }
  7261. }
  7262. public void ToggleRide()
  7263. {
  7264. if (Mount.MountType > -1)
  7265. {
  7266. RidingMount = !RidingMount;
  7267. RefreshMount();
  7268. }
  7269. else
  7270. ReceiveChat(GameLanguage.ServerTextMap.GetLocalization(ServerTextKeys.YouDoNotHaveMountEquiped), ChatType.System);
  7271. }
  7272. #endregion
  7273. }
  7274. }