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.15 by root, Mon Sep 4 13:55:54 2006 UTC vs.
Revision 1.21 by root, Sat Sep 9 21:48:28 2006 UTC

1/* 1/*
2 * static char *rcsid_object_c = 2 * static char *rcsid_object_c =
3 * "$Id: object.C,v 1.15 2006/09/04 13:55:54 root Exp $"; 3 * "$Id: object.C,v 1.21 2006/09/09 21:48:28 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};
56int freedir[SIZEOFFREE]= { 56int 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. */
62static int compare_ob_value_lists_one(const object * wants, const object * has) { 61static int compare_ob_value_lists_one(const object * wants, const object * has) {
63 key_value * wants_field; 62 key_value * wants_field;
64 63
111 * 110 *
112 * Improvements made with merge: Better checking on potion, and also 111 * Improvements made with merge: Better checking on potion, and also
113 * check weight 112 * check weight
114 */ 113 */
115 114
116int CAN_MERGE(object *ob1, object *ob2) { 115bool
117 116object::can_merge (object *ob1, object *ob2)
117{
118 /* A couple quicksanity checks */ 118 /* A couple quicksanity checks */
119 if ((ob1 == ob2) || (ob1->type != ob2->type)) return 0; 119 if ((ob1 == ob2) || (ob1->type != ob2->type))
120
121 if (ob1->speed != ob2->speed) return 0;
122 /* Note sure why the following is the case - either the object has to
123 * be animated or have a very low speed. Is this an attempted monster
124 * check?
125 */
126 if (!QUERY_FLAG(ob1,FLAG_ANIMATE) && FABS((ob1)->speed) > MIN_ACTIVE_SPEED)
127 return 0; 120 return 0;
128 121
122 if (ob1->speed != ob2->speed)
123 return 0;
124
129 /* Do not merge objects if nrof would overflow. We use 1UL<<31 since that 125 /* Do not merge objects if nrof would overflow. We use 1UL<<31 since that
130 * value could not be stored in a sint32 (which unfortunately sometimes is 126 * value could not be stored in a sint32 (which unfortunately sometimes is
131 * used to store nrof). 127 * used to store nrof).
132 */ 128 */
133 if (ob1->nrof+ob2->nrof >= 1UL<<31) 129 if (ob1->nrof + ob2->nrof >= 1UL << 31)
134 return 0; 130 return 0;
135 131
132 /* If the objects have been identified, set the BEEN_APPLIED flag.
133 * This is to the comparison of the flags below will be OK. We
134 * just can't ignore the been applied or identified flags, as they
135 * are not equal - just if it has been identified, the been_applied
136 * flags lose any meaning.
137 */
138 if (QUERY_FLAG (ob1, FLAG_IDENTIFIED))
139 SET_FLAG (ob1, FLAG_BEEN_APPLIED);
140
141 if (QUERY_FLAG (ob2, FLAG_IDENTIFIED))
142 SET_FLAG (ob2, FLAG_BEEN_APPLIED);
143
144
145 /* the 0x400000 on flags2 is FLAG_INV_LOCK. I don't think something
146 * being locked in inventory should prevent merging.
147 * 0x4 in flags3 is CLIENT_SENT
148 */
149 if ((ob1->arch != ob2->arch) ||
150 (ob1->flags[0] != ob2->flags[0]) ||
151 (ob1->flags[1] != ob2->flags[1]) ||
152 ((ob1->flags[2] & ~0x400000) != (ob2->flags[2] & ~0x400000)) ||
153 ((ob1->flags[3] & ~0x4) != (ob2->flags[3] & ~0x4)) ||
154 (ob1->name != ob2->name) ||
155 (ob1->title != ob2->title) ||
156 (ob1->msg != ob2->msg) ||
157 (ob1->weight != ob2->weight) ||
158 (memcmp (&ob1->resist, &ob2->resist, sizeof (ob1->resist)) != 0) ||
159 (memcmp (&ob1->stats, &ob2->stats, sizeof (ob1->stats)) != 0) ||
160 (ob1->attacktype != ob2->attacktype) ||
161 (ob1->magic != ob2->magic) ||
162 (ob1->slaying != ob2->slaying) ||
163 (ob1->skill != ob2->skill) ||
164 (ob1->value != ob2->value) ||
165 (ob1->animation_id != ob2->animation_id) ||
166 (ob1->client_type != ob2->client_type) ||
167 (ob1->materialname != ob2->materialname) ||
168 (ob1->lore != ob2->lore) ||
169 (ob1->subtype != ob2->subtype) ||
170 (ob1->move_type != ob2->move_type) ||
171 (ob1->move_block != ob2->move_block) ||
172 (ob1->move_allow != ob2->move_allow) ||
173 (ob1->move_on != ob2->move_on) ||
174 (ob1->move_off != ob2->move_off) ||
175 (ob1->move_slow != ob2->move_slow) ||
176 (ob1->move_slow_penalty != ob2->move_slow_penalty))
177 return 0;
178
136 /* This is really a spellbook check - really, we should 179 /* This is really a spellbook check - really, we should
137 * check all objects in the inventory. 180 * check all objects in the inventory.
138 */ 181 */
139 if (ob1->inv || ob2->inv) { 182 if (ob1->inv || ob2->inv)
183 {
140 /* if one object has inventory but the other doesn't, not equiv */ 184 /* if one object has inventory but the other doesn't, not equiv */
141 if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv)) return 0; 185 if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv))
186 return 0;
142 187
143 /* Now check to see if the two inventory objects could merge */ 188 /* Now check to see if the two inventory objects could merge */
144 if (!CAN_MERGE(ob1->inv, ob2->inv)) return 0; 189 if (!CAN_MERGE (ob1->inv, ob2->inv))
190 return 0;
145 191
146 /* inventory ok - still need to check rest of this object to see 192 /* inventory ok - still need to check rest of this object to see
147 * if it is valid. 193 * if it is valid.
148 */ 194 */
149 } 195 }
150 196
151 /* If the objects have been identified, set the BEEN_APPLIED flag.
152 * This is to the comparison of the flags below will be OK. We
153 * just can't ignore the been applied or identified flags, as they
154 * are not equal - just if it has been identified, the been_applied
155 * flags lose any meaning.
156 */
157 if (QUERY_FLAG(ob1, FLAG_IDENTIFIED))
158 SET_FLAG(ob1, FLAG_BEEN_APPLIED);
159
160 if (QUERY_FLAG(ob2, FLAG_IDENTIFIED))
161 SET_FLAG(ob2, FLAG_BEEN_APPLIED);
162
163
164 /* the 0x400000 on flags2 is FLAG_INV_LOCK. I don't think something
165 * being locked in inventory should prevent merging.
166 * 0x4 in flags3 is CLIENT_SENT
167 */
168 if ((ob1->arch != ob2->arch) ||
169 (ob1->flags[0] != ob2->flags[0]) ||
170 (ob1->flags[1] != ob2->flags[1]) ||
171 ((ob1->flags[2] & ~0x400000) != (ob2->flags[2] & ~ 0x400000)) ||
172 ((ob1->flags[3] & ~0x4) != (ob2->flags[3] & ~0x4)) ||
173 (ob1->name != ob2->name) ||
174 (ob1->title != ob2->title) ||
175 (ob1->msg != ob2->msg) ||
176 (ob1->weight != ob2->weight) ||
177 (memcmp(&ob1->resist, &ob2->resist, sizeof(ob1->resist))!=0) ||
178 (memcmp(&ob1->stats, &ob2->stats, sizeof(ob1->stats))!=0) ||
179 (ob1->attacktype != ob2->attacktype) ||
180 (ob1->magic != ob2->magic) ||
181 (ob1->slaying != ob2->slaying) ||
182 (ob1->skill != ob2->skill) ||
183 (ob1->value != ob2->value) ||
184 (ob1->animation_id != ob2->animation_id) ||
185 (ob1->client_type != ob2->client_type) ||
186 (ob1->materialname != ob2->materialname) ||
187 (ob1->lore != ob2->lore) ||
188 (ob1->subtype != ob2->subtype) ||
189 (ob1->move_type != ob2->move_type) ||
190 (ob1->move_block != ob2->move_block) ||
191 (ob1->move_allow != ob2->move_allow) ||
192 (ob1->move_on != ob2->move_on) ||
193 (ob1->move_off != ob2->move_off) ||
194 (ob1->move_slow != ob2->move_slow) ||
195 (ob1->move_slow_penalty != ob2->move_slow_penalty)
196 )
197 return 0;
198
199 /* Don't merge objects that are applied. With the new 'body' code, 197 /* Don't merge objects that are applied. With the new 'body' code,
200 * it is possible for most any character to have more than one of 198 * it is possible for most any character to have more than one of
201 * some items equipped, and we don't want those to merge. 199 * some items equipped, and we don't want those to merge.
202 */ 200 */
203 if (QUERY_FLAG(ob1, FLAG_APPLIED) || QUERY_FLAG(ob2, FLAG_APPLIED)) 201 if (QUERY_FLAG (ob1, FLAG_APPLIED) || QUERY_FLAG (ob2, FLAG_APPLIED))
204 return 0; 202 return 0;
205 203
204 /* Note sure why the following is the case - either the object has to
205 * be animated or have a very low speed. Is this an attempted monster
206 * check?
207 */
208 if (!QUERY_FLAG (ob1, FLAG_ANIMATE)
209 && FABS ((ob1)->speed) > MIN_ACTIVE_SPEED)
210 return 0;
211
206 switch (ob1->type) { 212 switch (ob1->type)
213 {
207 case SCROLL: 214 case SCROLL:
208 if (ob1->level != ob2->level) return 0; 215 if (ob1->level != ob2->level)
216 return 0;
209 break; 217 break;
210
211 } 218 }
219
212 if (ob1->key_values != NULL || ob2->key_values != NULL) { 220 if (ob1->key_values != NULL || ob2->key_values != NULL)
221 {
213 /* At least one of these has key_values. */ 222 /* At least one of these has key_values. */
214 if ((ob1->key_values == NULL) != (ob2->key_values == NULL)) { 223 if ((ob1->key_values == NULL) != (ob2->key_values == NULL))
215 /* One has fields, but the other one doesn't. */ 224 /* One has fields, but the other one doesn't. */
216 return 0; 225 return 0;
217 } else if (!compare_ob_value_lists(ob1, ob2)) { 226 else if (!compare_ob_value_lists (ob1, ob2))
218 return 0; 227 return 0;
219 } 228 }
229
230 //TODO: generate an event or call into perl for additional checks
231 if (ob1->self || ob2->self)
220 } 232 {
233 ob1->optimise ();
234 ob2->optimise ();
221 235
236 if (ob1->self || ob2->self)
237 return 0;
238 }
239
222 /* Everything passes, must be OK. */ 240 /* Everything passes, must be OK. */
223 return 1; 241 return 1;
224} 242}
225
226/* 243/*
227 * sum_weight() is a recursive function which calculates the weight 244 * sum_weight() is a recursive function which calculates the weight
228 * an object is carrying. It goes through in figures out how much 245 * an object is carrying. It goes through in figures out how much
229 * containers are carrying, and sums it up. 246 * containers are carrying, and sums it up.
230 */ 247 */
606 623
607 update_ob_speed (op); 624 update_ob_speed (op);
608} 625}
609 626
610/* 627/*
611 * get_object() grabs an object from the list of unused objects, makes
612 * sure it is initialised, and returns it.
613 * If there are no free objects, expand_objects() is called to get more.
614 */
615
616object *get_object ()
617{
618 object *op = new object;
619
620 op->count = ++ob_count;
621
622 op->active_next = 0;
623 op->active_prev = 0;
624
625 op->next = objects;
626 op->prev = 0;
627
628 if (objects)
629 objects->prev = op;
630
631 objects = op;
632
633 SET_FLAG (op, FLAG_REMOVED);
634
635 op->expmul = 1.0;
636 op->face = blank_face;
637 op->attacked_by_count = -1;
638
639 return op;
640}
641
642/*
643 * 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
644 * 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
645 * be called to update the face variable, _and_ how it looks on the map. 630 * be called to update the face variable, _and_ how it looks on the map.
646 */ 631 */
647 632
808 update_now=1; 793 update_now=1;
809 794
810 if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags & P_IS_ALIVE)) 795 if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags & P_IS_ALIVE))
811 update_now=1; 796 update_now=1;
812 797
798 if (op->type == SAFE_GROUND && !(flags & P_SAFE))
799 update_now=1;
800
813 if ((move_on | op->move_on) != move_on) update_now=1; 801 if ((move_on | op->move_on) != move_on) update_now=1;
802
814 if ((move_off | op->move_off) != move_off) update_now=1; 803 if ((move_off | op->move_off) != move_off) update_now=1;
804
815 /* 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
816 * to have move_allow right now. 806 * to have move_allow right now.
817 */ 807 */
818 if (((move_block | op->move_block) & ~op->move_allow) != move_block) 808 if (((move_block | op->move_block) & ~op->move_allow) != move_block)
819 update_now=1; 809 update_now=1;
810
820 if ((move_slow | op->move_slow) != move_slow) update_now=1; 811 if ((move_slow | op->move_slow) != move_slow)
812 update_now=1;
821 } 813 }
822 /* if the object is being removed, we can't make intelligent 814 /* if the object is being removed, we can't make intelligent
823 * decisions, because remove_ob can't really pass the object 815 * decisions, because remove_ob can't really pass the object
824 * that is being removed. 816 * that is being removed.
825 */ 817 */
839 831
840 if(op->more!=NULL) 832 if(op->more!=NULL)
841 update_object(op->more, action); 833 update_object(op->more, action);
842} 834}
843 835
836static std::vector<object *> mortals;
837
838void 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
846object::object ()
847{
848 count = ++ob_count;
849
850 prev = 0;
851 next = objects;
852
853 if (objects)
854 objects->prev = this;
855
856 objects = this;
857
858 SET_FLAG (this, FLAG_REMOVED);
859
860 expmul = 1.0;
861 face = blank_face;
862 attacked_by_count = -1;
863}
864
865object::~object ()
866{
867}
868
869object *object::create ()
870{
871 return new object;
872}
844 873
845/* 874/*
846 * free_object() frees everything allocated by an object, removes 875 * free_object() frees everything allocated by an object, removes
847 * it from the list of used objects, and puts it on the list of 876 * it from the list of used objects, and puts it on the list of
848 * free objects. The IS_FREED() flag is set in the object. 877 * free objects. The IS_FREED() flag is set in the object.
850 * this function to succeed. 879 * this function to succeed.
851 * 880 *
852 * If free_inventory is set, free inventory as well. Else drop items in 881 * If free_inventory is set, free inventory as well. Else drop items in
853 * inventory to the ground. 882 * inventory to the ground.
854 */ 883 */
855
856void 884void
857free_object (object * ob) 885object::free (bool free_inventory)
858{ 886{
859 free_object2 (ob, 0);
860}
861
862void
863free_object2 (object * ob, int free_inventory)
864{
865 object *tmp, *op;
866
867 if (!QUERY_FLAG (ob, FLAG_REMOVED)) 887 if (!QUERY_FLAG (this, FLAG_REMOVED))
868 { 888 {
869 LOG (llevDebug, "Free object called with non removed object\n"); 889 LOG (llevDebug, "Free object called with non removed object\n");
870 dump_object (ob); 890 dump_object (this);
871#ifdef MANY_CORES 891#ifdef MANY_CORES
872 abort (); 892 abort ();
873#endif 893#endif
874 } 894 }
875 895
876 if (QUERY_FLAG (ob, FLAG_FRIENDLY)) 896 if (QUERY_FLAG (this, FLAG_FRIENDLY))
877 { 897 {
878 LOG (llevMonster, "Warning: tried to free friendly object.\n"); 898 LOG (llevMonster, "Warning: tried to free friendly object.\n");
879 remove_friendly_object (ob); 899 remove_friendly_object (this);
880 } 900 }
881 901
882 if (QUERY_FLAG (ob, FLAG_FREED)) 902 if (QUERY_FLAG (this, FLAG_FREED))
883 { 903 {
884 dump_object (ob); 904 dump_object (this);
885 LOG (llevError, "Trying to free freed object.\n%s\n", errmsg); 905 LOG (llevError, "Trying to free freed object.\n%s\n", errmsg);
886 return; 906 return;
887 } 907 }
888 908
889 if (ob->more != NULL) 909 if (more)
890 { 910 {
891 free_object2 (ob->more, free_inventory); 911 more->free (free_inventory);
892 ob->more = NULL; 912 more = 0;
893 } 913 }
894 914
895 if (ob->inv) 915 if (inv)
896 { 916 {
897 /* Only if the space blocks everything do we not process - 917 /* Only if the space blocks everything do we not process -
898 * if some form of movemnt is allowed, let objects 918 * if some form of movement is allowed, let objects
899 * drop on that space. 919 * drop on that space.
900 */ 920 */
901 if (free_inventory || ob->map == NULL 921 if (free_inventory || !map
902 || ob->map->in_memory != MAP_IN_MEMORY 922 || map->in_memory != MAP_IN_MEMORY
903 || (GET_MAP_MOVE_BLOCK (ob->map, ob->x, ob->y) == MOVE_ALL)) 923 || (GET_MAP_MOVE_BLOCK (map, x, y) == MOVE_ALL))
904 { 924 {
905 op = ob->inv; 925 object *op = inv;
906 926
907 while (op != NULL) 927 while (op)
908 { 928 {
909 tmp = op->below; 929 object *tmp = op->below;
910 remove_ob (op); 930 remove_ob (op);
911 free_object2 (op, free_inventory); 931 op->free (free_inventory);
912 op = tmp; 932 op = tmp;
913 } 933 }
914 } 934 }
915 else 935 else
916 { /* Put objects in inventory onto this space */ 936 { /* Put objects in inventory onto this space */
917 op = ob->inv; 937 object *op = inv;
918 938
919 while (op != NULL) 939 while (op)
920 { 940 {
921 tmp = op->below; 941 object *tmp = op->below;
922 remove_ob (op); 942 remove_ob (op);
923 943
924 if (QUERY_FLAG (op, FLAG_STARTEQUIP) 944 if (QUERY_FLAG (op, FLAG_STARTEQUIP)
925 || QUERY_FLAG (op, FLAG_NO_DROP) || op->type == RUNE 945 || QUERY_FLAG (op, FLAG_NO_DROP) || op->type == RUNE
926 || op->type == TRAP || QUERY_FLAG (op, FLAG_IS_A_TEMPLATE)) 946 || op->type == TRAP || QUERY_FLAG (op, FLAG_IS_A_TEMPLATE))
927 free_object (op); 947 free_object (op);
928 else 948 else
929 { 949 {
930 op->x = ob->x; 950 op->x = x;
931 op->y = ob->y; 951 op->y = y;
932 insert_ob_in_map (op, ob->map, NULL, 0); /* Insert in same map as the envir */ 952 insert_ob_in_map (op, map, 0, 0); /* Insert in same map as the envir */
933 } 953 }
934 954
935 op = tmp; 955 op = tmp;
936 } 956 }
937 } 957 }
938 } 958 }
939 959
940 /* Remove object from the active list */ 960 /* Remove object from the active list */
941 ob->speed = 0; 961 speed = 0;
942 update_ob_speed (ob); 962 update_ob_speed (this);
943 963
944 SET_FLAG (ob, FLAG_FREED); 964 SET_FLAG (this, FLAG_FREED);
965
966 mortalise ();
967}
968
969void
970object::mortalise ()
971{
945 ob->count = 0; 972 count = 0;
946 973
947 /* Remove this object from the list of used objects */ 974 /* Remove this object from the list of used objects */
948 if (ob->prev == NULL) 975 if (prev) prev->next = next;
949 { 976 if (next) next->prev = prev;
950 objects = ob->next; 977 if (this == objects) objects = next;
951 978
952 if (objects != NULL)
953 objects->prev = NULL;
954 }
955 else
956 {
957 ob->prev->next = ob->next;
958
959 if (ob->next != NULL)
960 ob->next->prev = ob->prev;
961 }
962
963 free_key_values (ob); 979 free_key_values (this);
964 980
965 /* Now link it with the free_objects list: */ 981 mortals.push_back (this);
966 ob->prev = 0;
967 ob->next = 0;
968
969 delete ob;
970} 982}
971 983
972/* 984/*
973 * sub_weight() recursively (outwards) subtracts a number from the 985 * sub_weight() recursively (outwards) subtracts a number from the
974 * weight of an object (and what is carried by it's environment(s)). 986 * weight of an object (and what is carried by it's environment(s)).

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines