Crossfire Server, Branch 1.12  R12190
request.c
Go to the documentation of this file.
00001 /*
00002  * static char *rcsid_request_c =
00003  *    "$Id: request.c 17660 2012-03-23 19:08:26Z akirschbaum $";
00004  */
00005 
00006 /*
00007   CrossFire, A Multiplayer game for X-windows
00008 
00009   Copyright (C) 2001-2006 Mark Wedel
00010   Copyright (C) 1992 Frank Tore Johansen
00011 
00012   This program is free software; you can redistribute it and/or modify
00013   it under the terms of the GNU General Public License as published by
00014   the Free Software Foundation; either version 2 of the License, or
00015   (at your option) any later version.
00016 
00017   This program is distributed in the hope that it will be useful,
00018   but WITHOUT ANY WARRANTY; without even the implied warranty of
00019   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020   GNU General Public License for more details.
00021 
00022   You should have received a copy of the GNU General Public License
00023   along with this program; if not, write to the Free Software
00024   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00025 
00026   The author can be reached via e-mail to crossfire-devel@real-time.com
00027 */
00028 
00059 #include <assert.h>
00060 #include <global.h>
00061 #include <sproto.h>
00062 
00063 #include <newclient.h>
00064 #include <newserver.h>
00065 #include <living.h>
00066 #include <commands.h>
00067 
00068 /* This block is basically taken from socket.c - I assume if it works there,
00069  * it should work here.
00070  */
00071 #ifndef WIN32 /* ---win32 exclude unix headers */
00072 #include <sys/types.h>
00073 #include <sys/time.h>
00074 #include <sys/socket.h>
00075 #include <netinet/in.h>
00076 #include <netinet/tcp.h>
00077 #include <netdb.h>
00078 #endif /* win32 */
00079 
00080 #ifdef HAVE_UNISTD_H
00081 #include <unistd.h>
00082 #endif
00083 
00084 #ifdef HAVE_SYS_TIME_H
00085 #include <sys/time.h>
00086 #endif
00087 
00088 #include "sounds.h"
00089 
00096 static const short atnr_cs_stat[NROFATTACKS] = {
00097     CS_STAT_RES_PHYS, CS_STAT_RES_MAG,
00098     CS_STAT_RES_FIRE, CS_STAT_RES_ELEC,
00099     CS_STAT_RES_COLD, CS_STAT_RES_CONF,
00100     CS_STAT_RES_ACID,
00101     CS_STAT_RES_DRAIN, -1 /* weaponmagic */,
00102     CS_STAT_RES_GHOSTHIT, CS_STAT_RES_POISON,
00103     CS_STAT_RES_SLOW, CS_STAT_RES_PARA,
00104     CS_STAT_TURN_UNDEAD,
00105     CS_STAT_RES_FEAR, -1 /* Cancellation */,
00106     CS_STAT_RES_DEPLETE, CS_STAT_RES_DEATH,
00107     -1 /* Chaos */, -1 /* Counterspell */,
00108     -1 /* Godpower */, CS_STAT_RES_HOLYWORD,
00109     CS_STAT_RES_BLIND,
00110     -1, /* Internal */
00111     -1, /* life stealing */
00112     -1 /* Disease - not fully done yet */
00113 };
00114 
00116 void set_up_cmd(char *buf, int len, socket_struct *ns) {
00117     int s;
00118     char *cmd, *param;
00119     SockList sl;
00120 
00121     /* run through the cmds of setup
00122      * syntax is setup <cmdname1> <parameter> <cmdname2> <parameter> ...
00123      *
00124      * we send the status of the cmd back, or a FALSE is the cmd
00125      * is the server unknown
00126      * The client then must sort this out
00127      */
00128 
00129     LOG(llevInfo, "Get SetupCmd:: %s\n", buf);
00130     SockList_Init(&sl);
00131     SockList_AddString(&sl, "setup");
00132     for (s = 0; s < len; ) {
00133         cmd = &buf[s];
00134 
00135         /* find the next space, and put a null there */
00136         for (; buf[s] && buf[s] != ' '; s++)
00137             ;
00138         if (s >= len)
00139             break;
00140         buf[s++] = 0;
00141 
00142         while (buf[s] == ' ')
00143             s++;
00144         if (s >= len)
00145             break;
00146         param = &buf[s];
00147 
00148         for (; buf[s] && buf[s] != ' '; s++)
00149             ;
00150         buf[s++] = 0;
00151 
00152         while (s < len && buf[s] == ' ')
00153             s++;
00154 
00155         SockList_AddPrintf(&sl, " %s ", cmd);
00156 
00157         if (!strcmp(cmd, "sound")) {
00158             /* this is the old sound command, which means the client doesn't understand our sound => mute. */
00159             ns->sound = 0;
00160             SockList_AddString(&sl, "FALSE");
00161         } else if (!strcmp(cmd, "sound2")) {
00162             ns->sound = atoi(param)&(SND_EFFECTS|SND_MUSIC|SND_MUTE);
00163             SockList_AddString(&sl, param);
00164         } else if (!strcmp(cmd, "exp64")) {
00165             /* for compatibility, return 1 since older clients can be confused else. */
00166             SockList_AddString(&sl, "1");
00167         } else if (!strcmp(cmd, "spellmon")) {
00168             int monitor_spells;
00169 
00170             monitor_spells = atoi(param);
00171             if (monitor_spells != 0 && monitor_spells != 1) {
00172                 SockList_AddString(&sl, "FALSE");
00173             } else {
00174                 ns->monitor_spells = monitor_spells;
00175                 SockList_AddPrintf(&sl, "%d", monitor_spells);
00176             }
00177         } else if (!strcmp(cmd, "darkness")) {
00178             int darkness;
00179 
00180             darkness = atoi(param);
00181             if (darkness != 0 && darkness != 1) {
00182                 SockList_AddString(&sl, "FALSE");
00183             } else {
00184                 ns->darkness = darkness;
00185                 SockList_AddPrintf(&sl, "%d", darkness);
00186             }
00187         } else if (!strcmp(cmd, "map2cmd")) {
00188             int map2cmd;
00189 
00190             map2cmd = atoi(param);
00191             if (map2cmd != 1) {
00192                 SockList_AddString(&sl, "FALSE");
00193             } else {
00194                 SockList_AddString(&sl, "1");
00195             }
00196         } else if (!strcmp(cmd, "newmapcmd")) {
00197             int newmapcmd;
00198 
00199             newmapcmd = atoi(param);
00200             if (newmapcmd != 0 && newmapcmd != 1) {
00201                 SockList_AddString(&sl, "FALSE");
00202             } else {
00203                 ns->newmapcmd = newmapcmd;
00204                 SockList_AddPrintf(&sl, "%d", newmapcmd);
00205             }
00206         } else if (!strcmp(cmd, "facecache")) {
00207             int facecache;
00208 
00209             facecache = atoi(param);
00210             if (facecache != 0 && facecache != 1) {
00211                 SockList_AddString(&sl, "FALSE");
00212             } else {
00213                 ns->facecache = facecache;
00214                 SockList_AddPrintf(&sl, "%d", facecache);
00215             }
00216         } else if (!strcmp(cmd, "faceset")) {
00217             int q = atoi(param);
00218 
00219             if (is_valid_faceset(q))
00220                 ns->faceset = q;
00221             SockList_AddPrintf(&sl, "%d", ns->faceset);
00222         } else if (!strcmp(cmd, "itemcmd")) {
00223             /* client ignore the value anyway. */
00224             SockList_AddString(&sl, "2");
00225         } else if (!strcmp(cmd, "mapsize")) {
00226             int x, y, n;
00227 
00228             if (sscanf(param, "%dx%d%n", &x, &y, &n) != 2 || n != (int)strlen(param)) {
00229                 x = 0;
00230                 y = 0;
00231             }
00232             if (x < 9 || y < 9 || x > MAP_CLIENT_X || y > MAP_CLIENT_Y) {
00233                 SockList_AddPrintf(&sl, "%dx%d", MAP_CLIENT_X, MAP_CLIENT_Y);
00234             } else {
00235                 ns->mapx = x;
00236                 ns->mapy = y;
00237                 /* better to send back what we are really using and not the
00238                  * param as given to us in case it gets parsed differently.
00239                  */
00240                 SockList_AddPrintf(&sl, "%dx%d", x, y);
00241                 /* Client and server need to resynchronize on data - treating it as
00242                  * a new map is best way to go.
00243                  */
00244                 map_newmap_cmd(ns);
00245             }
00246         } else if (!strcmp(cmd, "extendedMapInfos")) {
00247             SockList_AddString(&sl, "1");
00248         } else if (!strcmp(cmd, "extendedTextInfos")) {
00249             int has_readable_type;
00250 
00251             has_readable_type = atoi(param);
00252             if (has_readable_type != 0 && has_readable_type != 1) {
00253                 SockList_AddString(&sl, "FALSE");
00254             } else {
00255                 ns->has_readable_type = has_readable_type;
00256                 SockList_AddPrintf(&sl, "%d", has_readable_type);
00257             }
00258         } else if (!strcmp(cmd, "tick")) {
00259             int tick;
00260 
00261             tick = atoi(param);
00262             if (tick != 0 && tick != 1) {
00263                 SockList_AddString(&sl, "FALSE");
00264             } else {
00265                 ns->tick = tick;
00266                 SockList_AddPrintf(&sl, "%d", tick);
00267             }
00268         } else if (!strcmp(cmd, "bot")) {
00269             int is_bot;
00270 
00271             is_bot = atoi(param);
00272             if (is_bot != 0 && is_bot != 1) {
00273                 SockList_AddString(&sl, "FALSE");
00274             } else {
00275                 ns->is_bot = is_bot;
00276                 SockList_AddPrintf(&sl, "%d", is_bot);
00277             }
00278         } else if (!strcmp(cmd, "want_pickup")) {
00279             int want_pickup;
00280 
00281             want_pickup = atoi(param);
00282             if (want_pickup != 0 && want_pickup != 1) {
00283                 SockList_AddString(&sl, "FALSE");
00284             } else {
00285                 ns->want_pickup = want_pickup;
00286                 SockList_AddPrintf(&sl, "%d", want_pickup);
00287             }
00288         } else if (!strcmp(cmd, "inscribe")) {
00289             SockList_AddString(&sl, "1");
00290         } else if (!strcmp(cmd, "num_look_objects")) {
00291             int tmp;
00292 
00293             tmp = atoi(param);
00294             if (tmp < MIN_NUM_LOOK_OBJECTS) {
00295                 tmp = MIN_NUM_LOOK_OBJECTS;
00296             } else if (tmp > MAX_NUM_LOOK_OBJECTS) {
00297                 tmp = MAX_NUM_LOOK_OBJECTS;
00298             }
00299             ns->num_look_objects = (uint8)tmp;
00300             SockList_AddPrintf(&sl, "%d", tmp);
00301         } else {
00302             /* Didn't get a setup command we understood -
00303              * report a failure to the client.
00304              */
00305             SockList_AddString(&sl, "FALSE");
00306         }
00307     } /* for processing all the setup commands */
00308     Send_With_Handling(ns, &sl);
00309     SockList_Term(&sl);
00310 }
00311 
00320 void add_me_cmd(char *buf, int len, socket_struct *ns) {
00321     Settings oldsettings;
00322     SockList sl;
00323 
00324     oldsettings = settings;
00325     if (ns->status != Ns_Add) {
00326         SockList_Init(&sl);
00327         SockList_AddString(&sl, "addme_failed");
00328         Send_With_Handling(ns, &sl);
00329         SockList_Term(&sl);
00330     } else {
00331         add_player(ns);
00332         /* Basically, the add_player copies the socket structure into
00333          * the player structure, so this one (which is from init_sockets)
00334          * is not needed anymore. The write below should still work,
00335          * as the stuff in ns is still relevant.
00336          */
00337         SockList_Init(&sl);
00338         SockList_AddString(&sl, "addme_success");
00339         Send_With_Handling(ns, &sl);
00340         SockList_Term(&sl);
00341         if (ns->sc_version < 1027 || ns->cs_version < 1023) {
00342             /* The space in the link isn't correct, but in my
00343              * quick test with client 1.1.0, it didn't print it
00344              * out correctly when done as a single line.
00345              */
00346             SockList_Init(&sl);
00347             SockList_AddString(&sl, "drawinfo 3 Warning: Your client is too old to receive map data. Please update to a new client at http://sourceforge.net/project/showfiles.php ?group_id=13833");
00348             Send_With_Handling(ns, &sl);
00349             SockList_Term(&sl);
00350         }
00351 
00352         socket_info.nconns--;
00353         ns->status = Ns_Avail;
00354     }
00355     settings = oldsettings;
00356 }
00357 
00359 void toggle_extended_infos_cmd(char *buf, int len, socket_struct *ns) {
00360     SockList sl;
00361     char command[50];
00362     int info, nextinfo, smooth = 0;
00363 
00364     nextinfo = 0;
00365     while (1) {
00366         /* 1. Extract an info*/
00367         info = nextinfo;
00368         while (info < len && buf[info] == ' ')
00369             info++;
00370         if (info >= len)
00371             break;
00372         nextinfo = info+1;
00373         while (nextinfo < len && buf[nextinfo] != ' ')
00374             nextinfo++;
00375         if (nextinfo-info >= 49) /*Erroneous info asked*/
00376             continue;
00377         strncpy(command, &buf[info], nextinfo-info);
00378         command[nextinfo-info] = '\0';
00379         /* 2. Interpret info*/
00380         if (!strcmp("smooth", command)) {
00381             /* Toggle smoothing*/
00382             smooth = 1;
00383         } else {
00384             /*bad value*/
00385         }
00386         /*3. Next info*/
00387     }
00388     SockList_Init(&sl);
00389     SockList_AddString(&sl, "ExtendedInfoSet");
00390     if (smooth) {
00391         SockList_AddString(&sl, " smoothing");
00392     }
00393     Send_With_Handling(ns, &sl);
00394     SockList_Term(&sl);
00395 }
00396 
00398 void toggle_extended_text_cmd(char *buf, int len, socket_struct *ns) {
00399     SockList sl;
00400     char command[50];
00401     int info, nextinfo, i, flag;
00402 
00403     nextinfo = 0;
00404     while (1) {
00405         /* 1. Extract an info*/
00406         info = nextinfo;
00407         while (info < len && buf[info] == ' ')
00408             info++;
00409         if (info >= len)
00410             break;
00411         nextinfo = info+1;
00412         while (nextinfo < len && buf[nextinfo] != ' ')
00413             nextinfo++;
00414         if (nextinfo-info >= 49) /*Erroneous info asked*/
00415             continue;
00416         strncpy(command, &buf[info], nextinfo-info);
00417         command[nextinfo-info] = '\0';
00418         /* 2. Interpret info*/
00419         i = sscanf(command, "%d", &flag);
00420         if (i == 1 && flag > 0 && flag <= MSG_TYPE_LAST)
00421             ns->supported_readables |= (1<<flag);
00422         /*3. Next info*/
00423     }
00424     /* Send resulting state */
00425     SockList_Init(&sl);
00426     SockList_AddString(&sl, "ExtendedTextSet");
00427     for (i = 0; i <= MSG_TYPE_LAST; i++)
00428         if (ns->supported_readables&(1<<i)) {
00429             SockList_AddPrintf(&sl, " %d", i);
00430         }
00431     Send_With_Handling(ns, &sl);
00432     SockList_Term(&sl);
00433 }
00434 
00442 static void send_smooth(socket_struct *ns, uint16 face) {
00443     uint16 smoothface;
00444     SockList sl;
00445 
00446     /* If we can't find a face, return and set it so we won't
00447      * try to send this again.
00448      */
00449     if (!find_smooth(face, &smoothface)
00450     && !find_smooth(smooth_face->number, &smoothface)) {
00451         LOG(llevError, "could not findsmooth for %d. Neither default (%s)\n", face, smooth_face->name);
00452         ns->faces_sent[face] |= NS_FACESENT_SMOOTH;
00453         return;
00454     }
00455 
00456     if (!(ns->faces_sent[smoothface]&NS_FACESENT_FACE))
00457         esrv_send_face(ns, smoothface, 0);
00458 
00459     ns->faces_sent[face] |= NS_FACESENT_SMOOTH;
00460 
00461     SockList_Init(&sl);
00462     SockList_AddString(&sl, "smooth ");
00463     SockList_AddShort(&sl, face);
00464     SockList_AddShort(&sl, smoothface);
00465     Send_With_Handling(ns, &sl);
00466     SockList_Term(&sl);
00467 }
00468 
00473 void ask_smooth_cmd(char *buf, int len, socket_struct *ns) {
00474     uint16 facenbr;
00475 
00476     facenbr = atoi(buf);
00477     send_smooth(ns, facenbr);
00478 }
00479 
00492 void new_player_cmd(uint8 *buf, int len, player *pl) {
00493     int time, repeat;
00494     short packet;
00495     char command[MAX_BUF];
00496     SockList sl;
00497 
00498     if (len < 7) {
00499         LOG(llevDebug, "Corrupt ncom command - not long enough - discarding\n");
00500         return;
00501     }
00502 
00503     packet = GetShort_String(buf);
00504     repeat = GetInt_String(buf+2);
00505     /* -1 is special - no repeat, but don't update */
00506     if (repeat != -1) {
00507         pl->count = repeat;
00508     }
00509     if (len-4 >= MAX_BUF)
00510         len = MAX_BUF-5;
00511 
00512     strncpy(command, (char *)buf+6, len-4);
00513     command[len-4] = '\0';
00514 
00515     /* The following should never happen with a proper or honest client.
00516      * Therefore, the error message doesn't have to be too clear - if
00517      * someone is playing with a hacked/non working client, this gives them
00518      * an idea of the problem, but they deserve what they get
00519      */
00520     if (pl->state != ST_PLAYING) {
00521         draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR,
00522                              "You can not issue commands - state is not ST_PLAYING (%s)",
00523                              "You can not issue commands - state is not ST_PLAYING (%s)",
00524                              buf);
00525         return;
00526     }
00527 
00528     /* This should not happen anymore. */
00529     if (pl->ob->speed_left < -1.0) {
00530         LOG(llevError, "Player has negative time - shouldn't do command.\n");
00531     }
00532     /* In c_new.c */
00533     execute_newserver_command(pl->ob, command);
00534     /* Perhaps something better should be done with a left over count.
00535      * Cleaning up the input should probably be done first - all actions
00536      * for the command that issued the count should be done before
00537      * any other commands.
00538      */
00539     pl->count = 0;
00540 
00541     /* Send confirmation of command execution now */
00542     SockList_Init(&sl);
00543     SockList_AddString(&sl, "comc ");
00544     SockList_AddShort(&sl, packet);
00545     if (FABS(pl->ob->speed) < 0.001)
00546         time = MAX_TIME*100;
00547     else
00548         time = (int)(MAX_TIME/FABS(pl->ob->speed));
00549     SockList_AddInt(&sl, time);
00550     Send_With_Handling(&pl->socket, &sl);
00551     SockList_Term(&sl);
00552 }
00553 
00555 void reply_cmd(char *buf, int len, player *pl) {
00556     /* This is to synthesize how the data would be stored if it
00557      * was normally entered. A bit of a hack, and should be cleaned up
00558      * once all the X11 code is removed from the server.
00559      *
00560      * We pass 13 to many of the functions because this way they
00561      * think it was the carriage return that was entered, and the
00562      * function then does not try to do additional input.
00563      */
00564     snprintf(pl->write_buf, sizeof(pl->write_buf), ":%s", buf);
00565 
00566     /* this avoids any hacking here */
00567 
00568     switch (pl->state) {
00569     case ST_PLAYING:
00570         LOG(llevError, "Got reply message with ST_PLAYING input state\n");
00571         break;
00572 
00573     case ST_PLAY_AGAIN:
00574         /* We can check this for return value (2==quit). Maybe we
00575          * should, and do something appropriate?
00576          */
00577         receive_play_again(pl->ob, buf[0]);
00578         break;
00579 
00580     case ST_ROLL_STAT:
00581         key_roll_stat(pl->ob, buf[0]);
00582         break;
00583 
00584     case ST_CHANGE_CLASS:
00585 
00586         key_change_class(pl->ob, buf[0]);
00587         break;
00588 
00589     case ST_CONFIRM_QUIT:
00590         key_confirm_quit(pl->ob, buf[0]);
00591         break;
00592 
00593     case ST_GET_NAME:
00594         receive_player_name(pl->ob);
00595         break;
00596 
00597     case ST_GET_PASSWORD:
00598     case ST_CONFIRM_PASSWORD:
00599     case ST_CHANGE_PASSWORD_OLD:
00600     case ST_CHANGE_PASSWORD_NEW:
00601     case ST_CHANGE_PASSWORD_CONFIRM:
00602         receive_player_password(pl->ob);
00603         break;
00604 
00605     case ST_GET_PARTY_PASSWORD:        /* Get password for party */
00606         receive_party_password(pl->ob);
00607         break;
00608 
00609     default:
00610         LOG(llevError, "Unknown input state: %d\n", pl->state);
00611     }
00612 }
00613 
00621 void version_cmd(char *buf, int len, socket_struct *ns) {
00622     char *cp;
00623 
00624     if (!buf) {
00625         LOG(llevError, "CS: received corrupted version command\n");
00626         return;
00627     }
00628 
00629     ns->cs_version = atoi(buf);
00630     ns->sc_version = ns->cs_version;
00631     if (VERSION_CS != ns->cs_version) {
00632 #ifdef ESRV_DEBUG
00633         LOG(llevDebug, "CS: csversion mismatch (%d,%d)\n", VERSION_CS, ns->cs_version);
00634 #endif
00635     }
00636     cp = strchr(buf+1, ' ');
00637     if (!cp)
00638         return;
00639     ns->sc_version = atoi(cp);
00640     if (VERSION_SC != ns->sc_version) {
00641 #ifdef ESRV_DEBUG
00642         LOG(llevDebug, "CS: scversion mismatch (%d,%d)\n", VERSION_SC, ns->sc_version);
00643 #endif
00644     }
00645     cp = strchr(cp+1, ' ');
00646     if (cp) {
00647         LOG(llevDebug, "CS: connection from client of type <%s>, ip %s\n", cp, ns->host);
00648     }
00649 }
00650 
00656 void set_sound_cmd(char *buf, int len, socket_struct *ns) {
00657 }
00658 
00662 void map_redraw_cmd(char *buf, int len, player *pl) {
00663     /* This function is currently disabled; just clearing the
00664      * map state results in display errors. It should clear the
00665      * cache and send a newmap command. Unfortunately this
00666      * solution does not work because some client versions send
00667      * a mapredraw command after receiving a newmap command.
00668      */
00669 }
00670 
00672 void map_newmap_cmd(socket_struct *ns) {
00673     /* If getting a newmap command, this scroll information
00674      * is no longer relevant.
00675      */
00676     ns->map_scroll_x = 0;
00677     ns->map_scroll_y = 0;
00678 
00679     if (ns->newmapcmd == 1) {
00680         SockList sl;
00681 
00682         memset(&ns->lastmap, 0, sizeof(ns->lastmap));
00683         SockList_Init(&sl);
00684         SockList_AddString(&sl, "newmap");
00685         Send_With_Handling(ns, &sl);
00686         SockList_Term(&sl);
00687     }
00688 }
00689 
00694 void move_cmd(char *buf, int len, player *pl) {
00695     int vals[3], i;
00696 
00697     /* A little funky here. We only cycle for 2 records, because
00698      * we obviously am not going to find a space after the third
00699      * record. Perhaps we should just replace this with a
00700      * sscanf?
00701      */
00702     for (i = 0; i < 2; i++) {
00703         vals[i] = atoi(buf);
00704         if (!(buf = strchr(buf, ' '))) {
00705             LOG(llevError, "Incomplete move command: %s\n", buf);
00706             return;
00707         }
00708         buf++;
00709     }
00710     vals[2] = atoi(buf);
00711 
00712 /*    LOG(llevDebug, "Move item %d (nrof=%d) to %d.\n", vals[1], vals[2], vals[0]);*/
00713     esrv_move_object(pl->ob, vals[0], vals[1], vals[2]);
00714 }
00715 
00716 /***************************************************************************
00717  *
00718  * Start of commands the server sends to the client.
00719  *
00720  ***************************************************************************
00721  */
00722 
00727 void send_query(socket_struct *ns, uint8 flags, const char *text) {
00728     SockList sl;
00729 
00730     SockList_Init(&sl);
00731     SockList_AddPrintf(&sl, "query %d %s", flags, text ? text : "");
00732     Send_With_Handling(ns, &sl);
00733     SockList_Term(&sl);
00734 }
00735 
00736 #define AddIfInt64(Old, New, Type)                  \
00737     if (Old != New) {                               \
00738         Old = New;                                  \
00739         SockList_AddChar(&sl, Type);                \
00740         SockList_AddInt64(&sl, New);                \
00741     }
00742 
00743 #define AddIfInt(Old, New, Type)                    \
00744     if (Old != New) {                               \
00745         Old = New;                                  \
00746         SockList_AddChar(&sl, Type);                \
00747         SockList_AddInt(&sl, New);                  \
00748     }
00749 
00750 #define AddIfShort(Old, New, Type)                  \
00751     if (Old != New) {                               \
00752         Old = New;                                  \
00753         SockList_AddChar(&sl, Type);                \
00754         SockList_AddShort(&sl, New);                \
00755     }
00756 
00757 #define AddIfFloat(Old, New, Type)                  \
00758     if (Old != New) {                               \
00759         Old = New;                                  \
00760         SockList_AddChar(&sl, Type);                \
00761         SockList_AddInt(&sl, (long)(New*FLOAT_MULTI));\
00762     }
00763 
00764 #define AddIfString(Old, New, Type)                 \
00765     if (Old == NULL || strcmp(Old, New)) {          \
00766         if (Old)                                    \
00767             free(Old);                              \
00768         Old = strdup_local(New);                    \
00769         SockList_AddChar(&sl, Type);                \
00770         SockList_AddLen8Data(&sl, New, strlen(New));\
00771     }
00772 
00779 void esrv_update_stats(player *pl) {
00780     SockList sl;
00781     char buf[MAX_BUF];
00782     uint16 flags;
00783     uint8 s;
00784 
00785     SockList_Init(&sl);
00786     SockList_AddString(&sl, "stats ");
00787 
00788     if (pl->ob != NULL) {
00789         AddIfShort(pl->last_stats.hp, pl->ob->stats.hp, CS_STAT_HP);
00790         AddIfShort(pl->last_stats.maxhp, pl->ob->stats.maxhp, CS_STAT_MAXHP);
00791         AddIfShort(pl->last_stats.sp, pl->ob->stats.sp, CS_STAT_SP);
00792         AddIfShort(pl->last_stats.maxsp, pl->ob->stats.maxsp, CS_STAT_MAXSP);
00793         AddIfShort(pl->last_stats.grace, pl->ob->stats.grace, CS_STAT_GRACE);
00794         AddIfShort(pl->last_stats.maxgrace, pl->ob->stats.maxgrace, CS_STAT_MAXGRACE);
00795         AddIfShort(pl->last_stats.Str, pl->ob->stats.Str, CS_STAT_STR);
00796         AddIfShort(pl->last_stats.Int, pl->ob->stats.Int, CS_STAT_INT);
00797         AddIfShort(pl->last_stats.Pow, pl->ob->stats.Pow, CS_STAT_POW);
00798         AddIfShort(pl->last_stats.Wis, pl->ob->stats.Wis, CS_STAT_WIS);
00799         AddIfShort(pl->last_stats.Dex, pl->ob->stats.Dex, CS_STAT_DEX);
00800         AddIfShort(pl->last_stats.Con, pl->ob->stats.Con, CS_STAT_CON);
00801         AddIfShort(pl->last_stats.Cha, pl->ob->stats.Cha, CS_STAT_CHA);
00802     }
00803 
00804     for (s = 0; s < NUM_SKILLS; s++) {
00805         if (pl->last_skill_ob[s]
00806         && pl->last_skill_exp[s] != pl->last_skill_ob[s]->stats.exp) {
00807             /* Always send along the level if exp changes. This
00808              * is only 1 extra byte, but keeps processing simpler.
00809              */
00810             SockList_AddChar(&sl, (char)(s+CS_STAT_SKILLINFO));
00811             SockList_AddChar(&sl, (char)pl->last_skill_ob[s]->level);
00812             SockList_AddInt64(&sl, pl->last_skill_ob[s]->stats.exp);
00813             pl->last_skill_exp[s] = pl->last_skill_ob[s]->stats.exp;
00814         }
00815     }
00816     AddIfInt64(pl->last_stats.exp, pl->ob->stats.exp, CS_STAT_EXP64);
00817     AddIfShort(pl->last_level, (char)pl->ob->level, CS_STAT_LEVEL);
00818     AddIfShort(pl->last_stats.wc, pl->ob->stats.wc, CS_STAT_WC);
00819     AddIfShort(pl->last_stats.ac, pl->ob->stats.ac, CS_STAT_AC);
00820     AddIfShort(pl->last_stats.dam, pl->ob->stats.dam, CS_STAT_DAM);
00821     AddIfFloat(pl->last_speed, pl->ob->speed, CS_STAT_SPEED);
00822     AddIfShort(pl->last_stats.food, pl->ob->stats.food, CS_STAT_FOOD);
00823     AddIfFloat(pl->last_weapon_sp, pl->weapon_sp, CS_STAT_WEAP_SP);
00824     AddIfInt(pl->last_weight_limit, (sint32)weight_limit[pl->ob->stats.Str], CS_STAT_WEIGHT_LIM);
00825     flags = 0;
00826     if (pl->fire_on)
00827         flags |= SF_FIREON;
00828     if (pl->run_on)
00829         flags |= SF_RUNON;
00830 
00831     AddIfShort(pl->last_flags, flags, CS_STAT_FLAGS);
00832     if (pl->socket.sc_version < 1025) {
00833         AddIfShort(pl->last_resist[ATNR_PHYSICAL], pl->ob->resist[ATNR_PHYSICAL], CS_STAT_ARMOUR);
00834     } else {
00835         int i;
00836 
00837         for (i = 0; i < NROFATTACKS; i++) {
00838             /* Skip ones we won't send */
00839             if (atnr_cs_stat[i] == -1)
00840                 continue;
00841             AddIfShort(pl->last_resist[i], pl->ob->resist[i], (char)atnr_cs_stat[i]);
00842         }
00843     }
00844     if (pl->socket.monitor_spells) {
00845         AddIfInt(pl->last_path_attuned, pl->ob->path_attuned, CS_STAT_SPELL_ATTUNE);
00846         AddIfInt(pl->last_path_repelled, pl->ob->path_repelled, CS_STAT_SPELL_REPEL);
00847         AddIfInt(pl->last_path_denied, pl->ob->path_denied, CS_STAT_SPELL_DENY);
00848     }
00849     /* we want to use the new fire & run system in new client */
00850     rangetostring(pl->ob, buf, sizeof(buf));
00851     AddIfString(pl->socket.stats.range, buf, CS_STAT_RANGE);
00852     set_title(pl->ob, buf, sizeof(buf));
00853     AddIfString(pl->socket.stats.title, buf, CS_STAT_TITLE);
00854 
00855     /* Only send it away if we have some actual data - 2 bytes for length, 6 for "stats ". */
00856     if (sl.len > 8) {
00857 #ifdef ESRV_DEBUG
00858         LOG(llevDebug, "Sending stats command, %d bytes long.\n", sl.len);
00859 #endif
00860         Send_With_Handling(&pl->socket, &sl);
00861     }
00862     SockList_Term(&sl);
00863 }
00864 
00868 void esrv_new_player(player *pl, uint32 weight) {
00869     SockList sl;
00870 
00871     pl->last_weight = weight;
00872 
00873     if (!(pl->socket.faces_sent[pl->ob->face->number]&NS_FACESENT_FACE))
00874         esrv_send_face(&pl->socket, pl->ob->face->number, 0);
00875 
00876     SockList_Init(&sl);
00877     SockList_AddString(&sl, "player ");
00878     SockList_AddInt(&sl, pl->ob->count);
00879     SockList_AddInt(&sl, weight);
00880     SockList_AddInt(&sl, pl->ob->face->number);
00881     SockList_AddLen8Data(&sl, pl->ob->name, strlen(pl->ob->name));
00882 
00883     Send_With_Handling(&pl->socket, &sl);
00884     SockList_Term(&sl);
00885     SET_FLAG(pl->ob, FLAG_CLIENT_SENT);
00886 }
00887 
00895 void esrv_send_animation(socket_struct *ns, short anim_num) {
00896     SockList sl;
00897     int i;
00898 
00899     /* Do some checking on the anim_num we got. Note that the animations
00900      * are added in contigous order, so if the number is in the valid
00901      * range, it must be a valid animation.
00902      */
00903     if (anim_num < 0 || anim_num > num_animations) {
00904         LOG(llevError, "esrv_send_anim (%d) out of bounds??\n", anim_num);
00905         return;
00906     }
00907 
00908     SockList_Init(&sl);
00909     SockList_AddString(&sl, "anim ");
00910     SockList_AddShort(&sl, anim_num);
00911     SockList_AddShort(&sl, 0); /* flags - not used right now */
00912     /* Build up the list of faces. Also, send any information (ie, the
00913      * the face itself) down to the client.
00914      */
00915     for (i = 0; i < animations[anim_num].num_animations; i++) {
00916         if (!(ns->faces_sent[animations[anim_num].faces[i]]&NS_FACESENT_FACE))
00917             esrv_send_face(ns, animations[anim_num].faces[i], 0);
00918         /* flags - not used right now */
00919         SockList_AddShort(&sl, animations[anim_num].faces[i]);
00920     }
00921     Send_With_Handling(ns, &sl);
00922     SockList_Term(&sl);
00923     ns->anims_sent[anim_num] = 1;
00924 }
00925 
00926 /****************************************************************************
00927  *
00928  * Start of map related commands.
00929  *
00930  ****************************************************************************/
00931 
00933 static void map_clearcell(struct map_cell_struct *cell, int face, int count) {
00934     cell->darkness = count;
00935     memset(cell->faces, face, sizeof(cell->faces));
00936 }
00937 
00938 #define MAX_HEAD_POS MAX(MAX_CLIENT_X, MAX_CLIENT_Y)
00939 
00947 static object *heads[MAX_HEAD_POS][MAX_HEAD_POS][MAP_LAYERS];
00948 
00949 /****************************************************************************
00950  * This block is for map2 drawing related commands.
00951  * Note that the map2 still uses other functions.
00952  *
00953  ***************************************************************************/
00954 
00974 static int map2_add_ob(int ax, int ay, int layer, object *ob, SockList *sl, socket_struct *ns, int *has_obj, int is_head) {
00975     uint16 face_num;
00976     uint8 nlayer, smoothlevel = 0;
00977     object *head;
00978 
00979     assert(ob != NULL);
00980 
00981     head = ob->head ? ob->head : ob;
00982     face_num = ob->face->number;
00983 
00984     /* This is a multipart object, and we are not at the lower
00985      * right corner. So we need to store away the lower right corner.
00986      */
00987     if (!is_head && (head->arch->tail_x || head->arch->tail_y)
00988     && (head->arch->tail_x != ob->arch->clone.x || head->arch->tail_y != ob->arch->clone.y)) {
00989         int bx, by, l;
00990 
00991         /* Basically figure out where the offset is from where we
00992          * are right now. the ob->arch->clone.{x,y} values hold
00993          * the offset that this current piece is from the head,
00994          * and the tail is where the tail is from the head.
00995          * Note that bx and by will equal sx and sy if we are
00996          * already working on the bottom right corner. If ob is
00997          * the head, the clone values will be zero, so the right
00998          * thing will still happen.
00999          */
01000         bx = ax+head->arch->tail_x-ob->arch->clone.x;
01001         by = ay+head->arch->tail_y-ob->arch->clone.y;
01002 
01003         /* I don't think this can ever happen, but better to check
01004          * for it just in case.
01005          */
01006         if (bx < ax || by < ay) {
01007             LOG(llevError, "map2_add_ob: bx (%d) or by (%d) is less than ax (%d) or ay (%d)\n", bx, by, ax, ay);
01008             face_num = 0;
01009         }
01010         /* the target position must be within +/-1 of our current
01011          * layer as the layers are defined. We are basically checking
01012          * to see if we have already stored this object away.
01013          */
01014         for (l = layer-1; l <= layer+1; l++) {
01015             if (l < 0 || l >= MAP_LAYERS)
01016                 continue;
01017             if (heads[by][bx][l] == head)
01018                 break;
01019         }
01020         /* Didn't find it.  So we need to store it away. Try to store it
01021          * on our original layer, and then move up a layer.
01022          */
01023         if (l == layer+2) {
01024             if (!heads[by][bx][layer])
01025                 heads[by][bx][layer] = head;
01026             else if (layer+1 < MAP_LAYERS && !heads[by][bx][layer+1])
01027                 heads[by][bx][layer+1] = head;
01028         }
01029         return 0;
01030         /* Ok - All done storing away the head for future use */
01031     } else {
01032         (*has_obj)++;
01033         if (QUERY_FLAG(ob, FLAG_CLIENT_ANIM_SYNC)
01034         || QUERY_FLAG(ob, FLAG_CLIENT_ANIM_RANDOM)) {
01035             face_num = ob->animation_id|(1<<15);
01036             if (QUERY_FLAG(ob, FLAG_CLIENT_ANIM_SYNC))
01037                 face_num |= ANIM_SYNC;
01038             else if (QUERY_FLAG(ob, FLAG_CLIENT_ANIM_RANDOM))
01039                 face_num |= ANIM_RANDOM;
01040         }
01041         /* Since face_num includes the bits for the animation tag,
01042          * and we will store that away in the faces[] array, below
01043          * check works fine _except_ for the case where animation
01044          * speed chances.
01045          */
01046         if (ns->lastmap.cells[ax][ay].faces[layer] != face_num) {
01047             uint8 len, anim_speed = 0, i;
01048 
01049             /* This block takes care of sending the actual face
01050              * to the client. */
01051             ns->lastmap.cells[ax][ay].faces[layer] = face_num;
01052 
01053             /* Now form the data packet */
01054             nlayer = 0x10+layer;
01055 
01056             len = 2;
01057 
01058             if (!MAP_NOSMOOTH(ob->map)) {
01059                 smoothlevel = ob->smoothlevel;
01060                 if (smoothlevel)
01061                     len++;
01062             }
01063 
01064             if (QUERY_FLAG(ob, FLAG_CLIENT_ANIM_SYNC)
01065             || QUERY_FLAG(ob, FLAG_CLIENT_ANIM_RANDOM)) {
01066                 len++;
01067                 /* 1/0.004 == 250, so this is a good cap for an
01068                  * upper limit */
01069                 if (ob->anim_speed)
01070                     anim_speed = ob->anim_speed;
01071                 else if (FABS(ob->speed) < 0.004)
01072                     anim_speed = 255;
01073                 else if (FABS(ob->speed) >= 1.0)
01074                     anim_speed = 1;
01075                 else
01076                     anim_speed = (int)(1.0/FABS(ob->speed));
01077 
01078                 if (!ns->anims_sent[ob->animation_id])
01079                     esrv_send_animation(ns, ob->animation_id);
01080 
01081                 /* If smoothing, need to send smoothing information
01082                  * for all faces in the animation sequence. Since
01083                  * smoothlevel is an object attribute,
01084                  * it applies to all faces.
01085                  */
01086                 if (smoothlevel) {
01087                     for (i = 0; i < NUM_ANIMATIONS(ob); i++) {
01088                         if (!(ns->faces_sent[animations[ob->animation_id].faces[i]]&NS_FACESENT_SMOOTH))
01089                             send_smooth(ns, animations[ob->animation_id].faces[i]);
01090                     }
01091                 }
01092             } else if (!(ns->faces_sent[face_num]&NS_FACESENT_FACE)) {
01093                 esrv_send_face(ns, face_num, 0);
01094             }
01095 
01096             if (smoothlevel
01097             && !(ns->faces_sent[ob->face->number]&NS_FACESENT_SMOOTH))
01098                 send_smooth(ns, ob->face->number);
01099 
01100             /* Length of packet */
01101             nlayer |= len<<5;
01102 
01103             SockList_AddChar(sl, nlayer);
01104             SockList_AddShort(sl, face_num);
01105             if (anim_speed)
01106                 SockList_AddChar(sl, anim_speed);
01107             if (smoothlevel)
01108                 SockList_AddChar(sl, smoothlevel);
01109             return 1;
01110         } /* Face is different */
01111     }
01112     return 0;
01113 }
01114 
01115 /* This function is used see if a layer needs to be cleared.
01116  * It updates the socklist, and returns 1 if the update is
01117  * needed, 0 otherwise.
01118  */
01119 static int map2_delete_layer(int ax, int ay, int layer, SockList *sl, socket_struct *ns) {
01120     int nlayer;
01121 
01122     if (ns->lastmap.cells[ax][ay].faces[layer] != 0) {
01123         /* Now form the data packet */
01124         nlayer = 0x10+layer+(2<<5);
01125         SockList_AddChar(sl, nlayer);
01126         SockList_AddShort(sl, 0);
01127         ns->lastmap.cells[ax][ay].faces[layer] = 0;
01128         return 1;
01129     }
01130     return 0;
01131 }
01132 
01133 /*
01134  * This function is used to check a space (ax, ay) whose only
01135  * data we may care about are any heads. Basically, this
01136  * space is out of direct view. This is only used with the
01137  * Map2 protocol.
01138  *
01139  * @param ax
01140  * viewport relative x-coordinate
01141  * @param ay
01142  * viewport relative y-coordinate
01143  * @param sl
01144  * the reply to append to
01145  * @param ns
01146  * the client socket
01147  */
01148 static void check_space_for_heads(int ax, int ay, SockList *sl, socket_struct *ns) {
01149     int layer, got_one = 0, del_one = 0, oldlen, has_obj = 0;
01150     uint16 coord;
01151 
01152     coord = MAP2_COORD_ENCODE(ax, ay, 0);
01153     oldlen = sl->len;
01154     SockList_AddShort(sl, coord);
01155 
01156     for (layer = 0; layer < MAP_LAYERS; layer++) {
01157         object *head;
01158 
01159         head = heads[ay][ax][layer];
01160         if (head) {
01161             /* in this context, got_one should always increase
01162              * because heads should always point to data to really send.
01163              */
01164             got_one += map2_add_ob(ax, ay, layer, head, sl, ns, &has_obj, 1);
01165         } else {
01166             del_one += map2_delete_layer(ax, ay, layer, sl, ns);
01167         }
01168     }
01169     /* Note - if/when lighting information is added, some code is
01170      * needed here - lighting sources that are out of sight may still
01171      * extend into the viewable area.
01172      */
01173 
01174     /* If nothing to do for this space, we
01175      * can erase the coordinate bytes
01176      */
01177     if (!del_one && !got_one) {
01178         sl->len = oldlen;
01179     } else if (del_one && !has_obj) {
01180         /* If we're only deleting faces and not adding, and there
01181          * are not any faces on the space we care about,
01182          * more efficient
01183          * to send 0 as the type/len field.
01184          */
01185         sl->len = oldlen+2;         /* 2 bytes for coordinate */
01186         SockList_AddChar(sl, 0);    /* Clear byte */
01187         SockList_AddChar(sl, 255);  /* Termination byte */
01188         map_clearcell(&ns->lastmap.cells[ax][ay], 0, 0);
01189     } else {
01190         SockList_AddChar(sl, 255);  /* Termination byte */
01191     }
01192 }
01193 
01194 void draw_client_map2(object *pl) {
01195     int x, y, ax, ay, d, min_x, max_x, min_y, max_y, oldlen, layer;
01196     size_t startlen;
01197     sint16 nx, ny;
01198     SockList sl;
01199     uint16 coord;
01200     mapstruct *m;
01201     object *ob;
01202 
01203     SockList_Init(&sl);
01204     SockList_AddString(&sl, "map2 ");
01205     startlen = sl.len;
01206 
01207     /* Handle map scroll */
01208     if (pl->contr->socket.map_scroll_x || pl->contr->socket.map_scroll_y) {
01209         coord = MAP2_COORD_ENCODE(pl->contr->socket.map_scroll_x, pl->contr->socket.map_scroll_y, 1);
01210         pl->contr->socket.map_scroll_x = 0;
01211         pl->contr->socket.map_scroll_y = 0;
01212         SockList_AddShort(&sl, coord);
01213     }
01214 
01215     /* Init data to zero */
01216     memset(heads, 0, sizeof(heads));
01217 
01218     /* We could do this logic as conditionals in the if statement,
01219      * but that started to get a bit messy to look at.
01220      */
01221     min_x = pl->x-pl->contr->socket.mapx/2;
01222     min_y = pl->y-pl->contr->socket.mapy/2;
01223     max_x = pl->x+(pl->contr->socket.mapx+1)/2+MAX_HEAD_OFFSET;
01224     max_y = pl->y+(pl->contr->socket.mapy+1)/2+MAX_HEAD_OFFSET;
01225 
01226     /* x, y are the real map locations. ax, ay are viewport relative
01227      * locations.
01228      */
01229     ay = 0;
01230     for (y = min_y; y < max_y; y++, ay++) {
01231         ax = 0;
01232         for (x = min_x; x < max_x; x++, ax++) {
01233             /* If this space is out of the normal viewable area,
01234              * we only check the heads value. This is used to
01235              * handle big images - if they extend to a viewable
01236              * portion, we need to send just the lower right corner.
01237              */
01238             if (ax >= pl->contr->socket.mapx || ay >= pl->contr->socket.mapy) {
01239                 check_space_for_heads(ax, ay, &sl, &pl->contr->socket);
01240             } else {
01241                 /* This space is within the viewport of the client. Due
01242                  * to walls or darkness, it may still not be visible.
01243                  */
01244 
01245                 /* Meaning of d:
01246                  * 0 - object is in plain sight, full brightness.
01247                  * 1 - MAX_DARKNESS - how dark the space is - higher
01248                  * value is darker space. If level is at max darkness,
01249                  * you can't see the space (too dark)
01250                  * 100 - space is blocked from sight.
01251                  */
01252                 d = pl->contr->blocked_los[ax][ay];
01253 
01254                 /* If the coordinates are not valid, or it is too
01255                  * dark to see, we tell the client as such
01256                  */
01257                 nx = x;
01258                 ny = y;
01259                 m = get_map_from_coord(pl->map, &nx, &ny);
01260                 coord = MAP2_COORD_ENCODE(ax, ay, 0);
01261 
01262                 if (!m) {
01263                     /* space is out of map. Update space and clear
01264                      * values if this hasn't already been done.
01265                      * If the space is out of the map, it shouldn't
01266                      * have a head.
01267                      */
01268                     if (pl->contr->socket.lastmap.cells[ax][ay].darkness != 0) {
01269                         SockList_AddShort(&sl, coord);
01270                         SockList_AddChar(&sl, 0);
01271                         SockList_AddChar(&sl, 255); /* Termination byte */
01272                         map_clearcell(&pl->contr->socket.lastmap.cells[ax][ay], 0, 0);
01273                     }
01274                 } else if (d >= MAX_LIGHT_RADII) {
01275                     /* This block deals with spaces that are not
01276                      * visible due to darkness or walls. Still
01277                      * need to send the heads for this space.
01278                      */
01279                     check_space_for_heads(ax, ay, &sl, &pl->contr->socket);
01280                 } else {
01281                     int have_darkness = 0, has_obj = 0, got_one = 0, del_one = 0, g1;
01282 
01283                     /* In this block, the space is visible. */
01284 
01285                     /* Rather than try to figure out what everything
01286                      * that we might need to send is, then form the
01287                      * packet after that, we presume that we will in
01288                      * fact form a packet, and update the bits by what
01289                      * we do actually send. If we send nothing, we
01290                      * just back out sl.len to the old value, and no
01291                      * harm is done.
01292                      * I think this is simpler than doing a bunch of
01293                      * checks to see what if anything we need to send,
01294                      * setting the bits, then doing those checks again
01295                      * to add the real data.
01296                      */
01297 
01298                     oldlen = sl.len;
01299                     SockList_AddShort(&sl, coord);
01300 
01301                     /* Darkness changed */
01302                     if (pl->contr->socket.lastmap.cells[ax][ay].darkness != d
01303                     && pl->contr->socket.darkness) {
01304                         pl->contr->socket.lastmap.cells[ax][ay].darkness = d;
01305                         /* Darkness tag & length*/
01306                         SockList_AddChar(&sl, 0x1|1<<5);
01307                         SockList_AddChar(&sl, 255-d*(256/MAX_LIGHT_RADII));
01308                         have_darkness = 1;
01309                     }
01310 
01311                     for (layer = 0; layer < MAP_LAYERS; layer++) {
01312                         ob = GET_MAP_FACE_OBJ(m, nx, ny, layer);
01313 
01314                         /* Special case: send player itself if invisible */
01315                         if (!ob
01316                         && x == pl->x
01317                         && y == pl->y
01318                         && (pl->invisible&(pl->invisible < 50 ? 4 : 1))
01319                         && (layer == MAP_LAYER_LIVING1 || layer == MAP_LAYER_LIVING2))
01320                             ob = pl;
01321 
01322                         if (ob) {
01323                             g1 = has_obj;
01324                             got_one += map2_add_ob(ax, ay, layer, ob, &sl, &pl->contr->socket, &has_obj, 0);
01325                             /* If we are just storing away the head
01326                              * for future use, then effectively this
01327                              * space/layer is blank, and we should clear
01328                              * it if needed.
01329                              */
01330                             if (g1 == has_obj)
01331                                 del_one += map2_delete_layer(ax, ay, layer, &sl, &pl->contr->socket);
01332                         } else {
01333                             del_one += map2_delete_layer(ax, ay, layer, &sl, &pl->contr->socket);
01334                         }
01335                     }
01336                     /* If nothing to do for this space, we
01337                      * can erase the coordinate bytes
01338                      */
01339                     if (!del_one && !got_one && !have_darkness) {
01340                         sl.len = oldlen;
01341                     } else if (del_one && !has_obj) {
01342                         /* If we're only deleting faces and don't
01343                          * have any objs we care about, just clear
01344                          * space. Note it is possible we may have
01345                          * darkness, but if there is nothing on the
01346                          * space, darkness isn't all that interesting
01347                          * - we can send it when an object shows up.
01348                          */
01349                         sl.len = oldlen+2;          /* 2 bytes for coordinate */
01350                         SockList_AddChar(&sl, 0);   /* Clear byte */
01351                         SockList_AddChar(&sl, 255); /* Termination byte */
01352                         map_clearcell(&pl->contr->socket.lastmap.cells[ax][ay], 0, 0);
01353                     } else {
01354                         SockList_AddChar(&sl, 255); /* Termination byte */
01355                     }
01356                 }
01357             } /* else this is a viewable space */
01358         } /* for x loop */
01359     } /* for y loop */
01360 
01361     /* Only send this if there are in fact some differences. */
01362     if (sl.len > startlen) {
01363         Send_With_Handling(&pl->contr->socket, &sl);
01364     }
01365     SockList_Term(&sl);
01366 }
01367 
01371 void draw_client_map(object *pl) {
01372     int i, j;
01373     sint16 ax, ay;
01374     int mflags;
01375     mapstruct *m, *pm;
01376     int min_x, min_y, max_x, max_y;
01377 
01378     if (pl->type != PLAYER) {
01379         LOG(llevError, "draw_client_map called with non player/non eric-server\n");
01380         return;
01381     }
01382 
01383     if (pl->contr->transport) {
01384         pm = pl->contr->transport->map;
01385     } else
01386         pm = pl->map;
01387 
01388     /* If player is just joining the game, he isn't here yet, so
01389      * the map can get swapped out. If so, don't try to send them
01390      * a map. All will be OK once they really log in.
01391      */
01392     if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
01393         return;
01394 
01395     /*
01396      * This block just makes sure all the spaces are properly
01397      * updated in terms of what they look like.
01398      */
01399     min_x = pl->x-pl->contr->socket.mapx/2;
01400     min_y = pl->y-pl->contr->socket.mapy/2;
01401     max_x = pl->x+(pl->contr->socket.mapx+1)/2;
01402     max_y = pl->y+(pl->contr->socket.mapy+1)/2;
01403     for (j = min_y; j < max_y; j++) {
01404         for (i = min_x; i < max_x; i++) {
01405             ax = i;
01406             ay = j;
01407             m = pm;
01408             mflags = get_map_flags(m, &m, ax, ay, &ax, &ay);
01409             if (mflags&P_OUT_OF_MAP)
01410                 continue;
01411             if (mflags&P_NEED_UPDATE)
01412                 update_position(m, ax, ay);
01413             /* If a map is visible to the player, we don't want
01414              * to swap it out just to reload it. This should
01415              * really call something like swap_map, but this is
01416              * much more efficient and 'good enough'
01417              */
01418             if (mflags&P_NEW_MAP)
01419                 m->timeout = 50;
01420         }
01421     }
01422 
01423     /* do LOS after calls to update_position */
01424     if (pl->contr->do_los) {
01425         update_los(pl);
01426         pl->contr->do_los = 0;
01427     }
01428 
01429     draw_client_map2(pl);
01430 }
01431 
01432 void esrv_map_scroll(socket_struct *ns, int dx, int dy) {
01433     struct Map newmap;
01434     int x, y, mx, my;
01435 
01436     ns->map_scroll_x += dx;
01437     ns->map_scroll_y += dy;
01438 
01439     mx = ns->mapx+MAX_HEAD_OFFSET;
01440     my = ns->mapy+MAX_HEAD_OFFSET;
01441 
01442     /* the x and y here are coordinates for the new map, i.e. if we moved
01443      * (dx,dy), newmap[x][y] = oldmap[x-dx][y-dy]. For this reason,
01444      * if the destination x or y coordinate is outside the viewable
01445      * area, we clear the values - otherwise, the old values
01446      * are preserved, and the check_head thinks it needs to clear them.
01447      */
01448     for (x = 0; x < mx; x++) {
01449         for (y = 0; y < my; y++) {
01450             if (x >= ns->mapx || y >= ns->mapy) {
01451                 /* clear cells outside the viewable area */
01452                 memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
01453             } else if (x+dx < 0 || x+dx >= ns->mapx || y+dy < 0 || y+dy >= ns->mapy) {
01454                 /* clear newly visible tiles within the viewable area */
01455                 memset(&newmap.cells[x][y], 0, sizeof(newmap.cells[x][y]));
01456             } else {
01457                 memcpy(&newmap.cells[x][y], &ns->lastmap.cells[x+dx][y+dy], sizeof(newmap.cells[x][y]));
01458             }
01459         }
01460     }
01461 
01462     memcpy(&ns->lastmap, &newmap, sizeof(ns->lastmap));
01463 }
01464 
01470 void send_plugin_custom_message(object *pl, char *buf) {
01471     SockList sl;
01472 
01473     SockList_Init(&sl);
01474     SockList_AddString(&sl, buf);
01475     Send_With_Handling(&pl->contr->socket, &sl);
01476     SockList_Term(&sl);
01477 }
01478 
01482 void send_exp_table(socket_struct *ns, char *params) {
01483     SockList sl;
01484     int i;
01485     extern sint64 *levels;
01486 
01487     SockList_Init(&sl);
01488     SockList_AddString(&sl, "replyinfo exp_table\n");
01489     SockList_AddShort(&sl, settings.max_level+1);
01490     for (i = 1; i <= settings.max_level; i++) {
01491         if (SockList_Avail(&sl) < 8) {
01492             LOG(llevError, "Buffer overflow in send_exp_table, not sending all information\n");
01493             break;
01494         }
01495         SockList_AddInt64(&sl, levels[i]);
01496     }
01497     Send_With_Handling(ns, &sl);
01498     SockList_Term(&sl);
01499 }
01500 
01505 void send_skill_info(socket_struct *ns, char *params) {
01506     SockList sl;
01507     int i;
01508 
01509     SockList_Init(&sl);
01510     SockList_AddString(&sl, "replyinfo skill_info\n");
01511     for (i = 1; i < NUM_SKILLS; i++) {
01512         size_t len;
01513 
01514         len = 16+strlen(skill_names[i]); /* upper bound for length */
01515         if (SockList_Avail(&sl) < len) {
01516             LOG(llevError, "Buffer overflow in send_skill_info, not sending all skill information\n");
01517             break;
01518         }
01519 
01520         SockList_AddPrintf(&sl, "%d:%s\n", i+CS_STAT_SKILLINFO, skill_names[i]);
01521     }
01522     Send_With_Handling(ns, &sl);
01523     SockList_Term(&sl);
01524 }
01525 
01530 void send_spell_paths(socket_struct *ns, char *params) {
01531     SockList sl;
01532     int i;
01533 
01534     SockList_Init(&sl);
01535     SockList_AddString(&sl, "replyinfo spell_paths\n");
01536     for (i = 0; i < NRSPELLPATHS; i++) {
01537         size_t len;
01538 
01539         len = 16+strlen(spellpathnames[i]); /* upper bound for length */
01540         if (SockList_Avail(&sl) < len) {
01541             LOG(llevError, "Buffer overflow in send_spell_paths, not sending all spell information\n");
01542             break;
01543         }
01544 
01545         SockList_AddPrintf(&sl, "%d:%s\n", 1<<i, spellpathnames[i]);
01546     }
01547     Send_With_Handling(ns, &sl);
01548     SockList_Term(&sl);
01549 }
01550 
01557 static void build_race_list_reply(SockList *sl) {
01558     archetype *race;
01559 
01560     SockList_AddString(sl, "replyinfo race_list ");
01561 
01562     for (race = first_archetype; race; race = race->next) {
01563         if (race->clone.type == PLAYER) {
01564             SockList_AddPrintf(sl, "|%s", race->name);
01565         }
01566     }
01567 }
01568 
01578 void send_race_list(socket_struct *ns, char *params) {
01579     static SockList sl;
01580     static int sl_initialized = 0;
01581 
01582     if (!sl_initialized) {
01583         sl_initialized = 1;
01584         SockList_Init(&sl);
01585         build_race_list_reply(&sl);
01586     }
01587 
01588     Send_With_Handling(ns, &sl);
01589 }
01590 
01600 void send_race_info(socket_struct *ns, char *params) {
01601     archetype *race = try_find_archetype(params);
01602     SockList sl;
01603 
01604     SockList_Init(&sl);
01605     SockList_AddPrintf(&sl, "replyinfo race_info %s", params);
01606 
01607     if (race) {
01608     }
01609 
01610     Send_With_Handling(ns, &sl);
01611     SockList_Term(&sl);
01612 }
01613 
01620 static void build_class_list_reply(SockList *sl) {
01621     archetype *cl;
01622 
01623     SockList_Reset(sl);
01624     SockList_AddString(sl, "replyinfo class_list ");
01625 
01626     for (cl = first_archetype; cl; cl = cl->next) {
01627         if (cl->clone.type == CLASS) {
01628             SockList_AddPrintf(sl, "|%s", cl->name);
01629         }
01630     }
01631 }
01632 
01642 void send_class_list(socket_struct *ns, char *params) {
01643     static SockList sl;
01644     static int sl_initialized = 0;
01645 
01646     if (!sl_initialized) {
01647         sl_initialized = 1;
01648         SockList_Init(&sl);
01649         build_class_list_reply(&sl);
01650     }
01651 
01652     Send_With_Handling(ns, &sl);
01653 }
01654 
01664 void send_class_info(socket_struct *ns, char *params) {
01665 }
01666 
01672 void esrv_update_spells(player *pl) {
01673     SockList sl;
01674     int flags = 0;
01675     object *spell;
01676     client_spell *spell_info;
01677 
01678     if (!pl->socket.monitor_spells)
01679         return;
01680 
01681     /* Handles problem at login, where this is called from fix_object
01682      * before we have had a chance to send spells to the player. It does seem
01683      * to me that there should never be a case where update_spells is called
01684      * before add_spells has been called. Add_spells() will update the
01685      * spell_state to non null.
01686      */
01687     if (!pl->spell_state)
01688         return;
01689 
01690     for (spell = pl->ob->inv; spell != NULL; spell = spell->below) {
01691         if (spell->type == SPELL) {
01692             spell_info = get_client_spell_state(pl, spell);
01693             /* check if we need to update it*/
01694             if (spell_info->last_sp != SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA)) {
01695                 spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
01696                 flags |= UPD_SP_MANA;
01697             }
01698             if (spell_info->last_grace != SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE)) {
01699                 spell_info->last_grace = SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE);
01700                 flags |= UPD_SP_GRACE;
01701             }
01702             if (spell_info->last_dam != spell->stats.dam+SP_level_dam_adjust(pl->ob, spell)) {
01703                 spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
01704                 flags |= UPD_SP_DAMAGE;
01705             }
01706             if (flags != 0) {
01707                 SockList_Init(&sl);
01708                 SockList_AddString(&sl, "updspell ");
01709                 SockList_AddChar(&sl, flags);
01710                 SockList_AddInt(&sl, spell->count);
01711                 if (flags&UPD_SP_MANA)
01712                     SockList_AddShort(&sl, spell_info->last_sp);
01713                 if (flags&UPD_SP_GRACE)
01714                     SockList_AddShort(&sl, spell_info->last_grace);
01715                 if (flags&UPD_SP_DAMAGE)
01716                     SockList_AddShort(&sl, spell_info->last_dam);
01717                 flags = 0;
01718                 Send_With_Handling(&pl->socket, &sl);
01719                 SockList_Term(&sl);
01720             }
01721         }
01722     }
01723 }
01724 
01725 void esrv_remove_spell(player *pl, object *spell) {
01726     SockList sl;
01727 
01728     if (!pl->socket.monitor_spells)
01729         return;
01730     if (!pl || !spell || spell->env != pl->ob) {
01731         LOG(llevError, "Invalid call to esrv_remove_spell\n");
01732         return;
01733     }
01734     SockList_Init(&sl);
01735     SockList_AddString(&sl, "delspell ");
01736     SockList_AddInt(&sl, spell->count);
01737     Send_With_Handling(&pl->socket, &sl);
01738     SockList_Term(&sl);
01739 }
01740 
01747 void esrv_send_pickup(player *pl) {
01748     SockList sl;
01749 
01750     if (!pl->socket.want_pickup)
01751         return;
01752     SockList_Init(&sl);
01753     SockList_AddString(&sl, "pickup ");
01754     SockList_AddInt(&sl, pl->mode);
01755     Send_With_Handling(&pl->socket, &sl);
01756     SockList_Term(&sl);
01757 }
01758 
01760 static void append_spell(player *pl, SockList *sl, object *spell) {
01761     client_spell *spell_info;
01762     int len, i, skill = 0;
01763 
01764     if (!spell->name) {
01765         LOG(llevError, "item number %d is a spell with no name.\n", spell->count);
01766         return;
01767     }
01768 
01769     if (spell->face && !(pl->socket.faces_sent[spell->face->number]&NS_FACESENT_FACE))
01770         esrv_send_face(&pl->socket, spell->face->number, 0);
01771 
01772     spell_info = get_client_spell_state(pl, spell);
01773     SockList_AddInt(sl, spell->count);
01774     SockList_AddShort(sl, spell->level);
01775     SockList_AddShort(sl, spell->casting_time);
01776     /* store costs and damage in the object struct, to compare to later */
01777     spell_info->last_sp = SP_level_spellpoint_cost(pl->ob, spell, SPELL_MANA);
01778     spell_info->last_grace = SP_level_spellpoint_cost(pl->ob, spell, SPELL_GRACE);
01779     spell_info->last_dam = spell->stats.dam+SP_level_dam_adjust(pl->ob, spell);
01780     /* send the current values */
01781     SockList_AddShort(sl, spell_info->last_sp);
01782     SockList_AddShort(sl, spell_info->last_grace);
01783     SockList_AddShort(sl, spell_info->last_dam);
01784 
01785     /* figure out which skill it uses, if it uses one */
01786     if (spell->skill) {
01787         for (i = 1; i < NUM_SKILLS; i++)
01788             if (!strcmp(spell->skill, skill_names[i])) {
01789                 skill = i+CS_STAT_SKILLINFO;
01790                 break;
01791             }
01792     }
01793     SockList_AddChar(sl, skill);
01794 
01795     SockList_AddInt(sl, spell->path_attuned);
01796     SockList_AddInt(sl, spell->face ? spell->face->number : 0);
01797     SockList_AddLen8Data(sl, spell->name, strlen(spell->name));
01798 
01799     if (!spell->msg) {
01800         SockList_AddShort(sl, 0);
01801     } else {
01802         len = strlen(spell->msg);
01803         SockList_AddShort(sl, len);
01804         SockList_AddData(sl, spell->msg, len);
01805     }
01806 }
01807 
01812 void esrv_add_spells(player *pl, object *spell) {
01813     SockList sl;
01814 
01815     if (!pl) {
01816         LOG(llevError, "esrv_add_spells, tried to add a spell to a NULL player\n");
01817         return;
01818     }
01819 
01820     if (!pl->socket.monitor_spells)
01821         return;
01822 
01823     SockList_Init(&sl);
01824     SockList_AddString(&sl, "addspell ");
01825     if (!spell) {
01826         for (spell = pl->ob->inv; spell != NULL; spell = spell->below) {
01827             if (spell->type != SPELL)
01828                 continue;
01829             /* Were we to simply keep appending data here, we could
01830              * exceed the SockList buffer if the player has enough spells
01831              * to add. We know that append_spell will always append
01832              * 23 data bytes, plus 3 length bytes and 2 strings
01833              * (because that is the spec) so we need to check that
01834              * the length of those 2 strings, plus the 26 bytes,
01835              * won't take us over the length limit for the socket.
01836              * If it does, we need to send what we already have,
01837              * and restart packet formation.
01838              */
01839             if (SockList_Avail(&sl) < 26+strlen(spell->name)+(spell->msg ? strlen(spell->msg) : 0)) {
01840                 Send_With_Handling(&pl->socket, &sl);
01841                 SockList_Reset(&sl);
01842                 SockList_AddString(&sl, "addspell ");
01843             }
01844             append_spell(pl, &sl, spell);
01845         }
01846     } else if (spell->type != SPELL) {
01847         LOG(llevError, "Asked to send a non-spell object as a spell\n");
01848         return;
01849     } else
01850         append_spell(pl, &sl, spell);
01851     /* finally, we can send the packet */
01852     Send_With_Handling(&pl->socket, &sl);
01853     SockList_Term(&sl);
01854 }
01855 
01856 /* sends a 'tick' information to the client.
01857  * We also take the opportunity to toggle TCP_NODELAY -
01858  * this forces the data in the socket to be flushed sooner to the
01859  * client - otherwise, the OS tries to wait for full packets
01860  * and will this hold sending the data for some amount of time,
01861  * which thus adds some additional latency.
01862  */
01863 void send_tick(player *pl) {
01864     SockList sl;
01865     int tmp;
01866 
01867     SockList_Init(&sl);
01868     SockList_AddString(&sl, "tick ");
01869     SockList_AddInt(&sl, pticks);
01870     tmp = 1;
01871     if (setsockopt(pl->socket.fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)))
01872         LOG(llevError, "send_tick: Unable to turn on TCP_NODELAY\n");
01873 
01874     Send_With_Handling(&pl->socket, &sl);
01875     tmp = 0;
01876     if (setsockopt(pl->socket.fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)))
01877         LOG(llevError, "send_tick: Unable to turn off TCP_NODELAY\n");
01878     SockList_Term(&sl);
01879 }