char.c 119 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477
  1. // $Id: char.c,v 1.3 2004/09/13 16:52:16 Yor Exp $
  2. // original : char2.c 2003/03/14 11:58:35 Rev.1.5
  3. #include <sys/types.h>
  4. #include <sys/socket.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <netinet/in.h>
  8. #include <sys/time.h>
  9. #include <time.h>
  10. #include <sys/ioctl.h>
  11. #include <unistd.h>
  12. #include <signal.h>
  13. #include <fcntl.h>
  14. #include <string.h>
  15. #include <arpa/inet.h>
  16. #include <netdb.h>
  17. #include <stdarg.h>
  18. #include "../common/strlib.h"
  19. #include "core.h"
  20. #include "socket.h"
  21. #include "timer.h"
  22. #include "mmo.h"
  23. #include "version.h"
  24. #include "lock.h"
  25. #include "char.h"
  26. #include "showmsg.h"
  27. #include "buffer.h"
  28. #include "inter.h"
  29. #include "int_pet.h"
  30. #include "int_guild.h"
  31. #include "int_party.h"
  32. #include "int_storage.h"
  33. #ifdef MEMWATCH
  34. #include "memwatch.h"
  35. #endif
  36. struct mmo_map_server server[MAX_MAP_SERVERS];
  37. int server_fd[MAX_MAP_SERVERS];
  38. int server_freezeflag[MAX_MAP_SERVERS]; // Map-server anti-freeze system. Counter. 5 ok, 4...0 freezed
  39. int anti_freeze_enable = 0;
  40. int ANTI_FREEZE_INTERVAL = 6;
  41. int login_fd, char_fd;
  42. char userid[24];
  43. char passwd[24];
  44. char server_name[20];
  45. char wisp_server_name[24] = "Server";
  46. int login_ip_set_ = 0;
  47. char login_ip_str[16];
  48. in_addr_t login_ip;
  49. int login_port = 6900;
  50. int char_ip_set_ = 0;
  51. char char_ip_str[16];
  52. int bind_ip_set_ = 0;
  53. char bind_ip_str[16];
  54. in_addr_t char_ip;
  55. int char_port = 6121;
  56. int char_maintenance;
  57. int char_new;
  58. int email_creation = 0; // disabled by default
  59. char char_txt[1024]="save/athena.txt";
  60. char backup_txt[1024]="save/backup.txt"; //By zanetheinsane
  61. char friends_txt[1024]="save/friends.txt"; // davidsiaw
  62. char backup_txt_flag = 0; // The backup_txt file was created because char deletion bug existed. Now it's finish and that take a lot of time to create a second file when there are a lot of characters. => option By [Yor]
  63. char unknown_char_name[1024] = "Unknown";
  64. char char_log_filename[1024] = "log/char.log";
  65. char db_path[1024]="db";
  66. //Added for lan support
  67. char lan_map_ip[128];
  68. int subneti[4];
  69. int subnetmaski[4];
  70. int name_ignoring_case = 0; // Allow or not identical name for characters but with a different case by [Yor]
  71. 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]
  72. char char_name_letters[1024] = ""; // list of letters/symbols authorised (or not) in a character name. by [Yor]
  73. int log_char = 1; // loggin char or not [devil]
  74. int log_inter = 1; // loggin inter or not [devil]
  75. struct char_session_data{
  76. int account_id, login_id1, login_id2, sex;
  77. int found_char[9];
  78. char email[40]; // e-mail (default: a@a.com) by [Yor]
  79. time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
  80. };
  81. //Added for Mugendai's I'm Alive mod
  82. int imalive_on=0;
  83. int imalive_time=60;
  84. //Added by Mugendai for GUI
  85. int flush_on=1;
  86. int flush_time=100;
  87. #define AUTH_FIFO_SIZE 256
  88. struct {
  89. int account_id, char_id, login_id1, login_id2, ip, char_pos, delflag, sex;
  90. time_t connect_until_time; // # of seconds 1/1/1970 (timestamp): Validity limit of the account (0 = unlimited)
  91. } auth_fifo[AUTH_FIFO_SIZE];
  92. int auth_fifo_pos = 0;
  93. int check_ip_flag = 1; // It's to check IP of a player between char-server and other servers (part of anti-hacking system)
  94. int char_id_count = 150000;
  95. struct mmo_charstatus *char_dat;
  96. int char_num, char_max;
  97. int max_connect_user = 0;
  98. int gm_allow_level = 99;
  99. int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
  100. int start_zeny = 500;
  101. int start_weapon = 1201;
  102. int start_armor = 2301;
  103. // Initial position (it's possible to set it in conf file)
  104. struct point start_point = {"new_1-1.gat", 53, 111};
  105. struct gm_account *gm_account = NULL;
  106. int GM_num = 0;
  107. // online players by [Yor]
  108. char online_txt_filename[1024] = "online.txt";
  109. char online_html_filename[1024] = "online.html";
  110. int online_sorting_option = 0; // sorting option to display online players in online files
  111. int online_display_option = 1; // display options: to know which columns must be displayed
  112. int online_players_max;
  113. int online_refresh_html = 20; // refresh time (in sec) of the html file in the explorer
  114. int online_gm_display_min_level = 20; // minimum GM level to display 'GM' when we want to display it
  115. struct online_chars {
  116. int char_id;
  117. int server;
  118. } *online_chars;
  119. time_t update_online; // to update online files when we receiving information from a server (not less than 8 seconds)
  120. int console = 0;
  121. //------------------------------
  122. // Writing function of logs file
  123. //------------------------------
  124. int char_log(char *fmt, ...) {
  125. if(log_char)
  126. {
  127. FILE *logfp;
  128. va_list ap;
  129. struct timeval tv;
  130. char tmpstr[2048];
  131. va_start(ap, fmt);
  132. logfp = fopen(char_log_filename, "a");
  133. if (logfp) {
  134. if (fmt[0] == '\0') // jump a line if no message
  135. fprintf(logfp, RETCODE);
  136. else {
  137. gettimeofday(&tv, NULL);
  138. strftime(tmpstr, 24, "%d-%m-%Y %H:%M:%S", localtime((const time_t*)&(tv.tv_sec)));
  139. sprintf(tmpstr + 19, ".%03d: %s", (int)tv.tv_usec / 1000, fmt);
  140. vfprintf(logfp, tmpstr, ap);
  141. }
  142. fclose(logfp);
  143. }
  144. va_end(ap);
  145. }
  146. return 0;
  147. }
  148. //----------------------------------------------------------------------
  149. // Determine if an account (id) is a GM account
  150. // and returns its level (or 0 if it isn't a GM account or if not found)
  151. //----------------------------------------------------------------------
  152. int isGM(int account_id) {
  153. int i;
  154. for(i = 0; i < GM_num; i++)
  155. if (gm_account[i].account_id == account_id)
  156. return gm_account[i].level;
  157. return 0;
  158. }
  159. //----------------------------------------------
  160. // Search an character id
  161. // (return character index or -1 (if not found))
  162. // If exact character name is not found,
  163. // the function checks without case sensitive
  164. // and returns index if only 1 character is found
  165. // and similar to the searched name.
  166. //----------------------------------------------
  167. int search_character_index(char* character_name) {
  168. int i, quantity, index;
  169. quantity = 0;
  170. index = -1;
  171. for(i = 0; i < char_num; i++) {
  172. // Without case sensitive check (increase the number of similar character names found)
  173. if (stricmp(char_dat[i].name, character_name) == 0) {
  174. // Strict comparison (if found, we finish the function immediatly with correct value)
  175. if (strcmp(char_dat[i].name, character_name) == 0)
  176. return i;
  177. quantity++;
  178. index = i;
  179. }
  180. }
  181. // Here, the exact character name is not found
  182. // We return the found index of a similar account ONLY if there is 1 similar character
  183. if (quantity == 1)
  184. return index;
  185. // Exact character name is not found and 0 or more than 1 similar characters have been found ==> we say not found
  186. return -1;
  187. }
  188. //-------------------------------------
  189. // Return character name with the index
  190. //-------------------------------------
  191. char * search_character_name(int index) {
  192. if (index >= 0 && index < char_num)
  193. return char_dat[index].name;
  194. return unknown_char_name;
  195. }
  196. /*---------------------------------------------------
  197. Make a data line for friends list
  198. --------------------------------------------------*/
  199. int mmo_friends_list_data_str(char *str, struct mmo_charstatus *p) {
  200. int i;
  201. char *str_p = str;
  202. str_p += sprintf(str_p, "%d", p->char_id);
  203. for (i=0;i<20;i++)
  204. {
  205. str_p += sprintf(str_p, ",%d,%s", p->friend_id[i],p->friend_name[i]);
  206. }
  207. return 0;
  208. }
  209. //-------------------------------------------------
  210. // Function to create the character line (for save)
  211. //-------------------------------------------------
  212. int mmo_char_tostr(char *str, struct mmo_charstatus *p) {
  213. int i;
  214. char *str_p = str;
  215. // on multi-map server, sometimes it's posssible that last_point become void. (reason???) We check that to not lost character at restart.
  216. if (p->last_point.map[0] == '\0') {
  217. memcpy(p->last_point.map, "prontera.gat", 16);
  218. p->last_point.x = 273;
  219. p->last_point.y = 354;
  220. }
  221. str_p += sprintf(str_p, "%d\t%d,%d\t%s\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d"
  222. "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d"
  223. "\t%s,%d,%d\t%s,%d,%d,%d\t",
  224. p->char_id, p->account_id, p->char_num, p->name, //
  225. p->class_, p->base_level, p->job_level,
  226. p->base_exp, p->job_exp, p->zeny,
  227. p->hp, p->max_hp, p->sp, p->max_sp,
  228. p->str, p->agi, p->vit, p->int_, p->dex, p->luk,
  229. p->status_point, p->skill_point,
  230. p->option, p->karma, p->manner, //
  231. p->party_id, p->guild_id, p->pet_id,
  232. p->hair, p->hair_color, p->clothes_color,
  233. p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom,
  234. p->last_point.map, p->last_point.x, p->last_point.y, //
  235. p->save_point.map, p->save_point.x, p->save_point.y,
  236. p->partner_id);
  237. for(i = 0; i < 10; i++)
  238. if (p->memo_point[i].map[0]) {
  239. str_p += sprintf(str_p, "%s,%d,%d", p->memo_point[i].map, p->memo_point[i].x, p->memo_point[i].y);
  240. }
  241. *(str_p++) = '\t';
  242. for(i = 0; i < MAX_INVENTORY; i++)
  243. if (p->inventory[i].nameid) {
  244. str_p += sprintf(str_p, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d ",
  245. p->inventory[i].id, p->inventory[i].nameid, p->inventory[i].amount, p->inventory[i].equip,
  246. p->inventory[i].identify, p->inventory[i].refine, p->inventory[i].attribute,
  247. p->inventory[i].card[0], p->inventory[i].card[1], p->inventory[i].card[2], p->inventory[i].card[3]);
  248. }
  249. *(str_p++) = '\t';
  250. for(i = 0; i < MAX_CART; i++)
  251. if (p->cart[i].nameid) {
  252. str_p += sprintf(str_p, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d ",
  253. p->cart[i].id, p->cart[i].nameid, p->cart[i].amount, p->cart[i].equip,
  254. p->cart[i].identify, p->cart[i].refine, p->cart[i].attribute,
  255. p->cart[i].card[0], p->cart[i].card[1], p->cart[i].card[2], p->cart[i].card[3]);
  256. }
  257. *(str_p++) = '\t';
  258. for(i = 0; i < MAX_SKILL; i++)
  259. if (p->skill[i].id && p->skill[i].flag != 1) {
  260. 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);
  261. }
  262. *(str_p++) = '\t';
  263. for(i = 0; i < p->global_reg_num; i++)
  264. if (p->global_reg[i].str[0])
  265. str_p += sprintf(str_p, "%s,%d ", p->global_reg[i].str, p->global_reg[i].value);
  266. *(str_p++) = '\t';
  267. *str_p = '\0';
  268. return 0;
  269. }
  270. //-------------------------------------------------------------------------
  271. // Function to set the character from the line (at read of characters file)
  272. //-------------------------------------------------------------------------
  273. int mmo_char_fromstr(char *str, struct mmo_charstatus *p) {
  274. int tmp_int[256];
  275. int set, next, len, i;
  276. // initilialise character
  277. memset(p, '\0', sizeof(struct mmo_charstatus));
  278. // If it's not char structure of version 1008 and after
  279. if ((set = sscanf(str, "%d\t%d,%d\t%[^\t]\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d"
  280. "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d"
  281. "\t%[^,],%d,%d\t%[^,],%d,%d,%d%n",
  282. &tmp_int[0], &tmp_int[1], &tmp_int[2], p->name, //
  283. &tmp_int[3], &tmp_int[4], &tmp_int[5],
  284. &tmp_int[6], &tmp_int[7], &tmp_int[8],
  285. &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12],
  286. &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18],
  287. &tmp_int[19], &tmp_int[20],
  288. &tmp_int[21], &tmp_int[22], &tmp_int[23], //
  289. &tmp_int[24], &tmp_int[25], &tmp_int[26],
  290. &tmp_int[27], &tmp_int[28], &tmp_int[29],
  291. &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34],
  292. p->last_point.map, &tmp_int[35], &tmp_int[36], //
  293. p->save_point.map, &tmp_int[37], &tmp_int[38], &tmp_int[39], &next)) != 43) {
  294. tmp_int[39] = 0; // partner id
  295. // If not char structure from version 384 to 1007
  296. if ((set = sscanf(str, "%d\t%d,%d\t%[^\t]\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d"
  297. "\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d"
  298. "\t%[^,],%d,%d\t%[^,],%d,%d%n",
  299. &tmp_int[0], &tmp_int[1], &tmp_int[2], p->name, //
  300. &tmp_int[3], &tmp_int[4], &tmp_int[5],
  301. &tmp_int[6], &tmp_int[7], &tmp_int[8],
  302. &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12],
  303. &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18],
  304. &tmp_int[19], &tmp_int[20],
  305. &tmp_int[21], &tmp_int[22], &tmp_int[23], //
  306. &tmp_int[24], &tmp_int[25], &tmp_int[26],
  307. &tmp_int[27], &tmp_int[28], &tmp_int[29],
  308. &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34],
  309. p->last_point.map, &tmp_int[35], &tmp_int[36], //
  310. p->save_point.map, &tmp_int[37], &tmp_int[38], &next)) != 42) {
  311. // It's char structure of a version before 384
  312. tmp_int[26] = 0; // pet id
  313. set = sscanf(str, "%d\t%d,%d\t%[^\t]\t%d,%d,%d\t%d,%d,%d\t%d,%d,%d,%d\t%d,%d,%d,%d,%d,%d\t%d,%d"
  314. "\t%d,%d,%d\t%d,%d\t%d,%d,%d\t%d,%d,%d,%d,%d"
  315. "\t%[^,],%d,%d\t%[^,],%d,%d%n",
  316. &tmp_int[0], &tmp_int[1], &tmp_int[2], p->name, //
  317. &tmp_int[3], &tmp_int[4], &tmp_int[5],
  318. &tmp_int[6], &tmp_int[7], &tmp_int[8],
  319. &tmp_int[9], &tmp_int[10], &tmp_int[11], &tmp_int[12],
  320. &tmp_int[13], &tmp_int[14], &tmp_int[15], &tmp_int[16], &tmp_int[17], &tmp_int[18],
  321. &tmp_int[19], &tmp_int[20],
  322. &tmp_int[21], &tmp_int[22], &tmp_int[23], //
  323. &tmp_int[24], &tmp_int[25], //
  324. &tmp_int[27], &tmp_int[28], &tmp_int[29],
  325. &tmp_int[30], &tmp_int[31], &tmp_int[32], &tmp_int[33], &tmp_int[34],
  326. p->last_point.map, &tmp_int[35], &tmp_int[36], //
  327. p->save_point.map, &tmp_int[37], &tmp_int[38], &next);
  328. set += 2;
  329. //printf("char: old char data ver.1\n");
  330. // Char structure of version 1007 or older
  331. } else {
  332. set++;
  333. //printf("char: old char data ver.2\n");
  334. }
  335. // Char structure of version 1008+
  336. } else {
  337. //printf("char: new char data ver.3\n");
  338. }
  339. if (set != 43)
  340. return 0;
  341. p->char_id = tmp_int[0];
  342. p->account_id = tmp_int[1];
  343. p->char_num = tmp_int[2];
  344. p->class_ = tmp_int[3];
  345. p->base_level = tmp_int[4];
  346. p->job_level = tmp_int[5];
  347. p->base_exp = tmp_int[6];
  348. p->job_exp = tmp_int[7];
  349. p->zeny = tmp_int[8];
  350. p->hp = tmp_int[9];
  351. p->max_hp = tmp_int[10];
  352. p->sp = tmp_int[11];
  353. p->max_sp = tmp_int[12];
  354. p->str = tmp_int[13];
  355. p->agi = tmp_int[14];
  356. p->vit = tmp_int[15];
  357. p->int_ = tmp_int[16];
  358. p->dex = tmp_int[17];
  359. p->luk = tmp_int[18];
  360. p->status_point = tmp_int[19];
  361. p->skill_point = tmp_int[20];
  362. p->option = tmp_int[21];
  363. p->karma = tmp_int[22];
  364. p->manner = tmp_int[23];
  365. p->party_id = tmp_int[24];
  366. p->guild_id = tmp_int[25];
  367. p->pet_id = tmp_int[26];
  368. p->hair = tmp_int[27];
  369. p->hair_color = tmp_int[28];
  370. p->clothes_color = tmp_int[29];
  371. p->weapon = tmp_int[30];
  372. p->shield = tmp_int[31];
  373. p->head_top = tmp_int[32];
  374. p->head_mid = tmp_int[33];
  375. p->head_bottom = tmp_int[34];
  376. p->last_point.x = tmp_int[35];
  377. p->last_point.y = tmp_int[36];
  378. p->save_point.x = tmp_int[37];
  379. p->save_point.y = tmp_int[38];
  380. p->partner_id = tmp_int[39];
  381. // Some checks
  382. for(i = 0; i < char_num; i++) {
  383. if (char_dat[i].char_id == p->char_id) {
  384. printf("\033[1;31mmmo_auth_init: ******Error: a character has an identical id to another.\n");
  385. printf(" character id #%d -> new character not readed.\n", p->char_id);
  386. printf(" Character saved in log file.\033[0m\n");
  387. return -1;
  388. } else if (strcmp(char_dat[i].name, p->name) == 0) {
  389. printf("\033[1;31mmmo_auth_init: ******Error: character name already exists.\n");
  390. printf(" character name '%s' -> new character not readed.\n", p->name);
  391. printf(" Character saved in log file.\033[0m\n");
  392. return -2;
  393. }
  394. }
  395. if (strcmpi(wisp_server_name, p->name) == 0) {
  396. printf("mmo_auth_init: ******WARNING: character name has wisp server name.\n");
  397. printf(" Character name '%s' = wisp server name '%s'.\n", p->name, wisp_server_name);
  398. printf(" Character readed. Suggestion: change the wisp server name.\n");
  399. char_log("mmo_auth_init: ******WARNING: character name has wisp server name: Character name '%s' = wisp server name '%s'." RETCODE,
  400. p->name, wisp_server_name);
  401. }
  402. if (str[next] == '\n' || str[next] == '\r')
  403. return 1; // 新規データ
  404. next++;
  405. for(i = 0; str[next] && str[next] != '\t'; i++) {
  406. if (sscanf(str+next, "%[^,],%d,%d%n", p->memo_point[i].map, &tmp_int[0], &tmp_int[1], &len) != 3)
  407. return -3;
  408. p->memo_point[i].x = tmp_int[0];
  409. p->memo_point[i].y = tmp_int[1];
  410. next += len;
  411. if (str[next] == ' ')
  412. next++;
  413. }
  414. next++;
  415. for(i = 0; str[next] && str[next] != '\t'; i++) {
  416. if (sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n",
  417. &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3],
  418. &tmp_int[4], &tmp_int[5], &tmp_int[6],
  419. &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], &tmp_int[10], &len) == 12) {
  420. // do nothing, it's ok
  421. } else if (sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n",
  422. &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3],
  423. &tmp_int[4], &tmp_int[5], &tmp_int[6],
  424. &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], &len) == 11) {
  425. } else // invalid structure
  426. return -4;
  427. p->inventory[i].id = tmp_int[0];
  428. p->inventory[i].nameid = tmp_int[1];
  429. p->inventory[i].amount = tmp_int[2];
  430. p->inventory[i].equip = tmp_int[3];
  431. p->inventory[i].identify = tmp_int[4];
  432. p->inventory[i].refine = tmp_int[5];
  433. p->inventory[i].attribute = tmp_int[6];
  434. p->inventory[i].card[0] = tmp_int[7];
  435. p->inventory[i].card[1] = tmp_int[8];
  436. p->inventory[i].card[2] = tmp_int[9];
  437. p->inventory[i].card[3] = tmp_int[10];
  438. next += len;
  439. if (str[next] == ' ')
  440. next++;
  441. }
  442. next++;
  443. for(i = 0; str[next] && str[next] != '\t'; i++) {
  444. if (sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n",
  445. &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3],
  446. &tmp_int[4], &tmp_int[5], &tmp_int[6],
  447. &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], &tmp_int[10], &len) == 12) {
  448. // do nothing, it's ok
  449. } else if (sscanf(str + next, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n",
  450. &tmp_int[0], &tmp_int[1], &tmp_int[2], &tmp_int[3],
  451. &tmp_int[4], &tmp_int[5], &tmp_int[6],
  452. &tmp_int[7], &tmp_int[8], &tmp_int[9], &tmp_int[10], &len) == 11) {
  453. } else // invalid structure
  454. return -5;
  455. p->cart[i].id = tmp_int[0];
  456. p->cart[i].nameid = tmp_int[1];
  457. p->cart[i].amount = tmp_int[2];
  458. p->cart[i].equip = tmp_int[3];
  459. p->cart[i].identify = tmp_int[4];
  460. p->cart[i].refine = tmp_int[5];
  461. p->cart[i].attribute = tmp_int[6];
  462. p->cart[i].card[0] = tmp_int[7];
  463. p->cart[i].card[1] = tmp_int[8];
  464. p->cart[i].card[2] = tmp_int[9];
  465. p->cart[i].card[3] = tmp_int[10];
  466. next += len;
  467. if (str[next] == ' ')
  468. next++;
  469. }
  470. next++;
  471. for(i = 0; str[next] && str[next] != '\t'; i++) {
  472. if (sscanf(str + next, "%d,%d%n", &tmp_int[0], &tmp_int[1], &len) != 2)
  473. return -6;
  474. p->skill[tmp_int[0]].id = tmp_int[0];
  475. p->skill[tmp_int[0]].lv = tmp_int[1];
  476. next += len;
  477. if (str[next] == ' ')
  478. next++;
  479. }
  480. next++;
  481. for(i = 0; str[next] && str[next] != '\t' && str[next] != '\n' && str[next] != '\r'; i++) { // global_reg実装以前のathena.txt互換のため一応'\n'チェック
  482. if (sscanf(str + next, "%[^,],%d%n", p->global_reg[i].str, &p->global_reg[i].value, &len) != 2) {
  483. // because some scripts are not correct, the str can be "". So, we must check that.
  484. // If it's, we must not refuse the character, but just this REG value.
  485. // Character line will have something like: nov_2nd_cos,9 ,9 nov_1_2_cos_c,1 (here, ,9 is not good)
  486. if (str[next] == ',' && sscanf(str + next, ",%d%n", &p->global_reg[i].value, &len) == 1)
  487. i--;
  488. else
  489. return -7;
  490. }
  491. next += len;
  492. if (str[next] == ' ')
  493. next++;
  494. }
  495. p->global_reg_num = i;
  496. return 1;
  497. }
  498. //---------------------------------
  499. // Function to read friend list
  500. //---------------------------------
  501. int parse_friend_txt(struct mmo_charstatus *p)
  502. {
  503. char line[1024];
  504. int i,cid=0,temp[20];
  505. FILE *fp;
  506. // Open the file and look for the ID
  507. fp = fopen(friends_txt, "r");
  508. if(fp == NULL)
  509. return 1;
  510. while(fgets(line, sizeof(line)-1, fp)) {
  511. if(line[0] == '/' && line[1] == '/')
  512. continue;
  513. sscanf(line, "%d,%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%[^,],%d,%s",&cid,
  514. &temp[0],p->friend_name[0],
  515. &temp[1],p->friend_name[1],
  516. &temp[2],p->friend_name[2],
  517. &temp[3],p->friend_name[3],
  518. &temp[4],p->friend_name[4],
  519. &temp[5],p->friend_name[5],
  520. &temp[6],p->friend_name[6],
  521. &temp[7],p->friend_name[7],
  522. &temp[8],p->friend_name[8],
  523. &temp[9],p->friend_name[9],
  524. &temp[10],p->friend_name[10],
  525. &temp[11],p->friend_name[11],
  526. &temp[12],p->friend_name[12],
  527. &temp[13],p->friend_name[13],
  528. &temp[14],p->friend_name[14],
  529. &temp[15],p->friend_name[15],
  530. &temp[16],p->friend_name[16],
  531. &temp[17],p->friend_name[17],
  532. &temp[18],p->friend_name[18],
  533. &temp[19],p->friend_name[19]);
  534. if (cid == p->char_id)
  535. break;
  536. }
  537. // No register of friends list
  538. if (cid == 0) {
  539. fclose(fp);
  540. return 0;
  541. }
  542. // Fill in the list
  543. for (i=0; i<20; i++)
  544. p->friend_id[i] = temp[i];
  545. fclose(fp);
  546. return 0;
  547. }
  548. //---------------------------------
  549. // Function to read characters file
  550. //---------------------------------
  551. int mmo_char_init(void) {
  552. char line[65536];
  553. int i;
  554. int ret, line_count;
  555. FILE *fp;
  556. char_max = 256;
  557. char_dat = (struct mmo_charstatus*)aCalloc(sizeof(struct mmo_charstatus) * 256, 1);
  558. if (!char_dat) {
  559. printf("out of memory: mmo_char_init (calloc of char_dat).\n");
  560. exit(1);
  561. }
  562. online_chars = (struct online_chars*)aCalloc(sizeof(struct online_chars) * 256, 1);
  563. if (!online_chars) {
  564. printf("out of memory: mmo_char_init (calloc of online_chars).\n");
  565. exit(1);
  566. }
  567. for(i = 0; i < char_max; i++)
  568. {
  569. online_chars[i].char_id = -1;
  570. online_chars[i].server = -1;
  571. }
  572. char_num = 0;
  573. fp = fopen(char_txt, "r");
  574. if (fp == NULL) {
  575. printf("Characters file not found: %s.\n", char_txt);
  576. char_log("Characters file not found: %s." RETCODE, char_txt);
  577. char_log("Id for the next created character: %d." RETCODE, char_id_count);
  578. return 0;
  579. }
  580. line_count = 0;
  581. while(fgets(line, sizeof(line)-1, fp)) {
  582. int i, j;
  583. line_count++;
  584. if (line[0] == '/' && line[1] == '/')
  585. continue;
  586. line[sizeof(line)-1] = '\0';
  587. j = 0;
  588. if (sscanf(line, "%d\t%%newid%%%n", &i, &j) == 1 && j > 0) {
  589. if (char_id_count < i)
  590. char_id_count = i;
  591. continue;
  592. }
  593. if (char_num >= char_max) {
  594. char_max += 256;
  595. char_dat = (struct mmo_charstatus*)aRealloc(char_dat, sizeof(struct mmo_charstatus) * char_max);
  596. if (!char_dat) {
  597. printf("Out of memory: mmo_char_init (realloc of char_dat).\n");
  598. char_log("Out of memory: mmo_char_init (realloc of char_dat)." RETCODE);
  599. exit(1);
  600. }
  601. online_chars = (struct online_chars*)aRealloc(online_chars, sizeof(struct online_chars) * char_max);
  602. if (!online_chars) {
  603. printf("Out of memory: mmo_char_init (realloc of online_chars).\n");
  604. char_log("Out of memory: mmo_char_init (realloc of online_chars)." RETCODE);
  605. exit(1);
  606. }
  607. for(i = char_max - 256; i < char_max; i++)
  608. {
  609. online_chars[i].char_id = -1;
  610. online_chars[i].server = -1;
  611. }
  612. }
  613. ret = mmo_char_fromstr(line, &char_dat[char_num]);
  614. // Initialize friends list
  615. parse_friend_txt(&char_dat[char_num]); // Grab friends for the character
  616. if (ret > 0) { // negative value or zero for errors
  617. if (char_dat[char_num].char_id >= char_id_count)
  618. char_id_count = char_dat[char_num].char_id + 1;
  619. char_num++;
  620. } else {
  621. printf("mmo_char_init: in characters file, unable to read the line #%d.\n", line_count);
  622. printf(" -> Character saved in log file.\n");
  623. switch (ret) {
  624. case -1:
  625. char_log("Duplicate character id in the next character line (character not readed):" RETCODE);
  626. break;
  627. case -2:
  628. char_log("Duplicate character name in the next character line (character not readed):" RETCODE);
  629. break;
  630. case -3:
  631. char_log("Invalid memo point structure in the next character line (character not readed):" RETCODE);
  632. break;
  633. case -4:
  634. char_log("Invalid inventory item structure in the next character line (character not readed):" RETCODE);
  635. break;
  636. case -5:
  637. char_log("Invalid cart item structure in the next character line (character not readed):" RETCODE);
  638. break;
  639. case -6:
  640. char_log("Invalid skill structure in the next character line (character not readed):" RETCODE);
  641. break;
  642. case -7:
  643. char_log("Invalid register structure in the next character line (character not readed):" RETCODE);
  644. break;
  645. default: // 0
  646. char_log("Unabled to get a character in the next line - Basic structure of line (before inventory) is incorrect (character not readed):" RETCODE);
  647. break;
  648. }
  649. char_log("%s", line);
  650. }
  651. }
  652. fclose(fp);
  653. if (char_num == 0) {
  654. printf("mmo_char_init: No character found in %s.\n", char_txt);
  655. char_log("mmo_char_init: No character found in %s." RETCODE, char_txt);
  656. } else if (char_num == 1) {
  657. printf("mmo_char_init: 1 character read in %s.\n", char_txt);
  658. char_log("mmo_char_init: 1 character read in %s." RETCODE, char_txt);
  659. } else {
  660. printf("mmo_char_init: %d characters read in %s.\n", char_num, char_txt);
  661. char_log("mmo_char_init: %d characters read in %s." RETCODE, char_num, char_txt);
  662. }
  663. char_log("Id for the next created character: %d." RETCODE, char_id_count);
  664. return 0;
  665. }
  666. //---------------------------------------------------------
  667. // Function to save characters in files (speed up by [Yor])
  668. //---------------------------------------------------------
  669. void mmo_char_sync(void) {
  670. char line[65536],f_line[1024];
  671. int i, j, k;
  672. int lock;
  673. FILE *fp,*f_fp;
  674. //int *id = (int *) aMalloc(sizeof(int) * char_num);
  675. CREATE_BUFFER(id, int, char_num);
  676. // Sorting before save (by [Yor])
  677. for(i = 0; i < char_num; i++) {
  678. id[i] = i;
  679. for(j = 0; j < i; j++) {
  680. if ((char_dat[i].account_id < char_dat[id[j]].account_id) ||
  681. // if same account id, we sort by slot.
  682. (char_dat[i].account_id == char_dat[id[j]].account_id &&
  683. char_dat[i].char_num < char_dat[id[j]].char_num)) {
  684. for(k = i; k > j; k--)
  685. id[k] = id[k-1];
  686. id[j] = i; // id[i]
  687. break;
  688. }
  689. }
  690. }
  691. // Data save
  692. fp = lock_fopen(char_txt, &lock);
  693. if (fp == NULL) {
  694. printf("WARNING: Server can't not save characters.\n");
  695. char_log("WARNING: Server can't not save characters." RETCODE);
  696. } else {
  697. for(i = 0; i < char_num; i++) {
  698. // create only once the line, and save it in the 2 files (it's speeder than repeat twice the loop and create twice the line)
  699. mmo_char_tostr(line, &char_dat[id[i]]); // use of sorted index
  700. fprintf(fp, "%s" RETCODE, line);
  701. }
  702. fprintf(fp, "%d\t%%newid%%" RETCODE, char_id_count);
  703. lock_fclose(fp, char_txt, &lock);
  704. }
  705. // Data save (backup)
  706. if (backup_txt_flag) { // The backup_txt file was created because char deletion bug existed. Now it's finish and that take a lot of time to create a second file when there are a lot of characters. => option By [Yor]
  707. fp = lock_fopen(backup_txt, &lock);
  708. if (fp == NULL) {
  709. printf("WARNING: Server can't not create backup of characters file.\n");
  710. char_log("WARNING: Server can't not create backup of characters file." RETCODE);
  711. //aFree(id); // free up the memory before leaving -.- [Ajarn]
  712. DELETE_BUFFER(id);
  713. return;
  714. }
  715. for(i = 0; i < char_num; i++) {
  716. // create only once the line, and save it in the 2 files (it's speeder than repeat twice the loop and create twice the line)
  717. mmo_char_tostr(line, &char_dat[id[i]]); // use of sorted index
  718. fprintf(fp, "%s" RETCODE, line);
  719. }
  720. fprintf(fp, "%d\t%%newid%%" RETCODE, char_id_count);
  721. lock_fclose(fp, backup_txt, &lock);
  722. }
  723. // Friends List data save (davidsiaw)
  724. f_fp = lock_fopen(friends_txt, &lock);
  725. for(i = 0; i < char_num; i++) {
  726. mmo_friends_list_data_str(f_line, &char_dat[id[i]]);
  727. fprintf(f_fp, "%s" RETCODE, f_line);
  728. }
  729. lock_fclose(f_fp, friends_txt, &lock);
  730. //aFree(id);
  731. DELETE_BUFFER(id);
  732. return;
  733. }
  734. //----------------------------------------------------
  735. // Function to save (in a periodic way) datas in files
  736. //----------------------------------------------------
  737. int mmo_char_sync_timer(int tid, unsigned int tick, int id, int data) {
  738. mmo_char_sync();
  739. inter_save();
  740. return 0;
  741. }
  742. //-----------------------------------
  743. // Function to create a new character
  744. //-----------------------------------
  745. int make_new_char(int fd, unsigned char *dat) {
  746. int i, j;
  747. struct char_session_data *sd;
  748. sd = (struct char_session_data*)session[fd]->session_data;
  749. // remove control characters from the name
  750. dat[23] = '\0';
  751. if (remove_control_chars((char*)dat)) {
  752. char_log("Make new char error (control char received in the name): (connection #%d, account: %d)." RETCODE,
  753. fd, sd->account_id);
  754. return -1;
  755. }
  756. // check lenght of character name
  757. if (strlen((const char*)dat) < 4) {
  758. char_log("Make new char error (character name too small): (connection #%d, account: %d, name: '%s')." RETCODE,
  759. fd, sd->account_id, dat);
  760. return -1;
  761. }
  762. // Check Authorised letters/symbols in the name of the character
  763. if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
  764. for (i = 0; dat[i]; i++)
  765. if (strchr(char_name_letters, dat[i]) == NULL) {
  766. char_log("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c." RETCODE,
  767. fd, sd->account_id, dat, dat[i]);
  768. return -1;
  769. }
  770. } else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden
  771. for (i = 0; dat[i]; i++)
  772. if (strchr(char_name_letters, dat[i]) != NULL) {
  773. char_log("Make new char error (invalid letter in the name): (connection #%d, account: %d), name: %s, invalid letter: %c." RETCODE,
  774. fd, sd->account_id, dat, dat[i]);
  775. return -1;
  776. }
  777. } // else, all letters/symbols are authorised (except control char removed before)
  778. if (dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29] != 5*6 || // stats
  779. dat[30] >= 9 || // slots (dat[30] can not be negativ)
  780. dat[33] <= 0 || dat[33] >= 20 || // hair style
  781. dat[31] >= 9) { // hair color (dat[31] can not be negativ)
  782. char_log("Make new char error (invalid values): (connection #%d, account: %d) slot %d, name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d" RETCODE,
  783. fd, sd->account_id, dat[30], dat, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], dat[31]);
  784. return -1;
  785. }
  786. // check individual stat value
  787. for(i = 24; i <= 29; i++) {
  788. if (dat[i] < 1 || dat[i] > 9) {
  789. char_log("Make new char error (invalid stat value: not between 1 to 9): (connection #%d, account: %d) slot %d, name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d" RETCODE,
  790. fd, sd->account_id, dat[30], dat, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], dat[31]);
  791. return -1;
  792. }
  793. }
  794. for(i = 0; i < char_num; i++) {
  795. if ((name_ignoring_case != 0 && strcmp(char_dat[i].name, (const char*)dat) == 0) ||
  796. (name_ignoring_case == 0 && strcmpi(char_dat[i].name, (const char*)dat) == 0)) {
  797. char_log("Make new char error (name already exists): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %d), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d." RETCODE,
  798. fd, sd->account_id, dat[30], dat, char_dat[i].name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], dat[31]);
  799. return -1;
  800. }
  801. if (char_dat[i].account_id == sd->account_id && char_dat[i].char_num == dat[30]) {
  802. char_log("Make new char error (slot already used): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %d), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d." RETCODE,
  803. fd, sd->account_id, dat[30], dat, char_dat[i].name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], dat[31]);
  804. return -1;
  805. }
  806. }
  807. if (strcmp(wisp_server_name, (const char*)dat) == 0) {
  808. char_log("Make new char error (name used is wisp name for server): (connection #%d, account: %d) slot %d, name: %s (actual name of other char: %d), stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d." RETCODE,
  809. fd, sd->account_id, dat[30], dat, char_dat[i].name, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], dat[31]);
  810. return -1;
  811. }
  812. if (char_num >= char_max) {
  813. char_max += 256;
  814. char_dat = (struct mmo_charstatus*)aRealloc(char_dat, sizeof(struct mmo_charstatus) * char_max);
  815. if (!char_dat) {
  816. printf("Out of memory: make_new_char (realloc of char_dat).\n");
  817. char_log("Out of memory: make_new_char (realloc of char_dat)." RETCODE);
  818. exit(1);
  819. }
  820. online_chars = (struct online_chars*)aRealloc(online_chars, sizeof(struct online_chars) * char_max);
  821. if (!online_chars) {
  822. printf("Out of memory: make_new_char (realloc of online_chars).\n");
  823. char_log("Out of memory: make_new_char (realloc of online_chars)." RETCODE);
  824. exit(1);
  825. }
  826. for(j = char_max - 256; j < char_max; j++) {
  827. online_chars[j].char_id = -1;
  828. online_chars[j].server = -1;
  829. }
  830. }
  831. char_log("Creation of New Character: (connection #%d, account: %d) slot %d, character Name: %s, stats: %d+%d+%d+%d+%d+%d=%d, hair: %d, hair color: %d." RETCODE,
  832. fd, sd->account_id, dat[30], dat, dat[24], dat[25], dat[26], dat[27], dat[28], dat[29], dat[24] + dat[25] + dat[26] + dat[27] + dat[28] + dat[29], dat[33], dat[31]);
  833. memset(&char_dat[i], 0, sizeof(struct mmo_charstatus));
  834. char_dat[i].char_id = char_id_count++;
  835. char_dat[i].account_id = sd->account_id;
  836. char_dat[i].char_num = dat[30];
  837. strcpy(char_dat[i].name, (const char*)dat);
  838. char_dat[i].class_ = 0;
  839. char_dat[i].base_level = 1;
  840. char_dat[i].job_level = 1;
  841. char_dat[i].base_exp = 0;
  842. char_dat[i].job_exp = 0;
  843. char_dat[i].zeny = start_zeny;
  844. char_dat[i].str = dat[24];
  845. char_dat[i].agi = dat[25];
  846. char_dat[i].vit = dat[26];
  847. char_dat[i].int_ = dat[27];
  848. char_dat[i].dex = dat[28];
  849. char_dat[i].luk = dat[29];
  850. char_dat[i].max_hp = 40 * (100 + char_dat[i].vit) / 100;
  851. char_dat[i].max_sp = 11 * (100 + char_dat[i].int_) / 100;
  852. char_dat[i].hp = char_dat[i].max_hp;
  853. char_dat[i].sp = char_dat[i].max_sp;
  854. char_dat[i].status_point = 0;
  855. char_dat[i].skill_point = 0;
  856. char_dat[i].option = 0;
  857. char_dat[i].karma = 0;
  858. char_dat[i].manner = 0;
  859. char_dat[i].party_id = 0;
  860. char_dat[i].guild_id = 0;
  861. char_dat[i].hair = dat[33];
  862. char_dat[i].hair_color = dat[31];
  863. char_dat[i].clothes_color = 0;
  864. char_dat[i].inventory[0].nameid = start_weapon; // Knife
  865. char_dat[i].inventory[0].amount = 1;
  866. char_dat[i].inventory[0].equip = 0x02;
  867. char_dat[i].inventory[0].identify = 1;
  868. char_dat[i].inventory[1].nameid = start_armor; // Cotton Shirt
  869. char_dat[i].inventory[1].amount = 1;
  870. char_dat[i].inventory[1].equip = 0x10;
  871. char_dat[i].inventory[1].identify = 1;
  872. char_dat[i].weapon = 1;
  873. char_dat[i].shield = 0;
  874. char_dat[i].head_top = 0;
  875. char_dat[i].head_mid = 0;
  876. char_dat[i].head_bottom = 0;
  877. memcpy(&char_dat[i].last_point, &start_point, sizeof(start_point));
  878. memcpy(&char_dat[i].save_point, &start_point, sizeof(start_point));
  879. char_num++;
  880. mmo_char_sync();
  881. return i;
  882. }
  883. //----------------------------------------------------
  884. // This function return the name of the job (by [Yor])
  885. //----------------------------------------------------
  886. char * job_name(int class_) {
  887. switch (class_) {
  888. case 0: return "Novice";
  889. case 1: return "Swordsman";
  890. case 2: return "Mage";
  891. case 3: return "Archer";
  892. case 4: return "Acolyte";
  893. case 5: return "Merchant";
  894. case 6: return "Thief";
  895. case 7: return "Knight";
  896. case 8: return "Priest";
  897. case 9: return "Wizard";
  898. case 10: return "Blacksmith";
  899. case 11: return "Hunter";
  900. case 12: return "Assassin";
  901. case 13: return "Knight 2";
  902. case 14: return "Crusader";
  903. case 15: return "Monk";
  904. case 16: return "Sage";
  905. case 17: return "Rogue";
  906. case 18: return "Alchemist";
  907. case 19: return "Bard";
  908. case 20: return "Dancer";
  909. case 21: return "Crusader 2";
  910. case 22: return "Wedding";
  911. case 23: return "Super Novice";
  912. case 4001: return "Novice High";
  913. case 4002: return "Swordsman High";
  914. case 4003: return "Mage High";
  915. case 4004: return "Archer High";
  916. case 4005: return "Acolyte High";
  917. case 4006: return "Merchant High";
  918. case 4007: return "Thief High";
  919. case 4008: return "Lord Knight";
  920. case 4009: return "High Priest";
  921. case 4010: return "High Wizard";
  922. case 4011: return "Whitesmith";
  923. case 4012: return "Sniper";
  924. case 4013: return "Assassin Cross";
  925. case 4014: return "Peko Knight";
  926. case 4015: return "Paladin";
  927. case 4016: return "Champion";
  928. case 4017: return "Professor";
  929. case 4018: return "Stalker";
  930. case 4019: return "Creator";
  931. case 4020: return "Clown";
  932. case 4021: return "Gypsy";
  933. case 4022: return "Peko Paladin";
  934. case 4023: return "Baby Novice";
  935. case 4024: return "Baby Swordsman";
  936. case 4025: return "Baby Mage";
  937. case 4026: return "Baby Archer";
  938. case 4027: return "Baby Acolyte";
  939. case 4028: return "Baby Merchant";
  940. case 4029: return "Baby Thief";
  941. case 4030: return "Baby Knight";
  942. case 4031: return "Baby Priest";
  943. case 4032: return "Baby Wizard";
  944. case 4033: return "Baby Blacksmith";
  945. case 4034: return "Baby Hunter";
  946. case 4035: return "Baby Assassin";
  947. case 4036: return "Baby Peco Knight";
  948. case 4037: return "Baby Crusader";
  949. case 4038: return "Baby Monk";
  950. case 4039: return "Baby Sage";
  951. case 4040: return "Baby Rogue";
  952. case 4041: return "Baby Alchemist";
  953. case 4042: return "Baby Bard";
  954. case 4043: return "Baby Dancer";
  955. case 4044: return "Baby Peco Crusader";
  956. case 4045: return "Super Baby";
  957. }
  958. return "Unknown Job";
  959. }
  960. //-------------------------------------------------------------
  961. // Function to create the online files (txt and html). by [Yor]
  962. //-------------------------------------------------------------
  963. void create_online_files(void) {
  964. int i, j, k, l; // for loops
  965. int players; // count the number of players
  966. FILE *fp; // for the txt file
  967. FILE *fp2; // for the html file
  968. char temp[256]; // to prepare what we must display
  969. time_t time_server; // for number of seconds
  970. struct tm *datetime; // variable for time in structure ->tm_mday, ->tm_sec, ...
  971. int id[online_players_max];
  972. // don't return here if we display nothing, because server[j].users is updated in the first loop.
  973. // Get number of online players, id of each online players, and verify if a server is offline
  974. players = 0;
  975. for (i = 0; i < online_players_max; i++) {
  976. if (online_chars[i].char_id != -1) {
  977. // check if map-server is online
  978. j = online_chars[i].server;
  979. if (j == -1) {
  980. online_chars[i].char_id = -1;
  981. continue;
  982. } else if (server_fd[j] < 0) {
  983. server[j].users = 0;
  984. online_chars[i].char_id = -1;
  985. online_chars[i].server = -1;
  986. continue;
  987. }
  988. // check if the character is twice or more in the list
  989. // (multiple map-servers and player have successfully connected twice!)
  990. for(j = i + 1; j < online_players_max; j++)
  991. if (online_chars[i].char_id == online_chars[j].char_id) {
  992. k = online_chars[j].server;
  993. if (k != -1 && server_fd[k] >= 0 && server[k].users > 0)
  994. server[k].users--;
  995. online_chars[j].char_id = -1;
  996. online_chars[j].server = -1;
  997. }
  998. // search position of character in char_dat and sort online characters.
  999. for(j = 0; j < char_num; j++) {
  1000. if (char_dat[j].char_id == online_chars[i].char_id) {
  1001. id[players] = j;
  1002. // use sorting option
  1003. switch (online_sorting_option) {
  1004. case 1: // by name (without case sensitive)
  1005. for(k = 0; k < players; k++)
  1006. if (stricmp(char_dat[j].name, char_dat[id[k]].name) < 0 ||
  1007. // if same name, we sort with case sensitive.
  1008. (stricmp(char_dat[j].name, char_dat[id[k]].name) == 0 &&
  1009. strcmp(char_dat[j].name, char_dat[id[k]].name) < 0)) {
  1010. for(l = players; l > k; l--)
  1011. id[l] = id[l-1];
  1012. id[k] = j; // id[players]
  1013. break;
  1014. }
  1015. break;
  1016. case 2: // by zeny
  1017. for(k = 0; k < players; k++)
  1018. if (char_dat[j].zeny < char_dat[id[k]].zeny ||
  1019. // if same number of zenys, we sort by name.
  1020. (char_dat[j].zeny == char_dat[id[k]].zeny &&
  1021. stricmp(char_dat[j].name, char_dat[id[k]].name) < 0)) {
  1022. for(l = players; l > k; l--)
  1023. id[l] = id[l-1];
  1024. id[k] = j; // id[players]
  1025. break;
  1026. }
  1027. break;
  1028. case 3: // by base level
  1029. for(k = 0; k < players; k++)
  1030. if (char_dat[j].base_level < char_dat[id[k]].base_level ||
  1031. // if same base level, we sort by base exp.
  1032. (char_dat[j].base_level == char_dat[id[k]].base_level &&
  1033. char_dat[j].base_exp < char_dat[id[k]].base_exp)) {
  1034. for(l = players; l > k; l--)
  1035. id[l] = id[l-1];
  1036. id[k] = j; // id[players]
  1037. break;
  1038. }
  1039. break;
  1040. case 4: // by job (and job level)
  1041. for(k = 0; k < players; k++)
  1042. if (char_dat[j].class_ < char_dat[id[k]].class_ ||
  1043. // if same job, we sort by job level.
  1044. (char_dat[j].class_ == char_dat[id[k]].class_ &&
  1045. char_dat[j].job_level < char_dat[id[k]].job_level) ||
  1046. // if same job and job level, we sort by job exp.
  1047. (char_dat[j].class_ == char_dat[id[k]].class_ &&
  1048. char_dat[j].job_level == char_dat[id[k]].job_level &&
  1049. char_dat[j].job_exp < char_dat[id[k]].job_exp)) {
  1050. for(l = players; l > k; l--)
  1051. id[l] = id[l-1];
  1052. id[k] = j; // id[players]
  1053. break;
  1054. }
  1055. break;
  1056. case 5: // by location map name
  1057. for(k = 0; k < players; k++)
  1058. if (stricmp(char_dat[j].last_point.map, char_dat[id[k]].last_point.map) < 0 ||
  1059. // if same map name, we sort by name.
  1060. (stricmp(char_dat[j].last_point.map, char_dat[id[k]].last_point.map) == 0 &&
  1061. stricmp(char_dat[j].name, char_dat[id[k]].name) < 0)) {
  1062. for(l = players; l > k; l--)
  1063. id[l] = id[l-1];
  1064. id[k] = j; // id[players]
  1065. break;
  1066. }
  1067. break;
  1068. default: // 0 or invalid value: no sorting
  1069. break;
  1070. }
  1071. players++;
  1072. break;
  1073. }
  1074. }
  1075. }
  1076. }
  1077. if (online_display_option == 0) // we display nothing, so return
  1078. return;
  1079. // write files
  1080. fp = fopen(online_txt_filename, "w");
  1081. if (fp != NULL) {
  1082. fp2 = fopen(online_html_filename, "w");
  1083. if (fp2 != NULL) {
  1084. // get time
  1085. time(&time_server); // get time in seconds since 1/1/1970
  1086. datetime = localtime(&time_server); // convert seconds in structure
  1087. strftime(temp, sizeof(temp), "%d %b %Y %X", datetime); // like sprintf, but only for date/time (05 dec 2003 15:12:52)
  1088. // write heading
  1089. fprintf(fp2, "<HTML>\n");
  1090. fprintf(fp2, " <META http-equiv=\"Refresh\" content=\"%d\">\n", online_refresh_html); // update on client explorer every x seconds
  1091. fprintf(fp2, " <HEAD>\n");
  1092. fprintf(fp2, " <TITLE>Online Players on %s</TITLE>\n", server_name);
  1093. fprintf(fp2, " </HEAD>\n");
  1094. fprintf(fp2, " <BODY>\n");
  1095. fprintf(fp2, " <H3>Online Players on %s (%s):</H3>\n", server_name, temp);
  1096. fprintf(fp, "Online Players on %s (%s):\n", server_name, temp);
  1097. fprintf(fp, "\n");
  1098. for (i = 0; i < players; i++) {
  1099. // if it's the first player
  1100. if (i == 0) {
  1101. j = 0; // count the number of characters for the txt version and to set the separate line
  1102. fprintf(fp2, " <table border=\"1\" cellspacing=\"1\">\n");
  1103. fprintf(fp2, " <tr>\n");
  1104. if ((online_display_option & 1) || (online_display_option & 64)) {
  1105. fprintf(fp2, " <td><b>Name</b></td>\n");
  1106. if (online_display_option & 64) {
  1107. fprintf(fp, "Name "); // 30
  1108. j += 30;
  1109. } else {
  1110. fprintf(fp, "Name "); // 25
  1111. j += 25;
  1112. }
  1113. }
  1114. if ((online_display_option & 6) == 6) {
  1115. fprintf(fp2, " <td><b>Job (levels)</b></td>\n");
  1116. fprintf(fp, "Job Levels "); // 27
  1117. j += 27;
  1118. } else if (online_display_option & 2) {
  1119. fprintf(fp2, " <td><b>Job</b></td>\n");
  1120. fprintf(fp, "Job "); // 19
  1121. j += 19;
  1122. } else if (online_display_option & 4) {
  1123. fprintf(fp2, " <td><b>Levels</b></td>\n");
  1124. fprintf(fp, " Levels "); // 8
  1125. j += 8;
  1126. }
  1127. if (online_display_option & 24) { // 8 or 16
  1128. fprintf(fp2, " <td><b>Location</b></td>\n");
  1129. if (online_display_option & 16) {
  1130. fprintf(fp, "Location ( x , y ) "); // 23
  1131. j += 23;
  1132. } else {
  1133. fprintf(fp, "Location "); // 13
  1134. j += 13;
  1135. }
  1136. }
  1137. if (online_display_option & 32) {
  1138. fprintf(fp2, " <td ALIGN=CENTER><b>zenys</b></td>\n");
  1139. fprintf(fp, " Zenys "); // 16
  1140. j += 16;
  1141. }
  1142. fprintf(fp2, " </tr>\n");
  1143. fprintf(fp, "\n");
  1144. for (k = 0; k < j; k++)
  1145. fprintf(fp, "-");
  1146. fprintf(fp, "\n");
  1147. }
  1148. fprintf(fp2, " <tr>\n");
  1149. // get id of the character (more speed)
  1150. j = id[i];
  1151. // displaying the character name
  1152. if ((online_display_option & 1) || (online_display_option & 64)) { // without/with 'GM' display
  1153. strcpy(temp, char_dat[j].name);
  1154. l = isGM(char_dat[j].account_id);
  1155. if (online_display_option & 64) {
  1156. if (l >= online_gm_display_min_level)
  1157. fprintf(fp, "%-24s (GM) ", temp);
  1158. else
  1159. fprintf(fp, "%-24s ", temp);
  1160. } else
  1161. fprintf(fp, "%-24s ", temp);
  1162. // name of the character in the html (no < >, because that create problem in html code)
  1163. fprintf(fp2, " <td>");
  1164. if ((online_display_option & 64) && l >= online_gm_display_min_level)
  1165. fprintf(fp2, "<b>");
  1166. for (k = 0; k < strlen(temp); k++) {
  1167. switch(temp[k]) {
  1168. case '<': // <
  1169. fprintf(fp2, "&lt;");
  1170. break;
  1171. case '>': // >
  1172. fprintf(fp2, "&gt;");
  1173. break;
  1174. default:
  1175. fprintf(fp2, "%c", temp[k]);
  1176. break;
  1177. };
  1178. }
  1179. if ((online_display_option & 64) && l >= online_gm_display_min_level)
  1180. fprintf(fp2, "</b> (GM)");
  1181. fprintf(fp2, "</td>\n");
  1182. }
  1183. // displaying of the job
  1184. if (online_display_option & 6) {
  1185. char * jobname = job_name(char_dat[j].class_);
  1186. if ((online_display_option & 6) == 6) {
  1187. fprintf(fp2, " <td>%s %d/%d</td>\n", jobname, char_dat[j].base_level, char_dat[j].job_level);
  1188. fprintf(fp, "%-18s %3d/%3d ", jobname, char_dat[j].base_level, char_dat[j].job_level);
  1189. } else if (online_display_option & 2) {
  1190. fprintf(fp2, " <td>%s</td>\n", jobname);
  1191. fprintf(fp, "%-18s ", jobname);
  1192. } else if (online_display_option & 4) {
  1193. fprintf(fp2, " <td>%d/%d</td>\n", char_dat[j].base_level, char_dat[j].job_level);
  1194. fprintf(fp, "%3d/%3d ", char_dat[j].base_level, char_dat[j].job_level);
  1195. }
  1196. }
  1197. // displaying of the map
  1198. if (online_display_option & 24) { // 8 or 16
  1199. // prepare map name
  1200. memset(temp, 0, 17);
  1201. strncpy(temp, char_dat[j].last_point.map, 16);
  1202. if (strstr(temp, ".gat") != NULL) {
  1203. temp[strstr(temp, ".gat") - temp] = 0; // suppress the '.gat'
  1204. }
  1205. // write map name
  1206. if (online_display_option & 16) { // map-name AND coordonates
  1207. fprintf(fp2, " <td>%s (%d, %d)</td>\n", temp, char_dat[j].last_point.x, char_dat[j].last_point.y);
  1208. fprintf(fp, "%-12s (%3d,%3d) ", temp, char_dat[j].last_point.x, char_dat[j].last_point.y);
  1209. } else {
  1210. fprintf(fp2, " <td>%s</td>\n", temp);
  1211. fprintf(fp, "%-12s ", temp);
  1212. }
  1213. }
  1214. // displaying nimber of zenys
  1215. if (online_display_option & 32) {
  1216. // write number of zenys
  1217. if (char_dat[j].zeny == 0) { // if no zeny
  1218. fprintf(fp2, " <td ALIGN=RIGHT>no zeny</td>\n");
  1219. fprintf(fp, " no zeny ");
  1220. } else {
  1221. fprintf(fp2, " <td ALIGN=RIGHT>%d z</td>\n", char_dat[j].zeny);
  1222. fprintf(fp, "%13d z ", char_dat[j].zeny);
  1223. }
  1224. }
  1225. fprintf(fp, "\n");
  1226. fprintf(fp2, " </tr>\n");
  1227. }
  1228. // If we display at least 1 player
  1229. if (players > 0) {
  1230. fprintf(fp2, " </table>\n");
  1231. fprintf(fp, "\n");
  1232. }
  1233. // Displaying number of online players
  1234. if (players == 0) {
  1235. fprintf(fp2, " <p>No user is online.</p>\n");
  1236. fprintf(fp, "No user is online.\n");
  1237. // no display if only 1 player
  1238. } else if (players == 1) {
  1239. } else {
  1240. fprintf(fp2, " <p>%d users are online.</p>\n", players);
  1241. fprintf(fp, "%d users are online.\n", players);
  1242. }
  1243. fprintf(fp2, " </BODY>\n");
  1244. fprintf(fp2, "</HTML>\n");
  1245. fclose(fp2);
  1246. }
  1247. fclose(fp);
  1248. }
  1249. return;
  1250. }
  1251. //---------------------------------------------------------------------
  1252. // This function return the number of online players in all map-servers
  1253. //---------------------------------------------------------------------
  1254. int count_users(void) {
  1255. int i, users;
  1256. users = 0;
  1257. for(i = 0; i < MAX_MAP_SERVERS; i++)
  1258. if (server_fd[i] >= 0)
  1259. users += server[i].users;
  1260. return users;
  1261. }
  1262. //----------------------------------------
  1263. // Function to send characters to a player
  1264. //----------------------------------------
  1265. int mmo_char_send006b(int fd, struct char_session_data *sd) {
  1266. int i, j, found_num;
  1267. struct mmo_charstatus *p;
  1268. #ifdef NEW_006b
  1269. const int offset = 24;
  1270. #else
  1271. const int offset = 4;
  1272. #endif
  1273. found_num = 0;
  1274. for(i = 0; i < char_num; i++) {
  1275. if (char_dat[i].account_id == sd->account_id) {
  1276. sd->found_char[found_num] = i;
  1277. found_num++;
  1278. if (found_num == 9)
  1279. break;
  1280. }
  1281. }
  1282. for(i = found_num; i < 9; i++)
  1283. sd->found_char[i] = -1;
  1284. memset(WFIFOP(fd,0), 0, offset + found_num * 106);
  1285. WFIFOW(fd,0) = 0x6b;
  1286. WFIFOW(fd,2) = offset + found_num * 106;
  1287. for(i = 0; i < found_num; i++) {
  1288. p = &char_dat[sd->found_char[i]];
  1289. j = offset + (i * 106); // increase speed of code
  1290. WFIFOL(fd,j) = p->char_id;
  1291. WFIFOL(fd,j+4) = p->base_exp;
  1292. WFIFOL(fd,j+8) = p->zeny;
  1293. WFIFOL(fd,j+12) = p->job_exp;
  1294. WFIFOL(fd,j+16) = p->job_level;
  1295. WFIFOL(fd,j+20) = 0;
  1296. WFIFOL(fd,j+24) = 0;
  1297. WFIFOL(fd,j+28) = p->option;
  1298. WFIFOL(fd,j+32) = p->karma;
  1299. WFIFOL(fd,j+36) = p->manner;
  1300. WFIFOW(fd,j+40) = p->status_point;
  1301. WFIFOW(fd,j+42) = (p->hp > 0x7fff) ? 0x7fff : p->hp;
  1302. WFIFOW(fd,j+44) = (p->max_hp > 0x7fff) ? 0x7fff : p->max_hp;
  1303. WFIFOW(fd,j+46) = (p->sp > 0x7fff) ? 0x7fff : p->sp;
  1304. WFIFOW(fd,j+48) = (p->max_sp > 0x7fff) ? 0x7fff : p->max_sp;
  1305. WFIFOW(fd,j+50) = DEFAULT_WALK_SPEED; // p->speed;
  1306. WFIFOW(fd,j+52) = p->class_;
  1307. WFIFOW(fd,j+54) = p->hair;
  1308. // pecopeco knights/crusaders crash fix
  1309. if (p->class_ == 13 || p->class_ == 21 ||
  1310. p->class_ == 4014 || p->class_ == 4022)
  1311. WFIFOW(fd,j+56) = 0;
  1312. else WFIFOW(fd,j+56) = p->weapon;
  1313. WFIFOW(fd,j+58) = p->base_level;
  1314. WFIFOW(fd,j+60) = p->skill_point;
  1315. WFIFOW(fd,j+62) = p->head_bottom;
  1316. WFIFOW(fd,j+64) = p->shield;
  1317. WFIFOW(fd,j+66) = p->head_top;
  1318. WFIFOW(fd,j+68) = p->head_mid;
  1319. WFIFOW(fd,j+70) = p->hair_color;
  1320. WFIFOW(fd,j+72) = p->clothes_color;
  1321. memcpy(WFIFOP(fd,j+74), p->name, 24);
  1322. WFIFOB(fd,j+98) = (p->str > 255) ? 255 : p->str;
  1323. WFIFOB(fd,j+99) = (p->agi > 255) ? 255 : p->agi;
  1324. WFIFOB(fd,j+100) = (p->vit > 255) ? 255 : p->vit;
  1325. WFIFOB(fd,j+101) = (p->int_ > 255) ? 255 : p->int_;
  1326. WFIFOB(fd,j+102) = (p->dex > 255) ? 255 : p->dex;
  1327. WFIFOB(fd,j+103) = (p->luk > 255) ? 255 : p->luk;
  1328. WFIFOB(fd,j+104) = p->char_num;
  1329. }
  1330. WFIFOSET(fd,WFIFOW(fd,2));
  1331. return 0;
  1332. }
  1333. int set_account_reg2(int acc, int num, struct global_reg *reg) {
  1334. int i, c;
  1335. c = 0;
  1336. for(i = 0; i < char_num; i++) {
  1337. if (char_dat[i].account_id == acc) {
  1338. memcpy(char_dat[i].account_reg2, reg, sizeof(char_dat[i].account_reg2));
  1339. char_dat[i].account_reg2_num = num;
  1340. c++;
  1341. }
  1342. }
  1343. return c;
  1344. }
  1345. // 離婚(char削除時に使用)
  1346. int char_divorce(struct mmo_charstatus *cs) {
  1347. if (cs == NULL)
  1348. return 0;
  1349. if (cs->partner_id > 0){
  1350. int i, j;
  1351. for(i = 0; i < char_num; i++) {
  1352. if (char_dat[i].char_id == cs->partner_id && char_dat[i].partner_id == cs->char_id) {
  1353. cs->partner_id = 0;
  1354. char_dat[i].partner_id = 0;
  1355. for(j = 0; j < MAX_INVENTORY; j++)
  1356. if (char_dat[i].inventory[j].nameid == WEDDING_RING_M || char_dat[i].inventory[j].nameid == WEDDING_RING_F)
  1357. memset(&char_dat[i].inventory[j], 0, sizeof(char_dat[i].inventory[0]));
  1358. if (cs->inventory[j].nameid == WEDDING_RING_M || cs->inventory[j].nameid == WEDDING_RING_F)
  1359. memset(&cs->inventory[j], 0, sizeof(cs->inventory[0]));
  1360. return 0;
  1361. }
  1362. }
  1363. }
  1364. return 0;
  1365. }
  1366. //------------------------------------------------------------
  1367. // E-mail check: return 0 (not correct) or 1 (valid). by [Yor]
  1368. //------------------------------------------------------------
  1369. int e_mail_check(char *email) {
  1370. char ch;
  1371. char* last_arobas;
  1372. // athena limits
  1373. if (strlen(email) < 3 || strlen(email) > 39)
  1374. return 0;
  1375. // part of RFC limits (official reference of e-mail description)
  1376. if (strchr(email, '@') == NULL || email[strlen(email)-1] == '@')
  1377. return 0;
  1378. if (email[strlen(email)-1] == '.')
  1379. return 0;
  1380. last_arobas = strrchr(email, '@');
  1381. if (strstr(last_arobas, "@.") != NULL ||
  1382. strstr(last_arobas, "..") != NULL)
  1383. return 0;
  1384. for(ch = 1; ch < 32; ch++) {
  1385. if (strchr(last_arobas, ch) != NULL) {
  1386. return 0;
  1387. break;
  1388. }
  1389. }
  1390. if (strchr(last_arobas, ' ') != NULL ||
  1391. strchr(last_arobas, ';') != NULL)
  1392. return 0;
  1393. // all correct
  1394. return 1;
  1395. }
  1396. //----------------------------------------------------------------------
  1397. // Force disconnection of an online player (with account value) by [Yor]
  1398. //----------------------------------------------------------------------
  1399. int disconnect_player(int accound_id) {
  1400. int i;
  1401. struct char_session_data *sd;
  1402. // disconnect player if online on char-server
  1403. for(i = 0; i < fd_max; i++) {
  1404. if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) {
  1405. if (sd->account_id == accound_id) {
  1406. session[i]->eof = 1;
  1407. return 1;
  1408. }
  1409. }
  1410. }
  1411. return 0;
  1412. }
  1413. // キャラ削除に伴うデータ削除
  1414. static int char_delete(struct mmo_charstatus *cs) {
  1415. int j;
  1416. // ペット削除
  1417. if (cs->pet_id)
  1418. inter_pet_delete(cs->pet_id);
  1419. for (j = 0; j < MAX_INVENTORY; j++)
  1420. if (cs->inventory[j].card[0] == (short)0xff00)
  1421. inter_pet_delete(*((long *)(&cs->inventory[j].card[2])));
  1422. for (j = 0; j < MAX_CART; j++)
  1423. if (cs->cart[j].card[0] == (short)0xff00)
  1424. inter_pet_delete(*((long *)(&cs->cart[j].card[2])));
  1425. // ギルド脱退
  1426. if (cs->guild_id)
  1427. inter_guild_leave(cs->guild_id, cs->account_id, cs->char_id);
  1428. // パーティー脱退
  1429. if (cs->party_id)
  1430. inter_party_leave(cs->party_id, cs->account_id);
  1431. // 離婚
  1432. if (cs->partner_id){
  1433. // 離婚情報をmapに通知
  1434. unsigned char buf[10];
  1435. WBUFW(buf,0) = 0x2b12;
  1436. WBUFL(buf,2) = cs->char_id;
  1437. WBUFL(buf,6) = cs->partner_id;
  1438. mapif_sendall(buf,10);
  1439. // 離婚
  1440. char_divorce(cs);
  1441. }
  1442. return 0;
  1443. }
  1444. int parse_tologin(int fd) {
  1445. int i;
  1446. struct char_session_data *sd;
  1447. // only login-server can have an access to here.
  1448. // so, if it isn't the login-server, we disconnect the session (fd != login_fd).
  1449. if (fd != login_fd)
  1450. session[fd]->eof = 1;
  1451. if(session[fd]->eof) {
  1452. if (fd == login_fd) {
  1453. printf("Char-server can't connect to login-server (connection #%d).\n", fd);
  1454. login_fd = -1;
  1455. }
  1456. close(fd);
  1457. delete_session(fd);
  1458. return 0;
  1459. }
  1460. sd = (struct char_session_data*)session[fd]->session_data;
  1461. while(RFIFOREST(fd) >= 2) {
  1462. // printf("parse_tologin: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd));
  1463. switch(RFIFOW(fd,0)) {
  1464. case 0x2711:
  1465. if (RFIFOREST(fd) < 3)
  1466. return 0;
  1467. if (RFIFOB(fd,2)) {
  1468. // printf("connect login server error : %d\n", RFIFOB(fd,2));
  1469. printf("Can not connect to login-server.\n");
  1470. printf("The server communication passwords (default s1/p1) is probably invalid.\n");
  1471. printf("Also, please make sure your accounts file (default: accounts.txt) has those values present.\n");
  1472. printf("If you changed the communication passwords, change them back at map_athena.conf and char_athena.conf\n");
  1473. exit(1);
  1474. } else {
  1475. printf("Connected to login-server (connection #%d).\n", fd);
  1476. // if no map-server already connected, display a message...
  1477. for(i = 0; i < MAX_MAP_SERVERS; i++)
  1478. if (server_fd[i] >= 0 && server[i].map[0][0]) // if map-server online and at least 1 map
  1479. break;
  1480. if (i == MAX_MAP_SERVERS)
  1481. printf("Awaiting maps from map-server.\n");
  1482. }
  1483. RFIFOSKIP(fd,3);
  1484. break;
  1485. case 0x2713:
  1486. if (RFIFOREST(fd) < 51)
  1487. return 0;
  1488. // printf("parse_tologin 2713 : %d\n", RFIFOB(fd,6));
  1489. for(i = 0; i < fd_max; i++) {
  1490. if (session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == RFIFOL(fd,2)) {
  1491. if (RFIFOB(fd,6) != 0) {
  1492. WFIFOW(i,0) = 0x6c;
  1493. WFIFOB(i,2) = 0x42;
  1494. WFIFOSET(i,3);
  1495. } else if (max_connect_user == 0 || count_users() < max_connect_user) {
  1496. // if (max_connect_user == 0)
  1497. // printf("max_connect_user (unlimited) -> accepted.\n");
  1498. // else
  1499. // printf("count_users(): %d < max_connect_user (%d) -> accepted.\n", count_users(), max_connect_user);
  1500. memcpy(sd->email, RFIFOP(fd, 7), 40);
  1501. if (e_mail_check(sd->email) == 0)
  1502. strncpy(sd->email, "a@a.com", 40); // default e-mail
  1503. sd->connect_until_time = (time_t)RFIFOL(fd,47);
  1504. // send characters to player
  1505. mmo_char_send006b(i, sd);
  1506. } else if(isGM(sd->account_id) >= gm_allow_level) {
  1507. sd->connect_until_time = (time_t)RFIFOL(fd,47);
  1508. // send characters to player
  1509. mmo_char_send006b(i, sd);
  1510. } else {
  1511. // refuse connection: too much online players
  1512. // printf("count_users(): %d < max_connect_use (%d) -> fail...\n", count_users(), max_connect_user);
  1513. WFIFOW(i,0) = 0x6c;
  1514. WFIFOW(i,2) = 0;
  1515. WFIFOSET(i,3);
  1516. }
  1517. break;
  1518. }
  1519. }
  1520. RFIFOSKIP(fd,51);
  1521. break;
  1522. // 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]
  1523. case 0x2717:
  1524. if (RFIFOREST(fd) < 50)
  1525. return 0;
  1526. for(i = 0; i < fd_max; i++) {
  1527. if (session[i] && (sd = (struct char_session_data*)session[i]->session_data)) {
  1528. if (sd->account_id == RFIFOL(fd,2)) {
  1529. memcpy(sd->email, RFIFOP(fd,6), 40);
  1530. if (e_mail_check(sd->email) == 0)
  1531. strncpy(sd->email, "a@a.com", 40); // default e-mail
  1532. sd->connect_until_time = (time_t)RFIFOL(fd,46);
  1533. break;
  1534. }
  1535. }
  1536. }
  1537. RFIFOSKIP(fd,50);
  1538. break;
  1539. // login-server alive packet
  1540. case 0x2718:
  1541. if (RFIFOREST(fd) < 2)
  1542. return 0;
  1543. // do whatever it's supposed to do here?
  1544. RFIFOSKIP(fd,2);
  1545. break;
  1546. case 0x2721: // gm reply
  1547. if (RFIFOREST(fd) < 10)
  1548. return 0;
  1549. {
  1550. unsigned char buf[10];
  1551. WBUFW(buf,0) = 0x2b0b;
  1552. WBUFL(buf,2) = RFIFOL(fd,2); // account
  1553. WBUFL(buf,6) = RFIFOL(fd,6); // GM level
  1554. mapif_sendall(buf,10);
  1555. // printf("parse_tologin: To become GM answer: char -> map.\n");
  1556. }
  1557. RFIFOSKIP(fd,10);
  1558. break;
  1559. case 0x2723: // changesex reply (modified by [Yor])
  1560. if (RFIFOREST(fd) < 7)
  1561. return 0;
  1562. {
  1563. int acc, sex, i, j;
  1564. unsigned char buf[7];
  1565. acc = RFIFOL(fd,2);
  1566. sex = RFIFOB(fd,6);
  1567. RFIFOSKIP(fd, 7);
  1568. if (acc > 0) {
  1569. for (i = 0; i < char_num; i++) {
  1570. if (char_dat[i].account_id == acc) {
  1571. int jobclass = char_dat[i].class_;
  1572. char_dat[i].sex = sex;
  1573. auth_fifo[i].sex = sex;
  1574. if (jobclass == 19 || jobclass == 20 ||
  1575. jobclass == 4020 || jobclass == 4021 ||
  1576. jobclass == 4042 || jobclass == 4043) {
  1577. // job modification
  1578. if (jobclass == 19 || jobclass == 20) {
  1579. char_dat[i].class_ = (sex) ? 19 : 20;
  1580. } else if (jobclass == 4020 || jobclass == 4021) {
  1581. char_dat[i].class_ = (sex) ? 4020 : 4021;
  1582. } else if (jobclass == 4042 || jobclass == 4043) {
  1583. char_dat[i].class_ = (sex) ? 4042 : 4043;
  1584. }
  1585. // remove specifical skills of classes 19, 4020 and 4042
  1586. for(j = 315; j <= 322; j++) {
  1587. if (char_dat[i].skill[j].id > 0 && !char_dat[i].skill[j].flag) {
  1588. char_dat[i].skill_point += char_dat[i].skill[j].lv;
  1589. char_dat[i].skill[j].id = 0;
  1590. char_dat[i].skill[j].lv = 0;
  1591. }
  1592. }
  1593. // remove specifical skills of classes 20, 4021 and 4043
  1594. for(j = 323; j <= 330; j++) {
  1595. if (char_dat[i].skill[j].id > 0 && !char_dat[i].skill[j].flag) {
  1596. char_dat[i].skill_point += char_dat[i].skill[j].lv;
  1597. char_dat[i].skill[j].id = 0;
  1598. char_dat[i].skill[j].lv = 0;
  1599. }
  1600. }
  1601. }
  1602. // to avoid any problem with equipment and invalid sex, equipment is unequiped.
  1603. for (j = 0; j < MAX_INVENTORY; j++) {
  1604. if (char_dat[i].inventory[j].nameid && char_dat[i].inventory[j].equip)
  1605. char_dat[i].inventory[j].equip = 0;
  1606. }
  1607. char_dat[i].weapon = 0;
  1608. char_dat[i].shield = 0;
  1609. char_dat[i].head_top = 0;
  1610. char_dat[i].head_mid = 0;
  1611. char_dat[i].head_bottom = 0;
  1612. }
  1613. }
  1614. // disconnect player if online on char-server
  1615. disconnect_player(acc);
  1616. }
  1617. WBUFW(buf,0) = 0x2b0d;
  1618. WBUFL(buf,2) = acc;
  1619. WBUFB(buf,6) = sex;
  1620. mapif_sendall(buf, 7);
  1621. }
  1622. break;
  1623. case 0x2726: // Request to send a broadcast message (no answer)
  1624. if (RFIFOREST(fd) < 8 || RFIFOREST(fd) < (8 + RFIFOL(fd,4)))
  1625. return 0;
  1626. if (RFIFOL(fd,4) < 1)
  1627. char_log("Receiving a message for broadcast, but message is void." RETCODE);
  1628. else {
  1629. // at least 1 map-server
  1630. for(i = 0; i < MAX_MAP_SERVERS; i++)
  1631. if (server_fd[i] >= 0)
  1632. break;
  1633. if (i == MAX_MAP_SERVERS)
  1634. char_log("'ladmin': Receiving a message for broadcast, but no map-server is online." RETCODE);
  1635. else {
  1636. unsigned char buf[128];
  1637. char message[RFIFOL(fd,4) + 1]; // +1 to add a null terminated if not exist in the packet
  1638. int lp;
  1639. char *p;
  1640. memset(message, '\0', sizeof(message));
  1641. memcpy(message, RFIFOP(fd,8), RFIFOL(fd,4));
  1642. message[sizeof(message)-1] = '\0';
  1643. remove_control_chars(message);
  1644. // remove all first spaces
  1645. p = message;
  1646. while(p[0] == ' ')
  1647. p++;
  1648. // if message is only composed of spaces
  1649. if (p[0] == '\0')
  1650. char_log("Receiving a message for broadcast, but message is only a lot of spaces." RETCODE);
  1651. // else send message to all map-servers
  1652. else {
  1653. if (RFIFOW(fd,2) == 0) {
  1654. char_log("'ladmin': Receiving a message for broadcast (message (in yellow): %s)" RETCODE,
  1655. message);
  1656. lp = 4;
  1657. } else {
  1658. char_log("'ladmin': Receiving a message for broadcast (message (in blue): %s)" RETCODE,
  1659. message);
  1660. lp = 8;
  1661. }
  1662. // split message to max 80 char
  1663. while(p[0] != '\0') { // if not finish
  1664. if (p[0] == ' ') // jump if first char is a space
  1665. p++;
  1666. else {
  1667. char split[80];
  1668. char* last_space;
  1669. sscanf(p, "%79[^\t]", split); // max 79 char, any char (\t is control char and control char was removed before)
  1670. split[sizeof(split)-1] = '\0'; // last char always \0
  1671. if ((last_space = strrchr(split, ' ')) != NULL) { // searching space from end of the string
  1672. last_space[0] = '\0'; // replace it by NULL to have correct length of split
  1673. p++; // to jump the new NULL
  1674. }
  1675. p += strlen(split);
  1676. // send broadcast to all map-servers
  1677. WBUFW(buf,0) = 0x3800;
  1678. WBUFW(buf,2) = lp + strlen(split) + 1;
  1679. WBUFL(buf,4) = 0x65756c62; // only write if in blue (lp = 8)
  1680. memcpy(WBUFP(buf,lp), split, strlen(split) + 1);
  1681. mapif_sendall(buf, WBUFW(buf,2));
  1682. }
  1683. }
  1684. }
  1685. }
  1686. }
  1687. RFIFOSKIP(fd,8 + RFIFOL(fd,4));
  1688. break;
  1689. // account_reg2変更通知
  1690. case 0x2729:
  1691. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  1692. return 0;
  1693. {
  1694. struct global_reg reg[ACCOUNT_REG2_NUM];
  1695. unsigned char buf[4096];
  1696. int j, p, acc;
  1697. acc = RFIFOL(fd,4);
  1698. for (p = 8, j = 0; p < RFIFOW(fd,2) && j < ACCOUNT_REG2_NUM; p += 36, j++) {
  1699. memcpy(reg[j].str, RFIFOP(fd,p), 32);
  1700. reg[j].value = RFIFOL(fd,p+32);
  1701. }
  1702. set_account_reg2(acc, j, reg);
  1703. // 同垢ログインを禁止していれば送る必要は無い
  1704. memcpy(buf, RFIFOP(fd,0), RFIFOW(fd,2));
  1705. WBUFW(buf,0) = 0x2b11;
  1706. mapif_sendall(buf, WBUFW(buf,2));
  1707. RFIFOSKIP(fd,RFIFOW(fd,2));
  1708. // printf("char: save_account_reg_reply\n");
  1709. }
  1710. break;
  1711. // Account deletion notification (from login-server)
  1712. case 0x2730:
  1713. if (RFIFOREST(fd) < 6)
  1714. return 0;
  1715. // Deletion of all characters of the account
  1716. for(i = 0; i < char_num; i++) {
  1717. if (char_dat[i].account_id == RFIFOL(fd,2)) {
  1718. char_delete(&char_dat[i]);
  1719. if (i < char_num - 1) {
  1720. memcpy(&char_dat[i], &char_dat[char_num-1], sizeof(struct mmo_charstatus));
  1721. // if moved character owns to deleted account, check again it's character
  1722. if (char_dat[i].account_id == RFIFOL(fd,2)) {
  1723. i--;
  1724. // Correct moved character reference in the character's owner by [Yor]
  1725. } else {
  1726. int j, k;
  1727. struct char_session_data *sd2;
  1728. for (j = 0; j < fd_max; j++) {
  1729. if (session[j] && (sd2 = (struct char_session_data*)session[j]->session_data) &&
  1730. sd2->account_id == char_dat[char_num-1].account_id) {
  1731. for (k = 0; k < 9; k++) {
  1732. if (sd2->found_char[k] == char_num-1) {
  1733. sd2->found_char[k] = i;
  1734. break;
  1735. }
  1736. }
  1737. break;
  1738. }
  1739. }
  1740. }
  1741. }
  1742. char_num--;
  1743. }
  1744. }
  1745. // Deletion of the storage
  1746. inter_storage_delete(RFIFOL(fd,2));
  1747. // send to all map-servers to disconnect the player
  1748. {
  1749. unsigned char buf[6];
  1750. WBUFW(buf,0) = 0x2b13;
  1751. WBUFL(buf,2) = RFIFOL(fd,2);
  1752. mapif_sendall(buf, 6);
  1753. }
  1754. // disconnect player if online on char-server
  1755. disconnect_player(RFIFOL(fd,2));
  1756. RFIFOSKIP(fd,6);
  1757. break;
  1758. // State change of account/ban notification (from login-server) by [Yor]
  1759. case 0x2731:
  1760. if (RFIFOREST(fd) < 11)
  1761. return 0;
  1762. // send to all map-servers to disconnect the player
  1763. {
  1764. unsigned char buf[11];
  1765. WBUFW(buf,0) = 0x2b14;
  1766. WBUFL(buf,2) = RFIFOL(fd,2);
  1767. WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
  1768. WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
  1769. mapif_sendall(buf, 11);
  1770. }
  1771. // disconnect player if online on char-server
  1772. disconnect_player(RFIFOL(fd,2));
  1773. RFIFOSKIP(fd,11);
  1774. break;
  1775. // Receiving GM acounts info from login-server (by [Yor])
  1776. case 0x2732:
  1777. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  1778. return 0;
  1779. {
  1780. unsigned char buf[32000];
  1781. if (gm_account != NULL)
  1782. aFree(gm_account);
  1783. gm_account = (struct gm_account*)aCalloc(sizeof(struct gm_account) * ((RFIFOW(fd,2) - 4) / 5), 1);
  1784. GM_num = 0;
  1785. for (i = 4; i < RFIFOW(fd,2); i = i + 5) {
  1786. gm_account[GM_num].account_id = RFIFOL(fd,i);
  1787. gm_account[GM_num].level = (int)RFIFOB(fd,i+4);
  1788. //printf("GM account: %d -> level %d\n", gm_account[GM_num].account_id, gm_account[GM_num].level);
  1789. GM_num++;
  1790. }
  1791. printf("From login-server: receiving of %d GM accounts information.\n", GM_num);
  1792. char_log("From login-server: receiving of %d GM accounts information." RETCODE, GM_num);
  1793. create_online_files(); // update online players files (perhaps some online players change of GM level)
  1794. // send new gm acccounts level to map-servers
  1795. memcpy(buf, RFIFOP(fd,0), RFIFOW(fd,2));
  1796. WBUFW(buf,0) = 0x2b15;
  1797. mapif_sendall(buf, RFIFOW(fd,2));
  1798. }
  1799. RFIFOSKIP(fd,RFIFOW(fd,2));
  1800. break;
  1801. default:
  1802. printf("parse_tologin: unknown packet %x! \n", RFIFOW(fd,0));
  1803. session[fd]->eof = 1;
  1804. return 0;
  1805. }
  1806. }
  1807. RFIFOFLUSH(fd);
  1808. return 0;
  1809. }
  1810. //--------------------------------
  1811. // Map-server anti-freeze system
  1812. //--------------------------------
  1813. int map_anti_freeze_system(int tid, unsigned int tick, int id, int data) {
  1814. int i;
  1815. //printf("Entering in map_anti_freeze_system function to check freeze of servers.\n");
  1816. for(i = 0; i < MAX_MAP_SERVERS; i++) {
  1817. if (server_fd[i] >= 0) {// if map-server is online
  1818. //printf("map_anti_freeze_system: server #%d, flag: %d.\n", i, server_freezeflag[i]);
  1819. if (server_freezeflag[i]-- < 1) { // Map-server anti-freeze system. Counter. 5 ok, 4...0 freezed
  1820. printf("Map-server anti-freeze system: char-server #%d is freezed -> disconnection.\n", i);
  1821. char_log("Map-server anti-freeze system: char-server #%d is freezed -> disconnection." RETCODE,
  1822. i);
  1823. session[server_fd[i]]->eof = 1;
  1824. }
  1825. }
  1826. }
  1827. return 0;
  1828. }
  1829. int parse_frommap(int fd) {
  1830. int i, j;
  1831. int id;
  1832. for(id = 0; id < MAX_MAP_SERVERS; id++)
  1833. if (server_fd[id] == fd)
  1834. break;
  1835. if(id==MAX_MAP_SERVERS)
  1836. session[fd]->eof=1;
  1837. if(session[fd]->eof){
  1838. for(i = 0; i < MAX_MAP_SERVERS; i++)
  1839. if (server_fd[i] == fd) {
  1840. printf("Map-server %d has disconnected.\n", i);
  1841. server_fd[i] = -1;
  1842. }
  1843. close(fd);
  1844. delete_session(fd);
  1845. create_online_files();
  1846. return 0;
  1847. }
  1848. while(RFIFOREST(fd) >= 2) {
  1849. // printf("parse_frommap: connection #%d, packet: 0x%x (with being read: %d bytes).\n", fd, RFIFOW(fd,0), RFIFOREST(fd));
  1850. switch(RFIFOW(fd,0)) {
  1851. // request from map-server to reload GM accounts. Transmission to login-server (by Yor)
  1852. case 0x2af7:
  1853. if (login_fd > 0) { // don't send request if no login-server
  1854. WFIFOW(login_fd,0) = 0x2709;
  1855. WFIFOSET(login_fd, 2);
  1856. // printf("char : request from map-server to reload GM accounts -> login-server.\n");
  1857. }
  1858. RFIFOSKIP(fd,2);
  1859. break;
  1860. // Receiving map names list from the map-server
  1861. case 0x2afa:
  1862. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  1863. return 0;
  1864. memset(server[id].map, 0, sizeof(server[id].map));
  1865. j = 0;
  1866. for(i = 4; i < RFIFOW(fd,2); i += 16) {
  1867. memcpy(server[id].map[j], RFIFOP(fd,i), 16);
  1868. // printf("set map %d.%d : %s\n", id, j, server[id].map[j]);
  1869. j++;
  1870. }
  1871. {
  1872. unsigned char *p = (unsigned char *)&server[id].ip;
  1873. printf("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n",
  1874. id, j, p[0], p[1], p[2], p[3], server[id].port);
  1875. printf("Map-server %d loading complete.\n", id);
  1876. char_log("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d. Map-server %d loading complete." RETCODE,
  1877. id, j, p[0], p[1], p[2], p[3], server[id].port, id);
  1878. }
  1879. WFIFOW(fd,0) = 0x2afb;
  1880. WFIFOB(fd,2) = 0;
  1881. memcpy(WFIFOP(fd,3), wisp_server_name, 24); // name for wisp to player
  1882. WFIFOSET(fd,27);
  1883. {
  1884. unsigned char buf[16384];
  1885. int x;
  1886. if (j == 0) {
  1887. printf("WARNING: Map-Server %d have NO map.\n", id);
  1888. char_log("WARNING: Map-Server %d have NO map." RETCODE, id);
  1889. // Transmitting maps information to the other map-servers
  1890. } else {
  1891. WBUFW(buf,0) = 0x2b04;
  1892. WBUFW(buf,2) = j * 16 + 10;
  1893. WBUFL(buf,4) = server[id].ip;
  1894. WBUFW(buf,8) = server[id].port;
  1895. memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 16);
  1896. mapif_sendallwos(fd, buf, WBUFW(buf,2));
  1897. }
  1898. // Transmitting the maps of the other map-servers to the new map-server
  1899. for(x = 0; x < MAX_MAP_SERVERS; x++) {
  1900. if (server_fd[x] >= 0 && x != id) {
  1901. WFIFOW(fd,0) = 0x2b04;
  1902. WFIFOL(fd,4) = server[x].ip;
  1903. WFIFOW(fd,8) = server[x].port;
  1904. j = 0;
  1905. for(i = 0; i < MAX_MAP_PER_SERVER; i++)
  1906. if (server[x].map[i][0])
  1907. memcpy(WFIFOP(fd,10+(j++)*16), server[x].map[i], 16);
  1908. if (j > 0) {
  1909. WFIFOW(fd,2) = j * 16 + 10;
  1910. WFIFOSET(fd,WFIFOW(fd,2));
  1911. }
  1912. }
  1913. }
  1914. }
  1915. RFIFOSKIP(fd,RFIFOW(fd,2));
  1916. break;
  1917. // 認証要�
  1918. // Send character data to map-server�
  1919. case 0x2afc:
  1920. if (RFIFOREST(fd) < 22)
  1921. return 0;
  1922. //printf("auth_fifo search: account: %d, char: %d, secure: %08x-%08x\n", RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14));
  1923. for(i = 0; i < AUTH_FIFO_SIZE; i++) {
  1924. if (auth_fifo[i].account_id == RFIFOL(fd,2) &&
  1925. auth_fifo[i].char_id == RFIFOL(fd,6) &&
  1926. auth_fifo[i].login_id1 == RFIFOL(fd,10) &&
  1927. #if CMP_AUTHFIFO_LOGIN2 != 0
  1928. // here, it's the only area where it's possible that we doesn't know login_id2 (map-server asks just after 0x72 packet, that doesn't given the value)
  1929. (auth_fifo[i].login_id2 == RFIFOL(fd,14) || RFIFOL(fd,14) == 0) && // relate to the versions higher than 18
  1930. #endif
  1931. (!check_ip_flag || auth_fifo[i].ip == RFIFOL(fd,18)) &&
  1932. !auth_fifo[i].delflag) {
  1933. auth_fifo[i].delflag = 1;
  1934. WFIFOW(fd,0) = 0x2afd;
  1935. WFIFOW(fd,2) = 16 + sizeof(struct mmo_charstatus);
  1936. WFIFOL(fd,4) = RFIFOL(fd,2);
  1937. WFIFOL(fd,8) = auth_fifo[i].login_id2;
  1938. WFIFOL(fd,12) = (unsigned long)auth_fifo[i].connect_until_time;
  1939. char_dat[auth_fifo[i].char_pos].sex = auth_fifo[i].sex;
  1940. memcpy(WFIFOP(fd,16), &char_dat[auth_fifo[i].char_pos], sizeof(struct mmo_charstatus));
  1941. WFIFOSET(fd, WFIFOW(fd,2));
  1942. //printf("auth_fifo search success (auth #%d, account %d, character: %d).\n", i, RFIFOL(fd,2), RFIFOL(fd,6));
  1943. break;
  1944. }
  1945. }
  1946. if (i == AUTH_FIFO_SIZE) {
  1947. WFIFOW(fd,0) = 0x2afe;
  1948. WFIFOL(fd,2) = RFIFOL(fd,2);
  1949. WFIFOSET(fd,6);
  1950. printf("auth_fifo search error! account %d not authentified.\n", RFIFOL(fd,2));
  1951. }
  1952. RFIFOSKIP(fd,22);
  1953. break;
  1954. // MAPサーバー上のユーザー数受信
  1955. // Recieve alive message from map-server
  1956. case 0x2aff:
  1957. if (RFIFOREST(fd) < 6 || RFIFOREST(fd) < RFIFOW(fd,2))
  1958. return 0;
  1959. server[id].users = RFIFOW(fd,4);
  1960. if(anti_freeze_enable)
  1961. server_freezeflag[id] = 5; // Map anti-freeze system. Counter. 5 ok, 4...0 freezed
  1962. // remove all previously online players of the server
  1963. for(i = 0; i < online_players_max; i++)
  1964. if (online_chars[i].server == id) {
  1965. online_chars[i].char_id = -1;
  1966. online_chars[i].server = -1;
  1967. }
  1968. // add online players in the list by [Yor]
  1969. j = 0;
  1970. for(i = 0; i < server[id].users; i++) {
  1971. for(; j < online_players_max; j++)
  1972. if (online_chars[j].char_id == -1) {
  1973. online_chars[j].char_id = RFIFOL(fd,6+i*4);
  1974. online_chars[j].server = id;
  1975. //printf("%d\n", online_chars[j].char_id);
  1976. break;
  1977. }
  1978. // no available slots...
  1979. if (j == online_players_max) {
  1980. // create 256 new slots
  1981. online_players_max += 256;
  1982. online_chars = (struct online_chars*)aRealloc(online_chars, sizeof(struct online_chars) * online_players_max);
  1983. if (!online_chars) {
  1984. printf("out of memory: parse_frommap - online_chars (realloc).\n");
  1985. exit(1);
  1986. }
  1987. for( ; j < online_players_max; j++) {
  1988. online_chars[j].char_id = -1;
  1989. online_chars[j].server = -1;
  1990. }
  1991. // save data
  1992. j = online_players_max - 256;
  1993. online_chars[j].char_id = RFIFOL(fd,6+i*4);
  1994. online_chars[j].server = id;
  1995. }
  1996. }
  1997. if (update_online < time(NULL)) { // Time is done
  1998. update_online = time(NULL) + 8;
  1999. create_online_files(); // only every 8 sec. (normally, 1 server send users every 5 sec.) Don't update every time, because that takes time, but only every 2 connection.
  2000. // it set to 8 sec because is more than 5 (sec) and if we have more than 1 map-server, informations can be received in shifted.
  2001. }
  2002. RFIFOSKIP(fd,6+i*4);
  2003. break;
  2004. // キャラデータ保存
  2005. // Recieve character data from map-server
  2006. case 0x2b01:
  2007. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2008. return 0;
  2009. for(i = 0; i < char_num; i++) {
  2010. if (char_dat[i].account_id == RFIFOL(fd,4) &&
  2011. char_dat[i].char_id == RFIFOL(fd,8))
  2012. break;
  2013. }
  2014. if (i != char_num)
  2015. memcpy(&char_dat[i], RFIFOP(fd,12), sizeof(struct mmo_charstatus));
  2016. RFIFOSKIP(fd,RFIFOW(fd,2));
  2017. break;
  2018. // キャラセレ要求
  2019. case 0x2b02:
  2020. if (RFIFOREST(fd) < 18)
  2021. return 0;
  2022. if (auth_fifo_pos >= AUTH_FIFO_SIZE)
  2023. auth_fifo_pos = 0;
  2024. //printf("auth_fifo set (auth #%d) - account: %d, secure: %08x-%08x\n", auth_fifo_pos, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10));
  2025. auth_fifo[auth_fifo_pos].account_id = RFIFOL(fd,2);
  2026. auth_fifo[auth_fifo_pos].char_id = 0;
  2027. auth_fifo[auth_fifo_pos].login_id1 = RFIFOL(fd,6);
  2028. auth_fifo[auth_fifo_pos].login_id2 = RFIFOL(fd,10);
  2029. auth_fifo[auth_fifo_pos].delflag = 2;
  2030. auth_fifo[auth_fifo_pos].char_pos = 0;
  2031. auth_fifo[auth_fifo_pos].connect_until_time = 0; // unlimited/unknown time by default (not display in map-server)
  2032. auth_fifo[auth_fifo_pos].ip = RFIFOL(fd,14);
  2033. auth_fifo_pos++;
  2034. WFIFOW(fd,0) = 0x2b03;
  2035. WFIFOL(fd,2) = RFIFOL(fd,2);
  2036. WFIFOB(fd,6) = 0;
  2037. WFIFOSET(fd,7);
  2038. RFIFOSKIP(fd,18);
  2039. break;
  2040. // マップサーバー間移動要求
  2041. case 0x2b05:
  2042. if (RFIFOREST(fd) < 49)
  2043. return 0;
  2044. if (auth_fifo_pos >= AUTH_FIFO_SIZE)
  2045. auth_fifo_pos = 0;
  2046. WFIFOW(fd,0) = 0x2b06;
  2047. memcpy(WFIFOP(fd,2), RFIFOP(fd,2), 42);
  2048. //printf("auth_fifo set (auth#%d) - account: %d, secure: 0x%08x-0x%08x\n", auth_fifo_pos, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10));
  2049. auth_fifo[auth_fifo_pos].account_id = RFIFOL(fd,2);
  2050. auth_fifo[auth_fifo_pos].char_id = RFIFOL(fd,14);
  2051. auth_fifo[auth_fifo_pos].login_id1 = RFIFOL(fd,6);
  2052. auth_fifo[auth_fifo_pos].login_id2 = RFIFOL(fd,10);
  2053. auth_fifo[auth_fifo_pos].delflag = 0;
  2054. auth_fifo[auth_fifo_pos].sex = RFIFOB(fd,44);
  2055. auth_fifo[auth_fifo_pos].connect_until_time = 0; // unlimited/unknown time by default (not display in map-server)
  2056. auth_fifo[auth_fifo_pos].ip = RFIFOL(fd,45);
  2057. for(i = 0; i < char_num; i++)
  2058. if (char_dat[i].account_id == RFIFOL(fd,2) &&
  2059. char_dat[i].char_id == RFIFOL(fd,14)) {
  2060. auth_fifo[auth_fifo_pos].char_pos = i;
  2061. auth_fifo_pos++;
  2062. WFIFOL(fd,6) = 0;
  2063. break;
  2064. }
  2065. if (i == char_num)
  2066. WFIFOW(fd,6) = 1;
  2067. WFIFOSET(fd,44);
  2068. RFIFOSKIP(fd,49);
  2069. break;
  2070. // キャラ名検索
  2071. case 0x2b08:
  2072. if (RFIFOREST(fd) < 6)
  2073. return 0;
  2074. for(i = 0; i < char_num; i++) {
  2075. if (char_dat[i].char_id == RFIFOL(fd,2))
  2076. break;
  2077. }
  2078. WFIFOW(fd,0) = 0x2b09;
  2079. WFIFOL(fd,2) = RFIFOL(fd,2);
  2080. if (i != char_num)
  2081. memcpy(WFIFOP(fd,6), char_dat[i].name, 24);
  2082. else
  2083. memcpy(WFIFOP(fd,6), unknown_char_name, 24);
  2084. WFIFOSET(fd,30);
  2085. RFIFOSKIP(fd,6);
  2086. break;
  2087. // it is a request to become GM
  2088. case 0x2b0a:
  2089. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2090. return 0;
  2091. // printf("parse_frommap: change gm -> login, account: %d, pass: '%s'.\n", RFIFOL(fd,4), RFIFOP(fd,8));
  2092. if (login_fd > 0) { // don't send request if no login-server
  2093. WFIFOW(login_fd,0) = 0x2720;
  2094. memcpy(WFIFOP(login_fd,2), RFIFOP(fd,2), RFIFOW(fd,2)-2);
  2095. WFIFOSET(login_fd, RFIFOW(fd,2));
  2096. } else {
  2097. WFIFOW(fd,0) = 0x2b0b;
  2098. WFIFOL(fd,2) = RFIFOL(fd,4);
  2099. WFIFOL(fd,6) = 0;
  2100. WFIFOSET(fd, 10);
  2101. }
  2102. RFIFOSKIP(fd, RFIFOW(fd,2));
  2103. break;
  2104. // Map server send information to change an email of an account -> login-server
  2105. case 0x2b0c:
  2106. if (RFIFOREST(fd) < 86)
  2107. return 0;
  2108. if (login_fd > 0) { // don't send request if no login-server
  2109. memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0), 86); // 0x2722 <account_id>.L <actual_e-mail>.40B <new_e-mail>.40B
  2110. WFIFOW(login_fd,0) = 0x2722;
  2111. WFIFOSET(login_fd, 86);
  2112. }
  2113. RFIFOSKIP(fd, 86);
  2114. break;
  2115. // Map server ask char-server about a character name to do some operations (all operations are transmitted to login-server)
  2116. case 0x2b0e:
  2117. if (RFIFOREST(fd) < 44)
  2118. return 0;
  2119. {
  2120. char character_name[24];
  2121. int acc = RFIFOL(fd,2); // account_id of who ask (-1 if nobody)
  2122. memcpy(character_name, RFIFOP(fd,6), 24);
  2123. character_name[sizeof(character_name) -1] = '\0';
  2124. // prepare answer
  2125. WFIFOW(fd,0) = 0x2b0f; // answer
  2126. WFIFOL(fd,2) = acc; // who want do operation
  2127. WFIFOW(fd,30) = RFIFOW(fd, 30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban, 5-changesex
  2128. // search character
  2129. i = search_character_index(character_name);
  2130. if (i >= 0) {
  2131. memcpy(WFIFOP(fd,6), search_character_name(i), 24); // put correct name if found
  2132. WFIFOW(fd,32) = 0; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2133. switch(RFIFOW(fd, 30)) {
  2134. case 1: // block
  2135. if (acc == -1 || isGM(acc) >= isGM(char_dat[i].account_id)) {
  2136. if (login_fd > 0) { // don't send request if no login-server
  2137. WFIFOW(login_fd,0) = 0x2724;
  2138. WFIFOL(login_fd,2) = char_dat[i].account_id; // account value
  2139. WFIFOL(login_fd,6) = 5; // status of the account
  2140. WFIFOSET(login_fd, 10);
  2141. // printf("char : status -> login: account %d, status: %d \n", char_dat[i].account_id, 5);
  2142. } else
  2143. WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2144. } else
  2145. WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2146. break;
  2147. case 2: // ban
  2148. if (acc == -1 || isGM(acc) >= isGM(char_dat[i].account_id)) {
  2149. if (login_fd > 0) { // don't send request if no login-server
  2150. WFIFOW(login_fd, 0) = 0x2725;
  2151. WFIFOL(login_fd, 2) = char_dat[i].account_id; // account value
  2152. WFIFOW(login_fd, 6) = RFIFOW(fd,32); // year
  2153. WFIFOW(login_fd, 8) = RFIFOW(fd,34); // month
  2154. WFIFOW(login_fd,10) = RFIFOW(fd,36); // day
  2155. WFIFOW(login_fd,12) = RFIFOW(fd,38); // hour
  2156. WFIFOW(login_fd,14) = RFIFOW(fd,40); // minute
  2157. WFIFOW(login_fd,16) = RFIFOW(fd,42); // second
  2158. WFIFOSET(login_fd,18);
  2159. // printf("char : status -> login: account %d, ban: %dy %dm %dd %dh %dmn %ds\n",
  2160. // char_dat[i].account_id, (short)RFIFOW(fd,32), (short)RFIFOW(fd,34), (short)RFIFOW(fd,36), (short)RFIFOW(fd,38), (short)RFIFOW(fd,40), (short)RFIFOW(fd,42));
  2161. } else
  2162. WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2163. } else
  2164. WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2165. break;
  2166. case 3: // unblock
  2167. if (acc == -1 || isGM(acc) >= isGM(char_dat[i].account_id)) {
  2168. if (login_fd > 0) { // don't send request if no login-server
  2169. WFIFOW(login_fd,0) = 0x2724;
  2170. WFIFOL(login_fd,2) = char_dat[i].account_id; // account value
  2171. WFIFOL(login_fd,6) = 0; // status of the account
  2172. WFIFOSET(login_fd, 10);
  2173. // printf("char : status -> login: account %d, status: %d \n", char_dat[i].account_id, 0);
  2174. } else
  2175. WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2176. } else
  2177. WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2178. break;
  2179. case 4: // unban
  2180. if (acc == -1 || isGM(acc) >= isGM(char_dat[i].account_id)) {
  2181. if (login_fd > 0) { // don't send request if no login-server
  2182. WFIFOW(login_fd, 0) = 0x272a;
  2183. WFIFOL(login_fd, 2) = char_dat[i].account_id; // account value
  2184. WFIFOSET(login_fd, 6);
  2185. // printf("char : status -> login: account %d, unban request\n", char_dat[i].account_id);
  2186. } else
  2187. WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2188. } else
  2189. WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2190. break;
  2191. case 5: // changesex
  2192. if (acc == -1 || isGM(acc) >= isGM(char_dat[i].account_id)) {
  2193. if (login_fd > 0) { // don't send request if no login-server
  2194. WFIFOW(login_fd, 0) = 0x2727;
  2195. WFIFOL(login_fd, 2) = char_dat[i].account_id; // account value
  2196. WFIFOSET(login_fd, 6);
  2197. // printf("char : status -> login: account %d, change sex request\n", char_dat[i].account_id);
  2198. } else
  2199. WFIFOW(fd,32) = 3; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2200. } else
  2201. WFIFOW(fd,32) = 2; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2202. break;
  2203. }
  2204. } else {
  2205. // character name not found
  2206. memcpy(WFIFOP(fd,6), character_name, 24);
  2207. WFIFOW(fd,32) = 1; // answer: 0-login-server resquest done, 1-player not found, 2-gm level too low, 3-login-server offline
  2208. }
  2209. // send answer if a player ask, not if the server ask
  2210. if (acc != -1) {
  2211. WFIFOSET(fd, 34);
  2212. }
  2213. RFIFOSKIP(fd, 44);
  2214. break;
  2215. }
  2216. // case 0x2b0f: not more used (available for futur usage)
  2217. // account_reg保存要求
  2218. case 0x2b10:
  2219. if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
  2220. return 0;
  2221. {
  2222. struct global_reg reg[ACCOUNT_REG2_NUM];
  2223. int p, acc;
  2224. acc = RFIFOL(fd,4);
  2225. for(p = 8, j = 0; p < RFIFOW(fd,2) && j < ACCOUNT_REG2_NUM; p += 36, j++) {
  2226. memcpy(reg[j].str, RFIFOP(fd,p), 32);
  2227. reg[j].value = RFIFOL(fd, p+32);
  2228. }
  2229. set_account_reg2(acc, j, reg);
  2230. // loginサーバーへ送る
  2231. if (login_fd > 0) { // don't send request if no login-server
  2232. WFIFOW(login_fd, 0) = 0x2728;
  2233. memcpy(WFIFOP(login_fd,0), RFIFOP(fd,0), RFIFOW(fd,2));
  2234. WFIFOSET(login_fd, WFIFOW(login_fd,2));
  2235. }
  2236. // ワールドへの同垢ログインがなければmapサーバーに送る必要はない
  2237. //memcpy(buf, RFIFOP(fd,0), RFIFOW(fd,2));
  2238. //WBUFW(buf,0) = 0x2b11;
  2239. //mapif_sendall(buf, WBUFW(buf,2));
  2240. RFIFOSKIP(fd, RFIFOW(fd,2));
  2241. // printf("char: save_account_reg (from map)\n");
  2242. break;
  2243. }
  2244. default:
  2245. // inter server処理に渡す
  2246. {
  2247. int r = inter_parse_frommap(fd);
  2248. if (r == 1) // 処理できた
  2249. break;
  2250. if (r == 2) // パケット長が足りない
  2251. return 0;
  2252. }
  2253. // inter server処理でもない場合は切断
  2254. printf("char: unknown packet 0x%04x (%d bytes to read in buffer)! (from map).\n", RFIFOW(fd,0), RFIFOREST(fd));
  2255. session[fd]->eof = 1;
  2256. return 0;
  2257. }
  2258. }
  2259. return 0;
  2260. }
  2261. int search_mapserver(char *map) {
  2262. int i, j;
  2263. char temp_map[16];
  2264. int temp_map_len;
  2265. // printf("Searching the map-server for map '%s'... ", map);
  2266. strncpy(temp_map, map, sizeof(temp_map));
  2267. temp_map[sizeof(temp_map)-1] = '\0';
  2268. if (strchr(temp_map, '.') != NULL)
  2269. temp_map[strchr(temp_map, '.') - temp_map + 1] = '\0'; // suppress the '.gat', but conserve the '.' to be sure of the name of the map
  2270. temp_map_len = strlen(temp_map);
  2271. for(i = 0; i < MAX_MAP_SERVERS; i++)
  2272. if (server_fd[i] >= 0)
  2273. for (j = 0; server[i].map[j][0]; j++)
  2274. //printf("%s : %s = %d\n", server[i].map[j], map, strncmp(server[i].map[j], temp_map, temp_map_len));
  2275. if (strncmp(server[i].map[j], temp_map, temp_map_len) == 0) {
  2276. // printf("found -> server #%d.\n", i);
  2277. return i;
  2278. }
  2279. // printf("not found.\n");
  2280. return -1;
  2281. }
  2282. // char_mapifの初期化処理(現在はinter_mapif初期化のみ)
  2283. static int char_mapif_init(int fd) {
  2284. return inter_mapif_init(fd);
  2285. }
  2286. //-----------------------------------------------------
  2287. // Test to know if an IP come from LAN or WAN. by [Yor]
  2288. //-----------------------------------------------------
  2289. int lan_ip_check(unsigned char *p){
  2290. int i;
  2291. int lancheck = 1;
  2292. // printf("lan_ip_check: to compare: %d.%d.%d.%d, network: %d.%d.%d.%d/%d.%d.%d.%d\n",
  2293. // p[0], p[1], p[2], p[3],
  2294. // subneti[0], subneti[1], subneti[2], subneti[3],
  2295. // subnetmaski[0], subnetmaski[1], subnetmaski[2], subnetmaski[3]);
  2296. for(i = 0; i < 4; i++) {
  2297. if ((subneti[i] & subnetmaski[i]) != (p[i] & subnetmaski[i])) {
  2298. lancheck = 0;
  2299. break;
  2300. }
  2301. }
  2302. printf("LAN test (result): %s source\033[0m.\n", (lancheck) ? "\033[1;36mLAN" : "\033[1;32mWAN");
  2303. return lancheck;
  2304. }
  2305. int parse_char(int fd) {
  2306. int i, ch;
  2307. unsigned short cmd;
  2308. char email[40];
  2309. struct char_session_data *sd;
  2310. unsigned char *p = (unsigned char *) &session[fd]->client_addr.sin_addr;
  2311. if (login_fd < 0)
  2312. session[fd]->eof = 1;
  2313. if(session[fd]->eof) { // disconnect any player (already connected to char-server or coming back from map-server) if login-server is diconnected.
  2314. if (fd == login_fd)
  2315. login_fd = -1;
  2316. close(fd);
  2317. delete_session(fd);
  2318. return 0;
  2319. }
  2320. sd = (struct char_session_data*)session[fd]->session_data;
  2321. while (RFIFOREST(fd) >= 2) {
  2322. cmd = RFIFOW(fd,0);
  2323. // crc32のスキップ用
  2324. if( sd==NULL && // 未ログインor管理パケット
  2325. RFIFOREST(fd)>=4 && // 最低バイト数制限 & 0x7530,0x7532管理パケ除去
  2326. RFIFOREST(fd)<=21 && // 最大バイト数制限 & サーバーログイン除去
  2327. cmd!=0x20b && // md5通知パケット除去
  2328. (RFIFOREST(fd)<6 || RFIFOW(fd,4)==0x65) ){ // 次に何かパケットが来てるなら、接続でないとだめ
  2329. RFIFOSKIP(fd,4);
  2330. cmd = RFIFOW(fd,0);
  2331. printf("parse_char : %d crc32 skipped\n",fd);
  2332. if(RFIFOREST(fd)==0)
  2333. return 0;
  2334. }
  2335. // if(cmd<30000 && cmd!=0x187)
  2336. // printf("parse_char : %d %d %d\n",fd,RFIFOREST(fd),cmd);
  2337. // 不正パケットの処理
  2338. // if (sd == NULL && cmd != 0x65 && cmd != 0x20b && cmd != 0x187 &&
  2339. // cmd != 0x2af8 && cmd != 0x7530 && cmd != 0x7532)
  2340. // cmd = 0xffff; // パケットダンプを表示させる
  2341. switch(cmd){
  2342. case 0x20b: //20040622暗号化ragexe対応
  2343. if (RFIFOREST(fd) < 19)
  2344. return 0;
  2345. RFIFOSKIP(fd,19);
  2346. break;
  2347. case 0x65: // 接続要求
  2348. if (RFIFOREST(fd) < 17)
  2349. return 0;
  2350. {
  2351. int GM_value;
  2352. if ((GM_value = isGM(RFIFOL(fd,2))))
  2353. printf("Account Logged On; Account ID: %d (GM level %d).\n", RFIFOL(fd,2), GM_value);
  2354. else
  2355. printf("Account Logged On; Account ID: %d.\n", RFIFOL(fd,2));
  2356. if (sd == NULL) {
  2357. sd = (struct char_session_data*)aCalloc(sizeof(struct char_session_data), 1);
  2358. session[fd]->session_data = sd;
  2359. memset(sd, 0, sizeof(struct char_session_data));
  2360. memcpy(sd->email, "no mail", 40); // put here a mail without '@' to refuse deletion if we don't receive the e-mail
  2361. sd->connect_until_time = 0; // unknow or illimited (not displaying on map-server)
  2362. }
  2363. sd->account_id = RFIFOL(fd,2);
  2364. sd->login_id1 = RFIFOL(fd,6);
  2365. sd->login_id2 = RFIFOL(fd,10);
  2366. sd->sex = RFIFOB(fd,16);
  2367. // send back account_id
  2368. WFIFOL(fd,0) = RFIFOL(fd,2);
  2369. WFIFOSET(fd,4);
  2370. // search authentification
  2371. for(i = 0; i < AUTH_FIFO_SIZE; i++) {
  2372. if (auth_fifo[i].account_id == sd->account_id &&
  2373. auth_fifo[i].login_id1 == sd->login_id1 &&
  2374. #if CMP_AUTHFIFO_LOGIN2 != 0
  2375. auth_fifo[i].login_id2 == sd->login_id2 && // relate to the versions higher than 18
  2376. #endif
  2377. (!check_ip_flag || auth_fifo[i].ip == session[fd]->client_addr.sin_addr.s_addr) &&
  2378. auth_fifo[i].delflag == 2) {
  2379. auth_fifo[i].delflag = 1;
  2380. if (max_connect_user == 0 || count_users() < max_connect_user) {
  2381. if (login_fd > 0) { // don't send request if no login-server
  2382. // request to login-server to obtain e-mail/time limit
  2383. WFIFOW(login_fd,0) = 0x2716;
  2384. WFIFOL(login_fd,2) = sd->account_id;
  2385. WFIFOSET(login_fd,6);
  2386. }
  2387. // send characters to player
  2388. mmo_char_send006b(fd, sd);
  2389. } else {
  2390. // refuse connection (over populated)
  2391. WFIFOW(fd,0) = 0x6c;
  2392. WFIFOW(fd,2) = 0;
  2393. WFIFOSET(fd,3);
  2394. }
  2395. break;
  2396. }
  2397. }
  2398. // authentification not found
  2399. if (i == AUTH_FIFO_SIZE) {
  2400. if (login_fd > 0) { // don't send request if no login-server
  2401. WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
  2402. WFIFOL(login_fd,2) = sd->account_id;
  2403. WFIFOL(login_fd,6) = sd->login_id1;
  2404. WFIFOL(login_fd,10) = sd->login_id2; // relate to the versions higher than 18
  2405. WFIFOB(login_fd,14) = sd->sex;
  2406. WFIFOL(login_fd,15) = session[fd]->client_addr.sin_addr.s_addr;
  2407. WFIFOSET(login_fd,19);
  2408. } else { // if no login-server, we must refuse connection
  2409. WFIFOW(fd,0) = 0x6c;
  2410. WFIFOW(fd,2) = 0;
  2411. WFIFOSET(fd,3);
  2412. }
  2413. }
  2414. }
  2415. RFIFOSKIP(fd,17);
  2416. break;
  2417. case 0x66: // キャラ選択
  2418. if (RFIFOREST(fd) < 3)
  2419. return 0;
  2420. // if we activated email creation and email is default email
  2421. if (email_creation != 0 && strcmp(sd->email, "a@a.com") == 0 && login_fd > 0) { // to modify an e-mail, login-server must be online
  2422. WFIFOW(fd, 0) = 0x70;
  2423. WFIFOB(fd, 2) = 0; // 00 = Incorrect Email address
  2424. WFIFOSET(fd, 3);
  2425. // otherwise, load the character
  2426. } else {
  2427. for (ch = 0; ch < 9; ch++)
  2428. if (sd->found_char[ch] >= 0 && char_dat[sd->found_char[ch]].char_num == RFIFOB(fd,2))
  2429. break;
  2430. if (ch != 9) {
  2431. char_log("Character Selected, Account ID: %d, Character Slot: %d, Character Name: %s." RETCODE,
  2432. sd->account_id, RFIFOB(fd,2), char_dat[sd->found_char[ch]].name);
  2433. // searching map server
  2434. i = search_mapserver(char_dat[sd->found_char[ch]].last_point.map);
  2435. // if map is not found, we check major cities
  2436. if (i < 0) {
  2437. if ((i = search_mapserver("prontera.gat")) >= 0) { // check is done without 'gat'.
  2438. memcpy(char_dat[sd->found_char[ch]].last_point.map, "prontera.gat", 16);
  2439. char_dat[sd->found_char[ch]].last_point.x = 273; // savepoint coordonates
  2440. char_dat[sd->found_char[ch]].last_point.y = 354;
  2441. } else if ((i = search_mapserver("geffen.gat")) >= 0) { // check is done without 'gat'.
  2442. memcpy(char_dat[sd->found_char[ch]].last_point.map, "geffen.gat", 16);
  2443. char_dat[sd->found_char[ch]].last_point.x = 120; // savepoint coordonates
  2444. char_dat[sd->found_char[ch]].last_point.y = 100;
  2445. } else if ((i = search_mapserver("morocc.gat")) >= 0) { // check is done without 'gat'.
  2446. memcpy(char_dat[sd->found_char[ch]].last_point.map, "morocc.gat", 16);
  2447. char_dat[sd->found_char[ch]].last_point.x = 160; // savepoint coordonates
  2448. char_dat[sd->found_char[ch]].last_point.y = 94;
  2449. } else if ((i = search_mapserver("alberta.gat")) >= 0) { // check is done without 'gat'.
  2450. memcpy(char_dat[sd->found_char[ch]].last_point.map, "alberta.gat", 16);
  2451. char_dat[sd->found_char[ch]].last_point.x = 116; // savepoint coordonates
  2452. char_dat[sd->found_char[ch]].last_point.y = 57;
  2453. } else if ((i = search_mapserver("payon.gat")) >= 0) { // check is done without 'gat'.
  2454. memcpy(char_dat[sd->found_char[ch]].last_point.map, "payon.gat", 16);
  2455. char_dat[sd->found_char[ch]].last_point.x = 87; // savepoint coordonates
  2456. char_dat[sd->found_char[ch]].last_point.y = 117;
  2457. } else if ((i = search_mapserver("izlude.gat")) >= 0) { // check is done without 'gat'.
  2458. memcpy(char_dat[sd->found_char[ch]].last_point.map, "izlude.gat", 16);
  2459. char_dat[sd->found_char[ch]].last_point.x = 94; // savepoint coordonates
  2460. char_dat[sd->found_char[ch]].last_point.y = 103;
  2461. } else {
  2462. int j;
  2463. // get first online server (with a map)
  2464. i = 0;
  2465. for(j = 0; j < MAX_MAP_SERVERS; j++)
  2466. if (server_fd[j] >= 0 && server[j].map[0][0]) { // change save point to one of map found on the server (the first)
  2467. i = j;
  2468. memcpy(char_dat[sd->found_char[ch]].last_point.map, server[j].map[0], 16);
  2469. printf("Map-server #%d found with a map: '%s'.\n", j, server[j].map[0]);
  2470. // coordonates are unknown
  2471. break;
  2472. }
  2473. // if no map-server is connected, we send: server closed
  2474. if (j == MAX_MAP_SERVERS) {
  2475. WFIFOW(fd,0) = 0x81;
  2476. WFIFOL(fd,2) = 1; // 01 = Server closed
  2477. WFIFOSET(fd,3);
  2478. RFIFOSKIP(fd,3);
  2479. break;
  2480. }
  2481. }
  2482. }
  2483. WFIFOW(fd,0) = 0x71;
  2484. WFIFOL(fd,2) = char_dat[sd->found_char[ch]].char_id;
  2485. memcpy(WFIFOP(fd,6), char_dat[sd->found_char[ch]].last_point.map, 16);
  2486. printf("Character selection '%s' (account: %d, slot: %d).\n", char_dat[sd->found_char[ch]].name, sd->account_id, ch);
  2487. printf("--Send IP of map-server. ");
  2488. if (lan_ip_check(p))
  2489. WFIFOL(fd, 22) = inet_addr(lan_map_ip);
  2490. else
  2491. WFIFOL(fd, 22) = server[i].ip;
  2492. WFIFOW(fd,26) = server[i].port;
  2493. WFIFOSET(fd,28);
  2494. if (auth_fifo_pos >= AUTH_FIFO_SIZE)
  2495. auth_fifo_pos = 0;
  2496. //printf("auth_fifo set #%d - account %d, char: %d, secure: %08x-%08x\n", auth_fifo_pos, sd->account_id, char_dat[sd->found_char[ch]].char_id, sd->login_id1, sd->login_id2);
  2497. auth_fifo[auth_fifo_pos].account_id = sd->account_id;
  2498. auth_fifo[auth_fifo_pos].char_id = char_dat[sd->found_char[ch]].char_id;
  2499. auth_fifo[auth_fifo_pos].login_id1 = sd->login_id1;
  2500. auth_fifo[auth_fifo_pos].login_id2 = sd->login_id2;
  2501. auth_fifo[auth_fifo_pos].delflag = 0;
  2502. auth_fifo[auth_fifo_pos].char_pos = sd->found_char[ch];
  2503. auth_fifo[auth_fifo_pos].sex = sd->sex;
  2504. auth_fifo[auth_fifo_pos].connect_until_time = sd->connect_until_time;
  2505. auth_fifo[auth_fifo_pos].ip = session[fd]->client_addr.sin_addr.s_addr;
  2506. auth_fifo_pos++;
  2507. }
  2508. }
  2509. RFIFOSKIP(fd,3);
  2510. break;
  2511. case 0x67: // 作成
  2512. if (RFIFOREST(fd) < 37)
  2513. return 0;
  2514. i = make_new_char(fd, RFIFOP(fd,2));
  2515. if (i < 0) {
  2516. WFIFOW(fd,0) = 0x6e;
  2517. WFIFOB(fd,2) = 0x00;
  2518. WFIFOSET(fd,3);
  2519. RFIFOSKIP(fd,37);
  2520. break;
  2521. }
  2522. WFIFOW(fd,0) = 0x6d;
  2523. memset(WFIFOP(fd,2), 0, 106);
  2524. WFIFOL(fd,2) = char_dat[i].char_id;
  2525. WFIFOL(fd,2+4) = char_dat[i].base_exp;
  2526. WFIFOL(fd,2+8) = char_dat[i].zeny;
  2527. WFIFOL(fd,2+12) = char_dat[i].job_exp;
  2528. WFIFOL(fd,2+16) = char_dat[i].job_level;
  2529. WFIFOL(fd,2+28) = char_dat[i].karma;
  2530. WFIFOL(fd,2+32) = char_dat[i].manner;
  2531. WFIFOW(fd,2+40) = 0x30;
  2532. WFIFOW(fd,2+42) = (char_dat[i].hp > 0x7fff) ? 0x7fff : char_dat[i].hp;
  2533. WFIFOW(fd,2+44) = (char_dat[i].max_hp > 0x7fff) ? 0x7fff : char_dat[i].max_hp;
  2534. WFIFOW(fd,2+46) = (char_dat[i].sp > 0x7fff) ? 0x7fff : char_dat[i].sp;
  2535. WFIFOW(fd,2+48) = (char_dat[i].max_sp > 0x7fff) ? 0x7fff : char_dat[i].max_sp;
  2536. WFIFOW(fd,2+50) = DEFAULT_WALK_SPEED; // char_dat[i].speed;
  2537. WFIFOW(fd,2+52) = char_dat[i].class_;
  2538. WFIFOW(fd,2+54) = char_dat[i].hair;
  2539. WFIFOW(fd,2+58) = char_dat[i].base_level;
  2540. WFIFOW(fd,2+60) = char_dat[i].skill_point;
  2541. WFIFOW(fd,2+64) = char_dat[i].shield;
  2542. WFIFOW(fd,2+66) = char_dat[i].head_top;
  2543. WFIFOW(fd,2+68) = char_dat[i].head_mid;
  2544. WFIFOW(fd,2+70) = char_dat[i].hair_color;
  2545. memcpy(WFIFOP(fd,2+74), char_dat[i].name, 24);
  2546. WFIFOB(fd,2+98) = (char_dat[i].str > 255) ? 255 : char_dat[i].str;
  2547. WFIFOB(fd,2+99) = (char_dat[i].agi > 255) ? 255 : char_dat[i].agi;
  2548. WFIFOB(fd,2+100) = (char_dat[i].vit > 255) ? 255 : char_dat[i].vit;
  2549. WFIFOB(fd,2+101) = (char_dat[i].int_ > 255) ? 255 : char_dat[i].int_;
  2550. WFIFOB(fd,2+102) = (char_dat[i].dex > 255) ? 255 : char_dat[i].dex;
  2551. WFIFOB(fd,2+103) = (char_dat[i].luk > 255) ? 255 : char_dat[i].luk;
  2552. WFIFOB(fd,2+104) = char_dat[i].char_num;
  2553. WFIFOSET(fd,108);
  2554. RFIFOSKIP(fd,37);
  2555. for(ch = 0; ch < 9; ch++) {
  2556. if (sd->found_char[ch] == -1) {
  2557. sd->found_char[ch] = i;
  2558. break;
  2559. }
  2560. }
  2561. case 0x68: // delete char //Yor's Fix
  2562. if (RFIFOREST(fd) < 46)
  2563. return 0;
  2564. memcpy(email, RFIFOP(fd,6), 40);
  2565. if (e_mail_check(email) == 0)
  2566. strncpy(email, "a@a.com", 40); // default e-mail
  2567. // if we activated email creation and email is default email
  2568. if (email_creation != 0 && strcmp(sd->email, "a@a.com") == 0 && login_fd > 0) { // to modify an e-mail, login-server must be online
  2569. // if sended email is incorrect e-mail
  2570. if (strcmp(email, "a@a.com") == 0) {
  2571. WFIFOW(fd, 0) = 0x70;
  2572. WFIFOB(fd, 2) = 0; // 00 = Incorrect Email address
  2573. WFIFOSET(fd, 3);
  2574. RFIFOSKIP(fd,46);
  2575. // we act like we have selected a character
  2576. } else {
  2577. // we change the packet to set it like selection.
  2578. for (i = 0; i < 9; i++)
  2579. if (char_dat[sd->found_char[i]].char_id == RFIFOL(fd,2)) {
  2580. // we save new e-mail
  2581. memcpy(sd->email, email, 40);
  2582. // we send new e-mail to login-server ('online' login-server is checked before)
  2583. WFIFOW(login_fd,0) = 0x2715;
  2584. WFIFOL(login_fd,2) = sd->account_id;
  2585. memcpy(WFIFOP(login_fd, 6), email, 40);
  2586. WFIFOSET(login_fd,46);
  2587. // skip part of the packet! (46, but leave the size of select packet: 3)
  2588. RFIFOSKIP(fd,43);
  2589. // change value to put new packet (char selection)
  2590. RFIFOW(fd, 0) = 0x66;
  2591. RFIFOB(fd, 2) = char_dat[sd->found_char[i]].char_num;
  2592. // not send packet, it's modify of actual packet
  2593. break;
  2594. }
  2595. if (i == 9) {
  2596. WFIFOW(fd, 0) = 0x70;
  2597. WFIFOB(fd, 2) = 0; // 00 = Incorrect Email address
  2598. WFIFOSET(fd, 3);
  2599. RFIFOSKIP(fd,46);
  2600. }
  2601. }
  2602. // otherwise, we delete the character
  2603. } else {
  2604. if (strcmpi(email, sd->email) != 0) { // if it's an invalid email
  2605. WFIFOW(fd, 0) = 0x70;
  2606. WFIFOB(fd, 2) = 0; // 00 = Incorrect Email address
  2607. WFIFOSET(fd, 3);
  2608. // if mail is correct
  2609. } else {
  2610. for (i = 0; i < 9; i++) {
  2611. struct mmo_charstatus *cs = NULL;
  2612. if ((cs = &char_dat[sd->found_char[i]])->char_id == RFIFOL(fd,2)) {
  2613. char_delete(cs); // deletion process
  2614. if (sd->found_char[i] != char_num - 1) {
  2615. memcpy(&char_dat[sd->found_char[i]], &char_dat[char_num-1], sizeof(struct mmo_charstatus));
  2616. // Correct moved character reference in the character's owner
  2617. {
  2618. int j, k;
  2619. struct char_session_data *sd2;
  2620. for (j = 0; j < fd_max; j++) {
  2621. if (session[j] && (sd2 = (struct char_session_data*)session[j]->session_data) &&
  2622. sd2->account_id == char_dat[char_num-1].account_id) {
  2623. for (k = 0; k < 9; k++) {
  2624. if (sd2->found_char[k] == char_num-1) {
  2625. sd2->found_char[k] = sd->found_char[i];
  2626. break;
  2627. }
  2628. }
  2629. break;
  2630. }
  2631. }
  2632. }
  2633. }
  2634. char_num--;
  2635. for(ch = i; ch < 9-1; ch++)
  2636. sd->found_char[ch] = sd->found_char[ch+1];
  2637. sd->found_char[8] = -1;
  2638. WFIFOW(fd,0) = 0x6f;
  2639. WFIFOSET(fd,2);
  2640. break;
  2641. }
  2642. }
  2643. if (i == 9) {
  2644. WFIFOW(fd,0) = 0x70;
  2645. WFIFOB(fd,2) = 0;
  2646. WFIFOSET(fd,3);
  2647. }
  2648. }
  2649. RFIFOSKIP(fd,46);
  2650. }
  2651. break;
  2652. case 0x2af8: // マップサーバーログイン
  2653. if (RFIFOREST(fd) < 60)
  2654. return 0;
  2655. WFIFOW(fd,0) = 0x2af9;
  2656. for(i = 0; i < MAX_MAP_SERVERS; i++) {
  2657. if (server_fd[i] < 0)
  2658. break;
  2659. }
  2660. if (i == MAX_MAP_SERVERS || strcmp((char*)RFIFOP(fd,2), userid) || strcmp((char*)RFIFOP(fd,26), passwd)){
  2661. WFIFOB(fd,2) = 3;
  2662. WFIFOSET(fd,3);
  2663. RFIFOSKIP(fd,60);
  2664. } else {
  2665. int len;
  2666. WFIFOB(fd,2) = 0;
  2667. session[fd]->func_parse = parse_frommap;
  2668. server_fd[i] = fd;
  2669. if(anti_freeze_enable)
  2670. server_freezeflag[i] = 5; // Map anti-freeze system. Counter. 5 ok, 4...0 freezed
  2671. server[i].ip = RFIFOL(fd,54);
  2672. server[i].port = RFIFOW(fd,58);
  2673. server[i].users = 0;
  2674. memset(server[i].map, 0, sizeof(server[i].map));
  2675. WFIFOSET(fd,3);
  2676. RFIFOSKIP(fd,60);
  2677. realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  2678. char_mapif_init(fd);
  2679. // send gm acccounts level to map-servers
  2680. len = 4;
  2681. WFIFOW(fd,0) = 0x2b15;
  2682. for(i = 0; i < GM_num; i++) {
  2683. WFIFOL(fd,len) = gm_account[i].account_id;
  2684. WFIFOB(fd,len+4) = (unsigned char)gm_account[i].level;
  2685. len += 5;
  2686. }
  2687. WFIFOW(fd,2) = len;
  2688. WFIFOSET(fd,len);
  2689. return 0;
  2690. }
  2691. break;
  2692. case 0x187: // Alive信号?
  2693. if (RFIFOREST(fd) < 6)
  2694. return 0;
  2695. RFIFOSKIP(fd, 6);
  2696. break;
  2697. case 0x7530: // Athena情報所得
  2698. WFIFOW(fd,0) = 0x7531;
  2699. WFIFOB(fd,2) = ATHENA_MAJOR_VERSION;
  2700. WFIFOB(fd,3) = ATHENA_MINOR_VERSION;
  2701. WFIFOB(fd,4) = ATHENA_REVISION;
  2702. WFIFOB(fd,5) = ATHENA_RELEASE_FLAG;
  2703. WFIFOB(fd,6) = ATHENA_OFFICIAL_FLAG;
  2704. WFIFOB(fd,7) = ATHENA_SERVER_INTER | ATHENA_SERVER_CHAR;
  2705. WFIFOW(fd,8) = ATHENA_MOD_VERSION;
  2706. WFIFOSET(fd,10);
  2707. RFIFOSKIP(fd,2);
  2708. return 0;
  2709. case 0x7532: // 接続の切断(defaultと処理は一緒だが明示的にするため)
  2710. session[fd]->eof = 1;
  2711. return 0;
  2712. default:
  2713. session[fd]->eof = 1;
  2714. return 0;
  2715. }
  2716. }
  2717. RFIFOFLUSH(fd);
  2718. return 0;
  2719. }
  2720. // Console Command Parser [Wizputer]
  2721. int parse_console(char *buf) {
  2722. char *type,*command;
  2723. type = (char *)aMalloc(64);
  2724. command = (char *)aMalloc(64);
  2725. memset(type,0,64);
  2726. memset(command,0,64);
  2727. printf("Console: %s\n",buf);
  2728. if ( sscanf(buf, "%[^:]:%[^\n]", type , command ) < 2 )
  2729. sscanf(buf,"%[^\n]",type);
  2730. printf("Type of command: %s || Command: %s \n",type,command);
  2731. if(buf) aFree(buf);
  2732. if(type) aFree(type);
  2733. if(command) aFree(command);
  2734. return 0;
  2735. }
  2736. // 全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す)
  2737. int mapif_sendall(unsigned char *buf, unsigned int len) {
  2738. int i, c;
  2739. c = 0;
  2740. for(i = 0; i < MAX_MAP_SERVERS; i++) {
  2741. int fd;
  2742. if ((fd = server_fd[i]) >= 0) {
  2743. memcpy(WFIFOP(fd,0), buf, len);
  2744. WFIFOSET(fd,len);
  2745. c++;
  2746. }
  2747. }
  2748. return c;
  2749. }
  2750. // 自分以外の全てのMAPサーバーにデータ送信(送信したmap鯖の数を返す)
  2751. int mapif_sendallwos(int sfd, unsigned char *buf, unsigned int len) {
  2752. int i, c;
  2753. c = 0;
  2754. for(i = 0; i < MAX_MAP_SERVERS; i++) {
  2755. int fd;
  2756. if ((fd = server_fd[i]) >= 0 && fd != sfd) {
  2757. memcpy(WFIFOP(fd,0), buf, len);
  2758. WFIFOSET(fd, len);
  2759. c++;
  2760. }
  2761. }
  2762. return c;
  2763. }
  2764. // MAPサーバーにデータ送信(map鯖生存確認有り)
  2765. int mapif_send(int fd, unsigned char *buf, unsigned int len) {
  2766. int i;
  2767. if (fd >= 0) {
  2768. for(i = 0; i < MAX_MAP_SERVERS; i++) {
  2769. if (fd == server_fd[i]) {
  2770. memcpy(WFIFOP(fd,0), buf, len);
  2771. WFIFOSET(fd,len);
  2772. return 1;
  2773. }
  2774. }
  2775. }
  2776. return 0;
  2777. }
  2778. int send_users_tologin(int tid, unsigned int tick, int id, int data) {
  2779. int users = count_users();
  2780. unsigned char buf[16];
  2781. if (login_fd > 0 && session[login_fd]) {
  2782. // send number of user to login server
  2783. WFIFOW(login_fd,0) = 0x2714;
  2784. WFIFOL(login_fd,2) = users;
  2785. WFIFOSET(login_fd,6);
  2786. }
  2787. // send number of players to all map-servers
  2788. WBUFW(buf,0) = 0x2b00;
  2789. WBUFL(buf,2) = users;
  2790. mapif_sendall(buf, 6);
  2791. return 0;
  2792. }
  2793. int check_connect_login_server(int tid, unsigned int tick, int id, int data) {
  2794. if (login_fd <= 0 || session[login_fd] == NULL) {
  2795. printf("Attempt to connect to login-server...\n");
  2796. login_fd = make_connection(login_ip, login_port);
  2797. session[login_fd]->func_parse = parse_tologin;
  2798. realloc_fifo(login_fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
  2799. WFIFOW(login_fd,0) = 0x2710;
  2800. memset(WFIFOP(login_fd,2), 0, 24);
  2801. memcpy(WFIFOP(login_fd,2), userid, strlen(userid) < 24 ? strlen(userid) : 24);
  2802. memset(WFIFOP(login_fd,26), 0, 24);
  2803. memcpy(WFIFOP(login_fd,26), passwd, strlen(passwd) < 24 ? strlen(passwd) : 24);
  2804. WFIFOL(login_fd,50) = 0;
  2805. WFIFOL(login_fd,54) = char_ip;
  2806. WFIFOL(login_fd,58) = char_port;
  2807. memset(WFIFOP(login_fd,60), 0, 20);
  2808. memcpy(WFIFOP(login_fd,60), server_name, strlen(server_name) < 20 ? strlen(server_name) : 20);
  2809. WFIFOW(login_fd,80) = 0;
  2810. WFIFOW(login_fd,82) = char_maintenance;
  2811. WFIFOW(login_fd,84) = char_new;
  2812. WFIFOSET(login_fd,86);
  2813. }
  2814. return 0;
  2815. }
  2816. //----------------------------------------------------------
  2817. // Return numerical value of a switch configuration by [Yor]
  2818. // on/off, english, fran軋is, deutsch, espa�l
  2819. //----------------------------------------------------------
  2820. int config_switch(const char *str) {
  2821. if (strcmpi(str, "on") == 0 || strcmpi(str, "yes") == 0 || strcmpi(str, "oui") == 0 || strcmpi(str, "ja") == 0 || strcmpi(str, "si") == 0)
  2822. return 1;
  2823. if (strcmpi(str, "off") == 0 || strcmpi(str, "no") == 0 || strcmpi(str, "non") == 0 || strcmpi(str, "nein") == 0)
  2824. return 0;
  2825. return atoi(str);
  2826. }
  2827. //-------------------------------------------
  2828. // Reading Lan Support configuration by [Yor]
  2829. //-------------------------------------------
  2830. int lan_config_read(const char *lancfgName) {
  2831. int j;
  2832. struct hostent * h = NULL;
  2833. char line[1024], w1[1024], w2[1024];
  2834. FILE *fp;
  2835. // set default configuration
  2836. strncpy(lan_map_ip, "127.0.0.1", sizeof(lan_map_ip));
  2837. subneti[0] = 127;
  2838. subneti[1] = 0;
  2839. subneti[2] = 0;
  2840. subneti[3] = 1;
  2841. for(j = 0; j < 4; j++)
  2842. subnetmaski[j] = 255;
  2843. fp = fopen(lancfgName, "r");
  2844. if (fp == NULL) {
  2845. printf("LAN support configuration file not found: %s\n", lancfgName);
  2846. return 1;
  2847. }
  2848. printf ("---start reading of Lan Support configuration...\n");
  2849. while(fgets(line, sizeof(line)-1, fp)) {
  2850. if (line[0] == '/' && line[1] == '/')
  2851. continue;
  2852. line[sizeof(line)-1] = '\0';
  2853. if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2)
  2854. continue;
  2855. remove_control_chars(w1);
  2856. remove_control_chars(w2);
  2857. if (strcmpi(w1, "lan_map_ip") == 0) { // Read map-server Lan IP Address
  2858. h = gethostbyname(w2);
  2859. if (h != NULL) {
  2860. sprintf(lan_map_ip, "%d.%d.%d.%d", (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1], (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]);
  2861. } else {
  2862. strncpy(lan_map_ip, w2, sizeof(lan_map_ip));
  2863. lan_map_ip[sizeof(lan_map_ip)-1] = 0;
  2864. }
  2865. printf("LAN IP of map-server: %s.\n", lan_map_ip);
  2866. } else if (strcmpi(w1, "subnet") == 0) { // Read Subnetwork
  2867. for(j = 0; j < 4; j++)
  2868. subneti[j] = 0;
  2869. h = gethostbyname(w2);
  2870. if (h != NULL) {
  2871. for(j = 0; j < 4; j++)
  2872. subneti[j] = (unsigned char)h->h_addr[j];
  2873. } else {
  2874. sscanf(w2, "%d.%d.%d.%d", &subneti[0], &subneti[1], &subneti[2], &subneti[3]);
  2875. }
  2876. printf("Sub-network of the map-server: %d.%d.%d.%d.\n", subneti[0], subneti[1], subneti[2], subneti[3]);
  2877. } else if (strcmpi(w1, "subnetmask") == 0){ // Read Subnetwork Mask
  2878. for(j = 0; j < 4; j++)
  2879. subnetmaski[j] = 255;
  2880. h = gethostbyname(w2);
  2881. if (h != NULL) {
  2882. for(j = 0; j < 4; j++)
  2883. subnetmaski[j] = (unsigned char)h->h_addr[j];
  2884. } else {
  2885. sscanf(w2, "%d.%d.%d.%d", &subnetmaski[0], &subnetmaski[1], &subnetmaski[2], &subnetmaski[3]);
  2886. }
  2887. printf("Sub-network mask of the map-server: %d.%d.%d.%d.\n", subnetmaski[0], subnetmaski[1], subnetmaski[2], subnetmaski[3]);
  2888. }
  2889. }
  2890. fclose(fp);
  2891. // sub-network check of the map-server
  2892. {
  2893. unsigned int a0, a1, a2, a3;
  2894. unsigned char p[4];
  2895. sscanf(lan_map_ip, "%d.%d.%d.%d", &a0, &a1, &a2, &a3);
  2896. p[0] = a0; p[1] = a1; p[2] = a2; p[3] = a3;
  2897. printf("LAN test of LAN IP of the map-server: ");
  2898. if (lan_ip_check(p) == 0) {
  2899. printf("\033[1;31m***ERROR: LAN IP of the map-server doesn't belong to the specified Sub-network.\033[0m\n");
  2900. }
  2901. }
  2902. printf("---End reading of Lan Support configuration...\n");
  2903. return 0;
  2904. }
  2905. int char_config_read(const char *cfgName) {
  2906. struct hostent *h = NULL;
  2907. char line[1024], w1[1024], w2[1024];
  2908. FILE *fp = fopen(cfgName, "r");
  2909. if (fp == NULL) {
  2910. printf("Configuration file not found: %s.\n", cfgName);
  2911. exit(1);
  2912. }
  2913. while(fgets(line, sizeof(line)-1, fp)) {
  2914. if (line[0] == '/' && line[1] == '/')
  2915. continue;
  2916. line[sizeof(line)-1] = '\0';
  2917. if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2)
  2918. continue;
  2919. remove_control_chars(w1);
  2920. remove_control_chars(w2);
  2921. if (strcmpi(w1, "userid") == 0) {
  2922. memcpy(userid, w2, 24);
  2923. } else if (strcmpi(w1, "passwd") == 0) {
  2924. memcpy(passwd, w2, 24);
  2925. } else if (strcmpi(w1, "server_name") == 0) {
  2926. memcpy(server_name, w2, sizeof(server_name));
  2927. server_name[sizeof(server_name) - 1] = '\0';
  2928. printf("%s server has been initialized\n", w2);
  2929. } else if (strcmpi(w1, "wisp_server_name") == 0) {
  2930. if (strlen(w2) >= 4) {
  2931. memcpy(wisp_server_name, w2, sizeof(wisp_server_name));
  2932. wisp_server_name[sizeof(wisp_server_name) - 1] = '\0';
  2933. }
  2934. } else if (strcmpi(w1, "login_ip") == 0) {
  2935. login_ip_set_ = 1;
  2936. h = gethostbyname(w2);
  2937. if (h != NULL) {
  2938. printf("Login server IP address : %s -> %d.%d.%d.%d\n", w2, (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1], (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]);
  2939. sprintf(login_ip_str, "%d.%d.%d.%d", (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1], (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]);
  2940. } else
  2941. memcpy(login_ip_str, w2, 16);
  2942. } else if (strcmpi(w1, "login_port") == 0) {
  2943. login_port = atoi(w2);
  2944. } else if (strcmpi(w1, "char_ip") == 0) {
  2945. char_ip_set_ = 1;
  2946. h = gethostbyname(w2);
  2947. if (h != NULL) {
  2948. printf("Character server IP address : %s -> %d.%d.%d.%d\n", w2, (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1], (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]);
  2949. sprintf(char_ip_str, "%d.%d.%d.%d", (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1], (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]);
  2950. } else
  2951. memcpy(char_ip_str, w2, 16);
  2952. } else if (strcmpi(w1, "bind_ip") == 0) {
  2953. bind_ip_set_ = 1;
  2954. h = gethostbyname(w2);
  2955. if (h != NULL) {
  2956. printf("Character server binding IP address : %s -> %d.%d.%d.%d\n", w2, (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1], (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]);
  2957. sprintf(bind_ip_str, "%d.%d.%d.%d", (unsigned char)h->h_addr[0], (unsigned char)h->h_addr[1], (unsigned char)h->h_addr[2], (unsigned char)h->h_addr[3]);
  2958. } else
  2959. memcpy(bind_ip_str, w2, 16);
  2960. } else if (strcmpi(w1, "char_port") == 0) {
  2961. char_port = atoi(w2);
  2962. } else if (strcmpi(w1, "char_maintenance") == 0) {
  2963. char_maintenance = atoi(w2);
  2964. } else if (strcmpi(w1, "char_new") == 0) {
  2965. char_new = atoi(w2);
  2966. } else if (strcmpi(w1, "email_creation") == 0) {
  2967. email_creation = config_switch(w2);
  2968. } else if (strcmpi(w1, "char_txt") == 0) {
  2969. strcpy(char_txt, w2);
  2970. } else if (strcmpi(w1, "backup_txt") == 0) { //By zanetheinsane
  2971. strcpy(backup_txt, w2);
  2972. } else if (strcmpi(w1, "friends_txt") == 0) { //By davidsiaw
  2973. strcpy(friends_txt, w2);
  2974. } else if (strcmpi(w1, "backup_txt_flag") == 0) { // The backup_txt file was created because char deletion bug existed. Now it's finish and that take a lot of time to create a second file when there are a lot of characters. By [Yor]
  2975. backup_txt_flag = config_switch(w2);
  2976. } else if (strcmpi(w1, "max_connect_user") == 0) {
  2977. max_connect_user = atoi(w2);
  2978. if (max_connect_user < 0)
  2979. max_connect_user = 0; // unlimited online players
  2980. } else if(strcmpi(w1, "gm_allow_level") == 0) {
  2981. gm_allow_level = atoi(w2);
  2982. if(gm_allow_level < 0)
  2983. gm_allow_level = 99;
  2984. } else if (strcmpi(w1, "check_ip_flag") == 0) {
  2985. check_ip_flag = config_switch(w2);
  2986. } else if (strcmpi(w1, "autosave_time") == 0) {
  2987. autosave_interval = atoi(w2)*1000;
  2988. if (autosave_interval <= 0)
  2989. autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
  2990. } else if (strcmpi(w1, "start_point") == 0) {
  2991. char map[32];
  2992. int x, y;
  2993. if (sscanf(w2, "%[^,],%d,%d", map, &x, &y) < 3)
  2994. continue;
  2995. if (strstr(map, ".gat") != NULL) { // Verify at least if '.gat' is in the map name
  2996. memcpy(start_point.map, map, 16);
  2997. start_point.x = x;
  2998. start_point.y = y;
  2999. }
  3000. } else if(strcmpi(w1,"imalive_on")==0) { //Added by Mugendai for I'm Alive mod
  3001. imalive_on = atoi(w2); //Added by Mugendai for I'm Alive mod
  3002. } else if(strcmpi(w1,"imalive_time")==0) { //Added by Mugendai for I'm Alive mod
  3003. imalive_time = atoi(w2); //Added by Mugendai for I'm Alive mod
  3004. } else if(strcmpi(w1,"flush_on")==0) { //Added by Mugendai for GUI
  3005. flush_on = atoi(w2); //Added by Mugendai for GUI
  3006. } else if(strcmpi(w1,"flush_time")==0) { //Added by Mugendai for GUI
  3007. flush_time = atoi(w2); //Added by Mugendai for GUI
  3008. } else if(strcmpi(w1,"log_char")==0) { //log char or not [devil]
  3009. log_char = atoi(w2);
  3010. } else if (strcmpi(w1, "start_zeny") == 0) {
  3011. start_zeny = atoi(w2);
  3012. if (start_zeny < 0)
  3013. start_zeny = 0;
  3014. } else if (strcmpi(w1, "start_weapon") == 0) {
  3015. start_weapon = atoi(w2);
  3016. if (start_weapon < 0)
  3017. start_weapon = 0;
  3018. } else if (strcmpi(w1, "start_armor") == 0) {
  3019. start_armor = atoi(w2);
  3020. if (start_armor < 0)
  3021. start_armor = 0;
  3022. } else if (strcmpi(w1, "unknown_char_name") == 0) {
  3023. strcpy(unknown_char_name, w2);
  3024. unknown_char_name[24] = 0;
  3025. } else if (strcmpi(w1, "char_log_filename") == 0) {
  3026. strcpy(char_log_filename, w2);
  3027. } else if (strcmpi(w1, "name_ignoring_case") == 0) {
  3028. name_ignoring_case = config_switch(w2);
  3029. } else if (strcmpi(w1, "char_name_option") == 0) {
  3030. char_name_option = atoi(w2);
  3031. } else if (strcmpi(w1, "char_name_letters") == 0) {
  3032. strcpy(char_name_letters, w2);
  3033. // online files options
  3034. } else if (strcmpi(w1, "online_txt_filename") == 0) {
  3035. strcpy(online_txt_filename, w2);
  3036. } else if (strcmpi(w1, "online_html_filename") == 0) {
  3037. strcpy(online_html_filename, w2);
  3038. } else if (strcmpi(w1, "online_sorting_option") == 0) {
  3039. online_sorting_option = atoi(w2);
  3040. } else if (strcmpi(w1, "online_display_option") == 0) {
  3041. online_display_option = atoi(w2);
  3042. } else if (strcmpi(w1, "online_gm_display_min_level") == 0) { // minimum GM level to display 'GM' when we want to display it
  3043. online_gm_display_min_level = atoi(w2);
  3044. if (online_gm_display_min_level < 5) // send online file every 5 seconds to player is enough
  3045. online_gm_display_min_level = 5;
  3046. } else if (strcmpi(w1, "online_refresh_html") == 0) {
  3047. online_refresh_html = atoi(w2);
  3048. if (online_refresh_html < 1)
  3049. online_refresh_html = 1;
  3050. } else if(strcmpi(w1,"db_path")==0) {
  3051. strcpy(db_path,w2);
  3052. } else if(strcmpi(w1,"anti_freeze_enable")==0){
  3053. anti_freeze_enable = config_switch(w2);
  3054. } else if (strcmpi(w1, "anti_freeze_interval") == 0) {
  3055. ANTI_FREEZE_INTERVAL = atoi(w2);
  3056. if (ANTI_FREEZE_INTERVAL < 5)
  3057. ANTI_FREEZE_INTERVAL = 5; // minimum 5 seconds
  3058. } else if (strcmpi(w1, "import") == 0) {
  3059. char_config_read(w2);
  3060. } else if (strcmpi(w1, "console") == 0) {
  3061. if(strcmpi(w2,"on") == 0 || strcmpi(w2,"yes") == 0 )
  3062. console = 1;
  3063. }
  3064. }
  3065. fclose(fp);
  3066. return 0;
  3067. }
  3068. //-----------------------------------------------------
  3069. //I'm Alive Alert
  3070. //Used to output 'I'm Alive' every few seconds
  3071. //Intended to let frontends know if the app froze
  3072. //-----------------------------------------------------
  3073. int imalive_timer(int tid, unsigned int tick, int id, int data){
  3074. printf("I'm Alive\n");
  3075. return 0;
  3076. }
  3077. //-----------------------------------------------------
  3078. //Flush stdout
  3079. //stdout buffer needs flushed to be seen in GUI
  3080. //-----------------------------------------------------
  3081. int flush_timer(int tid, unsigned int tick, int id, int data){
  3082. fflush(stdout);
  3083. return 0;
  3084. }
  3085. void do_final(void) {
  3086. int i;
  3087. printf("Terminating server.\n");
  3088. // write online players files with no player
  3089. for(i = 0; i < online_players_max; i++) {
  3090. online_chars[i].char_id = -1;
  3091. online_chars[i].server = -1;
  3092. }
  3093. create_online_files();
  3094. if(online_chars) aFree(online_chars);
  3095. mmo_char_sync();
  3096. inter_save();
  3097. if(gm_account) aFree(gm_account);
  3098. if(char_dat) aFree(char_dat);
  3099. delete_session(login_fd);
  3100. delete_session(char_fd);
  3101. for(i = 0; i < fd_max; i++)
  3102. if(session[i] != NULL) aFree(session[i]);
  3103. char_log("----End of char-server (normal end with closing of all files)." RETCODE);
  3104. }
  3105. int do_init(int argc, char **argv) {
  3106. int i;
  3107. char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]);
  3108. lan_config_read((argc > 1) ? argv[1] : LOGIN_LAN_CONF_NAME);
  3109. // a newline in the log...
  3110. char_log("");
  3111. // moved behind char_config_read in case we changed the filename [celest]
  3112. char_log("The char-server starting..." RETCODE);
  3113. if ((naddr_ != 0) && (login_ip_set_ == 0 || char_ip_set_ == 0)) {
  3114. // The char server should know what IP address it is running on
  3115. // - MouseJstr
  3116. int localaddr = ntohl(addr_[0]);
  3117. unsigned char *ptr = (unsigned char *) &localaddr;
  3118. char buf[16];
  3119. sprintf(buf, "%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]);;
  3120. if (naddr_ != 1)
  3121. printf("Multiple interfaces detected.. using %s as our IP address\n", buf);
  3122. else
  3123. printf("Defaulting to %s as our IP address\n", buf);
  3124. if (login_ip_set_ == 0)
  3125. strcpy(login_ip_str, buf);
  3126. if (char_ip_set_ == 0)
  3127. strcpy(char_ip_str, buf);
  3128. if (ptr[0] == 192 && ptr[1] == 168)
  3129. printf("Firewall detected.. edit lan_support.conf and char_athena.conf\n");
  3130. }
  3131. login_ip = inet_addr(login_ip_str);
  3132. char_ip = inet_addr(char_ip_str);
  3133. for(i = 0; i < MAX_MAP_SERVERS; i++) {
  3134. memset(&server[i], 0, sizeof(struct mmo_map_server));
  3135. server_fd[i] = -1;
  3136. }
  3137. online_players_max = 256;
  3138. online_chars = (struct online_chars*)aCalloc(sizeof(struct online_chars) * 256, 1);
  3139. if (!online_chars) {
  3140. printf("out of memory: do_init (calloc).\n");
  3141. exit(1);
  3142. }
  3143. for(i = 0; i < online_players_max; i++) {
  3144. online_chars[i].char_id = -1;
  3145. online_chars[i].server = -1;
  3146. }
  3147. mmo_char_init();
  3148. update_online = time(NULL);
  3149. create_online_files(); // update online players files at start of the server
  3150. inter_init((argc > 2) ? argv[2] : inter_cfgName); // inter server 初期化
  3151. set_termfunc(do_final);
  3152. set_defaultparse(parse_char);
  3153. if (bind_ip_set_)
  3154. char_fd = make_listen_bind(inet_addr(bind_ip_str),char_port);
  3155. else
  3156. char_fd = make_listen_bind(INADDR_ANY,char_port);
  3157. add_timer_func_list(check_connect_login_server, "check_connect_login_server");
  3158. add_timer_func_list(send_users_tologin, "send_users_tologin");
  3159. add_timer_func_list(mmo_char_sync_timer, "mmo_char_sync_timer");
  3160. i = add_timer_interval(gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000);
  3161. i = add_timer_interval(gettick() + 1000, send_users_tologin, 0, 0, 5 * 1000);
  3162. i = add_timer_interval(gettick() + autosave_interval, mmo_char_sync_timer, 0, 0, autosave_interval);
  3163. //Added for Mugendais I'm Alive mod
  3164. if (imalive_on)
  3165. add_timer_interval(gettick()+10, imalive_timer,0,0,imalive_time*1000);
  3166. //Added by Mugendai for GUI support
  3167. if (flush_on)
  3168. add_timer_interval(gettick()+10, flush_timer,0,0,flush_time);
  3169. if(anti_freeze_enable > 0) {
  3170. add_timer_func_list(map_anti_freeze_system, "map_anti_freeze_system");
  3171. i = add_timer_interval(gettick() + 1000, map_anti_freeze_system, 0, 0, ANTI_FREEZE_INTERVAL * 1000); // checks every X seconds user specifies
  3172. }
  3173. if(console) {
  3174. set_defaultconsoleparse(parse_console);
  3175. start_console();
  3176. }
  3177. char_log("The char-server is ready (Server is listening on the port %d)." RETCODE, char_port);
  3178. printf("The char-server is \033[1;32mready\033[0m (Server is listening on the port %d).\n\n", char_port);
  3179. return 0;
  3180. }