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

Comparing deliantra/server/common/object.C (file contents):
Revision 1.327 by root, Fri Apr 16 02:32:25 2010 UTC vs.
Revision 1.350 by root, Sun May 8 12:40:41 2011 UTC

1/* 1/*
2 * This file is part of Deliantra, the Roguelike Realtime MMORPG. 2 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 * 3 *
4 * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team 4 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 * Copyright (©) 2001 Mark Wedel & Crossfire Development Team 5 * Copyright (©) 2001 Mark Wedel & Crossfire Development Team
6 * Copyright (©) 1992 Frank Tore Johansen 6 * Copyright (©) 1992 Frank Tore Johansen
7 * 7 *
8 * Deliantra is free software: you can redistribute it and/or modify it under 8 * Deliantra is free software: you can redistribute it and/or modify it under
9 * the terms of the Affero GNU General Public License as published by the 9 * the terms of the Affero GNU General Public License as published by the
71 9, 10, 13, 14, 17, 18, 21, 22, 71 9, 10, 13, 14, 17, 18, 21, 22,
72 25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45, 48, 72 25, 26, 27, 30, 31, 32, 33, 36, 37, 39, 39, 42, 43, 44, 45, 48,
73 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49 73 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49
74}; 74};
75 75
76const char *wall_suffix[16] = {
77 "0",
78 "1_3",
79 "1_4",
80 "2_1_2",
81 "1_2",
82 "2_2_4",
83 "2_2_1",
84 "3_1",
85 "1_1",
86 "2_2_3",
87 "2_2_2",
88 "3_3",
89 "2_1_1",
90 "3_4",
91 "3_2",
92 "4"
93};
94
76static void 95static void
77write_uuid (uval64 skip, bool sync) 96write_uuid (uval64 skip, bool sync)
78{ 97{
79 CALL_BEGIN (2); 98 CALL_BEGIN (2);
80 CALL_ARG_SV (newSVval64 (skip)); 99 CALL_ARG_SV (newSVval64 (skip));
214 233
215/* Returns TRUE if every key_values in wants has a partner with the same value in has. */ 234/* Returns TRUE if every key_values in wants has a partner with the same value in has. */
216static bool 235static bool
217compare_ob_value_lists_one (const object *wants, const object *has) 236compare_ob_value_lists_one (const object *wants, const object *has)
218{ 237{
219 /* n-squared behaviour (see kv_get), but I'm hoping both 238 /* n-squared behaviour (see kv.get), but I'm hoping both
220 * objects with lists are rare, and lists stay short. If not, use a 239 * objects with lists are rare, and lists stay short. If not, use a
221 * different structure or at least keep the lists sorted... 240 * different structure or at least keep the lists sorted...
222 */ 241 */
223 242
224 /* For each field in wants, */ 243 /* For each field in wants, */
225 for (key_value *kv = wants->key_values; kv; kv = kv->next) 244 for (key_value *kv = wants->kv.first; kv; kv = kv->next)
226 if (has->kv_get (kv->key) != kv->value) 245 if (has->kv.get (kv->key) != kv->value)
227 return false; 246 return false;
228 247
229 /* If we get here, every field in wants has a matching field in has. */ 248 /* If we get here, every field in wants has a matching field in has. */
230 return true; 249 return true;
231} 250}
255 */ 274 */
256bool object::can_merge_slow (object *ob1, object *ob2) 275bool object::can_merge_slow (object *ob1, object *ob2)
257{ 276{
258 /* A couple quick sanity checks */ 277 /* A couple quick sanity checks */
259 if (ob1 == ob2 278 if (ob1 == ob2
260 || ob1->type != ob2->type 279 || ob1->type != ob2->type
261 || ob1->value != ob2->value 280 || ob1->value != ob2->value
262 || ob1->name != ob2->name 281 || ob1->name != ob2->name
282 || ob1->custom_name != ob2->custom_name
263 || fabs (ob1->speed - ob2->speed) >= MIN_ACTIVE_SPEED) 283 || fabs (ob1->speed - ob2->speed) >= MIN_ACTIVE_SPEED)
264 return 0; 284 return 0;
265 285
266 /* Do not merge objects if nrof would overflow, assume nrof 286 /* Do not merge objects if nrof would overflow, assume nrof
267 * is always 0 .. 2**31-1 */ 287 * is always 0 .. 2**31-1 */
353 if (ob1->level != ob2->level) 373 if (ob1->level != ob2->level)
354 return 0; 374 return 0;
355 break; 375 break;
356 } 376 }
357 377
358 if (ob1->key_values || ob2->key_values) 378 if (!ob1->kv.empty () || !ob2->kv.empty ())
359 { 379 {
360 /* At least one of these has key_values. */ 380 /* At least one of these has key_values. */
361 if ((!ob1->key_values) != (!ob2->key_values)) 381 if (ob1->kv.empty () != ob2->kv.empty ())
362 return 0; /* One has fields, but the other one doesn't. */ 382 return 0; /* One has fields, but the other one doesn't. */
363 383
364 if (!compare_ob_value_lists (ob1, ob2)) 384 if (!compare_ob_value_lists (ob1, ob2))
365 return 0; 385 return 0;
366 } 386 }
426 446
427 return 0; 447 return 0;
428} 448}
429 449
430// adjust weight per container type ("of holding") 450// adjust weight per container type ("of holding")
431static sint32 451static uint32
432weight_adjust_for (object *op, sint32 weight) 452weight_adjust_for (object *op, uint32 weight)
433{ 453{
434 return op->type == CONTAINER 454 return op->type == CONTAINER
435 ? lerp (weight, 0, 100, 0, 100 - op->stats.Str) 455 ? weight - weight * op->stats.Str / 100
436 : weight; 456 : weight;
437} 457}
438 458
439/* 459/*
440 * adjust_weight(object, weight) adds the specified weight to an object, 460 * subtracts, then adds, the specified weight to an object,
441 * and also updates how much the environment(s) is/are carrying. 461 * and also updates how much the environment(s) is/are carrying.
442 */ 462 */
443static void 463static void
444adjust_weight (object *op, sint32 weight) 464adjust_weight (object *op, sint32 sub, sint32 add)
445{ 465{
446 while (op) 466 while (op)
447 { 467 {
448 // adjust by actual difference to account for rounding errors 468 sint32 ocarrying = op->carrying;
449 // i.e. (w2 - w1) / f != w2 / f - w1 / f and the latter is correct
450 weight = weight_adjust_for (op, op->carrying)
451 - weight_adjust_for (op, op->carrying - weight);
452 469
453 if (!weight) 470 op->carrying -= weight_adjust_for (op, sub);
454 return; 471 op->carrying += weight_adjust_for (op, add);
455
456 op->carrying += weight;
457 472
458 if (object *pl = op->visible_to ()) 473 if (object *pl = op->visible_to ())
459 if (pl != op) // player is handled lazily 474 if (pl != op) // player is handled lazily
460 esrv_update_item (UPD_WEIGHT, pl, op); 475 esrv_update_item (UPD_WEIGHT, pl, op);
461 476
477 sub = ocarrying;
478 add = op->carrying;
479
462 op = op->env; 480 op = op->env;
463 } 481 }
464} 482}
465 483
466/* 484/*
473{ 491{
474 sint32 sum = 0; 492 sint32 sum = 0;
475 493
476 for (object *op = inv; op; op = op->below) 494 for (object *op = inv; op; op = op->below)
477 { 495 {
478 if (op->inv)
479 op->update_weight (); 496 op->update_weight ();
480 497
481 sum += op->total_weight (); 498 sum += weight_adjust_for (this, op->total_weight ());
482 } 499 }
483
484 sum = weight_adjust_for (this, sum);
485 500
486 if (sum != carrying) 501 if (sum != carrying)
487 { 502 {
488 if (carrying != sum)//D 503 if (carrying != sum && carrying)//D
489 LOG (llevDebug, "updating weight got %ld, expected %ld (%s)\n", 504 LOG (llevDebug, "updating carrying got %ld, expected %ld (%s)\n",
490 (long long)sum, (long long)carrying, debug_desc ()); 505 (long long)sum, (long long)carrying, debug_desc ());
491 506
492 carrying = sum; 507 carrying = sum;
493 508
494 if (object *pl = visible_to ()) 509 if (object *pl = visible_to ())
582 LOG (llevError | logBacktrace, "tried to set owner of %s to %s\n", debug_desc (), owner->debug_desc ()); 597 LOG (llevError | logBacktrace, "tried to set owner of %s to %s\n", debug_desc (), owner->debug_desc ());
583 return; 598 return;
584 } 599 }
585 600
586 this->owner = owner; 601 this->owner = owner;
587}
588
589/* Zero the key_values on op, decrementing the shared-string
590 * refcounts and freeing the links.
591 */
592static void
593free_key_values (object *op)
594{
595 for (key_value *i = op->key_values; i; )
596 {
597 key_value *next = i->next;
598 delete i;
599
600 i = next;
601 }
602
603 op->key_values = 0;
604} 602}
605 603
606/* 604/*
607 * copy_to first frees everything allocated by the dst object, 605 * copy_to first frees everything allocated by the dst object,
608 * and then copies the contents of itself into the second 606 * and then copies the contents of itself into the second
614void 612void
615object::copy_to (object *dst) 613object::copy_to (object *dst)
616{ 614{
617 dst->remove (); 615 dst->remove ();
618 *(object_copy *)dst = *this; 616 *(object_copy *)dst = *this;
617
618 // maybe move to object_copy?
619 dst->kv = kv;
620
619 dst->flag [FLAG_REMOVED] = true; 621 dst->flag [FLAG_REMOVED] = true;
620
621 /* Copy over key_values, if any. */
622 if (key_values)
623 {
624 key_value *tail = 0;
625 dst->key_values = 0;
626
627 for (key_value *i = key_values; i; i = i->next)
628 {
629 key_value *new_link = new key_value;
630
631 new_link->next = 0;
632 new_link->key = i->key;
633 new_link->value = i->value;
634
635 /* Try and be clever here, too. */
636 if (!dst->key_values)
637 {
638 dst->key_values = new_link;
639 tail = new_link;
640 }
641 else
642 {
643 tail->next = new_link;
644 tail = new_link;
645 }
646 }
647 }
648
649 dst->activate (); 622 dst->activate ();
650} 623}
651 624
652void 625void
653object::instantiate () 626object::instantiate ()
654{ 627{
655 if (!uuid.seq) // HACK 628 if (!uuid.seq) // HACK
656 uuid = UUID::gen (); 629 uuid = UUID::gen ();
657 630
658 // TODO: unclean state changes, should nt be done in copy_to AND instantiate 631 // TODO: unclean state changes, should not be done in copy_to AND instantiate
659 if (flag [FLAG_RANDOM_SPEED] && speed) 632 if (flag [FLAG_RANDOM_SPEED] && speed)
660 speed_left = - speed - rndm (); // TODO animation 633 speed_left = - speed - rndm (); // TODO animation
661 else 634 else
662 speed_left = -1.; 635 speed_left = -1.;
663 636
764 } 737 }
765 738
766 mapspace &m = op->ms (); 739 mapspace &m = op->ms ();
767 740
768 if (!(m.flags_ & P_UPTODATE)) 741 if (!(m.flags_ & P_UPTODATE))
769 /* nop */; 742 m.update_up (); // nothing to do except copy up
770 else if (action == UP_OBJ_INSERT) 743 else if (action == UP_OBJ_INSERT)
771 { 744 {
772#if 0 745#if 0
773 // this is likely overkill, TODO: revisit (schmorp) 746 // this is likely overkill, TODO: revisit (schmorp)
774 if ((op->flag [FLAG_BLOCKSVIEW] && !(m.flags_ & P_BLOCKSVIEW)) 747 if ((op->flag [FLAG_BLOCKSVIEW] && !(m.flags_ & P_BLOCKSVIEW))
795 * that is being removed. 768 * that is being removed.
796 */ 769 */
797 else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE) 770 else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE)
798 m.invalidate (); 771 m.invalidate ();
799 else if (action == UP_OBJ_FACE) 772 else if (action == UP_OBJ_FACE)
800 /* Nothing to do for that case */ ; 773 m.update_up (); // nothing to do for that case, except copy up
801 else 774 else
802 LOG (llevError, "update_object called with invalid action: %d\n", action); 775 LOG (llevError, "update_object called with invalid action: %d\n", action);
803 776
804 if (op->more) 777 if (op->more)
805 update_object (op->more, action); 778 update_object (op->more, action);
816 789
817object::~object () 790object::~object ()
818{ 791{
819 unlink (); 792 unlink ();
820 793
821 free_key_values (this); 794 kv.clear ();
822} 795}
823 796
824void object::link () 797void object::link ()
825{ 798{
826 assert (!index);//D 799 assert (!index);//D
925 * if some form of movement is allowed, let objects 898 * if some form of movement is allowed, let objects
926 * drop on that space. 899 * drop on that space.
927 */ 900 */
928 if (!drop_to_ground 901 if (!drop_to_ground
929 || !map 902 || !map
930 || map->in_memory != MAP_ACTIVE 903 || !map->linkable ()
931 || map->no_drop 904 || map->no_drop
932 || ms ().move_block == MOVE_ALL) 905 || ms ().move_block == MOVE_ALL)
933 { 906 {
934 while (inv) 907 while (inv)
935 inv->destroy (); 908 inv->destroy ();
1032 1005
1033 freelist = li; 1006 freelist = li;
1034 ++free_count; 1007 ++free_count;
1035} 1008}
1036 1009
1010// special "grave" map used to store all removed objects
1011// till they can be destroyed - saves a lot of checks in the rest
1012// of the code
1037static struct freed_map : maptile 1013static struct freed_map
1014: maptile
1038{ 1015{
1039 freed_map () 1016 freed_map ()
1040 : maptile (3, 3) 1017 : maptile (3, 3)
1041 { 1018 {
1042 path = "<freed objects map>"; 1019 path = "<freed objects map>";
1043 name = "/internal/freed_objects_map"; 1020 name = "/internal/freed_objects_map";
1044 no_drop = 1; 1021 no_drop = 1;
1045 no_reset = 1; 1022 no_reset = 1;
1046 1023
1047 in_memory = MAP_ACTIVE; 1024 state = MAP_ACTIVE;
1048 } 1025 }
1049 1026
1050 ~freed_map () 1027 ~freed_map ()
1051 { 1028 {
1052 destroy (); 1029 destroy ();
1144 flag [FLAG_REMOVED] = false; // hack around the issue of visible_to checking flag_removed 1121 flag [FLAG_REMOVED] = false; // hack around the issue of visible_to checking flag_removed
1145 if (object *pl = visible_to ()) 1122 if (object *pl = visible_to ())
1146 esrv_del_item (pl->contr, count); 1123 esrv_del_item (pl->contr, count);
1147 flag [FLAG_REMOVED] = true; // hack around the issue of visible_to checking flag_removed 1124 flag [FLAG_REMOVED] = true; // hack around the issue of visible_to checking flag_removed
1148 1125
1149 adjust_weight (env, -total_weight ()); 1126 adjust_weight (env, total_weight (), 0);
1150 1127
1151 object *pl = in_player (); 1128 object *pl = in_player ();
1152 1129
1153 /* we set up values so that it could be inserted into 1130 /* we set up values so that it could be inserted into
1154 * the map, but we don't actually do that - it is up 1131 * the map, but we don't actually do that - it is up
1168 1145
1169 if (pl && pl->is_player ()) 1146 if (pl && pl->is_player ())
1170 { 1147 {
1171 if (expect_false (pl->contr->combat_ob == this)) 1148 if (expect_false (pl->contr->combat_ob == this))
1172 { 1149 {
1173 pl->apply (pl->contr->combat_ob, AP_UNAPPLY); 1150 pl->apply (pl->contr->combat_ob, AP_UNAPPLY | AP_IGNORE_CURSE);
1174 pl->contr->combat_ob = 0; 1151 pl->contr->combat_ob = 0;
1175 if (pl->contr->ranged_ob) pl->apply (pl->contr->ranged_ob); 1152 if (pl->contr->ranged_ob) pl->apply (pl->contr->ranged_ob);
1176 } 1153 }
1177 1154
1178 if (expect_false (pl->contr->ranged_ob == this)) 1155 if (expect_false (pl->contr->ranged_ob == this))
1179 { 1156 {
1180 pl->apply (pl->contr->ranged_ob, AP_UNAPPLY); 1157 pl->apply (pl->contr->ranged_ob, AP_UNAPPLY | AP_IGNORE_CURSE);
1181 pl->contr->ranged_ob = 0; 1158 pl->contr->ranged_ob = 0;
1182 if (pl->contr->combat_ob) pl->apply (pl->contr->combat_ob); 1159 if (pl->contr->combat_ob) pl->apply (pl->contr->combat_ob);
1183 } 1160 }
1184 1161
1185 pl->contr->queue_stats_update (); 1162 pl->contr->queue_stats_update ();
1225 1202
1226 above = 0; 1203 above = 0;
1227 below = 0; 1204 below = 0;
1228 1205
1229 ms.invalidate (); 1206 ms.invalidate ();
1230
1231 if (map->in_memory == MAP_SAVING)
1232 return;
1233 1207
1234 int check_walk_off = !flag [FLAG_NO_APPLY]; 1208 int check_walk_off = !flag [FLAG_NO_APPLY];
1235 1209
1236 if (object *pl = ms.player ()) 1210 if (object *pl = ms.player ())
1237 { 1211 {
1372{ 1346{
1373 op->remove (); 1347 op->remove ();
1374 1348
1375 if (m == &freed_map)//D TODO: remove soon 1349 if (m == &freed_map)//D TODO: remove soon
1376 {//D 1350 {//D
1377 LOG (llevError | logBacktrace, "tries to insret object on freed objects map: %s", op->debug_desc ());//D 1351 LOG (llevError | logBacktrace, "tries to insert object on freed objects map: %s", op->debug_desc ());//D
1378 }//D 1352 }//D
1379 1353
1380 /* Ideally, the caller figures this out. However, it complicates a lot 1354 /* Ideally, the caller figures this out. However, it complicates a lot
1381 * of areas of callers (eg, anything that uses find_free_spot would now 1355 * of areas of callers (eg, anything that uses find_free_spot would now
1382 * need extra work 1356 * need extra work
1572 */ 1546 */
1573 1547
1574 /* if this is not the head or flag has been passed, don't check walk on status */ 1548 /* if this is not the head or flag has been passed, don't check walk on status */
1575 if (!(flag & INS_NO_WALK_ON) && op->is_head ()) 1549 if (!(flag & INS_NO_WALK_ON) && op->is_head ())
1576 { 1550 {
1577 if (check_move_on (op, originator)) 1551 if (check_move_on (op, originator, flag))
1578 return 0; 1552 return 0;
1579 1553
1580 /* If we are a multi part object, lets work our way through the check 1554 /* If we are a multi part object, let's work our way through the check
1581 * walk on's. 1555 * walk on's.
1582 */ 1556 */
1583 for (object *tmp = op->more; tmp; tmp = tmp->more) 1557 for (object *tmp = op->more; tmp; tmp = tmp->more)
1584 if (check_move_on (tmp, originator)) 1558 if (check_move_on (tmp, originator, flag))
1585 return 0; 1559 return 0;
1586 } 1560 }
1587 1561
1588 return op; 1562 return op;
1589} 1563}
1655 1629
1656 nr = min (nr, nrof); 1630 nr = min (nr, nrof);
1657 1631
1658 if (nrof > nr) 1632 if (nrof > nr)
1659 { 1633 {
1634 sint64 oweight = total_weight ();
1635
1660 nrof -= nr; 1636 nrof -= nr;
1661 adjust_weight (env, -weight * max (1, nr)); // carrying == 0
1662 1637
1663 if (object *pl = visible_to ()) 1638 if (object *pl = visible_to ())
1664 esrv_update_item (UPD_NROF, pl, this); 1639 esrv_update_item (UPD_NROF, pl, this);
1640
1641 adjust_weight (env, oweight, total_weight ());
1665 1642
1666 return true; 1643 return true;
1667 } 1644 }
1668 else 1645 else
1669 { 1646 {
1744 if (op->nrof) 1721 if (op->nrof)
1745 for (object *tmp = inv; tmp; tmp = tmp->below) 1722 for (object *tmp = inv; tmp; tmp = tmp->below)
1746 if (object::can_merge (tmp, op)) 1723 if (object::can_merge (tmp, op))
1747 { 1724 {
1748 /* return the original object and remove inserted object 1725 /* return the original object and remove inserted object
1749 (client needs the original object) */ 1726 (client prefers the original object) */
1727
1728 // carring must be 0 for mergable objects
1729 sint64 oweight = tmp->weight * tmp->nrof;
1730
1750 tmp->nrof += op->nrof; 1731 tmp->nrof += op->nrof;
1751 1732
1752 if (object *pl = tmp->visible_to ()) 1733 if (object *pl = tmp->visible_to ())
1753 esrv_update_item (UPD_NROF, pl, tmp); 1734 esrv_update_item (UPD_NROF, pl, tmp);
1754 1735
1755 adjust_weight (this, op->total_weight ()); 1736 adjust_weight (this, oweight, tmp->weight * tmp->nrof);
1756 1737
1757 op->destroy (); 1738 op->destroy ();
1758 op = tmp; 1739 op = tmp;
1759 goto inserted; 1740 goto inserted;
1760 } 1741 }
1776 op->flag [FLAG_REMOVED] = 0; 1757 op->flag [FLAG_REMOVED] = 0;
1777 1758
1778 if (object *pl = op->visible_to ()) 1759 if (object *pl = op->visible_to ())
1779 esrv_send_item (pl, op); 1760 esrv_send_item (pl, op);
1780 1761
1781 adjust_weight (this, op->total_weight ()); 1762 adjust_weight (this, 0, op->total_weight ());
1782 1763
1783inserted: 1764inserted:
1784 /* reset the light list and los of the players on the map */ 1765 /* reset the light list and los of the players on the map */
1785 if (op->glow_radius && is_on_map ()) 1766 if (op->glow_radius && is_on_map ())
1786 { 1767 {
1815 * MSW 2001-07-08: Check all objects on space, not just those below 1796 * MSW 2001-07-08: Check all objects on space, not just those below
1816 * object being inserted. insert_ob_in_map may not put new objects 1797 * object being inserted. insert_ob_in_map may not put new objects
1817 * on top. 1798 * on top.
1818 */ 1799 */
1819int 1800int
1820check_move_on (object *op, object *originator) 1801check_move_on (object *op, object *originator, int flags)
1821{ 1802{
1822 if (op->flag [FLAG_NO_APPLY]) 1803 if (op->flag [FLAG_NO_APPLY])
1823 return 0; 1804 return 0;
1824 1805
1825 object *tmp; 1806 object *tmp;
1884 1865
1885 /* Basically same logic as above, except now for actual apply. */ 1866 /* Basically same logic as above, except now for actual apply. */
1886 if ((!op->move_type && tmp->move_on & MOVE_WALK) || 1867 if ((!op->move_type && tmp->move_on & MOVE_WALK) ||
1887 ((op->move_type & tmp->move_on) && (op->move_type & ~tmp->move_on & ~tmp->move_block) == 0)) 1868 ((op->move_type & tmp->move_on) && (op->move_type & ~tmp->move_on & ~tmp->move_block) == 0))
1888 { 1869 {
1870 if ((flags & INS_NO_AUTO_EXIT)
1871 && (tmp->type == EXIT || tmp->type == TELEPORTER
1872 || tmp->type == HOLE || tmp->type == TRAPDOOR)) //TODO: temporary, fix exits instead
1873 continue;
1874
1889 move_apply (tmp, op, originator); 1875 move_apply (tmp, op, originator);
1890 1876
1891 if (op->destroyed ()) 1877 if (op->destroyed ())
1892 return 1; 1878 return 1;
1893 1879
2218{ 2204{
2219 return (ob1->x - ob2->x) * (ob1->x - ob2->x) + (ob1->y - ob2->y) * (ob1->y - ob2->y); 2205 return (ob1->x - ob2->x) * (ob1->x - ob2->x) + (ob1->y - ob2->y) * (ob1->y - ob2->y);
2220} 2206}
2221 2207
2222/* 2208/*
2223 * find_dir_2(delta-x,delta-y) will return a direction in which 2209 * find_dir_2(delta-x,delta-y) will return a direction value
2224 * an object which has subtracted the x and y coordinates of another 2210 * for running into direct [dx, dy].
2225 * object, needs to travel toward it. 2211 * (the opposite of crossfire's find_dir_2!)
2226 */ 2212 */
2227int 2213int
2228find_dir_2 (int x, int y) 2214find_dir_2 (int x, int y)
2229{ 2215{
2216#if 1 // new algorithm
2217 // this works by putting x, y into 16 sectors, which
2218 // are not equal sized, but are a better approximation
2219 // then the old algorithm, and then using a mapping
2220 // table to map it into a direction value.
2221 // basically, it maps these comparisons to each bit
2222 // bit #3: x < 0
2223 // bit #2: y < 0
2224 // bit #1: x > y
2225 // bit #0: x > 2y
2226
2227 static const uint8 dir[16] = {
2228 4, 5, 4, 3,
2229 2, 1, 2, 3,
2230 6, 5, 6, 7,
2231 8, 1, 8, 7,
2232 };
2233 int sector = 0;
2234
2235 // this is a bit ugly, but more likely to result in branchless code
2236 sector |= x < 0 ? 8 : 0;
2237 x = x < 0 ? -x : x; // abs
2238
2239 sector |= y < 0 ? 4 : 0;
2240 y = y < 0 ? -y : y; // abs
2241
2242 if (x > y)
2243 {
2244 sector |= 2;
2245
2246 if (x > y * 2)
2247 sector |= 1;
2248 }
2249 else
2250 {
2251 if (y > x * 2)
2252 sector |= 1;
2253 else if (!y)
2254 return 0; // x == 0 here
2255 }
2256
2257 return dir [sector];
2258#else // old algorithm
2230 int q; 2259 int q;
2231 2260
2232 if (y) 2261 if (y)
2233 q = x * 100 / y; 2262 q = 128 * x / y;
2234 else if (x) 2263 else if (x)
2235 q = -300 * x; 2264 q = -512 * x; // to make it > 309
2236 else 2265 else
2237 return 0; 2266 return 0;
2238 2267
2239 if (y > 0) 2268 if (y > 0)
2240 { 2269 {
2241 if (q < -242) 2270 if (q < -309) return 7;
2271 if (q < -52) return 6;
2272 if (q < 52) return 5;
2273 if (q < 309) return 4;
2274
2242 return 3; 2275 return 3;
2243 if (q < -41) 2276 }
2244 return 2; 2277 else
2245 if (q < 41) 2278 {
2246 return 1; 2279 if (q < -309) return 3;
2247 if (q < 242) 2280 if (q < -52) return 2;
2248 return 8; 2281 if (q < 52) return 1;
2282 if (q < 309) return 8;
2283
2249 return 7; 2284 return 7;
2250 } 2285 }
2251 2286#endif
2252 if (q < -242)
2253 return 7;
2254 if (q < -41)
2255 return 6;
2256 if (q < 41)
2257 return 5;
2258 if (q < 242)
2259 return 4;
2260
2261 return 3;
2262} 2287}
2263 2288
2264/* 2289/*
2265 * dirdiff(dir1, dir2) returns how many 45-degrees differences there is 2290 * dirdiff(dir1, dir2) returns how many 45-degrees differences there is
2266 * between two directions (which are expected to be absolute (see absdir()) 2291 * between two directions (which are expected to be absolute (see absdir())
2267 */ 2292 */
2268int 2293int
2269dirdiff (int dir1, int dir2) 2294dirdiff (int dir1, int dir2)
2270{ 2295{
2271 int d;
2272
2273 d = abs (dir1 - dir2); 2296 int d = abs (dir1 - dir2);
2274 if (d > 4)
2275 d = 8 - d;
2276 2297
2277 return d; 2298 return d > 4 ? 8 - d : d;
2278} 2299}
2279 2300
2280/* peterm: 2301/* peterm:
2281 * do LOS stuff for ball lightning. Go after the closest VISIBLE monster. 2302 * do LOS stuff for ball lightning. Go after the closest VISIBLE monster.
2282 * Basically, this is a table of directions, and what directions 2303 * Basically, this is a table of directions, and what directions
2393 return /*who->flag [FLAG_WIZ]|| */ 2414 return /*who->flag [FLAG_WIZ]|| */
2394 (item->weight > 0 && !item->flag [FLAG_NO_PICK] && 2415 (item->weight > 0 && !item->flag [FLAG_NO_PICK] &&
2395 !item->flag [FLAG_ALIVE] && !item->invisible && (who->is_player () || item->weight < who->weight / 3)); 2416 !item->flag [FLAG_ALIVE] && !item->invisible && (who->is_player () || item->weight < who->weight / 3));
2396} 2417}
2397 2418
2419//-GPL
2420
2398/* 2421/*
2399 * create clone from object to another 2422 * create clone from object to another
2400 */ 2423 */
2401object * 2424object *
2402object::deep_clone () 2425object::deep_clone ()
2432 return tmp; 2455 return tmp;
2433 2456
2434 return 0; 2457 return 0;
2435} 2458}
2436 2459
2460/* Zero the key_values on op, decrementing the shared-string
2461 * refcounts and freeing the links.
2462 */
2463void
2464key_values::clear ()
2465{
2466 for (key_value *kvp = first; kvp; )
2467 {
2468 key_value *next = kvp->next;
2469 delete kvp;
2470 kvp = next;
2471 }
2472
2473 first = 0;
2474}
2475
2437shstr_tmp 2476shstr_tmp
2438object::kv_get (shstr_tmp key) const 2477key_values::get (shstr_tmp key) const
2439{ 2478{
2440 for (key_value *kv = key_values; kv; kv = kv->next) 2479 for (key_value *kv = first; kv; kv = kv->next)
2441 if (kv->key == key) 2480 if (kv->key == key)
2442 return kv->value; 2481 return kv->value;
2443 2482
2444 return shstr (); 2483 return shstr ();
2445} 2484}
2446 2485
2447void 2486void
2487key_values::add (shstr_tmp key, shstr_tmp value)
2488{
2489 key_value *kv = new key_value;
2490
2491 kv->next = first;
2492 kv->key = key;
2493 kv->value = value;
2494
2495 first = kv;
2496}
2497
2498void
2448object::kv_set (shstr_tmp key, shstr_tmp value) 2499key_values::set (shstr_tmp key, shstr_tmp value)
2449{ 2500{
2450 for (key_value *kv = key_values; kv; kv = kv->next) 2501 for (key_value *kv = first; kv; kv = kv->next)
2451 if (kv->key == key) 2502 if (kv->key == key)
2452 { 2503 {
2453 kv->value = value; 2504 kv->value = value;
2454 return; 2505 return;
2455 } 2506 }
2456 2507
2457 key_value *kv = new key_value; 2508 add (key, value);
2458
2459 kv->next = key_values;
2460 kv->key = key;
2461 kv->value = value;
2462
2463 key_values = kv;
2464} 2509}
2465 2510
2466void 2511void
2467object::kv_del (shstr_tmp key) 2512key_values::del (shstr_tmp key)
2468{ 2513{
2469 for (key_value **kvp = &key_values; *kvp; kvp = &(*kvp)->next) 2514 for (key_value **kvp = &first; *kvp; kvp = &(*kvp)->next)
2470 if ((*kvp)->key == key) 2515 if ((*kvp)->key == key)
2471 { 2516 {
2472 key_value *kv = *kvp; 2517 key_value *kv = *kvp;
2473 *kvp = (*kvp)->next; 2518 *kvp = (*kvp)->next;
2474 delete kv; 2519 delete kv;
2475 return; 2520 return;
2476 } 2521 }
2522}
2523
2524void
2525key_values::reverse ()
2526{
2527 key_value *prev = 0;
2528 key_value *head = first;
2529
2530 while (head)
2531 {
2532 key_value *node = head;
2533 head = head->next;
2534 node->next = prev;
2535 prev = node;
2536 }
2537
2538 first = prev;
2539}
2540
2541key_values &
2542key_values::operator =(const key_values &kv)
2543{
2544 clear ();
2545
2546 for (key_value *kvp = kv.first; kvp; kvp = kvp->next)
2547 add (kvp->key, kvp->value);
2548
2549 reverse ();
2477} 2550}
2478 2551
2479object::depth_iterator::depth_iterator (object *container) 2552object::depth_iterator::depth_iterator (object *container)
2480: iterator_base (container) 2553: iterator_base (container)
2481{ 2554{
2564object::region () const 2637object::region () const
2565{ 2638{
2566 return map ? map->region (x, y) 2639 return map ? map->region (x, y)
2567 : region::default_region (); 2640 : region::default_region ();
2568} 2641}
2642
2643//+GPL
2569 2644
2570void 2645void
2571object::open_container (object *new_container) 2646object::open_container (object *new_container)
2572{ 2647{
2573 if (container == new_container) 2648 if (container == new_container)
2631 } 2706 }
2632// else if (!old_container->env && contr && contr->ns) 2707// else if (!old_container->env && contr && contr->ns)
2633// contr->ns->floorbox_reset (); 2708// contr->ns->floorbox_reset ();
2634} 2709}
2635 2710
2711//-GPL
2712
2713// prefetch some flat area around the player
2714static void
2715prefetch_surrounding_area (object *op, maptile *map, int range)
2716{
2717 for (maprect *rect = map->split_to_tiles (mapwalk_buf,
2718 op->x - range , op->y - range ,
2719 op->x + range + 1, op->y + range + 1);
2720 rect->m;
2721 ++rect)
2722 {
2723 rect->m->touch ();
2724 rect->m->activate ();
2725 }
2726}
2727
2728// prefetch a generous area around the player, also up and down
2729void
2730object::prefetch_surrounding_maps ()
2731{
2732 prefetch_surrounding_area (this, map, 40);
2733
2734 if (maptile *m = map->tile_available (TILE_DOWN))
2735 prefetch_surrounding_area (this, m, 20);
2736
2737 if (maptile *m = map->tile_available (TILE_UP))
2738 prefetch_surrounding_area (this, m, 20);
2739}
2740
2741//+GPL
2742
2636object * 2743object *
2637object::force_find (shstr_tmp name) 2744object::force_find (shstr_tmp name)
2638{ 2745{
2639 /* cycle through his inventory to look for the MARK we want to 2746 /* cycle through his inventory to look for the MARK we want to
2640 * place 2747 * place
2644 return splay (tmp); 2751 return splay (tmp);
2645 2752
2646 return 0; 2753 return 0;
2647} 2754}
2648 2755
2649//-GPL
2650
2651void 2756void
2652object::force_set_timer (int duration) 2757object::force_set_timer (int duration)
2653{ 2758{
2654 this->duration = 1; 2759 this->duration = 1;
2655 this->speed_left = -1.f; 2760 this->speed_left = -1.f;
2661object::force_add (shstr_tmp name, int duration) 2766object::force_add (shstr_tmp name, int duration)
2662{ 2767{
2663 if (object *force = force_find (name)) 2768 if (object *force = force_find (name))
2664 force->destroy (); 2769 force->destroy ();
2665 2770
2666 object *force = get_archetype (FORCE_NAME); 2771 object *force = archetype::get (FORCE_NAME);
2667 2772
2668 force->slaying = name; 2773 force->slaying = name;
2669 force->force_set_timer (duration); 2774 force->force_set_timer (duration);
2670 force->flag [FLAG_APPLIED] = true; 2775 force->flag [FLAG_APPLIED] = true;
2671 2776
2755 return contr->mark; 2860 return contr->mark;
2756 else 2861 else
2757 return 0; 2862 return 0;
2758} 2863}
2759 2864
2865// put marked object first in the inventory
2866// this is used by identify-like spells so players can influence
2867// the order a bit.
2868void
2869object::splay_marked ()
2870{
2871 if (object *marked = mark ())
2872 splay (marked);
2873}
2874

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines