WorldDatabase.cpp 278 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754
  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 <math.h>
  17. #include <iostream>
  18. #include <sstream>
  19. #include <iomanip>
  20. #include <ios>
  21. #include <assert.h>
  22. #include "WorldDatabase.h"
  23. #include "../common/debug.h"
  24. #include "../common/packet_dump.h"
  25. #include "../common/GlobalHeaders.h"
  26. #include "Items/Items.h"
  27. #include "Factions.h"
  28. #include "World.h"
  29. #include "Variables.h"
  30. #include "VisualStates.h"
  31. #include "Appearances.h"
  32. #include "Skills.h"
  33. #include "Quests.h"
  34. #include "LuaInterface.h"
  35. #include "classes.h"
  36. #include "../common/Log.h"
  37. #include "Rules/Rules.h"
  38. #include "Titles.h"
  39. #include "Languages.h"
  40. #include "Traits/Traits.h"
  41. #include "ClientPacketFunctions.h"
  42. #include "Zone/ChestTrap.h"
  43. #include "../common/version.h"
  44. extern Classes classes;
  45. extern Commands commands;
  46. extern MasterTitlesList master_titles_list;
  47. extern MasterItemList master_item_list;
  48. extern MasterSpellList master_spell_list;
  49. extern MasterTraitList master_trait_list;
  50. extern MasterFactionList master_faction_list;
  51. extern World world;
  52. extern Variables variables;
  53. extern VisualStates visual_states;
  54. extern Appearances master_appearance_list;
  55. extern MasterSkillList master_skill_list;
  56. extern MasterQuestList master_quest_list;
  57. extern LuaInterface* lua_interface;
  58. extern ZoneList zone_list;
  59. extern GuildList guild_list;
  60. extern MasterCollectionList master_collection_list;
  61. extern RuleManager rule_manager;
  62. extern MasterLanguagesList master_languages_list;
  63. extern ChestTrapList chest_trap_list;
  64. //devn00b: Fix for linux builds since we dont use stricmp we use strcasecmp
  65. #if defined(__GNUC__)
  66. #define stricmp strcasecmp
  67. #define strnicmp strncasecmp
  68. #endif
  69. WorldDatabase::WorldDatabase(){
  70. }
  71. WorldDatabase::~WorldDatabase(){
  72. }
  73. bool WorldDatabase::ConnectNewDatabase() {
  74. /*
  75. TESTS
  76. database_new.Connect();
  77. DatabaseResult result;
  78. database_new.Select(&result, "select name from characters where id=1");
  79. if (result.Next()) {
  80. printf("'%s'\n", result.GetStringStr("name"));
  81. printf("'%s'\n", result.GetStringStr("nameBAD"));
  82. printf("'%s'\n", result.GetString(3));
  83. }
  84. return true;
  85. */
  86. return database_new.Connect();
  87. }
  88. void WorldDatabase::PingNewDB()
  89. {
  90. database_new.PingNewDB();
  91. }
  92. void WorldDatabase::DeleteBuyBack(int32 char_id, int32 item_id, int16 quantity, int32 price) {
  93. LogWrite(MERCHANT__DEBUG, 0, "Merchant", "Deleting Buyback - Player: %u, Item ID: %u, Qty: %i, Price: %u", char_id, item_id, quantity, price);
  94. Query query;
  95. query.RunQuery2(Q_DELETE, "DELETE FROM character_buyback WHERE char_id = %u AND item_id = %u AND quantity = %i AND price = %u", char_id, item_id, quantity, price);
  96. }
  97. void WorldDatabase::LoadBuyBacks(Client* client) {
  98. LogWrite(MERCHANT__DEBUG, 0, "Merchant", "Loading Buyback - Player: %u", client->GetCharacterID());
  99. Query query;
  100. MYSQL_ROW row;
  101. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, item_id, quantity, price FROM character_buyback where char_id = %u ORDER BY id desc limit 10", client->GetCharacterID());
  102. int8 count = 0;
  103. int32 last_id = 0;
  104. if(result)
  105. {
  106. while(result && (row = mysql_fetch_row(result)))
  107. {
  108. LogWrite(MERCHANT__DEBUG, 5, "Merchant", "AddBuyBack: item: %u, qty: %i, price: %u", atoul(row[1]), atoi(row[2]), atoul(row[3]));
  109. last_id = atoul(row[0]);
  110. client->AddBuyBack(last_id, atoul(row[1]), atoi(row[2]), atoul(row[3]), false);
  111. count++;
  112. }
  113. if(count >= 10)
  114. {
  115. LogWrite(MERCHANT__DEBUG, 0, "Merchant", "Deleting excess Buyback from Player: %u", client->GetCharacterID());
  116. Query query2;
  117. query2.RunQuery2(Q_DELETE, "DELETE FROM character_buyback WHERE char_id = %u AND id < %u", client->GetCharacterID(), last_id);
  118. }
  119. }
  120. }
  121. void WorldDatabase::SaveBuyBacks(Client* client)
  122. {
  123. LogWrite(MERCHANT__DEBUG, 3, "Merchant", "Saving Buybacks - Player: %u", client->GetCharacterID());
  124. deque<BuyBackItem*>* buybacks = client->GetBuyBacks();
  125. if(buybacks && buybacks->size() > 0)
  126. {
  127. BuyBackItem* item = 0;
  128. deque<BuyBackItem*>::iterator itr;
  129. for(itr = buybacks->begin(); itr != buybacks->end(); itr++)
  130. {
  131. item = *itr;
  132. if(item && item->save_needed)
  133. {
  134. LogWrite(MERCHANT__DEBUG, 5, "Merchant", "SaveBuyBack: char: %u, item: %u, qty: %i, price: %u", client->GetCharacterID(), item->item_id, item->quantity, item->price);
  135. SaveBuyBack(client->GetCharacterID(), item->item_id, item->quantity, item->price);
  136. item->save_needed = false;
  137. }
  138. }
  139. }
  140. }
  141. void WorldDatabase::SaveBuyBack(int32 char_id, int32 item_id, int16 quantity, int32 price)
  142. {
  143. LogWrite(MERCHANT__DEBUG, 3, "Merchant", "Saving Buyback - Player: %u, Item ID: %u, Qty: %i, Price: %u", char_id, item_id, quantity, price);
  144. Query query;
  145. string insert = string("INSERT INTO character_buyback (char_id, item_id, quantity, price) VALUES (%u, %u, %i, %u) ");
  146. query.AddQueryAsync(char_id, this, Q_INSERT, insert.c_str(), char_id, item_id, quantity, price);
  147. }
  148. int32 WorldDatabase::LoadCharacterSpells(int32 char_id, Player* player)
  149. {
  150. LogWrite(SPELL__DEBUG, 0, "Spells", "Loading Character Spells for player %s...", player->GetName());
  151. Query query;
  152. MYSQL_ROW row;
  153. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT spell_id, tier, knowledge_slot, spell_book_type, linked_timer_id FROM character_spells, spells where character_spells.spell_id = spells.id and character_spells.char_id = %u ORDER BY spell_id, tier desc", char_id);
  154. int32 old_spell_id = 0;
  155. int32 new_spell_id = 0;
  156. int32 count = 0;
  157. if(result && mysql_num_rows(result) >0)
  158. {
  159. while(result && (row = mysql_fetch_row(result)))
  160. {
  161. count++;
  162. new_spell_id = atoul(row[0]);
  163. if(new_spell_id == old_spell_id)
  164. continue;
  165. LogWrite(SPELL__DEBUG, 5, "Spells", "\tLoading SpellID: %u, tier: %i, slot: %i, type: %u linked_timer_id: %u", new_spell_id, atoi(row[1]), atoi(row[2]), atoul(row[3]), atoul(row[4]));
  166. player->AddSpellBookEntry(new_spell_id, atoi(row[1]), atoi(row[2]), atoul(row[3]), atoul(row[4]));
  167. old_spell_id = new_spell_id;
  168. }
  169. }
  170. return count;
  171. }
  172. void WorldDatabase::SavePlayerSpells(Client* client)
  173. {
  174. if(!client || client->GetCharacterID() < 1)
  175. return;
  176. LogWrite(SPELL__DEBUG, 3, "Spells", "Saving Spell(s) for Player: '%s'", client->GetPlayer()->GetName());
  177. vector<SpellBookEntry*>* spells = client->GetPlayer()->GetSpellsSaveNeeded();
  178. if(spells)
  179. {
  180. vector<SpellBookEntry*>::iterator itr;
  181. SpellBookEntry* spell = 0;
  182. for(itr = spells->begin(); itr != spells->end(); itr++)
  183. {
  184. spell = *itr;
  185. Query query;
  186. LogWrite(SPELL__DEBUG, 5, "Spells", "\tSaving SpellID: %u, tier: %i, slot: %i", spell->spell_id, spell->tier, spell->slot);
  187. query.AddQueryAsync(client->GetCharacterID(), this, Q_INSERT, "INSERT INTO character_spells (char_id, spell_id, tier) SELECT %u, %u, %i ON DUPLICATE KEY UPDATE tier = %i",
  188. client->GetPlayer()->GetCharacterID(), spell->spell_id, spell->tier, spell->tier);
  189. spell->save_needed = false;
  190. }
  191. safe_delete(spells);
  192. }
  193. }
  194. int32 WorldDatabase::LoadCharacterSkills(int32 char_id, Player* player)
  195. {
  196. Query query;
  197. MYSQL_ROW row;
  198. int32 count = 0;
  199. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT skill_id, current_val, max_val FROM character_skills, skills where character_skills.skill_id = skills.id and character_skills.char_id = %u", char_id);
  200. if(result && mysql_num_rows(result) >0)
  201. {
  202. while(result && (row = mysql_fetch_row(result)))
  203. {
  204. count++;
  205. LogWrite(SKILL__DEBUG, 5, "Skills", "Loading SkillID: %u, cur_val: %i, max_val: %l", strtoul(row[0], NULL, 0), atoi(row[1]), atoi(row[2]));
  206. player->AddSkill(strtoul(row[0], NULL, 0), atoi(row[1]), atoi(row[2]));
  207. }
  208. }
  209. return count;
  210. }
  211. void WorldDatabase::DeleteCharacterSkill(int32 char_id, Skill* skill)
  212. {
  213. if (char_id > 0 && skill)
  214. {
  215. LogWrite(SKILL__DEBUG, 0, "Skills", "Deleting Skill '%s' (%u) from char_id: %u", skill->name.data.c_str(), skill->skill_id, char_id);
  216. Query query;
  217. query.RunQuery2(Q_DELETE, "DELETE FROM `character_skills` WHERE `char_id`=%u AND `skill_id`=%u", char_id, skill->skill_id);
  218. }
  219. }
  220. int32 WorldDatabase::LoadSkills()
  221. {
  222. int32 total = 0;
  223. Query query;
  224. MYSQL_ROW row;
  225. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, short_name, name, description, skill_type, display FROM skills");
  226. if(result)
  227. {
  228. if (mysql_num_rows(result) >0)
  229. {
  230. Skill* skill = 0;
  231. while(result && (row = mysql_fetch_row(result)))
  232. {
  233. skill = new Skill();
  234. skill->skill_id = strtoul(row[0], NULL, 0);
  235. skill->short_name.data = string(row[1]);
  236. skill->short_name.size = skill->short_name.data.length();
  237. skill->name.data = string(row[2]);
  238. skill->name.size = skill->name.data.length();
  239. skill->description.data = string(row[3]);
  240. skill->description.size = skill->description.data.length();
  241. skill->skill_type = strtoul(row[4], NULL, 0);
  242. skill->display = atoi(row[5]);
  243. master_skill_list.AddSkill(skill);
  244. total++;
  245. LogWrite(SKILL__DEBUG, 5, "Skill", "---Loading Skill: %s (%u)", skill->name.data.c_str(), skill->skill_id);
  246. LogWrite(SKILL__DEBUG, 7, "Skill", "---short_name: %s, type: %i, display: %i", skill->short_name.data.c_str(), skill->skill_type, skill->display);
  247. }
  248. }
  249. }
  250. LogWrite(SKILL__DEBUG, 3, "Skill", "--Loaded %u Skill(s)", total);
  251. return total;
  252. }
  253. map<int8, vector<MacroData*> >* WorldDatabase::LoadCharacterMacros(int32 char_id)
  254. {
  255. Query query;
  256. MYSQL_ROW row;
  257. int32 total = 0;
  258. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT macro_number, macro_name, macro_icon, macro_text FROM character_macros where char_id = %u ORDER BY macro_number, id", char_id);
  259. if(result && mysql_num_rows(result) >0)
  260. {
  261. map<int8, vector<MacroData*> >* macros = new map<int8, vector<MacroData*> >;
  262. while(result && (row = mysql_fetch_row(result)))
  263. {
  264. MacroData* data = new MacroData;
  265. data->name = row[1];
  266. data->icon = atoi(row[2]);
  267. data->text = row[3];
  268. (*macros)[atoi(row[0])].push_back(data);
  269. total++;
  270. LogWrite(PLAYER__DEBUG, 5, "Player", "\tLoading macro: %i. %s for player: %u", atoi(row[0]), row[1], char_id);
  271. }
  272. LogWrite(PLAYER__DEBUG, 0, "Player", "\tLoaded %u macro%s", total, total == 1 ? "" : "s");
  273. return macros;
  274. }
  275. return 0;
  276. }
  277. void WorldDatabase::UpdateCharacterMacro(int32 char_id, int8 number, const char* name, int16 icon, vector<string>* updates)
  278. {
  279. LogWrite(PLAYER__DEBUG, 0, "Player", "Update player id %u macro: %i", char_id, number);
  280. Query query;
  281. Query query2;
  282. query.RunQuery2(Q_DELETE, "delete FROM character_macros where char_id = %u and macro_number = %i", char_id, number);
  283. if(name && updates && updates->size() > 0)
  284. {
  285. for(int8 i=0;i<updates->size();i++)
  286. {
  287. query2.RunQuery2(Q_INSERT, "insert into character_macros (char_id, macro_number, macro_name, macro_icon, macro_text) values(%u, %i, '%s', %i, '%s')", char_id, number, getSafeEscapeString(name).c_str(), icon, getSafeEscapeString(updates->at(i).c_str()).c_str());
  288. LogWrite(PLAYER__DEBUG, 5, "Player", "\tAdding macro: %s, %s (Player: %u)", name, updates->at(i).c_str(), char_id);
  289. }
  290. }
  291. }
  292. //we use our timestamp just in case db is on another server, otherwise times might be off
  293. void WorldDatabase::UpdateVitality(int32 timestamp, float amount){
  294. Query query;
  295. LogWrite(PLAYER__DEBUG, 3, "Player", "Reset Vitality > 100: %f", amount);
  296. query.RunQuery2(Q_UPDATE, "update character_details set xp_vitality=100 where (xp_vitality + %f) > 100", amount);
  297. LogWrite(PLAYER__DEBUG, 3, "Player", "Update Vitality <= 100: %f", amount);
  298. query.RunQuery2(Q_UPDATE, "update character_details set xp_vitality=(xp_vitality+%f) where (xp_vitality + %f) <= 100", amount, amount);
  299. LogWrite(PLAYER__DEBUG, 3, "Player", "Update Vitality Timer: %u", timestamp);
  300. query.RunQuery2(Q_UPDATE, "update variables set variable_value=%u where variable_name='vitalitytimer'", timestamp);
  301. }
  302. void WorldDatabase::SaveVariable(const char* name, const char* value, const char* comment){
  303. LogWrite(WORLD__DEBUG, 0, "Variables", "Saving Variable: %s = %s", name, value);
  304. Query query;
  305. if(comment){
  306. query.RunQuery2(Q_REPLACE, "replace into variables (variable_name, variable_value, comment) values('%s', '%s', '%s')",
  307. getSafeEscapeString(name).c_str(), getSafeEscapeString(value).c_str(), getSafeEscapeString(comment).c_str());
  308. }
  309. else{
  310. query.RunQuery2(Q_REPLACE, "replace into variables (variable_name, variable_value) values('%s', '%s')",
  311. getSafeEscapeString(name).c_str(), getSafeEscapeString(value).c_str());
  312. }
  313. }
  314. void WorldDatabase::LoadGlobalVariables(){
  315. variables.ClearVariables ( );
  316. int32 total = 0;
  317. Query query;
  318. MYSQL_ROW row;
  319. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT variable_name, variable_value, comment FROM variables");
  320. while(result && (row = mysql_fetch_row(result)))
  321. {
  322. Variable* newVar = new Variable(row[0], row[1], row[2]);
  323. variables.AddVariable(newVar);
  324. total++;
  325. LogWrite(WORLD__DEBUG, 5, "World", "---Loading variable: '%s' = '%s'", row[0], row[1]);
  326. }
  327. LogWrite(WORLD__DEBUG, 3, "World", "--Loaded %u variables", total);
  328. }
  329. void WorldDatabase::LoadAppearanceMasterList()
  330. {
  331. DatabaseResult result;
  332. int32 total = 0;
  333. int32 appearance_id;
  334. int16 appearance_version;
  335. master_appearance_list.ClearAppearances();
  336. database_new.Select(&result, "SELECT appearance_id, `name`, min_client_version FROM appearances ORDER BY appearance_id");
  337. while( result.Next() )
  338. {
  339. appearance_id = result.GetInt32Str("appearance_id");
  340. const char *appearance_name = result.GetStringStr("name");
  341. appearance_version = result.GetInt16Str("min_client_version");
  342. Appearance* a = new Appearance(appearance_id, appearance_name, appearance_version);
  343. master_appearance_list.InsertAppearance(a);
  344. total++;
  345. LogWrite(WORLD__DEBUG, 5, "World", "---Loading appearances: '%s' (%i)", appearance_name, appearance_id);
  346. }
  347. LogWrite(WORLD__DEBUG, 3, "World", "--Loaded %u appearances", total);
  348. }
  349. void WorldDatabase::LoadVisualStates()
  350. {
  351. visual_states.Reset();
  352. int32 total = 0;
  353. Query query;
  354. Query query2;
  355. MYSQL_ROW row;
  356. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT visual_state_id, name FROM visual_states");
  357. while(result && (row = mysql_fetch_row(result)))
  358. {
  359. VisualState* vs = new VisualState(atoi(row[0]), row[1]);
  360. visual_states.InsertVisualState(vs);
  361. total++;
  362. LogWrite(WORLD__DEBUG, 5, "World", "---Loading visual state: '%s' (%i)", row[1], atoi(row[0]));
  363. }
  364. LogWrite(WORLD__DEBUG, 3, "World", "--Loaded %u visual states", total);
  365. total = 0;
  366. result = query2.RunQuery2(Q_SELECT, "SELECT name, visual_state_id, message, targeted_message FROM emotes");
  367. while(result && (row = mysql_fetch_row(result)))
  368. {
  369. Emote* emote = new Emote(row[0], atoi(row[1]), row[2], row[3]);
  370. visual_states.InsertEmote(emote);
  371. total++;
  372. LogWrite(WORLD__DEBUG, 5, "World", "---Loading emote state: '%s' (%i)", row[1], atoi(row[0]));
  373. }
  374. LogWrite(WORLD__DEBUG, 3, "World", "--Loaded %u emote state(s)", total);
  375. }
  376. void WorldDatabase::LoadSubCommandList()
  377. {
  378. int32 total = 0;
  379. Query query;
  380. MYSQL_ROW row;
  381. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT command, subcommand, handler, required_status FROM commands where length(subcommand) > 0 ORDER BY handler asc");
  382. while(result && (row = mysql_fetch_row(result)))
  383. {
  384. commands.GetRemoteCommands()->CheckAddSubCommand(string(row[0]), EQ2_RemoteCommandString(row[1], (int32)strtoul(row[2], NULL, 0), atoi(row[3])));
  385. total++;
  386. LogWrite(COMMAND__DEBUG, 5, "Command", "---Loading Command: '%s', sub '%s', handler, %u status %i", row[0], row[1], atoul(row[2]), atoi(row[3]));
  387. }
  388. LogWrite(COMMAND__DEBUG, 3, "Command", "--Loaded %i Subcommand(s)", total);
  389. }
  390. void WorldDatabase::LoadCommandList()
  391. {
  392. Query query;
  393. MYSQL_ROW row;
  394. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT command, handler, required_status FROM commands where length(subcommand) = 0 ORDER BY handler asc");
  395. int16 index = 0;
  396. while(result && (row = mysql_fetch_row(result)))
  397. {
  398. int32 handler = strtoul(row[1], NULL, 0);
  399. while(handler>index && handler != 999)
  400. {
  401. LogWrite(COMMAND__DEBUG, 5, "Command", "---Loading Remote Commands: handler %u, index %u", handler, index);
  402. commands.GetRemoteCommands()->addZero();
  403. index++;
  404. }
  405. LogWrite(COMMAND__DEBUG, 5, "Command", "---Loading Commands: handler %u, index %u", handler, index);
  406. commands.GetRemoteCommands()->addCommand(EQ2_RemoteCommandString(row[0], handler, atoi(row[2])));
  407. index++;
  408. }
  409. LogWrite(COMMAND__DEBUG, 3, "Command", "--Loaded %i Command%s", index, index > 0 ? "s" : "");
  410. LoadSubCommandList();
  411. }
  412. int32 WorldDatabase::LoadNPCSpells(ZoneServer* zone){
  413. Query query;
  414. MYSQL_ROW row;
  415. int32 count = 0;
  416. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT spell_list_id, spell_id, spell_tier FROM spawn_npc_spells where spell_list_id > 0");
  417. while(result && (row = mysql_fetch_row(result))){
  418. zone->AddNPCSpell(atoul(row[0]), atoul(row[1]), atoi(row[2]));
  419. count++;
  420. LogWrite(NPC__DEBUG, 5, "NPC", "---Loading NPC Spell List: %u, spell id: %u, tier: %i", atoul(row[0]), atoul(row[1]), atoi(row[2]));
  421. }
  422. return count;
  423. }
  424. int32 WorldDatabase::LoadNPCSkills(ZoneServer* zone){
  425. Query query;
  426. MYSQL_ROW row;
  427. int32 count = 0;
  428. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT skill_list_id, skill_id, starting_value FROM spawn_npc_skills");
  429. while(result && (row = mysql_fetch_row(result))){
  430. zone->AddNPCSkill(atoul(row[0]), atoul(row[1]), atoi(row[2]));
  431. count++;
  432. LogWrite(NPC__DEBUG, 5, "NPC", "---Loading NPC Skill List: %u, skill id: %u, value: %i", atoul(row[0]), atoul(row[1]), atoi(row[2]));
  433. }
  434. return count;
  435. }
  436. int32 WorldDatabase::LoadNPCEquipment(ZoneServer* zone){
  437. Query query;
  438. MYSQL_ROW row;
  439. int32 count = 0;
  440. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT equipment_list_id, item_id FROM spawn_npc_equipment");
  441. while(result && (row = mysql_fetch_row(result))){
  442. zone->AddNPCEquipment(atoul(row[0]), atoul(row[1]));
  443. count++;
  444. LogWrite(NPC__DEBUG, 5, "NPC", "---Loading NPC Equipment List: %u, item: %u", atoul(row[0]), atoul(row[1]));
  445. }
  446. return count;
  447. }
  448. int8 WorldDatabase::GetAppearanceType(string type){
  449. int8 ret = 255;
  450. if (type == "soga_hair_face_highlight_color")
  451. ret = APPEARANCE_SOGA_HFHC;
  452. else if (type == "soga_hair_type_highlight_color")
  453. ret = APPEARANCE_SOGA_HTHC;
  454. else if (type == "soga_hair_face_color")
  455. ret = APPEARANCE_SOGA_HFC;
  456. else if (type == "soga_hair_type_color")
  457. ret = APPEARANCE_SOGA_HTC;
  458. else if (type == "soga_hair_highlight")
  459. ret = APPEARANCE_SOGA_HH;
  460. else if (type == "soga_hair_color1")
  461. ret = APPEARANCE_SOGA_HC1;
  462. else if (type == "soga_hair_color2")
  463. ret = APPEARANCE_SOGA_HC2;
  464. else if (type == "hair_type_color")
  465. ret = APPEARANCE_HTC;
  466. else if (type == "soga_skin_color")
  467. ret = APPEARANCE_SOGA_SC;
  468. else if (type == "soga_eye_color")
  469. ret = APPEARANCE_SOGA_EC;
  470. else if (type == "hair_type_highlight_color")
  471. ret = APPEARANCE_HTHC;
  472. else if (type == "hair_face_highlight_color")
  473. ret = APPEARANCE_HFHC;
  474. else if (type == "hair_face_color")
  475. ret = APPEARANCE_HFC;
  476. else if (type == "hair_highlight")
  477. ret = APPEARANCE_HH;
  478. else if (type == "hair_color1")
  479. ret = APPEARANCE_HC1;
  480. else if (type == "wing_color1")
  481. ret = APPEARANCE_WC1;
  482. else if (type == "hair_color2")
  483. ret = APPEARANCE_HC2;
  484. else if (type == "wing_color2")
  485. ret = APPEARANCE_WC2;
  486. else if (type == "skin_color")
  487. ret = APPEARANCE_SC;
  488. else if (type == "eye_color")
  489. ret = APPEARANCE_EC;
  490. else if (type == "soga_eye_brow_type")
  491. ret = APPEARANCE_SOGA_EBT;
  492. else if (type == "soga_cheek_type")
  493. ret = APPEARANCE_SOGA_CHEEKT;
  494. else if (type == "soga_nose_type")
  495. ret = APPEARANCE_SOGA_NT;
  496. else if (type == "soga_chin_type")
  497. ret = APPEARANCE_SOGA_CHINT;
  498. else if (type == "soga_lip_type")
  499. ret = APPEARANCE_SOGA_LT;
  500. else if (type == "eye_brow_type")
  501. ret = APPEARANCE_EBT;
  502. else if (type == "soga_ear_type")
  503. ret = APPEARANCE_SOGA_EART;
  504. else if (type == "soga_eye_type")
  505. ret = APPEARANCE_SOGA_EYET;
  506. else if (type == "cheek_type")
  507. ret = APPEARANCE_CHEEKT;
  508. else if (type == "nose_type")
  509. ret = APPEARANCE_NT;
  510. else if (type == "chin_type")
  511. ret = APPEARANCE_CHINT;
  512. else if (type == "ear_type")
  513. ret = APPEARANCE_EART;
  514. else if (type == "eye_type")
  515. ret = APPEARANCE_EYET;
  516. else if (type == "lip_type")
  517. ret = APPEARANCE_LT;
  518. else if (type == "shirt_color")
  519. ret = APPEARANCE_SHIRT;
  520. else if (type == "unknown_chest_color")
  521. ret = APPEARANCE_UCC;
  522. else if (type == "pants_color")
  523. ret = APPEARANCE_PANTS;
  524. else if (type == "unknown_legs_color")
  525. ret = APPEARANCE_ULC;
  526. else if (type == "unknown9")
  527. ret = APPEARANCE_U9;
  528. else if (type == "body_size")
  529. ret = APPEARANCE_BODY_SIZE;
  530. else if (type == "soga_wing_color1")
  531. ret = APPEARANCE_SOGA_WC1;
  532. else if (type == "soga_wing_color2")
  533. ret = APPEARANCE_SOGA_WC2;
  534. else if (type == "soga_shirt_color")
  535. ret = APPEARANCE_SOGA_SHIRT;
  536. else if (type == "soga_unknown_chest_color")
  537. ret = APPEARANCE_SOGA_UCC;
  538. else if (type == "soga_pants_color")
  539. ret = APPEARANCE_SOGA_PANTS;
  540. else if (type == "soga_unknown_legs_color")
  541. ret = APPEARANCE_SOGA_ULC;
  542. else if (type == "soga_unknown13")
  543. ret = APPEARANCE_SOGA_U13;
  544. else if (type == "body_age")
  545. ret = APPEARANCE_BODY_AGE;
  546. return ret;
  547. }
  548. int32 WorldDatabase::LoadAppearances(ZoneServer* zone, Client* client){
  549. Query query, query2;
  550. MYSQL_ROW row;
  551. int32 count = 0, spawn_id = 0, new_spawn_id = 0;
  552. Entity* entity = 0;
  553. if(client)
  554. entity = client->GetPlayer();
  555. map<string, int8> appearance_types;
  556. map<int32, map<int8, EQ2_Color> > appearance_colors;
  557. EQ2_Color color;
  558. color.red = 0;
  559. color.green = 0;
  560. color.blue = 0;
  561. string type;
  562. MYSQL_RES* result = 0;
  563. if(!client)
  564. result = query.RunQuery2(Q_SELECT, "SELECT distinct `type` FROM npc_appearance where length(type) > 0");
  565. else
  566. result = query.RunQuery2(Q_SELECT, "SELECT distinct `type` FROM char_colors where length(type) > 0 and char_id=%u", client->GetCharacterID());
  567. while(result && (row = mysql_fetch_row(result))){
  568. type = string(row[0]);
  569. appearance_types[type] = GetAppearanceType(type);
  570. if(appearance_types[type] == 255)
  571. LogWrite(WORLD__ERROR, 0, "Appearance", "Unknown appearance type '%s' in LoadAppearances.", type.c_str());
  572. }
  573. MYSQL_RES* result2 = 0;
  574. if(!client)
  575. result2 = query2.RunQuery2(Q_SELECT, "SELECT `type`, spawn_id, signed_value, red, green, blue FROM npc_appearance where length(type) > 0 ORDER BY spawn_id");
  576. else
  577. result2 = query2.RunQuery2(Q_SELECT, "SELECT `type`, char_id, signed_value, red, green, blue FROM char_colors where length(type) > 0 and char_id=%u", client->GetCharacterID());
  578. while(result2 && (row = mysql_fetch_row(result2))){
  579. if(!client){
  580. new_spawn_id = atoul(row[1]);
  581. if(spawn_id != new_spawn_id){
  582. entity = zone->GetNPC(new_spawn_id, true);
  583. if(!entity)
  584. continue;
  585. if(spawn_id > 0)
  586. count++;
  587. spawn_id = new_spawn_id;
  588. }
  589. }
  590. if(appearance_types[row[0]] < APPEARANCE_SOGA_EBT){
  591. color.red = atoi(row[3]);
  592. color.green = atoi(row[4]);
  593. color.blue = atoi(row[5]);
  594. }
  595. switch(appearance_types[row[0]]){
  596. case APPEARANCE_SOGA_HFHC:{
  597. entity->features.soga_hair_face_highlight_color = color;
  598. break;
  599. }
  600. case APPEARANCE_SOGA_HTHC:{
  601. entity->features.soga_hair_type_highlight_color = color;
  602. break;
  603. }
  604. case APPEARANCE_SOGA_HFC:{
  605. entity->features.soga_hair_face_color = color;
  606. break;
  607. }
  608. case APPEARANCE_SOGA_HTC:{
  609. entity->features.soga_hair_type_color = color;
  610. break;
  611. }
  612. case APPEARANCE_SOGA_HH:{
  613. entity->features.soga_hair_highlight_color = color;
  614. break;
  615. }
  616. case APPEARANCE_SOGA_HC1:{
  617. entity->features.soga_hair_color1 = color;
  618. break;
  619. }
  620. case APPEARANCE_SOGA_HC2:{
  621. entity->features.soga_hair_color2 = color;
  622. break;
  623. }
  624. case APPEARANCE_SOGA_SC:{
  625. entity->features.soga_skin_color = color;
  626. break;
  627. }
  628. case APPEARANCE_SOGA_EC:{
  629. entity->features.soga_eye_color = color;
  630. break;
  631. }
  632. case APPEARANCE_HTHC:{
  633. entity->features.hair_type_highlight_color = color;
  634. break;
  635. }
  636. case APPEARANCE_HFHC:{
  637. entity->features.hair_face_highlight_color = color;
  638. break;
  639. }
  640. case APPEARANCE_HTC:{
  641. entity->features.hair_type_color = color;
  642. break;
  643. }
  644. case APPEARANCE_HFC:{
  645. entity->features.hair_face_color = color;
  646. break;
  647. }
  648. case APPEARANCE_HH:{
  649. entity->features.hair_highlight_color = color;
  650. break;
  651. }
  652. case APPEARANCE_HC1:{
  653. entity->features.hair_color1 = color;
  654. break;
  655. }
  656. case APPEARANCE_HC2:{
  657. entity->features.hair_color2 = color;
  658. break;
  659. }
  660. case APPEARANCE_WC1:{
  661. entity->features.wing_color1 = color;
  662. break;
  663. }
  664. case APPEARANCE_WC2:{
  665. entity->features.wing_color2 = color;
  666. break;
  667. }
  668. case APPEARANCE_SC:{
  669. entity->features.skin_color = color;
  670. break;
  671. }
  672. case APPEARANCE_EC:{
  673. entity->features.eye_color = color;
  674. break;
  675. }
  676. case APPEARANCE_SOGA_EBT:{
  677. for(int i=0;i<3;i++)
  678. entity->features.soga_eye_brow_type[i] = atoi(row[3+i]);
  679. break;
  680. }
  681. case APPEARANCE_SOGA_CHEEKT:{
  682. for(int i=0;i<3;i++)
  683. entity->features.soga_cheek_type[i] = atoi(row[3+i]);
  684. break;
  685. }
  686. case APPEARANCE_SOGA_NT:{
  687. for(int i=0;i<3;i++)
  688. entity->features.soga_nose_type[i] = atoi(row[3+i]);
  689. break;
  690. }
  691. case APPEARANCE_SOGA_CHINT:{
  692. for(int i=0;i<3;i++)
  693. entity->features.soga_chin_type[i] = atoi(row[3+i]);
  694. break;
  695. }
  696. case APPEARANCE_SOGA_LT:{
  697. for(int i=0;i<3;i++)
  698. entity->features.soga_lip_type[i] = atoi(row[3+i]);
  699. break;
  700. }
  701. case APPEARANCE_SOGA_EART:{
  702. for(int i=0;i<3;i++)
  703. entity->features.soga_ear_type[i] = atoi(row[3+i]);
  704. break;
  705. }
  706. case APPEARANCE_SOGA_EYET:{
  707. for(int i=0;i<3;i++)
  708. entity->features.soga_eye_type[i] = atoi(row[3+i]);
  709. break;
  710. }
  711. case APPEARANCE_EBT:{
  712. for(int i=0;i<3;i++)
  713. entity->features.eye_brow_type[i] = atoi(row[3+i]);
  714. break;
  715. }
  716. case APPEARANCE_CHEEKT:{
  717. for(int i=0;i<3;i++)
  718. entity->features.cheek_type[i] = atoi(row[3+i]);
  719. break;
  720. }
  721. case APPEARANCE_NT:{
  722. for(int i=0;i<3;i++)
  723. entity->features.nose_type[i] = atoi(row[3+i]);
  724. break;
  725. }
  726. case APPEARANCE_CHINT:{
  727. for(int i=0;i<3;i++)
  728. entity->features.chin_type[i] = atoi(row[3+i]);
  729. break;
  730. }
  731. case APPEARANCE_EART:{
  732. for(int i=0;i<3;i++)
  733. entity->features.ear_type[i] = atoi(row[3+i]);
  734. break;
  735. }
  736. case APPEARANCE_EYET:{
  737. for(int i=0;i<3;i++)
  738. entity->features.eye_type[i] = atoi(row[3+i]);
  739. break;
  740. }
  741. case APPEARANCE_LT:{
  742. for(int i=0;i<3;i++)
  743. entity->features.lip_type[i] = atoi(row[3+i]);
  744. break;
  745. }
  746. case APPEARANCE_SHIRT:{
  747. entity->features.shirt_color = color;
  748. break;
  749. }
  750. case APPEARANCE_UCC:{
  751. break;
  752. }
  753. case APPEARANCE_PANTS:{
  754. entity->features.pants_color = color;
  755. break;
  756. }
  757. case APPEARANCE_ULC:{
  758. break;
  759. }
  760. case APPEARANCE_U9:{
  761. break;
  762. }
  763. case APPEARANCE_BODY_SIZE:{
  764. entity->features.body_size = color.red;
  765. break;
  766. }
  767. case APPEARANCE_SOGA_WC1:{
  768. break;
  769. }
  770. case APPEARANCE_SOGA_WC2:{
  771. break;
  772. }
  773. case APPEARANCE_SOGA_SHIRT:{
  774. break;
  775. }
  776. case APPEARANCE_SOGA_UCC:{
  777. break;
  778. }
  779. case APPEARANCE_SOGA_PANTS:{
  780. break;
  781. }
  782. case APPEARANCE_SOGA_ULC:{
  783. break;
  784. }
  785. case APPEARANCE_SOGA_U13:{
  786. break;
  787. }
  788. case APPEARANCE_BODY_AGE: {
  789. entity->features.body_age = color.red;
  790. break;
  791. }
  792. }
  793. }
  794. return count;
  795. }
  796. void WorldDatabase::LoadNPCs(ZoneServer* zone){
  797. Query query;
  798. MYSQL_ROW row;
  799. NPC* npc = 0;
  800. int32 id = 0;
  801. int32 total = 0;
  802. MYSQL_RES* result = query.RunQuery2(Q_SELECT,"SELECT npc.spawn_id, s.name, npc.min_level, npc.max_level, npc.enc_level, s.race, s.model_type, npc.class_, npc.gender, s.command_primary, s.command_secondary, s.show_name, npc.min_group_size, npc.max_group_size, npc.hair_type_id, npc.facial_hair_type_id, npc.wing_type_id, npc.chest_type_id, npc.legs_type_id, npc.soga_hair_type_id, npc.soga_facial_hair_type_id, s.attackable, s.show_level, s.targetable, s.show_command_icon, s.display_hand_icon, s.hp, s.power, s.size, s.collision_radius, npc.action_state, s.visual_state, npc.mood_state, npc.initial_state, npc.activity_status, s.faction_id, s.sub_title, s.merchant_id, s.merchant_type, s.size_offset, npc.attack_type, npc.ai_strategy+0, npc.spell_list_id, npc.secondary_spell_list_id, npc.skill_list_id, npc.secondary_skill_list_id, npc.equipment_list_id, npc.str, npc.sta, npc.wis, npc.intel, npc.agi, npc.heat, npc.cold, npc.magic, npc.mental, npc.divine, npc.disease, npc.poison, npc.aggro_radius, npc.cast_percentage, npc.randomize, npc.soga_model_type, npc.heroic_flag, npc.alignment, npc.elemental, npc.arcane, npc.noxious, s.savagery, s.dissonance, npc.hide_hood, npc.emote_state, s.prefix, s.suffix, s.last_name, s.expansion_flag\n"
  803. "FROM spawn s\n"
  804. "INNER JOIN spawn_npcs npc\n"
  805. "ON s.id = npc.spawn_id\n"
  806. "INNER JOIN spawn_location_entry le\n"
  807. "ON npc.spawn_id = le.spawn_id\n"
  808. "INNER JOIN spawn_location_placement lp\n"
  809. "ON le.spawn_location_id = lp.spawn_location_id\n"
  810. "WHERE lp.zone_id = %u and (lp.instance_id = 0 or lp.instance_id = %u)\n"
  811. "GROUP BY s.id",
  812. zone->GetZoneID(), zone->GetInstanceID());
  813. while(result && (row = mysql_fetch_row(result))){
  814. /*npc->SetAppearanceID(atoi(row[12]));
  815. AppearanceData* appearance = world.GetNPCAppearance(npc->GetAppearanceID());
  816. if(appearance)
  817. memcpy(&npc->appearance, appearance, sizeof(AppearanceData));
  818. */
  819. int32 npcXpackFlag = atoul(row[75]);
  820. if (!CheckExpansionFlags(zone, npcXpackFlag))
  821. continue;
  822. id = atoul(row[0]);
  823. if(zone->GetNPC(id, true))
  824. continue;
  825. npc = new NPC();
  826. npc->SetDatabaseID(id);
  827. strcpy(npc->appearance.name, row[1]);
  828. vector<EntityCommand*>* primary_command_list = zone->GetEntityCommandList(atoul(row[9]));
  829. vector<EntityCommand*>* secondary_command_list = zone->GetEntityCommandList(atoul(row[10]));
  830. if(primary_command_list){
  831. npc->SetPrimaryCommands(primary_command_list);
  832. npc->primary_command_list_id = atoul(row[9]);
  833. }
  834. if(secondary_command_list){
  835. npc->SetSecondaryCommands(secondary_command_list);
  836. npc->secondary_command_list_id = atoul(row[10]);
  837. }
  838. npc->appearance.min_level = atoi(row[2]);
  839. npc->appearance.max_level = atoi(row[3]);
  840. npc->appearance.level = atoi(row[2]);
  841. npc->appearance.encounter_level = atoi(row[4]);
  842. npc->appearance.race = atoi(row[5]);
  843. //npc->appearance.lua_race_id = atoi(row[75]);
  844. if (atoi(row[74]) > 0) {
  845. int16 xxx = atoi(row[75]);
  846. int8 yyy = 0;
  847. }
  848. npc->appearance.model_type = atoi(row[6]);
  849. npc->appearance.soga_model_type = atoi(row[62]);
  850. npc->appearance.adventure_class = atoi(row[7]);
  851. npc->appearance.gender = atoi(row[8]);
  852. npc->appearance.display_name = atoi(row[11]);
  853. npc->features.hair_type = atoi(row[14]);
  854. npc->features.hair_face_type = atoi(row[15]);
  855. npc->features.wing_type = atoi(row[16]);
  856. npc->features.chest_type = atoi(row[17]);
  857. npc->features.legs_type = atoi(row[18]);
  858. npc->features.soga_hair_type = atoi(row[19]);
  859. npc->features.soga_hair_face_type = atoi(row[20]);
  860. npc->appearance.attackable = atoi(row[21]);
  861. npc->appearance.show_level = atoi(row[22]);
  862. npc->appearance.targetable = atoi(row[23]);
  863. npc->appearance.show_command_icon = atoi(row[24]);
  864. npc->appearance.display_hand_icon = atoi(row[25]);
  865. npc->appearance.hide_hood = atoi(row[70]);
  866. npc->appearance.randomize = atoi(row[61]);
  867. npc->SetTotalHP(atoul(row[26]));
  868. npc->SetTotalPower(atoul(row[27]));
  869. npc->SetHP(npc->GetTotalHP());
  870. npc->SetPower(npc->GetTotalPower());
  871. if(npc->GetTotalHP() == 0){
  872. npc->SetTotalHP(15*npc->GetLevel() + 1);
  873. npc->SetHP(15*npc->GetLevel() + 1);
  874. }
  875. if(npc->GetTotalPower() == 0){
  876. npc->SetTotalPower(15*npc->GetLevel() + 1);
  877. npc->SetPower(15*npc->GetLevel() + 1);
  878. }
  879. npc->size = atoi(row[28]);
  880. npc->appearance.pos.collision_radius = atoi(row[29]);
  881. npc->appearance.action_state = atoi(row[30]);
  882. npc->appearance.visual_state = atoi(row[31]);
  883. npc->appearance.mood_state = atoi(row[32]);
  884. npc->appearance.emote_state = atoi(row[71]);
  885. npc->appearance.pos.state = atoi(row[33]);
  886. npc->appearance.activity_status = atoi(row[34]);
  887. npc->faction_id = atoul(row[35]);
  888. if(row[36]){
  889. if(strlen(row[36]) < sizeof(npc->appearance.sub_title))
  890. strcpy(npc->appearance.sub_title, row[36]);
  891. else
  892. strncpy(npc->appearance.sub_title, row[36], sizeof(npc->appearance.sub_title));
  893. }
  894. npc->SetMerchantID(atoul(row[37]));
  895. npc->SetMerchantType(atoi(row[38]));
  896. npc->SetSizeOffset(atoi(row[39]));
  897. npc->SetAttackType(atoi(row[40]));
  898. npc->SetAIStrategy(atoi(row[41]));
  899. npc->SetPrimarySpellList(atoul(row[42]));
  900. npc->SetSecondarySpellList(atoul(row[43]));
  901. npc->SetPrimarySkillList(atoul(row[44]));
  902. npc->SetSecondarySkillList(atoul(row[45]));
  903. npc->SetEquipmentListID(atoul(row[46]));
  904. InfoStruct* info = npc->GetInfoStruct();
  905. info->str_base = atoi(row[47]);
  906. info->sta_base = atoi(row[48]);
  907. info->wis_base = atoi(row[49]);
  908. info->intel_base = atoi(row[50]);
  909. info->agi_base = atoi(row[51]);
  910. info->heat_base = atoi(row[52]);
  911. info->cold_base = atoi(row[53]);
  912. info->magic_base = atoi(row[54]);
  913. info->mental_base = atoi(row[55]);
  914. info->divine_base = atoi(row[56]);
  915. info->disease_base = atoi(row[57]);
  916. info->poison_base = atoi(row[58]);
  917. info->alignment = atoi(row[64]);
  918. npc->SetAggroRadius(atof(row[59]));
  919. npc->SetCastPercentage(atoi(row[60]));
  920. npc->appearance.heroic_flag = atoi(row[63]);
  921. info->elemental_base = atoi(row[65]);
  922. info->arcane_base = atoi(row[66]);
  923. info->noxious_base = atoi(row[67]);
  924. npc->SetTotalSavagery(atoul(row[68]));
  925. npc->SetTotalDissonance(atoul(row[69]));
  926. npc->SetSavagery(npc->GetTotalSavagery());
  927. npc->SetDissonance(npc->GetTotalDissonance());
  928. if(npc->GetTotalSavagery() == 0){
  929. npc->SetTotalSavagery(15*npc->GetLevel() + 1);
  930. npc->SetSavagery(15*npc->GetLevel() + 1);
  931. }
  932. if(npc->GetTotalDissonance() == 0){
  933. npc->SetTotalDissonance(15*npc->GetLevel() + 1);
  934. npc->SetDissonance(15*npc->GetLevel() + 1);
  935. }
  936. npc->SetPrefixTitle(row[72]);
  937. npc->SetSuffixTitle(row[73]);
  938. npc->SetLastName(row[74]);
  939. zone->AddNPC(id, npc);
  940. total++;
  941. LogWrite(NPC__DEBUG, 5, "NPC", "---Loading NPC: '%s' (%u)", npc->appearance.name, id);
  942. }
  943. LogWrite(NPC__INFO, 0, "NPC", "--Loaded %i NPC(s).", total);
  944. LogWrite(NPC__INFO, 0, "NPC", "--Loaded %i NPC Spell(s).", LoadNPCSpells(zone));
  945. LogWrite(NPC__INFO, 0, "NPC", "--Loaded %i NPC Skill(s).", LoadNPCSkills(zone));
  946. LogWrite(NPC__INFO, 0, "NPC", "--Loaded %i NPC Equipment Piece(s).", LoadNPCEquipment(zone));
  947. LogWrite(NPC__INFO, 0, "NPC", "--Loaded %i NPC Appearance(s).", LoadAppearances(zone));
  948. LogWrite(NPC__INFO, 0, "NPC", "--Loaded %i NPC Equipment Appearance(s).", LoadNPCAppearanceEquipmentData(zone));
  949. }
  950. void WorldDatabase::LoadSigns(ZoneServer* zone){
  951. Query query;
  952. MYSQL_ROW row;
  953. Sign* sign = 0;
  954. int32 id = 0;
  955. int32 total = 0;
  956. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT ss.spawn_id, s.name, s.model_type, s.size, s.show_command_icon, ss.widget_id, ss.widget_x, ss.widget_y, ss.widget_z, s.command_primary, s.command_secondary, s.collision_radius, ss.icon, ss.type, ss.title, ss.description, ss.sign_distance, ss.zone_id, ss.zone_x, ss.zone_y, ss.zone_z, ss.zone_heading, ss.include_heading, ss.include_location, s.transport_id, s.size_offset, s.display_hand_icon, s.visual_state\n"
  957. "FROM spawn s\n"
  958. "INNER JOIN spawn_signs ss\n"
  959. "ON s.id = ss.spawn_id\n"
  960. "INNER JOIN spawn_location_entry le\n"
  961. "ON ss.spawn_id = le.spawn_id\n"
  962. "INNER JOIN spawn_location_placement lp\n"
  963. "ON le.spawn_location_id = lp.spawn_location_id\n"
  964. "WHERE lp.zone_id = %u\n"
  965. "GROUP BY s.id",
  966. zone->GetZoneID());
  967. while(result && (row = mysql_fetch_row(result))){
  968. id = atoul(row[0]);
  969. if(zone->GetSign(id, true))
  970. continue;
  971. sign = new Sign();
  972. sign->SetDatabaseID(id);
  973. strcpy(sign->appearance.name, row[1]);
  974. sign->appearance.model_type = atoi(row[2]);
  975. sign->SetSize(atoi(row[3]));
  976. sign->appearance.show_command_icon = atoi(row[4]);
  977. sign->SetWidgetID(atoul(row[5]));
  978. sign->SetWidgetX(atof(row[6]));
  979. sign->SetWidgetY(atof(row[7]));
  980. sign->SetWidgetZ(atof(row[8]));
  981. vector<EntityCommand*>* primary_command_list = zone->GetEntityCommandList(atoul(row[9]));
  982. if(primary_command_list){
  983. sign->SetPrimaryCommands(primary_command_list);
  984. sign->primary_command_list_id = atoul(row[9]);
  985. }
  986. vector<EntityCommand*>* secondary_command_list = zone->GetEntityCommandList(atoul(row[10]));
  987. if (secondary_command_list){
  988. sign->SetSecondaryCommands(secondary_command_list);
  989. sign->secondary_command_list_id = atoul(row[10]);
  990. }
  991. sign->appearance.pos.collision_radius = atoi(row[11]);
  992. sign->SetSignIcon(atoi(row[12]));
  993. if(strncasecmp(row[13],"Generic", 7) == 0)
  994. sign->SetSignType(SIGN_TYPE_GENERIC);
  995. else if(strncasecmp(row[13],"Zone", 4) == 0)
  996. sign->SetSignType(SIGN_TYPE_ZONE);
  997. sign->SetSignTitle(row[14]);
  998. sign->SetSignDescription(row[15]);
  999. sign->SetSignDistance(atof(row[16]));
  1000. sign->SetSignZoneID(atoul(row[17]));
  1001. sign->SetSignZoneX(atof(row[18]));
  1002. sign->SetSignZoneY(atof(row[19]));
  1003. sign->SetSignZoneZ(atof(row[20]));
  1004. sign->SetSignZoneHeading(atof(row[21]));
  1005. sign->SetIncludeHeading(atoi(row[22]) == 1);
  1006. sign->SetIncludeLocation(atoi(row[23]) == 1);
  1007. sign->SetTransporterID(atoul(row[24]));
  1008. sign->SetSizeOffset(atoi(row[25]));
  1009. sign->appearance.display_hand_icon = atoi(row[26]);
  1010. sign->SetVisualState(atoi(row[27]));
  1011. zone->AddSign(id, sign);
  1012. total++;
  1013. LogWrite(SIGN__DEBUG, 5, "Sign", "---Loading Sign: '%s' (%u).", sign->appearance.name, id);
  1014. }
  1015. LogWrite(SIGN__DEBUG, 0, "Sign", "--Loaded %i Sign(s)", total);
  1016. }
  1017. void WorldDatabase::LoadWidgets(ZoneServer* zone){
  1018. Query query;
  1019. MYSQL_ROW row;
  1020. Widget* widget = 0;
  1021. int32 id = 0;
  1022. int32 total = 0;
  1023. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT sw.spawn_id, s.name, s.model_type, s.size, s.show_command_icon, sw.widget_id, sw.widget_x, sw.widget_y, sw.widget_z, s.command_primary, s.command_secondary, s.collision_radius, sw.include_heading, sw.include_location, sw.icon, sw.type, sw.open_heading, sw.open_y, sw.action_spawn_id, sw.open_sound_file, sw.close_sound_file, sw.open_duration, sw.closed_heading, sw.linked_spawn_id, sw.close_y, s.transport_id, s.size_offset, sw.house_id, sw.open_x, sw.open_z, sw.close_x, sw.close_z, s.display_hand_icon, s.expansion_flag\n"
  1024. "FROM spawn s\n"
  1025. "INNER JOIN spawn_widgets sw\n"
  1026. "ON s.id = sw.spawn_id\n"
  1027. "INNER JOIN spawn_location_entry le\n"
  1028. "ON sw.spawn_id = le.spawn_id\n"
  1029. "INNER JOIN spawn_location_placement lp\n"
  1030. "ON le.spawn_location_id = lp.spawn_location_id\n"
  1031. "WHERE lp.zone_id = %u\n"
  1032. "GROUP BY s.id",
  1033. zone->GetZoneID());
  1034. while(result && (row = mysql_fetch_row(result))){
  1035. int32 widgetXpackFlag = atoul(row[32]);
  1036. if (!CheckExpansionFlags(zone, widgetXpackFlag))
  1037. continue;
  1038. id = atoul(row[0]);
  1039. if(zone->GetWidget(id, true))
  1040. continue;
  1041. widget = new Widget();
  1042. widget->SetDatabaseID(id);
  1043. strcpy(widget->appearance.name, row[1]);
  1044. widget->appearance.model_type = atoi(row[2]);
  1045. widget->SetSize(atoi(row[3]));
  1046. widget->appearance.show_command_icon = atoi(row[4]);
  1047. if (row[5] == NULL)
  1048. widget->SetWidgetID(0xFFFFFFFF);
  1049. else
  1050. widget->SetWidgetID(atoul(row[5]));
  1051. widget->SetWidgetX(atof(row[6]));
  1052. widget->SetWidgetY(atof(row[7]));
  1053. widget->SetWidgetZ(atof(row[8]));
  1054. vector<EntityCommand*>* primary_command_list = zone->GetEntityCommandList(atoul(row[9]));
  1055. if(primary_command_list){
  1056. widget->SetPrimaryCommands(primary_command_list);
  1057. widget->primary_command_list_id = atoul(row[9]);
  1058. }
  1059. vector<EntityCommand*>* secondary_command_list = zone->GetEntityCommandList(atoul(row[10]));
  1060. if (secondary_command_list) {
  1061. widget->SetSecondaryCommands(secondary_command_list);
  1062. widget->secondary_command_list_id = atoul(row[10]);
  1063. }
  1064. widget->appearance.pos.collision_radius = atoi(row[11]);
  1065. widget->SetIncludeHeading(atoi(row[12]) == 1);
  1066. widget->SetIncludeLocation(atoi(row[13]) == 1);
  1067. widget->SetWidgetIcon(atoi(row[14]));
  1068. if (strncasecmp(row[15], "Generic", 7) == 0)
  1069. widget->SetWidgetType(WIDGET_TYPE_GENERIC);
  1070. else if (strncasecmp(row[15], "Door", 4) == 0)
  1071. widget->SetWidgetType(WIDGET_TYPE_DOOR);
  1072. else if (strncasecmp(row[15], "Lift", 4) == 0)
  1073. widget->SetWidgetType(WIDGET_TYPE_LIFT);
  1074. widget->SetOpenHeading(atof(row[16]));
  1075. widget->SetOpenY(atof(row[17]));
  1076. widget->SetActionSpawnID(atoul(row[18]));
  1077. if(row[19] && strlen(row[19]) > 5)
  1078. widget->SetOpenSound(row[19]);
  1079. if(row[20] && strlen(row[20]) > 5)
  1080. widget->SetCloseSound(row[20]);
  1081. widget->SetOpenDuration(atoi(row[21]));
  1082. widget->SetClosedHeading(atof(row[22]));
  1083. widget->SetLinkedSpawnID(atoul(row[23]));
  1084. widget->SetCloseY(atof(row[24]));
  1085. widget->SetTransporterID(atoul(row[25]));
  1086. widget->SetSizeOffset(atoi(row[26]));
  1087. widget->SetHouseID(atoul(row[27]));
  1088. widget->SetOpenX(atof(row[28]));
  1089. widget->SetOpenZ(atof(row[29]));
  1090. widget->SetCloseX(atof(row[30]));
  1091. widget->SetCloseZ(atof(row[31]));
  1092. widget->appearance.display_hand_icon = atoi(row[32]);
  1093. zone->AddWidget(id, widget);
  1094. total++;
  1095. LogWrite(WIDGET__DEBUG, 5, "Widget", "---Loading Widget: '%s' (%u).", widget->appearance.name, id);
  1096. }
  1097. LogWrite(WIDGET__DEBUG, 0, "Widget", "--Loaded %i Widget(s)", total);
  1098. }
  1099. void WorldDatabase::LoadObjects(ZoneServer* zone){
  1100. Query query;
  1101. MYSQL_ROW row;
  1102. Object* object = 0;
  1103. int32 id = 0;
  1104. int32 total = 0;
  1105. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT so.spawn_id, s.name, s.race, s.model_type, s.command_primary, s.command_secondary, s.targetable, s.size, s.show_name, s.visual_state, s.attackable, s.show_level, s.show_command_icon, s.display_hand_icon, s.faction_id, s.collision_radius, s.transport_id, s.size_offset, so.device_id, s.expansion_flag\n"
  1106. "FROM spawn s\n"
  1107. "INNER JOIN spawn_objects so\n"
  1108. "ON s.id = so.spawn_id\n"
  1109. "INNER JOIN spawn_location_entry le\n"
  1110. "ON so.spawn_id = le.spawn_id\n"
  1111. "INNER JOIN spawn_location_placement lp\n"
  1112. "ON le.spawn_location_id = lp.spawn_location_id\n"
  1113. "WHERE lp.zone_id = %u and (lp.instance_id = 0 or lp.instance_id = %u)\n"
  1114. "GROUP BY s.id",
  1115. zone->GetZoneID(), zone->GetInstanceID());
  1116. while(result && (row = mysql_fetch_row(result))){
  1117. int32 objXpackFlag = atoul(row[19]);
  1118. if (!CheckExpansionFlags(zone, objXpackFlag))
  1119. continue;
  1120. id = atoul(row[0]);
  1121. if(zone->GetObject(id, true))
  1122. continue;
  1123. object = new Object();
  1124. object->SetDatabaseID(id);
  1125. strcpy(object->appearance.name, row[1]);
  1126. vector<EntityCommand*>* primary_command_list = zone->GetEntityCommandList(atoul(row[4]));
  1127. vector<EntityCommand*>* secondary_command_list = zone->GetEntityCommandList(atoul(row[5]));
  1128. if(primary_command_list){
  1129. object->SetPrimaryCommands(primary_command_list);
  1130. object->primary_command_list_id = atoul(row[4]);
  1131. }
  1132. if(secondary_command_list){
  1133. object->SetSecondaryCommands(secondary_command_list);
  1134. object->secondary_command_list_id = atoul(row[5]);
  1135. }
  1136. object->appearance.race = atoi(row[2]);
  1137. object->appearance.model_type = atoi(row[3]);
  1138. object->appearance.targetable = atoi(row[6]);
  1139. object->size = atoi(row[7]);
  1140. object->appearance.display_name = atoi(row[8]);
  1141. object->appearance.visual_state = atoi(row[9]);
  1142. object->appearance.attackable = atoi(row[10]);
  1143. object->appearance.show_level = atoi(row[11]);
  1144. object->appearance.show_command_icon = atoi(row[12]);
  1145. object->appearance.display_hand_icon = atoi(row[13]);
  1146. object->faction_id = atoul(row[14]);
  1147. object->appearance.pos.collision_radius = atoi(row[15]);
  1148. object->SetTransporterID(atoul(row[16]));
  1149. object->SetSizeOffset(atoi(row[17]));
  1150. object->SetDeviceID(atoi(row[18]));
  1151. zone->AddObject(id, object);
  1152. total++;
  1153. LogWrite(OBJECT__DEBUG, 5, "Object", "---Loading Object: '%s' (%u)", object->appearance.name, id);
  1154. }
  1155. LogWrite(OBJECT__DEBUG, 0, "Object", "--Loaded %i Object(s)", total);
  1156. }
  1157. void WorldDatabase::LoadGroundSpawns(ZoneServer* zone){
  1158. Query query;
  1159. MYSQL_ROW row;
  1160. GroundSpawn* spawn = 0;
  1161. int32 id = 0;
  1162. int32 total = 0;
  1163. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT sg.spawn_id, s.name, s.race, s.model_type, s.command_primary, s.command_secondary, s.targetable, s.size, s.show_name, s.visual_state, s.attackable, s.show_level, s.show_command_icon, s.display_hand_icon, s.faction_id, s.collision_radius, sg.number_harvests, sg.num_attempts_per_harvest, sg.groundspawn_id, sg.collection_skill, s.size_offset, s.expansion_flag\n"
  1164. "FROM spawn s\n"
  1165. "INNER JOIN spawn_ground sg\n"
  1166. "ON s.id = sg.spawn_id\n"
  1167. "INNER JOIN spawn_location_entry le\n"
  1168. "ON sg.spawn_id = le.spawn_id\n"
  1169. "INNER JOIN spawn_location_placement lp\n"
  1170. "ON le.spawn_location_id = lp.spawn_location_id\n"
  1171. "WHERE lp.zone_id = %u\n"
  1172. "GROUP BY s.id",
  1173. zone->GetZoneID());
  1174. while(result && (row = mysql_fetch_row(result))){
  1175. int32 gsXpackFlag = atoul(row[21]);
  1176. if (!CheckExpansionFlags(zone, gsXpackFlag))
  1177. continue;
  1178. id = atoul(row[0]);
  1179. if(zone->GetGroundSpawn(id, true))
  1180. continue;
  1181. spawn = new GroundSpawn();
  1182. spawn->SetDatabaseID(id);
  1183. spawn->forceMapCheck = true;
  1184. strcpy(spawn->appearance.name, row[1]);
  1185. vector<EntityCommand*>* primary_command_list = zone->GetEntityCommandList(atoul(row[4]));
  1186. vector<EntityCommand*>* secondary_command_list = zone->GetEntityCommandList(atoul(row[5]));
  1187. if(primary_command_list){
  1188. spawn->SetPrimaryCommands(primary_command_list);
  1189. spawn->primary_command_list_id = atoul(row[4]);
  1190. }
  1191. if(secondary_command_list){
  1192. spawn->SetSecondaryCommands(secondary_command_list);
  1193. spawn->secondary_command_list_id = atoul(row[5]);
  1194. }
  1195. spawn->appearance.race = atoi(row[2]);
  1196. spawn->appearance.model_type = atoi(row[3]);
  1197. spawn->appearance.targetable = atoi(row[6]);
  1198. spawn->size = atoi(row[7]);
  1199. spawn->appearance.display_name = atoi(row[8]);
  1200. spawn->appearance.visual_state = atoi(row[9]);
  1201. spawn->appearance.attackable = atoi(row[10]);
  1202. spawn->appearance.show_level = atoi(row[11]);
  1203. spawn->appearance.show_command_icon = atoi(row[12]);
  1204. spawn->appearance.display_hand_icon = atoi(row[13]);
  1205. spawn->faction_id = atoul(row[14]);
  1206. spawn->appearance.pos.collision_radius = atoi(row[15]);
  1207. spawn->SetNumberHarvests(atoi(row[16]));
  1208. spawn->SetAttemptsPerHarvest(atoi(row[17]));
  1209. spawn->SetGroundSpawnEntryID(atoul(row[18]));
  1210. spawn->SetCollectionSkill(row[19]);
  1211. spawn->SetSizeOffset(atoi(row[20]));
  1212. zone->AddGroundSpawn(id, spawn);
  1213. total++;
  1214. LogWrite(GROUNDSPAWN__DEBUG, 5, "GSpawn", "---Loading GroundSpawn: '%s' (%u)", spawn->appearance.name, id);
  1215. }
  1216. LogWrite(GROUNDSPAWN__DEBUG, 0, "GSpawn", "--Loaded %i GroundSpawn(s)", total);
  1217. }
  1218. void WorldDatabase::LoadGroundSpawnItems(ZoneServer* zone) {
  1219. Query query;
  1220. MYSQL_ROW row;
  1221. int32 total = 0;
  1222. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT groundspawn_id, item_id, is_rare, grid_id FROM groundspawn_items;");
  1223. while(result && (row = mysql_fetch_row(result)))
  1224. {
  1225. zone->AddGroundSpawnItem(atoul(row[0]), atoul(row[1]), atoi(row[2]), atoul(row[3]));
  1226. LogWrite(GROUNDSPAWN__DEBUG, 5, "GSpawn", "---Loading GroundSpawn Items: ID: %u\n", atoul(row[0]));
  1227. LogWrite(GROUNDSPAWN__DEBUG, 5, "GSpawn", "---item: %ul, rare: %i, grid: %ul", atoul(row[1]), atoi(row[2]), atoul(row[3]));
  1228. total++;
  1229. }
  1230. LogWrite(GROUNDSPAWN__DEBUG, 0, "GSpawn", "--Loaded %i GroundSpawn Item%s.", total, total == 1 ? "" : "s");
  1231. }
  1232. void WorldDatabase::LoadGroundSpawnEntries(ZoneServer* zone) {
  1233. Query query;
  1234. MYSQL_ROW row;
  1235. int32 total = 0;
  1236. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT groundspawn_id, min_skill_level, min_adventure_level, bonus_table, harvest1, harvest3, harvest5, harvest_imbue, harvest_rare, harvest10, harvest_coin FROM groundspawns WHERE enabled = 1;");
  1237. while(result && (row = mysql_fetch_row(result)))
  1238. {
  1239. // this is getting ridonkulous...
  1240. LogWrite(GROUNDSPAWN__DEBUG, 5, "GSpawn", "---Loading GroundSpawn ID: %u\n" \
  1241. "---min_skill_level: %i, min_adventure_level: %i, bonus_table: %i\n" \
  1242. "---harvest1: %.2f, harvest3: %.2f, harvest5: %.2f\n" \
  1243. "---harvest_imbue: %.2f, harvest_rare: %.2f, harvest10: %.2f\n" \
  1244. "---harvest_coin: %u", atoul(row[0]), atoi(row[1]), atoi(row[2]), atoi(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atof(row[8]), atof(row[9]), atoul(row[10]));
  1245. zone->AddGroundSpawnEntry(atoul(row[0]), atoi(row[1]), atoi(row[2]), atoi(row[3]), atof(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atof(row[8]), atof(row[9]), atoul(row[10]));
  1246. total++;
  1247. }
  1248. LogWrite(GROUNDSPAWN__DEBUG, 0, "GSpawn", "--Loaded %i GroundSpawn Entr%s.", total, total == 1 ? "y" : "ies");
  1249. LoadGroundSpawnItems(zone);
  1250. }
  1251. bool WorldDatabase::LoadCharacterStats(int32 id, int32 account_id, Client* client)
  1252. {
  1253. DatabaseResult result;
  1254. if( database_new.Select(&result, "SELECT * FROM character_details WHERE char_id = %i LIMIT 0, 1", id) )
  1255. {
  1256. LogWrite(PLAYER__DEBUG, 0, "Player", "Loading character_details for '%s' (char_id: %u)", client->GetPlayer()->GetName(), id);
  1257. while( result.Next() )
  1258. {
  1259. InfoStruct* info = client->GetPlayer()->GetInfoStruct();
  1260. client->GetPlayer()->SetHP(result.GetSInt32Str("hp"));
  1261. client->GetPlayer()->SetPower(result.GetSInt32Str("power"));
  1262. info->max_concentration = result.GetInt8Str("max_concentration");
  1263. info->attack_base = result.GetInt16Str("attack");
  1264. info->mitigation_base = result.GetInt16Str("mitigation");
  1265. info->avoidance_base = result.GetInt16Str("avoidance");
  1266. info->parry_base = result.GetInt16Str("parry");
  1267. info->deflection_base = result.GetInt16Str("deflection");
  1268. info->block_base = result.GetInt16Str("block");
  1269. info->str_base = result.GetInt16Str("str");
  1270. info->sta_base = result.GetInt16Str("sta");
  1271. info->agi_base = result.GetInt16Str("agi");
  1272. info->wis_base = result.GetInt16Str("wis");
  1273. info->intel_base = result.GetInt16Str("intel");
  1274. // old resist types
  1275. info->heat_base = result.GetInt16Str("heat");
  1276. info->cold_base = result.GetInt16Str("cold");
  1277. info->magic_base = result.GetInt16Str("magic");
  1278. info->mental_base = result.GetInt16Str("mental");
  1279. info->divine_base = result.GetInt16Str("divine");
  1280. info->disease_base = result.GetInt16Str("disease");
  1281. info->poison_base = result.GetInt16Str("poison");
  1282. //
  1283. info->coin_copper = result.GetInt32Str("coin_copper");
  1284. info->coin_silver = result.GetInt32Str("coin_silver");
  1285. info->coin_gold = result.GetInt32Str("coin_gold");
  1286. info->coin_plat = result.GetInt32Str("coin_plat");
  1287. strcpy(info->pet_name, result.GetStringStr("pet_name"));
  1288. strcpy(info->biography, result.GetStringStr("biography"));
  1289. info->status_points = result.GetInt32Str("status_points");
  1290. client->GetPlayer()->GetPlayerInfo()->SetBindZone(result.GetInt32Str("bind_zone_id"));
  1291. client->GetPlayer()->GetPlayerInfo()->SetBindX(result.GetFloatStr("bind_x"));
  1292. client->GetPlayer()->GetPlayerInfo()->SetBindY(result.GetFloatStr("bind_y"));
  1293. client->GetPlayer()->GetPlayerInfo()->SetBindZ(result.GetFloatStr("bind_z"));
  1294. client->GetPlayer()->GetPlayerInfo()->SetBindHeading(result.GetFloatStr("bind_heading"));
  1295. client->GetPlayer()->GetPlayerInfo()->SetHouseZone(result.GetInt32Str("house_zone_id"));
  1296. client->GetPlayer()->SetTotalHP(result.GetSInt32Str("max_hp"));
  1297. client->GetPlayer()->SetTotalPower(result.GetSInt32Str("max_power"));
  1298. client->GetPlayer()->SetAssignedAA(result.GetInt16Str("assigned_aa"));
  1299. client->GetPlayer()->SetUnassignedAA(result.GetInt16Str("unassigned_aa"));
  1300. client->GetPlayer()->SetTradeskillAA(result.GetInt16Str("tradeskill_aa"));
  1301. client->GetPlayer()->SetUnassignedTradeskillAA(result.GetInt16Str("unassigned_tradeskill_aa"));
  1302. client->GetPlayer()->SetPrestigeAA(result.GetInt16Str("prestige_aa"));
  1303. client->GetPlayer()->SetUnassignedPrestigeAA(result.GetInt16Str("unassigned_prestige_aa"));
  1304. client->GetPlayer()->SetTradeskillPrestigeAA(result.GetInt16Str("tradeskill_prestige_aa"));
  1305. client->GetPlayer()->SetUnassignedTradeskillPrestigeAA(result.GetInt16Str("unassigned_tradeskill_prestige_aa"));
  1306. info->xp = result.GetInt32Str("xp");
  1307. info->xp_needed = result.GetInt32Str("xp_needed");
  1308. if(info->xp_needed == 0)
  1309. client->GetPlayer()->SetNeededXP();
  1310. info->xp_debt = result.GetInt32Str("xp_debt");
  1311. info->xp_vitality = result.GetFloatStr("xp_vitality");
  1312. info->ts_xp = result.GetInt32Str("tradeskill_xp");
  1313. info->ts_xp_needed = result.GetInt32Str("tradeskill_xp_needed");
  1314. if (info->ts_xp_needed == 0)
  1315. client->GetPlayer()->SetNeededTSXP();
  1316. info->tradeskill_xp_vitality = result.GetFloatStr("tradeskill_xp_vitality");
  1317. client->GetPlayer()->SetTotalHPBase(client->GetPlayer()->GetTotalHP());
  1318. client->GetPlayer()->SetTotalPowerBase(client->GetPlayer()->GetTotalPower());
  1319. info->bank_coin_copper = result.GetInt32Str("bank_copper");
  1320. info->bank_coin_silver = result.GetInt32Str("bank_silver");
  1321. info->bank_coin_gold = result.GetInt32Str("bank_gold");
  1322. info->bank_coin_plat = result.GetInt32Str("bank_plat");
  1323. client->GetPlayer()->SetCombatVoice(result.GetInt16Str("combat_voice"));
  1324. client->GetPlayer()->SetEmoteVoice(result.GetInt16Str("emote_voice"));
  1325. client->GetPlayer()->SetBiography(result.GetStringStr("biography"));
  1326. client->GetPlayer()->GetInfoStruct()->flags = result.GetInt32Str("flags");
  1327. client->GetPlayer()->GetInfoStruct()->flags2 = result.GetInt32Str("flags2");
  1328. client->GetPlayer()->SetLastName(result.GetStringStr("last_name"));
  1329. // new resist types
  1330. info->elemental_base = result.GetInt16Str("elemental");
  1331. info->arcane_base = result.GetInt16Str("arcane");
  1332. info->noxious_base = result.GetInt16Str("noxious");
  1333. // new savagery and dissonance
  1334. client->GetPlayer()->SetSavagery(result.GetSInt16Str("savagery"));
  1335. client->GetPlayer()->SetDissonance(result.GetSInt16Str("dissonance"));
  1336. client->GetPlayer()->SetTotalSavageryBase(client->GetPlayer()->GetTotalSavagery());
  1337. client->GetPlayer()->SetTotalDissonanceBase(client->GetPlayer()->GetTotalDissonance());
  1338. }
  1339. return true;
  1340. }
  1341. else
  1342. {
  1343. LogWrite(PLAYER__ERROR, 0, "Player", "Error loading character_details for '%s' (char_id: %u)", client->GetPlayer()->GetName(), id);
  1344. return false;
  1345. }
  1346. }
  1347. bool WorldDatabase::loadCharacter(const char* ch_name, int32 account_id, Client* client){
  1348. Query query, query4;
  1349. MYSQL_ROW row, row4;
  1350. int32 id = 0;
  1351. query.escaped_name = getEscapeString(ch_name);
  1352. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, current_zone_id, x, y, z, heading, admin_status, race, model_type, class, deity, level, gender, tradeskill_class, tradeskill_level, wing_type, hair_type, chest_type, legs_type, soga_wing_type, soga_hair_type, soga_chest_type, soga_legs_type, 0xFFFFFFFF - crc32(name), facial_hair_type, soga_facial_hair_type,instance_id,last_saved, DATEDIFF(curdate(), created_date) as accage FROM characters where name='%s' and account_id=%i AND deleted = 0", query.escaped_name, account_id);
  1353. // no character found
  1354. if ( result == NULL ) {
  1355. LogWrite(PLAYER__ERROR, 0, "Player", "Error loading character for '%s'", ch_name);
  1356. return false;
  1357. }
  1358. if (mysql_num_rows(result) == 1){
  1359. row = mysql_fetch_row(result);
  1360. id = strtoul(row[0], NULL, 0);
  1361. LogWrite(PLAYER__DEBUG, 0, "Player", "Loading character for '%s' (char_id: %u)", ch_name, id);
  1362. client->SetCharacterID(id);
  1363. client->GetPlayer()->SetCharacterID(id);
  1364. client->SetAccountID(account_id);
  1365. client->GetPlayer()->SetName(ch_name);
  1366. client->GetPlayer()->SetX(atof(row[2]));
  1367. client->GetPlayer()->SetY(atof(row[3]));
  1368. client->GetPlayer()->SetZ(atof(row[4]));
  1369. client->GetPlayer()->SetHeading(atof(row[5]));
  1370. client->SetAdminStatus(atoi(row[6]));
  1371. client->GetPlayer()->SetRace(atoi(row[7]));
  1372. client->GetPlayer()->SetModelType(atoi(row[8]));
  1373. client->GetPlayer()->SetAdventureClass(atoi(row[9]));
  1374. client->GetPlayer()->SetDeity(atoi(row[10]));
  1375. client->GetPlayer()->SetLevel(atoi(row[11]));
  1376. client->GetPlayer()->SetGender(atoi(row[12]));
  1377. client->GetPlayer()->SetTradeskillClass(atoi(row[13]));
  1378. client->GetPlayer()->SetTSLevel(atoi(row[14]));
  1379. LogWrite(MISC__TODO, 1, "TODO", "Fix client->GetPlayer()->SetArtLevel(atoi(row[14]));\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
  1380. client->GetPlayer()->features.wing_type = atoi(row[15]);
  1381. client->GetPlayer()->features.hair_type = atoi(row[16]);
  1382. client->GetPlayer()->features.chest_type = atoi(row[17]);
  1383. client->GetPlayer()->features.legs_type = atoi(row[18]);
  1384. LogWrite(MISC__TODO, 1, "TODO", "Fix SOGA appearances here\n\t(%s, function: %s, line #: %i)", __FILE__, __FUNCTION__, __LINE__);
  1385. client->GetPlayer()->features.wing_type = atoi(row[19]);
  1386. client->GetPlayer()->features.soga_hair_type = atoi(row[20]);
  1387. client->GetPlayer()->features.soga_chest_type = atoi(row[21]);
  1388. client->GetPlayer()->features.soga_legs_type = atoi(row[22]);
  1389. client->SetNameCRC(atoul(row[23]));
  1390. client->GetPlayer()->features.hair_face_type = atoi(row[24]);
  1391. client->GetPlayer()->features.soga_hair_face_type = atoi(row[25]);
  1392. int32 instanceid = atoi(row[26]);
  1393. int32 zoneid = atoul(row[1]);
  1394. /*
  1395. JA Notes on SOGA: I think there are many more settings to add than were commented out here,
  1396. because I can load a SOGA model player, but some features are missing (Barbarian WOAD, Skin tons, etc)
  1397. SOGA chars looked ok in LoginServer screen tho... odd.
  1398. */
  1399. // load character instances here
  1400. if ( LoadCharacterInstances(client) )
  1401. client->UpdateCharacterInstances();
  1402. if ( instanceid > 0 )
  1403. client->SetCurrentZoneByInstanceID(instanceid, zoneid);
  1404. else
  1405. client->SetCurrentZone(zoneid);
  1406. int32 lastsavedtime = atoi(row[27]);
  1407. client->SetLastSavedTimeStamp(lastsavedtime);
  1408. if (row[28])
  1409. client->GetPlayer()->GetPlayerInfo()->SetAccountAge(atoi(row[28]));
  1410. LoadCharacterFriendsIgnoreList(client->GetPlayer());
  1411. MYSQL_RES* result4 = query4.RunQuery2(Q_SELECT, "SELECT `guild_id` FROM `guild_members` WHERE `char_id`=%u", id);
  1412. if (result4 && (row4 = mysql_fetch_row(result4))) {
  1413. Guild* guild = guild_list.GetGuild(atoul(row4[0]));
  1414. if (guild) {
  1415. client->GetPlayer()->SetGuild(guild);
  1416. string subtitle;
  1417. subtitle.append("<").append(guild->GetName()).append(">");
  1418. client->GetPlayer()->SetSubTitle(subtitle.c_str());
  1419. }
  1420. }
  1421. LoadCharacterHistory(id, client->GetPlayer());
  1422. LoadCharacterLUAHistory(id, client->GetPlayer());
  1423. LoadPlayerStatistics(client->GetPlayer(), id);
  1424. LoadPlayerCollections(client->GetPlayer());
  1425. LoadPlayerRecipes(client->GetPlayer());
  1426. //LoadPlayerAchievements(client->GetPlayer());
  1427. LoadPlayerAchievementsUpdates(client->GetPlayer());
  1428. LoadAppearances(client->GetCurrentZone(), client);
  1429. return LoadCharacterStats(id, account_id, client);
  1430. }
  1431. // should not be here...
  1432. LogWrite(PLAYER__ERROR, 0, "Player", "Error loading character for '%s'", ch_name);
  1433. return false;
  1434. }
  1435. bool WorldDatabase::InsertCharacterStats(int32 character_id, int8 class_id, int8 race_id){
  1436. Query query1;
  1437. Query query2;
  1438. Query query3;
  1439. Query query4;
  1440. Query query5;
  1441. /* Blank record */
  1442. query1.RunQuery2(Q_INSERT, "INSERT INTO `character_details` (`char_id`) VALUES (%u)", character_id);
  1443. /* Using the class id and race id */
  1444. query2.RunQuery2(Q_UPDATE, "UPDATE character_details c, starting_details s SET c.max_hp = s.max_hp, c.hp = s.max_hp, c.max_power = s.max_power, c.power = s.max_power, c.str = s.str, c.sta = s.sta, c.agi = s.agi, c.wis = s.wis, c.intel = s.intel,c.heat = s.heat, c.cold = s.cold, c.magic = s.magic, c.mental = s.mental, c.divine = s.divine, c.disease = s.disease, c.poison = s.poison, c.coin_copper = s.coin_copper, c.coin_silver = s.coin_silver, c.coin_gold = s.coin_gold, c.coin_plat = s.coin_plat, c.status_points = s.status_points WHERE s.race_id = %d AND class_id = %d AND char_id = %u", race_id, class_id, character_id);
  1445. if (query2.GetAffectedRows() > 0)
  1446. return true;
  1447. /* Using the class id and race id = 255 */
  1448. query3.RunQuery2(Q_UPDATE, "UPDATE character_details c, starting_details s SET c.max_hp = s.max_hp, c.hp = s.max_hp, c.max_power = s.max_power, c.power = s.max_power, c.str = s.str, c.sta = s.sta, c.agi = s.agi, c.wis = s.wis, c.intel = s.intel,c.heat = s.heat, c.cold = s.cold, c.magic = s.magic, c.mental = s.mental, c.divine = s.divine, c.disease = s.disease, c.poison = s.poison, c.coin_copper = s.coin_copper, c.coin_silver = s.coin_silver, c.coin_gold = s.coin_gold, c.coin_plat = s.coin_plat, c.status_points = s.status_points WHERE s.race_id = 255 AND class_id = %d AND char_id = %u", class_id, character_id);
  1449. if (query3.GetAffectedRows() > 0)
  1450. return true;
  1451. /* Using class id = 255 and the race id */
  1452. query4.RunQuery2(Q_UPDATE, "UPDATE character_details c, starting_details s SET c.max_hp = s.max_hp, c.hp = s.max_hp, c.max_power = s.max_power, c.power = s.max_power, c.str = s.str, c.sta = s.sta, c.agi = s.agi, c.wis = s.wis, c.intel = s.intel,c.heat = s.heat, c.cold = s.cold, c.magic = s.magic, c.mental = s.mental, c.divine = s.divine, c.disease = s.disease, c.poison = s.poison, c.coin_copper = s.coin_copper, c.coin_silver = s.coin_silver, c.coin_gold = s.coin_gold, c.coin_plat = s.coin_plat, c.status_points = s.status_points WHERE s.race_id = %d AND class_id = 255 AND char_id = %u", race_id, character_id);
  1453. if (query4.GetAffectedRows() > 0)
  1454. return true;
  1455. /* Using class id = 255 and race id = 255 */
  1456. query5.RunQuery2(Q_UPDATE, "UPDATE character_details c, starting_details s SET c.max_hp = s.max_hp, c.hp = s.max_hp, c.max_power = s.max_power, c.power = s.max_power, c.str = s.str, c.sta = s.sta, c.agi = s.agi, c.wis = s.wis, c.intel = s.intel,c.heat = s.heat, c.cold = s.cold, c.magic = s.magic, c.mental = s.mental, c.divine = s.divine, c.disease = s.disease, c.poison = s.poison, c.coin_copper = s.coin_copper, c.coin_silver = s.coin_silver, c.coin_gold = s.coin_gold, c.coin_plat = s.coin_plat, c.status_points = s.status_points WHERE s.race_id = 255 AND class_id = 255 AND char_id = %u", character_id);
  1457. if (query5.GetAffectedRows() > 0)
  1458. return true;
  1459. return false;
  1460. }
  1461. int32 WorldDatabase::GetCharacterTimeStamp(int32 character_id, int32 account_id,bool* char_exists){
  1462. Query query;
  1463. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT unix_timestamp FROM characters where id=%i and account_id=%i",character_id,account_id);
  1464. if(result && mysql_num_rows(result) > 0) {
  1465. MYSQL_ROW row;
  1466. row = mysql_fetch_row(result);
  1467. *char_exists = true;
  1468. return atoi(row[0]); // Return timestamp
  1469. }
  1470. else
  1471. LogWrite(WORLD__ERROR, 0, "World", "Error in GetCharacterTimeStamp query '%s': %s", query.GetQuery(), query.GetError());
  1472. *char_exists = false;
  1473. return 0;
  1474. }
  1475. int32 WorldDatabase::GetCharacterTimeStamp(int32 character_id) {
  1476. Query query;
  1477. MYSQL_ROW row;
  1478. MYSQL_RES *result = query.RunQuery2(Q_SELECT, "SELECT unix_timestamp FROM characters WHERE id=%u", character_id);
  1479. int32 ret = 0;
  1480. if (result && (row = mysql_fetch_row(result)))
  1481. ret = atoul(row[0]);
  1482. return ret;
  1483. }
  1484. bool WorldDatabase::UpdateCharacterTimeStamp(int32 account_id, int32 character_id, int32 timestamp_update){
  1485. Query query;
  1486. string update_charts = string("update characters set unix_timestamp=%i where id=%i and account_id=%i");
  1487. query.RunQuery2(Q_UPDATE, update_charts.c_str(),timestamp_update,character_id,account_id);
  1488. if(!query.GetAffectedRows())
  1489. {
  1490. LogWrite(WORLD__ERROR, 0, "World", "Error in UpdateCharacterTimeStamp query '%s': %s", query.GetQuery(), query.GetError());
  1491. return false;
  1492. }
  1493. return true;
  1494. }
  1495. bool WorldDatabase::insertCharacterProperty(Client* client, char* propName, char* propValue) {
  1496. Query query;
  1497. string update_status = string("update charactersProperties set propvalue='%s' where charid=%i and propname='%s'");
  1498. query.RunQuery2(Q_UPDATE, update_status.c_str(), propValue, client->GetCharacterID(), propName);
  1499. if (!query.GetAffectedRows())
  1500. {
  1501. query.RunQuery2(Q_UPDATE, "insert into charactersProperties (charid, propname, propvalue) values(%i, '%s', '%s')", client->GetCharacterID(), propName, propValue);
  1502. if (query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF) {
  1503. LogWrite(WORLD__ERROR, 0, "World", "Error in insertCharacterProperty query '%s': %s", query.GetQuery(), query.GetError());
  1504. return false;
  1505. }
  1506. }
  1507. return true;
  1508. }
  1509. bool WorldDatabase::loadCharacterProperties(Client* client) {
  1510. Query query;
  1511. MYSQL_ROW row;
  1512. int32 id = 0;
  1513. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT propname, propvalue FROM charactersProperties where charid = %i", client->GetCharacterID());
  1514. // no character found
  1515. if (result == NULL) {
  1516. LogWrite(PLAYER__ERROR, 0, "Player", "Error loading character properties for '%s'", client->GetPlayer()->GetName());
  1517. return false;
  1518. }
  1519. while (result && (row = mysql_fetch_row(result))) {
  1520. char* prop_name = row[0];
  1521. char* prop_value = row[1];
  1522. if (!prop_name || !prop_value)
  1523. continue;
  1524. if (!stricmp(prop_name, CHAR_PROPERTY_SPEED))
  1525. {
  1526. float new_speed = atof(prop_value);
  1527. client->GetPlayer()->SetSpeed(new_speed,true);
  1528. client->GetPlayer()->SetCharSheetChanged(true);
  1529. }
  1530. else if (!stricmp(prop_name, CHAR_PROPERTY_FLYMODE))
  1531. {
  1532. int8 flymode = atoi(prop_value);
  1533. if (flymode) // avoid fly mode notification unless enabled
  1534. ClientPacketFunctions::SendFlyMode(client, flymode, false);
  1535. }
  1536. else if (!stricmp(prop_name, CHAR_PROPERTY_INVUL))
  1537. {
  1538. int8 invul = atoi(prop_value);
  1539. client->GetPlayer()->SetInvulnerable(invul == 1);
  1540. if (client->GetPlayer()->GetInvulnerable())
  1541. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You are now invulnerable!");
  1542. }
  1543. else if (!stricmp(prop_name, CHAR_PROPERTY_GMVISION))
  1544. {
  1545. int8 val = atoi(prop_value);
  1546. client->GetPlayer()->SetGMVision(val == 1);
  1547. client->GetCurrentZone()->SendAllSpawnsForVisChange(client, false);
  1548. if (val)
  1549. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "GM Vision Enabled!");
  1550. }
  1551. else if (!stricmp(prop_name, CHAR_PROPERTY_LUADEBUG))
  1552. {
  1553. int8 val = atoi(prop_value);
  1554. if (val)
  1555. {
  1556. client->SetLuaDebugClient(true);
  1557. if (lua_interface)
  1558. lua_interface->UpdateDebugClients(client);
  1559. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "You will now receive LUA error messages.");
  1560. }
  1561. }
  1562. }
  1563. return true;
  1564. }
  1565. //gets the name FROM the db with the right letters in caps
  1566. string WorldDatabase::GetPlayerName(char* name){
  1567. Query query;
  1568. string ret = "";
  1569. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT name FROM characters where name='%s'", getSafeEscapeString(name).c_str());
  1570. if(result && mysql_num_rows(result) > 0) {
  1571. MYSQL_ROW row;
  1572. row = mysql_fetch_row(result);
  1573. if(row[0])
  1574. ret = string(row[0]);
  1575. }
  1576. return ret;
  1577. }
  1578. int32 WorldDatabase::GetCharacterID(const char* name) {
  1579. int32 id = 0;
  1580. Query query;
  1581. if (name) {
  1582. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `id` FROM `characters` WHERE `name`='%s'", name);
  1583. if (result && mysql_num_rows(result) > 0) {
  1584. MYSQL_ROW row;
  1585. row = mysql_fetch_row(result);
  1586. id = atoul(row[0]);
  1587. }
  1588. }
  1589. return id;
  1590. }
  1591. int32 WorldDatabase::GetCharacterCurrentZoneID(int32 character_id) {
  1592. int32 id = 0;
  1593. Query query;
  1594. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `current_zone_id` FROM `characters` WHERE `id`=%u", character_id);
  1595. if (result && mysql_num_rows(result) > 0) {
  1596. MYSQL_ROW row;
  1597. row = mysql_fetch_row(result);
  1598. id = atoul(row[0]);
  1599. }
  1600. return id;
  1601. }
  1602. int32 WorldDatabase::GetCharacterAccountID(int32 character_id) {
  1603. int32 id = 0;
  1604. Query query;
  1605. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `account_id` FROM `characters` WHERE `id`=%u", character_id);
  1606. if (result && mysql_num_rows(result) > 0) {
  1607. MYSQL_ROW row;
  1608. row = mysql_fetch_row(result);
  1609. id = atoul(row[0]);
  1610. }
  1611. return id;
  1612. }
  1613. sint16 WorldDatabase::GetHighestCharacterAdminStatus(int32 account_id){
  1614. Query query;
  1615. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT max(admin_status) FROM characters where account_id=%i ",account_id);
  1616. if(result && mysql_num_rows(result) > 0) {
  1617. MYSQL_ROW row;
  1618. row = mysql_fetch_row(result);
  1619. if ( row[0] != NULL )
  1620. return atoi(row[0]); // Return characters status
  1621. else
  1622. return 0;
  1623. }
  1624. return 0;
  1625. }
  1626. sint16 WorldDatabase::GetLowestCharacterAdminStatus(int32 account_id){
  1627. Query query;
  1628. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT min(admin_status) FROM characters where account_id=%i ",account_id);
  1629. if(result && mysql_num_rows(result) > 0) {
  1630. MYSQL_ROW row;
  1631. row = mysql_fetch_row(result);
  1632. if ( row[0] != NULL )
  1633. return atoi(row[0]); // Return characters status
  1634. else
  1635. return 0;
  1636. }
  1637. return 0;
  1638. }
  1639. sint16 WorldDatabase::GetCharacterAdminStatus(char* character_name){
  1640. Query query;
  1641. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT admin_status FROM characters where name='%s'", getSafeEscapeString(character_name).c_str());
  1642. if(result && mysql_num_rows(result) > 0) {
  1643. MYSQL_ROW row;
  1644. row = mysql_fetch_row(result);
  1645. return atoi(row[0]); // Return characters level
  1646. }
  1647. else
  1648. LogWrite(WORLD__ERROR, 0, "World", "Error in GetCharacterAdminStatus query '%s': %s", query.GetQuery(), query.GetError());
  1649. return -10;
  1650. }
  1651. sint16 WorldDatabase::GetCharacterAdminStatus(int32 account_id , int32 char_id){
  1652. Query query;
  1653. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT admin_status FROM characters where account_id=%i and id=%i",account_id,char_id);
  1654. if(result && mysql_num_rows(result) > 0) {
  1655. MYSQL_ROW row;
  1656. row = mysql_fetch_row(result);
  1657. return atoi(row[0]); // Return characters status
  1658. }
  1659. else{
  1660. Query query2;
  1661. result = query2.RunQuery2(Q_SELECT, "SELECT count(id) FROM characters where account_id=%i and id=%i",account_id,char_id);
  1662. if(result && mysql_num_rows(result) > 0) {
  1663. MYSQL_ROW row;
  1664. row = mysql_fetch_row(result);
  1665. if(atoi(row[0]) == 0) //old character, needs to be deleted FROM login server
  1666. return -10;
  1667. return -8;
  1668. }
  1669. else
  1670. LogWrite(WORLD__ERROR, 0, "World", "Error in GetCharacterAdminStatus query '%s': %s", query.GetQuery(), query.GetError());
  1671. }
  1672. return PLAY_ERROR_PROBLEM;
  1673. }
  1674. bool WorldDatabase::UpdateAdminStatus(char* character_name, sint16 flag){
  1675. Query query;
  1676. string update_status = string("update characters set admin_status=%i where name='%s'");
  1677. query.RunQuery2(Q_UPDATE, update_status.c_str(),flag,character_name);
  1678. if(!query.GetAffectedRows())
  1679. {
  1680. LogWrite(WORLD__ERROR, 0, "World", "Error in UpdateAdminStatus query '%s': %s", query.GetQuery(), query.GetError());
  1681. return false;
  1682. }
  1683. return true;
  1684. }
  1685. void WorldDatabase::SaveCharacterFloats(int32 char_id, const char* type, float float1, float float2, float float3){
  1686. Query query;
  1687. string create_char = string("insert into char_colors (char_id, type, red, green, blue, signed_value) values(%i,'%s',%i,%i,%i, 1)");
  1688. query.RunQuery2(Q_INSERT, create_char.c_str(), char_id, type, (sint8)(float1*100), (sint8)(float2*100), (sint8)(float3*100));
  1689. if(query.GetError() && strlen(query.GetError()) > 0){
  1690. LogWrite(WORLD__ERROR, 0, "World", "Error in SaveCharacterFloats query '%s': %s", query.GetQuery(), query.GetError());
  1691. }
  1692. }
  1693. void WorldDatabase::SaveCharacterColors(int32 char_id, const char* type, EQ2_Color color){
  1694. Query query;
  1695. string create_char = string("insert into char_colors (char_id, type, red, green, blue) values(%i,'%s',%i,%i,%i)");
  1696. query.RunQuery2(Q_INSERT, create_char.c_str(), char_id, type, color.red, color.green, color.blue);
  1697. if(query.GetError() && strlen(query.GetError()) > 0){
  1698. LogWrite(WORLD__ERROR, 0, "World", "Error in SaveCharacterColors query '%s': %s", query.GetQuery(), query.GetError());
  1699. }
  1700. }
  1701. void WorldDatabase::SaveNPCAppearanceEquipment(int32 spawn_id, int8 slot_id, int16 type, int8 red, int8 green, int8 blue, int8 hred, int8 hgreen, int8 hblue){
  1702. Query query;
  1703. string appearance = string("INSERT INTO npc_appearance_equip (spawn_id, slot_id, equip_type, red, green, blue, highlight_red, highlight_green, highlight_blue) values (%i, %i, %i, %i, %i, %i, %i, %i, %i) ON DUPLICATE KEY UPDATE equip_type=%i, red=%i, green=%i, blue=%i, highlight_red=%i, highlight_green=%i, highlight_blue=%i");
  1704. query.RunQuery2(Q_INSERT, appearance.c_str(), spawn_id, slot_id, type, red, green, blue, hred, hgreen, hblue, type, red, green, blue, hred, hgreen, hblue);
  1705. if(query.GetError() && strlen(query.GetError()) > 0){
  1706. LogWrite(WORLD__ERROR, 0, "World", "Error in SaveNPCAppearanceEquipment query '%s': %s", query.GetQuery(), query.GetError());
  1707. }
  1708. }
  1709. int32 WorldDatabase::LoadNPCAppearanceEquipmentData(ZoneServer* zone){
  1710. Query query;
  1711. MYSQL_ROW row;
  1712. int32 spawn_id = 0, new_spawn_id = 0, count = 0;
  1713. NPC* npc = 0;
  1714. int8 slot = 0;
  1715. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT spawn_id, slot_id, equip_type, red, green, blue, highlight_red, highlight_green, highlight_blue FROM npc_appearance_equip ORDER BY spawn_id");
  1716. while(result && (row = mysql_fetch_row(result))){
  1717. new_spawn_id = atoul(row[0]);
  1718. if(new_spawn_id != spawn_id){
  1719. npc = zone->GetNPC(new_spawn_id, true);
  1720. if(!npc)
  1721. continue;
  1722. if(spawn_id > 0)
  1723. count++;
  1724. spawn_id = new_spawn_id;
  1725. }
  1726. slot = atoi(row[1]);
  1727. if(slot < NUM_SLOTS){
  1728. npc->equipment.equip_id[slot] = atoi(row[2]);
  1729. npc->equipment.color[slot].red = atoi(row[3]);
  1730. npc->equipment.color[slot].green = atoi(row[4]);
  1731. npc->equipment.color[slot].blue = atoi(row[5]);
  1732. npc->equipment.highlight[slot].red = atoi(row[6]);
  1733. npc->equipment.highlight[slot].green = atoi(row[7]);
  1734. npc->equipment.highlight[slot].blue = atoi(row[8]);
  1735. }
  1736. }
  1737. if(query.GetError() && strlen(query.GetError()) > 0)
  1738. LogWrite(WORLD__ERROR, 0, "World", "Error in LoadNPCAppearanceEquipmentData query '%s': %s", query.GetQuery(), query.GetError());
  1739. return count;
  1740. }
  1741. int16 WorldDatabase::GetAppearanceID(string name){
  1742. int32 id = 0;
  1743. Query query;
  1744. MYSQL_ROW row;
  1745. query.escaped_name = getEscapeString(name.c_str());
  1746. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT appearance_id FROM appearances where name='%s'", query.escaped_name);
  1747. if(result && mysql_num_rows(result) == 1){
  1748. row = mysql_fetch_row(result);
  1749. id = atoi(row[0]);
  1750. }
  1751. return id;
  1752. }
  1753. vector<int16>* WorldDatabase::GetAppearanceIDsLikeName(string name, bool filtered) {
  1754. vector<int16>* ids = 0;
  1755. Query query;
  1756. MYSQL_ROW row;
  1757. query.escaped_name = getEscapeString(name.c_str());
  1758. MYSQL_RES* result;
  1759. if (filtered)
  1760. result = query.RunQuery2(Q_SELECT, "SELECT `appearance_id` FROM `appearances` WHERE `name` RLIKE '%s' AND `name` NOT RLIKE 'ghost' AND `name` NOT RLIKE 'headless' AND `name` NOT RLIKE 'elemental' AND `name` NOT RLIKE 'test' AND `name` NOT RLIKE 'zombie' AND `name` NOT RLIKE 'vampire'", query.escaped_name);
  1761. else
  1762. result = query.RunQuery2(Q_SELECT, "SELECT `appearance_id` FROM `appearances` WHERE `name` RLIKE '%s' AND `name` NOT RLIKE 'ghost' AND `name`", query.escaped_name);
  1763. while (result && (row = mysql_fetch_row(result))) {
  1764. if (!ids)
  1765. ids = new vector<int16>;
  1766. ids->push_back(atoi(row[0]));
  1767. }
  1768. return ids;
  1769. }
  1770. string WorldDatabase::GetAppearanceName(int16 appearance_id) {
  1771. Query query;
  1772. MYSQL_ROW row;
  1773. string name;
  1774. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `name` FROM `appearances` WHERE `appearance_id`=%u", appearance_id);
  1775. if (result && (row = mysql_fetch_row(result)))
  1776. name = string(row[0]);
  1777. return name;
  1778. }
  1779. void WorldDatabase::UpdateRandomize(int32 spawn_id, sint32 value) {
  1780. Query query;
  1781. query.RunQuery2(Q_UPDATE, "UPDATE `spawn_npcs` SET `randomize`=`randomize` + %i WHERE `spawn_id`=%u", value, spawn_id);
  1782. }
  1783. int32 WorldDatabase::SaveCharacter(PacketStruct* create, int32 loginID){
  1784. Query query;
  1785. int8 race_id = create->getType_int8_ByName("race");
  1786. int8 class_id = create->getType_int8_ByName("class");//Normal server
  1787. //int8 class_id = 0; //CLassic Server Only
  1788. int8 gender_id = create->getType_int8_ByName("gender");
  1789. sint16 auto_admin_status = 0;
  1790. // fetch rules related to setting auto-admin status for server
  1791. bool auto_admin_players = rule_manager.GetGlobalRule(R_World, AutoAdminPlayers)->GetBool();
  1792. bool auto_admin_gm = rule_manager.GetGlobalRule(R_World, AutoAdminGMs)->GetBool();
  1793. /*
  1794. The way I think this is supposed to work :) is if any of your chars are already GM, and AutoAdminGMs rule is true,
  1795. set the new character's admin_status to your highest status for any character active on your loginID.
  1796. - If status > 0, new character > 0
  1797. - If status = 0, new character = 0
  1798. - If status < 0, new character < 0, too... even if auto_admin_gm is true
  1799. If we're not a GM (status = 0) but AutoAdminPlayers rule is true,
  1800. set the new character's admin_status to the default set in AutoAdminStatusValue rule.
  1801. Else, if both rules are False, set everyone to 0 like normal.
  1802. */
  1803. auto_admin_status = GetHighestCharacterAdminStatus(loginID);
  1804. if( auto_admin_status > 0 && auto_admin_gm )
  1805. LogWrite(WORLD__WARNING, 0, "World", "New character '%s' granted GM status (%i) from accountID: %i", create->getType_EQ2_16BitString_ByName("name").data.c_str(), auto_admin_status, loginID);
  1806. else if( auto_admin_players )
  1807. {
  1808. auto_admin_status = rule_manager.GetGlobalRule(R_World, AutoAdminStatusValue)->GetSInt16();
  1809. LogWrite(WORLD__DEBUG, 0, "World", "New character '%s' granted AutoAdminPlayer status: %i", create->getType_EQ2_16BitString_ByName("name").data.c_str(), auto_admin_status);
  1810. }
  1811. else
  1812. auto_admin_status = 0;
  1813. string create_char = string("Insert into characters (account_id, server_id, name, race, class, gender, deity, body_size, body_age, soga_wing_type, soga_chest_type, soga_legs_type, soga_hair_type, soga_model_type, legs_type, chest_type, wing_type, hair_type, model_type, facial_hair_type, soga_facial_hair_type, created_date, last_saved, admin_status) values(%i, %i, '%s', %i, %i, %i, %i, %f, %f, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, now(), unix_timestamp(), %i)");
  1814. query.RunQuery2(Q_INSERT, create_char.c_str(),
  1815. loginID,
  1816. create->getType_int32_ByName("server_id"),
  1817. create->getType_EQ2_16BitString_ByName("name").data.c_str(),
  1818. race_id,
  1819. class_id,
  1820. gender_id,
  1821. create->getType_int8_ByName("deity"),
  1822. create->getType_float_ByName("body_size"),
  1823. create->getType_float_ByName("body_age"),
  1824. GetAppearanceID(create->getType_EQ2_16BitString_ByName("soga_wing_file").data),
  1825. GetAppearanceID(create->getType_EQ2_16BitString_ByName("soga_chest_file").data),
  1826. GetAppearanceID(create->getType_EQ2_16BitString_ByName("soga_legs_file").data),
  1827. GetAppearanceID(create->getType_EQ2_16BitString_ByName("soga_hair_file").data),
  1828. GetAppearanceID(create->getType_EQ2_16BitString_ByName("soga_race_file").data),
  1829. GetAppearanceID(create->getType_EQ2_16BitString_ByName("legs_file").data),
  1830. GetAppearanceID(create->getType_EQ2_16BitString_ByName("chest_file").data),
  1831. GetAppearanceID(create->getType_EQ2_16BitString_ByName("wing_file").data),
  1832. GetAppearanceID(create->getType_EQ2_16BitString_ByName("hair_file").data),
  1833. GetAppearanceID(create->getType_EQ2_16BitString_ByName("race_file").data),
  1834. GetAppearanceID(create->getType_EQ2_16BitString_ByName("face_file").data),
  1835. GetAppearanceID(create->getType_EQ2_16BitString_ByName("soga_face_file").data),
  1836. auto_admin_status);
  1837. if(query.GetError() && strlen(query.GetError()) > 0)
  1838. {
  1839. LogWrite(PLAYER__ERROR, 0, "Player", "Error in SaveCharacter query '%s': %s", query.GetQuery(), query.GetError());
  1840. return 0;
  1841. }
  1842. int32 last_insert_id = query.GetLastInsertedID();
  1843. int32 char_id = last_insert_id;
  1844. UpdateStartingFactions(char_id, create->getType_int8_ByName("starting_zone"));
  1845. UpdateStartingZone(char_id, class_id, race_id, create->getType_int8_ByName("starting_zone"));
  1846. UpdateStartingItems(char_id, class_id, race_id);
  1847. UpdateStartingSkills(char_id, class_id, race_id);
  1848. UpdateStartingSpells(char_id, class_id, race_id);
  1849. UpdateStartingSkillbar(char_id, class_id, race_id);
  1850. UpdateStartingTitles(char_id, class_id, race_id, gender_id);
  1851. InsertCharacterStats(char_id, class_id, race_id);
  1852. AddNewPlayerToServerGuild(loginID, char_id);
  1853. SaveCharacterColors(char_id,"skin_color", create->getType_EQ2_Color_ByName("skin_color"));
  1854. SaveCharacterColors(char_id,"eye_color", create->getType_EQ2_Color_ByName("eye_color"));
  1855. SaveCharacterColors(char_id,"hair_color1", create->getType_EQ2_Color_ByName("hair_color1"));
  1856. SaveCharacterColors(char_id,"hair_color2", create->getType_EQ2_Color_ByName("hair_color2"));
  1857. SaveCharacterColors(char_id,"hair_highlight", create->getType_EQ2_Color_ByName("hair_highlight"));
  1858. SaveCharacterColors(char_id,"hair_type_color", create->getType_EQ2_Color_ByName("hair_type_color"));
  1859. SaveCharacterColors(char_id,"hair_type_highlight_color", create->getType_EQ2_Color_ByName("hair_type_highlight_color"));
  1860. SaveCharacterColors(char_id,"hair_face_color", create->getType_EQ2_Color_ByName("hair_face_color"));
  1861. SaveCharacterColors(char_id,"hair_face_highlight_color", create->getType_EQ2_Color_ByName("hair_face_highlight_color"));
  1862. SaveCharacterColors(char_id,"wing_color1", create->getType_EQ2_Color_ByName("wing_color1"));
  1863. SaveCharacterColors(char_id,"wing_color2", create->getType_EQ2_Color_ByName("wing_color2"));
  1864. SaveCharacterColors(char_id,"shirt_color", create->getType_EQ2_Color_ByName("shirt_color"));
  1865. SaveCharacterColors(char_id,"unknown_chest_color", create->getType_EQ2_Color_ByName("unknown_chest_color"));
  1866. SaveCharacterColors(char_id,"pants_color", create->getType_EQ2_Color_ByName("pants_color"));
  1867. SaveCharacterColors(char_id,"unknown_legs_color", create->getType_EQ2_Color_ByName("unknown_legs_color"));
  1868. SaveCharacterColors(char_id,"unknown9", create->getType_EQ2_Color_ByName("unknown9"));
  1869. SaveCharacterFloats(char_id,"eye_type", create->getType_float_ByName("eyes2",0), create->getType_float_ByName("eyes2",1), create->getType_float_ByName("eyes2",2));
  1870. SaveCharacterFloats(char_id,"ear_type", create->getType_float_ByName("ears",0), create->getType_float_ByName("ears",1), create->getType_float_ByName("ears",2));
  1871. SaveCharacterFloats(char_id,"eye_brow_type", create->getType_float_ByName("eye_brows",0), create->getType_float_ByName("eye_brows",1), create->getType_float_ByName("eye_brows",2));
  1872. SaveCharacterFloats(char_id,"cheek_type", create->getType_float_ByName("cheeks",0), create->getType_float_ByName("cheeks",1), create->getType_float_ByName("cheeks",2));
  1873. SaveCharacterFloats(char_id,"lip_type", create->getType_float_ByName("lips",0), create->getType_float_ByName("lips",1), create->getType_float_ByName("lips",2));
  1874. SaveCharacterFloats(char_id,"chin_type", create->getType_float_ByName("chin",0), create->getType_float_ByName("chin",1), create->getType_float_ByName("chin",2));
  1875. SaveCharacterFloats(char_id,"nose_type", create->getType_float_ByName("nose",0), create->getType_float_ByName("nose",1), create->getType_float_ByName("nose",2));
  1876. SaveCharacterFloats(char_id,"body_size", create->getType_float_ByName("body_size",0), 0, 0);
  1877. SaveCharacterColors(char_id,"soga_skin_color", create->getType_EQ2_Color_ByName("soga_skin_color"));
  1878. SaveCharacterColors(char_id,"soga_eye_color", create->getType_EQ2_Color_ByName("soga_eye_color"));
  1879. SaveCharacterColors(char_id,"soga_hair_color1", create->getType_EQ2_Color_ByName("soga_hair_color1"));
  1880. SaveCharacterColors(char_id,"soga_hair_color2", create->getType_EQ2_Color_ByName("soga_hair_color2"));
  1881. SaveCharacterColors(char_id,"soga_hair_highlight", create->getType_EQ2_Color_ByName("soga_hair_highlight"));
  1882. SaveCharacterColors(char_id,"soga_hair_type_color", create->getType_EQ2_Color_ByName("soga_hair_type_color"));
  1883. SaveCharacterColors(char_id,"soga_hair_type_highlight_color", create->getType_EQ2_Color_ByName("soga_hair_type_highlight_color"));
  1884. SaveCharacterColors(char_id,"soga_hair_face_color", create->getType_EQ2_Color_ByName("soga_hair_face_color"));
  1885. SaveCharacterColors(char_id,"soga_hair_face_highlight_color", create->getType_EQ2_Color_ByName("soga_hair_face_highlight_color"));
  1886. SaveCharacterColors(char_id,"soga_wing_color1", create->getType_EQ2_Color_ByName("soga_wing_color1"));
  1887. SaveCharacterColors(char_id,"soga_wing_color2", create->getType_EQ2_Color_ByName("soga_wing_color2"));
  1888. SaveCharacterColors(char_id,"soga_shirt_color", create->getType_EQ2_Color_ByName("soga_shirt_color"));
  1889. SaveCharacterColors(char_id,"soga_unknown_chest_color", create->getType_EQ2_Color_ByName("soga_unknown_chest_color"));
  1890. SaveCharacterColors(char_id,"soga_pants_color", create->getType_EQ2_Color_ByName("soga_pants_color"));
  1891. SaveCharacterColors(char_id,"soga_unknown_legs_color", create->getType_EQ2_Color_ByName("soga_unknown_legs_color"));
  1892. SaveCharacterColors(char_id,"soga_unknown13", create->getType_EQ2_Color_ByName("soga_unknown13"));
  1893. SaveCharacterFloats(char_id,"soga_eye_type", create->getType_float_ByName("soga_eyes2",0), create->getType_float_ByName("soga_eyes2",1), create->getType_float_ByName("soga_eyes2",2));
  1894. SaveCharacterFloats(char_id,"soga_ear_type", create->getType_float_ByName("soga_ears",0), create->getType_float_ByName("soga_ears",1), create->getType_float_ByName("soga_ears",2));
  1895. SaveCharacterFloats(char_id,"soga_eye_brow_type", create->getType_float_ByName("soga_eye_brows",0), create->getType_float_ByName("soga_eye_brows",1), create->getType_float_ByName("soga_eye_brows",2));
  1896. SaveCharacterFloats(char_id,"soga_cheek_type", create->getType_float_ByName("soga_cheeks",0), create->getType_float_ByName("soga_cheeks",1), create->getType_float_ByName("soga_cheeks",2));
  1897. SaveCharacterFloats(char_id,"soga_lip_type", create->getType_float_ByName("soga_lips",0), create->getType_float_ByName("soga_lips",1), create->getType_float_ByName("soga_lips",2));
  1898. SaveCharacterFloats(char_id,"soga_chin_type", create->getType_float_ByName("soga_chin",0), create->getType_float_ByName("soga_chin",1), create->getType_float_ByName("soga_chin",2));
  1899. SaveCharacterFloats(char_id,"soga_nose_type", create->getType_float_ByName("soga_nose",0), create->getType_float_ByName("soga_nose",1), create->getType_float_ByName("soga_nose",2));
  1900. return char_id;
  1901. }
  1902. int8 WorldDatabase::CheckNameFilter(const char* name) {
  1903. // the minimum 4 is enforced by the client too
  1904. if(!name || strlen(name) < 4 || strlen(name) > 15) // Even 20 char length is long...
  1905. return BADNAMELENGTH_REPLY;
  1906. uchar* checkname = (uchar*)name;
  1907. for (int32 i = 0; i < strlen(name); i++)
  1908. {
  1909. if(!alpha_check(checkname[i]))
  1910. return NAMEINVALID_REPLY;
  1911. }
  1912. Query query;
  1913. LogWrite(WORLD__DEBUG, 0, "World", "Name check on: %s", name);
  1914. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT count(*) FROM characters WHERE name='%s'",name);
  1915. if(result && mysql_num_rows(result) > 0) {
  1916. MYSQL_ROW row;
  1917. row = mysql_fetch_row(result);
  1918. if(row[0] != 0 && atoi(row[0]) > 0)
  1919. return NAMETAKEN_REPLY;
  1920. }
  1921. else
  1922. LogWrite(WORLD__ERROR, 0, "World", "Error in CheckNameFilter (name exist check) (Name query '%s': %s", query.GetQuery(), query.GetError());
  1923. Query query3;
  1924. LogWrite(WORLD__DEBUG, 0, "World", "Name check on: %s (Bots table)", name);
  1925. MYSQL_RES* result3 = query3.RunQuery2(Q_SELECT, "SELECT count(*) FROM bots WHERE name='%s'", name);
  1926. if (result3 && mysql_num_rows(result3) > 0) {
  1927. MYSQL_ROW row;
  1928. row = mysql_fetch_row(result3);
  1929. if (row[0] != 0 && atoi(row[0]) > 0)
  1930. return NAMETAKEN_REPLY;
  1931. }
  1932. else
  1933. LogWrite(WORLD__ERROR, 0, "World", "Error in CheckNameFilter (name exist check, bot table) (Name query '%s': %s", query3.GetQuery(), query3.GetError());
  1934. Query query2;
  1935. MYSQL_RES* result2 = query2.RunQuery2(Q_SELECT, "SELECT count(*) FROM name_filter WHERE '%s' like name",name);
  1936. if(result2 && mysql_num_rows(result2) > 0) {
  1937. MYSQL_ROW row;
  1938. row = mysql_fetch_row(result2);
  1939. if(row[0] != 0 && atoi(row[0]) > 0)
  1940. return NAMEFILTER_REPLY;
  1941. else if(row[0] != 0 && atoi(row[0]) == 0)
  1942. return CREATESUCCESS_REPLY;
  1943. }
  1944. else
  1945. LogWrite(WORLD__ERROR, 0, "World", "Error in CheckNameFilter (name_filter check) query '%s': %s", query.GetQuery(), query.GetError());
  1946. return UNKNOWNERROR_REPLY;
  1947. }
  1948. char* WorldDatabase::GetCharacterName(int32 character_id){
  1949. LogWrite(WORLD__TRACE, 9, "World", "Enter: %s", __FUNCTION__);
  1950. Query query;
  1951. char* name = 0;
  1952. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT name FROM characters where id=%u",character_id);
  1953. if(result && mysql_num_rows(result) > 0) {
  1954. MYSQL_ROW row;
  1955. row = mysql_fetch_row(result);
  1956. if(row[0] && strlen(row[0]) > 0)
  1957. {
  1958. name = new char[strlen(row[0])+1];
  1959. memset(name,0, strlen(row[0])+1);
  1960. strcpy(name, row[0]);
  1961. }
  1962. }
  1963. else
  1964. LogWrite(WORLD__ERROR, 0, "World", "Error in GetCharacterName query '%s': %s", query.GetQuery(), query.GetError());
  1965. LogWrite(WORLD__TRACE, 9, "World", "Exit: %s", __FUNCTION__);
  1966. return name;
  1967. }
  1968. int8 WorldDatabase::GetCharacterLevel(int32 character_id){
  1969. Query query;
  1970. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT level FROM characters where id=%u",character_id);
  1971. if(result && mysql_num_rows(result) > 0) {
  1972. MYSQL_ROW row;
  1973. row = mysql_fetch_row(result);
  1974. return atoi(row[0]); // Return characters level
  1975. }
  1976. else
  1977. LogWrite(WORLD__ERROR, 0, "World", "Error in GetCharacterLevel query '%s': %s", query.GetQuery(), query.GetError());
  1978. return 0;
  1979. }
  1980. int16 WorldDatabase::GetCharacterModelType(int32 character_id){
  1981. Query query;
  1982. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT model_type FROM characters where id=%u",character_id);
  1983. if(result && mysql_num_rows(result) > 0) {
  1984. MYSQL_ROW row;
  1985. row = mysql_fetch_row(result);
  1986. return atoi(row[0]); // Return characters race
  1987. }
  1988. else
  1989. LogWrite(WORLD__ERROR, 0, "World", "Error in GetCharacterModelType query '%s': %s", query.GetQuery(), query.GetError());
  1990. return 0;
  1991. }
  1992. int8 WorldDatabase::GetCharacterClass(int32 character_id){
  1993. Query query;
  1994. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT class FROM characters where id=%u",character_id);
  1995. if(result && mysql_num_rows(result) > 0) {
  1996. MYSQL_ROW row;
  1997. row = mysql_fetch_row(result);
  1998. return atoi(row[0]); // Return characters class
  1999. }
  2000. else
  2001. LogWrite(WORLD__ERROR, 0, "World", "Error in GetCharacterClass query '%s': %s", query.GetQuery(), query.GetError());
  2002. return 0;
  2003. }
  2004. int8 WorldDatabase::GetCharacterGender(int32 character_id){
  2005. Query query;
  2006. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT gender FROM characters where id=%u",character_id);
  2007. if(result && mysql_num_rows(result) > 0) {
  2008. MYSQL_ROW row;
  2009. row = mysql_fetch_row(result);
  2010. return atoi(row[0]); // Return characters gender
  2011. }
  2012. else
  2013. LogWrite(WORLD__ERROR, 0, "World", "Error in GetCharacterGender query '%s': %s", query.GetQuery(), query.GetError());
  2014. return 0;
  2015. }
  2016. void WorldDatabase::DeleteCharacterQuest(int32 quest_id, int32 char_id, bool repeated_quest) {
  2017. if (repeated_quest) {
  2018. if (!database_new.Query("UPDATE `character_quests` SET `given_date` = `completed_date` WHERE `char_id` = %u AND `quest_id` = %u", char_id, quest_id))
  2019. LogWrite(DATABASE__ERROR, 0, "DBNew", "Error (%u) in DeleteCharacterQuest query:\n%s", database_new.GetError(), database_new.GetErrorMsg());
  2020. }
  2021. else {
  2022. if (!database_new.Query("DELETE FROM `character_quests` WHERE `char_id` = %u AND `quest_id` = %u", char_id, quest_id))
  2023. LogWrite(DATABASE__ERROR, 0, "DBNew", "Error (%u) in DeleteCharacterQuest query:\n%s", database_new.GetError(), database_new.GetErrorMsg());
  2024. }
  2025. if (!database_new.Query("DELETE FROM `character_quest_progress` WHERE `char_id` = %u AND `quest_id` = %u", char_id, quest_id))
  2026. LogWrite(DATABASE__ERROR, 0, "DBNew", "Error (%u) in DeleteCharacterQuest query:\n%s", database_new.GetError(), database_new.GetErrorMsg());
  2027. }
  2028. void WorldDatabase::SaveCharacterSkills(Client* client){
  2029. vector<Skill*>* skills = client->GetPlayer()->GetSkills()->GetSaveNeededSkills();
  2030. if(skills){
  2031. Query query;
  2032. if(skills->size() > 0){
  2033. Skill* skill = 0;
  2034. for(int32 i=0;i<skills->size();i++){
  2035. skill = skills->at(i);
  2036. query.AddQueryAsync(client->GetCharacterID(),this,Q_REPLACE, "replace into character_skills (char_id, skill_id, current_val, max_val) values(%u, %u, %i, %i)", client->GetCharacterID(), skill->skill_id, skill->current_val, skill->max_val);
  2037. }
  2038. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF)
  2039. LogWrite(WORLD__ERROR, 0, "World", "Error in SaveCharacterSkills query '%s': %s", query.GetQuery(), query.GetError());
  2040. }
  2041. safe_delete(skills);
  2042. }
  2043. }
  2044. void WorldDatabase::SaveCharacterQuests(Client* client){
  2045. Query query;
  2046. map<int32, Quest*>::iterator itr;
  2047. master_quest_list.LockQuests(); //prevent reloading until we are done
  2048. client->GetPlayer()->LockQuests(); //prevent all quest modifications until we are done
  2049. map<int32, Quest*>* quests = client->GetPlayer()->GetPlayerQuests();
  2050. for(itr = quests->begin(); itr != quests->end(); itr++){
  2051. if(client->GetCurrentQuestID() == itr->first){
  2052. query.AddQueryAsync(client->GetCharacterID(),this,Q_UPDATE, "update character_quests set current_quest = 0 where char_id = %u", client->GetCharacterID());
  2053. query.AddQueryAsync(client->GetCharacterID(), this,Q_UPDATE, "update character_quests set current_quest = 1 where char_id = %u and quest_id = %u", client->GetCharacterID(), itr->first);
  2054. }
  2055. if(itr->second->GetSaveNeeded()){
  2056. query.AddQueryAsync(client->GetCharacterID(), this,Q_INSERT, "insert ignore into character_quests (char_id, quest_id, given_date, quest_giver) values(%u, %u, now(), %u)", client->GetCharacterID(), itr->first, itr->second->GetQuestGiver());
  2057. query.AddQueryAsync(client->GetCharacterID(), this,Q_UPDATE, "update character_quests set tracked = %i, quest_flags = %u, hidden = %i, complete_count = %u where char_id = %u and quest_id = %u", itr->second->IsTracked() ? 1 : 0, itr->second->GetQuestFlags(), itr->second->IsHidden() ? 1 : 0, itr->second->GetCompleteCount(), client->GetCharacterID(), itr->first);
  2058. SaveCharacterQuestProgress(client, itr->second);
  2059. itr->second->SetSaveNeeded(false);
  2060. }
  2061. }
  2062. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF)
  2063. LogWrite(WORLD__ERROR, 0, "World", "Error in SaveCharacterQuests query '%s': %s", query.GetQuery(), query.GetError());
  2064. quests = client->GetPlayer()->GetCompletedPlayerQuests();
  2065. for(itr = quests->begin(); itr != quests->end(); itr++){
  2066. if(itr->second->GetSaveNeeded()){
  2067. query.AddQueryAsync(client->GetCharacterID(), this,Q_DELETE, "delete FROM character_quest_progress where char_id = %u and quest_id = %u", client->GetCharacterID(), itr->first);
  2068. /* incase the quest is completed before the quest could be inserted in the PlayerQuests loop, we first try to insert it. If it already exists then we can just update
  2069. * the completed_date */
  2070. query.AddQueryAsync(client->GetCharacterID(), this,Q_INSERT, "INSERT INTO character_quests (char_id, quest_id, quest_giver, current_quest, given_date, completed_date, complete_count) values (%u,%u,%u,0, now(),now(), %u) ON DUPLICATE KEY UPDATE completed_date = now(), complete_count = %u, current_quest = 0", client->GetCharacterID(), itr->first, itr->second->GetQuestGiver(), itr->second->GetCompleteCount(), itr->second->GetCompleteCount());
  2071. itr->second->SetSaveNeeded(false);
  2072. }
  2073. }
  2074. client->GetPlayer()->UnlockQuests();
  2075. master_quest_list.UnlockQuests();
  2076. }
  2077. void WorldDatabase::SaveCharRepeatableQuest(Client* client, int32 quest_id, int16 quest_complete_count) {
  2078. if (!database_new.Query("UPDATE `character_quests` SET `given_date` = now(), complete_count = %u WHERE `char_id` = %u AND `quest_id` = %u", quest_complete_count, client->GetCharacterID(), quest_id))
  2079. LogWrite(DATABASE__ERROR, 0, "DBNew", "DB Error %u\n%s", database_new.GetError(), database_new.GetErrorMsg());
  2080. }
  2081. void WorldDatabase::SaveCharacterQuestProgress(Client* client, Quest* quest){
  2082. Query query;
  2083. vector<QuestStep*>* steps = quest->GetQuestSteps();
  2084. vector<QuestStep*>::iterator itr;
  2085. QuestStep* step = 0;
  2086. if(steps){
  2087. for(itr = steps->begin(); itr != steps->end(); itr++){
  2088. step = *itr;
  2089. if(step && step->GetQuestCurrentQuantity() > 0)
  2090. query.RunQuery2(Q_REPLACE, "replace into character_quest_progress (char_id, quest_id, step_id, progress) values(%u, %u, %u, %i)", client->GetCharacterID(), quest->GetQuestID(), step->GetStepID(), step->GetQuestCurrentQuantity());
  2091. }
  2092. }
  2093. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF)
  2094. LogWrite(WORLD__ERROR, 0, "World", "Error in SaveCharacterQuestProgress query '%s': %s", query.GetQuery(), query.GetError());
  2095. }
  2096. void WorldDatabase::LoadCharacterQuestProgress(Client* client){
  2097. Query query;
  2098. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT character_quest_progress.quest_id, step_id, progress FROM character_quest_progress, character_quests where character_quest_progress.char_id=%u and character_quest_progress.quest_id = character_quests.quest_id and character_quest_progress.char_id = character_quests.char_id ORDER BY character_quest_progress.quest_id",client->GetCharacterID());
  2099. if(result && mysql_num_rows(result) > 0) {
  2100. MYSQL_ROW row;
  2101. Quest* quest = 0;
  2102. int32 quest_id = 0;
  2103. map<int32, int32>* progress_map = new map<int32, int32>();
  2104. while(result && (row = mysql_fetch_row(result))){
  2105. if(quest_id != atoul(row[0])){
  2106. if(quest_id > 0){
  2107. quest = client->GetPlayer()->GetQuest(quest_id);
  2108. if(quest)
  2109. client->SetPlayerQuest(quest, progress_map);
  2110. }
  2111. quest_id = atoul(row[0]);
  2112. progress_map->clear();
  2113. }
  2114. (*progress_map)[atoul(row[1])] = atoul(row[2]);
  2115. }
  2116. if(progress_map->size() > 0){
  2117. quest = client->GetPlayer()->GetQuest(quest_id);
  2118. if(quest)
  2119. client->SetPlayerQuest(quest, progress_map);
  2120. }
  2121. safe_delete(progress_map);
  2122. }
  2123. else if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF)
  2124. LogWrite(WORLD__ERROR, 0, "World", "Error in LoadCharacterQuestProgress query '%s': %s", query.GetQuery(), query.GetError());
  2125. }
  2126. void WorldDatabase::LoadCharacterQuests(Client* client){
  2127. LogWrite(PLAYER__DEBUG, 0, "Player", "Loading Character Quests...");
  2128. Query query;
  2129. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT quest_id, DAY(given_date), MONTH(given_date), YEAR(given_date), DAY(completed_date), MONTH(completed_date), YEAR(completed_date), quest_giver, tracked, quest_flags, hidden, UNIX_TIMESTAMP(given_date), UNIX_TIMESTAMP(completed_date), complete_count FROM character_quests WHERE char_id=%u ORDER BY current_quest", client->GetCharacterID());
  2130. if(result && mysql_num_rows(result) > 0) {
  2131. MYSQL_ROW row;
  2132. Quest* quest = 0;
  2133. while(result && (row = mysql_fetch_row(result))){
  2134. quest = master_quest_list.GetQuest(atoul(row[0]));
  2135. if(quest) {
  2136. LogWrite(PLAYER__DEBUG, 5, "Player", "\tLoading quest_id: %u", atoul(row[0]));
  2137. bool addQuest = true;
  2138. if(row[4] && atoi(row[4]) > 0){
  2139. quest->SetTurnedIn(true);
  2140. if(row[4])
  2141. quest->SetDay(atoi(row[4]));
  2142. if(row[5])
  2143. quest->SetMonth(atoi(row[5]));
  2144. if(row[6] && atoi(row[6]) > 2000)
  2145. quest->SetYear(atoi(row[6]) - 2000);
  2146. client->GetPlayer()->AddCompletedQuest(quest);
  2147. // Added timestamps to quickly compare given and completed dates
  2148. int32 given_timestamp = atoul(row[11]);
  2149. int32 completed_timestamp = atoul(row[12]);
  2150. // If given timestamp is greater then completed then this is a repeatable quest we are working on
  2151. // so get a fresh quest object to add as an active quest
  2152. if (given_timestamp > completed_timestamp)
  2153. quest = master_quest_list.GetQuest(atoul(row[0]));
  2154. else
  2155. addQuest = false;
  2156. quest->SetCompleteCount(atoi(row[13]));
  2157. }
  2158. if (addQuest) {
  2159. if(row[1])
  2160. quest->SetDay(atoi(row[1]));
  2161. if(row[2])
  2162. quest->SetMonth(atoi(row[2]));
  2163. if(row[3] && atoi(row[3]) > 2000)
  2164. quest->SetYear(atoi(row[3]) - 2000);
  2165. quest->SetQuestGiver(atoul(row[7]));
  2166. quest->SetTracked(atoi(row[8]) == 1 ? true : false);
  2167. quest->SetQuestFlags(atoul(row[9]));
  2168. quest->SetHidden(atoi(row[10]) == 1 ? true : false);
  2169. client->AddPlayerQuest(quest, false, false);
  2170. }
  2171. quest->SetSaveNeeded(false);
  2172. // Changed this to call reload with step = 0 for all quests and not
  2173. // just quests with quest flags to allow customized set up if needed
  2174. if (lua_interface)
  2175. lua_interface->CallQuestFunction(quest, "Reload", client->GetPlayer(), 0);
  2176. }
  2177. }
  2178. LoadCharacterQuestProgress(client);
  2179. }
  2180. }
  2181. void WorldDatabase::LoadCharacterFriendsIgnoreList(Player* player) {
  2182. if (player) {
  2183. Query query;
  2184. MYSQL_ROW row;
  2185. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `name`, `type` FROM `character_social` WHERE `char_id`=%u", player->GetCharacterID());
  2186. while (result && (row = mysql_fetch_row(result))) {
  2187. if (strncmp(row[1], "FRIEND", 6) == 0)
  2188. player->AddFriend(row[0], false);
  2189. else
  2190. player->AddIgnore(row[0], false);
  2191. }
  2192. }
  2193. }
  2194. void WorldDatabase::LoadZoneInfo(ZoneServer* zone){
  2195. Query query;
  2196. int32 ruleset_id;
  2197. char* escaped = getEscapeString(zone->GetZoneName());
  2198. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, file, description, underworld, safe_x, safe_y, safe_z, min_status, min_level, max_level, instance_type+0, shutdown_timer, zone_motd, default_reenter_time, default_reset_time, default_lockout_time, force_group_to_zone, safe_heading, xp_modifier, ruleset_id, expansion_id, weather_allowed, sky_file FROM zones where name='%s'",escaped);
  2199. if(result && mysql_num_rows(result) > 0) {
  2200. MYSQL_ROW row;
  2201. row = mysql_fetch_row(result);
  2202. zone->SetZoneName(escaped);
  2203. zone->SetZoneID(strtoul(row[0], NULL, 0));
  2204. zone->SetZoneFile(row[1]);
  2205. zone->SetZoneDescription(row[2]);
  2206. zone->SetUnderWorld(atof(row[3]));
  2207. zone->SetSafeX(atof(row[4]));
  2208. zone->SetSafeY(atof(row[5]));
  2209. zone->SetSafeZ(atof(row[6]));
  2210. zone->SetMinimumStatus(atoi(row[7]));
  2211. zone->SetMinimumLevel(atoi(row[8]));
  2212. zone->SetMaximumLevel(atoi(row[9]));
  2213. int8 type = (atoi(row[10]) == 0) ? 0 : atoi(row[10]) - 1;
  2214. zone->SetInstanceType(type);
  2215. zone->SetShutdownTimer(atoul(row[11]));
  2216. char* zone_motd = row[12];
  2217. if (zone_motd && strlen(zone_motd) > 0)
  2218. zone->SetZoneMOTD(string(zone_motd));
  2219. zone->SetDefaultReenterTime(atoi(row[13]));
  2220. zone->SetDefaultResetTime(atoi(row[14]));
  2221. zone->SetDefaultLockoutTime(atoi(row[15]));
  2222. zone->SetForceGroupZoneOption(atoi(row[16]));
  2223. zone->SetSafeHeading(atof(row[17]));
  2224. zone->SetXPModifier(atof(row[18]));
  2225. if ((ruleset_id = atoul(row[19])) > 0 && !rule_manager.SetZoneRuleSet(zone->GetZoneID(), ruleset_id))
  2226. LogWrite(ZONE__ERROR, 0, "Zones", "Error setting rule set for zone '%s' (%u). A rule set with ID %u does not exist.", zone->GetZoneName(), zone->GetZoneID(), ruleset_id);
  2227. // check data_version to see if client has proper expansion to enter a zone
  2228. zone->SetMinimumVersion(GetMinimumClientVersion(atoi(row[20])));
  2229. zone->SetWeatherAllowed(atoi(row[21]) == 0 ? false : true);
  2230. zone->SetZoneSkyFile(row[22]);
  2231. if (zone->IsInstanceZone())
  2232. {
  2233. if ( zone->GetInstanceID() < 1 )
  2234. zone->SetupInstance(CreateNewInstance(zone->GetZoneID()));
  2235. else
  2236. zone->SetupInstance(zone->GetInstanceID());
  2237. }
  2238. }
  2239. safe_delete_array(escaped);
  2240. }
  2241. void WorldDatabase::LoadZoneInfo(ZoneInfo* zone_info) {
  2242. Query query;
  2243. int32 ruleset_id;
  2244. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT name, file, description, underworld, safe_x, safe_y, safe_z, min_status, min_level, max_level, instance_type, shutdown_timer, zone_motd, default_reenter_time, default_reset_time, default_lockout_time, force_group_to_zone, lua_script, xp_modifier, ruleset_id, expansion_id, always_loaded, city_zone, start_zone, zone_type, weather_allowed FROM zones WHERE id = %u", zone_info->id);
  2245. if (result && mysql_num_rows(result) > 0) {
  2246. MYSQL_ROW row;
  2247. row = mysql_fetch_row(result);
  2248. strncpy(zone_info->name, row[0], sizeof(zone_info->name));
  2249. strncpy(zone_info->file, row[1], sizeof(zone_info->file));
  2250. strncpy(zone_info->description, row[2], sizeof(zone_info->description));
  2251. zone_info->underworld = atof(row[3]);
  2252. zone_info->safe_x = atof(row[4]);
  2253. zone_info->safe_y = atof(row[5]);
  2254. zone_info->safe_z = atof(row[6]);
  2255. zone_info->min_status = atoi(row[7]);
  2256. zone_info->min_level = atoi(row[8]);
  2257. zone_info->max_level = atoi(row[9]);
  2258. zone_info->instance_type = (atoi(row[10]) == 0) ? 0 : atoi(row[10]) - 1;
  2259. zone_info->shutdown_timer = atoul(row[11]);
  2260. row[12] == NULL ? strncpy(zone_info->zone_motd, "", sizeof(zone_info->zone_motd)) : strncpy(zone_info->zone_motd, row[12], sizeof(zone_info->zone_motd));
  2261. zone_info->default_reenter_time = atoi(row[13]);
  2262. zone_info->default_reset_time = atoi(row[14]);
  2263. zone_info->default_lockout_time = atoi(row[15]);
  2264. zone_info->force_group_to_zone = atoi(row[16]);
  2265. row[17] == NULL ? strncpy(zone_info->lua_script, "", sizeof(zone_info->lua_script)) : strncpy(zone_info->lua_script, row[17], sizeof(zone_info->lua_script));
  2266. zone_info->xp_modifier = atof(row[18]);
  2267. zone_info->ruleset_id = atoul(row[19]);
  2268. if ((ruleset_id = atoul(row[19])) > 0 && !rule_manager.SetZoneRuleSet(zone_info->id, ruleset_id))
  2269. LogWrite(ZONE__ERROR, 0, "Zones", "Error setting rule set for zone '%s' (%u). A rule set with ID %u does not exist.", zone_info->name, zone_info->id, ruleset_id);
  2270. zone_info->expansion_id = atoi(row[20]);
  2271. zone_info->min_version = GetMinimumClientVersion(zone_info->expansion_id);
  2272. zone_info->always_loaded = atoi(row[21]);
  2273. zone_info->city_zone = atoi(row[22]);
  2274. zone_info->start_zone = atoi(row[23]);
  2275. row[24] == NULL ? strncpy(zone_info->zone_type, "", sizeof(zone_info->zone_type)) : strncpy(zone_info->zone_type, row[24], sizeof(zone_info->zone_type));
  2276. zone_info->weather_allowed = atoi(row[25]);
  2277. }
  2278. }
  2279. void WorldDatabase::SaveZoneInfo(int32 zone_id, const char* field, sint32 value) {
  2280. Query query;
  2281. query.RunQuery2(Q_UPDATE, "UPDATE `zones` SET `%s`=%i WHERE `id`=%u", field, value, zone_id);
  2282. }
  2283. void WorldDatabase::SaveZoneInfo(int32 zone_id, const char* field, float value) {
  2284. Query query;
  2285. query.RunQuery2(Q_UPDATE, "UPDATE `zones` SET `%s`=%f WHERE `id`=%u", field, value, zone_id);
  2286. }
  2287. void WorldDatabase::SaveZoneInfo(int32 zone_id, const char* field, const char* value) {
  2288. Query query;
  2289. query.RunQuery2(Q_UPDATE, "UPDATE `zones` SET `%s`='%s' WHERE `id`=%u", field, const_cast<char*>(getEscapeString(value)), zone_id);
  2290. }
  2291. int32 WorldDatabase::GetZoneID(const char* name) {
  2292. int32 zone_id = 0;
  2293. Query query;
  2294. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `id` FROM zones WHERE `name`='%s'", name);
  2295. if (result && mysql_num_rows(result) > 0) {
  2296. MYSQL_ROW row;
  2297. row = mysql_fetch_row(result);
  2298. zone_id = atoi(row[0]);
  2299. }
  2300. return zone_id;
  2301. }
  2302. bool WorldDatabase::GetZoneRequirements(const char* zoneName, sint16* minStatus, int16* minLevel, int16* maxLevel, int16* minVersion) {
  2303. Query query;
  2304. char* escaped = getEscapeString(zoneName);
  2305. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT min_status, min_level, max_level, expansion_id FROM zones where name='%s'",escaped);
  2306. if(result && mysql_num_rows(result) > 0) {
  2307. MYSQL_ROW row;
  2308. row = mysql_fetch_row(result);
  2309. sint16 status = (sint16)atoi(row[0]);
  2310. int16 levelMin = (int16)atoi(row[1]);
  2311. int16 levelMax = (int16)atoi(row[2]);
  2312. int8 expansion_id = (int8)atoi(row[3]);
  2313. *minStatus = status;
  2314. *minLevel = levelMin;
  2315. *maxLevel = levelMax;
  2316. if( expansion_id >= 40 ) // lowest client we support is RoK - exp04
  2317. *minVersion = GetMinimumClientVersion(expansion_id);
  2318. else
  2319. *minVersion = 0;
  2320. safe_delete_array(escaped);
  2321. return true;
  2322. }
  2323. safe_delete_array(escaped);
  2324. return false;
  2325. }
  2326. int16 WorldDatabase::GetMinimumClientVersion(int8 expansion_id)
  2327. {
  2328. /*
  2329. 1 n/a Classic Expansion
  2330. 2 adv01 Bloodline Chronicles
  2331. 3 adv02 Splitpaw Saga
  2332. 10 exp01 Desert of Flames
  2333. 20 exp02 Kingdom of Sky
  2334. 21 adv04 Fallen Dynasty
  2335. 30 exp03 Echoes of Faydwer
  2336. 40 exp04 Rise of Kunark
  2337. 50 exp05 The Shadow Odyssey
  2338. 60 exp06 Sentinel's Fate
  2339. 61 halas Halas Reborn
  2340. 70 exp07 Destiny of Velious
  2341. 80 exp08 Age of Discovery
  2342. */
  2343. int16 minVer = 0;
  2344. // TODO: eventually replace this with reading values from eq2expansions table
  2345. switch(expansion_id)
  2346. {
  2347. case 40: // ROK
  2348. {
  2349. minVer = 843;
  2350. break;
  2351. }
  2352. case 50: // TSO
  2353. {
  2354. minVer = 908;
  2355. break;
  2356. }
  2357. case 60: // SF
  2358. {
  2359. minVer = 1008;
  2360. break;
  2361. }
  2362. case 61: // Halas
  2363. {
  2364. minVer = 1045;
  2365. break;
  2366. }
  2367. case 70: // DoV
  2368. {
  2369. minVer = 1096;
  2370. break;
  2371. }
  2372. case 80: // AoD
  2373. {
  2374. minVer = 1144;
  2375. break;
  2376. }
  2377. case 90: // CoE
  2378. {
  2379. minVer = 1188;
  2380. break;
  2381. }
  2382. }
  2383. return minVer;
  2384. }
  2385. // returns Expansion Name depending on the connected client's data version
  2386. string WorldDatabase::GetExpansionIDByVersion(int16 version)
  2387. {
  2388. /*
  2389. 0 n/a Classic Expansion
  2390. 0 adv01 Bloodline Chronicles
  2391. 0 adv02 Splitpaw Saga
  2392. 0 exp01 Desert of Flames
  2393. 0 exp02 Kingdom of Sky
  2394. 0 adv04 Fallen Dynasty
  2395. 0 exp03 Echoes of Faydwer
  2396. 843 exp04 Rise of Kunark
  2397. 908 exp05 The Shadow Odyssey
  2398. 1008 exp06 Sentinel's Fate
  2399. 1045 halas Halas Reborn
  2400. 1096 exp07 Destiny of Velious
  2401. 1142 exp08 Age of Discovery
  2402. 1188 exp09 Chains of Eternity
  2403. 9999 (and beyond)
  2404. */
  2405. string ret = "";
  2406. if( version >= 9999 )
  2407. ret = "Unknown";
  2408. else if( version >= 1188 )
  2409. ret = "Chains of Eternity";
  2410. else if( version >= 1142 )
  2411. ret = "Age of Discovery";
  2412. else if( version >= 1096 )
  2413. ret = "Destiny of Velious";
  2414. else if( version >= 1045 )
  2415. ret = "Halas Reborn";
  2416. else if( version >= 1008 )
  2417. ret = "Sentinel's Fate";
  2418. else if( version >= 908 )
  2419. ret = "The Shadow Odyssey";
  2420. else if( version >= 843 )
  2421. ret = "Rise of Kunark";
  2422. else
  2423. ret = "Any";
  2424. return ret;
  2425. }
  2426. void WorldDatabase::LoadSpecialZones(){
  2427. Query query;
  2428. ZoneServer* zone = 0;
  2429. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, name, always_loaded, city_zone FROM zones where always_loaded = 1 or city_zone = 1");
  2430. if(result && mysql_num_rows(result) > 0) {
  2431. MYSQL_ROW row;
  2432. while(result && (row = mysql_fetch_row(result))){
  2433. zone = new ZoneServer(row[1]);
  2434. LoadZoneInfo(zone);
  2435. zone->Init();
  2436. zone->SetAlwaysLoaded(atoi(row[2]) == 1);
  2437. zone->SetCityZone(atoi(row[3]) == 1);
  2438. }
  2439. }
  2440. }
  2441. bool WorldDatabase::SpawnGroupRemoveAssociation(int32 group1, int32 group2){
  2442. Query query;
  2443. query.RunQuery2(Q_DELETE, "delete FROM spawn_location_group_associations where (group_id1 = %u and group_id2 = %u) or (group_id1 = %u and group_id2 = %u)", group1, group2, group2, group1);
  2444. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
  2445. LogWrite(WORLD__ERROR, 0, "World", "Error in SpawnGroupRemoveSpawn query '%s': %s", query.GetQuery(), query.GetError());
  2446. return false;
  2447. }
  2448. return true;
  2449. }
  2450. bool WorldDatabase::SpawnGroupAddAssociation(int32 group1, int32 group2){
  2451. Query query;
  2452. query.RunQuery2(Q_INSERT, "insert ignore into spawn_location_group_associations (group_id1, group_id2) values(%u, %u)", group1, group2);
  2453. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
  2454. LogWrite(WORLD__ERROR, 0, "World", "Error in SpawnGroupAddAssociation query '%s': %s", query.GetQuery(), query.GetError());
  2455. return false;
  2456. }
  2457. return true;
  2458. }
  2459. bool WorldDatabase::SpawnGroupAddSpawn(Spawn* spawn, int32 group_id){
  2460. Query query;
  2461. query.RunQuery2(Q_INSERT, "insert ignore into spawn_location_group (group_id, placement_id) values(%u, %u)", group_id, spawn->GetSpawnLocationPlacementID());
  2462. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
  2463. LogWrite(WORLD__ERROR, 0, "World", "Error in SpawnGroupAddSpawn query '%s': %s", query.GetQuery(), query.GetError());
  2464. return false;
  2465. }
  2466. return true;
  2467. }
  2468. bool WorldDatabase::SpawnGroupRemoveSpawn(Spawn* spawn, int32 group_id){
  2469. Query query;
  2470. query.RunQuery2(Q_DELETE, "delete FROM spawn_location_group where group_id = %u and placement_id = %u", group_id, spawn->GetSpawnLocationPlacementID());
  2471. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
  2472. LogWrite(WORLD__ERROR, 0, "World", "Error in SpawnGroupRemoveSpawn query '%s': %s", query.GetQuery(), query.GetError());
  2473. return false;
  2474. }
  2475. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT count(group_id) FROM spawn_location_group where group_id = %u", group_id);
  2476. if(result && mysql_num_rows(result) > 0) {
  2477. MYSQL_ROW row;
  2478. if((row = mysql_fetch_row(result))){
  2479. if(atoul(row[0]) == 0)
  2480. DeleteSpawnGroup(group_id);
  2481. }
  2482. }
  2483. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
  2484. LogWrite(WORLD__ERROR, 0, "World", "Error in SpawnGroupRemoveSpawn query '%s': %s", query.GetQuery(), query.GetError());
  2485. return false;
  2486. }
  2487. return true;
  2488. }
  2489. int32 WorldDatabase::CreateSpawnGroup(Spawn* spawn, string name)
  2490. {
  2491. int32 group_id = 0;
  2492. Query query;
  2493. // JA: As of 0.7.1, DB Milestone 2, Content Team needs to use group_id's from Raw Data, so start any manual group_id's > 100,000
  2494. query.RunQuery2(Q_INSERT, "INSERT INTO spawn_location_group (group_id, placement_id, name) SELECT IF(ISNULL(MAX(group_id))=1, 100000, MAX(group_id)+1), %u, '%s' FROM spawn_location_group", spawn->GetSpawnLocationPlacementID(), getSafeEscapeString(name.c_str()).c_str());
  2495. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF)
  2496. return 0;
  2497. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT max(group_id) FROM spawn_location_group");
  2498. if(result && mysql_num_rows(result) > 0)
  2499. {
  2500. MYSQL_ROW row;
  2501. if((row = mysql_fetch_row(result)))
  2502. {
  2503. if(row[0])
  2504. group_id = atoul(row[0]);
  2505. }
  2506. }
  2507. return group_id;
  2508. }
  2509. void WorldDatabase::DeleteSpawnGroup(int32 id){
  2510. Query query;
  2511. query.RunQuery2(Q_DELETE, "delete FROM spawn_location_group where group_id = %u", id);
  2512. }
  2513. bool WorldDatabase::SetGroupSpawnChance(int32 id, float chance){
  2514. Query query;
  2515. query.RunQuery2(Q_UPDATE, "replace into spawn_location_group_chances (group_id, percentage) values(%u, %f)", id, chance);
  2516. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
  2517. LogWrite(WORLD__ERROR, 0, "World", "Error in SetGroupSpawnChance query '%s': %s", query.GetQuery(), query.GetError());
  2518. return false;
  2519. }
  2520. return true;
  2521. }
  2522. int32 WorldDatabase::LoadSpawnGroupChances(ZoneServer* zone){
  2523. Query query;
  2524. int32 count = 0;
  2525. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT slgc.group_id, slgc.percentage FROM spawn_location_group_chances slgc, spawn_location_group slg, spawn_location_placement slp where slgc.group_id = slg.group_id and slg.placement_id = slp.id and slp.zone_id = %u", zone->GetZoneID());
  2526. if(result && mysql_num_rows(result) > 0) {
  2527. MYSQL_ROW row;
  2528. int32 group_id = 0;
  2529. float percent = 0;
  2530. while(result && (row = mysql_fetch_row(result))){
  2531. group_id = atoul(row[0]);
  2532. percent = atof(row[1]);
  2533. zone->AddSpawnGroupChance(group_id, percent);
  2534. count++;
  2535. }
  2536. }
  2537. return count;
  2538. }
  2539. int32 WorldDatabase::LoadSpawnLocationGroupAssociations(ZoneServer* zone){
  2540. Query query;
  2541. int32 count = 0;
  2542. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT distinct slga.group_id1, slga.group_id2 FROM spawn_location_group_associations slga, spawn_location_group slg, spawn_location_placement slp where (slg.group_id = slga.group_id1 or slg.group_id = slga.group_id2) and slg.placement_id = slp.id and slp.zone_id = %u", zone->GetZoneID());
  2543. if(result && mysql_num_rows(result) > 0) {
  2544. MYSQL_ROW row;
  2545. while(result && (row = mysql_fetch_row(result))){
  2546. zone->AddSpawnGroupAssociation(atoul(row[0]), atoul(row[1]));
  2547. count++;
  2548. }
  2549. }
  2550. return count;
  2551. }
  2552. int32 WorldDatabase::LoadSpawnLocationGroups(ZoneServer* zone){
  2553. Query query;
  2554. int32 count = 0;
  2555. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT slg.group_id, slg.placement_id, slp.spawn_location_id FROM spawn_location_group slg, spawn_location_placement slp WHERE slg.placement_id = slp.id and slp.zone_id = %u", zone->GetZoneID());
  2556. if(result && mysql_num_rows(result) > 0) {
  2557. MYSQL_ROW row;
  2558. int32 placement_id = 0;
  2559. int32 group_id = 0;
  2560. int32 spawn_location_id = 0;
  2561. while(result && (row = mysql_fetch_row(result))){
  2562. group_id = atoul(row[0]);
  2563. placement_id = atoul(row[1]);
  2564. spawn_location_id = atoul(row[2]);
  2565. zone->AddSpawnGroupLocation(group_id, placement_id, spawn_location_id);
  2566. count++;
  2567. }
  2568. }
  2569. return count;
  2570. }
  2571. int32 WorldDatabase::ProcessSpawnLocations(ZoneServer* zone, const char* sql_query, int8 type){
  2572. int32 number = 0;
  2573. Query query;
  2574. MYSQL_RES* result = query.RunQuery2(Q_SELECT, sql_query, zone->GetZoneID());
  2575. if(result && mysql_num_rows(result) > 0) {
  2576. MYSQL_ROW row;
  2577. int32 spawn_location_id = 0xFFFFFFFF;
  2578. SpawnLocation* spawn_location = 0;
  2579. while(result && (row = mysql_fetch_row(result))){
  2580. if((spawn_location_id == 0xFFFFFFFF) || atoul(row[0]) != spawn_location_id){
  2581. if(spawn_location){
  2582. zone->AddSpawnLocation(spawn_location_id, spawn_location);
  2583. number++;
  2584. }
  2585. spawn_location = new SpawnLocation();
  2586. }
  2587. SpawnEntry* entry = new SpawnEntry;
  2588. spawn_location_id = atoul(row[0]);
  2589. entry->spawn_location_id = spawn_location_id;
  2590. entry->spawn_entry_id = atoul(row[1]);
  2591. entry->spawn_type = type;
  2592. entry->spawn_id = atoul(row[9]);
  2593. entry->spawn_percentage = atof(row[10]);
  2594. entry->respawn = atoul(row[11]);
  2595. entry->expire_time = atoul(row[14]);
  2596. entry->expire_offset = atoul(row[15]);
  2597. spawn_location->x = atof(row[2]);
  2598. spawn_location->y = atof(row[3]);
  2599. spawn_location->z = atof(row[4]);
  2600. spawn_location->x_offset = atof(row[5]);
  2601. spawn_location->y_offset = atof(row[6]);
  2602. spawn_location->z_offset = atof(row[7]);
  2603. spawn_location->heading = atof(row[8]);
  2604. spawn_location->pitch = atof(row[16]);
  2605. spawn_location->roll = atof(row[17]);
  2606. spawn_location->conditional = atoi(row[18]);
  2607. spawn_location->total_percentage += entry->spawn_percentage;
  2608. spawn_location->grid_id = strtoul(row[12], NULL, 0);
  2609. spawn_location->placement_id = strtoul(row[13], NULL, 0);
  2610. spawn_location->AddSpawn(entry);
  2611. }
  2612. if(spawn_location){
  2613. zone->AddSpawnLocation(spawn_location_id, spawn_location);
  2614. number++;
  2615. }
  2616. }
  2617. return number;
  2618. }
  2619. void WorldDatabase::ResetDatabase(){
  2620. Query query;
  2621. query.RunQuery2("delete FROM table_versions where name != 'table_versions'", Q_DELETE);
  2622. }
  2623. void WorldDatabase::EnableConstraints(){
  2624. Query query;
  2625. query.RunQuery2("/*!40101 SET SQL_MODE=@OLD_SQL_MODE */", Q_DBMS);
  2626. query.RunQuery2("/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */", Q_DBMS);
  2627. }
  2628. void WorldDatabase::DisableConstraints(){
  2629. Query query;
  2630. query.RunQuery2("/*!40101 SET NAMES utf8 */", Q_DBMS);
  2631. query.RunQuery2("/*!40101 SET SQL_MODE=''*/", Q_DBMS);
  2632. query.RunQuery2("/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */", Q_DBMS);
  2633. query.RunQuery2("/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */", Q_DBMS);
  2634. }
  2635. void WorldDatabase::LoadSpawns(ZoneServer* zone)
  2636. {
  2637. Query query;
  2638. int32 npcs = 0, objects = 0, widgets = 0, signs = 0, ground_spawns = 0, spawn_groups = 0, spawn_group_associations = 0, spawn_group_chances = 0;
  2639. LogWrite(SPAWN__TRACE, 0, "Spawn", "Enter LoadSpawns");
  2640. npcs = ProcessSpawnLocations(zone, "SELECT sln.id, sle.id, slp.x, slp.y, slp.z, slp.x_offset, slp.y_offset, slp.z_offset, slp.heading, sle.spawn_id, sle.spawnpercentage, slp.respawn, slp.grid_id, slp.id, slp.expire_timer, slp.expire_offset, slp.pitch, slp.roll, sle.condition FROM spawn_location_placement slp, spawn_location_name sln, spawn_location_entry sle, spawn_npcs sn where sn.spawn_id = sle.spawn_id and sln.id = sle.spawn_location_id and sln.id = slp.spawn_location_id and slp.zone_id=%i ORDER BY sln.id, sle.id", SPAWN_ENTRY_TYPE_NPC);
  2641. objects = ProcessSpawnLocations(zone, "SELECT sln.id, sle.id, slp.x, slp.y, slp.z, slp.x_offset, slp.y_offset, slp.z_offset, slp.heading, sle.spawn_id, sle.spawnpercentage, slp.respawn, slp.grid_id, slp.id, slp.expire_timer, slp.expire_offset, slp.pitch, slp.roll, sle.condition FROM spawn_location_placement slp, spawn_location_name sln, spawn_location_entry sle, spawn_objects so where so.spawn_id = sle.spawn_id and sln.id = sle.spawn_location_id and sln.id = slp.spawn_location_id and slp.zone_id=%i ORDER BY sln.id, sle.id", SPAWN_ENTRY_TYPE_OBJECT);
  2642. widgets = ProcessSpawnLocations(zone, "SELECT sln.id, sle.id, slp.x, slp.y, slp.z, slp.x_offset, slp.y_offset, slp.z_offset, slp.heading, sle.spawn_id, sle.spawnpercentage, slp.respawn, slp.grid_id, slp.id, slp.expire_timer, slp.expire_offset, slp.pitch, slp.roll, sle.condition FROM spawn_location_placement slp, spawn_location_name sln, spawn_location_entry sle, spawn_widgets sw where sw.spawn_id = sle.spawn_id and sln.id = sle.spawn_location_id and sln.id = slp.spawn_location_id and slp.zone_id=%i ORDER BY sln.id, sle.id", SPAWN_ENTRY_TYPE_WIDGET);
  2643. signs = ProcessSpawnLocations(zone, "SELECT sln.id, sle.id, slp.x, slp.y, slp.z, slp.x_offset, slp.y_offset, slp.z_offset, slp.heading, sle.spawn_id, sle.spawnpercentage, slp.respawn, slp.grid_id, slp.id, slp.expire_timer, slp.expire_offset, slp.pitch, slp.roll, sle.condition FROM spawn_location_placement slp, spawn_location_name sln, spawn_location_entry sle, spawn_signs ss where ss.spawn_id = sle.spawn_id and sln.id = sle.spawn_location_id and sln.id = slp.spawn_location_id and slp.zone_id=%i ORDER BY sln.id, sle.id", SPAWN_ENTRY_TYPE_SIGN);
  2644. ground_spawns = ProcessSpawnLocations(zone, "SELECT sln.id, sle.id, slp.x, slp.y, slp.z, slp.x_offset, slp.y_offset, slp.z_offset, slp.heading, sle.spawn_id, sle.spawnpercentage, slp.respawn, slp.grid_id, slp.id, slp.expire_timer, slp.expire_offset, slp.pitch, slp.roll, sle.condition FROM spawn_location_placement slp, spawn_location_name sln, spawn_location_entry sle, spawn_ground sg where sg.spawn_id = sle.spawn_id and sln.id = sle.spawn_location_id and sln.id = slp.spawn_location_id and slp.zone_id=%i ORDER BY sln.id, sle.id", SPAWN_ENTRY_TYPE_GROUNDSPAWN);
  2645. spawn_groups = LoadSpawnLocationGroups(zone);
  2646. spawn_group_associations = LoadSpawnLocationGroupAssociations(zone);
  2647. spawn_group_chances = LoadSpawnGroupChances(zone);
  2648. LogWrite(SPAWN__INFO, 0, "Spawn", "Loaded for zone '%s' (%u):\n\t%u NPC(s), %u Object(s), %u Widget(s)\n\t%u Sign(s), %u Ground Spawn(s), %u Spawn Group(s)\n\t%u Spawn Group Association(s), %u Spawn Group Chance(s)", zone->GetZoneName(), zone->GetZoneID(), npcs, objects, widgets, signs, ground_spawns, spawn_groups, spawn_group_associations, spawn_group_chances);
  2649. LogWrite(SPAWN__TRACE, 0, "Spawn", "Exit LoadSpawns");
  2650. }
  2651. bool WorldDatabase::UpdateSpawnLocationSpawns(Spawn* spawn) {
  2652. Query query;
  2653. query.RunQuery2(Q_UPDATE, "update spawn_location_placement set x=%f, y=%f, z=%f, heading=%f, x_offset=%f, y_offset=%f, z_offset=%f, respawn=%u, expire_timer=%u, expire_offset=%u, grid_id=%u, pitch=%f, roll=%f where id = %u",
  2654. spawn->GetX(), spawn->GetY(), spawn->GetZ(), spawn->GetHeading(), spawn->GetXOffset(), spawn->GetYOffset(), spawn->GetZOffset(), spawn->GetRespawnTime(), spawn->GetExpireTime(), spawn->GetExpireOffsetTime(), spawn->appearance.pos.grid_id, spawn->GetPitch(), spawn->GetRoll(), spawn->GetSpawnLocationPlacementID());
  2655. if (query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF) {
  2656. LogWrite(WORLD__ERROR, 0, "World", "Error in UpdateSpawnLocationSpawns query '%s': %s", query.GetQuery(), query.GetError());
  2657. return false;
  2658. }
  2659. return true;
  2660. }
  2661. bool WorldDatabase::UpdateSpawnWidget(int32 widget_id, char* queryString) {
  2662. Query query;
  2663. query.RunQuery2(Q_UPDATE, "update spawn_widgets set %s where widget_id = %u",
  2664. queryString, widget_id);
  2665. if (query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF) {
  2666. LogWrite(WORLD__ERROR, 0, "World", "Error in UpdateSpawnWidget query '%s': %s", query.GetQuery(), query.GetError());
  2667. return false;
  2668. }
  2669. return true;
  2670. }
  2671. vector<string>* WorldDatabase::GetSpawnNameList(const char* in_name){
  2672. Query query;
  2673. string names = "";
  2674. vector<string>* ret = 0;
  2675. string name = getSafeEscapeString(in_name);
  2676. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT concat(spawn.id, ', ', name) FROM spawn where name like '%%%s%%'", name.c_str());
  2677. if(result && mysql_num_rows(result) > 0){
  2678. ret = new vector<string>;
  2679. MYSQL_ROW row;
  2680. int8 num = 0;
  2681. while(result && (row = mysql_fetch_row(result))){
  2682. if(num >= 10)
  2683. break;
  2684. ret->push_back(string(row[0]));
  2685. num++;
  2686. }
  2687. char total[60] = {0};
  2688. if(mysql_num_rows(result) > 10)
  2689. sprintf(total, "Total number of results: %u (Limited to 10)", (int32)mysql_num_rows(result));
  2690. else
  2691. sprintf(total, "Total number of results: %u", (int32)mysql_num_rows(result));
  2692. ret->push_back(string(total));
  2693. }
  2694. return ret;
  2695. }
  2696. string WorldDatabase::GetZoneName(char* zone_description){
  2697. string ret;
  2698. Query query;
  2699. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT name FROM zones where description = '%s'", getSafeEscapeString(zone_description).c_str());
  2700. if(result && mysql_num_rows(result) > 0){
  2701. MYSQL_ROW row = mysql_fetch_row(result);
  2702. ret = string(row[0]);
  2703. }
  2704. return ret;
  2705. }
  2706. void WorldDatabase::LoadRevivePoints(vector<RevivePoint*>* revive_points, int32 zone_id){
  2707. if(revive_points && revive_points->size() > 0){
  2708. LogWrite(WORLD__ERROR, 0, "World", "Revive points have already been loaded for this zone!");
  2709. return;
  2710. }
  2711. else if(!revive_points || zone_id == 0){
  2712. LogWrite(WORLD__ERROR, 0, "World", "LoadRevivePoints called with null variables!");
  2713. return;
  2714. }
  2715. Query query;
  2716. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT respawn_zone_id, location_name, safe_x, safe_y, safe_z, heading FROM revive_points where zone_id=%u ORDER BY id asc", zone_id);
  2717. if(revive_points && result && mysql_num_rows(result) > 0){
  2718. MYSQL_ROW row;
  2719. int32 id = 0;
  2720. RevivePoint* point = 0;
  2721. while(result && (row=mysql_fetch_row(result))){
  2722. point = new RevivePoint;
  2723. point->id = id;
  2724. point->zone_id = atoul(row[0]);
  2725. point->location_name = string(row[1]);
  2726. point->x = atof(row[2]);
  2727. point->y = atof(row[3]);
  2728. point->z = atof(row[4]);
  2729. point->heading = atof(row[5]);
  2730. revive_points->push_back(point);
  2731. id++;
  2732. }
  2733. }
  2734. }
  2735. int32 WorldDatabase::GetNextSpawnIDInZone(int32 zone_id)
  2736. {
  2737. Query query;
  2738. int32 ret = 0;
  2739. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT MAX(id) FROM spawn where id LIKE '%i____'", zone_id);
  2740. if(result && mysql_num_rows(result) > 0) {
  2741. MYSQL_ROW row;
  2742. row = mysql_fetch_row(result);
  2743. if(row[0])
  2744. ret = atoi(row[0]) + 1;
  2745. }
  2746. if( ret == 0 )
  2747. ret = zone_id * 10000; // there are no spawns for that zone yet, to start with the first ID
  2748. LogWrite(WORLD__DEBUG, 0, "World", "Next Spawn ID for Zone %i: %u", zone_id, ret);
  2749. return ret;
  2750. }
  2751. bool WorldDatabase::SaveSpawnInfo(Spawn* spawn){
  2752. Query query;
  2753. string name = getSafeEscapeString(spawn->GetName());
  2754. string suffix = getSafeEscapeString(spawn->GetSuffixTitle());
  2755. string prefix = getSafeEscapeString(spawn->GetPrefixTitle());
  2756. string last_name = getSafeEscapeString(spawn->GetLastName());
  2757. if(spawn->GetDatabaseID() == 0){
  2758. int8 isInstanceType = (spawn->GetZone()->GetInstanceType() == Instance_Type::PERSONAL_HOUSE_INSTANCE);
  2759. int32 new_spawn_id = GetNextSpawnIDInZone(spawn->GetZone()->GetZoneID());
  2760. query.RunQuery2(Q_INSERT, "insert into spawn (id, name, race, model_type, size, targetable, show_name, command_primary, command_secondary, visual_state, attackable, show_level, show_command_icon, display_hand_icon, faction_id, collision_radius, hp, power, prefix, suffix, last_name, is_instanced_spawn) values(%u, '%s', %i, %i, %i, %i, %i, %u, %u, %i, %i, %i, %i, %i, %u, %i, %u, %u, '%s', '%s', '%s', %u)",
  2761. new_spawn_id, name.c_str(), spawn->GetRace(), spawn->GetModelType(), spawn->GetSize(), spawn->appearance.targetable, spawn->appearance.display_name, spawn->GetPrimaryCommandListID(), spawn->GetSecondaryCommandListID(), spawn->GetVisualState(), spawn->appearance.attackable, spawn->appearance.show_level, spawn->appearance.show_command_icon, spawn->appearance.display_hand_icon, 0, spawn->appearance.pos.collision_radius, spawn->GetTotalHP(), spawn->GetTotalPower(), prefix.c_str(), suffix.c_str(), last_name.c_str(), isInstanceType);
  2762. if( new_spawn_id > 0 )
  2763. spawn->SetDatabaseID(new_spawn_id); // use the new zone_id range
  2764. else if( query.GetLastInsertedID() > 0 )
  2765. spawn->SetDatabaseID(query.GetLastInsertedID()); // else fall back to last_inserted_id
  2766. else
  2767. return false; // else, hang your head in shame as you are an utter failure
  2768. if(spawn->IsNPC()){
  2769. query.RunQuery2(Q_INSERT, "insert into spawn_npcs (spawn_id, min_level, max_level, enc_level, class_, gender, min_group_size, max_group_size, hair_type_id, facial_hair_type_id, wing_type_id, chest_type_id, legs_type_id, soga_hair_type_id, soga_facial_hair_type_id, soga_model_type, heroic_flag, action_state, mood_state, initial_state, activity_status, hide_hood, emote_state) values(%u, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i, %i)",
  2770. spawn->GetDatabaseID(), spawn->GetLevel(), spawn->GetLevel(), spawn->appearance.encounter_level, spawn->GetAdventureClass(), spawn->GetGender(), 0, 0, ((NPC*)spawn)->features.hair_type, ((NPC*)spawn)->features.hair_face_type,
  2771. ((NPC*)spawn)->features.wing_type, ((NPC*)spawn)->features.chest_type, ((NPC*)spawn)->features.legs_type, ((NPC*)spawn)->features.soga_hair_type, ((NPC*)spawn)->features.soga_hair_face_type, spawn->appearance.soga_model_type, spawn->appearance.heroic_flag, spawn->GetActionState(), spawn->GetMoodState(), spawn->GetInitialState(), spawn->GetActivityStatus(), spawn->appearance.hide_hood, spawn->appearance.emote_state);
  2772. }
  2773. else if(spawn->IsObject()){
  2774. query.RunQuery2(Q_INSERT, "insert into spawn_objects (spawn_id) values(%u)", spawn->GetDatabaseID());
  2775. }
  2776. else if(spawn->IsWidget()){
  2777. Widget* widget = (Widget*)spawn;
  2778. query.RunQuery2(Q_INSERT, "insert into spawn_widgets (spawn_id, widget_id) values(%u, %u)", spawn->GetDatabaseID(), widget->GetWidgetID());
  2779. }
  2780. else if(spawn->IsSign()){
  2781. query.RunQuery2(Q_INSERT, "insert into spawn_signs (spawn_id, description) values(%u, 'change me')", spawn->GetDatabaseID());
  2782. }
  2783. else if (spawn->IsGroundSpawn()) {
  2784. query.RunQuery2(Q_INSERT, "insert into spawn_ground (spawn_id) values(%u)", spawn->GetDatabaseID());
  2785. }
  2786. }
  2787. else{
  2788. if(spawn->IsNPC()){
  2789. query.RunQuery2(Q_UPDATE, "update spawn_npcs, spawn set name='%s', min_level=%i, max_level=%i, enc_level=%i, race=%i, model_type=%i, class_=%i, gender=%i, show_name=%i, attackable=%i, show_level=%i, targetable=%i, show_command_icon=%i, display_hand_icon=%i, hair_type_id=%i, facial_hair_type_id=%i, wing_type_id=%i, chest_type_id=%i, legs_type_id=%i, soga_hair_type_id=%i, soga_facial_hair_type_id=%i, soga_model_type=%i, size=%i, hp=%u, heroic_flag=%i, power=%u, collision_radius=%i, command_primary=%u, command_secondary=%u, visual_state=%i, action_state=%i, mood_state=%i, initial_state=%i, activity_status=%i, alignment=%i, faction_id=%u, hide_hood=%i, emote_state=%i, suffix ='%s', prefix='%s', last_name='%s' where spawn_npcs.spawn_id = spawn.id and spawn.id = %u",
  2790. name.c_str(), spawn->GetLevel(), spawn->GetLevel(), spawn->appearance.encounter_level, spawn->GetRace(), spawn->GetModelType(),
  2791. spawn->GetAdventureClass(), spawn->GetGender(), spawn->appearance.display_name, spawn->appearance.attackable, spawn->appearance.show_level, spawn->appearance.targetable, spawn->appearance.show_command_icon, spawn->appearance.display_hand_icon, ((NPC*)spawn)->features.hair_type,
  2792. ((NPC*)spawn)->features.hair_face_type, ((NPC*)spawn)->features.wing_type, ((NPC*)spawn)->features.chest_type, ((NPC*)spawn)->features.legs_type, ((NPC*)spawn)->features.soga_hair_type, ((NPC*)spawn)->features.soga_hair_face_type, spawn->appearance.soga_model_type, spawn->GetSize(),
  2793. spawn->GetTotalHP(), spawn->appearance.heroic_flag, spawn->GetTotalPower(), spawn->GetCollisionRadius(), spawn->GetPrimaryCommandListID(),
  2794. spawn->GetSecondaryCommandListID(), spawn->GetVisualState(), spawn->GetActionState(), spawn->GetMoodState(), spawn->GetInitialState(),
  2795. spawn->GetActivityStatus(), ((NPC*)spawn)->GetAlignment(), spawn->GetFactionID(), spawn->appearance.hide_hood, spawn->appearance.emote_state,
  2796. suffix.c_str(), prefix.c_str(), last_name.c_str(), spawn->GetDatabaseID());
  2797. }
  2798. else if(spawn->IsObject()){
  2799. query.RunQuery2(Q_UPDATE, "update spawn_objects, spawn set name='%s', model_type=%i, show_name=%i, targetable=%i, size=%i, command_primary=%u, command_secondary=%u, visual_state=%i, attackable=%i, show_level=%i, show_command_icon=%i, display_hand_icon=%i, collision_radius=%i, hp = %u, power = %u, device_id = %i where spawn_objects.spawn_id = spawn.id and spawn.id = %u",
  2800. name.c_str(), spawn->GetModelType(), spawn->appearance.display_name, spawn->appearance.targetable, spawn->GetSize(), spawn->GetPrimaryCommandListID(), spawn->GetSecondaryCommandListID(), spawn->GetVisualState(), spawn->appearance.attackable, spawn->appearance.show_level, spawn->appearance.show_command_icon, spawn->appearance.display_hand_icon,
  2801. spawn->GetCollisionRadius(), spawn->GetTotalHP(), spawn->GetTotalPower(), ((Object*)spawn)->GetDeviceID(), spawn->GetDatabaseID());
  2802. }
  2803. else if(spawn->IsWidget()){
  2804. Widget* widget = (Widget*)spawn;
  2805. char* openSound = 0;
  2806. char* closeSound = 0;
  2807. if (widget->GetOpenSound() != NULL) openSound = (char*)widget->GetOpenSound(); else openSound = (char*)string("0").c_str();
  2808. if (widget->GetCloseSound() != NULL) closeSound = (char*)widget->GetCloseSound(); else closeSound = (char*)string("0").c_str();
  2809. query.RunQuery2(Q_UPDATE, "update spawn_widgets, spawn set name='%s', race=%i, model_type=%i, show_name=%i, attackable=%i, show_level=%i, show_command_icon=%i, display_hand_icon=%i, size=%i, hp=%u, power=%u, collision_radius=%i, command_primary=%u, command_secondary=%u, visual_state=%i, faction_id=%u, suffix ='%s', prefix='%s', last_name='%s',widget_id = %u,widget_x = %f,widget_y = %f,widget_z = %f,include_heading = %u,include_location = %u,icon = %u,type='%s',open_heading = %f,closed_heading = %f,open_x = %f,open_y = %f,open_z = %f,action_spawn_id = %u,open_sound_file='%s',close_sound_file='%s',open_duration = %u,close_x = %f,close_y=%f,close_z=%f,linked_spawn_id = %u,house_id = %u where spawn_widgets.spawn_id = spawn.id and spawn.id = %u",
  2810. name.c_str(), spawn->GetRace(), spawn->GetModelType(), spawn->appearance.display_name, spawn->appearance.attackable, spawn->appearance.show_level, spawn->appearance.show_command_icon, spawn->appearance.display_hand_icon, spawn->GetSize(),
  2811. spawn->GetTotalHP(), spawn->GetTotalPower(), spawn->GetCollisionRadius(), spawn->GetPrimaryCommandListID(), spawn->GetSecondaryCommandListID(), spawn->GetVisualState(), spawn->GetFactionID(),
  2812. suffix.c_str(), prefix.c_str(), last_name.c_str(), widget->GetWidgetID(), widget->GetX(), widget->GetY(), widget->GetZ(), widget->GetIncludeHeading(), widget->GetIncludeLocation(), widget->GetIconValue(), Widget::GetWidgetTypeNameByTypeID(widget->GetWidgetType()).c_str(),
  2813. widget->GetOpenHeading(), widget->GetClosedHeading(), widget->GetOpenX(), widget->GetOpenY(), widget->GetOpenZ(),
  2814. widget->GetActionSpawnID(), openSound, closeSound,widget->GetOpenDuration(),
  2815. widget->GetCloseX(),widget->GetCloseY(),widget->GetCloseZ(),widget->GetLinkedSpawnID(),widget->GetHouseID(),
  2816. spawn->GetDatabaseID());
  2817. }
  2818. else if(spawn->IsSign()){
  2819. Sign* sign = (Sign*)spawn;
  2820. query.RunQuery2(Q_UPDATE, "update spawn_signs, spawn set name='%s', race=%i, model_type=%i, show_name=%i, attackable=%i, show_level=%i, show_command_icon=%i, display_hand_icon=%i, size=%i, hp=%u, power=%u, collision_radius=%i, command_primary=%u, command_secondary=%u, visual_state=%i, faction_id=%u, suffix ='%s', prefix='%s', last_name='%s', type='%s', zone_id = %u, widget_id = %u, title='%s', widget_x = %f, widget_y = %f, widget_z = %f, icon = %u, description='%s', sign_distance = %f, zone_x = %f, zone_y = %f, zone_z = %f, zone_heading = %f, include_heading = %u, include_location = %u where spawn_signs.spawn_id = spawn.id and spawn.id = %u",
  2821. name.c_str(), spawn->GetRace(), spawn->GetModelType(), spawn->appearance.display_name, spawn->appearance.attackable, spawn->appearance.show_level, spawn->appearance.show_command_icon, spawn->appearance.display_hand_icon, spawn->GetSize(),
  2822. spawn->GetTotalHP(), spawn->GetTotalPower(), spawn->GetCollisionRadius(), spawn->GetPrimaryCommandListID(), spawn->GetSecondaryCommandListID(), spawn->GetVisualState(), spawn->GetFactionID(),
  2823. suffix.c_str(), prefix.c_str(), last_name.c_str(), sign->GetSignType(), sign->GetSignZoneID(),
  2824. sign->GetWidgetID(), sign->GetSignTitle(), sign->GetWidgetX(), sign->GetWidgetY(), sign->GetWidgetZ(),
  2825. sign->GetIconValue(), sign->GetSignDescription(), sign->GetSignDistance(), sign->GetSignZoneX(),
  2826. sign->GetSignZoneY(), sign->GetSignZoneZ(), sign->GetSignZoneHeading(), sign->GetIncludeHeading(),
  2827. sign->GetIncludeLocation(), spawn->GetDatabaseID());
  2828. }
  2829. }
  2830. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
  2831. LogWrite(SPAWN__ERROR, 0, "Spawn", "Error in SaveSpawnInfo query '%s': %s", query.GetQuery(), query.GetError());
  2832. return false;
  2833. }
  2834. return true;
  2835. }
  2836. int32 WorldDatabase::SaveCombinedSpawnLocation(ZoneServer* zone, Spawn* in_spawn, const char* name){
  2837. vector<Spawn*>* spawns = in_spawn->GetSpawnGroup();
  2838. uint32 spawnLocationID = 0;
  2839. if(spawns && spawns->size() > 0){
  2840. vector<Spawn*>::iterator itr;
  2841. map<Spawn*, int32>::iterator freq_itr;
  2842. Spawn* spawn = 0;
  2843. map<Spawn*, int32> database_spawns;
  2844. int32 total = 0;
  2845. float x_offset = GetSpawnLocationPlacementOffsetX(in_spawn->GetSpawnLocationID());
  2846. float y_offset = GetSpawnLocationPlacementOffsetY(in_spawn->GetSpawnLocationID());
  2847. float z_offset = GetSpawnLocationPlacementOffsetZ(in_spawn->GetSpawnLocationID());
  2848. int32 spawn_location_id = GetNextSpawnLocation();
  2849. spawnLocationID = spawn_location_id;
  2850. if(!name)
  2851. name = "Combine SpawnGroup Generated";
  2852. if(!CreateNewSpawnLocation(spawn_location_id, name)){
  2853. safe_delete(spawns);
  2854. return 0;
  2855. }
  2856. for(itr = spawns->begin();itr!=spawns->end();itr++){
  2857. spawn = *itr;
  2858. if (spawn) {
  2859. RemoveSpawnFromSpawnLocation(spawn);
  2860. spawn->SetSpawnLocationID(spawn_location_id);
  2861. bool add = true;
  2862. for (freq_itr = database_spawns.begin(); freq_itr != database_spawns.end(); freq_itr++) {
  2863. if (spawn->GetDatabaseID() == freq_itr->first->GetDatabaseID()) {
  2864. freq_itr->second++;
  2865. total++;
  2866. add = false;
  2867. }
  2868. }
  2869. if (add) {
  2870. database_spawns[spawn] = 1;
  2871. total++;
  2872. }
  2873. }
  2874. }
  2875. for(freq_itr = database_spawns.begin(); freq_itr != database_spawns.end(); freq_itr++){
  2876. int8 percent = (freq_itr->second*100)/total;
  2877. if(!SaveSpawnEntry(freq_itr->first, name, percent, x_offset, y_offset, z_offset, freq_itr->first == in_spawn, false)){
  2878. safe_delete(spawns);
  2879. return 0;
  2880. }
  2881. }
  2882. for(itr=spawns->begin();itr!=spawns->end();itr++){
  2883. spawn = *itr;
  2884. zone->RemoveSpawn(false, spawn);
  2885. }
  2886. safe_delete(spawns);
  2887. }
  2888. else{
  2889. safe_delete(spawns);
  2890. return 0;
  2891. }
  2892. return spawnLocationID;
  2893. }
  2894. bool WorldDatabase::SaveSpawnEntry(Spawn* spawn, const char* spawn_location_name, int8 percent, float x_offset, float y_offset, float z_offset, bool save_zonespawn, bool create_spawnlocation){
  2895. Query query;
  2896. Query query2;
  2897. int32 count = 0;
  2898. if(create_spawnlocation){
  2899. count = GetSpawnLocationCount(spawn->GetSpawnLocationID());
  2900. if(count == 0){
  2901. if(!CreateNewSpawnLocation(spawn->GetSpawnLocationID(), spawn_location_name))
  2902. return false;
  2903. }
  2904. }
  2905. query.RunQuery2(Q_INSERT, "insert into spawn_location_entry (spawn_id, spawn_location_id, spawnpercentage) values(%u, %u, %i)", spawn->GetDatabaseID(), spawn->GetSpawnLocationID(), percent);
  2906. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
  2907. LogWrite(SPAWN__ERROR, 0, "Spawn", "Error in SaveSpawnEntry query '%s': %s", query.GetQuery(), query.GetError());
  2908. return false;
  2909. }
  2910. if(save_zonespawn){
  2911. query2.RunQuery2(Q_INSERT, "insert into spawn_location_placement (zone_id, instance_id, spawn_location_id, x, y, z, x_offset, y_offset, z_offset, heading, grid_id) values(%u, %u, %u, %f, %f, %f, %f, %f, %f, %f, %u)", spawn->GetZone()->GetZoneID(), spawn->GetZone()->GetInstanceID(), spawn->GetSpawnLocationID(), spawn->GetX(), spawn->GetY(), spawn->GetZ(),x_offset, y_offset, z_offset, spawn->GetHeading(), spawn->appearance.pos.grid_id);
  2912. if(query2.GetErrorNumber() && query2.GetError() && query2.GetErrorNumber() < 0xFFFFFFFF){
  2913. LogWrite(SPAWN__ERROR, 0, "Spawn", "Error in SaveSpawnEntry query '%s': %s", query2.GetQuery(), query2.GetError());
  2914. return false;
  2915. }
  2916. }
  2917. return true;
  2918. }
  2919. float WorldDatabase::GetSpawnLocationPlacementOffsetX(int32 location_id) {
  2920. Query query;
  2921. MYSQL_ROW row;
  2922. float ret = 0;
  2923. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `x_offset` FROM `spawn_location_placement` WHERE `spawn_location_id`=%u", location_id);
  2924. if (result && (row = mysql_fetch_row(result))) {
  2925. if (row[0])
  2926. ret = atof(row[0]);
  2927. }
  2928. return ret;
  2929. }
  2930. float WorldDatabase::GetSpawnLocationPlacementOffsetY(int32 location_id) {
  2931. Query query;
  2932. MYSQL_ROW row;
  2933. float ret = 0;
  2934. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `y_offset` FROM `spawn_location_placement` WHERE `spawn_location_id`=%u", location_id);
  2935. if (result && (row = mysql_fetch_row(result))) {
  2936. if (row[0])
  2937. ret = atof(row[0]);
  2938. }
  2939. return ret;
  2940. }
  2941. float WorldDatabase::GetSpawnLocationPlacementOffsetZ(int32 location_id) {
  2942. Query query;
  2943. MYSQL_ROW row;
  2944. float ret = 0;
  2945. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `z_offset` FROM `spawn_location_placement` WHERE `spawn_location_id`=%u", location_id);
  2946. if (result && (row = mysql_fetch_row(result))) {
  2947. if (row[0])
  2948. ret = atof(row[0]);
  2949. }
  2950. return ret;
  2951. }
  2952. bool WorldDatabase::CreateNewSpawnLocation(int32 id, const char* name){
  2953. Query query;
  2954. if(!name)
  2955. name = "Unknown Spawn Location Name";
  2956. string str_name = getSafeEscapeString(name);
  2957. query.RunQuery2(Q_INSERT, "insert into spawn_location_name (id, name) values(%u, '%s')", id, str_name.c_str());
  2958. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
  2959. LogWrite(SPAWN__ERROR, 0, "Spawn", "Error in CreateNewSpawnLocation query '%s': %s", query.GetQuery(), query.GetError());
  2960. return false;
  2961. }
  2962. return true;
  2963. }
  2964. int32 WorldDatabase::GetSpawnLocationCount(int32 location, Spawn* spawn){
  2965. Query query;
  2966. int32 ret = 0;
  2967. MYSQL_RES* result = 0;
  2968. if(spawn)
  2969. result = query.RunQuery2(Q_SELECT, "SELECT count(id) FROM spawn_location_entry where spawn_location_id=%u and spawn_id=%u", location, spawn->GetDatabaseID());
  2970. if(result && mysql_num_rows(result) > 0){
  2971. MYSQL_ROW row;
  2972. while(result && (row = mysql_fetch_row(result)) && row[0]){
  2973. ret = strtoul(row[0], NULL, 0);
  2974. }
  2975. }
  2976. return ret;
  2977. }
  2978. int32 WorldDatabase::GetNextSpawnLocation(){
  2979. Query query;
  2980. int32 ret = 0;
  2981. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT max(id) FROM spawn_location_name");
  2982. if(result && mysql_num_rows(result) > 0){
  2983. MYSQL_ROW row;
  2984. while(result && (row = mysql_fetch_row(result)) && row[0]){
  2985. ret = strtoul(row[0], NULL, 0);
  2986. }
  2987. }
  2988. ret++;
  2989. return ret;
  2990. }
  2991. bool WorldDatabase::RemoveSpawnFromSpawnLocation(Spawn* spawn){
  2992. Query query;
  2993. Query query2;
  2994. int32 count = GetSpawnLocationCount(spawn->GetSpawnLocationID(), spawn);
  2995. query.RunQuery2(Q_DELETE, "delete FROM spawn_location_placement where spawn_location_id=%u", spawn->GetSpawnLocationID());
  2996. if(count == 1)
  2997. query.RunQuery2(Q_DELETE, "delete FROM spawn_location_name where id=%u", spawn->GetSpawnLocationID());
  2998. query2.RunQuery2(Q_DELETE, "delete FROM spawn_location_entry where spawn_id=%u and spawn_location_id = %u", spawn->GetDatabaseID(), spawn->GetSpawnLocationID());
  2999. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
  3000. LogWrite(WORLD__ERROR, 0, "World", "Error in RemoveSpawnFromSpawnLocation query '%s': %s", query.GetQuery(), query.GetError());
  3001. return false;
  3002. }
  3003. else if(query2.GetErrorNumber() && query2.GetError() && query2.GetErrorNumber() < 0xFFFFFFFF){
  3004. LogWrite(SPAWN__ERROR, 0, "Spawn", "Error in RemoveSpawnFromSpawnLocation query '%s': %s", query2.GetQuery(), query.GetError());
  3005. return false;
  3006. }
  3007. return true;
  3008. }
  3009. map<int32, string>* WorldDatabase::GetZoneList(const char* name, bool is_admin)
  3010. {
  3011. Query query;
  3012. map<int32, string>* ret = 0;
  3013. string zone_name = getSafeEscapeString(name);
  3014. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `id`, `name` FROM zones WHERE `name` RLIKE '%s' %s", zone_name.c_str(), (is_admin)?"":" LIMIT 0,10");
  3015. if(result && mysql_num_rows(result) > 0)
  3016. {
  3017. ret = new map<int32, string>;
  3018. MYSQL_ROW row;
  3019. while(result && (row = mysql_fetch_row(result)))
  3020. {
  3021. zone_name = row[1];
  3022. (*ret)[atoi(row[0])] = zone_name;
  3023. }
  3024. }
  3025. return ret;
  3026. }
  3027. void WorldDatabase::UpdateStartingFactions(int32 char_id, int8 choice){
  3028. Query query;
  3029. query.RunQuery2(Q_INSERT, "insert into character_factions (char_id, faction_id, faction_level) select %u, faction_id, value FROM starting_factions where starting_city=%i", char_id, choice);
  3030. }
  3031. string WorldDatabase::GetStartingZoneName(int8 choice){
  3032. Query query;
  3033. string zone_name = "";
  3034. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT name FROM zones where start_zone = %u", choice);
  3035. if(result && mysql_num_rows(result) > 0){
  3036. MYSQL_ROW row;
  3037. while(result && (row = mysql_fetch_row(result))){
  3038. zone_name = string(row[0]);
  3039. }
  3040. }
  3041. return zone_name;
  3042. }
  3043. void WorldDatabase::UpdateStartingZone(int32 char_id, int8 class_id, int8 race_id, int8 choice)
  3044. {
  3045. Query query;
  3046. LogWrite(PLAYER__DEBUG, 0, "Player", "Adding default zone for race: %i, class: %i for char_id: %u (choice: %i)", race_id, class_id, char_id, choice);
  3047. // first, check to see if there is a starting_zones record for this race/class/choice combo (now using extended Archetype/BaseClass/Class combos
  3048. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `name` FROM starting_zones sz, zones z WHERE sz.zone_id = z.id AND class_id IN (%i, %i, %i, 255) AND race_id IN (%i, 255) AND choice IN (%i, 255)",
  3049. classes.GetBaseClass(class_id), classes.GetSecondaryBaseClass(class_id), class_id, race_id, choice);
  3050. // TODO: verify client version so clients do not crash trying to enter zones they do not own (paks)
  3051. if(result && mysql_num_rows(result) > 0)
  3052. {
  3053. string zone_name = "ERROR";
  3054. MYSQL_ROW row;
  3055. if( result && (row = mysql_fetch_row(result)) )
  3056. zone_name = string(row[0]);
  3057. query.RunQuery2(Q_UPDATE, "UPDATE characters c, zones z, starting_zones sz SET c.current_zone_id = z.id, c.x = z.safe_x, c.y = z.safe_y, c.z = z.safe_z, c.starting_city = %i WHERE z.id = sz.zone_id AND sz.class_id IN (%i, %i, %i, 255) AND sz.race_id IN (%i, 255) AND sz.choice IN (%i, 255) AND c.id = %u",
  3058. choice, classes.GetBaseClass(class_id), classes.GetSecondaryBaseClass(class_id), class_id, race_id, choice, char_id);
  3059. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF){
  3060. LogWrite(PLAYER__ERROR, 0, "Player", "Error in UpdateStartingZone custom starting_zones, query: '%s': %s", query.GetQuery(), query.GetError());
  3061. return;
  3062. }
  3063. if(query.GetAffectedRows() > 0)
  3064. {
  3065. LogWrite(PLAYER__DEBUG, 0, "Player", "Setting New Character Starting Zone to '%s' FROM starting_zones table.", zone_name.c_str());
  3066. return;
  3067. }
  3068. }
  3069. else
  3070. {
  3071. // there was no matching starting_zone value, so use default 'choice' starting city
  3072. query.RunQuery2(Q_UPDATE, "UPDATE characters c, zones z SET c.current_zone_id = z.id, c.x = z.safe_x, c.y = z.safe_y, c.z = z.safe_z, c.starting_city = %i WHERE z.start_zone = %i and c.id = %u",
  3073. choice, choice, char_id);
  3074. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF)
  3075. {
  3076. LogWrite(PLAYER__ERROR, 0, "Player", "Error in UpdateStartingZone player choice, query: '%s': %s", query.GetQuery(), query.GetError());
  3077. return;
  3078. }
  3079. if(query.GetAffectedRows() > 0)
  3080. {
  3081. LogWrite(PLAYER__DEBUG, 0, "Player", "Setting New Character Starting Zone to '%s' FROM player choice.", GetStartingZoneName(choice).c_str());
  3082. return;
  3083. }
  3084. }
  3085. // if we are here, it's a bad thing. zone tables have no start_city values to match client 'choice', so throw the player into zone according to R_World::DefaultStartingZoneID rule.
  3086. // shout a few warnings so the admin fixes this asap!
  3087. int16 default_zone_id = rule_manager.GetGlobalRule(R_World, DefaultStartingZoneID)->GetInt16();
  3088. LogWrite(WORLD__WARNING, 0, "World", "No Starting City defined for player choice: %i! BAD! BAD! BAD! Defaulting player to zone %i.", choice, default_zone_id);
  3089. query.RunQuery2(Q_UPDATE, "UPDATE characters c, zones z SET c.current_zone_id = z.id, c.x = z.safe_x, c.y = z.safe_y, c.z = z.safe_z, c.heading = z.safe_heading, c.starting_city = 1 WHERE z.id = %i and c.id = %u", default_zone_id, char_id);
  3090. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF)
  3091. {
  3092. LogWrite(PLAYER__ERROR, 0, "Player", "Error in UpdateStartingZone default zone %i, query: '%s': %s", default_zone_id, query.GetQuery(), query.GetError());
  3093. return;
  3094. }
  3095. if(query.GetAffectedRows() > 0)
  3096. LogWrite(PLAYER__DEBUG, 0, "Player", "Setting New Character Starting Zone to '%s' due to no valid options!", GetZoneName(1)->c_str());
  3097. return;
  3098. }
  3099. void WorldDatabase::UpdateStartingItems(int32 char_id, int8 class_id, int8 race_id, bool base_class){
  3100. LogWrite(PLAYER__DEBUG, 0, "Player", "Adding default items for race: %i, class: %i for char_id: %u", race_id, class_id, char_id);
  3101. Query query;
  3102. Query query2;
  3103. vector<Item*> items;
  3104. vector<Item*> bags;
  3105. map<int32, int8> total_slots;
  3106. map<int32, int8> slots_left;
  3107. map<int8, bool> equip_slots;
  3108. map<Item*, StartingItem> item_list;
  3109. int32 item_id = 0;
  3110. Item* item = 0;
  3111. StartingItem* starting_item = 0;
  3112. //first get a list of the starting items for the character
  3113. MYSQL_RES* result = 0;
  3114. /*if(!base_class)
  3115. result = query2.RunQuery2(Q_SELECT, "SELECT `type`, item_id, creator, condition_, attuned, count FROM starting_items where (class_id=%i and race_id=%i) or (class_id=%i and race_id=255) or (class_id=255 and race_id=%i) or (class_id=255 and race_id=255) ORDER BY id", class_id, race_id, class_id, race_id);
  3116. else
  3117. result = query2.RunQuery2(Q_SELECT, "SELECT `type`, item_id, creator, condition_, attuned, count FROM starting_items where (class_id=%i and race_id=%i) or (class_id=%i and race_id=255) ORDER BY id", class_id, race_id, class_id);*/
  3118. result = query2.RunQuery2(Q_SELECT, "SELECT `type`, item_id, creator, condition_, attuned, count FROM starting_items WHERE class_id IN (%i, %i, %i, 255) AND race_id IN (%i, 255) ORDER BY id", classes.GetBaseClass(class_id), classes.GetSecondaryBaseClass(class_id), class_id, race_id);
  3119. if(result && mysql_num_rows(result) > 0){
  3120. MYSQL_ROW row;
  3121. while(result && (row = mysql_fetch_row(result))){
  3122. item_id = atoul(row[1]);
  3123. item = master_item_list.GetItem(item_id);
  3124. if(item){
  3125. starting_item = &(item_list[item]);
  3126. starting_item->type = (row[0]) ? string(row[0]) : "";
  3127. starting_item->item_id = atoul(row[1]);
  3128. starting_item->creator = (row[2]) ? string(row[2]) : "";
  3129. starting_item->condition = atoi(row[3]);
  3130. starting_item->attuned = atoi(row[4]);
  3131. starting_item->count = atoi(row[5]);
  3132. item = master_item_list.GetItem(starting_item->item_id);
  3133. if(item){
  3134. if(bags.size() < NUM_INV_SLOTS && item->IsBag() && item->details.num_slots > 0)
  3135. bags.push_back(item);
  3136. else
  3137. items.push_back(item);
  3138. }
  3139. }
  3140. }
  3141. }
  3142. slots_left[0] = NUM_INV_SLOTS;
  3143. //next create the bags in the inventory
  3144. for(int8 i=0;i<bags.size();i++){
  3145. item = bags[i];
  3146. query.RunQuery2(Q_INSERT, "insert into character_items (char_id, type, slot, item_id, creator, condition_, attuned, bag_id, count) values(%u, '%s', %i, %u, '%s', %i, %i, %u, %i)",
  3147. char_id, item_list[item].type.c_str(), i, item_list[item].item_id, getSafeEscapeString(item_list[item].creator.c_str()).c_str(), item_list[item].condition, item_list[item].attuned, 0, item_list[item].count);
  3148. slots_left[query.GetLastInsertedID()] = item->details.num_slots;
  3149. total_slots[query.GetLastInsertedID()] = item->details.num_slots;
  3150. slots_left[0]--;
  3151. }
  3152. map<int32, int8>::iterator itr;
  3153. int32 inv_slot = 0;
  3154. int8 slot = 0;
  3155. //finally process the rest of the items, placing them in the first available slot
  3156. for(int32 x=0;x<items.size();x++){
  3157. item = items[x];
  3158. if(item_list[item].type.find("NOT") < 0xFFFFFFFF){ // NOT-EQUIPPED Items
  3159. for(itr = slots_left.begin(); itr != slots_left.end(); itr++){
  3160. if(itr->second > 0){
  3161. if(itr->first == 0 && slots_left.size() > 1) //we want items to go into bags first, then inventory after bags are full
  3162. continue;
  3163. inv_slot = itr->first;
  3164. slot = total_slots[itr->first] - itr->second;
  3165. itr->second--;
  3166. if(itr->second == 0)
  3167. slots_left.erase(itr);
  3168. break;
  3169. }
  3170. }
  3171. query.RunQuery2(Q_INSERT, "insert into character_items (char_id, type, slot, item_id, creator, condition_, attuned, bag_id, count) values(%u, '%s', %i, %u, '%s', %i, %i, %u, %i)",
  3172. char_id, item_list[item].type.c_str(), slot, item_list[item].item_id, getSafeEscapeString(item_list[item].creator.c_str()).c_str(), item_list[item].condition, item_list[item].attuned, inv_slot, item_list[item].count);
  3173. }
  3174. else{ //EQUIPPED Items
  3175. for(int8 i=0;i<item->slot_data.size();i++){
  3176. if(equip_slots.count(item->slot_data[i]) == 0){
  3177. equip_slots[item->slot_data[i]] = true;
  3178. query.RunQuery2(Q_INSERT, "insert into character_items (char_id, type, slot, item_id, creator, condition_, attuned, bag_id, count) values(%u, '%s', %i, %u, '%s', %i, %i, %u, %i)",
  3179. char_id, item_list[item].type.c_str(), item->slot_data[i], item_list[item].item_id, getSafeEscapeString(item_list[item].creator.c_str()).c_str(), item_list[item].condition, item_list[item].attuned, 0, item_list[item].count);
  3180. break;
  3181. }
  3182. }
  3183. }
  3184. }
  3185. }
  3186. void WorldDatabase::UpdateStartingSkills(int32 char_id, int8 class_id, int8 race_id)
  3187. {
  3188. Query query;
  3189. LogWrite(PLAYER__DEBUG, 0, "Player", "Adding default skills for race: %i, class: %i for char_id: %u", race_id, class_id, char_id);
  3190. query.RunQuery2(Q_INSERT, "INSERT IGNORE INTO character_skills (char_id, skill_id, current_val, max_val) SELECT %u, skill_id, current_val, max_val FROM starting_skills WHERE class_id IN (%i, %i, %i, 255) AND race_id IN (%i, 255)",
  3191. char_id, classes.GetBaseClass(class_id), classes.GetSecondaryBaseClass(class_id), class_id, race_id);
  3192. }
  3193. void WorldDatabase::UpdateStartingSpells(int32 char_id, int8 class_id, int8 race_id){
  3194. Query query;
  3195. LogWrite(PLAYER__DEBUG, 0, "Player", "Adding default spells for race: %i, class: %i for char_id: %u", race_id, class_id, char_id);
  3196. query.RunQuery2(Q_INSERT, "INSERT IGNORE INTO character_spells (char_id, spell_id, tier, knowledge_slot) SELECT %u, spell_id, tier, knowledge_slot FROM starting_spells WHERE class_id IN (%i, %i, %i, 255) AND race_id IN (%i, 255)",
  3197. char_id, classes.GetBaseClass(class_id), classes.GetSecondaryBaseClass(class_id), class_id, race_id);
  3198. }
  3199. void WorldDatabase::UpdateStartingSkillbar(int32 char_id, int8 class_id, int8 race_id){
  3200. Query query;
  3201. LogWrite(PLAYER__DEBUG, 0, "Player", "Adding default skillbar for race: %i, class: %i for char_id: %u", race_id, class_id, char_id);
  3202. query.RunQuery2(Q_INSERT, "INSERT IGNORE INTO character_skillbar (char_id, type, hotbar, spell_id, slot, text_val) SELECT %u, type, hotbar, spell_id, slot, text_val FROM starting_skillbar WHERE class_id IN (%i, %i, %i, 255) AND race_id IN (%i, 255)",
  3203. char_id, classes.GetBaseClass(class_id), classes.GetSecondaryBaseClass(class_id), class_id, race_id);
  3204. }
  3205. void WorldDatabase::UpdateStartingTitles(int32 char_id, int8 class_id, int8 race_id, int8 gender_id) {
  3206. Query query;
  3207. LogWrite(PLAYER__DEBUG, 0, "Player", "Adding default titles for race: %i, class: %i, gender: %i for char_id: %u", race_id, class_id, gender_id, char_id);
  3208. query.RunQuery2(Q_INSERT, "INSERT IGNORE INTO character_titles (char_id, title_id) SELECT %u, title_id FROM starting_titles WHERE class_id IN (%i, %i, %i, 255) AND race_id IN (%i, 255) and gender_id IN (%i, 255)",
  3209. char_id, classes.GetBaseClass(class_id), classes.GetSecondaryBaseClass(class_id), class_id, race_id, gender_id);
  3210. }
  3211. string WorldDatabase::GetZoneDescription(int32 id){
  3212. Query query;
  3213. string ret = "";
  3214. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT description FROM zones where id = %u", id);
  3215. if(result && mysql_num_rows(result) > 0){
  3216. MYSQL_ROW row;
  3217. row = mysql_fetch_row(result);
  3218. ret = string(row[0]);
  3219. }
  3220. return ret;
  3221. }
  3222. string* WorldDatabase::GetZoneName(int32 id){
  3223. string* ret = new string;
  3224. if (zone_names.count(id) > 0){
  3225. ret->assign(zone_names[id]);
  3226. return ret;
  3227. }
  3228. Query query;
  3229. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `name` FROM zones where `id` = %u", id);
  3230. if(result && mysql_num_rows(result) > 0){
  3231. MYSQL_ROW row;
  3232. row = mysql_fetch_row(result);
  3233. zone_names[id] = row[0];
  3234. ret->assign(zone_names[id]);
  3235. }
  3236. return ret;
  3237. }
  3238. bool WorldDatabase::VerifyZone(const char* name){
  3239. Query query;
  3240. char* escaped = getEscapeString(name);
  3241. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT name FROM zones where name='%s'",escaped);
  3242. safe_delete_array(escaped);
  3243. if(result && mysql_num_rows(result) > 0)
  3244. return true;
  3245. else
  3246. return false;
  3247. }
  3248. int8 WorldDatabase::GetInstanceTypeByZoneID(int32 zoneID)
  3249. {
  3250. DatabaseResult result;
  3251. int8 ret = 0;
  3252. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Getting instances for zone_id %u", zoneID);
  3253. if( !database_new.Select(&result, "SELECT instance_type+0 FROM zones WHERE id = %u", zoneID) )
  3254. {
  3255. LogWrite(INSTANCE__ERROR, 0, "Instance", "Error in GetInstanceTypeByZoneID() '%s': %i", database_new.GetErrorMsg(), database_new.GetError());
  3256. return ret;
  3257. }
  3258. if( result.GetNumRows() > 0 )
  3259. {
  3260. result.Next();
  3261. ret = (result.GetInt8Str("instance_type+0") == 0) ? 0 : result.GetInt8Str("instance_type+0") - 1;
  3262. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Found instance type %i for zone_id %u", ret, zoneID);
  3263. }
  3264. else
  3265. LogWrite(INSTANCE__DEBUG, 0, "Instance", "No instances found for zone_id %u", zoneID);
  3266. return ret;
  3267. }
  3268. void WorldDatabase::Save(Client* client){
  3269. Query query;
  3270. Player* player = client->GetPlayer();
  3271. if(!player->CheckPlayerInfo())
  3272. return;
  3273. int32 instance_id = 0;
  3274. if ( client->GetCurrentZone ( ) != NULL )
  3275. instance_id = client->GetCurrentZone()->GetInstanceID();
  3276. int32 zone_id = 0;
  3277. if(client->GetCurrentZone())
  3278. zone_id = client->GetCurrentZone()->GetZoneID();
  3279. query.AddQueryAsync(client->GetCharacterID(), this, Q_UPDATE, "update characters set current_zone_id=%u, x=%f, y=%f, z=%f, heading=%f, level=%i,instance_id=%i,last_saved=%i, `class`=%i, `tradeskill_level`=%i, `tradeskill_class`=%i where id = %u", zone_id, player->GetX(), player->GetY(), player->GetZ(), player->GetHeading(), player->GetLevel(), instance_id, client->GetLastSavedTimeStamp(), client->GetPlayer()->GetAdventureClass(), client->GetPlayer()->GetTSLevel(), client->GetPlayer()->GetTradeskillClass(), client->GetCharacterID());
  3280. query.AddQueryAsync(client->GetCharacterID(), this, Q_UPDATE, "update character_details set hp=%u, power=%u, str=%i, sta=%i, agi=%i, wis=%i, intel=%i, heat=%i, cold=%i, magic=%i, mental=%i, divine=%i, disease=%i, poison=%i, coin_copper=%u, coin_silver=%u, coin_gold=%u, coin_plat=%u, max_hp = %u, max_power=%u, xp = %u, xp_needed = %u, xp_debt = %u, xp_vitality = %f, tradeskill_xp = %u, tradeskill_xp_needed = %u, tradeskill_xp_vitality = %f, bank_copper = %u, bank_silver = %u, bank_gold = %u, bank_plat = %u, bind_zone_id=%u, bind_x = %f, bind_y = %f, bind_z = %f, bind_heading = %f, house_zone_id=%u, combat_voice = %i, emote_voice = %i, biography='%s', flags=%u, flags2=%u, last_name='%s' where char_id = %u",
  3281. player->GetHP(), player->GetPower(), player->GetStrBase(), player->GetStaBase(), player->GetAgiBase(), player->GetWisBase(), player->GetIntBase(), player->GetHeatResistanceBase(), player->GetColdResistanceBase(), player->GetMagicResistanceBase(),
  3282. player->GetMentalResistanceBase(), player->GetDivineResistanceBase(), player->GetDiseaseResistanceBase(), player->GetPoisonResistanceBase(), player->GetCoinsCopper(), player->GetCoinsSilver(), player->GetCoinsGold(), player->GetCoinsPlat(), player->GetTotalHPBase(), player->GetTotalPowerBase(), player->GetXP(), player->GetNeededXP(), player->GetXPDebt(), player->GetXPVitality(), player->GetTSXP(), player->GetNeededTSXP(), player->GetTSXPVitality(), player->GetBankCoinsCopper(),
  3283. player->GetBankCoinsSilver(), player->GetBankCoinsGold(), player->GetBankCoinsPlat(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneID(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneX(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneY(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneZ(), client->GetPlayer()->GetPlayerInfo()->GetBindZoneHeading(), client->GetPlayer()->GetPlayerInfo()->GetHouseZoneID(),
  3284. client->GetPlayer()->GetCombatVoice(), client->GetPlayer()->GetEmoteVoice(), getSafeEscapeString(client->GetPlayer()->GetBiography().c_str()).c_str(), player->GetFlags(), player->GetFlags2(), client->GetPlayer()->GetLastName(), client->GetCharacterID());
  3285. map<string, int8>::iterator itr;
  3286. map<string, int8>* friends = player->GetFriends();
  3287. if(friends && friends->size() > 0){
  3288. for(itr = friends->begin(); itr != friends->end(); itr++){
  3289. if(itr->second == 1){
  3290. query.AddQueryAsync(client->GetCharacterID(), this, Q_INSERT, "insert ignore into character_social (char_id, name, type) values(%u, '%s', 'FRIEND')", client->GetCharacterID(), getSafeEscapeString(itr->first.c_str()).c_str());
  3291. itr->second = 0;
  3292. }
  3293. else if(itr->second == 2){
  3294. query.AddQueryAsync(client->GetCharacterID(), this, Q_DELETE, "delete FROM character_social where char_id = %u and name = '%s'", client->GetCharacterID(), getSafeEscapeString(itr->first.c_str()).c_str());
  3295. itr->second = 3;
  3296. }
  3297. }
  3298. }
  3299. map<string, int8>* ignored = player->GetIgnoredPlayers();
  3300. if(ignored && ignored->size() > 0){
  3301. for(itr = ignored->begin(); itr != ignored->end(); itr++){
  3302. if(itr->second == 1){
  3303. query.AddQueryAsync(client->GetCharacterID(), this, Q_INSERT, "insert ignore into character_social (char_id, name, type) values(%u, '%s', 'IGNORE')", client->GetCharacterID(), getSafeEscapeString(itr->first.c_str()).c_str());
  3304. itr->second = 0;
  3305. }
  3306. else if(itr->second == 2){
  3307. query.AddQueryAsync(client->GetCharacterID(), this, Q_DELETE, "delete FROM character_social where char_id = %u and name = '%s'", client->GetCharacterID(), getSafeEscapeString(itr->first.c_str()).c_str());
  3308. itr->second = 3;
  3309. }
  3310. }
  3311. }
  3312. SavePlayerFactions(client);
  3313. SaveCharacterQuests(client);
  3314. SaveCharacterSkills(client);
  3315. SavePlayerSpells(client);
  3316. SavePlayerMail(client);
  3317. SavePlayerCollections(client);
  3318. LogWrite(PLAYER__INFO, 3, "Player", "Player '%s' (%u) data saved.", player->GetName(), player->GetCharacterID());
  3319. }
  3320. void WorldDatabase::LoadEntityCommands(ZoneServer* zone) {
  3321. int32 total = 0;
  3322. int32 id = 0;
  3323. EntityCommand* command = 0;
  3324. DatabaseResult result;
  3325. if (!database_new.Select(&result, "SELECT `command_list_id`, `command_text`, `distance`, `command`, `error_text`, `cast_time`, `spell_visual` FROM `entity_commands` ORDER BY `id`")) {
  3326. LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
  3327. return;
  3328. }
  3329. while (result.Next()) {
  3330. command = new EntityCommand;
  3331. id = result.GetInt32(0);
  3332. command->name = result.GetString(1);
  3333. command->distance = result.GetFloat(2);
  3334. command->command = result.GetString(3);
  3335. command->error_text = result.GetString(4);
  3336. command->cast_time = result.GetInt16(5);
  3337. command->spell_visual = result.GetInt32(6);
  3338. command->default_allow_list = true;
  3339. zone->SetEntityCommandList(id, command);
  3340. LogWrite(COMMAND__DEBUG, 5, "Command", "---Loading Command: '%s' (%s)", command->name.c_str(), command->command.c_str());
  3341. total++;
  3342. }
  3343. LogWrite(COMMAND__DEBUG, 0, "Command", "--Loaded %i entity command(s)", total);
  3344. }
  3345. void WorldDatabase::LoadFactionAlliances()
  3346. {
  3347. LogWrite(FACTION__DEBUG, 1, "Faction", "-Loading faction alliances...");
  3348. int32 total = 0;
  3349. int32 fTotal = 0;
  3350. int32 hTotal = 0;
  3351. Query query;
  3352. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT faction_id, friend_faction, hostile_faction FROM faction_alliances");
  3353. if(result && mysql_num_rows(result) > 0)
  3354. {
  3355. MYSQL_ROW row;
  3356. int32 faction_id = 0;
  3357. int32 friendly_id = 0;
  3358. int32 hostile_id = 0;
  3359. while(result && (row = mysql_fetch_row(result)))
  3360. {
  3361. faction_id = atoul(row[0]);
  3362. friendly_id = atoul(row[1]);
  3363. hostile_id = atoul(row[2]);
  3364. if(friendly_id > 0)
  3365. {
  3366. master_faction_list.AddFriendlyFaction(faction_id, friendly_id);
  3367. fTotal++;
  3368. LogWrite(FACTION__DEBUG, 5, "Faction", "---Faction %i is friendly towards %i", faction_id, friendly_id);
  3369. }
  3370. if(hostile_id > 0)
  3371. {
  3372. master_faction_list.AddHostileFaction(faction_id, hostile_id);
  3373. hTotal++;
  3374. LogWrite(FACTION__DEBUG, 5, "Faction", "---Faction %i is hostile towards %i", faction_id, hostile_id);
  3375. }
  3376. total++;
  3377. }
  3378. }
  3379. LogWrite(FACTION__DEBUG, 3, "Faction", "--Loaded %u Alliances: %i friendly, %i hostile", total, fTotal, hTotal);
  3380. }
  3381. bool WorldDatabase::UpdateSpawnScriptData(int32 spawn_id, int32 spawn_location_id, int32 spawnentry_id, const char* name){
  3382. bool ret = false;
  3383. if((spawn_id > 0 || spawn_location_id > 0 || spawnentry_id > 0) && name){
  3384. Query query;
  3385. int32 row_id = 0;
  3386. if(spawn_id > 0){
  3387. query.RunQuery2(Q_DELETE, "DELETE FROM spawn_scripts where spawn_id=%u", spawn_id);
  3388. query.RunQuery2(Q_INSERT, "INSERT into spawn_scripts (spawn_id, lua_script) values(%u, '%s')", spawn_id, getSafeEscapeString(name).c_str());
  3389. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF)
  3390. LogWrite(LUA__ERROR, 0, "LUA", "Error in UpdateSpawnScriptData, Query: %s, Error: %s", query.GetQuery(), query.GetError());
  3391. else{
  3392. row_id = query.GetLastInsertedID();
  3393. if(row_id > 0)
  3394. world.AddSpawnScript(row_id, name);
  3395. ret = true;
  3396. }
  3397. }
  3398. else if(spawn_location_id > 0){
  3399. query.RunQuery2(Q_DELETE, "DELETE FROM spawn_scripts where spawn_location_id=%u", spawn_location_id);
  3400. query.RunQuery2(Q_INSERT, "INSERT into spawn_scripts (spawn_location_id, lua_script) values(%u, '%s')", spawn_location_id, getSafeEscapeString(name).c_str());
  3401. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF)
  3402. LogWrite(LUA__ERROR, 0, "LUA", "Error in UpdateSpawnScriptData, Query: %s, Error: %s", query.GetQuery(), query.GetError());
  3403. else{
  3404. row_id = query.GetLastInsertedID();
  3405. if(row_id > 0)
  3406. world.AddSpawnLocationScript(row_id, name);
  3407. ret = true;
  3408. }
  3409. }
  3410. else if(spawnentry_id > 0){
  3411. query.RunQuery2(Q_DELETE, "DELETE FROM spawn_scripts where spawnentry_id=%u", spawnentry_id);
  3412. query.RunQuery2(Q_INSERT, "INSERT into spawn_scripts (spawnentry_id, lua_script) values(%u, '%s')", spawnentry_id, getSafeEscapeString(name).c_str());
  3413. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF)
  3414. LogWrite(LUA__ERROR, 0, "LUA", "Error in UpdateSpawnScriptData, Query: %s, Error: %s", query.GetQuery(), query.GetError());
  3415. else{
  3416. row_id = query.GetLastInsertedID();
  3417. if(row_id > 0)
  3418. world.AddSpawnEntryScript(row_id, name);
  3419. ret = true;
  3420. }
  3421. }
  3422. }
  3423. return ret;
  3424. }
  3425. void WorldDatabase::LoadSpawnScriptData() {
  3426. int32 total = 0;
  3427. Query query;
  3428. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT spawn_id, spawnentry_id, spawn_location_id, lua_script FROM spawn_scripts");
  3429. if(result && mysql_num_rows(result) > 0)
  3430. {
  3431. MYSQL_ROW row;
  3432. int32 spawn_id = 0;
  3433. int32 spawnentry_id = 0;
  3434. int32 spawn_location_id = 0;
  3435. while(result && (row = mysql_fetch_row(result)))
  3436. {
  3437. spawn_id = atoul(row[0]);
  3438. spawnentry_id = atoul(row[1]);
  3439. spawn_location_id = atoul(row[2]);
  3440. string spawn_script = string(row[3]);
  3441. if(spawnentry_id > 0)
  3442. {
  3443. world.AddSpawnEntryScript(spawnentry_id, row[3]);
  3444. total++;
  3445. }
  3446. else if(spawn_location_id > 0)
  3447. {
  3448. world.AddSpawnLocationScript(spawn_location_id, row[3]);
  3449. total++;
  3450. }
  3451. else if(spawn_id > 0)
  3452. {
  3453. world.AddSpawnScript(spawn_id, row[3]);
  3454. total++;
  3455. }
  3456. else {
  3457. if(row[3])
  3458. LogWrite(LUA__ERROR, 0, "LUA", "Invalid Entry in spawn_scripts table for lua_script '%s' (spawn_id, spawnentry_id and spawn_location_id are all 0)", row[3]);
  3459. else
  3460. LogWrite(LUA__ERROR, 0, "LUA", "Invalid Entry in spawn_scripts table.");
  3461. }
  3462. if( spawn_id || spawnentry_id || spawn_location_id ) {
  3463. LogWrite(LUA__DEBUG, 5, "LUA", "SpawnScript %s loaded.", spawn_script.c_str());
  3464. }
  3465. spawn_id = 0;
  3466. spawnentry_id = 0;
  3467. spawn_location_id = 0;
  3468. }
  3469. }
  3470. LogWrite(LUA__DEBUG, 0, "LUA", "\tLoaded %u SpawnScript%s", total, total == 1 ? "" : "s");
  3471. }
  3472. void WorldDatabase::LoadZoneScriptData() {
  3473. Query query;
  3474. int32 total = 0;
  3475. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `id`, `lua_script` FROM `zones`");
  3476. if (result && mysql_num_rows(result) > 0) {
  3477. MYSQL_ROW row;
  3478. while(result && (row = mysql_fetch_row(result))) {
  3479. if (row[1]) {
  3480. int32 zone_id = atoul(row[0]);
  3481. string zone_script = string(row[1]);
  3482. if (zone_id > 0 && zone_script.length() > 0) {
  3483. LogWrite(LUA__DEBUG, 5, "LUA", "ZoneScript: %s loaded.", zone_script.c_str());
  3484. world.AddZoneScript(zone_id, zone_script.c_str());
  3485. total++;
  3486. }
  3487. }
  3488. }
  3489. }
  3490. LogWrite(LUA__DEBUG, 0, "LUA", "\tLoaded %u ZoneScript%s", total, total == 1 ? "" : "s");
  3491. }
  3492. int32 WorldDatabase::LoadSpellScriptData() {
  3493. Query query;
  3494. MYSQL_ROW row;
  3495. int32 count;
  3496. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `lua_script` FROM `spells`"); // WHERE is_active = 1
  3497. while (result && (row = mysql_fetch_row(result))) {
  3498. if (row[0] && strlen(row[0]) > 0) {
  3499. if (lua_interface->LoadLuaSpell(row[0]))
  3500. LogWrite(SPELL__DEBUG, 5, "Spells", "SpellScript: %s loaded.", row[0]);
  3501. }
  3502. }
  3503. count = mysql_num_rows(result);
  3504. LogWrite(SPELL__DEBUG, 0, "Spells", "\tLoaded %i SpellScript%s", count, count == 1 ? "" : "s");
  3505. return count;
  3506. }
  3507. void WorldDatabase::LoadFactionList() {
  3508. int32 total = 0;
  3509. Query query;
  3510. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, name, type, description, default_level, negative_change, positive_change FROM factions");
  3511. if(result && mysql_num_rows(result) > 0) {
  3512. MYSQL_ROW row;
  3513. Faction* faction = 0;
  3514. while(result && (row = mysql_fetch_row(result))){
  3515. faction = new Faction;
  3516. faction->id = atoul(row[0]);
  3517. faction->name = string(row[1]);
  3518. faction->type = string(row[2]);
  3519. faction->description = string(row[3]);
  3520. faction->default_value = atoi(row[4]);
  3521. faction->negative_change = atoi(row[5]);
  3522. faction->positive_change = atoi(row[6]);
  3523. master_faction_list.AddFaction(faction);
  3524. total++;
  3525. LogWrite(FACTION__DEBUG, 5, "Faction", "---Loading Faction '%s' (%u)", faction->name.c_str(), faction->id);
  3526. }
  3527. }
  3528. LogWrite(FACTION__DEBUG, 3, "Faction", "--Loaded %u Faction%s", total, total == 1 ? "" : "s");
  3529. LoadFactionAlliances();
  3530. }
  3531. void WorldDatabase::SavePlayerFactions(Client* client){
  3532. LogWrite(PLAYER__DEBUG, 3, "Player", "Saving Player Factions...");
  3533. Query query;
  3534. map<int32, sint32>* factions = client->GetPlayer()->GetFactions()->GetFactionValues();
  3535. map<int32, sint32>::iterator itr;
  3536. for(itr = factions->begin(); itr != factions->end(); itr++)
  3537. query.AddQueryAsync(client->GetCharacterID(), this,Q_INSERT, "insert into character_factions (char_id, faction_id, faction_level) values(%u, %u, %i) ON DUPLICATE KEY UPDATE faction_level=%i", client->GetCharacterID(), itr->first, itr->second, itr->second);
  3538. }
  3539. bool WorldDatabase::LoadPlayerFactions(Client* client) {
  3540. LogWrite(PLAYER__DEBUG, 0, "Player", "Loading Player Factions...");
  3541. Query query;
  3542. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT faction_id, faction_level FROM character_factions where char_id=%i", client->GetCharacterID());
  3543. if(result && mysql_num_rows(result) > 0) {
  3544. MYSQL_ROW row;
  3545. while(result && (row = mysql_fetch_row(result))){
  3546. client->GetPlayer()->GetFactions()->SetFactionValue(atoul(row[0]), atol(row[1]));
  3547. }
  3548. }
  3549. if(query.GetErrorNumber())
  3550. return false;
  3551. return true;
  3552. }
  3553. void WorldDatabase::SavePlayerMail(Mail* mail) {
  3554. Query query_update;
  3555. Query query_insert;
  3556. if (mail) {
  3557. query_update.AddQueryAsync(mail->player_to_id, this, Q_UPDATE, "UPDATE `character_mail` SET `already_read`=%u, `coin_copper`=%u, `coin_silver`=%u, `coin_gold`=%u, `coin_plat`=%u WHERE `id`=%u", mail->already_read, mail->coin_copper, mail->coin_silver, mail->coin_gold, mail->coin_plat, mail->mail_id);
  3558. if (query_update.GetAffectedRows() == 0)
  3559. query_insert.AddQueryAsync(mail->player_to_id, this, Q_UPDATE, "INSERT INTO `character_mail` (`player_to_id`, `player_from`, `subject`, `mail_body`, `already_read`, `mail_type`, `coin_copper`, `coin_silver`, `coin_gold`, `coin_plat`, `stack`, `postage_cost`, `attachment_cost`, `char_item_id`, `time_sent`, `expire_time`) VALUES (%u, '%s', '%s', '%s', %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u)", mail->player_to_id, mail->player_from.c_str(), getSafeEscapeString(mail->subject.c_str()).c_str(), getSafeEscapeString(mail->mail_body.c_str()).c_str(), mail->already_read, mail->mail_type, mail->coin_copper, mail->coin_silver, mail->coin_gold, mail->coin_plat, mail->stack, mail->postage_cost, mail->attachment_cost, mail->char_item_id, mail->time_sent, mail->expire_time);
  3560. mail->save_needed = false;
  3561. }
  3562. }
  3563. void WorldDatabase::SavePlayerMail(Client* client) {
  3564. if (client) {
  3565. MutexMap<int32, Mail*>* mail_list = client->GetPlayer()->GetMail();
  3566. MutexMap<int32, Mail*>::iterator itr = mail_list->begin();
  3567. while (itr.Next()) {
  3568. Mail* mail = itr->second;
  3569. if (mail->save_needed)
  3570. SavePlayerMail(mail);
  3571. }
  3572. }
  3573. }
  3574. void WorldDatabase::LoadPlayerMail(Client* client, bool new_only) {
  3575. LogWrite(PLAYER__DEBUG, 0, "Player", "Loading Player Mail...");
  3576. if (client) {
  3577. Query query;
  3578. MYSQL_RES* result;
  3579. if (new_only)
  3580. result = query.RunQuery2(Q_SELECT, "SELECT `id`, `player_to_id`, `player_from`, `subject`, `mail_body`, `already_read`, `mail_type`, `coin_copper`, `coin_silver`, `coin_gold`, `coin_plat`, `stack`, `postage_cost`, `attachment_cost`, `char_item_id`, `time_sent`, `expire_time` FROM `character_mail` WHERE `player_to_id`=%u AND `unread`=1", client->GetCharacterID());
  3581. else
  3582. result = query.RunQuery2(Q_SELECT, "SELECT `id`, `player_to_id`, `player_from`, `subject`, `mail_body`, `already_read`, `mail_type`, `coin_copper`, `coin_silver`, `coin_gold`, `coin_plat`, `stack`, `postage_cost`, `attachment_cost`, `char_item_id`, `time_sent`, `expire_time` FROM `character_mail` WHERE `player_to_id`=%u", client->GetCharacterID());
  3583. if (result && mysql_num_rows(result) > 0) {
  3584. MYSQL_ROW row;
  3585. client->SimpleMessage(CHANNEL_COLOR_MAIL, "You've got mail! :)");
  3586. while (result && (row = mysql_fetch_row(result))) {
  3587. Mail* mail = new Mail;
  3588. mail->mail_id = atoul(row[0]);
  3589. mail->player_to_id = atoul(row[1]);
  3590. mail->player_from = string(row[2]);
  3591. mail->subject = string(row[3]);
  3592. if (row[4])
  3593. mail->mail_body = string(row[4]);
  3594. mail->already_read = atoi(row[5]);
  3595. mail->mail_type = atoi(row[6]);
  3596. mail->coin_copper = atoul(row[7]);
  3597. mail->coin_silver = atoul(row[8]);
  3598. mail->coin_gold = atoul(row[9]);
  3599. mail->coin_plat = atoul(row[10]);
  3600. mail->stack = atoi(row[11]);
  3601. mail->postage_cost = atoul(row[12]);
  3602. mail->attachment_cost = atoul(row[13]);
  3603. mail->char_item_id = atoul(row[14]);
  3604. mail->time_sent = atoul(row[15]);
  3605. mail->expire_time = atoul(row[16]);
  3606. mail->save_needed = false;
  3607. client->GetPlayer()->AddMail(mail);
  3608. LogWrite(PLAYER__DEBUG, 5, "Player", "Loaded Mail ID %i, to: %i, from: %s", atoul(row[0]), atoul(row[1]), string(row[2]).c_str());
  3609. }
  3610. }
  3611. }
  3612. }
  3613. void WorldDatabase::DeletePlayerMail(Mail* mail) {
  3614. Query query;
  3615. if (mail)
  3616. query.RunQuery2(Q_DELETE, "DELETE FROM `character_mail` WHERE `id`=%u", mail->mail_id);
  3617. LogWrite(PLAYER__DEBUG, 0, "Player", "Delete Player Mail...");
  3618. }
  3619. vector<int32>* WorldDatabase::GetAllPlayerIDs() {
  3620. Query query;
  3621. vector<int32>* ids = 0;
  3622. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `id` FROM `characters`");
  3623. MYSQL_ROW row;
  3624. while (result && (row = mysql_fetch_row(result))) {
  3625. if (ids == 0)
  3626. ids = new vector<int32>;
  3627. ids->push_back(atoul(row[0]));
  3628. }
  3629. return ids;
  3630. }
  3631. void WorldDatabase::GetPetNames(ZoneServer* zone)
  3632. {
  3633. DatabaseResult result;
  3634. int32 total = 0;
  3635. if( database_new.Select(&result, "SELECT pet_name FROM spawn_pet_names") )
  3636. {
  3637. while(result.Next())
  3638. {
  3639. zone->pet_names.push_back(result.GetStringStr("pet_name"));
  3640. total++;
  3641. LogWrite(PET__DEBUG, 5, "Pet", "---Loading Pet Name: '%s'", result.GetStringStr("pet_name"));
  3642. }
  3643. LogWrite(PET__DEBUG, 0, "Pet", "--Loaded %u Pet Names", total);
  3644. }
  3645. }
  3646. int32 WorldDatabase::CheckTableVersions(char* tablename) {
  3647. Query query;
  3648. char* escaped_name = getEscapeString(tablename);
  3649. LogWrite(INIT__PATCHER_DEBUG, 1, "Patcher", "\tChecking current version for table: %s", tablename);
  3650. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT version FROM table_versions WHERE name='%s';", escaped_name);
  3651. int32 ret_version = 0;
  3652. if(result && mysql_num_rows(result) > 0)
  3653. {
  3654. MYSQL_ROW row;
  3655. row = mysql_fetch_row(result);
  3656. ret_version = atoul(row[0]);
  3657. }
  3658. safe_delete_array(escaped_name);
  3659. return ret_version;
  3660. }
  3661. bool WorldDatabase::RunDatabaseQueries(TableQuery* queries, bool output_result, bool data){
  3662. for(int16 i=0;i<queries->num_queries;i++){
  3663. Query query;
  3664. if(string(queries->GetQuery(i)).length() > 5)
  3665. query.RunQuery2(string(queries->GetQuery(i)), Q_UPDATE);
  3666. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF)
  3667. {
  3668. if(output_result)
  3669. LogWrite(INIT__PATCHER_ERROR, 0, "Patcher", "FAILED!");
  3670. LogWrite(INIT__PATCHER_ERROR, 0, "Patcher", "Error in updating tables query '%s': %s", query.GetQuery(), query.GetError());
  3671. return false;
  3672. }
  3673. }
  3674. if(output_result)
  3675. LogWrite(INIT__PATCHER_DEBUG, 0, "Patcher", "SUCCESS!");
  3676. if(data)
  3677. UpdateDataTableVersion(queries->tablename, queries->latest_version);
  3678. else
  3679. UpdateTableVersion(queries->tablename, queries->latest_version);
  3680. return true;
  3681. }
  3682. void WorldDatabase::UpdateDataTableVersion(char* name, int32 version){
  3683. Query query;
  3684. char* escaped_name = getEscapeString(name);
  3685. query.RunQuery2(Q_UPDATE, "update table_versions set download_version=%u where name='%s'", version, escaped_name);
  3686. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF)
  3687. {
  3688. LogWrite(INIT__PATCHER_ERROR, 0, "Patcher", "Error in updating version table query '%s': %s", query.GetQuery(), query.GetError());
  3689. }
  3690. safe_delete_array(escaped_name);
  3691. }
  3692. void WorldDatabase::UpdateTableVersion(char* name, int32 version){
  3693. Query query;
  3694. char* escaped_name = getEscapeString(name);
  3695. query.RunQuery2(Q_UPDATE, "INSERT into table_versions (name, version) values('%s', %u) ON DUPLICATE KEY UPDATE version=%u", escaped_name, version, version);
  3696. if(query.GetErrorNumber() && query.GetError() && query.GetErrorNumber() < 0xFFFFFFFF)
  3697. {
  3698. LogWrite(WORLD__ERROR, 0, "Patcher", "Error in updating version table query '%s': %s", query.GetQuery(), query.GetError());
  3699. }
  3700. safe_delete_array(escaped_name);
  3701. }
  3702. bool WorldDatabase::CheckVersionTable() {
  3703. Query query;
  3704. // todo: suppress SQL errors while this command is running, because ERROR is normal on a new DB creation (Zcoretri)
  3705. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SHOW COLUMNS FROM table_versions");
  3706. if(result && mysql_num_rows(result) > 0) {
  3707. LogWrite(INIT__PATCHER_DEBUG, 0, "Patcher", "--DB Schema exists! Checking for updates...");
  3708. return true;
  3709. }
  3710. else {
  3711. LogWrite(INIT__PATCHER_ERROR, 0, "Patcher", "Version Table NOT Found! Creating...");
  3712. Query query2;
  3713. query2.RunQuery2(Q_UPDATE, "CREATE TABLE `table_versions` (`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, `name` VARCHAR(64) NOT NULL DEFAULT '',`version` INT(10) UNSIGNED NOT NULL DEFAULT '0',`download_version` INT(10) UNSIGNED NOT NULL DEFAULT '0',PRIMARY KEY (`id`),UNIQUE KEY `UniqueName` (`name`)) ENGINE=INNODB DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;");
  3714. LogWrite(INIT__PATCHER_DEBUG, 0, "Patcher", "--Setting table_version = 1...");
  3715. Query query3;
  3716. query3.RunQuery2(Q_INSERT, "INSERT INTO table_versions (name, version) VALUES ('table_versions', 1)");
  3717. }
  3718. return false;
  3719. }
  3720. sint32 WorldDatabase::GetLatestDataTableVersion(char* name){
  3721. Query query;
  3722. char* escaped_name = getEscapeString(name);
  3723. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT download_version FROM table_versions where name='%s'", escaped_name);
  3724. sint32 ret_version = 0;
  3725. if(result && mysql_num_rows(result) > 0) {
  3726. MYSQL_ROW row;
  3727. row = mysql_fetch_row(result);
  3728. ret_version = atol(row[0]);
  3729. }
  3730. safe_delete_array(escaped_name);
  3731. return ret_version;
  3732. }
  3733. int32 WorldDatabase::GetMaxHotBarID(){
  3734. Query query;
  3735. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT max(id) FROM character_skillbar");
  3736. int32 ret = 0;
  3737. if(result && mysql_num_rows(result) > 0) {
  3738. MYSQL_ROW row;
  3739. row = mysql_fetch_row(result);
  3740. if(row && row[0])
  3741. ret = strtoul(row[0], NULL, 0);
  3742. }
  3743. return ret;
  3744. }
  3745. void WorldDatabase::SaveQuickBar(int32 char_id, vector<QuickBarItem*>* quickbar_items){
  3746. vector<QuickBarItem*>::iterator itr;
  3747. QuickBarItem* qbi = 0;
  3748. for(itr = quickbar_items->begin(); itr != quickbar_items->end(); itr++){
  3749. qbi = *itr;
  3750. if(!qbi)
  3751. continue;
  3752. if(qbi->deleted == false){
  3753. Query query;
  3754. if(qbi->text.size > 0){
  3755. query.AddQueryAsync(char_id, this, Q_REPLACE, "replace into character_skillbar (id, hotbar, slot, char_id, spell_id, type, text_val, tier) values(%u, %u, %u, %u, %u, %i, '%s', %i)",
  3756. qbi->unique_id, qbi->hotbar, qbi->slot, char_id, qbi->id, qbi->type, getSafeEscapeString(qbi->text.data.c_str()).c_str(), qbi->tier);
  3757. }
  3758. else{
  3759. query.AddQueryAsync(char_id, this, Q_REPLACE, "replace into character_skillbar (id, hotbar, slot, char_id, spell_id, type, text_val, tier) values(%u, %u, %u, %u, %u, %i, 'Unused', %i)",
  3760. qbi->unique_id, qbi->hotbar, qbi->slot, char_id, qbi->id, qbi->type, qbi->tier);
  3761. }
  3762. }
  3763. else{
  3764. Query query;
  3765. query.AddQueryAsync(char_id, this, Q_DELETE, "delete FROM character_skillbar where hotbar=%u and slot=%u and char_id=%u", qbi->hotbar, qbi->slot, char_id);
  3766. }
  3767. }
  3768. }
  3769. map<int32, vector<LevelArray*> >* WorldDatabase::LoadSpellClasses(){
  3770. map<int32, vector<LevelArray*> >* ret = new map<int32, vector<LevelArray*> >();
  3771. Query query;
  3772. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT spell_id, adventure_class_id, tradeskill_class_id, level FROM spell_classes");
  3773. MYSQL_ROW row;
  3774. LevelArray* level = 0;
  3775. while(result && (row = mysql_fetch_row(result))){
  3776. level = new LevelArray();
  3777. level->adventure_class = atoi(row[1]);
  3778. level->tradeskill_class = atoi(row[2]);
  3779. level->spell_level = atoi(row[3]);
  3780. (*ret)[atoul(row[0])].push_back(level);
  3781. }
  3782. return ret;
  3783. }
  3784. void WorldDatabase::LoadTraits(){
  3785. Query query;
  3786. MYSQL_ROW row;
  3787. TraitData* trait;
  3788. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `spell_id`, `level`, `class_req`, `race_req`, `isTrait`,`isInate`, `isFocusEffect`, `isTraining`,`tier`, `group` FROM spell_traits");
  3789. while (result && (row = mysql_fetch_row(result))){
  3790. trait = new TraitData;
  3791. int8 i = 0;
  3792. trait->spellID = strtoul(row[0], NULL, 0);
  3793. trait->level = atoi(row[(++i)]);
  3794. trait->classReq = atoi(row[(++i)]);
  3795. trait->raceReq = atoi(row[(++i)]);
  3796. trait->isTrait = (atoi(row[(++i)]) == 0) ? false : true;
  3797. trait->isInate = (atoi(row[(++i)]) == 0) ? false : true;
  3798. trait->isFocusEffect = (atoi(row[(++i)]) == 0) ? false : true;
  3799. trait->isTraining = (atoi(row[(++i)]) == 0) ? false : true;
  3800. trait->tier = atoi(row[(++i)]);
  3801. trait->group = atoi(row[(++i)]);
  3802. master_trait_list.AddTrait(trait);
  3803. }
  3804. LogWrite(SPELL__INFO, 0, "Traits", "Loaded %u Trait(s)", master_trait_list.Size());
  3805. }
  3806. void WorldDatabase::LoadSpells()
  3807. {
  3808. DatabaseResult result;
  3809. Spell *spell;
  3810. SpellData *data;
  3811. int32 t_now = Timer::GetUnixTimeStamp();
  3812. int32 total = 0;
  3813. map<int32, vector<LevelArray*> >* level_data = LoadSpellClasses();
  3814. if( !database_new.Select(&result, "SELECT s.`id`, ts.spell_id, ts.index, `name`, `description`, `type`, `class_skill`, `mastery_skill`, `tier`, `is_aa`,`hp_req`, `power_req`,`power_by_level`, `cast_time`, `recast`, `radius`, `max_aoe_targets`, `req_concentration`, `range`, `duration1`, `duration2`, `resistibility`, `hp_upkeep`, `power_upkeep`, `duration_until_cancel`, `target_type`, `recovery`, `power_req_percent`, `hp_req_percent`, `icon`, `icon_heroic_op`, `icon_backdrop`, `success_message`, `fade_message`, `cast_type`, `lua_script`, `call_frequency`, `interruptable`, `spell_visual`, `effect_message`, `min_range`, `can_effect_raid`, `affect_only_group_members`, `hit_bonus`, `display_spell_tier`, `friendly_spell`, `group_spell`, `spell_book_type`, spell_type+0, s.is_active, savagery_req, savagery_req_percent, savagery_upkeep, dissonance_req, dissonance_req_percent, dissonance_upkeep, linked_timer_id, det_type, incurable, control_effect_type, cast_while_moving, casting_flags, persist_through_death, not_maintained, savage_bar, savage_bar_slot, soe_spell_crc "
  3815. "FROM (spells s, spell_tiers st) "
  3816. "LEFT JOIN spell_ts_ability_index ts "
  3817. "ON s.`id` = ts.spell_id "
  3818. "WHERE s.id = st.spell_id AND s.is_active = 1 "
  3819. "ORDER BY s.`id`, `tier`") )
  3820. {
  3821. // error
  3822. }
  3823. else
  3824. {
  3825. while( result.Next() )
  3826. {
  3827. data = new SpellData;
  3828. int32 spell_id = result.GetInt32Str("id");
  3829. string spell_name = result.GetStringStr("name");
  3830. /* General Spell info */
  3831. data->id = spell_id;
  3832. data->soe_spell_crc = result.GetInt32Str("soe_spell_crc");
  3833. data->tier = result.GetInt8Str("tier");
  3834. data->ts_loc_index = result.GetInt8Str("index");
  3835. data->name.data = spell_name.c_str();
  3836. data->name.size = data->name.data.length();
  3837. data->description.data = result.GetStringStr("description");
  3838. data->description.size = data->description.data.length();
  3839. data->icon = result.GetSInt16Str("icon");
  3840. data->icon_heroic_op = result.GetInt16Str("icon_heroic_op");
  3841. data->icon_backdrop = result.GetInt16Str("icon_backdrop");
  3842. data->spell_visual = result.GetInt32Str("spell_visual");
  3843. data->type = result.GetInt16Str("type");
  3844. data->target_type = result.GetInt8Str("target_type");
  3845. data->cast_type = result.GetInt8Str("cast_type");
  3846. data->spell_book_type = result.GetInt32Str("spell_book_type");
  3847. data->det_type = result.GetInt8Str("det_type");
  3848. data->incurable = (result.GetInt8Str("incurable") == 1);
  3849. data->control_effect_type = result.GetInt8Str("control_effect_type");
  3850. data->casting_flags = result.GetInt32Str("casting_flags");
  3851. data->savage_bar = result.GetInt8Str("savage_bar");
  3852. data->savage_bar_slot = result.GetInt8Str("savage_bar_slot");
  3853. data->spell_type = result.IsNullStr("spell_type+0") ? 0 : result.GetInt8Str("spell_type+0");
  3854. /* Toggles */
  3855. data->interruptable = ( result.GetInt8Str("interruptable") == 1);
  3856. data->duration_until_cancel = ( result.GetInt8Str("duration_until_cancel") == 1);
  3857. data->can_effect_raid = result.GetInt8Str("can_effect_raid");
  3858. data->affect_only_group_members = result.GetInt8Str("affect_only_group_members");
  3859. data->display_spell_tier = result.GetInt8Str("display_spell_tier");
  3860. data->friendly_spell = result.GetInt8Str("friendly_spell");
  3861. data->group_spell = result.GetInt8Str("group_spell");
  3862. data->is_active = result.GetInt8Str("is_active");
  3863. data->persist_though_death = ( result.GetInt8Str("persist_through_death") == 1);
  3864. data->cast_while_moving = ( result.GetInt8Str("cast_while_moving") == 1);
  3865. data->not_maintained = ( result.GetInt8Str("not_maintained") == 1);
  3866. data->is_aa = (result.GetInt8Str("is_aa") == 1);
  3867. /* Skill Requirements */
  3868. data->class_skill = result.GetInt32Str("class_skill");
  3869. data->mastery_skill = result.GetInt32Str("mastery_skill");
  3870. // no min_class_skill_req?
  3871. /* Cost */
  3872. data->req_concentration = result.GetInt16Str("req_concentration");
  3873. data->hp_req = result.GetInt16Str("hp_req");
  3874. data->hp_upkeep = result.GetInt16Str("hp_upkeep");
  3875. data->hp_req_percent = result.GetInt8Str("hp_req_percent");
  3876. data->power_req = result.GetFloatStr("power_req");
  3877. data->power_by_level = ( result.GetInt8Str("power_by_level") == 0)? false : true;
  3878. data->power_upkeep = result.GetInt16Str("power_upkeep");
  3879. data->power_req_percent = result.GetInt8Str("power_req_percent");
  3880. data->savagery_req = result.GetInt16Str("savagery_req");
  3881. data->savagery_upkeep = result.GetInt16Str("savagery_upkeep");
  3882. data->savagery_req_percent = result.GetInt8Str("savagery_req_percent");
  3883. data->dissonance_req = result.GetInt16Str("dissonance_req");
  3884. data->dissonance_upkeep = result.GetInt16Str("dissonance_upkeep");
  3885. data->dissonance_req_percent = result.GetInt8Str("dissonance_req_percent");
  3886. /* Spell Parameters */
  3887. data->call_frequency = result.GetInt32Str("call_frequency");
  3888. data->cast_time = result.GetInt16Str("cast_time");
  3889. data->duration1 = result.GetInt32Str("duration1");
  3890. data->duration2 = result.GetInt32Str("duration2");
  3891. data->hit_bonus = result.GetFloatStr("hit_bonus");
  3892. data->max_aoe_targets = result.GetInt16Str("max_aoe_targets");
  3893. data->min_range = result.GetFloatStr("min_range");
  3894. data->radius = result.GetFloatStr("radius");
  3895. data->range = result.GetFloatStr("range");
  3896. data->recast = result.GetFloatStr("recast");
  3897. data->recovery = result.GetFloatStr("recovery");
  3898. data->resistibility = result.GetFloatStr("resistibility");
  3899. data->linked_timer = result.GetInt32Str("linked_timer_id");
  3900. /* Cast Messaging */
  3901. string message = result.GetStringStr("success_message");
  3902. if( message.length() > 0 )
  3903. data->success_message = message;
  3904. message = result.GetStringStr("fade_message");
  3905. if( message.length() > 0 )
  3906. data->fade_message = string(message);
  3907. message = result.GetStringStr("effect_message");
  3908. if( message.length() > 0 )
  3909. data->effect_message = string(message);
  3910. string lua_script = result.GetStringStr("lua_script");
  3911. if( lua_script.length() > 0 )
  3912. data->lua_script = string(lua_script);
  3913. /* Load spell level data */
  3914. spell = new Spell(data);
  3915. if(level_data && level_data->count(data->id) > 0)
  3916. {
  3917. vector<LevelArray*>* level_array = &((*level_data)[data->id]);
  3918. for(int8 i=0; i<level_array->size(); i++)
  3919. {
  3920. spell->AddSpellLevel(level_array->at(i)->adventure_class, level_array->at(i)->tradeskill_class, level_array->at(i)->spell_level*10);
  3921. }
  3922. }
  3923. /* Add spell to master list */
  3924. master_spell_list.AddSpell(data->id, data->tier, spell);
  3925. total++;
  3926. if( lua_script.length() > 0 )
  3927. LogWrite(SPELL__DEBUG, 5, "Spells", "\t%i. %s (Tier: %i) - '%s'", spell_id, spell_name.c_str(), data->tier, lua_script.c_str());
  3928. else if(data->is_active)
  3929. LogWrite(SPELL__WARNING, 1, "Spells", "\tSpell %s (%u, Tier: %i) set 'Active', but missing LUAScript", spell_name.c_str(), spell_id, data->tier);
  3930. } // end while
  3931. } // end else
  3932. LogWrite(SPELL__DEBUG, 0, "Spells", "Loading Spell Effects...");
  3933. LoadSpellEffects();
  3934. LogWrite(SPELL__DEBUG, 0, "Spells", "Loading Spell LUA Data...");
  3935. LoadSpellLuaData();
  3936. if(lua_interface)
  3937. {
  3938. LogWrite(SPELL__DEBUG, 0, "Spells", "Loading Spells Scripts...");
  3939. LoadSpellScriptData();
  3940. }
  3941. if (level_data) {
  3942. map<int32, vector<LevelArray*> >::iterator map_itr;
  3943. vector<LevelArray*>::iterator level_itr;
  3944. for(map_itr = level_data->begin(); map_itr != level_data->end(); map_itr++)
  3945. {
  3946. for(level_itr = map_itr->second.begin(); level_itr != map_itr->second.end(); level_itr++)
  3947. {
  3948. safe_delete(*level_itr);
  3949. }
  3950. }
  3951. }
  3952. safe_delete(level_data);
  3953. LogWrite(SPELL__INFO, 0, "Spells", "Loaded %u Spell%s (took %u seconds)", total, total == 1 ? "" : "s", Timer::GetUnixTimeStamp() - t_now);
  3954. }
  3955. void WorldDatabase::LoadSpellLuaData(){
  3956. Spell *spell;
  3957. Query query;
  3958. MYSQL_ROW row;
  3959. int32 total = 0;
  3960. MYSQL_RES *result = query.RunQuery2(Q_SELECT, "SELECT `spell_id`,`tier`,`value_type`,`value`,`value2`,`dynamic_helper` "
  3961. "FROM `spell_data` "
  3962. "ORDER BY `index_field`");
  3963. while (result && (row = mysql_fetch_row(result))) {
  3964. if ((spell = master_spell_list.GetSpell(atoul(row[0]), atoi(row[1]))) && row[2] && row[3] && row[4] && row[4]) {
  3965. LogWrite(SPELL__DEBUG, 5, "Spells", "\tLoading Spell LUA Data for spell_id: %u", atoul(row[0]));
  3966. if (!strcmp(row[2], "INT"))
  3967. spell->AddSpellLuaDataInt(atoi(row[3]), atoi(row[4]), string(row[5]));
  3968. else if (!strcmp(row[2], "FLOAT"))
  3969. spell->AddSpellLuaDataFloat(atof(row[3]), atof(row[4]),string(row[5]));
  3970. else if (!strcmp(row[2], "BOOL"))
  3971. spell->AddSpellLuaDataBool(!(strncasecmp(row[3], "true", 4)), string(row[5]));
  3972. else if (!strcmp(row[2], "STRING"))
  3973. spell->AddSpellLuaDataString(string(row[3]), string(row[4]), string(row[5]));
  3974. else
  3975. LogWrite(SPELL__ERROR, 0, "Spells", "Invalid Lua Spell data '%s' for Spell ID: %u", row[2], spell->GetSpellID());
  3976. total++;
  3977. }
  3978. }
  3979. LogWrite(SPELL__DEBUG, 0, "Spells", "\tLoaded %i Spell LUA Data entr%s.", total, total == 1 ? "y" : "ies");
  3980. }
  3981. void WorldDatabase::LoadSpellEffects() {
  3982. Spell *spell;
  3983. Query query;
  3984. MYSQL_ROW row;
  3985. int32 total = 0;
  3986. MYSQL_RES *result = query.RunQuery2(Q_SELECT, "SELECT `spell_id`,`tier`,`percentage`,`bullet`,`description` "
  3987. "FROM `spell_display_effects` "
  3988. "ORDER BY `spell_id`,`id` ASC");
  3989. while (result && (row = mysql_fetch_row(result))) {
  3990. if ((spell = master_spell_list.GetSpell(atoul(row[0]), atoi(row[1]))) && row[4]) {
  3991. LogWrite(SPELL__DEBUG, 5, "Spells", "\tLoading Spell Effects for spell_id: %u", atoul(row[0]));
  3992. spell->AddSpellEffect(atoi(row[2]), atoi(row[3]), row[4]);
  3993. total++;
  3994. }
  3995. }
  3996. LogWrite(SPELL__DEBUG, 0, "Spells", "\tLoaded %u Spell Effect%s.", total, total == 1 ? "" : "s");
  3997. }
  3998. int32 WorldDatabase::LoadPlayerSkillbar(Client* client){
  3999. client->GetPlayer()->ClearQuickbarItems();
  4000. Query query;
  4001. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, type, spell_id, slot, text_val, hotbar, tier FROM character_skillbar where char_id = %u", client->GetCharacterID());
  4002. MYSQL_ROW row;
  4003. int32 count = 0;
  4004. while(result && (row = mysql_fetch_row(result))){
  4005. count++;
  4006. int8 tier = atoi(row[6]);
  4007. Spell* spell = master_spell_list.GetSpell(atoul(row[2]), tier);
  4008. if(spell)
  4009. client->GetPlayer()->AddQuickbarItem(atoul(row[5]), atoul(row[3]), atoul(row[1]), spell->GetSpellIcon(), spell->GetSpellIconBackdrop(), spell->GetSpellID(), spell->GetSpellTier(), atoul(row[0]), row[4], false);
  4010. else if(atoul(row[1]) == QUICKBAR_MACRO)
  4011. client->GetPlayer()->AddQuickbarItem(atoul(row[5]), atoul(row[3]), atoul(row[1]), client->GetPlayer()->macro_icons[atoul(row[2])], 0xFFFF, atoul(row[2]), 0, atoul(row[0]), row[4], false);
  4012. else
  4013. client->GetPlayer()->AddQuickbarItem(atoul(row[5]), atoul(row[3]), atoul(row[1]), 0, 0, atoul(row[2]), 0, atoul(row[0]), row[4], false);
  4014. }
  4015. return count;
  4016. }
  4017. bool WorldDatabase::DeleteCharacter(int32 account_id, int32 character_id){
  4018. Guild *guild;
  4019. if((guild = guild_list.GetGuild(GetGuildIDByCharacterID(character_id))))
  4020. guild->RemoveGuildMember(character_id);
  4021. Query query;
  4022. query.RunQuery2(Q_DELETE, "DELETE FROM characters WHERE id=%u AND account_id=%u", character_id, account_id);
  4023. if(!query.GetAffectedRows())
  4024. {
  4025. //No error just in case ppl try doing stupid stuff
  4026. return false;
  4027. }
  4028. else{ //successfull, so the character did exist with that character_id and account_id
  4029. // new DB constraints should handle all these deletes, and more... commenting out for now
  4030. /*query.RunQuery2(Q_DELETE, "delete FROM character_details where char_id=%u", character_id);
  4031. query.RunQuery2(Q_DELETE, "delete FROM character_factions where char_id=%u", character_id);
  4032. query.RunQuery2(Q_DELETE, "delete FROM character_items where char_id=%u", character_id);
  4033. query.RunQuery2(Q_DELETE, "delete FROM character_skillbar where char_id=%u", character_id);
  4034. query.RunQuery2(Q_DELETE, "delete FROM character_skills where char_id=%u", character_id);
  4035. query.RunQuery2(Q_DELETE, "delete FROM character_spells where char_id=%u", character_id);
  4036. query.RunQuery2(Q_DELETE, "delete FROM char_colors where char_id=%u", character_id);*/
  4037. }
  4038. return true;
  4039. }
  4040. void WorldDatabase::DeleteCharacterSpell(int32 character_id, int32 spell_id) {
  4041. if (character_id > 0 && spell_id > 0) {
  4042. Query query;
  4043. query.RunQuery2(Q_DELETE, "DELETE FROM character_spells WHERE char_id=%u AND spell_id=%u", character_id, spell_id);
  4044. }
  4045. }
  4046. bool WorldDatabase::GetItemResultsToClient (Client* client, const char* varSearch, int maxResults) {
  4047. Query query;
  4048. MYSQL_ROW row;
  4049. int results = 0;
  4050. if( maxResults > 10 && client->GetAdminStatus ( ) < 100 )
  4051. maxResults = 10;
  4052. else if( maxResults > 20 )
  4053. maxResults = 20;
  4054. client->Message(CHANNEL_COLOR_YELLOW, "Item Search Results");
  4055. client->Message(CHANNEL_COLOR_YELLOW, "ResultNum) [ItemID] ItemName");
  4056. string itemsearch_query = string("SELECT id, name FROM items where name like '%%%s%%' limit %i");
  4057. MYSQL_RES* result = query.RunQuery2(Q_SELECT, itemsearch_query.c_str(),getSafeEscapeString(varSearch).c_str(),maxResults);
  4058. while(result && (row = mysql_fetch_row(result))){
  4059. results++;
  4060. client->Message(CHANNEL_COLOR_YELLOW, "%i) [%s] %s",results,row[0],row[1]);
  4061. }
  4062. if(results == 0)
  4063. {
  4064. client->Message(CHANNEL_COLOR_YELLOW, "No Items Found.");
  4065. return false;
  4066. }
  4067. client->Message(CHANNEL_COLOR_YELLOW, "%i Items Found.",results);
  4068. return true;
  4069. }
  4070. void WorldDatabase::SaveWorldTime(WorldTime* time){
  4071. Query query;
  4072. query.RunQuery2(Q_REPLACE, "replace into variables (variable_name, variable_value) values('gametime', '%i/%i/%i %i:%i')", time->month, time->day, time->year, time->hour, time->minute);
  4073. }
  4074. void WorldDatabase::SaveBugReport(const char* category, const char* subcategory, const char* causes_crash, const char* reproducible, const char* summary, const char* description, const char* version, const char* player, int32 account_id, const char* spawn_name, int32 spawn_id, int32 zone_id){
  4075. Query query;
  4076. int32 dbVersion = rule_manager.GetGlobalRule(R_World, DatabaseVersion)->GetInt32();
  4077. string bug_report = string("insert into bugs (category, subcategory, causes_crash, reproducible, summary, description, version, player, account_id, spawn_name, spawn_id, zone_id, dbversion, worldversion) values('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %u, '%s', %u, %u, %u, '%s')");
  4078. query.RunQuery2(Q_INSERT, bug_report.c_str(), getSafeEscapeString(category).c_str(), getSafeEscapeString(subcategory).c_str(),
  4079. getSafeEscapeString(causes_crash).c_str(), getSafeEscapeString(reproducible).c_str(), getSafeEscapeString(summary).c_str(),
  4080. getSafeEscapeString(description).c_str(), getSafeEscapeString(version).c_str(), getSafeEscapeString(player).c_str(), account_id,
  4081. getSafeEscapeString(spawn_name).c_str(), spawn_id, zone_id, dbVersion, CURRENT_VERSION);
  4082. FixBugReport();
  4083. FixBugReport();
  4084. FixBugReport();
  4085. }
  4086. void WorldDatabase::FixBugReport(){
  4087. Query query;
  4088. string bug_report = string("update bugs set description = REPLACE(description,SUBSTRING(description,INSTR(description,'%'), 3),char(CONV(SUBSTRING(description,INSTR(description,'%')+1, 2), 16, 10))), summary = REPLACE(summary,SUBSTRING(summary,INSTR(summary,'%'), 3),char(CONV(SUBSTRING(summary,INSTR(summary,'%')+1, 2), 16, 10)))");
  4089. query.RunQuery2(bug_report.c_str(), Q_UPDATE);
  4090. }
  4091. int32 WorldDatabase::LoadQuests(){
  4092. Query query;
  4093. MYSQL_ROW row;
  4094. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `quest_id`, `name`, `type`, `zone`, `level`, `enc_level`, `description`, `lua_script`, `completed_text`, `spawn_id` FROM `quests`");
  4095. Quest* quest = 0;
  4096. char* name = 0;
  4097. char* type = 0;
  4098. char* zone = 0;
  4099. int8 level = 0;
  4100. int8 enc_level = 0;
  4101. char* description = 0;
  4102. char* script = 0;
  4103. int32 total = 0;
  4104. int32 id = 0;
  4105. char* completed_description = 0;
  4106. int32 return_npc_id = 0;
  4107. if(result){
  4108. while(result && (row = mysql_fetch_row(result))){
  4109. id = atoul(row[0]);
  4110. name = row[1];
  4111. type = row[2];
  4112. zone = row[3];
  4113. level = atoul(row[4]);
  4114. enc_level = atoul(row[5]);
  4115. description = row[6];
  4116. script = row[7];
  4117. completed_description = row[8];
  4118. return_npc_id = atoi(row[9]);
  4119. if(lua_interface) {
  4120. quest = lua_interface->LoadQuest(id, name, type, zone, level, description, script);
  4121. }
  4122. if(quest){
  4123. LogWrite(QUEST__DEBUG, 5, "Quests", "\tLoading Quest: '%s' (%u)", name, id);
  4124. LoadQuestDetails(quest);
  4125. string compDescription;
  4126. if (completed_description == NULL)
  4127. {
  4128. compDescription = string("Missing! Notify Developer");
  4129. LogWrite(QUEST__WARNING, 5, "Quests", "\tLoading Quest MISSING completed_text in quests table for: '%s' (%u)", name, id);
  4130. }
  4131. else
  4132. compDescription = string(completed_description);
  4133. quest->SetCompletedDescription(string(compDescription));
  4134. quest->SetQuestReturnNPC(return_npc_id);
  4135. quest->SetEncounterLevel(enc_level);
  4136. total++;
  4137. master_quest_list.AddQuest(id, quest);
  4138. }
  4139. }
  4140. }
  4141. LogWrite(QUEST__DEBUG, 0, "Quest", "\tLoaded %i Quest(s)", total);
  4142. return total;
  4143. }
  4144. void WorldDatabase::LoadQuestDetails(Quest* quest) {
  4145. Query query;
  4146. MYSQL_ROW row;
  4147. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `type`, `subtype`, `value`, `faction_id`, `quantity` FROM `quest_details` WHERE `quest_id`=%u", quest->GetQuestID());
  4148. string type;
  4149. string subtype;
  4150. sint64 value;
  4151. int32 faction_id;
  4152. int32 quantity;
  4153. while (result && (row = mysql_fetch_row(result))) {
  4154. type = string(row[0]);
  4155. subtype = string(row[1]);
  4156. value = atoi(row[2]);
  4157. faction_id = atoi(row[3]);
  4158. quantity = atoi(row[4]);
  4159. LogWrite(QUEST__DEBUG, 5, "Quests", "\t- Type: %s, SubType: %s, Val: %u, Faction: %u, Qty: %u", type.c_str(), subtype.c_str(), value, faction_id, quantity);
  4160. if (type == "Prereq") {
  4161. if (subtype == "Class")
  4162. quest->AddPrereqClass(value);
  4163. else if (subtype == "Faction")
  4164. quest->AddPrereqFaction(faction_id, value);
  4165. else if (subtype == "Item") {
  4166. Item* master_item = master_item_list.GetItem(value);
  4167. if (master_item) {
  4168. Item* item = new Item(master_item);
  4169. quest->AddPrereqItem(item);
  4170. }
  4171. }
  4172. else if (subtype == "AdvLevel")
  4173. quest->SetPrereqLevel(value);
  4174. else if (subtype == "Quest")
  4175. quest->AddPrereqQuest(value);
  4176. else if (subtype == "Race")
  4177. quest->AddPrereqRace(value);
  4178. else if (subtype == "TSClass")
  4179. quest->AddPrereqTradeskillClass(value);
  4180. else if (subtype == "TSLevel")
  4181. quest->SetPrereqTSLevel(value);
  4182. else if (subtype == "MaxTSLevel")
  4183. quest->SetPrereqMaxTSLevel(value);
  4184. else if (subtype == "MaxAdvLevel")
  4185. quest->SetPrereqMaxLevel(value);
  4186. }
  4187. else if (type == "Reward") {
  4188. if (subtype == "Item") {
  4189. Item* master_item = master_item_list.GetItem(value);
  4190. if (master_item) {
  4191. Item* item = new Item(master_item);
  4192. item->details.count = quantity;
  4193. quest->AddRewardItem(item);
  4194. }
  4195. }
  4196. else if (subtype == "Selectable") {
  4197. Item* master_item = master_item_list.GetItem(value);
  4198. if (master_item) {
  4199. Item* item = new Item(master_item);
  4200. item->details.count = quantity;
  4201. quest->AddSelectableRewardItem(item);
  4202. }
  4203. }
  4204. else if (subtype == "Coin") {
  4205. int32 copper = 0;
  4206. int32 silver = 0;
  4207. int32 gold = 0;
  4208. int32 plat = 0;
  4209. if (value >= 1000000) {
  4210. plat = value / 1000000;
  4211. value -= 1000000 * plat;
  4212. }
  4213. if (value >= 10000) {
  4214. gold = value / 10000;
  4215. value -= 10000 * gold;
  4216. }
  4217. if (value >= 100) {
  4218. silver = value / 100;
  4219. value -= 100 * silver;
  4220. }
  4221. if (value > 0)
  4222. copper = value;
  4223. quest->AddRewardCoins(copper, silver, gold, plat);
  4224. }
  4225. else if (subtype == "MaxCoin") {
  4226. quest->AddRewardCoinsMax(value);
  4227. }
  4228. else if (subtype == "Faction")
  4229. quest->AddRewardFaction(faction_id, value);
  4230. else if (subtype == "Experience")
  4231. quest->SetRewardXP(value);
  4232. else if (subtype == "TSExperience")
  4233. quest->SetRewardTSXP(value);
  4234. }
  4235. }
  4236. }
  4237. void WorldDatabase::LoadMerchantInformation() {
  4238. LogWrite(MERCHANT__DEBUG, 0, "Merchant", "\tClearing Merchant Inventory...");
  4239. world.DeleteMerchantItems();
  4240. LogWrite(MERCHANT__DEBUG, 0, "Merchant", "\tLoading Merchant Inventory...");
  4241. LoadMerchantInventory();
  4242. Query query;
  4243. MYSQL_ROW row;
  4244. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT merchant_id, inventory_id FROM merchants ORDER BY merchant_id");
  4245. int32 total = 0;
  4246. int32 last_merchant_id = 0;
  4247. int32 id = 0;
  4248. MerchantInfo* merchant = 0;
  4249. if(result) {
  4250. while(result && (row = mysql_fetch_row(result))) {
  4251. id = atoul(row[0]);
  4252. LogWrite(MERCHANT__DEBUG, 5, "Merchant", "\tMerchantID: %u, InventoryID: %u", id, atoul(row[1]));
  4253. if(id != last_merchant_id) {
  4254. if(merchant)
  4255. world.AddMerchantInfo(last_merchant_id, merchant);
  4256. merchant = new MerchantInfo;
  4257. last_merchant_id = id;
  4258. total++;
  4259. }
  4260. merchant->inventory_ids.push_back(atoul(row[1]));
  4261. }
  4262. if(merchant)
  4263. world.AddMerchantInfo(last_merchant_id, merchant);
  4264. }
  4265. LogWrite(MERCHANT__DEBUG, 0, "Merchant", "\tLoaded %i Merchant List(s)", total);
  4266. }
  4267. void WorldDatabase::LoadMerchantInventory(){
  4268. Query query;
  4269. MYSQL_ROW row;
  4270. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT inventory_id, item_id, quantity, price_item_id, price_item_qty, price_item2_id, price_item2_qty, price_status, price_coins, price_stationcash FROM merchant_inventory ORDER BY inventory_id");
  4271. int32 total = 0;
  4272. int32 id;
  4273. if(result) {
  4274. while(result && (row = mysql_fetch_row(result))) {
  4275. MerchantItemInfo ItemInfo;
  4276. id = atoul(row[0]);
  4277. ItemInfo.item_id = atoul(row[1]);
  4278. ItemInfo.quantity = atoi(row[2]);
  4279. ItemInfo.price_item_id = atoul(row[3]);
  4280. ItemInfo.price_item_qty = atoi(row[4]);
  4281. ItemInfo.price_item2_id = atoul(row[5]);
  4282. ItemInfo.price_item2_qty = atoi(row[6]);
  4283. ItemInfo.price_status = atoul(row[7]);
  4284. ItemInfo.price_coins = atoul(row[8]);
  4285. ItemInfo.price_stationcash = atoul(row[9]);
  4286. LogWrite(MERCHANT__DEBUG, 5, "Merchant", "\tInventoryID: %u, ItemID: %u, Qty: %u", id, ItemInfo.item_id, ItemInfo.quantity);
  4287. world.AddMerchantItem(id, ItemInfo);
  4288. total++;
  4289. }
  4290. }
  4291. LogWrite(MERCHANT__DEBUG, 0, "Merchant", "\tLoaded %i Merchant Inventory Item(s)", total);
  4292. }
  4293. string WorldDatabase::GetMerchantDescription(int32 merchant_id) {
  4294. Query query;
  4295. MYSQL_ROW row;
  4296. string description;
  4297. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `description` FROM `merchants` WHERE `merchant_id`=%u", merchant_id);
  4298. if (result && (row = mysql_fetch_row(result)))
  4299. description = string(row[0]);
  4300. return description;
  4301. }
  4302. void WorldDatabase::LoadTransporters(ZoneServer* zone){
  4303. int32 total = 0;
  4304. zone->DeleteGlobalTransporters();
  4305. Query query;
  4306. MYSQL_ROW row;
  4307. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT transport_id, transport_type, display_name, message, destination_zone_id, destination_x, destination_y, destination_z, destination_heading, trigger_location_zone_id, trigger_location_x, trigger_location_y, trigger_location_z, trigger_radius, cost, id, min_level, max_level, quest_req, quest_step_req, quest_completed, map_x, map_y FROM transporters ORDER BY transport_id");
  4308. if(result){
  4309. while(result && (row = mysql_fetch_row(result))){
  4310. LogWrite(TRANSPORT__DEBUG, 5, "Transport", "---Loading Transporter ID: %u, transport_type: %s", row[0], row[1]);
  4311. LogWrite(TRANSPORT__DEBUG, 7, "Transport", "---display_name: %s, message: %s", row[2], row[3]);
  4312. LogWrite(TRANSPORT__DEBUG, 7, "Transport", "---destination_zone_id: %s", row[4]);
  4313. LogWrite(TRANSPORT__DEBUG, 7, "Transport", "---destination_x: %s, destination_y: %s, destination_z: %s, destination_heading: %s", row[5], row[6], row[7], row[8]);
  4314. LogWrite(TRANSPORT__DEBUG, 7, "Transport", "---trigger_location_zone_id: %s", row[9]);
  4315. LogWrite(TRANSPORT__DEBUG, 7, "Transport", "---trigger_location_x: %s, trigger_location_y: %s, trigger_location_z: %s", row[10], row[11], row[12], row[13]);
  4316. LogWrite(TRANSPORT__DEBUG, 7, "Transport", "---trigger_radius: %s, cost: %s, id: %s", row[14], row[15]);
  4317. string name = "";
  4318. if(row[2])
  4319. name = string(row[2]);
  4320. string message = "";
  4321. if(row[3])
  4322. message = string(row[3]);
  4323. if(row[1] && strcmp(row[1], "Zone") == 0)
  4324. zone->AddTransporter(atoul(row[0]), TRANSPORT_TYPE_ZONE, name, message, atoul(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atof(row[8]), atoul(row[14]), atoul(row[15]), atoi(row[16]), atoi(row[17]), atoul(row[18]), atoi(row[19]), atoul(row[20]), atoul(row[21]), atoul(row[22]));
  4325. else if(row[1] && strcmp(row[1], "Location") == 0)
  4326. zone->AddLocationTransporter(atoul(row[9]), message, atof(row[10]), atof(row[11]), atof(row[12]), atof(row[13]), atoul(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atof(row[8]), atoul(row[14]), atoul(row[15]));
  4327. else
  4328. zone->AddTransporter(atoul(row[0]), TRANSPORT_TYPE_GENERIC, "", message, atoul(row[4]), atof(row[5]), atof(row[6]), atof(row[7]), atof(row[8]), atoul(row[14]), atoul(row[15]), atoi(row[16]), atoi(row[17]), atoul(row[18]), atoi(row[19]), atoul(row[20]), atoul(row[21]), atoul(row[22]));
  4329. total++;
  4330. }
  4331. }
  4332. LogWrite(TRANSPORT__DEBUG, 0, "Transport", "--Loaded %i Transporter(s)", total);
  4333. LoadTransportMaps(zone);
  4334. }
  4335. void WorldDatabase::LoadFogInit(string zone, PacketStruct* packet)
  4336. {
  4337. LogWrite(WORLD__TRACE, 9, "World", "Enter: %s", __FUNCTION__);
  4338. if(!packet || zone.length() == 0)
  4339. return;
  4340. Query query;
  4341. MYSQL_ROW row;
  4342. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT highest, lowest, zone_name, explored_map_name, unexplored_map_name, bounds1_x, bounds1_z, bounds2_x, bounds2_z, bounds3_x, bounds3_z, bounds4_x, bounds4_z, explored_key, unexplored_key, map_id FROM map_data where zone_name like '%s%%'", getSafeEscapeString(&zone).c_str());
  4343. if(result){
  4344. int count = mysql_num_rows(result);
  4345. int i=0;
  4346. int64 explored_key;
  4347. int64 unexplored_key;
  4348. packet->setArrayLengthByName("num_maps", count);
  4349. while(result && (row = mysql_fetch_row(result))){
  4350. packet->setDataByName("highest_z", atof(row[0]));
  4351. packet->setDataByName("lowest_z", atof(row[1]));
  4352. packet->setDataByName("map_id", atoul(row[15]));
  4353. packet->setArrayDataByName("unknown7", 1600, i);
  4354. packet->setArrayDataByName("unknown8", 1200, i);
  4355. packet->setArrayDataByName("zone_name", row[2], i);
  4356. packet->setArrayDataByName("explored_map_name", row[3], i);
  4357. packet->setArrayDataByName("unexplored_map_name", row[4], i);
  4358. packet->setArrayDataByName("map_bounds1_x", atof(row[5]), i);
  4359. packet->setArrayDataByName("map_bounds1_z", atof(row[6]), i);
  4360. packet->setArrayDataByName("map_bounds2_x", atof(row[7]), i);
  4361. packet->setArrayDataByName("map_bounds2_z", atof(row[8]), i);
  4362. packet->setArrayDataByName("map_bounds3_x", atof(row[9]), i);
  4363. packet->setArrayDataByName("map_bounds3_z", atof(row[10]), i);
  4364. packet->setArrayDataByName("map_bounds4_x", atof(row[11]), i);
  4365. packet->setArrayDataByName("map_bounds4_z", atof(row[12]), i);
  4366. #ifdef WIN32
  4367. explored_key = _strtoui64(row[13], NULL, 10);
  4368. unexplored_key = _strtoui64(row[14], NULL, 10);
  4369. #else
  4370. explored_key = strtoull(row[13], 0, 10);
  4371. unexplored_key = strtoull(row[14], 0, 10);
  4372. #endif
  4373. packet->setArrayDataByName("explored_key", explored_key, i);
  4374. packet->setArrayDataByName("unexplored_key", unexplored_key, i);
  4375. i++;
  4376. }
  4377. }
  4378. LogWrite(WORLD__TRACE, 9, "World", "Exit: %s", __FUNCTION__);
  4379. }
  4380. string WorldDatabase::GetColumnNames(char* name){
  4381. Query query;
  4382. MYSQL_ROW row;
  4383. string columns = "";
  4384. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "show columns FROM %s", name);
  4385. if(result && mysql_num_rows(result) > 0){
  4386. int16 i = 0;
  4387. while((row = mysql_fetch_row(result))){
  4388. if(strcmp(row[0], "table_data_version") != 0){
  4389. if(i>0)
  4390. columns.append(",");
  4391. columns.append(row[0]);
  4392. i++;
  4393. }
  4394. }
  4395. }
  4396. columns.append("");
  4397. return columns;
  4398. }
  4399. void WorldDatabase::ToggleCharacterOnline() {
  4400. Query query;
  4401. query.RunQuery2(Q_UPDATE, "UPDATE characters SET is_online = 0;");
  4402. }
  4403. void WorldDatabase::ToggleCharacterOnline(Client* client, int8 toggle) {
  4404. if (client) {
  4405. Query query;
  4406. Player* player = client->GetPlayer();
  4407. //if(!player->CheckPlayerInfo())
  4408. // return;
  4409. if (player)
  4410. {
  4411. LogWrite(PLAYER__DEBUG, 0, "Player", "Toggling Character %s", toggle ? "ONLINE!" : "OFFLINE!");
  4412. query.RunQuery2(Q_UPDATE, "UPDATE characters SET is_online=%i WHERE id = %u;", toggle, client->GetCharacterID());
  4413. }
  4414. }
  4415. }
  4416. void WorldDatabase::LoadPlayerStatistics(Player* player, int32 char_id) {
  4417. Query query;
  4418. MYSQL_ROW row;
  4419. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT stat_id, stat_value, stat_date FROM statistics WHERE char_id=%i", char_id);
  4420. while (result && (row = mysql_fetch_row(result))) {
  4421. int32 stat_id = atoi(row[0]);
  4422. sint32 stat_value = atoi(row[1]);
  4423. int32 stat_date = atoi(row[2]);
  4424. player->AddPlayerStatistic(stat_id, stat_value, stat_date);
  4425. }
  4426. }
  4427. void WorldDatabase::WritePlayerStatistic(Player *player, Statistic* stat) {
  4428. if (player && player->GetCharacterID() > 0 && stat) {
  4429. Query query;
  4430. query.RunQuery2(Q_INSERT, "INSERT INTO statistics (char_id, guild_id, stat_id, stat_value, stat_date) VALUES(%i, %i, %i, %i, %i) ON DUPLICATE KEY UPDATE stat_value = %i, stat_date = %i;",
  4431. player->GetCharacterID(), 0, stat->stat_id, stat->stat_value, stat->stat_date,
  4432. stat->stat_value, stat->stat_date);
  4433. }
  4434. }
  4435. void WorldDatabase::LoadServerStatistics()
  4436. {
  4437. Query query;
  4438. MYSQL_ROW row;
  4439. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT stat_id, stat_value, stat_date FROM statistics WHERE char_id=0 AND guild_id=0");
  4440. while (result && (row = mysql_fetch_row(result))) {
  4441. int32 stat_id = atoi(row[0]);
  4442. sint32 stat_value = atoi(row[1]);
  4443. int32 stat_date = atoi(row[2]);
  4444. world.AddServerStatistic(stat_id, stat_value, stat_date);
  4445. LogWrite(INIT__DEBUG, 5, "Stats", "Loading Stat ID %i, value: %i", stat_id, stat_value);
  4446. }
  4447. }
  4448. void WorldDatabase::WriteServerStatistic(Statistic* stat) {
  4449. if (stat) {
  4450. Query query;
  4451. query.RunQuery2(Q_INSERT, "INSERT INTO statistics (char_id, guild_id, stat_id, stat_value, stat_date) VALUES(0, 0, %i, %i, %i) ON DUPLICATE KEY UPDATE stat_value = %i, stat_date = %i;",
  4452. stat->stat_id, stat->stat_value, stat->stat_date,
  4453. stat->stat_value, stat->stat_date);
  4454. }
  4455. }
  4456. void WorldDatabase::WriteServerStatistic(int32 stat_id, sint32 stat_value) {
  4457. Query query;
  4458. query.RunQuery2(Q_INSERT, "INSERT INTO statistics (char_id, guild_id, stat_id, stat_value, stat_date) VALUES(0, 0, %i, %i, %i) ON DUPLICATE KEY UPDATE stat_value = %i, stat_date = %i;",
  4459. stat_id, stat_value, Timer::GetUnixTimeStamp(),
  4460. stat_value, Timer::GetUnixTimeStamp());
  4461. }
  4462. void WorldDatabase::WriteServerStatisticsNeededQueries() {
  4463. Query query1, query2, query3;
  4464. MYSQL_ROW row1, row2, row3;
  4465. // Number of unique accounts
  4466. MYSQL_RES* result1 = query1.RunQuery2(Q_SELECT, "SELECT COUNT(DISTINCT account_id) FROM characters");
  4467. if (result1 && (row1 = mysql_fetch_row(result1)) && row1[0] != NULL)
  4468. WriteServerStatistic(STAT_SERVER_NUM_ACCOUNTS, atoi(row1[0]));
  4469. else
  4470. WriteServerStatistic(STAT_SERVER_NUM_ACCOUNTS, 0);
  4471. // Number of characters
  4472. MYSQL_RES* result2 = query2.RunQuery2(Q_SELECT, "SELECT COUNT(id) FROM characters");
  4473. if (result2 && (row2 = mysql_fetch_row(result2)) && row2[0] != NULL)
  4474. WriteServerStatistic(STAT_SERVER_NUM_CHARACTERS, atoi(row2[0]));
  4475. else
  4476. WriteServerStatistic(STAT_SERVER_NUM_CHARACTERS, 0);
  4477. // Average character level
  4478. MYSQL_RES* result3 = query3.RunQuery2(Q_SELECT, "SELECT ROUND(AVG(level)) FROM characters");
  4479. if (result3 && (row3 = mysql_fetch_row(result3)) && row3[0] != NULL)
  4480. WriteServerStatistic(STAT_SERVER_AVG_CHAR_LEVEL, atoi(row3[0]));
  4481. else
  4482. WriteServerStatistic(STAT_SERVER_AVG_CHAR_LEVEL, 0);
  4483. }
  4484. map<int32,int32>* WorldDatabase::GetInstanceRemovedSpawns(int32 instance_id, int8 type)
  4485. {
  4486. DatabaseResult result;
  4487. map<int32,int32>* ret = NULL;
  4488. LogWrite(SPAWN__TRACE, 1, "Spawn", "Enter %s", __FUNCTION__);
  4489. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Loading removed spawns for instance_id: %u, spawn_type: %i", instance_id, type);
  4490. if( !database_new.Select(&result, "SELECT spawn_location_entry_id, respawn_time FROM instance_spawns_removed WHERE instance_id = %i AND spawn_type = %i", instance_id, type) )
  4491. {
  4492. LogWrite(INSTANCE__ERROR, 0, "Instance", "Error in GetInstanceRemovedSpawns() '%s': %i", database_new.GetErrorMsg(), database_new.GetError());
  4493. return ret;
  4494. }
  4495. else
  4496. {
  4497. if( result.GetNumRows() > 0 )
  4498. {
  4499. ret = new map<int32,int32>;
  4500. while( result.Next() )
  4501. {
  4502. int32 spawn_location_entry_id = result.GetInt32Str("spawn_location_entry_id");
  4503. /*
  4504. respawnTime == 0 - never respawn
  4505. respawnTime = 1 - spawn now
  4506. respawnTime > 1 (continue timer)
  4507. */
  4508. int32 respawntime = result.GetInt32Str("respawn_time");
  4509. LogWrite(INSTANCE__DEBUG, 5, "Instance", "Found spawn point: %u, respawn time: %i", spawn_location_entry_id, respawntime);
  4510. ret->insert(make_pair(spawn_location_entry_id, respawntime));
  4511. }
  4512. }
  4513. else
  4514. LogWrite(INSTANCE__DEBUG, 0, "Instance", "No removed spawns found for instance_id: %u, spawn_type: %i", instance_id, type);
  4515. }
  4516. LogWrite(SPAWN__TRACE, 1, "Spawn", "Exit %s", __FUNCTION__);
  4517. return ret;
  4518. }
  4519. bool WorldDatabase::CheckVectorForValue(vector<int32>* vector, int32 value) {
  4520. if ( vector != NULL )
  4521. {
  4522. for(int32 i=0;i<vector->size();i++)
  4523. {
  4524. int32 compare = vector->at(i);
  4525. if ( compare == value )
  4526. return true;
  4527. }
  4528. }
  4529. return false;
  4530. }
  4531. int32 WorldDatabase::CheckSpawnRemoveInfo(map<int32,int32>* inmap, int32 spawn_location_entry_id)
  4532. {
  4533. LogWrite(SPAWN__TRACE, 0, "Spawn", "Enter %s", __FUNCTION__);
  4534. map<int32, int32>::iterator iter;
  4535. if ( inmap != NULL )
  4536. {
  4537. for(iter=inmap->begin();iter!=inmap->end();iter++)
  4538. {
  4539. if ( iter->first == spawn_location_entry_id )
  4540. return (int32)iter->second;
  4541. }
  4542. }
  4543. return 1;
  4544. }
  4545. int32 WorldDatabase::AddCharacterInstance(int32 char_id, int32 instance_id, string zone_name, int8 instance_type, int32 last_success, int32 last_failure, int32 success_lockout, int32 failure_lockout)
  4546. {
  4547. int32 ret = 0;
  4548. if( !database_new.Query("INSERT INTO character_instances (char_id, instance_id, instance_zone_name, instance_type, last_success_timestamp, last_failure_timestamp, success_lockout_time, failure_lockout_time) VALUES (%u, %u, '%s', %i, %u, %u, %u, %u) ", char_id, instance_id, database_new.EscapeStr(zone_name).c_str(), instance_type, last_success, last_failure, success_lockout, failure_lockout) )
  4549. {
  4550. LogWrite(INSTANCE__ERROR, 0, "Instance", "Error in AddCharacterInstance() '%s': %i", database_new.GetErrorMsg(), database_new.GetError());
  4551. return 0;
  4552. }
  4553. ret = database_new.LastInsertID();
  4554. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Adding character %u to instance: %u", char_id, instance_id);
  4555. //LogWrite(INSTANCE__DEBUG, 1, "Instance", "-- Reenter: %u, Reset: %u, Lockout: %u", grant_reenter_time_left, grant_reset_time_left, lockout_time);
  4556. return ret;
  4557. }
  4558. bool WorldDatabase::UpdateCharacterInstanceTimers(int32 char_id, int32 instance_id, int32 lockout_time, int32 reset_time, int32 reenter_time )
  4559. {
  4560. if ( lockout_time > 0 && reset_time > 0 && reenter_time > 0 )
  4561. database_new.Query("UPDATE character_instances SET lockout_time = %i, grant_reset_time_left = %i, grant_reenter_time_left = %i WHERE char_id = %i AND instance_id = %i", lockout_time, reset_time, reenter_time, char_id, instance_id);
  4562. else if ( lockout_time > 0 && reset_time > 0 )
  4563. database_new.Query("UPDATE character_instances SET lockout_time = %i, grant_reset_time_left = %i WHERE char_id = %i AND instance_id = %i", lockout_time, reset_time, char_id, instance_id);
  4564. else if ( reset_time > 0 && reenter_time > 0 )
  4565. database_new.Query("UPDATE character_instances SET grant_reset_time_left = %i, grant_reenter_time_left = %i WHERE char_id = %i AND instance_id = %i",reset_time, reenter_time, char_id, instance_id);
  4566. else if ( lockout_time > 0 && reenter_time > 0 )
  4567. database_new.Query("UPDATE character_instances SET lockout_time = %i, grant_reenter_time_left = %i WHERE char_id = %i AND instance_id = %i", lockout_time, reenter_time, char_id, instance_id);
  4568. else if ( lockout_time > 0 )
  4569. database_new.Query("UPDATE character_instances SET lockout_time = %i WHERE char_id = %i AND instance_id = %i", lockout_time, char_id, instance_id);
  4570. else if ( reset_time > 0 )
  4571. database_new.Query("UPDATE character_instances SET grant_reset_time_left = %i WHERE char_id = %i AND instance_id = %i", reset_time, char_id, instance_id);
  4572. else if ( reenter_time > 0 )
  4573. database_new.Query("UPDATE character_instances SET grant_reenter_time_left = %i WHERE char_id = %i AND instance_id = %i", reenter_time, char_id, instance_id);
  4574. if( database_new.GetError() )
  4575. {
  4576. LogWrite(INSTANCE__ERROR, 0, "Instance", "Error in UpdateCharacterInstanceTimers() '%s': %i", database_new.GetErrorMsg(), database_new.GetError());
  4577. return false;
  4578. }
  4579. else
  4580. {
  4581. if ( database_new.AffectedRows() > 0 )
  4582. {
  4583. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Updating instance timers for character %u to instance: %u", char_id, instance_id);
  4584. LogWrite(INSTANCE__DEBUG, 1, "Instance", "-- Reenter: %u, Reset: %u, Lockout: %u", reenter_time, reset_time, lockout_time);
  4585. return true;
  4586. }
  4587. else
  4588. return false;
  4589. }
  4590. }
  4591. bool WorldDatabase::UpdateCharacterInstance(int32 char_id, string zone_name, int32 instance_id, int8 type, int32 timestamp) {
  4592. // type = 1 = success timestamp
  4593. // type = 2 = failure timestamp
  4594. if (instance_id > 0) {
  4595. if (type == 1) {
  4596. database_new.Query("UPDATE character_instances SET instance_id = %u, last_success_timestamp = %u WHERE char_id = %u AND instance_zone_name = '%s'", instance_id, timestamp, char_id, database_new.EscapeStr(zone_name).c_str());
  4597. }
  4598. else if (type == 2) {
  4599. database_new.Query("UPDATE character_instances SET instance_id = %u, last_failure_timestamp = %u WHERE char_id = %u AND instance_zone_name = '%s'", instance_id, timestamp, char_id, database_new.EscapeStr(zone_name).c_str());
  4600. }
  4601. else {
  4602. database_new.Query("UPDATE character_instances SET instance_id = %u WHERE char_id = %u AND instance_zone_name = '%s'", instance_id, char_id, database_new.EscapeStr(zone_name).c_str());
  4603. }
  4604. }
  4605. else {
  4606. if (type == 1) {
  4607. database_new.Query("UPDATE character_instances SET last_success_timestamp = %u WHERE char_id = %u AND instance_zone_name = '%s'", timestamp, char_id, database_new.EscapeStr(zone_name).c_str());
  4608. }
  4609. else if (type == 2) {
  4610. database_new.Query("UPDATE character_instances SET last_failure_timestamp = %u WHERE char_id = %u AND instance_zone_name = '%s'", timestamp, char_id, database_new.EscapeStr(zone_name).c_str());
  4611. }
  4612. }
  4613. if (database_new.GetError()) {
  4614. LogWrite(INSTANCE__ERROR, 0, "Instance", "Error in UpdateCharacterInstance() '%s': %i", database_new.GetErrorMsg(), database_new.GetError());
  4615. return false;
  4616. }
  4617. return true;
  4618. }
  4619. bool WorldDatabase::VerifyInstanceID(int32 char_id, int32 instance_id) {
  4620. DatabaseResult result;
  4621. database_new.Select(&result, "SELECT COUNT(id) as num_instances FROM instances WHERE id = %u", instance_id);
  4622. if (result.Next() && result.GetInt32Str("num_instances") == 0) {
  4623. DeleteCharacterFromInstance(char_id, instance_id);
  4624. return false;
  4625. }
  4626. return true;
  4627. }
  4628. bool WorldDatabase::UpdateInstancedSpawnRemoved(int32 spawn_location_entry_id, int32 spawn_type, int32 respawn_time, int32 instance_id )
  4629. {
  4630. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Updating removed spawns for instance_id: %u", instance_id);
  4631. LogWrite(INSTANCE__DEBUG, 1, "Instance", "-- Spawn Location Entry ID: %u, Type: %u, Respawn: %u", spawn_location_entry_id, spawn_type, respawn_time);
  4632. if( !database_new.Query("UPDATE instance_spawns_removed SET respawn_time = %i WHERE spawn_location_entry_id = %i AND spawn_type = %i AND instance_id = %i", respawn_time, spawn_location_entry_id, spawn_type, instance_id) )
  4633. {
  4634. LogWrite(INSTANCE__ERROR, 0, "Instance", "Error in UpdateInstancedSpawnRemoved() '%s': %i", database_new.GetErrorMsg(), database_new.GetError());
  4635. return false;
  4636. }
  4637. if ( database_new.AffectedRows() > 0 )
  4638. {
  4639. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Updated removed spawns for instance_id: %u", instance_id);
  4640. return true;
  4641. }
  4642. else
  4643. return false;
  4644. }
  4645. int32 WorldDatabase::CreateNewInstance(int32 zone_id)
  4646. {
  4647. int32 ret = 0;
  4648. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Creating new instance for zone: %u ", zone_id);
  4649. if( !database_new.Query("INSERT INTO instances (zone_id) VALUES (%u)", zone_id) )
  4650. LogWrite(INSTANCE__ERROR, 0, "Instance", "Error in CreateNewInstance() '%s': %i", database_new.GetErrorMsg(), database_new.GetError());
  4651. else
  4652. ret = database_new.LastInsertID();
  4653. if( ret > 0 )
  4654. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Created new instance_id %u for zone: %u ", ret, zone_id);
  4655. return ret;
  4656. }
  4657. int32 WorldDatabase::CreateInstanceSpawnRemoved(int32 spawn_location_entry_id, int32 spawn_type, int32 respawn_time, int32 instance_id )
  4658. {
  4659. int32 ret = 0;
  4660. LogWrite(INSTANCE__DEBUG, 3, "Instance", "Creating new instance spawn removed entries for instance_id: %u ", instance_id);
  4661. LogWrite(INSTANCE__DEBUG, 5, "Instance", "-- Spawn Location Entry ID: %u, Type: %u, Respawn: %u", spawn_location_entry_id, spawn_type, respawn_time);
  4662. if( !database_new.Query("INSERT INTO instance_spawns_removed (spawn_location_entry_id, spawn_type, instance_id, respawn_time) values(%u, %u, %u, %u)", spawn_location_entry_id, spawn_type, instance_id, respawn_time) )
  4663. LogWrite(INSTANCE__ERROR, 0, "Instance", "Error in CreateInstanceSpawnRemoved() query '%s': %i", database_new.GetErrorMsg(), database_new.GetError());
  4664. else
  4665. ret = database_new.LastInsertID();
  4666. // potentially spammy, if it calls for every spawn added. Set to level 3 or 5?
  4667. if( ret > 0 )
  4668. LogWrite(INSTANCE__DEBUG, 5, "Instance", "Created new spawn removed entry: %u for instance_id %u", ret, instance_id);
  4669. return ret;
  4670. }
  4671. bool WorldDatabase::DeleteInstance(int32 instance_id)
  4672. {
  4673. if( !database_new.Query("DELETE FROM instances WHERE id = %u", instance_id) )
  4674. {
  4675. LogWrite(INSTANCE__ERROR, 0, "Instance", "Error in DeleteInstance() '%s': %i", database_new.GetErrorMsg(), database_new.GetError());
  4676. return false;
  4677. }
  4678. /* JA: should not need this delete with FK/Constraints
  4679. if( !database_new.Query("DELETE FROM instance_spawns_removed WHERE instance_id = %u", instance_id) )
  4680. {
  4681. LogWrite(INSTANCE__ERROR, 0, "Instance", "Error in DeleteInstance() '%s': %i", database_new.GetErrorMsg(), database_new.GetError());
  4682. return false;
  4683. }
  4684. */
  4685. // Remove the instance from the character_instances table
  4686. database_new.Query("UPDATE `character_instances` SET `instance_id` = 0 WHERE `instance_id` = %u", instance_id);
  4687. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Deleted instance_id %u", instance_id);
  4688. return true;
  4689. }
  4690. bool WorldDatabase::DeleteInstanceSpawnRemoved(int32 instance_id, int32 spawn_location_entry_id)
  4691. {
  4692. if( !database_new.Query("DELETE FROM instance_spawns_removed WHERE instance_id = %u AND spawn_location_entry_id = %u", instance_id, spawn_location_entry_id) )
  4693. {
  4694. LogWrite(INSTANCE__ERROR, 0, "Instance", "Error in DeleteInstanceSpawnRemoved() '%s': %i", database_new.GetErrorMsg(), database_new.GetError());
  4695. return false;
  4696. }
  4697. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Deleted removed spawn: %u for instance_id %u", spawn_location_entry_id, instance_id);
  4698. return true;
  4699. }
  4700. bool WorldDatabase::DeleteCharacterFromInstance(int32 char_id, int32 instance_id)
  4701. {
  4702. LogWrite(INSTANCE__DEBUG, 0, "Instance", "Delete character %u from instance_id %u.", char_id, instance_id);
  4703. if( !database_new.Query("UPDATE `character_instances` SET `instance_id` = 0 WHERE `instance_id` = %u AND `char_id` = %u", instance_id, char_id) )
  4704. {
  4705. LogWrite(INSTANCE__ERROR, 0, "Instance", "Error in DeleteCharacterFromInstance() '%s': %i", database_new.GetErrorMsg(), database_new.GetError());
  4706. return false;
  4707. }
  4708. if ( database_new.AffectedRows() == 0 ) // didn't find an instance to delete
  4709. {
  4710. LogWrite(INSTANCE__DEBUG, 1, "Instance", "No instance_id %u for character %u to delete.", instance_id, char_id);
  4711. return false;
  4712. }
  4713. else
  4714. {
  4715. // delete entire instance if the last player has left
  4716. DatabaseResult result;
  4717. database_new.Select(&result, "SELECT count(id) as num_instances FROM character_instances where instance_id = %u",instance_id);
  4718. if(result.Next() && result.GetInt32Str("num_instances") == 0)
  4719. {
  4720. LogWrite(INSTANCE__DEBUG, 0, "Instance", "No characters in instance: Delete instance_id %u.", instance_id);
  4721. DeleteInstance(instance_id);
  4722. }
  4723. }
  4724. return true;
  4725. }
  4726. bool WorldDatabase::LoadCharacterInstances(Client* client)
  4727. {
  4728. DatabaseResult result;
  4729. DatabaseResult result2;
  4730. bool addedInstance = false;
  4731. database_new.Select(&result, "SELECT `id`, `instance_id`, `instance_zone_name`, `instance_type`, `last_success_timestamp`, `last_failure_timestamp`, `success_lockout_time`, `failure_lockout_time` FROM `character_instances` WHERE `char_id` = %u", client->GetCharacterID());
  4732. if( result.GetNumRows() > 0 )
  4733. {
  4734. while( result.Next() )
  4735. {
  4736. int32 zone_id = 0;
  4737. int32 instance_id = result.GetInt32Str("instance_id");
  4738. // If `instance_id` is greater then 0 then get the zone id with it, else get the zone id from the zone name
  4739. if (instance_id != 0) {
  4740. if (database_new.Select(&result2, "SELECT `zone_id` FROM `instances` WHERE `id` = %u", instance_id)) {
  4741. if (result2.Next())
  4742. zone_id = result2.GetInt32Str("zone_id");
  4743. }
  4744. }
  4745. if (zone_id == 0)
  4746. zone_id = GetZoneID(result.GetStringStr("instance_zone_name"));
  4747. client->GetPlayer()->GetCharacterInstances()->AddInstance(
  4748. result.GetInt32Str("id"),
  4749. instance_id,
  4750. result.GetInt32Str("last_success_timestamp"),
  4751. result.GetInt32Str("last_failure_timestamp"),
  4752. result.GetInt32Str("success_lockout_time"),
  4753. result.GetInt32Str("failure_lockout_time"),
  4754. zone_id,
  4755. result.GetInt8Str("instance_type"),
  4756. string(result.GetStringStr("instance_zone_name"))
  4757. );
  4758. addedInstance = true;
  4759. }
  4760. }
  4761. return addedInstance;
  4762. }
  4763. void WorldDatabase::UpdateLoginEquipment()
  4764. {
  4765. LogWrite(INIT__LOGIN_DEBUG, 0, "Login", "Updating `character_items` CRC in %s", __FUNCTION__);
  4766. database_new.Query("UPDATE character_items SET login_checksum = CRC32(CRC32(type) + CRC32(slot) + CRC32(item_id)) WHERE `type` = 'EQUIPPED' AND ( slot <= 8 OR slot = 19 )");
  4767. }
  4768. MutexMap<int32, LoginEquipmentUpdate>* WorldDatabase::GetEquipmentUpdates()
  4769. {
  4770. DatabaseResult result;
  4771. MutexMap<int32, LoginEquipmentUpdate>* ret = 0;
  4772. LoginEquipmentUpdate update;
  4773. int32 count = 0;
  4774. LogWrite(INIT__LOGIN_DEBUG, 0, "Login", "Looking for Login Appearance Updates...");
  4775. // TODO: Someday store the equipment colors in character_items, for custom colorization of gear (?)
  4776. if( database_new.Select(&result, "SELECT ci.id, ci.char_id, ia.equip_type, ia.red, green, ia.blue, ia.highlight_red, ia.highlight_green, ia.highlight_blue, ci.slot FROM characters c JOIN character_items ci ON c.id = ci.char_id JOIN item_appearances ia ON ci.item_id = ia.item_id WHERE c.deleted = 0 AND ci.type = 'EQUIPPED' AND ( ci.slot <= 8 OR ci.slot = 19 ) AND ci.login_checksum <> CRC32(CRC32(`ci`.`type`) + CRC32(ci.slot) + CRC32(ci.item_id)) ORDER BY ci.char_id, ci.slot") )
  4777. {
  4778. while( result.Next() )
  4779. {
  4780. LogWrite(INIT__LOGIN_DEBUG, 5, "Login", "Found update for char_id %i!", result.GetInt32Str("char_id"));
  4781. if(!ret)
  4782. ret = new MutexMap<int32, LoginEquipmentUpdate>();
  4783. update.world_char_id = result.GetInt32Str("char_id");
  4784. update.equip_type = result.GetInt16Str("equip_type");
  4785. update.red = result.GetInt8Str("red");
  4786. update.green = result.GetInt8Str("green");
  4787. update.blue = result.GetInt8Str("blue");
  4788. update.highlight_red = result.GetInt8Str("highlight_red");
  4789. update.highlight_green = result.GetInt8Str("highlight_green");
  4790. update.highlight_blue = result.GetInt8Str("highlight_blue");
  4791. update.slot = result.GetInt8Str("slot");
  4792. ret->Put(result.GetInt32Str("id"), update);
  4793. count++;
  4794. }
  4795. }
  4796. if(count)
  4797. LogWrite(INIT__LOGIN_DEBUG, 0, "Login", "Found %i Login Appearance Update%s...", count, count == 1 ? "" : "s");
  4798. return ret;
  4799. }
  4800. MutexMap<int32, LoginEquipmentUpdate>* WorldDatabase::GetEquipmentUpdates(int32 char_id)
  4801. {
  4802. DatabaseResult result;
  4803. MutexMap<int32, LoginEquipmentUpdate>* ret = 0;
  4804. LoginEquipmentUpdate update;
  4805. int32 count = 0;
  4806. LogWrite(INIT__LOGIN_DEBUG, 0, "Login", "Looking for Login Appearance Updates for char_id: %u", char_id);
  4807. // TODO: Someday store the equipment colors in character_items, for custom colorization of gear (?)
  4808. if( database_new.Select(&result, "SELECT ci.id, ci.char_id, ia.equip_type, ia.red, green, ia.blue, ia.highlight_red, ia.highlight_green, ia.highlight_blue, ci.slot FROM characters c JOIN character_items ci ON c.id = ci.char_id JOIN item_appearances ia ON ci.item_id = ia.item_id WHERE c.deleted = 0 AND ci.type = 'EQUIPPED' AND ( ci.slot <= 8 OR ci.slot = 19 ) AND ci.login_checksum <> CRC32(CRC32(ci.type) + CRC32(ci.slot) + CRC32(ci.item_id)) AND ci.char_id = %u ORDER BY ci.slot", char_id) )
  4809. {
  4810. while( result.Next() )
  4811. {
  4812. LogWrite(INIT__LOGIN_DEBUG, 5, "Login", "Found update for char_id %i!", result.GetInt32Str("char_id"));
  4813. if(!ret)
  4814. ret = new MutexMap<int32, LoginEquipmentUpdate>();
  4815. update.world_char_id = char_id;
  4816. update.equip_type = result.GetInt16Str("equip_type");
  4817. update.red = result.GetInt8Str("red");
  4818. update.green = result.GetInt8Str("green");
  4819. update.blue = result.GetInt8Str("blue");
  4820. update.highlight_red = result.GetInt8Str("highlight_red");
  4821. update.highlight_green = result.GetInt8Str("highlight_green");
  4822. update.highlight_blue = result.GetInt8Str("highlight_blue");
  4823. update.slot = result.GetInt8Str("slot");
  4824. ret->Put(result.GetInt32Str("id"), update);
  4825. count++;
  4826. }
  4827. }
  4828. if(count)
  4829. LogWrite(INIT__LOGIN_DEBUG, 0, "Login", "Found %i Login Appearance Update%s...", count, count == 1 ? "" : "s");
  4830. return ret;
  4831. }
  4832. void WorldDatabase::UpdateLoginZones() {
  4833. Query query;
  4834. LogWrite(INIT__LOGIN_DEBUG, 0, "Login", "Updating `zones` CRC in %s", __FUNCTION__);
  4835. query.RunQuery2("UPDATE zones SET login_checksum = CRC32(CRC32(id) + CRC32(`name`) + CRC32(`file`) + CRC32(description))", Q_UPDATE);
  4836. }
  4837. MutexMap<int32, LoginZoneUpdate>* WorldDatabase::GetZoneUpdates() {
  4838. LogWrite(INIT__LOGIN_DEBUG, 0, "Login", "Looking for Login Zone Updates...");
  4839. MutexMap<int32, LoginZoneUpdate>* ret = 0;
  4840. LoginZoneUpdate update;
  4841. Query query;
  4842. MYSQL_ROW row;
  4843. int32 count = 0;
  4844. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, name, description FROM zones where login_checksum != crc32(crc32(id) + crc32(name) + crc32(file) + crc32(description))");
  4845. while(result && (row = mysql_fetch_row(result))) {
  4846. if(row[0] && row[1]) {
  4847. LogWrite(INIT__LOGIN_DEBUG, 5, "Login", "Found update for zone_id %i!", atoi(row[0]));
  4848. if(!ret)
  4849. ret = new MutexMap<int32, LoginZoneUpdate>();
  4850. update.name = string(row[1]);
  4851. if(row[2])
  4852. update.description = string(row[2]);
  4853. else
  4854. update.description = "";
  4855. ret->Put(atoi(row[0]), update);
  4856. count++;
  4857. }
  4858. }
  4859. if(count)
  4860. LogWrite(INIT__LOGIN_DEBUG, 0, "Login", "Found %i Login Zone Update%s...", count, count == 1 ? "" : "s");
  4861. return ret;
  4862. }
  4863. void WorldDatabase::LoadLocationGrids(ZoneServer* zone) {
  4864. if (zone) {
  4865. Query query;
  4866. MYSQL_ROW row;
  4867. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `id`, `grid_id`, `name`, `include_y`, `discovery` FROM `locations` WHERE `zone_id`=%u", zone->GetZoneID());
  4868. while (result && (row = mysql_fetch_row(result))) {
  4869. LocationGrid* grid = new LocationGrid;
  4870. grid->id = atoul(row[0]);
  4871. grid->grid_id = atoul(row[1]);
  4872. grid->name = string(row[2]);
  4873. grid->include_y = (atoi(row[3]) == 1);
  4874. grid->discovery = (atoi(row[4]) == 1);
  4875. if (LoadLocationGridLocations(grid))
  4876. zone->AddLocationGrid(grid);
  4877. else
  4878. safe_delete(grid);
  4879. }
  4880. }
  4881. }
  4882. bool WorldDatabase::LoadLocationGridLocations(LocationGrid* grid) {
  4883. bool ret = false;
  4884. if (grid) {
  4885. Query query;
  4886. MYSQL_ROW row;
  4887. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `id`, `x`, `y`, `z` FROM `location_details` WHERE `location_id`=%u", grid->id);
  4888. if (result->row_count >= 3) {
  4889. while (result && (row = mysql_fetch_row(result))) {
  4890. Location* location = new Location;
  4891. location->id = atoul(row[0]);
  4892. location->x = atof(row[1]);
  4893. location->y = atof(row[2]);
  4894. location->z = atof(row[3]);
  4895. grid->locations.Add(location);
  4896. }
  4897. ret = true;
  4898. }
  4899. else
  4900. LogWrite(WORLD__ERROR, 0, "World", "Grid '%s' only has %u location(s). A minimum of 3 is needed.", grid->name.c_str(), result->row_count);
  4901. }
  4902. return ret;
  4903. }
  4904. int32 WorldDatabase::CreateLocation(int32 zone_id, int32 grid_id, const char* name, bool include_y) {
  4905. int32 ret = 0;
  4906. if (name && strlen(name) > 0) {
  4907. Query query;
  4908. query.RunQuery2(Q_INSERT, "INSERT INTO `locations` (`zone_id`, `grid_id`, `name`, `include_y`) VALUES (%u, %u, '%s', %u)", zone_id, grid_id, name, include_y == true ? 1 : 0);
  4909. ret = query.GetLastInsertedID();
  4910. }
  4911. return ret;
  4912. }
  4913. bool WorldDatabase::AddLocationPoint(int32 location_id, float x, float y, float z) {
  4914. bool ret = false;
  4915. if (LocationExists(location_id)) {
  4916. Query query;
  4917. query.RunQuery2(Q_INSERT, "INSERT INTO `location_details` (`location_id`, `x`, `y`, `z`) VALUES (%u, %f, %f, %f)", location_id, x, y, z);
  4918. ret = true;
  4919. }
  4920. return ret;
  4921. }
  4922. bool WorldDatabase::DeleteLocation(int32 location_id) {
  4923. bool ret = false;
  4924. if (LocationExists(location_id)) {
  4925. Query query;
  4926. query.RunQuery2(Q_DELETE, "DELETE FROM `locations` WHERE `id`=%u", location_id);
  4927. ret = true;
  4928. }
  4929. return ret;
  4930. }
  4931. bool WorldDatabase::DeleteLocationPoint(int32 location_point_id) {
  4932. Query query;
  4933. query.RunQuery2(Q_DELETE, "DELETE FROM `location_details` WHERE `id`=%u", location_point_id);
  4934. return true;
  4935. }
  4936. void WorldDatabase::ListLocations(Client* client) {
  4937. if (client) {
  4938. Query query;
  4939. MYSQL_ROW row;
  4940. client->SimpleMessage(CHANNEL_COLOR_YELLOW, "Listing all locations:");
  4941. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `id`, `zone_id`, `grid_id`, `name` FROM `locations`");
  4942. while (result && (row = mysql_fetch_row(result))) {
  4943. int32 id = atoul(row[0]);
  4944. int32 zone_id = atoul(row[1]);
  4945. int32 grid_id = atoul(row[2]);
  4946. const char* name = row[3];
  4947. client->Message(CHANNEL_COLOR_YELLOW, "%u) Zone ID: %u Grid ID:%u Name: '%s'", id, zone_id, grid_id, name);
  4948. }
  4949. }
  4950. }
  4951. void WorldDatabase::ListLocationPoints(Client* client, int32 location_id) {
  4952. if (client) {
  4953. if (LocationExists(location_id)) {
  4954. Query query;
  4955. client->Message(CHANNEL_COLOR_YELLOW, "Listing all points for location ID %u:", location_id);
  4956. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `id`, `x`, `y`, `z` FROM `location_details` WHERE `location_id`=%u", location_id);
  4957. MYSQL_ROW row;
  4958. while (result && (row = mysql_fetch_row(result))) {
  4959. int32 id = atoul(row[0]);
  4960. float x = atof(row[1]);
  4961. float y = atof(row[2]);
  4962. float z = atof(row[3]);
  4963. client->Message(CHANNEL_COLOR_YELLOW, "%u) (%f, %f, %f)", id, x, y, z);
  4964. }
  4965. }
  4966. else
  4967. client->Message(CHANNEL_COLOR_YELLOW, "A location with ID %u does not exist", location_id);
  4968. }
  4969. }
  4970. bool WorldDatabase::LocationExists(int32 location_id) {
  4971. bool ret = false;
  4972. Query query;
  4973. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT COUNT(id) FROM `locations` WHERE `id`=%u", location_id);
  4974. MYSQL_ROW row;
  4975. if (result && (row = mysql_fetch_row(result))) {
  4976. if (atoul(row[0]) > 0)
  4977. ret = true;
  4978. }
  4979. return ret;
  4980. }
  4981. bool WorldDatabase::GetTableVersions(vector<TableVersion*>* table_versions) {
  4982. DatabaseResult result;
  4983. TableVersion *table_version;
  4984. bool success;
  4985. //don't treat 1146 (table not found) as an error since the patch server will create it
  4986. database_new.SetIgnoredErrno(1146);
  4987. success = database_new.Select(&result, "SELECT `name`,`version`,`download_version`\n"
  4988. "FROM `table_versions`\n");
  4989. database_new.RemoveIgnoredErrno(1146);
  4990. if (!success)
  4991. return false;
  4992. while (result.Next()) {
  4993. table_version = (TableVersion *)malloc(sizeof(*table_version));
  4994. table_version->name_len = (unsigned int)strlcpy(table_version->name, result.GetString(0), sizeof(table_version->name));
  4995. table_version->version = result.GetInt32(1);
  4996. table_version->data_version = result.GetInt32(2);
  4997. table_versions->push_back(table_version);
  4998. }
  4999. return true;
  5000. }
  5001. bool WorldDatabase::QueriesFromFile(const char * file) {
  5002. return database_new.QueriesFromFile(file);
  5003. }
  5004. bool WorldDatabase::CheckBannedIPs(const char* loginIP)
  5005. {
  5006. // til you build the table, all IPs are allowed
  5007. return false;
  5008. }
  5009. void WorldDatabase::LoadTitles(){
  5010. int32 index = 0;
  5011. Query query;
  5012. MYSQL_ROW row;
  5013. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, title, prefix FROM titles");
  5014. if(result && mysql_num_rows(result) > 0){
  5015. Title* title = 0;
  5016. while(result && (row = mysql_fetch_row(result))){
  5017. LogWrite(WORLD__DEBUG, 5, "World", "\tLoading Title '%s' (%u), Prefix: %i, Index: %u", row[1], atoul(row[0]), atoi(row[2]), index);
  5018. title = new Title;
  5019. title->SetID(index);
  5020. title->SetName(row[1]);
  5021. title->SetPrefix(atoi(row[2]));
  5022. master_titles_list.AddTitle(title);
  5023. index++;
  5024. }
  5025. }
  5026. LogWrite(WORLD__DEBUG, 0, "World", "\tLoaded %u Title%s", index, index == 1 ? "" : "s");
  5027. }
  5028. int32 WorldDatabase::LoadCharacterTitles(int32 char_id, Player *player){
  5029. LogWrite(WORLD__DEBUG, 0, "World", "Loading Titles for player '%s'...", player->GetName());
  5030. Query query;
  5031. MYSQL_ROW row;
  5032. int32 index = 0;
  5033. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT title_id, title, prefix FROM character_titles, titles WHERE character_titles.title_id = titles.id AND character_titles.char_id = %u", char_id);
  5034. if(result && mysql_num_rows(result) > 0){
  5035. while(result && (row = mysql_fetch_row(result))){
  5036. LogWrite(WORLD__DEBUG, 5, "World", "\tLoading Title ID: %u, Title: '%s' Index: %u", atoul(row[0]), row[1], index);
  5037. player->AddTitle(index, row[1], atoi(row[2]));
  5038. index++;
  5039. }
  5040. }
  5041. return index;
  5042. }
  5043. sint16 WorldDatabase::GetCharPrefixIndex(int32 char_id, Player *player){
  5044. LogWrite(PLAYER__DEBUG, 0, "Player", "Getting current title index for player '%s'...", player->GetName());
  5045. Query query;
  5046. MYSQL_ROW row;
  5047. sint16 ret = -1;
  5048. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT prefix_title FROM character_details WHERE char_id = %u", char_id);
  5049. if(result && mysql_num_rows(result) > 0)
  5050. while(result && (row = mysql_fetch_row(result))){
  5051. ret = atoi(row[0]);
  5052. LogWrite(PLAYER__DEBUG, 5, "Player", "\tPrefix Index: %i", ret);
  5053. }
  5054. return ret;
  5055. }
  5056. sint16 WorldDatabase::GetCharSuffixIndex(int32 char_id, Player *player){
  5057. LogWrite(PLAYER__DEBUG, 0, "Player", "Getting current title index for player '%s'...", player->GetName());
  5058. Query query;
  5059. MYSQL_ROW row;
  5060. sint16 ret = -1;
  5061. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT suffix_title FROM character_details WHERE char_id = %u", char_id);
  5062. if(result && mysql_num_rows(result) > 0)
  5063. while(result && (row = mysql_fetch_row(result))){
  5064. ret = atoi(row[0]);
  5065. LogWrite(PLAYER__DEBUG, 5, "Player", "\tSuffix Index: %i", ret);
  5066. }
  5067. return ret;
  5068. }
  5069. void WorldDatabase::SaveCharPrefixIndex(sint16 index, int32 char_id, Client *client){
  5070. Query query;
  5071. query.RunQuery2(Q_UPDATE, "UPDATE character_details SET prefix_title = %i WHERE char_id = %u", index, client->GetCharacterID());
  5072. LogWrite(PLAYER__DEBUG, 0, "Player", "Saving Prefix Index %i for player '%s'...", index, client->GetPlayer()->GetName());
  5073. }
  5074. void WorldDatabase::SaveCharSuffixIndex(sint16 index, int32 char_id, Client *client){
  5075. Query query;
  5076. query.RunQuery2(Q_SELECT, "UPDATE character_details SET suffix_title = %i WHERE char_id = %u", index, client->GetCharacterID());
  5077. LogWrite(PLAYER__DEBUG, 0, "Player", "Saving Suffix Index %i for player '%s'...", index, client->GetPlayer()->GetName());
  5078. }
  5079. void WorldDatabase::LoadLanguages()
  5080. {
  5081. int32 count = 0;
  5082. Query query;
  5083. MYSQL_ROW row;
  5084. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, language FROM languages");
  5085. if(result && mysql_num_rows(result) > 0)
  5086. {
  5087. Language* language = 0;
  5088. while(result && (row = mysql_fetch_row(result)))
  5089. {
  5090. LogWrite(WORLD__DEBUG, 5, "World", "\tLoading language '%s' , ID: %u", row[1], atoul(row[0]));
  5091. language = new Language;
  5092. language->SetID(atoul(row[0]));
  5093. language->SetName(row[1]);
  5094. master_languages_list.AddLanguage(language);
  5095. count++;
  5096. }
  5097. }
  5098. LogWrite(WORLD__DEBUG, 0, "World", "\tLoaded %u Language%s", count, count == 1 ? "" : "s");
  5099. }
  5100. int32 WorldDatabase::LoadCharacterLanguages(int32 char_id, Player *player)
  5101. {
  5102. LogWrite(WORLD__DEBUG, 0, "World", "Loading Languages for player '%s'...", player->GetName());
  5103. Query query;
  5104. MYSQL_ROW row;
  5105. int32 count = 0;
  5106. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT language_id, language FROM character_languages, languages WHERE character_languages.language_id = languages.id AND character_languages.char_id = %u", char_id);
  5107. if(result && mysql_num_rows(result) > 0)
  5108. {
  5109. while(result && (row = mysql_fetch_row(result)))
  5110. {
  5111. LogWrite(WORLD__DEBUG, 5, "World", "\tLoading Language ID: %u, Language: '%s'", atoul(row[0]), row[1]);
  5112. player->AddLanguage(atoul(row[0]), row[1]);
  5113. count++;
  5114. }
  5115. }
  5116. return count;
  5117. }
  5118. int16 WorldDatabase::GetCharacterCurrentLang(int32 char_id, Player *player)
  5119. {
  5120. LogWrite(PLAYER__DEBUG, 0, "Player", "Getting current language for player '%s'...", player->GetName());
  5121. Query query;
  5122. MYSQL_ROW row;
  5123. int16 ret = 0;
  5124. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT current_language FROM character_details WHERE char_id = %u", char_id);
  5125. if(result && mysql_num_rows(result) > 0)
  5126. while(result && (row = mysql_fetch_row(result)))
  5127. {
  5128. ret = atoi(row[0]);
  5129. LogWrite(PLAYER__DEBUG, 5, "Player", "\tLanguage ID: %i", ret);
  5130. }
  5131. return ret;
  5132. }
  5133. void WorldDatabase::SaveCharacterCurrentLang(int32 id, int32 char_id, Client *client)
  5134. {
  5135. Query query;
  5136. query.RunQuery2(Q_UPDATE, "UPDATE character_details SET current_language = %i WHERE char_id = %u", id, char_id);
  5137. LogWrite(PLAYER__DEBUG, 3, "Player", "Saving current language ID %i for player '%s'...", id, client->GetPlayer()->GetName());
  5138. }
  5139. void WorldDatabase::SaveCharacterLang(int32 char_id, int32 lang_id) {
  5140. if (!database_new.Query("INSERT INTO character_languages (char_id, language_id) VALUES (%u, %u)", char_id, lang_id))
  5141. LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
  5142. }
  5143. // JA - this is not used yet, lots more to consider for storing player history
  5144. void WorldDatabase::LoadCharacterHistory(int32 char_id, Player *player)
  5145. {
  5146. DatabaseResult result;
  5147. // Use -1 on type and subtype to turn the enum into an int and make it a 0 index
  5148. if (!database_new.Select(&result, "SELECT type-1, subtype-1, value, value2, location, event_id, event_date FROM character_history WHERE char_id = %u", char_id)) {
  5149. LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
  5150. return;
  5151. }
  5152. while (result.Next()) {
  5153. int8 type = result.GetInt8(0);
  5154. int8 subtype = result.GetInt8(1);
  5155. HistoryData* hd = new HistoryData;
  5156. hd->Value = result.GetInt32(2);
  5157. hd->Value2 = result.GetInt32(3);
  5158. strcpy(hd->Location, result.GetString(4));
  5159. // skipped event id as use for it has not been determined yet
  5160. hd->EventDate = result.GetInt32(6);
  5161. player->LoadPlayerHistory(type, subtype, hd);
  5162. }
  5163. }
  5164. void WorldDatabase::LoadSpellErrors() {
  5165. Query query;
  5166. MYSQL_ROW row;
  5167. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `version`, `error_index`, `value` FROM `spell_error_versions`");
  5168. if (result && mysql_num_rows(result) > 0) {
  5169. while ((row = mysql_fetch_row(result))) {
  5170. master_spell_list.AddSpellError(atoi(row[0]), atoi(row[1]), atoi(row[2]));
  5171. }
  5172. }
  5173. }
  5174. void WorldDatabase::SaveCharacterHistory(Player* player, int8 type, int8 subtype, int32 value, int32 value2, char* location, int32 event_date) {
  5175. string str_type;
  5176. string str_subtype;
  5177. switch (type) {
  5178. case HISTORY_TYPE_NONE:
  5179. str_type = "None";
  5180. break;
  5181. case HISTORY_TYPE_DEATH:
  5182. str_type = "Death";
  5183. break;
  5184. case HISTORY_TYPE_DISCOVERY:
  5185. str_type = "Discovery";
  5186. break;
  5187. case HISTORY_TYPE_XP:
  5188. str_type = "XP";
  5189. break;
  5190. default:
  5191. LogWrite(PLAYER__ERROR, 0, "Player", "WorldDatabase::SaveCharacterHistory() - Invalid history type given (%i) with subtype (%i), character history NOT saved.", type, subtype);
  5192. return;
  5193. }
  5194. switch (subtype) {
  5195. case HISTORY_SUBTYPE_NONE:
  5196. str_subtype = "None";
  5197. break;
  5198. case HISTORY_SUBTYPE_ADVENTURE:
  5199. str_subtype = "Adventure";
  5200. break;
  5201. case HISTORY_SUBTYPE_TRADESKILL:
  5202. str_subtype = "Tradeskill";
  5203. break;
  5204. case HISTORY_SUBTYPE_QUEST:
  5205. str_subtype = "Quest";
  5206. break;
  5207. case HISTORY_SUBTYPE_AA:
  5208. str_subtype = "AA";
  5209. break;
  5210. case HISTORY_SUBTYPE_ITEM:
  5211. str_subtype = "Item";
  5212. break;
  5213. case HISTORY_SUBTYPE_LOCATION:
  5214. str_subtype = "Location";
  5215. break;
  5216. default:
  5217. LogWrite(PLAYER__ERROR, 0, "Player", "WorldDatabase::SaveCharacterHistory() - Invalid history sub type given (%i) with type (%i), character history NOT saved.", subtype, type);
  5218. return;
  5219. }
  5220. LogWrite(PLAYER__INFO, 1, "Player", "Saving character history, type = %s (%i) subtype = %s (%i)", (char*)str_type.c_str(), type, (char*)str_subtype.c_str(), subtype);
  5221. Query query;
  5222. query.AddQueryAsync(player->GetCharacterID(), this, Q_REPLACE, "replace into character_history (char_id, type, subtype, value, value2, location, event_date) values (%u, '%s', '%s', %i, %i, '%s', %u)",
  5223. player->GetCharacterID(), str_type.c_str(), str_subtype.c_str(), value, value2, location, event_date);
  5224. }
  5225. void WorldDatabase::LoadTransportMaps(ZoneServer* zone) {
  5226. int32 total = 0;
  5227. LogWrite(TRANSPORT__DEBUG, 0, "Transport", "-Loading Transporter Maps...");
  5228. zone->DeleteTransporterMaps();
  5229. Query query;
  5230. MYSQL_ROW row;
  5231. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT `transport_id`, `map_name` FROM `transport_maps`");
  5232. if(result) {
  5233. while(result && (row = mysql_fetch_row(result))){
  5234. zone->AddTransportMap(atoul(row[0]), string(row[1]));
  5235. total++;
  5236. }
  5237. }
  5238. LogWrite(TRANSPORT__DEBUG, 0, "Transport", "--Loaded %i Transporter Maps", total);
  5239. }
  5240. bool WorldDatabase::LoadSign(ZoneServer* zone, int32 spawn_id) {
  5241. Sign* sign = 0;
  5242. int32 id = 0;
  5243. DatabaseResult result;
  5244. database_new.Select(&result, "SELECT ss.spawn_id, s.name, s.model_type, s.size, s.show_command_icon, ss.widget_id, ss.widget_x, ss.widget_y, ss.widget_z, s.command_primary, s.command_secondary, s.collision_radius, ss.icon, ss.type, ss.title, ss.description, ss.sign_distance, ss.zone_id, ss.zone_x, ss.zone_y, ss.zone_z, ss.zone_heading, ss.include_heading, ss.include_location, s.transport_id, s.size_offset, s.display_hand_icon, s.visual_state\n"
  5245. "FROM spawn s\n"
  5246. "INNER JOIN spawn_signs ss\n"
  5247. "ON ss.spawn_id = s.id\n"
  5248. "WHERE s.id = %u\n",
  5249. spawn_id);
  5250. if (result.GetNumRows() > 0 && result.Next()) {
  5251. id = result.GetInt32(0);
  5252. sign = new Sign();
  5253. sign->SetDatabaseID(id);
  5254. strcpy(sign->appearance.name, result.GetString(1));
  5255. sign->appearance.model_type = result.GetInt16(2);
  5256. sign->SetSize(result.GetInt16(3));
  5257. sign->appearance.show_command_icon = result.GetInt8(4);
  5258. sign->SetWidgetID(result.GetInt32(5));
  5259. sign->SetWidgetX(result.GetFloat(6));
  5260. sign->SetWidgetY(result.GetFloat(7));
  5261. sign->SetWidgetZ(result.GetFloat(8));
  5262. vector<EntityCommand*>* primary_command_list = zone->GetEntityCommandList(result.GetInt32(9));
  5263. if(primary_command_list){
  5264. sign->SetPrimaryCommands(primary_command_list);
  5265. sign->primary_command_list_id = result.GetInt32(9);
  5266. }
  5267. vector<EntityCommand*>* secondary_command_list = zone->GetEntityCommandList(result.GetInt32(10));
  5268. if (secondary_command_list) {
  5269. sign->SetSecondaryCommands(secondary_command_list);
  5270. sign->secondary_command_list_id = result.GetInt32(10);
  5271. }
  5272. sign->appearance.pos.collision_radius = result.GetInt16(11);
  5273. sign->SetSignIcon(result.GetInt8(12));
  5274. if(strncasecmp(result.GetString(13), "Generic", 7) == 0)
  5275. sign->SetSignType(SIGN_TYPE_GENERIC);
  5276. else if(strncasecmp(result.GetString(13), "Zone", 4) == 0)
  5277. sign->SetSignType(SIGN_TYPE_ZONE);
  5278. sign->SetSignTitle(result.GetString(14));
  5279. sign->SetSignDescription(result.GetString(15));
  5280. sign->SetSignDistance(result.GetFloat(16));
  5281. sign->SetSignZoneID(result.GetInt32(17));
  5282. sign->SetSignZoneX(result.GetFloat(18));
  5283. sign->SetSignZoneY(result.GetFloat(19));
  5284. sign->SetSignZoneZ(result.GetFloat(20));
  5285. sign->SetSignZoneHeading(result.GetFloat(21));
  5286. sign->SetIncludeHeading(result.GetInt8(22) == 1);
  5287. sign->SetIncludeLocation(result.GetInt8(23) == 1);
  5288. sign->SetTransporterID(result.GetInt32(24));
  5289. sign->SetSizeOffset(result.GetInt8(25));
  5290. sign->appearance.display_hand_icon = result.GetInt8(26);
  5291. sign->SetVisualState(result.GetInt16(27));
  5292. zone->AddSign(id, sign);
  5293. LogWrite(SIGN__DEBUG, 0, "Sign", "Loaded Sign: '%s' (%u).", sign->appearance.name, spawn_id);
  5294. return true;
  5295. }
  5296. LogWrite(SIGN__DEBUG, 0, "Sign", "Unable to find a sign for spawn id of %u", spawn_id);
  5297. return false;
  5298. }
  5299. bool WorldDatabase::LoadWidget(ZoneServer* zone, int32 spawn_id) {
  5300. Widget* widget = 0;
  5301. int32 id = 0;
  5302. DatabaseResult result;
  5303. database_new.Select(&result, "SELECT sw.spawn_id, s.name, s.model_type, s.size, s.show_command_icon, sw.widget_id, sw.widget_x, sw.widget_y, sw.widget_z, s.command_primary, s.command_secondary, s.collision_radius, sw.include_heading, sw.include_location, sw.icon, sw.type, sw.open_heading, sw.open_y, sw.action_spawn_id, sw.open_sound_file, sw.close_sound_file, sw.open_duration, sw.closed_heading, sw.linked_spawn_id, sw.close_y, s.transport_id, s.size_offset, sw.house_id, sw.open_x, sw.open_z, sw.close_x, sw.close_z, s.display_hand_icon\n"
  5304. "FROM spawn s\n"
  5305. "INNER JOIN spawn_widgets sw\n"
  5306. "ON sw.spawn_id = s.id\n"
  5307. "WHERE s.id = %u",
  5308. spawn_id);
  5309. if (result.GetNumRows() > 0 && result.Next()) {
  5310. id = result.GetInt32(0);
  5311. widget = new Widget();
  5312. widget->SetDatabaseID(id);
  5313. strcpy(widget->appearance.name, result.GetString(1));
  5314. widget->appearance.model_type = result.GetInt16(2);
  5315. widget->SetSize(result.GetInt16(3));
  5316. widget->appearance.show_command_icon = result.GetInt8(4);
  5317. widget->SetWidgetID(result.GetInt32(5));
  5318. widget->SetWidgetX(result.GetFloat(6));
  5319. widget->SetWidgetY(result.GetFloat(7));
  5320. widget->SetWidgetZ(result.GetFloat(8));
  5321. vector<EntityCommand*>* primary_command_list = zone->GetEntityCommandList(result.GetInt32(9));
  5322. if(primary_command_list){
  5323. widget->SetPrimaryCommands(primary_command_list);
  5324. widget->primary_command_list_id = result.GetInt32(9);
  5325. }
  5326. vector<EntityCommand*>* secondary_command_list = zone->GetEntityCommandList(result.GetInt32(10));
  5327. if (secondary_command_list) {
  5328. widget->SetSecondaryCommands(secondary_command_list);
  5329. widget->secondary_command_list_id = result.GetInt32(10);
  5330. }
  5331. widget->appearance.pos.collision_radius = result.GetInt16(11);
  5332. widget->SetIncludeHeading(result.GetInt8(12) == 1);
  5333. widget->SetIncludeLocation(result.GetInt8(13) == 1);
  5334. widget->SetWidgetIcon(result.GetInt8(14));
  5335. if(strncasecmp(result.GetString(15),"Generic", 7) == 0)
  5336. widget->SetWidgetType(WIDGET_TYPE_GENERIC);
  5337. else if(strncasecmp(result.GetString(15),"Door", 4) == 0)
  5338. widget->SetWidgetType(WIDGET_TYPE_DOOR);
  5339. widget->SetOpenHeading(result.GetFloat(16));
  5340. widget->SetOpenY(result.GetFloat(17));
  5341. widget->SetActionSpawnID(result.GetInt32(18));
  5342. if(!result.IsNull(19) && strlen(result.GetString(19)) > 5)
  5343. widget->SetOpenSound(result.GetString(19));
  5344. if(!result.IsNull(20) && strlen(result.GetString(20)) > 5)
  5345. widget->SetCloseSound(result.GetString(20));
  5346. widget->SetOpenDuration(result.GetInt16(21));
  5347. widget->SetClosedHeading(result.GetFloat(22));
  5348. widget->SetLinkedSpawnID(result.GetInt32(23));
  5349. widget->SetCloseY(result.GetFloat(24));
  5350. widget->SetTransporterID(result.GetInt32(25));
  5351. widget->SetSizeOffset(result.GetInt8(26));
  5352. widget->SetHouseID(result.GetInt32(27));
  5353. widget->SetOpenX(result.GetFloat(28));
  5354. widget->SetOpenZ(result.GetFloat(29));
  5355. widget->SetCloseX(result.GetFloat(30));
  5356. widget->SetCloseZ(result.GetFloat(31));
  5357. widget->appearance.display_hand_icon = result.GetInt8(32);
  5358. zone->AddWidget(id, widget);
  5359. LogWrite(WIDGET__DEBUG, 0, "Widget", "Loaded Widget: '%s' (%u).", widget->appearance.name, spawn_id);
  5360. return true;
  5361. }
  5362. LogWrite(WIDGET__DEBUG, 0, "Widget", "Unable to find a widget for spawn id of %u", spawn_id);
  5363. return false;
  5364. }
  5365. bool WorldDatabase::LoadObject(ZoneServer* zone, int32 spawn_id) {
  5366. Object* object = 0;
  5367. int32 id = 0;
  5368. DatabaseResult result;
  5369. database_new.Select(&result, "SELECT so.spawn_id, s.name, s.race, s.model_type, s.command_primary, s.command_secondary, s.targetable, s.size, s.show_name, s.visual_state, s.attackable, s.show_level, s.show_command_icon, s.display_hand_icon, s.faction_id, s.collision_radius, s.transport_id, s.size_offset, so.device_id\n"
  5370. "FROM spawn s\n"
  5371. "INNER JOIN spawn_objects so\n"
  5372. "ON so.spawn_id = s.id\n"
  5373. "WHERE s.id = %u",
  5374. spawn_id);
  5375. if (result.GetNumRows() > 0 && result.Next()) {
  5376. id = result.GetInt32(0);
  5377. object = new Object();
  5378. object->SetDatabaseID(id);
  5379. strcpy(object->appearance.name, result.GetString(1));
  5380. vector<EntityCommand*>* primary_command_list = zone->GetEntityCommandList(result.GetInt32(4));
  5381. vector<EntityCommand*>* secondary_command_list = zone->GetEntityCommandList(result.GetInt32(5));
  5382. if(primary_command_list){
  5383. object->SetPrimaryCommands(primary_command_list);
  5384. object->primary_command_list_id = result.GetInt32(4);
  5385. }
  5386. if(secondary_command_list){
  5387. object->SetSecondaryCommands(secondary_command_list);
  5388. object->secondary_command_list_id = result.GetInt32(5);
  5389. }
  5390. object->appearance.race = result.GetInt8(2);
  5391. object->appearance.model_type = result.GetInt16(3);
  5392. object->appearance.targetable = result.GetInt8(6);
  5393. object->size = result.GetInt16(7);
  5394. object->appearance.display_name = result.GetInt8(8);
  5395. object->appearance.visual_state = result.GetInt16(9);
  5396. object->appearance.attackable = result.GetInt8(10);
  5397. object->appearance.show_level = result.GetInt8(11);
  5398. object->appearance.show_command_icon = result.GetInt8(12);
  5399. object->appearance.display_hand_icon = result.GetInt8(13);
  5400. object->faction_id = result.GetInt32(14);
  5401. object->appearance.pos.collision_radius = result.GetInt16(15);
  5402. object->SetTransporterID(result.GetInt32(16));
  5403. object->SetSizeOffset(result.GetInt8(17));
  5404. object->SetDeviceID(result.GetInt8(18));
  5405. zone->AddObject(id, object);
  5406. LogWrite(OBJECT__DEBUG, 0, "Object", "Loaded Object: '%s' (%u).", object->appearance.name, spawn_id);
  5407. return true;
  5408. }
  5409. LogWrite(OBJECT__DEBUG, 0, "Object", "Unable to find an object for spawn id of %u", spawn_id);
  5410. return false;
  5411. }
  5412. bool WorldDatabase::LoadGroundSpawn(ZoneServer* zone, int32 spawn_id) {
  5413. GroundSpawn* spawn = 0;
  5414. int32 id = 0;
  5415. DatabaseResult result;
  5416. database_new.Select(&result, "SELECT sg.spawn_id, s.name, s.race, s.model_type, s.command_primary, s.command_secondary, s.targetable, s.size, s.show_name, s.visual_state, s.attackable, s.show_level, s.show_command_icon, s.display_hand_icon, s.faction_id, s.collision_radius, sg.number_harvests, sg.num_attempts_per_harvest, sg.groundspawn_id, sg.collection_skill, s.size_offset, s.expansion_flag\n"
  5417. "FROM spawn s\n"
  5418. "INNER JOIN spawn_ground sg\n"
  5419. "ON sg.spawn_id = s.id\n"
  5420. "WHERE s.id = %u",
  5421. spawn_id);
  5422. if (result.GetNumRows() > 0 && result.Next()) {
  5423. id = result.GetInt32(0);
  5424. spawn = new GroundSpawn();
  5425. spawn->SetDatabaseID(id);
  5426. strcpy(spawn->appearance.name, result.GetString(1));
  5427. vector<EntityCommand*>* primary_command_list = zone->GetEntityCommandList(result.GetInt32(4));
  5428. vector<EntityCommand*>* secondary_command_list = zone->GetEntityCommandList(result.GetInt32(5));
  5429. if(primary_command_list){
  5430. spawn->SetPrimaryCommands(primary_command_list);
  5431. spawn->primary_command_list_id = result.GetInt32(4);
  5432. }
  5433. if(secondary_command_list){
  5434. spawn->SetSecondaryCommands(secondary_command_list);
  5435. spawn->secondary_command_list_id = result.GetInt32(5);
  5436. }
  5437. spawn->appearance.race = result.GetInt8(2);
  5438. spawn->appearance.model_type = result.GetInt16(3);
  5439. spawn->appearance.targetable = result.GetInt8(6);
  5440. spawn->size = result.GetInt16(7);
  5441. spawn->appearance.display_name = result.GetInt8(8);
  5442. spawn->appearance.visual_state = result.GetInt16(9);
  5443. spawn->appearance.attackable = result.GetInt8(10);
  5444. spawn->appearance.show_level = result.GetInt8(11);
  5445. spawn->appearance.show_command_icon = result.GetInt8(12);
  5446. spawn->appearance.display_hand_icon = result.GetInt8(13);
  5447. spawn->faction_id = result.GetInt32(14);
  5448. spawn->appearance.pos.collision_radius = result.GetInt16(15);
  5449. spawn->SetNumberHarvests(result.GetInt8(16));
  5450. spawn->SetAttemptsPerHarvest(result.GetInt8(17));
  5451. spawn->SetGroundSpawnEntryID(result.GetInt32(18));
  5452. spawn->SetCollectionSkill(result.GetString(19));
  5453. spawn->SetSizeOffset(result.GetInt8(20));
  5454. zone->AddGroundSpawn(id, spawn);
  5455. if (!zone->GetGroundSpawnEntries(spawn->GetGroundSpawnEntryID()))
  5456. LoadGroundSpawnEntry(zone, spawn->GetGroundSpawnEntryID());
  5457. LogWrite(GROUNDSPAWN__DEBUG, 0, "GSpawn", "Loaded Ground Spawn: '%s' (%u).", spawn->appearance.name, spawn_id);
  5458. return true;
  5459. }
  5460. LogWrite(GROUNDSPAWN__DEBUG, 0, "GSpawn", "Unable to find a ground spawn for spawn id of %u", spawn_id);
  5461. return false;
  5462. }
  5463. void WorldDatabase::LoadGroundSpawnItems(ZoneServer* zone, int32 entry_id) {
  5464. DatabaseResult result;
  5465. database_new.Select(&result, "SELECT item_id, is_rare, grid_id\n"
  5466. "FROM groundspawn_items\n"
  5467. "WHERE groundspawn_id = %u",
  5468. entry_id);
  5469. if (result.GetNumRows() > 0 && result.Next()) {
  5470. zone->AddGroundSpawnItem(entry_id, result.GetInt32(0), result.GetInt8(1), result.GetInt32(2));
  5471. LogWrite(GROUNDSPAWN__DEBUG, 5, "GSpawn", "---Loading GroundSpawn Items: ID: %u\n", entry_id);
  5472. LogWrite(GROUNDSPAWN__DEBUG, 5, "GSpawn", "---item: %ul, rare: %i, grid: %ul", result.GetInt32(0), result.GetInt8(1), result.GetInt32(2));
  5473. }
  5474. }
  5475. void WorldDatabase::LoadGroundSpawnEntry(ZoneServer* zone, int32 entry_id) {
  5476. DatabaseResult result;
  5477. database_new.Select(&result, "SELECT min_skill_level, min_adventure_level, bonus_table, harvest1, harvest3, harvest5, harvest_imbue, harvest_rare, harvest10, harvest_coin\n"
  5478. "FROM groundspawns\n"
  5479. "WHERE enabled = 1 AND groundspawn_id = %u",
  5480. entry_id);
  5481. if (result.GetNumRows() > 0 && result.Next()) {
  5482. // this is getting ridonkulous...
  5483. LogWrite(GROUNDSPAWN__DEBUG, 5, "GSpawn", "---Loading GroundSpawn ID: %u\n" \
  5484. "---min_skill_level: %i, min_adventure_level: %i, bonus_table: %i\n" \
  5485. "---harvest1: %.2f, harvest3: %.2f, harvest5: %.2f\n" \
  5486. "---harvest_imbue: %.2f, harvest_rare: %.2f, harvest10: %.2f\n" \
  5487. "---harvest_coin: %u", entry_id, result.GetInt16(0), result.GetInt16(1), result.GetInt8(2), result.GetFloat(3), result.GetFloat(4), result.GetFloat(5), result.GetFloat(6), result.GetFloat(7), result.GetFloat(8), result.GetInt32(9));
  5488. zone->AddGroundSpawnEntry(entry_id, result.GetInt16(0), result.GetInt16(1), result.GetInt8(2), result.GetFloat(3), result.GetFloat(4), result.GetFloat(5), result.GetFloat(6), result.GetFloat(7), result.GetFloat(8), result.GetInt32(9));
  5489. LoadGroundSpawnItems(zone, entry_id);
  5490. }
  5491. }
  5492. bool WorldDatabase::LoadNPC(ZoneServer* zone, int32 spawn_id) {
  5493. NPC* npc = nullptr;
  5494. int32 id = 0;
  5495. DatabaseResult result;
  5496. database_new.Select(&result, "SELECT npc.spawn_id, s.name, npc.min_level, npc.max_level, npc.enc_level, s.race, s.model_type, npc.class_, npc.gender, s.command_primary, s.command_secondary, s.show_name, npc.min_group_size, npc.max_group_size, npc.hair_type_id, npc.facial_hair_type_id, npc.wing_type_id, npc.chest_type_id, npc.legs_type_id, npc.soga_hair_type_id, npc.soga_facial_hair_type_id, s.attackable, s.show_level, s.targetable, s.show_command_icon, s.display_hand_icon, s.hp, s.power, s.size, s.collision_radius, npc.action_state, s.visual_state, npc.mood_state, npc.initial_state, npc.activity_status, s.faction_id, s.sub_title, s.merchant_id, s.merchant_type, s.size_offset, npc.attack_type, npc.ai_strategy+0, npc.spell_list_id, npc.secondary_spell_list_id, npc.skill_list_id, npc.secondary_skill_list_id, npc.equipment_list_id, npc.str, npc.sta, npc.wis, npc.intel, npc.agi, npc.heat, npc.cold, npc.magic, npc.mental, npc.divine, npc.disease, npc.poison, npc.aggro_radius, npc.cast_percentage, npc.randomize, npc.soga_model_type, npc.heroic_flag, npc.alignment, npc.elemental, npc.arcane, npc.noxious, s.savagery, s.dissonance, npc.hide_hood, npc.emote_state, s.prefix, s.suffix, s.last_name\n"
  5497. "FROM spawn s\n"
  5498. "INNER JOIN spawn_npcs npc\n"
  5499. "ON npc.spawn_id = s.id\n"
  5500. "WHERE s.id = %u",
  5501. spawn_id);
  5502. if (result.GetNumRows() > 0 && result.Next()) {
  5503. id = result.GetInt32(0);
  5504. npc = new NPC();
  5505. npc->SetDatabaseID(id);
  5506. strcpy(npc->appearance.name, result.GetString(1));
  5507. vector<EntityCommand*>* primary_command_list = zone->GetEntityCommandList(result.GetInt32(9));
  5508. vector<EntityCommand*>* secondary_command_list = zone->GetEntityCommandList(result.GetInt32(10));
  5509. if(primary_command_list){
  5510. npc->SetPrimaryCommands(primary_command_list);
  5511. npc->primary_command_list_id = result.GetInt32(9);
  5512. }
  5513. if(secondary_command_list){
  5514. npc->SetSecondaryCommands(secondary_command_list);
  5515. npc->secondary_command_list_id = result.GetInt32(10);
  5516. }
  5517. npc->appearance.min_level = result.GetInt8(2);
  5518. npc->appearance.max_level = result.GetInt8(3);
  5519. npc->appearance.level = result.GetInt8(2);
  5520. npc->appearance.encounter_level = result.GetInt8(4);
  5521. npc->appearance.race = result.GetInt8(5);
  5522. //npc->appearance.lua_race_id = result.GetInt16(74);
  5523. npc->appearance.model_type = result.GetInt16(6);
  5524. npc->appearance.soga_model_type = result.GetInt16(62);
  5525. npc->appearance.adventure_class = result.GetInt8(7);
  5526. npc->appearance.gender = result.GetInt8(8);
  5527. npc->appearance.display_name = result.GetInt8(11);
  5528. npc->features.hair_type = result.GetInt16(14);
  5529. npc->features.hair_face_type = result.GetInt16(15);
  5530. npc->features.wing_type = result.GetInt16(16);
  5531. npc->features.chest_type = result.GetInt16(17);
  5532. npc->features.legs_type = result.GetInt16(18);
  5533. npc->features.soga_hair_type = result.GetInt16(19);
  5534. npc->features.soga_hair_face_type = result.GetInt16(20);
  5535. npc->appearance.attackable = result.GetInt8(21);
  5536. npc->appearance.show_level = result.GetInt8(22);
  5537. npc->appearance.targetable = result.GetInt8(23);
  5538. npc->appearance.show_command_icon = result.GetInt8(24);
  5539. npc->appearance.display_hand_icon = result.GetInt8(25);
  5540. npc->appearance.hide_hood = result.GetInt8(70);
  5541. npc->appearance.randomize = result.GetInt32(61);
  5542. npc->SetTotalHP(result.GetInt32(26));
  5543. npc->SetTotalPower(result.GetInt32(27));
  5544. npc->SetHP(npc->GetTotalHP());
  5545. npc->SetPower(npc->GetTotalPower());
  5546. if(npc->GetTotalHP() == 0){
  5547. npc->SetTotalHP(15*npc->GetLevel() + 1);
  5548. npc->SetHP(15*npc->GetLevel() + 1);
  5549. }
  5550. if(npc->GetTotalPower() == 0){
  5551. npc->SetTotalPower(15*npc->GetLevel() + 1);
  5552. npc->SetPower(15*npc->GetLevel() + 1);
  5553. }
  5554. npc->size = result.GetInt16(28);
  5555. npc->appearance.pos.collision_radius = result.GetInt16(29);
  5556. npc->appearance.action_state = result.GetInt16(30);
  5557. npc->appearance.visual_state = result.GetInt16(31);
  5558. npc->appearance.mood_state = result.GetInt16(32);
  5559. npc->appearance.emote_state = result.GetInt16(71);
  5560. npc->appearance.pos.state = result.GetInt16(33);
  5561. npc->appearance.activity_status = result.GetInt16(34);
  5562. npc->faction_id = result.GetInt32(35);
  5563. if(!result.IsNull(36)){
  5564. if(strlen(result.GetString(36)) < sizeof(npc->appearance.sub_title))
  5565. strcpy(npc->appearance.sub_title, result.GetString(36));
  5566. else
  5567. strncpy(npc->appearance.sub_title, result.GetString(36), sizeof(npc->appearance.sub_title));
  5568. }
  5569. npc->SetMerchantID(result.GetInt32(37));
  5570. npc->SetMerchantType(result.GetInt8(38));
  5571. npc->SetSizeOffset(result.GetInt8(39));
  5572. npc->SetAttackType(result.GetInt8(40));
  5573. npc->SetAIStrategy(result.GetInt8(41));
  5574. npc->SetPrimarySpellList(result.GetInt32(42));
  5575. npc->SetSecondarySpellList(result.GetInt32(43));
  5576. npc->SetPrimarySkillList(result.GetInt32(44));
  5577. npc->SetSecondarySkillList(result.GetInt32(45));
  5578. npc->SetEquipmentListID(result.GetInt32(46));
  5579. InfoStruct* info = npc->GetInfoStruct();
  5580. info->str_base = result.GetInt16(47);
  5581. info->sta_base = result.GetInt16(48);
  5582. info->wis_base = result.GetInt16(49);
  5583. info->intel_base = result.GetInt16(50);
  5584. info->agi_base = result.GetInt16(51);
  5585. info->heat_base = result.GetInt16(52);
  5586. info->cold_base = result.GetInt16(53);
  5587. info->magic_base = result.GetInt16(54);
  5588. info->mental_base = result.GetInt16(55);
  5589. info->divine_base = result.GetInt16(56);
  5590. info->disease_base = result.GetInt16(57);
  5591. info->poison_base = result.GetInt16(58);
  5592. info->alignment = result.GetInt8(64);
  5593. npc->SetAggroRadius(result.GetFloat(59));
  5594. npc->SetCastPercentage(result.GetInt8(60));
  5595. npc->appearance.heroic_flag = result.GetInt8(63);
  5596. info->elemental_base = result.GetInt16(65);
  5597. info->arcane_base = result.GetInt16(66);
  5598. info->noxious_base = result.GetInt16(67);
  5599. npc->SetTotalSavagery(result.GetInt32(68));
  5600. npc->SetTotalDissonance(result.GetInt32(69));
  5601. npc->SetSavagery(npc->GetTotalSavagery());
  5602. npc->SetDissonance(npc->GetTotalDissonance());
  5603. if(npc->GetTotalSavagery() == 0){
  5604. npc->SetTotalSavagery(15*npc->GetLevel() + 1);
  5605. npc->SetSavagery(15*npc->GetLevel() + 1);
  5606. }
  5607. if(npc->GetTotalDissonance() == 0){
  5608. npc->SetTotalDissonance(15*npc->GetLevel() + 1);
  5609. npc->SetDissonance(15*npc->GetLevel() + 1);
  5610. }
  5611. npc->SetPrefixTitle(result.GetString(72));
  5612. npc->SetSuffixTitle(result.GetString(73));
  5613. npc->SetLastName(result.GetString(74));
  5614. zone->AddNPC(id, npc);
  5615. //skipped spells/skills/equipment as it is all loaded, the following rely on a spawn to load
  5616. LoadAppearance(zone, spawn_id);
  5617. LoadNPCAppearanceEquipmentData(zone, spawn_id);
  5618. LogWrite(NPC__DEBUG, 0, "NPC", "Loaded NPC: '%s' (%u).", npc->appearance.name, spawn_id);
  5619. return true;
  5620. }
  5621. LogWrite(NPC__DEBUG, 0, "NPC", "Unable to find a npc for spawn id of %u", spawn_id);
  5622. return false;
  5623. }
  5624. void WorldDatabase::LoadAppearance(ZoneServer* zone, int32 spawn_id) {
  5625. Entity* entity = zone->GetNPC(spawn_id);
  5626. if (!entity)
  5627. return;
  5628. DatabaseResult result, result2;
  5629. map<string, int8> appearance_types;
  5630. map<int32, map<int8, EQ2_Color> > appearance_colors;
  5631. EQ2_Color color;
  5632. color.red = 0;
  5633. color.green = 0;
  5634. color.blue = 0;
  5635. string type;
  5636. database_new.Select(&result2, "SELECT distinct `type`\n"
  5637. "FROM npc_appearance\n"
  5638. "WHERE length(`type`) > 0 AND `spawn_id` = %u",
  5639. spawn_id);
  5640. while(result2.Next()) {
  5641. type = string(result2.GetString(0));
  5642. appearance_types[type] = GetAppearanceType(type);
  5643. if(appearance_types[type] == 255)
  5644. LogWrite(WORLD__ERROR, 0, "Appearance", "Unknown appearance type '%s' in LoadAppearances.", type.c_str());
  5645. }
  5646. database_new.Select(&result, "SELECT `type`, `signed_value`, `red`, `green`, `blue`\n"
  5647. "FROM npc_appearance\n"
  5648. "WHERE length(`type`) > 0 AND `spawn_id` = %u",
  5649. spawn_id);
  5650. while(result.Next()) {
  5651. if(appearance_types[result.GetString(0)] < APPEARANCE_SOGA_EBT){
  5652. color.red = result.GetInt8(2);
  5653. color.green = result.GetInt8(3);
  5654. color.blue = result.GetInt8(4);
  5655. }
  5656. switch(appearance_types[result.GetString(0)]){
  5657. case APPEARANCE_SOGA_HFHC:{
  5658. entity->features.soga_hair_face_highlight_color = color;
  5659. break;
  5660. }
  5661. case APPEARANCE_SOGA_HTHC:{
  5662. entity->features.soga_hair_type_highlight_color = color;
  5663. break;
  5664. }
  5665. case APPEARANCE_SOGA_HFC:{
  5666. entity->features.soga_hair_face_color = color;
  5667. break;
  5668. }
  5669. case APPEARANCE_SOGA_HTC:{
  5670. entity->features.soga_hair_type_color = color;
  5671. break;
  5672. }
  5673. case APPEARANCE_SOGA_HH:{
  5674. entity->features.soga_hair_highlight_color = color;
  5675. break;
  5676. }
  5677. case APPEARANCE_SOGA_HC1:{
  5678. entity->features.soga_hair_color1 = color;
  5679. break;
  5680. }
  5681. case APPEARANCE_SOGA_HC2:{
  5682. entity->features.soga_hair_color2 = color;
  5683. break;
  5684. }
  5685. case APPEARANCE_SOGA_SC:{
  5686. entity->features.soga_skin_color = color;
  5687. break;
  5688. }
  5689. case APPEARANCE_SOGA_EC:{
  5690. entity->features.soga_eye_color = color;
  5691. break;
  5692. }
  5693. case APPEARANCE_HTHC:{
  5694. entity->features.hair_type_highlight_color = color;
  5695. break;
  5696. }
  5697. case APPEARANCE_HFHC:{
  5698. entity->features.hair_face_highlight_color = color;
  5699. break;
  5700. }
  5701. case APPEARANCE_HTC:{
  5702. entity->features.hair_type_color = color;
  5703. break;
  5704. }
  5705. case APPEARANCE_HFC:{
  5706. entity->features.hair_face_color = color;
  5707. break;
  5708. }
  5709. case APPEARANCE_HH:{
  5710. entity->features.hair_highlight_color = color;
  5711. break;
  5712. }
  5713. case APPEARANCE_HC1:{
  5714. entity->features.hair_color1 = color;
  5715. break;
  5716. }
  5717. case APPEARANCE_HC2:{
  5718. entity->features.hair_color2 = color;
  5719. break;
  5720. }
  5721. case APPEARANCE_WC1:{
  5722. entity->features.wing_color1 = color;
  5723. break;
  5724. }
  5725. case APPEARANCE_WC2:{
  5726. entity->features.wing_color2 = color;
  5727. break;
  5728. }
  5729. case APPEARANCE_SC:{
  5730. entity->features.skin_color = color;
  5731. break;
  5732. }
  5733. case APPEARANCE_EC:{
  5734. entity->features.eye_color = color;
  5735. break;
  5736. }
  5737. case APPEARANCE_SOGA_EBT:{
  5738. for(int i=0;i<3;i++)
  5739. entity->features.soga_eye_brow_type[i] = result.GetInt8(2+i);
  5740. break;
  5741. }
  5742. case APPEARANCE_SOGA_CHEEKT:{
  5743. for(int i=0;i<3;i++)
  5744. entity->features.soga_cheek_type[i] = result.GetInt8(2+i);
  5745. break;
  5746. }
  5747. case APPEARANCE_SOGA_NT:{
  5748. for(int i=0;i<3;i++)
  5749. entity->features.soga_nose_type[i] = result.GetInt8(2+i);
  5750. break;
  5751. }
  5752. case APPEARANCE_SOGA_CHINT:{
  5753. for(int i=0;i<3;i++)
  5754. entity->features.soga_chin_type[i] = result.GetInt8(2+i);
  5755. break;
  5756. }
  5757. case APPEARANCE_SOGA_LT:{
  5758. for(int i=0;i<3;i++)
  5759. entity->features.soga_lip_type[i] = result.GetInt8(2+i);
  5760. break;
  5761. }
  5762. case APPEARANCE_SOGA_EART:{
  5763. for(int i=0;i<3;i++)
  5764. entity->features.soga_ear_type[i] = result.GetInt8(2+i);
  5765. break;
  5766. }
  5767. case APPEARANCE_SOGA_EYET:{
  5768. for(int i=0;i<3;i++)
  5769. entity->features.soga_eye_type[i] = result.GetInt8(2+i);
  5770. break;
  5771. }
  5772. case APPEARANCE_EBT:{
  5773. for(int i=0;i<3;i++)
  5774. entity->features.eye_brow_type[i] = result.GetInt8(2+i);
  5775. break;
  5776. }
  5777. case APPEARANCE_CHEEKT:{
  5778. for(int i=0;i<3;i++)
  5779. entity->features.cheek_type[i] = result.GetInt8(2+i);
  5780. break;
  5781. }
  5782. case APPEARANCE_NT:{
  5783. for(int i=0;i<3;i++)
  5784. entity->features.nose_type[i] = result.GetInt8(2+i);
  5785. break;
  5786. }
  5787. case APPEARANCE_CHINT:{
  5788. for(int i=0;i<3;i++)
  5789. entity->features.chin_type[i] = result.GetInt8(2+i);
  5790. break;
  5791. }
  5792. case APPEARANCE_EART:{
  5793. for(int i=0;i<3;i++)
  5794. entity->features.ear_type[i] = result.GetInt8(2+i);
  5795. break;
  5796. }
  5797. case APPEARANCE_EYET:{
  5798. for(int i=0;i<3;i++)
  5799. entity->features.eye_type[i] = result.GetInt8(2+i);
  5800. break;
  5801. }
  5802. case APPEARANCE_LT:{
  5803. for(int i=0;i<3;i++)
  5804. entity->features.lip_type[i] = result.GetInt8(2+i);
  5805. break;
  5806. }
  5807. case APPEARANCE_SHIRT:{
  5808. entity->features.shirt_color = color;
  5809. break;
  5810. }
  5811. case APPEARANCE_UCC:{
  5812. break;
  5813. }
  5814. case APPEARANCE_PANTS:{
  5815. entity->features.pants_color = color;
  5816. break;
  5817. }
  5818. case APPEARANCE_ULC:{
  5819. break;
  5820. }
  5821. case APPEARANCE_U9:{
  5822. break;
  5823. }
  5824. case APPEARANCE_BODY_SIZE:{
  5825. entity->features.body_size = color.red;
  5826. break;
  5827. }
  5828. case APPEARANCE_SOGA_WC1:{
  5829. break;
  5830. }
  5831. case APPEARANCE_SOGA_WC2:{
  5832. break;
  5833. }
  5834. case APPEARANCE_SOGA_SHIRT:{
  5835. break;
  5836. }
  5837. case APPEARANCE_SOGA_UCC:{
  5838. break;
  5839. }
  5840. case APPEARANCE_SOGA_PANTS:{
  5841. break;
  5842. }
  5843. case APPEARANCE_SOGA_ULC:{
  5844. break;
  5845. }
  5846. case APPEARANCE_SOGA_U13:{
  5847. break;
  5848. }
  5849. }
  5850. }
  5851. }
  5852. void WorldDatabase::LoadNPCAppearanceEquipmentData(ZoneServer* zone, int32 spawn_id) {
  5853. NPC* npc = zone->GetNPC(spawn_id);
  5854. if(!npc) {
  5855. LogWrite(NPC__ERROR, 0, "NPC", "Unable to get a valid npc (%u) in %s", spawn_id, __FUNCTION__);
  5856. return;
  5857. }
  5858. DatabaseResult result;
  5859. int8 slot = 0;
  5860. if (!database_new.Select(&result, "SELECT slot_id, equip_type, red, green, blue, highlight_red, highlight_green, highlight_blue\n"
  5861. "FROM npc_appearance_equip\n"
  5862. "WHERE spawn_id = %u\n",
  5863. spawn_id))
  5864. {
  5865. LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
  5866. return;
  5867. }
  5868. while (result.Next()) {
  5869. slot = result.GetInt8(0);
  5870. if(slot < NUM_SLOTS) {
  5871. npc->equipment.equip_id[slot] = result.GetInt16(1);
  5872. npc->equipment.color[slot].red = result.GetInt8(2);
  5873. npc->equipment.color[slot].green = result.GetInt8(3);
  5874. npc->equipment.color[slot].blue = result.GetInt8(4);
  5875. npc->equipment.highlight[slot].red = result.GetInt8(5);
  5876. npc->equipment.highlight[slot].green = result.GetInt8(6);
  5877. npc->equipment.highlight[slot].blue = result.GetInt8(7);
  5878. }
  5879. }
  5880. }
  5881. void WorldDatabase::SaveCharacterPicture(int32 characterID, int8 type, uchar* picture, int32 picture_size) {
  5882. stringstream ss_hex;
  5883. stringstream ss_query;
  5884. ss_hex.flags(ios::hex);
  5885. for (int32 i = 0; i < picture_size; i++)
  5886. ss_hex << setfill('0') << setw(2) << (int32)picture[i];
  5887. ss_query << "INSERT INTO `character_pictures` (`char_id`, `pic_type`, `picture`) VALUES (" << characterID << ", " << (int32)type << ", '" << ss_hex.str() << "') ON DUPLICATE KEY UPDATE `picture` = '" << ss_hex.str() << "'";
  5888. if (!database_new.Query(ss_query.str().c_str()))
  5889. LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
  5890. }
  5891. void WorldDatabase::LoadZoneFlightPaths(ZoneServer* zone) {
  5892. DatabaseResult result;
  5893. int32 total = 0;
  5894. if (!database_new.Select(&result, "SELECT id, speed, flying, early_dismount FROM flight_paths WHERE zone_id = %u", zone->GetZoneID())) {
  5895. LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
  5896. return;
  5897. }
  5898. while (result.Next()) {
  5899. FlightPathInfo* info = new FlightPathInfo;
  5900. int32 id = result.GetInt32(0);
  5901. info->speed = result.GetFloat(1);
  5902. info->flying = result.GetInt8(2) == 1 ? true : false;
  5903. info->dismount = result.GetInt8(3) == 1 ? true : false;
  5904. zone->AddFlightPath(id, info);
  5905. total++;
  5906. }
  5907. LogWrite(ZONE__DEBUG, 0, "Zone", "Loaded %u flight paths for %s", total, zone->GetZoneDescription());
  5908. LoadZoneFlightPathLocations(zone);
  5909. }
  5910. void WorldDatabase::LoadZoneFlightPathLocations(ZoneServer* zone) {
  5911. DatabaseResult result;
  5912. int32 total = 0;
  5913. if (!database_new.Select(&result, "SELECT loc.flight_path, loc.x, loc.y, loc.z FROM flight_paths_locations loc\n"
  5914. "INNER JOIN flight_paths path\n"
  5915. "ON loc.flight_path = path.id\n"
  5916. "WHERE path.zone_id = %u\n"
  5917. "ORDER BY loc.id",
  5918. zone->GetZoneID()))
  5919. {
  5920. LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
  5921. return;
  5922. }
  5923. while (result.Next()) {
  5924. FlightPathLocation* loc = new FlightPathLocation;
  5925. int32 id = result.GetInt32(0);
  5926. loc->X = result.GetFloat(1);
  5927. loc->Y = result.GetFloat(2);
  5928. loc->Z = result.GetFloat(3);
  5929. zone->AddFlightPathLocation(id, loc);
  5930. total++;
  5931. }
  5932. LogWrite(ZONE__DEBUG, 0, "Zone", "Loaded %u flight path locations for %s", total, zone->GetZoneDescription());
  5933. }
  5934. void WorldDatabase::SaveCharacterLUAHistory(Player* player, int32 event_id, int32 value, int32 value2) {
  5935. Query query;
  5936. query.AddQueryAsync(player->GetCharacterID(), this, Q_REPLACE, "REPLACE INTO character_lua_history(char_id, event_id, value, value2) VALUES(% u, % u, % u, % u)", player->GetCharacterID(), event_id, value, value2);
  5937. // if (!database_new.Query("REPLACE INTO character_lua_history (char_id, event_id, value, value2) VALUES (%u, %u, %u, %u)", player->GetCharacterID(), event_id, value, value2))
  5938. // LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
  5939. }
  5940. void WorldDatabase::LoadCharacterLUAHistory(int32 char_id, Player* player) {
  5941. DatabaseResult result;
  5942. int32 total = 0;
  5943. if (!database_new.Select(&result, "SELECT event_id, value, value2 FROM character_lua_history WHERE char_id = %u", char_id)) {
  5944. LogWrite(DATABASE__ERROR, 0, "DBNew", "MySQL Error %u: %s", database_new.GetError(), database_new.GetErrorMsg());
  5945. return;
  5946. }
  5947. while (result.Next()) {
  5948. int32 id = result.GetInt32(0);
  5949. LUAHistory* hd = new LUAHistory;
  5950. hd->Value = result.GetInt32(1);
  5951. hd->Value2 = result.GetInt32(2);
  5952. hd->SaveNeeded = false;
  5953. player->LoadLUAHistory(id, hd);
  5954. total++;
  5955. }
  5956. LogWrite(PLAYER__DEBUG, 0, "Player", "Loaded %u LUA history for %s", total, player->GetName());
  5957. }
  5958. void WorldDatabase::FindSpell(Client* client, char* findString)
  5959. {
  5960. DatabaseResult result;
  5961. if (!database_new.Select(&result, "SELECT s.`id`, ts.spell_id, ts.index, `name`, `tier` "
  5962. "FROM (spells s, spell_tiers st) "
  5963. "LEFT JOIN spell_ts_ability_index ts "
  5964. "ON s.`id` = ts.spell_id "
  5965. "WHERE s.id = st.spell_id and s.name like '%%%s%%' AND s.is_active = 1 "
  5966. "ORDER BY s.`id`, `tier` limit 50", findString))
  5967. {
  5968. // error
  5969. }
  5970. else
  5971. {
  5972. client->Message(CHANNEL_COLOR_YELLOW, "SpellID (SpellTier): SpellName for %s", findString);
  5973. while (result.Next())
  5974. {
  5975. int32 spell_id = result.GetInt32Str("id");
  5976. string spell_name = result.GetStringStr("name");
  5977. int8 tier = result.GetInt8Str("tier");
  5978. client->Message(CHANNEL_COLOR_YELLOW, "%i (%i): %s", spell_id, tier, spell_name.c_str());
  5979. }
  5980. client->Message(CHANNEL_COLOR_YELLOW, "End Spell Results for %s", findString);
  5981. }
  5982. }
  5983. void WorldDatabase::LoadChestTraps() {
  5984. chest_trap_list.Clear();
  5985. int32 index = 0;
  5986. Query query;
  5987. MYSQL_ROW row;
  5988. MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, applicable_zone_id, chest_min_difficulty, chest_max_difficulty, spell_id, spell_tier FROM chest_traps");
  5989. if (result && mysql_num_rows(result) > 0) {
  5990. Title* title = 0;
  5991. while (result && (row = mysql_fetch_row(result))) {
  5992. int32 dbid = atoul(row[0]);
  5993. sint32 applicable_zone_id = atoi(row[1]);
  5994. int32 mindifficulty = atoul(row[2]);
  5995. int32 maxdifficulty = atoul(row[3]);
  5996. int32 spellid = atoul(row[4]);
  5997. int32 tier = atoul(row[5]);
  5998. ChestTrap* trap = new ChestTrap(dbid,applicable_zone_id,mindifficulty,maxdifficulty,spellid,tier);
  5999. chest_trap_list.AddChestTrap(trap);
  6000. }
  6001. }
  6002. }
  6003. bool WorldDatabase::CheckExpansionFlags(ZoneServer* zone, int32 spawnXpackFlag)
  6004. {
  6005. if (spawnXpackFlag == 0)
  6006. return true;
  6007. int32 globalXpackFlag = rule_manager.GetGlobalRule(R_Expansion, GlobalExpansionFlag)->GetInt32();
  6008. int32 zoneXpackFlag = zone->GetExpansionFlag();
  6009. // zone expansion flag takes priority
  6010. if (zoneXpackFlag > 0 && (spawnXpackFlag & zoneXpackFlag) == 0)
  6011. return false;
  6012. // zone expansion flag fails, then if global expansion flag set, we see if that bit operand doesn't match, skip mob then
  6013. else if (zoneXpackFlag == 0 && globalXpackFlag > 0 && (spawnXpackFlag & globalXpackFlag) == 0)
  6014. return false;
  6015. return true;
  6016. }
  6017. void WorldDatabase::GetHouseSpawnInstanceData(ZoneServer* zone, Spawn* spawn)
  6018. {
  6019. if (!spawn)
  6020. return;
  6021. if (zone->house_object_database_lookup.count(spawn->GetModelType()) < 1)
  6022. zone->house_object_database_lookup.Put(spawn->GetModelType(), spawn->GetDatabaseID());
  6023. DatabaseResult result;
  6024. database_new.Select(&result, "SELECT pickup_item_id, pickup_unique_item_id\n"
  6025. " FROM spawn_instance_data\n"
  6026. " WHERE spawn_id = %u and spawn_location_id = %u",
  6027. spawn->GetDatabaseID(),spawn->GetSpawnLocationID());
  6028. if (result.GetNumRows() > 0 && result.Next()) {
  6029. spawn->SetPickupItemID(result.GetInt32(0));
  6030. spawn->SetPickupUniqueItemID(result.GetInt32(1));
  6031. if (spawn->GetZone() != nullptr && spawn->GetZone()->zonemap != nullptr && spawn->GetZone()->zonemap->IsMapLoaded())
  6032. {
  6033. int32 newGrid = spawn->GetZone()->Grid->GetGridID(spawn);
  6034. spawn->SetPos(&(spawn->appearance.pos.grid_id), newGrid);
  6035. }
  6036. }
  6037. }
  6038. int32 WorldDatabase::FindHouseInstanceSpawn(Spawn* spawn)
  6039. {
  6040. DatabaseResult result;
  6041. database_new.Select(&result, "SELECT id\n"
  6042. " FROM spawn\n"
  6043. " WHERE model_type = %u and is_instanced_spawn=1 limit 1",
  6044. spawn->GetModelType());
  6045. if (result.GetNumRows() > 0 && result.Next()) {
  6046. return result.GetInt32(0);
  6047. }
  6048. return 0;
  6049. }