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 |
… | |
… | |
233 | |
233 | |
234 | /* 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. */ |
235 | static bool |
235 | static bool |
236 | compare_ob_value_lists_one (const object *wants, const object *has) |
236 | compare_ob_value_lists_one (const object *wants, const object *has) |
237 | { |
237 | { |
238 | /* n-squared behaviour (see kv_get), but I'm hoping both |
238 | /* n-squared behaviour (see kv.get), but I'm hoping both |
239 | * 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 |
240 | * different structure or at least keep the lists sorted... |
240 | * different structure or at least keep the lists sorted... |
241 | */ |
241 | */ |
242 | |
242 | |
243 | /* For each field in wants, */ |
243 | /* For each field in wants, */ |
244 | for (key_value *kv = wants->key_values; kv; kv = kv->next) |
244 | for (key_value *kv = wants->kv.first; kv; kv = kv->next) |
245 | if (has->kv_get (kv->key) != kv->value) |
245 | if (has->kv.get (kv->key) != kv->value) |
246 | return false; |
246 | return false; |
247 | |
247 | |
248 | /* 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. */ |
249 | return true; |
249 | return true; |
250 | } |
250 | } |
… | |
… | |
274 | */ |
274 | */ |
275 | bool object::can_merge_slow (object *ob1, object *ob2) |
275 | bool object::can_merge_slow (object *ob1, object *ob2) |
276 | { |
276 | { |
277 | /* A couple quick sanity checks */ |
277 | /* A couple quick sanity checks */ |
278 | if (ob1 == ob2 |
278 | if (ob1 == ob2 |
279 | || ob1->type != ob2->type |
279 | || ob1->type != ob2->type |
280 | || ob1->value != ob2->value |
280 | || ob1->value != ob2->value |
281 | || ob1->name != ob2->name |
281 | || ob1->name != ob2->name |
|
|
282 | || ob1->custom_name != ob2->custom_name |
282 | || fabs (ob1->speed - ob2->speed) >= MIN_ACTIVE_SPEED) |
283 | || fabs (ob1->speed - ob2->speed) >= MIN_ACTIVE_SPEED) |
283 | return 0; |
284 | return 0; |
284 | |
285 | |
285 | /* Do not merge objects if nrof would overflow, assume nrof |
286 | /* Do not merge objects if nrof would overflow, assume nrof |
286 | * is always 0 .. 2**31-1 */ |
287 | * is always 0 .. 2**31-1 */ |
… | |
… | |
372 | if (ob1->level != ob2->level) |
373 | if (ob1->level != ob2->level) |
373 | return 0; |
374 | return 0; |
374 | break; |
375 | break; |
375 | } |
376 | } |
376 | |
377 | |
377 | if (ob1->key_values || ob2->key_values) |
378 | if (!ob1->kv.empty () || !ob2->kv.empty ()) |
378 | { |
379 | { |
379 | /* At least one of these has key_values. */ |
380 | /* At least one of these has key_values. */ |
380 | if ((!ob1->key_values) != (!ob2->key_values)) |
381 | if (ob1->kv.empty () != ob2->kv.empty ()) |
381 | return 0; /* One has fields, but the other one doesn't. */ |
382 | return 0; /* One has fields, but the other one doesn't. */ |
382 | |
383 | |
383 | if (!compare_ob_value_lists (ob1, ob2)) |
384 | if (!compare_ob_value_lists (ob1, ob2)) |
384 | return 0; |
385 | return 0; |
385 | } |
386 | } |
… | |
… | |
598 | } |
599 | } |
599 | |
600 | |
600 | this->owner = owner; |
601 | this->owner = owner; |
601 | } |
602 | } |
602 | |
603 | |
603 | /* Zero the key_values on op, decrementing the shared-string |
|
|
604 | * refcounts and freeing the links. |
|
|
605 | */ |
|
|
606 | static void |
|
|
607 | free_key_values (object *op) |
|
|
608 | { |
|
|
609 | for (key_value *i = op->key_values; i; ) |
|
|
610 | { |
|
|
611 | key_value *next = i->next; |
|
|
612 | delete i; |
|
|
613 | |
|
|
614 | i = next; |
|
|
615 | } |
|
|
616 | |
|
|
617 | op->key_values = 0; |
|
|
618 | } |
|
|
619 | |
|
|
620 | /* |
604 | /* |
621 | * copy_to first frees everything allocated by the dst object, |
605 | * copy_to first frees everything allocated by the dst object, |
622 | * and then copies the contents of itself into the second |
606 | * and then copies the contents of itself into the second |
623 | * object, allocating what needs to be allocated. Basically, any |
607 | * object, allocating what needs to be allocated. Basically, any |
624 | * 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, |
… | |
… | |
628 | void |
612 | void |
629 | object::copy_to (object *dst) |
613 | object::copy_to (object *dst) |
630 | { |
614 | { |
631 | dst->remove (); |
615 | dst->remove (); |
632 | *(object_copy *)dst = *this; |
616 | *(object_copy *)dst = *this; |
|
|
617 | |
|
|
618 | // maybe move to object_copy? |
|
|
619 | dst->kv = kv; |
|
|
620 | |
633 | dst->flag [FLAG_REMOVED] = true; |
621 | dst->flag [FLAG_REMOVED] = true; |
634 | |
|
|
635 | /* Copy over key_values, if any. */ |
|
|
636 | if (key_values) |
|
|
637 | { |
|
|
638 | key_value *tail = 0; |
|
|
639 | dst->key_values = 0; |
|
|
640 | |
|
|
641 | for (key_value *i = key_values; i; i = i->next) |
|
|
642 | { |
|
|
643 | key_value *new_link = new key_value; |
|
|
644 | |
|
|
645 | new_link->next = 0; |
|
|
646 | new_link->key = i->key; |
|
|
647 | new_link->value = i->value; |
|
|
648 | |
|
|
649 | /* Try and be clever here, too. */ |
|
|
650 | if (!dst->key_values) |
|
|
651 | { |
|
|
652 | dst->key_values = new_link; |
|
|
653 | tail = new_link; |
|
|
654 | } |
|
|
655 | else |
|
|
656 | { |
|
|
657 | tail->next = new_link; |
|
|
658 | tail = new_link; |
|
|
659 | } |
|
|
660 | } |
|
|
661 | } |
|
|
662 | |
|
|
663 | dst->activate (); |
622 | dst->activate (); |
664 | } |
623 | } |
665 | |
624 | |
666 | void |
625 | void |
667 | object::instantiate () |
626 | object::instantiate () |
668 | { |
627 | { |
669 | if (!uuid.seq) // HACK |
628 | if (!uuid.seq) // HACK |
670 | uuid = UUID::gen (); |
629 | uuid = UUID::gen (); |
671 | |
630 | |
672 | // 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 |
673 | if (flag [FLAG_RANDOM_SPEED] && speed) |
632 | if (flag [FLAG_RANDOM_SPEED] && speed) |
674 | speed_left = - speed - rndm (); // TODO animation |
633 | speed_left = - speed - rndm (); // TODO animation |
675 | else |
634 | else |
676 | speed_left = -1.; |
635 | speed_left = -1.; |
677 | |
636 | |
… | |
… | |
830 | |
789 | |
831 | object::~object () |
790 | object::~object () |
832 | { |
791 | { |
833 | unlink (); |
792 | unlink (); |
834 | |
793 | |
835 | free_key_values (this); |
794 | kv.clear (); |
836 | } |
795 | } |
837 | |
796 | |
838 | void object::link () |
797 | void object::link () |
839 | { |
798 | { |
840 | assert (!index);//D |
799 | assert (!index);//D |
… | |
… | |
1386 | { |
1345 | { |
1387 | op->remove (); |
1346 | op->remove (); |
1388 | |
1347 | |
1389 | if (m == &freed_map)//D TODO: remove soon |
1348 | if (m == &freed_map)//D TODO: remove soon |
1390 | {//D |
1349 | {//D |
1391 | 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 |
1392 | }//D |
1351 | }//D |
1393 | |
1352 | |
1394 | /* Ideally, the caller figures this out. However, it complicates a lot |
1353 | /* Ideally, the caller figures this out. However, it complicates a lot |
1395 | * 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 |
1396 | * need extra work |
1355 | * need extra work |
… | |
… | |
2493 | return tmp; |
2452 | return tmp; |
2494 | |
2453 | |
2495 | return 0; |
2454 | return 0; |
2496 | } |
2455 | } |
2497 | |
2456 | |
|
|
2457 | /* Zero the key_values on op, decrementing the shared-string |
|
|
2458 | * refcounts and freeing the links. |
|
|
2459 | */ |
|
|
2460 | void |
|
|
2461 | key_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 | |
2498 | shstr_tmp |
2473 | shstr_tmp |
2499 | object::kv_get (shstr_tmp key) const |
2474 | key_values::get (shstr_tmp key) const |
2500 | { |
2475 | { |
2501 | for (key_value *kv = key_values; kv; kv = kv->next) |
2476 | for (key_value *kv = first; kv; kv = kv->next) |
2502 | if (kv->key == key) |
2477 | if (kv->key == key) |
2503 | return kv->value; |
2478 | return kv->value; |
2504 | |
2479 | |
2505 | return shstr (); |
2480 | return shstr (); |
2506 | } |
2481 | } |
2507 | |
2482 | |
2508 | void |
2483 | void |
|
|
2484 | key_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 | |
|
|
2495 | void |
2509 | object::kv_set (shstr_tmp key, shstr_tmp value) |
2496 | key_values::set (shstr_tmp key, shstr_tmp value) |
2510 | { |
2497 | { |
2511 | for (key_value *kv = key_values; kv; kv = kv->next) |
2498 | for (key_value *kv = first; kv; kv = kv->next) |
2512 | if (kv->key == key) |
2499 | if (kv->key == key) |
2513 | { |
2500 | { |
2514 | kv->value = value; |
2501 | kv->value = value; |
2515 | return; |
2502 | return; |
2516 | } |
2503 | } |
2517 | |
2504 | |
2518 | key_value *kv = new key_value; |
2505 | add (key, value); |
2519 | |
|
|
2520 | kv->next = key_values; |
|
|
2521 | kv->key = key; |
|
|
2522 | kv->value = value; |
|
|
2523 | |
|
|
2524 | key_values = kv; |
|
|
2525 | } |
2506 | } |
2526 | |
2507 | |
2527 | void |
2508 | void |
2528 | object::kv_del (shstr_tmp key) |
2509 | key_values::del (shstr_tmp key) |
2529 | { |
2510 | { |
2530 | for (key_value **kvp = &key_values; *kvp; kvp = &(*kvp)->next) |
2511 | for (key_value **kvp = &first; *kvp; kvp = &(*kvp)->next) |
2531 | if ((*kvp)->key == key) |
2512 | if ((*kvp)->key == key) |
2532 | { |
2513 | { |
2533 | key_value *kv = *kvp; |
2514 | key_value *kv = *kvp; |
2534 | *kvp = (*kvp)->next; |
2515 | *kvp = (*kvp)->next; |
2535 | delete kv; |
2516 | delete kv; |
2536 | return; |
2517 | return; |
2537 | } |
2518 | } |
|
|
2519 | } |
|
|
2520 | |
|
|
2521 | void |
|
|
2522 | key_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 | |
|
|
2538 | key_values & |
|
|
2539 | key_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 (); |
2538 | } |
2547 | } |
2539 | |
2548 | |
2540 | object::depth_iterator::depth_iterator (object *container) |
2549 | object::depth_iterator::depth_iterator (object *container) |
2541 | : iterator_base (container) |
2550 | : iterator_base (container) |
2542 | { |
2551 | { |
… | |
… | |
2722 | object::force_add (shstr_tmp name, int duration) |
2731 | object::force_add (shstr_tmp name, int duration) |
2723 | { |
2732 | { |
2724 | if (object *force = force_find (name)) |
2733 | if (object *force = force_find (name)) |
2725 | force->destroy (); |
2734 | force->destroy (); |
2726 | |
2735 | |
2727 | object *force = get_archetype (FORCE_NAME); |
2736 | object *force = archetype::get (FORCE_NAME); |
2728 | |
2737 | |
2729 | force->slaying = name; |
2738 | force->slaying = name; |
2730 | force->force_set_timer (duration); |
2739 | force->force_set_timer (duration); |
2731 | force->flag [FLAG_APPLIED] = true; |
2740 | force->flag [FLAG_APPLIED] = true; |
2732 | |
2741 | |
… | |
… | |
2816 | return contr->mark; |
2825 | return contr->mark; |
2817 | else |
2826 | else |
2818 | return 0; |
2827 | return 0; |
2819 | } |
2828 | } |
2820 | |
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. |
|
|
2833 | void |
|
|
2834 | object::splay_marked () |
|
|
2835 | { |
|
|
2836 | if (object *marked = mark ()) |
|
|
2837 | splay (marked); |
|
|
2838 | } |
|
|
2839 | |