char.c 137 KB

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