Crossfire Server, Branch 1.12
R12190
|
00001 /* 00002 * static char *rcsid_item_c = 00003 * "$Id: item.c 11578 2009-02-23 22:02:27Z lalo $"; 00004 */ 00005 00006 /* 00007 CrossFire, A Multiplayer game for X-windows 00008 00009 Copyright (C) 2002,2006 Mark Wedel & Crossfire Development Team 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 00040 #include <global.h> 00041 #include <object.h> /* LOOK_OBJ */ 00042 #include <newclient.h> 00043 #include <newserver.h> 00044 #include <sproto.h> 00045 00047 #define MAXITEMLEN 300 00048 00049 /************************************************************************* 00050 * 00051 * Functions related to sending object data to the client. 00052 * 00053 ************************************************************************* 00054 */ 00055 00060 static unsigned int query_flags(const object *op) { 00061 unsigned int flags = 0; 00062 00063 if (QUERY_FLAG(op, FLAG_APPLIED)) { 00064 switch (op->type) { 00065 case BOW: 00066 case WAND: 00067 case ROD: 00068 case HORN: 00069 flags = a_readied; 00070 break; 00071 00072 case WEAPON: 00073 flags = a_wielded; 00074 break; 00075 00076 case SKILL: 00077 case ARMOUR: 00078 case HELMET: 00079 case SHIELD: 00080 case RING: 00081 case BOOTS: 00082 case GLOVES: 00083 case AMULET: 00084 case GIRDLE: 00085 case BRACERS: 00086 case CLOAK: 00087 flags = a_worn; 00088 break; 00089 00090 case CONTAINER: 00091 flags = a_active; 00092 break; 00093 00094 default: 00095 flags = a_applied; 00096 break; 00097 } 00098 } 00099 if (op->type == CONTAINER 00100 && ((op->env && op->env->container == op) || (!op->env && QUERY_FLAG(op, FLAG_APPLIED)))) 00101 flags |= F_OPEN; 00102 00103 if (QUERY_FLAG(op, FLAG_KNOWN_CURSED)) { 00104 if (QUERY_FLAG(op, FLAG_DAMNED)) 00105 flags |= F_DAMNED; 00106 else if (QUERY_FLAG(op, FLAG_CURSED)) 00107 flags |= F_CURSED; 00108 } 00109 if (QUERY_FLAG(op, FLAG_KNOWN_MAGICAL) && !QUERY_FLAG(op, FLAG_IDENTIFIED)) 00110 flags |= F_MAGIC; 00111 if (QUERY_FLAG(op, FLAG_UNPAID)) 00112 flags |= F_UNPAID; 00113 if (QUERY_FLAG(op, FLAG_INV_LOCKED)) 00114 flags |= F_LOCKED; 00115 if (QUERY_FLAG(op, FLAG_KNOWN_BLESSED) && QUERY_FLAG(op, FLAG_BLESSED)) 00116 flags |= F_BLESSED; 00117 00118 return flags; 00119 } 00120 00126 static void add_object_to_socklist(socket_struct *ns, SockList *sl, object *head) { 00127 int flags, len, anim_speed; 00128 char item_n[MAX_BUF], item_p[MAX_BUF]; 00129 00130 flags = query_flags(head); 00131 if (QUERY_FLAG(head, FLAG_NO_PICK)) 00132 flags |= F_NOPICK; 00133 00134 if (!(ns->faces_sent[head->face->number]&NS_FACESENT_FACE)) 00135 esrv_send_face(ns, head->face->number, 0); 00136 00137 if (QUERY_FLAG(head, FLAG_ANIMATE) && !ns->anims_sent[head->animation_id]) 00138 esrv_send_animation(ns, head->animation_id); 00139 00140 SockList_AddInt(sl, head->count); 00141 SockList_AddInt(sl, flags); 00142 SockList_AddInt(sl, QUERY_FLAG(head, FLAG_NO_PICK) ? -1 : WEIGHT(head)); 00143 SockList_AddInt(sl, head->face->number); 00144 00145 if (!head->custom_name) { 00146 query_base_name(head, 0, item_n, 126); 00147 item_n[127] = 0; 00148 len = strlen(item_n); 00149 query_base_name(head, 1, item_p, MAX_BUF); 00150 } else { 00151 strncpy(item_n, head->custom_name, 127); 00152 item_n[127] = 0; 00153 len = strlen(item_n); 00154 strncpy(item_p, head->custom_name, MAX_BUF); 00155 } 00156 strncpy(item_n+len+1, item_p, 127); 00157 /* This is needed because strncpy may not add a ending \0 if the string is long enough. */ 00158 item_n[len+1+127] = 0; 00159 len += strlen(item_n+1+len)+1; 00160 SockList_AddLen8Data(sl, item_n, len); 00161 00162 SockList_AddShort(sl, head->animation_id); 00163 anim_speed = 0; 00164 if (QUERY_FLAG(head, FLAG_ANIMATE)) { 00165 if (head->anim_speed) 00166 anim_speed = head->anim_speed; 00167 else { 00168 if (FABS(head->speed) < 0.001) 00169 anim_speed = 255; 00170 else if (FABS(head->speed) >= 1.0) 00171 anim_speed = 1; 00172 else 00173 anim_speed = (int)(1.0/FABS(head->speed)); 00174 } 00175 if (anim_speed > 255) 00176 anim_speed = 255; 00177 } 00178 SockList_AddChar(sl, (char)anim_speed); 00179 SockList_AddInt(sl, head->nrof); 00180 00181 SockList_AddShort(sl, head->client_type); 00182 00183 SET_FLAG(head, FLAG_CLIENT_SENT); 00184 } 00185 00191 void esrv_draw_look(object *pl) { 00192 object *tmp, *last; 00193 int got_one = 0, start_look = 0, end_look = 0, objects_sent = 0; 00194 SockList sl; 00195 char buf[MAX_BUF]; 00196 00197 if (!pl->contr->socket.update_look) { 00198 LOG(llevDebug, "esrv_draw_look called when update_look was not set\n"); 00199 return; 00200 } else { 00201 pl->contr->socket.update_look = 0; 00202 } 00203 00204 if (QUERY_FLAG(pl, FLAG_REMOVED) 00205 || pl->map == NULL 00206 || pl->map->in_memory != MAP_IN_MEMORY 00207 || out_of_map(pl->map, pl->x, pl->y)) 00208 return; 00209 00210 if (pl->contr->transport) 00211 for (tmp = pl->contr->transport->inv; tmp && tmp->above; tmp = tmp->above) 00212 ; 00213 else 00214 for (tmp = GET_MAP_OB(pl->map, pl->x, pl->y); tmp && tmp->above; tmp = tmp->above) 00215 ; 00216 00217 SockList_Init(&sl); 00218 SockList_AddString(&sl, "delinv 0"); 00219 Send_With_Handling(&pl->contr->socket, &sl); 00220 00221 SockList_Reset(&sl); 00222 SockList_AddPrintf(&sl, "item2 "); 00223 SockList_AddInt(&sl, 0); 00224 00225 if (!(pl->contr->socket.faces_sent[empty_face->number]&NS_FACESENT_FACE)) 00226 esrv_send_face(&pl->contr->socket, empty_face->number, 0); 00227 00228 if (pl->contr->socket.look_position) { 00229 int overhead = 1+(pl->contr->transport != NULL); 00230 int prev_len = pl->contr->socket.num_look_objects-overhead-(pl->contr->socket.look_position > pl->contr->socket.num_look_objects-overhead); 00231 SockList_AddInt(&sl, 0x80000000|MAX(0, pl->contr->socket.look_position-prev_len)); 00232 SockList_AddInt(&sl, 0); 00233 SockList_AddInt(&sl, -1); 00234 SockList_AddInt(&sl, empty_face->number); 00235 snprintf(buf, sizeof(buf), "Click here to see previous group of items"); 00236 SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255)); 00237 SockList_AddShort(&sl, 0); 00238 SockList_AddChar(&sl, 0); 00239 SockList_AddInt(&sl, 0); 00240 SockList_AddShort(&sl, 0); 00241 objects_sent++; 00242 got_one++; 00243 } 00244 00245 if (pl->contr->transport) { 00246 add_object_to_socklist(&pl->contr->socket, &sl, pl->contr->transport); 00247 objects_sent++; 00248 got_one++; 00249 } 00250 00251 for (last = NULL; tmp != last; tmp = tmp->below) { 00252 object *head; 00253 00254 if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !last) { 00255 last = tmp->below; /* assumes double floor mode */ 00256 if (last && QUERY_FLAG(last, FLAG_IS_FLOOR)) 00257 last = last->below; 00258 } 00259 if (LOOK_OBJ(tmp)) { 00260 if (start_look++ < pl->contr->socket.look_position) 00261 continue; 00262 end_look++; 00263 objects_sent++; 00264 if (objects_sent >= pl->contr->socket.num_look_objects) { 00265 /* What we basically do is make a 'fake' object - 00266 * when the user applies it, we notice the special 00267 * tag the object has, and act accordingly. 00268 */ 00269 SockList_AddInt(&sl, 0x80000000|(pl->contr->socket.look_position+end_look-1)); 00270 SockList_AddInt(&sl, 0); 00271 SockList_AddInt(&sl, -1); 00272 SockList_AddInt(&sl, empty_face->number); 00273 snprintf(buf, sizeof(buf), "Click here to see next group of items"); 00274 SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255)); 00275 SockList_AddShort(&sl, 0); 00276 SockList_AddChar(&sl, 0); 00277 SockList_AddInt(&sl, 0); 00278 SockList_AddShort(&sl, 0); 00279 break; 00280 } 00281 if (tmp->head) 00282 head = tmp->head; 00283 else 00284 head = tmp; 00285 00286 add_object_to_socklist(&pl->contr->socket, &sl, head); 00287 got_one++; 00288 00289 if (SockList_Avail(&sl) < MAXITEMLEN) { 00290 Send_With_Handling(&pl->contr->socket, &sl); 00291 SockList_Reset(&sl); 00292 SockList_AddPrintf(&sl, "item2 "); 00293 SockList_AddInt(&sl, 0); 00294 got_one = 0; 00295 } 00296 } /* If LOOK_OBJ() */ 00297 } 00298 if (got_one) 00299 Send_With_Handling(&pl->contr->socket, &sl); 00300 00301 SockList_Term(&sl); 00302 } 00303 00307 void esrv_send_inventory(object *pl, object *op) { 00308 object *tmp; 00309 int got_one = 0; 00310 SockList sl; 00311 00312 SockList_Init(&sl); 00313 SockList_AddPrintf(&sl, "delinv %u", op->count); 00314 Send_With_Handling(&pl->contr->socket, &sl); 00315 00316 SockList_Reset(&sl); 00317 SockList_AddString(&sl, "item2 "); 00318 SockList_AddInt(&sl, op->count); 00319 00320 for (tmp = op->inv; tmp; tmp = tmp->below) { 00321 object *head; 00322 00323 if (tmp->head) 00324 head = tmp->head; 00325 else 00326 head = tmp; 00327 00328 if (LOOK_OBJ(head)) { 00329 add_object_to_socklist(&pl->contr->socket, &sl, head); 00330 00331 got_one++; 00332 00333 /* It is possible for players to accumulate a huge amount of 00334 * items (especially with some of the bags out there) to 00335 * overflow the buffer. IF so, send multiple item commands. 00336 */ 00337 if (SockList_Avail(&sl) < MAXITEMLEN) { 00338 Send_With_Handling(&pl->contr->socket, &sl); 00339 SockList_Reset(&sl); 00340 SockList_AddString(&sl, "item2 "); 00341 SockList_AddInt(&sl, op->count); 00342 got_one = 0; 00343 } 00344 } /* If LOOK_OBJ() */ 00345 } 00346 if (got_one) 00347 Send_With_Handling(&pl->contr->socket, &sl); 00348 SockList_Term(&sl); 00349 } 00350 00359 void esrv_update_item(int flags, object *pl, object *op) { 00360 SockList sl; 00361 00362 if (!pl->contr) 00363 return; 00364 00365 /* If we have a request to send the player item, skip a few checks. */ 00366 if (op != pl) { 00367 if (!LOOK_OBJ(op)) 00368 return; 00369 /* we remove the check for op->env, because in theory, the object 00370 * is hopefully in the same place, so the client should preserve 00371 * order. 00372 */ 00373 } 00374 if (!QUERY_FLAG(op, FLAG_CLIENT_SENT)) { 00375 /* FLAG_CLIENT_SENT is debug only. We are using it to see where 00376 * this is happening - we can set a breakpoint here in the debugger 00377 * and track back the call. 00378 */ 00379 LOG(llevDebug, "We have not sent item %s (%d)\n", op->name, op->count); 00380 } 00381 00382 SockList_Init(&sl); 00383 SockList_AddString(&sl, "upditem "); 00384 SockList_AddChar(&sl, (char)flags); 00385 00386 if (op->head) 00387 op = op->head; 00388 00389 SockList_AddInt(&sl, op->count); 00390 00391 if (flags&UPD_LOCATION) 00392 SockList_AddInt(&sl, op->env ? op->env->count : 0); 00393 00394 if (flags&UPD_FLAGS) 00395 SockList_AddInt(&sl, query_flags(op)); 00396 00397 if (flags&UPD_WEIGHT) { 00398 sint32 weight = WEIGHT(op); 00399 00400 /* TRANSPORTS are odd - they sort of look like containers, 00401 * yet can't be picked up. So we don't to send the weight, 00402 * as it is odd that you see weight sometimes and not other 00403 * (the draw_look won't send it for example. 00404 */ 00405 SockList_AddInt(&sl, QUERY_FLAG(op, FLAG_NO_PICK) ? -1 : weight); 00406 if (pl == op) { 00407 op->contr->last_weight = weight; 00408 } 00409 } 00410 00411 if (flags&UPD_FACE) { 00412 if (!(pl->contr->socket.faces_sent[op->face->number]&NS_FACESENT_FACE)) 00413 esrv_send_face(&pl->contr->socket, op->face->number, 0); 00414 SockList_AddInt(&sl, op->face->number); 00415 } 00416 if (flags&UPD_NAME) { 00417 int len; 00418 char item_p[MAX_BUF]; 00419 char item_n[MAX_BUF]; 00420 00421 if (!op->custom_name) { 00422 query_base_name(op, 0, item_n, MAX_BUF); 00423 len = strlen(item_n); 00424 query_base_name(op, 1, item_p, MAX_BUF); 00425 } else { 00426 strncpy(item_n, op->custom_name, MAX_BUF-1); 00427 item_n[MAX_BUF-1] = 0; 00428 len = strlen(item_n); 00429 strncpy(item_p, op->custom_name, MAX_BUF-1); 00430 item_p[MAX_BUF-1] = 0; 00431 } 00432 00433 strncpy(item_n+len+1, item_p, 127); 00434 item_n[254] = 0; 00435 len += strlen(item_n+1+len)+1; 00436 SockList_AddLen8Data(&sl, item_n, len); 00437 } 00438 if (flags&UPD_ANIM) 00439 SockList_AddShort(&sl, op->animation_id); 00440 00441 if (flags&UPD_ANIMSPEED) { 00442 int anim_speed = 0; 00443 00444 if (QUERY_FLAG(op, FLAG_ANIMATE)) { 00445 if (op->anim_speed) 00446 anim_speed = op->anim_speed; 00447 else { 00448 if (FABS(op->speed) < 0.001) 00449 anim_speed = 255; 00450 else if (FABS(op->speed) >= 1.0) 00451 anim_speed = 1; 00452 else 00453 anim_speed = (int)(1.0/FABS(op->speed)); 00454 } 00455 if (anim_speed > 255) 00456 anim_speed = 255; 00457 } 00458 SockList_AddChar(&sl, (char)anim_speed); 00459 } 00460 if (flags&UPD_NROF) 00461 SockList_AddInt(&sl, op->nrof); 00462 00463 Send_With_Handling(&pl->contr->socket, &sl); 00464 SockList_Term(&sl); 00465 } 00466 00470 void esrv_send_item(object *pl, object*op) { 00471 SockList sl; 00472 00473 /* If this is not the player object, do some more checks */ 00474 if (op != pl) { 00475 /* We only send 'visibile' objects to the client */ 00476 if (!LOOK_OBJ(op)) 00477 return; 00478 /* if the item is on the ground, mark that the look needs to 00479 * be updated. 00480 */ 00481 if (!op->env) { 00482 pl->contr->socket.update_look = 1; 00483 return; 00484 } 00485 } 00486 00487 SockList_Init(&sl); 00488 SockList_AddString(&sl, "item2 "); 00489 00490 if (op->head) 00491 op = op->head; 00492 00493 SockList_AddInt(&sl, op->env ? op->env->count : 0); 00494 00495 add_object_to_socklist(&pl->contr->socket, &sl, op); 00496 00497 Send_With_Handling(&pl->contr->socket, &sl); 00498 SET_FLAG(op, FLAG_CLIENT_SENT); 00499 SockList_Term(&sl); 00500 } 00501 00507 void esrv_del_item(player *pl, int tag) { 00508 SockList sl; 00509 00510 SockList_Init(&sl); 00511 SockList_AddString(&sl, "delitem "); 00512 SockList_AddInt(&sl, tag); 00513 Send_With_Handling(&pl->socket, &sl); 00514 SockList_Term(&sl); 00515 } 00516 00517 /************************************************************************** 00518 * 00519 * Client has requested us to do something with an object. 00520 * 00521 ************************************************************************** 00522 */ 00523 00529 static object *esrv_get_ob_from_count(object *pl, tag_t count) { 00530 object *op, *tmp; 00531 00532 if (pl->count == count) 00533 return pl; 00534 00535 for (op = pl->inv; op; op = op->below) 00536 if (op->count == count) 00537 return op; 00538 else if (op->type == CONTAINER && pl->container == op) 00539 for (tmp = op->inv; tmp; tmp = tmp->below) 00540 if (tmp->count == count) 00541 return tmp; 00542 00543 for (op = GET_MAP_OB(pl->map, pl->x, pl->y); op; op = op->above) 00544 if (op->head != NULL && op->head->count == count) 00545 return op; 00546 else if (op->count == count) 00547 return op; 00548 else if (op->type == CONTAINER && pl->container == op) 00549 for (tmp = op->inv; tmp; tmp = tmp->below) 00550 if (tmp->count == count) 00551 return tmp; 00552 00553 if (pl->contr->transport) { 00554 for (tmp = pl->contr->transport->inv; tmp; tmp = tmp->below) 00555 if (tmp->count == count) 00556 return tmp; 00557 } 00558 return NULL; 00559 } 00560 00562 void examine_cmd(char *buf, int len, player *pl) { 00563 long tag; 00564 object *op; 00565 00566 if (len <= 0 || !buf) { 00567 LOG(llevDebug, "Player '%s' sent bogus examine_cmd information\n", pl->ob->name); 00568 return; 00569 } 00570 00571 tag = atoi(buf); 00572 op = esrv_get_ob_from_count(pl->ob, tag); 00573 if (!op) { 00574 LOG(llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n", pl->ob->name, tag); 00575 return; 00576 } 00577 examine(pl->ob, op); 00578 } 00579 00581 void apply_cmd(char *buf, int len, player *pl) { 00582 uint32 tag; 00583 object *op; 00584 00585 if (!buf || len <= 0) { 00586 LOG(llevDebug, "Player '%s' sent bogus apply_cmd information\n", pl->ob->name); 00587 return; 00588 } 00589 00590 tag = atoi(buf); 00591 op = esrv_get_ob_from_count(pl->ob, tag); 00592 00593 /* sort of a hack, but if the player saves and the player then 00594 * manually applies a savebed (or otherwise tries to do stuff), 00595 * we run into trouble. 00596 */ 00597 if (QUERY_FLAG(pl->ob, FLAG_REMOVED)) 00598 return; 00599 00600 /* If the high bit is set, player applied a pseudo object. */ 00601 if (tag&0x80000000) { 00602 pl->socket.look_position = tag&0x7fffffff; 00603 pl->socket.update_look = 1; 00604 return; 00605 } 00606 00607 if (!op) { 00608 LOG(llevDebug, "Player '%s' tried to apply the unknown object (%d)\n", pl->ob->name, tag); 00609 return; 00610 } 00611 player_apply(pl->ob, op, 0, 0); 00612 } 00613 00615 void lock_item_cmd(uint8 *data, int len, player *pl) { 00616 int flag, tag; 00617 object *op; 00618 object *tmp; 00619 00620 if (len != 5) { 00621 LOG(llevDebug, "Player '%s' sent bogus lock_item_cmd information\n", pl->ob->name); 00622 return; 00623 } 00624 flag = data[0]; 00625 tag = GetInt_String(data+1); 00626 op = esrv_get_ob_from_count(pl->ob, tag); 00627 00628 if (!op) { 00629 draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00630 "Could not find object to lock/unlock", NULL); 00631 return; 00632 } 00633 if (!flag) 00634 CLEAR_FLAG(op, FLAG_INV_LOCKED); 00635 else 00636 SET_FLAG(op, FLAG_INV_LOCKED); 00637 00638 tmp = merge_ob(op, NULL); 00639 if (tmp == NULL) { 00640 /* object was not merged - if it was, merge_ob sent updates for us. */ 00641 esrv_update_item(UPD_FLAGS, pl->ob, op); 00642 } 00643 } 00644 00655 void mark_item_cmd(uint8 *data, int len, player *pl) { 00656 int tag; 00657 object *op; 00658 char name[MAX_BUF]; 00659 00660 if (len != 4) { 00661 LOG(llevDebug, "Player '%s' sent bogus mark_item_cmd information\n", pl->ob->name); 00662 return; 00663 } 00664 00665 tag = GetInt_String(data); 00666 op = esrv_get_ob_from_count(pl->ob, tag); 00667 if (!op) { 00668 draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, 00669 "Could not find object to mark", NULL); 00670 return; 00671 } 00672 pl->mark = op; 00673 pl->mark_count = op->count; 00674 query_name(op, name, MAX_BUF); 00675 draw_ext_info_format(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, 00676 "Marked item %s", 00677 "Marked item %s", 00678 name); 00679 } 00680 00687 void look_at(object *op, int dx, int dy) { 00688 object *tmp; 00689 int flag = 0; 00690 sint16 x, y; 00691 mapstruct *m; 00692 char name[MAX_BUF]; 00693 00694 if (out_of_map(op->map, op->x+dx, op->y+dy)) 00695 return; 00696 00697 x = op->x+dx; 00698 y = op->y+dy; 00699 00700 m = get_map_from_coord(op->map, &x, &y); 00701 if (!m) 00702 return; 00703 00704 for (tmp = GET_MAP_OB(m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above) 00705 ; 00706 00707 for (; tmp != NULL; tmp = tmp->below) { 00708 if (tmp->invisible && !QUERY_FLAG(op, FLAG_WIZ)) 00709 continue; 00710 00711 if (!flag) { 00712 if (dx || dy) 00713 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, 00714 "There you see:", NULL); 00715 else { 00716 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, 00717 "You see:", NULL); 00718 } 00719 flag = 1; 00720 } 00721 00722 query_name(tmp, name, MAX_BUF); 00723 if (QUERY_FLAG(op, FLAG_WIZ)) 00724 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_EXAMINE, 00725 "- %s (%d).", 00726 "- %s (%d).", 00727 name, tmp->count); 00728 else 00729 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_EXAMINE, 00730 "- %s.", 00731 "- %s.", 00732 name); 00733 00734 if (((tmp->inv != NULL || (tmp->head && tmp->head->inv)) && (tmp->type != CONTAINER && tmp->type != FLESH)) 00735 || QUERY_FLAG(op, FLAG_WIZ)) 00736 inventory(op, tmp->head == NULL ? tmp : tmp->head); 00737 00738 /* don't continue under the floor */ 00739 if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !QUERY_FLAG(op, FLAG_WIZ)) 00740 break; 00741 } 00742 00743 if (!flag) { 00744 if (dx || dy) 00745 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, 00746 "You see nothing there.", NULL); 00747 else 00748 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, 00749 "You see nothing.", NULL); 00750 } 00751 } 00752 00754 void look_at_cmd(char *buf, int len, player *pl) { 00755 int dx, dy; 00756 char *cp; 00757 00758 dx = atoi(buf); 00759 if (!(cp = strchr(buf, ' '))) { 00760 return; 00761 } 00762 dy = atoi(cp); 00763 00764 if (FABS(dx) > MAP_CLIENT_X/2 || FABS(dy) > MAP_CLIENT_Y/2) 00765 return; 00766 00767 if (pl->blocked_los[dx+(pl->socket.mapx/2)][dy+(pl->socket.mapy/2)]) 00768 return; 00769 look_at(pl->ob, dx, dy); 00770 } 00771 00773 void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof) { 00774 object *op, *env; 00775 00776 op = esrv_get_ob_from_count(pl, tag); 00777 if (!op) { 00778 LOG(llevDebug, "Player '%s' tried to move an unknown object (%lu)\n", pl->name, (unsigned long)tag); 00779 return; 00780 } 00781 00782 /* If on a transport, you don't drop to the ground - you drop to the 00783 * transport. 00784 */ 00785 if (!to && !pl->contr->transport) { /* drop it to the ground */ 00786 /* LOG(llevDebug, "Drop it on the ground.\n");*/ 00787 00788 if (op->map && !op->env) { 00789 /* LOG(llevDebug, "Dropping object to ground that is already on ground\n");*/ 00790 return; 00791 } 00792 /* If it is an active container, then we should drop all objects 00793 * in the container and not the container itself. 00794 */ 00795 if (op->inv && QUERY_FLAG(op, FLAG_APPLIED)) { 00796 object *current, *next; 00797 00798 for (current = op->inv; current != NULL; current = next) { 00799 next = current->below; 00800 drop_object(pl, current, 0); 00801 } 00802 esrv_update_item(UPD_WEIGHT, pl, op); 00803 } else { 00804 drop_object(pl, op, nrof); 00805 } 00806 return; 00807 } else if (to == pl->count) { /* pick it up to the inventory */ 00808 /* return if player has already picked it up */ 00809 if (op->env == pl) 00810 return; 00811 00812 pl->contr->count = nrof; 00813 pick_up(pl, op); 00814 return; 00815 } 00816 /* If not dropped or picked up, we are putting it into a sack */ 00817 if (pl->contr->transport) { 00818 if (can_pick(pl, op) 00819 && transport_can_hold(pl->contr->transport, op, nrof)) { 00820 put_object_in_sack(pl, pl->contr->transport, op, nrof); 00821 } 00822 } else { 00823 env = esrv_get_ob_from_count(pl, to); 00824 if (!env) { 00825 LOG(llevDebug, "Player '%s' tried to move object to the unknown location (%d)\n", pl->name, to); 00826 return; 00827 } 00828 /* put_object_in_sack presumes that necessary sanity checking 00829 * has already been done (eg, it can be picked up and fits in 00830 * in a sack, so check for those things. We should also check 00831 * an make sure env is in fact a container for that matter. 00832 */ 00833 if (env->type == CONTAINER 00834 && can_pick(pl, op) 00835 && sack_can_hold(pl, env, op, nrof)) { 00836 put_object_in_sack(pl, env, op, nrof); 00837 } 00838 } 00839 } 00840 00841 void inscribe_scroll_cmd(char *buf, int len, player *pl) { 00842 object *scroll, *spell, *marked, *inscription, *currentspell; 00843 tag_t tscroll, tspell, tmarked; 00844 char type; 00845 00846 if (len < 1) { 00847 LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name); 00848 return; 00849 } 00850 00851 type = buf[0]; 00852 00853 inscription = find_skill_by_name(pl->ob, "inscription"); 00854 if (!inscription) { 00855 draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You don't know how to write!", NULL); 00856 return; 00857 } 00858 00859 if (type == 0) { 00860 if (len != 9) { 00861 LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name); 00862 return; 00863 } 00864 tscroll = GetInt_String((uint8 *)buf+1); 00865 tspell = GetInt_String((uint8 *)buf+5); 00866 00867 scroll = esrv_get_ob_from_count(pl->ob, tscroll); 00868 if (!scroll) { 00869 LOG(llevDebug, "Player %s sent an invalid scroll for inscribe command.\n", pl->ob->name); 00870 return; 00871 } 00872 00873 spell = esrv_get_ob_from_count(pl->ob, tspell); 00874 if (!spell) { 00875 LOG(llevDebug, "Player %s sent an invalid spell for inscribe command.\n", pl->ob->name); 00876 return; 00877 } 00878 00879 tmarked = pl->mark_count; 00880 marked = pl->mark; 00881 currentspell = pl->ranges[range_magic]; 00882 00883 pl->mark_count = tscroll; 00884 pl->mark = scroll; 00885 pl->ranges[range_magic] = spell; 00886 00887 write_on_item(pl->ob, "", inscription); 00888 00889 pl->mark_count = tmarked; 00890 pl->mark = marked; 00891 pl->ranges[range_magic] = currentspell; 00892 } else { 00893 } 00894 }