char.c 156 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include <sys/types.h>
  4. #ifdef _WIN32
  5. #include <winsock.h>
  6. #else
  7. #include <sys/socket.h>
  8. #include <netinet/in.h>
  9. #include <arpa/inet.h>
  10. #endif
  11. #include <time.h>
  12. #include <signal.h>
  13. #include <fcntl.h>
  14. #include <string.h>
  15. #include <stdarg.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <limits.h>
  19. #include "../common/strlib.h"
  20. #include "../common/core.h"
  21. #include "../common/socket.h"
  22. #include "../common/timer.h"
  23. #include "../common/mmo.h"
  24. #include "../common/db.h"
  25. #include "../common/version.h"
  26. #include "../common/lock.h"
  27. #include "../common/showmsg.h"
  28. #include "../common/malloc.h"
  29. #include "char.h"
  30. #include "inter.h"
  31. #include "int_pet.h"
  32. #include "int_homun.h"
  33. #include "int_guild.h"
  34. #include "int_party.h"
  35. #include "int_storage.h"
  36. #ifdef ENABLE_SC_SAVING
  37. #include "int_status.h"
  38. #endif
  39. #ifndef TXT_SQL_CONVERT
  40. struct mmo_map_server{
  41. long ip;
  42. short port;
  43. int users;
  44. unsigned short map[MAX_MAP_PER_SERVER];
  45. } server[MAX_MAP_SERVERS];
  46. int server_fd[MAX_MAP_SERVERS];
  47. int login_fd, char_fd;
  48. char userid[24];
  49. char passwd[24];
  50. char server_name[20];
  51. char wisp_server_name[NAME_LENGTH] = "Server";
  52. char login_ip_str[128];
  53. in_addr_t login_ip;
  54. int login_port = 6900;
  55. char char_ip_str[128];
  56. in_addr_t char_ip;
  57. char bind_ip_str[128];
  58. in_addr_t bind_ip;
  59. int char_port = 6121;
  60. int char_maintenance;
  61. int char_new;
  62. int char_new_display;
  63. int email_creation = 0; // disabled by default
  64. #endif
  65. char char_txt[1024]="save/athena.txt";
  66. char backup_txt[1024]="save/backup.txt"; //By zanetheinsane
  67. char friends_txt[1024]="save/friends.txt"; // davidsiaw
  68. #ifndef TXT_SQL_CONVERT
  69. char backup_txt_flag = 0; // The backup_txt file was created because char deletion bug existed. Now it's finish and that take a lot of time to create a second file when there are a lot of characters. => option By [Yor]
  70. char unknown_char_name[1024] = "Unknown";
  71. char char_log_filename[1024] = "log/char.log";
  72. char db_path[1024]="db";
  73. // Advanced subnet check [LuzZza]
  74. struct _subnet {
  75. long subnet;
  76. long mask;
  77. long char_ip;
  78. long map_ip;
  79. } subnet[16];
  80. int subnet_count = 0;
  81. int name_ignoring_case = 0; // Allow or not identical name for characters but with a different case by [Yor]
  82. int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor]
  83. //The following are characters that are trimmed regardless because they cause confusion and problems on the servers. [Skotlex]
  84. #define TRIM_CHARS "\032\t\x0A\x0D "
  85. char char_name_letters[1024] = ""; // list of letters/symbols authorised (or not) in a character name. by [Yor]
  86. int log_char = 1; // loggin char or not [devil]
  87. int log_inter = 1; // loggin inter or not [devil]
  88. struct char_session_data{
  89. int account_id, login_id1, login_id2, sex;
  90. int found_char[9];
  91. char email[40]; // e-mail (default: a@a.com) by [Yor]
  92. time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
  93. };
  94. #define AUTH_FIFO_SIZE 256
  95. struct {
  96. int account_id, char_id, login_id1, login_id2, ip, char_pos, delflag, sex;
  97. time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
  98. } auth_fifo[AUTH_FIFO_SIZE];
  99. int auth_fifo_pos = 0;
  100. int check_ip_flag = 1; // It's to check IP of a player between char-server and other servers (part of anti-hacking system)
  101. static int online_check = 1; //If one, it won't let players connect when their account is already registered online and will send the relevant map server a kick user request. [Skotlex]
  102. int char_id_count = START_CHAR_NUM;
  103. struct character_data *char_dat;
  104. int char_num, char_max;
  105. int max_connect_user = 0;
  106. int gm_allow_level = 99;
  107. int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
  108. int save_log = 1;
  109. int start_zeny = 500;
  110. int start_weapon = 1201;
  111. int start_armor = 2301;
  112. int guild_exp_rate = 100;
  113. //Custom limits for the fame lists. [Skotlex]
  114. int fame_list_size_chemist = MAX_FAME_LIST;
  115. int fame_list_size_smith = MAX_FAME_LIST;
  116. int fame_list_size_taekwon = MAX_FAME_LIST;
  117. // Char-server-side stored fame lists [DracoRPG]
  118. struct fame_list smith_fame_list[MAX_FAME_LIST];
  119. struct fame_list chemist_fame_list[MAX_FAME_LIST];
  120. struct fame_list taekwon_fame_list[MAX_FAME_LIST];
  121. // Initial position (it's possible to set it in conf file)
  122. struct point start_point = { 0, 53, 111};
  123. struct gm_account *gm_account = NULL;
  124. int GM_num = 0;
  125. // online players by [Yor]
  126. char online_txt_filename[1024] = "online.txt";
  127. char online_html_filename[1024] = "online.html";
  128. int online_sorting_option = 0; // sorting option to display online players in online files
  129. int online_display_option = 1; // display options: to know which columns must be displayed
  130. int online_refresh_html = 20; // refresh time (in sec) of the html file in the explorer
  131. int online_gm_display_min_level = 20; // minimum GM level to display 'GM' when we want to display it
  132. //These are used to aid the map server in identifying valid clients. [Skotlex]
  133. static int max_account_id = DEFAULT_MAX_ACCOUNT_ID, max_char_id = DEFAULT_MAX_CHAR_ID;
  134. struct online_char_data {
  135. int account_id;
  136. int char_id;
  137. short server;
  138. unsigned waiting_disconnect :1;
  139. };
  140. struct dbt *online_char_db; //Holds all online characters.
  141. time_t update_online; // to update online files when we receiving information from a server (not less than 8 seconds)
  142. int console = 0;
  143. //------------------------------
  144. // Writing function of logs file
  145. //------------------------------
  146. int char_log(char *fmt, ...) {
  147. if(log_char)
  148. {
  149. FILE *logfp;
  150. va_list ap;
  151. time_t raw_time;
  152. char tmpstr[2048];
  153. va_start(ap, fmt);
  154. logfp = fopen(char_log_filename, "a");
  155. if (logfp) {
  156. if (fmt[0] == '\0') // jump a line if no message
  157. fprintf(logfp, RETCODE);
  158. else {
  159. time(&raw_time);
  160. strftime(tmpstr, 24, "%d-%m-%Y %H:%M:%S", localtime(&raw_time));
  161. sprintf(tmpstr + 19, ": %s", fmt);
  162. vfprintf(logfp, tmpstr, ap);
  163. }
  164. fclose(logfp);
  165. }
  166. va_end(ap);
  167. }
  168. return 0;
  169. }
  170. //----------------------------------------------------------------------
  171. // Determine if an account (id) is a GM account
  172. // and returns its level (or 0 if it isn't a GM account or if not found)
  173. //----------------------------------------------------------------------
  174. int isGM(int account_id) {
  175. int i;
  176. for(i = 0; i < GM_num; i++)
  177. if (gm_account[i].account_id == account_id)
  178. return gm_account[i].level;
  179. return 0;
  180. }
  181. //Search character data from the aid/cid givem
  182. struct mmo_charstatus* search_character(int aid, int cid) {
  183. int i;
  184. for (i = 0; i < char_num; i++) {
  185. if (char_dat[i].status.char_id == cid && char_dat[i].status.account_id == aid)
  186. return &char_dat[i].status;
  187. }
  188. return NULL;
  189. }
  190. struct mmo_charstatus* search_character_byname(char* character_name)
  191. {
  192. int i = search_character_index(character_name);
  193. if (i == -1) return NULL;
  194. return &char_dat[i].status;
  195. }
  196. //----------------------------------------------
  197. // Search an character id
  198. // (return character index or -1 (if not found))
  199. // If exact character name is not found,
  200. // the function checks without case sensitive
  201. // and returns index if only 1 character is found
  202. // and similar to the searched name.
  203. //----------------------------------------------
  204. int search_character_index(char* character_name) {
  205. int i, quantity, index;
  206. quantity = 0;
  207. index = -1;
  208. for(i = 0; i < char_num; i++) {
  209. // Without case sensitive check (increase the number of similar character names found)
  210. if (stricmp(char_dat[i].status.name, character_name) == 0) {
  211. // Strict comparison (if found, we finish the function immediatly with correct value)
  212. if (strcmp(char_dat[i].status.name, character_name) == 0)
  213. return i;
  214. quantity++;
  215. index = i;
  216. }
  217. }
  218. // Here, the exact character name is not found
  219. // We return the found index of a similar account ONLY if there is 1 similar character
  220. if (quantity == 1)
  221. return index;
  222. // Exact character name is not found and 0 or more than 1 similar characters have been found ==> we say not found
  223. return -1;
  224. }
  225. //-------------------------------------
  226. // Return character name with the index
  227. //-------------------------------------
  228. char * search_character_name(int index) {
  229. if (index >= 0 && index < char_num)
  230. return char_dat[index].status.name;
  231. return unknown_char_name;
  232. }
  233. // Searches if the given character is online, and returns the fd of the
  234. // map-server it is connected to.
  235. int search_character_online(int aid, int cid)
  236. {
  237. //Look for online character.
  238. struct online_char_data* character;
  239. character = idb_get(online_char_db, aid);
  240. if(character &&
  241. character->char_id == cid &&
  242. character->server > -1)
  243. return server_fd[character->server];
  244. return -1;
  245. }
  246. static void * create_online_char_data(DBKey key, va_list args) {
  247. struct online_char_data* character;
  248. character = aCalloc(1, sizeof(struct online_char_data));
  249. character->account_id = key.i;
  250. character->char_id = -1;
  251. character->server = -1;
  252. return character;
  253. }
  254. static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, int data);
  255. //-------------------------------------------------
  256. // Set Character online/offline [Wizputer]
  257. //-------------------------------------------------
  258. void set_char_online(int map_id, int char_id, int account_id) {
  259. struct online_char_data* character;
  260. if ( char_id != 99 && (max_account_id < account_id || max_char_id < char_id))
  261. { //Notify map-server of the new max IDs [Skotlex]
  262. if (account_id > max_account_id)
  263. max_account_id = account_id;
  264. if (char_id > max_char_id)
  265. max_char_id = char_id;
  266. mapif_send_maxid(max_account_id, max_char_id);
  267. }
  268. character = idb_ensure(online_char_db, account_id, create_online_char_data);
  269. if (online_check && character->char_id != -1 && character->server > -1 && character->server != map_id)
  270. {
  271. //char == 99 <- Character logging in, so someone has logged in while one
  272. //char is still on map-server, so kick him out, but don't print "error"
  273. //as this is normal behaviour. [Skotlex]
  274. if (char_id != 99)
  275. ShowNotice("set_char_online: Character %d:%d marked in map server %d, but map server %d claims to have (%d:%d) online!\n",
  276. character->account_id, character->char_id, character->server, map_id, account_id, char_id);
  277. mapif_disconnectplayer(server_fd[character->server], character->account_id, character->char_id, 2);
  278. }
  279. character->waiting_disconnect = 0;
  280. character->char_id = (char_id==99)?-1:char_id;
  281. character->server = (char_id==99)?-1:map_id;
  282. if (login_fd <= 0 || session[login_fd]->eof)
  283. return;
  284. WFIFOHEAD(login_fd, 6);
  285. WFIFOW(login_fd,0) = 0x272b;
  286. WFIFOL(login_fd,2) = account_id;
  287. WFIFOSET(login_fd,6);
  288. //printf ("set online\n");
  289. }
  290. void set_char_offline(int char_id, int account_id) {
  291. struct online_char_data* character;
  292. if ((character = idb_get(online_char_db, account_id)) != NULL)
  293. { //We don't free yet to avoid aCalloc/aFree spamming during char change. [Skotlex]
  294. character->char_id = -1;
  295. character->server = -1;
  296. character->waiting_disconnect = 0;
  297. }
  298. if (login_fd <= 0 || session[login_fd]->eof)
  299. return;
  300. WFIFOHEAD(login_fd, 6);
  301. WFIFOW(login_fd,0) = 0x272c;
  302. WFIFOL(login_fd,2) = account_id;
  303. WFIFOSET(login_fd,6);
  304. }
  305. static int char_db_setoffline(DBKey key, void* data, va_list ap) {
  306. struct online_char_data* character = (struct online_char_data*)data;
  307. int server = va_arg(ap, int);
  308. if (server == -1) {
  309. character->char_id = -1;
  310. character->server = -1;
  311. character->waiting_disconnect = 0;
  312. } else if (character->server == server)
  313. character->server = -2; //In some map server that we aren't connected to.
  314. return 0;
  315. }
  316. static int char_db_kickoffline(DBKey key, void* data, va_list ap) {
  317. struct online_char_data* character = (struct online_char_data*)data;
  318. int server = va_arg(ap, int);
  319. if (server > -1 && character->server != server)
  320. return 0;
  321. //Kick out any connected characters, and set them offline as appropiate.
  322. if (character->server > -1)
  323. mapif_disconnectplayer(server_fd[character->server],
  324. character->account_id, character->char_id, 1);
  325. else if (!character->waiting_disconnect)
  326. set_char_offline(character->char_id, character->account_id);
  327. else return 0;
  328. return 1;
  329. }
  330. void set_all_offline(int id) {
  331. if (id < 0)
  332. ShowNotice("Sending all users offline.\n");
  333. else
  334. ShowNotice("Sending users of map-server %d offline.\n", id);
  335. online_char_db->foreach(online_char_db,char_db_kickoffline,id);
  336. if (id >= 0 || login_fd <= 0 || session[login_fd]->eof)
  337. return;
  338. //Tell login-server to also mark all our characters as offline.
  339. WFIFOHEAD(login_fd, 2);
  340. WFIFOW(login_fd,0) = 0x2737;
  341. WFIFOSET(login_fd,2);
  342. }
  343. /*---------------------------------------------------
  344. Make a data line for friends list
  345. --------------------------------------------------*/
  346. int mmo_friends_list_data_str(char *str, struct mmo_charstatus *p) {
  347. int i;
  348. char *str_p = str;
  349. str_p += sprintf(str_p, "%d", p->char_id);
  350. for (i=0;i<MAX_FRIENDS;i++){
  351. if (p->friends[i].account_id > 0 && p->friends[i].char_id > 0 && p->friends[i].name[0])
  352. str_p += sprintf(str_p, ",%d,%d,%s", p->friends[i].account_id, p->friends[i].char_id, p->friends[i].name);
  353. }
  354. str_p += '\0';
  355. return 0;
  356. }
  357. //-------------------------------------------------
  358. // Function to create the character line (for save)
  359. //-------------------------------------------------
  360. int mmo_char_tostr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int reg_num) {
  361. int i,j;
  362. char *str_p = str;
  363. /* We shouldn't need this anymore... [Skotlex]
  364. // on multi-map server, sometimes it's posssible that last_point become void. (reason???) We check that to not lost character at restart.
  365. if (!p->last_point.map) {
  366. p->last_point.map = mapindex_name2id(MAP_PRONTERA);
  367. p->last_point.x = 273;
  368. p->last_point.y = 354;
  369. }
  370. */
  371. str_p += sprintf(str_p,
  372. "%d\t%d,%d\t%s\t%d,%d,%d\t%u,%u,%d" //Up to Zeny field
  373. "\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d" //Up to Skill Point
  374. "\t%d,%d,%d\t%d,%d,%d,%d" //Up to hom id
  375. "\t%d,%d,%d\t%d,%d,%d,%d,%d" //Up to head bottom
  376. "\t%d,%d,%d\t%d,%d,%d" //last point + save point
  377. ",%d,%d,%d,%d,%d\t", //Family info
  378. p->char_id, p->account_id, p->char_num, p->name, //
  379. p->class_, p->base_level, p->job_level,
  380. p->base_exp, p->job_exp, p->zeny,
  381. p->hp, p->max_hp, p->sp, p->max_sp,
  382. p->str, p->agi, p->vit, p->int_, p->dex, p->luk,
  383. p->status_point, p->skill_point,
  384. p->option, p->karma, p->manner, //
  385. p->party_id, p->guild_id, p->pet_id, p->hom_id,
  386. p->hair, p->hair_color, p->clothes_color,
  387. p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom,
  388. p->last_point.map, p->last_point.x, p->last_point.y, //
  389. p->save_point.map, p->save_point.x, p->save_point.y,
  390. p->partner_id,p->father,p->mother,p->child,p->fame);
  391. for(i = 0; i < MAX_MEMOPOINTS; i++)
  392. if (p->memo_point[i].map) {
  393. str_p += sprintf(str_p, "%d,%d,%d", p->memo_point[i].map, p->memo_point[i].x, p->memo_point[i].y);
  394. }
  395. *(str_p++) = '\t';
  396. for(i = 0; i < MAX_INVENTORY; i++)
  397. if (p->inventory[i].nameid) {
  398. str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d",
  399. p->inventory[i].id,p->inventory[i].nameid,p->inventory[i].amount,p->inventory[i].equip,
  400. p->inventory[i].identify,p->inventory[i].refine,p->inventory[i].attribute);
  401. for(j=0; j<MAX_SLOTS; j++)
  402. str_p += sprintf(str_p,",%d",p->inventory[i].card[j]);
  403. str_p += sprintf(str_p," ");
  404. }
  405. *(str_p++) = '\t';
  406. for(i = 0; i < MAX_CART; i++)
  407. if (p->cart[i].nameid) {
  408. str_p += sprintf(str_p,"%d,%d,%d,%d,%d,%d,%d",
  409. p->cart[i].id,p->cart[i].nameid,p->cart[i].amount,p->cart[i].equip,
  410. p->cart[i].identify,p->cart[i].refine,p->cart[i].attribute);
  411. for(j=0; j<MAX_SLOTS; j++)
  412. str_p += sprintf(str_p,",%d",p->cart[i].card[j]);
  413. str_p += sprintf(str_p," ");
  414. }
  415. *(str_p++) = '\t';
  416. for(i = 0; i < MAX_SKILL; i++)
  417. if (p->skill[i].id && p->skill[i].flag != 1) {
  418. str_p += sprintf(str_p, "%d,%d ", p->skill[i].id, (p->skill[i].flag == 0) ? p->skill[i].lv : p->skill[i].flag-2);
  419. }
  420. *(str_p++) = '\t';
  421. for(i = 0; i < reg_num; i++)
  422. if (reg[i].str[0])
  423. str_p += sprintf(str_p, "%s,%s ", reg[i].str, reg[i].value);
  424. *(str_p++) = '\t';
  425. *str_p = '\0';
  426. return 0;
  427. }
  428. #endif //TXT_SQL_CONVERT
  429. //-------------------------------------------------------------------------
  430. // Function to set the character from the line (at read of characters file)
  431. //-------------------------------------------------------------------------
  432. int mmo_char_fromstr(char *str, struct mmo_charstatus *p, struct global_reg *reg, int *reg_num) {
  433. char tmp_str[3][128]; //To avoid deleting chars with too long names.
  434. int tmp_int[256];
  435. unsigned int tmp_uint[2]; //To read exp....
  436. int next, len, i, j;
  437. // initilialise character
  438. memset(p, '\0', sizeof(struct mmo_charstatus));
  439. // Char structure of version 1500 (homun + mapindex maps)
  440. if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d"
  441. "\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d"
  442. "\t%d,%d,%d\t%d,%d,%d,%d,%d,%d,%d,%d%n",
  443. &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0],
  444. &tmp_int[3], &tmp_int[4], &tmp_int[5],
  445. &tmp_uint[0], &tmp_uint[1], &tmp_int[8],
  446. &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12],
  447. &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18],
  448. &tmp_int[19], &tmp_int[20],
  449. &tmp_int[21], &tmp_int[22], &tmp_int[23], //
  450. &tmp_int[24], &tmp_int[25], &tmp_int[26], &tmp_int[44],
  451. &tmp_int[27], &tmp_int[28], &tmp_int[29],
  452. &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34],
  453. &tmp_int[45], &tmp_int[35], &tmp_int[36],
  454. &tmp_int[46], &tmp_int[37], &tmp_int[38], &tmp_int[39],
  455. &tmp_int[40], &tmp_int[41], &tmp_int[42], &tmp_int[43], &next) != 48)
  456. {
  457. tmp_int[44] = 0; //Hom ID.
  458. // Char structure of version 1488 (fame field addition)
  459. if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d"
  460. "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d"
  461. "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d,%d,%d,%d,%d%n",
  462. &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0],
  463. &tmp_int[3], &tmp_int[4], &tmp_int[5],
  464. &tmp_uint[0], &tmp_uint[1], &tmp_int[8],
  465. &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12],
  466. &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18],
  467. &tmp_int[19], &tmp_int[20],
  468. &tmp_int[21], &tmp_int[22], &tmp_int[23], //
  469. &tmp_int[24], &tmp_int[25], &tmp_int[26],
  470. &tmp_int[27], &tmp_int[28], &tmp_int[29],
  471. &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34],
  472. tmp_str[1], &tmp_int[35], &tmp_int[36],
  473. tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39],
  474. &tmp_int[40], &tmp_int[41], &tmp_int[42], &tmp_int[43], &next) != 47)
  475. {
  476. tmp_int[43] = 0; //Fame
  477. // Char structure of version 1363 (family data addition)
  478. if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d"
  479. "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d"
  480. "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d,%d,%d,%d%n",
  481. &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], //
  482. &tmp_int[3], &tmp_int[4], &tmp_int[5],
  483. &tmp_uint[0], &tmp_uint[1], &tmp_int[8],
  484. &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12],
  485. &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18],
  486. &tmp_int[19], &tmp_int[20],
  487. &tmp_int[21], &tmp_int[22], &tmp_int[23], //
  488. &tmp_int[24], &tmp_int[25], &tmp_int[26],
  489. &tmp_int[27], &tmp_int[28], &tmp_int[29],
  490. &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34],
  491. tmp_str[1], &tmp_int[35], &tmp_int[36], //
  492. tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39],
  493. &tmp_int[40], &tmp_int[41], &tmp_int[42], &next) != 46)
  494. {
  495. tmp_int[40] = 0; // father
  496. tmp_int[41] = 0; // mother
  497. tmp_int[42] = 0; // child
  498. // Char structure version 1008 (marriage partner addition)
  499. if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d"
  500. "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d"
  501. "\t%127[^,],%d,%d\t%127[^,],%d,%d,%d%n",
  502. &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], //
  503. &tmp_int[3], &tmp_int[4], &tmp_int[5],
  504. &tmp_uint[0], &tmp_uint[1], &tmp_int[8],
  505. &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12],
  506. &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18],
  507. &tmp_int[19], &tmp_int[20],
  508. &tmp_int[21], &tmp_int[22], &tmp_int[23], //
  509. &tmp_int[24], &tmp_int[25], &tmp_int[26],
  510. &tmp_int[27], &tmp_int[28], &tmp_int[29],
  511. &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34],
  512. tmp_str[1], &tmp_int[35], &tmp_int[36], //
  513. tmp_str[2], &tmp_int[37], &tmp_int[38], &tmp_int[39], &next) != 43)
  514. {
  515. tmp_int[39] = 0; // partner id
  516. // Char structure version 384 (pet addition)
  517. if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d"
  518. "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d"
  519. "\t%127[^,],%d,%d\t%127[^,],%d,%d%n",
  520. &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], //
  521. &tmp_int[3], &tmp_int[4], &tmp_int[5],
  522. &tmp_uint[0], &tmp_uint[1], &tmp_int[8],
  523. &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12],
  524. &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18],
  525. &tmp_int[19], &tmp_int[20],
  526. &tmp_int[21], &tmp_int[22], &tmp_int[23], //
  527. &tmp_int[24], &tmp_int[25], &tmp_int[26],
  528. &tmp_int[27], &tmp_int[28], &tmp_int[29],
  529. &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34],
  530. tmp_str[1], &tmp_int[35], &tmp_int[36], //
  531. tmp_str[2], &tmp_int[37], &tmp_int[38], &next) != 42)
  532. {
  533. tmp_int[26] = 0; // pet id
  534. // Char structure of a version 1 (original data structure)
  535. if (sscanf(str, "%d\t%d,%d\t%127[^\t]\t%d,%d,%d\t%u,%u,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d"
  536. "\t%d,%d,%d\t%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d"
  537. "\t%127[^,],%d,%d\t%127[^,],%d,%d%n",
  538. &tmp_int[0], &tmp_int[1], &tmp_int[2], tmp_str[0], //
  539. &tmp_int[3], &tmp_int[4], &tmp_int[5],
  540. &tmp_uint[0], &tmp_uint[1], &tmp_int[8],
  541. &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12],
  542. &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18],
  543. &tmp_int[19], &tmp_int[20],
  544. &tmp_int[21], &tmp_int[22], &tmp_int[23], //
  545. &tmp_int[24], &tmp_int[25], //
  546. &tmp_int[27], &tmp_int[28], &tmp_int[29],
  547. &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34],
  548. tmp_str[1], &tmp_int[35], &tmp_int[36], //
  549. tmp_str[2], &tmp_int[37], &tmp_int[38], &next) != 41)
  550. {
  551. ShowError("Char-loading: Unrecognized character data version, info lost!\n");
  552. ShowDebug("Character info: %s\n", str);
  553. return 0;
  554. }
  555. } // Char structure version 384 (pet addition)
  556. } // Char structure version 1008 (marriage partner addition)
  557. } // Char structure of version 1363 (family data addition)
  558. } // Char structure of version 1488 (fame field addition)
  559. //Convert save data from string to integer for older formats
  560. tmp_int[45] = mapindex_name2id(tmp_str[1]);
  561. tmp_int[46] = mapindex_name2id(tmp_str[2]);
  562. } // Char structure of version 1500 (homun + mapindex maps)
  563. memcpy(p->name, tmp_str[0], NAME_LENGTH-1); //Overflow protection [Skotlex]
  564. p->char_id = tmp_int[0];
  565. p->account_id = tmp_int[1];
  566. p->char_num = tmp_int[2];
  567. p->class_ = tmp_int[3];
  568. /* Unneeded unless you are running a real old character database now.
  569. //Temporal fix until all chars are reverted from peco-flying-class to
  570. //normal classes. [Skotlex]
  571. switch (p->class_) {
  572. case JOB_KNIGHT2: //Job_Knight2
  573. p->class_ = JOB_KNIGHT;
  574. break;
  575. case JOB_CRUSADER2: //Job_Crusader2
  576. p->class_ = JOB_CRUSADER;
  577. break;
  578. case JOB_LORD_KNIGHT2: //Job_Lord_Knight2
  579. p->class_ = JOB_LORD_KNIGHT;
  580. break;
  581. case JOB_PALADIN2: //Job_Paladin2
  582. p->class_ = JOB_PALADIN;
  583. break;
  584. case JOB_BABY_KNIGHT2: //Job_Baby_Knight2
  585. p->class_ = JOB_BABY_KNIGHT;
  586. break;
  587. case JOB_BABY_CRUSADER2: //Job_Baby_Crusader2
  588. p->class_ = JOB_BABY_CRUSADER;
  589. break;
  590. case JOB_STAR_GLADIATOR2: //Job_Star_Gladiator2
  591. p->class_ = JOB_STAR_GLADIATOR;
  592. break;
  593. }
  594. */
  595. p->base_level = tmp_int[4];
  596. p->job_level = tmp_int[5];
  597. p->base_exp = tmp_uint[0];
  598. p->job_exp = tmp_uint[1];
  599. p->zeny = tmp_int[8];
  600. p->hp = tmp_int[9];
  601. p->max_hp = tmp_int[10];
  602. p->sp = tmp_int[11];
  603. p->max_sp = tmp_int[12];
  604. p->str = tmp_int[13];
  605. p->agi = tmp_int[14];
  606. p->vit = tmp_int[15];
  607. p->int_ = tmp_int[16];
  608. p->dex = tmp_int[17];
  609. p->luk = tmp_int[18];
  610. p->status_point = tmp_int[19] > USHRT_MAX ? USHRT_MAX : tmp_int[19];
  611. p->skill_point = tmp_int[20] > USHRT_MAX ? USHRT_MAX : tmp_int[20];
  612. p->option = tmp_int[21];
  613. p->karma = tmp_int[22];
  614. p->manner = tmp_int[23];
  615. p->party_id = tmp_int[24];
  616. p->guild_id = tmp_int[25];
  617. p->pet_id = tmp_int[26];
  618. p->hair = tmp_int[27];
  619. p->hair_color = tmp_int[28];
  620. p->clothes_color = tmp_int[29];
  621. p->weapon = tmp_int[30];
  622. p->shield = tmp_int[31];
  623. p->head_top = tmp_int[32];
  624. p->head_mid = tmp_int[33];
  625. p->head_bottom = tmp_int[34];
  626. p->last_point.x = tmp_int[35];
  627. p->last_point.y = tmp_int[36];
  628. p->save_point.x = tmp_int[37];
  629. p->save_point.y = tmp_int[38];
  630. p->partner_id = tmp_int[39];
  631. p->father = tmp_int[40];
  632. p->mother = tmp_int[41];
  633. p->child = tmp_int[42];
  634. p->fame = tmp_int[43];
  635. p->hom_id = tmp_int[44];
  636. p->last_point.map = tmp_int[45];
  637. p->save_point.map = tmp_int[46];
  638. #ifndef TXT_SQL_CONVERT
  639. // Some checks
  640. for(i = 0; i < char_num; i++) {
  641. if (char_dat[i].status.char_id == p->char_id) {
  642. ShowError(CL_RED"mmmo_auth_init: a character has an identical id to another.\n");
  643. ShowError(" character id #%d -> new character not readed.\n", p->char_id);
  644. ShowError(" Character saved in log file."CL_RESET"\n");
  645. return -1;
  646. } else if (strcmp(char_dat[i].status.name, p->name) == 0) {
  647. ShowError(CL_RED"mmmo_auth_init: a character name already exists.\n");
  648. ShowError(" character name '%s' -> new character not read.\n", p->name);
  649. ShowError(" Character saved in log file."CL_RESET"\n");
  650. return -2;
  651. }
  652. }
  653. if (strcmpi(wisp_server_name, p->name) == 0) {
  654. ShowWarning("mmo_auth_init: ******WARNING: character name has wisp server name.\n");
  655. ShowWarning(" Character name '%s' = wisp server name '%s'.\n", p->name, wisp_server_name);
  656. ShowWarning(" Character readed. Suggestion: change the wisp server name.\n");
  657. char_log("mmo_auth_init: ******WARNING: character name has wisp server name: Character name '%s' = wisp server name '%s'." RETCODE,
  658. p->name, wisp_server_name);
  659. }
  660. #endif //TXT_SQL_CONVERT
  661. if (str[next] == '\n' || str[next] == '\r')
  662. return 1; // 新規データ
  663. next++;
  664. for(i = 0; str[next] && str[next] != '\t'; i++) {
  665. //mapindex memo format
  666. if (sscanf(str+next, "%d,%d,%d%n", &tmp_int[2], &tmp_int[0], &tmp_int[1], &len) != 3)
  667. { //Old string-based memo format.
  668. if (sscanf(str+next, "%[^,],%d,%d%n", tmp_str[0], &tmp_int[0], &tmp_int[1], &len) != 3)
  669. return -3;
  670. tmp_int[2] = mapindex_name2id(tmp_str[0]);
  671. }
  672. if (i < MAX_MEMOPOINTS)
  673. { //Avoid overflowing (but we must also read through all saved memos)
  674. p->memo_point[i].x = tmp_int[0];
  675. p->memo_point[i].y = tmp_int[1];
  676. p->memo_point[i].map = tmp_int[2];
  677. }
  678. next += len;
  679. if (str[next] == ' ')
  680. next++;
  681. }
  682. next++;
  683. for(i = 0; str[next] && str[next] != '\t'; i++) {
  684. if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n",
  685. &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3],
  686. &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str[0], &len) == 8)
  687. {
  688. p->inventory[i].id = tmp_int[0];
  689. p->inventory[i].nameid = tmp_int[1];
  690. p->inventory[i].amount = tmp_int[2];
  691. p->inventory[i].equip = tmp_int[3];
  692. p->inventory[i].identify = tmp_int[4];
  693. p->inventory[i].refine = tmp_int[5];
  694. p->inventory[i].attribute = tmp_int[6];
  695. for(j = 0; j < MAX_SLOTS && tmp_str[0] && sscanf(tmp_str[0], ",%d%[0-9,-]",&tmp_int[0], tmp_str[0]) > 0; j++)
  696. p->inventory[i].card[j] = tmp_int[0];
  697. next += len;
  698. if (str[next] == ' ')
  699. next++;
  700. } else // invalid structure
  701. return -4;
  702. }
  703. next++;
  704. for(i = 0; str[next] && str[next] != '\t'; i++) {
  705. if(sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d%[0-9,-]%n",
  706. &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3],
  707. &tmp_int[4], &tmp_int[5], &tmp_int[6], tmp_str[0], &len) == 8)
  708. {
  709. p->cart[i].id = tmp_int[0];
  710. p->cart[i].nameid = tmp_int[1];
  711. p->cart[i].amount = tmp_int[2];
  712. p->cart[i].equip = tmp_int[3];
  713. p->cart[i].identify = tmp_int[4];
  714. p->cart[i].refine = tmp_int[5];
  715. p->cart[i].attribute = tmp_int[6];
  716. for(j = 0; j < MAX_SLOTS && tmp_str && sscanf(tmp_str[0], ",%d%[0-9,-]",&tmp_int[0], tmp_str[0]) > 0; j++)
  717. p->cart[i].card[j] = tmp_int[0];
  718. next += len;
  719. if (str[next] == ' ')
  720. next++;
  721. } else // invalid structure
  722. return -5;
  723. }
  724. next++;
  725. for(i = 0; str[next] && str[next] != '\t'; i++) {
  726. if (sscanf(str + next, "%d,%d%n", &tmp_int[0], &tmp_int[1], &len) != 2)
  727. return -6;
  728. p->skill[tmp_int[0]].id = tmp_int[0];
  729. p->skill[tmp_int[0]].lv = tmp_int[1];
  730. next += len;
  731. if (str[next] == ' ')
  732. next++;
  733. }
  734. next++;
  735. for(i = 0; str[next] && str[next] != '\t' && str[next] != '\n' && str[next] != '\r'; i++) { // global_reg実装以前のathena.txt互換のため一応'\n'チェック
  736. if (sscanf(str + next, "%[^,],%[^ ] %n", reg[i].str, reg[i].value, &len) != 2) {
  737. // because some scripts are not correct, the str can be "". So, we must check that.
  738. // If it's, we must not refuse the character, but just this REG value.
  739. // Character line will have something like: nov_2nd_cos,9 ,9 nov_1_2_cos_c,1 (here, ,9 is not good)
  740. if (str[next] == ',' && sscanf(str + next, ",%[^ ] %n", reg[i].value, &len) == 1)
  741. i--;
  742. else
  743. return -7;
  744. }
  745. next += len;
  746. if (str[next] == ' ')
  747. next++;
  748. }
  749. *reg_num = i;
  750. return 1;
  751. }
  752. //---------------------------------
  753. // Function to read friend list
  754. //---------------------------------
  755. int parse_friend_txt(struct mmo_charstatus *p)
  756. {
  757. char line[1024], temp[1024];
  758. int pos = 0, count = 0, next;
  759. int i,len;
  760. FILE *fp;
  761. // Open the file and look for the ID
  762. fp = fopen(friends_txt, "r");
  763. if(fp == NULL)
  764. return -1;
  765. while(fgets(line, sizeof(line)-1, fp)) {
  766. if(line[0] == '/' && line[1] == '/')
  767. continue;
  768. if (sscanf(line, "%d%n",&i, &pos) < 1 || i != p->char_id)
  769. continue; //Not this line...
  770. //Read friends
  771. len = strlen(line);
  772. next = pos;
  773. for (count = 0; next < len && count < MAX_FRIENDS; count++)
  774. { //Read friends.
  775. if (sscanf(line+next, ",%d,%d,%23[^,^\n]%n",&p->friends[count].account_id,&p->friends[count].char_id, p->friends[count].name, &pos) < 3)
  776. { //Invalid friend?
  777. memset(&p->friends[count], 0, sizeof(p->friends[count]));
  778. break;
  779. }
  780. next+=pos;
  781. //What IF the name contains a comma? while the next field is not a
  782. //number, we assume it belongs to the current name. [Skotlex]
  783. //NOTE: Of course, this will fail if someone sets their name to something like
  784. //Bob,2005 but... meh, it's the problem of parsing a text file (encasing it in "
  785. //won't do as quotes are also valid name chars!)
  786. while(next < len && sscanf(line+next, ",%23[^,^\n]%n", temp, &pos) > 0)
  787. {
  788. if (atoi(temp)) //We read the next friend, just continue.
  789. break;
  790. //Append the name.
  791. next+=pos;
  792. i = strlen(p->friends[count].name);
  793. if (i + strlen(temp) +1 < NAME_LENGTH)
  794. {
  795. p->friends[count].name[i] = ',';
  796. strcpy(p->friends[count].name+i+1, temp);
  797. }
  798. } //End Guess Block
  799. } //Friend's for.
  800. break; //Found friends.
  801. }
  802. fclose(fp);
  803. return count;
  804. }
  805. #ifndef TXT_SQL_CONVERT
  806. //---------------------------------
  807. // Function to read characters file
  808. //---------------------------------
  809. int mmo_char_init(void) {
  810. char line[65536];
  811. int ret, line_count;
  812. FILE *fp;
  813. char_max = 256;
  814. char_dat = (struct character_data*)aCalloc(sizeof(struct character_data) * 256, 1);
  815. if (!char_dat) {
  816. ShowFatalError("out of memory: mmo_char_init (calloc of char_dat).\n");
  817. exit(1);
  818. }
  819. char_num = 0;
  820. fp = fopen(char_txt, "r");
  821. if (fp == NULL) {
  822. ShowError("Characters file not found: %s.\n", char_txt);
  823. char_log("Characters file not found: %s." RETCODE, char_txt);
  824. char_log("Id for the next created character: %d." RETCODE, char_id_count);
  825. return 0;
  826. }
  827. line_count = 0;
  828. while(fgets(line, sizeof(line)-1, fp)) {
  829. int i, j;
  830. line_count++;
  831. if (line[0] == '/' && line[1] == '/')
  832. continue;
  833. line[sizeof(line)-1] = '\0';
  834. j = 0;
  835. if (sscanf(line, "%d\t%%newid%%%n", &i, &j) == 1 && j > 0) {
  836. if (char_id_count < i)
  837. char_id_count = i;
  838. continue;
  839. }
  840. if (char_num >= char_max) {
  841. char_max += 256;
  842. char_dat = (struct character_data*)aRealloc(char_dat, sizeof(struct character_data) * char_max);
  843. if (!char_dat) {
  844. ShowFatalError("Out of memory: mmo_char_init (realloc of char_dat).\n");
  845. char_log("Out of memory: mmo_char_init (realloc of char_dat)." RETCODE);
  846. exit(1);
  847. }
  848. }
  849. ret = mmo_char_fromstr(line, &char_dat[char_num].status, char_dat[char_num].global, &char_dat[char_num].global_num);
  850. // Initialize friends list
  851. parse_friend_txt(&char_dat[char_num].status); // Grab friends for the character
  852. if (ret > 0) { // negative value or zero for errors
  853. if (char_dat[char_num].status.char_id >= char_id_count)
  854. char_id_count = char_dat[char_num].status.char_id + 1;
  855. char_num++;
  856. } else {
  857. ShowError("mmo_char_init: in characters file, unable to read the line #%d.\n", line_count);
  858. ShowError(" -> Character saved in log file.\n");
  859. switch (ret) {
  860. case -1:
  861. char_log("Duplicate character id in the next character line (character not readed):" RETCODE);
  862. break;
  863. case -2:
  864. char_log("Duplicate character name in the next character line (character not readed):" RETCODE);
  865. break;
  866. case -3:
  867. char_log("Invalid memo point structure in the next character line (character not readed):" RETCODE);
  868. break;
  869. case -4:
  870. char_log("Invalid inventory item structure in the next character line (character not readed):" RETCODE);
  871. break;
  872. case -5:
  873. char_log("Invalid cart item structure in the next character line (character not readed):" RETCODE);
  874. break;
  875. case -6:
  876. char_log("Invalid skill structure in the next character line (character not readed):" RETCODE);
  877. break;
  878. case -7:
  879. char_log("Invalid register structure in the next character line (character not readed):" RETCODE);
  880. break;
  881. default: // 0
  882. char_log("Unabled to get a character in the next line - Basic structure of line (before inventory) is incorrect (character not readed):" RETCODE);
  883. break;
  884. }
  885. char_log("%s", line);
  886. }
  887. }
  888. fclose(fp);
  889. if (char_num == 0) {
  890. ShowNotice("mmo_char_init: No character found in %s.\n", char_txt);
  891. char_log("mmo_char_init: No character found in %s." RETCODE, char_txt);
  892. } else if (char_num == 1) {
  893. ShowStatus("mmo_char_init: 1 character read in %s.\n", char_txt);
  894. char_log("mmo_char_init: 1 character read in %s." RETCODE, char_txt);
  895. } else {
  896. ShowStatus("mmo_char_init: %d characters read in %s.\n", char_num, char_txt);
  897. char_log("mmo_char_init: %d characters read in %s." RETCODE, char_num, char_txt);
  898. }
  899. char_log("Id for the next created character: %d." RETCODE, char_id_count);
  900. return 0;
  901. }
  902. //---------------------------------------------------------
  903. // Function to save characters in files (speed up by [Yor])
  904. //---------------------------------------------------------
  905. void mmo_char_sync(void) {
  906. char line[65536],f_line[1024];
  907. int i, j, k;
  908. int lock;
  909. FILE *fp,*f_fp;
  910. //int *id = (int *) aMalloc(sizeof(int) * char_num);
  911. CREATE_BUFFER(id, int, char_num);
  912. // Sorting before save (by [Yor])
  913. for(i = 0; i < char_num; i++) {
  914. id[i] = i;
  915. for(j = 0; j < i; j++) {
  916. if ((char_dat[i].status.account_id < char_dat[id[j]].status.account_id) ||
  917. // if same account id, we sort by slot.
  918. (char_dat[i].status.account_id == char_dat[id[j]].status.account_id &&
  919. char_dat[i].status.char_num < char_dat[id[j]].status.char_num)) {
  920. for(k = i; k > j; k--)
  921. id[k] = id[k-1];
  922. id[j] = i; // id[i]
  923. break;
  924. }
  925. }
  926. }
  927. // Data save
  928. fp = lock_fopen(char_txt, &lock);
  929. if (fp == NULL) {
  930. ShowWarning("Server can't not save characters.\n");
  931. char_log("WARNING: Server can't not save characters." RETCODE);
  932. } else {
  933. for(i = 0; i < char_num; i++) {
  934. // create only once the line, and save it in the 2 files (it's speeder than repeat twice the loop and create twice the line)
  935. mmo_char_tostr(line, &char_dat[id[i]].status, char_dat[id[i]].global, char_dat[id[i]].global_num); // use of sorted index
  936. fprintf(fp, "%s" RETCODE, line);
  937. }
  938. fprintf(fp, "%d\t%%newid%%" RETCODE, char_id_count);
  939. lock_fclose(fp, char_txt, &lock);
  940. }
  941. // Data save (backup)
  942. if (backup_txt_flag) { // The backup_txt file was created because char deletion bug existed. Now it's finish and that take a lot of time to create a second file when there are a lot of characters. => option By [Yor]
  943. fp = lock_fopen(backup_txt, &lock);
  944. if (fp == NULL) {
  945. ShowWarning("Server can't not create backup of characters file.\n");
  946. char_log("WARNING: Server can't not create backup of characters file." RETCODE);
  947. //aFree(id); // free up the memory before leaving -.- [Ajarn]
  948. DELETE_BUFFER(id);
  949. return;
  950. }
  951. for(i = 0; i < char_num; i++) {
  952. // create only once the line, and save it in the 2 files (it's speeder than repeat twice the loop and create twice the line)
  953. mmo_char_tostr(line, &char_dat[id[i]].status,char_dat[id[i]].global, char_dat[id[i]].global_num); // use of sorted index
  954. fprintf(fp, "%s" RETCODE, line);
  955. }
  956. fprintf(fp, "%d\t%%newid%%" RETCODE, char_id_count);
  957. lock_fclose(fp, backup_txt, &lock);
  958. }
  959. // Friends List data save (davidsiaw)
  960. f_fp = lock_fopen(friends_txt, &lock);
  961. for(i = 0; i < char_num; i++) {
  962. mmo_friends_list_data_str(f_line, &char_dat[id[i]].status);
  963. fprintf(f_fp, "%s" RETCODE, f_line);
  964. }
  965. lock_fclose(f_fp, friends_txt, &lock);
  966. //aFree(id);
  967. DELETE_BUFFER(id);
  968. return;
  969. }
  970. //----------------------------------------------------
  971. // Function to save (in a periodic way) datas in files
  972. //----------------------------------------------------
  973. int mmo_char_sync_timer(int tid, unsigned int tick, int id, int data) {
  974. if (save_log)
  975. ShowInfo("Saving all files...\n");
  976. mmo_char_sync();
  977. inter_save();
  978. return 0;
  979. }
  980. //-----------------------------------
  981. // Function to create a new character
  982. //-----------------------------------
  983. int make_new_char(int fd, unsigned char *dat) {
  984. int i;
  985. struct char_session_data *sd;
  986. char name[NAME_LENGTH];
  987. sd = (struct char_session_data*)session[fd]->session_data;
  988. // remove control characters from the name
  989. strncpy(name, dat, NAME_LENGTH);
  990. name[NAME_LENGTH-1] = '\0'; //Trunc name to max possible value (23)
  991. trim(name,TRIM_CHARS); //Trim character name. [Skotlex]
  992. //check name != main chat nick [LuzZza]
  993. if(strcmpi(name, main_chat_nick) == 0) {
  994. char_log("Create char failed (%d): this nick (%s) reserved for mainchat messages." RETCODE,
  995. sd->account_id, name);
  996. return -1;
  997. }
  998. if (remove_control_chars((unsigned char *)name)) {
  999. char_log("Make new char error (control char received in the name): (connection #%d, account: %d)." RETCODE,
  1000. fd, sd->account_id);
  1001. return -1;
  1002. }
  1003. // check lenght of character name
  1004. if (strlen(name) < 4) {
  1005. char_log("Make new char error (character name too small): (connection #%d, account: %d, name: '%s')." RETCODE,
  1006. fd, sd->account_id, dat);
  1007. return -1;
  1008. }
  1009. // Check Authorised letters/symbols in the name of the character
  1010. if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
  1011. for (i = 0; i < NAME_LENGTH && name[i]; i++)
  1012. if (strchr(char_name_letters, name[i]) == NULL) {
  1013. char_log("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c." RETCODE,
  1014. fd, sd->account_id, name, name[i]);
  1015. return -1;
  1016. }
  1017. } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden
  1018. for (i = 0; i < NAME_LENGTH && name[i]; i++)
  1019. if (strchr(char_name_letters, name[i]) != NULL) {
  1020. char_log("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c." RETCODE,
  1021. fd, sd->account_id, dat, dat[i]);
  1022. return -1;
  1023. }
  1024. } // else, all letters/symbols are authorised (except control char removed before)
  1025. if (dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29] != 5*6 || // stats
  1026. dat[30] >= 9 || // slots (dat[30] can not be negativ)
  1027. dat[33] <= 0 || dat[33] >= 24 || // hair style
  1028. dat[31] >= 9) { // hair color (dat[31] can not be negativ)
  1029. char_log("Make new char error (invalid values): (connection #%d, account: %d) slot %d, name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d" RETCODE,
  1030. fd, sd->account_id, dat[30], dat, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], dat[31]);
  1031. return -1;
  1032. }
  1033. // check individual stat value
  1034. for(i = 24; i <= 29; i++) {
  1035. if (dat[i] < 1 || dat[i] > 9) {
  1036. char_log("Make new char error (invalid stat value: not between 1 to 9): (connection #%d, account: %d) slot %d, name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d" RETCODE,
  1037. fd, sd->account_id, dat[30], dat, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], dat[31]);
  1038. return -1;
  1039. }
  1040. } // now we know that every stat has proper value but we have to check if str/int agi/luk vit/dex pairs are correct
  1041. if( ((dat[24]+dat[27]) > 10) || ((dat[25]+dat[29]) > 10) || ((dat[26]+dat[28]) > 10) ) {
  1042. if (log_char) {
  1043. char_log("Make new char error (invalid stat value): (connection #%d, account: %d) slot %d, name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d" RETCODE,
  1044. fd, sd->account_id, dat[30], dat, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], dat[31]);
  1045. return -1;
  1046. }
  1047. } // now when we have passed all stat checks
  1048. for(i = 0; i < char_num; i++) {
  1049. if ((name_ignoring_case != 0 && strncmp(char_dat[i].status.name, name, NAME_LENGTH) == 0) ||
  1050. (name_ignoring_case == 0 && strncmpi(char_dat[i].status.name, name, NAME_LENGTH) == 0)) {
  1051. char_log("Make new char error (name already exists): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %d), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d." RETCODE,
  1052. fd, sd->account_id, dat[30], dat, char_dat[i].status.name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], dat[31]);
  1053. return -1;
  1054. }
  1055. if (char_dat[i].status.account_id == sd->account_id && char_dat[i].status.char_num == dat[30]) {
  1056. char_log("Make new char error (slot already used): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %d), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d." RETCODE,
  1057. fd, sd->account_id, dat[30], dat, char_dat[i].status.name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], dat[31]);
  1058. return -1;
  1059. }
  1060. }
  1061. if (strcmp(wisp_server_name, name) == 0) {
  1062. char_log("Make new char error (name used is wisp name for server): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %d), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d." RETCODE,
  1063. fd, sd->account_id, dat[30], name, char_dat[i].status.name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], dat[31]);
  1064. return -1;
  1065. }
  1066. if (char_num >= char_max) {
  1067. char_max += 256;
  1068. char_dat = (struct character_data*)aRealloc(char_dat, sizeof(struct character_data) * char_max);
  1069. if (!char_dat) {
  1070. ShowFatalError("Out of memory: make_new_char (realloc of char_dat).\n");
  1071. char_log("Out of memory: make_new_char (realloc of char_dat)." RETCODE);
  1072. exit(1);
  1073. }
  1074. }
  1075. char_log("Creation of New Character: (connection #%d, account: %d) slot %d, character Name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d." RETCODE,
  1076. fd, sd->account_id, dat[30], name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], dat[31]);
  1077. memset(&char_dat[i], 0, sizeof(struct character_data));
  1078. char_dat[i].status.char_id = char_id_count++;
  1079. char_dat[i].status.account_id = sd->account_id;
  1080. char_dat[i].status.char_num = dat[30];
  1081. strcpy(char_dat[i].status.name,name);
  1082. char_dat[i].status.class_ = 0;
  1083. char_dat[i].status.base_level = 1;
  1084. char_dat[i].status.job_level = 1;
  1085. char_dat[i].status.base_exp = 0;
  1086. char_dat[i].status.job_exp = 0;
  1087. char_dat[i].status.zeny = start_zeny;
  1088. char_dat[i].status.str = dat[24];
  1089. char_dat[i].status.agi = dat[25];
  1090. char_dat[i].status.vit = dat[26];
  1091. char_dat[i].status.int_ = dat[27];
  1092. char_dat[i].status.dex = dat[28];
  1093. char_dat[i].status.luk = dat[29];
  1094. char_dat[i].status.max_hp = 40 * (100 + char_dat[i].status.vit) / 100;
  1095. char_dat[i].status.max_sp = 11 * (100 + char_dat[i].status.int_) / 100;
  1096. char_dat[i].status.hp = char_dat[i].status.max_hp;
  1097. char_dat[i].status.sp = char_dat[i].status.max_sp;
  1098. char_dat[i].status.status_point = 0;
  1099. char_dat[i].status.skill_point = 0;
  1100. char_dat[i].status.option = 0;
  1101. char_dat[i].status.karma = 0;
  1102. char_dat[i].status.manner = 0;
  1103. char_dat[i].status.party_id = 0;
  1104. char_dat[i].status.guild_id = 0;
  1105. char_dat[i].status.hair = dat[33];
  1106. char_dat[i].status.hair_color = dat[31];
  1107. char_dat[i].status.clothes_color = 0;
  1108. char_dat[i].status.inventory[0].nameid = start_weapon; // Knife
  1109. char_dat[i].status.inventory[0].amount = 1;
  1110. char_dat[i].status.inventory[0].equip = 0x02;
  1111. char_dat[i].status.inventory[0].identify = 1;
  1112. char_dat[i].status.inventory[1].nameid = start_armor; // Cotton Shirt
  1113. char_dat[i].status.inventory[1].amount = 1;
  1114. char_dat[i].status.inventory[1].equip = 0x10;
  1115. char_dat[i].status.inventory[1].identify = 1;
  1116. char_dat[i].status.weapon = 1;
  1117. char_dat[i].status.shield = 0;
  1118. char_dat[i].status.head_top = 0;
  1119. char_dat[i].status.head_mid = 0;
  1120. char_dat[i].status.head_bottom = 0;
  1121. memcpy(&char_dat[i].status.last_point, &start_point, sizeof(start_point));
  1122. memcpy(&char_dat[i].status.save_point, &start_point, sizeof(start_point));
  1123. char_num++;
  1124. mmo_char_sync();
  1125. return i;
  1126. }
  1127. //----------------------------------------------------
  1128. // This function return the name of the job (by [Yor])
  1129. //----------------------------------------------------
  1130. char * job_name(int class_) {
  1131. switch (class_) {
  1132. case JOB_NOVICE: return "Novice";
  1133. case JOB_SWORDMAN: return "Swordsman";
  1134. case JOB_MAGE: return "Mage";
  1135. case JOB_ARCHER: return "Archer";
  1136. case JOB_ACOLYTE: return "Acolyte";
  1137. case JOB_MERCHANT: return "Merchant";
  1138. case JOB_THIEF: return "Thief";
  1139. case JOB_KNIGHT: return "Knight";
  1140. case JOB_PRIEST: return "Priest";
  1141. case JOB_WIZARD: return "Wizard";
  1142. case JOB_BLACKSMITH: return "Blacksmith";
  1143. case JOB_HUNTER: return "Hunter";
  1144. case JOB_ASSASSIN: return "Assassin";
  1145. case JOB_KNIGHT2: return "Peco-Knight";
  1146. case JOB_CRUSADER: return "Crusader";
  1147. case JOB_MONK: return "Monk";
  1148. case JOB_SAGE: return "Sage";
  1149. case JOB_ROGUE: return "Rogue";
  1150. case JOB_ALCHEMIST: return "Alchemist";
  1151. case JOB_BARD: return "Bard";
  1152. case JOB_DANCER: return "Dancer";
  1153. case JOB_CRUSADER2: return "Peco-Crusader";
  1154. case JOB_WEDDING: return "Wedding";
  1155. case JOB_SUPER_NOVICE: return "Super Novice";
  1156. case JOB_GUNSLINGER: return "Gunslinger";
  1157. case JOB_NINJA: return "Ninja";
  1158. case JOB_XMAS: return "Christmas";
  1159. case JOB_NOVICE_HIGH: return "Novice High";
  1160. case JOB_SWORDMAN_HIGH: return "Swordsman High";
  1161. case JOB_MAGE_HIGH: return "Mage High";
  1162. case JOB_ARCHER_HIGH: return "Archer High";
  1163. case JOB_ACOLYTE_HIGH: return "Acolyte High";
  1164. case JOB_MERCHANT_HIGH: return "Merchant High";
  1165. case JOB_THIEF_HIGH: return "Thief High";
  1166. case JOB_LORD_KNIGHT: return "Lord Knight";
  1167. case JOB_HIGH_PRIEST: return "High Priest";
  1168. case JOB_HIGH_WIZARD: return "High Wizard";
  1169. case JOB_WHITESMITH: return "Whitesmith";
  1170. case JOB_SNIPER: return "Sniper";
  1171. case JOB_ASSASSIN_CROSS: return "Assassin Cross";
  1172. case JOB_LORD_KNIGHT2: return "Peko Knight";
  1173. case JOB_PALADIN: return "Paladin";
  1174. case JOB_CHAMPION: return "Champion";
  1175. case JOB_PROFESSOR: return "Professor";
  1176. case JOB_STALKER: return "Stalker";
  1177. case JOB_CREATOR: return "Creator";
  1178. case JOB_CLOWN: return "Clown";
  1179. case JOB_GYPSY: return "Gypsy";
  1180. case JOB_PALADIN2: return "Peko Paladin";
  1181. case JOB_BABY: return "Baby Novice";
  1182. case JOB_BABY_SWORDMAN: return "Baby Swordsman";
  1183. case JOB_BABY_MAGE: return "Baby Mage";
  1184. case JOB_BABY_ARCHER: return "Baby Archer";
  1185. case JOB_BABY_ACOLYTE: return "Baby Acolyte";
  1186. case JOB_BABY_MERCHANT: return "Baby Merchant";
  1187. case JOB_BABY_THIEF: return "Baby Thief";
  1188. case JOB_BABY_KNIGHT: return "Baby Knight";
  1189. case JOB_BABY_PRIEST: return "Baby Priest";
  1190. case JOB_BABY_WIZARD: return "Baby Wizard";
  1191. case JOB_BABY_BLACKSMITH: return "Baby Blacksmith";
  1192. case JOB_BABY_HUNTER: return "Baby Hunter";
  1193. case JOB_BABY_ASSASSIN: return "Baby Assassin";
  1194. case JOB_BABY_KNIGHT2: return "Baby Peco Knight";
  1195. case JOB_BABY_CRUSADER: return "Baby Crusader";
  1196. case JOB_BABY_MONK: return "Baby Monk";
  1197. case JOB_BABY_SAGE: return "Baby Sage";
  1198. case JOB_BABY_ROGUE: return "Baby Rogue";
  1199. case JOB_BABY_ALCHEMIST: return "Baby Alchemist";
  1200. case JOB_BABY_BARD: return "Baby Bard";
  1201. case JOB_BABY_DANCER: return "Baby Dancer";
  1202. case JOB_BABY_CRUSADER2: return "Baby Peco Crusader";
  1203. case JOB_SUPER_BABY: return "Super Baby";
  1204. case JOB_TAEKWON: return "Taekwon";
  1205. case JOB_STAR_GLADIATOR: return "Star Gladiator";
  1206. case JOB_STAR_GLADIATOR2: return "Flying Star Gladiator";
  1207. case JOB_SOUL_LINKER: return "Soul Linker";
  1208. }
  1209. return "Unknown Job";
  1210. }
  1211. static int create_online_files_sub(DBKey key, void* data, va_list va)
  1212. {
  1213. struct online_char_data *character;
  1214. int* players;
  1215. int *id;
  1216. int j,k,l;
  1217. character = (struct online_char_data*) data;
  1218. players = va_arg(va, int*);
  1219. id = va_arg(va, int*);
  1220. // check if map-server is online
  1221. if (character->server == -1 || character->char_id == -1) { //Character not currently online.
  1222. return -1;
  1223. }
  1224. j = character->server;
  1225. if (server_fd[j] < 0) {
  1226. server[j].users = 0;
  1227. return -1;
  1228. }
  1229. // search position of character in char_dat and sort online characters.
  1230. for(j = 0; j < char_num; j++) {
  1231. if (char_dat[j].status.char_id != character->char_id)
  1232. continue;
  1233. id[*players] = j;
  1234. // use sorting option
  1235. switch (online_sorting_option) {
  1236. case 1: // by name (without case sensitive)
  1237. for(k = 0; k < *players; k++)
  1238. if (stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0 ||
  1239. // if same name, we sort with case sensitive.
  1240. (stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) == 0 &&
  1241. strcmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) {
  1242. for(l = *players; l > k; l--)
  1243. id[l] = id[l-1];
  1244. id[k] = j; // id[*players]
  1245. break;
  1246. }
  1247. break;
  1248. case 2: // by zeny
  1249. for(k = 0; k < *players; k++)
  1250. if (char_dat[j].status.zeny < char_dat[id[k]].status.zeny ||
  1251. // if same number of zenys, we sort by name.
  1252. (char_dat[j].status.zeny == char_dat[id[k]].status.zeny &&
  1253. stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) {
  1254. for(l = *players; l > k; l--)
  1255. id[l] = id[l-1];
  1256. id[k] = j; // id[*players]
  1257. break;
  1258. }
  1259. break;
  1260. case 3: // by base level
  1261. for(k = 0; k < *players; k++)
  1262. if (char_dat[j].status.base_level < char_dat[id[k]].status.base_level ||
  1263. // if same base level, we sort by base exp.
  1264. (char_dat[j].status.base_level == char_dat[id[k]].status.base_level &&
  1265. char_dat[j].status.base_exp < char_dat[id[k]].status.base_exp)) {
  1266. for(l = *players; l > k; l--)
  1267. id[l] = id[l-1];
  1268. id[k] = j; // id[*players]
  1269. break;
  1270. }
  1271. break;
  1272. case 4: // by job (and job level)
  1273. for(k = 0; k < *players; k++)
  1274. if (char_dat[j].status.class_ < char_dat[id[k]].status.class_ ||
  1275. // if same job, we sort by job level.
  1276. (char_dat[j].status.class_ == char_dat[id[k]].status.class_ &&
  1277. char_dat[j].status.job_level < char_dat[id[k]].status.job_level) ||
  1278. // if same job and job level, we sort by job exp.
  1279. (char_dat[j].status.class_ == char_dat[id[k]].status.class_ &&
  1280. char_dat[j].status.job_level == char_dat[id[k]].status.job_level &&
  1281. char_dat[j].status.job_exp < char_dat[id[k]].status.job_exp)) {
  1282. for(l = *players; l > k; l--)
  1283. id[l] = id[l-1];
  1284. id[k] = j; // id[*players]
  1285. break;
  1286. }
  1287. break;
  1288. case 5: // by location map name
  1289. {
  1290. const char *map1, *map2;
  1291. map1 = mapindex_id2name(char_dat[j].status.last_point.map);
  1292. for(k = 0; k < *players; k++) {
  1293. map2 = mapindex_id2name(char_dat[id[k]].status.last_point.map);
  1294. if (!map1 || !map2 || //Avoid sorting if either one failed to resolve.
  1295. stricmp(map1, map2) < 0 ||
  1296. // if same map name, we sort by name.
  1297. (stricmp(map1, map2) == 0 &&
  1298. stricmp(char_dat[j].status.name, char_dat[id[k]].status.name) < 0)) {
  1299. for(l = *players; l > k; l--)
  1300. id[l] = id[l-1];
  1301. id[k] = j; // id[*players]
  1302. break;
  1303. }
  1304. }
  1305. }
  1306. break;
  1307. default: // 0 or invalid value: no sorting
  1308. break;
  1309. }
  1310. (*players)++;
  1311. break;
  1312. }
  1313. return 0;
  1314. }
  1315. //-------------------------------------------------------------
  1316. // Function to create the online files (txt and html). by [Yor]
  1317. //-------------------------------------------------------------
  1318. void create_online_files(void) {
  1319. unsigned int k, j; // for loop with strlen comparing
  1320. int i, l; // for loops
  1321. int players; // count the number of players
  1322. FILE *fp; // for the txt file
  1323. FILE *fp2; // for the html file
  1324. char temp[256]; // to prepare what we must display
  1325. time_t time_server; // for number of seconds
  1326. struct tm *datetime; // variable for time in structure ->tm_mday, ->tm_sec, ...
  1327. int id[4096];
  1328. if (online_display_option == 0) // we display nothing, so return
  1329. return;
  1330. // Get number of online players, id of each online players, and verify if a server is offline
  1331. players = 0;
  1332. online_char_db->foreach(online_char_db, create_online_files_sub, &players, &id);
  1333. // write files
  1334. fp = fopen(online_txt_filename, "w");
  1335. if (fp != NULL) {
  1336. fp2 = fopen(online_html_filename, "w");
  1337. if (fp2 != NULL) {
  1338. // get time
  1339. time(&time_server); // get time in seconds since 1/1/1970
  1340. datetime = localtime(&time_server); // convert seconds in structure
  1341. strftime(temp, sizeof(temp), "%d %b %Y %X", datetime); // like sprintf, but only for date/time (05 dec 2003 15:12:52)
  1342. // write heading
  1343. fprintf(fp2, "<HTML>\n");
  1344. fprintf(fp2, " <META http-equiv=\"Refresh\" content=\"%d\">\n", online_refresh_html); // update on client explorer every x seconds
  1345. fprintf(fp2, " <HEAD>\n");
  1346. fprintf(fp2, " <TITLE>Online Players on %s</TITLE>\n", server_name);
  1347. fprintf(fp2, " </HEAD>\n");
  1348. fprintf(fp2, " <BODY>\n");
  1349. fprintf(fp2, " <H3>Online Players on %s (%s):</H3>\n", server_name, temp);
  1350. fprintf(fp, "Online Players on %s (%s):\n", server_name, temp);
  1351. fprintf(fp, "\n");
  1352. for (i = 0; i < players; i++) {
  1353. // if it's the first player
  1354. if (i == 0) {
  1355. j = 0; // count the number of characters for the txt version and to set the separate line
  1356. fprintf(fp2, " <table border=\"1\" cellspacing=\"1\">\n");
  1357. fprintf(fp2, " <tr>\n");
  1358. if ((online_display_option & 1) || (online_display_option & 64)) {
  1359. fprintf(fp2, " <td><b>Name</b></td>\n");
  1360. if (online_display_option & 64) {
  1361. fprintf(fp, "Name "); // 30
  1362. j += 30;
  1363. } else {
  1364. fprintf(fp, "Name "); // 25
  1365. j += 25;
  1366. }
  1367. }
  1368. if ((online_display_option & 6) == 6) {
  1369. fprintf(fp2, " <td><b>Job (levels)</b></td>\n");
  1370. fprintf(fp, "Job Levels "); // 27
  1371. j += 27;
  1372. } else if (online_display_option & 2) {
  1373. fprintf(fp2, " <td><b>Job</b></td>\n");
  1374. fprintf(fp, "Job "); // 19
  1375. j += 19;
  1376. } else if (online_display_option & 4) {
  1377. fprintf(fp2, " <td><b>Levels</b></td>\n");
  1378. fprintf(fp, " Levels "); // 8
  1379. j += 8;
  1380. }
  1381. if (online_display_option & 24) { // 8 or 16
  1382. fprintf(fp2, " <td><b>Location</b></td>\n");
  1383. if (online_display_option & 16) {
  1384. fprintf(fp, "Location ( x , y ) "); // 23
  1385. j += 23;
  1386. } else {
  1387. fprintf(fp, "Location "); // 13
  1388. j += 13;
  1389. }
  1390. }
  1391. if (online_display_option & 32) {
  1392. fprintf(fp2, " <td ALIGN=CENTER><b>zenys</b></td>\n");
  1393. fprintf(fp, " Zenys "); // 16
  1394. j += 16;
  1395. }
  1396. fprintf(fp2, " </tr>\n");
  1397. fprintf(fp, "\n");
  1398. for (k = 0; k < j; k++)
  1399. fprintf(fp, "-");
  1400. fprintf(fp, "\n");
  1401. }
  1402. fprintf(fp2, " <tr>\n");
  1403. // get id of the character (more speed)
  1404. j = id[i];
  1405. // displaying the character name
  1406. if ((online_display_option & 1) || (online_display_option & 64)) { // without/with 'GM' display
  1407. strcpy(temp, char_dat[j].status.name);
  1408. l = isGM(char_dat[j].status.account_id);
  1409. if (online_display_option & 64) {
  1410. if (l >= online_gm_display_min_level)
  1411. fprintf(fp, "%-24s (GM) ", temp);
  1412. else
  1413. fprintf(fp, "%-24s ", temp);
  1414. } else
  1415. fprintf(fp, "%-24s ", temp);
  1416. // name of the character in the html (no < >, because that create problem in html code)
  1417. fprintf(fp2, " <td>");
  1418. if ((online_display_option & 64) && l >= online_gm_display_min_level)
  1419. fprintf(fp2, "<b>");
  1420. for (k = 0; k < strlen(temp); k++) {
  1421. switch(temp[k]) {
  1422. case '<': // <
  1423. fprintf(fp2, "&lt;");
  1424. break;
  1425. case '>': // >
  1426. fprintf(fp2, "&gt;");
  1427. break;
  1428. default:
  1429. fprintf(fp2, "%c", temp[k]);
  1430. break;
  1431. };
  1432. }
  1433. if ((online_display_option & 64) && l >= online_gm_display_min_level)
  1434. fprintf(fp2, "</b> (GM)");
  1435. fprintf(fp2, "</td>\n");
  1436. }
  1437. // displaying of the job
  1438. if (online_display_option & 6) {
  1439. char * jobname = job_name(char_dat[j].status.class_);
  1440. if ((online_display_option & 6) == 6) {
  1441. fprintf(fp2, " <td>%s %d/%d</td>\n", jobname, char_dat[j].status.base_level, char_dat[j].status.job_level);
  1442. fprintf(fp, "%-18s %3d/%3d ", jobname, char_dat[j].status.base_level, char_dat[j].status.job_level);
  1443. } else if (online_display_option & 2) {
  1444. fprintf(fp2, " <td>%s</td>\n", jobname);
  1445. fprintf(fp, "%-18s ", jobname);
  1446. } else if (online_display_option & 4) {
  1447. fprintf(fp2, " <td>%d/%d</td>\n", char_dat[j].status.base_level, char_dat[j].status.job_level);
  1448. fprintf(fp, "%3d/%3d ", char_dat[j].status.base_level, char_dat[j].status.job_level);
  1449. }
  1450. }
  1451. // displaying of the map
  1452. if (online_display_option & 24) { // 8 or 16
  1453. // prepare map name
  1454. memcpy(temp, mapindex_id2name(char_dat[j].status.last_point.map), MAP_NAME_LENGTH);
  1455. temp[MAP_NAME_LENGTH] = '\0';
  1456. if (strstr(temp, ".gat") != NULL) {
  1457. temp[strstr(temp, ".gat") - temp] = 0; // suppress the '.gat'
  1458. }
  1459. // write map name
  1460. if (online_display_option & 16) { // map-name AND coordinates
  1461. fprintf(fp2, " <td>%s (%d, %d)</td>\n", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y);
  1462. fprintf(fp, "%-12s (%3d,%3d) ", temp, char_dat[j].status.last_point.x, char_dat[j].status.last_point.y);
  1463. } else {
  1464. fprintf(fp2, " <td>%s</td>\n", temp);
  1465. fprintf(fp, "%-12s ", temp);
  1466. }
  1467. }
  1468. // displaying nimber of zenys
  1469. if (online_display_option & 32) {
  1470. // write number of zenys
  1471. if (char_dat[j].status.zeny == 0) { // if no zeny
  1472. fprintf(fp2, " <td ALIGN=RIGHT>no zeny</td>\n");
  1473. fprintf(fp, " no zeny ");
  1474. } else {
  1475. fprintf(fp2, " <td ALIGN=RIGHT>%d z</td>\n", char_dat[j].status.zeny);
  1476. fprintf(fp, "%13d z ", char_dat[j].status.zeny);
  1477. }
  1478. }
  1479. fprintf(fp, "\n");
  1480. fprintf(fp2, " </tr>\n");
  1481. }
  1482. // If we display at least 1 player
  1483. if (players > 0) {
  1484. fprintf(fp2, " </table>\n");
  1485. fprintf(fp, "\n");
  1486. }
  1487. // Displaying number of online players
  1488. if (players == 0) {
  1489. fprintf(fp2, " <p>No user is online.</p>\n");
  1490. fprintf(fp, "No user is online.\n");
  1491. } else if (players == 1) {
  1492. fprintf(fp2, " <p>%d user is online.</p>\n", players);
  1493. fprintf(fp, "%d user is online.\n", players);
  1494. } else {
  1495. fprintf(fp2, " <p>%d users are online.</p>\n", players);
  1496. fprintf(fp, "%d users are online.\n", players);
  1497. }
  1498. fprintf(fp2, " </BODY>\n");
  1499. fprintf(fp2, "</HTML>\n");
  1500. fclose(fp2);
  1501. }
  1502. fclose(fp);
  1503. }
  1504. return;
  1505. }
  1506. //---------------------------------------------------------------------
  1507. // This function return the number of online players in all map-servers
  1508. //---------------------------------------------------------------------
  1509. int count_users(void) {
  1510. int i, users;
  1511. users = 0;
  1512. for(i = 0; i < MAX_MAP_SERVERS; i++)
  1513. if (server_fd[i] >= 0)
  1514. users += server[i].users;
  1515. return users;
  1516. }
  1517. //----------------------------------------
  1518. // Function to send characters to a player
  1519. //----------------------------------------
  1520. int mmo_char_send006b(int fd, struct char_session_data *sd) {
  1521. int i, j, found_num;
  1522. struct mmo_charstatus *p;
  1523. //#ifdef NEW_006b
  1524. const int offset = 24;
  1525. //#else
  1526. // const int offset = 4;
  1527. //#endif
  1528. set_char_online(-1, 99,sd->account_id);
  1529. found_num = 0;
  1530. for(i = 0; i < char_num; i++) {
  1531. if (char_dat[i].status.account_id == sd->account_id) {
  1532. sd->found_char[found_num] = i;
  1533. found_num++;
  1534. if (found_num == 9)
  1535. break;
  1536. }
  1537. }
  1538. for(i = found_num; i < 9; i++)
  1539. sd->found_char[i] = -1;
  1540. WFIFOHEAD(fd, offset + found_num * 106);
  1541. memset(WFIFOP(fd,0), 0, offset + found_num * 106);
  1542. WFIFOW(fd,0) = 0x6b;
  1543. WFIFOW(fd,2) = offset + found_num * 106;
  1544. for(i = 0; i < found_num; i++) {
  1545. p = &char_dat[sd->found_char[i]].status;
  1546. j = offset + (i * 106); // increase speed of code
  1547. WFIFOL(fd,j) = p->char_id;
  1548. WFIFOL(fd,j+4) = p->base_exp>LONG_MAX?LONG_MAX:p->base_exp;
  1549. WFIFOL(fd,j+8) = p->zeny;
  1550. WFIFOL(fd,j+12) = p->job_exp>LONG_MAX?LONG_MAX:p->job_exp;
  1551. WFIFOL(fd,j+16) = p->job_level;
  1552. WFIFOL(fd,j+20) = 0;
  1553. WFIFOL(fd,j+24) = 0;
  1554. WFIFOL(fd,j+28) = p->option;
  1555. WFIFOL(fd,j+32) = p->karma;
  1556. WFIFOL(fd,j+36) = p->manner;
  1557. WFIFOW(fd,j+40) = (p->status_point>SHRT_MAX) ? SHRT_MAX : p->status_point;
  1558. WFIFOW(fd,j+42) = (p->hp > SHRT_MAX) ? SHRT_MAX : p->hp;
  1559. WFIFOW(fd,j+44) = (p->max_hp > SHRT_MAX) ? SHRT_MAX : p->max_hp;
  1560. WFIFOW(fd,j+46) = (p->sp > SHRT_MAX) ? SHRT_MAX : p->sp;
  1561. WFIFOW(fd,j+48) = (p->max_sp > SHRT_MAX) ? SHRT_MAX : p->max_sp;
  1562. WFIFOW(fd,j+50) = DEFAULT_WALK_SPEED; // p->speed;
  1563. WFIFOW(fd,j+52) = p->class_;
  1564. WFIFOW(fd,j+54) = p->hair;
  1565. WFIFOW(fd,j+56) = p->option&0x20?0:p->weapon; //When the weapon is sent and your option is riding, the client crashes on login!?
  1566. WFIFOW(fd,j+58) = p->base_level;
  1567. WFIFOW(fd,j+60) = (p->skill_point>SHRT_MAX)? SHRT_MAX : p->skill_point;
  1568. WFIFOW(fd,j+62) = p->head_bottom;
  1569. WFIFOW(fd,j+64) = p->shield;
  1570. WFIFOW(fd,j+66) = p->head_top;
  1571. WFIFOW(fd,j+68) = p->head_mid;
  1572. WFIFOW(fd,j+70) = p->hair_color;
  1573. WFIFOW(fd,j+72) = p->clothes_color;
  1574. memcpy(WFIFOP(fd,j+74), p->name, NAME_LENGTH);
  1575. WFIFOB(fd,j+98) = (p->str > 255) ? 255 : p->str;
  1576. WFIFOB(fd,j+99) = (p->agi > 255) ? 255 : p->agi;
  1577. WFIFOB(fd,j+100) = (p->vit > 255) ? 255 : p->vit;
  1578. WFIFOB(fd,j+101) = (p->int_ > 255) ? 255 : p->int_;
  1579. WFIFOB(fd,j+102) = (p->dex > 255) ? 255 : p->dex;
  1580. WFIFOB(fd,j+103) = (p->luk > 255) ? 255 : p->luk;
  1581. WFIFOB(fd,j+104) = p->char_num;
  1582. }
  1583. WFIFOSET(fd,WFIFOW(fd,2));
  1584. return 0;
  1585. }
  1586. // 離婚(char削除時に使用)
  1587. int char_divorce(struct mmo_charstatus *cs) {
  1588. if (cs == NULL)
  1589. return 0;
  1590. if (cs->partner_id > 0){
  1591. int i, j;
  1592. for(i = 0; i < char_num; i++) {
  1593. if (char_dat[i].status.char_id == cs->partner_id && char_dat[i].status.partner_id == cs->char_id) {
  1594. cs->partner_id = 0;
  1595. char_dat[i].status.partner_id = 0;
  1596. for(j = 0; j < MAX_INVENTORY; j++)
  1597. if (char_dat[i].status.inventory[j].nameid == WEDDING_RING_M || char_dat[i].status.inventory[j].nameid == WEDDING_RING_F)
  1598. memset(&char_dat[i].status.inventory[j], 0, sizeof(char_dat[i].status.inventory[0]));
  1599. if (cs->inventory[j].nameid == WEDDING_RING_M || cs->inventory[j].nameid == WEDDING_RING_F)
  1600. memset(&cs->inventory[j], 0, sizeof(cs->inventory[0]));
  1601. return 0;
  1602. }
  1603. }
  1604. }
  1605. return 0;
  1606. }
  1607. int char_married(int pl1,int pl2) {
  1608. return (char_dat[pl1].status.char_id == char_dat[pl2].status.partner_id && char_dat[pl2].status.char_id == char_dat[pl1].status.partner_id);
  1609. }
  1610. int char_child(int parent_id, int child_id) {
  1611. return (char_dat[parent_id].status.child == char_dat[child_id].status.char_id &&
  1612. ((char_dat[parent_id].status.char_id == char_dat[child_id].status.father) ||
  1613. (char_dat[parent_id].status.char_id == char_dat[child_id].status.mother)));
  1614. }
  1615. int char_family(int cid1, int cid2, int cid3) {
  1616. int i, idx1 = -1, idx2 =-1;//, idx3 =-1;
  1617. for(i = 0; i < char_num && (idx1 == -1 || idx2 == -1/* || idx3 == 1*/); i++)
  1618. {
  1619. if (char_dat[i].status.char_id == cid1)
  1620. idx1 = i;
  1621. if (char_dat[i].status.char_id == cid2)
  1622. idx2 = i;
  1623. // if (char_dat[i].status.char_id == cid2)
  1624. // idx3 = i;
  1625. }
  1626. if (idx1 == -1 || idx2 == -1/* || idx3 == -1*/)
  1627. return 0; //Some character not found??
  1628. //Unless the dbs are corrupted, these 3 checks should suffice, even though
  1629. //we could do a lot more checks and force cross-reference integrity.
  1630. if(char_dat[idx1].status.partner_id == cid2 &&
  1631. char_dat[idx1].status.child == cid3)
  1632. return cid3; //cid1/cid2 parents. cid3 child.
  1633. if(char_dat[idx1].status.partner_id == cid3 &&
  1634. char_dat[idx1].status.child == cid2)
  1635. return cid2; //cid1/cid3 parents. cid2 child.
  1636. if(char_dat[idx2].status.partner_id == cid3 &&
  1637. char_dat[idx2].status.child == cid1)
  1638. return cid1; //cid2/cid3 parents. cid1 child.
  1639. return 0;
  1640. }
  1641. //Clears the given party id from all characters.
  1642. //Since sometimes the party format changes and parties must be wiped, this
  1643. //method is required to prevent stress during the "party not found!" stages.
  1644. void char_clearparty(int party_id)
  1645. {
  1646. int i;
  1647. for(i = 0; i < char_num; i++)
  1648. {
  1649. if (char_dat[i].status.party_id == party_id)
  1650. char_dat[i].status.party_id = 0;
  1651. }
  1652. }
  1653. //------------------------------------------------------------
  1654. // E-mail check: return 0 (not correct) or 1 (valid). by [Yor]
  1655. //------------------------------------------------------------
  1656. int e_mail_check(char *email) {
  1657. char ch;
  1658. char* last_arobas;
  1659. // athena limits
  1660. if (strlen(email) < 3 || strlen(email) > 39)
  1661. return 0;
  1662. // part of RFC limits (official reference of e-mail description)
  1663. if (strchr(email, '@') == NULL || email[strlen(email)-1] == '@')
  1664. return 0;
  1665. if (email[strlen(email)-1] == '.')
  1666. return 0;
  1667. last_arobas = strrchr(email, '@');
  1668. if (strstr(last_arobas, "@.") != NULL ||
  1669. strstr(last_arobas, "..") != NULL)
  1670. return 0;
  1671. for(ch = 1; ch < 32; ch++) {
  1672. if (strchr(last_arobas, ch) != NULL) {
  1673. return 0;
  1674. break;
  1675. }
  1676. }
  1677. if (strchr(last_arobas, ' ') != NULL ||
  1678. strchr(last_arobas, ';') != NULL)
  1679. return 0;
  1680. // all correct
  1681. return 1;
  1682. }
  1683. //----------------------------------------------------------------------
  1684. // Force disconnection of an online player (with account value) by [Yor]
  1685. //----------------------------------------------------------------------
  1686. int disconnect_player(int account_id) {
  1687. int i;
  1688. struct char_session_data *sd;
  1689. // disconnect player if online on char-server
  1690. for(i = 0; i < fd_max; i++) {
  1691. if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) {
  1692. if (sd->account_id == account_id) {
  1693. session[i]->eof = 1;
  1694. return 1;
  1695. }
  1696. }
  1697. }
  1698. return 0;
  1699. }
  1700. // キャラ削除に伴うデータ削除
  1701. static int char_delete(struct mmo_charstatus *cs) {
  1702. int j;
  1703. // ペット削除
  1704. if (cs->pet_id)
  1705. inter_pet_delete(cs->pet_id);
  1706. if (cs->hom_id)
  1707. inter_homun_delete(cs->hom_id);
  1708. for (j = 0; j < MAX_INVENTORY; j++)
  1709. if (cs->inventory[j].card[0] == (short)0xff00)
  1710. inter_pet_delete(MakeDWord(cs->inventory[j].card[1],cs->inventory[j].card[2]));
  1711. for (j = 0; j < MAX_CART; j++)
  1712. if (cs->cart[j].card[0] == (short)0xff00)
  1713. inter_pet_delete( MakeDWord(cs->cart[j].card[1],cs->cart[j].card[2]) );
  1714. // ギルド脱退
  1715. if (cs->guild_id)
  1716. inter_guild_leave(cs->guild_id, cs->account_id, cs->char_id);
  1717. // パーティー脱退
  1718. if (cs->party_id)
  1719. inter_party_leave(cs->party_id, cs->account_id, cs->char_id);
  1720. // 離婚
  1721. if (cs->partner_id){
  1722. // 離婚情報をmapに通知
  1723. unsigned char buf[10];
  1724. WBUFW(buf,0) = 0x2b12;
  1725. WBUFL(buf,2) = cs->char_id;
  1726. WBUFL(buf,6) = cs->partner_id;
  1727. mapif_sendall(buf,10);
  1728. // 離婚
  1729. char_divorce(cs);
  1730. }
  1731. #ifdef ENABLE_SC_SAVING
  1732. status_delete_scdata(cs->account_id, cs->char_id);
  1733. #endif
  1734. return 0;
  1735. }
  1736. int send_accounts_tologin(int tid, unsigned int tick, int id, int data);
  1737. int parse_tologin(int fd) {
  1738. int i;
  1739. struct char_session_data *sd;
  1740. RFIFOHEAD(fd);
  1741. // only login-server can have an access to here.
  1742. // so, if it isn't the login-server, we disconnect the session (fd != login_fd).
  1743. if (fd != login_fd)
  1744. session[fd]->eof = 1;
  1745. if(session[fd]->eof) {
  1746. if (fd == login_fd) {
  1747. ShowWarning("Connection to login-server lost (connection #%d).\n", fd);
  1748. login_fd = -1;
  1749. }
  1750. do_close(fd);
  1751. return 0;
  1752. }
  1753. sd = (struct char_session_data*)session[fd]->session_data;
  1754. while(RFIFOREST(fd) >= 2 && !session[fd]->eof) {
  1755. // printf("parse_tologin: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd));
  1756. switch(RFIFOW(fd,0)) {
  1757. case 0x2711:
  1758. if (RFIFOREST(fd) < 3)
  1759. return 0;
  1760. if (RFIFOB(fd,2)) {
  1761. // printf("connect login server error : %d\n", RFIFOB(fd,2));
  1762. ShowError("Can not connect to the login-server.\n");
  1763. ShowError("The server communication passwords (default s1/p1) are probably invalid.\n");
  1764. ShowInfo("Also, please make sure your accounts file (default: accounts.txt) has those values present.\n");
  1765. ShowInfo("The communication passwords can be changed in map_athena.conf and char_athena.conf\n");
  1766. exit(1);
  1767. } else {
  1768. ShowStatus("Connected to login-server (connection #%d).\n", fd);
  1769. //Send to login accounts currently connected.
  1770. send_accounts_tologin(-1, gettick(), 0, 0);
  1771. // if no map-server already connected, display a message...
  1772. for(i = 0; i < MAX_MAP_SERVERS; i++)
  1773. if (server_fd[i] >= 0 && server[i].map[0]) // if map-server online and at least 1 map
  1774. break;
  1775. if (i == MAX_MAP_SERVERS)
  1776. ShowStatus("Awaiting maps from map-server.\n");
  1777. }
  1778. RFIFOSKIP(fd,3);
  1779. break;
  1780. case 0x2713:
  1781. if (RFIFOREST(fd) < 51)
  1782. return 0;
  1783. // printf("parse_tologin 2713 : %d\n", RFIFOB(fd,6));
  1784. for(i = 0; i < fd_max; i++) {
  1785. if (session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == RFIFOL(fd,2)) {
  1786. if (RFIFOB(fd,6) != 0) {
  1787. WFIFOHEAD(i, 3);
  1788. WFIFOW(i,0) = 0x6c;
  1789. WFIFOB(i,2) = 0x42;
  1790. WFIFOSET(i,3);
  1791. } else if (max_connect_user == 0 || count_users() < max_connect_user) {
  1792. // if (max_connect_user == 0)
  1793. // printf("max_connect_user (unlimited) -> accepted.\n");
  1794. // else
  1795. // printf("count_users(): %d < max_connect_user (%d) -> accepted.\n", count_users(), max_connect_user);
  1796. memcpy(sd->email, RFIFOP(fd, 7), 40);
  1797. if (e_mail_check(sd->email) == 0)
  1798. strncpy(sd->email, "a@a.com", 40); // default e-mail
  1799. sd->connect_until_time = (time_t)RFIFOL(fd,47);
  1800. // send characters to player
  1801. mmo_char_send006b(i, sd);
  1802. } else if(isGM(sd->account_id) >= gm_allow_level) {
  1803. sd->connect_until_time = (time_t)RFIFOL(fd,47);
  1804. // send characters to player
  1805. mmo_char_send006b(i, sd);
  1806. } else {
  1807. // refuse connection: too much online players
  1808. // printf("count_users(): %d < max_connect_use (%d) -> fail...\n", count_users(), max_connect_user);
  1809. WFIFOHEAD(fd, 3);
  1810. WFIFOW(i,0) = 0x6c;
  1811. WFIFOW(i,2) = 0;
  1812. WFIFOSET(i,3);
  1813. }
  1814. break;
  1815. }
  1816. }
  1817. RFIFOSKIP(fd,51);
  1818. break;
  1819. // Receiving of an e-mail/time limit from the login-server (answer of a request because a player comes back from map-server to char-server) by [Yor]
  1820. case 0x2717:
  1821. if (RFIFOREST(fd) < 50)
  1822. return 0;
  1823. for(i = 0; i < fd_max; i++) {
  1824. if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) {
  1825. if (sd->account_id == RFIFOL(fd,2)) {
  1826. memcpy(sd->email, RFIFOP(fd,6), 40);
  1827. if (e_mail_check(sd->email) == 0)
  1828. strncpy(sd->email, "a@a.com", 40); // default e-mail
  1829. sd->connect_until_time = (time_t)RFIFOL(fd,46);
  1830. break;
  1831. }
  1832. }
  1833. }
  1834. RFIFOSKIP(fd,50);
  1835. break;
  1836. // login-server alive packet
  1837. case 0x2718:
  1838. if (RFIFOREST(fd) < 2)
  1839. return 0;
  1840. RFIFOSKIP(fd,2);
  1841. break;
  1842. // Receiving authentification from Freya-type login server (to avoid char->login->char)
  1843. case 0x2719:
  1844. if (RFIFOREST(fd) < 18)
  1845. return 0;
  1846. // to conserv a maximum of authentification, search if account is already authentified and replace it
  1847. // that will reduce multiple connection too
  1848. for(i = 0; i < AUTH_FIFO_SIZE; i++)
  1849. if (auth_fifo[i].account_id == RFIFOL(fd,2))
  1850. break;
  1851. // if not found, use next value
  1852. if (i == AUTH_FIFO_SIZE) {
  1853. if (auth_fifo_pos >= AUTH_FIFO_SIZE)
  1854. auth_fifo_pos = 0;
  1855. i = auth_fifo_pos;
  1856. auth_fifo_pos++;
  1857. }
  1858. auth_fifo[i].account_id = RFIFOL(fd,2);
  1859. auth_fifo[i].char_id = 0;
  1860. auth_fifo[i].login_id1 = RFIFOL(fd,6);
  1861. auth_fifo[i].login_id2 = RFIFOL(fd,10);
  1862. auth_fifo[i].delflag = 2; // 0: auth_fifo canceled/void, 2: auth_fifo received from login/map server in memory, 1: connection authentified
  1863. auth_fifo[i].char_pos = 0;
  1864. auth_fifo[i].connect_until_time = 0; // unlimited/unknown time by default (not display in map-server)
  1865. auth_fifo[i].ip = RFIFOL(fd,14);
  1866. RFIFOSKIP(fd,18);
  1867. break;
  1868. case 0x2721: // gm reply
  1869. if (RFIFOREST(fd) < 10)
  1870. return 0;
  1871. {
  1872. unsigned char buf[10];
  1873. WBUFW(buf,0) = 0x2b0b;
  1874. WBUFL(buf,2) = RFIFOL(fd,2); // account
  1875. WBUFL(buf,6) = RFIFOL(fd,6); // GM level
  1876. mapif_sendall(buf,10);
  1877. // printf("parse_tologin: To become GM answer: char -> map.\n");
  1878. }
  1879. RFIFOSKIP(fd,10);
  1880. break;
  1881. case 0x2723: // changesex reply (modified by [Yor])
  1882. if (RFIFOREST(fd) < 7)
  1883. return 0;
  1884. {
  1885. int acc, sex, i, j;
  1886. unsigned char buf[7];
  1887. acc = RFIFOL(fd,2);
  1888. sex = RFIFOB(fd,6);
  1889. RFIFOSKIP(fd, 7);
  1890. if (acc > 0) {
  1891. for(i = 0; i < AUTH_FIFO_SIZE; i++) {
  1892. if (auth_fifo[i].account_id == acc)
  1893. auth_fifo[i].sex = sex;
  1894. }
  1895. for (i = 0; i < char_num; i++) {
  1896. if (char_dat[i].status.account_id == acc) {
  1897. int jobclass = char_dat[i].status.class_;
  1898. char_dat[i].status.sex = sex;
  1899. if (jobclass == JOB_BARD || jobclass == JOB_DANCER ||
  1900. jobclass == JOB_CLOWN || jobclass == JOB_GYPSY ||
  1901. jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) {
  1902. // job modification
  1903. if (jobclass == JOB_BARD || jobclass == JOB_DANCER) {
  1904. char_dat[i].status.class_ = (sex) ? JOB_BARD : JOB_DANCER;
  1905. } else if (jobclass == JOB_CLOWN || jobclass == JOB_GYPSY) {
  1906. char_dat[i].status.class_ = (sex) ? JOB_CLOWN : JOB_GYPSY;
  1907. } else if (jobclass == JOB_BABY_BARD || jobclass == JOB_BABY_DANCER) {
  1908. char_dat[i].status.class_ = (sex) ? JOB_BABY_BARD : JOB_BABY_DANCER;
  1909. }
  1910. // remove specifical skills of classes 19, 4020 and 4042
  1911. for(j = 315; j <= 322; j++) {
  1912. if (char_dat[i].status.skill[j].id > 0 && !char_dat[i].status.skill[j].flag) {
  1913. if (char_dat[i].status.skill_point > USHRT_MAX - char_dat[i].status.skill[j].lv)
  1914. char_dat[i].status.skill_point = USHRT_MAX;
  1915. else
  1916. char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv;
  1917. char_dat[i].status.skill[j].id = 0;
  1918. char_dat[i].status.skill[j].lv = 0;
  1919. }
  1920. }
  1921. // remove specifical skills of classes 20, 4021 and 4043
  1922. for(j = 323; j <= 330; j++) {
  1923. if (char_dat[i].status.skill[j].id > 0 && !char_dat[i].status.skill[j].flag) {
  1924. if (char_dat[i].status.skill_point > USHRT_MAX - char_dat[i].status.skill[j].lv)
  1925. char_dat[i].status.skill_point = USHRT_MAX;
  1926. else
  1927. char_dat[i].status.skill_point += char_dat[i].status.skill[j].lv;
  1928. char_dat[i].status.skill[j].id = 0;
  1929. char_dat[i].status.skill[j].lv = 0;
  1930. }
  1931. }
  1932. }
  1933. // to avoid any problem with equipment and invalid sex, equipment is unequiped.
  1934. for (j = 0; j < MAX_INVENTORY; j++) {
  1935. if (char_dat[i].status.inventory[j].nameid && char_dat[i].status.inventory[j].equip)
  1936. char_dat[i].status.inventory[j].equip = 0;
  1937. }
  1938. char_dat[i].status.weapon = 0;
  1939. char_dat[i].status.shield = 0;
  1940. char_dat[i].status.head_top = 0;
  1941. char_dat[i].status.head_mid = 0;
  1942. char_dat[i].status.head_bottom = 0;
  1943. if (char_dat[i].status.guild_id) //If there is a guild, update the guild_member data [Skotlex]
  1944. inter_guild_sex_changed(char_dat[i].status.guild_id, acc, char_dat[i].status.char_id, sex);
  1945. }
  1946. }
  1947. // disconnect player if online on char-server
  1948. disconnect_player(acc);
  1949. }
  1950. WBUFW(buf,0) = 0x2b0d;
  1951. WBUFL(buf,2) = acc;
  1952. WBUFB(buf,6) = sex;
  1953. mapif_sendall(buf, 7);
  1954. }
  1955. break;
  1956. case 0x2726: // Request to send a broadcast message (no answer)
  1957. if (RFIFOREST(fd) < 8 || RFIFOREST(fd) < (8 + RFIFOL(fd,4)))
  1958. return 0;
  1959. if (RFIFOL(fd,4) < 1)
  1960. char_log("Receiving a message for broadcast, but message is void." RETCODE);
  1961. else {
  1962. // at least 1 map-server
  1963. for(i = 0; i < MAX_MAP_SERVERS; i++)
  1964. if (server_fd[i] >= 0)
  1965. break;
  1966. if (i == MAX_MAP_SERVERS)
  1967. char_log("'ladmin': Receiving a message for broadcast, but no map-server is online." RETCODE);
  1968. else {
  1969. unsigned char buf[128];
  1970. char message[4096]; // +1 to add a null terminated if not exist in the packet
  1971. int lp;
  1972. char *p;
  1973. memset(message, '\0', sizeof(message));
  1974. memcpy(message, RFIFOP(fd,8), RFIFOL(fd,4));
  1975. message[sizeof(message)-1] = '\0';
  1976. remove_control_chars((unsigned char *)message);
  1977. // remove all first spaces
  1978. p = message;
  1979. while(p[0] == ' ')
  1980. p++;
  1981. // if message is only composed of spaces
  1982. if (p[0] == '\0')
  1983. char_log("Receiving a message for broadcast, but message is only a lot of spaces." RETCODE);
  1984. // else send message to all map-servers
  1985. else {
  1986. if (RFIFOW(fd,2) == 0) {
  1987. char_log("'ladmin': Receiving a message for broadcast (message (in yellow): %s)" RETCODE,
  1988. message);
  1989. lp = 4;
  1990. } else {
  1991. char_log("'ladmin': Receiving a message for broadcast (message (in blue): %s)" RETCODE,
  1992. message);
  1993. lp = 8;
  1994. }
  1995. // split message to max 80 char
  1996. while(p[0] != '\0') { // if not finish
  1997. if (p[0] == ' ') // jump if first char is a space
  1998. p++;
  1999. else {
  2000. char split[80];
  2001. char* last_space;
  2002. sscanf(p, "%79[^\t]", split); // max 79 char, any char (\t is control char and control char was removed before)
  2003. split[sizeof(split)-1] = '\0'; // last char always \0
  2004. if ((last_space = strrchr(split, ' ')) != NULL) { // searching space from end of the string
  2005. last_space[0] = '\0'; // replace it by NULL to have correct length of split
  2006. p++; // to jump the new NULL
  2007. }
  2008. p += strlen(split);
  2009. // send broadcast to all map-servers
  2010. WBUFW(buf,0) = 0x3800;
  2011. WBUFW(buf,2) = lp + strlen(split) + 1;
  2012. WBUFL(buf,4) = 0x65756c62; // only write if in blue (lp = 8)
  2013. memcpy(WBUFP(buf,lp), split, strlen(split) + 1);
  2014. mapif_sendall(buf, WBUFW(buf,2));
  2015. }
  2016. }
  2017. }
  2018. }
  2019. }
  2020. RFIFOSKIP(fd,8 + RFIFOL(fd,4));
  2021. break;
  2022. // account_reg2変更通知
  2023. case 0x2729:
  2024. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2025. return 0;
  2026. { //Receive account_reg2 registry, forward to map servers.
  2027. unsigned char buf[ACCOUNT_REG2_NUM*(256+32+2)+16];
  2028. memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
  2029. // WBUFW(buf,0) = 0x2b11;
  2030. WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
  2031. mapif_sendall(buf, WBUFW(buf,2));
  2032. RFIFOSKIP(fd, RFIFOW(fd,2));
  2033. }
  2034. break;
  2035. // Account deletion notification (from login-server)
  2036. case 0x2730:
  2037. if (RFIFOREST(fd) < 6)
  2038. return 0;
  2039. // Deletion of all characters of the account
  2040. for(i = 0; i < char_num; i++) {
  2041. if (char_dat[i].status.account_id == RFIFOL(fd,2)) {
  2042. char_delete(&char_dat[i].status);
  2043. if (i < char_num - 1) {
  2044. memcpy(&char_dat[i], &char_dat[char_num-1], sizeof(struct character_data));
  2045. // if moved character owns to deleted account, check again it's character
  2046. if (char_dat[i].status.account_id == RFIFOL(fd,2)) {
  2047. i--;
  2048. // Correct moved character reference in the character's owner by [Yor]
  2049. } else {
  2050. int j, k;
  2051. struct char_session_data *sd2;
  2052. for (j = 0; j < fd_max; j++) {
  2053. if (session[j] && (sd2 = (struct char_session_data*)session[j]->session_data) &&
  2054. sd2->account_id == char_dat[char_num-1].status.account_id) {
  2055. for (k = 0; k < 9; k++) {
  2056. if (sd2->found_char[k] == char_num-1) {
  2057. sd2->found_char[k] = i;
  2058. break;
  2059. }
  2060. }
  2061. break;
  2062. }
  2063. }
  2064. }
  2065. }
  2066. char_num--;
  2067. }
  2068. }
  2069. // Deletion of the storage
  2070. inter_storage_delete(RFIFOL(fd,2));
  2071. // send to all map-servers to disconnect the player
  2072. {
  2073. unsigned char buf[6];
  2074. WBUFW(buf,0) = 0x2b13;
  2075. WBUFL(buf,2) = RFIFOL(fd,2);
  2076. mapif_sendall(buf, 6);
  2077. }
  2078. // disconnect player if online on char-server
  2079. disconnect_player(RFIFOL(fd,2));
  2080. RFIFOSKIP(fd,6);
  2081. break;
  2082. // State change of account/ban notification (from login-server) by [Yor]
  2083. case 0x2731:
  2084. if (RFIFOREST(fd) < 11)
  2085. return 0;
  2086. // send to all map-servers to disconnect the player
  2087. {
  2088. unsigned char buf[11];
  2089. WBUFW(buf,0) = 0x2b14;
  2090. WBUFL(buf,2) = RFIFOL(fd,2);
  2091. WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
  2092. WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
  2093. mapif_sendall(buf, 11);
  2094. }
  2095. // disconnect player if online on char-server
  2096. disconnect_player(RFIFOL(fd,2));
  2097. RFIFOSKIP(fd,11);
  2098. break;
  2099. // Receiving GM acounts info from login-server (by [Yor])
  2100. case 0x2732:
  2101. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2102. return 0;
  2103. {
  2104. unsigned char buf[32000];
  2105. if (gm_account != NULL)
  2106. aFree(gm_account);
  2107. gm_account = (struct gm_account*)aCalloc(sizeof(struct gm_account) * ((RFIFOW(fd,2) - 4) / 5), 1);
  2108. GM_num = 0;
  2109. for (i = 4; i < RFIFOW(fd,2); i = i + 5) {
  2110. gm_account[GM_num].account_id = RFIFOL(fd,i);
  2111. gm_account[GM_num].level = (int)RFIFOB(fd,i+4);
  2112. //printf("GM account: %d -> level %d\n", gm_account[GM_num].account_id, gm_account[GM_num].level);
  2113. GM_num++;
  2114. }
  2115. ShowStatus("From login-server: receiving information of %d GM accounts.\n", GM_num);
  2116. char_log("From login-server: receiving information of %d GM accounts." RETCODE, GM_num);
  2117. create_online_files(); // update online players files (perhaps some online players change of GM level)
  2118. // send new gm acccounts level to map-servers
  2119. memcpy(buf, RFIFOP(fd,0), RFIFOW(fd,2));
  2120. WBUFW(buf,0) = 0x2b15;
  2121. mapif_sendall(buf, RFIFOW(fd,2));
  2122. }
  2123. RFIFOSKIP(fd,RFIFOW(fd,2));
  2124. break;
  2125. // Receive GM accounts [Freya login server packet by Yor]
  2126. case 0x2733:
  2127. // add test here to remember that the login-server is Freya-type
  2128. // sprintf (login_server_type, "Freya");
  2129. if (RFIFOREST(fd) < 7)
  2130. return 0;
  2131. {
  2132. unsigned char buf[32000];
  2133. int new_level = 0;
  2134. for(i = 0; i < GM_num; i++)
  2135. if (gm_account[i].account_id == RFIFOL(fd,2)) {
  2136. if (gm_account[i].level != (int)RFIFOB(fd,6)) {
  2137. gm_account[i].level = (int)RFIFOB(fd,6);
  2138. new_level = 1;
  2139. }
  2140. break;
  2141. }
  2142. // if not found, add it
  2143. if (i == GM_num) {
  2144. // limited to 4000, because we send information to char-servers (more than 4000 GM accounts???)
  2145. // int (id) + int (level) = 8 bytes * 4000 = 32k (limit of packets in windows)
  2146. if (((int)RFIFOB(fd,6)) > 0 && GM_num < 4000) {
  2147. if (GM_num == 0) {
  2148. gm_account = (struct gm_account*)aMalloc(sizeof(struct gm_account));
  2149. } else {
  2150. gm_account = (struct gm_account*)aRealloc(gm_account, sizeof(struct gm_account) * (GM_num + 1));
  2151. }
  2152. gm_account[GM_num].account_id = RFIFOL(fd,2);
  2153. gm_account[GM_num].level = (int)RFIFOB(fd,6);
  2154. new_level = 1;
  2155. GM_num++;
  2156. if (GM_num >= 4000) {
  2157. ShowWarning("4000 GM accounts found. Next GM accounts are not readed.\n");
  2158. char_log("***WARNING: 4000 GM accounts found. Next GM accounts are not readed." RETCODE);
  2159. }
  2160. }
  2161. }
  2162. if (new_level == 1) {
  2163. int len;
  2164. ShowStatus("From login-server: receiving GM account information (%d: level %d).\n", RFIFOL(fd,2), (int)RFIFOB(fd,6));
  2165. char_log("From login-server: receiving a GM account information (%d: level %d)." RETCODE, RFIFOL(fd,2), (int)RFIFOB(fd,6));
  2166. //create_online_files(); // not change online file for only 1 player (in next timer, that will be done
  2167. // send gm acccounts level to map-servers
  2168. len = 4;
  2169. WBUFW(buf,0) = 0x2b15;
  2170. for(i = 0; i < GM_num; i++) {
  2171. WBUFL(buf, len) = gm_account[i].account_id;
  2172. WBUFB(buf, len+4) = (unsigned char)gm_account[i].level;
  2173. len += 5;
  2174. }
  2175. WBUFW(buf, 2) = len;
  2176. mapif_sendall(buf, len);
  2177. }
  2178. }
  2179. RFIFOSKIP(fd,7);
  2180. break;
  2181. //Login server request to kick a character out. [Skotlex]
  2182. case 0x2734:
  2183. if (RFIFOREST(fd) < 6)
  2184. return 0;
  2185. {
  2186. struct online_char_data* character;
  2187. int aid = RFIFOL(fd,2);
  2188. if ((character = idb_get(online_char_db, aid)) != NULL)
  2189. { //Kick out this player.
  2190. if (character->server > -1)
  2191. { //Kick it from the map server it is on.
  2192. mapif_disconnectplayer(server_fd[character->server], character->account_id, character->char_id, 2);
  2193. if (!character->waiting_disconnect)
  2194. add_timer(gettick()+15000, chardb_waiting_disconnect, character->account_id, 0);
  2195. character->waiting_disconnect = 1;
  2196. } else { //Manual kick from char server.
  2197. struct char_session_data *tsd;
  2198. int i;
  2199. for(i = 0; i < fd_max; i++) {
  2200. if (session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid)
  2201. {
  2202. WFIFOHEAD(fd, 3);
  2203. WFIFOW(i,0) = 0x81;
  2204. WFIFOB(i,2) = 2;
  2205. WFIFOSET(i,3);
  2206. break;
  2207. }
  2208. }
  2209. if (i == fd_max) //Shouldn't happen, but just in case.
  2210. set_char_offline(99, aid);
  2211. }
  2212. }
  2213. RFIFOSKIP(fd,6);
  2214. }
  2215. break;
  2216. case 0x2735:
  2217. {
  2218. unsigned char buf[2];
  2219. in_addr_t new_ip = 0;
  2220. RFIFOSKIP(fd,2);
  2221. WBUFW(buf,0) = 0x2b1e;
  2222. mapif_sendall(buf, 2);
  2223. new_ip = resolve_hostbyname(login_ip_str, NULL, NULL);
  2224. if (new_ip && new_ip != login_ip)
  2225. login_ip = new_ip; //Update login up.
  2226. new_ip = resolve_hostbyname(char_ip_str, NULL, NULL);
  2227. if (new_ip && new_ip != char_ip)
  2228. { //Update ip.
  2229. char_ip = new_ip;
  2230. ShowInfo("Updating IP for [%s].\n",char_ip_str);
  2231. WFIFOW(fd,0) = 0x2736;
  2232. WFIFOL(fd,2) = char_ip;
  2233. WFIFOSET(fd,6);
  2234. }
  2235. break;
  2236. }
  2237. default:
  2238. ShowWarning("Unknown packet 0x%04x received from login-server, disconnecting.\n", RFIFOW(fd,0));
  2239. session[fd]->eof = 1;
  2240. return 0;
  2241. }
  2242. }
  2243. RFIFOFLUSH(fd);
  2244. return 0;
  2245. }
  2246. int request_accreg2(int account_id, int char_id) {
  2247. if (login_fd > 0) {
  2248. WFIFOW(login_fd, 0) = 0x272e;
  2249. WFIFOL(login_fd, 2) = account_id;
  2250. WFIFOL(login_fd, 6) = char_id;
  2251. WFIFOSET(login_fd, 10);
  2252. return 1;
  2253. }
  2254. return 0;
  2255. }
  2256. //Send packet forward to login-server for account saving
  2257. int save_accreg2(unsigned char* buf, int len) {
  2258. if (login_fd > 0) {
  2259. WFIFOHEAD(login_fd, len+4);
  2260. memcpy(WFIFOP(login_fd,4), buf, len);
  2261. WFIFOW(login_fd,0) = 0x2728;
  2262. WFIFOW(login_fd,2) = len+4;
  2263. WFIFOSET(login_fd,len+4);
  2264. return 1;
  2265. }
  2266. return 0;
  2267. }
  2268. //Receive Registry information for a character.
  2269. int char_parse_Registry(int account_id, int char_id, unsigned char *buf, int buf_len) {
  2270. int i,j,p,len;
  2271. for (i = 0; i < char_num; i++) {
  2272. if (char_dat[i].status.account_id == account_id && char_dat[i].status.char_id == char_id)
  2273. break;
  2274. }
  2275. if(i >= char_num) //Character not found?
  2276. return 1;
  2277. for(j=0,p=0;j<GLOBAL_REG_NUM && p<buf_len;j++){
  2278. sscanf(WBUFP(buf,p), "%31c%n",char_dat[i].global[j].str,&len);
  2279. char_dat[i].global[j].str[len]='\0';
  2280. p +=len+1; //+1 to skip the '\0' between strings.
  2281. sscanf(WBUFP(buf,p), "%255c%n",char_dat[i].global[j].value,&len);
  2282. char_dat[i].global[j].value[len]='\0';
  2283. p +=len+1;
  2284. }
  2285. char_dat[i].global_num = j;
  2286. return 0;
  2287. }
  2288. //Reply to map server with acc reg values.
  2289. int char_account_reg_reply(int fd,int account_id,int char_id) {
  2290. int i,j,p;
  2291. WFIFOHEAD(login_fd, GLOBAL_REG_NUM*288 + 13);
  2292. WFIFOW(fd,0)=0x3804;
  2293. WFIFOL(fd,4)=account_id;
  2294. WFIFOL(fd,8)=char_id;
  2295. WFIFOB(fd,12)=3; //Type 3: char acc reg.
  2296. for (i = 0;i < char_num; i++) {
  2297. if (char_dat[i].status.account_id == account_id && char_dat[i].status.char_id == char_id)
  2298. break;
  2299. }
  2300. if(i >= char_num){ //Character not found? Sent empty packet.
  2301. WFIFOW(fd,2)=13;
  2302. }else{
  2303. for (p=13,j = 0; j < char_dat[i].global_num; j++) {
  2304. if (char_dat[i].global[j].str[0]) {
  2305. p+= sprintf(WFIFOP(fd,p), "%s", char_dat[i].global[j].str)+1; //We add 1 to consider the '\0' in place.
  2306. p+= sprintf(WFIFOP(fd,p), "%s", char_dat[i].global[j].value)+1;
  2307. }
  2308. }
  2309. WFIFOW(fd,2)=p;
  2310. }
  2311. WFIFOSET(fd,WFIFOW(fd,2));
  2312. return 0;
  2313. }
  2314. void char_read_fame_list(void)
  2315. {
  2316. int i, j, k;
  2317. struct fame_list fame_item;
  2318. CREATE_BUFFER(id, int, char_num);
  2319. for(i = 0; i < char_num; i++) {
  2320. id[i] = i;
  2321. for(j = 0; j < i; j++) {
  2322. if (char_dat[i].status.fame > char_dat[id[j]].status.fame) {
  2323. for(k = i; k > j; k--)
  2324. id[k] = id[k-1];
  2325. id[j] = i; // id[i]
  2326. break;
  2327. }
  2328. }
  2329. }
  2330. // Empty ranking lists
  2331. memset(smith_fame_list, 0, sizeof(smith_fame_list));
  2332. memset(chemist_fame_list, 0, sizeof(chemist_fame_list));
  2333. memset(taekwon_fame_list, 0, sizeof(taekwon_fame_list));
  2334. // Build Blacksmith ranking list
  2335. for (i = 0, j = 0; i < char_num && j < fame_list_size_smith; i++) {
  2336. if (char_dat[id[i]].status.fame && (
  2337. char_dat[id[i]].status.class_ == JOB_BLACKSMITH ||
  2338. char_dat[id[i]].status.class_ == JOB_WHITESMITH ||
  2339. char_dat[id[i]].status.class_ == JOB_BABY_BLACKSMITH))
  2340. {
  2341. fame_item.id = char_dat[id[i]].status.char_id;
  2342. fame_item.fame = char_dat[id[i]].status.fame;
  2343. strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
  2344. memcpy(&smith_fame_list[j],&fame_item,sizeof(struct fame_list));
  2345. j++;
  2346. }
  2347. }
  2348. // Build Alchemist ranking list
  2349. for (i = 0, j = 0; i < char_num && j < fame_list_size_chemist; i++) {
  2350. if (char_dat[id[i]].status.fame && (
  2351. char_dat[id[i]].status.class_ == JOB_ALCHEMIST ||
  2352. char_dat[id[i]].status.class_ == JOB_CREATOR ||
  2353. char_dat[id[i]].status.class_ == JOB_BABY_ALCHEMIST))
  2354. {
  2355. fame_item.id = char_dat[id[i]].status.char_id;
  2356. fame_item.fame = char_dat[id[i]].status.fame;
  2357. strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
  2358. memcpy(&chemist_fame_list[j],&fame_item,sizeof(struct fame_list));
  2359. j++;
  2360. }
  2361. }
  2362. // Build Taekwon ranking list
  2363. for (i = 0, j = 0; i < char_num && j < fame_list_size_taekwon; i++) {
  2364. if (char_dat[id[i]].status.fame &&
  2365. char_dat[id[i]].status.class_ == JOB_TAEKWON)
  2366. {
  2367. fame_item.id = char_dat[id[i]].status.char_id;
  2368. fame_item.fame = char_dat[id[i]].status.fame;
  2369. strncpy(fame_item.name, char_dat[id[i]].status.name, NAME_LENGTH);
  2370. memcpy(&taekwon_fame_list[j],&fame_item,sizeof(struct fame_list));
  2371. j++;
  2372. }
  2373. }
  2374. DELETE_BUFFER(id);
  2375. }
  2376. // Send map-servers the fame ranking lists
  2377. int char_send_fame_list(int fd) {
  2378. int i, len = 8;
  2379. unsigned char buf[32000];
  2380. WBUFW(buf,0) = 0x2b1b;
  2381. for(i = 0; i < fame_list_size_smith && smith_fame_list[i].id; i++) {
  2382. memcpy(WBUFP(buf, len), &smith_fame_list[i], sizeof(struct fame_list));
  2383. len += sizeof(struct fame_list);
  2384. }
  2385. // add blacksmith's block length
  2386. WBUFW(buf, 6) = len;
  2387. for(i = 0; i < fame_list_size_chemist && chemist_fame_list[i].id; i++) {
  2388. memcpy(WBUFP(buf, len), &chemist_fame_list[i], sizeof(struct fame_list));
  2389. len += sizeof(struct fame_list);
  2390. }
  2391. // add alchemist's block length
  2392. WBUFW(buf, 4) = len;
  2393. for(i = 0; i < fame_list_size_taekwon && taekwon_fame_list[i].id; i++) {
  2394. memcpy(WBUFP(buf, len), &taekwon_fame_list[i], sizeof(struct fame_list));
  2395. len += sizeof(struct fame_list);
  2396. }
  2397. // add total packet length
  2398. WBUFW(buf, 2) = len;
  2399. if(fd!=-1)
  2400. mapif_send(fd, buf, len);
  2401. else
  2402. mapif_sendall(buf, len);
  2403. return 0;
  2404. }
  2405. int search_mapserver(unsigned short map, long ip, short port);
  2406. int parse_frommap(int fd) {
  2407. int i, j;
  2408. int id;
  2409. RFIFOHEAD(fd);
  2410. for(id = 0; id < MAX_MAP_SERVERS; id++)
  2411. if (server_fd[id] == fd)
  2412. break;
  2413. if(id==MAX_MAP_SERVERS)
  2414. session[fd]->eof=1;
  2415. if(session[fd]->eof){
  2416. if (id < MAX_MAP_SERVERS) {
  2417. unsigned char buf[16384];
  2418. ShowStatus("Map-server %d has disconnected.\n", id);
  2419. //Notify other map servers that this one is gone. [Skotlex]
  2420. WBUFW(buf,0) = 0x2b20;
  2421. WBUFL(buf,4) = server[id].ip;
  2422. WBUFW(buf,8) = server[id].port;
  2423. j = 0;
  2424. for(i = 0; i < MAX_MAP_PER_SERVER; i++)
  2425. if (server[id].map[i])
  2426. WBUFW(buf,10+(j++)*4) = server[id].map[i];
  2427. if (j > 0) {
  2428. WBUFW(buf,2) = j * 4 + 10;
  2429. mapif_sendallwos(fd, buf, WBUFW(buf,2));
  2430. }
  2431. server_fd[id] = -1;
  2432. online_char_db->foreach(online_char_db,char_db_setoffline,i); //Tag relevant chars as 'in disconnected' server.
  2433. }
  2434. do_close(fd);
  2435. create_online_files();
  2436. return 0;
  2437. }
  2438. while(RFIFOREST(fd) >= 2 && !session[fd]->eof) {
  2439. //ShowDebug("Received packet 0x%4x (%d bytes) from map-server (connection %d)\n", RFIFOW(fd, 0), RFIFOREST(fd), fd);
  2440. switch(RFIFOW(fd,0)) {
  2441. // map-server alive packet
  2442. case 0x2718:
  2443. if (RFIFOREST(fd) < 2)
  2444. return 0;
  2445. RFIFOSKIP(fd,2);
  2446. break;
  2447. // request from map-server to reload GM accounts. Transmission to login-server (by Yor)
  2448. case 0x2af7:
  2449. if (login_fd > 0) { // don't send request if no login-server
  2450. WFIFOHEAD(login_fd, 2);
  2451. WFIFOW(login_fd,0) = 0x2709;
  2452. WFIFOSET(login_fd, 2);
  2453. }
  2454. RFIFOSKIP(fd,2);
  2455. break;
  2456. // Receiving map names list from the map-server
  2457. case 0x2afa:
  2458. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2459. return 0;
  2460. memset(server[id].map, 0, sizeof(server[id].map));
  2461. j = 0;
  2462. for(i = 4; i < RFIFOW(fd,2); i += 4) {
  2463. server[id].map[j] = RFIFOW(fd,i);
  2464. j++;
  2465. }
  2466. {
  2467. unsigned char *p = (unsigned char *)&server[id].ip;
  2468. ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n",
  2469. id, j, p[0], p[1], p[2], p[3], server[id].port);
  2470. ShowStatus("Map-server %d loading complete.\n", id);
  2471. char_log("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d. Map-server %d loading complete." RETCODE,
  2472. id, j, p[0], p[1], p[2], p[3], server[id].port, id);
  2473. if (max_account_id != DEFAULT_MAX_ACCOUNT_ID || max_char_id != DEFAULT_MAX_CHAR_ID)
  2474. mapif_send_maxid(max_account_id, max_char_id); //Send the current max ids to the server to keep in sync [Skotlex]
  2475. }
  2476. WFIFOHEAD(fd, 3 + NAME_LENGTH);
  2477. WFIFOW(fd,0) = 0x2afb;
  2478. WFIFOB(fd,2) = 0;
  2479. memcpy(WFIFOP(fd,3), wisp_server_name, NAME_LENGTH); // name for wisp to player
  2480. WFIFOSET(fd,3+NAME_LENGTH);
  2481. //WFIFOSET(fd,27);
  2482. char_send_fame_list(fd); //Send fame list.
  2483. {
  2484. unsigned char buf[16384];
  2485. int x;
  2486. if (j == 0) {
  2487. ShowWarning("Map-Server %d have NO map.\n", id);
  2488. char_log("WARNING: Map-Server %d have NO map." RETCODE, id);
  2489. // Transmitting maps information to the other map-servers
  2490. } else {
  2491. WBUFW(buf,0) = 0x2b04;
  2492. WBUFW(buf,2) = j * 4 + 10;
  2493. WBUFL(buf,4) = server[id].ip;
  2494. WBUFW(buf,8) = server[id].port;
  2495. memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4);
  2496. mapif_sendallwos(fd, buf, WBUFW(buf,2));
  2497. }
  2498. // Transmitting the maps of the other map-servers to the new map-server
  2499. for(x = 0; x < MAX_MAP_SERVERS; x++) {
  2500. if (server_fd[x] >= 0 && x != id) {
  2501. WFIFOW(fd,0) = 0x2b04;
  2502. WFIFOL(fd,4) = server[x].ip;
  2503. WFIFOW(fd,8) = server[x].port;
  2504. j = 0;
  2505. for(i = 0; i < MAX_MAP_PER_SERVER; i++)
  2506. if (server[x].map[i])
  2507. WFIFOW(fd,10+(j++)*4) = server[x].map[i];
  2508. if (j > 0) {
  2509. WFIFOW(fd,2) = j * 4 + 10;
  2510. WFIFOSET(fd,WFIFOW(fd,2));
  2511. }
  2512. }
  2513. }
  2514. }
  2515. RFIFOSKIP(fd,RFIFOW(fd,2));
  2516. break;
  2517. //Packet command is now used for sc_data request. [Skotlex]
  2518. case 0x2afc:
  2519. if (RFIFOREST(fd) < 10)
  2520. return 0;
  2521. {
  2522. #ifdef ENABLE_SC_SAVING
  2523. int aid, cid;
  2524. struct scdata *data;
  2525. aid = RFIFOL(fd,2);
  2526. cid = RFIFOL(fd,6);
  2527. #endif
  2528. RFIFOSKIP(fd, 10);
  2529. #ifdef ENABLE_SC_SAVING
  2530. data = status_search_scdata(aid, cid);
  2531. if (data->count > 0)
  2532. { //Deliver status change data.
  2533. WFIFOW(fd,0) = 0x2b1d;
  2534. WFIFOW(fd,2) = 14 + data->count*sizeof(struct status_change_data);
  2535. WFIFOL(fd,4) = aid;
  2536. WFIFOL(fd,8) = cid;
  2537. WFIFOW(fd,12) = data->count;
  2538. for (i = 0; i < data->count; i++)
  2539. memcpy(WFIFOP(fd,14+i*sizeof(struct status_change_data)), &data->data[i], sizeof(struct status_change_data));
  2540. WFIFOSET(fd, WFIFOW(fd,2));
  2541. status_delete_scdata(aid, cid); //Data sent, so it needs be discarded now.
  2542. }
  2543. #endif
  2544. break;
  2545. }
  2546. //set MAP user count
  2547. case 0x2afe:
  2548. if (RFIFOREST(fd) < 4)
  2549. return 0;
  2550. if (RFIFOW(fd,2) != server[id].users) {
  2551. server[id].users = RFIFOW(fd,2);
  2552. ShowInfo("User Count: %d (Server: %d)\n", server[id].users, id);
  2553. }
  2554. RFIFOSKIP(fd, 4);
  2555. break;
  2556. //set MAP users
  2557. case 0x2aff:
  2558. if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
  2559. return 0;
  2560. //TODO: When data mismatches memory, update guild/party online/offline states.
  2561. server[id].users = RFIFOW(fd,4);
  2562. // add online players in the list by [Yor], adapted to use dbs by [Skotlex]
  2563. j = 0;
  2564. online_char_db->foreach(online_char_db,char_db_setoffline,id); //Set all chars from this server as 'unknown'
  2565. for(i = 0; i < server[id].users; i++) {
  2566. int aid, cid;
  2567. struct online_char_data* character;
  2568. aid = RFIFOL(fd,6+i*8);
  2569. cid = RFIFOL(fd,6+i*8+4);
  2570. character = idb_ensure(online_char_db, aid, create_online_char_data);
  2571. if (online_check && character->server > -1 && character->server != id)
  2572. {
  2573. ShowNotice("Set map user: Character (%d:%d) marked on map server %d, but map server %d claims to have (%d:%d) online!\n",
  2574. character->account_id, character->char_id, character->server, id, aid, cid);
  2575. mapif_disconnectplayer(server_fd[character->server], character->account_id, character->char_id, 2);
  2576. }
  2577. character->char_id = cid;
  2578. character->server = id;
  2579. }
  2580. if (update_online < time(NULL)) { // Time is done
  2581. update_online = time(NULL) + 8;
  2582. create_online_files(); // only every 8 sec. (normally, 1 server send users every 5 sec.) Don't update every time, because that takes time, but only every 2 connection.
  2583. // it set to 8 sec because is more than 5 (sec) and if we have more than 1 map-server, informations can be received in shifted.
  2584. }
  2585. //If any chars remain in -2, they will be cleaned in the cleanup timer.
  2586. RFIFOSKIP(fd,6+i*8);
  2587. break;
  2588. // キャラデータ保存
  2589. // Recieve character data from map-server
  2590. case 0x2b01:
  2591. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2592. return 0;
  2593. for(i = 0; i < char_num; i++) {
  2594. if (char_dat[i].status.account_id == RFIFOL(fd,4) &&
  2595. char_dat[i].status.char_id == RFIFOL(fd,8))
  2596. break;
  2597. }
  2598. if (i != char_num)
  2599. memcpy(&char_dat[i].status, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
  2600. if (RFIFOB(fd,12))
  2601. { //Flag, set character offline. [Skotlex]
  2602. set_char_offline(RFIFOL(fd,8),RFIFOL(fd,4));
  2603. WFIFOW(fd, 0) = 0x2b21; //Save ack only needed on final save.
  2604. WFIFOL(fd, 2) = RFIFOL(fd,4);
  2605. WFIFOL(fd, 6) = RFIFOL(fd,8);
  2606. WFIFOSET(fd, 10);
  2607. }
  2608. RFIFOSKIP(fd,RFIFOW(fd,2));
  2609. break;
  2610. // キャラセレ要求
  2611. case 0x2b02:
  2612. if (RFIFOREST(fd) < 18)
  2613. return 0;
  2614. if (auth_fifo_pos >= AUTH_FIFO_SIZE)
  2615. auth_fifo_pos = 0;
  2616. auth_fifo[auth_fifo_pos].account_id = RFIFOL(fd,2);
  2617. auth_fifo[auth_fifo_pos].char_id = 0;
  2618. auth_fifo[auth_fifo_pos].login_id1 = RFIFOL(fd,6);
  2619. auth_fifo[auth_fifo_pos].login_id2 = RFIFOL(fd,10);
  2620. auth_fifo[auth_fifo_pos].delflag = 2;
  2621. auth_fifo[auth_fifo_pos].char_pos = 0;
  2622. auth_fifo[auth_fifo_pos].connect_until_time = 0; // unlimited/unknown time by default (not display in map-server)
  2623. auth_fifo[auth_fifo_pos].ip = RFIFOL(fd,14);
  2624. auth_fifo_pos++;
  2625. WFIFOW(fd,0) = 0x2b03;
  2626. WFIFOL(fd,2) = RFIFOL(fd,2);
  2627. WFIFOB(fd,6) = 0;
  2628. WFIFOSET(fd,7);
  2629. RFIFOSKIP(fd,18);
  2630. break;
  2631. // request "change map server"
  2632. case 0x2b05:
  2633. if (RFIFOREST(fd) < 35)
  2634. return 0;
  2635. {
  2636. unsigned short name;
  2637. int map_id, map_fd = -1;
  2638. struct online_char_data* data;
  2639. struct mmo_charstatus* char_data;
  2640. name = RFIFOW(fd,18);
  2641. map_id = search_mapserver(name, RFIFOL(fd,24), RFIFOW(fd,28)); //Locate mapserver by ip and port.
  2642. if (map_id >= 0)
  2643. map_fd = server_fd[map_id];
  2644. for(i = 0; i < char_num; i++) {
  2645. if (char_dat[i].status.account_id == RFIFOL(fd,2) &&
  2646. char_dat[i].status.char_id == RFIFOL(fd,14))
  2647. break;
  2648. }
  2649. char_data = i< char_num? &char_dat[i].status:NULL;
  2650. //Tell the new map server about this player using Kevin's new auth packet. [Skotlex]
  2651. if (map_fd>=0 && session[map_fd] && char_data)
  2652. { //Send the map server the auth of this player.
  2653. //Update the "last map" as this is where the player must be spawned on the new map server.
  2654. char_data->last_point.map = RFIFOW(fd,18);
  2655. char_data->last_point.x = RFIFOW(fd,20);
  2656. char_data->last_point.y = RFIFOW(fd,22);
  2657. char_data->sex = RFIFOB(fd,30); // Buuyo^
  2658. WFIFOW(map_fd,0) = 0x2afd;
  2659. WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus);
  2660. WFIFOL(map_fd,4) = RFIFOL(fd, 2); //Account ID
  2661. WFIFOL(map_fd,8) = RFIFOL(fd, 6); //Login1
  2662. WFIFOL(map_fd,16) = RFIFOL(fd,10); //Login2
  2663. WFIFOL(map_fd,12) = (unsigned long)0; //TODO: connect_until_time, how do I figure it out right now?
  2664. memcpy(WFIFOP(map_fd,20), char_data, sizeof(struct mmo_charstatus));
  2665. WFIFOSET(map_fd, WFIFOW(map_fd,2));
  2666. data = idb_ensure(online_char_db, RFIFOL(fd, 2), create_online_char_data);
  2667. data->char_id = char_data->char_id;
  2668. data->server = map_id; //Update server where char is.
  2669. //Reply with an ack.
  2670. WFIFOW(fd, 0) = 0x2b06;
  2671. memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  2672. WFIFOSET(fd, 30);
  2673. } else { //Reply with nak
  2674. WFIFOW(fd, 0) = 0x2b06;
  2675. memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 28);
  2676. WFIFOL(fd, 6) = 0; //Set login1 to 0.
  2677. WFIFOSET(fd, 30);
  2678. }
  2679. RFIFOSKIP(fd, 35);
  2680. }
  2681. break;
  2682. // キャラ名検索
  2683. case 0x2b08:
  2684. if (RFIFOREST(fd) < 6)
  2685. return 0;
  2686. for(i = 0; i < char_num; i++) {
  2687. if (char_dat[i].status.char_id == RFIFOL(fd,2))
  2688. break;
  2689. }
  2690. WFIFOW(fd,0) = 0x2b09;
  2691. WFIFOL(fd,2) = RFIFOL(fd,2);
  2692. if (i != char_num)
  2693. memcpy(WFIFOP(fd,6), char_dat[i].status.name, NAME_LENGTH);
  2694. else
  2695. memcpy(WFIFOP(fd,6), unknown_char_name, NAME_LENGTH);
  2696. WFIFOSET(fd,6+NAME_LENGTH);
  2697. RFIFOSKIP(fd,6);
  2698. break;
  2699. // it is a request to become GM
  2700. case 0x2b0a:
  2701. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2702. return 0;
  2703. // printf("parse_frommap: change gm -> login, account: %d, pass: '%s'.\n", RFIFOL(fd,4), RFIFOP(fd,8));
  2704. if (login_fd > 0) { // don't send request if no login-server
  2705. WFIFOW(login_fd,0) = 0x2720;
  2706. memcpy(WFIFOP(login_fd,2), RFIFOP(fd,2), RFIFOW(fd,2)-2);
  2707. WFIFOSET(login_fd, RFIFOW(fd,2));
  2708. } else {
  2709. WFIFOW(fd,0) = 0x2b0b;
  2710. WFIFOL(fd,2) = RFIFOL(fd,4);
  2711. WFIFOL(fd,6) = 0;
  2712. WFIFOSET(fd, 10);
  2713. }
  2714. RFIFOSKIP(fd, RFIFOW(fd,2));
  2715. break;
  2716. // Map server send information to change an email of an account -> login-server
  2717. case 0x2b0c:
  2718. if (RFIFOREST(fd) < 86)
  2719. return 0;
  2720. if (login_fd > 0) { // don't send request if no login-server
  2721. memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0), 86); // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
  2722. WFIFOW(login_fd,0) = 0x2722;
  2723. WFIFOSET(login_fd, 86);
  2724. }
  2725. RFIFOSKIP(fd, 86);
  2726. break;
  2727. // Map server ask char-server about a character name to do some operations (all operations are transmitted to login-server)
  2728. case 0x2b0e:
  2729. if (RFIFOREST(fd) < 44)
  2730. return 0;
  2731. {
  2732. char character_name[NAME_LENGTH];
  2733. int acc = RFIFOL(fd,2); // account_id of who ask (-1 if nobody)
  2734. memcpy(character_name, RFIFOP(fd,6), NAME_LENGTH-1);
  2735. character_name[NAME_LENGTH -1] = '\0';
  2736. // prepare answer
  2737. WFIFOW(fd,0) = 0x2b0f; // answer
  2738. WFIFOL(fd,2) = acc; // who want do operation
  2739. WFIFOW(fd,30) = RFIFOW(fd, 30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban, 5-changesex
  2740. // search character
  2741. i = search_character_index(character_name);
  2742. if (i >= 0) {
  2743. memcpy(WFIFOP(fd,6), search_character_name(i), NAME_LENGTH); // put correct name if found
  2744. WFIFOW(fd,6+NAME_LENGTH) = 0; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2745. //WFIFOW(fd,32) = 0; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2746. switch(RFIFOW(fd, 30)) {
  2747. case 1: // block
  2748. if (acc == -1 || isGM(acc) >= isGM(char_dat[i].status.account_id)) {
  2749. if (login_fd > 0) { // don't send request if no login-server
  2750. WFIFOW(login_fd,0) = 0x2724;
  2751. WFIFOL(login_fd,2) = char_dat[i].status.account_id; // account value
  2752. WFIFOL(login_fd,6) = 5; // status of the account
  2753. WFIFOSET(login_fd, 10);
  2754. // printf("char : status -> login: account %d, status: %d \n", char_dat[i].account_id, 5);
  2755. } else
  2756. WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2757. } else
  2758. WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2759. break;
  2760. case 2: // ban
  2761. if (acc == -1 || isGM(acc) >= isGM(char_dat[i].status.account_id)) {
  2762. if (login_fd > 0) { // don't send request if no login-server
  2763. WFIFOW(login_fd, 0) = 0x2725;
  2764. WFIFOL(login_fd, 2) = char_dat[i].status.account_id; // account value
  2765. WFIFOW(login_fd, 6) = RFIFOW(fd,32); // year
  2766. WFIFOW(login_fd, 8) = RFIFOW(fd,34); // month
  2767. WFIFOW(login_fd,10) = RFIFOW(fd,36); // day
  2768. WFIFOW(login_fd,12) = RFIFOW(fd,38); // hour
  2769. WFIFOW(login_fd,14) = RFIFOW(fd,40); // minute
  2770. WFIFOW(login_fd,16) = RFIFOW(fd,42); // second
  2771. WFIFOSET(login_fd,18);
  2772. // printf("char : status -> login: account %d, ban: %dy %dm %dd %dh %dmn %ds\n",
  2773. // char_dat[i].account_id, (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), (short)RFIFOW(fd,38), (short)RFIFOW(fd,40), (short)RFIFOW(fd,42));
  2774. } else
  2775. WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2776. } else
  2777. WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2778. break;
  2779. case 3: // unblock
  2780. if (acc == -1 || isGM(acc) >= isGM(char_dat[i].status.account_id)) {
  2781. if (login_fd > 0) { // don't send request if no login-server
  2782. WFIFOW(login_fd,0) = 0x2724;
  2783. WFIFOL(login_fd,2) = char_dat[i].status.account_id; // account value
  2784. WFIFOL(login_fd,6) = 0; // status of the account
  2785. WFIFOSET(login_fd, 10);
  2786. // printf("char : status -> login: account %d, status: %d \n", char_dat[i].account_id, 0);
  2787. } else
  2788. WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2789. } else
  2790. WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2791. break;
  2792. case 4: // unban
  2793. if (acc == -1 || isGM(acc) >= isGM(char_dat[i].status.account_id)) {
  2794. if (login_fd > 0) { // don't send request if no login-server
  2795. WFIFOW(login_fd, 0) = 0x272a;
  2796. WFIFOL(login_fd, 2) = char_dat[i].status.account_id; // account value
  2797. WFIFOSET(login_fd, 6);
  2798. // printf("char : status -> login: account %d, unban request\n", char_dat[i].account_id);
  2799. } else
  2800. WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2801. } else
  2802. WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2803. break;
  2804. case 5: // changesex
  2805. if (acc == -1 || isGM(acc) >= isGM(char_dat[i].status.account_id)) {
  2806. if (login_fd > 0) { // don't send request if no login-server
  2807. WFIFOW(login_fd, 0) = 0x2727;
  2808. WFIFOL(login_fd, 2) = char_dat[i].status.account_id; // account value
  2809. WFIFOSET(login_fd, 6);
  2810. // printf("char : status -> login: account %d, change sex request\n", char_dat[i].account_id);
  2811. } else
  2812. WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2813. } else
  2814. WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2815. break;
  2816. }
  2817. } else {
  2818. // character name not found
  2819. memcpy(WFIFOP(fd,6), character_name, NAME_LENGTH);
  2820. WFIFOW(fd,8+NAME_LENGTH) = 1; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2821. //WFIFOW(fd,32) = 1; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2822. }
  2823. // send answer if a player ask, not if the server ask
  2824. if (acc != -1) {
  2825. //WFIFOSET(fd, 34);
  2826. WFIFOSET(fd, 10+NAME_LENGTH);
  2827. }
  2828. RFIFOSKIP(fd, 44);
  2829. break;
  2830. }
  2831. // case 0x2b0f: Not used anymore, available for future use
  2832. // Update and send fame ranking list [DracoRPG]
  2833. case 0x2b10:
  2834. if (RFIFOREST(fd) < 12)
  2835. return 0;
  2836. {
  2837. int cid = RFIFOL(fd, 2);
  2838. int fame = RFIFOL(fd, 6);
  2839. char type = RFIFOB(fd, 10);
  2840. char pos = RFIFOB(fd, 11);
  2841. int size;
  2842. struct fame_list *list = NULL;
  2843. RFIFOSKIP(fd,12);
  2844. switch(type) {
  2845. case 1:
  2846. size = fame_list_size_smith;
  2847. list = smith_fame_list;
  2848. break;
  2849. case 2:
  2850. size = fame_list_size_chemist;
  2851. list = chemist_fame_list;
  2852. break;
  2853. case 3:
  2854. size = fame_list_size_taekwon;
  2855. list = taekwon_fame_list;
  2856. break;
  2857. default:
  2858. size = 0;
  2859. break;
  2860. }
  2861. if(!size)
  2862. break;
  2863. if(pos)
  2864. {
  2865. pos--; //Convert from pos to index.
  2866. if(
  2867. (pos == 0 || fame < list[pos-1].fame) &&
  2868. (pos == size-1 || fame > list[pos+1].fame)
  2869. ) { //No change in order.
  2870. list[(int)pos].fame = fame;
  2871. char_send_fame_list(fd);
  2872. break;
  2873. }
  2874. // If the player's already in the list, remove the entry and shift the following ones 1 step up
  2875. memmove(list+pos, list+pos+1, (size-pos-1) * sizeof(struct fame_list));
  2876. //Clear out last entry.
  2877. list[size-1].id = 0;
  2878. list[size-1].fame = 0;
  2879. }
  2880. // Find the position where the player has to be inserted
  2881. for(i = 0; i < size && fame < list[i].fame; i++);
  2882. // When found someone with less or as much fame, insert just above
  2883. if(i >= size) break;//Out of ranking.
  2884. memmove(list+i+1, list+i, (size-i-1) * sizeof(struct fame_list));
  2885. list[i].id = cid;
  2886. list[i].fame = fame;
  2887. // Look for the player's name
  2888. for(j = 0; j < char_num && char_dat[j].status.char_id != id; j++);
  2889. if(j < char_num)
  2890. strncpy(list[i].name, char_dat[j].status.name, NAME_LENGTH);
  2891. else //Not found??
  2892. strncpy(list[i].name, "Unknown", NAME_LENGTH);
  2893. char_send_fame_list(-1);
  2894. }
  2895. break;
  2896. // Recieve rates [Wizputer]
  2897. case 0x2b16:
  2898. if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,8))
  2899. return 0;
  2900. // Txt doesn't need this packet, so just skip it
  2901. RFIFOSKIP(fd,RFIFOW(fd,8));
  2902. break;
  2903. // Character disconnected set online 0 [Wizputer]
  2904. case 0x2b17:
  2905. if (RFIFOREST(fd) < 6)
  2906. return 0;
  2907. set_char_offline(RFIFOL(fd,2),RFIFOL(fd,6));
  2908. RFIFOSKIP(fd,10);
  2909. break;
  2910. // Reset all chars to offline [Wizputer]
  2911. case 0x2b18:
  2912. set_all_offline(id);
  2913. RFIFOSKIP(fd,2);
  2914. break;
  2915. // Character set online [Wizputer]
  2916. case 0x2b19:
  2917. if (RFIFOREST(fd) < 6)
  2918. return 0;
  2919. set_char_online(id, RFIFOL(fd,2),RFIFOL(fd,6));
  2920. RFIFOSKIP(fd,10);
  2921. break;
  2922. // Build and send fame ranking lists [DracoRPG]
  2923. case 0x2b1a:
  2924. if (RFIFOREST(fd) < 2)
  2925. return 0;
  2926. char_read_fame_list();
  2927. char_send_fame_list(-1);
  2928. RFIFOSKIP(fd,2);
  2929. break;
  2930. //Request to save status change data. [Skotlex]
  2931. case 0x2b1c:
  2932. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2933. return 0;
  2934. {
  2935. #ifdef ENABLE_SC_SAVING
  2936. int count, aid, cid;
  2937. struct scdata *data;
  2938. aid = RFIFOL(fd, 4);
  2939. cid = RFIFOL(fd, 8);
  2940. count = RFIFOW(fd, 12);
  2941. data = status_search_scdata(aid, cid);
  2942. if (data->count != count)
  2943. {
  2944. data->count = count;
  2945. data->data = aRealloc(data->data, count*sizeof(struct status_change_data));
  2946. }
  2947. for (i = 0; i < count; i++)
  2948. memcpy (&data->data[i], RFIFOP(fd, 14+i*sizeof(struct status_change_data)), sizeof(struct status_change_data));
  2949. #endif
  2950. RFIFOSKIP(fd, RFIFOW(fd, 2));
  2951. break;
  2952. }
  2953. case 0x2736:
  2954. if (RFIFOREST(fd) < 6) return 0;
  2955. ShowInfo("Updated IP address of Server #%d to %d.%d.%d.%d.\n",id,
  2956. (int)RFIFOB(fd,2),(int)RFIFOB(fd,3),
  2957. (int)RFIFOB(fd,4),(int)RFIFOB(fd,5));
  2958. server[id].ip = RFIFOL(fd, 2);
  2959. RFIFOSKIP(fd,6);
  2960. break;
  2961. default:
  2962. // inter server処理に渡す
  2963. {
  2964. int r = inter_parse_frommap(fd);
  2965. if (r == 1) // 処理できた
  2966. break;
  2967. if (r == 2) // パケット長が足りない
  2968. return 0;
  2969. }
  2970. // inter server処理でもない場合は切断
  2971. ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0));
  2972. session[fd]->eof = 1;
  2973. return 0;
  2974. }
  2975. }
  2976. return 0;
  2977. }
  2978. int search_mapserver(unsigned short map, long ip, short port) {
  2979. int i, j;
  2980. for(i = 0; i < MAX_MAP_SERVERS; i++)
  2981. if (server_fd[i] >= 0)
  2982. for (j = 0; server[i].map[j]; j++)
  2983. if (server[i].map[j] == map) {
  2984. if (ip > 0 && server[i].ip != ip)
  2985. continue;
  2986. if (port > 0 && server[i].port != port)
  2987. continue;
  2988. return i;
  2989. }
  2990. return -1;
  2991. }
  2992. // char_mapifの初期化処理(現在はinter_mapif初期化のみ)
  2993. static int char_mapif_init(int fd) {
  2994. return inter_mapif_init(fd);
  2995. }
  2996. //--------------------------------------------
  2997. // Test to know if an IP come from LAN or WAN.
  2998. // Rewrote: Adnvanced subnet check [LuzZza]
  2999. //--------------------------------------------
  3000. int lan_subnetcheck(long *p) {
  3001. int i;
  3002. unsigned char *sbn, *msk, *src = (unsigned char *)p;
  3003. for(i=0; i<subnet_count; i++) {
  3004. if(subnet[i].subnet == (*p & subnet[i].mask)) {
  3005. sbn = (unsigned char *)&subnet[i].subnet;
  3006. msk = (unsigned char *)&subnet[i].mask;
  3007. ShowInfo("Subnet check [%u.%u.%u.%u]: Matches "CL_CYAN"%u.%u.%u.%u/%u.%u.%u.%u"CL_RESET"\n",
  3008. src[0], src[1], src[2], src[3], sbn[0], sbn[1], sbn[2], sbn[3], msk[0], msk[1], msk[2], msk[3]);
  3009. return subnet[i].map_ip;
  3010. }
  3011. }
  3012. ShowInfo("Subnet check [%u.%u.%u.%u]: "CL_CYAN"WAN"CL_RESET"\n", src[0], src[1], src[2], src[3]);
  3013. return 0;
  3014. }
  3015. int parse_char(int fd) {
  3016. int i, ch;
  3017. unsigned short cmd;
  3018. char email[40];
  3019. int map_fd;
  3020. struct char_session_data *sd;
  3021. unsigned char *p = (unsigned char *) &session[fd]->client_addr.sin_addr;
  3022. long subnet_map_ip;
  3023. RFIFOHEAD(fd);
  3024. sd = (struct char_session_data*)session[fd]->session_data;
  3025. if (login_fd < 0)
  3026. session[fd]->eof = 1;
  3027. if(session[fd]->eof) { // disconnect any player (already connected to char-server or coming back from map-server) if login-server is diconnected.
  3028. if (fd == login_fd)
  3029. login_fd = -1;
  3030. if (sd != NULL)
  3031. {
  3032. struct online_char_data* data = idb_get(online_char_db, sd->account_id);
  3033. if (!data || data->server== -1) //If it is not in any server, send it offline. [Skotlex]
  3034. set_char_offline(99,sd->account_id);
  3035. }
  3036. do_close(fd);
  3037. return 0;
  3038. }
  3039. while(RFIFOREST(fd) >= 2 && !session[fd]->eof) {
  3040. cmd = RFIFOW(fd,0);
  3041. // crc32のスキップ用
  3042. if( sd==NULL && // 未ログインor管理パケット
  3043. RFIFOREST(fd)>=4 && // 最低バイト数制限 & 0x7530,0x7532管理パケ除去
  3044. RFIFOREST(fd)<=21 && // 最大バイト数制限 & サーバーログイン除去
  3045. cmd!=0x20b && // md5通知パケット除去
  3046. (RFIFOREST(fd)<6 || RFIFOW(fd,4)==0x65) ){ // 次に何かパケットが来てるなら、接続でないとだめ
  3047. RFIFOSKIP(fd,4);
  3048. cmd = RFIFOW(fd,0);
  3049. ShowDebug("parse_char : %d crc32 skipped\n",fd);
  3050. if(RFIFOREST(fd)==0)
  3051. return 0;
  3052. }
  3053. //For use in packets that depend on an sd being present [Skotlex]
  3054. #define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL) { RFIFOSKIP(fd,rest); return 0; } }
  3055. switch(cmd){
  3056. case 0x20b: //20040622暗号化ragexe対応
  3057. if (RFIFOREST(fd) < 19)
  3058. return 0;
  3059. RFIFOSKIP(fd,19);
  3060. break;
  3061. case 0x65: // 接続要求
  3062. if (RFIFOREST(fd) < 17)
  3063. return 0;
  3064. {
  3065. int GM_value;
  3066. if ((GM_value = isGM(RFIFOL(fd,2))))
  3067. ShowInfo("Account Logged On; Account ID: %d (GM level %d).\n", RFIFOL(fd,2), GM_value);
  3068. else
  3069. ShowInfo("Account Logged On; Account ID: %d.\n", RFIFOL(fd,2));
  3070. if (sd == NULL) {
  3071. sd = (struct char_session_data*)aCalloc(sizeof(struct char_session_data), 1);
  3072. session[fd]->session_data = sd;
  3073. // memset(sd, 0, sizeof(struct char_session_data)); aCalloc does this [Skotlex]
  3074. strncpy(sd->email, "no mail", 40); // put here a mail without '@' to refuse deletion if we don't receive the e-mail
  3075. sd->connect_until_time = 0; // unknow or illimited (not displaying on map-server)
  3076. } else {
  3077. //Received again auth packet for already authentified account?? Discard it.
  3078. //TODO: Perhaps log this as a hack attempt?
  3079. RFIFOSKIP(fd,17);
  3080. break;
  3081. }
  3082. sd->account_id = RFIFOL(fd,2);
  3083. sd->login_id1 = RFIFOL(fd,6);
  3084. sd->login_id2 = RFIFOL(fd,10);
  3085. sd->sex = RFIFOB(fd,16);
  3086. // send back account_id
  3087. WFIFOHEAD(fd, 4);
  3088. WFIFOL(fd,0) = RFIFOL(fd,2);
  3089. WFIFOSET(fd,4);
  3090. // search authentification
  3091. for(i = 0; i < AUTH_FIFO_SIZE; i++) {
  3092. if (auth_fifo[i].account_id == sd->account_id &&
  3093. auth_fifo[i].login_id1 == sd->login_id1 &&
  3094. #if CMP_AUTHFIFO_LOGIN2 != 0
  3095. auth_fifo[i].login_id2 == sd->login_id2 && // relate to the versions higher than 18
  3096. #endif
  3097. (!check_ip_flag || auth_fifo[i].ip == session[fd]->client_addr.sin_addr.s_addr) &&
  3098. auth_fifo[i].delflag == 2) {
  3099. auth_fifo[i].delflag = 1;
  3100. if (online_check)
  3101. { // check if character is not online already. [Skotlex]
  3102. struct online_char_data* character;
  3103. character = idb_get(online_char_db, sd->account_id);
  3104. if (character)
  3105. {
  3106. if(character->server > -1)
  3107. { //Kick it from the map server it is on.
  3108. mapif_disconnectplayer(server_fd[character->server], character->account_id, character->char_id, 2);
  3109. if (!character->waiting_disconnect)
  3110. add_timer(gettick()+20000, chardb_waiting_disconnect, character->account_id, 0);
  3111. character->waiting_disconnect = 1;
  3112. /* Not a good idea because this would trigger when you do a char-change from the map server! [Skotlex]
  3113. } else { //Manual kick from char server.
  3114. struct char_session_data *tsd;
  3115. int i;
  3116. for(i = 0; i < fd_max; i++) {
  3117. if (session[i] && i!=fd && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == sd->account_id)
  3118. {
  3119. WFIFOW(i,0) = 0x81;
  3120. WFIFOB(i,2) = 2;
  3121. WFIFOSET(i,3);
  3122. break;
  3123. }
  3124. }
  3125. if (i == fd_max) //Shouldn't happen, but just in case.
  3126. set_char_offline(99, sd->account_id);
  3127. */
  3128. WFIFOW(fd,0) = 0x81;
  3129. WFIFOB(fd,2) = 8;
  3130. WFIFOSET(fd,3);
  3131. break;
  3132. }
  3133. }
  3134. }
  3135. if (max_connect_user == 0 || count_users() < max_connect_user) {
  3136. if (login_fd > 0) { // don't send request if no login-server
  3137. // request to login-server to obtain e-mail/time limit
  3138. WFIFOW(login_fd,0) = 0x2716;
  3139. WFIFOL(login_fd,2) = sd->account_id;
  3140. WFIFOSET(login_fd,6);
  3141. }
  3142. // send characters to player
  3143. mmo_char_send006b(fd, sd);
  3144. } else {
  3145. // refuse connection (over populated)
  3146. WFIFOW(fd,0) = 0x6c;
  3147. WFIFOW(fd,2) = 0;
  3148. WFIFOSET(fd,3);
  3149. }
  3150. break;
  3151. }
  3152. }
  3153. // authentification not found
  3154. if (i == AUTH_FIFO_SIZE) {
  3155. if (login_fd > 0) { // don't send request if no login-server
  3156. WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
  3157. WFIFOL(login_fd,2) = sd->account_id;
  3158. WFIFOL(login_fd,6) = sd->login_id1;
  3159. WFIFOL(login_fd,10) = sd->login_id2; // relate to the versions higher than 18
  3160. WFIFOB(login_fd,14) = sd->sex;
  3161. WFIFOL(login_fd,15) = session[fd]->client_addr.sin_addr.s_addr;
  3162. WFIFOSET(login_fd,19);
  3163. } else { // if no login-server, we must refuse connection
  3164. WFIFOW(fd,0) = 0x6c;
  3165. WFIFOW(fd,2) = 0;
  3166. WFIFOSET(fd,3);
  3167. }
  3168. }
  3169. }
  3170. RFIFOSKIP(fd,17);
  3171. break;
  3172. case 0x66: // キャラ選択
  3173. FIFOSD_CHECK(3);
  3174. {
  3175. int char_num = RFIFOB(fd,2);
  3176. struct mmo_charstatus *cd;
  3177. RFIFOSKIP(fd,3);
  3178. // if we activated email creation and email is default email
  3179. if (email_creation != 0 && strcmp(sd->email, "a@a.com") == 0 && login_fd > 0) { // to modify an e-mail, login-server must be online
  3180. WFIFOHEAD(fd, 3);
  3181. WFIFOW(fd, 0) = 0x70;
  3182. WFIFOB(fd, 2) = 0; // 00 = Incorrect Email address
  3183. WFIFOSET(fd, 3);
  3184. break;
  3185. }
  3186. // otherwise, load the character
  3187. for (ch = 0; ch < 9; ch++)
  3188. if (sd->found_char[ch] >= 0 && char_dat[sd->found_char[ch]].status.char_num == char_num)
  3189. break;
  3190. if (ch == 9)
  3191. { //Not found?? May be forged packet.
  3192. break;
  3193. }
  3194. cd = &char_dat[sd->found_char[ch]].status;
  3195. char_log("Character Selected, Account ID: %d, Character Slot: %d, Character Name: %s." RETCODE,
  3196. sd->account_id, char_num, cd->name);
  3197. cd->sex = sd->sex;
  3198. // searching map server
  3199. i = search_mapserver(cd->last_point.map,-1,-1);
  3200. // if map is not found, we check major cities
  3201. if (i < 0) {
  3202. unsigned short j;
  3203. //First check that there's actually a map server online.
  3204. for(j = 0; j < MAX_MAP_SERVERS; j++)
  3205. if (server_fd[j] >= 0 && server[j].map[0])
  3206. break;
  3207. if (j == MAX_MAP_SERVERS) {
  3208. ShowInfo("Connection Closed. No map servers available.\n");
  3209. WFIFOHEAD(fd, 3);
  3210. WFIFOW(fd,0) = 0x81;
  3211. WFIFOB(fd,2) = 1; // 01 = Server closed
  3212. WFIFOSET(fd,3);
  3213. break;
  3214. }
  3215. if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
  3216. cd->last_point.x = 273;
  3217. cd->last_point.y = 354;
  3218. } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
  3219. cd->last_point.x = 120;
  3220. cd->last_point.y = 100;
  3221. } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
  3222. cd->last_point.x = 160;
  3223. cd->last_point.y = 94;
  3224. } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
  3225. cd->last_point.x = 116;
  3226. cd->last_point.y = 57;
  3227. } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
  3228. cd->last_point.x = 87;
  3229. cd->last_point.y = 117;
  3230. } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
  3231. cd->last_point.x = 94;
  3232. cd->last_point.y = 103;
  3233. } else {
  3234. ShowInfo("Connection Closed. No map server available that has a major city, and unable to find map-server for '%s'.\n", mapindex_id2name(cd->last_point.map));
  3235. WFIFOHEAD(fd, 3);
  3236. WFIFOW(fd,0) = 0x81;
  3237. WFIFOB(fd,2) = 1; // 01 = Server closed
  3238. WFIFOSET(fd,3);
  3239. break;
  3240. }
  3241. ShowWarning("Unable to find map-server for '%s', sending to major city '%s'.\n", mapindex_id2name(cd->last_point.map), mapindex_id2name(j));
  3242. cd->last_point.map = j;
  3243. }
  3244. WFIFOHEAD(fd, 28);
  3245. WFIFOW(fd,0) = 0x71;
  3246. WFIFOL(fd,2) = cd->char_id;
  3247. memcpy(WFIFOP(fd,6), mapindex_id2name(cd->last_point.map), MAP_NAME_LENGTH);
  3248. ShowInfo("Character selection '%s' (account: %d, slot: %d).\n", cd->name, sd->account_id, ch);
  3249. // Advanced subnet check [LuzZza]
  3250. if((subnet_map_ip = lan_subnetcheck((long *)p)))
  3251. WFIFOL(fd,22) = subnet_map_ip;
  3252. else
  3253. WFIFOL(fd,22) = server[i].ip;
  3254. WFIFOW(fd,26) = server[i].port;
  3255. WFIFOSET(fd,28);
  3256. if (auth_fifo_pos >= AUTH_FIFO_SIZE)
  3257. auth_fifo_pos = 0;
  3258. auth_fifo[auth_fifo_pos].account_id = sd->account_id;
  3259. auth_fifo[auth_fifo_pos].char_id = cd->char_id;
  3260. auth_fifo[auth_fifo_pos].login_id1 = sd->login_id1;
  3261. auth_fifo[auth_fifo_pos].login_id2 = sd->login_id2;
  3262. auth_fifo[auth_fifo_pos].delflag = 0;
  3263. auth_fifo[auth_fifo_pos].char_pos = sd->found_char[ch];
  3264. auth_fifo[auth_fifo_pos].sex = sd->sex;
  3265. auth_fifo[auth_fifo_pos].connect_until_time = sd->connect_until_time;
  3266. auth_fifo[auth_fifo_pos].ip = session[fd]->client_addr.sin_addr.s_addr;
  3267. //Send NEW auth packet [Kevin]
  3268. if ((map_fd = server_fd[i]) < 1 || session[map_fd] == NULL)
  3269. { //0 Should not be a valid server_fd [Skotlex]
  3270. ShowError("parse_char: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", map_fd, i);
  3271. server_fd[i] = -1;
  3272. memset(&server[i], 0, sizeof(struct mmo_map_server));
  3273. //Send server closed.
  3274. WFIFOW(fd,0) = 0x81;
  3275. WFIFOB(fd,2) = 1; // 01 = Server closed
  3276. WFIFOSET(fd,3);
  3277. break;
  3278. }
  3279. WFIFOW(map_fd,0) = 0x2afd;
  3280. WFIFOW(map_fd,2) = 20 + sizeof(struct mmo_charstatus);
  3281. WFIFOL(map_fd,4) = auth_fifo[auth_fifo_pos].account_id;
  3282. WFIFOL(map_fd,8) = auth_fifo[auth_fifo_pos].login_id1;
  3283. WFIFOL(map_fd,16) = auth_fifo[auth_fifo_pos].login_id2;
  3284. WFIFOL(map_fd,12) = (unsigned long)auth_fifo[auth_fifo_pos].connect_until_time;
  3285. memcpy(WFIFOP(map_fd,20), cd, sizeof(struct mmo_charstatus));
  3286. WFIFOSET(map_fd, WFIFOW(map_fd,2));
  3287. set_char_online(i, cd->char_id, cd->account_id);
  3288. //Sets char online in the party and breaks even share if needed.
  3289. inter_party_logged(cd->party_id, cd->account_id, cd->char_id);
  3290. auth_fifo_pos++;
  3291. }
  3292. break;
  3293. case 0x67: // 作成
  3294. FIFOSD_CHECK(37);
  3295. if(char_new == 0) //turn character creation on/off [Kevin]
  3296. i = -2;
  3297. else
  3298. i = make_new_char(fd, RFIFOP(fd,2));
  3299. if(i == -1){ //added some better faile reporting to client on the txt version [Kevin]
  3300. //already exists
  3301. WFIFOHEAD(fd, 3);
  3302. WFIFOW(fd, 0) = 0x6e;
  3303. WFIFOB(fd, 2) = 0x00;
  3304. WFIFOSET(fd, 3);
  3305. RFIFOSKIP(fd, 37);
  3306. break;
  3307. }else if(i == -2){
  3308. //denied
  3309. WFIFOHEAD(fd, 3);
  3310. WFIFOW(fd, 0) = 0x6e;
  3311. WFIFOB(fd, 2) = 0x02;
  3312. WFIFOSET(fd, 3);
  3313. RFIFOSKIP(fd, 37);
  3314. break;
  3315. }else if(i == -3){
  3316. //underaged XD
  3317. WFIFOHEAD(fd, 3);
  3318. WFIFOW(fd, 0) = 0x6e;
  3319. WFIFOB(fd, 2) = 0x01;
  3320. WFIFOSET(fd, 3);
  3321. RFIFOSKIP(fd, 37);
  3322. break;
  3323. }
  3324. WFIFOHEAD(fd, 108);
  3325. WFIFOW(fd,0) = 0x6d;
  3326. memset(WFIFOP(fd,2), 0, 106);
  3327. WFIFOL(fd,2) = char_dat[i].status.char_id;
  3328. WFIFOL(fd,2+4) = char_dat[i].status.base_exp>LONG_MAX?LONG_MAX:char_dat[i].status.base_exp;
  3329. WFIFOL(fd,2+8) = char_dat[i].status.zeny;
  3330. WFIFOL(fd,2+12) = char_dat[i].status.job_exp>LONG_MAX?LONG_MAX:char_dat[i].status.job_exp;
  3331. WFIFOL(fd,2+16) = char_dat[i].status.job_level;
  3332. WFIFOL(fd,2+28) = char_dat[i].status.karma;
  3333. WFIFOL(fd,2+32) = char_dat[i].status.manner;
  3334. WFIFOW(fd,2+40) = 0x30;
  3335. WFIFOW(fd,2+42) = (char_dat[i].status.hp > SHRT_MAX) ? SHRT_MAX : char_dat[i].status.hp;
  3336. WFIFOW(fd,2+44) = (char_dat[i].status.max_hp > SHRT_MAX) ? SHRT_MAX : char_dat[i].status.max_hp;
  3337. WFIFOW(fd,2+46) = (char_dat[i].status.sp > SHRT_MAX) ? SHRT_MAX : char_dat[i].status.sp;
  3338. WFIFOW(fd,2+48) = (char_dat[i].status.max_sp > SHRT_MAX) ? SHRT_MAX : char_dat[i].status.max_sp;
  3339. WFIFOW(fd,2+50) = DEFAULT_WALK_SPEED; // char_dat[i].status.speed;
  3340. WFIFOW(fd,2+52) = char_dat[i].status.class_;
  3341. WFIFOW(fd,2+54) = char_dat[i].status.hair;
  3342. WFIFOW(fd,2+58) = char_dat[i].status.base_level;
  3343. WFIFOW(fd,2+60) = (char_dat[i].status.skill_point > SHRT_MAX) ? SHRT_MAX : char_dat[i].status.skill_point;
  3344. WFIFOW(fd,2+64) = char_dat[i].status.shield;
  3345. WFIFOW(fd,2+66) = char_dat[i].status.head_top;
  3346. WFIFOW(fd,2+68) = char_dat[i].status.head_mid;
  3347. WFIFOW(fd,2+70) = char_dat[i].status.hair_color;
  3348. memcpy(WFIFOP(fd,2+74), char_dat[i].status.name, NAME_LENGTH);
  3349. WFIFOB(fd,2+98) = (char_dat[i].status.str > UCHAR_MAX) ? UCHAR_MAX : char_dat[i].status.str;
  3350. WFIFOB(fd,2+99) = (char_dat[i].status.agi > UCHAR_MAX) ? UCHAR_MAX : char_dat[i].status.agi;
  3351. WFIFOB(fd,2+100) = (char_dat[i].status.vit > UCHAR_MAX) ? UCHAR_MAX : char_dat[i].status.vit;
  3352. WFIFOB(fd,2+101) = (char_dat[i].status.int_ > UCHAR_MAX) ? UCHAR_MAX : char_dat[i].status.int_;
  3353. WFIFOB(fd,2+102) = (char_dat[i].status.dex > UCHAR_MAX) ? UCHAR_MAX : char_dat[i].status.dex;
  3354. WFIFOB(fd,2+103) = (char_dat[i].status.luk > UCHAR_MAX) ? UCHAR_MAX : char_dat[i].status.luk;
  3355. WFIFOB(fd,2+104) = char_dat[i].status.char_num;
  3356. WFIFOSET(fd,108);
  3357. RFIFOSKIP(fd,37);
  3358. for(ch = 0; ch < 9; ch++) {
  3359. if (sd->found_char[ch] == -1) {
  3360. sd->found_char[ch] = i;
  3361. break;
  3362. }
  3363. }
  3364. case 0x68: // delete char //Yor's Fix
  3365. FIFOSD_CHECK(46);
  3366. memcpy(email, RFIFOP(fd,6), 40);
  3367. if (e_mail_check(email) == 0)
  3368. strncpy(email, "a@a.com", 40); // default e-mail
  3369. // if we activated email creation and email is default email
  3370. if (email_creation != 0 && strcmp(sd->email, "a@a.com") == 0 && login_fd > 0) { // to modify an e-mail, login-server must be online
  3371. // if sended email is incorrect e-mail
  3372. if (strcmp(email, "a@a.com") == 0) {
  3373. WFIFOW(fd, 0) = 0x70;
  3374. WFIFOB(fd, 2) = 0; // 00 = Incorrect Email address
  3375. WFIFOSET(fd, 3);
  3376. RFIFOSKIP(fd,46);
  3377. // we act like we have selected a character
  3378. } else {
  3379. // we change the packet to set it like selection.
  3380. for (i = 0; i < 9; i++)
  3381. if (char_dat[sd->found_char[i]].status.char_id == RFIFOL(fd,2)) {
  3382. // we save new e-mail
  3383. memcpy(sd->email, email, 40);
  3384. // we send new e-mail to login-server ('online' login-server is checked before)
  3385. WFIFOW(login_fd,0) = 0x2715;
  3386. WFIFOL(login_fd,2) = sd->account_id;
  3387. memcpy(WFIFOP(login_fd, 6), email, 40);
  3388. WFIFOSET(login_fd,46);
  3389. // skip part of the packet! (46, but leave the size of select packet: 3)
  3390. RFIFOSKIP(fd,43);
  3391. // change value to put new packet (char selection)
  3392. RFIFOW(fd, 0) = 0x66;
  3393. RFIFOB(fd, 2) = char_dat[sd->found_char[i]].status.char_num;
  3394. // not send packet, it's modify of actual packet
  3395. break;
  3396. }
  3397. if (i == 9) {
  3398. WFIFOW(fd, 0) = 0x70;
  3399. WFIFOB(fd, 2) = 0; // 00 = Incorrect Email address
  3400. WFIFOSET(fd, 3);
  3401. RFIFOSKIP(fd,46);
  3402. }
  3403. }
  3404. // otherwise, we delete the character
  3405. } else {
  3406. if (strcmpi(email, sd->email) != 0) { // if it's an invalid email
  3407. WFIFOW(fd, 0) = 0x70;
  3408. WFIFOB(fd, 2) = 0; // 00 = Incorrect Email address
  3409. WFIFOSET(fd, 3);
  3410. // if mail is correct
  3411. } else {
  3412. for (i = 0; i < 9; i++) {
  3413. struct mmo_charstatus *cs = NULL;
  3414. if ((cs = &char_dat[sd->found_char[i]].status)->char_id == RFIFOL(fd,2)) {
  3415. char_delete(cs); // deletion process
  3416. if (sd->found_char[i] != char_num - 1) {
  3417. memcpy(&char_dat[sd->found_char[i]], &char_dat[char_num-1], sizeof(struct mmo_charstatus));
  3418. // Correct moved character reference in the character's owner
  3419. {
  3420. int j, k;
  3421. struct char_session_data *sd2;
  3422. for (j = 0; j < fd_max; j++) {
  3423. if (session[j] && (sd2 = (struct char_session_data*)session[j]->session_data) &&
  3424. sd2->account_id == char_dat[char_num-1].status.account_id) {
  3425. for (k = 0; k < 9; k++) {
  3426. if (sd2->found_char[k] == char_num-1) {
  3427. sd2->found_char[k] = sd->found_char[i];
  3428. break;
  3429. }
  3430. }
  3431. break;
  3432. }
  3433. }
  3434. }
  3435. }
  3436. char_num--;
  3437. for(ch = i; ch < 9-1; ch++)
  3438. sd->found_char[ch] = sd->found_char[ch+1];
  3439. sd->found_char[8] = -1;
  3440. WFIFOW(fd,0) = 0x6f;
  3441. WFIFOSET(fd,2);
  3442. break;
  3443. }
  3444. }
  3445. if (i == 9) {
  3446. WFIFOW(fd,0) = 0x70;
  3447. WFIFOB(fd,2) = 0;
  3448. WFIFOSET(fd,3);
  3449. }
  3450. }
  3451. RFIFOSKIP(fd,46);
  3452. }
  3453. break;
  3454. case 0x2af8: // マップサーバーログイン
  3455. if (RFIFOREST(fd) < 60)
  3456. return 0;
  3457. WFIFOW(fd,0) = 0x2af9;
  3458. for(i = 0; i < MAX_MAP_SERVERS; i++) {
  3459. if (server_fd[i] < 0)
  3460. break;
  3461. }
  3462. if (i == MAX_MAP_SERVERS || strcmp((char*)RFIFOP(fd,2), userid) || strcmp((char*)RFIFOP(fd,26), passwd)){
  3463. WFIFOB(fd,2) = 3;
  3464. WFIFOSET(fd,3);
  3465. RFIFOSKIP(fd,60);
  3466. } else {
  3467. int len;
  3468. WFIFOB(fd,2) = 0;
  3469. session[fd]->func_parse = parse_frommap;
  3470. server_fd[i] = fd;
  3471. server[i].ip = RFIFOL(fd,54);
  3472. server[i].port = RFIFOW(fd,58);
  3473. server[i].users = 0;
  3474. memset(server[i].map, 0, sizeof(server[i].map));
  3475. WFIFOSET(fd,3);
  3476. RFIFOSKIP(fd,60);
  3477. realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  3478. char_mapif_init(fd);
  3479. // send gm acccounts level to map-servers
  3480. len = 4;
  3481. WFIFOW(fd,0) = 0x2b15;
  3482. for(i = 0; i < GM_num; i++) {
  3483. WFIFOL(fd,len) = gm_account[i].account_id;
  3484. WFIFOB(fd,len+4) = (unsigned char)gm_account[i].level;
  3485. len += 5;
  3486. }
  3487. WFIFOW(fd,2) = len;
  3488. WFIFOSET(fd,len);
  3489. return 0;
  3490. }
  3491. break;
  3492. case 0x187: // Alive信号?
  3493. if (RFIFOREST(fd) < 6)
  3494. return 0;
  3495. RFIFOSKIP(fd, 6);
  3496. break;
  3497. case 0x7530: // Athena情報所得
  3498. WFIFOW(fd,0) = 0x7531;
  3499. WFIFOB(fd,2) = ATHENA_MAJOR_VERSION;
  3500. WFIFOB(fd,3) = ATHENA_MINOR_VERSION;
  3501. WFIFOB(fd,4) = ATHENA_REVISION;
  3502. WFIFOB(fd,5) = ATHENA_RELEASE_FLAG;
  3503. WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG;
  3504. WFIFOB(fd,7) = ATHENA_SERVER_INTER | ATHENA_SERVER_CHAR;
  3505. WFIFOW(fd,8) = ATHENA_MOD_VERSION;
  3506. WFIFOSET(fd,10);
  3507. RFIFOSKIP(fd,2);
  3508. return 0;
  3509. case 0x7532: // 接続の切断(defaultと処理は一緒だが明示的にするため)
  3510. default:
  3511. session[fd]->eof = 1;
  3512. return 0;
  3513. }
  3514. }
  3515. RFIFOFLUSH(fd);
  3516. return 0;
  3517. }
  3518. // Console Command Parser [Wizputer]
  3519. int parse_console(char *buf) {
  3520. char *type,*command;
  3521. type = (char *)aCalloc(64,1);
  3522. command = (char *)aCalloc(64,1);
  3523. // memset(type,0,64);
  3524. // memset(command,0,64);
  3525. ShowStatus("Console: %s\n",buf);
  3526. if ( sscanf(buf, "%[^:]:%[^\n]", type , command ) < 2 )
  3527. sscanf(buf,"%[^\n]",type);
  3528. ShowDebug("Type of command: %s || Command: %s \n",type,command);
  3529. if(buf) aFree(buf);
  3530. if(type) aFree(type);
  3531. if(command) aFree(command);
  3532. return 0;
  3533. }
  3534. // 全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す)
  3535. int mapif_sendall(unsigned char *buf, unsigned int len) {
  3536. int i, c;
  3537. c = 0;
  3538. for(i = 0; i < MAX_MAP_SERVERS; i++) {
  3539. int fd;
  3540. if ((fd = server_fd[i]) >= 0) {
  3541. if (session[fd] == NULL)
  3542. { //Could this be the crash's source? [Skotlex]
  3543. ShowError("mapif_sendall: Attempting to write to invalid session %d! Map Server #%d disconnected.\n", fd, i);
  3544. server_fd[i] = -1;
  3545. memset(&server[i], 0, sizeof(struct mmo_map_server));
  3546. continue;
  3547. }
  3548. WFIFOHEAD(fd, len);
  3549. if (WFIFOSPACE(fd) < len) //Increase buffer size.
  3550. realloc_writefifo(fd, len);
  3551. memcpy(WFIFOP(fd,0), buf, len);
  3552. WFIFOSET(fd,len);
  3553. c++;
  3554. }
  3555. }
  3556. return c;
  3557. }
  3558. // 自分以外の全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す)
  3559. int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) {
  3560. int i, c;
  3561. c = 0;
  3562. for(i = 0; i < MAX_MAP_SERVERS; i++) {
  3563. int fd;
  3564. if ((fd = server_fd[i]) >= 0 && fd != sfd) {
  3565. WFIFOHEAD(fd, len);
  3566. if (WFIFOSPACE(fd) < len) //Increase buffer size.
  3567. realloc_writefifo(fd, len);
  3568. memcpy(WFIFOP(fd,0), buf, len);
  3569. WFIFOSET(fd, len);
  3570. c++;
  3571. }
  3572. }
  3573. return c;
  3574. }
  3575. // MAPサーバーにデータ送信(map鯖生存確認有り)
  3576. int mapif_send(int fd, unsigned char *buf, unsigned int len) {
  3577. int i;
  3578. if (fd >= 0) {
  3579. for(i = 0; i < MAX_MAP_SERVERS; i++) {
  3580. if (fd == server_fd[i]) {
  3581. WFIFOHEAD(fd, len);
  3582. if (WFIFOSPACE(fd) < len) //Increase buffer size.
  3583. realloc_writefifo(fd, len);
  3584. memcpy(WFIFOP(fd,0), buf, len);
  3585. WFIFOSET(fd,len);
  3586. return 1;
  3587. }
  3588. }
  3589. }
  3590. return 0;
  3591. }
  3592. int send_users_tologin(int tid, unsigned int tick, int id, int data) {
  3593. int users = count_users();
  3594. unsigned char buf[16];
  3595. if (login_fd > 0 && session[login_fd]) {
  3596. // send number of user to login server
  3597. WFIFOHEAD(login_fd, 6);
  3598. WFIFOW(login_fd,0) = 0x2714;
  3599. WFIFOL(login_fd,2) = users;
  3600. WFIFOSET(login_fd,6);
  3601. }
  3602. // send number of players to all map-servers
  3603. WBUFW(buf,0) = 0x2b00;
  3604. WBUFL(buf,2) = users;
  3605. mapif_sendall(buf, 6);
  3606. return 0;
  3607. }
  3608. static int send_accounts_tologin_sub(DBKey key, void* data, va_list ap) {
  3609. struct online_char_data* character = (struct online_char_data*)data;
  3610. int *i = va_arg(ap, int*);
  3611. int count = va_arg(ap, int);
  3612. if ((*i) >= count)
  3613. return 0; //This is an error that shouldn't happen....
  3614. if(character->server > -1) {
  3615. WFIFOHEAD(login_fd, 8+count*4);
  3616. WFIFOL(login_fd, 8+(*i)*4) =character->account_id;
  3617. (*i)++;
  3618. return 1;
  3619. }
  3620. return 0;
  3621. }
  3622. int send_accounts_tologin(int tid, unsigned int tick, int id, int data) {
  3623. int users = count_users(), i=0;
  3624. if (login_fd > 0 && session[login_fd]) {
  3625. // send account list to login server
  3626. WFIFOHEAD(login_fd, 8+users*4);
  3627. WFIFOW(login_fd,0) = 0x272d;
  3628. WFIFOL(login_fd,4) = users;
  3629. online_char_db->foreach(online_char_db, send_accounts_tologin_sub, &i);
  3630. WFIFOW(login_fd,2) = 8+ i*4;
  3631. WFIFOSET(login_fd,WFIFOW(login_fd,2));
  3632. }
  3633. return 0;
  3634. }
  3635. int check_connect_login_server(int tid, unsigned int tick, int id, int data) {
  3636. if (login_fd > 0 && session[login_fd] != NULL)
  3637. return 0;
  3638. ShowInfo("Attempt to connect to login-server...\n");
  3639. login_fd = make_connection(login_ip, login_port);
  3640. if (login_fd == -1)
  3641. { //Try again later... [Skotlex]
  3642. login_fd = 0;
  3643. return 0;
  3644. }
  3645. session[login_fd]->func_parse = parse_tologin;
  3646. realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  3647. WFIFOHEAD(login_fd, 86);
  3648. WFIFOW(login_fd,0) = 0x2710;
  3649. memcpy(WFIFOP(login_fd,2), userid, 24);
  3650. memcpy(WFIFOP(login_fd,26), passwd, 24);
  3651. WFIFOL(login_fd,50) = 0;
  3652. WFIFOL(login_fd,54) = char_ip;
  3653. WFIFOL(login_fd,58) = char_port;
  3654. memcpy(WFIFOP(login_fd,60), server_name, 20);
  3655. WFIFOW(login_fd,80) = 0;
  3656. WFIFOW(login_fd,82) = char_maintenance;
  3657. WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin]
  3658. WFIFOSET(login_fd,86);
  3659. return 1;
  3660. }
  3661. //------------------------------------------------
  3662. //Invoked 15 seconds after mapif_disconnectplayer in case the map server doesn't
  3663. //replies/disconnect the player we tried to kick. [Skotlex]
  3664. //------------------------------------------------
  3665. static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, int data)
  3666. {
  3667. struct online_char_data* character;
  3668. if ((character = idb_get(online_char_db, id)) != NULL && character->waiting_disconnect)
  3669. { //Mark it offline due to timeout.
  3670. set_char_offline(character->char_id, character->account_id);
  3671. }
  3672. return 0;
  3673. }
  3674. //----------------------------------------------------------
  3675. // Return numerical value of a switch configuration by [Yor]
  3676. // on/off, english, fran軋is, deutsch, espa�l
  3677. //----------------------------------------------------------
  3678. int config_switch(const char *str) {
  3679. if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0)
  3680. return 1;
  3681. if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0)
  3682. return 0;
  3683. return atoi(str);
  3684. }
  3685. //----------------------------------
  3686. // Reading Lan Support configuration
  3687. // Rewrote: Anvanced subnet check [LuzZza]
  3688. //----------------------------------
  3689. int char_lan_config_read(const char *lancfgName) {
  3690. FILE *fp;
  3691. int line_num = 0;
  3692. char line[1024], w1[64], w2[64], w3[64], w4[64];
  3693. if((fp = fopen(lancfgName, "r")) == NULL) {
  3694. ShowWarning("LAN Support configuration file is not found: %s\n", lancfgName);
  3695. return 1;
  3696. }
  3697. ShowInfo("Reading the configuration file %s...\n", lancfgName);
  3698. while(fgets(line, sizeof(line)-1, fp)) {
  3699. line_num++;
  3700. if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n')
  3701. continue;
  3702. line[sizeof(line)-1] = '\0';
  3703. if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) {
  3704. ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num);
  3705. continue;
  3706. }
  3707. remove_control_chars((unsigned char *)w1);
  3708. remove_control_chars((unsigned char *)w2);
  3709. remove_control_chars((unsigned char *)w3);
  3710. remove_control_chars((unsigned char *)w4);
  3711. if(strcmpi(w1, "subnet") == 0) {
  3712. subnet[subnet_count].mask = inet_addr(w2);
  3713. subnet[subnet_count].char_ip = inet_addr(w3);
  3714. subnet[subnet_count].map_ip = inet_addr(w4);
  3715. subnet[subnet_count].subnet = subnet[subnet_count].char_ip&subnet[subnet_count].mask;
  3716. if (subnet[subnet_count].subnet != (subnet[subnet_count].map_ip&subnet[subnet_count].mask)) {
  3717. ShowError("%s: Configuration Error: The char server (%s) and map server (%s) belong to different subnetworks!\n", lancfgName, w3, w4);
  3718. continue;
  3719. }
  3720. subnet_count++;
  3721. }
  3722. ShowStatus("Read information about %d subnetworks.\n", subnet_count);
  3723. }
  3724. fclose(fp);
  3725. return 0;
  3726. }
  3727. #endif //TXT_SQL_CONVERT
  3728. int char_config_read(const char *cfgName) {
  3729. char line[1024], w1[1024], w2[1024];
  3730. FILE *fp = fopen(cfgName, "r");
  3731. if (fp == NULL) {
  3732. ShowFatalError("Configuration file not found: %s.\n", cfgName);
  3733. exit(1);
  3734. }
  3735. ShowInfo("Reading configuration file %s...\n", cfgName);
  3736. while(fgets(line, sizeof(line)-1, fp)) {
  3737. if (line[0] == '/' && line[1] == '/')
  3738. continue;
  3739. line[sizeof(line)-1] = '\0';
  3740. if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2)
  3741. continue;
  3742. remove_control_chars((unsigned char *)w1);
  3743. remove_control_chars((unsigned char *)w2);
  3744. if(strcmpi(w1,"timestamp_format") == 0) {
  3745. strncpy(timestamp_format, w2, 20);
  3746. } else if(strcmpi(w1,"stdout_with_ansisequence")==0){
  3747. stdout_with_ansisequence = config_switch(w2);
  3748. } else if(strcmpi(w1,"console_silent")==0){
  3749. msg_silent = 0; //To always allow the next line to show up.
  3750. ShowInfo("Console Silent Setting: %d\n", atoi(w2));
  3751. msg_silent = atoi(w2);
  3752. #ifndef TXT_SQL_CONVERT
  3753. } else if (strcmpi(w1, "userid") == 0) {
  3754. strncpy(userid, w2, 24);
  3755. } else if (strcmpi(w1, "passwd") == 0) {
  3756. strncpy(passwd, w2, 24);
  3757. } else if (strcmpi(w1, "server_name") == 0) {
  3758. strncpy(server_name, w2, 20);
  3759. server_name[sizeof(server_name) - 1] = '\0';
  3760. ShowStatus("%s server has been initialized\n", w2);
  3761. } else if (strcmpi(w1, "wisp_server_name") == 0) {
  3762. if (strlen(w2) >= 4) {
  3763. memcpy(wisp_server_name, w2, sizeof(wisp_server_name));
  3764. wisp_server_name[sizeof(wisp_server_name) - 1] = '\0';
  3765. }
  3766. } else if (strcmpi(w1, "login_ip") == 0) {
  3767. char ip_str[16];
  3768. login_ip = resolve_hostbyname(w2, NULL, ip_str);
  3769. if (login_ip) {
  3770. strncpy(login_ip_str, w2, sizeof(login_ip_str));
  3771. ShowStatus("Login server IP address : %s -> %s\n", w2, ip_str);
  3772. }
  3773. } else if (strcmpi(w1, "login_port") == 0) {
  3774. login_port = atoi(w2);
  3775. } else if (strcmpi(w1, "char_ip") == 0) {
  3776. char ip_str[16];
  3777. char_ip = resolve_hostbyname(w2, NULL, ip_str);
  3778. if (char_ip){
  3779. strncpy(char_ip_str, w2, sizeof(char_ip_str));
  3780. ShowStatus("Character server IP address : %s -> %s\n", w2, ip_str);
  3781. }
  3782. } else if (strcmpi(w1, "bind_ip") == 0) {
  3783. char ip_str[16];
  3784. bind_ip = resolve_hostbyname(w2, NULL, ip_str);
  3785. if (bind_ip) {
  3786. strncpy(bind_ip_str, w2, sizeof(bind_ip_str));
  3787. ShowStatus("Character server binding IP address : %s -> %s\n", w2, ip_str);
  3788. }
  3789. } else if (strcmpi(w1, "char_port") == 0) {
  3790. char_port = atoi(w2);
  3791. } else if (strcmpi(w1, "char_maintenance") == 0) {
  3792. char_maintenance = atoi(w2);
  3793. } else if (strcmpi(w1, "char_new") == 0) {
  3794. char_new = atoi(w2);
  3795. } else if (strcmpi(w1, "char_new_display") == 0) {
  3796. char_new_display = atoi(w2);
  3797. } else if (strcmpi(w1, "email_creation") == 0) {
  3798. email_creation = config_switch(w2);
  3799. } else if (strcmpi(w1, "scdata_txt") == 0) { //By Skotlex
  3800. strcpy(scdata_txt, w2);
  3801. #endif
  3802. } else if (strcmpi(w1, "char_txt") == 0) {
  3803. strcpy(char_txt, w2);
  3804. } else if (strcmpi(w1, "backup_txt") == 0) { //By zanetheinsane
  3805. strcpy(backup_txt, w2);
  3806. } else if (strcmpi(w1, "friends_txt") == 0) { //By davidsiaw
  3807. strcpy(friends_txt, w2);
  3808. #ifndef TXT_SQL_CONVERT
  3809. } else if (strcmpi(w1, "backup_txt_flag") == 0) { // The backup_txt file was created because char deletion bug existed. Now it's finish and that take a lot of time to create a second file when there are a lot of characters. By [Yor]
  3810. backup_txt_flag = config_switch(w2);
  3811. } else if (strcmpi(w1, "max_connect_user") == 0) {
  3812. max_connect_user = atoi(w2);
  3813. if (max_connect_user < 0)
  3814. max_connect_user = 0; // unlimited online players
  3815. } else if(strcmpi(w1, "gm_allow_level") == 0) {
  3816. gm_allow_level = atoi(w2);
  3817. if(gm_allow_level < 0)
  3818. gm_allow_level = 99;
  3819. } else if (strcmpi(w1, "check_ip_flag") == 0) {
  3820. check_ip_flag = config_switch(w2);
  3821. } else if (strcmpi(w1, "online_check") == 0) {
  3822. online_check = config_switch(w2);
  3823. } else if (strcmpi(w1, "autosave_time") == 0) {
  3824. autosave_interval = atoi(w2)*1000;
  3825. if (autosave_interval <= 0)
  3826. autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
  3827. } else if (strcmpi(w1, "save_log") == 0) {
  3828. save_log = config_switch(w2);
  3829. } else if (strcmpi(w1, "start_point") == 0) {
  3830. char map[32];
  3831. int x, y;
  3832. if (sscanf(w2, "%[^,],%d,%d", map, &x, &y) < 3)
  3833. continue;
  3834. if (strstr(map, ".gat") != NULL) { // Verify at least if '.gat' is in the map name
  3835. start_point.map = mapindex_name2id(map);
  3836. if (!start_point.map) {
  3837. ShowError("Specified start_point %s not found in map-index cache.\n", map);
  3838. start_point.map = 0;
  3839. }
  3840. start_point.x = x;
  3841. start_point.y = y;
  3842. }
  3843. } else if(strcmpi(w1,"log_char")==0) { //log char or not [devil]
  3844. log_char = atoi(w2);
  3845. } else if (strcmpi(w1, "start_zeny") == 0) {
  3846. start_zeny = atoi(w2);
  3847. if (start_zeny < 0)
  3848. start_zeny = 0;
  3849. } else if (strcmpi(w1, "start_weapon") == 0) {
  3850. start_weapon = atoi(w2);
  3851. if (start_weapon < 0)
  3852. start_weapon = 0;
  3853. } else if (strcmpi(w1, "start_armor") == 0) {
  3854. start_armor = atoi(w2);
  3855. if (start_armor < 0)
  3856. start_armor = 0;
  3857. } else if (strcmpi(w1, "unknown_char_name") == 0) {
  3858. strcpy(unknown_char_name, w2);
  3859. unknown_char_name[NAME_LENGTH-1] = '\0';
  3860. } else if (strcmpi(w1, "char_log_filename") == 0) {
  3861. strcpy(char_log_filename, w2);
  3862. } else if (strcmpi(w1, "name_ignoring_case") == 0) {
  3863. name_ignoring_case = config_switch(w2);
  3864. } else if (strcmpi(w1, "char_name_option") == 0) {
  3865. char_name_option = atoi(w2);
  3866. } else if (strcmpi(w1, "char_name_letters") == 0) {
  3867. strcpy(char_name_letters, w2);
  3868. // online files options
  3869. } else if (strcmpi(w1, "online_txt_filename") == 0) {
  3870. strcpy(online_txt_filename, w2);
  3871. } else if (strcmpi(w1, "online_html_filename") == 0) {
  3872. strcpy(online_html_filename, w2);
  3873. } else if (strcmpi(w1, "online_sorting_option") == 0) {
  3874. online_sorting_option = atoi(w2);
  3875. } else if (strcmpi(w1, "online_display_option") == 0) {
  3876. online_display_option = atoi(w2);
  3877. } else if (strcmpi(w1, "online_gm_display_min_level") == 0) { // minimum GM level to display 'GM' when we want to display it
  3878. online_gm_display_min_level = atoi(w2);
  3879. if (online_gm_display_min_level < 5) // send online file every 5 seconds to player is enough
  3880. online_gm_display_min_level = 5;
  3881. } else if (strcmpi(w1, "online_refresh_html") == 0) {
  3882. online_refresh_html = atoi(w2);
  3883. if (online_refresh_html < 1)
  3884. online_refresh_html = 1;
  3885. } else if(strcmpi(w1,"db_path")==0) {
  3886. strcpy(db_path,w2);
  3887. } else if (strcmpi(w1, "console") == 0) {
  3888. if(strcmpi(w2,"on") == 0 || strcmpi(w2,"yes") == 0 )
  3889. console = 1;
  3890. } else if (strcmpi(w1, "fame_list_alchemist") == 0) {
  3891. fame_list_size_chemist = atoi(w2);
  3892. if (fame_list_size_chemist > MAX_FAME_LIST) {
  3893. ShowWarning("Max fame list size is %d (fame_list_alchemist)\n", MAX_FAME_LIST);
  3894. fame_list_size_chemist = MAX_FAME_LIST;
  3895. }
  3896. } else if (strcmpi(w1, "fame_list_blacksmith") == 0) {
  3897. fame_list_size_smith = atoi(w2);
  3898. if (fame_list_size_smith > MAX_FAME_LIST) {
  3899. ShowWarning("Max fame list size is %d (fame_list_blacksmith)\n", MAX_FAME_LIST);
  3900. fame_list_size_smith = MAX_FAME_LIST;
  3901. }
  3902. } else if (strcmpi(w1, "fame_list_taekwon") == 0) {
  3903. fame_list_size_taekwon = atoi(w2);
  3904. if (fame_list_size_taekwon > MAX_FAME_LIST) {
  3905. ShowWarning("Max fame list size is %d (fame_list_taekwon)\n", MAX_FAME_LIST);
  3906. fame_list_size_taekwon = MAX_FAME_LIST;
  3907. }
  3908. } else if (strcmpi(w1, "guild_exp_rate") == 0) {
  3909. guild_exp_rate = atoi(w2);
  3910. #endif //TXT_SQL_CONVERT
  3911. } else if (strcmpi(w1, "import") == 0) {
  3912. char_config_read(w2);
  3913. }
  3914. }
  3915. fclose(fp);
  3916. ShowInfo("done reading %s.\n", cfgName);
  3917. return 0;
  3918. }
  3919. #ifndef TXT_SQL_CONVERT
  3920. int chardb_final(int key, void* data, va_list va)
  3921. {
  3922. aFree(data);
  3923. return 0;
  3924. }
  3925. void do_final(void) {
  3926. ShowStatus("Terminating server.\n");
  3927. // write online players files with no player
  3928. online_char_db->clear(online_char_db, NULL); //clean the db...
  3929. create_online_files();
  3930. online_char_db->destroy(online_char_db, NULL); //dispose the db...
  3931. mmo_char_sync();
  3932. inter_save();
  3933. set_all_offline(-1);
  3934. flush_fifos();
  3935. if(gm_account) aFree(gm_account);
  3936. if(char_dat) aFree(char_dat);
  3937. delete_session(login_fd);
  3938. delete_session(char_fd);
  3939. #ifdef ENABLE_SC_SAVING
  3940. status_final();
  3941. #endif
  3942. inter_final();
  3943. mapindex_final();
  3944. char_log("----End of char-server (normal end with closing of all files)." RETCODE);
  3945. }
  3946. void set_server_type(void)
  3947. {
  3948. SERVER_TYPE = ATHENA_SERVER_CHAR;
  3949. }
  3950. static int online_data_cleanup_sub(DBKey key, void *data, va_list ap)
  3951. {
  3952. struct online_char_data *character= (struct online_char_data*)data;
  3953. if (character->server == -2) //Unknown server.. set them offline
  3954. set_char_offline(character->char_id, character->account_id);
  3955. if (character->server < 0)
  3956. //Free data from players that have not been online for a while.
  3957. db_remove(online_char_db, key);
  3958. return 0;
  3959. }
  3960. static int online_data_cleanup(int tid, unsigned int tick, int id, int data)
  3961. {
  3962. online_char_db->foreach(online_char_db, online_data_cleanup_sub);
  3963. return 0;
  3964. }
  3965. int do_init(int argc, char **argv) {
  3966. int i;
  3967. mapindex_init(); //Needed here for the start-point reading.
  3968. start_point.map = mapindex_name2id("new_zone01.gat");
  3969. char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]);
  3970. char_lan_config_read((argc > 3) ? argv[3] : LOGIN_LAN_CONF_NAME);
  3971. if (strcmp(userid, "s1")==0 && strcmp(passwd, "p1")==0) {
  3972. ShowError("Using the default user/password s1/p1 is NOT RECOMMENDED.\n");
  3973. ShowNotice("Please edit your save/account.txt file to create a proper inter-server user/password (gender 'S')\n");
  3974. ShowNotice("And then change the user/password to use in conf/char_athena.conf (or conf/import/char_conf.txt)\n");
  3975. }
  3976. // a newline in the log...
  3977. char_log("");
  3978. // moved behind char_config_read in case we changed the filename [celest]
  3979. char_log("The char-server starting..." RETCODE);
  3980. if ((naddr_ != 0) && (!login_ip || !char_ip)) {
  3981. // The char server should know what IP address it is running on
  3982. // - MouseJstr
  3983. int localaddr = ntohl(addr_[0]);
  3984. unsigned char *ptr = (unsigned char *) &localaddr;
  3985. char buf[16];
  3986. sprintf(buf, "%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]);;
  3987. if (naddr_ != 1)
  3988. ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", buf);
  3989. else
  3990. ShowStatus("Defaulting to %s as our IP address\n", buf);
  3991. if (!login_ip) {
  3992. strcpy(login_ip_str, buf);
  3993. login_ip = inet_addr(login_ip_str);
  3994. }
  3995. if (!char_ip) {
  3996. strcpy(char_ip_str, buf);
  3997. char_ip = inet_addr(char_ip_str);
  3998. }
  3999. if (ptr[0] == 192 && ptr[1] == 168)
  4000. ShowWarning("Firewall detected.. edit subnet_athena.conf and char_athena.conf\n");
  4001. }
  4002. for(i = 0; i < MAX_MAP_SERVERS; i++) {
  4003. memset(&server[i], 0, sizeof(struct mmo_map_server));
  4004. server_fd[i] = -1;
  4005. }
  4006. online_char_db = db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
  4007. mmo_char_init();
  4008. #ifdef ENABLE_SC_SAVING
  4009. status_init();
  4010. #endif
  4011. update_online = time(NULL);
  4012. create_online_files(); // update online players files at start of the server
  4013. inter_init_txt((argc > 2) ? argv[2] : inter_cfgName); // inter server 初期化
  4014. set_defaultparse(parse_char);
  4015. char_fd = make_listen_bind(bind_ip?bind_ip:INADDR_ANY,char_port);
  4016. add_timer_func_list(check_connect_login_server, "check_connect_login_server");
  4017. add_timer_func_list(send_users_tologin, "send_users_tologin");
  4018. add_timer_func_list(send_accounts_tologin, "send_accounts_tologin");
  4019. add_timer_func_list(mmo_char_sync_timer, "mmo_char_sync_timer");
  4020. add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect");
  4021. add_timer_func_list(online_data_cleanup, "online_data_cleanup");
  4022. add_timer_interval(gettick() + 600*1000, online_data_cleanup, 0, 0, 600 * 1000);
  4023. add_timer_interval(gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000);
  4024. add_timer_interval(gettick() + 1000, send_users_tologin, 0, 0, 5 * 1000);
  4025. add_timer_interval(gettick() + 3600*1000, send_accounts_tologin, 0, 0, 3600*1000); //Sync online accounts every hour
  4026. add_timer_interval(gettick() + autosave_interval, mmo_char_sync_timer, 0, 0, autosave_interval);
  4027. char_read_fame_list(); //Read fame lists.
  4028. if(console) {
  4029. set_defaultconsoleparse(parse_console);
  4030. start_console();
  4031. }
  4032. char_log("The char-server is ready (Server is listening on the port %d)." RETCODE, char_port);
  4033. ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port);
  4034. return 0;
  4035. }
  4036. #endif //TXT_SQL_CONVERT