ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
(Generate patch)

Comparing deliantra/server/server/c_object.C (file contents):
Revision 1.89 by elmex, Mon Jan 12 00:17:23 2009 UTC vs.
Revision 1.105 by root, Tue Nov 10 16:29:20 2009 UTC

3 * 3 *
4 * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team 4 * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team 5 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992,2007 Frank Tore Johansen 6 * Copyright (©) 1992,2007 Frank Tore Johansen
7 * 7 *
8 * Deliantra is free software: you can redistribute it and/or modify 8 * Deliantra is free software: you can redistribute it and/or modify it under
9 * it under the terms of the GNU General Public License as published by 9 * the terms of the Affero GNU General Public License as published by the
10 * the Free Software Foundation, either version 3 of the License, or 10 * Free Software Foundation, either version 3 of the License, or (at your
11 * (at your option) any later version. 11 * option) any later version.
12 * 12 *
13 * This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details. 16 * GNU General Public License for more details.
17 * 17 *
18 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the Affero GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 * and the GNU General Public License along with this program. If not, see
20 * <http://www.gnu.org/licenses/>.
20 * 21 *
21 * The authors can be reached via e-mail to <support@deliantra.net> 22 * The authors can be reached via e-mail to <support@deliantra.net>
22 */ 23 */
23 24
24/* 25/*
28#include <global.h> 29#include <global.h>
29#include <loader.h> 30#include <loader.h>
30#include <skills.h> 31#include <skills.h>
31#include <sproto.h> 32#include <sproto.h>
32#include <living.h> 33#include <living.h>
33#include <math.h>
34 34
35/* 35/*
36 * Object id parsing functions 36 * Object id parsing functions
37 */ 37 */
38 38
361 count = tmp->nrof; 361 count = tmp->nrof;
362 362
363 /* container is open, so use it */ 363 /* container is open, so use it */
364 if (tmp->flag [FLAG_STARTEQUIP]) 364 if (tmp->flag [FLAG_STARTEQUIP])
365 alt = op; 365 alt = op;
366 else if (op->container) 366 else if ((alt = op->container_ ()))
367 { 367 {
368 alt = op->container;
369 if (alt != tmp->env && !sack_can_hold (op, alt, tmp, count)) 368 if (alt != tmp->env && !sack_can_hold (op, alt, tmp, count))
370 goto leave; 369 goto leave;
371 } 370 }
372 else 371 else
373 { /* non container pickup */ 372 { /* non container pickup */
427int 426int
428command_take (object *op, char *params) 427command_take (object *op, char *params)
429{ 428{
430 object *tmp, *next; 429 object *tmp, *next;
431 430
432 if (op->container) 431 if (op->container_ ())
433 tmp = op->container->inv; 432 tmp = op->container_ ()->inv;
434 else 433 else
435 { 434 {
436 tmp = op->above; 435 tmp = op->above;
437 if (tmp) 436 if (tmp)
438 while (tmp->above) 437 while (tmp->above)
450 449
451 /* Makes processing easier */ 450 /* Makes processing easier */
452 if (params && *params == '\0') 451 if (params && *params == '\0')
453 params = 0; 452 params = 0;
454 453
455 int cnt = MAX_ITEM_PER_DROP; 454 int cnt = MAX_ITEM_PER_ACTION;
456 455
457 while (tmp) 456 while (tmp)
458 { 457 {
459 next = tmp->below; 458 next = tmp->below;
460 459
520 char buf[MAX_BUF]; 519 char buf[MAX_BUF];
521 520
522 if (sack == tmp) 521 if (sack == tmp)
523 return; /* Can't put an object in itself */ 522 return; /* Can't put an object in itself */
524 523
525 if (QUERY_FLAG (tmp, FLAG_STARTEQUIP)) 524 if (QUERY_FLAG (tmp, FLAG_STARTEQUIP) || QUERY_FLAG (tmp, FLAG_NO_DROP))
526 { 525 {
527 new_draw_info_format (NDI_UNIQUE, 0, op, "You cannot put the %s in the %s.", query_name (tmp), query_name (sack)); 526 new_draw_info_format (NDI_UNIQUE, 0, op, "You cannot put the %s in the %s.", query_name (tmp), query_name (sack));
528 return; 527 return;
529 } 528 }
530 529
539 538
540 for (tmp2 = tmp->inv; tmp2; tmp2 = tmp) 539 for (tmp2 = tmp->inv; tmp2; tmp2 = tmp)
541 { 540 {
542 tmp = tmp2->below; 541 tmp = tmp2->below;
543 542
544 if ((sack->type == CONTAINER && sack_can_hold (op, op->container, tmp2, tmp2->nrof))) 543 if ((sack->type == CONTAINER && sack_can_hold (op, op->container_ (), tmp2, tmp2->nrof)))
545 put_object_in_sack (op, sack, tmp2, 0); 544 put_object_in_sack (op, sack, tmp2, 0);
546 else 545 else
547 { 546 {
548 sprintf (buf, "Your %s fills up.", query_name (sack)); 547 sprintf (buf, "Your %s fills up.", query_name (sack));
549 new_draw_info (NDI_UNIQUE, 0, op, buf); 548 new_draw_info (NDI_UNIQUE, 0, op, buf);
568 if (!can_split (op, tmp, nrof)) 567 if (!can_split (op, tmp, nrof))
569 return; 568 return;
570 569
571 new_draw_info_format (NDI_UNIQUE, 0, op, "You put the %s in %s.", query_name (tmp), query_name (sack)); 570 new_draw_info_format (NDI_UNIQUE, 0, op, "You put the %s in %s.", query_name (tmp), query_name (sack));
572 sack->insert (tmp); 571 sack->insert (tmp);
573}
574
575/*
576 * This function was part of drop, now is own function.
577 * Player 'op' tries to drop object 'tmp', if tmp is non zero, then
578 * nrof objects is tried to dropped.
579 * This is used when dropping objects onto the floor.
580 */
581void
582drop_object (object *op, object *tmp, uint32 nrof)
583{
584 if (QUERY_FLAG (tmp, FLAG_NO_DROP))
585 return;
586
587 if (QUERY_FLAG (tmp, FLAG_APPLIED))
588 if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE))
589 return; /* can't unapply it */
590
591 //fprintf (stderr, "ui, on space is %ld\n", op->ms ().volume ());//D
592
593 /* We are only dropping some of the items. We split the current object
594 * off
595 */
596 if (!can_split (op, tmp, nrof))
597 return;
598
599 drop_object (op, tmp);
600
601 if (!tmp->destroyed () && !tmp->is_inserted ())
602 {
603 // if nothing happened with the object we give it back
604 op->insert (tmp);
605 }
606} 572}
607 573
608/* In contrast to drop_object (op, tmp, nrof) above this function takes the 574/* In contrast to drop_object (op, tmp, nrof) above this function takes the
609 * already split off object, and feeds it to the event handlers and does 575 * already split off object, and feeds it to the event handlers and does
610 * other magic with it. 576 * other magic with it.
613 * object that was dropped. 579 * object that was dropped.
614 * 580 *
615 * Make sure to check what happened with <obj> after this function returns! 581 * Make sure to check what happened with <obj> after this function returns!
616 * Otherwise you may leak this object. 582 * Otherwise you may leak this object.
617 */ 583 */
618
619void 584void
620drop_object (object *dropper, object *obj) 585drop_object (object *dropper, object *obj)
621{ 586{
622 if (INVOKE_OBJECT (DROP, obj, ARG_OBJECT (dropper))) 587 if (INVOKE_OBJECT (DROP, obj, ARG_OBJECT (dropper)))
623 return; 588 return;
646 611
647 if (is_in_shop (dropper) && !QUERY_FLAG (obj, FLAG_UNPAID) && obj->type != MONEY) 612 if (is_in_shop (dropper) && !QUERY_FLAG (obj, FLAG_UNPAID) && obj->type != MONEY)
648 if (!sell_item (obj, dropper)) 613 if (!sell_item (obj, dropper))
649 return; 614 return;
650 615
616 if (!obj->can_drop_at (dropper->map, dropper->x, dropper->y, dropper))
617 return;
618
651 /* If nothing special happened with this object, the default action is to 619 /* If nothing special happened with this object, the default action is to
652 * insert it below the dropper: 620 * insert it below the dropper:
653 */ 621 */
654 622
655 obj->x = dropper->x; 623 obj->x = dropper->x;
656 obj->y = dropper->y; 624 obj->y = dropper->y;
657 625
658 insert_ob_in_map (obj, dropper->map, dropper, INS_BELOW_ORIGINATOR); 626 insert_ob_in_map (obj, dropper->map, dropper, INS_BELOW_ORIGINATOR);
627}
628
629/*
630 * This function was part of drop, now is own function.
631 * Player 'op' tries to drop object 'tmp', if tmp is non zero, then
632 * nrof objects are tried to drop.
633 * This is used when dropping objects onto the floor.
634 */
635void
636drop_object (object *op, object *tmp, uint32 nrof)
637{
638 if (QUERY_FLAG (tmp, FLAG_NO_DROP))
639 return;
640
641 if (QUERY_FLAG (tmp, FLAG_APPLIED))
642 if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE))
643 return; /* can't unapply it */
644
645 /* We are only dropping some of the items. We split the current object
646 * off
647 */
648 if (!can_split (op, tmp, nrof))
649 return;
650
651 drop_object (op, tmp);
652
653 if (!tmp->destroyed () && !tmp->is_inserted ())
654 {
655 // if nothing happened with the object we give it back
656 op->insert (tmp);
657 }
659} 658}
660 659
661void 660void
662drop (object *op, object *tmp) 661drop (object *op, object *tmp)
663{ 662{
676 */ 675 */
677 tmp->destroy (); 676 tmp->destroy ();
678 return; 677 return;
679 } 678 }
680 else 679 else
681 {
682 while (tmp && tmp->invisible) 680 while (tmp && tmp->invisible)
683 tmp = tmp->below; 681 tmp = tmp->below;
684 }
685 } 682 }
686 683
687 if (tmp == NULL) 684 if (!tmp)
688 { 685 {
689 new_draw_info (NDI_UNIQUE, 0, op, "You don't have anything to drop."); 686 new_draw_info (NDI_UNIQUE, 0, op, "You don't have anything to drop.");
690 return; 687 return;
691 } 688 }
692 689
706 } 703 }
707 704
708 if (op->type == PLAYER && op->contr->last_used == tmp) 705 if (op->type == PLAYER && op->contr->last_used == tmp)
709 op->contr->last_used = tmp->below ? tmp->below 706 op->contr->last_used = tmp->below ? tmp->below
710 : tmp->above ? tmp->above 707 : tmp->above ? tmp->above
711 : 0; 708 : (object *)0;
712 709
713 if (op->container) 710 if (op->container_ ())
714 { 711 {
715 if (op->type == PLAYER) 712 if (op->type == PLAYER)
716 put_object_in_sack (op, op->container, tmp, op->contr->count); 713 put_object_in_sack (op, op->container_ (), tmp, op->contr->count);
717 else 714 else
718 put_object_in_sack (op, op->container, tmp, 0); 715 put_object_in_sack (op, op->container_ (), tmp, 0);
719 } 716 }
720 else 717 else
721 { 718 {
722 if (op->type == PLAYER) 719 if (op->type == PLAYER)
723 drop_object (op, tmp, op->contr->count); 720 drop_object (op, tmp, op->contr->count);
750 /* 747 /*
751 Care must be taken that the next item pointer is not to money as 748 Care must be taken that the next item pointer is not to money as
752 the drop() routine will do unknown things to it when dropping 749 the drop() routine will do unknown things to it when dropping
753 in a shop. --Tero.Pelander@utu.fi 750 in a shop. --Tero.Pelander@utu.fi
754 */ 751 */
755
756 int cnt = MAX_ITEM_PER_DROP; 752 int cnt = MAX_ITEM_PER_ACTION;
757 753
758 if (!params) 754 if (!params)
759 { 755 {
760 while (curinv) 756 while (curinv)
761 { 757 {
762 nextinv = curinv->below; 758 nextinv = curinv->below;
763 759
764 while (nextinv && nextinv->type == MONEY) 760 while (nextinv && nextinv->type == MONEY)
765 nextinv = nextinv->below; 761 nextinv = nextinv->below;
766 762
767 if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && curinv->type != MONEY && 763 if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED)
768 curinv->type != FOOD && curinv->type != KEY && 764 && curinv->type != MONEY
769 curinv->type != SPECIAL_KEY && curinv->type != GEM && 765 && curinv->type != FOOD
766 && curinv->type != KEY
767 && curinv->type != SPECIAL_KEY
768 && curinv->type != GEM
769 && !curinv->invisible
770 !curinv->invisible && (curinv->type != CONTAINER || op->container != curinv)) 770 && (curinv->type != CONTAINER || op->container_ () != curinv))
771 { 771 {
772 drop (op, curinv); 772 drop (op, curinv);
773 if (--cnt <= 0) break; 773 if (--cnt <= 0) break;
774 } 774 }
775 775
869 * <cnt> can be a 0 pointer or a pointer to the maximum number of 869 * <cnt> can be a 0 pointer or a pointer to the maximum number of
870 * drop operations to perform. 870 * drop operations to perform.
871 * 871 *
872 * Returns true if at least one item was dropped. 872 * Returns true if at least one item was dropped.
873 */ 873 */
874bool 874static bool
875drop_vector (object *dropper, vector<object *> &objs, int *cnt) 875drop_vector (object *dropper, vector<object *> &objs, int *cnt)
876{ 876{
877 vector<object *>::iterator i; 877 vector<object *>::iterator i;
878 878
879 bool did_one = false; 879 bool did_one = false;
914 914
915 if (item_matched_string (op, tmp, params)) 915 if (item_matched_string (op, tmp, params))
916 matched_objs.push_back (tmp); 916 matched_objs.push_back (tmp);
917 } 917 }
918 918
919 int cnt = MAX_ITEM_PER_DROP; 919 int cnt = MAX_ITEM_PER_ACTION;
920 920
921 if (!drop_vector (op, matched_objs, &cnt)) 921 if (!drop_vector (op, matched_objs, &cnt))
922 new_draw_info (NDI_UNIQUE, 0, op, "Nothing to drop."); 922 new_draw_info (NDI_UNIQUE, 0, op, "Nothing to drop.");
923 923
924 if (cnt <= 0) 924 if (cnt <= 0)
1103examine_monster (object *op, object *tmp) 1103examine_monster (object *op, object *tmp)
1104{ 1104{
1105 new_draw_info (NDI_UNIQUE, 0, op, tmp->describe_monster (op).c_str ()); 1105 new_draw_info (NDI_UNIQUE, 0, op, tmp->describe_monster (op).c_str ());
1106} 1106}
1107 1107
1108static void
1109describe_dump_object (dynbuf &buf, object *ob)
1110{
1111 char *txt = dump_object (ob);
1112 for (char *p = txt; *p; ++p) if (*p == '\n') *p = '\r';
1113 buf << "\n" << txt << "\n";
1114
1115 if (!ob->is_arch ())
1116 describe_dump_object (buf, ob->arch);
1117}
1118
1108std::string 1119std::string
1109object::describe (object *who) 1120object::describe (object *who)
1110{ 1121{
1111 dynbuf_text buf (1024, 1024); 1122 dynbuf_text buf (1024, 1024);
1112 1123
1144 if (flag [FLAG_IDENTIFIED]) 1155 if (flag [FLAG_IDENTIFIED])
1145 buf.printf ("It has %d charges left.\r", stats.food); 1156 buf.printf ("It has %d charges left.\r", stats.food);
1146 break; 1157 break;
1147 } 1158 }
1148 1159
1149 if (materialname && !msg) 1160 if (material != MATERIAL_NULL && !msg)
1150 buf.printf ("It is made of: %s.\r", &materialname); 1161 buf << (nrof > 1 ? "They are made of " : "It is made of ")
1162 << material->description
1163 << ".\r";
1151 1164
1152 if (who) 1165 if (who)
1153 /* Where to wear this item */ 1166 /* Where to wear this item */
1154 for (int i = 0; i < NUM_BODY_LOCATIONS; i++) 1167 for (int i = 0; i < NUM_BODY_LOCATIONS; i++)
1155 if (slot[i].info) 1168 if (slot[i].info)
1163 } 1176 }
1164 1177
1165 if (weight) 1178 if (weight)
1166 buf.printf ("%s %3.3f kg.\r", nrof > 1 ? "They weigh" : "It weighs", weight * (nrof ? nrof : 1) / 1000.0); 1179 buf.printf ("%s %3.3f kg.\r", nrof > 1 ? "They weigh" : "It weighs", weight * (nrof ? nrof : 1) / 1000.0);
1167 1180
1181 if (flag [FLAG_STARTEQUIP])
1182 buf << (nrof > 1 ? "They were" : "It was")
1183 << " given by a god and will vanish when dropped.\r";
1184
1168 if (value && !flag [FLAG_STARTEQUIP] && !flag [FLAG_NO_PICK] && who) 1185 if (value && !flag [FLAG_STARTEQUIP] && !flag [FLAG_NO_PICK] && who)
1169 { 1186 {
1170 buf.printf ("You reckon %s worth %s.\r", nrof > 1 ? "they are" : "it is", query_cost_string (this, who, F_TRUE | F_APPROX)); 1187 buf.printf ("You reckon %s worth %s.\r", nrof > 1 ? "they are" : "it is", query_cost_string (this, who, F_TRUE | F_APPROX));
1171 1188
1172 if (is_in_shop (who)) 1189 if (is_in_shop (who))
1186 buf << "This is a buildable item.\r"; 1203 buf << "This is a buildable item.\r";
1187 1204
1188 /* Does the object have a message? Don't show message for all object 1205 /* Does the object have a message? Don't show message for all object
1189 * types - especially if the first entry is a match 1206 * types - especially if the first entry is a match
1190 */ 1207 */
1208 if (msg)
1209 {
1191 if (msg && type != EXIT && type != BOOK && type != CORPSE && !move_on && !has_dialogue ()) 1210 if (type != EXIT && type != BOOK && type != CORPSE && !move_on && !has_dialogue ())
1192 { 1211 {
1212 buf << '\r';
1213
1193 /* This is just a hack so when identifying the items, we print 1214 /* This is just a hack so when identifying the items, we print
1194 * out the extra message 1215 * out the extra message
1195 */ 1216 */
1196 if (need_identify (this) && flag [FLAG_IDENTIFIED]) 1217 if (need_identify (this) && flag [FLAG_IDENTIFIED])
1197 buf << "The object has a story:\r"; 1218 buf << "The object has a story:\r";
1198 1219
1199 buf << msg << '\n'; 1220 buf << msg << '\n';
1221 }
1222 }
1223 else if (inv && inv->type == SPELL && flag [FLAG_IDENTIFIED]
1224 && (type == SPELLBOOK || type == ROD || type == WAND
1225 || type == ROD || type == POTION || type == SCROLL))
1226 // for spellbooks and other stuff that contains spells, print the spell message,
1227 // unless the object has a custom message handled above.
1228 buf << '\r' << inv->msg << '\n';
1229
1230 // try to display the duration for some potions and scrolls
1231 // this includes change ability potions and group spells,
1232 // but does not handle protection potions
1233 if (inv && inv->type == SPELL && flag [FLAG_IDENTIFIED]
1234 && (type == POTION || type == SCROLL))
1235 {
1236 object *spell = inv;
1237
1238 if (spell->subtype == SP_PARTY_SPELL)
1239 spell = spell->other_arch;
1240
1241 if (spell->subtype == SP_CHANGE_ABILITY)
1242 buf.printf ("\nH<The effect will last about %.10g seconds.>",
1243 TICK2TIME (change_ability_duration (spell, this)));
1244 }
1245
1246 // Display a hint about inscribable items [empty books]
1247 // This includes the amount of text they can hold.
1248 if (type == INSCRIBABLE)
1249 {
1250 if (other_arch && other_arch->type == SCROLL)
1251 buf.printf ("\nH<You can use the inscription skill to inscribe a spell into it.>");
1252 else
1253 buf.printf ("\nH<You can use the inscription skill to inscribe text into it. It has room for up to %d characters.>",
1254 weight_limit);
1200 } 1255 }
1201 1256
1202 buf << '\n'; 1257 buf << '\n';
1258
1259 // the dungeon master additionally gets a complete dump
1260 if (who && who->flag [FLAG_WIZLOOK])
1261 {
1262 buf << "\nT<Object>\n";
1263 describe_dump_object (buf, this);
1264
1265 if (inv)
1266 {
1267 buf << "\nT<Top Inventory>\n";
1268 describe_dump_object (buf, inv);
1269 }
1270 }
1203 1271
1204 return std::string (buf.linearise (), buf.size ()); 1272 return std::string (buf.linearise (), buf.size ());
1205} 1273}
1206 1274
1207static void 1275static void

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines