1 | /* |
1 | /* |
2 | * static char *rcsid_object_c = |
2 | * static char *rcsid_object_c = |
3 | * "$Id: object.C,v 1.18 2006/09/08 16:51:42 root Exp $"; |
3 | * "$Id: object.C,v 1.23 2006/09/10 14:54:02 root Exp $"; |
4 | */ |
4 | */ |
5 | |
5 | |
6 | /* |
6 | /* |
7 | CrossFire, A Multiplayer game for X-windows |
7 | CrossFire, A Multiplayer game for X-windows |
8 | |
8 | |
… | |
… | |
54 | {0,9,10,13,14,17,18,21,22,25,26,27,30,31,32,33,36,37,39,39,42,43,44,45, |
54 | {0,9,10,13,14,17,18,21,22,25,26,27,30,31,32,33,36,37,39,39,42,43,44,45, |
55 | 48,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49}; |
55 | 48,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49}; |
56 | int freedir[SIZEOFFREE]= { |
56 | int freedir[SIZEOFFREE]= { |
57 | 0,1,2,3,4,5,6,7,8,1,2,2,2,3,4,4,4,5,6,6,6,7,8,8,8, |
57 | 0,1,2,3,4,5,6,7,8,1,2,2,2,3,4,4,4,5,6,6,6,7,8,8,8, |
58 | 1,2,2,2,2,2,3,4,4,4,4,4,5,6,6,6,6,6,7,8,8,8,8,8}; |
58 | 1,2,2,2,2,2,3,4,4,4,4,4,5,6,6,6,6,6,7,8,8,8,8,8}; |
59 | |
|
|
60 | |
59 | |
61 | /* Returns TRUE if every key_values in wants has a partner with the same value in has. */ |
60 | /* Returns TRUE if every key_values in wants has a partner with the same value in has. */ |
62 | static int compare_ob_value_lists_one(const object * wants, const object * has) { |
61 | static int compare_ob_value_lists_one(const object * wants, const object * has) { |
63 | key_value * wants_field; |
62 | key_value * wants_field; |
64 | |
63 | |
… | |
… | |
530 | SET_FLAG (this, FLAG_REMOVED); |
529 | SET_FLAG (this, FLAG_REMOVED); |
531 | } |
530 | } |
532 | |
531 | |
533 | void object::clone (object *destination) |
532 | void object::clone (object *destination) |
534 | { |
533 | { |
535 | *(object_copy *)destination = *(object_copy *)this; |
534 | *(object_copy *)destination = *this; |
536 | *(object_pod *)destination = *(object_pod *)this; |
535 | *(object_pod *)destination = *this; |
537 | |
536 | |
538 | if (self || cb) |
537 | if (self || cb) |
539 | INVOKE_OBJECT (CLONE, this, ARG_OBJECT (destination)); |
538 | INVOKE_OBJECT (CLONE, this, ARG_OBJECT (destination)); |
540 | } |
539 | } |
541 | |
540 | |
… | |
… | |
591 | |
590 | |
592 | if (op2->speed < 0) |
591 | if (op2->speed < 0) |
593 | op->speed_left = op2->speed_left - RANDOM() % 200 / 100.0; |
592 | op->speed_left = op2->speed_left - RANDOM() % 200 / 100.0; |
594 | |
593 | |
595 | /* Copy over key_values, if any. */ |
594 | /* Copy over key_values, if any. */ |
596 | if (op2->key_values != NULL) |
595 | if (op2->key_values) |
597 | { |
596 | { |
598 | key_value *tail = NULL; |
597 | key_value *tail = 0; |
599 | key_value *i; |
598 | key_value *i; |
600 | |
599 | |
601 | op->key_values = NULL; |
600 | op->key_values = 0; |
602 | |
601 | |
603 | for (i = op2->key_values; i != NULL; i = i->next) |
602 | for (i = op2->key_values; i; i = i->next) |
604 | { |
603 | { |
605 | key_value *new_link = new key_value; |
604 | key_value *new_link = new key_value; |
606 | |
605 | |
607 | new_link->next = NULL; |
606 | new_link->next = 0; |
608 | new_link->key = i->key; |
607 | new_link->key = i->key; |
609 | new_link->value = i->value; |
608 | new_link->value = i->value; |
610 | |
609 | |
611 | /* Try and be clever here, too. */ |
610 | /* Try and be clever here, too. */ |
612 | if (op->key_values == NULL) |
611 | if (!op->key_values) |
613 | { |
612 | { |
614 | op->key_values = new_link; |
613 | op->key_values = new_link; |
615 | tail = new_link; |
614 | tail = new_link; |
616 | } |
615 | } |
617 | else |
616 | else |
… | |
… | |
621 | } |
620 | } |
622 | } |
621 | } |
623 | } |
622 | } |
624 | |
623 | |
625 | update_ob_speed (op); |
624 | update_ob_speed (op); |
626 | } |
|
|
627 | |
|
|
628 | /* |
|
|
629 | * get_object() grabs an object from the list of unused objects, makes |
|
|
630 | * sure it is initialised, and returns it. |
|
|
631 | * If there are no free objects, expand_objects() is called to get more. |
|
|
632 | */ |
|
|
633 | |
|
|
634 | object *get_object () |
|
|
635 | { |
|
|
636 | object *op = new object; |
|
|
637 | |
|
|
638 | op->count = ++ob_count; |
|
|
639 | |
|
|
640 | op->next = objects; |
|
|
641 | |
|
|
642 | if (objects) |
|
|
643 | objects->prev = op; |
|
|
644 | |
|
|
645 | objects = op; |
|
|
646 | |
|
|
647 | SET_FLAG (op, FLAG_REMOVED); |
|
|
648 | |
|
|
649 | op->expmul = 1.0; |
|
|
650 | op->face = blank_face; |
|
|
651 | op->attacked_by_count = -1; |
|
|
652 | |
|
|
653 | return op; |
|
|
654 | } |
625 | } |
655 | |
626 | |
656 | /* |
627 | /* |
657 | * If an object with the IS_TURNABLE() flag needs to be turned due |
628 | * If an object with the IS_TURNABLE() flag needs to be turned due |
658 | * to the closest player being on the other side, this function can |
629 | * to the closest player being on the other side, this function can |
… | |
… | |
822 | update_now=1; |
793 | update_now=1; |
823 | |
794 | |
824 | if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags & P_IS_ALIVE)) |
795 | if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags & P_IS_ALIVE)) |
825 | update_now=1; |
796 | update_now=1; |
826 | |
797 | |
|
|
798 | if (op->type == SAFE_GROUND && !(flags & P_SAFE)) |
|
|
799 | update_now=1; |
|
|
800 | |
827 | if ((move_on | op->move_on) != move_on) update_now=1; |
801 | if ((move_on | op->move_on) != move_on) update_now=1; |
|
|
802 | |
828 | if ((move_off | op->move_off) != move_off) update_now=1; |
803 | if ((move_off | op->move_off) != move_off) update_now=1; |
|
|
804 | |
829 | /* This isn't perfect, but I don't expect a lot of objects to |
805 | /* This isn't perfect, but I don't expect a lot of objects to |
830 | * to have move_allow right now. |
806 | * to have move_allow right now. |
831 | */ |
807 | */ |
832 | if (((move_block | op->move_block) & ~op->move_allow) != move_block) |
808 | if (((move_block | op->move_block) & ~op->move_allow) != move_block) |
833 | update_now=1; |
809 | update_now=1; |
|
|
810 | |
834 | if ((move_slow | op->move_slow) != move_slow) update_now=1; |
811 | if ((move_slow | op->move_slow) != move_slow) |
|
|
812 | update_now=1; |
835 | } |
813 | } |
836 | /* if the object is being removed, we can't make intelligent |
814 | /* if the object is being removed, we can't make intelligent |
837 | * decisions, because remove_ob can't really pass the object |
815 | * decisions, because remove_ob can't really pass the object |
838 | * that is being removed. |
816 | * that is being removed. |
839 | */ |
817 | */ |
… | |
… | |
853 | |
831 | |
854 | if(op->more!=NULL) |
832 | if(op->more!=NULL) |
855 | update_object(op->more, action); |
833 | update_object(op->more, action); |
856 | } |
834 | } |
857 | |
835 | |
|
|
836 | static std::vector<object *> mortals; |
|
|
837 | |
|
|
838 | void object::free_mortals () |
|
|
839 | { |
|
|
840 | for (std::vector<object *>::iterator i = mortals.begin (); i != mortals.end (); ++i) |
|
|
841 | delete *i; |
|
|
842 | |
|
|
843 | mortals.clear (); |
|
|
844 | } |
|
|
845 | |
|
|
846 | object::object () |
|
|
847 | { |
|
|
848 | SET_FLAG (this, FLAG_REMOVED); |
|
|
849 | |
|
|
850 | expmul = 1.0; |
|
|
851 | face = blank_face; |
|
|
852 | attacked_by_count = -1; |
|
|
853 | } |
|
|
854 | |
|
|
855 | object::~object () |
|
|
856 | { |
|
|
857 | free_key_values (this); |
|
|
858 | } |
|
|
859 | |
|
|
860 | void |
|
|
861 | object::link () |
|
|
862 | { |
|
|
863 | count = ++ob_count; |
|
|
864 | |
|
|
865 | prev = 0; |
|
|
866 | next = objects; |
|
|
867 | |
|
|
868 | if (objects) |
|
|
869 | objects->prev = this; |
|
|
870 | |
|
|
871 | objects = this; |
|
|
872 | } |
|
|
873 | |
|
|
874 | void |
|
|
875 | object::unlink () |
|
|
876 | { |
|
|
877 | count = 0; |
|
|
878 | |
|
|
879 | /* Remove this object from the list of used objects */ |
|
|
880 | if (prev) prev->next = next; |
|
|
881 | if (next) next->prev = prev; |
|
|
882 | if (this == objects) objects = next; |
|
|
883 | } |
|
|
884 | |
|
|
885 | object *object::create () |
|
|
886 | { |
|
|
887 | object *op = new object; |
|
|
888 | op->link (); |
|
|
889 | return op; |
|
|
890 | } |
858 | |
891 | |
859 | /* |
892 | /* |
860 | * free_object() frees everything allocated by an object, removes |
893 | * free_object() frees everything allocated by an object, removes |
861 | * it from the list of used objects, and puts it on the list of |
894 | * it from the list of used objects, and puts it on the list of |
862 | * free objects. The IS_FREED() flag is set in the object. |
895 | * free objects. The IS_FREED() flag is set in the object. |
… | |
… | |
864 | * this function to succeed. |
897 | * this function to succeed. |
865 | * |
898 | * |
866 | * If free_inventory is set, free inventory as well. Else drop items in |
899 | * If free_inventory is set, free inventory as well. Else drop items in |
867 | * inventory to the ground. |
900 | * inventory to the ground. |
868 | */ |
901 | */ |
869 | |
|
|
870 | void |
902 | void |
871 | free_object (object * ob) |
903 | object::free (bool free_inventory) |
872 | { |
904 | { |
873 | free_object2 (ob, 0); |
|
|
874 | } |
|
|
875 | |
|
|
876 | void |
|
|
877 | free_object2 (object * ob, int free_inventory) |
|
|
878 | { |
|
|
879 | object *tmp, *op; |
|
|
880 | |
|
|
881 | if (!QUERY_FLAG (ob, FLAG_REMOVED)) |
905 | if (!QUERY_FLAG (this, FLAG_REMOVED)) |
882 | { |
906 | { |
883 | LOG (llevDebug, "Free object called with non removed object\n"); |
907 | LOG (llevDebug, "Free object called with non removed object\n"); |
884 | dump_object (ob); |
908 | dump_object (this); |
885 | #ifdef MANY_CORES |
909 | #ifdef MANY_CORES |
886 | abort (); |
910 | abort (); |
887 | #endif |
911 | #endif |
888 | } |
912 | } |
889 | |
913 | |
890 | if (QUERY_FLAG (ob, FLAG_FRIENDLY)) |
914 | if (QUERY_FLAG (this, FLAG_FRIENDLY)) |
891 | { |
915 | { |
892 | LOG (llevMonster, "Warning: tried to free friendly object.\n"); |
916 | LOG (llevMonster, "Warning: tried to free friendly object.\n"); |
893 | remove_friendly_object (ob); |
917 | remove_friendly_object (this); |
894 | } |
918 | } |
895 | |
919 | |
896 | if (QUERY_FLAG (ob, FLAG_FREED)) |
920 | if (QUERY_FLAG (this, FLAG_FREED)) |
897 | { |
921 | { |
898 | dump_object (ob); |
922 | dump_object (this); |
899 | LOG (llevError, "Trying to free freed object.\n%s\n", errmsg); |
923 | LOG (llevError, "Trying to free freed object.\n%s\n", errmsg); |
900 | return; |
924 | return; |
901 | } |
925 | } |
902 | |
926 | |
903 | if (ob->more != NULL) |
927 | if (more) |
904 | { |
928 | { |
905 | free_object2 (ob->more, free_inventory); |
929 | more->free (free_inventory); |
906 | ob->more = NULL; |
930 | more = 0; |
907 | } |
931 | } |
908 | |
932 | |
909 | if (ob->inv) |
933 | if (inv) |
910 | { |
934 | { |
911 | /* Only if the space blocks everything do we not process - |
935 | /* Only if the space blocks everything do we not process - |
912 | * if some form of movement is allowed, let objects |
936 | * if some form of movement is allowed, let objects |
913 | * drop on that space. |
937 | * drop on that space. |
914 | */ |
938 | */ |
915 | if (free_inventory || ob->map == NULL |
939 | if (free_inventory || !map |
916 | || ob->map->in_memory != MAP_IN_MEMORY |
940 | || map->in_memory != MAP_IN_MEMORY |
917 | || (GET_MAP_MOVE_BLOCK (ob->map, ob->x, ob->y) == MOVE_ALL)) |
941 | || (GET_MAP_MOVE_BLOCK (map, x, y) == MOVE_ALL)) |
918 | { |
942 | { |
919 | op = ob->inv; |
943 | object *op = inv; |
920 | |
944 | |
921 | while (op != NULL) |
945 | while (op) |
922 | { |
946 | { |
923 | tmp = op->below; |
947 | object *tmp = op->below; |
924 | remove_ob (op); |
948 | remove_ob (op); |
925 | free_object2 (op, free_inventory); |
949 | op->free (free_inventory); |
926 | op = tmp; |
950 | op = tmp; |
927 | } |
951 | } |
928 | } |
952 | } |
929 | else |
953 | else |
930 | { /* Put objects in inventory onto this space */ |
954 | { /* Put objects in inventory onto this space */ |
931 | op = ob->inv; |
955 | object *op = inv; |
932 | |
956 | |
933 | while (op != NULL) |
957 | while (op) |
934 | { |
958 | { |
935 | tmp = op->below; |
959 | object *tmp = op->below; |
936 | remove_ob (op); |
960 | remove_ob (op); |
937 | |
961 | |
938 | if (QUERY_FLAG (op, FLAG_STARTEQUIP) |
962 | if (QUERY_FLAG (op, FLAG_STARTEQUIP) |
939 | || QUERY_FLAG (op, FLAG_NO_DROP) || op->type == RUNE |
963 | || QUERY_FLAG (op, FLAG_NO_DROP) || op->type == RUNE |
940 | || op->type == TRAP || QUERY_FLAG (op, FLAG_IS_A_TEMPLATE)) |
964 | || op->type == TRAP || QUERY_FLAG (op, FLAG_IS_A_TEMPLATE)) |
941 | free_object (op); |
965 | free_object (op); |
942 | else |
966 | else |
943 | { |
967 | { |
944 | op->x = ob->x; |
968 | op->x = x; |
945 | op->y = ob->y; |
969 | op->y = y; |
946 | insert_ob_in_map (op, ob->map, NULL, 0); /* Insert in same map as the envir */ |
970 | insert_ob_in_map (op, map, 0, 0); /* Insert in same map as the envir */ |
947 | } |
971 | } |
948 | |
972 | |
949 | op = tmp; |
973 | op = tmp; |
950 | } |
974 | } |
951 | } |
975 | } |
952 | } |
976 | } |
953 | |
977 | |
954 | /* Remove object from the active list */ |
978 | /* Remove object from the active list */ |
955 | ob->speed = 0; |
979 | speed = 0; |
956 | update_ob_speed (ob); |
980 | update_ob_speed (this); |
957 | |
981 | |
|
|
982 | unlink (); |
|
|
983 | |
958 | SET_FLAG (ob, FLAG_FREED); |
984 | SET_FLAG (this, FLAG_FREED); |
959 | ob->count = 0; |
|
|
960 | |
985 | |
961 | /* Remove this object from the list of used objects */ |
986 | mortals.push_back (this); |
962 | if (ob->prev == NULL) |
|
|
963 | { |
|
|
964 | objects = ob->next; |
|
|
965 | |
|
|
966 | if (objects != NULL) |
|
|
967 | objects->prev = NULL; |
|
|
968 | } |
|
|
969 | else |
|
|
970 | { |
|
|
971 | ob->prev->next = ob->next; |
|
|
972 | |
|
|
973 | if (ob->next != NULL) |
|
|
974 | ob->next->prev = ob->prev; |
|
|
975 | } |
|
|
976 | |
|
|
977 | free_key_values (ob); |
|
|
978 | |
|
|
979 | /* Now link it with the free_objects list: */ |
|
|
980 | ob->prev = 0; |
|
|
981 | ob->next = 0; |
|
|
982 | |
|
|
983 | delete ob; |
|
|
984 | } |
987 | } |
985 | |
988 | |
986 | /* |
989 | /* |
987 | * sub_weight() recursively (outwards) subtracts a number from the |
990 | * sub_weight() recursively (outwards) subtracts a number from the |
988 | * weight of an object (and what is carried by it's environment(s)). |
991 | * weight of an object (and what is carried by it's environment(s)). |