client.cpp 287 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004
  1. /*
  2. EQ2Emulator: Everquest II Server Emulator
  3. Copyright (C) 2007 EQ2EMulator Development Team (http://www.eq2emulator.net)
  4. This file is part of EQ2Emulator.
  5. EQ2Emulator is free software: you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation, either version 3 of the License, or
  8. (at your option) any later version.
  9. EQ2Emulator is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with EQ2Emulator. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include "../common/debug.h"
  17. #include "../common/Log.h"
  18. #include <iostream>
  19. #include <iomanip>
  20. #include <string.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <math.h>
  24. #include <zlib.h>
  25. #include <assert.h>
  26. #include <algorithm>
  27. #include "Player.h"
  28. #include "Commands/Commands.h"
  29. #include "ClientPacketFunctions.h"
  30. #include "../common/ConfigReader.h"
  31. #include "Guilds/Guild.h"
  32. #include "Variables.h"
  33. #include "Rules/Rules.h"
  34. #include "Titles.h"
  35. #include "IRC/IRC.h"
  36. #include "Chat/Chat.h"
  37. //#include "Quests.h"
  38. #ifdef WIN32
  39. #include <WinSock2.h>
  40. #include <windows.h>
  41. #define snprintf _snprintf
  42. #define vsnprintf _vsnprintf
  43. #define strncasecmp _strnicmp
  44. #define strcasecmp _stricmp
  45. #else
  46. #include <sys/socket.h>
  47. #ifdef FREEBSD
  48. #include <sys/types.h>
  49. #endif
  50. #include <netinet/in.h>
  51. #include <arpa/inet.h>
  52. #include <unistd.h>
  53. #endif
  54. #include "client.h"
  55. #include "../common/emu_opcodes.h"
  56. #include "../common/packet_dump.h"
  57. #include "WorldDatabase.h"
  58. #include "races.h"
  59. #include "classes.h"
  60. #include "LoginServer.h"
  61. #include "World.h"
  62. #include "../common/EQ2_Common_Structs.h"
  63. #include "net.h"
  64. #include "../common/MiscFunctions.h"
  65. #include "Items/Items.h"
  66. #include "Skills.h"
  67. #include "LuaInterface.h"
  68. #include "Quests.h"
  69. #include "Collections/Collections.h"
  70. #include "Achievements/Achievements.h"
  71. #include "Traits/Traits.h"
  72. #include "Recipes/Recipe.h"
  73. #include "Tradeskills/Tradeskills.h"
  74. #include "AltAdvancement/AltAdvancement.h"
  75. #include "Bots/Bot.h"
  76. extern WorldDatabase database;
  77. extern const char* ZONE_NAME;
  78. extern LoginServer loginserver;
  79. extern sint32 numclients;
  80. extern NetConnection net;
  81. extern Commands commands;
  82. extern ClientList client_list;
  83. extern ZoneList zone_list;
  84. extern ZoneAuth zone_auth;
  85. extern MasterItemList master_item_list;
  86. extern MasterSkillList master_skill_list;
  87. extern MasterSpellList master_spell_list;
  88. extern MasterTraitList master_trait_list;
  89. extern MasterQuestList master_quest_list;
  90. extern MasterFactionList master_faction_list;
  91. extern MasterRecipeList master_recipe_list;
  92. extern volatile bool RunLoops;
  93. extern ConfigReader configReader;
  94. extern LuaInterface* lua_interface;
  95. extern World world;
  96. extern Variables variables;
  97. extern Classes classes;
  98. extern Races races;
  99. extern GuildList guild_list;
  100. extern MasterCollectionList master_collection_list;
  101. extern MasterAchievementList master_achievement_list;
  102. extern RuleManager rule_manager;
  103. extern IRC irc;
  104. extern Chat chat;
  105. extern MasterAAList master_aa_list;
  106. extern MasterAAList master_tree_nodes;
  107. using namespace std;
  108. Client::Client(EQStream* ieqs) : pos_update(125), quest_pos_timer(2000), lua_debug_timer(30000), transmuteID(0) {
  109. eqs = ieqs;
  110. ip = eqs->GetrIP();
  111. port = ntohs(eqs->GetrPort());
  112. merchant_transaction = nullptr;
  113. SetMailTransaction(nullptr);
  114. timestamp_flag = 0;
  115. current_quest_id = 0;
  116. last_update_time = 0;
  117. quest_updates = false;
  118. //autobootup_timeout = new Timer(10000);
  119. //autobootup_timeout->Disable();
  120. CLE_keepalive_timer = new Timer(15000);
  121. connect = new Timer(1000);
  122. connect->Disable();
  123. zoneID = 0;
  124. account_name[0] = 0;
  125. account_id = 0;
  126. pwaitingforbootup = 0;
  127. current_zone = 0;
  128. connected_to_zone = false;
  129. connected = false;
  130. camp_timer = 0;
  131. disconnect_timer = 0;
  132. client_zoning = false;
  133. player_pos_changed = false;
  134. ++numclients;
  135. if (world.GetServerStatisticValue(STAT_SERVER_MOST_CONNECTIONS) < numclients)
  136. world.UpdateServerStatistic(STAT_SERVER_MOST_CONNECTIONS, numclients, true);
  137. remove_from_list = false;
  138. new_client_login = false;
  139. UpdateWindowTitle(0);
  140. num_active_failures = 0;
  141. player = new Player();
  142. combine_spawn = 0;
  143. lua_debug = false;
  144. ready_for_spawns = false;
  145. ready_for_updates = false;
  146. lua_debug_timer.Disable();
  147. transport_spawn = 0;
  148. MBuyBack.SetName("Client::MBuyBack");
  149. MPendingQuestAccept.SetName("Client::MPendingQuestAccept");
  150. MDeletePlayer.SetName("Client::MDeletePlayer");
  151. MQuestPendingUpdates.SetName("Client::MQuestPendingUpdates");
  152. search_items = 0;
  153. version = 0;
  154. next_conversation_id = 0;
  155. pending_guild_invite.guild = 0;
  156. pending_guild_invite.invited_by = 0;
  157. m_recipeListSent = false;
  158. m_resurrect.SetName("Client::m_resurrect");
  159. current_rez.expire_timer = 0;
  160. current_rez.should_delete = true;
  161. pending_last_name = 0;
  162. should_target = false;
  163. initial_spawns_sent = false;
  164. MQuestTimers.SetName("Client::quest_timers");
  165. memset(&incoming_paperdoll, 0, sizeof(incoming_paperdoll));
  166. on_auto_mount = false;
  167. should_load_spells = true;
  168. }
  169. Client::~Client() {
  170. if(current_zone && player){
  171. if(player->GetGroupMemberInfo() && (player->GetActivityStatus() & ACTIVITY_STATUS_LINKDEAD) > 0)
  172. world.GetGroupManager()->RemoveGroupMember(player->GetGroupMemberInfo()->group_id, player);
  173. world.GetGroupManager()->ClearPendingInvite(player);
  174. }
  175. if(lua_interface)
  176. lua_interface->RemoveDebugClients(this);
  177. if (player)
  178. zone_list.RemoveClientFromMap(player->GetName(), this);
  179. //let the stream factory know were done with this stream
  180. if(eqs){
  181. eqs->Close();
  182. try{
  183. eqs->ReleaseFromUse();
  184. }
  185. catch(...){}
  186. }
  187. eqs = NULL;
  188. //safe_delete(autobootup_timeout);
  189. safe_delete(disconnect_timer);
  190. safe_delete(camp_timer);
  191. safe_delete(CLE_keepalive_timer);
  192. safe_delete(connect);
  193. --numclients;
  194. MDeletePlayer.writelock(__FUNCTION__, __LINE__);
  195. if (player && !player->GetPendingDeletion())
  196. safe_delete(player);
  197. MDeletePlayer.releasewritelock(__FUNCTION__, __LINE__);
  198. safe_delete(search_items);
  199. safe_delete(current_rez.expire_timer);
  200. safe_delete(pending_last_name);
  201. safe_delete_array(incoming_paperdoll.image_bytes);
  202. UpdateWindowTitle(0);
  203. }
  204. void Client::QueuePacket(EQ2Packet* app){
  205. if(eqs){
  206. if(!eqs->CheckActive()){
  207. client_list.Remove(this);
  208. eqs = 0;
  209. }
  210. }
  211. if(app && eqs && version > 0)
  212. eqs->EQ2QueuePacket(app);
  213. else{
  214. safe_delete(app);
  215. }
  216. }
  217. void Client::PopulateSkillMap(){
  218. EQ2Packet* app = master_skill_list.GetPopulateSkillsPacket(GetVersion());
  219. if(app)
  220. QueuePacket(app);
  221. else{
  222. LogWrite(WORLD__ERROR, 0, "World", "Unable to send populate skills packet for version: %i!", GetVersion());
  223. Disconnect(); //the client cant proceed without the skill packet, might as well kick it now
  224. }
  225. }
  226. void Client::SendLoginInfo() {
  227. if(firstlogin) {
  228. LogWrite(WORLD__DEBUG, 0, "World", "Increment Server_Accepted_Connection + 1");
  229. world.UpdateServerStatistic(STAT_SERVER_ACCEPTED_CONNECTION, 1);
  230. LogWrite(CCLIENT__DEBUG, 0, "Client", "Populate Skill Map...");
  231. PopulateSkillMap();
  232. // JA: Check client version and move player to valid zone if current client does not support last saved zone (loading SF client on DoV saved zone) IT CAN HAPPEN!
  233. LogWrite(MISC__TODO, 1, "TODO", "Check client version at login, move char if invalid zone file");
  234. }
  235. LogWrite(CCLIENT__DEBUG, 0, "Client", "Toggle Character Online...");
  236. database.ToggleCharacterOnline(this, 1);
  237. LogWrite(CCLIENT__DEBUG, 0, "Client", "Loading Character Skills for player '%s'...", player->GetName());
  238. int32 count = database.LoadCharacterSkills(GetCharacterID(), player);
  239. if(count == 0) {
  240. LogWrite(CCLIENT__WARNING, 0, "Client", "No character skills found!");
  241. database.UpdateStartingSkills(GetCharacterID(), player->GetAdventureClass(), player->GetRace());
  242. database.LoadCharacterSkills(GetCharacterID(), player);
  243. }
  244. count = database.LoadCharacterTitles(GetCharacterID(), player);
  245. if(count == 0) {
  246. LogWrite(CCLIENT__DEBUG, 0, "Client", "No character titles found!");
  247. LogWrite(CCLIENT__DEBUG, 0, "Client", "Initializing starting values - Titles");
  248. database.UpdateStartingTitles(GetCharacterID(), player->GetAdventureClass(), player->GetRace(), player->GetGender());
  249. }
  250. count = database.LoadCharacterLanguages(GetCharacterID(), player);
  251. if(count == 0)
  252. LogWrite(CCLIENT__DEBUG, 0, "Client", "No character languages loaded!");
  253. count = database.LoadCharacterSpells(GetCharacterID(), player);
  254. if(count == 0) {
  255. LogWrite(CCLIENT__DEBUG, 0, "Client", "No character spells found!");
  256. database.UpdateStartingSpells(GetCharacterID(), player->GetAdventureClass(), player->GetRace());
  257. database.LoadCharacterSpells(GetCharacterID(), player);
  258. }
  259. count = database.LoadPlayerRecipeBooks(GetCharacterID(), player);
  260. if(count == 0)
  261. LogWrite(CCLIENT__DEBUG, 0, "Client", "No character recipe books found!");
  262. ClientPacketFunctions::SendLoginAccepted( this );
  263. //ClientPacketFunctions::SendAbilities ( this );
  264. ClientPacketFunctions::SendCommandNamePacket ( this );
  265. ClientPacketFunctions::SendQuickBarInit ( this );
  266. // we only need to send the MOTD if it is the first time the person is logging in.
  267. if(firstlogin){
  268. ClientPacketFunctions::SendMOTD ( this );
  269. ClientPacketFunctions::SendCharacterMacros(this);
  270. zone_list.CheckFriendList(this);
  271. }
  272. database.LoadCharacterItemList(GetAccountID(), GetCharacterID(), player, GetVersion());
  273. if (firstlogin && player->item_list.GetNumberOfItems() == 0 && player->GetEquipmentList()->GetNumberOfItems() == 0) //re-add starting items if missing
  274. {
  275. LogWrite(CCLIENT__WARNING, 0, "Client", "Player has no items - reloading starting items: '%s' (%u)", player->GetName(), GetCharacterID());
  276. database.UpdateStartingItems(GetCharacterID(), player->GetAdventureClass(), player->GetRace());
  277. database.LoadCharacterItemList(GetAccountID(), GetCharacterID(), player, GetVersion());
  278. }
  279. database.LoadPlayerFactions(this);
  280. database.LoadCharacterQuests(this);
  281. database.LoadPlayerMail(this);
  282. LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal...");
  283. SendQuestJournal(true);
  284. master_aa_list.DisplayAA(this, 0, 3);
  285. SendCollectionList();
  286. SendBiography();
  287. map<int32, Quest*>::iterator itr;
  288. Quest* quest = 0;
  289. for (itr = player->player_quests.begin(); itr != player->player_quests.end(); itr++) {
  290. quest = itr->second;
  291. if (quest->IsTracked()) {
  292. quest->SetTracked(false);
  293. QueuePacket(itr->second->QuestJournalReply(version, GetNameCRC(), player));
  294. quest->SetTracked(true);
  295. QueuePacket(itr->second->QuestJournalReply(version, GetNameCRC(), player));
  296. }
  297. }
  298. // SendAchievementsList();
  299. /*Guild* guild = player->GetGuild();
  300. if (guild) {
  301. guild->UpdateGuildMemberInfo(GetPlayer());
  302. if (firstlogin)
  303. guild->SendGuildMOTD(this);
  304. guild->SendGuildUpdate(this);
  305. guild->SendGuildMember(GetPlayer(), firstlogin);
  306. guild->SendGuildEventList(this);
  307. guild->SendGuildBankEventList(this);
  308. guild->SendAllGuildEvents(this);
  309. guild->SendGuildMemberList(this);
  310. }*/
  311. LogWrite(CCLIENT__DEBUG, 0, "Client", "Loading Faction Updates...");
  312. EQ2Packet* outapp = player->GetFactions()->FactionUpdate(GetVersion());
  313. if(outapp){
  314. LogWrite(CCLIENT__PACKET, 0, "Client", "Dump/Print Packet in func: %s, line: %i", __FUNCTION__, __LINE__);
  315. //DumpPacket(outapp);
  316. QueuePacket(outapp);
  317. }
  318. LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Command List...");
  319. ClientPacketFunctions::SendCommandList( this );
  320. LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Language Updates...");
  321. SendLanguagesUpdate(database.GetCharacterCurrentLang(GetCharacterID(), player));
  322. ClientPacketFunctions::SendInstanceList(this);
  323. SendZoneInfo();
  324. /*Spell* spell = 0;
  325. vector<QuickBarItem*>::iterator itr;
  326. for(itr = player->GetQuickbar()->begin(); itr != player->GetQuickbar()->end(); itr++){
  327. if((*itr)->type == 1){
  328. spell = master_spell_list.GetSpell((*itr)->id);
  329. if(spell)
  330. QueuePacket(spell->serialize(this, false, 0x20));
  331. }
  332. }*/
  333. }
  334. void Client::SendPlayerDeathWindow()
  335. {
  336. LogWrite(CCLIENT__DEBUG, 0, "Client", "SendPlayerDeathWindow");
  337. vector<RevivePoint*>* results=GetCurrentZone()->GetRevivePoints(this);
  338. vector<RevivePoint*>::iterator itr;
  339. if (results && results->size()>0)
  340. {
  341. PacketStruct* packet=configReader.getStruct("WS_DeathWindow", GetVersion());
  342. if (packet)
  343. {
  344. packet->setArrayLengthByName("location_count", results->size());
  345. RevivePoint* point = 0;
  346. int32 i=0;
  347. for (itr=results->begin();itr!=results->end();itr++, i++)
  348. {
  349. point = *itr;
  350. if(point)
  351. {
  352. packet->setArrayDataByName("location_id", point->id, i);
  353. //zone_name = database.GetZoneName(point->zone_id);
  354. string zone_name = database.GetZoneDescription(point->zone_id);
  355. if(zone_name.length() > 0)
  356. packet->setArrayDataByName("zone_name", zone_name.c_str(), i);
  357. packet->setArrayDataByName("location_name", point->location_name.c_str(), i);
  358. packet->setArrayDataByName("distance", GetPlayer()->GetDistance(point->x, point->y, point->z), i);
  359. }
  360. if(point->id == 0xFFFFFFFF)//tmp location
  361. safe_delete(point);
  362. }
  363. // done with the revive points so lets free up the pointer
  364. safe_delete(results);
  365. #if EQDEBUG >= 3
  366. LogWrite(CCLIENT__DEBUG, 0, "Client", "WS_DeathWindow Packet:");
  367. packet->PrintPacket();
  368. #endif
  369. EQ2Packet* outapp = packet->serialize();
  370. QueuePacket(outapp);
  371. safe_delete(packet);
  372. }
  373. }
  374. }
  375. void Client::DisplayDeadWindow()
  376. {
  377. LogWrite(ZONE__DEBUG, 0, "Zone", "DisplayDeadWindow()");
  378. player->SetHP(0);
  379. player->SetPower(0);
  380. GetCurrentZone()->TriggerCharSheetTimer();
  381. PacketStruct* packet = configReader.getStruct("WS_ServerControlFlags", GetVersion());
  382. if(packet)
  383. {
  384. packet->setDataByName("parameter1", 8);
  385. packet->setDataByName("value", 1);
  386. QueuePacket(packet->serialize());
  387. packet->setDataByName("parameter1", 16);
  388. QueuePacket(packet->serialize());
  389. safe_delete(packet);
  390. }
  391. packet = configReader.getStruct("WS_ServerUpdateTarget", GetVersion());
  392. if(packet)
  393. {
  394. packet->setDataByName("spawn_id", 0xFFFFFFFF);
  395. QueuePacket(packet->serialize());
  396. safe_delete(packet);
  397. }
  398. SendPlayerDeathWindow();
  399. }
  400. void Client::HandlePlayerRevive(int32 point_id)
  401. {
  402. PacketStruct* packet = configReader.getStruct("WS_ServerControlFlags", GetVersion());
  403. if(packet)
  404. {
  405. packet->setDataByName("parameter1", 8);
  406. QueuePacket(packet->serialize());
  407. packet->setDataByName("parameter1", 16);
  408. QueuePacket(packet->serialize());
  409. safe_delete(packet);
  410. }
  411. SimpleMessage(CHANNEL_COLOR_REVIVE, "You regain consciousness!");
  412. packet = configReader.getStruct("WS_Resurrected", GetVersion());
  413. if(packet)
  414. {
  415. QueuePacket(packet->serialize());
  416. safe_delete(packet);
  417. }
  418. float x, y, z, heading;
  419. RevivePoint* revive_point = 0;
  420. if(point_id != 0xFFFFFFFF)
  421. revive_point = GetCurrentZone()->GetRevivePoint(point_id);
  422. string zone_desc;
  423. const char* location_name = "Unknown";
  424. //revive at zone safe coords
  425. if(!revive_point)
  426. {
  427. LogWrite(CCLIENT__WARNING, 0, "Client", "No Revive Point! Spawning player at safe coordinates!");
  428. x = GetCurrentZone()->GetSafeX();
  429. y = GetCurrentZone()->GetSafeY();
  430. z = GetCurrentZone()->GetSafeZ();
  431. heading = GetCurrentZone()->GetSafeHeading();
  432. zone_desc = GetCurrentZone()->GetZoneDescription();
  433. location_name = "Zone Safe Point";
  434. Zone(GetCurrentZone()->GetZoneName(), false);
  435. }
  436. else
  437. {
  438. LogWrite(CCLIENT__DEBUG, 0, "Client", "Sending player to chosen Revive Point.");
  439. x = revive_point->x;
  440. y = revive_point->y;
  441. z = revive_point->z;
  442. heading = revive_point->heading;
  443. zone_desc = database.GetZoneDescription(revive_point->zone_id);
  444. location_name = revive_point->location_name.c_str();
  445. Zone(GetCurrentZone()->GetZoneName(), false);
  446. }
  447. player->SetResurrecting(true);
  448. player->SetX(x);
  449. player->SetY(y);
  450. player->SetZ(z);
  451. player->SetHeading(heading);
  452. player->SetHP(player->GetTotalHP());
  453. player->SetPower(player->GetTotalPower());
  454. LogWrite(CCLIENT__DEBUG, 0, "Client", "Attempt Revive @ %s, %.2f, %.2f, %.2f, %.2f, HP: %i, Pow: %i, %s",
  455. zone_desc.c_str(),
  456. player->GetX(),
  457. player->GetY(),
  458. player->GetZ(),
  459. player->GetHeading(),
  460. player->GetHP(),
  461. player->GetPower(),
  462. location_name);
  463. //player->ClearEverything();
  464. Save();
  465. if(revive_point && revive_point->zone_id != GetCurrentZone()->GetZoneID() && revive_point->zone_id != 0)
  466. {
  467. string* zone_name = database.GetZoneName(revive_point->zone_id);
  468. if(!zone_name || zone_name->length() == 0)
  469. {
  470. LogWrite(CCLIENT__WARNING, 0, "Client", "Unable to zone player to revive zone ID '%u', using current zone's safe coords.", revive_point->zone_id);
  471. x = GetCurrentZone()->GetSafeX();
  472. y = GetCurrentZone()->GetSafeY();
  473. z = GetCurrentZone()->GetSafeZ();
  474. heading = GetCurrentZone()->GetSafeHeading();
  475. location_name = "Zone Safe Point";
  476. }
  477. else
  478. {
  479. LogWrite(CCLIENT__DEBUG, 0, "Client", "Sending player to revive zone ID '%u', using current zone's safe coords.", revive_point->zone_id);
  480. location_name = revive_point->location_name.c_str();
  481. player->ClearEverything();
  482. Zone(zone_name->c_str(), false);
  483. }
  484. safe_delete(zone_name);
  485. }
  486. zone_desc = GetCurrentZone()->GetZoneDescription();
  487. Message(CHANNEL_COLOR_REVIVE, "Reviving in %s at %s.", zone_desc.c_str(), location_name);
  488. player->SetSpawnType(4);
  489. packet = configReader.getStruct("WS_CancelMoveObjectMode", GetVersion());
  490. if(packet)
  491. {
  492. QueuePacket(packet->serialize());
  493. safe_delete(packet);
  494. }
  495. packet = configReader.getStruct("WS_TeleportWithinZone", GetVersion());
  496. if(packet)
  497. {
  498. packet->setDataByName("x", x);
  499. packet->setDataByName("y", y);
  500. packet->setDataByName("z", z);
  501. QueuePacket(packet->serialize());
  502. safe_delete(packet);
  503. }
  504. packet = configReader.getStruct("WS_SetControlGhost", GetVersion());
  505. if(packet)
  506. {
  507. packet->setDataByName("spawn_id", 0xFFFFFFFF);
  508. packet->setDataByName("unknown2", 255);
  509. QueuePacket(packet->serialize());
  510. safe_delete(packet);
  511. }
  512. packet = configReader.getStruct("WS_SetPOVGhostCmd", GetVersion());
  513. if(packet)
  514. {
  515. packet->setDataByName("spawn_id", 0xFFFFFFFF);
  516. QueuePacket(packet->serialize());
  517. safe_delete(packet);
  518. }
  519. GetCurrentZone()->RemoveSpawn(player, false);
  520. m_resurrect.writelock(__FUNCTION__, __LINE__);
  521. if(current_rez.active)
  522. current_rez.should_delete = true;
  523. m_resurrect.releasewritelock(__FUNCTION__, __LINE__);
  524. }
  525. void Client::SendCharInfo(){
  526. EQ2Packet* app;
  527. player->SetEquippedItemAppearances();
  528. ClientPacketFunctions::SendCharacterData ( this );
  529. SendCharPOVGhost();
  530. PacketStruct* packet = configReader.getStruct("WS_SetControlGhost",GetVersion());
  531. if(packet){
  532. packet->setDataByName("spawn_id", player->GetIDWithPlayerSpawn(player));
  533. packet->setDataByName("size", .56);
  534. packet->setDataByName("unknown2", 255);
  535. EQ2Packet* app = packet->serialize();
  536. QueuePacket(app);
  537. safe_delete(packet);
  538. }
  539. //SendAchievementsList();
  540. ClientPacketFunctions::SendCharacterSheet(this);
  541. ClientPacketFunctions::SendTraitList(this);// moved from below
  542. //ClientPacketFunctions::SendAbilities(this);
  543. ClientPacketFunctions::SendSkillBook(this);
  544. if (!player->IsResurrecting()) {
  545. ClientPacketFunctions::SendUpdateSpellBook(this);
  546. }
  547. else {
  548. player->SetResurrecting(false);
  549. }
  550. ClientPacketFunctions::SendLoginCommandMessages(this);
  551. GetCurrentZone()->AddSpawn(player);
  552. //SendCollectionList();
  553. Guild* guild = player->GetGuild();
  554. if (guild)
  555. guild->GuildMemberLogin(this, firstlogin);
  556. app = player->item_list.serialize(GetPlayer(), GetVersion());
  557. if(app){
  558. LogWrite(CCLIENT__PACKET, 0, "Client", "Dump/Print Packet in func: %s, line: %i", __FUNCTION__, __LINE__);
  559. //DumpPacket(app);
  560. QueuePacket(app);
  561. }
  562. app = player->GetEquipmentList()->serialize(GetVersion());
  563. if(app){
  564. QueuePacket(app);
  565. }
  566. vector<Item*>* items = player->item_list.GetItemsFromBagID(-3); // bank items
  567. if(items && items->size() > 0){
  568. for(int32 i=0;i<items->size();i++){
  569. EQ2Packet* outapp = items->at(i)->serialize(GetVersion(), false, GetPlayer());
  570. LogWrite(CCLIENT__PACKET, 0, "Client", "Dump/Print Packet in func: %s, line: %i", __FUNCTION__, __LINE__);
  571. //DumpPacket(outapp);
  572. QueuePacket(outapp);
  573. }
  574. }
  575. if (firstlogin && (app = chat.GetWorldChannelList(this)) != NULL)
  576. QueuePacket(app);
  577. safe_delete(items);
  578. items = player->item_list.GetItemsFromBagID(-4); //shared bank items
  579. if(items && items->size() > 0){
  580. for(int32 i=0;i<items->size();i++)
  581. QueuePacket(items->at(i)->serialize(GetVersion(), false, GetPlayer()));
  582. }
  583. safe_delete(items);
  584. SendTitleUpdate();
  585. GetPlayer()->ChangePrimaryWeapon();
  586. GetPlayer()->ChangeSecondaryWeapon();
  587. GetPlayer()->ChangeRangedWeapon();
  588. database.LoadBuyBacks(this);
  589. master_aa_list.DisplayAA(this, 0, 0);
  590. string zone_motd = GetCurrentZone()->GetZoneMOTD();
  591. if (zone_motd.length() > 0 && zone_motd[0] != ' ') {
  592. string zone_motd_send = "Zone MOTD: " + zone_motd;
  593. SimpleMessage(CHANNEL_COLOR_WHITE, zone_motd_send.c_str());
  594. }
  595. const char* zone_script = world.GetZoneScript(GetCurrentZone()->GetZoneID());
  596. if (zone_script && lua_interface)
  597. lua_interface->RunZoneScript(zone_script, "player_entry", GetCurrentZone(), GetPlayer());
  598. this->client_zoning = false;
  599. if(player->GetHP() < player->GetTotalHP() || player->GetPower() < player->GetTotalPower())
  600. GetCurrentZone()->AddDamagedSpawn(player);
  601. if (firstlogin && rule_manager.GetGlobalRule(R_World, IRCGlobalEnabled)->GetBool())
  602. Message(CHANNEL_BROADCAST, "This server has a global IRC channel, join the world channel %s to use", rule_manager.GetGlobalRule(R_World, IRCChan)->GetString());
  603. if (firstlogin)
  604. firstlogin = false;
  605. player->ClearProcs();
  606. items = player->GetEquippedItemList();
  607. if (items && items->size() > 0) {
  608. for(int32 i = 0; i < items->size(); i++) {
  609. Item* item = items->at(i);
  610. if (item && item->GetItemScript() && lua_interface)
  611. lua_interface->RunItemScript(item->GetItemScript(), "equipped", item, player);
  612. }
  613. }
  614. //Allow this player to change their last name if they meet the level requirement
  615. if (!player->get_character_flag(CF_ENABLE_CHANGE_LASTNAME) && player->GetLevel() >= rule_manager.GetGlobalRule(R_Player, MinLastNameLevel)->GetInt8())
  616. player->set_character_flag(CF_ENABLE_CHANGE_LASTNAME);
  617. safe_delete(items);
  618. if (!player->Alive())
  619. DisplayDeadWindow();
  620. }
  621. void Client::SendZoneSpawns(){
  622. //Allows us to place spawns almost anywhere
  623. uchar blah[] ={0x00,0x3C,0x1C,0x46,0x00,0x3C,0x1C,0x46,0x00,0x3C,0x1C,0x46};
  624. EQ2Packet* app = new EQ2Packet(OP_MoveableObjectPlacementCriteri, blah, sizeof(blah));
  625. QueuePacket(app);
  626. ClientPacketFunctions::SendSkillSlotMappings(this);
  627. ClientPacketFunctions::SendGameWorldTime ( this );
  628. GetCurrentZone()->StartZoneInitialSpawnThread(this);
  629. }
  630. void Client::SendCharPOVGhost(){
  631. PacketStruct* set_pov = configReader.getStruct("WS_SetPOVGhostCmd",GetVersion());
  632. if(set_pov){
  633. set_pov->setDataByName("spawn_id", player->GetIDWithPlayerSpawn(player));
  634. EQ2Packet* app_pov = set_pov->serialize();
  635. QueuePacket(app_pov);
  636. safe_delete(set_pov);
  637. }
  638. }
  639. void Client::SendZoneInfo(){
  640. ZoneServer* zone = GetCurrentZone();
  641. if(zone){
  642. EQ2Packet* packet = zone->GetZoneInfoPacket(this);
  643. QueuePacket(packet);
  644. PacketStruct* fog_packet = configReader.getStruct("WS_FogInit", GetVersion());
  645. LogWrite(CCLIENT__PACKET, 0, "Client", "Dump/Print Packet in func: %s, line: %i", __FUNCTION__, __LINE__);
  646. #if EQDEBUG >= 9
  647. fog_packet->PrintPacket();
  648. #endif
  649. if(fog_packet){
  650. database.LoadFogInit(zone->GetZoneFile(), fog_packet);
  651. QueuePacket(fog_packet->serialize());
  652. safe_delete(fog_packet);
  653. }
  654. zone->SendFlightPathsPackets(this);
  655. }
  656. /*
  657. uchar blah[] ={0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x01,0x00,0x00,0x00,0x00
  658. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  659. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF
  660. ,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
  661. ,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00
  662. ,0x00,0x00,0x00,0x00,0x10,0x49,0x2B,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  663. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  664. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  665. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  666. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  667. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  668. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  669. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  670. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  671. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  672. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  673. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  674. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  675. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  676. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  677. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  678. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  679. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  680. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  681. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  682. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  683. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  684. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  685. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  686. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  687. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  688. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  689. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  690. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  691. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  692. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00};
  693. EQ2Packet* appA = new EQ2Packet(OP_GuildUpdateMsg, blah, sizeof(blah));
  694. QueuePacket(appA);
  695. uchar blahA[] ={0x45,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00
  696. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  697. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
  698. ,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00
  699. ,0x00,0x10,0xE2,0x10,0x6C,0x00,0x00,0x00,0x00};
  700. EQ2Packet* appB = new EQ2Packet(OP_KeymapDataMsg, blahA, sizeof(blahA));
  701. QueuePacket(appB);
  702. */
  703. LogWrite(CCLIENT__DEBUG, 0, "Client", "SendFriendList");
  704. SendFriendList();
  705. LogWrite(CCLIENT__DEBUG, 0, "Client", "SendIgnoreList");
  706. SendIgnoreList();
  707. }
  708. void Client::SendDefaultGroupOptions(){
  709. /*
  710. 0 - loot method
  711. 1 - loot items rarity
  712. 2 - Auto split coin
  713. 4 - default yell method
  714. 6 - group autolock
  715. 7 - solo autolock
  716. */
  717. uchar blah7[] = {0x01,0x01,0x01,0x01,0x00,0x00,0x00};
  718. EQ2Packet* app7 = new EQ2Packet(OP_DefaultGroupOptionsMsg, blah7, sizeof(blah7));
  719. QueuePacket(app7);
  720. }
  721. bool Client::HandlePacket(EQApplicationPacket *app) {
  722. bool ret = true;
  723. LogWrite(PACKET__DEBUG, 9, "Packet", "[EQDEBUG] Received Packet:");
  724. #if EQDEBUG >= 9
  725. DumpPacket(app, true);
  726. #endif
  727. EmuOpcode opcode = app->GetOpcode();
  728. #if EQDEBUG >= 9
  729. const char* name = app->GetOpcodeName();
  730. if(name)
  731. cout << name;
  732. else
  733. cout << "Unknown";
  734. cout << " Packet: OPCode: 0x" << hex << setw(2) << setfill('0') << app->GetOpcode() << dec << ", size: " << setw(5) << setfill(' ') << app->Size() << endl;
  735. DumpPacket(app);
  736. #endif
  737. //if (opcode != OP_UpdatePositionMsg) {
  738. // LogWrite(PACKET__DEBUG, 0, "opcode %s received", app->GetOpcodeName());
  739. //}
  740. switch(opcode){
  741. case OP_LoginByNumRequestMsg:{
  742. LogWrite(OPCODE__DEBUG, 0, "Opcode", "Opcode 0x%X (%i): OP_LoginByNumRequestMsg", opcode, opcode);
  743. PacketStruct* request;
  744. request = configReader.getStruct("LoginByNumRequest", 1);
  745. if (request && request->LoadPacketData(app->pBuffer,app->size)) {
  746. // test the original location of Version for clients older than 1212
  747. version = request->getType_int16_ByName("version");
  748. if (version >= 1212 || EQOpcodeManager.count(GetOpcodeVersion(version)) == 0) {
  749. // must be new client data version method, re-fetch the packet
  750. safe_delete(request);
  751. request = configReader.getStruct("LoginByNumRequest", 1212);
  752. if (request && request->LoadPacketData(app->pBuffer, app->size)) {
  753. // Xinux suggests using an INT16 here. Our first new version = 57000
  754. version = request->getType_int16_ByName("version");
  755. }
  756. else {
  757. LogWrite(LOGIN__ERROR, 0, "Login", "Nasty Horrible things happening. Tell a dev asap! Version: %i", version);
  758. break;
  759. }
  760. }
  761. if (EQOpcodeManager.count(GetOpcodeVersion(version)) == 0) {
  762. LogWrite(WORLD__ERROR, 0, "World", "Incompatible version: %i", version);
  763. ClientPacketFunctions::SendLoginDenied( this );
  764. return false;
  765. }
  766. int32 account_id = request->getType_int32_ByName("account_id");
  767. int32 access_code = request->getType_int32_ByName("access_code");
  768. ZoneAuthRequest* zar = zone_auth.GetAuth(account_id, access_code);
  769. if(zar)
  770. {
  771. firstlogin = zar->isFirstLogin ( );
  772. LogWrite(ZONE__INFO, 0, "ZoneAuth", "Access Key: %u, Character Name: %s, Account ID: %u, Client Data Version: %u", zar->GetAccessKey(), zar->GetCharacterName(), zar->GetAccountID(), version);
  773. if(database.loadCharacter(zar->GetCharacterName(), zar->GetAccountID(), this)){
  774. version = request->getType_int16_ByName("version");
  775. MDeletePlayer.writelock(__FUNCTION__, __LINE__);
  776. Client* client = zone_list.GetClientByCharName(player->GetName());
  777. if(client){
  778. if(client->getConnection())
  779. client->getConnection()->SendDisconnect();
  780. if(client->GetCurrentZone() && !client->IsZoning()){
  781. //swap players, allowing the client to resume his LD'd player (ONLY if same version of the client)
  782. if(client->GetVersion() == version){
  783. Player* current_player = GetPlayer();
  784. SetPlayer(client->GetPlayer());
  785. client->SetPlayer(current_player);
  786. client->GetPlayer()->SetPendingDeletion(true);
  787. GetPlayer()->SetPendingDeletion(false);
  788. GetPlayer()->ResetSavedSpawns();
  789. GetPlayer()->SetReturningFromLD(true);
  790. GetPlayer()->GetZone()->RemoveDelayedSpawnRemove(GetPlayer());
  791. }
  792. client->GetCurrentZone()->RemoveClientImmediately(client);
  793. }
  794. }
  795. MDeletePlayer.releasewritelock(__FUNCTION__, __LINE__);
  796. if(!GetCurrentZone()){
  797. LogWrite(ZONE__ERROR, 0, "Zone", "Error loading zone for character: %s", player->GetName());
  798. ClientPacketFunctions::SendLoginDenied( this );
  799. }
  800. else if(EQOpcodeManager.count(GetOpcodeVersion(version)) > 0 && getConnection()){
  801. getConnection()->SetClientVersion(version);
  802. connected_to_zone = true;
  803. client_list.Remove(this); //remove from master client list
  804. new_client_login = true;
  805. GetCurrentZone()->AddClient(this); //add to zones client list
  806. world.RejoinGroup(this);
  807. zone_list.AddClientToMap(player->GetName(), this);
  808. }
  809. else{
  810. LogWrite(WORLD__ERROR, 0, "World", "Incompatible version: %i", version);
  811. ClientPacketFunctions::SendLoginDenied( this );
  812. return false;
  813. }
  814. }
  815. else{
  816. LogWrite(WORLD__ERROR, 0, "World", "Could not load character '%s' with account id of: %u", zar->GetCharacterName(), zar->GetAccountID());
  817. ClientPacketFunctions::SendLoginDenied( this );
  818. }
  819. zone_auth.RemoveAuth(zar);
  820. database.loadCharacterProperties(this);
  821. }
  822. else
  823. {
  824. LogWrite(WORLD__ERROR, 0, "World", "Invalid ZoneAuthRequest, disconnecting client.");
  825. Disconnect();
  826. }
  827. }
  828. safe_delete(request);
  829. break;
  830. }
  831. case OP_SysClient: {
  832. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_SysClient", opcode, opcode);
  833. LogWrite(CCLIENT__DEBUG, 0, "Client", "Client '%s' (%u) is ready for spawn updates.", GetPlayer()->GetName(), GetPlayer()->GetCharacterID());
  834. ready_for_updates = true;
  835. break;
  836. }
  837. case OP_MapRequest:{
  838. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_MapRequest", opcode, opcode);
  839. PacketStruct* packet = configReader.getStruct("WS_MapRequest", GetVersion());
  840. if(packet && app->size > 2 && GetCurrentZone()){
  841. packet->LoadPacketData(app->pBuffer, app->size);
  842. PacketStruct* fog_packet = configReader.getStruct("WS_FogInit", GetVersion());
  843. if(fog_packet){
  844. LogWrite(PACKET__DEBUG, 0, "Packet", "In OP_MapRequest: Fog Packet");
  845. database.LoadFogInit(packet->getType_EQ2_16BitString_ByName("zone").data, fog_packet);
  846. fog_packet->setDataByName("unknown1", 1);
  847. fog_packet->setDataByName("unknown3", 1);
  848. LogWrite(CCLIENT__PACKET, 0, "Client", "Dump/Print Packet in func: %s, line: %i", __FUNCTION__, __LINE__);
  849. //fog_packet->PrintPacket();
  850. QueuePacket(fog_packet->serialize());
  851. safe_delete(fog_packet);
  852. }
  853. safe_delete(packet);
  854. }
  855. break;
  856. }
  857. case OP_RequestCampMsg: {
  858. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_RequestCampMsg", opcode, opcode);
  859. PacketStruct* request = configReader.getStruct("WS_RequestCamp", GetVersion());
  860. if (request && request->LoadPacketData(app->pBuffer, app->size)) {
  861. LogWrite(CCLIENT__DEBUG, 0, "CClient", "Client '%s' (%u) is camping...", GetPlayer()->GetName(), GetPlayer()->GetCharacterID());
  862. LogWrite(CCLIENT__DEBUG, 0, "CClient", "WS_RequestCamp - quit: %i, camp_desktop: %i, camp_char_select: %i, (to) char_name: %s",
  863. request->getType_int8_ByName("quit"),
  864. request->getType_int8_ByName("camp_desktop"),
  865. request->getType_int16_ByName("camp_char_select"),
  866. (request->getType_EQ2_16BitString_ByName("char_name").data.length() > 0) ? request->getType_EQ2_16BitString_ByName("char_name").data.c_str() : "");
  867. //DumpPacket(app->pBuffer, app->size);
  868. //request->PrintPacket();
  869. if (!camp_timer) {
  870. int16 camp_time = 20; // default if rule cannot be found
  871. if (GetAdminStatus() >= 100)
  872. camp_time = rule_manager.GetGlobalRule(R_World, GMCampTimer)->GetInt16();
  873. else
  874. camp_time = rule_manager.GetGlobalRule(R_World, PlayerCampTimer)->GetInt16();
  875. PacketStruct* response = configReader.getStruct("WS_Camp", GetVersion());
  876. if (response) {
  877. bool disconnect = false;
  878. if (request->getType_int8_ByName("camp_desktop") == 1 && request->getType_int8_ByName("quit") == 1) {
  879. // Command: /camp desktop
  880. // Command: /quit
  881. response->setDataByName("camp_desktop", 1);
  882. disconnect = true;
  883. }
  884. else {
  885. // Command: /camp
  886. response->setDataByName("camp_desktop", request->getType_int8_ByName("camp_desktop"));
  887. response->setDataByName("camp_char_select", request->getType_int16_ByName("camp_char_select"));
  888. response->setDataByName("seconds", camp_time);
  889. }
  890. camp_timer = new Timer(camp_time * 1000);
  891. camp_timer->Enable();
  892. if (request->getType_EQ2_16BitString_ByName("char_name").data.length() > 0) {
  893. // /camp {char_name}
  894. response->setDataByName("char_name", request->getType_EQ2_16BitString_ByName("char_name").data.c_str());
  895. }
  896. else if (request->getType_int8_ByName("camp_desktop") == 0 && request->getType_int16_ByName("camp_char_select") == 0) {
  897. // /camp (go back to char selection screen)
  898. response->setDataByName("char_name", " ");
  899. response->setDataByName("camp_char_select", 1);
  900. }
  901. LogWrite(CCLIENT__DEBUG, 0, "CClient", "WS_Camp - seconds: %i, camp_desktop: %i, camp_char_select: %i, (to) char_name: %s",
  902. response->getType_int8_ByName("seconds"),
  903. response->getType_int8_ByName("camp_desktop"),
  904. response->getType_int8_ByName("camp_char_select"),
  905. (response->getType_EQ2_16BitString_ByName("char_name").data.length() > 0) ? response->getType_EQ2_16BitString_ByName("char_name").data.c_str() : "");
  906. // JA: trying to recognize /camp vs LD (see ZoneServer::ClientProcess())
  907. if ((player->GetActivityStatus() & ACTIVITY_STATUS_CAMPING) == 0)
  908. player->SetActivityStatus(player->GetActivityStatus() + ACTIVITY_STATUS_CAMPING);
  909. //response->PrintPacket();
  910. QueuePacket(response->serialize());
  911. safe_delete(response);
  912. if (disconnect)
  913. Disconnect();
  914. }
  915. }
  916. }
  917. safe_delete(request);
  918. break;
  919. }
  920. case OP_StoodMsg:{
  921. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_StoodMsg", opcode, opcode);
  922. if(camp_timer)
  923. {
  924. // JA: clear camping flag
  925. if( (player->GetActivityStatus() & ACTIVITY_STATUS_CAMPING) > 0 )
  926. player->SetActivityStatus(player->GetActivityStatus() - ACTIVITY_STATUS_CAMPING);
  927. safe_delete(camp_timer);
  928. EQ2Packet* outapp = new EQ2Packet(OP_CampAbortedMsg, 0, 0);
  929. QueuePacket(outapp);
  930. }
  931. player->SetTempVisualState(0);
  932. break;
  933. }
  934. case OP_StandMsg:{
  935. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_StandMsg", opcode, opcode);
  936. if(camp_timer)
  937. {
  938. // JA: clear camping flag
  939. if( (player->GetActivityStatus() & ACTIVITY_STATUS_CAMPING) > 0 )
  940. player->SetActivityStatus(player->GetActivityStatus() - ACTIVITY_STATUS_CAMPING);
  941. safe_delete(camp_timer);
  942. EQ2Packet* outapp = new EQ2Packet(OP_CampAbortedMsg, 0, 0);
  943. QueuePacket(outapp);
  944. }
  945. player->SetTempVisualState(539);
  946. break;
  947. }
  948. case OP_SitMsg: {
  949. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_SitMsg", opcode, opcode);
  950. player->SetTempVisualState(538);
  951. break;
  952. }
  953. case OP_SatMsg: {
  954. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_SatMsg", opcode, opcode);
  955. player->SetTempVisualState(540);
  956. break;
  957. }
  958. case OP_QuestJournalOpenMsg:
  959. case OP_QuestJournalInspectMsg:{
  960. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_QuestJournalOpenMsg, OP_QuestJournalInspectMsg", opcode, opcode);
  961. if(app->size < sizeof(int32))
  962. break;
  963. int32 quest_id = 0;
  964. memcpy(&quest_id, app->pBuffer, sizeof(int32));
  965. Quest* quest = GetActiveQuest(quest_id);
  966. if(quest)
  967. QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player));
  968. else{
  969. quest = player->GetCompletedQuest(quest_id);
  970. if(quest)
  971. QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player, 0, 1, true));
  972. }
  973. break;
  974. }
  975. case OP_QuestJournalSetVisibleMsg:{
  976. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_QuestJournalSetVisibleMsg", opcode, opcode);
  977. PacketStruct* packet = configReader.getStruct("WS_QuestJournalVisible", GetVersion());
  978. if (packet && packet->LoadPacketData(app->pBuffer, app->size)) {
  979. int32 quest_id = packet->getType_int32_ByName("quest_id");
  980. bool hidden = packet->getType_int8_ByName("visible") == 1 ? false : true;
  981. map<int32, Quest*>* player_quests = player->GetPlayerQuests();
  982. if (player_quests) {
  983. if (player_quests->count(quest_id) > 0)
  984. player_quests->at(quest_id)->SetHidden(hidden);
  985. else
  986. LogWrite(CCLIENT__ERROR, 0, "Client", "OP_QuestJournalSetVisibleMsg error: Player does not have quest with id of %u", quest_id);
  987. }
  988. else
  989. LogWrite(CCLIENT__ERROR, 0, "Client", "OP_QuestJournalSetVisibleMsg error: Unable to get player(%s) quests", player->GetName());
  990. safe_delete(packet);
  991. }
  992. break;
  993. }
  994. case OP_MacroUpdateMsg:{
  995. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_MacroUpdateMsg", opcode, opcode);
  996. PacketStruct* macro_update=configReader.getStruct("WS_MacroUpdate",GetVersion());
  997. if(macro_update && macro_update->LoadPacketData(app->pBuffer, app->size)){
  998. vector<string>* update = new vector<string>;
  999. int8 number = macro_update->getType_int8_ByName("number");
  1000. int16 icon = macro_update->getType_int16_ByName("icon");
  1001. string name = macro_update->getType_EQ2_8BitString_ByName("name").data;
  1002. int8 count = macro_update->getType_int8_ByName("macro_count");
  1003. for(int8 i=0;i<count;i++){
  1004. char tmp_command[15] = {0};
  1005. sprintf(tmp_command, "command_%i", i);
  1006. update->push_back(macro_update->getType_EQ2_16BitString_ByName(tmp_command).data);
  1007. }
  1008. if(name.length() == 0)
  1009. database.UpdateCharacterMacro(GetCharacterID(), number, 0, icon, update);
  1010. else
  1011. database.UpdateCharacterMacro(GetCharacterID(), number, name.c_str(), icon, update);
  1012. safe_delete(update);
  1013. safe_delete(macro_update);
  1014. }
  1015. break;
  1016. }
  1017. case OP_DialogSelectMsg:{
  1018. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_DialogSelectMsg", opcode, opcode);
  1019. PacketStruct* packet = configReader.getStruct("WS_DialogSelect", GetVersion());
  1020. if(packet){
  1021. packet->LoadPacketData(app->pBuffer, app->size);
  1022. int32 conversation_id = packet->getType_int32_ByName("conversation_id");
  1023. int32 response_index = packet->getType_int32_ByName("response");
  1024. if(GetCurrentZone()){
  1025. Spawn* spawn = conversation_spawns[conversation_id];
  1026. Item* item = conversation_items[conversation_id];
  1027. if (conversation_map.count(conversation_id) > 0 && conversation_map[conversation_id].count(response_index) > 0) {
  1028. if (spawn)
  1029. GetCurrentZone()->CallSpawnScript(spawn, SPAWN_SCRIPT_CONVERSATION, player, conversation_map[conversation_id][response_index].c_str());
  1030. else if (item && lua_interface && item->GetItemScript())
  1031. lua_interface->RunItemScript(item->GetItemScript(), conversation_map[conversation_id][response_index].c_str(), item, player);
  1032. }
  1033. else
  1034. CloseDialog(conversation_id);
  1035. }
  1036. safe_delete(packet);
  1037. }
  1038. break;
  1039. }
  1040. case OP_PositionMoveableObject:{
  1041. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_PositionMoveableObject", opcode, opcode);
  1042. PacketStruct* place_object=configReader.getStruct("WS_PlaceMoveableObject",GetVersion());
  1043. if(place_object && place_object->LoadPacketData(app->pBuffer, app->size)){
  1044. Spawn* spawn = GetPlayer()->GetSpawnWithPlayerID(place_object->getType_int32_ByName("spawn_id"));
  1045. if(!spawn){
  1046. SimpleMessage(CHANNEL_COLOR_YELLOW, "Unable to find spawn.");
  1047. break;
  1048. }
  1049. spawn->SetX(place_object->getType_float_ByName("x"));
  1050. spawn->SetY(place_object->getType_float_ByName("y"));
  1051. spawn->SetZ(place_object->getType_float_ByName("z"));
  1052. spawn->SetHeading(place_object->getType_float_ByName("heading") + 180);
  1053. spawn->SetSpawnOrigX(spawn->GetX());
  1054. spawn->SetSpawnOrigY(spawn->GetY());
  1055. spawn->SetSpawnOrigZ(spawn->GetZ());
  1056. spawn->SetSpawnOrigHeading(spawn->GetHeading());
  1057. if(spawn->GetSpawnLocationID() > 0 && database.UpdateSpawnLocationSpawns(spawn))
  1058. SimpleMessage(CHANNEL_COLOR_YELLOW, "Successfully saved spawn information.");
  1059. else if(spawn->GetSpawnLocationID() > 0)
  1060. SimpleMessage(CHANNEL_COLOR_YELLOW, "Error saving spawn information, see console window for details.");
  1061. safe_delete(place_object);
  1062. }
  1063. break;
  1064. }
  1065. case OP_CampAbortedMsg:{
  1066. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_CampAbortedMsg", opcode, opcode);
  1067. if(camp_timer)
  1068. {
  1069. // JA: clear camping flag
  1070. if( (player->GetActivityStatus() & ACTIVITY_STATUS_CAMPING) > 0 )
  1071. player->SetActivityStatus(player->GetActivityStatus() - ACTIVITY_STATUS_CAMPING);
  1072. safe_delete(camp_timer);
  1073. EQ2Packet* outapp = new EQ2Packet(OP_CampAbortedMsg, 0, 0);
  1074. QueuePacket(outapp);
  1075. }
  1076. break;
  1077. }
  1078. case OP_DoneLoadingZoneResourcesMsg:{
  1079. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_DoneLoadingZoneResourcesMsg", opcode, opcode);
  1080. SendZoneSpawns();
  1081. break;
  1082. }
  1083. case OP_DefaultGroupOptionsRequestMsg:{
  1084. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_DefaultGroupOptionsRequestMsg", opcode, opcode);
  1085. SendDefaultGroupOptions();
  1086. break;
  1087. }
  1088. case OP_DoneLoadingEntityResourcesMsg:{
  1089. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_DoneLoadingEntityResourcesMsg", opcode, opcode);
  1090. if(!IsReadyForSpawns())
  1091. SetReadyForSpawns(true);
  1092. SendCharInfo();
  1093. pos_update.Start();
  1094. quest_pos_timer.Start();
  1095. break;
  1096. }
  1097. case OP_LootItemsRequestMsg:{
  1098. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_LootItemsRequestMsg", opcode, opcode);
  1099. HandleLoot(app);
  1100. break;
  1101. }
  1102. case OP_KnowledgeWindowSlotMappingMsg:{
  1103. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_KnowledgeWindowSlotMappingMsg", opcode, opcode);
  1104. PacketStruct* packet = configReader.getStruct("WS_SpellSlotMapping", GetVersion());
  1105. if(packet){
  1106. if(packet->LoadPacketData(app->pBuffer, app->size)){
  1107. int num_updates = packet->getType_int16_ByName("spell_count");
  1108. int32 spell_id = 0;
  1109. int16 slot_id = 0;
  1110. char tmp_spell_id[15];
  1111. char tmp_slot[15];
  1112. for(int i=0;i<num_updates;i++){
  1113. memset(tmp_spell_id, 0, 15);
  1114. memset(tmp_slot, 0, 15);
  1115. sprintf(tmp_spell_id, "spell_id_%i", i);
  1116. sprintf(tmp_slot, "slot_id_%i", i);
  1117. spell_id = packet->getType_int32_ByName(tmp_spell_id);
  1118. if(spell_id > 0){
  1119. slot_id = packet->getType_int16_ByName(tmp_slot);
  1120. SpellBookEntry* spell = player->GetSpellBookSpell(spell_id);
  1121. if(spell && spell->slot != slot_id){
  1122. spell->slot = slot_id;
  1123. spell->save_needed = true;
  1124. }
  1125. }
  1126. }
  1127. }
  1128. safe_delete(packet);
  1129. }
  1130. //SendKnowledgeWindowSlot();
  1131. break;
  1132. }
  1133. case OP_ReadyToZoneMsg:{
  1134. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_ReadyToZoneMsg", opcode, opcode);
  1135. if(client_zoning)
  1136. LogWrite(WORLD__INFO, 0, "World", "OP_ReadyToZone: Player %s zoning to %s", player->GetName(), GetCurrentZone()->GetZoneName());
  1137. else
  1138. LogWrite(WORLD__ERROR, 0, "World", "OP_ReadyToZone: Player %s attempting to zone without server authorization.", player->GetName());
  1139. Disconnect();
  1140. break;
  1141. }
  1142. case OP_ClientFellMsg:{
  1143. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_ClientFellMsg (ouch!)", opcode, opcode);
  1144. PacketStruct* request = configReader.getStruct("WS_ClientFell", GetVersion());
  1145. if(request && request->LoadPacketData(app->pBuffer, app->size)){
  1146. float height = request->getType_float_ByName("height");
  1147. /*int32 spawn_id = request->getType_int32_ByName("spawn_id");
  1148. if(GetPlayer()->GetSpawnWithPlayerID(spawn_id) != GetPlayer()){
  1149. cout << "Error: " << GetPlayer()->GetName() << " called ClientFell with an invalid ID of: " << spawn_id << endl;
  1150. break;
  1151. }*/
  1152. float safe_height = 13.0f;
  1153. Skill* skill = GetPlayer()->GetSkillByName("Safe Fall", true);
  1154. if(skill)
  1155. safe_height += (skill->current_val + 1)/5;
  1156. if (height > safe_height) {
  1157. int16 damage = (int16)ceil((height-safe_height)*125);
  1158. if(height >= 80)
  1159. damage = 30000;
  1160. //cout << "Detected fall height:" << height << " damage:" << damage << endl;
  1161. if (damage > 0){
  1162. GetPlayer()->TakeDamage(damage);
  1163. if (GetPlayer()->GetPlayerStatisticValue(STAT_PLAYER_HIGHEST_FALLING_HIT) < damage)
  1164. GetPlayer()->UpdatePlayerStatistic(STAT_PLAYER_HIGHEST_FALLING_HIT, damage, true);
  1165. if(!GetPlayer()->GetInvulnerable())
  1166. GetPlayer()->SetCharSheetChanged(true);
  1167. GetCurrentZone()->SendDamagePacket(0, GetPlayer(), DAMAGE_PACKET_TYPE_SIMPLE_DAMAGE, GetPlayer()->GetInvulnerable() ? DAMAGE_PACKET_RESULT_INVULNERABLE : DAMAGE_PACKET_RESULT_SUCCESSFUL, DAMAGE_PACKET_DAMAGE_TYPE_FALLING, damage, 0);
  1168. if(GetPlayer()->GetHP() == 0) {
  1169. GetCurrentZone()->KillSpawn(GetPlayer(), 0);
  1170. }
  1171. }
  1172. }
  1173. safe_delete(request);
  1174. }
  1175. break;
  1176. }
  1177. case OP_MapFogDataUpdateMsg:{
  1178. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_MapFogDataUpdateMsg", opcode, opcode);
  1179. LogWrite(MISC__TODO, 3, "TODO", "Handle (OP_MapFogDataUpdateMsg), ignoring it for now\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
  1180. break;
  1181. }
  1182. case OP_SelectZoneTeleporterDestinatio:{
  1183. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_SelectZoneTeleporterDestinatio", opcode, opcode);
  1184. ProcessTeleportLocation(app);
  1185. break;
  1186. }
  1187. case OP_SendLatestRequestMsg:{
  1188. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_SendLatestRequestMsg", opcode, opcode);
  1189. uchar blah25[] = {0x01};
  1190. EQ2Packet* app25 = new EQ2Packet(OP_ClearDataMsg, blah25, sizeof(blah25));
  1191. QueuePacket(app25);
  1192. break;
  1193. }
  1194. case OP_ShowCreateFromRecipeUIMsg:{
  1195. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_ShowCreateFromRecipeUIMsg", opcode, opcode);
  1196. break;
  1197. /*uchar blah[] ={0x09,0x0e,0x00,0x51,0x75,0x65,0x65,0x6e,0x27,0x73,0x20,0x43,0x6f,0x6c,0x6f,0x6e
  1198. ,0x79,0x00,0x00,0x00,0x00,0x40,0x40,0xff,0xff,0xff};
  1199. EQ2Packet* app = new EQ2Packet(OP_EncounterBrokenMsg, blah, sizeof(blah));
  1200. QueuePacket(app);
  1201. uchar blah2[] = {0x00,0x00,0xff,0xff,0xff,0xff};
  1202. app = new EQ2Packet(OP_CreateCharFromCBBRequestMsg, blah2, sizeof(blah2));
  1203. QueuePacket(app);
  1204. uchar blah3[] ={0x09,0x17,0x00,0x5c,0x23,0x46,0x46,0x45,0x34,0x30,0x30,0x20,0x51,0x75,0x65,0x65
  1205. ,0x6e,0x27,0x73,0x20,0x43,0x6f,0x6c,0x6f,0x6e,0x79,0x00,0x00,0x00,0x00,0xa0,0x40
  1206. ,0xff,0xff,0xff};
  1207. app = new EQ2Packet(OP_CreateCharFromCBBRequestMsg, blah3, sizeof(blah3));
  1208. QueuePacket(app);
  1209. uchar blah4[] ={0x0b,0x00,0x21,0x00,0x00,0x00,0x1d,0x81,0x42,0x17,0x81,0x42,0x17,0x81,0x42,0x17
  1210. ,0x81,0x42,0x17,0x81,0x42,0x17,0x81,0x42,0x17,0x81,0x42,0x17,0x81,0x42,0x17,0x81
  1211. ,0x42,0x17,0x81,0x42,0x17,0x81,0x42};
  1212. app = new EQ2Packet(OP_UpdateSpellBookMsg, blah4, sizeof(blah4));
  1213. QueuePacket(app);
  1214. uchar blah5[] ={0x00,0x00};
  1215. app = new EQ2Packet(OP_RecipeDetailsMsg, blah5, sizeof(blah5));
  1216. QueuePacket(app);
  1217. break;*/
  1218. //player->GetPlayerInfo()->GetInfo()->cur_power = 100;
  1219. //EQ2Packet* app = player->GetPlayerInfo()->serialize(1);
  1220. //QueuePacket(app);
  1221. }
  1222. case OP_BeginItemCreationMsg: {
  1223. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_BeginItemCreationMsg", opcode, opcode);
  1224. //DumpPacket(app->pBuffer, app->size);
  1225. PacketStruct* packet = configReader.getStruct("WS_BeginItemCreation", GetVersion());
  1226. if (packet) {
  1227. packet->LoadPacketData(app->pBuffer, app->size);
  1228. int32 item = 0;
  1229. vector<int32> items;
  1230. char tmp_item_id[20];
  1231. item = packet->getType_int32_ByName("primary_component_id");
  1232. if (item > 0)
  1233. items.push_back(item);
  1234. item = 0;
  1235. int8 build_components = packet->getType_int8_ByName("num_build_components");
  1236. for (int8 i = 0; i < build_components; i++) {
  1237. memset(tmp_item_id, 0, 20);
  1238. sprintf(tmp_item_id, "component_id_%i", i);
  1239. item = packet->getType_int32_ByName(tmp_item_id);
  1240. if (item > 0)
  1241. items.push_back(item);
  1242. item = 0;
  1243. }
  1244. item = packet->getType_int32_ByName("fuel_id");
  1245. if (item > 0)
  1246. items.push_back(item);
  1247. GetCurrentZone()->GetTradeskillMgr()->BeginCrafting(this, items);
  1248. safe_delete(packet);
  1249. }
  1250. break;
  1251. }
  1252. case OP_StopItemCreationMsg: {
  1253. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_StopItemCreationMsg", opcode, opcode);
  1254. //DumpPacket(app->pBuffer, app->size);
  1255. GetCurrentZone()->GetTradeskillMgr()->StopCrafting(this);
  1256. break;
  1257. }
  1258. //case OP_SignalMsg:{
  1259. // LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_SignalMsg", opcode, opcode);
  1260. // //if(app->size == 25 && app->pBuffer[0] == 0x17 && app->pBuffer[24] == 0x79)
  1261. // // GetPlayer()->ModifySpellStatus(0, 66, true);
  1262. // if(connected && player->GetHP() == 0)
  1263. // DisplayDeadWindow();
  1264. // break;
  1265. // }
  1266. case OP_EntityVerbsRequestMsg:{
  1267. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_EntityVerbsRequestMsg", opcode, opcode);
  1268. HandleVerbRequest(app);
  1269. break;
  1270. }
  1271. case OP_EntityVerbsVerbMsg:{
  1272. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_EntityVerbsVerbMsg", opcode, opcode);
  1273. PacketStruct* packet = configReader.getStruct("WS_EntityVerbsVerb", GetVersion());
  1274. if(packet){
  1275. packet->LoadPacketData(app->pBuffer, app->size);
  1276. int32 spawn_id = packet->getType_int32_ByName("spawn_id");
  1277. player->SetTarget(player->GetSpawnWithPlayerID(spawn_id));
  1278. Spawn* spawn = player->GetTarget();
  1279. if (spawn && !spawn->IsNPC() && !spawn->IsPlayer()){
  1280. string command = packet->getType_EQ2_16BitString_ByName("command").data;
  1281. if (EntityCommandPrecheck(spawn, command.c_str())){
  1282. if (spawn->IsGroundSpawn())
  1283. ((GroundSpawn*)spawn)->HandleUse(this, command);
  1284. else if (spawn->IsObject())
  1285. ((Object*)spawn)->HandleUse(this, command);
  1286. else if (spawn->IsWidget())
  1287. ((Widget*)spawn)->HandleUse(this, command);
  1288. else if (spawn->IsSign())
  1289. ((Sign*)spawn)->HandleUse(this, command);
  1290. }
  1291. }
  1292. else{
  1293. EQ2_16BitString command = packet->getType_EQ2_16BitString_ByName("command");
  1294. if(command.size > 0){
  1295. string command_name = command.data;
  1296. if(command_name.find(" ") < 0xFFFFFFFF)
  1297. command_name = command_name.substr(0, command_name.find(" "));
  1298. int32 handler = commands.GetCommandHandler(command_name.c_str());
  1299. if(handler != 0xFFFFFFFF){
  1300. if(command.data == command_name){
  1301. command.data = "";
  1302. command.size = 0;
  1303. }
  1304. else{
  1305. command.data = command.data.substr(command.data.find(" ")+1);
  1306. command.size = command.data.length();
  1307. }
  1308. commands.Process(handler, &command, this);
  1309. }
  1310. else{
  1311. if(spawn && spawn->IsNPC()){
  1312. if (EntityCommandPrecheck(spawn, command.data.c_str())){
  1313. if (!((NPC*)spawn)->HandleUse(this, command.data)){
  1314. LogWrite(WORLD__ERROR, 0, "World", "Unhandled command in OP_EntityVerbsVerbMsg: %s", command.data.c_str());
  1315. }
  1316. }
  1317. }
  1318. else
  1319. LogWrite(WORLD__ERROR, 0, "World", "Unknown command in OP_EntityVerbsVerbMsg: %s", command.data.c_str());
  1320. }
  1321. }
  1322. }
  1323. safe_delete(packet);
  1324. }
  1325. break;
  1326. }
  1327. case OP_SkillInfoRequest:{
  1328. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_SkillInfoRequest", opcode, opcode);
  1329. HandleSkillInfoRequest(app);
  1330. break;
  1331. }
  1332. case OP_UpdateTargetMsg:{
  1333. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_UpdateTargetMsg", opcode, opcode);
  1334. int16 index = 0;
  1335. memcpy(&index, app->pBuffer, sizeof(int16));
  1336. if (index == 0xFFFF)
  1337. GetPlayer()->SetTarget(0);
  1338. else
  1339. GetPlayer()->SetTarget(GetPlayer()->GetSpawnByIndex(index));
  1340. if(GetPlayer()->GetTarget())
  1341. GetCurrentZone()->CallSpawnScript(GetPlayer()->GetTarget(), SPAWN_SCRIPT_TARGETED, GetPlayer());
  1342. //player->SetTarget((int16*)app->pBuffer);
  1343. break;
  1344. }
  1345. case OP_ExamineInfoRequestMsg:{
  1346. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_ExamineInfoRequestMsg", opcode, opcode);
  1347. HandleExamineInfoRequest(app);
  1348. break;
  1349. }
  1350. case OP_QuickbarUpdateMsg:
  1351. //case OP_QuickbarAddMsg:
  1352. {
  1353. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_QuickbarUpdateMsg, OP_QuickbarAddMsg", opcode, opcode);
  1354. HandleQuickbarUpdateRequest(app);
  1355. break;
  1356. }
  1357. case OP_PredictionUpdateMsg:{
  1358. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_PredictionUpdateMsg", opcode, opcode);
  1359. EQ2Packet* app = new EQ2Packet(OP_PredictionUpdateMsg, 0, 0);
  1360. QueuePacket(app);
  1361. break;
  1362. }
  1363. case OP_RemoteCmdMsg:{
  1364. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_RemoteCmdMsg", opcode, opcode);
  1365. if(app->size > 0){
  1366. EQ2_CommandString remote(app->pBuffer, app->size);
  1367. LogWrite(PACKET__DEBUG, 1, "Packet", "RemoteCmdMsg Packet dump:");
  1368. #if EQDEBUG >= 9
  1369. DumpPacket(app);
  1370. #endif
  1371. commands.Process(remote.handler, &remote.command, this);
  1372. }
  1373. else //bad client, disconnect
  1374. Disconnect();
  1375. break;
  1376. }
  1377. case OP_CancelSpellCast:{
  1378. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_CancelSpellCast", opcode, opcode);
  1379. current_zone->Interrupted(player, 0, 0, true);
  1380. SimpleMessage(CHANNEL_COLOR_SPELL_INTERRUPT, "You stop casting.");
  1381. break;
  1382. }
  1383. case OP_UpdatePositionMsg:{
  1384. LogWrite(OPCODE__DEBUG, 7, "Opcode", "Opcode 0x%X (%i): OP_UpdatePositionMsg", opcode, opcode);
  1385. int8 offset = 13;
  1386. if(app->pBuffer[0]==0xFF)
  1387. offset +=2;
  1388. if (app->size>offset) {
  1389. if(player->IsCasting()){
  1390. float distance = 0;
  1391. float x = player->GetX();
  1392. float y = player->GetY();
  1393. float z = player->GetZ();
  1394. player->PrepareIncomingMovementPacket(app->size - offset, app->pBuffer + offset, version);
  1395. distance = player->GetDistance(x, y, z, false);
  1396. if (distance > .5)
  1397. current_zone->Interrupted(player, 0, SPELL_ERROR_INTERRUPTED, false, true);
  1398. }
  1399. else
  1400. player->PrepareIncomingMovementPacket(app->size - offset, app->pBuffer + offset, version);
  1401. player_pos_changed = true;
  1402. LogWrite(CCLIENT__PACKET, 0, "Client", "Dump/Print Packet in func: %s, line: %i", __FUNCTION__, __LINE__);
  1403. //DumpPacket(app);
  1404. }
  1405. break;
  1406. }
  1407. case OP_MailSendMessageMsg: {
  1408. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_MailSendMessageMsg", opcode, opcode);
  1409. HandleSentMail(app);
  1410. break;
  1411. }
  1412. case OP_StopTrackingMsg: {
  1413. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_StopTrackingMsg", opcode, opcode);
  1414. player->GetZone()->RemovePlayerTracking(player, TRACKING_STOP);
  1415. break;
  1416. }
  1417. case OP_BeginTrackingMsg: {
  1418. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_BeginTrackingMsg", opcode, opcode);
  1419. PacketStruct* packet = configReader.getStruct("WS_BeginTracking", GetVersion());
  1420. if (packet) {
  1421. packet->LoadPacketData(app->pBuffer, app->size);
  1422. int32 spawn_id = packet->getType_int32_ByName("spawn_id");
  1423. Spawn* spawn = player->GetSpawnWithPlayerID(spawn_id);
  1424. if (spawn) {
  1425. AddWaypoint(spawn->GetName(), WAYPOINT_CATEGORY_TRACKING, spawn_id);
  1426. BeginWaypoint(spawn->GetName(), spawn->GetX(), spawn->GetY(), spawn->GetZ());
  1427. player->GetZone()->RemovePlayerTracking(player, TRACKING_CLOSE_WINDOW);
  1428. }
  1429. safe_delete(packet);
  1430. }
  1431. break;
  1432. }
  1433. case OP_BioUpdateMsg: {
  1434. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_BioUpdateMsg", opcode, opcode);
  1435. PacketStruct* packet = configReader.getStruct("WS_BioUpdate", GetVersion());
  1436. if (packet) {
  1437. packet->LoadPacketData(app->pBuffer, app->size);
  1438. player->SetBiography(packet->getType_EQ2_16BitString_ByName("biography").data);
  1439. safe_delete(packet);
  1440. }
  1441. break;
  1442. }
  1443. case OP_RewardPackMsg: {
  1444. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_RewardPackMsg", opcode, opcode);
  1445. /* This logging is still here because I remember another system using this packet and just want to make sure we can figure out that it's being sent
  1446. when we come across it (scatman) */
  1447. const char* name = app->GetOpcodeName();
  1448. if(name)
  1449. LogWrite(WORLD__DEBUG, 0, "World", "%s Received OP_RewardPackMsg %04i", name, app->GetRawOpcode());
  1450. else
  1451. LogWrite(WORLD__DEBUG, 0, "World", "Received OP_RewardPackMsg %04i", app->GetRawOpcode());
  1452. //DumpPacket(app);
  1453. PacketStruct* packet = configReader.getStruct("WS_RewardPackMsg", GetVersion());
  1454. if (packet) {
  1455. packet->LoadPacketData(app->pBuffer, app->size);
  1456. string recruiter_name = packet->getType_EQ2_16BitString_ByName("recruiter_name").data;
  1457. /* Player has contacted a guild recruiter */
  1458. if (recruiter_name.length() > 0) {
  1459. Guild* guild = guild_list.GetGuild(packet->getType_int32_ByName("guild_id"));
  1460. Client* recruiter = zone_list.GetClientByCharName(recruiter_name);
  1461. if (recruiter && guild) {
  1462. Message(CHANNEL_COLOR_GUILD_EVENT, "Contact request sent to %s of %s.", recruiter->GetPlayer()->GetName(), guild->GetName());
  1463. recruiter->Message(CHANNEL_COLOR_GUILD_EVENT, "%s [%u %s], [0 Unskilled] (%s) is requesting to speak to YOU about joining the guild.", player->GetName(), player->GetLevel(), classes.GetClassNameCase(player->GetAdventureClass()).c_str(), races.GetRaceNameCase(player->GetRace()));
  1464. recruiter->PlaySound("ui_guild_page");
  1465. }
  1466. }
  1467. /* New picture taken for guild recruiting */
  1468. else {
  1469. //DumpPacket(app->pBuffer, app->size);
  1470. int32 guild_id = 0;
  1471. int16 picture_data_size = 0;
  1472. unsigned char* recruiter_picture_data = 0;
  1473. memcpy(&guild_id, app->pBuffer + 4, sizeof(int32));
  1474. memcpy(&picture_data_size, app->pBuffer + 15, sizeof(int16));
  1475. Guild* guild = guild_list.GetGuild(guild_id);
  1476. if (guild) {
  1477. GuildMember* gm = guild->GetGuildMember(player);
  1478. if (gm) {
  1479. safe_delete_array(gm->recruiter_picture_data);
  1480. recruiter_picture_data = new unsigned char[picture_data_size];
  1481. for (int16 i = 0; i < picture_data_size; i++)
  1482. memcpy(recruiter_picture_data + i, app->pBuffer + 17 + i, 2);
  1483. gm->recruiter_picture_data = recruiter_picture_data;
  1484. gm->recruiter_picture_data_size = picture_data_size;
  1485. guild->SetMemberSaveNeeded(true);
  1486. }
  1487. }
  1488. }
  1489. safe_delete(packet);
  1490. }
  1491. break;
  1492. }
  1493. case OP_PetOptions: {
  1494. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_PetOptions", opcode, opcode);
  1495. Spawn* target = player->GetTarget();
  1496. PacketStruct* packet = configReader.getStruct("WS_PetOptions", GetVersion());
  1497. if (packet && target && (target == player->GetPet() || target == player->GetCharmedPet() || target == player->GetDeityPet() || target == player->GetCosmeticPet())) {
  1498. bool change = false;
  1499. packet->LoadPacketData(app->pBuffer, app->size);
  1500. string name = packet->getType_EQ2_16BitString_ByName("pet_name").data;
  1501. if (strlen(name.c_str()) != 0) {
  1502. target->SetName(name.c_str());
  1503. strcpy(player->GetInfoStruct()->pet_name, name.c_str());
  1504. GetCurrentZone()->SendUpdateTitles(target);
  1505. change = true;
  1506. }
  1507. // Check protect self setting and update if needed
  1508. if (packet->getType_int8_ByName("protect_self") == 1) {
  1509. if ((player->GetInfoStruct()->pet_behavior & 2) == 0) {
  1510. player->GetInfoStruct()->pet_behavior += 2;
  1511. change = true;
  1512. }
  1513. }
  1514. else {
  1515. if ((player->GetInfoStruct()->pet_behavior & 2) != 0) {
  1516. player->GetInfoStruct()->pet_behavior -= 2;
  1517. change = true;
  1518. }
  1519. }
  1520. // Check protect master setting and update if needed
  1521. if (packet->getType_int8_ByName("protect_master") == 1) {
  1522. if ((player->GetInfoStruct()->pet_behavior & 1) == 0) {
  1523. player->GetInfoStruct()->pet_behavior += 1;
  1524. change = true;
  1525. }
  1526. }
  1527. else {
  1528. if ((player->GetInfoStruct()->pet_behavior & 1) != 0) {
  1529. player->GetInfoStruct()->pet_behavior -= 1;
  1530. change = true;
  1531. }
  1532. }
  1533. // Check stay/follow setting and update if needed
  1534. if (packet->getType_int8_ByName("stay_follow_toggle") == 1) {
  1535. if (player->GetInfoStruct()->pet_movement != 2) {
  1536. player->GetInfoStruct()->pet_movement = 2;
  1537. change = true;
  1538. }
  1539. }
  1540. else {
  1541. if (player->GetInfoStruct()->pet_movement != 1) {
  1542. player->GetInfoStruct()->pet_movement = 1;
  1543. change = true;
  1544. }
  1545. }
  1546. // Ranged/Melee settings are not implemented yet
  1547. if (change)
  1548. player->SetCharSheetChanged(true);
  1549. safe_delete(packet);
  1550. }
  1551. break;
  1552. }
  1553. case OP_RecipeBook:{
  1554. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_RecipeBook", opcode, opcode);
  1555. SendRecipeList();
  1556. break;
  1557. }
  1558. case OP_BuyPlayerHouseMsg: {
  1559. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_BuyPlayerHouseMsg", opcode, opcode);
  1560. DumpPacket(app);
  1561. PacketStruct* packet = configReader.getStruct("WS_BuyHouse", GetVersion());
  1562. if (packet) {
  1563. packet->LoadPacketData(app->pBuffer, app->size);
  1564. HouseZone* hz = world.GetHouseZone(packet->getType_int64_ByName("house_id"));
  1565. if (hz) {
  1566. ZoneServer* instance_zone = zone_list.GetByInstanceID(0,hz->zone_id);
  1567. int32 upkeep_due = Timer::GetUnixTimeStamp() + 604800; // 604800 = 7 days
  1568. int64 unique_id = database.AddPlayerHouse(GetPlayer()->GetCharacterID(), hz->id, instance_zone->GetInstanceID(), upkeep_due);
  1569. world.AddPlayerHouse(GetPlayer()->GetCharacterID(), hz->id, unique_id, instance_zone->GetInstanceID(), upkeep_due, 0, 0, GetPlayer()->GetName());
  1570. }
  1571. }
  1572. safe_delete(packet);
  1573. break;
  1574. }
  1575. case OP_EnterHouseMsg: {
  1576. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_EnterHouseMsg", opcode, opcode);
  1577. DumpPacket(app);
  1578. PacketStruct* packet = configReader.getStruct("WS_EnterHouse", GetVersion());
  1579. if (packet) {
  1580. packet->LoadPacketData(app->pBuffer, app->size);
  1581. PlayerHouse* ph = world.GetPlayerHouseByUniqueID(packet->getType_int64_ByName("house_id"));
  1582. if (ph) {
  1583. HouseZone* hz = world.GetHouseZone(ph->house_id);
  1584. if (hz) {
  1585. ZoneServer* house = zone_list.GetByInstanceID(ph->instance_id, hz->zone_id);
  1586. if (house) {
  1587. Zone(house, true);
  1588. }
  1589. }
  1590. }
  1591. }
  1592. safe_delete(packet);
  1593. break;
  1594. }
  1595. case OP_PayHouseUpkeepMsg: {
  1596. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_PayHouseUpkeepMsg", opcode, opcode);
  1597. DumpPacket(app);
  1598. PacketStruct* packet = configReader.getStruct("WS_PayUpkeep", GetVersion());
  1599. if (packet) {
  1600. packet->LoadPacketData(app->pBuffer, app->size);
  1601. }
  1602. safe_delete(packet);
  1603. break;
  1604. }
  1605. case OP_ExitHouseMsg: {
  1606. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_ExitHouseMsg", opcode, opcode);
  1607. int32 instance_id = GetCurrentZone()->GetInstanceID();
  1608. if (instance_id > 0) {
  1609. PlayerHouse* ph = world.GetPlayerHouseByInstanceID(instance_id);
  1610. if (ph) {
  1611. HouseZone* hz = world.GetHouseZone(ph->house_id);
  1612. if (hz) {
  1613. ZoneServer* new_zone = zone_list.Get(hz->exit_zone_id);
  1614. // determine if this is an instanced zone that already exists
  1615. ZoneServer* instance_zone = GetPlayer()->GetGroupMemberInZone(hz->exit_zone_id);
  1616. if(instance_zone || new_zone){
  1617. GetPlayer()->SetX(hz->exit_x);
  1618. GetPlayer()->SetY(hz->exit_y);
  1619. GetPlayer()->SetZ(hz->exit_z);
  1620. GetPlayer()->SetHeading(hz->exit_heading);
  1621. if ( instance_zone )
  1622. Zone(instance_zone->GetInstanceID(),false,true);
  1623. else
  1624. Zone(new_zone, false);
  1625. }
  1626. }
  1627. }
  1628. }
  1629. DumpPacket(app);
  1630. break;
  1631. }
  1632. case OP_QuestJournalWaypointMsg: {
  1633. //DumpPacket(app);
  1634. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_QuestJournalWaypointMsg", opcode, opcode);
  1635. PacketStruct* packet = configReader.getStruct("WS_QuestJournalWaypoint", GetVersion());
  1636. if (packet) {
  1637. packet->LoadPacketData(app->pBuffer, app->size);
  1638. int32 quests = packet->getType_int32_ByName("num_quests");
  1639. if( quests > 100 ) // just picking a number higher than max allowed
  1640. {
  1641. LogWrite(CCLIENT__ERROR, 0, "Client", "num_quests = %u - quantity too high, aborting load.", quests);
  1642. break;
  1643. }
  1644. LogWrite(CCLIENT__DEBUG, 0, "Client", "num_quests = %u", quests);
  1645. for (int32 i = 0; i < quests; i++) {
  1646. int32 id = packet->getType_int32_ByName("quest_id_0", i);
  1647. if( id == 0 )
  1648. continue;
  1649. LogWrite(CCLIENT__DEBUG, 5, "Client", "quest_id = %u", id);
  1650. bool tracked = packet->getType_int8_ByName("quest_tracked_0", i) == 1 ? true : false;
  1651. if (player->player_quests.count(id) > 0) {
  1652. player->player_quests[id]->SetTracked(tracked);
  1653. player->player_quests[id]->SetSaveNeeded(true);
  1654. }
  1655. }
  1656. safe_delete(packet);
  1657. }
  1658. break;
  1659. }
  1660. case OP_PaperdollImage: {
  1661. PacketStruct* packet = configReader.getStruct("WS_PaperdollImage", version);
  1662. if (packet && packet->LoadPacketData(app->pBuffer, app->size)) {
  1663. //First check if this is a new image... delete an existing partial image if one exists
  1664. int8 packet_index = packet->getType_int8_ByName("packetIndex");
  1665. if (packet_index == 0){
  1666. safe_delete_array(incoming_paperdoll.image_bytes);
  1667. incoming_paperdoll.last_received_packet_index = 0;
  1668. incoming_paperdoll.current_size_bytes = 0;
  1669. }
  1670. //return if this packet is not the one we are expecting...
  1671. else if (packet_index != incoming_paperdoll.last_received_packet_index + 1) {
  1672. safe_delete(packet);
  1673. break;
  1674. }
  1675. //Check how many packets we're supposed to be receiving for this/these images
  1676. incoming_paperdoll.image_num_packets = packet->getType_int8_ByName("totalNumPackets");
  1677. //Check the image type, if this is a new type in the same series of packets we have a new image
  1678. int8 img_type = packet->getType_int8_ByName("image_type");
  1679. if (packet_index != 0 && img_type != incoming_paperdoll.image_type){
  1680. //We have a new image. Save the old data and clear before continuing
  1681. SavePlayerImages();
  1682. }
  1683. incoming_paperdoll.image_type = img_type;
  1684. //Get the size of the image data in this packet
  1685. sint64 image_size = packet->getType_int32_ByName("imageSize");
  1686. if (image_size <= 0 || image_size > 1048576) {
  1687. //If this packet is saying that the array is size <= 0 or > 1 MiB return out... it shouldn't be those sizes ever
  1688. safe_delete(packet);
  1689. break;
  1690. }
  1691. //Create a new array
  1692. int32 new_image_size = image_size;
  1693. uchar* new_image = new uchar[incoming_paperdoll.current_size_bytes + new_image_size];
  1694. if (incoming_paperdoll.image_bytes){
  1695. memcpy(new_image, incoming_paperdoll.image_bytes, incoming_paperdoll.current_size_bytes);
  1696. safe_delete_array(incoming_paperdoll.image_bytes);
  1697. }
  1698. //variable i should be the index in the packet of the first PNG file byte
  1699. vector<DataStruct*>* d_structs = packet->getStructs();
  1700. vector<DataStruct*>::iterator itr;
  1701. int32 i = 0;
  1702. for (itr = d_structs->begin(); itr != d_structs->end(); itr++){
  1703. DataStruct* ds = (*itr);
  1704. if (strcmp(ds->GetName(), "pngData_0") != 0)
  1705. i += ds->GetDataSizeInBytes();
  1706. else
  1707. break;
  1708. }
  1709. //Return if this packet is bad and we would read out of bounds
  1710. if (app->size - i < new_image_size) {
  1711. safe_delete(packet);
  1712. safe_delete_array(new_image);
  1713. break;
  1714. }
  1715. uchar* tmp = new_image + incoming_paperdoll.current_size_bytes;
  1716. memcpy(tmp, app->pBuffer + i, new_image_size);
  1717. incoming_paperdoll.current_size_bytes += new_image_size;
  1718. incoming_paperdoll.image_bytes = new_image;
  1719. //Check if this is the last packet we're expecting for this image. Create a final image if so
  1720. if (incoming_paperdoll.image_num_packets == 1 ||
  1721. incoming_paperdoll.last_received_packet_index + 2 == incoming_paperdoll.image_num_packets){
  1722. SavePlayerImages();
  1723. }
  1724. incoming_paperdoll.last_received_packet_index = packet_index;
  1725. }
  1726. safe_delete(packet);
  1727. break;
  1728. }
  1729. case OP_ReadyForTakeOffMsg:
  1730. {
  1731. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_ReadyForTakeOffMsg", opcode, opcode);
  1732. int32 index = GetCurrentZone()->GetFlightPathIndex(GetPendingFlightPath());
  1733. if (GetPendingFlightPath() > 0) {
  1734. if (index != -1) {
  1735. PacketStruct* packet = configReader.getStruct("WS_ClearForTakeOff", GetVersion());
  1736. if (packet) {
  1737. packet->setDataByName("spawn_id", GetPlayer()->GetIDWithPlayerSpawn(GetPlayer()));
  1738. packet->setDataByName("path_id", index);
  1739. packet->setDataByName("speed", GetCurrentZone()->GetFlightPathSpeed(GetPendingFlightPath()));
  1740. QueuePacket(packet->serialize());
  1741. safe_delete(packet);
  1742. on_auto_mount = true;
  1743. }
  1744. }
  1745. else {
  1746. LogWrite(CCLIENT__ERROR, 0, "Client", "OP_ReadyForTakeOffMsg recieved but unable to get an index for path (%u) in zone (%u)", GetPendingFlightPath(), GetCurrentZone()->GetZoneID());
  1747. Message(CHANNEL_ERROR, "Unable to get index for path (%u) in zone (%u)", GetPendingFlightPath(), GetCurrentZone()->GetZoneID());
  1748. EndAutoMount();
  1749. }
  1750. SetPendingFlightPath(0);
  1751. }
  1752. else
  1753. LogWrite(CCLIENT__ERROR, 0, "Client", "OP_ReadyForTakeOffMsg recieved but there is no pending flight path...");
  1754. break;
  1755. }
  1756. case OP_EarlyLandingRequestMsg:
  1757. {
  1758. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_EarlyLandingRequestMsg", opcode, opcode);
  1759. EndAutoMount();
  1760. break;
  1761. }
  1762. case OP_SubmitCharCust:
  1763. {
  1764. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): OP_SubmitCharCust", opcode, opcode);
  1765. PacketStruct* packet = configReader.getStruct("WS_SubmitCharCust", version);
  1766. if (packet && packet->LoadPacketData(app->pBuffer, app->size)) {
  1767. int8 type = packet->getType_int8_ByName("type");
  1768. if (type == 0) {
  1769. if (player->custNPC) {
  1770. player->custNPCTarget->CustomizeAppearance(packet);
  1771. current_zone->SendSpawnChanges(player->custNPCTarget);
  1772. }
  1773. else {
  1774. player->CustomizeAppearance(packet);
  1775. current_zone->SendSpawnChanges(player);
  1776. }
  1777. }
  1778. }
  1779. if (player->custNPC) {
  1780. memcpy(&player->appearance, &player->SavedApp, sizeof(AppearanceData));
  1781. memcpy(&player->features, &player->SavedFeatures, sizeof(CharFeatures));
  1782. if (player->custNPCTarget->IsBot())
  1783. database.SaveBotAppearance((Bot*)player->custNPCTarget);
  1784. player->custNPC = false;
  1785. player->custNPCTarget = 0;
  1786. player->changed = true;
  1787. player->info_changed = true;
  1788. current_zone->SendSpawnChanges(player, this);
  1789. }
  1790. break;
  1791. }
  1792. default:{
  1793. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Opcode 0x%X (%i): Unknown in %s", opcode, opcode, __FILE__);
  1794. const char* name = app->GetOpcodeName();
  1795. if(name)
  1796. LogWrite(OPCODE__DEBUG, 1, "Opcode", "%s Received %04X (%i)", name, app->GetRawOpcode(), app->GetRawOpcode());
  1797. else
  1798. LogWrite(OPCODE__DEBUG, 1, "Opcode", "Received %04X (%i)", app->GetRawOpcode(), app->GetRawOpcode());
  1799. //DumpPacket(app);
  1800. }
  1801. }
  1802. if (!eqs || !eqs->CheckActive()) {
  1803. return false;
  1804. }
  1805. return ret;
  1806. }
  1807. bool Client::HandleLootItem(Entity* entity, Item* item){
  1808. if(!item){
  1809. SimpleMessage(CHANNEL_COLOR_YELLOW, "Unable to find item to loot!");
  1810. return false;
  1811. }
  1812. if(player->item_list.HasFreeSlot() || player->item_list.CanStack(item)){
  1813. if(player->item_list.AssignItemToFreeSlot(item)){
  1814. int8 type = CHANNEL_COLOR_LOOT;
  1815. if(GetVersion() >= 973 && GetVersion() <= 1000)
  1816. type = CHANNEL_COLOR_NEW_LOOT;
  1817. else if(GetVersion() >= 973)
  1818. type = CHANNEL_COLOR_NEWEST_LOOT;
  1819. if(entity)
  1820. Message(type, "You loot \\aITEM %u 0:%s\\/a from the corpse of %s", item->details.item_id, item->name.c_str(), entity->GetName());
  1821. else
  1822. Message(type, "You found a \\aITEM %u 0:%s\\/a", item->details.item_id, item->name.c_str());
  1823. Guild* guild = player->GetGuild();
  1824. if (guild && item->details.tier >= ITEM_TAG_LEGENDARY) {
  1825. char adjective[32];
  1826. int8 type;
  1827. memset(adjective, 0, sizeof(adjective));
  1828. if (item->details.tier >= ITEM_TAG_MYTHICAL) {
  1829. strncpy(adjective, "Mythical", sizeof(adjective) - 1);
  1830. type = GUILD_EVENT_LOOTS_MYTHICAL_ITEM;
  1831. }
  1832. else if (item->details.tier >= ITEM_TAG_FABLED) {
  1833. strncpy(adjective, "Fabled", sizeof(adjective) - 1);
  1834. type = GUILD_EVENT_LOOTS_FABELED_ITEM;
  1835. }
  1836. else {
  1837. strncpy(adjective, "Legendary", sizeof(adjective) - 1);
  1838. type = GUILD_EVENT_LOOTS_LEGENDARY_ITEM;
  1839. }
  1840. guild->AddNewGuildEvent(type, "%s has looted the %s \\aITEM %u 0:%s\\/a", Timer::GetUnixTimeStamp(), true, player->GetName(), adjective, item->details.item_id, item->name.c_str());
  1841. guild->SendMessageToGuild(type, "%s has looted the %s \\aITEM %u 0:%s\\/a", player->GetName(), adjective, item->details.item_id, item->name.c_str());
  1842. }
  1843. CheckPlayerQuestsItemUpdate(item);
  1844. return true;
  1845. }
  1846. else
  1847. SimpleMessage(CHANNEL_COLOR_RED, "Could not find free slot to place item.");
  1848. }
  1849. else
  1850. SimpleMessage(CHANNEL_COLOR_YELLOW, "Unable to loot item: Inventory is FULL.");
  1851. return false;
  1852. }
  1853. bool Client::HandleLootItem(Entity* entity, int32 item_id){
  1854. if(!entity) {
  1855. return false;
  1856. }
  1857. return HandleLootItem(entity, entity->LootItem(item_id));
  1858. }
  1859. void Client::HandleLoot(EQApplicationPacket* app){
  1860. PacketStruct* packet = configReader.getStruct("WS_LootType", GetVersion());
  1861. if(packet){
  1862. packet->LoadPacketData(app->pBuffer, app->size);
  1863. int32 loot_id = packet->getType_int32_ByName("loot_id");
  1864. bool loot_all = (packet->getType_int8_ByName("loot_all") == 1);
  1865. safe_delete(packet);
  1866. int32 item_id = 0;
  1867. Item* item = 0;
  1868. Spawn* spawn = GetCurrentZone()->GetSpawnByID(loot_id);
  1869. if(player->HasPendingLootItems(loot_id)){
  1870. Item* master_item = 0;
  1871. if(loot_all){
  1872. vector<Item*>* items = player->GetPendingLootItems(loot_id);
  1873. if(items){
  1874. for(int32 i=0;loot_all && i<items->size();i++){
  1875. master_item = items->at(i);
  1876. if(master_item){
  1877. item = new Item(master_item);
  1878. if(item){
  1879. loot_all = HandleLootItem(0, item);
  1880. if(loot_all)
  1881. player->RemovePendingLootItem(loot_id, item->details.item_id);
  1882. }
  1883. }
  1884. }
  1885. safe_delete(items);
  1886. }
  1887. }
  1888. else{
  1889. packet = configReader.getStruct("WS_LootItem", GetVersion());
  1890. if(packet){
  1891. packet->LoadPacketData(app->pBuffer, app->size);
  1892. item_id = packet->getType_int32_ByName("item_id");
  1893. vector<Item*>* items = player->GetPendingLootItems(loot_id);
  1894. if(items){
  1895. for(int32 i=0;i<items->size();i++){
  1896. master_item = items->at(i);
  1897. if(master_item && master_item->details.item_id == item_id){
  1898. item = new Item(master_item);
  1899. if(item && HandleLootItem(0, item))
  1900. player->RemovePendingLootItem(loot_id, item->details.item_id);
  1901. break;
  1902. }
  1903. }
  1904. safe_delete(items);
  1905. }
  1906. safe_delete(packet);
  1907. }
  1908. }
  1909. EQ2Packet* outapp = player->SendInventoryUpdate(GetVersion());
  1910. if(outapp)
  1911. QueuePacket(outapp);
  1912. Loot(0, player->GetPendingLootItems(loot_id), (Entity*)spawn);
  1913. }
  1914. else{
  1915. if(spawn && !spawn->Alive() && spawn->IsNPC() && ((NPC*)spawn)->Brain()->CheckLootAllowed(player)){
  1916. if(loot_all){
  1917. while(loot_all && ((item_id = ((Entity*)spawn)->GetLootItemID()) > 0)){
  1918. loot_all = HandleLootItem((Entity*)spawn, item_id);
  1919. }
  1920. }
  1921. else{
  1922. packet = configReader.getStruct("WS_LootItem", GetVersion());
  1923. if(packet){
  1924. packet->LoadPacketData(app->pBuffer, app->size);
  1925. item_id = packet->getType_int32_ByName("item_id");
  1926. HandleLootItem((Entity*)spawn, item_id);
  1927. safe_delete(packet);
  1928. }
  1929. }
  1930. EQ2Packet* outapp = player->SendInventoryUpdate(GetVersion());
  1931. if(outapp)
  1932. QueuePacket(outapp);
  1933. Loot((Entity*)spawn);
  1934. if(!((Entity*)spawn)->HasLoot()){
  1935. CloseLoot();
  1936. if(((Entity*)spawn)->IsNPC())
  1937. GetCurrentZone()->RemoveDeadSpawn(spawn);
  1938. }
  1939. }
  1940. else{
  1941. if(!spawn){
  1942. LogWrite(WORLD__ERROR, 0, "World", "Unknown id of %u when looting!", loot_id);
  1943. SimpleMessage(CHANNEL_COLOR_YELLOW, "Unable to find spawn to loot!");
  1944. }
  1945. else
  1946. SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not unable to loot that at this time.");
  1947. }
  1948. }
  1949. }
  1950. }
  1951. void Client::HandleSkillInfoRequest(EQApplicationPacket* app){
  1952. PacketStruct* request = 0;
  1953. // cout << "Request: \n";
  1954. // DumpPacket(app);
  1955. switch(app->pBuffer[0]){
  1956. case 0:{ //items
  1957. request = configReader.getStruct("WS_SkillInfoItemRequest", GetVersion());
  1958. if(request){
  1959. request->LoadPacketData(app->pBuffer, app->size);
  1960. Item* item = GetPlayer()->GetEquipmentList()->GetItemFromUniqueID(request->getType_int32_ByName("unique_id"));
  1961. if(!item)
  1962. item = GetPlayer()->item_list.GetItemFromUniqueID(request->getType_int32_ByName("unique_id"), true);
  1963. if(item){
  1964. PacketStruct* response = configReader.getStruct("WS_SkillInfoItemResponse", GetVersion());
  1965. if(response){
  1966. response->setDataByName("request_type", request->getType_int32_ByName("request_type"));
  1967. response->setDataByName("unique_id", request->getType_int32_ByName("unique_id"));
  1968. response->setSmallStringByName("name", item->name.c_str());
  1969. EQ2Packet* app2 = response->serialize();
  1970. //DumpPacket(app2);
  1971. QueuePacket(app2);
  1972. safe_delete(response);
  1973. }
  1974. }
  1975. }
  1976. break;
  1977. }
  1978. case 2:{//spells
  1979. request = configReader.getStruct("WS_SkillInfoSpellRequest", GetVersion());
  1980. if(request){
  1981. request->LoadPacketData(app->pBuffer, app->size);
  1982. int32 id = request->getType_int32_ByName("id");
  1983. int8 tier = request->getType_int32_ByName("unique_id"); //on live this is really unique_id, but I'm going to make it tier instead :)
  1984. Spell* spell = master_spell_list.GetSpell(id, tier);
  1985. PacketStruct* response = configReader.getStruct("WS_SkillInfoResponse", GetVersion());
  1986. if(response){
  1987. response->setDataByName("request_type", 2);
  1988. response->setDataByName("unique_id", tier);
  1989. response->setDataByName("id", id);
  1990. if(spell)
  1991. response->setSmallStringByName("name", spell->GetName());
  1992. else
  1993. response->setSmallStringByName("name", "Unknown Spell");
  1994. EQ2Packet* app2 = response->serialize();
  1995. // DumpPacket(app2);
  1996. QueuePacket(app2);
  1997. safe_delete(response);
  1998. }
  1999. }
  2000. break;
  2001. }
  2002. default:{
  2003. LogWrite(WORLD__ERROR, 0, "World", "Unknown SkillInfoRequest type of %i", (int)app->pBuffer[0]);
  2004. }
  2005. }
  2006. safe_delete(request);
  2007. }
  2008. void Client::HandleExamineInfoRequest(EQApplicationPacket* app){
  2009. PacketStruct* request = 0;
  2010. //LogWrite(CCLIENT__DEBUG, 0, "Client", "Request2:");
  2011. //DumpPacket(app);
  2012. int8 type = app->pBuffer[0];
  2013. if(type == 3){
  2014. Spell* spell = 0;
  2015. bool trait_display;
  2016. request = configReader.getStruct("WS_ExamineInfoRequest", GetVersion());
  2017. if(!request) {
  2018. return;
  2019. }
  2020. request->LoadPacketData(app->pBuffer, app->size);
  2021. int32 id = request->getType_int32_ByName("id");
  2022. int32 tier = request->getType_int32_ByName("tier");
  2023. int32 trait_tier = request->getType_int32_ByName("unknown_id");
  2024. //printf("Type: (%i) Tier: (%u) Unknown ID: (%u) Item ID: (%u)\n",type,tier,trait_tier,id);
  2025. if (trait_tier != 0xFFFFFFFF){
  2026. spell = master_spell_list.GetSpell(id, trait_tier);
  2027. if (!spell) {
  2028. spell = master_spell_list.GetSpell(id, trait_tier +1);
  2029. }
  2030. trait_display = true;
  2031. }
  2032. else{
  2033. spell = master_spell_list.GetSpell(id, tier );
  2034. trait_display = false;
  2035. }
  2036. if(spell && sent_spell_details.count(id) == 0){
  2037. sent_spell_details[id] = true;
  2038. EQ2Packet* app = spell->SerializeSpell(this, false, trait_display);
  2039. //DumpPacket(app);
  2040. QueuePacket(app);
  2041. }
  2042. }
  2043. else if(type == 0){
  2044. request = configReader.getStruct("WS_ExamineInfoItemRequest", GetVersion());
  2045. if(!request) {
  2046. return;
  2047. }
  2048. request->LoadPacketData(app->pBuffer, app->size);
  2049. int32 id = request->getType_int32_ByName("id");
  2050. Item* item = GetPlayer()->item_list.GetItemFromUniqueID(id, true);
  2051. if(!item)
  2052. item = GetPlayer()->GetEquipmentList()->GetItemFromUniqueID(id);
  2053. if(!item)
  2054. item = master_item_list.GetItem(id);
  2055. if(item){// && sent_item_details.count(id) == 0){
  2056. sent_item_details[id] = true;
  2057. EQ2Packet* app = item->serialize(GetVersion(), false, GetPlayer());
  2058. //DumpPacket(app);
  2059. QueuePacket(app);
  2060. }
  2061. else{
  2062. LogWrite(WORLD__ERROR, 0, "World", "HandleExamineInfoRequest: Unknown Item ID = %u", id);
  2063. DumpPacket(app);
  2064. }
  2065. }
  2066. else if(type == 1){
  2067. request = configReader.getStruct("WS_ExamineInfoItemRequest", GetVersion());
  2068. if(!request) {
  2069. return;
  2070. }
  2071. request->LoadPacketData(app->pBuffer, app->size);
  2072. int32 id = request->getType_int32_ByName("id");
  2073. int32 unique_id = request->getType_int32_ByName("unique_id");
  2074. Item* item = GetPlayer()->item_list.GetItemFromUniqueID(unique_id, true);
  2075. if (!item)
  2076. item = GetPlayer()->GetEquipmentList()->GetItemFromUniqueID(unique_id);
  2077. if (!item)
  2078. item = master_item_list.GetItem(id);
  2079. if (item){
  2080. sent_item_details[id] = true;
  2081. EQ2Packet* app = item->serialize(GetVersion(), false, GetPlayer());
  2082. //DumpPacket(app);
  2083. QueuePacket(app);
  2084. }
  2085. else{
  2086. LogWrite(WORLD__ERROR, 0, "World", "HandleExamineInfoRequest: Unknown Item ID = %u", id);
  2087. DumpPacket(app);
  2088. }
  2089. }
  2090. else if (type == 2) {
  2091. request = configReader.getStruct("WS_ExamineInfoItemLinkRequest", GetVersion());
  2092. if (!request) {
  2093. return;
  2094. }
  2095. request->LoadPacketData(app->pBuffer, app->size);
  2096. int32 id = request->getType_int32_ByName("item_id");
  2097. //int32 unknown_0 = request->getType_int32_ByName("unknown",0);
  2098. //int32 unknown_1 = request->getType_int32_ByName("unknown",1);
  2099. //int8 unknown2 = request->getType_int8_ByName("unknown2");
  2100. //int32 unique_id = request->getType_int32_ByName("unique_id");
  2101. //int16 unknown5 = request->getType_sint16_ByName("unknown5");
  2102. //printf("Type: (%i) Unknown_0: (%u) Unknown_1: (%u) Unknown2: (%i) Unique ID: (%u) Unknown5: (%i) Item ID: (%u)\n",type,unknown_0,unknown_1,unknown2,unique_id,unknown5,id);
  2103. Item* item = master_item_list.GetItem(id);
  2104. if (item) {
  2105. //only display popup for non merchant links
  2106. EQ2Packet* app = item->serialize(GetVersion(), (request->getType_int8_ByName("show_popup") != 0), GetPlayer(), true, 0, 0, true);
  2107. //DumpPacket(app);
  2108. QueuePacket(app);
  2109. }
  2110. else {
  2111. LogWrite(WORLD__ERROR, 0, "World", "HandleExamineInfoRequest: Unknown Item ID = %u", id);
  2112. DumpPacket(app);
  2113. }
  2114. }
  2115. else if(type == 4){ //spell effect
  2116. request = configReader.getStruct("WS_ExamineSpellEffectRequest", GetVersion());
  2117. if(!request) {
  2118. return;
  2119. }
  2120. request->LoadPacketData(app->pBuffer, app->size);
  2121. int32 id = request->getType_int32_ByName("id");
  2122. //int16 unknown5 = request->getType_sint16_ByName("unknown5");
  2123. SpellEffects* effect = player->GetSpellEffect(id);
  2124. //printf("Type: (%i) Unknown5: (%i) Item ID: (%u)\n",type,unknown5,id);
  2125. if(effect){
  2126. int8 tier = effect->tier;
  2127. Spell* spell = master_spell_list.GetSpell(id, tier);
  2128. if(spell && sent_spell_details.count(id) == 0){
  2129. sent_spell_details[id] = true;
  2130. EQ2Packet* app = spell->SerializeSpecialSpell(this, false, 0x00, 0x81);
  2131. //DumpPacket(app);
  2132. QueuePacket(app);
  2133. }
  2134. }
  2135. }
  2136. else if(type == 5){ // recipe info
  2137. request = configReader.getStruct("WS_ExamineInfoRequest", GetVersion());
  2138. if(!request)
  2139. return;
  2140. request->LoadPacketData(app->pBuffer, app->size);
  2141. int32 id = request->getType_int32_ByName("unknown_id");
  2142. Recipe *recipe = master_recipe_list.GetRecipe(id);
  2143. if(recipe){
  2144. EQ2Packet* app = recipe->SerializeRecipe(this, recipe, false, GetItemPacketType(GetVersion()), 0x02);
  2145. //DumpPacket(app);
  2146. QueuePacket(app);
  2147. }
  2148. }
  2149. else if(type == 6){ // AA spell info
  2150. Spell* spell = 0;
  2151. //Spell* spell2 = 0;
  2152. //AltAdvanceData* data = 0;
  2153. request = configReader.getStruct("WS_ExamineInfoRequest", GetVersion());
  2154. if(!request)
  2155. return;
  2156. request->LoadPacketData(app->pBuffer, app->size);
  2157. int32 id = request->getType_int32_ByName("id");
  2158. int32 tier = GetPlayer()->GetSpellTier(id);
  2159. LogWrite(WORLD__INFO, 0, "World", "Examine Info Request->Unique ID: %u Tier: %u ", id, tier);
  2160. //data = master_aa_list.GetAltAdvancement(id);
  2161. //LogWrite(WORLD__INFO, 0, "World", "SOE Spell CRC: %u", data->spell_crc);
  2162. //spell = master_spell_list.GetSpellByCRC(data->spell_crc);
  2163. spell = master_spell_list.GetSpell(id, 1);
  2164. //if (spell && sent_spell_details.count(spell->GetSpellID()) == 0) {
  2165. sent_spell_details[spell->GetSpellID()] = true;
  2166. // EQ2Packet* app = spell->SerializeAASpell(this,tier, data, false, GetItemPacketType(GetVersion()), 0x04);
  2167. EQ2Packet* app = master_spell_list.GetAASpellPacket(id, tier, this, false, 0x4F);//0x45 change version to match client
  2168. /////////////////////////////////////////GetAASpellPacket(int32 id, int8 tier, Client* client, bool display, int8 packet_type) {
  2169. //DumpPacket(app);
  2170. LogWrite(WORLD__INFO, 0, "WORLD", "Examine Info Request-> Spell ID: %u", spell->GetSpellID());
  2171. QueuePacket(app);
  2172. //}
  2173. }
  2174. else{
  2175. LogWrite(WORLD__ERROR, 0, "World", "Unknown examine request: %i", (int)type);
  2176. DumpPacket(app);
  2177. }
  2178. safe_delete(request);
  2179. }
  2180. void Client::HandleQuickbarUpdateRequest(EQApplicationPacket* app){
  2181. PacketStruct* request = configReader.getStruct("WS_QuickBarUpdateRequest", GetVersion());
  2182. if(request){
  2183. request->LoadPacketData(app->pBuffer, app->size);
  2184. int32 id = request->getType_int32_ByName("id");
  2185. int32 bar = request->getType_int32_ByName("hotbar_number");
  2186. int32 slot = request->getType_int32_ByName("hotkey_slot");
  2187. int32 type = request->getType_int32_ByName("type");
  2188. int8 tier = request->getType_int32_ByName("unique_id");
  2189. EQ2_16BitString text = request->getType_EQ2_16BitString_ByName("text");
  2190. Spell* spell = 0;
  2191. if(type == 0xFFFFFFFF)
  2192. GetPlayer()->RemoveQuickbarItem(bar, slot);
  2193. else{
  2194. if(type == QUICKBAR_NORMAL)
  2195. spell = master_spell_list.GetSpell(id, tier);
  2196. if(spell)
  2197. GetPlayer()->AddQuickbarItem(bar, slot, type, spell->GetSpellIcon(), spell->GetSpellIconBackdrop(), id, tier, 0, text.data.c_str());
  2198. else
  2199. GetPlayer()->AddQuickbarItem(bar, slot, type, 0, 0, id, 0, 0, text.data.c_str());
  2200. }
  2201. safe_delete(request);
  2202. }
  2203. }
  2204. bool Client::Process(bool zone_process) {
  2205. if(!eqs) {
  2206. return false;
  2207. }
  2208. if((connected_to_zone && !zone_process) || (!connected_to_zone && zone_process)) {
  2209. return true;
  2210. }
  2211. if(new_client_login){
  2212. LogWrite(CCLIENT__DEBUG, 0, "Client", "SendLoginInfo to new client...");
  2213. SendLoginInfo();
  2214. new_client_login = false;
  2215. }
  2216. bool ret = true;
  2217. sockaddr_in to;
  2218. memset((char *) &to, 0, sizeof(to));
  2219. to.sin_family = AF_INET;
  2220. to.sin_port = port;
  2221. to.sin_addr.s_addr = ip;
  2222. /************ Get all packets from packet manager out queue and process them ************/
  2223. EQApplicationPacket *app = 0;
  2224. if(eqs && !eqs->CheckActive()){
  2225. num_active_failures++;
  2226. LogWrite(CCLIENT__DEBUG, 7, "Client", "%s, num_active_failures = %i", __FUNCTION__, num_active_failures);
  2227. if(num_active_failures > 100) {
  2228. return false;
  2229. }
  2230. return true;
  2231. }
  2232. while(ret && eqs && (app = eqs->PopPacket())) {
  2233. ret = HandlePacket(app);
  2234. LogWrite(CCLIENT__DEBUG, 5, "Client", "Func: %s, Line: %i, Opcode: '%s'", __FUNCTION__, __LINE__, app->GetOpcodeName());
  2235. delete app;
  2236. }
  2237. if (GetCurrentZone() && GetCurrentZone()->GetSpawnByID(GetPlayer()->GetID()) && should_load_spells) {
  2238. player->ApplyPassiveSpells();
  2239. //database.LoadCharacterActiveSpells(player);
  2240. player->UnlockAllSpells(true);
  2241. should_load_spells = false;
  2242. }
  2243. if(quest_updates) {
  2244. LogWrite(CCLIENT__DEBUG, 1, "Client", "%s, ProcessQuestUpdates", __FUNCTION__, __LINE__);
  2245. ProcessQuestUpdates();
  2246. }
  2247. if(last_update_time > 0 && last_update_time < (Timer::GetCurrentTime2() - 300)) {
  2248. LogWrite(CCLIENT__DEBUG, 1, "Client", "%s, CheckQuestQueue", __FUNCTION__, __LINE__);
  2249. CheckQuestQueue();
  2250. }
  2251. if(pos_update.Check() && player_pos_changed){
  2252. //GetPlayer()->CalculateLocation();
  2253. GetCurrentZone()->SendPlayerPositionChanges(GetPlayer());
  2254. player_pos_changed = false;
  2255. GetCurrentZone()->CheckTransporters(this);
  2256. }
  2257. if(lua_interface && lua_debug && lua_debug_timer.Check())
  2258. lua_interface->UpdateDebugClients(this);
  2259. if(quest_pos_timer.Check())
  2260. CheckPlayerQuestsLocationUpdate();
  2261. if(camp_timer && camp_timer->Check() && getConnection()){
  2262. getConnection()->SendDisconnect(false);
  2263. safe_delete(camp_timer);
  2264. disconnect_timer = new Timer(2000);
  2265. disconnect_timer->Start();
  2266. }
  2267. if(player->GetSkills()->HasSkillUpdates()){
  2268. vector<Skill*>* skills = player->GetSkills()->GetSkillUpdates();
  2269. if(skills){
  2270. Skill* skill = 0;
  2271. vector<Skill*>::iterator itr;
  2272. for(itr = skills->begin(); itr != skills->end(); itr++){
  2273. skill = *itr;
  2274. SkillChanged(skill, skill->previous_val, skill->current_val);
  2275. }
  2276. EQ2Packet* app = GetPlayer()->skill_list.GetSkillPacket(GetVersion());
  2277. if (app) QueuePacket(app);
  2278. safe_delete(skills);
  2279. }
  2280. }
  2281. if(disconnect_timer && disconnect_timer->Check()){
  2282. safe_delete(disconnect_timer);
  2283. ret = false;
  2284. }
  2285. m_resurrect.writelock(__FUNCTION__, __LINE__);
  2286. if(current_rez.should_delete || (current_rez.expire_timer && current_rez.expire_timer->Check(false))){
  2287. safe_delete(current_rez.expire_timer);
  2288. current_rez.expire_timer = 0;
  2289. current_rez.active = false;
  2290. current_rez.caster = 0;
  2291. current_rez.crit = false;
  2292. current_rez.crit_mod = 0;
  2293. current_rez.expire_timer = 0;
  2294. current_rez.heal_name = "";
  2295. current_rez.hp_perc = 0;
  2296. current_rez.mp_perc = 0;
  2297. current_rez.no_calcs = false;
  2298. current_rez.range = 0;
  2299. current_rez.should_delete = false;
  2300. current_rez.spell_name = "";
  2301. current_rez.spell_visual = 0;
  2302. current_rez.subspell = 0;
  2303. }
  2304. m_resurrect.releasewritelock(__FUNCTION__, __LINE__);
  2305. // Quest timers
  2306. Quest* failed_step = 0;
  2307. MQuestTimers.writelock(__FUNCTION__, __LINE__);
  2308. if (quest_timers.size() > 0) {
  2309. vector<int32>::iterator itr;
  2310. map<int32, Quest*>* player_quests = player->GetPlayerQuests();
  2311. for (itr = quest_timers.begin(); itr != quest_timers.end(); itr++) {
  2312. if (player_quests->count(*itr) > 0 && player_quests->at(*itr)->GetStepTimer() != 0) {
  2313. Quest* quest = player_quests->at(*itr);
  2314. if (Timer::GetUnixTimeStamp() >= quest->GetStepTimer()) {
  2315. failed_step = quest;
  2316. break;
  2317. }
  2318. }
  2319. else {
  2320. quest_timers.erase(itr);
  2321. break;
  2322. }
  2323. }
  2324. }
  2325. MQuestTimers.releasewritelock(__FUNCTION__, __LINE__);
  2326. if (failed_step)
  2327. failed_step->StepFailed(failed_step->GetTimerStep());
  2328. if (player->ControlFlagsChanged())
  2329. player->SendControlFlagUpdates(this);
  2330. if (!eqs || (eqs && !eqs->CheckActive()))
  2331. ret = false;
  2332. if(!ret)
  2333. Save();
  2334. return ret;
  2335. }
  2336. ClientList::ClientList() {
  2337. MClients.SetName("ClientList::MClients");
  2338. }
  2339. ClientList::~ClientList() {
  2340. }
  2341. void ClientList::ReloadQuests() {
  2342. list<Client*>::iterator client_iter;
  2343. Client* client = 0;
  2344. MClients.readlock(__FUNCTION__, __LINE__);
  2345. for(client_iter=client_list.begin(); client_iter!=client_list.end(); client_iter++){
  2346. client = *client_iter;
  2347. if(client)
  2348. client->ReloadQuests();
  2349. }
  2350. MClients.releasereadlock(__FUNCTION__, __LINE__);
  2351. }
  2352. int32 ClientList::Count(){
  2353. return client_list.size();
  2354. }
  2355. void ClientList::Add(Client* client) {
  2356. MClients.writelock(__FUNCTION__, __LINE__);
  2357. client_list.push_back(client);
  2358. MClients.releasewritelock(__FUNCTION__, __LINE__);
  2359. }
  2360. Client* ClientList::FindByAccountID(int32 account_id) {
  2361. list<Client*>::iterator client_iter;
  2362. Client* client = 0;
  2363. Client* ret = 0;
  2364. MClients.readlock(__FUNCTION__, __LINE__);
  2365. for(client_iter=client_list.begin(); client_list.size() > 0 && client_iter!=client_list.end(); client_iter++){
  2366. client = *client_iter;
  2367. if (client->GetAccountID() == account_id) {
  2368. ret = client;
  2369. break;
  2370. }
  2371. }
  2372. MClients.releasereadlock(__FUNCTION__, __LINE__);
  2373. return ret;
  2374. }
  2375. Client* ClientList::FindByName(char* charName) {
  2376. list<Client*>::iterator client_iter;
  2377. Client* client = 0;
  2378. Client* ret = 0;
  2379. MClients.readlock(__FUNCTION__, __LINE__);
  2380. for(client_iter=client_list.begin(); client_list.size() > 0 && client_iter!=client_list.end(); client_iter++){
  2381. client = *client_iter;
  2382. if (!client || !client->GetPlayer())
  2383. continue;
  2384. if (!strncmp(client->GetPlayer()->GetName(),charName,strlen(charName))) {
  2385. ret = client;
  2386. break;
  2387. }
  2388. }
  2389. MClients.releasereadlock(__FUNCTION__, __LINE__);
  2390. return ret;
  2391. }
  2392. Client* ClientList::Get(int32 ip, int16 port) {
  2393. list<Client*>::iterator client_iter;
  2394. Client* client = 0;
  2395. Client* ret = 0;
  2396. MClients.readlock(__FUNCTION__, __LINE__);
  2397. for(client_iter=client_list.begin(); client_list.size() > 0 && client_iter!=client_list.end(); client_iter++){
  2398. client = *client_iter;
  2399. if(client->GetIP() == ip && client->GetPort() == port){
  2400. ret = client;
  2401. break;
  2402. }
  2403. }
  2404. MClients.releasereadlock(__FUNCTION__, __LINE__);
  2405. return ret;
  2406. }
  2407. void ClientList::Process() {
  2408. list<Client*>::iterator client_iter;
  2409. list<Client*>::iterator erase_iter;
  2410. Client* client = 0;
  2411. MClients.readlock(__FUNCTION__, __LINE__);
  2412. erase_iter = client_list.end();
  2413. for(client_iter=client_list.begin(); client_iter!=client_list.end();client_iter++){
  2414. client = *client_iter;
  2415. // have a sanity check because the client list can sometimes obtain null client pointers
  2416. if (!client || (!client->Process() || client->remove_from_list)) {
  2417. erase_iter = client_iter;
  2418. break;
  2419. }
  2420. }
  2421. MClients.releasereadlock(__FUNCTION__, __LINE__);
  2422. if(erase_iter != client_list.end()){
  2423. client = *erase_iter;
  2424. MClients.writelock(__FUNCTION__, __LINE__);
  2425. client_list.erase(erase_iter);
  2426. MClients.releasewritelock(__FUNCTION__, __LINE__);
  2427. if(client && !client->remove_from_list){
  2428. struct in_addr in;
  2429. in.s_addr = client->GetIP();
  2430. LogWrite(WORLD__INFO, 0, "World", "Removing client from ip: %s port: %i", inet_ntoa(in), client->GetPort());
  2431. safe_delete(client);
  2432. }
  2433. }
  2434. }
  2435. void ClientList::RemoveConnection(EQStream* eqs){
  2436. Client *client;
  2437. if(eqs){
  2438. list<Client*>::iterator client_iter;
  2439. MClients.readlock(__FUNCTION__, __LINE__);
  2440. for(client_iter=client_list.begin(); client_iter!=client_list.end(); client_iter++){
  2441. client = *client_iter;
  2442. if(client->getConnection() == eqs)
  2443. client->Disconnect(false);
  2444. }
  2445. MClients.releasereadlock(__FUNCTION__, __LINE__);
  2446. }
  2447. }
  2448. bool ClientList::ContainsStream(EQStream* eqs){
  2449. if(!eqs) {
  2450. return false;
  2451. }
  2452. list<Client*>::iterator client_iter;
  2453. bool ret = false;
  2454. MClients.readlock(__FUNCTION__, __LINE__);
  2455. for(client_iter=client_list.begin(); client_iter!=client_list.end(); client_iter++){
  2456. if((*client_iter)->getConnection() && (*client_iter)->getConnection()->GetRemotePort() == eqs->GetRemotePort() && (*client_iter)->getConnection()->GetRemoteIP() == eqs->GetRemoteIP()){
  2457. ret = true;
  2458. break;
  2459. }
  2460. }
  2461. MClients.releasereadlock(__FUNCTION__, __LINE__);
  2462. return ret;
  2463. }
  2464. void ClientList::Remove(Client* client, bool remove_data) {
  2465. client->remove_from_list = true;
  2466. if(remove_data){
  2467. safe_delete(client);
  2468. }
  2469. }
  2470. void Client::SetCurrentZone(int32 id){
  2471. if(current_zone){
  2472. //current_zone->GetCombat()->RemoveHate(player);
  2473. current_zone->RemoveSpawn(player, false);
  2474. }
  2475. SetCurrentZone(zone_list.Get(id));
  2476. }
  2477. void Client::SetCurrentZoneByInstanceID(int32 id,int32 zoneid){
  2478. if(current_zone){
  2479. //current_zone->GetCombat()->RemoveHate(player);
  2480. current_zone->RemoveSpawn(player, false);
  2481. }
  2482. SetCurrentZone(zone_list.GetByInstanceID(id,zoneid));
  2483. }
  2484. ZoneServer* Client::GetCurrentZone(){
  2485. return current_zone;
  2486. }
  2487. void Client::SimpleMessage(int8 color, const char* message){
  2488. PacketStruct* command_packet = configReader.getStruct("WS_DisplayText", GetVersion());
  2489. if(command_packet){
  2490. command_packet->setDataByName("color", color);
  2491. command_packet->setMediumStringByName("text", message);
  2492. command_packet->setDataByName("unknown02", 0x00ff);
  2493. EQ2Packet* outapp = command_packet->serialize();
  2494. QueuePacket(outapp);
  2495. safe_delete(command_packet);
  2496. }
  2497. }
  2498. void Client::SendSpellUpdate(Spell* spell){
  2499. PacketStruct* packet = configReader.getStruct("WS_SpellGainedMsg", GetVersion());
  2500. if(packet){
  2501. int8 xxx = spell->GetSpellData()->is_aa;
  2502. packet->setDataByName("spell_type", spell->GetSpellData()->type);
  2503. packet->setDataByName("spell_id", spell->GetSpellID());
  2504. packet->setDataByName("unique_id", spell->GetSpellTier());
  2505. packet->setDataByName("spell_name", spell->GetName());
  2506. packet->setDataByName("unknown", xxx);
  2507. packet->setDataByName("display_spell_tier", 1);
  2508. packet->setDataByName("unknown3", 1);
  2509. packet->setDataByName("tier", spell->GetSpellTier());
  2510. packet->setDataByName("icon", spell->GetSpellIcon());
  2511. packet->setDataByName("icon_type", spell->GetSpellIconBackdrop());
  2512. packet->setDataByName("unknown5", 0xFFFFFFFF);
  2513. //packet->PrintPacket();
  2514. EQ2Packet* outapp = packet->serialize();
  2515. //DumpPacket(outapp);
  2516. QueuePacket(outapp);
  2517. safe_delete(packet);
  2518. }
  2519. }
  2520. void Client::Message(int8 type, const char* message, ...) {
  2521. va_list argptr;
  2522. char buffer[4096];
  2523. va_start(argptr, message);
  2524. vsnprintf(buffer, sizeof(buffer), message, argptr);
  2525. va_end(argptr);
  2526. SimpleMessage(type, buffer);
  2527. }
  2528. void Client::Disconnect(bool send_disconnect)
  2529. {
  2530. LogWrite(CCLIENT__DEBUG, 0, "CClient", "Client Disconnect...");
  2531. SetConnected(false);
  2532. if(send_disconnect && getConnection())
  2533. getConnection()->SendDisconnect(true);
  2534. this->Save();
  2535. this->GetPlayer()->WritePlayerStatistics();
  2536. eqs = 0;
  2537. }
  2538. bool Client::Summon(const char* search_name){
  2539. Spawn* target = 0;
  2540. if(search_name || GetPlayer()->GetTarget()){
  2541. Client* search_client = 0;
  2542. if(search_name){
  2543. target = GetCurrentZone()->FindSpawn(GetPlayer(), search_name);
  2544. if(target && target->IsPlayer())
  2545. search_client = GetCurrentZone()->GetClientBySpawn(target);
  2546. if(!target){
  2547. search_client = zone_list.GetClientByCharName(string(search_name));
  2548. if(search_client)
  2549. target = search_client->GetPlayer();
  2550. }
  2551. }
  2552. else
  2553. target = GetPlayer()->GetTarget();
  2554. if(target && target != GetPlayer()){
  2555. target->SetX(GetPlayer()->GetX());
  2556. target->SetY(GetPlayer()->GetY());
  2557. target->SetZ(GetPlayer()->GetZ());
  2558. target->SetHeading(GetPlayer()->GetHeading());
  2559. if(!target->IsPlayer()){
  2560. target->SetSpawnOrigX(target->GetX());
  2561. target->SetSpawnOrigY(target->GetY());
  2562. target->SetSpawnOrigZ(target->GetZ());
  2563. target->SetSpawnOrigHeading(target->GetHeading());
  2564. }
  2565. target->SetLocation(GetPlayer()->GetLocation());
  2566. }
  2567. else if(target)
  2568. Message(CHANNEL_COLOR_RED,"Error: You cannot summon yourself!");
  2569. if(search_client && search_client != this){
  2570. search_client->Message(CHANNEL_COLOR_YELLOW, "You have been summoned by '%s'!", GetPlayer()->GetName());
  2571. Message(CHANNEL_COLOR_YELLOW, "Summoning '%s'...", search_client->GetPlayer()->GetName());
  2572. if(search_client->GetCurrentZone() != GetCurrentZone())
  2573. search_client->Zone(GetCurrentZone()->GetZoneName(), false);
  2574. else{
  2575. EQ2Packet* app = search_client->GetPlayer()->Move(GetPlayer()->GetX(), GetPlayer()->GetY(), GetPlayer()->GetZ(), search_client->GetVersion());
  2576. if(app)
  2577. search_client->QueuePacket(app);
  2578. }
  2579. }
  2580. }
  2581. if(!target)
  2582. return false;
  2583. else
  2584. return true;
  2585. }
  2586. bool Client::TryZoneInstance(int32 zoneID, bool zone_coords_valid) {
  2587. ZoneServer* instance_zone = NULL;
  2588. int8 instanceType = 0;
  2589. // determine if this is a group instanced zone that already exists
  2590. instance_zone = GetPlayer()->GetGroupMemberInZone(zoneID);
  2591. if ( instance_zone != NULL )
  2592. Zone(instance_zone->GetInstanceID(),zone_coords_valid, true);
  2593. else if ( (instanceType = database.GetInstanceTypeByZoneID(zoneID) ) > 0 )
  2594. {
  2595. // best to check if we already have our own instance!
  2596. InstanceData* data = GetPlayer()->GetCharacterInstances()->FindInstanceByZoneID(zoneID);
  2597. if (data) {
  2598. // If lockout instances check to see if we are locked out
  2599. if (instanceType == SOLO_LOCKOUT_INSTANCE || instanceType == GROUP_LOCKOUT_INSTANCE || instanceType == RAID_LOCKOUT_INSTANCE) {
  2600. int32 time = 0;
  2601. // Check success timer
  2602. if (data->last_success_timestamp > 0) {
  2603. if (Timer::GetUnixTimeStamp() < data->last_success_timestamp + data->success_lockout_time) {
  2604. // Timer has not expired yet can't re enter
  2605. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Success lockout not expired for character %s in zone %u", GetPlayer()->GetName(), zoneID);
  2606. time = (data->last_success_timestamp + data->success_lockout_time) - Timer::GetUnixTimeStamp();
  2607. }
  2608. }
  2609. // Check failure timer
  2610. if (data->last_failure_timestamp > 0) {
  2611. if (Timer::GetUnixTimeStamp() < data->last_failure_timestamp + data->failure_lockout_time) {
  2612. // Timer has not expired yet
  2613. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Failure lockout not expired for character %s in zone %u", GetPlayer()->GetName(), zoneID);
  2614. time = (data->last_failure_timestamp + data->failure_lockout_time) - Timer::GetUnixTimeStamp();
  2615. }
  2616. }
  2617. // Time > 0 then we are locked out, make the message and send it and return true
  2618. if (time > 0) {
  2619. string time_msg = "";
  2620. int16 hour;
  2621. int8 min;
  2622. int8 sec;
  2623. hour = time / 3600;
  2624. time = time % 3600;
  2625. min = time / 60;
  2626. time = time % 60;
  2627. sec = time;
  2628. if (hour > 0) {
  2629. char temp[10];
  2630. sprintf(temp, " %i", hour);
  2631. time_msg.append(temp);
  2632. time_msg.append(" hour");
  2633. time_msg.append((hour > 1) ? "s" : "");
  2634. }
  2635. if (min > 0) {
  2636. char temp[5];
  2637. sprintf(temp, " %i", min);
  2638. time_msg.append(temp);
  2639. time_msg.append(" minute");
  2640. time_msg.append((min > 1) ? "s" : "");
  2641. }
  2642. // Only add seconds if minutes and hours are 0
  2643. if (hour == 0 && min == 0 && sec > 0) {
  2644. char temp[5];
  2645. sprintf(temp, " %i", sec);
  2646. time_msg.append(temp);
  2647. time_msg.append(" second");
  2648. time_msg.append((sec > 1) ? "s" : "");
  2649. }
  2650. Message(CHANNEL_COLOR_YELLOW, "You may not enter again for%s.", time_msg.c_str());
  2651. return true;
  2652. }
  2653. }
  2654. // Need to update `character_instances` table with new timestamps (for persistent) and instance id's
  2655. instance_zone = zone_list.GetByInstanceID(data->instance_id,zoneID);
  2656. // if we got an instance_zone and the instance_id from the data is 0 or data instance id is not the same as the zone instance id then update values
  2657. if (instance_zone && (data->instance_id == 0 || data->instance_id != instance_zone->GetInstanceID())) {
  2658. if (instanceType == SOLO_PERSIST_INSTANCE || instanceType == GROUP_PERSIST_INSTANCE || instanceType == RAID_PERSIST_INSTANCE) {
  2659. database.UpdateCharacterInstance(GetCharacterID(), string(instance_zone->GetZoneName()), instance_zone->GetInstanceID(), 1, Timer::GetUnixTimeStamp());
  2660. data->last_success_timestamp = Timer::GetUnixTimeStamp();
  2661. }
  2662. else
  2663. database.UpdateCharacterInstance(GetCharacterID(), string(instance_zone->GetZoneName()), instance_zone->GetInstanceID());
  2664. data->instance_id = instance_zone->GetInstanceID();
  2665. }
  2666. }
  2667. else {
  2668. switch(instanceType)
  2669. {
  2670. case SOLO_LOCKOUT_INSTANCE:
  2671. case GROUP_LOCKOUT_INSTANCE:
  2672. case RAID_LOCKOUT_INSTANCE:
  2673. {
  2674. instance_zone = zone_list.GetByInstanceID(0,zoneID);
  2675. if (instance_zone) {
  2676. // once lockout instance zone shuts down you can't renenter if you have a lockout or if you don't you get a new zone
  2677. // so delete `instances` entry for the zone when it shuts down.
  2678. int32 db_id = database.AddCharacterInstance(GetPlayer()->GetCharacterID(), instance_zone->GetInstanceID(), string(instance_zone->GetZoneName()), instance_zone->GetInstanceType(), 0, 0, instance_zone->GetDefaultLockoutTime(), instance_zone->GetDefaultReenterTime());
  2679. if (db_id > 0)
  2680. GetPlayer()->GetCharacterInstances()->AddInstance(db_id, instance_zone->GetInstanceID(), 0, 0, instance_zone->GetDefaultLockoutTime(), instance_zone->GetDefaultReenterTime(), zoneID, instance_zone->GetInstanceType(), string(instance_zone->GetZoneName()));
  2681. }
  2682. break;
  2683. }
  2684. case SOLO_PERSIST_INSTANCE:
  2685. case GROUP_PERSIST_INSTANCE:
  2686. case RAID_PERSIST_INSTANCE:
  2687. {
  2688. instance_zone = zone_list.GetByInstanceID(0,zoneID);
  2689. if (instance_zone) {
  2690. int32 db_id = database.AddCharacterInstance(GetPlayer()->GetCharacterID(), instance_zone->GetInstanceID(), string(instance_zone->GetZoneName()), instance_zone->GetInstanceType(), Timer::GetUnixTimeStamp(), 0, instance_zone->GetDefaultLockoutTime(), instance_zone->GetDefaultReenterTime());
  2691. if (db_id > 0)
  2692. GetPlayer()->GetCharacterInstances()->AddInstance(db_id, instance_zone->GetInstanceID(), Timer::GetUnixTimeStamp(), 0, instance_zone->GetDefaultLockoutTime(), instance_zone->GetDefaultReenterTime(), zoneID, instance_zone->GetInstanceType(), string(instance_zone->GetZoneName()));
  2693. }
  2694. break;
  2695. }
  2696. case PUBLIC_INSTANCE:
  2697. case TRADESKILL_INSTANCE:
  2698. {
  2699. // if its public/tradeskill, look for a public already setup
  2700. instance_zone = zone_list.GetByLowestPopulation(zoneID);
  2701. if (instance_zone) {
  2702. // Check the current population against the max population, if greater or equal start a new version
  2703. if (instance_zone->GetClientCount() >= rule_manager.GetGlobalRule(R_Zone, MaxPlayers)->GetInt32())
  2704. instance_zone = zone_list.GetByInstanceID(0, zoneID);
  2705. }
  2706. else
  2707. instance_zone = zone_list.GetByInstanceID(0, zoneID);
  2708. break;
  2709. }
  2710. case PERSONAL_HOUSE_INSTANCE:
  2711. case GUILD_HOUSE_INSTANCE:
  2712. {
  2713. // Because of the way housing works (need to load a specific instance id supplied in a packet) we can't
  2714. // use this function without some rework, so it will all be handled in Client::HandlePacket()
  2715. // with the OP_EnterHouseMsg opcode
  2716. break;
  2717. }
  2718. case QUEST_INSTANCE:
  2719. {
  2720. instance_zone = zone_list.GetByInstanceID(0, zoneID);
  2721. break;
  2722. /*
  2723. ALTER TABLE `zones` CHANGE COLUMN `instance_type` `instance_type` ENUM('NONE','GROUP_LOCKOUT_INSTANCE','GROUP_PERSIST_INSTANCE','RAID_LOCKOUT_INSTANCE','RAID_PERSIST_INSTANCE','SOLO_LOCKOUT_INSTANCE','SOLO_PERSIST_INSTANCE','TRADESKILL_INSTANCE','PUBLIC_INSTANCE','PERSONAL_HOUSE_INSTANCE','GUILD_HOUSE_INSTANCE','QUEST_INSTANCE') NOT NULL DEFAULT 'NONE' COLLATE 'latin1_general_ci' AFTER `start_zone`;
  2724. */
  2725. }
  2726. default:
  2727. {
  2728. // NONE
  2729. }
  2730. }
  2731. }
  2732. if ( instance_zone != NULL )
  2733. Zone(instance_zone, zone_coords_valid );
  2734. }
  2735. if ( instance_zone != NULL )
  2736. return true;
  2737. else
  2738. return false;
  2739. }
  2740. bool Client::GotoSpawn(const char* search_name){
  2741. Spawn* target = 0;
  2742. if(search_name || GetPlayer()->GetTarget()){
  2743. Client* search_client = 0;
  2744. if(search_name){
  2745. target = GetCurrentZone()->FindSpawn(GetPlayer(), search_name);
  2746. if(!target){
  2747. search_client = zone_list.GetClientByCharName(search_name);
  2748. if(search_client)
  2749. target = search_client->GetPlayer();
  2750. }
  2751. }
  2752. else
  2753. target = GetPlayer()->GetTarget();
  2754. if(target && target != GetPlayer()){
  2755. GetPlayer()->SetX(target->GetX());
  2756. GetPlayer()->SetY(target->GetY());
  2757. GetPlayer()->SetZ(target->GetZ());
  2758. GetPlayer()->SetHeading(target->GetHeading());
  2759. GetPlayer()->SetLocation(target->GetLocation());
  2760. Message(CHANNEL_COLOR_YELLOW, "Warping to '%s'", target->GetName());
  2761. }
  2762. else if(target)
  2763. Message(CHANNEL_COLOR_RED,"Error: You cannot goto yourself!");
  2764. if(search_client && search_client->GetCurrentZone() != GetCurrentZone())
  2765. Zone(search_client->GetCurrentZone()->GetZoneName(), false);
  2766. else if(target){
  2767. EQ2Packet* app = GetPlayer()->Move(target->GetX(), target->GetY(), target->GetZ(), GetVersion());
  2768. if(app)
  2769. QueuePacket(app);
  2770. }
  2771. }
  2772. if(!target)
  2773. return false;
  2774. else
  2775. return true;
  2776. }
  2777. bool Client::CheckZoneAccess(const char* zoneName) {
  2778. LogWrite(CCLIENT__DEBUG, 0, "Client", "Zone access check for %s (%u), client: %u",zoneName, database.GetZoneID(zoneName), GetVersion());
  2779. ZoneServer* zone = zone_list.Get(zoneName,false);
  2780. // JA: implemented /zone lock|unlock commands (2012.07.28)
  2781. if( zone && zone->GetZoneLockState() )
  2782. {
  2783. LogWrite(CCLIENT__DEBUG, 0, "Client", "Zone currently LOCKED: '%s' (%ul)", zoneName, zone->GetZoneID());
  2784. Message(CHANNEL_COLOR_RED, "This zone is locked, and you don't have the key! (%s).", zoneName);
  2785. return false;
  2786. }
  2787. sint16 zoneMinStatus = 0;
  2788. int16 zoneMinLevel = 0;
  2789. int16 zoneMaxLevel = 0;
  2790. int16 zoneMinVersion = 0;
  2791. if ( !zone )
  2792. {
  2793. LogWrite(CCLIENT__DEBUG, 0, "Client", "Grabbing zone requirements for %s", zoneName);
  2794. bool success = database.GetZoneRequirements(zoneName, &zoneMinStatus, &zoneMinLevel, &zoneMaxLevel, &zoneMinVersion);
  2795. if ( !success ) { // couldn't even find the zone, this shouldn't happen though..
  2796. return true;
  2797. }
  2798. }
  2799. else
  2800. {
  2801. zoneMinStatus = zone->GetMinimumStatus();
  2802. zoneMinLevel = zone->GetMinimumLevel();
  2803. zoneMaxLevel = zone->GetMaximumLevel();
  2804. zoneMinVersion = zone->GetMinimumVersion();
  2805. }
  2806. LogWrite(CCLIENT__DEBUG, 0, "Client", "Access Requirements: status %i, level %i - %i, req >= %i version", zoneMinStatus, zoneMinLevel, zoneMaxLevel, zoneMinVersion);
  2807. // use ZoneLevelOverrideStatus in both min_level and max_level checks
  2808. sint16 ZoneLevelOverrideStatus = rule_manager.GetGlobalRule(R_Zone, MinZoneLevelOverrideStatus)->GetSInt16();
  2809. if ( (zoneMinVersion > 0) && (GetVersion() < zoneMinVersion) )
  2810. {
  2811. LogWrite(CCLIENT__DEBUG, 0, "Client", "Zone MinVersion of %i challenge...", zoneMinVersion);
  2812. Message(CHANNEL_COLOR_RED, "You do not have the required expansion pack to enter here (%s).", database.GetExpansionIDByVersion(zoneMinVersion).c_str());
  2813. LogWrite(CCLIENT__DEBUG, 0, "Client", "Client denied access to zone '%s' (version req: %i)", zoneName, zoneMinVersion);
  2814. return false;
  2815. }
  2816. if ( (zoneMinLevel > 1) && (player->GetLevel() < zoneMinLevel) )
  2817. {
  2818. if( ZoneLevelOverrideStatus && ZoneLevelOverrideStatus > GetAdminStatus() )
  2819. {
  2820. LogWrite(CCLIENT__DEBUG, 0, "Client", "Player denied access to zone '%s' (level req: %i)", zoneName, player->GetLevel());
  2821. Message(CHANNEL_COLOR_RED, "Your level is too low to enter here (%s)", zoneMinLevel);
  2822. return false;
  2823. }
  2824. }
  2825. if ( (zoneMaxLevel > 1) && (player->GetLevel() > zoneMaxLevel) )
  2826. {
  2827. if( ZoneLevelOverrideStatus && ZoneLevelOverrideStatus > GetAdminStatus() )
  2828. {
  2829. LogWrite(CCLIENT__DEBUG, 0, "Client", "Player denied access to zone '%s' (level req: %i)", zoneName, player->GetLevel());
  2830. Message(CHANNEL_COLOR_RED, "Your level is too high to enter here (%s)", zoneMaxLevel);
  2831. return false;
  2832. }
  2833. }
  2834. if ( (zoneMinStatus > 0) && (GetAdminStatus() < zoneMinStatus) )
  2835. {
  2836. LogWrite(CCLIENT__DEBUG, 0, "Client", "Zone MinStatus of %i challenge...", zoneMinStatus);
  2837. sint16 ZoneAccessOverrideStatus = rule_manager.GetGlobalRule(R_Zone, MinZoneAccessOverrideStatus)->GetSInt16();
  2838. if( ZoneAccessOverrideStatus && ZoneAccessOverrideStatus > GetAdminStatus() )
  2839. {
  2840. LogWrite(CCLIENT__DEBUG, 0, "Client", "Player denied access to zone '%s' (status req: %i)", zoneName, GetAdminStatus());
  2841. Message(CHANNEL_COLOR_RED, "You do not have permission to enter here (%i).", zoneMinStatus);
  2842. return false;
  2843. }
  2844. }
  2845. return true;
  2846. }
  2847. void Client::Zone(int32 instanceid, bool set_coords, bool byInstanceID) {
  2848. Zone(zone_list.GetByInstanceID(instanceid), set_coords);
  2849. }
  2850. void Client::Zone(ZoneServer* new_zone, bool set_coords){
  2851. if(!new_zone) {
  2852. LogWrite(CCLIENT__DEBUG, 0, "Client", "Zone Request Denied! No 'new_zone' value");
  2853. return;
  2854. }
  2855. client_zoning = true;
  2856. LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: Setting player Resurrecting to 'true'", __FUNCTION__);
  2857. player->SetResurrecting(true);
  2858. LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: Removing player from fighting...", __FUNCTION__);
  2859. //GetCurrentZone()->GetCombat()->RemoveHate(player);
  2860. // Remove players pet from zone if there is one
  2861. player->DismissPet((NPC*)player->GetPet());
  2862. player->DismissPet((NPC*)player->GetCharmedPet());
  2863. player->DismissPet((NPC*)player->GetDeityPet());
  2864. player->DismissPet((NPC*)player->GetCosmeticPet());
  2865. LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: Removing player from current zone...", __FUNCTION__);
  2866. GetCurrentZone()->RemoveSpawn(player, false);
  2867. LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: Setting zone to '%s'...", __FUNCTION__, new_zone->GetZoneName());
  2868. SetCurrentZone(new_zone);
  2869. if(player->GetGroupMemberInfo())
  2870. {
  2871. LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: Player in group, updating group info...", __FUNCTION__);
  2872. player->UpdateGroupMemberInfo();
  2873. world.GetGroupManager()->SendGroupUpdate(player->GetGroupMemberInfo()->group_id, this);
  2874. }
  2875. UpdateTimeStampFlag(ZONE_UPDATE_FLAG);
  2876. if(set_coords)
  2877. {
  2878. LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: Zoning player to coordinates x: %2f, y: %2f, z: %2f, heading: %2f in zone '%s'...",
  2879. __FUNCTION__,
  2880. GetCurrentZone()->GetSafeX(),
  2881. GetCurrentZone()->GetSafeY(),
  2882. GetCurrentZone()->GetSafeZ(),
  2883. GetCurrentZone()->GetSafeHeading(),
  2884. new_zone->GetZoneName()
  2885. );
  2886. player->SetX(GetCurrentZone()->GetSafeX());
  2887. player->SetY(GetCurrentZone()->GetSafeY());
  2888. player->SetZ(GetCurrentZone()->GetSafeZ());
  2889. player->SetHeading(GetCurrentZone()->GetSafeHeading());
  2890. }
  2891. LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: Saving Player info...", __FUNCTION__);
  2892. Save();
  2893. char* new_zone_ip = 0;
  2894. struct in_addr in;
  2895. in.s_addr = this->GetIP();
  2896. if(strncmp(inet_ntoa(in), "192.168",7)==0 && strlen(net.GetInternalWorldAddress()) > 0)
  2897. new_zone_ip = net.GetInternalWorldAddress();
  2898. else
  2899. new_zone_ip = net.GetWorldAddress();
  2900. LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: New Zone IP '%s'...", __FUNCTION__, new_zone_ip);
  2901. int32 key = Timer::GetUnixTimeStamp();
  2902. LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: Sending ZoneChangeMsg...", __FUNCTION__);
  2903. ClientPacketFunctions::SendZoneChange(this, new_zone_ip, net.GetWorldPort(), key);
  2904. LogWrite(CCLIENT__DEBUG, 0, "Client", "%s: Sending to zone_auth.AddAuth...", __FUNCTION__);
  2905. zone_auth.AddAuth(new ZoneAuthRequest(GetAccountID(), player->GetName(), key));
  2906. }
  2907. void Client::Zone(const char* new_zone, bool set_coords)
  2908. {
  2909. LogWrite(CCLIENT__DEBUG, 0, "Client", "Zone Request to '%s'", new_zone);
  2910. Zone(zone_list.Get(new_zone), set_coords);
  2911. }
  2912. float Client::DistanceFrom(Client* client){
  2913. float ret = 0;
  2914. if(client && client != this){
  2915. ret = pow(player->GetX() - client->player->GetX(), 2) + pow(player->GetY() - client->player->GetY(), 2) + pow(player->GetZ() - client->player->GetZ(), 2);
  2916. ret = sqrt(ret);
  2917. }
  2918. return ret;
  2919. }
  2920. void Client::DetermineCharacterUpdates ( ) {
  2921. ServerPacket* outpack = new ServerPacket(ServerOP_BasicCharUpdate, sizeof(CharDataUpdate_Struct));
  2922. CharDataUpdate_Struct* cdu = (CharDataUpdate_Struct*)outpack->pBuffer;
  2923. cdu->account_id = GetAccountID ( );
  2924. cdu->char_id = GetCharacterID ( );
  2925. int32 timestamp = Timer::GetUnixTimeStamp();
  2926. int8 flag = GetTimeStampFlag( );
  2927. if(flag&LEVEL_UPDATE_FLAG)
  2928. {
  2929. cdu->update_field = LEVEL_UPDATE_FLAG;
  2930. cdu->update_data = player->GetLevel ( );
  2931. loginserver.SendPacket(outpack);
  2932. }
  2933. //if(flag&CLASS_UPDATE_FLAG && player->GetLevel() >= 20)// Perseverance only
  2934. if(flag&CLASS_UPDATE_FLAG)
  2935. {
  2936. cdu->update_field = CLASS_UPDATE_FLAG;
  2937. cdu->update_data = player->GetAdventureClass();
  2938. loginserver.SendPacket(outpack);
  2939. }
  2940. if(flag&GENDER_UPDATE_FLAG)
  2941. {
  2942. cdu->update_field = GENDER_UPDATE_FLAG;
  2943. cdu->update_data = player->GetGender ( );
  2944. loginserver.SendPacket(outpack);
  2945. }
  2946. if(flag&DELETE_UPDATE_FLAG) {
  2947. LogWrite(MISC__TODO, 1, "TODO", "Delete update req in func: %s, line: %i", __FUNCTION__, __LINE__);
  2948. }
  2949. safe_delete(outpack); // Zone, armor and name use a different structure
  2950. if(flag&RACE_UPDATE_FLAG)
  2951. {
  2952. outpack = new ServerPacket(ServerOP_RaceUpdate, sizeof(RaceUpdate_Struct));
  2953. RaceUpdate_Struct* ru = (RaceUpdate_Struct*)outpack->pBuffer;
  2954. ru->account_id = GetAccountID ( );
  2955. ru->char_id = GetCharacterID ( );
  2956. ru->race = player->GetRace ( );
  2957. ru->model_type = player->GetModelType ( );
  2958. loginserver.SendPacket ( outpack );
  2959. safe_delete(outpack);
  2960. }
  2961. if(flag&ZONE_UPDATE_FLAG){
  2962. ServerPacket* outpack = new ServerPacket(ServerOP_ZoneUpdate, CHARZONESTRUCT_MAXSIZE);
  2963. memset(outpack->pBuffer, 0, CHARZONESTRUCT_MAXSIZE);
  2964. CharZoneUpdate_Struct* czu = (CharZoneUpdate_Struct*)outpack->pBuffer;
  2965. czu->account_id = GetAccountID();
  2966. czu->char_id = GetCharacterID();
  2967. czu->zone_id = GetCurrentZone()->GetZoneID();
  2968. const char* zone_file = GetCurrentZone()->GetZoneFile();
  2969. czu->zone_length = strlen(zone_file);
  2970. if(czu->zone_length > 64)
  2971. czu->zone_length = 64;
  2972. strncpy(czu->new_zone, zone_file, czu->zone_length);
  2973. loginserver.SendPacket(outpack);
  2974. safe_delete(outpack);
  2975. }
  2976. if(flag&ARMOR_UPDATE_FLAG) {
  2977. LogWrite(MISC__TODO, 1, "TODO", "Armor update req in func: %s, line: %i", __FUNCTION__, __LINE__);
  2978. }
  2979. if(flag&NAME_UPDATE_FLAG) {
  2980. LogWrite(MISC__TODO, 1, "TODO", "Name update req in func: %s, line: %i", __FUNCTION__, __LINE__);
  2981. }
  2982. database.UpdateCharacterTimeStamp(GetAccountID ( ),GetCharacterID ( ),timestamp);
  2983. }
  2984. void Client::Save(){
  2985. if(current_zone){
  2986. DetermineCharacterUpdates();
  2987. UpdateCharacterInstances();
  2988. database.Save(this);
  2989. if(GetPlayer()->UpdateQuickbarNeeded()){
  2990. database.SaveQuickBar(GetCharacterID(), GetPlayer()->GetQuickbar());
  2991. GetPlayer()->ResetQuickbarNeeded();
  2992. }
  2993. database.SaveItems(this);
  2994. database.SaveBuyBacks(this);
  2995. GetPlayer()->SaveHistory();
  2996. GetPlayer()->SaveLUAHistory();
  2997. }
  2998. }
  2999. void Client::UpdateCharacterInstances() {
  3000. if (GetPlayer() != NULL)
  3001. GetPlayer()->GetCharacterInstances()->ProcessInstanceTimers(GetPlayer());
  3002. /*if ( GetPlayer() != NULL )
  3003. {
  3004. // determine the last timestamp then get a new one, determine the difference in the timestamp
  3005. // to use for applying the update to each instances timer
  3006. int32 lastSaveTS = GetLastSavedTimeStamp();
  3007. int32 newSaveTS = Timer::GetUnixTimeStamp();
  3008. int32 diffTS = newSaveTS - lastSaveTS;
  3009. // update instance timers
  3010. GetPlayer()->GetCharacterInstances().ProcessInstanceTimers(GetPlayer(),diffTS);
  3011. // update with the new timestamp and save the db
  3012. this->SetLastSavedTimeStamp(newSaveTS);
  3013. }*/
  3014. }
  3015. void Client::HandleVerbRequest(EQApplicationPacket* app){
  3016. PacketStruct* packet = configReader.getStruct("WS_EntityVerbsRequest", GetVersion());
  3017. if(packet){
  3018. packet->LoadPacketData(app->pBuffer, app->size);
  3019. int32 spawn_id = packet->getType_int32_ByName("spawn_id");
  3020. PacketStruct* out = configReader.getStruct("WS_EntityVerbsResponse", GetVersion());
  3021. Spawn* spawn = GetPlayer()->GetSpawnWithPlayerID(spawn_id);
  3022. vector<EntityCommand*> commands;
  3023. vector<EntityCommand*> delete_commands;
  3024. if(out && spawn){
  3025. for(int32 i=0;i<spawn->primary_command_list.size();i++)
  3026. commands.push_back(spawn->primary_command_list[i]);
  3027. for(int32 i=0;i<spawn->secondary_command_list.size();i++)
  3028. commands.push_back(spawn->secondary_command_list[i]);
  3029. if(spawn->IsPlayer()){
  3030. if(player->IsFriend(spawn->GetName()))
  3031. delete_commands.push_back(player->CreateEntityCommand("remove from friends list", 10000, "friend_remove", "", 0, 0));
  3032. else
  3033. delete_commands.push_back(player->CreateEntityCommand("add to friends list", 10000, "friend_add", "", 0, 0));
  3034. if(player->IsIgnored(spawn->GetName()))
  3035. delete_commands.push_back(player->CreateEntityCommand("remove from ignore list", 10000, "ignore_remove", "", 0, 0));
  3036. else
  3037. delete_commands.push_back(player->CreateEntityCommand("add to ignore list", 10000, "ignore_add", "", 0, 0));
  3038. if(((Player*)spawn)->GetGroupMemberInfo()) {
  3039. if(player->IsGroupMember((Player*)spawn) && player->GetGroupMemberInfo()->leader) { //group leader
  3040. delete_commands.push_back(player->CreateEntityCommand("kick from group", 10000, "kickfromgroup", "", 0, 0));
  3041. delete_commands.push_back(player->CreateEntityCommand("make group leader", 10000, "makeleader", "", 0, 0));
  3042. }
  3043. }
  3044. else if(!player->GetGroupMemberInfo() || (player->GetGroupMemberInfo()->leader && world.GetGroupManager()->GetGroupSize(player->GetGroupMemberInfo()->group_id) < 6))
  3045. delete_commands.push_back(player->CreateEntityCommand("invite to group", 10000, "invite", "", 0, 0));
  3046. commands.insert(commands.end(), delete_commands.begin(), delete_commands.end());
  3047. }
  3048. out->setDataByName("spawn_id", spawn_id);
  3049. out->setArrayLengthByName("num_verbs", commands.size());
  3050. for(int32 i=0;i<commands.size();i++){
  3051. out->setArrayDataByName("command", commands[i]->command.c_str(), i);
  3052. out->setArrayDataByName("distance", commands[i]->distance, i);
  3053. if(commands[i]->error_text.length() == 0)
  3054. out->setArrayAddToPacketByName("error", false, i);
  3055. else{
  3056. out->setArrayDataByName("display_error", 1, i);
  3057. out->setArrayDataByName("error", commands[i]->error_text.c_str(), i);
  3058. }
  3059. out->setArrayDataByName("display_text", commands[i]->name.c_str(), i);
  3060. }
  3061. EQ2Packet* outapp = out->serialize();
  3062. //DumpPacket(outapp);
  3063. QueuePacket(outapp);
  3064. safe_delete(out);
  3065. for(int32 i=0;i<delete_commands.size();i++){
  3066. safe_delete(delete_commands[i]);
  3067. }
  3068. }
  3069. safe_delete(packet);
  3070. }
  3071. }
  3072. void Client::SkillChanged(Skill* skill, int16 previous_value, int16 new_value){
  3073. if (previous_value != new_value) {
  3074. Message(CHANNEL_COLOR_SKILL, "You get %s at %s (%i/%i).", new_value > previous_value ? "better" : "worse", skill->name.data.c_str(), new_value, skill->max_val);
  3075. char tmp[200] = { 0 };
  3076. sprintf(tmp, "\\#6EFF6EYou get %s at \12\\#C8FFC8%s\\#6EFF6E! (%i/%i)", new_value > previous_value ? "better" : "worse", skill->name.data.c_str(), new_value, skill->max_val);
  3077. SendPopupMessage(6, tmp, new_value > previous_value ? "skill_up" : "skill_down", 2.75, 0xFF, 0xFF, 0xFF);
  3078. }
  3079. }
  3080. void Client::SendPopupMessage(int8 unknown, const char* text, const char* type, float size, int8 red, int8 green, int8 blue)
  3081. {
  3082. /* JA notes on the unknown:
  3083. 2 = ding glimmer
  3084. 16 = Achievement Unlocked
  3085. 6 no longer does anything
  3086. */
  3087. PacketStruct* packet = configReader.getStruct("WS_OnScreenMsg", GetVersion());
  3088. if(packet){
  3089. packet->setDataByName("unknown", unknown);
  3090. packet->setMediumStringByName("text", text);
  3091. if (type && strlen(type) > 0)
  3092. packet->setMediumStringByName("message_type", type);
  3093. packet->setDataByName("size", size);
  3094. packet->setDataByName("red", red);
  3095. packet->setDataByName("green", green);
  3096. packet->setDataByName("blue", blue);
  3097. QueuePacket(packet->serialize());
  3098. safe_delete(packet);
  3099. }
  3100. }
  3101. void Client::ChangeLevel(int16 old_level, int16 new_level){
  3102. if (new_level < 1) {
  3103. SimpleMessage(CHANNEL_COLOR_RED, "You cannot be lower than level 1!");
  3104. return;
  3105. }
  3106. if(player->GetLevel() != new_level){
  3107. player->SetLevel(new_level);
  3108. if (player->GetGroupMemberInfo()) {
  3109. player->UpdateGroupMemberInfo();
  3110. world.GetGroupManager()->SendGroupUpdate(player->GetGroupMemberInfo()->group_id);
  3111. }
  3112. }
  3113. if (new_level > old_level)
  3114. player->UpdatePlayerHistory(HISTORY_TYPE_XP, HISTORY_SUBTYPE_ADVENTURE, new_level, player->GetAdventureClass());
  3115. if (player->GetPet()) {
  3116. NPC* pet = (NPC*)player->GetPet();
  3117. if (pet->GetMaxPetLevel() == 0 || new_level <= pet->GetMaxPetLevel()) {
  3118. pet->SetLevel(new_level);
  3119. PacketStruct* command_packet=configReader.getStruct("WS_CannedEmote", GetVersion());
  3120. if (command_packet){
  3121. command_packet->setDataByName("spawn_id", player->GetIDWithPlayerSpawn(pet));
  3122. command_packet->setDataByName("anim_type",1753);
  3123. QueuePacket(command_packet->serialize());
  3124. safe_delete(command_packet);
  3125. }
  3126. }
  3127. }
  3128. PacketStruct* level_update = configReader.getStruct("WS_LevelChanged", GetVersion());
  3129. if(level_update){
  3130. level_update->setDataByName("old_level", old_level);
  3131. level_update->setDataByName("new_level", new_level);
  3132. QueuePacket(level_update->serialize());
  3133. safe_delete(level_update);
  3134. GetCurrentZone()->StartZoneSpawnsForLevelThread(this);
  3135. //GetCurrentZone()->SendAllSpawnsForLevelChange(this);
  3136. }
  3137. PacketStruct* command_packet=configReader.getStruct("WS_CannedEmote", GetVersion());
  3138. if (command_packet){
  3139. command_packet->setDataByName("spawn_id", player->GetIDWithPlayerSpawn(player));
  3140. command_packet->setDataByName("anim_type",1753);
  3141. QueuePacket(command_packet->serialize());
  3142. safe_delete(command_packet);
  3143. }
  3144. if (!player->get_character_flag(CF_ENABLE_CHANGE_LASTNAME) && new_level >= rule_manager.GetGlobalRule(R_Player, MinLastNameLevel)->GetInt8())
  3145. player->set_character_flag(CF_ENABLE_CHANGE_LASTNAME);
  3146. SendNewSpells(player->GetAdventureClass());
  3147. SendNewSpells(classes.GetBaseClass(player->GetAdventureClass()));
  3148. SendNewSpells(classes.GetSecondaryBaseClass(player->GetAdventureClass()));
  3149. GetPlayer()->ChangePrimaryWeapon();
  3150. GetPlayer()->ChangeSecondaryWeapon();
  3151. GetPlayer()->ChangeRangedWeapon();
  3152. GetPlayer()->GetInfoStruct()->level = new_level;
  3153. // GetPlayer()->SetLevel(new_level);
  3154. LogWrite(MISC__TODO, 1, "TODO", "Get new HP/POWER/stat based on default values from DB\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
  3155. GetPlayer()->SetTotalHPBase(new_level*new_level*2+40);
  3156. GetPlayer()->SetTotalPowerBase((sint32)(new_level*new_level*2.1+45));
  3157. GetPlayer()->CalculateBonuses();
  3158. GetPlayer()->SetHP(GetPlayer()->GetTotalHP());
  3159. GetPlayer()->SetPower(GetPlayer()->GetTotalPower());
  3160. InfoStruct* info = player->GetInfoStruct();
  3161. info->agi_base = new_level*2+15;
  3162. info->intel_base = new_level*2+15;
  3163. info->wis_base = new_level*2+15;
  3164. info->str_base = new_level*2+15;
  3165. info->sta_base = new_level*2+15;
  3166. info->cold_base = (int16)(new_level*1.5+10);
  3167. info->heat_base = (int16)(new_level*1.5+10);
  3168. info->disease_base = (int16)(new_level*1.5+10);
  3169. info->mental_base = (int16)(new_level*1.5+10);
  3170. info->magic_base = (int16)(new_level*1.5+10);
  3171. info->divine_base = (int16)(new_level*1.5+10);
  3172. info->poison_base = (int16)(new_level*1.5+10);
  3173. GetPlayer()->SetHPRegen((int)(new_level*.75)+(int)(new_level/10)+3);
  3174. GetPlayer()->SetPowerRegen(new_level+(int)(new_level/10)+4);
  3175. GetPlayer()->GetInfoStruct()->poison_base = (int16)(new_level*1.5+10);
  3176. UpdateTimeStampFlag ( LEVEL_UPDATE_FLAG );
  3177. GetPlayer()->SetCharSheetChanged(true);
  3178. Message(CHANNEL_COLOR_EXP,"You are now level %i!", new_level);
  3179. LogWrite(WORLD__DEBUG, 0, "World", "Player: %s leveled from %u to %u", GetPlayer()->GetName(), old_level, new_level);
  3180. int16 new_skill_cap = 5 * new_level;
  3181. PlayerSkillList* player_skills = player->GetSkills();
  3182. player_skills->SetSkillCapsByType(SKILL_TYPE_COMBAT, new_skill_cap);
  3183. player_skills->SetSkillCapsByType(SKILL_TYPE_SPELLCASTING, new_skill_cap);
  3184. player_skills->SetSkillCapsByType(SKILL_TYPE_AVOIDANCE, new_skill_cap);
  3185. player_skills->SetSkillCapsByType(SKILL_TYPE_GENERAL, new_skill_cap);
  3186. if (new_level > player->GetTSLevel())
  3187. player_skills->SetSkillCapsByType(SKILL_TYPE_HARVESTING, new_skill_cap);
  3188. Guild* guild = GetPlayer()->GetGuild();
  3189. if (guild) {
  3190. int8 event_type = 0;
  3191. if (new_level < 10)
  3192. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_1_10;
  3193. else if (new_level == 10)
  3194. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_10;
  3195. else if (new_level >= 11 && new_level < 20)
  3196. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_11_20;
  3197. else if (new_level == 20)
  3198. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_20;
  3199. else if (new_level >= 21 && new_level < 30)
  3200. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_21_30;
  3201. else if (new_level == 30)
  3202. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_30;
  3203. else if (new_level >= 31 && new_level < 40)
  3204. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_31_40;
  3205. else if (new_level == 40)
  3206. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_40;
  3207. else if (new_level >= 41 && new_level < 50)
  3208. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_41_50;
  3209. else if (new_level == 50)
  3210. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_50;
  3211. else if (new_level >= 51 && new_level < 60)
  3212. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_51_60;
  3213. else if (new_level == 60)
  3214. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_60;
  3215. else if (new_level >= 61 && new_level < 70)
  3216. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_61_70;
  3217. else if (new_level == 70)
  3218. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_70;
  3219. else if (new_level >= 71 && new_level < 80)
  3220. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_71_80;
  3221. else if (new_level == 80)
  3222. event_type = GUILD_EVENT_GAINS_ADV_LEVEL_80;
  3223. guild->AddNewGuildEvent(event_type, "%s has gained an adventure level and is now a level %u %s.", Timer::GetUnixTimeStamp(), true, GetPlayer()->GetName(), new_level, classes.GetClassNameCase(GetPlayer()->GetAdventureClass()).c_str());
  3224. guild->SendMessageToGuild(event_type, "%s has gained an adventure level and is now a level %u %s.", GetPlayer()->GetName(), new_level, classes.GetClassNameCase(GetPlayer()->GetAdventureClass()).c_str());
  3225. guild->UpdateGuildMemberInfo(GetPlayer());
  3226. guild->SendGuildMember(GetPlayer());
  3227. guild->SendGuildMemberList();
  3228. }
  3229. // Need to send the trait list every time the players level changes
  3230. // Also need to force the char sheet update or else there can be a large delay from when you level
  3231. // to when you are actually able to select traits.
  3232. QueuePacket(GetPlayer()->GetPlayerInfo()->serialize(GetVersion()));
  3233. QueuePacket(master_trait_list.GetTraitListPacket(this));
  3234. master_aa_list.DisplayAA(this, 0, 0);
  3235. if (GetPlayer()->SpawnedBots.size() > 0) {
  3236. map<int32, int32>::iterator itr;
  3237. for (itr = GetPlayer()->SpawnedBots.begin(); itr != GetPlayer()->SpawnedBots.end(); itr++) {
  3238. Spawn* bot = GetCurrentZone()->GetSpawnByID(itr->second);
  3239. if (bot && bot->IsBot())
  3240. ((Bot*)bot)->ChangeLevel(old_level, new_level);
  3241. }
  3242. }
  3243. }
  3244. void Client::ChangeTSLevel(int16 old_level, int16 new_level){
  3245. if (new_level < 1) {
  3246. SimpleMessage(CHANNEL_COLOR_RED, "You cannot be lower than level 1!");
  3247. return;
  3248. }
  3249. if ((player->GetTSLevel() >= 9 && player->GetTradeskillClass() == 1) || (player->GetTSLevel() >= 19 && (player->GetTradeskillClass() == 1 || player->GetTradeskillClass() == 2 || player->GetTradeskillClass() == 6 || player->GetTradeskillClass() == 10))) {
  3250. SimpleMessage(CHANNEL_COLOR_YELLOW, "You can not gain levels until you select your next class!");
  3251. return;
  3252. }
  3253. if (new_level > old_level)
  3254. player->UpdatePlayerHistory(HISTORY_TYPE_XP, HISTORY_SUBTYPE_TRADESKILL, new_level, player->GetTradeskillClass());
  3255. if(player->GetTSLevel() != new_level){
  3256. player->SetTSLevel(new_level);
  3257. if (player->GetGroupMemberInfo()) {
  3258. player->UpdateGroupMemberInfo();
  3259. world.GetGroupManager()->SendGroupUpdate(player->GetGroupMemberInfo()->group_id);
  3260. }
  3261. }
  3262. // Only tradeskill skills should increace, and then only those related to your class
  3263. PacketStruct* level_update = configReader.getStruct("WS_LevelChanged", GetVersion());
  3264. if(level_update){
  3265. level_update->setDataByName("old_level", old_level);
  3266. level_update->setDataByName("new_level", new_level);
  3267. level_update->setDataByName("type", 1);
  3268. QueuePacket(level_update->serialize());
  3269. safe_delete(level_update);
  3270. }
  3271. // Need to make tradeskill versions of the following
  3272. //SendNewSpells(player->GetAdventureClass());
  3273. //SendNewSpells(classes.GetBaseClass(player->GetAdventureClass()));
  3274. //SendNewSpells(classes.GetSecondaryBaseClass(player->GetAdventureClass()));
  3275. PacketStruct* command_packet=configReader.getStruct("WS_CannedEmote", GetVersion());
  3276. if (command_packet){
  3277. command_packet->setDataByName("spawn_id", GetPlayer()->GetIDWithPlayerSpawn(GetPlayer()));
  3278. command_packet->setDataByName("anim_type",1753);
  3279. QueuePacket(command_packet->serialize());
  3280. safe_delete(command_packet);
  3281. }
  3282. GetPlayer()->GetInfoStruct()->tradeskill_level = new_level;
  3283. GetPlayer()->SetTSLevel(new_level);
  3284. UpdateTimeStampFlag ( LEVEL_UPDATE_FLAG );
  3285. GetPlayer()->SetCharSheetChanged(true);
  3286. Message(CHANNEL_COLOR_WHITE,"Your tradeskill level is now %i!", new_level);
  3287. LogWrite(WORLD__DEBUG, 0, "World", "Player: %s leveled from %u to %u", GetPlayer()->GetName(), old_level, new_level);
  3288. PlayerSkillList* player_skills = player->GetSkills();
  3289. int16 specialize_skill_cap = new_level * 5;
  3290. int16 artisan_skill_cap = std::max<int16>(specialize_skill_cap, 49);
  3291. int16 specialize_10_skill_cap = std::max<int16>(specialize_skill_cap, 99);
  3292. int8 ts_class = player->GetTradeskillClass();
  3293. int8 base_ts_class = classes.GetSecondaryTSBaseClass(ts_class);
  3294. int32 skill_id_1, skill_id_2, skill_id_3;
  3295. switch (base_ts_class) {
  3296. case ARTISAN:
  3297. player_skills->SetSkillCapsByType(SKILL_TYPE_OUTFITTER, artisan_skill_cap);
  3298. player_skills->SetSkillCapsByType(SKILL_TYPE_SCHOLAR, artisan_skill_cap);
  3299. player_skills->SetSkillCapsByType(SKILL_TYPE_CRAFTSMAN, artisan_skill_cap);
  3300. break;
  3301. case OUTFITTER:
  3302. player_skills->SetSkillCapsByType(SKILL_TYPE_SCHOLAR, artisan_skill_cap);
  3303. player_skills->SetSkillCapsByType(SKILL_TYPE_CRAFTSMAN, artisan_skill_cap);
  3304. skill_id_1 = SKILL_ID_TAILORING;
  3305. skill_id_2 = SKILL_ID_METALSHAPING;
  3306. skill_id_3 = SKILL_ID_METALWORKING;
  3307. if (ts_class == TAILOR) {
  3308. player_skills->SetSkillCap(skill_id_1, specialize_skill_cap);
  3309. skill_id_1 = 0;
  3310. }
  3311. else if (ts_class == ARMORER) {
  3312. player_skills->SetSkillCap(skill_id_2, specialize_skill_cap);
  3313. skill_id_2 = 0;
  3314. }
  3315. else if (ts_class == WEAPONSMITH) {
  3316. player_skills->SetSkillCap(skill_id_3, specialize_skill_cap);
  3317. skill_id_3 = 0;
  3318. }
  3319. if (skill_id_1) player_skills->SetSkillCap(skill_id_1, specialize_10_skill_cap);
  3320. if (skill_id_2) player_skills->SetSkillCap(skill_id_2, specialize_10_skill_cap);
  3321. if (skill_id_3) player_skills->SetSkillCap(skill_id_3, specialize_10_skill_cap);
  3322. break;
  3323. case SCHOLAR:
  3324. player_skills->SetSkillCapsByType(SKILL_TYPE_OUTFITTER, artisan_skill_cap);
  3325. player_skills->SetSkillCapsByType(SKILL_TYPE_CRAFTSMAN, artisan_skill_cap);
  3326. skill_id_1 = SKILL_ID_SCRIBING;
  3327. skill_id_2 = SKILL_ID_CHEMISTRY;
  3328. skill_id_3 = SKILL_ID_ARTIFICING;
  3329. if (ts_class == SAGE) {
  3330. player_skills->SetSkillCap(skill_id_1, specialize_skill_cap);
  3331. skill_id_1 = 0;
  3332. }
  3333. else if (ts_class == ALCHEMIST) {
  3334. player_skills->SetSkillCap(skill_id_2, specialize_skill_cap);
  3335. skill_id_2 = 0;
  3336. }
  3337. else if (ts_class == JEWELER) {
  3338. player_skills->SetSkillCap(skill_id_3, specialize_skill_cap);
  3339. skill_id_3 = 0;
  3340. }
  3341. if (skill_id_1) player_skills->SetSkillCap(skill_id_1, specialize_10_skill_cap);
  3342. if (skill_id_2) player_skills->SetSkillCap(skill_id_2, specialize_10_skill_cap);
  3343. if (skill_id_3) player_skills->SetSkillCap(skill_id_3, specialize_10_skill_cap);
  3344. break;
  3345. case CRAFTSMAN:
  3346. player_skills->SetSkillCapsByType(SKILL_TYPE_OUTFITTER, artisan_skill_cap);
  3347. player_skills->SetSkillCapsByType(SKILL_TYPE_SCHOLAR, artisan_skill_cap);
  3348. skill_id_1 = SKILL_ID_ARTISTRY;
  3349. skill_id_2 = SKILL_ID_FLETCHING;
  3350. skill_id_3 = SKILL_ID_SCULPTING;
  3351. if (ts_class == PROVISIONER) {
  3352. player_skills->SetSkillCap(skill_id_1, specialize_skill_cap);
  3353. skill_id_1 = 0;
  3354. }
  3355. else if (ts_class == WOODWORKER) {
  3356. player_skills->SetSkillCap(skill_id_2, specialize_skill_cap);
  3357. skill_id_2 = 0;
  3358. }
  3359. else if (ts_class == CARPENTER) {
  3360. player_skills->SetSkillCap(skill_id_3, specialize_skill_cap);
  3361. skill_id_3 = 0;
  3362. }
  3363. if (skill_id_1) player_skills->SetSkillCap(skill_id_1, specialize_10_skill_cap);
  3364. if (skill_id_2) player_skills->SetSkillCap(skill_id_2, specialize_10_skill_cap);
  3365. if (skill_id_3) player_skills->SetSkillCap(skill_id_3, specialize_10_skill_cap);
  3366. break;
  3367. default:
  3368. break;
  3369. }
  3370. if (new_level > player->GetAdventureClass())
  3371. player_skills->SetSkillCapsByType(SKILL_TYPE_HARVESTING, specialize_skill_cap);
  3372. Guild* guild = GetPlayer()->GetGuild();
  3373. if (guild) {
  3374. int8 event_type = 0;
  3375. if (new_level < 10)
  3376. event_type = GUILD_EVENT_GAINS_TS_LEVEL_1_10;
  3377. else if (new_level == 10)
  3378. event_type = GUILD_EVENT_GAINS_TS_LEVEL_10;
  3379. else if (new_level >= 11 && new_level < 20)
  3380. event_type = GUILD_EVENT_GAINS_TS_LEVEL_11_20;
  3381. else if (new_level == 20)
  3382. event_type = GUILD_EVENT_GAINS_TS_LEVEL_20;
  3383. else if (new_level >= 21 && new_level < 30)
  3384. event_type = GUILD_EVENT_GAINS_TS_LEVEL_21_30;
  3385. else if (new_level == 30)
  3386. event_type = GUILD_EVENT_GAINS_TS_LEVEL_30;
  3387. else if (new_level >= 31 && new_level < 40)
  3388. event_type = GUILD_EVENT_GAINS_TS_LEVEL_31_40;
  3389. else if (new_level == 40)
  3390. event_type = GUILD_EVENT_GAINS_TS_LEVEL_40;
  3391. else if (new_level >= 41 && new_level < 50)
  3392. event_type = GUILD_EVENT_GAINS_TS_LEVEL_41_50;
  3393. else if (new_level == 50)
  3394. event_type = GUILD_EVENT_GAINS_TS_LEVEL_50;
  3395. else if (new_level >= 51 && new_level < 60)
  3396. event_type = GUILD_EVENT_GAINS_TS_LEVEL_51_60;
  3397. else if (new_level == 60)
  3398. event_type = GUILD_EVENT_GAINS_TS_LEVEL_60;
  3399. else if (new_level >= 61 && new_level < 70)
  3400. event_type = GUILD_EVENT_GAINS_TS_LEVEL_61_70;
  3401. else if (new_level == 70)
  3402. event_type = GUILD_EVENT_GAINS_TS_LEVEL_70;
  3403. else if (new_level >= 71 && new_level < 80)
  3404. event_type = GUILD_EVENT_GAINS_TS_LEVEL_71_80;
  3405. else if (new_level == 80)
  3406. event_type = GUILD_EVENT_GAINS_TS_LEVEL_80;
  3407. guild->AddNewGuildEvent(event_type, "%s has gained a tradeskill level and is now a level %u %s.", Timer::GetUnixTimeStamp(), true, GetPlayer()->GetName(), new_level, classes.GetClassNameCase(GetPlayer()->GetTradeskillClass() + 42).c_str());
  3408. guild->SendMessageToGuild(event_type, "%s has gained a tradeskill level and is now a level %u %s.", GetPlayer()->GetName(), new_level, classes.GetClassNameCase(GetPlayer()->GetTradeskillClass() + 42).c_str());
  3409. guild->UpdateGuildMemberInfo(GetPlayer());
  3410. guild->SendGuildMember(GetPlayer());
  3411. guild->SendGuildMemberList();
  3412. }
  3413. // Need to send the trait list every time the players level changes
  3414. // Also need to force the char sheet update or else there can be a large delay from when you level
  3415. // to when you are actually able to select traits.
  3416. QueuePacket(GetPlayer()->GetPlayerInfo()->serialize(GetVersion()));
  3417. QueuePacket(master_trait_list.GetTraitListPacket(this));
  3418. }
  3419. void Client::SendPendingLoot(int32 total_coins, Entity* entity){
  3420. if(entity)
  3421. Loot(total_coins, player->GetPendingLootItems(entity->GetID()), entity);
  3422. }
  3423. void Client::CloseLoot(){
  3424. PacketStruct* packet = configReader.getStruct("WS_CloseWindow", GetVersion());
  3425. packet->setDataByName("window_id", 4);
  3426. EQ2Packet* outapp = packet->serialize();
  3427. //DumpPacket(outapp);
  3428. QueuePacket(outapp);
  3429. safe_delete(packet);
  3430. }
  3431. string Client::GetCoinMessage(int32 total_coins){
  3432. if(total_coins == 0) {
  3433. return " 0 Copper";
  3434. }
  3435. char tmp[64] = {0};
  3436. string message = "";
  3437. int32 val = 0;
  3438. if(total_coins >= 1000000){
  3439. val = total_coins / 1000000;
  3440. total_coins -= 1000000 * val;
  3441. sprintf(tmp, " %u Platinum", val);
  3442. message.append(tmp);
  3443. memset(tmp, 0, 64);
  3444. }
  3445. if(total_coins >= 10000){
  3446. val = total_coins / 10000;
  3447. total_coins -= 10000 * val;
  3448. sprintf(tmp, " %u Gold", val);
  3449. message.append(tmp);
  3450. memset(tmp, 0, 64);
  3451. }
  3452. if(total_coins >= 100){
  3453. val = total_coins / 100;
  3454. total_coins -= 100 * val;
  3455. sprintf(tmp, " %u Silver", val);
  3456. message.append(tmp);
  3457. memset(tmp, 0, 64);
  3458. }
  3459. if(total_coins > 0){
  3460. sprintf(tmp, " %u Copper", (int32)total_coins);
  3461. message.append(tmp);
  3462. }
  3463. return message;
  3464. }
  3465. void Client::Loot(int32 total_coins, vector<Item*>* items, Entity* entity){
  3466. if(!entity){
  3467. CloseLoot();
  3468. return;
  3469. }
  3470. if(total_coins > 0){
  3471. player->AddCoins(total_coins);
  3472. //PlaySound("coin_cha_ching");
  3473. string message = "";
  3474. if(entity->GetHP() == 0){
  3475. message = "You loot ";
  3476. entity->SetLootCoins(0);
  3477. }
  3478. else
  3479. message = "You receive ";
  3480. message.append(GetCoinMessage(total_coins));
  3481. if(entity->GetHP() == 0)
  3482. message.append(" from the corpse of ").append(entity->GetName());
  3483. int8 type = CHANNEL_COLOR_LOOT;
  3484. if (GetVersion() >= 1208)
  3485. type = CHANNEL_LOOT;
  3486. else if(GetVersion() >= 973)
  3487. type = CHANNEL_COLOR_NEW_LOOT;
  3488. SimpleMessage(type, message.c_str());
  3489. }
  3490. if(!items || items->size() == 0)
  3491. CloseLoot();
  3492. PacketStruct* packet = configReader.getStruct("WS_UpdateLoot", GetVersion());
  3493. if(packet){
  3494. vector<Item*>::iterator itr;
  3495. int32 packet_size = 0;
  3496. if(items && items->size() > 0){
  3497. packet->setDataByName("loot_count", items->size());
  3498. packet->setDataByName("display", 1);
  3499. }
  3500. packet->setDataByName("unknown2", 1);
  3501. if (version >= 1096)
  3502. packet->setDataByName("unknown3", 0x78);
  3503. else
  3504. packet->setDataByName("unknown3", 0x3C);
  3505. packet->setDataByName("loot_id", entity->GetID());
  3506. EQ2Packet* tmpPacket = packet->serialize();
  3507. packet_size += tmpPacket->size;
  3508. uchar* data = 0;
  3509. if(items && items->size() > 0){
  3510. data = new uchar[items->size()*1000 + packet_size];
  3511. memset(data, 0, items->size()*1000 + packet_size);
  3512. }
  3513. else{
  3514. data = new uchar[packet_size];
  3515. memset(data, 0, packet_size);
  3516. }
  3517. uchar* ptr = data;
  3518. memcpy(ptr, tmpPacket->pBuffer, tmpPacket->size);
  3519. ptr += tmpPacket->size;
  3520. safe_delete(tmpPacket);
  3521. Item* item = 0;
  3522. if(items && items->size() > 0){
  3523. for(itr = items->begin(); itr != items->end(); itr++){
  3524. item = *itr;
  3525. memcpy(ptr, &item->details.item_id, sizeof(int32));
  3526. ptr += sizeof(int32);
  3527. packet_size += sizeof(int32);
  3528. tmpPacket = item->serialize(GetVersion(), true, GetPlayer(), false, 1, 0, false, true);
  3529. int8 offset = 0;
  3530. if (GetVersion() >= 1188) {
  3531. offset = 13;
  3532. }
  3533. else if (GetVersion() >= 860){
  3534. offset = 11;
  3535. }
  3536. else{
  3537. offset = 10;
  3538. }
  3539. memcpy(ptr, tmpPacket->pBuffer + offset, tmpPacket->size - offset);
  3540. ptr += tmpPacket->size - offset;
  3541. packet_size += tmpPacket->size - offset;
  3542. safe_delete(tmpPacket);
  3543. }
  3544. }
  3545. packet_size -= sizeof(int32);
  3546. memcpy(data, &packet_size, sizeof(int32));
  3547. packet_size += sizeof(int32);
  3548. EQ2Packet* outapp = new EQ2Packet(OP_ClientCmdMsg, data, packet_size);
  3549. //DumpPacket(outapp);
  3550. QueuePacket(outapp);
  3551. safe_delete_array(data);
  3552. safe_delete(packet);
  3553. }
  3554. }
  3555. void Client::Loot(Entity* entity){
  3556. if(entity->IsNPC() && ((NPC*)entity)->Brain()->CheckLootAllowed(GetPlayer())){
  3557. int32 total_coins = entity->GetLootCoins();
  3558. entity->LockLoot();
  3559. Loot(total_coins, entity->GetLootItems(), entity);
  3560. entity->UnlockLoot();
  3561. int32 state = 0;
  3562. // Check for the chest and set the action state
  3563. /*4034 = small chest | 5864 = treasure chest | 5865 = ornate treasure chest | 4015 = exquisite chest*/
  3564. if (entity->GetModelType() == 4034) {
  3565. // small chest, open with copper coins
  3566. state = 11899;
  3567. }
  3568. else if (entity->GetModelType() == 5864) {
  3569. // treasure chest, open with silver coins
  3570. state = 11901;
  3571. }
  3572. else if (entity->GetModelType() == 5865) {
  3573. // ornate chest, open with gold coins
  3574. state = 11900;
  3575. }
  3576. else if (entity->GetModelType() == 4015) {
  3577. // exquisite chest, open with gold coins and jewels as well as a glow effect
  3578. state = 11898;
  3579. }
  3580. // We set the visual state with out updating so those not in range will see it opened when it is finally sent to them,
  3581. // for those in range the SendStateCommand will cause it to animate open.
  3582. entity->SetVisualState(state, false);
  3583. GetCurrentZone()->SendStateCommand(entity, state);
  3584. }
  3585. else
  3586. SimpleMessage(CHANNEL_COLOR_YELLOW, "You are not allowed to loot at this time.");
  3587. }
  3588. Spawn* Client::GetBanker(){
  3589. return banker;
  3590. }
  3591. void Client::SetBanker(Spawn* in_banker){
  3592. banker = in_banker;
  3593. }
  3594. void Client::Bank(Spawn* banker, bool cancel){
  3595. if(banker && banker->primary_command_list.size() > 0 && banker->primary_command_list[0]->command == "bank"){
  3596. if(!cancel)
  3597. SetBanker(banker);
  3598. else
  3599. SetBanker(0);
  3600. PacketStruct* packet = configReader.getStruct("WS_UpdateBank", GetVersion());
  3601. if(packet){
  3602. packet->setDataByName("spawn_id", GetPlayer()->GetIDWithPlayerSpawn(banker));
  3603. int64 coins = GetPlayer()->GetInfoStruct()->bank_coin_copper + GetPlayer()->GetInfoStruct()->bank_coin_silver * 100 +
  3604. GetPlayer()->GetInfoStruct()->bank_coin_gold * 10000 + (int64)GetPlayer()->GetInfoStruct()->bank_coin_plat * 1000000;
  3605. int32 coins1, coins2;
  3606. coins1 = ((int32*)&coins)[0];
  3607. coins2 = ((int32*)&coins)[1];
  3608. packet->setDataByName("bank_coins", coins1);
  3609. packet->setDataByName("bank_coins2", coins2);
  3610. packet->setDataByName("copper", GetPlayer()->GetInfoStruct()->coin_copper);
  3611. packet->setDataByName("silver", GetPlayer()->GetInfoStruct()->coin_silver);
  3612. packet->setDataByName("gold", GetPlayer()->GetInfoStruct()->coin_gold);
  3613. packet->setDataByName("plat", GetPlayer()->GetInfoStruct()->coin_plat);
  3614. if(!cancel)
  3615. packet->setDataByName("display", 1);
  3616. QueuePacket(packet->serialize());
  3617. safe_delete(packet);
  3618. }
  3619. }
  3620. }
  3621. void Client::BankWithdrawal(int64 amount){
  3622. bool cheater = false;
  3623. if(GetBanker() && amount > 0){
  3624. string withdrawal = "";
  3625. char withdrawal_data[512] = {0};
  3626. int32 tmp = 0;
  3627. if(amount >= 1000000){
  3628. tmp = amount/1000000;
  3629. if(tmp > GetPlayer()->GetBankCoinsPlat())
  3630. cheater = true;
  3631. else{
  3632. GetPlayer()->GetInfoStruct()->bank_coin_plat -= tmp;
  3633. GetPlayer()->GetInfoStruct()->coin_plat += tmp;
  3634. amount -= (int64)tmp *1000000;
  3635. sprintf(withdrawal_data, "%u Platinum ", tmp);
  3636. withdrawal.append(withdrawal_data);
  3637. memset(withdrawal_data, 0, sizeof(withdrawal_data));
  3638. }
  3639. }
  3640. if(!cheater && amount >= 10000){
  3641. tmp = amount/10000;
  3642. if(tmp > GetPlayer()->GetBankCoinsGold())
  3643. cheater = true;
  3644. else{
  3645. GetPlayer()->GetInfoStruct()->bank_coin_gold -= tmp;
  3646. if ((GetPlayer()->GetInfoStruct()->coin_gold + tmp) > 100) {
  3647. GetPlayer()->GetInfoStruct()->coin_gold = (GetPlayer()->GetInfoStruct()->coin_gold + tmp) - 100;
  3648. GetPlayer()->GetInfoStruct()->coin_plat += 1;
  3649. }
  3650. else
  3651. GetPlayer()->GetInfoStruct()->coin_gold += tmp;
  3652. amount -= tmp *10000;
  3653. sprintf(withdrawal_data, "%u Gold ", tmp);
  3654. withdrawal.append(withdrawal_data);
  3655. memset(withdrawal_data, 0, sizeof(withdrawal_data));
  3656. }
  3657. }
  3658. if(!cheater && amount >= 100){
  3659. tmp = amount/100;
  3660. if(tmp > GetPlayer()->GetBankCoinsSilver())
  3661. cheater = true;
  3662. else{
  3663. GetPlayer()->GetInfoStruct()->bank_coin_silver -= tmp;
  3664. if ((GetPlayer()->GetInfoStruct()->coin_silver + tmp) > 100) {
  3665. GetPlayer()->GetInfoStruct()->coin_silver = (GetPlayer()->GetInfoStruct()->coin_silver + tmp) - 100;
  3666. GetPlayer()->GetInfoStruct()->coin_gold += 1;
  3667. }
  3668. else
  3669. GetPlayer()->GetInfoStruct()->coin_silver += tmp;
  3670. amount -= tmp *100;
  3671. sprintf(withdrawal_data, "%u Silver ", tmp);
  3672. withdrawal.append(withdrawal_data);
  3673. memset(withdrawal_data, 0, sizeof(withdrawal_data));
  3674. }
  3675. }
  3676. if(!cheater){
  3677. if(amount > 0){
  3678. sprintf(withdrawal_data, "%u Copper ", (int32)amount);
  3679. withdrawal.append(withdrawal_data);
  3680. GetPlayer()->GetInfoStruct()->bank_coin_copper -= amount;
  3681. if ((GetPlayer()->GetInfoStruct()->coin_copper + amount) > 100) {
  3682. GetPlayer()->GetInfoStruct()->coin_copper = (GetPlayer()->GetInfoStruct()->coin_copper + amount) - 100;
  3683. GetPlayer()->GetInfoStruct()->coin_silver += 1;
  3684. }
  3685. else
  3686. GetPlayer()->GetInfoStruct()->coin_copper += amount;
  3687. }
  3688. if(withdrawal.length() > 0){
  3689. withdrawal.append("withdrawn ");
  3690. sprintf(withdrawal_data, "(%u Plat %u Gold %u Silver %u Copper in the bank now.)", GetPlayer()->GetInfoStruct()->bank_coin_plat,
  3691. GetPlayer()->GetInfoStruct()->bank_coin_gold, GetPlayer()->GetInfoStruct()->bank_coin_silver, GetPlayer()->GetInfoStruct()->bank_coin_copper);
  3692. withdrawal.append(withdrawal_data);
  3693. SimpleMessage(CHANNEL_COLOR_REVIVE, withdrawal.c_str());
  3694. }
  3695. }
  3696. else
  3697. Message(CHANNEL_COLOR_RED, "Stop trying to cheat!");
  3698. player->SetCharSheetChanged(true);
  3699. Bank(banker);
  3700. }
  3701. }
  3702. void Client::BankDeposit(int64 amount){
  3703. bool cheater = false;
  3704. if(GetBanker() && amount > 0){
  3705. int32 tmp = 0;
  3706. char deposit_data[512] = {0};
  3707. string deposit = "";
  3708. if(amount >= 1000000){
  3709. tmp = amount/1000000;
  3710. if(tmp > GetPlayer()->GetCoinsPlat())
  3711. cheater = true;
  3712. else{
  3713. GetPlayer()->GetInfoStruct()->bank_coin_plat += tmp;
  3714. GetPlayer()->GetInfoStruct()->coin_plat -= tmp;
  3715. amount -= (int64)tmp *1000000;
  3716. sprintf(deposit_data, "%u Platinum ", tmp);
  3717. deposit.append(deposit_data);
  3718. memset(deposit_data, 0, sizeof(deposit_data));
  3719. }
  3720. }
  3721. if(!cheater && amount >= 10000){
  3722. tmp = amount/10000;
  3723. if(tmp > GetPlayer()->GetCoinsGold())
  3724. cheater = true;
  3725. else{
  3726. if ((GetPlayer()->GetInfoStruct()->bank_coin_gold + tmp) > 100) {
  3727. GetPlayer()->GetInfoStruct()->bank_coin_gold = (GetPlayer()->GetInfoStruct()->bank_coin_gold + tmp) - 100;
  3728. GetPlayer()->GetInfoStruct()->bank_coin_plat += 1;
  3729. }
  3730. else
  3731. GetPlayer()->GetInfoStruct()->bank_coin_gold += tmp;
  3732. GetPlayer()->GetInfoStruct()->coin_gold -= tmp;
  3733. amount -= tmp *10000;
  3734. sprintf(deposit_data, "%u Gold ", tmp);
  3735. deposit.append(deposit_data);
  3736. memset(deposit_data, 0, sizeof(deposit_data));
  3737. }
  3738. }
  3739. if(!cheater && amount >= 100){
  3740. tmp = amount/100;
  3741. if(tmp > GetPlayer()->GetCoinsSilver())
  3742. cheater = true;
  3743. else{
  3744. if ((GetPlayer()->GetInfoStruct()->bank_coin_silver + tmp) > 100) {
  3745. GetPlayer()->GetInfoStruct()->bank_coin_silver = (GetPlayer()->GetInfoStruct()->bank_coin_silver + tmp) - 100;
  3746. GetPlayer()->GetInfoStruct()->bank_coin_gold += 1;
  3747. }
  3748. else
  3749. GetPlayer()->GetInfoStruct()->bank_coin_silver += tmp;
  3750. GetPlayer()->GetInfoStruct()->coin_silver -= tmp;
  3751. amount -= tmp *100;
  3752. sprintf(deposit_data, "%u Silver ", tmp);
  3753. deposit.append(deposit_data);
  3754. memset(deposit_data, 0, sizeof(deposit_data));
  3755. }
  3756. }
  3757. if(!cheater){
  3758. if(amount > 0){
  3759. sprintf(deposit_data, "%u Copper ", (int32)amount);
  3760. deposit.append(deposit_data);
  3761. if ((GetPlayer()->GetInfoStruct()->bank_coin_copper + amount) > 100) {
  3762. GetPlayer()->GetInfoStruct()->bank_coin_copper = (GetPlayer()->GetInfoStruct()->bank_coin_copper + amount) - 100;
  3763. GetPlayer()->GetInfoStruct()->bank_coin_silver += 1;
  3764. }
  3765. else
  3766. GetPlayer()->GetInfoStruct()->bank_coin_copper += amount;
  3767. GetPlayer()->GetInfoStruct()->coin_copper -= amount;
  3768. }
  3769. if(deposit.length() > 0){
  3770. deposit.append("deposited ");
  3771. sprintf(deposit_data, "(%u Plat %u Gold %u Silver %u Copper in the bank now.)", GetPlayer()->GetInfoStruct()->bank_coin_plat,
  3772. GetPlayer()->GetInfoStruct()->bank_coin_gold, GetPlayer()->GetInfoStruct()->bank_coin_silver, GetPlayer()->GetInfoStruct()->bank_coin_copper);
  3773. deposit.append(deposit_data);
  3774. SimpleMessage(CHANNEL_COLOR_REVIVE, deposit.c_str());
  3775. }
  3776. }
  3777. else
  3778. Message(CHANNEL_COLOR_RED, "Stop trying to cheat!");
  3779. player->SetCharSheetChanged(true);
  3780. Bank(banker);
  3781. }
  3782. }
  3783. void Client::AddPendingQuestReward(Quest* quest){
  3784. MQuestPendingUpdates.writelock(__FUNCTION__, __LINE__);
  3785. quest_pending_reward.push_back(quest);
  3786. quest_updates = true;
  3787. MQuestPendingUpdates.releasewritelock(__FUNCTION__, __LINE__);
  3788. }
  3789. void Client::AddPendingQuestUpdate(int32 quest_id, int32 step_id, int32 progress){
  3790. MQuestPendingUpdates.writelock(__FUNCTION__, __LINE__);
  3791. quest_pending_updates[quest_id][step_id] = progress;
  3792. quest_updates = true;
  3793. MQuestPendingUpdates.releasewritelock(__FUNCTION__, __LINE__);
  3794. }
  3795. void Client::ProcessQuestUpdates(){
  3796. if(quest_pending_updates.size() > 0){
  3797. map<int32, map<int32, int32> > tmp_quest_updates;
  3798. MQuestPendingUpdates.writelock(__FUNCTION__, __LINE__);
  3799. tmp_quest_updates.insert(quest_pending_updates.begin(), quest_pending_updates.end());
  3800. quest_pending_updates.clear();
  3801. MQuestPendingUpdates.releasewritelock(__FUNCTION__, __LINE__);
  3802. map<int32, map<int32, int32> >::iterator quest_itr;
  3803. map<int32, int32>::iterator step_itr;
  3804. for(quest_itr = tmp_quest_updates.begin(); quest_itr != tmp_quest_updates.end(); quest_itr++){
  3805. for(step_itr = quest_itr->second.begin(); step_itr != quest_itr->second.end(); step_itr++){
  3806. if(step_itr->second == 0xFFFFFFFF){
  3807. SetStepComplete(quest_itr->first, step_itr->first);
  3808. player->SendQuestRequiredSpawns(quest_itr->first);
  3809. }
  3810. else
  3811. AddStepProgress(quest_itr->first, step_itr->first, step_itr->second);
  3812. }
  3813. }
  3814. }
  3815. if(quest_pending_reward.size() > 0){
  3816. vector<Quest*>::iterator itr;
  3817. vector<Quest*> tmp_quest_rewards;
  3818. MQuestPendingUpdates.writelock(__FUNCTION__, __LINE__);
  3819. tmp_quest_rewards.insert(tmp_quest_rewards.begin(), quest_pending_reward.begin(), quest_pending_reward.end());
  3820. quest_pending_reward.clear();
  3821. MQuestPendingUpdates.releasewritelock(__FUNCTION__, __LINE__);
  3822. for(itr = tmp_quest_rewards.begin(); itr != tmp_quest_rewards.end(); itr++){
  3823. GiveQuestReward(*itr);
  3824. }
  3825. }
  3826. quest_updates = false;
  3827. }
  3828. void Client::CheckQuestQueue(){
  3829. MQuestQueue.writelock();
  3830. last_update_time = 0;
  3831. vector<QueuedQuest*>::iterator itr;
  3832. QueuedQuest* queued_quest = 0;
  3833. for(itr = quest_queue.begin(); itr != quest_queue.end(); itr++){
  3834. queued_quest = *itr;
  3835. SendQuestUpdateStepImmediately(queued_quest->quest, queued_quest->step, queued_quest->display_quest_helper);
  3836. safe_delete(queued_quest);
  3837. }
  3838. quest_queue.clear();
  3839. MQuestQueue.releasewritelock();
  3840. }
  3841. void Client::SetStepComplete(int32 quest_id, int32 step){
  3842. Quest* quest = player->SetStepComplete(quest_id, step);
  3843. if(quest){
  3844. SendQuestUpdate(quest);
  3845. GetCurrentZone()->SendQuestUpdates(this);
  3846. }
  3847. }
  3848. void Client::AddStepProgress(int32 quest_id, int32 step, int32 progress) {
  3849. Quest* quest = player->AddStepProgress(quest_id, step, progress);
  3850. if (quest) {
  3851. SendQuestUpdate(quest);
  3852. GetCurrentZone()->SendQuestUpdates(this);
  3853. }
  3854. }
  3855. void Client::CheckPlayerQuestsKillUpdate(Spawn* spawn){
  3856. vector<Quest*>* quest_updates = player->CheckQuestsKillUpdate(spawn);
  3857. if(quest_updates){
  3858. for(int32 i=0;i<quest_updates->size();i++)
  3859. SendQuestUpdate(quest_updates->at(i));
  3860. }
  3861. safe_delete(quest_updates);
  3862. vector<Quest*>* quest_failures = player->CheckQuestsFailures();
  3863. if(quest_failures){
  3864. for(int32 i=0;i<quest_failures->size();i++)
  3865. SendQuestFailure(quest_failures->at(i));
  3866. }
  3867. safe_delete(quest_failures);
  3868. }
  3869. void Client::CheckPlayerQuestsChatUpdate(Spawn* spawn){
  3870. vector<Quest*>* quest_updates = player->CheckQuestsChatUpdate(spawn);
  3871. if(quest_updates){
  3872. for(int32 i=0;i<quest_updates->size();i++)
  3873. SendQuestUpdate(quest_updates->at(i));
  3874. GetCurrentZone()->SendQuestUpdates(this);
  3875. }
  3876. safe_delete(quest_updates);
  3877. }
  3878. void Client::CheckPlayerQuestsItemUpdate(Item* item){
  3879. vector<Quest*>* quest_updates = player->CheckQuestsItemUpdate(item);
  3880. if(quest_updates){
  3881. for(int32 i=0;i<quest_updates->size();i++)
  3882. SendQuestUpdate(quest_updates->at(i));
  3883. }
  3884. safe_delete(quest_updates);
  3885. vector<Quest*>* quest_failures = player->CheckQuestsFailures();
  3886. if(quest_failures){
  3887. for(int32 i=0;i<quest_failures->size();i++)
  3888. SendQuestFailure(quest_failures->at(i));
  3889. }
  3890. safe_delete(quest_failures);
  3891. }
  3892. void Client::CheckPlayerQuestsLocationUpdate(){
  3893. vector<Quest*>* quest_updates = player->CheckQuestsLocationUpdate();
  3894. if(quest_updates){
  3895. for(int32 i=0;i<quest_updates->size();i++)
  3896. SendQuestUpdate(quest_updates->at(i));
  3897. }
  3898. safe_delete(quest_updates);
  3899. }
  3900. void Client::CheckPlayerQuestsSpellUpdate(Spell* spell){
  3901. vector<Quest*>* quest_updates = player->CheckQuestsSpellUpdate(spell);
  3902. if(quest_updates) {
  3903. for(int32 i = 0; i < quest_updates->size(); i++)
  3904. SendQuestUpdate(quest_updates->at(i));
  3905. }
  3906. safe_delete(quest_updates);
  3907. vector<Quest*>* quest_failures = player->CheckQuestsFailures();
  3908. if(quest_failures){
  3909. for(int32 i = 0; i< quest_failures->size(); i++)
  3910. SendQuestFailure(quest_failures->at(i));
  3911. }
  3912. safe_delete(quest_failures);
  3913. }
  3914. void Client::AddPendingQuest(Quest* quest){
  3915. player->pending_quests[quest->GetQuestID()] = quest;
  3916. EQ2Packet* outapp = quest->OfferQuest(GetVersion(), player);
  3917. //DumpPacket(outapp);
  3918. QueuePacket(outapp);
  3919. }
  3920. Quest* Client::GetActiveQuest(int32 quest_id){
  3921. if(player->player_quests.count(quest_id) > 0) {
  3922. LogWrite(CCLIENT__DEBUG, 0, "Client", "Found %u active quests for char_id: %u", player->player_quests.count(quest_id), player->GetCharacterID());
  3923. return player->player_quests[quest_id];
  3924. }
  3925. return 0;
  3926. }
  3927. Quest* Client::GetPendingQuest(int32 id){
  3928. if(player->pending_quests.count(id) > 0) {
  3929. LogWrite(CCLIENT__DEBUG, 0, "Client", "Found %u pending quests for char_id: %u", player->pending_quests.count(id), player->GetCharacterID());
  3930. return player->pending_quests[id];
  3931. }
  3932. return 0;
  3933. }
  3934. void Client::RemovePendingQuest(Quest* quest){
  3935. player->pending_quests.erase(quest->GetQuestID());
  3936. }
  3937. void Client::SetPlayerQuest(Quest* quest, map<int32, int32>* progress){
  3938. if(!quest || !progress) {
  3939. return;
  3940. }
  3941. map<int32, int32>::iterator itr;
  3942. QuestStep* step = 0;
  3943. player->SetZone(GetCurrentZone());
  3944. for(itr = progress->begin(); itr != progress->end(); itr++){
  3945. step = quest->GetQuestStep(itr->first);
  3946. if(step && itr->second > 0){
  3947. step->SetStepProgress(itr->second);
  3948. if(lua_interface && step->GetQuestCurrentQuantity() >= step->GetQuestNeededQuantity())
  3949. lua_interface->CallQuestFunction(quest, "Reload", player, step->GetStepID());
  3950. }
  3951. }
  3952. }
  3953. void Client::AddPlayerQuest(Quest* quest, bool call_accepted, bool send_packets){
  3954. if(player->player_quests.count(quest->GetQuestID()) > 0) {
  3955. if (player->player_quests[quest->GetQuestID()]->GetQuestFlags() > 0)
  3956. quest->SetQuestFlags(player->player_quests[quest->GetQuestID()]->GetQuestFlags());
  3957. RemovePlayerQuest(quest->GetQuestID(), false, false);
  3958. }
  3959. player->player_quests[quest->GetQuestID()] = quest;
  3960. quest->SetPlayer(player);
  3961. current_quest_id = quest->GetQuestID();
  3962. if(send_packets && quest->GetQuestGiver() > 0)
  3963. GetCurrentZone()->SendSpawnChanges(quest->GetQuestGiver(), this, false, true);
  3964. if(lua_interface && call_accepted)
  3965. lua_interface->CallQuestFunction(quest, "Accepted", player);
  3966. if(send_packets) {
  3967. LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal...");
  3968. //SendQuestJournal();
  3969. SendQuestJournalUpdate(quest);
  3970. // sent twice to match live
  3971. quest->SetTracked(false);
  3972. QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player));
  3973. quest->SetTracked(true);
  3974. QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player));
  3975. }
  3976. //This isn't during a load screen, so update spawns with required quests
  3977. if(call_accepted)
  3978. player->SendQuestRequiredSpawns(quest->GetQuestID());
  3979. }
  3980. void Client::RemovePlayerQuest(int32 id, bool send_update, bool delete_quest){
  3981. if(current_quest_id == id)
  3982. current_quest_id = 0;
  3983. if(player->player_quests.count(id) > 0){
  3984. if(delete_quest){
  3985. player->player_quests[id]->SetDeleted(true);
  3986. database.DeleteCharacterQuest(id, GetCharacterID(), player->GetCompletedPlayerQuests()->count(id) > 0);
  3987. }
  3988. if(send_update && player->player_quests[id]->GetQuestGiver() > 0)
  3989. GetCurrentZone()->SendSpawnChanges(player->player_quests[id]->GetQuestGiver(), this, false, true);
  3990. if(send_update) {
  3991. LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal...");
  3992. SendQuestJournal();
  3993. }
  3994. player->RemoveQuest(id, delete_quest);
  3995. if(send_update) {
  3996. LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal...");
  3997. SendQuestJournal();
  3998. }
  3999. }
  4000. }
  4001. void Client::SendQuestUpdateStepImmediately(Quest* quest, int32 step, bool display_quest_helper){
  4002. if(quest){
  4003. QuestStep* quest_step = quest->GetQuestStep(step);
  4004. if(quest_step){
  4005. QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player, quest_step, 1, false, false, display_quest_helper));
  4006. quest_step->WasUpdated(false);
  4007. }
  4008. }
  4009. }
  4010. void Client::SendQuestUpdateStep(Quest* quest, int32 step, bool display_quest_helper){
  4011. QueuedQuest* item = new QueuedQuest;
  4012. item->quest = quest;
  4013. item->step = step;
  4014. item->display_quest_helper = display_quest_helper;
  4015. MQuestQueue.writelock();
  4016. quest_queue.push_back(item);
  4017. last_update_time = Timer::GetCurrentTime2();
  4018. MQuestQueue.releasewritelock();
  4019. }
  4020. void Client::SendQuestFailure(Quest* quest){
  4021. vector<QuestStep*>* failures = quest->GetQuestFailures();
  4022. if(failures){
  4023. QuestStep* step = 0;
  4024. for(int32 i=0;i<failures->size();i++){
  4025. step = failures->at(i);
  4026. QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player, step, 1, false, true));
  4027. LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal...");
  4028. SendQuestJournal();
  4029. }
  4030. failures->clear();
  4031. }
  4032. }
  4033. void Client::SendQuestUpdate(Quest* quest){
  4034. vector<QuestStep*>* updates = quest->GetQuestUpdates();
  4035. if(updates){
  4036. QuestStep* step = 0;
  4037. for(int32 i=0;i<updates->size();i++){
  4038. step = updates->at(i);
  4039. if(lua_interface && step->Complete() && quest->GetCompleteAction(step->GetStepID()))
  4040. lua_interface->CallQuestFunction(quest, quest->GetCompleteAction(step->GetStepID()), player);
  4041. if(step->WasUpdated()){
  4042. SendQuestJournal();
  4043. QueuePacket(quest->QuestJournalReply(GetVersion(), GetNameCRC(), player, step));
  4044. }
  4045. LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal...");
  4046. }
  4047. if(lua_interface && quest->GetCompleted() && quest->GetCompleteAction())
  4048. lua_interface->CallQuestFunction(quest, quest->GetCompleteAction(), player);
  4049. if(quest->GetCompleted()){
  4050. if (quest->GetQuestReturnNPC() > 0)
  4051. GetCurrentZone()->SendSpawnChanges(quest->GetQuestReturnNPC(), this, false, true);
  4052. if (quest->GetCompletedFlag())
  4053. quest->SetCompletedFlag(false);
  4054. }
  4055. updates->clear();
  4056. }
  4057. }
  4058. void Client::SendQuestJournal(bool all_quests, Client* client){
  4059. if(!client)
  4060. client = this;
  4061. PacketStruct* packet = player->GetQuestJournalPacket(all_quests, GetVersion(), GetNameCRC(), current_quest_id);
  4062. if(packet){
  4063. EQ2Packet* outapp = packet->serialize();
  4064. //DumpPacket(outapp);
  4065. client->QueuePacket(outapp);
  4066. safe_delete(packet);
  4067. }
  4068. }
  4069. void Client::SendQuestJournalUpdate(Quest* quest) {
  4070. PacketStruct* packet = player->GetQuestJournalPacket(quest, GetVersion(), GetNameCRC());
  4071. if (packet) {
  4072. QueuePacket(packet->serialize());
  4073. safe_delete(packet);
  4074. }
  4075. }
  4076. void Client::ReloadQuests(){
  4077. vector<int32> ids = player->GetQuestIDs();
  4078. Quest* quest = 0;
  4079. for(int32 i=0;i<ids.size();i++){
  4080. quest = master_quest_list.GetQuest(ids[i]);
  4081. if(quest)
  4082. AddPlayerQuest(quest, false);
  4083. else
  4084. RemovePlayerQuest(ids[i]);
  4085. }
  4086. }
  4087. Quest* Client::GetPendingQuestAcceptance(int32 item_id){
  4088. bool found_quest = false;
  4089. vector<Quest*>::iterator itr;
  4090. vector<Item*>* items = 0;
  4091. Quest* quest = 0;
  4092. MPendingQuestAccept.lock();
  4093. for(itr = pending_quest_accept.begin(); itr != pending_quest_accept.end(); itr++){
  4094. quest = *itr;
  4095. items = quest->GetSelectableRewardItems();
  4096. if(items && items->size() > 0){
  4097. for(int32 i=0;i<items->size();i++){
  4098. if(items->at(i)->details.item_id == item_id){
  4099. found_quest = true;
  4100. break;
  4101. }
  4102. }
  4103. }
  4104. else if(item_id == 0)
  4105. found_quest = true;
  4106. if(found_quest){
  4107. pending_quest_accept.erase(itr);
  4108. break;
  4109. }
  4110. }
  4111. MPendingQuestAccept.unlock();
  4112. if(found_quest)
  4113. return quest;
  4114. return 0;
  4115. }
  4116. void Client::AcceptQuestReward(Quest* quest, int32 item_id){
  4117. int8 num_slots_needed = 0;
  4118. int16 free_slots = player->item_list.GetNumberOfFreeSlots();
  4119. Item* master_item = 0;
  4120. if(item_id > 0){
  4121. num_slots_needed++;
  4122. master_item = master_item_list.GetItem(item_id);
  4123. }
  4124. vector<Item*>* items = quest->GetRewardItems();
  4125. if(items && items->size() > 0)
  4126. num_slots_needed += items->size();
  4127. if(free_slots >= num_slots_needed || (player->item_list.HasFreeBagSlot() && master_item && master_item->IsBag() && master_item->bag_info->num_slots >= items->size())){
  4128. if(master_item)
  4129. AddItem(item_id);
  4130. if(items && items->size() > 0){
  4131. for(int32 i=0;i<items->size();i++)
  4132. AddItem(new Item(items->at(i)));
  4133. }
  4134. EQ2Packet* outapp = player->SendInventoryUpdate(GetVersion());
  4135. if(outapp)
  4136. QueuePacket(outapp);
  4137. map<int32, sint32>* reward_factions = quest->GetRewardFactions();
  4138. map<int32, sint32>::iterator itr;
  4139. for (itr = reward_factions->begin(); itr != reward_factions->end(); itr++) {
  4140. int32 faction_id = itr->first;
  4141. sint32 amount = itr->second;
  4142. if (amount > 0)
  4143. player->GetFactions()->IncreaseFaction(faction_id, amount);
  4144. else
  4145. player->GetFactions()->DecreaseFaction(faction_id, (amount * -1));
  4146. }
  4147. }
  4148. else{
  4149. MPendingQuestAccept.lock();
  4150. pending_quest_accept.push_back(quest);
  4151. MPendingQuestAccept.unlock();
  4152. SimpleMessage(CHANNEL_COLOR_RED, "You do not have enough free slots! Free some slots and try again.");
  4153. DisplayQuestComplete(quest);
  4154. }
  4155. }
  4156. void Client::DisplayQuestComplete(Quest* quest){
  4157. PacketStruct* packet = configReader.getStruct("WS_QuestComplete", GetVersion());
  4158. if(packet){
  4159. packet->setDataByName("title", "Quest Reward!");
  4160. packet->setDataByName("name", quest->GetName());
  4161. packet->setDataByName("description", quest->GetDescription());
  4162. packet->setDataByName("level", quest->GetLevel());
  4163. packet->setDataByName("encounter_level", quest->GetEncounterLevel());
  4164. int8 difficulty = 0;
  4165. if((string)quest->GetType() == "Tradeskill")
  4166. difficulty = player->GetTSArrowColor(quest->GetLevel());
  4167. else
  4168. difficulty = player->GetArrowColor(quest->GetLevel());
  4169. packet->setDataByName("difficulty", difficulty);
  4170. int64 rewarded_coin = 0;
  4171. if (quest->GetCoinsReward() > 0){
  4172. if (quest->GetCoinsRewardMax() > 0)
  4173. rewarded_coin = MakeRandomInt(quest->GetCoinsReward(), quest->GetCoinsRewardMax());
  4174. else
  4175. rewarded_coin = quest->GetCoinsReward();
  4176. }
  4177. quest->SetGeneratedCoin(rewarded_coin);
  4178. packet->setDataByName("max_coin", rewarded_coin);
  4179. packet->setDataByName("min_coin", rewarded_coin);
  4180. packet->setDataByName("status_points", quest->GetStatusPoints());
  4181. vector<Item*>* items2 = quest->GetSelectableRewardItems();
  4182. vector<Item*>* items = quest->GetRewardItems();
  4183. if(items){
  4184. packet->setArrayLengthByName("num_rewards", items->size());
  4185. for(int32 i=0;i<items->size();i++){
  4186. packet->setArrayDataByName("reward_id", items->at(i)->details.item_id, i);
  4187. if(version < 860)
  4188. packet->setItemArrayDataByName("item", items->at(i), player, i, 0, -1);
  4189. else if (version < 1193)
  4190. packet->setItemArrayDataByName("item", items->at(i), player, i);
  4191. else
  4192. packet->setItemArrayDataByName("item", items->at(i), player, i, 0, 2);
  4193. }
  4194. }
  4195. if(items2 && items2->size() > 0){
  4196. packet->setArrayLengthByName("num_select_rewards", items2->size());
  4197. for(int32 i=0;i<items2->size();i++){
  4198. packet->setArrayDataByName("select_reward_id", items2->at(i)->details.item_id, i);
  4199. if(version < 860)
  4200. packet->setItemArrayDataByName("select_item", items2->at(i), player, i, 0, -1);
  4201. else if (version < 1193)
  4202. packet->setItemArrayDataByName("select_item", items2->at(i), player, i);
  4203. else
  4204. packet->setItemArrayDataByName("select_item", items2->at(i), player, i, 0, 2);
  4205. }
  4206. }
  4207. map<int32, sint32>* reward_factions = quest->GetRewardFactions();
  4208. if (reward_factions && reward_factions->size() > 0) {
  4209. packet->setArrayLengthByName("num_factions", reward_factions->size());
  4210. map<int32, sint32>::iterator itr;
  4211. int16 index = 0;
  4212. for (itr = reward_factions->begin(); itr != reward_factions->end(); itr++) {
  4213. int32 faction_id = itr->first;
  4214. sint32 amount = itr->second;
  4215. const char* faction_name = master_faction_list.GetFactionNameByID(faction_id);
  4216. if (faction_name) {
  4217. packet->setArrayDataByName("faction_name", const_cast<char*>(faction_name), index);
  4218. packet->setArrayDataByName("amount", amount, index);
  4219. }
  4220. index++;
  4221. }
  4222. }
  4223. EQ2Packet* outapp = packet->serialize();
  4224. // DumpPacket(outapp);
  4225. QueuePacket(outapp);
  4226. safe_delete(packet);
  4227. }
  4228. }
  4229. void Client::DisplayRandomizeFeatures(int32 flags) {
  4230. SimpleMessage(CHANNEL_COLOR_WHITE, "Showing Active Randomize Features:");
  4231. if(flags > 0) {
  4232. if (flags & RANDOMIZE_GENDER)
  4233. SimpleMessage(CHANNEL_COLOR_WHITE, "- Gender");
  4234. if (flags & RANDOMIZE_RACE)
  4235. SimpleMessage(CHANNEL_COLOR_WHITE, "- Race");
  4236. if (flags & RANDOMIZE_MODEL_TYPE)
  4237. SimpleMessage(CHANNEL_COLOR_WHITE, "- Model");
  4238. if (flags & RANDOMIZE_FACIAL_HAIR_TYPE)
  4239. SimpleMessage(CHANNEL_COLOR_WHITE, "- Facial Hair");
  4240. if (flags & RANDOMIZE_HAIR_TYPE)
  4241. SimpleMessage(CHANNEL_COLOR_WHITE, "- Hair");
  4242. if (flags & RANDOMIZE_WING_TYPE)
  4243. SimpleMessage(CHANNEL_COLOR_WHITE, "- Wing");
  4244. if (flags & RANDOMIZE_CHEEK_TYPE)
  4245. SimpleMessage(CHANNEL_COLOR_WHITE, "- Cheek");
  4246. if (flags & RANDOMIZE_CHIN_TYPE)
  4247. SimpleMessage(CHANNEL_COLOR_WHITE, "- Chin");
  4248. if (flags & RANDOMIZE_EAR_TYPE)
  4249. SimpleMessage(CHANNEL_COLOR_WHITE, "- Ear");
  4250. if (flags & RANDOMIZE_EYE_BROW_TYPE)
  4251. SimpleMessage(CHANNEL_COLOR_WHITE, "- Eyebrow");
  4252. if (flags & RANDOMIZE_EYE_TYPE)
  4253. SimpleMessage(CHANNEL_COLOR_WHITE, "- Eye");
  4254. if (flags & RANDOMIZE_LIP_TYPE)
  4255. SimpleMessage(CHANNEL_COLOR_WHITE, "- Lip");
  4256. if (flags & RANDOMIZE_NOSE_TYPE)
  4257. SimpleMessage(CHANNEL_COLOR_WHITE, "- Nose");
  4258. if (flags & RANDOMIZE_EYE_COLOR)
  4259. SimpleMessage(CHANNEL_COLOR_WHITE, "- Eye Color");
  4260. if (flags & RANDOMIZE_HAIR_COLOR1)
  4261. SimpleMessage(CHANNEL_COLOR_WHITE, "- Hair Color1");
  4262. if (flags & RANDOMIZE_HAIR_COLOR2)
  4263. SimpleMessage(CHANNEL_COLOR_WHITE, "- Hair Color2");
  4264. if (flags & RANDOMIZE_HAIR_HIGHLIGHT)
  4265. SimpleMessage(CHANNEL_COLOR_WHITE, "- Hair Color Highlights");
  4266. if (flags & RANDOMIZE_HAIR_FACE_COLOR)
  4267. SimpleMessage(CHANNEL_COLOR_WHITE, "- Facial Hair Color");
  4268. if (flags & RANDOMIZE_HAIR_FACE_HIGHLIGHT_COLOR)
  4269. SimpleMessage(CHANNEL_COLOR_WHITE, "- Facial Hair Color Highlights");
  4270. if (flags & RANDOMIZE_HAIR_TYPE_COLOR)
  4271. SimpleMessage(CHANNEL_COLOR_WHITE, "- Hair Type Color");
  4272. if (flags & RANDOMIZE_HAIR_TYPE_HIGHLIGHT_COLOR)
  4273. SimpleMessage(CHANNEL_COLOR_WHITE, "- Hair Type Highlights");
  4274. if (flags & RANDOMIZE_SKIN_COLOR)
  4275. SimpleMessage(CHANNEL_COLOR_WHITE, "- Skin Color");
  4276. if (flags & RANDOMIZE_WING_COLOR1)
  4277. SimpleMessage(CHANNEL_COLOR_WHITE, "- Wing Color1");
  4278. if (flags & RANDOMIZE_WING_COLOR2)
  4279. SimpleMessage(CHANNEL_COLOR_WHITE, "- Wing Color2");
  4280. }
  4281. else
  4282. {
  4283. SimpleMessage(CHANNEL_COLOR_WHITE, "- No Randomization Set.");
  4284. }
  4285. }
  4286. void Client::GiveQuestReward(Quest* quest){
  4287. current_quest_id = 0;
  4288. MPendingQuestAccept.lock();
  4289. pending_quest_accept.push_back(quest);
  4290. MPendingQuestAccept.unlock();
  4291. quest->IncrementCompleteCount();
  4292. player->AddCompletedQuest(quest);
  4293. LogWrite(CCLIENT__DEBUG, 0, "Client", "Send Quest Journal...");
  4294. SendQuestJournal();
  4295. player->RemoveQuest(quest->GetQuestID(), false);
  4296. DisplayQuestComplete(quest);
  4297. if(quest->GetExpReward() > 0){
  4298. int16 level = player->GetLevel();
  4299. int32 xp = quest->GetExpReward();
  4300. if (player->AddXP(xp)) {
  4301. Message(CHANNEL_COLOR_EXP, "You gain %u experience!",(int32)xp);
  4302. if(player->GetLevel() != level)
  4303. ChangeLevel(level, player->GetLevel());
  4304. player->SetCharSheetChanged(true);
  4305. }
  4306. }
  4307. if(quest->GetTSExpReward() > 0){
  4308. int8 ts_level = player->GetTSLevel();
  4309. int32 xp = quest->GetTSExpReward();
  4310. if (player->AddTSXP(xp)) {
  4311. Message(CHANNEL_COLOR_EXP, "You gain %u tradeskill experience!", (int32)xp);
  4312. if(player->GetTSLevel() != ts_level)
  4313. ChangeTSLevel(ts_level, player->GetTSLevel());
  4314. player->SetCharSheetChanged(true);
  4315. }
  4316. }
  4317. int64 total_coins = quest->GetGeneratedCoin();
  4318. if(total_coins > 0){
  4319. player->AddCoins(total_coins);
  4320. PlaySound("coin_cha_ching");
  4321. char tmp[64] = {0};
  4322. string message = "You receive ";
  4323. int32 val = 0;
  4324. if(total_coins >= 1000000){
  4325. val = total_coins / 1000000;
  4326. total_coins -= 1000000 * val;
  4327. sprintf(tmp, "%u Platinum ", val);
  4328. message.append(tmp);
  4329. memset(tmp, 0, 64);
  4330. }
  4331. if(total_coins >= 10000){
  4332. val = total_coins / 10000;
  4333. total_coins -= 10000 * val;
  4334. sprintf(tmp, "%u Gold ", val);
  4335. message.append(tmp);
  4336. memset(tmp, 0, 64);
  4337. }
  4338. if(total_coins >= 100){
  4339. val = total_coins / 100;
  4340. total_coins -= 100 * val;
  4341. sprintf(tmp, "%u Silver ", val);
  4342. message.append(tmp);
  4343. memset(tmp, 0, 64);
  4344. }
  4345. if(total_coins > 0){
  4346. sprintf(tmp, "%u Copper ", (int32)total_coins);
  4347. message.append(tmp);
  4348. }
  4349. message.append("for completing ").append(quest->GetName());
  4350. int8 type = CHANNEL_COLOR_LOOT;
  4351. if(GetVersion() >= 973)
  4352. type = CHANNEL_COLOR_NEW_LOOT;
  4353. SimpleMessage(type, message.c_str());
  4354. }
  4355. if(quest->GetQuestGiver() > 0)
  4356. GetCurrentZone()->SendSpawnChanges(quest->GetQuestGiver(), this, false, true);
  4357. RemovePlayerQuest(quest->GetQuestID(), true, false);
  4358. }
  4359. void Client::DisplayConversation(int32 conversation_id, int32 spawn_id, vector<ConversationOption>* conversations, const char* text, const char* mp3, int32 key1, int32 key2){
  4360. PacketStruct* packet = configReader.getStruct("WS_DialogOpen", GetVersion());
  4361. if(packet){
  4362. packet->setDataByName("conversation_id", conversation_id);
  4363. packet->setDataByName("text", text);
  4364. packet->setDataByName("unknown2", 1);
  4365. conversation_map[conversation_id].clear();
  4366. if (conversations) {
  4367. packet->setArrayLengthByName("num_responses", conversations->size());
  4368. for(int32 i=0;i<conversations->size();i++){
  4369. packet->setArrayDataByName("response", conversations->at(i).option.c_str(), i);
  4370. if(conversations->at(i).function.length() > 0)
  4371. conversation_map[conversation_id][i] = conversations->at(i).function;
  4372. }
  4373. }
  4374. packet->setDataByName("spawn_id", spawn_id);
  4375. if(mp3){
  4376. packet->setDataByName("voice", mp3);
  4377. packet->setDataByName("key1", key1);
  4378. packet->setDataByName("key2", key2);
  4379. }
  4380. QueuePacket(packet->serialize());
  4381. safe_delete(packet);
  4382. }
  4383. }
  4384. void Client::DisplayConversation(Item* item, vector<ConversationOption>* conversations, const char* text, int8 type, const char* mp3, int32 key1, int32 key2){
  4385. if(!item || !text || !conversations || conversations->size() == 0) {
  4386. return;
  4387. }
  4388. int32 conversation_id = GetConversationID(0, item);
  4389. if(conversation_id == 0){
  4390. next_conversation_id++;
  4391. conversation_id = next_conversation_id;
  4392. }
  4393. conversation_items[conversation_id] = item;
  4394. if (type == 4)
  4395. DisplayConversation(conversation_id, player->GetIDWithPlayerSpawn(player), conversations, text, mp3, key1, key2);
  4396. else
  4397. DisplayConversation(conversation_id, 0xFFFFFFFF, conversations, text, mp3, key1, key2);
  4398. }
  4399. void Client::DisplayConversation(Entity* npc, int8 type, vector<ConversationOption>* conversations, const char* text, const char* mp3, int32 key1, int32 key2){
  4400. if(!npc || !(type == 1 || type == 2 || type == 3) || !text /*|| !conversations || conversations->size() == 0*/) {
  4401. return;
  4402. }
  4403. int32 conversation_id = GetConversationID(npc, 0);
  4404. if(conversation_id == 0){
  4405. next_conversation_id++;
  4406. conversation_id = next_conversation_id;
  4407. }
  4408. conversation_spawns[conversation_id] = npc;
  4409. /* NPCs can start two different types of conversations.
  4410. * Type 1: The chat type with bubbles.
  4411. * Type 2: The dialog type with the blue box. */
  4412. if (type == 1)
  4413. DisplayConversation(conversation_id, player->GetIDWithPlayerSpawn(npc), conversations, text, mp3, key1, key2);
  4414. else if (type == 2)
  4415. DisplayConversation(conversation_id, 0xFFFFFFFF, conversations, text, mp3, key1, key2);
  4416. else //if (type == 3)
  4417. DisplayConversation(conversation_id, player->GetIDWithPlayerSpawn(player), conversations, text, mp3, key1, key2);
  4418. }
  4419. void Client::CloseDialog(int32 conversation_id){
  4420. PacketStruct* packet = configReader.getStruct("WS_ServerDialogClose", GetVersion());
  4421. if(packet){
  4422. packet->setDataByName("conversation_id", conversation_id);
  4423. QueuePacket(packet->serialize());
  4424. safe_delete(packet);
  4425. }
  4426. conversation_items.erase(conversation_id);
  4427. conversation_spawns.erase(conversation_id);
  4428. }
  4429. int32 Client::GetConversationID(Spawn* spawn, Item* item){
  4430. int32 conversation_id = 0;
  4431. if(spawn){
  4432. map<int32, Spawn*>::iterator itr;
  4433. for(itr = conversation_spawns.begin(); itr != conversation_spawns.end(); itr++){
  4434. if(itr->second == spawn){
  4435. conversation_id = itr->first;
  4436. break;
  4437. }
  4438. }
  4439. }
  4440. else if(item){
  4441. map<int32, Item*>::iterator itr;
  4442. for(itr = conversation_items.begin(); itr != conversation_items.end(); itr++){
  4443. if(itr->second == item){
  4444. conversation_id = itr->first;
  4445. break;
  4446. }
  4447. }
  4448. }
  4449. return conversation_id;
  4450. }
  4451. Spawn* Client::GetCombineSpawn(){
  4452. return combine_spawn;
  4453. }
  4454. bool Client::ShouldTarget(){
  4455. return should_target;
  4456. }
  4457. void Client::TargetSpawn(Spawn* spawn){
  4458. should_target = false;
  4459. PacketStruct* packet = configReader.getStruct("WS_ServerUpdateTarget", GetVersion());
  4460. if(packet){
  4461. packet->setDataByName("spawn_id", GetPlayer()->GetIDWithPlayerSpawn(spawn));
  4462. QueuePacket(packet->serialize());
  4463. safe_delete(packet);
  4464. }
  4465. }
  4466. void Client::CombineSpawns(float radius, Spawn* spawn){
  4467. combine_spawn = spawn;
  4468. spawn->RemoveSpawnFromGroup(true);
  4469. if(!GetCurrentZone()->AddCloseSpawnsToSpawnGroup(combine_spawn, radius))
  4470. SimpleMessage(CHANNEL_COLOR_YELLOW, "One or more spawns are in a spawn group and cannot be combined until they are removed from their group.");
  4471. GetCurrentZone()->RepopSpawns(this, combine_spawn);
  4472. should_target = true;
  4473. }
  4474. void Client::AddCombineSpawn(Spawn* spawn){
  4475. if(combine_spawn && combine_spawn != spawn && spawn){
  4476. combine_spawn->AddSpawnToGroup(spawn);
  4477. spawn->AddSpawnToGroup(combine_spawn);
  4478. GetCurrentZone()->RepopSpawns(this, combine_spawn);
  4479. }
  4480. else if(spawn)
  4481. combine_spawn = spawn;
  4482. should_target = true;
  4483. }
  4484. void Client::RemoveCombineSpawn(Spawn* spawn){
  4485. if(combine_spawn && spawn)
  4486. spawn->RemoveSpawnFromGroup();
  4487. if(combine_spawn == spawn)
  4488. combine_spawn->RemoveSpawnFromGroup(true);
  4489. GetCurrentZone()->RepopSpawns(this, combine_spawn);
  4490. if(combine_spawn == spawn)
  4491. combine_spawn = 0;
  4492. }
  4493. void Client::SaveCombineSpawns(const char* name){
  4494. if(!combine_spawn) {
  4495. return;
  4496. }
  4497. vector<Spawn*>* spawns = combine_spawn->GetSpawnGroup();
  4498. if(!spawns) {
  4499. return;
  4500. }
  4501. int32 count = spawns->size();
  4502. safe_delete(spawns);
  4503. if(count == 1)
  4504. SimpleMessage(CHANNEL_COLOR_YELLOW, "Error: You only have a single Spawn in the group!");
  4505. else if(database.SaveCombinedSpawnLocation(GetCurrentZone(), combine_spawn, name)){
  4506. Message(CHANNEL_COLOR_YELLOW, "Successfully combined %u spawns into spawn location: %u", count, combine_spawn->GetSpawnLocationID());
  4507. GetCurrentZone()->RemoveSpawn(combine_spawn);
  4508. }
  4509. else
  4510. SimpleMessage(CHANNEL_COLOR_YELLOW, "Error saving spawn group, check console for details.");
  4511. combine_spawn = 0;
  4512. }
  4513. bool Client::AddItem(int32 item_id, int16 quantity){
  4514. Item* master_item = master_item_list.GetItem(item_id);
  4515. Item* item = 0;
  4516. if(master_item)
  4517. item = new Item(master_item);
  4518. if(item){
  4519. if(quantity > 0 )
  4520. item->details.count = quantity;
  4521. return AddItem(item);
  4522. }
  4523. else
  4524. Message(CHANNEL_COLOR_RED, "Could not find item with id of: %i", item_id);
  4525. return false;
  4526. }
  4527. bool Client::AddItem(Item* item){
  4528. if(!item) {
  4529. return false;
  4530. }
  4531. if(item->IsBag())
  4532. item->details.bag_id = item->details.unique_id;
  4533. if(player->AddItem(item)){
  4534. EQ2Packet* outapp = player->SendInventoryUpdate(GetVersion());
  4535. if(outapp){
  4536. QueuePacket(outapp);
  4537. //resend bag desc with new item name added
  4538. outapp = player->SendBagUpdate(item->details.inv_slot_id, GetVersion());
  4539. if(outapp)
  4540. QueuePacket(outapp);
  4541. /*EQ2Packet* app = item->serialize(client->GetVersion(), false);
  4542. DumpPacket(app);
  4543. client->QueuePacket(app);
  4544. */
  4545. }
  4546. CheckPlayerQuestsItemUpdate(item);
  4547. if(item->GetItemScript() && lua_interface)
  4548. lua_interface->RunItemScript(item->GetItemScript(), "obtained", item, player);
  4549. }
  4550. else{
  4551. SimpleMessage(CHANNEL_COLOR_RED, "Could not find free slot to place item.");
  4552. safe_delete(item);
  4553. return false;
  4554. }
  4555. return true;
  4556. }
  4557. bool Client::AddItemToBank(int32 item_id, int16 quantity) {
  4558. Item* master_item = master_item_list.GetItem(item_id);
  4559. Item* item = 0;
  4560. if (master_item)
  4561. item = new Item(master_item);
  4562. if (item) {
  4563. if (quantity > 0)
  4564. item->details.count = quantity;
  4565. return AddItemToBank(item);
  4566. }
  4567. else
  4568. Message(CHANNEL_COLOR_RED, "Could not find item with id of: %i", item_id);
  4569. return false;
  4570. }
  4571. bool Client::AddItemToBank(Item* item) {
  4572. if (!item) {
  4573. return false;
  4574. }
  4575. if (item->IsBag())
  4576. item->details.bag_id = item->details.unique_id;
  4577. if (player->AddItemToBank(item)) {
  4578. EQ2Packet* outapp = player->SendInventoryUpdate(GetVersion());
  4579. if (outapp) {
  4580. QueuePacket(outapp);
  4581. //resend bag desc with new item name added
  4582. outapp = player->SendBagUpdate(item->details.inv_slot_id, GetVersion());
  4583. if (outapp)
  4584. QueuePacket(outapp);
  4585. /*EQ2Packet* app = item->serialize(client->GetVersion(), false);
  4586. DumpPacket(app);
  4587. client->QueuePacket(app);
  4588. */
  4589. }
  4590. CheckPlayerQuestsItemUpdate(item);
  4591. if (item->GetItemScript() && lua_interface)
  4592. lua_interface->RunItemScript(item->GetItemScript(), "obtained", item, player);
  4593. }
  4594. else {
  4595. SimpleMessage(CHANNEL_COLOR_RED, "Could not find free slot to place item.");
  4596. safe_delete(item);
  4597. return false;
  4598. }
  4599. return true;
  4600. }
  4601. bool Client::RemoveItem(Item *item, int16 quantity) {
  4602. EQ2Packet *outapp;
  4603. bool delete_item = false;
  4604. assert(item);
  4605. if (quantity > 0 && !item->IsBag() && item->details.count > quantity) {
  4606. item->details.count -= quantity;
  4607. item->save_needed = true;
  4608. }
  4609. else {
  4610. database.DeleteItem(character_id, item, 0);
  4611. player->GetPlayerItemList()->RemoveItem(item, false);
  4612. delete_item = true;
  4613. }
  4614. if ((outapp = player->SendInventoryUpdate(version))) {
  4615. QueuePacket(outapp);
  4616. if (item->GetItemScript() && lua_interface)
  4617. lua_interface->RunItemScript(item->GetItemScript(), "removed", item, player);
  4618. if (delete_item)
  4619. safe_delete(item);
  4620. return true;
  4621. }
  4622. return false;
  4623. }
  4624. void Client::SetLuaDebugClient(bool val){
  4625. if(val)
  4626. lua_debug_timer.Start();
  4627. lua_debug = val;
  4628. if(lua_interface && !val){
  4629. lua_interface->RemoveDebugClients(this);
  4630. lua_debug_timer.Disable();
  4631. }
  4632. }
  4633. void Client::SetMerchantTransaction(Spawn* spawn){
  4634. merchant_transaction = spawn;
  4635. }
  4636. Spawn* Client::GetMerchantTransaction(){
  4637. return merchant_transaction;
  4638. }
  4639. void Client::SetMailTransaction(Spawn* spawn) {
  4640. mail_transaction = spawn;
  4641. mail_window.coin_copper = 0;
  4642. mail_window.coin_silver = 0;
  4643. mail_window.coin_gold = 0;
  4644. mail_window.coin_plat = 0;
  4645. mail_window.char_item_id = 0;
  4646. }
  4647. Spawn* Client::GetMailTransaction() {
  4648. return mail_transaction;
  4649. }
  4650. void Client::PlaySound(const char* name){
  4651. if(name){
  4652. PacketStruct* packet = configReader.getStruct("WS_PlaySound", GetVersion());
  4653. if(packet){
  4654. packet->setMediumStringByName("name", name);
  4655. QueuePacket(packet->serialize());
  4656. safe_delete(packet);
  4657. }
  4658. }
  4659. }
  4660. float Client::CalculateBuyMultiplier(int32 merchant_id){
  4661. /*MerchantFactionMultiplier* multiplier = world.GetMerchantMultiplier(merchant_id);
  4662. if(multiplier){
  4663. sint32 faction_val = player->GetFactions()->GetFactionValue(multiplier->faction_id);
  4664. float diff_low = faction_val - multiplier->faction_min;
  4665. if(diff_low < 0)
  4666. diff_low*=-1;
  4667. float total_diff = multiplier->faction_max - multiplier->faction_min;
  4668. if(total_diff < 0)
  4669. total_diff*=-1;
  4670. float buy_multiplier = multiplier->high_buy_multiplier - multiplier->low_buy_multiplier;
  4671. float total1 = (diff_low/total_diff);
  4672. float final_buy_multiplier = total1*buy_multiplier + total1*multiplier->low_buy_multiplier;
  4673. return final_buy_multiplier;
  4674. }*/
  4675. return 1;
  4676. }
  4677. float Client::CalculateSellMultiplier(int32 merchant_id){
  4678. /*MerchantFactionMultiplier* multiplier = world.GetMerchantMultiplier(merchant_id);
  4679. if(multiplier){
  4680. sint32 faction_val = player->GetFactions()->GetFactionValue(multiplier->faction_id);
  4681. float diff_low = faction_val - multiplier->faction_min;
  4682. if(diff_low < 0)
  4683. diff_low*=-1;
  4684. float total_diff = multiplier->faction_max - multiplier->faction_min;
  4685. if(total_diff < 0)
  4686. total_diff*=-1;
  4687. float sell_multiplier = multiplier->high_sell_multiplier - multiplier->low_sell_multiplier;
  4688. float total1 = (diff_low/total_diff);
  4689. float final_sell_multiplier = total1*sell_multiplier + total1*multiplier->low_sell_multiplier;
  4690. return final_sell_multiplier;
  4691. }*/
  4692. return 1;
  4693. }
  4694. void Client::SellItem(int32 item_id, int16 quantity, int32 unique_id){
  4695. Spawn* spawn = GetMerchantTransaction();
  4696. Guild* guild = GetPlayer()->GetGuild();
  4697. if(spawn && spawn->GetMerchantID() > 0){
  4698. int32 total_sell_price = 0;
  4699. int32 total_status_sell_price = 0; //for status
  4700. float multiplier = CalculateBuyMultiplier(spawn->GetMerchantID());
  4701. int32 sell_price = 0;
  4702. int32 status_sell_price = 0; //for status
  4703. Item* master_item = master_item_list.GetItem(item_id);
  4704. Item* item = 0;
  4705. if (unique_id == 0)
  4706. item = player->item_list.GetItemFromID(item_id, quantity);
  4707. else
  4708. item = player->item_list.GetItemFromUniqueID(unique_id);
  4709. if(!item)
  4710. player->item_list.GetItemFromID(item_id);
  4711. if(item && master_item){
  4712. int32 sell_price = (int32)(master_item->sell_price * multiplier);
  4713. if(sell_price > item->sell_price)
  4714. sell_price = item->sell_price;
  4715. if(quantity > item->details.count)
  4716. quantity = item->details.count;
  4717. total_sell_price = sell_price * quantity;
  4718. //------------------------------For Selling Status Items
  4719. status_sell_price = (int32)(master_item->sell_status * multiplier);
  4720. if (status_sell_price > item->sell_status )
  4721. status_sell_price = item->sell_status;
  4722. if (quantity > item->details.count)
  4723. quantity = item->details.count;
  4724. if (player->GetGuild()){
  4725. total_status_sell_price = status_sell_price * quantity;
  4726. player->GetInfoStruct()->status_points += total_status_sell_price;
  4727. guild->UpdateGuildStatus(GetPlayer(), total_status_sell_price / 10);
  4728. guild->SendGuildMemberList();
  4729. guild->AddEXPCurrent((total_status_sell_price / 10), true);
  4730. }
  4731. if(quantity > 1)
  4732. Message(CHANNEL_COLOR_MERCHANT, "You sell %i \\aITEM %u 0:%s\\/a to %s for %s.", quantity, master_item->details.item_id, master_item->name.c_str(), spawn->GetName(), GetCoinMessage(total_sell_price).c_str());
  4733. else
  4734. Message(CHANNEL_COLOR_MERCHANT, "You sell \\aITEM %u 0:%s\\/a to %s for %s.", master_item->details.item_id, master_item->name.c_str(), spawn->GetName(), GetCoinMessage(total_sell_price).c_str());
  4735. player->AddCoins(total_sell_price);
  4736. AddBuyBack(unique_id, item_id, quantity, sell_price);
  4737. if(quantity >= item->details.count) {
  4738. database.DeleteItem(GetCharacterID(), item, 0);
  4739. player->item_list.DestroyItem(item->details.index);
  4740. }
  4741. else{
  4742. item->details.count -= quantity;
  4743. item->save_needed = true;
  4744. }
  4745. EQ2Packet* outapp = player->SendInventoryUpdate(GetVersion());
  4746. if(outapp)
  4747. QueuePacket(outapp);
  4748. if(!(spawn->GetMerchantType() & MERCHANT_TYPE_NO_BUY))
  4749. SendSellMerchantList();
  4750. if(!(spawn->GetMerchantType() & MERCHANT_TYPE_NO_BUY_BACK))
  4751. SendBuyBackList();
  4752. }
  4753. }
  4754. }
  4755. void Client::BuyBack(int32 item_id, int16 quantity){
  4756. Spawn* spawn = GetMerchantTransaction();
  4757. if(spawn && spawn->GetMerchantID() > 0){
  4758. deque<BuyBackItem*>::iterator itr;
  4759. BuyBackItem* buyback = 0;
  4760. BuyBackItem* closest = 0;
  4761. MBuyBack.readlock(__FUNCTION__, __LINE__);
  4762. for(itr = buy_back_items.begin(); itr != buy_back_items.end(); itr++){
  4763. buyback = *itr;
  4764. if(buyback->unique_id == item_id){
  4765. closest = buyback;
  4766. quantity = buyback->quantity;
  4767. break;
  4768. }
  4769. }
  4770. MBuyBack.releasereadlock(__FUNCTION__, __LINE__);
  4771. if(closest){
  4772. Item* item = 0;
  4773. Item* master_item = master_item_list.GetItem(closest->item_id);
  4774. if(master_item){
  4775. item = new Item(master_item);
  4776. if(closest->quantity >= quantity)
  4777. item->details.count = quantity;
  4778. else
  4779. item->details.count = closest->quantity;
  4780. }
  4781. if(!player->item_list.HasFreeSlot() && !player->item_list.CanStack(item))
  4782. SimpleMessage(CHANNEL_COLOR_RED, "You do not have any slots available for this item.");
  4783. else if(player->RemoveCoins(closest->quantity*closest->price)){
  4784. bool removed = false;
  4785. if(closest->quantity == quantity){
  4786. MBuyBack.writelock(__FUNCTION__, __LINE__);
  4787. for(itr = buy_back_items.begin(); itr != buy_back_items.end(); itr++){
  4788. if(*itr == closest){
  4789. buy_back_items.erase(itr);
  4790. removed = true;
  4791. break;
  4792. }
  4793. }
  4794. MBuyBack.releasewritelock(__FUNCTION__, __LINE__);
  4795. }
  4796. else{
  4797. closest->quantity -= quantity;
  4798. closest->save_needed = true;
  4799. }
  4800. AddItem(item);
  4801. //EQ2Packet* outapp = player->SendInventoryUpdate(GetVersion());
  4802. //if(outapp)
  4803. //QueuePacket(outapp);
  4804. if(removed){
  4805. database.DeleteBuyBack(GetCharacterID(), closest->item_id, closest->quantity, closest->price);
  4806. safe_delete(closest);
  4807. }
  4808. if(!(spawn->GetMerchantType() & MERCHANT_TYPE_NO_BUY))
  4809. SendSellMerchantList();
  4810. if(!(spawn->GetMerchantType() & MERCHANT_TYPE_NO_BUY_BACK))
  4811. SendBuyBackList();
  4812. }
  4813. else
  4814. SimpleMessage(CHANNEL_COLOR_RED, "You cannot afford this item.");
  4815. }
  4816. }
  4817. }
  4818. void Client::BuyItem(int32 item_id, int16 quantity){
  4819. // Get the merchant we are buying from
  4820. Spawn* spawn = GetMerchantTransaction();
  4821. // Make sure the spawn has a merchant list
  4822. if(spawn && spawn->GetMerchantID() > 0){
  4823. int32 total_buy_price = 0;
  4824. float multiplier = CalculateBuyMultiplier(spawn->GetMerchantID());
  4825. int32 sell_price = 0;
  4826. Item* master_item = master_item_list.GetItem(item_id);
  4827. Item* item = 0;
  4828. int16 total_available = 0;
  4829. vector<MerchantItemInfo>* temp;
  4830. vector<MerchantItemInfo>::iterator itr;
  4831. MerchantItemInfo* ItemInfo = 0;
  4832. temp = world.GetMerchantList(spawn->GetMerchantID());
  4833. for (itr = temp->begin(); itr != temp->end(); itr++) {
  4834. if ((*itr).item_id == item_id) {
  4835. ItemInfo = &(*itr);
  4836. break;
  4837. }
  4838. }
  4839. if(master_item && ItemInfo){
  4840. if (spawn->GetMerchantType() & MERCHANT_TYPE_LOTTO) {
  4841. quantity = 1;
  4842. total_available = 0xFFFF;
  4843. sell_price = master_item->sell_price;
  4844. }
  4845. else {
  4846. total_available = world.GetMerchantItemQuantity(spawn->GetMerchantID(), item_id);
  4847. sell_price = (int32)(master_item->sell_price * multiplier);
  4848. if(quantity > total_available)
  4849. quantity = total_available;
  4850. }
  4851. total_buy_price = sell_price * quantity;
  4852. item = new Item(master_item);
  4853. item->details.count = quantity;
  4854. if(!player->item_list.HasFreeSlot() && !player->item_list.CanStack(item)){
  4855. SimpleMessage(CHANNEL_COLOR_RED, "You do not have any slots available for this item.");
  4856. safe_delete(item);
  4857. }
  4858. else {
  4859. // Price not set in the merchant_inventory table, use the old method
  4860. if (ItemInfo->price_item_id == 0 && ItemInfo->price_item2_id == 0 && ItemInfo->price_status == 0 && ItemInfo->price_stationcash == 0 && ItemInfo->price_coins == 0) {
  4861. if(player->RemoveCoins(total_buy_price)){
  4862. item->SetMaxSellValue(sell_price);
  4863. if(quantity > 1)
  4864. Message(CHANNEL_COLOR_MERCHANT, "You buy %i \\aITEM %u 0:%s\\/a from %s for%s.", quantity, master_item->details.item_id, master_item->name.c_str(), spawn->GetName(), GetCoinMessage(total_buy_price).c_str());
  4865. else
  4866. Message(CHANNEL_COLOR_MERCHANT, "You buy \\aITEM %u 0:%s\\/a from %s for%s.", master_item->details.item_id, master_item->name.c_str(), spawn->GetName(), GetCoinMessage(total_buy_price).c_str());
  4867. AddItem(item);
  4868. CheckPlayerQuestsItemUpdate(item);
  4869. if(item && total_available < 0xFFFF){
  4870. world.DecreaseMerchantQuantity(spawn->GetMerchantID(), item_id, quantity);
  4871. SendBuyMerchantList();
  4872. }
  4873. //EQ2Packet* outapp = player->SendInventoryUpdate(GetVersion());
  4874. //if(outapp)
  4875. // QueuePacket(outapp);
  4876. if(!(spawn->GetMerchantType() & MERCHANT_TYPE_NO_BUY) && !(spawn->GetMerchantType() & MERCHANT_TYPE_LOTTO))
  4877. SendSellMerchantList();
  4878. if (spawn->GetMerchantType() & MERCHANT_TYPE_LOTTO)
  4879. PlayLotto(total_buy_price, item->details.item_id);
  4880. }
  4881. else{
  4882. Message(CHANNEL_COLOR_RED, "You do not have enough coin to purchase \\aITEM %u 0:%s\\/a.", master_item->details.item_id, master_item->name.c_str());
  4883. GetCurrentZone()->SendSpellFailedPacket(this, SPELL_ERROR_NOT_ENOUGH_COIN);
  4884. PlaySound("buy_failed");
  4885. }
  4886. }
  4887. else {
  4888. // Price set in merchant_inventory table
  4889. // Check if the player has enough status, coins and staion cash to buy the item before checking the items
  4890. // TODO: need to add support for station cash
  4891. if (player->GetInfoStruct()->status_points >= ItemInfo->price_status && player->HasCoins(ItemInfo->price_coins * quantity)) {
  4892. // Check items
  4893. int16 item_quantity = 0;
  4894. // Default these to true in case price_item_id or price_item2_id was never set
  4895. bool hasItem1 = true;
  4896. bool hasItem2 = true;
  4897. Item* tempItem1 = 0;
  4898. Item* tempItem2 = 0;
  4899. if (ItemInfo->price_item_id != 0) {
  4900. // Same item for whatever reason lets add the quantities together
  4901. if (ItemInfo->price_item_id == ItemInfo->price_item2_id)
  4902. item_quantity = ItemInfo->price_item_qty + ItemInfo->price_item2_qty;
  4903. else
  4904. item_quantity = ItemInfo->price_item_qty;
  4905. tempItem1 = player->item_list.GetItemFromID(ItemInfo->price_item_id);
  4906. if (tempItem1) {
  4907. if (tempItem1->details.count < item_quantity)
  4908. hasItem1 = false;
  4909. }
  4910. else {
  4911. hasItem1 = false;
  4912. }
  4913. }
  4914. // Check item2, if item_quantity is greater then item1 quantity then item2 is the same item
  4915. // as item1 and we already checked for it so we can skip this check
  4916. if (ItemInfo->price_item2_id != 0 && item_quantity <= ItemInfo->price_item_qty) {
  4917. tempItem2 = player->item_list.GetItemFromID(ItemInfo->price_item2_id);
  4918. if (tempItem2) {
  4919. if (tempItem2->details.count < ItemInfo->price_item2_qty)
  4920. hasItem2 = false;
  4921. }
  4922. else {
  4923. hasItem2 = false;
  4924. }
  4925. }
  4926. // if we have every thing then remove the price and give the item
  4927. if (hasItem1 && hasItem2) {
  4928. player->GetInfoStruct()->status_points -= ItemInfo->price_status;
  4929. // TODO: station cash
  4930. // The update that would normally be sent after modifing the players inventory is automatically sent in AddItem wich is called later
  4931. // so there is no need to send it more then that one time
  4932. if (tempItem1) {
  4933. if (tempItem1->details.count > item_quantity) {
  4934. tempItem1->details.count -= item_quantity;
  4935. tempItem1->save_needed = true;
  4936. }
  4937. else {
  4938. database.DeleteItem(GetCharacterID(), tempItem1, 0);
  4939. player->item_list.DestroyItem(tempItem1->details.index);
  4940. }
  4941. }
  4942. if (tempItem2) {
  4943. if (tempItem2->details.count > ItemInfo->price_item2_qty) {
  4944. tempItem2->details.count -= ItemInfo->price_item2_qty;
  4945. tempItem2->save_needed = true;
  4946. }
  4947. else {
  4948. database.DeleteItem(GetCharacterID(), tempItem2, 0);
  4949. player->item_list.DestroyItem(tempItem2->details.index);
  4950. }
  4951. }
  4952. // Checked to see if we had enough coins already so don't need to check the return type on RemoveCoins as it will always be true
  4953. player->RemoveCoins(ItemInfo->price_coins * quantity);
  4954. item->SetMaxSellValue(sell_price);
  4955. if(quantity > 1)
  4956. Message(CHANNEL_COLOR_MERCHANT, "You buy %i \\aITEM %u 0:%s\\/a from %s for%s.", quantity, master_item->details.item_id, master_item->name.c_str(), spawn->GetName(), GetCoinMessage(ItemInfo->price_coins * quantity).c_str());
  4957. else
  4958. Message(CHANNEL_COLOR_MERCHANT, "You buy \\aITEM %u 0:%s\\/a from %s for%s.", master_item->details.item_id, master_item->name.c_str(), spawn->GetName(), GetCoinMessage(ItemInfo->price_coins * quantity).c_str());
  4959. AddItem(item);
  4960. CheckPlayerQuestsItemUpdate(item);
  4961. if(item && total_available < 0xFFFF){
  4962. world.DecreaseMerchantQuantity(spawn->GetMerchantID(), item_id, quantity);
  4963. SendBuyMerchantList();
  4964. }
  4965. if(!(spawn->GetMerchantType() & MERCHANT_TYPE_NO_BUY) && !(spawn->GetMerchantType() & MERCHANT_TYPE_LOTTO))
  4966. SendSellMerchantList();
  4967. if (spawn->GetMerchantType() & MERCHANT_TYPE_LOTTO)
  4968. PlayLotto(total_buy_price, item->details.item_id);
  4969. }
  4970. else{
  4971. Message(CHANNEL_COLOR_RED, "You do not have enough coin to purchase \\aITEM %u 0:%s\\/a.", master_item->details.item_id, master_item->name.c_str());
  4972. GetCurrentZone()->SendSpellFailedPacket(this, SPELL_ERROR_NOT_ENOUGH_COIN);
  4973. PlaySound("buy_failed");
  4974. }
  4975. }
  4976. else{
  4977. Message(CHANNEL_COLOR_RED, "You do not have enough coin to purchase \\aITEM %u 0:%s\\/a.", master_item->details.item_id, master_item->name.c_str());
  4978. GetCurrentZone()->SendSpellFailedPacket(this, SPELL_ERROR_NOT_ENOUGH_COIN);
  4979. PlaySound("buy_failed");
  4980. }
  4981. }
  4982. }
  4983. }
  4984. }
  4985. }
  4986. void Client::RepairItem(int32 item_id) {
  4987. Spawn* spawn = GetMerchantTransaction();
  4988. if (spawn) {
  4989. Item* item = player->item_list.GetItemFromID(item_id);
  4990. if (!item)
  4991. item = player->GetEquipmentList()->GetItemFromItemID(item_id);
  4992. if (item) {
  4993. int32 repair_cost = item->CalculateRepairCost();
  4994. if (player->RemoveCoins((int32)repair_cost)) {
  4995. item->generic_info.condition = 100;
  4996. item->save_needed = true;
  4997. QueuePacket(player->GetEquipmentList()->serialize(GetVersion()));
  4998. QueuePacket(player->SendInventoryUpdate(GetVersion()));
  4999. QueuePacket(item->serialize(version, false, player));
  5000. Message(CHANNEL_COLOR_MERCHANT, "You give %s %s to repair your \\aITEM %u 0:%s\\/a.", spawn->GetName(), GetCoinMessage(repair_cost).c_str(), item->details.item_id, item->name.c_str());
  5001. PlaySound("coin_cha_ching");
  5002. if (spawn->GetMerchantType() & MERCHANT_TYPE_REPAIR)
  5003. SendRepairList();
  5004. }
  5005. else {
  5006. LogWrite(MISC__TODO, 1, "TODO", " Send pop up that says 'Not enough coin.'\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
  5007. Message(CHANNEL_COLOR_MERCHANT, "You do not have enough coin to repair \\aITEM %u 0:%s\\/a.", item->details.item_id, item->name.c_str());
  5008. PlaySound("buy_failed");
  5009. }
  5010. }
  5011. }
  5012. }
  5013. void Client::RepairAllItems() {
  5014. Spawn* spawn = GetMerchantTransaction();
  5015. if (spawn) {
  5016. vector<Item*>* repairable_items = GetRepairableItems();
  5017. if (repairable_items && repairable_items->size() > 0) {
  5018. vector<Item*>::iterator itr;
  5019. int64 total_cost = 0;
  5020. for (itr = repairable_items->begin(); itr != repairable_items->end(); itr++)
  5021. total_cost += (*itr)->CalculateRepairCost();
  5022. if (player->RemoveCoins((int32)total_cost)) {
  5023. Message(CHANNEL_COLOR_MERCHANT, "You give %s to repair all of your items.", GetCoinMessage((int32)total_cost).c_str());
  5024. for (itr = repairable_items->begin(); itr != repairable_items->end(); itr++) {
  5025. Item* item = *itr;
  5026. if (item) {
  5027. item->generic_info.condition = 100;
  5028. item->save_needed = true;
  5029. QueuePacket(item->serialize(version, false, player));
  5030. Message(CHANNEL_COLOR_YELLOW, "Repaired: \\aITEM %u 0:%s\\/a.", item->details.item_id, item->name.c_str());
  5031. }
  5032. }
  5033. QueuePacket(player->GetEquipmentList()->serialize(GetVersion()));
  5034. QueuePacket(player->SendInventoryUpdate(GetVersion()));
  5035. PlaySound("coin_cha_ching");
  5036. if (spawn->GetMerchantType() & MERCHANT_TYPE_REPAIR)
  5037. SendRepairList();
  5038. }
  5039. else {
  5040. LogWrite(MISC__TODO, 1, "TODO", "Send pop up that says 'Not enough coin.'\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
  5041. SimpleMessage(CHANNEL_COLOR_MERCHANT, "You do not have enough coin to repair all of your items.");
  5042. PlaySound("buy_failed");
  5043. }
  5044. }
  5045. safe_delete(repairable_items);
  5046. }
  5047. }
  5048. void Client::SendAchievementsList()
  5049. {
  5050. /*map<int32, Achievement *> *achievements = player->GetAchievementList()->GetAchievements();
  5051. map<int32, Achievement *>::iterator itr;
  5052. Achievement *achievement;
  5053. vector<AchievementRequirements *> *requirements = 0;
  5054. vector<AchievementRequirements *>::iterator itr2;
  5055. AchievementRequirements *requirement;
  5056. vector<AchievementRewards *> *rewards = 0;
  5057. vector<AchievementRewards *>::iterator itr3;
  5058. AchievementRewards *reward;
  5059. PacketStruct *packet;
  5060. int16 i = 0;
  5061. int16 j = 0;
  5062. int16 k = 0;
  5063. if (!(packet = configReader.getStruct("WS_CharacterAchievements", version))) {
  5064. return;
  5065. }
  5066. packet->setArrayLengthByName("num_achievements" , achievements->size());
  5067. for (itr = achievements->begin(); itr != achievements->end(); itr++) {
  5068. achievement = itr->second;
  5069. packet->setArrayDataByName("achievement_id", achievement->GetID(), i);
  5070. packet->setArrayDataByName("title", achievement->GetTitle(), i);
  5071. packet->setArrayDataByName("uncompleted_text", achievement->GetUncompletedText(), i);
  5072. packet->setArrayDataByName("completed_text", achievement->GetCompletedText(), i);
  5073. packet->setArrayDataByName("category", achievement->GetCategory(), i);
  5074. packet->setArrayDataByName("expansion", achievement->GetExpansion(), i);
  5075. packet->setArrayDataByName("icon", achievement->GetIcon(), i);
  5076. packet->setArrayDataByName("point_value", achievement->GetPointValue(), i);
  5077. packet->setArrayDataByName("qty_req", achievement->GetQtyReq(), i);
  5078. packet->setArrayDataByName("hide_achievement", achievement->GetHide(), i);
  5079. packet->setArrayDataByName("unknown3", achievement->GetUnknown3a(), i);
  5080. packet->setArrayDataByName("unknown3", achievement->GetUnknown3b(), i);
  5081. requirements = achievement->GetRequirements();
  5082. rewards = achievement->GetRewards();
  5083. j = 0;
  5084. k = 0;
  5085. packet->setSubArrayLengthByName("num_items", requirements->size(), i, j);
  5086. for (itr2 = requirements->begin(); itr2 != requirements->end(); itr2++) {
  5087. requirement = *itr2;
  5088. packet->setSubArrayDataByName("item_name", requirement->name.c_str(), i, j);
  5089. packet->setSubArrayDataByName("item_qty_req", requirement->qty_req, i, j);
  5090. j++;
  5091. }
  5092. packet->setSubArrayLengthByName("num_rewards", achievement->GetRewards()->size(), i, k);
  5093. for (itr3 = rewards->begin(); itr3 != rewards->end(); itr3++) {
  5094. reward = *itr3;
  5095. packet->setSubArrayDataByName("reward_item", reward->reward.c_str(), i, k);
  5096. k++;
  5097. }
  5098. i++;
  5099. }
  5100. //packet->PrintPacket();
  5101. EQ2Packet* data = packet->serialize();
  5102. EQ2Packet* app = new EQ2Packet(OP_ClientCmdMsg, data->pBuffer, data->size);
  5103. safe_delete(packet);
  5104. safe_delete(data);
  5105. //DumpPacket(app);
  5106. QueuePacket(app);*/
  5107. QueuePacket(master_achievement_list.GetAchievementPacket()->Copy());
  5108. SendAchievementUpdate(true);
  5109. }
  5110. void Client::SendAchievementUpdate(bool first_login) {
  5111. map<int32, AchievementUpdate *> *updates = player->GetAchievementUpdateList()->GetAchievementUpdates();
  5112. map<int32, AchievementUpdate *>::iterator itr;
  5113. AchievementUpdate *update;
  5114. vector<AchievementUpdateItems *> *update_items = 0;
  5115. vector<AchievementUpdateItems *>::iterator itr2;
  5116. AchievementUpdateItems *update_item;
  5117. int16 i = 0;
  5118. int16 j = 0;
  5119. PacketStruct *packet;
  5120. if (!(packet = configReader.getStruct("WS_AchievementUpdate", version))) {
  5121. return;
  5122. }
  5123. packet->setDataByName("unknown1", first_login ? 1 : 0);
  5124. packet->setArrayLengthByName("num_achievements", updates->size());
  5125. for (itr = updates->begin(); itr != updates->end(); itr++) {
  5126. update = itr->second;
  5127. packet->setArrayDataByName("achievement_id", update->GetID(), i);
  5128. packet->setArrayDataByName("completed_date", update->GetCompletedDate(), i);
  5129. update_items = update->GetUpdateItems();
  5130. j = 0;
  5131. packet->setSubArrayLengthByName("num_items", update_items->size(), i);
  5132. for (itr2 = update_items->begin(); itr2 != update_items->end(); itr2++) {
  5133. update_item = *itr2;
  5134. packet->setSubArrayDataByName("item_update", update_item->item_update, i, j);
  5135. j++;
  5136. }
  5137. i++;
  5138. }
  5139. //packet->PrintPacket();
  5140. EQ2Packet* data = packet->serialize();
  5141. EQ2Packet* app = new EQ2Packet(OP_ClientCmdMsg, data->pBuffer, data->size);
  5142. safe_delete(packet);
  5143. safe_delete(data);
  5144. //DumpPacket(app);
  5145. QueuePacket(app);
  5146. }
  5147. void Client::SendBuyMerchantList(bool sell){
  5148. Spawn* spawn = GetMerchantTransaction();
  5149. if(spawn && spawn->GetMerchantID() > 0){
  5150. vector<MerchantItemInfo>* items = world.GetMerchantItemList(spawn->GetMerchantID(), spawn->GetMerchantType(), player);
  5151. if(items){
  5152. PacketStruct* packet = configReader.getStruct("WS_UpdateMerchant", GetVersion());
  5153. if(packet){
  5154. float multiplier = CalculateBuyMultiplier(spawn->GetMerchantID());
  5155. packet->setDataByName("spawn_id", player->GetIDWithPlayerSpawn(spawn));
  5156. packet->setArrayLengthByName("num_items", items->size());
  5157. vector<MerchantItemInfo>::iterator itr;
  5158. sint8 item_difficulty = 0;
  5159. int32 sell_price = 0;
  5160. int i = 0;
  5161. int tmp_level = 0;
  5162. for(itr = items->begin(); itr != items->end(); itr++, i++){
  5163. MerchantItemInfo ItemInfo = *itr;
  5164. Item* item = master_item_list.GetItem(ItemInfo.item_id);
  5165. if (!item)
  5166. continue;
  5167. packet->setArrayDataByName("item_name", item->name.c_str(), i);
  5168. packet->setArrayDataByName("item_id", item->details.item_id, i);
  5169. packet->setArrayDataByName("stack_size", item->stack_count, i);
  5170. packet->setArrayDataByName("icon", item->details.icon, i);
  5171. if(item->generic_info.adventure_default_level > 0)
  5172. tmp_level = item->generic_info.adventure_default_level;
  5173. else
  5174. tmp_level = item->generic_info.tradeskill_default_level;
  5175. packet->setArrayDataByName("level", tmp_level, i);
  5176. packet->setArrayDataByName("tier", item->details.tier, i);
  5177. packet->setArrayDataByName("item_id2", item->details.item_id, i);
  5178. item_difficulty = player->GetArrowColor(tmp_level);
  5179. if(item_difficulty != ARROW_COLOR_WHITE && item_difficulty != ARROW_COLOR_RED && item_difficulty != ARROW_COLOR_GRAY)
  5180. item_difficulty = ARROW_COLOR_WHITE;
  5181. item_difficulty -= 6;
  5182. if(item_difficulty < 0)
  5183. item_difficulty*=-1;
  5184. packet->setArrayDataByName("item_difficulty", item_difficulty, i);
  5185. packet->setArrayDataByName("quantity", ItemInfo.quantity, i);
  5186. packet->setArrayDataByName("unknown5", 255, i);
  5187. packet->setArrayDataByName("stack_size2", item->stack_count, i);
  5188. if (GetVersion() <= 1096)
  5189. packet->setArrayDataByName("description", item->description.c_str(), i);
  5190. // If no price set in the merchant_inventory table then use the old method
  5191. if (ItemInfo.price_item_id == 0 && ItemInfo.price_item2_id == 0 && ItemInfo.price_coins == 0 && ItemInfo.price_status == 0 && ItemInfo.price_stationcash == 0) {
  5192. sell_price = (int32)(item->sell_price * multiplier);
  5193. packet->setArrayDataByName("price", sell_price, i);
  5194. }
  5195. else {
  5196. int8 count = 0;
  5197. if (ItemInfo.price_item_id != 0 && ItemInfo.price_item_qty != 0)
  5198. count++;
  5199. if (ItemInfo.price_item2_id != 0 && ItemInfo.price_item2_qty != 0)
  5200. count++;
  5201. if (count != 0) {
  5202. packet->setSubArrayLengthByName("num_tokens", count, i);
  5203. int8 index = 0;
  5204. Item* token = 0;
  5205. if (ItemInfo.price_item_id != 0) {
  5206. token = master_item_list.GetItem(ItemInfo.price_item_id);
  5207. if (item) {
  5208. packet->setSubArrayDataByName("token_icon", token->details.icon, i, index);
  5209. packet->setSubArrayDataByName("token_qty", ItemInfo.price_item_qty, i, index);
  5210. packet->setSubArrayDataByName("token_id", ItemInfo.price_item_id, i, index);
  5211. packet->setSubArrayDataByName("token_name", token->name.c_str(), i, index);
  5212. }
  5213. token = 0;
  5214. index++;
  5215. }
  5216. if (ItemInfo.price_item2_id != 0) {
  5217. token = master_item_list.GetItem(ItemInfo.price_item2_id);
  5218. if (item) {
  5219. packet->setSubArrayDataByName("token_icon", token->details.icon, i, index);
  5220. packet->setSubArrayDataByName("token_qty", ItemInfo.price_item2_qty, i, index);
  5221. packet->setSubArrayDataByName("token_id", ItemInfo.price_item2_id, i, index);
  5222. packet->setSubArrayDataByName("token_name", token->name.c_str(), i, index);
  5223. }
  5224. }
  5225. }
  5226. packet->setArrayDataByName("price", ItemInfo.price_coins, i);
  5227. packet->setArrayDataByName("status", ItemInfo.price_status, i);
  5228. packet->setArrayDataByName("station_cash", ItemInfo.price_stationcash, i);
  5229. }
  5230. }
  5231. if (sell)
  5232. packet->setDataByName("type", 130);
  5233. else
  5234. packet->setDataByName("type", 2);
  5235. EQ2Packet* outapp = packet->serialize();
  5236. // DumpPacket(outapp);
  5237. QueuePacket(outapp);
  5238. safe_delete(packet);
  5239. }
  5240. safe_delete(items);
  5241. }
  5242. else {
  5243. // Need to send an empty packet in the event there is no item list, otherwise the
  5244. // last item list sent to the player will show for this merchant
  5245. PacketStruct* packet = configReader.getStruct("WS_UpdateMerchant", GetVersion());
  5246. if (packet) {
  5247. packet->setDataByName("spawn_id", player->GetIDWithPlayerSpawn(spawn));
  5248. if (sell)
  5249. packet->setDataByName("type", 130);
  5250. else
  5251. packet->setDataByName("type", 2);
  5252. EQ2Packet* outapp = packet->serialize();
  5253. QueuePacket(outapp);
  5254. safe_delete(packet);
  5255. }
  5256. }
  5257. }
  5258. }
  5259. void Client::SendSellMerchantList(bool sell){
  5260. Spawn* spawn = GetMerchantTransaction();
  5261. if(spawn && spawn->GetMerchantID() > 0){
  5262. map<int32, Item*>* items = player->GetItemList();
  5263. if(items){
  5264. PacketStruct* packet = configReader.getStruct("WS_UpdateMerchant", GetVersion());
  5265. if(packet){
  5266. vector<Item*> sellable_items;
  5267. map<int32, Item*>::iterator test_itr;
  5268. for(test_itr = items->begin(); test_itr != items->end(); test_itr++){
  5269. if(test_itr->second && !test_itr->second->CheckFlag(NO_VALUE))
  5270. sellable_items.push_back(test_itr->second);
  5271. }
  5272. packet->setDataByName("spawn_id", player->GetIDWithPlayerSpawn(spawn));
  5273. packet->setArrayLengthByName("num_items", sellable_items.size());
  5274. vector<Item*>::iterator itr;
  5275. Item* item = 0;
  5276. sint8 item_difficulty = 0;
  5277. float multiplier = CalculateSellMultiplier(spawn->GetMerchantID());
  5278. int32 sell_price = 0;
  5279. Item* master_item = 0;
  5280. int i = 0;
  5281. int tmp_level = 0;
  5282. for(itr = sellable_items.begin(); itr != sellable_items.end(); itr++, i++){
  5283. item = *itr;
  5284. master_item = master_item_list.GetItem(item->details.item_id);
  5285. if(master_item)
  5286. sell_price = (int32)(master_item->sell_price * multiplier);
  5287. else
  5288. sell_price = 0;
  5289. if(sell_price > item->sell_price)
  5290. sell_price = item->sell_price;
  5291. packet->setArrayDataByName("item_name", item->name.c_str(), i);
  5292. string thename = item->name;
  5293. packet->setArrayDataByName("price", sell_price, i);
  5294. if (player->GetGuild()){
  5295. packet->setArrayDataByName("status", 0, i);//additive to status 2 maybe for server bonus etc
  5296. packet->setArrayDataByName("status2", item->sell_status, i); //this one is the main status
  5297. }
  5298. packet->setArrayDataByName("item_id", item->details.item_id, i);
  5299. packet->setArrayDataByName("unique_item_id", item->details.unique_id, i);
  5300. packet->setArrayDataByName("stack_size", item->details.count, i);
  5301. packet->setArrayDataByName("icon", item->details.icon, i);
  5302. if(item->generic_info.adventure_default_level > 0)
  5303. tmp_level = item->generic_info.adventure_default_level;
  5304. else
  5305. tmp_level = item->generic_info.tradeskill_default_level;
  5306. packet->setArrayDataByName("level", item->details.recommended_level, i);
  5307. packet->setArrayDataByName("tier", item->details.tier, i);
  5308. packet->setArrayDataByName("item_id2", item->details.item_id, i);
  5309. item_difficulty = player->GetArrowColor(tmp_level);
  5310. if(item_difficulty != ARROW_COLOR_WHITE && item_difficulty != ARROW_COLOR_RED && item_difficulty != ARROW_COLOR_GRAY)
  5311. item_difficulty = ARROW_COLOR_WHITE;
  5312. item_difficulty -= 6;
  5313. if(item_difficulty < 0)
  5314. item_difficulty*=-1;
  5315. packet->setArrayDataByName("item_difficulty", item_difficulty, i);
  5316. if(item->details.count == 1)
  5317. packet->setArrayDataByName("quantity", 0xFFFF, i);
  5318. else
  5319. packet->setArrayDataByName("quantity", item->details.count, i);
  5320. packet->setArrayDataByName("stack_size2", item->details.count, i);
  5321. if (GetVersion() <= 1096)
  5322. packet->setArrayDataByName("description", item->description.c_str(), i);
  5323. }
  5324. if (sell)
  5325. packet->setDataByName("type", 129);
  5326. else
  5327. packet->setDataByName("type", 1);
  5328. packet->setDataByName("unknown8a", 16256,6);
  5329. packet->setDataByName("unknown8a", 16256, 10);
  5330. //packet->PrintPacket();
  5331. EQ2Packet* outapp = packet->serialize();
  5332. //DumpPacket(outapp);
  5333. QueuePacket(outapp);
  5334. safe_delete(packet);
  5335. }
  5336. safe_delete(items);
  5337. }
  5338. }
  5339. }
  5340. void Client::SendBuyBackList(bool sell){
  5341. Spawn* spawn = GetMerchantTransaction();
  5342. if(spawn && spawn->GetMerchantID() > 0){
  5343. deque<BuyBackItem*>::iterator itr;
  5344. int i = 0;
  5345. Item* master_item = 0;
  5346. BuyBackItem* buyback = 0;
  5347. PacketStruct* packet = configReader.getStruct("WS_UpdateMerchant", GetVersion());
  5348. if(packet){
  5349. packet->setDataByName("spawn_id", player->GetIDWithPlayerSpawn(spawn));
  5350. packet->setArrayLengthByName("num_items", buy_back_items.size());
  5351. sint8 item_difficulty = 0;
  5352. MBuyBack.readlock(__FUNCTION__, __LINE__);
  5353. int tmp_level = 0;
  5354. for(itr = buy_back_items.begin(); itr != buy_back_items.end(); itr++, i++){
  5355. buyback = *itr;
  5356. master_item = master_item_list.GetItem(buyback->item_id);
  5357. if(master_item){
  5358. packet->setArrayDataByName("item_name", master_item->name.c_str(), i);
  5359. packet->setArrayDataByName("price", buyback->price, i);
  5360. packet->setArrayDataByName("item_id", master_item->details.item_id, i);
  5361. packet->setArrayDataByName("unique_item_id", buyback->unique_id, i);
  5362. packet->setArrayDataByName("stack_size", buyback->quantity, i);
  5363. packet->setArrayDataByName("icon", master_item->details.icon, i);
  5364. if(master_item->generic_info.adventure_default_level > 0)
  5365. tmp_level = master_item->generic_info.adventure_default_level;
  5366. else
  5367. tmp_level = master_item->generic_info.tradeskill_default_level;
  5368. packet->setArrayDataByName("level", tmp_level, i);
  5369. packet->setArrayDataByName("tier", master_item->details.tier, i);
  5370. packet->setArrayDataByName("item_id2", master_item->details.item_id, i);
  5371. item_difficulty = player->GetArrowColor(tmp_level);
  5372. if(item_difficulty != ARROW_COLOR_WHITE && item_difficulty != ARROW_COLOR_RED && item_difficulty != ARROW_COLOR_GRAY)
  5373. item_difficulty = ARROW_COLOR_WHITE;
  5374. item_difficulty -= 6;
  5375. if(item_difficulty < 0)
  5376. item_difficulty*=-1;
  5377. packet->setArrayDataByName("item_difficulty", item_difficulty, i);
  5378. if(buyback->quantity == 1)
  5379. packet->setArrayDataByName("quantity", 0xFFFF, i);
  5380. else
  5381. packet->setArrayDataByName("quantity", buyback->quantity, i);
  5382. packet->setArrayDataByName("stack_size2", buyback->quantity, i);
  5383. if (GetVersion() <= 1096)
  5384. packet->setArrayDataByName("description", master_item->description.c_str(), i);
  5385. }
  5386. }
  5387. MBuyBack.releasereadlock(__FUNCTION__, __LINE__);
  5388. if (sell)
  5389. packet->setDataByName("type", 640);
  5390. else
  5391. packet->setDataByName("type", 512);
  5392. EQ2Packet* outapp = packet->serialize();
  5393. // DumpPacket(outapp);
  5394. QueuePacket(outapp);
  5395. safe_delete(packet);
  5396. }
  5397. }
  5398. }
  5399. void Client::SendRepairList() {
  5400. Spawn* spawn = GetMerchantTransaction();
  5401. if (spawn) {
  5402. vector<Item*>* repairable_items = GetRepairableItems();
  5403. PacketStruct* packet = configReader.getStruct("WS_UpdateMerchant", GetVersion());
  5404. if (packet) {
  5405. packet->setDataByName("spawn_id", player->GetIDWithPlayerSpawn(spawn));
  5406. packet->setArrayLengthByName("num_items", repairable_items->size());
  5407. Item* item = 0;
  5408. sint8 item_difficulty = 0;
  5409. int32 i = 0;
  5410. vector<Item*>::iterator itr;
  5411. for (itr = repairable_items->begin(); itr != repairable_items->end(); itr++, i++) {
  5412. item = *itr;
  5413. packet->setArrayDataByName("item_name", item->name.c_str(), i);
  5414. packet->setArrayDataByName("price", item->CalculateRepairCost(), i);
  5415. packet->setArrayDataByName("item_id", item->details.item_id, i);
  5416. packet->setArrayDataByName("stack_size", item->details.count, i);
  5417. packet->setArrayDataByName("icon", item->details.icon, i);
  5418. /*if (item->generic_info.adventure_default_level > 0)
  5419. tmp_level = item->generic_info.adventure_default_level;
  5420. else
  5421. tmp_level = item->generic_info.tradeskill_default_level;
  5422. packet->setArrayDataByName("level", tmp_level, i);*/
  5423. packet->setArrayDataByName("level", item->generic_info.adventure_default_level, i);
  5424. packet->setArrayDataByName("tier", item->details.tier, i);
  5425. packet->setArrayDataByName("item_id2", item->details.item_id, i);
  5426. item_difficulty = player->GetArrowColor(item->generic_info.adventure_default_level);
  5427. if(item_difficulty != ARROW_COLOR_WHITE && item_difficulty != ARROW_COLOR_RED && item_difficulty != ARROW_COLOR_GRAY)
  5428. item_difficulty = ARROW_COLOR_WHITE;
  5429. item_difficulty -= 6;
  5430. if(item_difficulty < 0)
  5431. item_difficulty*=-1;
  5432. packet->setArrayDataByName("item_difficulty", item_difficulty, i);
  5433. if(item->details.count == 1)
  5434. packet->setArrayDataByName("quantity", 0xFFFF, i);
  5435. else
  5436. packet->setArrayDataByName("quantity", item->details.count, i);
  5437. packet->setArrayDataByName("stack_size2", item->details.count, i);
  5438. if (GetVersion() <= 1096)
  5439. packet->setArrayDataByName("description", item->description.c_str(), i);
  5440. }
  5441. packet->setDataByName("type", 96);
  5442. EQ2Packet* outapp = packet->serialize();
  5443. QueuePacket(outapp);
  5444. safe_delete(packet);
  5445. }
  5446. safe_delete(repairable_items);
  5447. }
  5448. }
  5449. void Client::ShowLottoWindow() {
  5450. Spawn* spawn = GetMerchantTransaction();
  5451. if (spawn) {
  5452. int32 item_id = rule_manager.GetGlobalRule(R_World, GamblingTokenItemID)->GetInt32();
  5453. if( !item_id )
  5454. {
  5455. LogWrite(WORLD__ERROR, 0, "World", "No GamblingTokenItemID rule set!");
  5456. SimpleMessage(CHANNEL_COLOR_RED, "The server admin has not setup a lotto item ticket.");
  5457. return;
  5458. }
  5459. else if( item_id == 0 )
  5460. {
  5461. LogWrite(WORLD__ERROR, 0, "World", "Error! Invalid GamblingTokenItemID value!");
  5462. return;
  5463. }
  5464. Item* item = master_item_list.GetItem(item_id);
  5465. if (!item) {
  5466. LogWrite(WORLD__ERROR, 0, "World", "The 'GamblingTokenItemID' rule value %u is not a valid item id.", item_id);
  5467. return;
  5468. }
  5469. LogWrite(WORLD__DEBUG, 0, "World", "GamblingTokenItemID = '%s' (%u)", item->name.c_str(), item_id);
  5470. PacketStruct* packet = configReader.getStruct("WS_UpdateMerchant", GetVersion());
  5471. if (packet) {
  5472. packet->setDataByName("spawn_id", player->GetIDWithPlayerSpawn(spawn));
  5473. packet->setArrayLengthByName("num_items", 1);
  5474. packet->setArrayDataByName("item_name", item->name.c_str());
  5475. packet->setArrayDataByName("price", item->sell_price);
  5476. packet->setArrayDataByName("item_id", item->details.item_id);
  5477. packet->setArrayDataByName("stack_size", item->details.count);
  5478. packet->setArrayDataByName("icon", item->details.icon);
  5479. packet->setArrayDataByName("level", item->generic_info.adventure_default_level);
  5480. packet->setArrayDataByName("tier", item->details.tier);
  5481. packet->setArrayDataByName("item_id2", item->details.item_id);
  5482. int8 item_difficulty = player->GetArrowColor(item->generic_info.adventure_default_level);
  5483. if(item_difficulty != ARROW_COLOR_WHITE && item_difficulty != ARROW_COLOR_RED && item_difficulty != ARROW_COLOR_GRAY)
  5484. item_difficulty = ARROW_COLOR_WHITE;
  5485. item_difficulty -= 6;
  5486. if(item_difficulty < 0)
  5487. item_difficulty*=-1;
  5488. packet->setArrayDataByName("item_difficulty", item_difficulty);
  5489. //if(item->details.count == 1)
  5490. packet->setArrayDataByName("quantity", 0xFFFF);
  5491. //else
  5492. // packet->setArrayDataByName("quantity", item->details.count);
  5493. packet->setArrayDataByName("stack_size2", item->details.count);
  5494. packet->setArrayDataByName("description", item->description.c_str());
  5495. packet->setDataByName("type", 0x00000102);
  5496. QueuePacket(packet->serialize());
  5497. safe_delete(packet);
  5498. }
  5499. }
  5500. }
  5501. void Client::PlayLotto(int32 price, int32 ticket_item_id) {
  5502. PacketStruct* packet = configReader.getStruct("WS_Lottery", GetVersion());
  5503. if (packet) {
  5504. world.AddLottoPlayer(GetCharacterID(), Timer::GetCurrentTime2() + 4500);
  5505. int32 rolls[6] = {0};
  5506. int32 lottery_digits[6] = {0};
  5507. int8 num_matches = 0;
  5508. int64 jackpot = 0;
  5509. Item* item = GetPlayer()->item_list.GetItemFromID(ticket_item_id);
  5510. if (!item) {
  5511. return;
  5512. }
  5513. database.DeleteItem(GetCharacterID(), item, 0);
  5514. GetPlayer()->item_list.RemoveItem(item, true);
  5515. QueuePacket(GetPlayer()->SendInventoryUpdate(GetVersion()));
  5516. Variable* winning_numbers = variables.FindVariable("gambling_winning_numbers");
  5517. if (!winning_numbers) {
  5518. winning_numbers = new Variable("gambling_winning_numbers", "231205182236", "Current Gigglegibber Gambling Game winning numbers");
  5519. variables.AddVariable(winning_numbers);
  5520. database.SaveVariable(winning_numbers->GetName(), winning_numbers->GetValue(), winning_numbers->GetComment());
  5521. }
  5522. if (strlen(winning_numbers->GetValue()) != 12) {
  5523. winning_numbers->SetValue("231205182236");
  5524. database.SaveVariable(winning_numbers->GetName(), winning_numbers->GetValue(), winning_numbers->GetComment());
  5525. }
  5526. try {
  5527. for (int32 i = 0; i < 12; i+=2) {
  5528. char num[4];
  5529. strncpy(num, winning_numbers->GetValue() + i, 2);
  5530. lottery_digits[i / 2] = atoi(num);
  5531. }
  5532. }
  5533. catch (...) {
  5534. LogWrite(WORLD__ERROR, 0, "World", "Error parsing 'gambling_winning_numbers' variable");
  5535. return;
  5536. }
  5537. Variable* jackpot_var = variables.FindVariable("gambling_current_jackpot");
  5538. if (!jackpot_var) {
  5539. jackpot_var = new Variable("gambling_current_jackpot", "10000", "Current Gigglegibber Gambling Game Jackpot");
  5540. variables.AddVariable(jackpot_var);
  5541. database.SaveVariable(jackpot_var->GetName(), jackpot_var->GetValue(), jackpot_var->GetComment());
  5542. }
  5543. try {
  5544. jackpot = atoul(jackpot_var->GetValue());
  5545. if (jackpot < 10000)
  5546. jackpot = 10000;
  5547. }
  5548. catch (...) {
  5549. jackpot = 10000;
  5550. }
  5551. char new_jackpot[128] = {0};
  5552. sprintf(new_jackpot, "%llu", jackpot + price);
  5553. jackpot_var->SetValue(new_jackpot);
  5554. database.SaveVariable(jackpot_var->GetName(), jackpot_var->GetValue(), jackpot_var->GetComment());
  5555. world.PickRandomLottoDigits(rolls);
  5556. packet->setDataByName("roll_digit1", rolls[0]);
  5557. packet->setDataByName("roll_digit2", rolls[1]);
  5558. packet->setDataByName("roll_digit3", rolls[2]);
  5559. packet->setDataByName("roll_digit4", rolls[3]);
  5560. packet->setDataByName("roll_digit5", rolls[4]);
  5561. packet->setDataByName("roll_digit6", rolls[5]);
  5562. packet->setDataByName("lottery_digit1", lottery_digits[0]);
  5563. packet->setDataByName("lottery_digit2", lottery_digits[1]);
  5564. packet->setDataByName("lottery_digit3", lottery_digits[2]);
  5565. packet->setDataByName("lottery_digit4", lottery_digits[3]);
  5566. packet->setDataByName("lottery_digit5", lottery_digits[4]);
  5567. packet->setDataByName("lottery_digit6", lottery_digits[5]);
  5568. QueuePacket(packet->serialize());
  5569. safe_delete(packet);
  5570. for (int32 i = 0; i < 6; i++) {
  5571. for (int32 j = 0; j < 6; j++) {
  5572. if (rolls[i] == lottery_digits[j]) {
  5573. num_matches++;
  5574. break;
  5575. }
  5576. }
  5577. }
  5578. char new_jackpot_str[16];
  5579. memset(new_jackpot_str, 0, sizeof(new_jackpot_str));
  5580. world.SetLottoPlayerNumMatches(GetCharacterID(), num_matches);
  5581. if (num_matches == 6) {
  5582. world.PickRandomLottoDigits(lottery_digits);
  5583. for (int32 i = 0; i < 12; i+=2)
  5584. sprintf(new_jackpot_str + i, "%02d", lottery_digits[i / 2]);
  5585. winning_numbers->SetValue(new_jackpot_str);
  5586. jackpot_var->SetValue("10000");
  5587. database.SaveVariable(winning_numbers->GetName(), winning_numbers->GetValue(), winning_numbers->GetComment());
  5588. database.SaveVariable(jackpot_var->GetName(), jackpot_var->GetValue(), jackpot_var->GetComment());
  5589. }
  5590. }
  5591. }
  5592. void Client::SendGuildCreateWindow() {
  5593. Spawn* spawn = GetPlayer()->GetTarget();
  5594. if (spawn) {
  5595. PacketStruct* packet = configReader.getStruct("WS_UpdateMerchant", GetVersion());
  5596. if (packet) {
  5597. packet->setDataByName("spawn_id", player->GetIDWithPlayerSpawn(spawn));
  5598. packet->setArrayLengthByName("num_items", 0);
  5599. packet->setDataByName("type", 0x00008000);
  5600. QueuePacket(packet->serialize());
  5601. safe_delete(packet);
  5602. }
  5603. }
  5604. }
  5605. void Client::AddBuyBack(int32 unique_id, int32 item_id, int16 quantity, int32 price, bool save_needed){
  5606. BuyBackItem* item = new BuyBackItem;
  5607. item->item_id = item_id;
  5608. item->unique_id = unique_id;
  5609. item->price = price;
  5610. item->quantity = quantity;
  5611. item->save_needed = save_needed;
  5612. MBuyBack.writelock(__FUNCTION__, __LINE__);
  5613. buy_back_items.push_back(item);
  5614. if(buy_back_items.size() > 10){
  5615. safe_delete(buy_back_items.front());
  5616. buy_back_items.pop_front();
  5617. }
  5618. MBuyBack.releasewritelock(__FUNCTION__, __LINE__);
  5619. }
  5620. deque<BuyBackItem*>* Client::GetBuyBacks(){
  5621. return &buy_back_items;
  5622. }
  5623. vector<Item*>* Client::GetRepairableItems() {
  5624. vector<Item*>* repairable_items = new vector<Item*>;
  5625. vector<Item*>* equipped_items = player->GetEquipmentList()->GetAllEquippedItems();
  5626. map<int32, Item*>* items = player->GetItemList();
  5627. if (equipped_items && equipped_items->size() > 0) {
  5628. for (int32 i = 0; i < equipped_items->size(); i++) {
  5629. Item* item = equipped_items->at(i);
  5630. if (item && item->generic_info.condition < 100)
  5631. repairable_items->push_back(item);
  5632. }
  5633. }
  5634. if (items && items->size() > 0) {
  5635. map<int32, Item*>::iterator itr;
  5636. for (itr = items->begin(); itr != items->end(); itr++) {
  5637. Item* item = itr->second;
  5638. if (item && item->generic_info.condition < 100)
  5639. repairable_items->push_back(item);
  5640. }
  5641. }
  5642. safe_delete(equipped_items);
  5643. safe_delete(items);
  5644. return repairable_items;
  5645. }
  5646. void Client::SendMailList() {
  5647. int32 kiosk_id = player->GetIDWithPlayerSpawn(GetMailTransaction());
  5648. if (kiosk_id > 0) {
  5649. PacketStruct* p = configReader.getStruct("WS_GetMailHeader", GetVersion());
  5650. if (p) {
  5651. MutexMap<int32, Mail*>* mail_list = player->GetMail();
  5652. MutexMap<int32, Mail*>::iterator itr = mail_list->begin();
  5653. int16 i = 0;
  5654. p->setDataByName("kiosk_id", kiosk_id);
  5655. p->setArrayLengthByName("num_messages", (int16)mail_list->size());
  5656. while (itr.Next()) {
  5657. Mail* mail = itr->second;
  5658. p->setArrayDataByName("mail_id", mail->mail_id, i);
  5659. p->setArrayDataByName("player_to_id", mail->player_to_id, i);
  5660. p->setArrayDataByName("player_from", mail->player_from.c_str(), i);
  5661. p->setArrayDataByName("subject", mail->subject.c_str(), i);
  5662. p->setArrayDataByName("unknown1", 0x0000, i);
  5663. p->setArrayDataByName("already_read", mail->already_read, i);
  5664. p->setArrayDataByName("mail_deletion", mail->expire_time - mail->time_sent, i);
  5665. p->setArrayDataByName("mail_type", mail->mail_type, i);
  5666. p->setArrayDataByName("mail_expire", 0xFFFFFFFF, i);
  5667. p->setArrayDataByName("unknown1a", 0xFFFFFFFF, i);
  5668. p->setArrayDataByName("coin_copper", mail->coin_copper, i);
  5669. p->setArrayDataByName("coin_silver", mail->coin_silver, i);
  5670. p->setArrayDataByName("coin_gold", mail->coin_gold, i);
  5671. p->setArrayDataByName("coin_plat", mail->coin_plat, i);
  5672. p->setArrayDataByName("num_items", mail->stack, i);
  5673. p->setArrayDataByName("packettype", GetItemPacketType(GetVersion()));
  5674. p->setArrayDataByName("packetsubtype", 0xFF, i);
  5675. p->setArrayDataByName("unknown2", 0, i);
  5676. //p->setArrayDataByName("item_id", 5, i, 0);
  5677. //Item* item = master_item_list.GetItem(5);
  5678. //if (item)
  5679. // printf("%s\n", item->name.c_str());
  5680. //else
  5681. // printf("no item\n");
  5682. //p->setItemArrayDataByName("item", master_item_list.GetItem(5), i, 0);
  5683. i++;
  5684. }
  5685. // GMs send mail for free!
  5686. if( GetAdminStatus() > 0 )
  5687. {
  5688. p->setDataByName("postage_cost", 0);
  5689. p->setDataByName("attachment_cost", 0);
  5690. }
  5691. else
  5692. {
  5693. p->setDataByName("postage_cost", 10);
  5694. p->setDataByName("attachment_cost", 50);
  5695. }
  5696. p->setDataByName("unknown3", 0x01F4);
  5697. p->setDataByName("unknown4", 0x01000000);
  5698. QueuePacket(p->serialize());
  5699. safe_delete(p);
  5700. }
  5701. }
  5702. else
  5703. SimpleMessage(CHANNEL_COLOR_MAIL, "You are currently not in a mail transaction.");
  5704. }
  5705. void Client::DisplayMailMessage(int32 mail_id) {
  5706. Mail* mail = player->GetMail(mail_id);
  5707. if (mail) {
  5708. int32 kiosk_id = player->GetIDWithPlayerSpawn(GetMailTransaction());
  5709. if (kiosk_id > 0) {
  5710. PacketStruct* update = configReader.getStruct("WS_UpdatePlayerMail", GetVersion());
  5711. if (update) {
  5712. update->setDataByName("action", 0x03);
  5713. update->setDataByName("packettype", GetItemPacketType(GetVersion()));
  5714. update->setDataByName("packetsubtype", 0xFF);
  5715. QueuePacket(update->serialize());
  5716. safe_delete(update);
  5717. }
  5718. PacketStruct* packet = configReader.getStruct("WS_MailGetMessage", GetVersion());
  5719. if (packet) {
  5720. packet->setDataByName("kiosk_id", kiosk_id);
  5721. packet->setDataByName("mail_id", mail->mail_id);
  5722. packet->setDataByName("player_to_id", mail->player_to_id);
  5723. packet->setDataByName("player_from", mail->player_from.c_str());
  5724. packet->setDataByName("subject", mail->subject.c_str());
  5725. packet->setDataByName("mail_body", mail->mail_body.c_str());
  5726. packet->setDataByName("unknown1", 1);
  5727. packet->setDataByName("unknown2", 0);
  5728. packet->setDataByName("lock_report_button", 1);
  5729. packet->setDataByName("unknown3", 0xFFFFFFFF);
  5730. packet->setDataByName("unknown3a", 0xFFFFFFFF);
  5731. packet->setDataByName("coin_copper", mail->coin_copper);
  5732. packet->setDataByName("coin_silver", mail->coin_silver);
  5733. packet->setDataByName("coin_gold", mail->coin_gold);
  5734. packet->setDataByName("coin_plat", mail->coin_plat);
  5735. packet->setDataByName("stack", mail->stack);
  5736. packet->setDataByName("packettype", GetItemPacketType(GetVersion()));
  5737. packet->setDataByName("packetsubtype", 0xFF);
  5738. packet->setDataByName("unknown4", 0);
  5739. packet->setDataByName("unknown5", 0);
  5740. packet->setDataByName("unknown6", 0);
  5741. packet->setDataByName("unknown7", 0);
  5742. mail->already_read = true;
  5743. mail->save_needed = true;
  5744. QueuePacket(packet->serialize());
  5745. safe_delete(packet);
  5746. //SendMailList();
  5747. }
  5748. }
  5749. else
  5750. SimpleMessage(CHANNEL_COLOR_MAIL, "You are currently not in a mail transaction.");
  5751. }
  5752. }
  5753. /* This is called when the client sends a mail message. This determines whether or not the mail can be sent and must send the reply
  5754. packet back to the client before the mail actually sent. */
  5755. void Client::HandleSentMail(EQApplicationPacket* app) {
  5756. PacketStruct* packet = configReader.getStruct("WS_MailSendMessage", GetVersion());
  5757. if (packet) {
  5758. packet->LoadPacketData(app->pBuffer, app->size);
  5759. string player_to = packet->getType_EQ2_16BitString_ByName("player_to").data;
  5760. PacketStruct* reply_packet = configReader.getStruct("WS_MailSendMessageReply", GetVersion());
  5761. vector<int32>* ids = 0;
  5762. if (reply_packet) {
  5763. int8 reply_type = MAIL_SEND_RESULT_UNKNOWN_ERROR;
  5764. if (player_to.length() == 0)
  5765. reply_type = MAIL_SEND_RESULT_EMPTY_TO_LIST;
  5766. else if (player_to.compare(string(GetPlayer()->GetName())) == 0)
  5767. reply_type = MAIL_SEND_RESULT_CANNOT_SEND_TO_SELF;
  5768. else if (GetAdminStatus() == 0 && !player->RemoveCoins(10))
  5769. reply_type = MAIL_SEND_RESULT_NOT_ENOUGH_COIN;
  5770. else {
  5771. if (player_to.compare("<all>") == 0) {
  5772. if (mail_window.coin_copper + mail_window.coin_silver + mail_window.coin_gold + mail_window.coin_plat == 0)
  5773. ids = database.GetAllPlayerIDs();
  5774. else
  5775. SimpleMessage(CHANNEL_COLOR_MAIL, "You may not mail gifts to multiple players.");
  5776. }
  5777. else {
  5778. ids = new vector<int32>;
  5779. ids->push_back(database.GetCharacterID(player_to.c_str()));
  5780. }
  5781. if (ids) {
  5782. for (int32 i = 0; i < ids->size(); i++) {
  5783. int32 player_to_id = ids->at(i);
  5784. if (player_to_id > 0) {
  5785. reply_type = MAIL_SEND_RESULT_SUCCESS;
  5786. Mail* mail = new Mail;
  5787. mail->mail_id = 0;
  5788. mail->player_to_id = player_to_id;
  5789. mail->player_from = string(GetPlayer()->GetName());
  5790. mail->subject = packet->getType_EQ2_16BitString_ByName("subject").data;
  5791. mail->mail_body = packet->getType_EQ2_16BitString_ByName("mail_body").data;
  5792. mail->already_read = 0;
  5793. mail->mail_type = MAIL_TYPE_REGULAR;
  5794. mail->coin_copper = mail_window.coin_copper;
  5795. mail->coin_silver = mail_window.coin_silver;
  5796. mail->coin_gold = mail_window.coin_gold;
  5797. mail->coin_plat = mail_window.coin_plat;
  5798. mail->stack = 0;
  5799. // GM's send mail for free!
  5800. if( GetAdminStatus() > 0 )
  5801. {
  5802. mail->postage_cost = 0;
  5803. mail->attachment_cost = 0;
  5804. }
  5805. else
  5806. {
  5807. mail->postage_cost = 10;
  5808. mail->attachment_cost = 50;
  5809. }
  5810. mail->char_item_id = 0;
  5811. mail->time_sent = Timer::GetUnixTimeStamp();
  5812. mail->expire_time = mail->time_sent + 2592000; //30 days in seconds
  5813. //int16 packettype = packet->getType_int16_ByName("packettype");
  5814. //int8 packetsubtype = packet->getType_int8_ByName("packetsubtype");
  5815. /*int32 postage_cost = packet->getType_int32_ByName("postage_cost");
  5816. int32 attachment_cost = packet->getType_int32_ByName("attachment_cost");
  5817. if (postage_cost > 0 || attachment_cost > 0)
  5818. PlaySoundA("coin_cha_ching");*/
  5819. mail->save_needed = false;
  5820. Client* to_client = zone_list.GetClientByCharID(player_to_id);
  5821. if (to_client) {
  5822. to_client->GetPlayer()->AddMail(mail);
  5823. to_client->SimpleMessage(CHANNEL_COLOR_MAIL, "You've got mail! :)");
  5824. }
  5825. database.SavePlayerMail(mail);
  5826. mail_window.coin_copper = 0;
  5827. mail_window.coin_silver = 0;
  5828. mail_window.coin_gold = 0;
  5829. mail_window.coin_plat = 0;
  5830. }
  5831. else
  5832. reply_type = MAIL_SEND_RESULT_UNKNOWN_PLAYER;
  5833. }
  5834. }
  5835. }
  5836. string players_to = "";
  5837. if (ids) {
  5838. for (int32 i = 0; i < ids->size(); i++) {
  5839. if (ids->at(i) != 0)
  5840. players_to.append(database.GetCharacterName(ids->at(i)));
  5841. if (i < (ids->size() - 1))
  5842. players_to.append(", ");
  5843. }
  5844. }
  5845. reply_packet->setDataByName("player_to", players_to.c_str());
  5846. reply_packet->setDataByName("reply_type", reply_type);
  5847. QueuePacket(reply_packet->serialize());
  5848. safe_delete(reply_packet);
  5849. safe_delete(ids);
  5850. }
  5851. safe_delete(packet);
  5852. }
  5853. }
  5854. void Client::DeleteMail(int32 mail_id, bool from_database) {
  5855. player->DeleteMail(mail_id, from_database);
  5856. }
  5857. bool Client::AddMailCoin(int32 copper, int32 silver, int32 gold, int32 plat) {
  5858. bool ret = false;
  5859. if (GetMailTransaction()) {
  5860. PacketStruct* packet = configReader.getStruct("WS_UpdatePlayerMail", GetVersion());
  5861. if (packet) {
  5862. if (copper > 0) {
  5863. if (player->RemoveCoins(copper)) {
  5864. mail_window.coin_copper += copper;
  5865. Message(CHANNEL_COLOR_MAIL, "You add %u copper to the mail window.", copper);
  5866. ret = true;
  5867. }
  5868. }
  5869. else if (silver > 0) {
  5870. if (player->RemoveCoins(silver * 100)) {
  5871. mail_window.coin_silver += silver;
  5872. Message(CHANNEL_COLOR_MAIL, "You add %u silver to the mail window.", silver);
  5873. ret = true;
  5874. }
  5875. }
  5876. else if (gold > 0) {
  5877. if (player->RemoveCoins(gold * 10000)) {
  5878. mail_window.coin_gold += gold;
  5879. Message(CHANNEL_COLOR_MAIL, "You add %u gold to the mail window.", gold);
  5880. ret = true;
  5881. }
  5882. }
  5883. else if (plat > 0) {
  5884. if (player->RemoveCoins(plat * 1000000)) {
  5885. mail_window.coin_plat += plat;
  5886. Message(CHANNEL_COLOR_MAIL, "You add %u platinum to the mail window.", plat);
  5887. ret = true;
  5888. }
  5889. }
  5890. if (ret) {
  5891. packet->setDataByName("coin_copper", mail_window.coin_copper);
  5892. packet->setDataByName("coin_silver", mail_window.coin_silver);
  5893. packet->setDataByName("coin_gold", mail_window.coin_gold);
  5894. packet->setDataByName("coin_plat", mail_window.coin_plat);
  5895. packet->setDataByName("stack", 0);
  5896. packet->setDataByName("packettype", GetItemPacketType(version));
  5897. packet->setDataByName("packetsubtype", 0xFF);
  5898. packet->setDataByName("unknown2", 0);
  5899. //packet->PrintPacket();
  5900. QueuePacket(packet->serialize());
  5901. }
  5902. else
  5903. SimpleMessage(CHANNEL_COLOR_MAIL, "You don't have that much money.");
  5904. safe_delete(packet);
  5905. }
  5906. }
  5907. else
  5908. SimpleMessage(CHANNEL_COLOR_MAIL, "You are currently not in a mail transaction.");
  5909. return ret;
  5910. }
  5911. bool Client::RemoveMailCoin(int32 copper, int32 silver, int32 gold, int32 plat) {
  5912. bool ret = false;
  5913. if (GetMailTransaction()) {
  5914. PacketStruct* packet = configReader.getStruct("WS_UpdatePlayerMail", GetVersion());
  5915. if (packet) {
  5916. if (copper > 0) {
  5917. player->AddCoins(copper);
  5918. mail_window.coin_copper -= copper;
  5919. Message(CHANNEL_COLOR_MAIL, "You remove %u copper from the mail window.", copper);
  5920. ret = true;
  5921. }
  5922. else if (silver > 0) {
  5923. player->AddCoins(silver * 100);
  5924. mail_window.coin_silver -= silver;
  5925. Message(CHANNEL_COLOR_MAIL, "You remove %u silver from the mail window.", silver);
  5926. ret = true;
  5927. }
  5928. else if (gold > 0) {
  5929. player->AddCoins(gold * 10000);
  5930. mail_window.coin_gold -= gold;
  5931. Message(CHANNEL_COLOR_MAIL, "You remove %u gold from the mail window.", gold);
  5932. ret = true;
  5933. }
  5934. else if (plat > 0) {
  5935. player->AddCoins(plat * 1000000);
  5936. mail_window.coin_plat -= plat;
  5937. Message(CHANNEL_COLOR_MAIL, "You remove %u platinum from the mail window.", plat);
  5938. ret = true;
  5939. }
  5940. if (ret) {
  5941. packet->setDataByName("coin_copper", mail_window.coin_copper);
  5942. packet->setDataByName("coin_silver", mail_window.coin_silver);
  5943. packet->setDataByName("coin_gold", mail_window.coin_gold);
  5944. packet->setDataByName("coin_plat", mail_window.coin_plat);
  5945. packet->setDataByName("stack", 0);
  5946. packet->setDataByName("packettype", 0x2BFE);
  5947. packet->setDataByName("packetsubtype", 0xFF);
  5948. packet->setDataByName("unknown2", 0);
  5949. QueuePacket(packet->serialize());
  5950. }
  5951. safe_delete(packet);
  5952. }
  5953. }
  5954. else
  5955. SimpleMessage(CHANNEL_COLOR_MAIL, "You are currently not in a mail transaction.");
  5956. return ret;
  5957. }
  5958. void Client::TakeMailAttachments(int32 mail_id) {
  5959. if (GetMailTransaction()) {
  5960. Mail* mail = player->GetMail(mail_id);
  5961. if (mail) {
  5962. int64 amount = 0;
  5963. if (mail->coin_copper > 0) {
  5964. amount += mail->coin_copper;
  5965. mail->coin_copper = 0;
  5966. }
  5967. if (mail->coin_silver > 0) {
  5968. amount += mail->coin_silver * 100;
  5969. mail->coin_silver = 0;
  5970. }
  5971. if (mail->coin_gold > 0) {
  5972. amount += mail->coin_gold * 10000;
  5973. mail->coin_gold = 0;
  5974. }
  5975. if (mail->coin_plat > 0) {
  5976. amount += mail->coin_plat * 1000000;
  5977. mail->coin_plat = 0;
  5978. }
  5979. if (mail->char_item_id > 0) {
  5980. LogWrite(MISC__TODO, 1, "TODO", "Items by Mail\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
  5981. }
  5982. /* Can't find the right packet to send to update the player's mail. This packet below updates the mail the player is sending, not
  5983. the mail the player is getting attachments from. There is an opcode OP_MailRemoveAttachFromMailMsg with opcode 328 but i can't
  5984. find it in any packet logs.*/
  5985. /*PacketStruct* packet = configReader.getStruct("WS_UpdatePlayerMail", GetVersion());
  5986. if (packet) {
  5987. packet->setDataByName("unknown", 0x03);
  5988. packet->setDataByName("coin_copper", mail->coin_copper);
  5989. packet->setDataByName("coin_silver", mail->coin_silver);
  5990. packet->setDataByName("coin_gold", mail->coin_gold);
  5991. packet->setDataByName("coin_plat", mail->coin_plat);
  5992. packet->setDataByName("stack", 0);
  5993. packet->setDataByName("packettype", 0x2BFE);
  5994. packet->setDataByName("packetsubtype", 0xFF);
  5995. packet->setDataByName("unknown2", 0);
  5996. packet->setDataByName("unknown3", 0x00000001);//0x00000016
  5997. DumpPacket(packet->serialize());
  5998. QueuePacket(packet->serialize());
  5999. safe_delete(packet);
  6000. }*/
  6001. database.SavePlayerMail(mail);
  6002. if (amount > 0)
  6003. player->AddCoins(amount);
  6004. SendMailList();
  6005. }
  6006. }
  6007. else
  6008. SimpleMessage(CHANNEL_COLOR_MAIL, "You are currently not in a mail transaction.");
  6009. }
  6010. void Client::CancelSendMail() {
  6011. SimpleMessage(CHANNEL_COLOR_MAIL, "You cancel sending a letter.");
  6012. player->AddCoins(mail_window.coin_copper + (mail_window.coin_silver * 100) + (mail_window.coin_gold * 10000) + (mail_window.coin_plat * 1000000));
  6013. mail_window.coin_copper = 0;
  6014. mail_window.coin_silver = 0;
  6015. mail_window.coin_gold = 0;
  6016. mail_window.coin_plat = 0;
  6017. mail_window.char_item_id = 0;
  6018. }
  6019. bool Client::GateAllowed(){
  6020. ZoneServer* zone = zone_list.Get(player->GetPlayerInfo()->GetBindZoneID());
  6021. LogWrite(MISC__TODO, 1, "TODO", "possibly add a check here to see if a player is allowed to gate from this spot, allow for now\nfile: %s, func: %s, line: %i", __FILE__, __FUNCTION__, __LINE__);
  6022. if(zone)
  6023. return true;
  6024. return false;
  6025. }
  6026. bool Client::BindAllowed(){
  6027. LogWrite(MISC__TODO, 1, "TODO", "possibly add a check here to see if a player is allowed to bind in this spot, allow anywhere for now\nfile: %s, func: %s, line: %i", __FILE__, __FUNCTION__, __LINE__);
  6028. return true;
  6029. }
  6030. bool Client::Bind(){
  6031. player->GetPlayerInfo()->SetBindZone(GetCurrentZone()->GetZoneID());
  6032. player->GetPlayerInfo()->SetBindX(player->GetX());
  6033. player->GetPlayerInfo()->SetBindY(player->GetY());
  6034. player->GetPlayerInfo()->SetBindZ(player->GetZ());
  6035. player->GetPlayerInfo()->SetBindHeading(player->GetHeading());
  6036. return true;
  6037. }
  6038. bool Client::Gate(){
  6039. if (player->GetPlayerInfo()->GetBindZoneID() == 0)
  6040. return false;
  6041. ZoneServer* zone = zone_list.Get(player->GetPlayerInfo()->GetBindZoneID());
  6042. if(zone){
  6043. player->SetX(player->GetPlayerInfo()->GetBindZoneX());
  6044. player->SetY(player->GetPlayerInfo()->GetBindZoneY());
  6045. player->SetZ(player->GetPlayerInfo()->GetBindZoneZ());
  6046. player->SetHeading(player->GetPlayerInfo()->GetBindZoneHeading());
  6047. Zone(zone, false);
  6048. return true;
  6049. }
  6050. return false;
  6051. }
  6052. void Client::ProcessTeleport(Spawn* spawn, vector<TransportDestination*>* destinations, int32 transport_id){
  6053. if(!destinations || !spawn) {
  6054. return;
  6055. }
  6056. bool has_map = false;
  6057. if (transport_id > 0)
  6058. has_map = GetCurrentZone()->TransportHasMap(transport_id);
  6059. transport_spawn = spawn;
  6060. vector<TransportDestination*> transport_list;
  6061. vector<TransportDestination*>::iterator itr;
  6062. TransportDestination* destination = 0;
  6063. for(itr = destinations->begin(); itr != destinations->end(); itr++){
  6064. destination = *itr;
  6065. if(has_map || (destination->type == TRANSPORT_TYPE_ZONE && ((destination->destination_zone_id != GetCurrentZone()->GetZoneID()) || GetPlayer()->GetDistance(destination->destination_x, destination->destination_y, destination->destination_z) > 100)))
  6066. transport_list.push_back(destination);
  6067. }
  6068. if(transport_list.size() == 0 && destination){
  6069. if(destination->destination_zone_id == 0 || destination->destination_zone_id == GetCurrentZone()->GetZoneID()){
  6070. EQ2Packet* app = GetPlayer()->Move(destination->destination_x, destination->destination_y, destination->destination_z, GetVersion());
  6071. if(app)
  6072. QueuePacket(app);
  6073. }
  6074. else{
  6075. ZoneServer* new_zone = zone_list.Get(destination->destination_zone_id);
  6076. // determine if this is an instanced zone that already exists
  6077. ZoneServer* instance_zone = GetPlayer()->GetGroupMemberInZone(destination->destination_zone_id);
  6078. if(instance_zone || new_zone){
  6079. GetPlayer()->SetX(destination->destination_x);
  6080. GetPlayer()->SetY(destination->destination_y);
  6081. GetPlayer()->SetZ(destination->destination_z);
  6082. GetPlayer()->SetHeading(destination->destination_heading);
  6083. if ( instance_zone )
  6084. Zone(instance_zone->GetInstanceID(),false,true);
  6085. else
  6086. Zone(new_zone, false);
  6087. }
  6088. }
  6089. if(destination->message.length() > 0)
  6090. SimpleMessage(CHANNEL_COLOR_YELLOW, destination->message.c_str());
  6091. }
  6092. else if(transport_list.size() > 0){
  6093. PlaySound("mariner_bell");
  6094. PacketStruct* packet = configReader.getStruct("WS_TeleportList", GetVersion());
  6095. if(packet){
  6096. packet->setDataByName("spawn_id", GetPlayer()->GetIDWithPlayerSpawn(spawn));
  6097. // Put all the destinations the player can go in a new vector
  6098. vector<TransportDestination*> destinations;
  6099. for (int32 i = 0; i < transport_list.size(); i++) {
  6100. destination = transport_list.at(i);
  6101. // Check min level
  6102. if (destination->min_level > 0 && GetPlayer()->GetLevel() < destination->min_level)
  6103. continue;
  6104. // Check max level
  6105. if (destination->max_level > 0 && GetPlayer()->GetLevel() > destination->max_level)
  6106. continue;
  6107. // Check quest complete
  6108. if (destination->req_quest_complete > 0 && GetPlayer()->GetCompletedQuest(destination->req_quest_complete) == 0)
  6109. continue;
  6110. // Check req quest and step
  6111. if (destination->req_quest > 0 && destination->req_quest_step > 0 && GetPlayer()->GetQuestStep(destination->req_quest) != destination->req_quest_step)
  6112. continue;
  6113. // If we have a map and our current location is the same as the detination and player is within 20 units from the transport set the "current" elements but don't addt to the destination list
  6114. if (has_map && (destination->destination_zone_id == GetCurrentZone()->GetZoneID() && GetPlayer()->GetDistance(destination->destination_x, destination->destination_y, destination->destination_z) < 20)) {
  6115. packet->setDataByName("current_zone", destination->display_name.c_str());
  6116. packet->setDataByName("current_map_x", destination->map_x);
  6117. packet->setDataByName("current_map_y", destination->map_y);
  6118. }
  6119. else {
  6120. destinations.push_back(destination);
  6121. }
  6122. }
  6123. // Use the new vector to create the packet
  6124. destination = 0;
  6125. packet->setArrayLengthByName("num_destinations", destinations.size());
  6126. for(int32 i = 0; i < destinations.size(); i++) {
  6127. destination = destinations.at(i);
  6128. packet->setArrayDataByName("unique_id", destination->unique_id, i);
  6129. packet->setArrayDataByName("display_name", destination->display_name.c_str(), i);
  6130. packet->setArrayDataByName("zone_name", destination->display_name.c_str(), i);
  6131. packet->setArrayDataByName("zone_file_name", destination->display_name.c_str(), i);
  6132. packet->setArrayDataByName("cost", destination->cost, i);
  6133. if (has_map) {
  6134. packet->setArrayDataByName("map_x", destination->map_x, i);
  6135. packet->setArrayDataByName("map_y", destination->map_y, i);
  6136. }
  6137. }
  6138. if (has_map)
  6139. packet->setDataByName("map_name", GetCurrentZone()->GetTransportMap(transport_id).c_str());
  6140. EQ2Packet* app = packet->serialize();
  6141. //DumpPacket(app);
  6142. if (destinations.size() > 0)
  6143. QueuePacket(app);
  6144. safe_delete(packet);
  6145. }
  6146. }
  6147. }
  6148. void Client::ProcessTeleportLocation(EQApplicationPacket* app){
  6149. PacketStruct* packet = configReader.getStruct("WS_TeleportDestination", GetVersion());
  6150. if(packet){
  6151. if(packet->LoadPacketData(app->pBuffer, app->size)){
  6152. Spawn* spawn = GetPlayer()->GetSpawnWithPlayerID(packet->getType_int32_ByName("spawn_id"));
  6153. int32 unique_id = packet->getType_int32_ByName("unique_id");
  6154. string zone_name = packet->getType_EQ2_16BitString_ByName("zone_name").data;
  6155. int32 cost = packet->getType_int32_ByName("cost");
  6156. vector<TransportDestination*>* destinations = 0;
  6157. TransportDestination* destination = 0;
  6158. if(spawn && spawn == transport_spawn && spawn->GetTransporterID() > 0)
  6159. destinations = GetCurrentZone()->GetTransporters(spawn->GetTransporterID());
  6160. if(destinations){
  6161. vector<TransportDestination*>::iterator itr;
  6162. for(itr = destinations->begin(); itr != destinations->end(); itr++){
  6163. if((*itr)->unique_id == unique_id && (*itr)->display_name == zone_name && (*itr)->cost == cost){
  6164. destination=*itr;
  6165. break;
  6166. }
  6167. }
  6168. }
  6169. if(!destination)
  6170. SimpleMessage(CHANNEL_COLOR_RED, "Error processing transport.");
  6171. else{
  6172. if(cost == 0 || player->RemoveCoins(cost)){
  6173. if(destination->destination_zone_id == 0 || destination->destination_zone_id == GetCurrentZone()->GetZoneID()){
  6174. EQ2Packet* outapp = GetPlayer()->Move(destination->destination_x, destination->destination_y, destination->destination_z, GetVersion());
  6175. if(outapp)
  6176. QueuePacket(outapp);
  6177. }
  6178. else{
  6179. GetPlayer()->SetX(destination->destination_x);
  6180. GetPlayer()->SetY(destination->destination_y);
  6181. GetPlayer()->SetZ(destination->destination_z);
  6182. GetPlayer()->SetHeading(destination->destination_heading);
  6183. // Test if where we're going is an Instanced zone
  6184. if (!TryZoneInstance(destination->destination_zone_id, false)) {
  6185. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Attempting to zone normally");
  6186. ZoneServer* new_zone = zone_list.Get(destination->destination_zone_id);
  6187. Zone(new_zone, false);
  6188. }
  6189. }
  6190. if(destination->message.length() > 0)
  6191. SimpleMessage(CHANNEL_COLOR_YELLOW, destination->message.c_str());
  6192. }
  6193. else
  6194. SimpleMessage(CHANNEL_COLOR_RED, "You do not have enough money to use this transport.");
  6195. }
  6196. }
  6197. safe_delete(packet);
  6198. }
  6199. }
  6200. void Client::SendNewSpells(int8 class_id){
  6201. if(class_id > 0){
  6202. vector<Spell*>* spells = master_spell_list.GetSpellListByAdventureClass(class_id, player->GetLevel(), 1);
  6203. vector<Spell*>::iterator itr;
  6204. Spell* spell = 0;
  6205. bool send_updates = false;
  6206. for(itr = spells->begin(); itr != spells->end(); itr++){
  6207. spell = *itr;
  6208. if(spell && !player->HasSpell(spell->GetSpellID(), spell->GetSpellTier(), true) && spell->GetSpellData()->lua_script.length() > 0){
  6209. send_updates = true;
  6210. SendSpellUpdate(spell);
  6211. player->AddSpellBookEntry(spell->GetSpellID(), spell->GetSpellTier(), player->GetFreeSpellBookSlot(spell->GetSpellData()->spell_book_type), spell->GetSpellData()->spell_book_type, spell->GetSpellData()->linked_timer, true);
  6212. player->UnlockSpell(spell);
  6213. }
  6214. }
  6215. if(send_updates){
  6216. EQ2Packet* outapp = player->GetSpellBookUpdatePacket(GetVersion());
  6217. if(outapp)
  6218. QueuePacket(outapp);
  6219. }
  6220. safe_delete(spells);
  6221. }
  6222. }
  6223. void Client::SetItemSearch(vector<Item*>* items){
  6224. if(items){
  6225. safe_delete(search_items);
  6226. search_items = items;
  6227. }
  6228. }
  6229. vector<Item*>* Client::GetSearchItems(){
  6230. return search_items;
  6231. }
  6232. void Client::SearchStore(int32 page){
  6233. if(search_items){
  6234. PacketStruct* packet = configReader.getStruct("WS_BrokerItems", GetVersion());
  6235. if(packet){
  6236. int32 x = page*8;
  6237. if(search_items->size() > 8){
  6238. if((search_items->size() - x) > 8)
  6239. packet->setArrayLengthByName("num_items", 8);
  6240. else
  6241. packet->setArrayLengthByName("num_items", search_items->size() - x);
  6242. }
  6243. else
  6244. packet->setArrayLengthByName("num_items", search_items->size());
  6245. if(search_items->size() > 0){
  6246. packet->setArrayLengthByName("num_sellers", 1);
  6247. packet->setArrayDataByName("seller_seller_id", 1);
  6248. packet->setArrayDataByName("seller_name", "EQ2EmuDevs");
  6249. packet->setDataByName("per_page", 8);
  6250. packet->setDataByName("num_pages", search_items->size()/8+1);
  6251. packet->setDataByName("page", page);
  6252. Item* item = 0;
  6253. int32 limit = search_items->size() > 8 ? 8 : search_items->size();
  6254. for(int32 i=0;i<limit;i++, x++){
  6255. if(x >= search_items->size())
  6256. break;
  6257. item = search_items->at(x);
  6258. packet->setArrayDataByName("item_id", item->details.item_id, i);
  6259. packet->setArrayDataByName("item_id2", item->details.item_id, i);
  6260. packet->setArrayDataByName("icon", item->details.icon, i);
  6261. //packet->setArrayDataByName("unknown2b", i, i);
  6262. packet->setArrayDataByName("item_seller_id", 1, i);
  6263. if(item->stack_count == 0)
  6264. packet->setArrayDataByName("quantity", 1, i);
  6265. else
  6266. packet->setArrayDataByName("quantity", item->stack_count, i);
  6267. packet->setArrayDataByName("stack_size", item->stack_count, i);
  6268. packet->setArrayDataByName("item_name", item->name.c_str(), i);
  6269. packet->setArrayDataByName("req_level", item->generic_info.adventure_default_level, i);
  6270. //QueuePacket(item->serialize(GetVersion(), false, GetPlayer()));
  6271. }
  6272. }
  6273. /*EQ2Packet* outapp = packet->serialize();
  6274. DumpPacket(outapp);
  6275. QueuePacket(outapp);*/
  6276. QueuePacket(packet->serialize());
  6277. safe_delete(packet);
  6278. }
  6279. }
  6280. }
  6281. void Client::SetReadyForSpawns(bool val){
  6282. ready_for_spawns = val;
  6283. if(GetPlayer()->GetActivityStatus() > 0){
  6284. GetPlayer()->SetActivityStatus(0);
  6285. if (GetPlayer()->GetGroupMemberInfo()) {
  6286. world.GetGroupManager()->GroupMessage(GetPlayer()->GetGroupMemberInfo()->group_id, "%s has returned from Linkdead.", GetPlayer()->GetName());
  6287. }
  6288. }
  6289. zone_list.CheckFriendZoned(this);
  6290. }
  6291. void Client::SendChatRelationship(int8 type, const char* name){
  6292. if(!name) {
  6293. return;
  6294. }
  6295. PacketStruct* packet = configReader.getStruct("WS_ChatRelationship", GetVersion());
  6296. if(packet){
  6297. packet->setDataByName("account_id", GetAccountID());
  6298. packet->setDataByName("type", type);
  6299. packet->setArrayLengthByName("num_names", 1);
  6300. packet->setArrayDataByName("name", name);
  6301. if(type == 0){
  6302. Client* client = zone_list.GetClientByCharName(name);
  6303. if(client){
  6304. packet->setArrayDataByName("location", client->GetCurrentZone()->GetZoneName());
  6305. packet->setArrayDataByName("class_name", classes.GetClassName(client->GetPlayer()->GetAdventureClass()));
  6306. }
  6307. }
  6308. QueuePacket(packet->serialize());
  6309. safe_delete(packet);
  6310. }
  6311. }
  6312. void Client::SendFriendList(){
  6313. PacketStruct* packet = configReader.getStruct("WS_ChatRelationship", GetVersion());
  6314. if(packet){
  6315. packet->setDataByName("account_id", GetAccountID());
  6316. map<string, int8>::iterator itr;
  6317. map<string, int8>* friends = player->GetFriends();
  6318. if(friends && friends->size() > 0){
  6319. Client* client = 0;
  6320. vector<string> names;
  6321. for(itr = friends->begin(); itr != friends->end(); itr++){
  6322. if(itr->second == 2)
  6323. continue;
  6324. names.push_back(itr->first);
  6325. }
  6326. packet->setArrayLengthByName("num_names", names.size());
  6327. for(int32 i=0;i<names.size();i++){
  6328. client = zone_list.GetClientByCharName(names[i]);
  6329. packet->setArrayDataByName("name", names[i].c_str(), i);
  6330. if(client){
  6331. packet->setArrayDataByName("location", client->GetCurrentZone()->GetZoneName(), i);
  6332. packet->setArrayDataByName("class_name", classes.GetClassName(client->GetPlayer()->GetAdventureClass()), i);
  6333. }
  6334. }
  6335. }
  6336. QueuePacket(packet->serialize());
  6337. safe_delete(packet);
  6338. }
  6339. }
  6340. void Client::SendIgnoreList(){
  6341. PacketStruct* packet = configReader.getStruct("WS_ChatRelationship", GetVersion());
  6342. if(packet){
  6343. packet->setDataByName("account_id", GetAccountID());
  6344. packet->setDataByName("type", 2);
  6345. map<string, int8>::iterator itr;
  6346. map<string, int8>* ignored = player->GetIgnoredPlayers();
  6347. if(ignored && ignored->size() > 0){
  6348. vector<string> names;
  6349. for(itr = ignored->begin(); itr != ignored->end(); itr++){
  6350. if(itr->second == 2)
  6351. continue;
  6352. names.push_back(itr->first);
  6353. }
  6354. packet->setArrayLengthByName("num_names", names.size());
  6355. for(int32 i=0;i<names.size();i++)
  6356. packet->setArrayDataByName("name", names[i].c_str(), i);
  6357. }
  6358. QueuePacket(packet->serialize());
  6359. safe_delete(packet);
  6360. }
  6361. }
  6362. void Client::AddWaypoint(const char* waypoint_name, int8 waypoint_category, int32 spawn_id) {
  6363. if (waypoint_name) {
  6364. PacketStruct* packet = configReader.getStruct("WS_WaypointUpdate", GetVersion());
  6365. if (packet) {
  6366. packet->setArrayLengthByName("num_updates", 1);
  6367. packet->setArrayDataByName("waypoint_name", waypoint_name, 0);
  6368. packet->setArrayDataByName("waypoint_category", waypoint_category, 0);
  6369. packet->setArrayDataByName("spawn_id", spawn_id, 0);
  6370. packet->setArrayDataByName("waypoint_category2", waypoint_category, 0);
  6371. packet->setArrayDataByName("spawn_id2", spawn_id, 0);
  6372. QueuePacket(packet->serialize());
  6373. safe_delete(packet);
  6374. }
  6375. }
  6376. }
  6377. void Client::BeginWaypoint(const char* waypoint_name, float x, float y, float z) {
  6378. if (waypoint_name) {
  6379. PacketStruct* packet = configReader.getStruct("WS_GlowPath", GetVersion());
  6380. if (packet) {
  6381. packet->setArrayLengthByName("num_points", 1);
  6382. packet->setArrayDataByName("x", x, 0);
  6383. packet->setArrayDataByName("y", y, 0);
  6384. packet->setArrayDataByName("z", z, 0);
  6385. packet->setDataByName("waypoint_x", x);
  6386. packet->setDataByName("waypoint_y", y);
  6387. packet->setDataByName("waypoint_z", z);
  6388. packet->setDataByName("waypoint_name", waypoint_name);
  6389. packet->setDataByName("unknown", 0);
  6390. QueuePacket(packet->serialize());
  6391. safe_delete(packet);
  6392. }
  6393. }
  6394. }
  6395. void Client::InspectPlayer(Player* player_to_inspect) {
  6396. if (player_to_inspect) {
  6397. PacketStruct* packet = configReader.getStruct("WS_InspectPlayer", GetVersion());
  6398. if (packet) {
  6399. packet->setDataByName("unknown", 0);
  6400. packet->setSmallStringByName("name", player_to_inspect->GetName());
  6401. packet->setDataByName("race", player_to_inspect->GetRace());
  6402. packet->setDataByName("gender", player_to_inspect->GetGender());
  6403. packet->setDataByName("adventure_level", player_to_inspect->GetLevel());
  6404. LogWrite(MISC__TODO, 1, "TODO", "Put mentored level here (adventure_level_effective)\nfile: %s, func: %s, line: %i", __FILE__, __FUNCTION__, __LINE__);
  6405. packet->setDataByName("adventure_level_effective", player_to_inspect->GetLevel());
  6406. packet->setDataByName("adventure_class", player_to_inspect->GetAdventureClass());
  6407. packet->setDataByName("tradeskill_level", player_to_inspect->GetTSLevel());
  6408. packet->setDataByName("tradeskill_class", player_to_inspect->GetTradeskillClass());
  6409. packet->setDataByName("health", player_to_inspect->GetHP());
  6410. packet->setDataByName("health_max", player_to_inspect->GetTotalHP());
  6411. packet->setDataByName("health_base", player_to_inspect->GetTotalHPBase());
  6412. packet->setDataByName("power", player_to_inspect->GetPower());
  6413. packet->setDataByName("power_max", player_to_inspect->GetTotalPower());
  6414. packet->setDataByName("power_base", player_to_inspect->GetTotalPowerBase());
  6415. packet->setDataByName("mitigation", 0);
  6416. packet->setDataByName("unknown1", 0);
  6417. packet->setDataByName("avoidance", 0);
  6418. packet->setDataByName("unknown2", 0);
  6419. packet->setDataByName("mitigation_percentage", 0);
  6420. packet->setDataByName("strength", player_to_inspect->GetStr());
  6421. packet->setDataByName("strength_base", player_to_inspect->GetStrBase());
  6422. packet->setDataByName("stamina", player_to_inspect->GetSta());
  6423. packet->setDataByName("stamina_base", player_to_inspect->GetStaBase());
  6424. packet->setDataByName("agility", player_to_inspect->GetAgi());
  6425. packet->setDataByName("agility_base", player_to_inspect->GetAgiBase());
  6426. packet->setDataByName("wisdom", player_to_inspect->GetWis());
  6427. packet->setDataByName("wisdom_base", player_to_inspect->GetWisBase());
  6428. packet->setDataByName("intelligence", player_to_inspect->GetInt());
  6429. packet->setDataByName("intelligence_base", player_to_inspect->GetIntBase());
  6430. packet->setDataByName("unknown4", 0);
  6431. packet->setDataByName("unknown5", 0);
  6432. packet->setDataByName("unknown6", 0);
  6433. packet->setDataByName("unknown7", 0);
  6434. packet->setDataByName("unknown8", 0);
  6435. packet->setDataByName("unknown9", 0);
  6436. packet->setDataByName("unknown10", 0);
  6437. packet->setDataByName("unknown11", 0);
  6438. packet->setDataByName("unknown12", 0);
  6439. packet->setDataByName("heat_resist", player_to_inspect->GetHeatResistance());
  6440. packet->setDataByName("heat_resist_base", player_to_inspect->GetHeatResistanceBase());
  6441. packet->setDataByName("heat_resist_percentage", 0);
  6442. packet->setDataByName("cold_resist", player_to_inspect->GetColdResistance());
  6443. packet->setDataByName("cold_resist_base", player_to_inspect->GetColdResistanceBase());
  6444. packet->setDataByName("cold_resist_percentage", 0);
  6445. packet->setDataByName("magic_resist", player_to_inspect->GetMagicResistance());
  6446. packet->setDataByName("magic_resist_base", player_to_inspect->GetMagicResistanceBase());
  6447. packet->setDataByName("magic_resist_percentage", 0);
  6448. packet->setDataByName("mental_resist", player_to_inspect->GetMentalResistance());
  6449. packet->setDataByName("mental_resist_base", player_to_inspect->GetMentalResistanceBase());
  6450. packet->setDataByName("mental_resist_percentage", 0);
  6451. packet->setDataByName("divine_resist", player_to_inspect->GetDivineResistance());
  6452. packet->setDataByName("divine_resist_base", player_to_inspect->GetDivineResistanceBase());
  6453. packet->setDataByName("divine_resist_percentage", 0);
  6454. packet->setDataByName("disease_resist", player_to_inspect->GetDiseaseResistance());
  6455. packet->setDataByName("disease_resist_base", player_to_inspect->GetDiseaseResistanceBase());
  6456. packet->setDataByName("disease_resist_percentage", 0);
  6457. packet->setDataByName("poison_resist", player_to_inspect->GetPoisonResistance());
  6458. packet->setDataByName("poison_resist_base", player_to_inspect->GetPoisonResistanceBase());
  6459. packet->setDataByName("poison_resist_percentage", 0);
  6460. packet->setArrayLengthByName("num_chars", 0x01FF);
  6461. string biography = player_to_inspect->GetBiography();
  6462. for (size_t i = 0; i < biography.length(); i++)
  6463. packet->setArrayDataByName("biography_char", biography[i], i);
  6464. LogWrite(MISC__TODO, 0, "TODO", "Why is inspect player weapons commented out? in func: %s, line: %i", __FUNCTION__, __LINE__);
  6465. /*Item* pw = player_to_inspect->GetEquipmentList()->GetItem(0);
  6466. if (pw)
  6467. packet->setItemByName("primary", pw, player_to_inspect, 0);
  6468. Item* sw = player_to_inspect->GetEquipmentList()->GetItem(1);
  6469. if (sw)
  6470. packet->setItemByName("secondary", sw, player_to_inspect, 0);*/
  6471. //DumpPacket(packet->serialize());
  6472. QueuePacket(packet->serialize());
  6473. safe_delete(packet);
  6474. }
  6475. }
  6476. }
  6477. void Client::SetPendingGuildInvite(Guild* guild, Player* invited_by) {
  6478. pending_guild_invite.guild = guild;
  6479. pending_guild_invite.invited_by = invited_by;
  6480. }
  6481. void Client::ShowClaimWindow() {
  6482. PacketStruct* packet = configReader.getStruct("WS_PromoFlagsDetails", GetVersion());
  6483. if (packet) {
  6484. map<int32, Item*>* items = &master_item_list.items;
  6485. map<int32, Item*>::iterator itr;
  6486. int32 i = 0;
  6487. if (items->size() > 10)
  6488. packet->setArrayLengthByName("num_claim_items", 10);
  6489. else
  6490. packet->setArrayLengthByName("num_claim_items", items->size());
  6491. for (itr = items->begin(); itr != items->end(); itr++) {
  6492. if (i == 10)
  6493. break;
  6494. Item* item = itr->second;
  6495. packet->setArrayDataByName("id", i, i);
  6496. packet->setArrayDataByName("not_yet_claimed", 1, i);
  6497. packet->setArrayDataByName("num_remaining", 5, i);
  6498. packet->setArrayDataByName("one_per_character", 1, i);
  6499. packet->setArrayDataByName("claimed_on_this_char", 0, i);
  6500. packet->setArrayDataByName("item_name", item->name.c_str(), i);
  6501. packet->setArrayDataByName("text", "If you ever see this text, let Scatman know, thanks! :)", i);
  6502. packet->setArrayDataByName("category", "Scott's Shit", i);
  6503. packet->setArrayDataByName("icon", item->details.icon, i);
  6504. packet->setArrayDataByName("item_id", item->details.item_id, i);
  6505. i++;
  6506. }
  6507. QueuePacket(packet->serialize());
  6508. safe_delete(packet);
  6509. }
  6510. }
  6511. void Client::ShowGuildSearchWindow() {
  6512. PacketStruct* packet = configReader.getStruct("WS_GuildRecruiting", GetVersion());
  6513. if (packet) {
  6514. MutexMap<int32, Guild*>* guilds = guild_list.GetGuilds();
  6515. MutexMap<int32, Guild*>::iterator itr = guilds->begin();
  6516. packet->setArrayLengthByName("num_guilds", guilds->size());
  6517. int32 i = 0;
  6518. while (itr.Next()) {
  6519. Guild* guild = itr.second;
  6520. packet->setArrayDataByName("guild_id", guild->GetID(), i);
  6521. packet->setArrayDataByName("guild_name", guild->GetName(), i);
  6522. packet->setArrayDataByName("recruiting_short_description", guild->GetRecruitingShortDesc().c_str(), i);
  6523. packet->setArrayDataByName("descriptive_tag1", guild->GetRecruitingDescTag(0), i);
  6524. packet->setArrayDataByName("descriptive_tag2", guild->GetRecruitingDescTag(1), i);
  6525. packet->setArrayDataByName("descriptive_tag3", guild->GetRecruitingDescTag(2), i);
  6526. packet->setArrayDataByName("descriptive_tag4", guild->GetRecruitingDescTag(3), i);
  6527. packet->setArrayDataByName("playstyle", guild->GetRecruitingPlayStyle(), i);
  6528. packet->setArrayDataByName("looking_for", guild->GetRecruitingLookingForPacketValue(), i); //tradeskillers, fighters, new
  6529. packet->setArrayDataByName("unknown7", 0x02, i);
  6530. packet->setArrayDataByName("min_level", guild->GetRecruitingMinLevel(), i);
  6531. i++;
  6532. }
  6533. QueuePacket(packet->serialize());
  6534. safe_delete(packet);
  6535. }
  6536. }
  6537. void Client::ShowDressingRoom(Item *item, sint32 crc) {
  6538. PacketStruct *packet;
  6539. vector<int8> *slot_data;
  6540. vector<int8>::iterator itr;
  6541. int32 slots = 0;
  6542. assert(item);
  6543. if (!(packet = configReader.getStruct("WS_DressingRoom", GetVersion()))) {
  6544. return;
  6545. }
  6546. slot_data = &item->slot_data;
  6547. for (itr = slot_data->begin(); itr != slot_data->end(); itr++) {
  6548. if (version >= 1188)
  6549. slots = *itr;
  6550. else
  6551. slots += (int8)pow(2.0, *itr);
  6552. }
  6553. packet->setDataByName("slot", slots);
  6554. packet->setDataByName("appearance_id", item->generic_info.appearance_id);
  6555. if(slots == 2){
  6556. packet->setDataByName("rgb", item->generic_info.appearance_red, 2);
  6557. packet->setDataByName("rgb", item->generic_info.appearance_blue, 0);
  6558. }
  6559. else{
  6560. packet->setDataByName("rgb", item->generic_info.appearance_red, 0);
  6561. packet->setDataByName("rgb", item->generic_info.appearance_blue, 2);
  6562. }
  6563. packet->setDataByName("rgb", item->generic_info.appearance_green, 1);
  6564. if(slots == 4){
  6565. packet->setDataByName("highlight_rgb", item->generic_info.appearance_highlight_red, 2);
  6566. packet->setDataByName("highlight_rgb", item->generic_info.appearance_highlight_green, 1);
  6567. packet->setDataByName("highlight_rgb", item->generic_info.appearance_highlight_blue, 0);
  6568. }
  6569. else if(slots == 7){
  6570. packet->setDataByName("highlight_rgb", item->generic_info.appearance_highlight_red, 1);
  6571. packet->setDataByName("highlight_rgb", item->generic_info.appearance_highlight_green, 0);
  6572. packet->setDataByName("highlight_rgb", item->generic_info.appearance_highlight_blue, 2);
  6573. }
  6574. else{
  6575. packet->setDataByName("highlight_rgb", item->generic_info.appearance_highlight_red, 0);
  6576. packet->setDataByName("highlight_rgb", item->generic_info.appearance_highlight_green, 1);
  6577. packet->setDataByName("highlight_rgb", item->generic_info.appearance_highlight_blue, 2);
  6578. }
  6579. packet->setDataByName("icon", item->details.icon);
  6580. packet->setDataByName("item_id", item->details.item_id);
  6581. packet->setDataByName("item_crc", crc);
  6582. packet->setDataByName("unknown2", 0xFFFFFFFF);
  6583. packet->setDataByName("unknown4", 0xFFFFFFFF);
  6584. packet->setDataByName("unknown5", 0xFF, 9);
  6585. packet->setDataByName("unknown5", 0xFF, 10);
  6586. QueuePacket(packet->serialize());
  6587. safe_delete(packet);
  6588. }
  6589. void Client::SendCollectionList() {
  6590. map<int32, Collection *> *collections = player->GetCollectionList()->GetCollections();
  6591. map<int32, Collection *>::iterator itr;
  6592. vector<struct CollectionItem *> *collection_items;
  6593. Collection *collection;
  6594. struct CollectionItem *collection_item;
  6595. PacketStruct *packet = 0;
  6596. int16 i = 0, j;
  6597. if (!(packet = configReader.getStruct("WS_CollectionUpdate", version)))
  6598. return;
  6599. packet->setArrayLengthByName("num_collections", collections->size());
  6600. for (itr = collections->begin(); itr != collections->end(); itr++) {
  6601. collection = itr->second;
  6602. collection_items = collection->GetCollectionItems();
  6603. packet->setArrayDataByName("unknown", 1, i);
  6604. packet->setArrayDataByName("collection_name", collection->GetName(), i);
  6605. packet->setArrayDataByName("collection_category", collection->GetCategory(), i);
  6606. packet->setArrayDataByName("completed", collection->GetCompleted(), i);
  6607. packet->setArrayDataByName("collection_id", collection->GetID(), i);
  6608. packet->setArrayDataByName("level", collection->GetLevel(), i);
  6609. packet->setArrayDataByName("ready_to_turn_in", collection->GetIsReadyToTurnIn(), i);
  6610. packet->setSubArrayLengthByName("num_items", collection_items->size(), i);
  6611. for (j = 0; j < collection_items->size(); j++) {
  6612. collection_item = collection_items->at(j);
  6613. Item* item = master_item_list.GetItem(collection_item->item);
  6614. if (item) {
  6615. packet->setSubArrayDataByName("item_icon", item->details.icon, i, j);
  6616. if (version < 955)
  6617. packet->setSubArrayDataByName("item_name", item->name.c_str(), i, j);
  6618. else
  6619. packet->setSubArrayDataByName("item_id", item->details.item_id, i, j);
  6620. }
  6621. packet->setSubArrayDataByName("item_flag", collection_item->found, i, j);
  6622. }
  6623. i++;
  6624. }
  6625. packet->setDataByName("new_collection_flag", 1);
  6626. QueuePacket(packet->serialize());
  6627. safe_delete(packet);
  6628. }
  6629. bool Client::SendCollectionsForItem(Item *item) {
  6630. map<int32, Collection *> collections_to_send;
  6631. map<int32, Collection *> *collections;
  6632. map<int32, Collection *>::iterator itr;
  6633. vector<struct CollectionItem *> *collection_items;
  6634. Collection *collection;
  6635. struct CollectionItem *collection_item;
  6636. PacketStruct *packet;
  6637. int16 i;
  6638. assert(item);
  6639. /* get any collections required by this item that the player already has */
  6640. collections = player->GetCollectionList()->GetCollections();
  6641. for (itr = collections->begin(); itr != collections->end(); itr++) {
  6642. collection = itr->second;
  6643. if (!collection->GetCompleted() && !collection->GetIsReadyToTurnIn() && collection->NeedsItem(item)) {
  6644. LogWrite(COLLECTION__DEBUG, 0, "Collect", "Adding collection from player list %u\n", collection->GetID());
  6645. collections_to_send[collection->GetID()] = collection;
  6646. }
  6647. }
  6648. /* get any collections required by this item that the player does not have and send it to the client */
  6649. collections = master_collection_list.GetCollections();
  6650. for (itr = collections->begin(); itr != collections->end(); itr++) {
  6651. collection = itr->second;
  6652. if (collection->NeedsItem(item) && !player->GetCollectionList()->GetCollection(collection->GetID())) {
  6653. if (!(packet = configReader.getStruct("WS_CollectionUpdate", version))) {
  6654. return false;
  6655. }
  6656. packet->setArrayLengthByName("num_collections", 1);
  6657. packet->setArrayDataByName("unknown", 1, 0);
  6658. packet->setArrayDataByName("collection_name", collection->GetName(), 0);
  6659. packet->setArrayDataByName("collection_category", collection->GetCategory(), 0);
  6660. packet->setArrayDataByName("completed", 0, 0);
  6661. packet->setArrayDataByName("collection_id", collection->GetID(), 0);
  6662. packet->setArrayDataByName("level", collection->GetLevel(), 0);
  6663. packet->setArrayDataByName("ready_to_turn_in", 0, 0);
  6664. packet->setArrayDataByName("unknown3", 0x28, 0);
  6665. collection_items = collection->GetCollectionItems();
  6666. packet->setSubArrayLengthByName("num_items", collection_items->size(), 0);
  6667. for (i = 0; i < collection_items->size(); i++) {
  6668. collection_item = collection_items->at(i);
  6669. Item* item2 = master_item_list.GetItem(collection_item->item);
  6670. if (item2) {
  6671. packet->setSubArrayDataByName("item_icon", item2->details.icon, 0, i);
  6672. if (version < 955)
  6673. packet->setSubArrayDataByName("item_name", item2->name.c_str(), 0, i);
  6674. else
  6675. packet->setSubArrayDataByName("item_id", item2->details.item_id, 0, i);
  6676. packet->setSubArrayDataByName("item_flag", collection_item->found, 0, i);
  6677. }
  6678. }
  6679. packet->setDataByName("new_collection_flag", 0);
  6680. QueuePacket(packet->serialize());
  6681. safe_delete(packet);
  6682. LogWrite(COLLECTION__DEBUG, 0, "Collect", "Adding collection from master list %u\n", collection->GetID());
  6683. collections_to_send[collection->GetID()] = collection;
  6684. }
  6685. }
  6686. /* send the client a list of collections that should be filtered for this item */
  6687. if (collections_to_send.size() > 0) {
  6688. if (!(packet = configReader.getStruct("WS_CollectionFilter", version))) {
  6689. return false;
  6690. }
  6691. i = 0;
  6692. packet->setArrayLengthByName("num_filters", collections_to_send.size());
  6693. for (itr = collections_to_send.begin(); itr != collections_to_send.end(); itr++) {
  6694. collection = itr->second;
  6695. packet->setArrayDataByName("collection_id", collection->GetID(), i);
  6696. packet->setArrayDataByName("collection_item_num", collection->GetCollectionItemByItemID(item->details.item_id)->index, i);
  6697. i++;
  6698. }
  6699. packet->setDataByName("item_icon", item->details.icon);
  6700. packet->setDataByName("item_name", item->name.c_str());
  6701. packet->setDataByName("item_id", item->details.item_id);
  6702. packet->setDataByName("unknown3", player->GetCollectionList()->Size());
  6703. QueuePacket(packet->serialize());
  6704. safe_delete(packet);
  6705. }
  6706. return collections_to_send.size() > 0;
  6707. }
  6708. void Client::HandleCollectionAddItem(int32 collection_id, Item *item) {
  6709. Collection *collection;
  6710. struct CollectionItem *collection_item;
  6711. PacketStruct *packet;
  6712. char tmp[200] = {0};
  6713. assert(item);
  6714. /* first try to get the collection from the player's collection list. if it's not found, get it from the master list */
  6715. if ((collection = player->GetCollectionList()->GetCollection(collection_id))) {
  6716. /* get the item struct that represents the item for this collection */
  6717. if (!(collection_item = collection->GetCollectionItemByItemID(item->details.item_id))) {
  6718. SendCollectionList();
  6719. LogWrite(COLLECTION__ERROR, 0, "Collect", "Error in Client::HandleCollectionAddItem. Could not find item '%s' required by collection '%s'", item->name.c_str(), collection->GetName());
  6720. return;
  6721. }
  6722. /* sanity check */
  6723. if (collection_item->found) {
  6724. SendCollectionList();
  6725. LogWrite(COLLECTION__ERROR, 0, "Collect", "Error in Client::HandleCollectionAddItem. Player '%s' has already found item '%s' for collection '%s'", player->GetName(), item->name.c_str(), collection->GetName());
  6726. return;
  6727. }
  6728. }
  6729. else if ((collection = master_collection_list.GetCollection(collection_id))) {
  6730. collection = new Collection(collection);
  6731. /* get the item struct that represents the item for this collection */
  6732. if (!(collection_item = collection->GetCollectionItemByItemID(item->details.item_id))) {
  6733. SendCollectionList();
  6734. LogWrite(COLLECTION__ERROR, 0, "Collect", "Error in Client::HandleCollectionAddItem. Could not find item '%s' required by collection '%s'", item->name.c_str(), collection->GetName());
  6735. safe_delete(collection);
  6736. return;
  6737. }
  6738. /* add the new collection to the player's collection list */
  6739. if (!player->GetCollectionList()->AddCollection(collection)) {
  6740. SendCollectionList();
  6741. LogWrite(COLLECTION__ERROR, 0, "Collect", "Error in Client::HandleCollectionAddItem. Player '%s' already has collection '%s'", player->GetName(), collection->GetName());
  6742. safe_delete(collection);
  6743. return;
  6744. }
  6745. }
  6746. else {
  6747. LogWrite(COLLECTION__ERROR, 0, "Collect", "Error in Client::HandleCollectionAddItem. Could not find collection with id %u", collection_id);
  6748. return;
  6749. }
  6750. collection_item->found = 1;
  6751. collection->SetSaveNeeded(true);
  6752. if (!(packet = configReader.getStruct("WS_CollectionItem", version))) {
  6753. SendCollectionList();
  6754. LogWrite(COLLECTION__ERROR, 0, "Collect", "Error in Client::HandleCollectionAddItem. Could not find struct 'WS_CollectionItem'");
  6755. return;
  6756. }
  6757. packet->setDataByName("collection_id", collection_id);
  6758. packet->setDataByName("collection_item_num", collection_item->index);
  6759. packet->setDataByName("add", 1);
  6760. QueuePacket(packet->serialize());
  6761. Item* item2 = master_item_list.GetItem(collection_item->item);
  6762. if (item2) {
  6763. Message(CHANNEL_COLOR_YELLOW, "You added: %s to %s", item2->name.c_str(), collection->GetName());
  6764. sprintf(tmp, "You added: %s to %s", item2->name.c_str(), collection->GetName());
  6765. SendPopupMessage(5, tmp, "quest_item", 3.5, 0x64, 0xFF, 0xFF);
  6766. }
  6767. safe_delete(packet);
  6768. RemoveItem(item, 1);
  6769. SendCollectionList();
  6770. }
  6771. void Client::DisplayCollectionComplete(Collection *collection) {
  6772. vector<struct CollectionRewardItem *> *reward_items;
  6773. vector<struct CollectionRewardItem *> *selectable_reward_items;
  6774. struct CollectionRewardItem *reward_item;
  6775. PacketStruct *packet;
  6776. int32 i;
  6777. assert(collection);
  6778. if (!(packet = configReader.getStruct("WS_QuestComplete", version))) {
  6779. return;
  6780. }
  6781. reward_items = collection->GetRewardItems();
  6782. selectable_reward_items = collection->GetSelectableRewardItems();
  6783. packet->setDataByName("title", "Quest Reward!");
  6784. packet->setDataByName("name", collection->GetName());
  6785. packet->setDataByName("description", collection->GetCategory());
  6786. packet->setDataByName("level", collection->GetLevel());
  6787. packet->setDataByName("max_coin", collection->GetRewardCoin());
  6788. packet->setDataByName("min_coin", collection->GetRewardCoin());
  6789. //packet->setDataByName("status_points", quest->GetStatusPoints());
  6790. packet->setArrayLengthByName("num_rewards", reward_items->size());
  6791. for (i = 0; i < reward_items->size(); i++) {
  6792. reward_item = reward_items->at(i);
  6793. packet->setArrayDataByName("reward_id", reward_item->item->details.item_id, i);
  6794. if (version < 860)
  6795. packet->setItemArrayDataByName("item",reward_item->item, player, i, 0, -1);
  6796. else if (version < 1193)
  6797. packet->setItemArrayDataByName("item",reward_item->item, player, i);
  6798. else
  6799. packet->setItemArrayDataByName("item",reward_item->item, player, i, 0, 2);
  6800. }
  6801. packet->setArrayLengthByName("num_select_rewards", selectable_reward_items->size());
  6802. for(i = 0; i < selectable_reward_items->size(); i++) {
  6803. reward_item = selectable_reward_items->at(i);
  6804. packet->setArrayDataByName("select_reward_id", reward_item->item->details.item_id, i);
  6805. if(version < 860)
  6806. packet->setItemArrayDataByName("select_item", reward_item->item, player, i, 0, -1);
  6807. else if (version < 1193)
  6808. packet->setItemArrayDataByName("select_item", reward_item->item, player, i);
  6809. else
  6810. packet->setItemArrayDataByName("select_item", reward_item->item, player, i, 0, 2);
  6811. }
  6812. QueuePacket(packet->serialize());
  6813. safe_delete(packet);
  6814. }
  6815. void Client::HandInCollections() {
  6816. map<int32, Collection *> *collections;
  6817. map<int32, Collection *>::iterator itr;
  6818. Collection *collection;
  6819. /* only show 1 collection reward dialog at a time */
  6820. if (player->GetPendingCollectionReward()) {
  6821. return;
  6822. }
  6823. collections = player->GetCollectionList()->GetCollections();
  6824. /* we only want to display 1 collection reward dialog at a time. so once we find one to display, send it and return. once the player accepts the reward
  6825. for this collection, this function gets called again and the process repeats until there are no more collections to hand in */
  6826. for (itr = collections->begin(); itr != collections->end(); itr++) {
  6827. collection = itr->second;
  6828. if (collection->GetIsReadyToTurnIn()) {
  6829. player->SetPendingCollectionReward(collection);
  6830. DisplayCollectionComplete(collection);
  6831. return;
  6832. }
  6833. }
  6834. }
  6835. void Client::AcceptCollectionRewards(Collection *collection, int32 selectable_item_id) {
  6836. vector<struct CollectionRewardItem *> *reward_items;
  6837. vector<struct CollectionRewardItem *>::iterator itr;
  6838. struct CollectionRewardItem *reward_item;
  6839. int16 num_slots_needed;
  6840. int16 num_slots;
  6841. assert(collection);
  6842. reward_items = collection->GetRewardItems();
  6843. num_slots_needed = (int16)reward_items->size();
  6844. if (selectable_item_id > 0)
  6845. num_slots_needed++;
  6846. num_slots = player->GetPlayerItemList()->GetNumberOfFreeSlots();
  6847. if (num_slots < num_slots_needed) {
  6848. SimpleMessage(CHANNEL_COLOR_RED, "You do not have enough free slots. Free up some slots and try again");
  6849. HandInCollections();
  6850. return;
  6851. }
  6852. /* add manditory items */
  6853. for (itr = reward_items->begin(); itr != reward_items->end(); itr++) {
  6854. reward_item = *itr;
  6855. AddItem(reward_item->item->details.item_id, reward_item->quantity);
  6856. }
  6857. /* find and add the selectable item if there's one */
  6858. if (selectable_item_id > 0) {
  6859. reward_items = collection->GetSelectableRewardItems();
  6860. for (itr = reward_items->begin(); itr != reward_items->end(); itr++) {
  6861. reward_item = *itr;
  6862. if (reward_item->item->details.item_id == selectable_item_id) {
  6863. AddItem(reward_item->item->details.item_id, reward_item->quantity);
  6864. break;
  6865. }
  6866. }
  6867. }
  6868. if (collection->GetRewardXP() > 0) {
  6869. player->AddXP((int32)collection->GetRewardXP());
  6870. SimpleMessage(CHANNEL_COLOR_YELLOW, "You gain experience!");
  6871. }
  6872. if (collection->GetRewardCoin() > 0) {
  6873. player->AddCoins(collection->GetRewardCoin());
  6874. Message(CHANNEL_COLOR_YELLOW, "You receive %s", GetCoinMessage(collection->GetRewardCoin()).c_str());
  6875. }
  6876. collection->SetCompleted(true);
  6877. //update achievements for completeing collection here
  6878. collection->SetSaveNeeded(true);
  6879. SendCollectionList();
  6880. /* reset the pending collection reward and check for my collections that the player needs to hand in */
  6881. player->SetPendingCollectionReward(0);
  6882. HandInCollections();
  6883. }
  6884. void Client::SendRecipeList() {
  6885. PacketStruct* packet = 0;
  6886. if (GetRecipeListSent()) {
  6887. return;
  6888. }
  6889. if (!(packet = configReader.getStruct("WS_RecipeList", version))) {
  6890. return;
  6891. }
  6892. map<int32, Recipe *> *recipes = player->GetRecipeList()->GetRecipes();
  6893. map<int32, Recipe *>::iterator itr;
  6894. Recipe *recipe;
  6895. int16 i = 0;
  6896. packet->setArrayLengthByName("num_recipes", recipes->size());
  6897. for (itr = recipes->begin(); itr != recipes->end(); itr++){
  6898. recipe = itr->second;
  6899. packet->setArrayDataByName("id", recipe->GetID(), i);
  6900. packet->setArrayDataByName("tier", recipe->GetTier(), i);
  6901. packet->setArrayDataByName("level", recipe->GetLevel(), i);
  6902. packet->setArrayDataByName("icon", recipe->GetIcon(), i);
  6903. packet->setArrayDataByName("classes", recipe->GetClasses(), i);
  6904. packet->setArrayDataByName("skill", recipe->GetSkill(), i);
  6905. packet->setArrayDataByName("technique", recipe->GetTechnique(), i);
  6906. packet->setArrayDataByName("knowledge", recipe->GetKnowledge(), i);
  6907. packet->setArrayDataByName("unknown2", recipe->GetUnknown2(), i);
  6908. packet->setArrayDataByName("recipe_name", recipe->GetName(), i);
  6909. packet->setArrayDataByName("recipe_book", recipe->GetBook(), i);
  6910. packet->setArrayDataByName("unknown3", recipe->GetUnknown3(), i);
  6911. i++;
  6912. }
  6913. //packet->PrintPacket();
  6914. //DumpPacket(packet->serialize());
  6915. QueuePacket(packet->serialize());
  6916. safe_delete(packet);
  6917. SetRecipeListSent(true);
  6918. }
  6919. void Client::ShowRecipeBook() {
  6920. PacketStruct* packet = 0;
  6921. Spawn* target = 0;
  6922. if (!(target = player->GetTarget())) {
  6923. SimpleMessage(CHANNEL_COLOR_YELLOW, "You do not have a tradeskill device targeted");
  6924. return;
  6925. }
  6926. if (!target->IsObject()) {
  6927. return;
  6928. }
  6929. if (!(packet = configReader.getStruct("WS_ShowRecipeBook", version))) {
  6930. return;
  6931. }
  6932. packet->setDataByName("device", target->GetName());
  6933. packet->setDataByName("unknown1", 1);
  6934. if (((Object*)target)->GetDeviceID() > 0) {
  6935. int32 deviceID = (int32)pow(2.0, (double)((Object*)target)->GetDeviceID());
  6936. //LogWrite(TRADESKILL__ERROR, 0, "Tradeskills", "GetDeviceID() = %u, deviceID = %u", ((Object*)target)->GetDeviceID(), deviceID);
  6937. packet->setDataByName("unknown2", 8);
  6938. packet->setDataByName("unknown3", deviceID);
  6939. }
  6940. //packet->PrintPacket();
  6941. QueuePacket(packet->serialize());
  6942. safe_delete(packet);
  6943. }
  6944. void Client::SendTitleUpdate(){
  6945. list<Title*> *titles = player->GetPlayerTitles()->GetAllTitles();
  6946. list<Title*>::iterator itr;
  6947. Title *title;
  6948. int16 i = 0;
  6949. sint16 prefix_index = database.GetCharPrefixIndex(GetCharacterID(), player);
  6950. sint16 suffix_index = database.GetCharSuffixIndex(GetCharacterID(), player);
  6951. PacketStruct* packet = configReader.getStruct("WS_TitleUpdate", GetVersion());
  6952. if(packet){
  6953. packet->setArrayLengthByName("num_titles", titles->size());
  6954. for(itr = titles->begin(); itr != titles->end(); itr++){
  6955. title = *itr;
  6956. packet->setArrayDataByName("title", title->GetName(), i);
  6957. packet->setArrayDataByName("prefix", title->GetPrefix(), i);
  6958. i++;
  6959. }
  6960. packet->setDataByName("current_prefix", prefix_index);
  6961. packet->setDataByName("current_suffix", suffix_index);
  6962. LogWrite(CCLIENT__PACKET, 0, "Client", "Dump/Print Packet in func: %s, line: %i", __FUNCTION__, __LINE__);
  6963. #if EQDEBUG >= 9
  6964. packet->PrintPacket();
  6965. #endif
  6966. QueuePacket(packet->serialize());
  6967. safe_delete(packet);
  6968. SendUpdateTitles(prefix_index, suffix_index);
  6969. }
  6970. }
  6971. void Client::SendUpdateTitles(sint16 prefix, sint16 suffix){
  6972. Title* suffix_title = 0;
  6973. Title* prefix_title = 0;
  6974. if (suffix != -1){
  6975. suffix_title = player->GetPlayerTitles()->GetTitle(suffix);
  6976. strcpy(player->appearance.suffix_title, suffix_title->GetName());
  6977. }
  6978. else
  6979. memset(player->appearance.suffix_title, 0, strlen(player->appearance.suffix_title));
  6980. if (prefix != -1){
  6981. prefix_title = player->GetPlayerTitles()->GetTitle(prefix);
  6982. strcpy(player->appearance.prefix_title, prefix_title->GetName());
  6983. }
  6984. else
  6985. memset(player->appearance.prefix_title, 0, strlen(player->appearance.prefix_title));
  6986. current_zone->SendUpdateTitles(this, suffix_title, prefix_title);
  6987. }
  6988. void Client::SendLanguagesUpdate(int32 id){
  6989. list<Language*> *languages = player->GetPlayerLanguages()->GetAllLanguages();
  6990. list<Language*>::iterator itr;
  6991. Language* language;
  6992. int32 i = 0;
  6993. PacketStruct* packet = configReader.getStruct("WS_Languages", GetVersion());
  6994. if(packet){
  6995. packet->setArrayLengthByName("num_languages", languages->size());
  6996. for(itr = languages->begin(); itr != languages->end(); itr++){
  6997. language = *itr;
  6998. packet->setArrayDataByName("language_id", language->GetID(), i);
  6999. i++;
  7000. }
  7001. packet->setDataByName("current_language", id);
  7002. LogWrite(CCLIENT__PACKET, 0, "Client", "Dump/Print Packet in func: %s, line: %i", __FUNCTION__, __LINE__);
  7003. #if EQDEBUG >= 9
  7004. packet->PrintPacket();
  7005. #endif
  7006. QueuePacket(packet->serialize());
  7007. safe_delete(packet);
  7008. }
  7009. }
  7010. void Client::SendPetOptionsWindow(const char* pet_name, int8 type) {
  7011. PacketStruct* packet = configReader.getStruct("WS_PetOptions", GetVersion());
  7012. if (packet) {
  7013. if (pet_name)
  7014. packet->setDataByName("pet_name", pet_name);
  7015. if (player->GetInfoStruct()->pet_behavior & 1)
  7016. packet->setDataByName("protect_master", 1);
  7017. if (player->GetInfoStruct()->pet_behavior & 2)
  7018. packet->setDataByName("protect_self", 1);
  7019. if (player->GetInfoStruct()->pet_movement == 2)
  7020. packet->setDataByName("stay_follow_toggle", 1);
  7021. packet->setDataByName("pet_type", type);
  7022. QueuePacket(packet->serialize());
  7023. }
  7024. safe_delete(packet);
  7025. }
  7026. bool Client::IsCrafting() {
  7027. return current_zone->GetTradeskillMgr()->IsClientCrafting(this);
  7028. }
  7029. void Client::SendBiography() {
  7030. PacketStruct* packet = configReader.getStruct("WS_BioUpdate", GetVersion());
  7031. if (packet) {
  7032. if (strlen(player->GetInfoStruct()->biography) > 0)
  7033. packet->setDataByName("biography",player->GetInfoStruct()->biography);
  7034. QueuePacket(packet->serialize());
  7035. }
  7036. safe_delete(packet);
  7037. }
  7038. PendingResurrection* Client::GetCurrentRez() {
  7039. return &current_rez;
  7040. }
  7041. Mutex* Client::GetResurrectMutex() {
  7042. return &m_resurrect;
  7043. }
  7044. void Client::SendResurrectionWindow() {
  7045. Spawn* caster = current_rez.caster;
  7046. if(!caster || !player)
  7047. return;
  7048. PacketStruct* packet = configReader.getStruct("WS_ChoiceWindow", GetVersion());
  7049. if(!packet)
  7050. return;
  7051. char* tmp = new char[512];
  7052. sprintf(tmp, "%s would like to cast '%s' on you. Do you accept?", caster->GetName(), current_rez.spell_name.c_str());
  7053. packet->setMediumStringByName("text", tmp);
  7054. packet->setMediumStringByName("accept_text", "Yes");
  7055. packet->setMediumStringByName("cancel_text", "No");
  7056. sprintf(tmp, "accept_resurrection %u", player->GetID());
  7057. packet->setMediumStringByName("accept_command", tmp);
  7058. sprintf(tmp, "decline_resurrection %u", player->GetID());
  7059. packet->setMediumStringByName("cancel_command", tmp);
  7060. packet->setDataByName("time", current_rez.expire_timer->GetRemainingTime() / 1000);
  7061. QueuePacket(packet->serialize());
  7062. safe_delete(packet);
  7063. safe_delete_array(tmp);
  7064. }
  7065. void Client::AcceptResurrection() {
  7066. Spawn* caster = current_rez.caster;
  7067. if(!player || !caster)
  7068. return;
  7069. if(player->Alive())
  7070. return;
  7071. if((caster->GetZone() != player->GetZone()) || (current_rez.range > 0 && player->GetDistance(caster) > current_rez.range)){
  7072. SimpleMessage(CHANNEL_COLOR_YELLOW, "The caster must be nearby to complete the spell.");
  7073. SendResurrectionWindow();
  7074. return;
  7075. }
  7076. player->GetZone()->ResurrectSpawn(player, this);
  7077. current_rez.should_delete = true;
  7078. }
  7079. void Client::SetPendingLastName(string last_name) {
  7080. pending_last_name = new string;
  7081. pending_last_name->assign(last_name);
  7082. }
  7083. string* Client::GetPendingLastName() {
  7084. return pending_last_name;
  7085. }
  7086. void Client::RemovePendingLastName() {
  7087. safe_delete(pending_last_name);
  7088. }
  7089. void Client::SendLastNameConfirmation() {
  7090. if (!pending_last_name)
  7091. return;
  7092. PacketStruct* packet = configReader.getStruct("WS_ChoiceWindow", GetVersion());
  7093. if (packet){
  7094. char* text = new char[128];
  7095. sprintf(text, "Are you sure you want your last name to be \"%s\"?" , pending_last_name->c_str());
  7096. packet->setDataByName("text", text);
  7097. packet->setDataByName("accept_text", "Yes");
  7098. packet->setDataByName("accept_command", "confirmedlastname");
  7099. packet->setDataByName("cancel_text", "No");
  7100. packet->setDataByName("unknown2", 50);
  7101. packet->setDataByName("unknown4", 1);
  7102. packet->setDataByName("unknown5", 1);
  7103. QueuePacket(packet->serialize());
  7104. safe_delete(packet);
  7105. safe_delete_array(text);
  7106. }
  7107. }
  7108. void Client::AddQuestTimer(int32 quest_id) {
  7109. MQuestTimers.writelock(__FUNCTION__, __LINE__);
  7110. quest_timers.push_back(quest_id);
  7111. MQuestTimers.releasewritelock(__FUNCTION__, __LINE__);
  7112. }
  7113. void Client::RemoveQuestTimer(int32 quest_id) {
  7114. MQuestTimers.writelock(__FUNCTION__, __LINE__);
  7115. vector<int32>::iterator itr;
  7116. for (itr = quest_timers.begin(); itr != quest_timers.end(); itr++) {
  7117. if ((*itr) == quest_id) {
  7118. quest_timers.erase(itr);
  7119. break;
  7120. }
  7121. }
  7122. MQuestTimers.releasewritelock(__FUNCTION__, __LINE__);
  7123. }
  7124. void Client::SavePlayerImages() {
  7125. LogWrite(CCLIENT__DEBUG, 0, "Client", "Saving %s image for player %s (%u)", (incoming_paperdoll.image_type == PAPERDOLL_TYPE_FULL ? "paperdoll" : "headshot"), GetPlayer()->GetName(), GetCharacterID());
  7126. // Save the paperdoll image if the server allows it
  7127. if (incoming_paperdoll.image_type == PAPERDOLL_TYPE_FULL && rule_manager.GetGlobalRule(R_World, SavePaperdollImage)->GetBool())
  7128. database.SaveCharacterPicture(GetCharacterID(), incoming_paperdoll.image_type, incoming_paperdoll.image_bytes, incoming_paperdoll.current_size_bytes);
  7129. if (incoming_paperdoll.image_type == PAPERDOLL_TYPE_HEAD) {
  7130. // Save the head shot if the server allows it
  7131. if (rule_manager.GetGlobalRule(R_World, SaveHeadshotImage)->GetBool())
  7132. database.SaveCharacterPicture(GetCharacterID(), incoming_paperdoll.image_type, incoming_paperdoll.image_bytes, incoming_paperdoll.current_size_bytes);
  7133. // Send the head shot to the login server
  7134. if (rule_manager.GetGlobalRule(R_World, SendPaperdollImagesToLogin)->GetBool()) {
  7135. int32 size = incoming_paperdoll.current_size_bytes + CHARPICSTRUCT_MINSIZE;
  7136. ServerPacket* packet = new ServerPacket(ServerOP_CharacterPicture, size);
  7137. memset(packet->pBuffer, 0, size);
  7138. CharPictureUpdate_Struct* pic = (CharPictureUpdate_Struct*)packet->pBuffer;
  7139. pic->account_id = GetAccountID();
  7140. pic->char_id = GetCharacterID();
  7141. pic->pic_size = (int16)incoming_paperdoll.current_size_bytes;
  7142. memcpy(pic->pic, incoming_paperdoll.image_bytes, incoming_paperdoll.current_size_bytes);
  7143. loginserver.SendPacket(packet);
  7144. safe_delete(packet);
  7145. }
  7146. }
  7147. safe_delete_array(incoming_paperdoll.image_bytes);
  7148. incoming_paperdoll.current_size_bytes = 0;
  7149. }
  7150. void Client::EndAutoMount() {
  7151. PacketStruct* packet = configReader.getStruct("WS_ServerControlFlags", GetVersion());
  7152. if (packet) {
  7153. packet->setDataByName("parameter1", 128);
  7154. packet->setDataByName("parameter2", 64);
  7155. packet->setDataByName("value", 1);
  7156. QueuePacket(packet->serialize());
  7157. safe_delete(packet);
  7158. }
  7159. packet = configReader.getStruct("WS_ServerControlFlags", GetVersion());
  7160. if (packet) {
  7161. packet->setDataByName("parameter3", 4);
  7162. packet->setDataByName("parameter5", 2);
  7163. packet->setDataByName("value", 0);
  7164. QueuePacket(packet->serialize());
  7165. safe_delete(packet);
  7166. }
  7167. packet = configReader.getStruct("WS_ClearForLanding", GetVersion());
  7168. if (packet) {
  7169. packet->setDataByName("spawn_id", GetPlayer()->GetIDWithPlayerSpawn(GetPlayer()));
  7170. QueuePacket(packet->serialize());
  7171. safe_delete(packet);
  7172. }
  7173. on_auto_mount = false;
  7174. player->SetMount(((Player*)player)->GetTempMount());
  7175. EQ2_Color mount_color = player->GetTempMountColor();
  7176. EQ2_Color saddle_color = player->GetTempMountSaddleColor();
  7177. player->SetMountColor(&mount_color);
  7178. player->SetMountSaddleColor(&saddle_color);
  7179. player->SetTempMount(0);
  7180. }
  7181. bool Client::EntityCommandPrecheck(Spawn* spawn, const char* command){
  7182. const char* spawn_script = spawn->GetSpawnScript();
  7183. bool should_use_spawn = true;
  7184. if (spawn_script){
  7185. lua_State* state = lua_interface->GetSpawnScript(spawn_script);
  7186. if (state){
  7187. Mutex* state_mutex = lua_interface->GetSpawnScriptMutex(spawn_script);
  7188. if (state_mutex)
  7189. state_mutex->writelock(__FUNCTION__, __LINE__);
  7190. lua_getglobal(state, "can_use_command");
  7191. if (lua_isfunction(state, -1)){
  7192. lua_interface->SetSpawnValue(state, spawn);
  7193. lua_interface->SetSpawnValue(state, GetPlayer());
  7194. lua_interface->SetStringValue(state, command ? command : "");
  7195. if (lua_pcall(state, 3, 1, 0) == 0){
  7196. should_use_spawn = lua_interface->GetBooleanValue(state, 1);
  7197. }
  7198. }
  7199. lua_interface->ResetFunctionStack(state);
  7200. if (state_mutex)
  7201. state_mutex->releasewritelock(__FUNCTION__, __LINE__);
  7202. }
  7203. }
  7204. return should_use_spawn;
  7205. }
  7206. bool Client::IsCurrentTransmuteID(int32 req_id) {
  7207. return req_id == transmuteID;
  7208. }
  7209. void Client::SetTransmuteID(int32 trans_id) {
  7210. transmuteID = trans_id;
  7211. }
  7212. int32 Client::GetTransmuteID() {
  7213. return transmuteID;
  7214. }