|
Atrinik Server 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00032 #include <global.h> 00033 00034 static object *esrv_get_ob_from_count_DM(object *pl, tag_t count); 00035 static int check_container(object *pl, object *con); 00036 00038 #define MAXITEMLEN 300 00039 00045 unsigned int query_flags(object *op) 00046 { 00047 unsigned int flags = 0; 00048 00049 if (QUERY_FLAG(op, FLAG_APPLIED)) 00050 { 00051 switch (op->type) 00052 { 00053 case BOW: 00054 case WAND: 00055 case ROD: 00056 case HORN: 00057 flags = a_readied; 00058 break; 00059 00060 case WEAPON: 00061 flags = a_wielded; 00062 break; 00063 00064 case SKILL: 00065 case ARMOUR: 00066 case HELMET: 00067 case SHIELD: 00068 case RING: 00069 case BOOTS: 00070 case GLOVES: 00071 case AMULET: 00072 case GIRDLE: 00073 case BRACERS: 00074 case CLOAK: 00075 flags = a_worn; 00076 break; 00077 00078 case CONTAINER: 00079 flags = a_active; 00080 break; 00081 00082 default: 00083 flags = a_applied; 00084 break; 00085 } 00086 } 00087 00088 if (op->type == CONTAINER && (op->attacked_by || (!op->env && QUERY_FLAG(op, FLAG_APPLIED)))) 00089 { 00090 flags |= F_OPEN; 00091 } 00092 00093 if (QUERY_FLAG(op, FLAG_IS_TRAPPED)) 00094 { 00095 flags |= F_TRAPPED; 00096 } 00097 00098 if (QUERY_FLAG(op, FLAG_IDENTIFIED) || QUERY_FLAG(op, FLAG_APPLIED)) 00099 { 00100 if (QUERY_FLAG(op, FLAG_DAMNED)) 00101 { 00102 flags |= F_DAMNED; 00103 } 00104 else if (QUERY_FLAG(op, FLAG_CURSED)) 00105 { 00106 flags |= F_CURSED; 00107 } 00108 } 00109 00110 if (QUERY_FLAG(op, FLAG_IS_MAGICAL) && QUERY_FLAG(op, FLAG_IDENTIFIED)) 00111 { 00112 flags |= F_MAGIC; 00113 } 00114 00115 if (QUERY_FLAG(op, FLAG_UNPAID)) 00116 { 00117 flags |= F_UNPAID; 00118 } 00119 00120 if (QUERY_FLAG(op, FLAG_INV_LOCKED)) 00121 { 00122 flags |= F_LOCKED; 00123 } 00124 00125 if (QUERY_FLAG(op, FLAG_IS_INVISIBLE)) 00126 { 00127 flags |= F_INVISIBLE; 00128 } 00129 00130 if (QUERY_FLAG(op, FLAG_IS_ETHEREAL)) 00131 { 00132 flags |= F_ETHEREAL; 00133 } 00134 00135 if (QUERY_FLAG(op, FLAG_NO_PICK)) 00136 { 00137 flags |= F_NOPICK; 00138 } 00139 00140 return flags; 00141 } 00142 00149 static void add_object_to_socklist(SockList *sl, object *op, object *pl, uint32 flags) 00150 { 00151 SockList_AddInt(sl, op->count); 00152 00153 if (flags & UPD_LOCATION) 00154 { 00155 SockList_AddInt(sl, op->env ? op->env->count : 0); 00156 } 00157 00158 if (flags & UPD_FLAGS) 00159 { 00160 SockList_AddInt(sl, query_flags(op)); 00161 } 00162 00163 if (flags & UPD_WEIGHT) 00164 { 00165 SockList_AddInt(sl, WEIGHT(op)); 00166 } 00167 00168 if (flags & UPD_FACE) 00169 { 00170 if (op->inv_face && QUERY_FLAG(op, FLAG_IDENTIFIED)) 00171 { 00172 SockList_AddInt(sl, op->inv_face->number); 00173 } 00174 else 00175 { 00176 SockList_AddInt(sl, op->face->number); 00177 } 00178 } 00179 00180 if (flags & UPD_DIRECTION) 00181 { 00182 SockList_AddChar(sl, op->facing); 00183 } 00184 00185 if (flags & UPD_TYPE) 00186 { 00187 SockList_AddChar(sl, op->type); 00188 SockList_AddChar(sl, op->sub_type); 00189 00190 if (QUERY_FLAG(op, FLAG_IDENTIFIED)) 00191 { 00192 SockList_AddChar(sl, op->item_quality); 00193 SockList_AddChar(sl, op->item_condition); 00194 SockList_AddChar(sl, op->item_level); 00195 SockList_AddChar(sl, op->item_skill); 00196 } 00197 else 00198 { 00199 SockList_AddChar(sl, (char) 255); 00200 SockList_AddChar(sl, (char) 255); 00201 SockList_AddChar(sl, (char) 255); 00202 SockList_AddChar(sl, (char) 255); 00203 } 00204 } 00205 00206 if (flags & UPD_NAME) 00207 { 00208 size_t len; 00209 char item_name[MAX_BUF]; 00210 00211 if (op->custom_name) 00212 { 00213 memcpy(item_name, op->custom_name, 127); 00214 } 00215 else 00216 { 00217 memcpy(item_name, query_base_name(op, pl), 127); 00218 } 00219 00220 item_name[127] = '\0'; 00221 len = strlen(item_name); 00222 SockList_AddLen8Data(sl, item_name, len); 00223 } 00224 00225 if (flags & UPD_ANIM) 00226 { 00227 if (!(flags & UPD_ANIM_NO_INV) && op->inv_animation_id) 00228 { 00229 SockList_AddShort(sl, op->inv_animation_id); 00230 } 00231 else 00232 { 00233 SockList_AddShort(sl, op->animation_id); 00234 } 00235 } 00236 00237 if (flags & UPD_ANIMSPEED) 00238 { 00239 int anim_speed = 0; 00240 00241 if (QUERY_FLAG(op, FLAG_ANIMATE)) 00242 { 00243 if (op->anim_speed) 00244 { 00245 anim_speed = op->anim_speed; 00246 } 00247 else 00248 { 00249 if (FABS(op->speed) < 0.001) 00250 { 00251 anim_speed = 255; 00252 } 00253 else if (FABS(op->speed) >= 1.0) 00254 { 00255 anim_speed = 1; 00256 } 00257 else 00258 { 00259 anim_speed = (int) (1.0 / FABS(op->speed)); 00260 } 00261 } 00262 00263 if (anim_speed > 255) 00264 { 00265 anim_speed = 255; 00266 } 00267 } 00268 00269 SockList_AddChar(sl, (char) anim_speed); 00270 } 00271 00272 if (flags & UPD_NROF) 00273 { 00274 SockList_AddInt(sl, op->nrof); 00275 } 00276 } 00277 00284 static int esrv_draw_look_rec(object *pl, SockList *sl, object *op) 00285 { 00286 char buf[MAX_BUF]; 00287 object *tmp; 00288 int got_one = 0; 00289 00290 SockList_AddInt(sl, 0); 00291 SockList_AddInt(sl, 0); 00292 SockList_AddInt(sl, -1); 00293 SockList_AddInt(sl, (uint32) blank_face->number); 00294 SockList_AddChar(sl, 0); 00295 strncpy(buf, "in inventory", sizeof(buf)); 00296 buf[sizeof(buf) - 1] = '\0'; 00297 SockList_AddLen8Data(sl, buf, MIN(strlen(buf), 255)); 00298 SockList_AddShort(sl, 0); 00299 SockList_AddChar(sl, 0); 00300 SockList_AddInt(sl, 0); 00301 00302 for (tmp = op->inv; tmp; tmp = tmp->below) 00303 { 00304 add_object_to_socklist(sl, HEAD(tmp), pl, UPD_FLAGS | UPD_WEIGHT | UPD_FACE | UPD_DIRECTION | UPD_NAME | UPD_ANIM | UPD_ANIM_NO_INV | UPD_ANIMSPEED | UPD_NROF); 00305 got_one++; 00306 00307 if (sl->len > (MAXSOCKBUF - MAXITEMLEN)) 00308 { 00309 Send_With_Handling(&CONTR(pl)->socket, sl); 00310 SOCKET_SET_BINARY_CMD(sl, BINARY_CMD_ITEMY); 00311 SockList_AddInt(sl, -2); 00312 SockList_AddInt(sl, 0); 00313 got_one = 0; 00314 } 00315 00316 if (tmp->inv && tmp->type != PLAYER) 00317 { 00318 got_one = esrv_draw_look_rec(pl, sl, tmp); 00319 } 00320 } 00321 00322 SockList_AddInt(sl, 0); 00323 SockList_AddInt(sl, 0); 00324 SockList_AddInt(sl, -1); 00325 SockList_AddInt(sl, (uint32) blank_face->number); 00326 SockList_AddChar(sl, 0); 00327 strncpy(buf, "end inventory", sizeof(buf)); 00328 buf[sizeof(buf) - 1] = '\0'; 00329 SockList_AddLen8Data(sl, buf, MIN(strlen(buf), 255)); 00330 SockList_AddShort(sl, 0); 00331 SockList_AddChar(sl, 0); 00332 SockList_AddInt(sl, 0); 00333 return got_one; 00334 } 00335 00342 void esrv_draw_look(object *pl) 00343 { 00344 socket_struct *ns = &CONTR(pl)->socket; 00345 char buf[MAX_BUF]; 00346 object *tmp, *last; 00347 int got_one = 0, start_look = 0, end_look = 0, wiz; 00348 SockList sl; 00349 00350 if (QUERY_FLAG(pl, FLAG_REMOVED) || pl->map == NULL || pl->map->in_memory != MAP_IN_MEMORY || OUT_OF_REAL_MAP(pl->map, pl->x, pl->y)) 00351 { 00352 return; 00353 } 00354 00355 wiz = QUERY_FLAG(pl, FLAG_WIZ); 00356 /* Grab last (top) object without browsing the objects. */ 00357 tmp = GET_MAP_OB_LAST(pl->map, pl->x, pl->y); 00358 00359 sl.buf = malloc(MAXSOCKBUF); 00360 00361 SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_ITEMY); 00362 00363 SockList_AddInt(&sl, 0); 00364 SockList_AddInt(&sl, 0); 00365 00366 if (CONTR(pl)->socket.look_position) 00367 { 00368 SockList_AddInt(&sl, 0x80000000 | (CONTR(pl)->socket.look_position - NUM_LOOK_OBJECTS)); 00369 SockList_AddInt(&sl, 0); 00370 SockList_AddInt(&sl, -1); 00371 SockList_AddInt(&sl, prev_item_face->number); 00372 SockList_AddChar(&sl, 0); 00373 snprintf(buf, sizeof(buf), "Apply to see %d previous items", NUM_LOOK_OBJECTS); 00374 SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255)); 00375 SockList_AddShort(&sl, 0); 00376 SockList_AddChar(&sl, 0); 00377 SockList_AddInt(&sl, 0); 00378 } 00379 00380 for (last = NULL; tmp != last; tmp = tmp->below) 00381 { 00382 if (tmp == pl) 00383 { 00384 continue; 00385 } 00386 00387 /* Skip map mask, sys_objects and invisible objects when we can't 00388 * see them. */ 00389 if (tmp->layer <= LAYER_FMASK || IS_SYS_INVISIBLE(tmp) || (!QUERY_FLAG(pl, FLAG_SEE_INVISIBLE) && QUERY_FLAG(tmp, FLAG_IS_INVISIBLE))) 00390 { 00391 /* But only when we are not a DM */ 00392 if (!QUERY_FLAG(pl, FLAG_WIZ)) 00393 { 00394 continue; 00395 } 00396 } 00397 00398 if (++start_look < CONTR(pl)->socket.look_position) 00399 { 00400 continue; 00401 } 00402 00403 /* If we have too many items to send, send a 'next group' object 00404 * and leave here. */ 00405 if (++end_look > NUM_LOOK_OBJECTS) 00406 { 00407 SockList_AddInt(&sl, 0x80000000 | (CONTR(pl)->socket.look_position + NUM_LOOK_OBJECTS)); 00408 SockList_AddInt(&sl, 0); 00409 SockList_AddInt(&sl, -1); 00410 SockList_AddInt(&sl, next_item_face->number); 00411 SockList_AddChar(&sl, 0); 00412 snprintf(buf, sizeof(buf), "Apply to see next group of items"); 00413 SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255)); 00414 SockList_AddShort(&sl, 0); 00415 SockList_AddChar(&sl, 0); 00416 SockList_AddInt(&sl, 0); 00417 break; 00418 } 00419 00420 add_object_to_socklist(&sl, HEAD(tmp), pl, UPD_FLAGS | UPD_WEIGHT | UPD_FACE | UPD_DIRECTION | UPD_NAME | UPD_ANIM | UPD_ANIM_NO_INV | UPD_ANIMSPEED | UPD_NROF); 00421 got_one++; 00422 00423 if (sl.len > (MAXSOCKBUF - MAXITEMLEN)) 00424 { 00425 Send_With_Handling(ns, &sl); 00426 SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_ITEMY); 00427 /* do no delinv */ 00428 SockList_AddInt(&sl, -2); 00429 SockList_AddInt(&sl, 0); 00430 got_one = 0; 00431 } 00432 00433 if (wiz && tmp->inv && tmp->type != PLAYER) 00434 { 00435 got_one = esrv_draw_look_rec(pl, &sl, tmp); 00436 } 00437 } 00438 00439 if (got_one || (!got_one && !ns->below_clear)) 00440 { 00441 Send_With_Handling(ns, &sl); 00442 ns->below_clear = 0; 00443 } 00444 00445 free(sl.buf); 00446 } 00447 00451 void esrv_close_container(object *op) 00452 { 00453 SockList sl; 00454 00455 sl.buf = malloc(256); 00456 SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_ITEMX); 00457 /* Container mode flag */ 00458 SockList_AddInt(&sl, -1); 00459 SockList_AddInt(&sl, -1); 00460 00461 Send_With_Handling(&CONTR(op)->socket, &sl); 00462 free(sl.buf); 00463 } 00464 00470 void esrv_send_inventory(object *pl, object *op) 00471 { 00472 object *tmp; 00473 int got_one = 0; 00474 SockList sl; 00475 00476 sl.buf = malloc(MAXSOCKBUF); 00477 00478 SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_ITEMY); 00479 00480 /* In this case we're sending a container inventory */ 00481 if (pl != op) 00482 { 00483 /* Container mode flag */ 00484 SockList_AddInt(&sl, -1); 00485 } 00486 else 00487 { 00488 SockList_AddInt(&sl, op->count); 00489 } 00490 00491 SockList_AddInt(&sl, op->count); 00492 00493 for (tmp = op->inv; tmp; tmp = tmp->below) 00494 { 00495 if (!QUERY_FLAG(pl, FLAG_SEE_INVISIBLE) && QUERY_FLAG(tmp, FLAG_IS_INVISIBLE)) 00496 { 00497 /* Skip this for DMs */ 00498 if (!QUERY_FLAG(pl, FLAG_WIZ)) 00499 { 00500 continue; 00501 } 00502 } 00503 00504 if (LOOK_OBJ(tmp) || QUERY_FLAG(pl, FLAG_WIZ)) 00505 { 00506 add_object_to_socklist(&sl, tmp, pl, UPD_FLAGS | UPD_WEIGHT | UPD_FACE | UPD_DIRECTION | UPD_TYPE | UPD_NAME | UPD_ANIM | UPD_ANIMSPEED | UPD_NROF); 00507 got_one++; 00508 00509 /* It is possible for players to accumulate a huge amount of 00510 * items (especially with some of the bags out there) to 00511 * overflow the buffer. If so, send multiple item1 00512 * commands. */ 00513 if (sl.len > (MAXSOCKBUF - MAXITEMLEN)) 00514 { 00515 Send_With_Handling(&CONTR(pl)->socket, &sl); 00516 SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_ITEMY); 00517 /* no del inv */ 00518 SockList_AddInt(&sl, -3); 00519 SockList_AddInt(&sl, op->count); 00520 got_one = 0; 00521 } 00522 } 00523 } 00524 00525 /* Container can be empty */ 00526 if (got_one || pl != op) 00527 { 00528 Send_With_Handling(&CONTR(pl)->socket, &sl); 00529 } 00530 00531 free(sl.buf); 00532 } 00533 00539 static void esrv_update_item_send(int flags, object *pl, object *op) 00540 { 00541 SockList sl; 00542 00543 /* If we have a request to send the player item, skip a few checks. */ 00544 if (op != pl) 00545 { 00546 if (!LOOK_OBJ(op) && !QUERY_FLAG(pl, FLAG_WIZ)) 00547 { 00548 return; 00549 } 00550 } 00551 00552 sl.buf = malloc(MAXSOCKBUF); 00553 00554 SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_UPITEM); 00555 SockList_AddShort(&sl, (uint16) flags); 00556 add_object_to_socklist(&sl, op, pl, flags); 00557 Send_With_Handling(&CONTR(pl)->socket, &sl); 00558 free(sl.buf); 00559 } 00560 00566 void esrv_update_item(int flags, object *pl, object *op) 00567 { 00568 object *tmp; 00569 00570 /* Update something in a container. */ 00571 if (op->env && op->env->type == CONTAINER) 00572 { 00573 for (tmp = op->env->attacked_by; tmp; tmp = CONTR(tmp)->container_above) 00574 { 00575 esrv_update_item_send(flags, tmp, op); 00576 } 00577 00578 return; 00579 } 00580 00581 esrv_update_item_send(flags, pl, op); 00582 } 00583 00588 static void esrv_send_item_send(object *pl, object *op) 00589 { 00590 SockList sl; 00591 00592 /* If this is not the player object, do some more checks. */ 00593 if (op != pl) 00594 { 00595 /* We only send 'visible' objects to the client. */ 00596 if (!LOOK_OBJ(op)) 00597 { 00598 return; 00599 } 00600 } 00601 00602 sl.buf = malloc(MAXSOCKBUF); 00603 00604 SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_ITEMX); 00605 /* no delinv */ 00606 SockList_AddInt(&sl, -4); 00607 SockList_AddInt(&sl, op->env ? op->env->count : 0); 00608 00609 /* If not below */ 00610 if (op->env) 00611 { 00612 add_object_to_socklist(&sl, HEAD(op), pl, UPD_FLAGS | UPD_WEIGHT | UPD_FACE | UPD_DIRECTION | UPD_TYPE | UPD_NAME | UPD_ANIM | UPD_ANIMSPEED | UPD_NROF); 00613 } 00614 else 00615 { 00616 add_object_to_socklist(&sl, HEAD(op), pl, UPD_FLAGS | UPD_WEIGHT | UPD_FACE | UPD_DIRECTION | UPD_NAME | UPD_ANIM | UPD_ANIM_NO_INV | UPD_ANIMSPEED | UPD_NROF); 00617 } 00618 00619 Send_With_Handling(&CONTR(pl)->socket, &sl); 00620 free(sl.buf); 00621 } 00622 00627 void esrv_send_item(object *pl, object *op) 00628 { 00629 object *tmp; 00630 00631 /* Update something in a container. */ 00632 if (op->env && op->env->type == CONTAINER) 00633 { 00634 for (tmp = op->env->attacked_by; tmp; tmp = CONTR(tmp)->container_above) 00635 { 00636 esrv_send_item_send(tmp, op); 00637 } 00638 00639 return; 00640 } 00641 00642 if (pl->type != PLAYER) 00643 { 00644 LOG(llevBug, "esrv_send_item(): called for non PLAYER/CONTAINER object! (%s) (%s)\n", query_name(pl, NULL), query_name(op, NULL)); 00645 return; 00646 } 00647 00648 esrv_send_item_send(pl, op); 00649 } 00650 00655 static void esrv_del_item_send(player *pl, int tag) 00656 { 00657 SockList sl; 00658 00659 sl.buf = malloc(MAXSOCKBUF); 00660 00661 SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_DELITEM); 00662 SockList_AddInt(&sl, tag); 00663 00664 Send_With_Handling(&pl->socket, &sl); 00665 free(sl.buf); 00666 } 00667 00673 void esrv_del_item(player *pl, int tag, object *cont) 00674 { 00675 object *tmp; 00676 00677 if (cont && cont->type == CONTAINER) 00678 { 00679 for (tmp = cont->attacked_by; tmp; tmp = CONTR(tmp)->container_above) 00680 { 00681 esrv_del_item_send(CONTR(tmp), tag); 00682 } 00683 00684 return; 00685 } 00686 00687 esrv_del_item_send(pl, tag); 00688 } 00689 00696 object *esrv_get_ob_from_count(object *pl, tag_t count) 00697 { 00698 object *op, *tmp; 00699 00700 /* Easy case */ 00701 if (pl->count == count) 00702 { 00703 return pl; 00704 } 00705 00706 /* Special case, we can examine deep inside every inventory even from 00707 * non containers. */ 00708 if (QUERY_FLAG(pl, FLAG_WIZ)) 00709 { 00710 for (op = pl->inv; op; op = op->below) 00711 { 00712 if (op->count == count) 00713 { 00714 return op; 00715 } 00716 else if (op->inv) 00717 { 00718 if ((tmp = esrv_get_ob_from_count_DM(op->inv, count))) 00719 { 00720 return tmp; 00721 } 00722 } 00723 } 00724 00725 for (op = get_map_ob(pl->map, pl->x, pl->y); op; op = op->above) 00726 { 00727 if (op->count == count) 00728 { 00729 return op; 00730 } 00731 else if (op->inv) 00732 { 00733 if ((tmp = esrv_get_ob_from_count_DM(op->inv, count))) 00734 { 00735 return tmp; 00736 } 00737 } 00738 } 00739 00740 return NULL; 00741 } 00742 00743 if (pl->count == count) 00744 { 00745 return pl; 00746 } 00747 00748 for (op = pl->inv; op; op = op->below) 00749 { 00750 if (op->count == count) 00751 { 00752 return op; 00753 } 00754 else if (op->type == CONTAINER && CONTR(pl)->container == op) 00755 { 00756 for (tmp = op->inv; tmp; tmp = tmp->below) 00757 { 00758 if (tmp->count == count) 00759 { 00760 return tmp; 00761 } 00762 } 00763 } 00764 } 00765 00766 for (op = get_map_ob(pl->map, pl->x, pl->y); op; op = op->above) 00767 { 00768 if (op->count == count) 00769 { 00770 return op; 00771 } 00772 else if (op->type == CONTAINER && CONTR(pl)->container == op) 00773 { 00774 for (tmp = op->inv; tmp; tmp = tmp->below) 00775 { 00776 if (tmp->count == count) 00777 { 00778 return tmp; 00779 } 00780 } 00781 } 00782 } 00783 00784 return NULL; 00785 } 00786 00792 static object *esrv_get_ob_from_count_DM(object *pl, tag_t count) 00793 { 00794 object *tmp, *op; 00795 00796 for (op = pl; op; op = op->below) 00797 { 00798 if (op->count == count) 00799 { 00800 return op; 00801 } 00802 else if (op->inv) 00803 { 00804 if ((tmp = esrv_get_ob_from_count_DM(op->inv, count))) 00805 { 00806 return tmp; 00807 } 00808 } 00809 } 00810 00811 return NULL; 00812 } 00813 00819 void ExamineCmd(char *buf, int len, player *pl) 00820 { 00821 long tag; 00822 object *op; 00823 00824 if (!buf || !len) 00825 { 00826 return; 00827 } 00828 00829 tag = atoi(buf); 00830 op = esrv_get_ob_from_count(pl->ob, tag); 00831 00832 if (!op) 00833 { 00834 return; 00835 } 00836 00837 examine(pl->ob, op); 00838 } 00839 00844 static void remove_quickslot(uint8 slot, player *pl) 00845 { 00846 object *tmp; 00847 00848 if (pl->spell_quickslots[slot - 1] != SP_NO_SPELL) 00849 { 00850 pl->spell_quickslots[slot - 1] = SP_NO_SPELL; 00851 return; 00852 } 00853 00854 for (tmp = pl->ob->inv; tmp; tmp = tmp->below) 00855 { 00856 if (tmp->quickslot && tmp->quickslot == slot) 00857 { 00858 tmp->quickslot = 0; 00859 } 00860 } 00861 } 00862 00866 void send_quickslots(player *pl) 00867 { 00868 SockList sl; 00869 unsigned char buf[MAXSOCKBUF]; 00870 object *tmp; 00871 uint8 i; 00872 00873 sl.buf = buf; 00874 SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_QUICKSLOT); 00875 00876 for (tmp = pl->ob->inv; tmp; tmp = tmp->below) 00877 { 00878 if (tmp->quickslot) 00879 { 00880 SockList_AddChar(&sl, QUICKSLOT_TYPE_ITEM); 00881 SockList_AddChar(&sl, tmp->quickslot - 1); 00882 SockList_AddInt(&sl, tmp->count); 00883 } 00884 } 00885 00886 for (i = 0; i < MAX_QUICKSLOT; i++) 00887 { 00888 if (pl->spell_quickslots[i] != SP_NO_SPELL) 00889 { 00890 SockList_AddChar(&sl, QUICKSLOT_TYPE_SPELL); 00891 SockList_AddChar(&sl, i); 00892 SockList_AddString(&sl, spells[pl->spell_quickslots[i]].name); 00893 } 00894 } 00895 00896 Send_With_Handling(&pl->socket, &sl); 00897 } 00898 00904 void QuickSlotCmd(uint8 *buf, int len, player *pl) 00905 { 00906 uint8 command, quickslot; 00907 00908 if (!buf || len < 2) 00909 { 00910 return; 00911 } 00912 00913 command = buf[0]; 00914 quickslot = buf[1]; 00915 00916 if (quickslot < 1 || quickslot > MAX_QUICKSLOT) 00917 { 00918 return; 00919 } 00920 00921 if (command == CMD_QUICKSLOT_SET) 00922 { 00923 tag_t tag; 00924 object *op; 00925 00926 if (len < 6) 00927 { 00928 return; 00929 } 00930 00931 tag = GetInt_String(buf + 2); 00932 op = esrv_get_ob_from_count(pl->ob, tag); 00933 00934 if (!op) 00935 { 00936 return; 00937 } 00938 00939 remove_quickslot(quickslot, pl); 00940 op->quickslot = quickslot; 00941 } 00942 else if (command == CMD_QUICKSLOT_SETSPELL) 00943 { 00944 sint16 spell_id; 00945 00946 /* Assumes that all spells have at least 2 letters. */ 00947 if (len < 4) 00948 { 00949 return; 00950 } 00951 00952 spell_id = look_up_spell_name((char *) buf + 2); 00953 00954 if (spell_id == SP_NO_SPELL) 00955 { 00956 return; 00957 } 00958 00959 remove_quickslot(quickslot, pl); 00960 pl->spell_quickslots[quickslot - 1] = spell_id; 00961 } 00962 else if (command == CMD_QUICKSLOT_UNSET) 00963 { 00964 remove_quickslot(quickslot, pl); 00965 } 00966 else 00967 { 00968 LOG(llevSystem, "Client %s@%s sent invalid quickslot command.\n", pl->ob->name, pl->socket.host); 00969 pl->socket.status = Ns_Dead; 00970 } 00971 } 00972 00978 void ApplyCmd(char *buf, int len, player *pl) 00979 { 00980 uint32 tag; 00981 object *op; 00982 00983 if (!buf || !len) 00984 { 00985 return; 00986 } 00987 00988 tag = atoi(buf); 00989 op = esrv_get_ob_from_count(pl->ob, tag); 00990 00991 if (QUERY_FLAG(pl->ob, FLAG_REMOVED)) 00992 { 00993 return; 00994 } 00995 00996 /* If the high bit is set, player applied a pseudo object. */ 00997 if (tag & 0x80000000) 00998 { 00999 pl->socket.look_position = tag & 0x7fffffff; 01000 pl->socket.update_tile = 0; 01001 return; 01002 } 01003 01004 if (!op) 01005 { 01006 return; 01007 } 01008 01009 player_apply(pl->ob, op, 0, 0); 01010 } 01011 01017 void LockItem(uint8 *data, int len, player *pl) 01018 { 01019 int flag, tag; 01020 object *op; 01021 01022 if (!data || !len) 01023 { 01024 return; 01025 } 01026 01027 flag = data[0]; 01028 tag = GetInt_String(data + 1); 01029 op = esrv_get_ob_from_count(pl->ob, tag); 01030 01031 /* Can happen as result of latency or client/server async. */ 01032 if (!op) 01033 { 01034 return; 01035 } 01036 01037 /* Only lock item inside the player's own inventory */ 01038 if (is_player_inv(op) != pl->ob) 01039 { 01040 new_draw_info(0, COLOR_WHITE, pl->ob, "You can't lock items outside your inventory!"); 01041 return; 01042 } 01043 01044 if (!flag) 01045 { 01046 CLEAR_FLAG(op, FLAG_INV_LOCKED); 01047 } 01048 else 01049 { 01050 SET_FLAG(op, FLAG_INV_LOCKED); 01051 } 01052 01053 esrv_update_item(UPD_FLAGS, pl->ob, op); 01054 } 01055 01061 void MarkItem(uint8 *data, int len, player *pl) 01062 { 01063 int tag; 01064 object *op; 01065 01066 if (!data || !len) 01067 { 01068 return; 01069 } 01070 01071 tag = GetInt_String(data); 01072 op = esrv_get_ob_from_count(pl->ob, tag); 01073 01074 if (!op) 01075 { 01076 return; 01077 } 01078 01079 if (pl->mark_count == op->count) 01080 { 01081 new_draw_info_format(0, COLOR_WHITE, pl->ob, "Unmarked item %s.", query_name(op, NULL)); 01082 pl->mark = NULL; 01083 pl->mark_count = -1; 01084 } 01085 else 01086 { 01087 new_draw_info_format(0, COLOR_WHITE, pl->ob, "Marked item %s.", query_name(op, NULL)); 01088 pl->mark_count = op->count; 01089 pl->mark = op; 01090 } 01091 } 01092 01099 void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof) 01100 { 01101 object *op, *env; 01102 int tmp; 01103 01104 op = esrv_get_ob_from_count(pl, tag); 01105 01106 if (!op) 01107 { 01108 return; 01109 } 01110 01111 /* drop it to the ground */ 01112 if (!to) 01113 { 01114 if (op->map && !op->env) 01115 { 01116 return; 01117 } 01118 01119 CLEAR_FLAG(pl, FLAG_INV_LOCKED); 01120 01121 if ((tmp = check_container(pl, op))) 01122 { 01123 new_draw_info(0, COLOR_WHITE, pl, "First remove all god-given items from this container!"); 01124 } 01125 else if (QUERY_FLAG(pl, FLAG_INV_LOCKED)) 01126 { 01127 new_draw_info(0, COLOR_WHITE, pl, "You can't drop a container with locked items inside!"); 01128 } 01129 else 01130 { 01131 drop_object(pl, op, nrof, 0); 01132 } 01133 01134 CLEAR_FLAG(pl, FLAG_INV_LOCKED); 01135 01136 return; 01137 } 01138 /* Pick it up to the inventory */ 01139 else if (to == pl->count || (to == op->count && !op->env)) 01140 { 01141 /* Return if player has already picked it up */ 01142 if (op->env == pl) 01143 { 01144 return; 01145 } 01146 01147 CONTR(pl)->count = nrof; 01148 /* It goes in player inv or readied container */ 01149 pick_up(pl, op, 0); 01150 return; 01151 } 01152 01153 /* If not dropped or picked up, we are putting it into a sack */ 01154 env = esrv_get_ob_from_count(pl, to); 01155 01156 if (!env) 01157 { 01158 return; 01159 } 01160 01161 /* put_object_in_sack() presumes that necessary sanity checking has 01162 * already been done (eg, it can be picked up and fits in in a sack, 01163 * so check for those things. We should also check and make sure env 01164 * is in fact a container for that matter. */ 01165 if (env->type == CONTAINER && can_pick(pl, op) && sack_can_hold(pl, env, op, nrof)) 01166 { 01167 CLEAR_FLAG(pl, FLAG_INV_LOCKED); 01168 tmp = check_container(pl, op); 01169 01170 if (QUERY_FLAG(pl, FLAG_INV_LOCKED) && env->env != pl) 01171 { 01172 new_draw_info(0, COLOR_WHITE, pl, "You can't drop a container with locked items inside!"); 01173 } 01174 else if (tmp && env->env != pl) 01175 { 01176 new_draw_info(0, COLOR_WHITE, pl, "First remove all god-given items from this container!"); 01177 } 01178 else if (QUERY_FLAG(op, FLAG_STARTEQUIP) && env->env != pl) 01179 { 01180 new_draw_info(0, COLOR_WHITE, pl, "You can't store god-given items outside your inventory!"); 01181 } 01182 else 01183 { 01184 put_object_in_sack(pl, env, op, nrof); 01185 } 01186 01187 CLEAR_FLAG(pl, FLAG_INV_LOCKED); 01188 01189 return; 01190 } 01191 } 01192 01201 static int check_container(object *pl, object *con) 01202 { 01203 object *current, *next; 01204 int ret = 0; 01205 01206 /* Only check stuff *inside* a container */ 01207 if (con->type != CONTAINER) 01208 { 01209 return 0; 01210 } 01211 01212 for (current = con->inv; current != NULL; current = next) 01213 { 01214 next = current->below; 01215 ret += check_container(pl, current); 01216 01217 if (QUERY_FLAG(current, FLAG_STARTEQUIP)) 01218 { 01219 ret += 1; 01220 } 01221 01222 if (QUERY_FLAG(current, FLAG_INV_LOCKED)) 01223 { 01224 SET_FLAG(pl, FLAG_INV_LOCKED); 01225 } 01226 } 01227 01228 return ret; 01229 } 01230 01237 void cmd_ready_send(player *pl, tag_t tag, int type) 01238 { 01239 SockList sl; 01240 unsigned char sockbuf[6]; 01241 01242 sl.buf = sockbuf; 01243 SOCKET_SET_BINARY_CMD(&sl, BINARY_CMD_READY); 01244 SockList_AddChar(&sl, type); 01245 SockList_AddInt(&sl, tag); 01246 Send_With_Handling(&pl->socket, &sl); 01247 } 01248 01254 int cmd_ready_determine(object *tmp) 01255 { 01256 /* System object, can't be any of the below. */ 01257 if (QUERY_FLAG(tmp, FLAG_SYS_OBJECT)) 01258 { 01259 return -1; 01260 } 01261 01262 /* Objects that can be thrown. */ 01263 if (QUERY_FLAG(tmp, FLAG_IS_THROWN)) 01264 { 01265 return READY_OBJ_THROW; 01266 } 01267 /* Arrows, or containers like quivers. */ 01268 else if (tmp->type == ARROW || tmp->type == CONTAINER) 01269 { 01270 return READY_OBJ_ARROW; 01271 } 01272 else 01273 { 01274 return -1; 01275 } 01276 } 01277 01284 void cmd_ready_clear(object *op, int type) 01285 { 01286 object *tmp; 01287 01288 for (tmp = op->inv; tmp; tmp = tmp->below) 01289 { 01290 if (QUERY_FLAG(tmp, FLAG_IS_READY) && cmd_ready_determine(tmp) == type) 01291 { 01292 CLEAR_FLAG(tmp, FLAG_IS_READY); 01293 break; 01294 } 01295 } 01296 }
1.7.4