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.325 by root, Wed Apr 14 21:36:31 2010 UTC vs.
Revision 1.348 by root, Sat May 7 20:03:27 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 {
503 if (carrying != sum && carrying)//D
504 LOG (llevDebug, "updating carrying got %ld, expected %ld (%s)\n",
505 (long long)sum, (long long)carrying, debug_desc ());
506
488 carrying = sum; 507 carrying = sum;
489 508
490 if (object *pl = visible_to ()) 509 if (object *pl = visible_to ())
491 if (pl != this) // player is handled lazily 510 if (pl != this) // player is handled lazily
492 esrv_update_item (UPD_WEIGHT, pl, this); 511 esrv_update_item (UPD_WEIGHT, pl, this);
578 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 ());
579 return; 598 return;
580 } 599 }
581 600
582 this->owner = owner; 601 this->owner = owner;
583}
584
585/* Zero the key_values on op, decrementing the shared-string
586 * refcounts and freeing the links.
587 */
588static void
589free_key_values (object *op)
590{
591 for (key_value *i = op->key_values; i; )
592 {
593 key_value *next = i->next;
594 delete i;
595
596 i = next;
597 }
598
599 op->key_values = 0;
600} 602}
601 603
602/* 604/*
603 * copy_to first frees everything allocated by the dst object, 605 * copy_to first frees everything allocated by the dst object,
604 * and then copies the contents of itself into the second 606 * and then copies the contents of itself into the second
610void 612void
611object::copy_to (object *dst) 613object::copy_to (object *dst)
612{ 614{
613 dst->remove (); 615 dst->remove ();
614 *(object_copy *)dst = *this; 616 *(object_copy *)dst = *this;
617
618 // maybe move to object_copy?
619 dst->kv = kv;
620
615 dst->flag [FLAG_REMOVED] = true; 621 dst->flag [FLAG_REMOVED] = true;
616
617 /* Copy over key_values, if any. */
618 if (key_values)
619 {
620 key_value *tail = 0;
621 dst->key_values = 0;
622
623 for (key_value *i = key_values; i; i = i->next)
624 {
625 key_value *new_link = new key_value;
626
627 new_link->next = 0;
628 new_link->key = i->key;
629 new_link->value = i->value;
630
631 /* Try and be clever here, too. */
632 if (!dst->key_values)
633 {
634 dst->key_values = new_link;
635 tail = new_link;
636 }
637 else
638 {
639 tail->next = new_link;
640 tail = new_link;
641 }
642 }
643 }
644
645 dst->activate (); 622 dst->activate ();
646} 623}
647 624
648void 625void
649object::instantiate () 626object::instantiate ()
650{ 627{
651 if (!uuid.seq) // HACK 628 if (!uuid.seq) // HACK
652 uuid = UUID::gen (); 629 uuid = UUID::gen ();
653 630
654 // 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
655 if (flag [FLAG_RANDOM_SPEED] && speed) 632 if (flag [FLAG_RANDOM_SPEED] && speed)
656 speed_left = - speed - rndm (); // TODO animation 633 speed_left = - speed - rndm (); // TODO animation
657 else 634 else
658 speed_left = -1.; 635 speed_left = -1.;
659 636
760 } 737 }
761 738
762 mapspace &m = op->ms (); 739 mapspace &m = op->ms ();
763 740
764 if (!(m.flags_ & P_UPTODATE)) 741 if (!(m.flags_ & P_UPTODATE))
765 /* nop */; 742 m.update_up (); // nothing to do except copy up
766 else if (action == UP_OBJ_INSERT) 743 else if (action == UP_OBJ_INSERT)
767 { 744 {
768#if 0 745#if 0
769 // this is likely overkill, TODO: revisit (schmorp) 746 // this is likely overkill, TODO: revisit (schmorp)
770 if ((op->flag [FLAG_BLOCKSVIEW] && !(m.flags_ & P_BLOCKSVIEW)) 747 if ((op->flag [FLAG_BLOCKSVIEW] && !(m.flags_ & P_BLOCKSVIEW))
791 * that is being removed. 768 * that is being removed.
792 */ 769 */
793 else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE) 770 else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE)
794 m.invalidate (); 771 m.invalidate ();
795 else if (action == UP_OBJ_FACE) 772 else if (action == UP_OBJ_FACE)
796 /* Nothing to do for that case */ ; 773 m.update_up (); // nothing to do for that case, except copy up
797 else 774 else
798 LOG (llevError, "update_object called with invalid action: %d\n", action); 775 LOG (llevError, "update_object called with invalid action: %d\n", action);
799 776
800 if (op->more) 777 if (op->more)
801 update_object (op->more, action); 778 update_object (op->more, action);
812 789
813object::~object () 790object::~object ()
814{ 791{
815 unlink (); 792 unlink ();
816 793
817 free_key_values (this); 794 kv.clear ();
818} 795}
819 796
820void object::link () 797void object::link ()
821{ 798{
822 assert (!index);//D 799 assert (!index);//D
921 * if some form of movement is allowed, let objects 898 * if some form of movement is allowed, let objects
922 * drop on that space. 899 * drop on that space.
923 */ 900 */
924 if (!drop_to_ground 901 if (!drop_to_ground
925 || !map 902 || !map
926 || map->in_memory != MAP_ACTIVE 903 || !map->linkable ()
927 || map->no_drop 904 || map->no_drop
928 || ms ().move_block == MOVE_ALL) 905 || ms ().move_block == MOVE_ALL)
929 { 906 {
930 while (inv) 907 while (inv)
931 inv->destroy (); 908 inv->destroy ();
1031} 1008}
1032 1009
1033static struct freed_map : maptile 1010static struct freed_map : maptile
1034{ 1011{
1035 freed_map () 1012 freed_map ()
1013 : maptile (3, 3)
1036 { 1014 {
1037 path = "<freed objects map>"; 1015 path = "<freed objects map>";
1038 name = "/internal/freed_objects_map"; 1016 name = "/internal/freed_objects_map";
1039 width = 3;
1040 height = 3;
1041 no_drop = 1; 1017 no_drop = 1;
1042 no_reset = 1; 1018 no_reset = 1;
1043 1019
1044 alloc ();
1045 in_memory = MAP_ACTIVE; 1020 state = MAP_ACTIVE;
1046 } 1021 }
1047 1022
1048 ~freed_map () 1023 ~freed_map ()
1049 { 1024 {
1050 destroy (); 1025 destroy ();
1142 flag [FLAG_REMOVED] = false; // hack around the issue of visible_to checking flag_removed 1117 flag [FLAG_REMOVED] = false; // hack around the issue of visible_to checking flag_removed
1143 if (object *pl = visible_to ()) 1118 if (object *pl = visible_to ())
1144 esrv_del_item (pl->contr, count); 1119 esrv_del_item (pl->contr, count);
1145 flag [FLAG_REMOVED] = true; // hack around the issue of visible_to checking flag_removed 1120 flag [FLAG_REMOVED] = true; // hack around the issue of visible_to checking flag_removed
1146 1121
1147 adjust_weight (env, -total_weight ()); 1122 adjust_weight (env, total_weight (), 0);
1148 1123
1149 object *pl = in_player (); 1124 object *pl = in_player ();
1150 1125
1151 /* we set up values so that it could be inserted into 1126 /* we set up values so that it could be inserted into
1152 * the map, but we don't actually do that - it is up 1127 * the map, but we don't actually do that - it is up
1166 1141
1167 if (pl && pl->is_player ()) 1142 if (pl && pl->is_player ())
1168 { 1143 {
1169 if (expect_false (pl->contr->combat_ob == this)) 1144 if (expect_false (pl->contr->combat_ob == this))
1170 { 1145 {
1171 pl->apply (pl->contr->combat_ob, AP_UNAPPLY); 1146 pl->apply (pl->contr->combat_ob, AP_UNAPPLY | AP_IGNORE_CURSE);
1172 pl->contr->combat_ob = 0; 1147 pl->contr->combat_ob = 0;
1173 if (pl->contr->ranged_ob) pl->apply (pl->contr->ranged_ob); 1148 if (pl->contr->ranged_ob) pl->apply (pl->contr->ranged_ob);
1174 } 1149 }
1175 1150
1176 if (expect_false (pl->contr->ranged_ob == this)) 1151 if (expect_false (pl->contr->ranged_ob == this))
1177 { 1152 {
1178 pl->apply (pl->contr->ranged_ob, AP_UNAPPLY); 1153 pl->apply (pl->contr->ranged_ob, AP_UNAPPLY | AP_IGNORE_CURSE);
1179 pl->contr->ranged_ob = 0; 1154 pl->contr->ranged_ob = 0;
1180 if (pl->contr->combat_ob) pl->apply (pl->contr->combat_ob); 1155 if (pl->contr->combat_ob) pl->apply (pl->contr->combat_ob);
1181 } 1156 }
1182 1157
1183 pl->contr->queue_stats_update (); 1158 pl->contr->queue_stats_update ();
1223 1198
1224 above = 0; 1199 above = 0;
1225 below = 0; 1200 below = 0;
1226 1201
1227 ms.invalidate (); 1202 ms.invalidate ();
1228
1229 if (map->in_memory == MAP_SAVING)
1230 return;
1231 1203
1232 int check_walk_off = !flag [FLAG_NO_APPLY]; 1204 int check_walk_off = !flag [FLAG_NO_APPLY];
1233 1205
1234 if (object *pl = ms.player ()) 1206 if (object *pl = ms.player ())
1235 { 1207 {
1370{ 1342{
1371 op->remove (); 1343 op->remove ();
1372 1344
1373 if (m == &freed_map)//D TODO: remove soon 1345 if (m == &freed_map)//D TODO: remove soon
1374 {//D 1346 {//D
1375 LOG (llevError | logBacktrace, "tries to insret object on freed objects map: %s", op->debug_desc ());//D 1347 LOG (llevError | logBacktrace, "tries to insert object on freed objects map: %s", op->debug_desc ());//D
1376 }//D 1348 }//D
1377 1349
1378 /* Ideally, the caller figures this out. However, it complicates a lot 1350 /* Ideally, the caller figures this out. However, it complicates a lot
1379 * of areas of callers (eg, anything that uses find_free_spot would now 1351 * of areas of callers (eg, anything that uses find_free_spot would now
1380 * need extra work 1352 * need extra work
1570 */ 1542 */
1571 1543
1572 /* if this is not the head or flag has been passed, don't check walk on status */ 1544 /* if this is not the head or flag has been passed, don't check walk on status */
1573 if (!(flag & INS_NO_WALK_ON) && op->is_head ()) 1545 if (!(flag & INS_NO_WALK_ON) && op->is_head ())
1574 { 1546 {
1575 if (check_move_on (op, originator)) 1547 if (check_move_on (op, originator, flag))
1576 return 0; 1548 return 0;
1577 1549
1578 /* If we are a multi part object, lets work our way through the check 1550 /* If we are a multi part object, let's work our way through the check
1579 * walk on's. 1551 * walk on's.
1580 */ 1552 */
1581 for (object *tmp = op->more; tmp; tmp = tmp->more) 1553 for (object *tmp = op->more; tmp; tmp = tmp->more)
1582 if (check_move_on (tmp, originator)) 1554 if (check_move_on (tmp, originator, flag))
1583 return 0; 1555 return 0;
1584 } 1556 }
1585 1557
1586 return op; 1558 return op;
1587} 1559}
1653 1625
1654 nr = min (nr, nrof); 1626 nr = min (nr, nrof);
1655 1627
1656 if (nrof > nr) 1628 if (nrof > nr)
1657 { 1629 {
1630 sint64 oweight = total_weight ();
1631
1658 nrof -= nr; 1632 nrof -= nr;
1659 adjust_weight (env, -weight * max (1, nr)); // carrying == 0
1660 1633
1661 if (object *pl = visible_to ()) 1634 if (object *pl = visible_to ())
1662 esrv_update_item (UPD_NROF, pl, this); 1635 esrv_update_item (UPD_NROF, pl, this);
1636
1637 adjust_weight (env, oweight, total_weight ());
1663 1638
1664 return true; 1639 return true;
1665 } 1640 }
1666 else 1641 else
1667 { 1642 {
1742 if (op->nrof) 1717 if (op->nrof)
1743 for (object *tmp = inv; tmp; tmp = tmp->below) 1718 for (object *tmp = inv; tmp; tmp = tmp->below)
1744 if (object::can_merge (tmp, op)) 1719 if (object::can_merge (tmp, op))
1745 { 1720 {
1746 /* return the original object and remove inserted object 1721 /* return the original object and remove inserted object
1747 (client needs the original object) */ 1722 (client prefers the original object) */
1723
1724 // carring must be 0 for mergable objects
1725 sint64 oweight = tmp->weight * tmp->nrof;
1726
1748 tmp->nrof += op->nrof; 1727 tmp->nrof += op->nrof;
1749 1728
1750 if (object *pl = tmp->visible_to ()) 1729 if (object *pl = tmp->visible_to ())
1751 esrv_update_item (UPD_NROF, pl, tmp); 1730 esrv_update_item (UPD_NROF, pl, tmp);
1752 1731
1753 adjust_weight (this, op->total_weight ()); 1732 adjust_weight (this, oweight, tmp->weight * tmp->nrof);
1754 1733
1755 op->destroy (); 1734 op->destroy ();
1756 op = tmp; 1735 op = tmp;
1757 goto inserted; 1736 goto inserted;
1758 } 1737 }
1774 op->flag [FLAG_REMOVED] = 0; 1753 op->flag [FLAG_REMOVED] = 0;
1775 1754
1776 if (object *pl = op->visible_to ()) 1755 if (object *pl = op->visible_to ())
1777 esrv_send_item (pl, op); 1756 esrv_send_item (pl, op);
1778 1757
1779 adjust_weight (this, op->total_weight ()); 1758 adjust_weight (this, 0, op->total_weight ());
1780 1759
1781inserted: 1760inserted:
1782 /* reset the light list and los of the players on the map */ 1761 /* reset the light list and los of the players on the map */
1783 if (op->glow_radius && is_on_map ()) 1762 if (op->glow_radius && is_on_map ())
1784 { 1763 {
1813 * MSW 2001-07-08: Check all objects on space, not just those below 1792 * MSW 2001-07-08: Check all objects on space, not just those below
1814 * object being inserted. insert_ob_in_map may not put new objects 1793 * object being inserted. insert_ob_in_map may not put new objects
1815 * on top. 1794 * on top.
1816 */ 1795 */
1817int 1796int
1818check_move_on (object *op, object *originator) 1797check_move_on (object *op, object *originator, int flags)
1819{ 1798{
1820 if (op->flag [FLAG_NO_APPLY]) 1799 if (op->flag [FLAG_NO_APPLY])
1821 return 0; 1800 return 0;
1822 1801
1823 object *tmp; 1802 object *tmp;
1882 1861
1883 /* Basically same logic as above, except now for actual apply. */ 1862 /* Basically same logic as above, except now for actual apply. */
1884 if ((!op->move_type && tmp->move_on & MOVE_WALK) || 1863 if ((!op->move_type && tmp->move_on & MOVE_WALK) ||
1885 ((op->move_type & tmp->move_on) && (op->move_type & ~tmp->move_on & ~tmp->move_block) == 0)) 1864 ((op->move_type & tmp->move_on) && (op->move_type & ~tmp->move_on & ~tmp->move_block) == 0))
1886 { 1865 {
1866 if ((flags & INS_NO_AUTO_EXIT)
1867 && (tmp->type == EXIT || tmp->type == TELEPORTER
1868 || tmp->type == HOLE || tmp->type == TRAPDOOR)) //TODO: temporary, fix exits instead
1869 continue;
1870
1887 move_apply (tmp, op, originator); 1871 move_apply (tmp, op, originator);
1888 1872
1889 if (op->destroyed ()) 1873 if (op->destroyed ())
1890 return 1; 1874 return 1;
1891 1875
2216{ 2200{
2217 return (ob1->x - ob2->x) * (ob1->x - ob2->x) + (ob1->y - ob2->y) * (ob1->y - ob2->y); 2201 return (ob1->x - ob2->x) * (ob1->x - ob2->x) + (ob1->y - ob2->y) * (ob1->y - ob2->y);
2218} 2202}
2219 2203
2220/* 2204/*
2221 * find_dir_2(delta-x,delta-y) will return a direction in which 2205 * find_dir_2(delta-x,delta-y) will return a direction value
2222 * an object which has subtracted the x and y coordinates of another 2206 * for running into direct [dx, dy].
2223 * object, needs to travel toward it. 2207 * (the opposite of crossfire's find_dir_2!)
2224 */ 2208 */
2225int 2209int
2226find_dir_2 (int x, int y) 2210find_dir_2 (int x, int y)
2227{ 2211{
2212#if 1 // new algorithm
2213 // this works by putting x, y into 16 sectors, which
2214 // are not equal sized, but are a better approximation
2215 // then the old algorithm, and then using a mapping
2216 // table to map it into a direction value.
2217 // basically, it maps these comparisons to each bit
2218 // bit #3: x < 0
2219 // bit #2: y < 0
2220 // bit #1: x > y
2221 // bit #0: x > 2y
2222
2223 static const uint8 dir[16] = {
2224 4, 5, 4, 3,
2225 2, 1, 2, 3,
2226 6, 5, 6, 7,
2227 8, 1, 8, 7,
2228 };
2229 int sector = 0;
2230
2231 // this is a bit ugly, but more likely to result in branchless code
2232 sector |= x < 0 ? 8 : 0;
2233 x = x < 0 ? -x : x; // abs
2234
2235 sector |= y < 0 ? 4 : 0;
2236 y = y < 0 ? -y : y; // abs
2237
2238 if (x > y)
2239 {
2240 sector |= 2;
2241
2242 if (x > y * 2)
2243 sector |= 1;
2244 }
2245 else
2246 {
2247 if (y > x * 2)
2248 sector |= 1;
2249 else if (!y)
2250 return 0; // x == 0 here
2251 }
2252
2253 return dir [sector];
2254#else // old algorithm
2228 int q; 2255 int q;
2229 2256
2230 if (y) 2257 if (y)
2231 q = x * 100 / y; 2258 q = 128 * x / y;
2232 else if (x) 2259 else if (x)
2233 q = -300 * x; 2260 q = -512 * x; // to make it > 309
2234 else 2261 else
2235 return 0; 2262 return 0;
2236 2263
2237 if (y > 0) 2264 if (y > 0)
2238 { 2265 {
2239 if (q < -242) 2266 if (q < -309) return 7;
2267 if (q < -52) return 6;
2268 if (q < 52) return 5;
2269 if (q < 309) return 4;
2270
2240 return 3; 2271 return 3;
2241 if (q < -41) 2272 }
2242 return 2; 2273 else
2243 if (q < 41) 2274 {
2244 return 1; 2275 if (q < -309) return 3;
2245 if (q < 242) 2276 if (q < -52) return 2;
2246 return 8; 2277 if (q < 52) return 1;
2278 if (q < 309) return 8;
2279
2247 return 7; 2280 return 7;
2248 } 2281 }
2249 2282#endif
2250 if (q < -242)
2251 return 7;
2252 if (q < -41)
2253 return 6;
2254 if (q < 41)
2255 return 5;
2256 if (q < 242)
2257 return 4;
2258
2259 return 3;
2260} 2283}
2261 2284
2262/* 2285/*
2263 * dirdiff(dir1, dir2) returns how many 45-degrees differences there is 2286 * dirdiff(dir1, dir2) returns how many 45-degrees differences there is
2264 * between two directions (which are expected to be absolute (see absdir()) 2287 * between two directions (which are expected to be absolute (see absdir())
2265 */ 2288 */
2266int 2289int
2267dirdiff (int dir1, int dir2) 2290dirdiff (int dir1, int dir2)
2268{ 2291{
2269 int d;
2270
2271 d = abs (dir1 - dir2); 2292 int d = abs (dir1 - dir2);
2272 if (d > 4)
2273 d = 8 - d;
2274 2293
2275 return d; 2294 return d > 4 ? 8 - d : d;
2276} 2295}
2277 2296
2278/* peterm: 2297/* peterm:
2279 * do LOS stuff for ball lightning. Go after the closest VISIBLE monster. 2298 * do LOS stuff for ball lightning. Go after the closest VISIBLE monster.
2280 * Basically, this is a table of directions, and what directions 2299 * Basically, this is a table of directions, and what directions
2430 return tmp; 2449 return tmp;
2431 2450
2432 return 0; 2451 return 0;
2433} 2452}
2434 2453
2454/* Zero the key_values on op, decrementing the shared-string
2455 * refcounts and freeing the links.
2456 */
2457void
2458key_values::clear ()
2459{
2460 for (key_value *kvp = first; kvp; )
2461 {
2462 key_value *next = kvp->next;
2463 delete kvp;
2464 kvp = next;
2465 }
2466
2467 first = 0;
2468}
2469
2435shstr_tmp 2470shstr_tmp
2436object::kv_get (shstr_tmp key) const 2471key_values::get (shstr_tmp key) const
2437{ 2472{
2438 for (key_value *kv = key_values; kv; kv = kv->next) 2473 for (key_value *kv = first; kv; kv = kv->next)
2439 if (kv->key == key) 2474 if (kv->key == key)
2440 return kv->value; 2475 return kv->value;
2441 2476
2442 return shstr (); 2477 return shstr ();
2443} 2478}
2444 2479
2445void 2480void
2481key_values::add (shstr_tmp key, shstr_tmp value)
2482{
2483 key_value *kv = new key_value;
2484
2485 kv->next = first;
2486 kv->key = key;
2487 kv->value = value;
2488
2489 first = kv;
2490}
2491
2492void
2446object::kv_set (shstr_tmp key, shstr_tmp value) 2493key_values::set (shstr_tmp key, shstr_tmp value)
2447{ 2494{
2448 for (key_value *kv = key_values; kv; kv = kv->next) 2495 for (key_value *kv = first; kv; kv = kv->next)
2449 if (kv->key == key) 2496 if (kv->key == key)
2450 { 2497 {
2451 kv->value = value; 2498 kv->value = value;
2452 return; 2499 return;
2453 } 2500 }
2454 2501
2455 key_value *kv = new key_value; 2502 add (key, value);
2456
2457 kv->next = key_values;
2458 kv->key = key;
2459 kv->value = value;
2460
2461 key_values = kv;
2462} 2503}
2463 2504
2464void 2505void
2465object::kv_del (shstr_tmp key) 2506key_values::del (shstr_tmp key)
2466{ 2507{
2467 for (key_value **kvp = &key_values; *kvp; kvp = &(*kvp)->next) 2508 for (key_value **kvp = &first; *kvp; kvp = &(*kvp)->next)
2468 if ((*kvp)->key == key) 2509 if ((*kvp)->key == key)
2469 { 2510 {
2470 key_value *kv = *kvp; 2511 key_value *kv = *kvp;
2471 *kvp = (*kvp)->next; 2512 *kvp = (*kvp)->next;
2472 delete kv; 2513 delete kv;
2473 return; 2514 return;
2474 } 2515 }
2516}
2517
2518void
2519key_values::reverse ()
2520{
2521 key_value *prev = 0;
2522 key_value *head = first;
2523
2524 while (head)
2525 {
2526 key_value *node = head;
2527 head = head->next;
2528 node->next = prev;
2529 prev = node;
2530 }
2531
2532 first = prev;
2533}
2534
2535key_values &
2536key_values::operator =(const key_values &kv)
2537{
2538 clear ();
2539
2540 for (key_value *kvp = kv.first; kvp; kvp = kvp->next)
2541 add (kvp->key, kvp->value);
2542
2543 reverse ();
2475} 2544}
2476 2545
2477object::depth_iterator::depth_iterator (object *container) 2546object::depth_iterator::depth_iterator (object *container)
2478: iterator_base (container) 2547: iterator_base (container)
2479{ 2548{
2659object::force_add (shstr_tmp name, int duration) 2728object::force_add (shstr_tmp name, int duration)
2660{ 2729{
2661 if (object *force = force_find (name)) 2730 if (object *force = force_find (name))
2662 force->destroy (); 2731 force->destroy ();
2663 2732
2664 object *force = get_archetype (FORCE_NAME); 2733 object *force = archetype::get (FORCE_NAME);
2665 2734
2666 force->slaying = name; 2735 force->slaying = name;
2667 force->force_set_timer (duration); 2736 force->force_set_timer (duration);
2668 force->flag [FLAG_APPLIED] = true; 2737 force->flag [FLAG_APPLIED] = true;
2669 2738
2753 return contr->mark; 2822 return contr->mark;
2754 else 2823 else
2755 return 0; 2824 return 0;
2756} 2825}
2757 2826
2827// put marked object first in the inventory
2828// this is used by identify-like spells so players can influence
2829// the order a bit.
2830void
2831object::splay_marked ()
2832{
2833 if (object *marked = mark ())
2834 splay (marked);
2835}
2836

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines