|
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 00030 #include <global.h> 00031 00039 object *find_best_object_match(object *pl, char *params) 00040 { 00041 object *tmp, *best = NULL; 00042 int match_val = 0, tmpmatch; 00043 00044 for (tmp = pl->inv; tmp; tmp = tmp->below) 00045 { 00046 if (IS_SYS_INVISIBLE(tmp)) 00047 { 00048 continue; 00049 } 00050 00051 if ((tmpmatch = item_matched_string(pl, tmp, params)) > match_val) 00052 { 00053 match_val = tmpmatch; 00054 best = tmp; 00055 } 00056 } 00057 00058 return best; 00059 } 00060 00061 00067 int command_uskill(object *pl, char *params) 00068 { 00069 if (!params) 00070 { 00071 new_draw_info(0, COLOR_WHITE, pl, "Usage: /use_skill <skill name>"); 00072 return 0; 00073 } 00074 00075 if (pl->type == PLAYER) 00076 { 00077 CONTR(pl)->praying = 0; 00078 } 00079 00080 return use_skill(pl, params); 00081 } 00082 00088 int command_rskill(object *pl, char *params) 00089 { 00090 int skillno; 00091 00092 if (!params) 00093 { 00094 new_draw_info(0, COLOR_WHITE, pl, "Usage: /ready_skill <skill name>"); 00095 return 0; 00096 } 00097 00098 if (pl->type == PLAYER) 00099 { 00100 CONTR(pl)->praying = 0; 00101 } 00102 00103 skillno = lookup_skill_by_name(params); 00104 00105 if (skillno == -1) 00106 { 00107 new_draw_info_format(0, COLOR_WHITE, pl, "Couldn't find the skill %s", params); 00108 return 0; 00109 } 00110 00111 return change_skill(pl, skillno); 00112 } 00113 00120 int command_apply(object *op, char *params) 00121 { 00122 if (op->type == PLAYER) 00123 CONTR(op)->praying = 0; 00124 00125 if (!params) 00126 { 00127 player_apply_below(op); 00128 return 0; 00129 } 00130 else 00131 { 00132 enum apply_flag aflag = 0; 00133 object *inv; 00134 00135 while (*params == ' ') 00136 { 00137 params++; 00138 } 00139 00140 if (!strncmp(params, "-a ", 3)) 00141 { 00142 aflag = AP_APPLY; 00143 params += 3; 00144 } 00145 00146 if (!strncmp(params, "-u ", 3)) 00147 { 00148 aflag = AP_UNAPPLY; 00149 params += 3; 00150 } 00151 00152 while (*params == ' ') 00153 { 00154 params++; 00155 } 00156 00157 inv = find_best_object_match(op, params); 00158 00159 if (inv) 00160 { 00161 player_apply(op, inv, aflag, 0); 00162 } 00163 else 00164 { 00165 new_draw_info_format(0, COLOR_WHITE, op, "Could not find any match to the %s.", params); 00166 } 00167 } 00168 00169 return 0; 00170 } 00171 00180 int sack_can_hold(object *pl, object *sack, object *op, int nrof) 00181 { 00182 char buf[MAX_BUF]; 00183 00184 buf[0] = '\0'; 00185 00186 if (!QUERY_FLAG(sack, FLAG_APPLIED)) 00187 { 00188 snprintf(buf, sizeof(buf), "The %s is not active.", query_name(sack, NULL)); 00189 } 00190 00191 if (sack == op) 00192 { 00193 snprintf(buf, sizeof(buf), "You can't put the %s into itself.", query_name(sack, NULL)); 00194 } 00195 00196 if ((sack->race && (sack->sub_type & 1) != ST1_CONTAINER_CORPSE) && (sack->race != op->race || op->type == CONTAINER || (sack->stats.food && sack->stats.food != op->type))) 00197 { 00198 snprintf(buf, sizeof(buf), "You can put only %s into the %s.", sack->race, query_name(sack, NULL)); 00199 } 00200 00201 if (sack->weight_limit && sack->carrying + (sint32) ((float) (((nrof ? nrof : 1) * op->weight) + op->carrying) * sack->weapon_speed) > (sint32) sack->weight_limit) 00202 { 00203 snprintf(buf, sizeof(buf), "That won't fit in the %s!", query_name(sack, NULL)); 00204 } 00205 00206 if (buf[0]) 00207 { 00208 if (pl) 00209 { 00210 new_draw_info(0, COLOR_WHITE, pl, buf); 00211 } 00212 00213 return 0; 00214 } 00215 00216 return 1; 00217 } 00218 00226 static void pick_up_object(object *pl, object *op, object *tmp, int nrof, int no_mevent) 00227 { 00228 char buf[HUGE_BUF]; 00229 object *env = tmp->env; 00230 int tmp_nrof = tmp->nrof ? tmp->nrof : 1; 00231 00232 if (pl->type == PLAYER) 00233 { 00234 CONTR(pl)->praying = 0; 00235 } 00236 00237 /* IF the player is flying & trying to take the item out of a container 00238 * that is in his inventory, let him. tmp->env points to the container 00239 * (sack, luggage, etc), tmp->env->env then points to the player (nested 00240 * containers not allowed as of now) */ 00241 if (QUERY_FLAG(pl, FLAG_FLYING) && !QUERY_FLAG(pl, FLAG_WIZ) && is_player_inv(tmp) != pl) 00242 { 00243 new_draw_info(0, COLOR_WHITE, pl, "You are levitating, you can't reach the ground!"); 00244 return; 00245 } 00246 00247 if (QUERY_FLAG(tmp, FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) 00248 { 00249 new_draw_info(0, COLOR_WHITE, pl, "The object disappears in a puff of smoke!\nIt must have been an illusion."); 00250 00251 if (pl->type == PLAYER) 00252 { 00253 esrv_del_item(CONTR(pl), tmp->count, tmp->env); 00254 } 00255 00256 if (!QUERY_FLAG(tmp, FLAG_REMOVED)) 00257 { 00258 remove_ob(tmp); 00259 check_walk_off(tmp, NULL, MOVE_APPLY_VANISHED); 00260 } 00261 00262 return; 00263 } 00264 00265 if (nrof > tmp_nrof || nrof == 0) 00266 { 00267 nrof = tmp_nrof; 00268 } 00269 00270 if (!player_can_carry(pl, WEIGHT_NROF(tmp, nrof))) 00271 { 00272 new_draw_info(0, COLOR_WHITE, pl, "That item is too heavy for you to pick up."); 00273 return; 00274 } 00275 00276 if (tmp->type == CONTAINER) 00277 { 00278 container_unlink(NULL, tmp); 00279 } 00280 00281 /* Trigger the PICKUP event */ 00282 if (trigger_event(EVENT_PICKUP, pl, tmp, op, NULL, tmp_nrof, 0, 0, SCRIPT_FIX_ACTIVATOR)) 00283 { 00284 return; 00285 } 00286 00287 /* Trigger the map-wide pick up event. */ 00288 if (!no_mevent && pl->map && pl->map->events && trigger_map_event(MEVENT_PICK, pl->map, pl, tmp, op, NULL, nrof)) 00289 { 00290 return; 00291 } 00292 00293 #ifndef REAL_WIZ 00294 if (QUERY_FLAG(pl, FLAG_WAS_WIZ)) 00295 { 00296 SET_FLAG(tmp, FLAG_WAS_WIZ); 00297 } 00298 #endif 00299 00300 if (pl->type == PLAYER) 00301 { 00302 CONTR(pl)->stat_items_picked++; 00303 } 00304 00305 if (QUERY_FLAG(tmp, FLAG_UNPAID)) 00306 { 00307 /* This is a clone shop - clone an item for inventory */ 00308 if (QUERY_FLAG(tmp, FLAG_NO_PICK)) 00309 { 00310 tmp = object_create_clone(tmp); 00311 CLEAR_FLAG(tmp, FLAG_NO_PICK); 00312 SET_FLAG(tmp, FLAG_STARTEQUIP); 00313 tmp->nrof = nrof; 00314 tmp_nrof = nrof; 00315 snprintf(buf, sizeof(buf), "You pick up %s for %s from the storage.", query_name(tmp, NULL), query_cost_string(tmp, pl, COST_BUY)); 00316 } 00317 /* This is an unique shop item */ 00318 else 00319 { 00320 tmp->nrof = nrof; 00321 snprintf(buf, sizeof(buf), "%s will cost you %s.", query_name(tmp, NULL), query_cost_string(tmp, pl, COST_BUY)); 00322 tmp->nrof = tmp_nrof; 00323 } 00324 } 00325 else 00326 { 00327 tmp->nrof = nrof; 00328 snprintf(buf, sizeof(buf), "You pick up the %s.", query_name(tmp, NULL)); 00329 tmp->nrof = tmp_nrof; 00330 } 00331 00332 if (nrof != tmp_nrof) 00333 { 00334 object *tmp2 = tmp, *tmp2_cont = tmp->env; 00335 tag_t tmp2_tag = tmp2->count; 00336 char err[MAX_BUF]; 00337 tmp = get_split_ob(tmp, nrof, err, sizeof(err)); 00338 00339 if (!tmp) 00340 { 00341 new_draw_info(0, COLOR_WHITE, pl, err); 00342 return; 00343 } 00344 00345 /* Tell the client what happened to rest of the objects */ 00346 if (pl->type == PLAYER) 00347 { 00348 if (was_destroyed(tmp2, tmp2_tag)) 00349 { 00350 esrv_del_item(CONTR(pl), tmp2_tag, tmp2_cont); 00351 } 00352 else 00353 { 00354 esrv_send_item(pl, tmp2); 00355 } 00356 } 00357 } 00358 else 00359 { 00360 /* If the object is in a container, send a delete to the client. 00361 * - we are moving all the items from the container to elsewhere, 00362 * so it needs to be deleted. */ 00363 if (!QUERY_FLAG(tmp, FLAG_REMOVED)) 00364 { 00365 if (tmp->env && pl->type == PLAYER) 00366 { 00367 esrv_del_item (CONTR(pl), tmp->count, tmp->env); 00368 } 00369 00370 /* Unlink it - no move off check */ 00371 remove_ob(tmp); 00372 } 00373 } 00374 00375 new_draw_info(0, COLOR_WHITE, pl, buf); 00376 tmp = insert_ob_in_ob(tmp, op); 00377 00378 /* All the stuff below deals with client/server code, and is only 00379 * usable by players */ 00380 if (pl->type != PLAYER) 00381 { 00382 return; 00383 } 00384 00385 esrv_send_item(pl, tmp); 00386 /* These are needed to update the weight for the container we 00387 * are putting the object in, and the players weight, if different. */ 00388 esrv_update_item(UPD_WEIGHT, pl, op); 00389 00390 if (op != pl) 00391 { 00392 esrv_send_item(pl, pl); 00393 } 00394 00395 /* Update the container the object was in */ 00396 if (env && env != pl && env != op) 00397 { 00398 esrv_update_item(UPD_WEIGHT, pl, env); 00399 } 00400 } 00401 00408 void pick_up(object *op, object *alt, int no_mevent) 00409 { 00410 int need_fix_tmp = 0, count; 00411 object *tmp = NULL; 00412 mapstruct *tmp_map = NULL; 00413 tag_t tag; 00414 00415 /* Decide which object to pick. */ 00416 if (alt) 00417 { 00418 if (!can_pick(op, alt)) 00419 { 00420 new_draw_info_format(0, COLOR_WHITE, op, "You can't pick up %s.", alt->name); 00421 goto leave; 00422 } 00423 00424 tmp = alt; 00425 } 00426 else 00427 { 00428 if (op->below == NULL || !can_pick(op, op->below)) 00429 { 00430 new_draw_info(0, COLOR_WHITE, op, "There is nothing to pick up here."); 00431 goto leave; 00432 } 00433 00434 tmp = op->below; 00435 } 00436 00437 if (tmp->type == CONTAINER) 00438 { 00439 container_unlink(NULL, tmp); 00440 } 00441 00442 /* Try to catch it. */ 00443 tmp_map = tmp->map; 00444 tmp = stop_item(tmp); 00445 00446 if (tmp == NULL) 00447 { 00448 goto leave; 00449 } 00450 00451 need_fix_tmp = 1; 00452 00453 if (!can_pick(op, tmp)) 00454 { 00455 goto leave; 00456 } 00457 00458 if (op->type == PLAYER) 00459 { 00460 count = CONTR(op)->count; 00461 00462 if (count == 0) 00463 { 00464 count = tmp->nrof; 00465 } 00466 } 00467 else 00468 { 00469 count = tmp->nrof; 00470 } 00471 00472 /* Container is open, so use it */ 00473 if (op->type == PLAYER && CONTR(op)->container) 00474 { 00475 alt = CONTR(op)->container; 00476 00477 if (alt != tmp->env && !sack_can_hold(op, alt, tmp, count) && !check_magical_container(tmp, alt)) 00478 { 00479 goto leave; 00480 } 00481 } 00482 /* Con container pickup */ 00483 else 00484 { 00485 for (alt = op->inv; alt; alt = alt->below) 00486 { 00487 if (alt->type == CONTAINER && QUERY_FLAG(alt, FLAG_APPLIED) && alt->race && alt->race == tmp->race && sack_can_hold(NULL, alt, tmp, count) && !check_magical_container(tmp, alt)) 00488 { 00489 /* Perfect match */ 00490 break; 00491 } 00492 } 00493 00494 if (!alt) 00495 { 00496 for (alt = op->inv; alt; alt = alt->below) 00497 { 00498 if (alt->type == CONTAINER && QUERY_FLAG(alt, FLAG_APPLIED) && sack_can_hold(NULL, alt, tmp, count) && !check_magical_container(tmp, alt)) 00499 { 00500 /* General container comes next */ 00501 break; 00502 } 00503 } 00504 } 00505 00506 /* No free containers */ 00507 if (!alt) 00508 { 00509 alt = op; 00510 } 00511 } 00512 00513 if (tmp->env == alt) 00514 { 00515 alt = op; 00516 } 00517 00518 /* Startequip items are not allowed to be put into containers. */ 00519 if (op->type == PLAYER && alt->type == CONTAINER && QUERY_FLAG(tmp, FLAG_STARTEQUIP)) 00520 { 00521 new_draw_info(0, COLOR_WHITE, op, "This object cannot be put into containers!"); 00522 goto leave; 00523 } 00524 00525 tag = tmp->count; 00526 pick_up_object(op, alt, tmp, count, no_mevent); 00527 00528 if (was_destroyed(tmp, tag) || tmp->env) 00529 { 00530 need_fix_tmp = 0; 00531 } 00532 00533 if (op->type == PLAYER) 00534 { 00535 CONTR(op)->count = 0; 00536 } 00537 00538 goto leave; 00539 00540 leave: 00541 if (need_fix_tmp) 00542 { 00543 fix_stopped_item(tmp, tmp_map, op); 00544 } 00545 } 00546 00554 void put_object_in_sack(object *op, object *sack, object *tmp, long nrof) 00555 { 00556 tag_t tmp_tag, tmp2_tag; 00557 object *tmp2, *tmp_cont; 00558 char buf[MAX_BUF]; 00559 int tmp_nrof = tmp->nrof ? tmp->nrof : 1; 00560 00561 if (op->type != PLAYER) 00562 { 00563 LOG(llevDebug, "put_object_in_sack: op not a player.\n"); 00564 return; 00565 } 00566 00567 /* Can't put an object in itself */ 00568 if (sack == tmp) 00569 { 00570 return; 00571 } 00572 00573 if (sack->type != CONTAINER) 00574 { 00575 new_draw_info_format(0, COLOR_WHITE, op, "The %s is not a container.", query_name(sack, NULL)); 00576 return; 00577 } 00578 00579 if (check_magical_container(tmp, sack)) 00580 { 00581 new_draw_info(0, COLOR_WHITE, op, "You can't put a magical container into another magical container."); 00582 return; 00583 } 00584 00585 /* Trigger the map-wide put event. */ 00586 if (op->map && op->map->events && trigger_map_event(MEVENT_PUT, op->map, op, tmp, sack, NULL, nrof)) 00587 { 00588 return; 00589 } 00590 00591 if (tmp->type == CONTAINER) 00592 { 00593 container_unlink(NULL, tmp); 00594 } 00595 00596 if (nrof > tmp_nrof || nrof == 0) 00597 { 00598 nrof = tmp_nrof; 00599 } 00600 00601 if (!sack_can_hold(op, sack, tmp, nrof)) 00602 { 00603 return; 00604 } 00605 00606 if (QUERY_FLAG(tmp, FLAG_APPLIED)) 00607 { 00608 if (apply_special(op, tmp, AP_UNAPPLY | AP_NO_MERGE)) 00609 { 00610 return; 00611 } 00612 } 00613 00614 if (QUERY_FLAG(tmp, FLAG_UNPAID)) 00615 { 00616 /* This is a clone shop - clone an item for inventory */ 00617 if (QUERY_FLAG(tmp, FLAG_NO_PICK)) 00618 { 00619 tmp = object_create_clone(tmp); 00620 CLEAR_FLAG(tmp, FLAG_NO_PICK); 00621 SET_FLAG(tmp, FLAG_STARTEQUIP); 00622 tmp->nrof = nrof; 00623 tmp_nrof = nrof; 00624 new_draw_info_format(0, COLOR_WHITE, op, "You pick up %s for %s from the storage.", query_name(tmp, NULL), query_cost_string(tmp, op, COST_BUY)); 00625 } 00626 /* This is an unique shop item */ 00627 else 00628 { 00629 tmp->nrof = nrof; 00630 new_draw_info_format(0, COLOR_WHITE, op, "%s will cost you %s.", query_name(tmp, NULL), query_cost_string(tmp, op, COST_BUY)); 00631 tmp->nrof = tmp_nrof; 00632 } 00633 } 00634 00635 /* We want to put some portion of the item into the container */ 00636 if (nrof != tmp_nrof) 00637 { 00638 object *tmp2_cont = tmp->env; 00639 char err[MAX_BUF]; 00640 00641 tmp2 = tmp; 00642 tmp2_tag = tmp2->count; 00643 tmp = get_split_ob(tmp, nrof, err, sizeof(err)); 00644 00645 if (!tmp) 00646 { 00647 new_draw_info(0, COLOR_WHITE, op, err); 00648 return; 00649 } 00650 00651 /* Tell the client what happened to the other objects */ 00652 if (was_destroyed(tmp2, tmp2_tag)) 00653 { 00654 esrv_del_item(CONTR(op), tmp2_tag, tmp2_cont); 00655 } 00656 /* This can probably be replaced with an update */ 00657 else 00658 { 00659 esrv_send_item(op, tmp2); 00660 } 00661 } 00662 else 00663 { 00664 /* If the object is in a container, send a delete to the client. 00665 * - we are moving all the items from the container to elsewhere, 00666 * so it needs to be deleted. */ 00667 if (!QUERY_FLAG(tmp, FLAG_REMOVED)) 00668 { 00669 esrv_del_item(CONTR(op), tmp->count, tmp->env); 00670 /* Unlink it - no move off check */ 00671 remove_ob(tmp); 00672 } 00673 } 00674 00675 snprintf(buf, sizeof(buf), "You put the %s in %s.", query_name(tmp, NULL), query_name(sack, NULL)); 00676 tmp_tag = tmp->count; 00677 tmp_cont = tmp->env; 00678 tmp2 = insert_ob_in_ob(tmp, sack); 00679 new_draw_info(0, COLOR_WHITE, op, buf); 00680 /* This is overkill, fix_player() is called somewhere in object.c */ 00681 fix_player(op); 00682 00683 /* If an object merged (and thus, different object), we need to 00684 * delete the original. */ 00685 if (tmp2 != tmp) 00686 { 00687 esrv_del_item(CONTR(op), tmp_tag, tmp_cont); 00688 } 00689 00690 esrv_send_item(op, tmp2); 00691 /* update the sack's and player's weight */ 00692 esrv_update_item(UPD_WEIGHT, op, sack); 00693 esrv_update_item(UPD_WEIGHT, op, op); 00694 } 00695 00702 void drop_object(object *op, object *tmp, long nrof, int no_mevent) 00703 { 00704 object *floor; 00705 00706 if (QUERY_FLAG(tmp, FLAG_NO_DROP) && !QUERY_FLAG(op, FLAG_WIZ)) 00707 { 00708 new_draw_info(0, COLOR_WHITE, op, "You can't drop that item."); 00709 return; 00710 } 00711 00712 /* Trigger the map-wide drop event. */ 00713 if (!no_mevent && op->map && op->map->events && trigger_map_event(MEVENT_DROP, op->map, op, tmp, NULL, NULL, nrof)) 00714 { 00715 return; 00716 } 00717 00718 /* Stop praying. */ 00719 if (op->type == PLAYER) 00720 { 00721 CONTR(op)->praying = 0; 00722 } 00723 00724 if (QUERY_FLAG(tmp, FLAG_APPLIED)) 00725 { 00726 /* Can't unapply it */ 00727 if (apply_special(op, tmp, AP_UNAPPLY | AP_NO_MERGE)) 00728 { 00729 return; 00730 } 00731 } 00732 00733 if (tmp->type == CONTAINER) 00734 { 00735 container_unlink(NULL, tmp); 00736 } 00737 00738 /* Trigger the DROP event */ 00739 if (trigger_event(EVENT_DROP, op, tmp, NULL, NULL, nrof, 0, 0, SCRIPT_FIX_ACTIVATOR)) 00740 { 00741 return; 00742 } 00743 00744 /* We are only dropping some of the items. We split the current 00745 * object off. */ 00746 if (nrof && tmp->nrof != (uint32) nrof) 00747 { 00748 object *tmp2 = tmp, *tmp2_cont = tmp->env; 00749 tag_t tmp2_tag = tmp2->count; 00750 char err[MAX_BUF]; 00751 tmp = get_split_ob(tmp, nrof, err, sizeof(err)); 00752 00753 if (!tmp) 00754 { 00755 new_draw_info(0, COLOR_WHITE, op, err); 00756 return; 00757 } 00758 00759 /* Tell the client what happened to the rest of the objects. tmp2 00760 * is now the original object */ 00761 if (op->type == PLAYER) 00762 { 00763 if (was_destroyed(tmp2, tmp2_tag)) 00764 { 00765 esrv_del_item(CONTR(op), tmp2_tag, tmp2_cont); 00766 } 00767 else 00768 { 00769 esrv_send_item(op, tmp2); 00770 } 00771 } 00772 } 00773 else 00774 { 00775 remove_ob(tmp); 00776 00777 if (check_walk_off(tmp, NULL, MOVE_APPLY_DEFAULT) != CHECK_WALK_OK) 00778 { 00779 return; 00780 } 00781 } 00782 00783 if (op->type == PLAYER) 00784 { 00785 CONTR(op)->stat_items_dropped++; 00786 } 00787 00788 if (QUERY_FLAG(tmp, FLAG_STARTEQUIP) || QUERY_FLAG(tmp, FLAG_UNPAID)) 00789 { 00790 if (op->type == PLAYER) 00791 { 00792 new_draw_info_format(0, COLOR_WHITE, op, "You drop the %s.", query_name(tmp, NULL)); 00793 esrv_del_item(CONTR(op), tmp->count, tmp->env); 00794 00795 if (QUERY_FLAG(tmp, FLAG_UNPAID)) 00796 { 00797 new_draw_info(0, COLOR_WHITE, op, "The shop magic put it back to the storage."); 00798 00799 floor = GET_MAP_OB_LAYER(op->map, op->x, op->y, 0); 00800 00801 /* If the player is standing on a unique shop floor or unique randomitems shop floor, drop the object back to the floor */ 00802 if (floor && floor->type == SHOP_FLOOR && (QUERY_FLAG(floor, FLAG_IS_MAGICAL) || (floor->randomitems && QUERY_FLAG(floor, FLAG_CURSED)))) 00803 { 00804 tmp->x = op->x; 00805 tmp->y = op->y; 00806 insert_ob_in_map(tmp, op->map, op, 0); 00807 } 00808 } 00809 else 00810 { 00811 new_draw_info(0, COLOR_WHITE, op, "The god-given item vanishes to nowhere as you drop it!"); 00812 } 00813 } 00814 00815 fix_player(op); 00816 return; 00817 } 00818 00819 /* If SAVE_INTERVAL is commented out, we never want to save 00820 * the player here. */ 00821 #ifdef SAVE_INTERVAL 00822 if (op->type == PLAYER && !QUERY_FLAG(tmp, FLAG_UNPAID) && (tmp->nrof ? tmp->value * tmp->nrof : tmp->value > 2000) && (CONTR(op)->last_save_time + SAVE_INTERVAL) <= time(NULL)) 00823 { 00824 save_player(op, 1); 00825 CONTR(op)->last_save_time = time(NULL); 00826 } 00827 #endif 00828 00829 floor = GET_MAP_OB_LAYER(op->map, op->x, op->y, 0); 00830 00831 if (floor && floor->type == SHOP_FLOOR && !QUERY_FLAG(tmp, FLAG_UNPAID) && tmp->type != MONEY) 00832 { 00833 sell_item(tmp, op, -1); 00834 00835 /* Ok, we have really sold it - not only dropped. Run this only 00836 * if the floor is not magical (i.e., unique shop) */ 00837 if (QUERY_FLAG(tmp, FLAG_UNPAID) && !QUERY_FLAG(floor, FLAG_IS_MAGICAL)) 00838 { 00839 if (op->type == PLAYER) 00840 { 00841 new_draw_info(0, COLOR_WHITE, op, "The shop magic put it to the storage."); 00842 esrv_del_item(CONTR(op), tmp->count, tmp->env); 00843 } 00844 00845 fix_player(op); 00846 00847 if (op->type == PLAYER) 00848 { 00849 esrv_send_item(op, op); 00850 } 00851 00852 return; 00853 } 00854 } 00855 00856 tmp->x = op->x; 00857 tmp->y = op->y; 00858 00859 if (op->type == PLAYER) 00860 { 00861 esrv_del_item(CONTR(op), tmp->count, tmp->env); 00862 } 00863 00864 insert_ob_in_map(tmp, op->map, op, 0); 00865 00866 SET_FLAG(op, FLAG_NO_APPLY); 00867 remove_ob(op); 00868 insert_ob_in_map(op, op->map, op, INS_NO_MERGE | INS_NO_WALK_ON); 00869 CLEAR_FLAG(op, FLAG_NO_APPLY); 00870 00871 /* Need to update the weight for the player */ 00872 if (op->type == PLAYER) 00873 { 00874 fix_player(op); 00875 esrv_send_item(op, op); 00876 } 00877 } 00878 00884 void drop(object *op, object *tmp, int no_mevent) 00885 { 00886 if (tmp == NULL) 00887 { 00888 new_draw_info(0, COLOR_WHITE, op, "You don't have anything to drop."); 00889 return; 00890 } 00891 00892 if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) 00893 { 00894 new_draw_info(0, COLOR_WHITE, op, "This item is locked."); 00895 return; 00896 } 00897 00898 if (QUERY_FLAG(tmp, FLAG_NO_DROP)) 00899 { 00900 new_draw_info(0, COLOR_WHITE, op, "You can't drop that item."); 00901 return; 00902 } 00903 00904 if (op->type == PLAYER) 00905 { 00906 if (CONTR(op)->container) 00907 { 00908 put_object_in_sack(op, CONTR(op)->container, tmp, CONTR(op)->count); 00909 } 00910 else 00911 { 00912 drop_object(op, tmp, CONTR(op)->count, no_mevent); 00913 } 00914 00915 CONTR(op)->count = 0; 00916 } 00917 else 00918 { 00919 drop_object(op, tmp, 0, no_mevent); 00920 } 00921 } 00922 00928 int command_take(object *op, char *params) 00929 { 00930 object *tmp, *next; 00931 int did_one = 0, missed = 0, ground_total = 0, ival; 00932 00933 if (!params) 00934 { 00935 new_draw_info(0, COLOR_WHITE, op, "Take what?"); 00936 return 0; 00937 } 00938 00939 if (CONTR(op)->container) 00940 { 00941 tmp = CONTR(op)->container->inv; 00942 } 00943 else 00944 { 00945 tmp = GET_MAP_OB_LAST(op->map, op->x, op->y); 00946 } 00947 00948 if (!tmp) 00949 { 00950 new_draw_info(0, COLOR_WHITE, op, "Nothing to take."); 00951 return 0; 00952 } 00953 00954 if (op->map && op->map->events && trigger_map_event(MEVENT_CMD_TAKE, op->map, op, tmp, NULL, params, 0)) 00955 { 00956 return 0; 00957 } 00958 00959 SET_FLAG(op, FLAG_NO_FIX_PLAYER); 00960 00961 for ( ; tmp; tmp = next) 00962 { 00963 next = tmp->below; 00964 00965 if ((tmp->layer != LAYER_ITEM && tmp->layer != LAYER_ITEM2) || QUERY_FLAG(tmp, FLAG_NO_PICK) || IS_SYS_INVISIBLE(tmp)) 00966 { 00967 continue; 00968 } 00969 00970 ival = item_matched_string(op, tmp, params); 00971 00972 if (ival > 0) 00973 { 00974 if (ival <= 2 && !can_pick(op, tmp)) 00975 { 00976 missed++; 00977 } 00978 else 00979 { 00980 pick_up(op, tmp, 1); 00981 did_one = 1; 00982 } 00983 } 00984 00985 /* Keep track how many visible objects are left on the ground. */ 00986 if (!CONTR(op)->container && !tmp->env) 00987 { 00988 if (!(tmp->layer <= LAYER_FMASK || IS_SYS_INVISIBLE(tmp) || (!QUERY_FLAG(op, FLAG_SEE_INVISIBLE) && QUERY_FLAG(tmp, FLAG_IS_INVISIBLE))) || QUERY_FLAG(op, FLAG_WIZ)) 00989 { 00990 ground_total++; 00991 } 00992 } 00993 } 00994 00995 CLEAR_FLAG(op, FLAG_NO_FIX_PLAYER); 00996 00997 if (did_one) 00998 { 00999 int layer; 01000 01001 fix_player(op); 01002 01003 /* Update below inventory positions for all players on this tile. */ 01004 for (layer = LAYER_LIVING; ; layer = LAYER_LIVING + NUM_LAYERS) 01005 { 01006 for (tmp = GET_MAP_OB_LAYER(op->map, op->x, op->y, layer - 1); tmp && tmp->layer == LAYER_LIVING; tmp = tmp->above) 01007 { 01008 /* Ensures the below inventory position is not higher than 01009 * the actual number of visible items on the tile. */ 01010 if (tmp->type == PLAYER && CONTR(tmp) && CONTR(tmp)->socket.look_position > ground_total) 01011 { 01012 /* Update the visible row of objects. */ 01013 CONTR(tmp)->socket.look_position = ((int) (((float) ground_total / NUM_LOOK_OBJECTS) - 0.5f)) * NUM_LOOK_OBJECTS; 01014 } 01015 } 01016 01017 if (layer != LAYER_LIVING) 01018 { 01019 break; 01020 } 01021 } 01022 } 01023 else if (!missed) 01024 { 01025 new_draw_info(0, COLOR_WHITE, op, "Nothing to take."); 01026 } 01027 01028 if (missed == 1) 01029 { 01030 new_draw_info(0, COLOR_WHITE, op, "You were unable to take one of the items."); 01031 } 01032 else if (missed > 1) 01033 { 01034 new_draw_info_format(0, COLOR_WHITE, op, "You were unable to take %d of the items.", missed); 01035 } 01036 01037 if (op->type == PLAYER) 01038 { 01039 CONTR(op)->count = 0; 01040 } 01041 01042 return 0; 01043 } 01044 01050 int command_drop(object *op, char *params) 01051 { 01052 object *tmp, *next; 01053 int did_one = 0, missed = 0, ival; 01054 01055 if (!params) 01056 { 01057 new_draw_info(0, COLOR_WHITE, op, "Drop what?"); 01058 return 0; 01059 } 01060 01061 if (op->map && op->map->events && trigger_map_event(MEVENT_CMD_DROP, op->map, op, NULL, NULL, params, 0)) 01062 { 01063 return 0; 01064 } 01065 01066 SET_FLAG(op, FLAG_NO_FIX_PLAYER); 01067 01068 for (tmp = op->inv; tmp; tmp = next) 01069 { 01070 next = tmp->below; 01071 01072 if (QUERY_FLAG(tmp, FLAG_NO_DROP) || QUERY_FLAG(tmp, FLAG_STARTEQUIP) || IS_SYS_INVISIBLE(tmp)) 01073 { 01074 continue; 01075 } 01076 01077 ival = item_matched_string(op, tmp, params); 01078 01079 if (ival > 0) 01080 { 01081 if (ival <= 2 && QUERY_FLAG(tmp, FLAG_INV_LOCKED)) 01082 { 01083 missed++; 01084 } 01085 else 01086 { 01087 drop(op, tmp, 1); 01088 did_one = 1; 01089 } 01090 } 01091 } 01092 01093 CLEAR_FLAG(op, FLAG_NO_FIX_PLAYER); 01094 01095 if (did_one) 01096 { 01097 fix_player(op); 01098 } 01099 else if (!missed) 01100 { 01101 new_draw_info(0, COLOR_WHITE, op, "Nothing to drop."); 01102 } 01103 01104 if (missed == 1) 01105 { 01106 new_draw_info(0, COLOR_WHITE, op, "One item couldn't be dropped because it was locked."); 01107 } 01108 else if (missed > 1) 01109 { 01110 new_draw_info_format(0, COLOR_WHITE, op, "%d items couldn't be dropped because they were locked.", missed); 01111 } 01112 01113 if (op->type == PLAYER) 01114 { 01115 CONTR(op)->count = 0; 01116 } 01117 01118 return 0; 01119 } 01120 01128 static object *find_marked_object_rec(object *op, object **marked, uint32 *marked_count) 01129 { 01130 object *tmp, *tmp2; 01131 int wiz = QUERY_FLAG(op, FLAG_WIZ); 01132 01133 /* This may seem like overkill, but we need to make sure that they 01134 * player hasn't dropped the item. We use count on the off chance 01135 * that an item got reincarnated at some point. */ 01136 for (tmp = op->inv; tmp; tmp = tmp->below) 01137 { 01138 if (IS_SYS_INVISIBLE(tmp) && !wiz) 01139 { 01140 continue; 01141 } 01142 01143 if (tmp == *marked) 01144 { 01145 if (tmp->count == *marked_count) 01146 { 01147 return tmp; 01148 } 01149 else 01150 { 01151 *marked = NULL; 01152 *marked_count = 0; 01153 return NULL; 01154 } 01155 } 01156 else if (tmp->inv) 01157 { 01158 tmp2 = find_marked_object_rec(tmp, marked, marked_count); 01159 01160 if (tmp2) 01161 { 01162 return tmp2; 01163 } 01164 01165 if (*marked == NULL) 01166 { 01167 return NULL; 01168 } 01169 } 01170 } 01171 01172 return NULL; 01173 } 01174 01179 object *find_marked_object(object *op) 01180 { 01181 if (op->type != PLAYER || !op || !CONTR(op) || !CONTR(op)->mark) 01182 { 01183 return NULL; 01184 } 01185 01186 return find_marked_object_rec(op, &CONTR(op)->mark, &CONTR(op)->mark_count); 01187 } 01188 01193 void examine_living(object *op, object *tmp) 01194 { 01195 object *mon = tmp->head ? tmp->head : tmp; 01196 int val, val2, i, gender; 01197 01198 CONTR(op)->praying = 0; 01199 gender = object_get_gender(mon); 01200 01201 if (QUERY_FLAG(mon, FLAG_IS_GOOD)) 01202 { 01203 new_draw_info_format(0, COLOR_WHITE, op, "%s is a good aligned %s %s.", gender_subjective_upper[gender], gender_noun[gender], mon->race); 01204 } 01205 else if (QUERY_FLAG(mon, FLAG_IS_EVIL)) 01206 { 01207 new_draw_info_format(0, COLOR_WHITE, op, "%s is an evil aligned %s %s.", gender_subjective_upper[gender], gender_noun[gender], mon->race); 01208 } 01209 else if (QUERY_FLAG(mon, FLAG_IS_NEUTRAL)) 01210 { 01211 new_draw_info_format(0, COLOR_WHITE, op, "%s is a neutral aligned %s %s.", gender_subjective_upper[gender], gender_noun[gender], mon->race); 01212 } 01213 else 01214 { 01215 new_draw_info_format(0, COLOR_WHITE, op, "%s is a %s %s.", gender_subjective_upper[gender], gender_noun[gender], mon->race); 01216 } 01217 01218 new_draw_info_format(0, COLOR_WHITE, op, "%s is level %d.", gender_subjective_upper[gender], mon->level); 01219 new_draw_info_format(0, COLOR_WHITE, op, "%s has a base damage of %d and hp of %d.", gender_subjective_upper[gender], mon->stats.dam, mon->stats.maxhp); 01220 new_draw_info_format(0, COLOR_WHITE, op, "%s has a wc of %d and ac of %d.", gender_subjective_upper[gender], mon->stats.wc, mon->stats.ac); 01221 01222 for (val = val2 = -1, i = 0; i < NROFATTACKS; i++) 01223 { 01224 if (mon->protection[i] > 0) 01225 { 01226 val = i; 01227 } 01228 else if (mon->protection[i] < 0) 01229 { 01230 val = i; 01231 } 01232 } 01233 01234 if (val != -1) 01235 { 01236 new_draw_info_format(0, COLOR_WHITE, op, "%s can naturally resist some attacks.", gender_subjective_upper[gender]); 01237 } 01238 01239 if (val2 != -1) 01240 { 01241 new_draw_info_format(0, COLOR_WHITE, op, "%s is naturally vulnerable to some attacks.", gender_subjective_upper[gender]); 01242 } 01243 01244 for (val =- 1, val2 = i = 0; i < NROFATTACKS; i++) 01245 { 01246 if (mon->protection[i] > val2) 01247 { 01248 val = i; 01249 val2 = mon->protection[i]; 01250 } 01251 } 01252 01253 if (val != -1) 01254 { 01255 new_draw_info_format(0, COLOR_WHITE, op, "Best armour protection seems to be for %s.", attack_name[val]); 01256 } 01257 01258 if (QUERY_FLAG(mon, FLAG_UNDEAD)) 01259 { 01260 new_draw_info_format(0, COLOR_WHITE, op, "%s is an undead force.", gender_subjective_upper[gender]); 01261 } 01262 01263 switch ((mon->stats.hp + 1) * 4 / (mon->stats.maxhp + 1)) 01264 { 01265 case 1: 01266 new_draw_info_format(0, COLOR_WHITE, op, "%s is in a bad shape.", gender_subjective_upper[gender]); 01267 break; 01268 01269 case 2: 01270 new_draw_info_format(0, COLOR_WHITE, op, "%s is hurt.", gender_subjective_upper[gender]); 01271 break; 01272 01273 case 3: 01274 new_draw_info_format(0, COLOR_WHITE, op, "%s is somewhat hurt.", gender_subjective_upper[gender]); 01275 break; 01276 01277 default: 01278 new_draw_info_format(0, COLOR_WHITE, op, "%s is in excellent shape.", gender_subjective_upper[gender]); 01279 break; 01280 } 01281 01282 if (present_in_ob(POISONING, mon) != NULL) 01283 { 01284 new_draw_info_format(0, COLOR_WHITE, op, "%s looks very ill.", gender_subjective_upper[gender]); 01285 } 01286 } 01287 01293 char *long_desc(object *tmp, object *caller) 01294 { 01295 static char buf[VERY_BIG_BUF]; 01296 char *cp; 01297 01298 if (tmp == NULL) 01299 { 01300 return ""; 01301 } 01302 01303 buf[0] = '\0'; 01304 01305 switch (tmp->type) 01306 { 01307 case RING: 01308 case SKILL: 01309 case WEAPON: 01310 case ARMOUR: 01311 case BRACERS: 01312 case HELMET: 01313 case SHIELD: 01314 case BOOTS: 01315 case GLOVES: 01316 case AMULET: 01317 case GIRDLE: 01318 case POTION: 01319 case BOW: 01320 case ARROW: 01321 case CLOAK: 01322 case FOOD: 01323 case DRINK: 01324 case HORN: 01325 case WAND: 01326 case ROD: 01327 case FLESH: 01328 case BOOK: 01329 case CONTAINER: 01330 if (*(cp = describe_item(tmp)) != '\0') 01331 { 01332 size_t len; 01333 01334 strncat(buf, query_name(tmp, caller), VERY_BIG_BUF - 1); 01335 01336 buf[VERY_BIG_BUF - 1] = '\0'; 01337 len = strlen(buf); 01338 01339 if (len < VERY_BIG_BUF - 5 && ((tmp->type != AMULET && tmp->type != RING) || tmp->title)) 01340 { 01341 /* Since we know the length, we save a few CPU cycles by using 01342 * it instead of calling strcat */ 01343 strcpy(buf + len, " "); 01344 len++; 01345 strncpy(buf + len, cp, VERY_BIG_BUF - len - 1); 01346 buf[VERY_BIG_BUF - 1] = '\0'; 01347 } 01348 } 01349 01350 break; 01351 } 01352 01353 if (buf[0] == '\0') 01354 { 01355 strncat(buf, query_name(tmp, caller), VERY_BIG_BUF - 1); 01356 buf[VERY_BIG_BUF - 1] = '\0'; 01357 } 01358 01359 return buf; 01360 } 01361 01366 void examine(object *op, object *tmp) 01367 { 01368 char buf[VERY_BIG_BUF], tmp_buf[64]; 01369 int i; 01370 01371 if (tmp == NULL || tmp->type == CLOSE_CON) 01372 { 01373 return; 01374 } 01375 01376 strcpy(buf, "That is "); 01377 strncat(buf, long_desc(tmp, op), VERY_BIG_BUF - strlen(buf) - 1); 01378 buf[VERY_BIG_BUF - 1] = '\0'; 01379 01380 /* Only add this for usable items, not for objects like walls or 01381 * floors for example. */ 01382 if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED) && need_identify(tmp)) 01383 { 01384 strncat(buf, " (unidentified)", VERY_BIG_BUF - strlen(buf) - 1); 01385 } 01386 01387 buf[VERY_BIG_BUF - 1] = '\0'; 01388 new_draw_info(0, COLOR_WHITE, op, buf); 01389 buf[0] = '\0'; 01390 01391 if (tmp->custom_name) 01392 { 01393 new_draw_info_format(0, COLOR_WHITE, op, "You name it %s.", tmp->custom_name); 01394 } 01395 01396 if (QUERY_FLAG(tmp, FLAG_MONSTER) || tmp->type == PLAYER) 01397 { 01398 new_draw_info_format(0, COLOR_WHITE, op, "%s.", describe_item(tmp->head ? tmp->head : tmp)); 01399 examine_living(op, tmp); 01400 } 01401 /* We don't double use the item_xxx arch commands, so they are always valid */ 01402 else if (QUERY_FLAG(tmp, FLAG_IDENTIFIED)) 01403 { 01404 if (QUERY_FLAG(tmp, FLAG_IS_GOOD)) 01405 { 01406 new_draw_info_format(0, COLOR_WHITE, op, "It is good aligned."); 01407 } 01408 else if (QUERY_FLAG(tmp, FLAG_IS_EVIL)) 01409 { 01410 new_draw_info_format(0, COLOR_WHITE, op, "It is evil aligned."); 01411 } 01412 else if (QUERY_FLAG(tmp, FLAG_IS_NEUTRAL)) 01413 { 01414 new_draw_info_format(0, COLOR_WHITE, op, "It is neutral aligned."); 01415 } 01416 01417 if (tmp->item_level) 01418 { 01419 if (tmp->item_skill) 01420 { 01421 new_draw_info_format(0, COLOR_WHITE, op, "It needs a level of %d in %s to use.", tmp->item_level, find_skill_exp_skillname(tmp->item_skill)); 01422 } 01423 else 01424 { 01425 new_draw_info_format(0, COLOR_WHITE, op, "It needs a level of %d to use.", tmp->item_level); 01426 } 01427 } 01428 01429 if (tmp->item_quality) 01430 { 01431 if (QUERY_FLAG(tmp, FLAG_INDESTRUCTIBLE)) 01432 { 01433 new_draw_info_format(0, COLOR_WHITE, op, "Qua: %d Con: Indestructible.", tmp->item_quality); 01434 } 01435 else 01436 { 01437 new_draw_info_format(0, COLOR_WHITE, op, "Qua: %d Con: %d.", tmp->item_quality, tmp->item_condition); 01438 } 01439 } 01440 01441 buf[0] = '\0'; 01442 } 01443 01444 switch (tmp->type) 01445 { 01446 case SPELLBOOK: 01447 if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) && tmp->stats.sp >= 0 && tmp->stats.sp <= NROFREALSPELLS) 01448 { 01449 if (tmp->sub_type == ST1_SPELLBOOK_CLERIC) 01450 { 01451 snprintf(buf, sizeof(buf), "%s is a %d level prayer.", spells[tmp->stats.sp].name, spells[tmp->stats.sp].level); 01452 } 01453 else 01454 { 01455 snprintf(buf, sizeof(buf), "%s is a %d level spell.", spells[tmp->stats.sp].name, spells[tmp->stats.sp].level); 01456 } 01457 } 01458 01459 break; 01460 01461 case BOOK: 01462 if (tmp->msg) 01463 { 01464 strcpy(buf, "Something is written in it."); 01465 01466 if (op->type == PLAYER && !QUERY_FLAG(tmp, FLAG_NO_SKILL_IDENT)) 01467 { 01468 int level = CONTR(op)->skill_ptr[SK_LITERACY]->level; 01469 01470 new_draw_info(0, COLOR_WHITE, op, buf); 01471 01472 /* Gray. */ 01473 if (tmp->level < level_color[level].green) 01474 { 01475 strcpy(buf, "It seems to contain no knowledge you could learn from."); 01476 } 01477 /* Green. */ 01478 else if (tmp->level < level_color[level].blue) 01479 { 01480 strcpy(buf, "It seems to contain tiny bits of knowledge you could learn from."); 01481 } 01482 /* Blue. */ 01483 else if (tmp->level < level_color[level].yellow) 01484 { 01485 strcpy(buf, "It seems to contain a small amount of knowledge you could learn from."); 01486 } 01487 /* Yellow. */ 01488 else if (tmp->level < level_color[level].orange) 01489 { 01490 strcpy(buf, "It seems to contain an average amount of knowledge you could learn from."); 01491 } 01492 /* Orange. */ 01493 else if (tmp->level < level_color[level].red) 01494 { 01495 strcpy(buf, "It seems to contain a moderate amount of knowledge you could learn from."); 01496 } 01497 /* Red. */ 01498 else if (tmp->level < level_color[level].purple) 01499 { 01500 strcpy(buf, "It seems to contain a fair amount of knowledge you could learn from."); 01501 } 01502 /* Purple. */ 01503 else 01504 { 01505 strcpy(buf, "It seems to contain a great amount of knowledge you could learn from."); 01506 } 01507 } 01508 } 01509 01510 break; 01511 01512 case CONTAINER: 01513 if (QUERY_FLAG(tmp, FLAG_IDENTIFIED)) 01514 { 01515 if (tmp->race != NULL) 01516 { 01517 if (tmp->weight_limit) 01518 { 01519 snprintf(buf, sizeof(buf), "It can hold only %s and its weight limit is %.1f kg.", tmp->race, (float) tmp->weight_limit / 1000.0f); 01520 } 01521 else 01522 { 01523 snprintf(buf, sizeof(buf), "It can hold only %s.", tmp->race); 01524 } 01525 01526 /* Has magic modifier? */ 01527 if (tmp->weapon_speed != 1.0f) 01528 { 01529 new_draw_info(0, COLOR_WHITE, op, buf); 01530 01531 /* Bad */ 01532 if (tmp->weapon_speed > 1.0f) 01533 { 01534 snprintf(buf, sizeof(buf), "It increases the weight of items inside by %.1f%%.", tmp->weapon_speed * 100.0f); 01535 } 01536 /* Good */ 01537 else 01538 { 01539 snprintf(buf, sizeof(buf), "It decreases the weight of items inside by %.1f%%.", 100.0f - (tmp->weapon_speed * 100.0f)); 01540 } 01541 } 01542 } 01543 else 01544 { 01545 if (tmp->weight_limit) 01546 { 01547 snprintf(buf, sizeof(buf), "Its weight limit is %.1f kg.", (float)tmp->weight_limit / 1000.0f); 01548 } 01549 01550 /* Has magic modifier? */ 01551 if (tmp->weapon_speed != 1.0f) 01552 { 01553 new_draw_info(0, COLOR_WHITE, op, buf); 01554 01555 /* Bad */ 01556 if (tmp->weapon_speed > 1.0f) 01557 { 01558 snprintf(buf, sizeof(buf), "It increases the weight of items inside by %.1f%%.", tmp->weapon_speed * 100.0f); 01559 } 01560 /* Good */ 01561 else 01562 { 01563 snprintf(buf, sizeof(buf), "It decreases the weight of items inside by %.1f%%.", 100.0f - (tmp->weapon_speed * 100.0f)); 01564 } 01565 } 01566 } 01567 01568 new_draw_info(0, COLOR_WHITE, op, buf); 01569 01570 if (tmp->weapon_speed == 1.0f) 01571 { 01572 snprintf(buf, sizeof(buf), "It contains %3.3f kg.", (float) tmp->carrying / 1000.0f); 01573 } 01574 else if (tmp->weapon_speed > 1.0f) 01575 { 01576 snprintf(buf, sizeof(buf), "It contains %3.3f kg, increased to %3.3f kg.", (float) tmp->damage_round_tag / 1000.0f, (float) tmp->carrying / 1000.0f); 01577 } 01578 else 01579 { 01580 snprintf(buf, sizeof(buf), "It contains %3.3f kg, decreased to %3.3f kg.", (float) tmp->damage_round_tag / 1000.0f, (float) tmp->carrying / 1000.0f); 01581 } 01582 } 01583 01584 break; 01585 01586 case WAND: 01587 if (QUERY_FLAG(tmp, FLAG_IDENTIFIED)) 01588 { 01589 snprintf(buf, sizeof(buf), "It has %d charges left.", tmp->stats.food); 01590 } 01591 01592 break; 01593 01594 case POWER_CRYSTAL: 01595 /* Avoid division by zero... */ 01596 if (tmp->stats.maxsp == 0) 01597 { 01598 snprintf(buf, sizeof(buf), "It has capacity of %d.", tmp->stats.maxsp); 01599 } 01600 else 01601 { 01602 /* Higher capacity crystals */ 01603 if (tmp->stats.maxsp > 1000) 01604 { 01605 i = (tmp->stats.maxsp % 1000) / 100; 01606 01607 if (i) 01608 { 01609 snprintf(tmp_buf, sizeof(tmp_buf), "It has capacity of %d.%dk and is ", tmp->stats.maxsp / 1000, i); 01610 } 01611 else 01612 { 01613 snprintf(tmp_buf, sizeof(tmp_buf), "It has capacity of %dk and is ", tmp->stats.maxsp / 1000); 01614 } 01615 } 01616 else 01617 { 01618 snprintf(tmp_buf, sizeof(tmp_buf), "It has capacity of %d and is ", tmp->stats.maxsp); 01619 } 01620 01621 strcat(buf, tmp_buf); 01622 i = (tmp->stats.sp * 10) / tmp->stats.maxsp; 01623 01624 if (tmp->stats.sp == 0) 01625 { 01626 strcat(buf, "empty."); 01627 } 01628 else if (i == 0) 01629 { 01630 strcat(buf, "almost empty."); 01631 } 01632 else if (i < 3) 01633 { 01634 strcat(buf, "partially filled."); 01635 } 01636 else if (i < 6) 01637 { 01638 strcat(buf, "half full."); 01639 } 01640 else if (i < 9) 01641 { 01642 strcat(buf, "well charged."); 01643 } 01644 else if (tmp->stats.sp == tmp->stats.maxsp) 01645 { 01646 strcat(buf, "fully charged."); 01647 } 01648 else 01649 { 01650 strcat(buf, "almost full."); 01651 } 01652 } 01653 01654 break; 01655 } 01656 01657 if (buf[0] != '\0') 01658 { 01659 new_draw_info(0, COLOR_WHITE, op, buf); 01660 } 01661 01662 if (tmp->material && (need_identify(tmp) && QUERY_FLAG(tmp, FLAG_IDENTIFIED))) 01663 { 01664 strcpy(buf, "It is made of: "); 01665 01666 for (i = 0; i < NROFMATERIALS; i++) 01667 { 01668 if (tmp->material & (1 << i)) 01669 { 01670 strcat(buf, materials[i].name); 01671 strcat(buf, " "); 01672 } 01673 } 01674 01675 new_draw_info(0, COLOR_WHITE, op, buf); 01676 } 01677 01678 if (tmp->weight) 01679 { 01680 float weight = (float) (tmp->nrof ? tmp->weight * (int) tmp->nrof : tmp->weight) / 1000.0f; 01681 01682 if (tmp->type == MONSTER) 01683 { 01684 new_draw_info_format(0, COLOR_WHITE, op, "%s weighs %3.3f kg.", gender_subjective_upper[object_get_gender(tmp)], weight); 01685 } 01686 else if (tmp->type == PLAYER) 01687 { 01688 new_draw_info_format(0, COLOR_WHITE, op, "%s weighs %3.3f kg and is carrying %3.3f kg.", gender_subjective_upper[object_get_gender(tmp)], weight, (float) tmp->carrying / 1000.0f); 01689 } 01690 else 01691 { 01692 new_draw_info_format(0, COLOR_WHITE, op, tmp->nrof > 1 ? "They weigh %3.3f kg." : "It weighs %3.3f kg.", weight); 01693 } 01694 } 01695 01696 if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) 01697 { 01698 /* Unpaid clone shop item */ 01699 if (QUERY_FLAG(tmp, FLAG_UNPAID)) 01700 { 01701 new_draw_info_format(0, COLOR_WHITE, op, "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", query_cost_string(tmp, op, COST_BUY)); 01702 } 01703 /* God-given item */ 01704 else 01705 { 01706 new_draw_info_format(0, COLOR_WHITE, op, "%s god-given item%s.", tmp->nrof > 1 ? "They are" : "It is a", tmp->nrof > 1 ? "s" : ""); 01707 01708 if (QUERY_FLAG(tmp, FLAG_IDENTIFIED)) 01709 { 01710 if (tmp->value) 01711 { 01712 new_draw_info_format(0, COLOR_WHITE, op, "But %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", query_cost_string(tmp, op, COST_TRUE)); 01713 } 01714 else 01715 { 01716 new_draw_info_format(0, COLOR_WHITE, op, "%s worthless.", tmp->nrof > 1 ? "They are" : "It is"); 01717 } 01718 } 01719 } 01720 } 01721 else if (tmp->value && !IS_LIVE(tmp)) 01722 { 01723 if (QUERY_FLAG(tmp, FLAG_IDENTIFIED)) 01724 { 01725 if (QUERY_FLAG(tmp, FLAG_UNPAID)) 01726 { 01727 new_draw_info_format(0, COLOR_WHITE, op, "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", query_cost_string(tmp, op, COST_BUY)); 01728 } 01729 else 01730 { 01731 new_draw_info_format(0, COLOR_WHITE, op, "%s worth %s.", tmp->nrof > 1 ? "They are" : "It is", query_cost_string(tmp, op, COST_TRUE)); 01732 goto dirty_little_jump1; 01733 } 01734 } 01735 else 01736 { 01737 object *floor; 01738 dirty_little_jump1: 01739 01740 floor = GET_MAP_OB_LAYER(op->map, op->x, op->y, 0); 01741 01742 if (floor && floor->type == SHOP_FLOOR && tmp->type != MONEY) 01743 { 01744 /* Used for SK_BARGAINING modification */ 01745 int charisma = op->stats.Cha; 01746 01747 /* This skill gives us a charisma boost */ 01748 if (find_skill(op, SK_BARGAINING)) 01749 { 01750 charisma += 4; 01751 01752 if (charisma > MAX_STAT) 01753 { 01754 charisma = MAX_STAT; 01755 } 01756 } 01757 01758 new_draw_info_format(0, COLOR_WHITE, op, "This shop will pay you %s (%0.1f%%).", query_cost_string(tmp, op, COST_SELL), 20.0f + 100.0f * cha_bonus[charisma]); 01759 } 01760 } 01761 } 01762 else if (!IS_LIVE(tmp)) 01763 { 01764 if (QUERY_FLAG(tmp, FLAG_IDENTIFIED)) 01765 { 01766 if (QUERY_FLAG(tmp, FLAG_UNPAID)) 01767 { 01768 new_draw_info_format(0, COLOR_WHITE, op, "%s would cost nothing.", tmp->nrof > 1 ? "They" : "It"); 01769 } 01770 else 01771 { 01772 new_draw_info_format(0, COLOR_WHITE, op, "%s worthless.", tmp->nrof > 1 ? "They are" : "It is"); 01773 } 01774 } 01775 } 01776 01777 /* Does the object have a message? Don't show message for all object 01778 * types - especially if the first entry is a match */ 01779 if (tmp->msg && tmp->type != EXIT && tmp->type != BOOK && tmp->type != CORPSE && !QUERY_FLAG(tmp, FLAG_WALK_ON) && strncasecmp(tmp->msg, "@match", 7)) 01780 { 01781 /* This is just a hack so when identifying the items, we print 01782 * out the extra message */ 01783 if ((need_identify(tmp) || QUERY_FLAG(tmp, FLAG_QUEST_ITEM)) && QUERY_FLAG(tmp, FLAG_IDENTIFIED)) 01784 { 01785 new_draw_info(0, COLOR_WHITE, op, "The object has a story:"); 01786 new_draw_info(0, COLOR_WHITE, op, tmp->msg); 01787 } 01788 } 01789 01790 trigger_map_event(MEVENT_EXAMINE, op->map, op, tmp, NULL, NULL, 0); 01791 01792 /* Blank line */ 01793 new_draw_info(0, COLOR_WHITE, op, " "); 01794 01795 if (QUERY_FLAG(op, FLAG_WIZ)) 01796 { 01797 StringBuffer *sb = stringbuffer_new(); 01798 char *diff; 01799 01800 stringbuffer_append_printf(sb, "count %d\n", tmp->count); 01801 dump_object(tmp, sb); 01802 diff = stringbuffer_finish(sb); 01803 new_draw_info(0, COLOR_WHITE, op, diff); 01804 free(diff); 01805 } 01806 } 01807 01813 int command_rename_item(object *op, char *params) 01814 { 01815 object *tmp = find_marked_object(op), *merged, *cont; 01816 tag_t del_tag; 01817 01818 if (!tmp) 01819 { 01820 new_draw_info(0, COLOR_WHITE, op, "No marked item to rename."); 01821 return 1; 01822 } 01823 01824 /* Will also clear unprintable chars. */ 01825 params = cleanup_chat_string(params); 01826 01827 /* Clear custom name. */ 01828 if (!params) 01829 { 01830 if (!tmp->custom_name) 01831 { 01832 new_draw_info(0, COLOR_WHITE, op, "This item has no custom name."); 01833 return 1; 01834 } 01835 01836 FREE_AND_CLEAR_HASH(tmp->custom_name); 01837 new_draw_info_format(0, COLOR_WHITE, op, "You stop calling your %s with weird names.", query_base_name(tmp, NULL)); 01838 } 01839 else 01840 { 01841 if (tmp->type == MONEY) 01842 { 01843 new_draw_info(0, COLOR_WHITE, op, "You cannot rename that item."); 01844 return 1; 01845 } 01846 01847 if (strlen(params) > 127) 01848 { 01849 new_draw_info(0, COLOR_WHITE, op, "New name is too long, maximum is 127 characters."); 01850 return 1; 01851 } 01852 01853 if (tmp->custom_name && !strcmp(tmp->custom_name, params)) 01854 { 01855 new_draw_info_format(0, COLOR_WHITE, op, "You keep calling your %s %s.", query_base_name(tmp, NULL), tmp->custom_name); 01856 return 1; 01857 } 01858 01859 string_remove_markup(params); 01860 /* Set custom name. */ 01861 FREE_AND_COPY_HASH(tmp->custom_name, params); 01862 new_draw_info_format(0, COLOR_WHITE, op, "Your %s will now be called %s.", query_base_name(tmp, NULL), tmp->custom_name); 01863 CONTR(op)->stat_renamed_items++; 01864 } 01865 01866 del_tag = tmp->count; 01867 cont = tmp->env; 01868 merged = merge_ob(tmp, NULL); 01869 01870 /* It was merged. */ 01871 if (merged) 01872 { 01873 esrv_del_item(CONTR(op), del_tag, cont); 01874 tmp = merged; 01875 } 01876 01877 esrv_send_item(op, tmp); 01878 return 1; 01879 }
1.7.4