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.326 by root, Thu Apr 15 00:56:40 2010 UTC vs.
Revision 1.345 by root, Sun May 1 16:58:15 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
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
1035} 1008}
1036 1009
1037static struct freed_map : maptile 1010static struct freed_map : maptile
1038{ 1011{
1039 freed_map () 1012 freed_map ()
1013 : maptile (3, 3)
1040 { 1014 {
1041 path = "<freed objects map>"; 1015 path = "<freed objects map>";
1042 name = "/internal/freed_objects_map"; 1016 name = "/internal/freed_objects_map";
1043 width = 3;
1044 height = 3;
1045 no_drop = 1; 1017 no_drop = 1;
1046 no_reset = 1; 1018 no_reset = 1;
1047 1019
1048 alloc ();
1049 in_memory = MAP_ACTIVE; 1020 in_memory = MAP_ACTIVE;
1050 } 1021 }
1051 1022
1052 ~freed_map () 1023 ~freed_map ()
1053 { 1024 {
1146 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
1147 if (object *pl = visible_to ()) 1118 if (object *pl = visible_to ())
1148 esrv_del_item (pl->contr, count); 1119 esrv_del_item (pl->contr, count);
1149 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
1150 1121
1151 adjust_weight (env, -total_weight ()); 1122 adjust_weight (env, total_weight (), 0);
1152 1123
1153 object *pl = in_player (); 1124 object *pl = in_player ();
1154 1125
1155 /* we set up values so that it could be inserted into 1126 /* we set up values so that it could be inserted into
1156 * 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
1170 1141
1171 if (pl && pl->is_player ()) 1142 if (pl && pl->is_player ())
1172 { 1143 {
1173 if (expect_false (pl->contr->combat_ob == this)) 1144 if (expect_false (pl->contr->combat_ob == this))
1174 { 1145 {
1175 pl->apply (pl->contr->combat_ob, AP_UNAPPLY); 1146 pl->apply (pl->contr->combat_ob, AP_UNAPPLY | AP_IGNORE_CURSE);
1176 pl->contr->combat_ob = 0; 1147 pl->contr->combat_ob = 0;
1177 if (pl->contr->ranged_ob) pl->apply (pl->contr->ranged_ob); 1148 if (pl->contr->ranged_ob) pl->apply (pl->contr->ranged_ob);
1178 } 1149 }
1179 1150
1180 if (expect_false (pl->contr->ranged_ob == this)) 1151 if (expect_false (pl->contr->ranged_ob == this))
1181 { 1152 {
1182 pl->apply (pl->contr->ranged_ob, AP_UNAPPLY); 1153 pl->apply (pl->contr->ranged_ob, AP_UNAPPLY | AP_IGNORE_CURSE);
1183 pl->contr->ranged_ob = 0; 1154 pl->contr->ranged_ob = 0;
1184 if (pl->contr->combat_ob) pl->apply (pl->contr->combat_ob); 1155 if (pl->contr->combat_ob) pl->apply (pl->contr->combat_ob);
1185 } 1156 }
1186 1157
1187 pl->contr->queue_stats_update (); 1158 pl->contr->queue_stats_update ();
1374{ 1345{
1375 op->remove (); 1346 op->remove ();
1376 1347
1377 if (m == &freed_map)//D TODO: remove soon 1348 if (m == &freed_map)//D TODO: remove soon
1378 {//D 1349 {//D
1379 LOG (llevError | logBacktrace, "tries to insret object on freed objects map: %s", op->debug_desc ());//D 1350 LOG (llevError | logBacktrace, "tries to insert object on freed objects map: %s", op->debug_desc ());//D
1380 }//D 1351 }//D
1381 1352
1382 /* Ideally, the caller figures this out. However, it complicates a lot 1353 /* Ideally, the caller figures this out. However, it complicates a lot
1383 * of areas of callers (eg, anything that uses find_free_spot would now 1354 * of areas of callers (eg, anything that uses find_free_spot would now
1384 * need extra work 1355 * need extra work
1574 */ 1545 */
1575 1546
1576 /* if this is not the head or flag has been passed, don't check walk on status */ 1547 /* if this is not the head or flag has been passed, don't check walk on status */
1577 if (!(flag & INS_NO_WALK_ON) && op->is_head ()) 1548 if (!(flag & INS_NO_WALK_ON) && op->is_head ())
1578 { 1549 {
1579 if (check_move_on (op, originator)) 1550 if (check_move_on (op, originator, flag))
1580 return 0; 1551 return 0;
1581 1552
1582 /* If we are a multi part object, lets work our way through the check 1553 /* If we are a multi part object, let's work our way through the check
1583 * walk on's. 1554 * walk on's.
1584 */ 1555 */
1585 for (object *tmp = op->more; tmp; tmp = tmp->more) 1556 for (object *tmp = op->more; tmp; tmp = tmp->more)
1586 if (check_move_on (tmp, originator)) 1557 if (check_move_on (tmp, originator, flag))
1587 return 0; 1558 return 0;
1588 } 1559 }
1589 1560
1590 return op; 1561 return op;
1591} 1562}
1657 1628
1658 nr = min (nr, nrof); 1629 nr = min (nr, nrof);
1659 1630
1660 if (nrof > nr) 1631 if (nrof > nr)
1661 { 1632 {
1633 sint64 oweight = total_weight ();
1634
1662 nrof -= nr; 1635 nrof -= nr;
1663 adjust_weight (env, -weight * max (1, nr)); // carrying == 0
1664 1636
1665 if (object *pl = visible_to ()) 1637 if (object *pl = visible_to ())
1666 esrv_update_item (UPD_NROF, pl, this); 1638 esrv_update_item (UPD_NROF, pl, this);
1639
1640 adjust_weight (env, oweight, total_weight ());
1667 1641
1668 return true; 1642 return true;
1669 } 1643 }
1670 else 1644 else
1671 { 1645 {
1746 if (op->nrof) 1720 if (op->nrof)
1747 for (object *tmp = inv; tmp; tmp = tmp->below) 1721 for (object *tmp = inv; tmp; tmp = tmp->below)
1748 if (object::can_merge (tmp, op)) 1722 if (object::can_merge (tmp, op))
1749 { 1723 {
1750 /* return the original object and remove inserted object 1724 /* return the original object and remove inserted object
1751 (client needs the original object) */ 1725 (client prefers the original object) */
1726
1727 // carring must be 0 for mergable objects
1728 sint64 oweight = tmp->weight * tmp->nrof;
1729
1752 tmp->nrof += op->nrof; 1730 tmp->nrof += op->nrof;
1753 1731
1754 if (object *pl = tmp->visible_to ()) 1732 if (object *pl = tmp->visible_to ())
1755 esrv_update_item (UPD_NROF, pl, tmp); 1733 esrv_update_item (UPD_NROF, pl, tmp);
1756 1734
1757 adjust_weight (this, op->total_weight ()); 1735 adjust_weight (this, oweight, tmp->weight * tmp->nrof);
1758 1736
1759 op->destroy (); 1737 op->destroy ();
1760 op = tmp; 1738 op = tmp;
1761 goto inserted; 1739 goto inserted;
1762 } 1740 }
1778 op->flag [FLAG_REMOVED] = 0; 1756 op->flag [FLAG_REMOVED] = 0;
1779 1757
1780 if (object *pl = op->visible_to ()) 1758 if (object *pl = op->visible_to ())
1781 esrv_send_item (pl, op); 1759 esrv_send_item (pl, op);
1782 1760
1783 adjust_weight (this, op->total_weight ()); 1761 adjust_weight (this, 0, op->total_weight ());
1784 1762
1785inserted: 1763inserted:
1786 /* reset the light list and los of the players on the map */ 1764 /* reset the light list and los of the players on the map */
1787 if (op->glow_radius && is_on_map ()) 1765 if (op->glow_radius && is_on_map ())
1788 { 1766 {
1817 * MSW 2001-07-08: Check all objects on space, not just those below 1795 * MSW 2001-07-08: Check all objects on space, not just those below
1818 * object being inserted. insert_ob_in_map may not put new objects 1796 * object being inserted. insert_ob_in_map may not put new objects
1819 * on top. 1797 * on top.
1820 */ 1798 */
1821int 1799int
1822check_move_on (object *op, object *originator) 1800check_move_on (object *op, object *originator, int flags)
1823{ 1801{
1824 if (op->flag [FLAG_NO_APPLY]) 1802 if (op->flag [FLAG_NO_APPLY])
1825 return 0; 1803 return 0;
1826 1804
1827 object *tmp; 1805 object *tmp;
1886 1864
1887 /* Basically same logic as above, except now for actual apply. */ 1865 /* Basically same logic as above, except now for actual apply. */
1888 if ((!op->move_type && tmp->move_on & MOVE_WALK) || 1866 if ((!op->move_type && tmp->move_on & MOVE_WALK) ||
1889 ((op->move_type & tmp->move_on) && (op->move_type & ~tmp->move_on & ~tmp->move_block) == 0)) 1867 ((op->move_type & tmp->move_on) && (op->move_type & ~tmp->move_on & ~tmp->move_block) == 0))
1890 { 1868 {
1869 if ((flags & INS_NO_AUTO_EXIT)
1870 && (tmp->type == EXIT || tmp->type == TELEPORTER
1871 || tmp->type == HOLE || tmp->type == TRAPDOOR)) //TODO: temporary, fix exits instead
1872 continue;
1873
1891 move_apply (tmp, op, originator); 1874 move_apply (tmp, op, originator);
1892 1875
1893 if (op->destroyed ()) 1876 if (op->destroyed ())
1894 return 1; 1877 return 1;
1895 1878
2220{ 2203{
2221 return (ob1->x - ob2->x) * (ob1->x - ob2->x) + (ob1->y - ob2->y) * (ob1->y - ob2->y); 2204 return (ob1->x - ob2->x) * (ob1->x - ob2->x) + (ob1->y - ob2->y) * (ob1->y - ob2->y);
2222} 2205}
2223 2206
2224/* 2207/*
2225 * find_dir_2(delta-x,delta-y) will return a direction in which 2208 * find_dir_2(delta-x,delta-y) will return a direction value
2226 * an object which has subtracted the x and y coordinates of another 2209 * for running into direct [dx, dy].
2227 * object, needs to travel toward it. 2210 * (the opposite of crossfire's find_dir_2!)
2228 */ 2211 */
2229int 2212int
2230find_dir_2 (int x, int y) 2213find_dir_2 (int x, int y)
2231{ 2214{
2215#if 1 // new algorithm
2216 // this works by putting x, y into 16 sectors, which
2217 // are not equal sized, but are a better approximation
2218 // then the old algorithm, and then using a mapping
2219 // table to map it into a direction value.
2220 // basically, it maps these comparisons to each bit
2221 // bit #3: x < 0
2222 // bit #2: y < 0
2223 // bit #1: x > y
2224 // bit #0: x > 2y
2225
2226 static const uint8 dir[16] = {
2227 4, 5, 4, 3,
2228 2, 1, 2, 3,
2229 6, 5, 6, 7,
2230 8, 1, 8, 7,
2231 };
2232 int sector = 0;
2233
2234 // this is a bit ugly, but more likely to result in branchless code
2235 sector |= x < 0 ? 8 : 0;
2236 x = x < 0 ? -x : x; // abs
2237
2238 sector |= y < 0 ? 4 : 0;
2239 y = y < 0 ? -y : y; // abs
2240
2241 if (x > y)
2242 {
2243 sector |= 2;
2244
2245 if (x > y * 2)
2246 sector |= 1;
2247 }
2248 else
2249 {
2250 if (y > x * 2)
2251 sector |= 1;
2252 else if (!y)
2253 return 0; // x == 0 here
2254 }
2255
2256 return dir [sector];
2257#else // old algorithm
2232 int q; 2258 int q;
2233 2259
2234 if (y) 2260 if (y)
2235 q = x * 100 / y; 2261 q = 128 * x / y;
2236 else if (x) 2262 else if (x)
2237 q = -300 * x; 2263 q = -512 * x; // to make it > 309
2238 else 2264 else
2239 return 0; 2265 return 0;
2240 2266
2241 if (y > 0) 2267 if (y > 0)
2242 { 2268 {
2243 if (q < -242) 2269 if (q < -309) return 7;
2270 if (q < -52) return 6;
2271 if (q < 52) return 5;
2272 if (q < 309) return 4;
2273
2244 return 3; 2274 return 3;
2245 if (q < -41) 2275 }
2246 return 2; 2276 else
2247 if (q < 41) 2277 {
2248 return 1; 2278 if (q < -309) return 3;
2249 if (q < 242) 2279 if (q < -52) return 2;
2250 return 8; 2280 if (q < 52) return 1;
2281 if (q < 309) return 8;
2282
2251 return 7; 2283 return 7;
2252 } 2284 }
2253 2285#endif
2254 if (q < -242)
2255 return 7;
2256 if (q < -41)
2257 return 6;
2258 if (q < 41)
2259 return 5;
2260 if (q < 242)
2261 return 4;
2262
2263 return 3;
2264} 2286}
2265 2287
2266/* 2288/*
2267 * dirdiff(dir1, dir2) returns how many 45-degrees differences there is 2289 * dirdiff(dir1, dir2) returns how many 45-degrees differences there is
2268 * between two directions (which are expected to be absolute (see absdir()) 2290 * between two directions (which are expected to be absolute (see absdir())
2269 */ 2291 */
2270int 2292int
2271dirdiff (int dir1, int dir2) 2293dirdiff (int dir1, int dir2)
2272{ 2294{
2273 int d;
2274
2275 d = abs (dir1 - dir2); 2295 int d = abs (dir1 - dir2);
2276 if (d > 4)
2277 d = 8 - d;
2278 2296
2279 return d; 2297 return d > 4 ? 8 - d : d;
2280} 2298}
2281 2299
2282/* peterm: 2300/* peterm:
2283 * do LOS stuff for ball lightning. Go after the closest VISIBLE monster. 2301 * do LOS stuff for ball lightning. Go after the closest VISIBLE monster.
2284 * Basically, this is a table of directions, and what directions 2302 * Basically, this is a table of directions, and what directions
2434 return tmp; 2452 return tmp;
2435 2453
2436 return 0; 2454 return 0;
2437} 2455}
2438 2456
2457/* Zero the key_values on op, decrementing the shared-string
2458 * refcounts and freeing the links.
2459 */
2460void
2461key_values::clear ()
2462{
2463 for (key_value *kvp = first; kvp; )
2464 {
2465 key_value *next = kvp->next;
2466 delete kvp;
2467 kvp = next;
2468 }
2469
2470 first = 0;
2471}
2472
2439shstr_tmp 2473shstr_tmp
2440object::kv_get (shstr_tmp key) const 2474key_values::get (shstr_tmp key) const
2441{ 2475{
2442 for (key_value *kv = key_values; kv; kv = kv->next) 2476 for (key_value *kv = first; kv; kv = kv->next)
2443 if (kv->key == key) 2477 if (kv->key == key)
2444 return kv->value; 2478 return kv->value;
2445 2479
2446 return shstr (); 2480 return shstr ();
2447} 2481}
2448 2482
2449void 2483void
2484key_values::add (shstr_tmp key, shstr_tmp value)
2485{
2486 key_value *kv = new key_value;
2487
2488 kv->next = first;
2489 kv->key = key;
2490 kv->value = value;
2491
2492 first = kv;
2493}
2494
2495void
2450object::kv_set (shstr_tmp key, shstr_tmp value) 2496key_values::set (shstr_tmp key, shstr_tmp value)
2451{ 2497{
2452 for (key_value *kv = key_values; kv; kv = kv->next) 2498 for (key_value *kv = first; kv; kv = kv->next)
2453 if (kv->key == key) 2499 if (kv->key == key)
2454 { 2500 {
2455 kv->value = value; 2501 kv->value = value;
2456 return; 2502 return;
2457 } 2503 }
2458 2504
2459 key_value *kv = new key_value; 2505 add (key, value);
2460
2461 kv->next = key_values;
2462 kv->key = key;
2463 kv->value = value;
2464
2465 key_values = kv;
2466} 2506}
2467 2507
2468void 2508void
2469object::kv_del (shstr_tmp key) 2509key_values::del (shstr_tmp key)
2470{ 2510{
2471 for (key_value **kvp = &key_values; *kvp; kvp = &(*kvp)->next) 2511 for (key_value **kvp = &first; *kvp; kvp = &(*kvp)->next)
2472 if ((*kvp)->key == key) 2512 if ((*kvp)->key == key)
2473 { 2513 {
2474 key_value *kv = *kvp; 2514 key_value *kv = *kvp;
2475 *kvp = (*kvp)->next; 2515 *kvp = (*kvp)->next;
2476 delete kv; 2516 delete kv;
2477 return; 2517 return;
2478 } 2518 }
2519}
2520
2521void
2522key_values::reverse ()
2523{
2524 key_value *prev = 0;
2525 key_value *head = first;
2526
2527 while (head)
2528 {
2529 key_value *node = head;
2530 head = head->next;
2531 node->next = prev;
2532 prev = node;
2533 }
2534
2535 first = prev;
2536}
2537
2538key_values &
2539key_values::operator =(const key_values &kv)
2540{
2541 clear ();
2542
2543 for (key_value *kvp = kv.first; kvp; kvp = kvp->next)
2544 add (kvp->key, kvp->value);
2545
2546 reverse ();
2479} 2547}
2480 2548
2481object::depth_iterator::depth_iterator (object *container) 2549object::depth_iterator::depth_iterator (object *container)
2482: iterator_base (container) 2550: iterator_base (container)
2483{ 2551{
2663object::force_add (shstr_tmp name, int duration) 2731object::force_add (shstr_tmp name, int duration)
2664{ 2732{
2665 if (object *force = force_find (name)) 2733 if (object *force = force_find (name))
2666 force->destroy (); 2734 force->destroy ();
2667 2735
2668 object *force = get_archetype (FORCE_NAME); 2736 object *force = archetype::get (FORCE_NAME);
2669 2737
2670 force->slaying = name; 2738 force->slaying = name;
2671 force->force_set_timer (duration); 2739 force->force_set_timer (duration);
2672 force->flag [FLAG_APPLIED] = true; 2740 force->flag [FLAG_APPLIED] = true;
2673 2741
2757 return contr->mark; 2825 return contr->mark;
2758 else 2826 else
2759 return 0; 2827 return 0;
2760} 2828}
2761 2829
2830// put marked object first in the inventory
2831// this is used by identify-like spells so players can influence
2832// the order a bit.
2833void
2834object::splay_marked ()
2835{
2836 if (object *marked = mark ())
2837 splay (marked);
2838}
2839

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines