Atrinik Client 2.5
client/commands.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00067 #include <global.h>
00068 
00073 void BookCmd(unsigned char *data, int len)
00074 {
00075     sound_play_effect("book.ogg", 100);
00076     book_load((char *) data, len);
00077 }
00078 
00084 void SetupCmd(char *buf, int len)
00085 {
00086     int s;
00087     char *cmd, *param;
00088 
00089     server_files_clear_update();
00090     LOG(llevInfo, "Get SetupCmd:: %s\n", buf);
00091 
00092     for (s = 0; ;)
00093     {
00094         while (s < len && buf[s] == ' ')
00095         {
00096             s++;
00097         }
00098 
00099         if (s >= len)
00100         {
00101             break;
00102         }
00103 
00104         cmd = &buf[s];
00105 
00106         while (s < len && buf[s] != ' ')
00107         {
00108             s++;
00109         }
00110 
00111         if (s >= len)
00112         {
00113             break;
00114         }
00115 
00116         buf[s++] = '\0';
00117 
00118         if (s >= len)
00119         {
00120             break;
00121         }
00122 
00123         while (s < len && buf[s] == ' ')
00124         {
00125             s++;
00126         }
00127 
00128         if (s >= len)
00129         {
00130             break;
00131         }
00132 
00133         param = &buf[s];
00134 
00135         while (s < len && buf[s] != ' ')
00136         {
00137             s++;
00138         }
00139 
00140         buf[s++] = '\0';
00141 
00142         while (s < len && buf[s] == ' ')
00143         {
00144             s++;
00145         }
00146 
00147         if (!strcmp(cmd, "sound"))
00148         {
00149             if (!strcmp(param, "FALSE"))
00150             {
00151             }
00152         }
00153         else if (!strcmp(cmd, "mapsize"))
00154         {
00155         }
00156         else if (!strcmp(cmd, "map2cmd"))
00157         {
00158         }
00159         else if (!strcmp(cmd, "darkness"))
00160         {
00161         }
00162         else if (!strcmp(cmd, "facecache"))
00163         {
00164         }
00165         else if (server_files_parse_setup(cmd, param))
00166         {
00167         }
00168         else
00169         {
00170             LOG(llevBug, "Got setup for a command we don't understand: %s %s\n", cmd, param);
00171         }
00172     }
00173 
00174     if (GameStatus != GAME_STATUS_PLAY)
00175     {
00176         GameStatus = GAME_STATUS_REQUEST_FILES;
00177     }
00178 }
00179 
00184 void AddMeFail(unsigned char *data, int len)
00185 {
00186     (void) data;
00187     (void) len;
00188 
00189     LOG(llevInfo, "addme_failed received.\n");
00190     GameStatus = GAME_STATUS_START;
00191 }
00192 
00196 void AddMeSuccess(unsigned char *data, int len)
00197 {
00198     (void) data;
00199     (void) len;
00200 
00201     LOG(llevInfo, "addme_success received.\n");
00202 }
00203 
00208 void AnimCmd(unsigned char *data, int len)
00209 {
00210     short anum;
00211     int i, j;
00212 
00213     anum = GetShort_String(data);
00214 
00215     if (anum < 0)
00216     {
00217         fprintf(stderr, "AnimCmd: animation number invalid: %d\n", anum);
00218         return;
00219     }
00220 
00221     animations[anum].flags = *(data + 2);
00222     animations[anum].facings = *(data + 3);
00223     animations[anum].num_animations = (len - 4) / 2;
00224 
00225     if (animations[anum].num_animations < 1)
00226     {
00227         LOG(llevDebug, "AnimCmd: num animations invalid: %d\n", animations[anum].num_animations);
00228         return;
00229     }
00230 
00231     if (animations[anum].facings > 1)
00232     {
00233         animations[anum].frame = animations[anum].num_animations / animations[anum].facings;
00234     }
00235     else
00236     {
00237         animations[anum].frame = animations[anum].num_animations;
00238     }
00239 
00240     animations[anum].faces = malloc(sizeof(uint16) * animations[anum].num_animations);
00241 
00242     for (i = 4, j = 0; i < len; i += 2, j++)
00243     {
00244         animations[anum].faces[j] = GetShort_String(data + i);
00245         request_face(animations[anum].faces[j]);
00246     }
00247 
00248     if (j != animations[anum].num_animations)
00249     {
00250         LOG(llevDebug, "Calculated animations does not equal stored animations? (%d != %d)\n", j, animations[anum].num_animations);
00251     }
00252 }
00253 
00258 void ImageCmd(unsigned char *data, int len)
00259 {
00260     int pnum, plen;
00261     char buf[2048];
00262     FILE *stream;
00263 
00264     pnum = GetInt_String(data);
00265     plen = GetInt_String(data + 4);
00266 
00267     if (len < 8 || (len - 8) != plen)
00268     {
00269         LOG(llevBug, "ImageCmd(): Lengths don't compare (%d, %d)\n", (len - 8), plen);
00270         return;
00271     }
00272 
00273     /* Save picture to cache and load it to FaceList */
00274     sprintf(buf, DIRECTORY_CACHE"/%s", FaceList[pnum].name);
00275     LOG(llevInfo, "ImageFromServer: %s\n", FaceList[pnum].name);
00276 
00277     if ((stream = fopen_wrapper(buf, "wb+")) != NULL)
00278     {
00279         fwrite((char *) data + 8, 1, plen, stream);
00280         fclose(stream);
00281     }
00282 
00283     FaceList[pnum].sprite = sprite_tryload_file(buf, 0, NULL);
00284     map_udate_flag = 2;
00285     map_redraw_flag = 1;
00286     book_redraw();
00287 }
00288 
00293 void SkillRdyCmd(char *data, int len)
00294 {
00295     size_t type, id;
00296 
00297     (void) len;
00298 
00299     strncpy(cpl.skill_name, data, sizeof(cpl.skill_name) - 1);
00300     cpl.skill_name[sizeof(cpl.skill_name) - 1] = '\0';
00301     cpl.skill = NULL;
00302 
00303     if (skill_find(cpl.skill_name, &type, &id))
00304     {
00305         skill_entry_struct *skill = skill_get(type, id);
00306 
00307         if (skill->known)
00308         {
00309             cpl.skill = skill;
00310         }
00311     }
00312 
00313     WIDGET_REDRAW_ALL(SKILL_EXP_ID);
00314 }
00315 
00319 void DrawInfoCmd(unsigned char *data)
00320 {
00321     char color[COLOR_BUF];
00322     int pos = 0;
00323 
00324     GetString_String(data, &pos, color, sizeof(color));
00325     draw_info(color, (char *) data + pos);
00326 }
00327 
00333 void DrawInfoCmd2(unsigned char *data, int len)
00334 {
00335     int flags;
00336     char color[COLOR_BUF], buf[20048], *tmp = NULL;
00337     int pos = 0;
00338 
00339     flags = (int) GetShort_String(data);
00340     pos += 2;
00341 
00342     GetString_String(data, &pos, color, sizeof(color));
00343     len -= pos;
00344 
00345     data += pos;
00346 
00347     if (len >= 0)
00348     {
00349         if (len > 20000)
00350         {
00351             len = 20000;
00352         }
00353 
00354         if (setting_get_int(OPT_CAT_GENERAL, OPT_CHAT_TIMESTAMPS) && (flags & NDI_PLAYER))
00355         {
00356             time_t now = time(NULL);
00357             char timebuf[32], *format;
00358             struct tm *tm = localtime(&now);
00359             size_t timelen;
00360 
00361             switch (setting_get_int(OPT_CAT_GENERAL, OPT_CHAT_TIMESTAMPS))
00362             {
00363                 /* HH:MM */
00364                 case 1:
00365                 default:
00366                     format = "%H:%M";
00367                     break;
00368 
00369                 /* HH:MM:SS */
00370                 case 2:
00371                     format = "%H:%M:%S";
00372                     break;
00373 
00374                 /* H:MM AM/PM */
00375                 case 3:
00376                     format = "%I:%M %p";
00377                     break;
00378 
00379                 /* H:MM:SS AM/PM */
00380                 case 4:
00381                     format = "%I:%M:%S %p";
00382                     break;
00383             }
00384 
00385             timelen = strftime(timebuf, sizeof(timebuf), format, tm);
00386 
00387             if (timelen == 0)
00388             {
00389                 strncpy(buf, (char *) data, len);
00390             }
00391             else
00392             {
00393                 len += (int) timelen + 4;
00394                 snprintf(buf, len, "[%s] %s", timebuf, (char *) data);
00395             }
00396         }
00397         else
00398         {
00399             strncpy(buf, (char *) data, len);
00400         }
00401 
00402         buf[len] = '\0';
00403     }
00404     else
00405     {
00406         buf[0] = '\0';
00407     }
00408 
00409     if (buf[0] && (flags & (NDI_PLAYER | NDI_SAY | NDI_SHOUT | NDI_TELL | NDI_EMOTE)))
00410     {
00411         tmp = strchr((char *) data, ' ');
00412 
00413         if (tmp)
00414         {
00415             *tmp = '\0';
00416         }
00417     }
00418 
00419     /* We have communication input */
00420     if (tmp)
00421     {
00422         if ((flags & NDI_SAY) && ignore_check((char *) data, "say"))
00423         {
00424             return;
00425         }
00426 
00427         if ((flags & NDI_SHOUT) && ignore_check((char *) data, "shout"))
00428         {
00429             return;
00430         }
00431 
00432         if ((flags & NDI_TELL) && ignore_check((char *) data, "tell"))
00433         {
00434             return;
00435         }
00436 
00437         if ((flags & NDI_EMOTE) && ignore_check((char *) data, "emote"))
00438         {
00439             return;
00440         }
00441 
00442         /* Save last incoming tell for client-sided /reply */
00443         if (flags & NDI_TELL)
00444         {
00445             strncpy(cpl.player_reply, (char *) data, sizeof(cpl.player_reply));
00446         }
00447     }
00448 
00449     if (flags & NDI_ANIM)
00450     {
00451         strncpy(msg_anim.message, buf, sizeof(msg_anim.message) - 1);
00452         msg_anim.tick = LastTick;
00453         strncpy(msg_anim.color, color, sizeof(msg_anim.color) - 1);
00454         msg_anim.color[sizeof(msg_anim.color) - 1] = '\0';
00455     }
00456 
00457     draw_info_flags(color, flags, buf);
00458 }
00459 
00464 void TargetObject(unsigned char *data, int len)
00465 {
00466     int pos = 0;
00467 
00468     (void) len;
00469 
00470     cpl.target_mode = data[pos++];
00471 
00472     if (cpl.target_mode)
00473     {
00474         sound_play_effect("weapon_attack.ogg", 100);
00475     }
00476     else
00477     {
00478         sound_play_effect("weapon_hold.ogg", 100);
00479     }
00480 
00481     cpl.target_code = data[pos++];
00482     GetString_String(data, &pos, cpl.target_color, sizeof(cpl.target_color));
00483     GetString_String(data, &pos, cpl.target_name, sizeof(cpl.target_name));
00484 
00485     map_udate_flag = 2;
00486     map_redraw_flag = 1;
00487 }
00488 
00493 void StatsCmd(unsigned char *data, int len)
00494 {
00495     int i = 0;
00496     int c, temp;
00497 
00498     while (i < len)
00499     {
00500         c = data[i++];
00501 
00502         if (c >= CS_STAT_PROT_START && c <= CS_STAT_PROT_END)
00503         {
00504             cpl.stats.protection[c - CS_STAT_PROT_START] = (sint16) *(((signed char *) data) + i++);
00505             WIDGET_REDRAW_ALL(RESIST_ID);
00506         }
00507         else
00508         {
00509             switch (c)
00510             {
00511                 case CS_STAT_TARGET_HP:
00512                     cpl.target_hp = (int)*(data + i++);
00513                     break;
00514 
00515                 case CS_STAT_REG_HP:
00516                     cpl.gen_hp = abs(GetShort_String(data + i)) / 10.0f;
00517                     i += 2;
00518                     WIDGET_REDRAW_ALL(REGEN_ID);
00519                     break;
00520 
00521                 case CS_STAT_REG_MANA:
00522                     cpl.gen_sp = abs(GetShort_String(data + i)) / 10.0f;
00523                     i += 2;
00524                     WIDGET_REDRAW_ALL(REGEN_ID);
00525                     break;
00526 
00527                 case CS_STAT_REG_GRACE:
00528                     cpl.gen_grace = abs(GetShort_String(data + i)) / 10.0f;
00529                     i += 2;
00530                     WIDGET_REDRAW_ALL(REGEN_ID);
00531                     break;
00532 
00533                 case CS_STAT_HP:
00534                     temp = GetInt_String(data + i);
00535 
00536                     if (temp < cpl.stats.hp && cpl.stats.food)
00537                     {
00538                         cpl.warn_hp = 1;
00539 
00540                         if (cpl.stats.maxhp / 12 <= cpl.stats.hp - temp)
00541                         {
00542                             cpl.warn_hp = 2;
00543                         }
00544                     }
00545 
00546                     cpl.stats.hp = temp;
00547                     i += 4;
00548                     WIDGET_REDRAW_ALL(STATS_ID);
00549                     break;
00550 
00551                 case CS_STAT_MAXHP:
00552                     cpl.stats.maxhp = GetInt_String(data + i);
00553                     i += 4;
00554                     WIDGET_REDRAW_ALL(STATS_ID);
00555                     break;
00556 
00557                 case CS_STAT_SP:
00558                     cpl.stats.sp = GetShort_String(data + i);
00559                     i += 2;
00560                     WIDGET_REDRAW_ALL(STATS_ID);
00561                     break;
00562 
00563                 case CS_STAT_MAXSP:
00564                     cpl.stats.maxsp = GetShort_String(data + i);
00565                     i += 2;
00566                     WIDGET_REDRAW_ALL(STATS_ID);
00567                     break;
00568 
00569                 case CS_STAT_GRACE:
00570                     cpl.stats.grace = GetShort_String(data + i);
00571                     i += 2;
00572                     WIDGET_REDRAW_ALL(STATS_ID);
00573                     break;
00574 
00575                 case CS_STAT_MAXGRACE:
00576                     cpl.stats.maxgrace = GetShort_String(data + i);
00577                     i += 2;
00578                     WIDGET_REDRAW_ALL(STATS_ID);
00579                     break;
00580 
00581                 case CS_STAT_STR:
00582                     temp = (int) *(data + i++);
00583 
00584                     if (temp > cpl.stats.Str)
00585                     {
00586                         cpl.warn_statup = 1;
00587                     }
00588                     else
00589                     {
00590                         cpl.warn_statdown = 1;
00591                     }
00592 
00593                     cpl.stats.Str = temp;
00594                     WIDGET_REDRAW_ALL(STATS_ID);
00595                     break;
00596 
00597                 case CS_STAT_INT:
00598                     temp = (int) *(data + i++);
00599 
00600                     if (temp > cpl.stats.Int)
00601                     {
00602                         cpl.warn_statup = 1;
00603                     }
00604                     else
00605                     {
00606                         cpl.warn_statdown = 1;
00607                     }
00608 
00609                     cpl.stats.Int = temp;
00610                     WIDGET_REDRAW_ALL(STATS_ID);
00611                     break;
00612 
00613                 case CS_STAT_POW:
00614                     temp = (int) *(data + i++);
00615 
00616                     if (temp > cpl.stats.Pow)
00617                     {
00618                         cpl.warn_statup = 1;
00619                     }
00620                     else
00621                     {
00622                         cpl.warn_statdown = 1;
00623                     }
00624 
00625                     cpl.stats.Pow = temp;
00626                     WIDGET_REDRAW_ALL(STATS_ID);
00627                     break;
00628 
00629                 case CS_STAT_WIS:
00630                     temp = (int) *(data + i++);
00631 
00632                     if (temp > cpl.stats.Wis)
00633                     {
00634                         cpl.warn_statup = 1;
00635                     }
00636                     else
00637                     {
00638                         cpl.warn_statdown = 1;
00639                     }
00640 
00641                     cpl.stats.Wis = temp;
00642                     WIDGET_REDRAW_ALL(STATS_ID);
00643                     break;
00644 
00645                 case CS_STAT_DEX:
00646                     temp = (int) *(data + i++);
00647 
00648                     if (temp > cpl.stats.Dex)
00649                     {
00650                         cpl.warn_statup = 1;
00651                     }
00652                     else
00653                     {
00654                         cpl.warn_statdown = 1;
00655                     }
00656 
00657                     cpl.stats.Dex = temp;
00658                     WIDGET_REDRAW_ALL(STATS_ID);
00659                     break;
00660 
00661                 case CS_STAT_CON:
00662                     temp = (int) *(data + i++);
00663 
00664                     if (temp > cpl.stats.Con)
00665                     {
00666                         cpl.warn_statup = 1;
00667                     }
00668                     else
00669                     {
00670                         cpl.warn_statdown = 1;
00671                     }
00672 
00673                     cpl.stats.Con = temp;
00674                     WIDGET_REDRAW_ALL(STATS_ID);
00675                     break;
00676 
00677                 case CS_STAT_CHA:
00678                     temp = (int) *(data + i++);
00679 
00680                     if (temp > cpl.stats.Cha)
00681                     {
00682                         cpl.warn_statup = 1;
00683                     }
00684                     else
00685                     {
00686                         cpl.warn_statdown = 1;
00687                     }
00688 
00689                     cpl.stats.Cha = temp;
00690                     WIDGET_REDRAW_ALL(STATS_ID);
00691                     break;
00692 
00693                 case CS_STAT_EXP:
00694                     cpl.stats.exp = GetInt64_String(data + i);
00695                     i += 8;
00696                     WIDGET_REDRAW_ALL(MAIN_LVL_ID);
00697                     break;
00698 
00699                 case CS_STAT_LEVEL:
00700                     cpl.stats.level = (char) *(data + i++);
00701                     WIDGET_REDRAW_ALL(MAIN_LVL_ID);
00702                     break;
00703 
00704                 case CS_STAT_WC:
00705                     cpl.stats.wc = GetShort_String(data + i);
00706                     i += 2;
00707                     break;
00708 
00709                 case CS_STAT_AC:
00710                     cpl.stats.ac = GetShort_String(data + i);
00711                     i += 2;
00712                     break;
00713 
00714                 case CS_STAT_DAM:
00715                     cpl.stats.dam = GetShort_String(data + i);
00716                     i += 2;
00717                     break;
00718 
00719                 case CS_STAT_SPEED:
00720                     cpl.stats.speed = GetInt_String(data + i);
00721                     i += 4;
00722                     break;
00723 
00724                 case CS_STAT_FOOD:
00725                     cpl.stats.food = GetShort_String(data + i);
00726                     i += 2;
00727                     WIDGET_REDRAW_ALL(STATS_ID);
00728                     break;
00729 
00730                 case CS_STAT_WEAP_SP:
00731                     cpl.stats.weapon_sp = (int) *(data + i++);
00732                     break;
00733 
00734                 case CS_STAT_FLAGS:
00735                     cpl.stats.flags = GetShort_String(data + i);
00736                     i += 2;
00737                     break;
00738 
00739                 case CS_STAT_WEIGHT_LIM:
00740                     set_weight_limit(GetInt_String(data + i));
00741                     i += 4;
00742                     break;
00743 
00744                 case CS_STAT_ACTION_TIME:
00745                     cpl.action_timer = abs(GetInt_String(data + i)) / 1000.0f;
00746                     i += 4;
00747                     WIDGET_REDRAW_ALL(SKILL_EXP_ID);
00748                     break;
00749 
00750                 case CS_STAT_SKILLEXP_AGILITY:
00751                 case CS_STAT_SKILLEXP_PERSONAL:
00752                 case CS_STAT_SKILLEXP_MENTAL:
00753                 case CS_STAT_SKILLEXP_PHYSIQUE:
00754                 case CS_STAT_SKILLEXP_MAGIC:
00755                 case CS_STAT_SKILLEXP_WISDOM:
00756                     cpl.stats.skill_exp[(c - CS_STAT_SKILLEXP_START) / 2] = GetInt64_String(data + i);
00757                     i += 8;
00758                     WIDGET_REDRAW_ALL(SKILL_LVL_ID);
00759                     break;
00760 
00761                 case CS_STAT_SKILLEXP_AGLEVEL:
00762                 case CS_STAT_SKILLEXP_PELEVEL:
00763                 case CS_STAT_SKILLEXP_MELEVEL:
00764                 case CS_STAT_SKILLEXP_PHLEVEL:
00765                 case CS_STAT_SKILLEXP_MALEVEL:
00766                 case CS_STAT_SKILLEXP_WILEVEL:
00767                     cpl.stats.skill_level[(c - CS_STAT_SKILLEXP_START - 1) / 2] = (sint16)*(data + i++);
00768                     WIDGET_REDRAW_ALL(SKILL_LVL_ID);
00769                     break;
00770 
00771                 case CS_STAT_RANGE:
00772                 {
00773                     int rlen = data[i++];
00774 
00775                     strncpy(cpl.range, (const char *) data + i, rlen);
00776                     cpl.range[rlen] = '\0';
00777                     i += rlen;
00778                     break;
00779                 }
00780 
00781                 case CS_STAT_EXT_TITLE:
00782                 {
00783                     int rlen = data[i++];
00784 
00785                     strncpy(cpl.ext_title, (const char *) data + i, rlen);
00786                     cpl.ext_title[rlen] = '\0';
00787                     i += rlen;
00788 
00789                     if (strstr(cpl.ext_title, "[WIZ]"))
00790                     {
00791                         cpl.dm = 1;
00792                     }
00793                     else
00794                     {
00795                         cpl.dm = 0;
00796                     }
00797 
00798                     break;
00799                 }
00800 
00801                 case CS_STAT_RANGED_DAM:
00802                     cpl.stats.ranged_dam = GetShort_String(data + i);
00803                     i += 2;
00804                     break;
00805 
00806                 case CS_STAT_RANGED_WC:
00807                     cpl.stats.ranged_wc = GetShort_String(data + i);
00808                     i += 2;
00809                     break;
00810 
00811                 case CS_STAT_RANGED_WS:
00812                     cpl.stats.ranged_ws = GetInt_String(data + i);
00813                     i += 4;
00814                     break;
00815 
00816                 default:
00817                     fprintf(stderr, "Unknown stat number %d\n", c);
00818             }
00819         }
00820     }
00821 
00822     if (i > len)
00823     {
00824         fprintf(stderr, "Got stats overflow, processed %d bytes out of %d\n", i, len);
00825     }
00826 }
00827 
00831 void PreParseInfoStat(char *cmd)
00832 {
00833     /* Find input name */
00834     if (strstr(cmd, "What is your name?"))
00835     {
00836         LOG(llevInfo, "Login: Enter name\n");
00837         cpl.name[0] = '\0';
00838         cpl.password[0] = '\0';
00839         GameStatus = GAME_STATUS_NAME;
00840     }
00841 
00842     if (strstr(cmd, "What is your password?"))
00843     {
00844         LOG(llevInfo, "Login: Enter password\n");
00845         GameStatus = GAME_STATUS_PSWD;
00846     }
00847 
00848     if (strstr(cmd, "Please type your password again."))
00849     {
00850         LOG(llevInfo, "Login: Enter verify password\n");
00851         GameStatus = GAME_STATUS_VERIFYPSWD;
00852     }
00853 
00854     if (GameStatus >= GAME_STATUS_NAME && GameStatus <= GAME_STATUS_VERIFYPSWD)
00855     {
00856         text_input_open(64);
00857     }
00858 }
00859 
00863 void handle_query(char *data)
00864 {
00865     char *buf, *cp;
00866 
00867     buf = strchr(data, ' ');
00868 
00869     if (buf)
00870     {
00871         buf++;
00872     }
00873 
00874     if (buf)
00875     {
00876         cp = buf;
00877 
00878         while ((buf = strchr(buf, '\n')) != NULL)
00879         {
00880             *buf++ = '\0';
00881             LOG(llevInfo, "Received query string: %s\n", cp);
00882             PreParseInfoStat(cp);
00883             cp = buf;
00884         }
00885     }
00886 }
00887 
00891 void send_reply(char *text)
00892 {
00893     char buf[HUGE_BUF];
00894 
00895     snprintf(buf, sizeof(buf), "reply %s", text);
00896     cs_write_string(buf, strlen(buf));
00897 }
00898 
00904 void PlayerCmd(unsigned char *data, int len)
00905 {
00906     char name[MAX_BUF];
00907     int tag, weight, face, i = 0, nlen;
00908 
00909     GameStatus = GAME_STATUS_PLAY;
00910     text_input_string_end_flag = 0;
00911     tag = GetInt_String(data);
00912     i += 4;
00913     weight = GetInt_String(data + i);
00914     i += 4;
00915     face = GetInt_String(data + i);
00916     request_face(face);
00917     i += 4;
00918     nlen = data[i++];
00919     memcpy(name, (const char *) data + i, nlen);
00920 
00921     name[nlen] = '\0';
00922     i += nlen;
00923 
00924     if (i != len)
00925     {
00926         fprintf(stderr, "PlayerCmd: lengths do not match (%d!=%d)\n", len, i);
00927     }
00928 
00929     new_player(tag, weight, (short) face);
00930     map_udate_flag = 2;
00931     map_redraw_flag = 1;
00932 
00933     ignore_list_load();
00934 }
00935 
00940 void ItemXCmd(unsigned char *data, int len)
00941 {
00942     int weight, loc, tag, face, flags, pos = 0, nlen, anim, nrof, dmode;
00943     uint8 itype, stype, item_qua, item_con, item_skill, item_level;
00944     uint8 animspeed, direction = 0;
00945     char name[MAX_BUF];
00946 
00947     map_udate_flag = 2;
00948     itype = stype = item_qua = item_con = item_skill = item_level = 0;
00949 
00950     dmode = GetInt_String(data);
00951     pos += 4;
00952 
00953     loc = GetInt_String(data+pos);
00954 
00955     if (dmode >= 0)
00956     {
00957         object_remove_inventory(object_find(loc));
00958     }
00959 
00960     /* send item flag */
00961     if (dmode == -4)
00962     {
00963         /* and redirect it to our invisible sack */
00964         if (loc == cpl.container_tag)
00965         {
00966             loc = -1;
00967         }
00968     }
00969     /* container flag! */
00970     else if (dmode == -1)
00971     {
00972         /* we catch the REAL container tag */
00973         cpl.container_tag = loc;
00974         object_remove_inventory(object_find(-1));
00975 
00976         /* if this happens, we want to close the container */
00977         if (loc == -1)
00978         {
00979             cpl.container_tag = -998;
00980             return;
00981         }
00982 
00983         /* and redirect it to our invisible sack */
00984         loc = -1;
00985     }
00986 
00987     pos += 4;
00988 
00989     if (pos == len && loc != -1)
00990     {
00991         LOG(llevBug, "ItemXCmd(): Got location with no other data\n");
00992     }
00993     else
00994     {
00995         while (pos < len)
00996         {
00997             tag = GetInt_String(data + pos);
00998             pos += 4;
00999             flags = GetInt_String(data + pos);
01000             pos += 4;
01001             weight = GetInt_String(data + pos);
01002             pos += 4;
01003             face = GetInt_String(data + pos);
01004             pos += 4;
01005             request_face(face);
01006             direction = data[pos++];
01007 
01008             if (loc)
01009             {
01010                 itype = data[pos++];
01011                 stype = data[pos++];
01012                 item_qua = data[pos++];
01013                 item_con = data[pos++];
01014                 item_level = data[pos++];
01015                 item_skill = data[pos++];
01016             }
01017 
01018             nlen = data[pos++];
01019             memcpy(name, (char *) data + pos, nlen);
01020             pos += nlen;
01021             name[nlen] = '\0';
01022             anim = GetShort_String(data + pos);
01023             pos += 2;
01024             animspeed = data[pos++];
01025             nrof = GetInt_String(data + pos);
01026             pos += 4;
01027             update_object(tag, loc, name, weight, face, flags, anim, animspeed, nrof, itype, stype, item_qua, item_con, item_skill, item_level, direction, 0);
01028         }
01029 
01030         if (pos > len)
01031         {
01032             LOG(llevBug, "ItemXCmd(): Overread buffer: %d > %d\n", pos, len);
01033         }
01034     }
01035 
01036     map_udate_flag = 2;
01037 }
01038 
01043 void ItemYCmd(unsigned char *data, int len)
01044 {
01045     int weight, loc, tag, face, flags, pos = 0, nlen, anim, nrof, dmode;
01046     uint8 itype, stype, item_qua, item_con, item_skill, item_level;
01047     uint8 animspeed, direction = 0;
01048     char name[MAX_BUF];
01049 
01050     map_udate_flag = 2;
01051     itype = stype = item_qua = item_con = item_skill = item_level = 0;
01052 
01053     dmode = GetInt_String(data);
01054     pos += 4;
01055 
01056     loc = GetInt_String(data + pos);
01057 
01058     if (dmode >= 0)
01059     {
01060         object_remove_inventory(object_find(loc));
01061     }
01062 
01063     /* send item flag */
01064     if (dmode == -4)
01065     {
01066         /* and redirect it to our invisible sack */
01067         if (loc == cpl.container_tag)
01068         {
01069             loc = -1;
01070         }
01071     }
01072     /* container flag! */
01073     else if (dmode == -1)
01074     {
01075         /* we catch the REAL container tag */
01076         cpl.container_tag = loc;
01077         object_remove_inventory(object_find(-1));
01078 
01079         /* if this happens, we want to close the container */
01080         if (loc == -1)
01081         {
01082             cpl.container_tag = -998;
01083             return;
01084         }
01085 
01086         /* and redirect it to our invisible sack */
01087         loc = -1;
01088     }
01089 
01090 
01091     pos += 4;
01092 
01093     if (pos == len && loc != -1)
01094     {
01095         /* server sends no clean command to clear below window */
01096     }
01097     else
01098     {
01099         while (pos < len)
01100         {
01101             tag = GetInt_String(data + pos);
01102             pos += 4;
01103             flags = GetInt_String(data + pos);
01104             pos += 4;
01105             weight = GetInt_String(data + pos);
01106             pos += 4;
01107             face = GetInt_String(data + pos);
01108             pos += 4;
01109             request_face(face);
01110             direction = data[pos++];
01111 
01112             if (loc)
01113             {
01114                 itype = data[pos++];
01115                 stype = data[pos++];
01116                 item_qua = data[pos++];
01117                 item_con = data[pos++];
01118                 item_level = data[pos++];
01119                 item_skill = data[pos++];
01120             }
01121 
01122             nlen = data[pos++];
01123             memcpy(name, (char *) data + pos, nlen);
01124             pos += nlen;
01125             name[nlen] = '\0';
01126             anim = GetShort_String(data + pos);
01127             pos += 2;
01128             animspeed = data[pos++];
01129             nrof = GetInt_String(data + pos);
01130             pos += 4;
01131             update_object(tag, loc, name, weight, face, flags, anim, animspeed, nrof, itype, stype, item_qua, item_con, item_skill, item_level, direction, 1);
01132         }
01133 
01134         if (pos > len)
01135         {
01136             LOG(llevBug, "ItemYCmd(): Overread buffer: %d > %d\n", pos, len);
01137         }
01138     }
01139 
01140     map_udate_flag = 2;
01141 }
01142 
01147 void UpdateItemCmd(unsigned char *data, int len)
01148 {
01149     int weight, loc, tag, face, sendflags, flags, pos = 0, nlen, anim, nrof;
01150     uint8 direction;
01151     char name[MAX_BUF];
01152     object *ip, *env = NULL;
01153     uint8 animspeed;
01154 
01155     map_udate_flag = 2;
01156     sendflags = GetShort_String(data);
01157     pos += 2;
01158     tag = GetInt_String(data + pos);
01159     pos += 4;
01160     ip = object_find(tag);
01161 
01162     if (!ip)
01163     {
01164         return;
01165     }
01166 
01167     *name = '\0';
01168     loc = ip->env ? ip->env->tag : 0;
01169     weight = (int) (ip->weight * 1000);
01170     face = ip->face;
01171     request_face(face);
01172     flags = ip->flags;
01173     anim = ip->animation_id;
01174     animspeed = (uint8) ip->anim_speed;
01175     nrof = ip->nrof;
01176     direction = ip->direction;
01177 
01178     if (sendflags & UPD_LOCATION)
01179     {
01180         loc = GetInt_String(data + pos);
01181         env = object_find(loc);
01182 
01183         if (!env)
01184         {
01185             fprintf(stderr, "UpdateItemCmd: unknown object tag (%d) for new location\n", loc);
01186         }
01187 
01188         pos += 4;
01189     }
01190 
01191     if (sendflags & UPD_FLAGS)
01192     {
01193         flags = GetInt_String(data + pos);
01194         pos += 4;
01195     }
01196 
01197     if (sendflags & UPD_WEIGHT)
01198     {
01199         weight = GetInt_String(data + pos);
01200         pos += 4;
01201     }
01202 
01203     if (sendflags & UPD_FACE)
01204     {
01205         face = GetInt_String(data + pos);
01206         request_face(face);
01207         pos += 4;
01208     }
01209 
01210     if (sendflags & UPD_DIRECTION)
01211     {
01212         direction = data[pos++];
01213     }
01214 
01215     if (sendflags & UPD_NAME)
01216     {
01217         nlen = data[pos++];
01218         memcpy(name, (char *) data + pos, nlen);
01219         pos += nlen;
01220         name[nlen] = '\0';
01221     }
01222 
01223     if (pos > len)
01224     {
01225         fprintf(stderr, "UpdateItemCmd: Overread buffer: %d > %d\n", pos, len);
01226         return;
01227     }
01228 
01229     if (sendflags & UPD_ANIM)
01230     {
01231         anim = GetShort_String(data + pos);
01232         pos += 2;
01233     }
01234 
01235     if (sendflags & UPD_ANIMSPEED)
01236     {
01237         animspeed = data[pos++];
01238     }
01239 
01240     if (sendflags & UPD_NROF)
01241     {
01242         nrof = GetInt_String(data + pos);
01243         pos += 4;
01244     }
01245 
01246     update_object(tag, loc, name, weight, face, flags, anim, animspeed, nrof, 254, 254, 254, 254, 254, 254, direction, 0);
01247     map_udate_flag = 2;
01248 }
01249 
01254 void DeleteItem(unsigned char *data, int len)
01255 {
01256     int pos = 0,tag;
01257 
01258     while (pos < len)
01259     {
01260         tag = GetInt_String(data);
01261         pos += 4;
01262         delete_object(tag);
01263     }
01264 
01265     if (pos > len)
01266     {
01267         fprintf(stderr, "ItemCmd: Overread buffer: %d > %d\n", pos, len);
01268     }
01269 
01270     map_udate_flag = 2;
01271 }
01272 
01276 void DeleteInventory(unsigned char *data)
01277 {
01278     int tag;
01279 
01280     tag = atoi((const char *) data);
01281 
01282     if (tag < 0)
01283     {
01284         fprintf(stderr, "DeleteInventory: Invalid tag: %d\n", tag);
01285         return;
01286     }
01287 
01288     object_remove_inventory(object_find(tag));
01289     map_udate_flag = 2;
01290 }
01291 
01294 static void map_play_footstep()
01295 {
01296     static int step = 0;
01297     static uint32 tick = 0;
01298 
01299     if (LastTick - tick > 125)
01300     {
01301         step++;
01302 
01303         if (step % 2)
01304         {
01305             sound_play_effect("step1.ogg", 100);
01306         }
01307         else
01308         {
01309             step = 0;
01310             sound_play_effect("step2.ogg", 100);
01311         }
01312 
01313         tick = LastTick;
01314     }
01315 }
01316 
01321 void MapStatsCmd(unsigned char *data, int len)
01322 {
01323     int pos = 0;
01324     char buf[HUGE_BUF];
01325     uint8 type;
01326 
01327     /* Loop, trying to find data. */
01328     while (pos < len)
01329     {
01330         /* Get the type of this command... */
01331         type = (uint8) (data[pos++]);
01332 
01333         /* Change map name. */
01334         if (type == CMD_MAPSTATS_NAME)
01335         {
01336             strncpy(buf, (const char *) (data + pos), sizeof(buf) - 1);
01337             buf[sizeof(buf) - 1] = '\0';
01338             pos += strlen(buf) + 1;
01339             update_map_name(buf);
01340         }
01341         /* Change map music. */
01342         else if (type == CMD_MAPSTATS_MUSIC)
01343         {
01344             strncpy(buf, (const char *) (data + pos), sizeof(buf) - 1);
01345             buf[sizeof(buf) - 1] = '\0';
01346             pos += strlen(buf) + 1;
01347             update_map_bg_music(buf);
01348         }
01349         /* Change map weather. */
01350         else if (type == CMD_MAPSTATS_WEATHER)
01351         {
01352             strncpy(buf, (const char *) (data + pos), sizeof(buf) - 1);
01353             buf[sizeof(buf) - 1] = '\0';
01354             pos += strlen(buf) + 1;
01355             update_map_weather(buf);
01356         }
01357     }
01358 }
01359 
01364 void Map2Cmd(unsigned char *data, int len)
01365 {
01366     static int mx = 0, my = 0;
01367     int mask, x, y, pos = 0;
01368     int mapstat;
01369     int xpos, ypos;
01370     int layer, ext_flags;
01371     uint8 num_layers;
01372 
01373     mapstat = (uint8) (data[pos++]);
01374 
01375     if (mapstat != MAP_UPDATE_CMD_SAME)
01376     {
01377         char mapname[HUGE_BUF], bg_music[HUGE_BUF], weather[MAX_BUF];
01378 
01379         strncpy(mapname, (const char *) (data + pos), sizeof(mapname) - 1);
01380         pos += strlen(mapname) + 1;
01381         strncpy(bg_music, (const char *) (data + pos), sizeof(bg_music) - 1);
01382         pos += strlen(bg_music) + 1;
01383         strncpy(weather, (const char *) (data + pos), sizeof(weather) - 1);
01384         pos += strlen(weather) + 1;
01385 
01386         if (mapstat == MAP_UPDATE_CMD_NEW)
01387         {
01388             int map_w, map_h;
01389 
01390             map_w = (uint8) (data[pos++]);
01391             map_h = (uint8) (data[pos++]);
01392             xpos = (uint8) (data[pos++]);
01393             ypos = (uint8) (data[pos++]);
01394             mx = xpos;
01395             my = ypos;
01396             object_remove_inventory(object_find(0));
01397             init_map_data(map_w, map_h, xpos, ypos);
01398         }
01399         else
01400         {
01401             int xoff, yoff;
01402 
01403             mapstat = (sint8) (data[pos++]);
01404             xoff = (sint8) (data[pos++]);
01405             yoff = (sint8) (data[pos++]);
01406             xpos = (uint8) (data[pos++]);
01407             ypos = (uint8) (data[pos++]);
01408             mx = xpos;
01409             my = ypos;
01410             object_remove_inventory(object_find(0));
01411             display_mapscroll(xoff, yoff);
01412 
01413             map_play_footstep();
01414         }
01415 
01416         update_map_name(mapname);
01417         update_map_bg_music(bg_music);
01418         update_map_weather(weather);
01419     }
01420     else
01421     {
01422         xpos = (uint8) (data[pos++]);
01423         ypos = (uint8) (data[pos++]);
01424 
01425         /* we have moved */
01426         if ((xpos - mx || ypos - my))
01427         {
01428             object_remove_inventory(object_find(0));
01429             cpl.win_below_slot = 0;
01430 
01431             display_mapscroll(xpos - mx, ypos - my);
01432             map_play_footstep();
01433         }
01434 
01435         mx = xpos;
01436         my = ypos;
01437     }
01438 
01439     MapData.posx = xpos;
01440     MapData.posy = ypos;
01441 
01442     while (pos < len)
01443     {
01444         mask = GetShort_String(data + pos);
01445         pos += 2;
01446         x = (mask >> 11) & 0x1f;
01447         y = (mask >> 6) & 0x1f;
01448 
01449         /* Clear the whole cell? */
01450         if (mask & MAP2_MASK_CLEAR)
01451         {
01452             map_clear_cell(x, y);
01453             continue;
01454         }
01455 
01456         /* Do we have darkness information? */
01457         if (mask & MAP2_MASK_DARKNESS)
01458         {
01459             map_set_darkness(x, y, (uint8) (data[pos++]));
01460         }
01461 
01462         num_layers = data[pos++];
01463 
01464         /* Go through all the layers on this tile. */
01465         for (layer = 0; layer < num_layers; layer++)
01466         {
01467             uint8 type = data[pos++];
01468 
01469             /* Clear this layer. */
01470             if (type == MAP2_LAYER_CLEAR)
01471             {
01472                 map_set_data(x, y, data[pos++], 0, 0, 0, "", "", 0, 0, 0, 0, 0, 0, 0, 0);
01473             }
01474             /* We have some data. */
01475             else
01476             {
01477                 sint16 face = GetShort_String(data + pos), height = 0, zoom = 0, align = 0, rotate = 0;
01478                 uint8 flags, obj_flags, quick_pos = 0, probe = 0, draw_double = 0, alpha = 0, infravision = 0;
01479                 char player_name[64], player_color[COLOR_BUF];
01480 
01481                 player_name[0] = '\0';
01482                 player_color[0] = '\0';
01483 
01484                 pos += 2;
01485                 /* Request the face. */
01486                 request_face(face);
01487                 /* Object flags. */
01488                 obj_flags = data[pos++];
01489                 /* Flags of this layer. */
01490                 flags = data[pos++];
01491 
01492                 /* Multi-arch? */
01493                 if (flags & MAP2_FLAG_MULTI)
01494                 {
01495                     quick_pos = data[pos++];
01496                 }
01497 
01498                 /* Player name? */
01499                 if (flags & MAP2_FLAG_NAME)
01500                 {
01501                     GetString_String(data, &pos, player_name, sizeof(player_name));
01502                     GetString_String(data, &pos, player_color, sizeof(player_color));
01503                 }
01504 
01505                 /* Target's HP? */
01506                 if (flags & MAP2_FLAG_PROBE)
01507                 {
01508                     probe = data[pos++];
01509                 }
01510 
01511                 /* Z position? */
01512                 if (flags & MAP2_FLAG_HEIGHT)
01513                 {
01514                     height = GetShort_String(data + pos);
01515                     pos += 2;
01516                 }
01517 
01518                 /* Zoom? */
01519                 if (flags & MAP2_FLAG_ZOOM)
01520                 {
01521                     zoom = GetShort_String(data + pos);
01522                     pos += 2;
01523                 }
01524 
01525                 /* Align? */
01526                 if (flags & MAP2_FLAG_ALIGN)
01527                 {
01528                     align = GetShort_String(data + pos);
01529                     pos += 2;
01530                 }
01531 
01532                 /* Double? */
01533                 if (flags & MAP2_FLAG_DOUBLE)
01534                 {
01535                     draw_double = 1;
01536                 }
01537 
01538                 if (flags & MAP2_FLAG_MORE)
01539                 {
01540                     uint32 flags2 = GetInt_String(data + pos);
01541 
01542                     pos += 4;
01543 
01544                     if (flags2 & MAP2_FLAG2_ALPHA)
01545                     {
01546                         alpha = data[pos++];
01547                     }
01548 
01549                     if (flags2 & MAP2_FLAG2_ROTATE)
01550                     {
01551                         rotate = GetShort_String(data + pos);
01552                         pos += 2;
01553                     }
01554 
01555                     if (flags2 & MAP2_FLAG2_INFRAVISION)
01556                     {
01557                         infravision = 1;
01558                     }
01559                 }
01560 
01561                 /* Set the data we figured out. */
01562                 map_set_data(x, y, type, face, quick_pos, obj_flags, player_name, player_color, height, probe, zoom, align, draw_double, alpha, rotate, infravision);
01563             }
01564         }
01565 
01566         /* Get tile flags. */
01567         ext_flags = data[pos++];
01568 
01569         /* Animation? */
01570         if (ext_flags & MAP2_FLAG_EXT_ANIM)
01571         {
01572             uint8 anim_type;
01573             sint16 anim_value;
01574 
01575             anim_type = data[pos++];
01576             anim_value = GetShort_String(data + pos);
01577             pos += 2;
01578 
01579             add_anim(anim_type, xpos + x, ypos + y, anim_value);
01580         }
01581     }
01582 
01583     adjust_tile_stretch();
01584     map_udate_flag = 2;
01585     map_redraw_flag = 1;
01586 }
01587 
01590 void MagicMapCmd(unsigned char *data, int len)
01591 {
01592     (void) data;
01593     (void) len;
01594 }
01595 
01599 void VersionCmd(char *data)
01600 {
01601     (void) data;
01602 }
01603 
01607 void SendVersion()
01608 {
01609     char buf[MAX_BUF];
01610 
01611     snprintf(buf, sizeof(buf), "version %d %s", SOCKET_VERSION, PACKAGE_NAME);
01612     cs_write_string(buf, strlen(buf));
01613 }
01614 
01619 void RequestFile(int idx)
01620 {
01621     char buf[MAX_BUF];
01622 
01623     sprintf(buf, "rf %d", idx);
01624     cs_write_string(buf, strlen(buf));
01625 }
01626 
01630 void SendAddMe()
01631 {
01632     cs_write_string("addme", 5);
01633 }
01634 
01638 void NewCharCmd()
01639 {
01640     GameStatus = GAME_STATUS_NEW_CHAR;
01641 }
01642 
01648 void DataCmd(unsigned char *data, int len)
01649 {
01650     uint8 data_type;
01651     unsigned long len_ucomp;
01652     unsigned char *dest;
01653 
01654     data_type = *data++;
01655     len_ucomp = GetInt_String(data);
01656     data += 4;
01657     len -= 5;
01658     /* Allocate large enough buffer to hold the uncompressed file. */
01659     dest = malloc(len_ucomp);
01660 
01661     LOG(llevInfo, "DataCmd(): Uncompressing file #%d (len: %d, uncompressed len: %lu)\n", data_type, len, len_ucomp);
01662     uncompress((Bytef *) dest, (uLongf *) &len_ucomp, (const Bytef *) data, (uLong) len);
01663     data = dest;
01664     len = len_ucomp;
01665     server_file_save(data_type, data, len);
01666     free(dest);
01667 }
01668 
01673 void ShopCmd(unsigned char *data, int len)
01674 {
01675     (void) data;
01676     (void) len;
01677 }
01678 
01685 void QuestListCmd(unsigned char *data, int len)
01686 {
01687     sound_play_effect("book.ogg", 100);
01688 
01689     data += 4;
01690     book_load((char *) data, len - 4);
01691 }
01692 
01698 void ReadyCmd(unsigned char *data, int len)
01699 {
01700     int tag;
01701     uint8 type;
01702 
01703     (void) len;
01704 
01705     type = data[0];
01706     tag = GetInt_String(data + 1);
01707 
01708     if (type == READY_OBJ_ARROW)
01709     {
01710         fire_mode_tab[FIRE_MODE_BOW].amun = tag;
01711     }
01712     else if (type == READY_OBJ_THROW)
01713     {
01714         fire_mode_tab[FIRE_MODE_THROW].item = tag;
01715     }
01716 }