00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
00069
00070
00071 #ifndef WIN32
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
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 ,
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 ,
00106 CS_STAT_RES_DEPLETE, CS_STAT_RES_DEATH,
00107 -1 , -1 ,
00108 -1 , CS_STAT_RES_HOLYWORD,
00109 CS_STAT_RES_BLIND,
00110 -1,
00111 -1,
00112 -1
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
00122
00123
00124
00125
00126
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
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
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
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
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
00238
00239
00240 SockList_AddPrintf(&sl, "%dx%d", x, y);
00241
00242
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
00303
00304
00305 SockList_AddString(&sl, "FALSE");
00306 }
00307 }
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
00333
00334
00335
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
00343
00344
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
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)
00376 continue;
00377 strncpy(command, &buf[info], nextinfo-info);
00378 command[nextinfo-info] = '\0';
00379
00380 if (!strcmp("smooth", command)) {
00381
00382 smooth = 1;
00383 } else {
00384
00385 }
00386
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
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)
00415 continue;
00416 strncpy(command, &buf[info], nextinfo-info);
00417 command[nextinfo-info] = '\0';
00418
00419 i = sscanf(command, "%d", &flag);
00420 if (i == 1 && flag > 0 && flag <= MSG_TYPE_LAST)
00421 ns->supported_readables |= (1<<flag);
00422
00423 }
00424
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
00447
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
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
00516
00517
00518
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
00529 if (pl->ob->speed_left < -1.0) {
00530 LOG(llevError, "Player has negative time - shouldn't do command.\n");
00531 }
00532
00533 execute_newserver_command(pl->ob, command);
00534
00535
00536
00537
00538
00539 pl->count = 0;
00540
00541
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
00557
00558
00559
00560
00561
00562
00563
00564 snprintf(pl->write_buf, sizeof(pl->write_buf), ":%s", buf);
00565
00566
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
00575
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:
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
00664
00665
00666
00667
00668
00669 }
00670
00672 void map_newmap_cmd(socket_struct *ns) {
00673
00674
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
00698
00699
00700
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
00713 esrv_move_object(pl->ob, vals[0], vals[1], vals[2]);
00714 }
00715
00716
00717
00718
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
00808
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
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
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
00856 if (sl.len > 6) {
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
00900
00901
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);
00912
00913
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
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
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
00951
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
00985
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
00992
00993
00994
00995
00996
00997
00998
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
01004
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
01011
01012
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
01021
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
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
01042
01043
01044
01045
01046 if (ns->lastmap.cells[ax][ay].faces[layer] != face_num) {
01047 uint8 len, anim_speed = 0, i;
01048
01049
01050
01051 ns->lastmap.cells[ax][ay].faces[layer] = face_num;
01052
01053
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
01068
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
01082
01083
01084
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
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 }
01111 }
01112 return 0;
01113 }
01114
01115
01116
01117
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
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
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
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
01162
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
01170
01171
01172
01173
01174
01175
01176
01177 if (!del_one && !got_one) {
01178 sl->len = oldlen;
01179 } else if (del_one && !has_obj) {
01180
01181
01182
01183
01184
01185 sl->len = oldlen+2;
01186 SockList_AddChar(sl, 0);
01187 SockList_AddChar(sl, 255);
01188 map_clearcell(&ns->lastmap.cells[ax][ay], 0, 0);
01189 } else {
01190 SockList_AddChar(sl, 255);
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
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
01216 memset(heads, 0, sizeof(heads));
01217
01218
01219
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
01227
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
01234
01235
01236
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
01242
01243
01244
01245
01246
01247
01248
01249
01250
01251
01252 d = pl->contr->blocked_los[ax][ay];
01253
01254
01255
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
01264
01265
01266
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);
01272 map_clearcell(&pl->contr->socket.lastmap.cells[ax][ay], 0, 0);
01273 }
01274 } else if (d >= MAX_LIGHT_RADII) {
01275
01276
01277
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
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295
01296
01297
01298 oldlen = sl.len;
01299 SockList_AddShort(&sl, coord);
01300
01301
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
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
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
01326
01327
01328
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
01337
01338
01339 if (!del_one && !got_one && !have_darkness) {
01340 sl.len = oldlen;
01341 } else if (del_one && !has_obj) {
01342
01343
01344
01345
01346
01347
01348
01349 sl.len = oldlen+2;
01350 SockList_AddChar(&sl, 0);
01351 SockList_AddChar(&sl, 255);
01352 map_clearcell(&pl->contr->socket.lastmap.cells[ax][ay], 0, 0);
01353 } else {
01354 SockList_AddChar(&sl, 255);
01355 }
01356 }
01357 }
01358 }
01359 }
01360
01361
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
01389
01390
01391
01392 if (pm == NULL || pm->in_memory != MAP_IN_MEMORY)
01393 return;
01394
01395
01396
01397
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
01414
01415
01416
01417
01418 if (mflags&P_NEW_MAP)
01419 m->timeout = 50;
01420 }
01421 }
01422
01423
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
01443
01444
01445
01446
01447
01448 for (x = 0; x < mx; x++) {
01449 for (y = 0; y < my; y++) {
01450 if (x >= ns->mapx || y >= ns->mapy) {
01451
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
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]);
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]);
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
01682
01683
01684
01685
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
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
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
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
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
01830
01831
01832
01833
01834
01835
01836
01837
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
01852 Send_With_Handling(&pl->socket, &sl);
01853 SockList_Term(&sl);
01854 }
01855
01856
01857
01858
01859
01860
01861
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 }