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.337 by root, Thu May 6 21:45:49 2010 UTC vs.
Revision 1.353 by root, Fri Jan 27 22:00:39 2012 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,2012 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 }
579 } 599 }
580 600
581 this->owner = owner; 601 this->owner = owner;
582} 602}
583 603
584/* Zero the key_values on op, decrementing the shared-string
585 * refcounts and freeing the links.
586 */
587static void
588free_key_values (object *op)
589{
590 for (key_value *i = op->key_values; i; )
591 {
592 key_value *next = i->next;
593 delete i;
594
595 i = next;
596 }
597
598 op->key_values = 0;
599}
600
601/* 604/*
602 * copy_to first frees everything allocated by the dst object, 605 * copy_to first frees everything allocated by the dst object,
603 * and then copies the contents of itself into the second 606 * and then copies the contents of itself into the second
604 * object, allocating what needs to be allocated. Basically, any 607 * object, allocating what needs to be allocated. Basically, any
605 * data that is malloc'd needs to be re-malloc/copied. Otherwise, 608 * data that is malloc'd needs to be re-malloc/copied. Otherwise,
609void 612void
610object::copy_to (object *dst) 613object::copy_to (object *dst)
611{ 614{
612 dst->remove (); 615 dst->remove ();
613 *(object_copy *)dst = *this; 616 *(object_copy *)dst = *this;
617
618 // maybe move to object_copy?
619 dst->kv = kv;
620
614 dst->flag [FLAG_REMOVED] = true; 621 dst->flag [FLAG_REMOVED] = true;
615
616 /* Copy over key_values, if any. */
617 if (key_values)
618 {
619 key_value *tail = 0;
620 dst->key_values = 0;
621
622 for (key_value *i = key_values; i; i = i->next)
623 {
624 key_value *new_link = new key_value;
625
626 new_link->next = 0;
627 new_link->key = i->key;
628 new_link->value = i->value;
629
630 /* Try and be clever here, too. */
631 if (!dst->key_values)
632 {
633 dst->key_values = new_link;
634 tail = new_link;
635 }
636 else
637 {
638 tail->next = new_link;
639 tail = new_link;
640 }
641 }
642 }
643
644 dst->activate (); 622 dst->activate ();
645} 623}
646 624
647void 625void
648object::instantiate () 626object::instantiate ()
649{ 627{
650 if (!uuid.seq) // HACK 628 if (!uuid.seq) // HACK
651 uuid = UUID::gen (); 629 uuid = UUID::gen ();
652 630
653 // 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
654 if (flag [FLAG_RANDOM_SPEED] && speed) 632 if (flag [FLAG_RANDOM_SPEED] && speed)
655 speed_left = - speed - rndm (); // TODO animation 633 speed_left = - speed - rndm (); // TODO animation
656 else 634 else
657 speed_left = -1.; 635 speed_left = -1.;
658 636
759 } 737 }
760 738
761 mapspace &m = op->ms (); 739 mapspace &m = op->ms ();
762 740
763 if (!(m.flags_ & P_UPTODATE)) 741 if (!(m.flags_ & P_UPTODATE))
764 /* nop */; 742 m.update_up (); // nothing to do except copy up
765 else if (action == UP_OBJ_INSERT) 743 else if (action == UP_OBJ_INSERT)
766 { 744 {
767#if 0 745#if 0
768 // this is likely overkill, TODO: revisit (schmorp) 746 // this is likely overkill, TODO: revisit (schmorp)
769 if ((op->flag [FLAG_BLOCKSVIEW] && !(m.flags_ & P_BLOCKSVIEW)) 747 if ((op->flag [FLAG_BLOCKSVIEW] && !(m.flags_ & P_BLOCKSVIEW))
790 * that is being removed. 768 * that is being removed.
791 */ 769 */
792 else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE) 770 else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE)
793 m.invalidate (); 771 m.invalidate ();
794 else if (action == UP_OBJ_FACE) 772 else if (action == UP_OBJ_FACE)
795 /* Nothing to do for that case */ ; 773 m.update_up (); // nothing to do for that case, except copy up
796 else 774 else
797 LOG (llevError, "update_object called with invalid action: %d\n", action); 775 LOG (llevError, "update_object called with invalid action: %d\n", action);
798 776
799 if (op->more) 777 if (op->more)
800 update_object (op->more, action); 778 update_object (op->more, action);
811 789
812object::~object () 790object::~object ()
813{ 791{
814 unlink (); 792 unlink ();
815 793
816 free_key_values (this); 794 kv.clear ();
817} 795}
818 796
819void object::link () 797void object::link ()
820{ 798{
821 assert (!index);//D 799 assert (!index);//D
920 * if some form of movement is allowed, let objects 898 * if some form of movement is allowed, let objects
921 * drop on that space. 899 * drop on that space.
922 */ 900 */
923 if (!drop_to_ground 901 if (!drop_to_ground
924 || !map 902 || !map
925 || map->in_memory != MAP_ACTIVE 903 || !map->linkable ()
926 || map->no_drop 904 || map->no_drop
927 || ms ().move_block == MOVE_ALL) 905 || ms ().move_block == MOVE_ALL)
928 { 906 {
929 while (inv) 907 while (inv)
930 inv->destroy (); 908 inv->destroy ();
1027 1005
1028 freelist = li; 1006 freelist = li;
1029 ++free_count; 1007 ++free_count;
1030} 1008}
1031 1009
1032static struct freed_map : maptile
1033{
1034 freed_map ()
1035 : maptile (3, 3)
1036 {
1037 path = "<freed objects map>";
1038 name = "/internal/freed_objects_map";
1039 no_drop = 1;
1040 no_reset = 1;
1041
1042 in_memory = MAP_ACTIVE;
1043 }
1044
1045 ~freed_map ()
1046 {
1047 destroy ();
1048 }
1049} freed_map; // freed objects are moved here to avoid crashes
1050
1051void 1010void
1052object::do_destroy () 1011object::do_destroy ()
1053{ 1012{
1054 if (flag [FLAG_IS_LINKED]) 1013 if (flag [FLAG_IS_LINKED])
1055 remove_link (); 1014 remove_link ();
1163 1122
1164 if (pl && pl->is_player ()) 1123 if (pl && pl->is_player ())
1165 { 1124 {
1166 if (expect_false (pl->contr->combat_ob == this)) 1125 if (expect_false (pl->contr->combat_ob == this))
1167 { 1126 {
1168 pl->apply (pl->contr->combat_ob, AP_UNAPPLY); 1127 pl->apply (pl->contr->combat_ob, AP_UNAPPLY | AP_IGNORE_CURSE);
1169 pl->contr->combat_ob = 0; 1128 pl->contr->combat_ob = 0;
1170 if (pl->contr->ranged_ob) pl->apply (pl->contr->ranged_ob); 1129 if (pl->contr->ranged_ob) pl->apply (pl->contr->ranged_ob);
1171 } 1130 }
1172 1131
1173 if (expect_false (pl->contr->ranged_ob == this)) 1132 if (expect_false (pl->contr->ranged_ob == this))
1174 { 1133 {
1175 pl->apply (pl->contr->ranged_ob, AP_UNAPPLY); 1134 pl->apply (pl->contr->ranged_ob, AP_UNAPPLY | AP_IGNORE_CURSE);
1176 pl->contr->ranged_ob = 0; 1135 pl->contr->ranged_ob = 0;
1177 if (pl->contr->combat_ob) pl->apply (pl->contr->combat_ob); 1136 if (pl->contr->combat_ob) pl->apply (pl->contr->combat_ob);
1178 } 1137 }
1179 1138
1180 pl->contr->queue_stats_update (); 1139 pl->contr->queue_stats_update ();
1220 1179
1221 above = 0; 1180 above = 0;
1222 below = 0; 1181 below = 0;
1223 1182
1224 ms.invalidate (); 1183 ms.invalidate ();
1225
1226 if (map->in_memory == MAP_SAVING)
1227 return;
1228 1184
1229 int check_walk_off = !flag [FLAG_NO_APPLY]; 1185 int check_walk_off = !flag [FLAG_NO_APPLY];
1230 1186
1231 if (object *pl = ms.player ()) 1187 if (object *pl = ms.player ())
1232 { 1188 {
1367{ 1323{
1368 op->remove (); 1324 op->remove ();
1369 1325
1370 if (m == &freed_map)//D TODO: remove soon 1326 if (m == &freed_map)//D TODO: remove soon
1371 {//D 1327 {//D
1372 LOG (llevError | logBacktrace, "tries to insret object on freed objects map: %s", op->debug_desc ());//D 1328 LOG (llevError | logBacktrace, "tries to insert object on freed objects map: %s", op->debug_desc ());//D
1373 }//D 1329 }//D
1374 1330
1375 /* Ideally, the caller figures this out. However, it complicates a lot 1331 /* Ideally, the caller figures this out. However, it complicates a lot
1376 * of areas of callers (eg, anything that uses find_free_spot would now 1332 * of areas of callers (eg, anything that uses find_free_spot would now
1377 * need extra work 1333 * need extra work
2052 */ 2008 */
2053int 2009int
2054find_free_spot (const object *ob, maptile *m, int x, int y, int start, int stop) 2010find_free_spot (const object *ob, maptile *m, int x, int y, int start, int stop)
2055{ 2011{
2056 int altern[SIZEOFFREE]; 2012 int altern[SIZEOFFREE];
2057 int index = 0, flag; 2013 int index = 0;
2058 2014
2059 for (int i = start; i < stop; i++) 2015 for (int i = start; i < stop; i++)
2060 { 2016 {
2061 mapxy pos (m, x, y); pos.move (i); 2017 mapxy pos (m, x, y); pos.move (i);
2062 2018
2174 * there is capable of. 2130 * there is capable of.
2175 */ 2131 */
2176int 2132int
2177find_dir (maptile *m, int x, int y, object *exclude) 2133find_dir (maptile *m, int x, int y, object *exclude)
2178{ 2134{
2179 int max = SIZEOFFREE, mflags; 2135 int max = SIZEOFFREE;
2180 MoveType move_type; 2136 MoveType move_type;
2181 2137
2182 if (exclude && exclude->head_ () != exclude) 2138 if (exclude && exclude->head_ () != exclude)
2183 { 2139 {
2184 exclude = exclude->head; 2140 exclude = exclude->head;
2435 return /*who->flag [FLAG_WIZ]|| */ 2391 return /*who->flag [FLAG_WIZ]|| */
2436 (item->weight > 0 && !item->flag [FLAG_NO_PICK] && 2392 (item->weight > 0 && !item->flag [FLAG_NO_PICK] &&
2437 !item->flag [FLAG_ALIVE] && !item->invisible && (who->is_player () || item->weight < who->weight / 3)); 2393 !item->flag [FLAG_ALIVE] && !item->invisible && (who->is_player () || item->weight < who->weight / 3));
2438} 2394}
2439 2395
2396//-GPL
2397
2440/* 2398/*
2441 * create clone from object to another 2399 * create clone from object to another
2442 */ 2400 */
2443object * 2401object *
2444object::deep_clone () 2402object::deep_clone ()
2474 return tmp; 2432 return tmp;
2475 2433
2476 return 0; 2434 return 0;
2477} 2435}
2478 2436
2437/* Zero the key_values on op, decrementing the shared-string
2438 * refcounts and freeing the links.
2439 */
2440void
2441key_values::clear ()
2442{
2443 for (key_value *kvp = first; kvp; )
2444 {
2445 key_value *next = kvp->next;
2446 delete kvp;
2447 kvp = next;
2448 }
2449
2450 first = 0;
2451}
2452
2479shstr_tmp 2453shstr_tmp
2480object::kv_get (shstr_tmp key) const 2454key_values::get (shstr_tmp key) const
2481{ 2455{
2482 for (key_value *kv = key_values; kv; kv = kv->next) 2456 for (key_value *kv = first; kv; kv = kv->next)
2483 if (kv->key == key) 2457 if (kv->key == key)
2484 return kv->value; 2458 return kv->value;
2485 2459
2486 return shstr (); 2460 return shstr ();
2487} 2461}
2488 2462
2489void 2463void
2464key_values::add (shstr_tmp key, shstr_tmp value)
2465{
2466 key_value *kv = new key_value;
2467
2468 kv->next = first;
2469 kv->key = key;
2470 kv->value = value;
2471
2472 first = kv;
2473}
2474
2475void
2490object::kv_set (shstr_tmp key, shstr_tmp value) 2476key_values::set (shstr_tmp key, shstr_tmp value)
2491{ 2477{
2492 for (key_value *kv = key_values; kv; kv = kv->next) 2478 for (key_value *kv = first; kv; kv = kv->next)
2493 if (kv->key == key) 2479 if (kv->key == key)
2494 { 2480 {
2495 kv->value = value; 2481 kv->value = value;
2496 return; 2482 return;
2497 } 2483 }
2498 2484
2499 key_value *kv = new key_value; 2485 add (key, value);
2500
2501 kv->next = key_values;
2502 kv->key = key;
2503 kv->value = value;
2504
2505 key_values = kv;
2506} 2486}
2507 2487
2508void 2488void
2509object::kv_del (shstr_tmp key) 2489key_values::del (shstr_tmp key)
2510{ 2490{
2511 for (key_value **kvp = &key_values; *kvp; kvp = &(*kvp)->next) 2491 for (key_value **kvp = &first; *kvp; kvp = &(*kvp)->next)
2512 if ((*kvp)->key == key) 2492 if ((*kvp)->key == key)
2513 { 2493 {
2514 key_value *kv = *kvp; 2494 key_value *kv = *kvp;
2515 *kvp = (*kvp)->next; 2495 *kvp = (*kvp)->next;
2516 delete kv; 2496 delete kv;
2517 return; 2497 return;
2518 } 2498 }
2499}
2500
2501void
2502key_values::reverse ()
2503{
2504 key_value *prev = 0;
2505 key_value *head = first;
2506
2507 while (head)
2508 {
2509 key_value *node = head;
2510 head = head->next;
2511 node->next = prev;
2512 prev = node;
2513 }
2514
2515 first = prev;
2516}
2517
2518key_values &
2519key_values::operator =(const key_values &kv)
2520{
2521 clear ();
2522
2523 for (key_value *kvp = kv.first; kvp; kvp = kvp->next)
2524 add (kvp->key, kvp->value);
2525
2526 reverse ();
2519} 2527}
2520 2528
2521object::depth_iterator::depth_iterator (object *container) 2529object::depth_iterator::depth_iterator (object *container)
2522: iterator_base (container) 2530: iterator_base (container)
2523{ 2531{
2606object::region () const 2614object::region () const
2607{ 2615{
2608 return map ? map->region (x, y) 2616 return map ? map->region (x, y)
2609 : region::default_region (); 2617 : region::default_region ();
2610} 2618}
2619
2620//+GPL
2611 2621
2612void 2622void
2613object::open_container (object *new_container) 2623object::open_container (object *new_container)
2614{ 2624{
2615 if (container == new_container) 2625 if (container == new_container)
2673 } 2683 }
2674// else if (!old_container->env && contr && contr->ns) 2684// else if (!old_container->env && contr && contr->ns)
2675// contr->ns->floorbox_reset (); 2685// contr->ns->floorbox_reset ();
2676} 2686}
2677 2687
2688//-GPL
2689
2690// prefetch some flat area around the player
2691static void
2692prefetch_surrounding_area (object *op, maptile *map, int range)
2693{
2694 for (maprect *rect = map->split_to_tiles (mapwalk_buf,
2695 op->x - range , op->y - range ,
2696 op->x + range + 1, op->y + range + 1);
2697 rect->m;
2698 ++rect)
2699 {
2700 rect->m->touch ();
2701 rect->m->activate ();
2702 }
2703}
2704
2705// prefetch a generous area around the player, also up and down
2706void
2707object::prefetch_surrounding_maps ()
2708{
2709 prefetch_surrounding_area (this, map, 40);
2710
2711 if (maptile *m = map->tile_available (TILE_DOWN))
2712 prefetch_surrounding_area (this, m, 20);
2713
2714 if (maptile *m = map->tile_available (TILE_UP))
2715 prefetch_surrounding_area (this, m, 20);
2716}
2717
2718//+GPL
2719
2678object * 2720object *
2679object::force_find (shstr_tmp name) 2721object::force_find (shstr_tmp name)
2680{ 2722{
2681 /* cycle through his inventory to look for the MARK we want to 2723 /* cycle through his inventory to look for the MARK we want to
2682 * place 2724 * place
2686 return splay (tmp); 2728 return splay (tmp);
2687 2729
2688 return 0; 2730 return 0;
2689} 2731}
2690 2732
2691//-GPL
2692
2693void 2733void
2694object::force_set_timer (int duration) 2734object::force_set_timer (int duration)
2695{ 2735{
2696 this->duration = 1; 2736 this->duration = 1;
2697 this->speed_left = -1.f; 2737 this->speed_left = -1.f;
2703object::force_add (shstr_tmp name, int duration) 2743object::force_add (shstr_tmp name, int duration)
2704{ 2744{
2705 if (object *force = force_find (name)) 2745 if (object *force = force_find (name))
2706 force->destroy (); 2746 force->destroy ();
2707 2747
2708 object *force = get_archetype (FORCE_NAME); 2748 object *force = archetype::get (FORCE_NAME);
2709 2749
2710 force->slaying = name; 2750 force->slaying = name;
2711 force->force_set_timer (duration); 2751 force->force_set_timer (duration);
2712 force->flag [FLAG_APPLIED] = true; 2752 force->flag [FLAG_APPLIED] = true;
2713 2753
2797 return contr->mark; 2837 return contr->mark;
2798 else 2838 else
2799 return 0; 2839 return 0;
2800} 2840}
2801 2841
2842// put marked object first in the inventory
2843// this is used by identify-like spells so players can influence
2844// the order a bit.
2845void
2846object::splay_marked ()
2847{
2848 if (object *marked = mark ())
2849 splay (marked);
2850}
2851

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines