1 | /* |
1 | /* |
2 | * static char *rcsid_object_c = |
2 | * static char *rcsid_object_c = |
3 | * "$Id: object.c,v 1.2 2006/02/07 23:29:55 root Exp $"; |
3 | * "$Id: object.c,v 1.3 2006/02/22 18:53:48 elmex 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 | |
… | |
… | |
69 | 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, |
69 | 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, |
70 | 1,2,2,2,2,2,3,4,4,4,4,4,5,6,6,6,6,6,7,8,8,8,8,8}; |
70 | 1,2,2,2,2,2,3,4,4,4,4,4,5,6,6,6,6,6,7,8,8,8,8,8}; |
71 | |
71 | |
72 | |
72 | |
73 | /* Returns TRUE if every key_values in wants has a partner with the same value in has. */ |
73 | /* Returns TRUE if every key_values in wants has a partner with the same value in has. */ |
74 | static int compare_ob_value_lists_one(object * wants, object * has) { |
74 | static int compare_ob_value_lists_one(const object * wants, const object * has) { |
75 | key_value * wants_field; |
75 | key_value * wants_field; |
76 | |
76 | |
77 | /* n-squared behaviour (see get_ob_key_link()), but I'm hoping both |
77 | /* n-squared behaviour (see get_ob_key_link()), but I'm hoping both |
78 | * objects with lists are rare, and lists stay short. If not, use a |
78 | * objects with lists are rare, and lists stay short. If not, use a |
79 | * different structure or at least keep the lists sorted... |
79 | * different structure or at least keep the lists sorted... |
… | |
… | |
103 | /* If we get here, every field in wants has a matching field in has. */ |
103 | /* If we get here, every field in wants has a matching field in has. */ |
104 | return TRUE; |
104 | return TRUE; |
105 | } |
105 | } |
106 | |
106 | |
107 | /* Returns TRUE if ob1 has the same key_values as ob2. */ |
107 | /* Returns TRUE if ob1 has the same key_values as ob2. */ |
108 | static int compare_ob_value_lists(object * ob1, object * ob2) { |
108 | static int compare_ob_value_lists(const object * ob1, const object * ob2) { |
109 | /* However, there may be fields in has which aren't partnered in wants, |
109 | /* However, there may be fields in has which aren't partnered in wants, |
110 | * so we need to run the comparison *twice*. :( |
110 | * so we need to run the comparison *twice*. :( |
111 | */ |
111 | */ |
112 | return compare_ob_value_lists_one(ob1, ob2) && compare_ob_value_lists_one(ob2, ob1); |
112 | return compare_ob_value_lists_one(ob1, ob2) && compare_ob_value_lists_one(ob2, ob1); |
113 | } |
113 | } |
… | |
… | |
198 | (ob1->materialname != ob2->materialname) || |
198 | (ob1->materialname != ob2->materialname) || |
199 | (ob1->lore != ob2->lore) || |
199 | (ob1->lore != ob2->lore) || |
200 | (ob1->subtype != ob2->subtype) || |
200 | (ob1->subtype != ob2->subtype) || |
201 | (ob1->move_type != ob2->move_type) || |
201 | (ob1->move_type != ob2->move_type) || |
202 | (ob1->move_block != ob2->move_block) || |
202 | (ob1->move_block != ob2->move_block) || |
|
|
203 | (ob1->move_allow != ob2->move_allow) || |
203 | (ob1->move_on != ob2->move_on) || |
204 | (ob1->move_on != ob2->move_on) || |
204 | (ob1->move_off != ob2->move_off) || |
205 | (ob1->move_off != ob2->move_off) || |
205 | (ob1->move_slow != ob2->move_slow) || |
206 | (ob1->move_slow != ob2->move_slow) || |
206 | (ob1->move_slow_penalty != ob2->move_slow_penalty) |
207 | (ob1->move_slow_penalty != ob2->move_slow_penalty) |
207 | ) |
208 | ) |
… | |
… | |
385 | * get_nearest_part(multi-object, object 2) returns the part of the |
386 | * get_nearest_part(multi-object, object 2) returns the part of the |
386 | * multi-object 1 which is closest to the second object. |
387 | * multi-object 1 which is closest to the second object. |
387 | * If it's not a multi-object, it is returned. |
388 | * If it's not a multi-object, it is returned. |
388 | */ |
389 | */ |
389 | |
390 | |
390 | object *get_nearest_part(object *op,object *pl) { |
391 | object *get_nearest_part(object *op, const object *pl) { |
391 | object *tmp,*closest; |
392 | object *tmp,*closest; |
392 | int last_dist,i; |
393 | int last_dist,i; |
393 | if(op->more==NULL) |
394 | if(op->more==NULL) |
394 | return op; |
395 | return op; |
395 | for(last_dist=distance(op,pl),closest=op,tmp=op->more;tmp!=NULL;tmp=tmp->more) |
396 | for(last_dist=distance(op,pl),closest=op,tmp=op->more;tmp!=NULL;tmp=tmp->more) |
… | |
… | |
414 | * Returns the first object which has a name equal to the argument. |
415 | * Returns the first object which has a name equal to the argument. |
415 | * Used only by the patch command, but not all that useful. |
416 | * Used only by the patch command, but not all that useful. |
416 | * Enables features like "patch <name-of-other-player> food 999" |
417 | * Enables features like "patch <name-of-other-player> food 999" |
417 | */ |
418 | */ |
418 | |
419 | |
419 | object *find_object_name(char *str) { |
420 | object *find_object_name(const char *str) { |
420 | const char *name=add_string(str); |
421 | const char *name=add_string(str); |
421 | object *op; |
422 | object *op; |
422 | for(op=objects;op!=NULL;op=op->next) |
423 | for(op=objects;op!=NULL;op=op->next) |
423 | if(op->name==name) |
424 | if(op->name==name) |
424 | break; |
425 | break; |
… | |
… | |
1019 | if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags & P_IS_ALIVE)) |
1020 | if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags & P_IS_ALIVE)) |
1020 | update_now=1; |
1021 | update_now=1; |
1021 | |
1022 | |
1022 | if ((move_on | op->move_on) != move_on) update_now=1; |
1023 | if ((move_on | op->move_on) != move_on) update_now=1; |
1023 | if ((move_off | op->move_off) != move_off) update_now=1; |
1024 | if ((move_off | op->move_off) != move_off) update_now=1; |
|
|
1025 | /* This isn't perfect, but I don't expect a lot of objects to |
|
|
1026 | * to have move_allow right now. |
|
|
1027 | */ |
1024 | if ((move_block | op->move_block) != move_block) update_now=1; |
1028 | if (((move_block | op->move_block) & ~op->move_allow) != move_block) |
|
|
1029 | update_now=1; |
1025 | if ((move_slow | op->move_slow) != move_slow) update_now=1; |
1030 | if ((move_slow | op->move_slow) != move_slow) update_now=1; |
1026 | } |
1031 | } |
1027 | /* if the object is being removed, we can't make intelligent |
1032 | /* if the object is being removed, we can't make intelligent |
1028 | * decisions, because remove_ob can't really pass the object |
1033 | * decisions, because remove_ob can't really pass the object |
1029 | * that is being removed. |
1034 | * that is being removed. |
… | |
… | |
1511 | if(op->more!=NULL) { |
1516 | if(op->more!=NULL) { |
1512 | /* The part may be on a different map. */ |
1517 | /* The part may be on a different map. */ |
1513 | |
1518 | |
1514 | object *more = op->more; |
1519 | object *more = op->more; |
1515 | |
1520 | |
|
|
1521 | /* We really need the caller to normalize coordinates - if |
|
|
1522 | * we set the map, that doesn't work if the location is within |
|
|
1523 | * a map and this is straddling an edge. So only if coordinate |
|
|
1524 | * is clear wrong do we normalize it. |
|
|
1525 | */ |
|
|
1526 | if (OUT_OF_REAL_MAP(more->map, more->x, more->y)) { |
1516 | /* Debugging information so you can see the last coordinates this object had */ |
1527 | /* Debugging information so you can see the last coordinates this object had */ |
1517 | more->ox = more->x; |
1528 | more->ox = more->x; |
1518 | more->oy = more->y; |
1529 | more->oy = more->y; |
1519 | more->map = get_map_from_coord(m, &more->x, &more->y); |
1530 | more->map = get_map_from_coord(m, &more->x, &more->y); |
|
|
1531 | } else if (!more->map) { |
|
|
1532 | /* For backwards compatibility - when not dealing with tiled maps, |
|
|
1533 | * more->map should always point to the parent. |
|
|
1534 | */ |
|
|
1535 | more->map = m; |
|
|
1536 | } |
1520 | |
1537 | |
1521 | if (insert_ob_in_map(more, more->map, originator, flag) == NULL) { |
1538 | if (insert_ob_in_map(more, more->map, originator, flag) == NULL) { |
1522 | if ( ! op->head) |
1539 | if ( ! op->head) |
1523 | LOG (llevError, "BUG: insert_ob_in_map(): inserting op->more killed op\n"); |
1540 | LOG (llevError, "BUG: insert_ob_in_map(): inserting op->more killed op\n"); |
1524 | return NULL; |
1541 | return NULL; |
… | |
… | |
1706 | |
1723 | |
1707 | /* this function inserts an object in the map, but if it |
1724 | /* this function inserts an object in the map, but if it |
1708 | * finds an object of its own type, it'll remove that one first. |
1725 | * finds an object of its own type, it'll remove that one first. |
1709 | * op is the object to insert it under: supplies x and the map. |
1726 | * op is the object to insert it under: supplies x and the map. |
1710 | */ |
1727 | */ |
1711 | void replace_insert_ob_in_map(char *arch_string, object *op) { |
1728 | void replace_insert_ob_in_map(const char *arch_string, object *op) { |
1712 | object *tmp; |
1729 | object *tmp; |
1713 | object *tmp1; |
1730 | object *tmp1; |
1714 | |
1731 | |
1715 | /* first search for itself and remove any old instances */ |
1732 | /* first search for itself and remove any old instances */ |
1716 | |
1733 | |
… | |
… | |
2084 | * present_arch(arch, map, x, y) searches for any objects with |
2101 | * present_arch(arch, map, x, y) searches for any objects with |
2085 | * a matching archetype at the given map and coordinates. |
2102 | * a matching archetype at the given map and coordinates. |
2086 | * The first matching object is returned, or NULL if none. |
2103 | * The first matching object is returned, or NULL if none. |
2087 | */ |
2104 | */ |
2088 | |
2105 | |
2089 | object *present_arch(archetype *at, mapstruct *m, int x, int y) { |
2106 | object *present_arch(const archetype *at, mapstruct *m, int x, int y) { |
2090 | object *tmp; |
2107 | object *tmp; |
2091 | if(m==NULL || out_of_map(m,x,y)) { |
2108 | if(m==NULL || out_of_map(m,x,y)) { |
2092 | LOG(llevError,"Present_arch called outside map.\n"); |
2109 | LOG(llevError,"Present_arch called outside map.\n"); |
2093 | return NULL; |
2110 | return NULL; |
2094 | } |
2111 | } |
… | |
… | |
2120 | * present_in_ob(type, object) searches for any objects with |
2137 | * present_in_ob(type, object) searches for any objects with |
2121 | * a matching type variable in the inventory of the given object. |
2138 | * a matching type variable in the inventory of the given object. |
2122 | * The first matching object is returned, or NULL if none. |
2139 | * The first matching object is returned, or NULL if none. |
2123 | */ |
2140 | */ |
2124 | |
2141 | |
2125 | object *present_in_ob(unsigned char type,object *op) { |
2142 | object *present_in_ob(unsigned char type, const object *op) { |
2126 | object *tmp; |
2143 | object *tmp; |
2127 | for(tmp=op->inv;tmp!=NULL;tmp=tmp->below) |
2144 | for(tmp=op->inv;tmp!=NULL;tmp=tmp->below) |
2128 | if(tmp->type==type) |
2145 | if(tmp->type==type) |
2129 | return tmp; |
2146 | return tmp; |
2130 | return NULL; |
2147 | return NULL; |
… | |
… | |
2143 | * the object name, not the archetype name. this is so that the |
2160 | * the object name, not the archetype name. this is so that the |
2144 | * spell code can use one object type (force), but change it's name |
2161 | * spell code can use one object type (force), but change it's name |
2145 | * to be unique. |
2162 | * to be unique. |
2146 | */ |
2163 | */ |
2147 | |
2164 | |
2148 | object *present_in_ob_by_name(int type, char *str,object *op) { |
2165 | object *present_in_ob_by_name(int type, const char *str, const object *op) { |
2149 | object *tmp; |
2166 | object *tmp; |
2150 | |
2167 | |
2151 | for(tmp=op->inv; tmp!=NULL; tmp=tmp->below) { |
2168 | for(tmp=op->inv; tmp!=NULL; tmp=tmp->below) { |
2152 | if ((type==-1 || tmp->type==type) && (!strcmp(str, tmp->name))) |
2169 | if ((type==-1 || tmp->type==type) && (!strcmp(str, tmp->name))) |
2153 | return tmp; |
2170 | return tmp; |
… | |
… | |
2159 | * present_arch_in_ob(archetype, object) searches for any objects with |
2176 | * present_arch_in_ob(archetype, object) searches for any objects with |
2160 | * a matching archetype in the inventory of the given object. |
2177 | * a matching archetype in the inventory of the given object. |
2161 | * The first matching object is returned, or NULL if none. |
2178 | * The first matching object is returned, or NULL if none. |
2162 | */ |
2179 | */ |
2163 | |
2180 | |
2164 | object *present_arch_in_ob(archetype *at, object *op) { |
2181 | object *present_arch_in_ob(const archetype *at, const object *op) { |
2165 | object *tmp; |
2182 | object *tmp; |
2166 | for(tmp=op->inv;tmp!=NULL;tmp=tmp->below) |
2183 | for(tmp=op->inv;tmp!=NULL;tmp=tmp->below) |
2167 | if( tmp->arch == at) |
2184 | if( tmp->arch == at) |
2168 | return tmp; |
2185 | return tmp; |
2169 | return NULL; |
2186 | return NULL; |
… | |
… | |
2223 | * to know if the space in question will block the object. We can't use |
2240 | * to know if the space in question will block the object. We can't use |
2224 | * the archetype because that isn't correct if the monster has been |
2241 | * the archetype because that isn't correct if the monster has been |
2225 | * customized, changed states, etc. |
2242 | * customized, changed states, etc. |
2226 | */ |
2243 | */ |
2227 | |
2244 | |
2228 | int find_free_spot(object *ob, mapstruct *m,int x,int y,int start,int stop) { |
2245 | int find_free_spot(const object *ob, mapstruct *m,int x,int y,int start,int stop) { |
2229 | int i,index=0, flag; |
2246 | int i,index=0, flag; |
2230 | static int altern[SIZEOFFREE]; |
2247 | static int altern[SIZEOFFREE]; |
2231 | |
2248 | |
2232 | for(i=start;i<stop;i++) { |
2249 | for(i=start;i<stop;i++) { |
2233 | flag = ob_blocked(ob,m,x+freearr_x[i],y+freearr_y[i]); |
2250 | flag = ob_blocked(ob,m,x+freearr_x[i],y+freearr_y[i]); |
… | |
… | |
2254 | * find_free_spot(), but it will search max number of squares. |
2271 | * find_free_spot(), but it will search max number of squares. |
2255 | * But it will return the first available spot, not a random choice. |
2272 | * But it will return the first available spot, not a random choice. |
2256 | * Changed 0.93.2: Have it return -1 if there is no free spot available. |
2273 | * Changed 0.93.2: Have it return -1 if there is no free spot available. |
2257 | */ |
2274 | */ |
2258 | |
2275 | |
2259 | int find_first_free_spot(object *ob, mapstruct *m,int x,int y) { |
2276 | int find_first_free_spot(const object *ob, mapstruct *m,int x,int y) { |
2260 | int i; |
2277 | int i; |
2261 | for(i=0;i<SIZEOFFREE;i++) { |
2278 | for(i=0;i<SIZEOFFREE;i++) { |
2262 | if(!ob_blocked(ob,m,x+freearr_x[i],y+freearr_y[i])) |
2279 | if(!ob_blocked(ob,m,x+freearr_x[i],y+freearr_y[i])) |
2263 | return i; |
2280 | return i; |
2264 | } |
2281 | } |
… | |
… | |
2365 | /* |
2382 | /* |
2366 | * distance(object 1, object 2) will return the square of the |
2383 | * distance(object 1, object 2) will return the square of the |
2367 | * distance between the two given objects. |
2384 | * distance between the two given objects. |
2368 | */ |
2385 | */ |
2369 | |
2386 | |
2370 | int distance(object *ob1,object *ob2) { |
2387 | int distance(const object *ob1, const object *ob2) { |
2371 | int i; |
2388 | int i; |
2372 | i= (ob1->x - ob2->x)*(ob1->x - ob2->x)+ |
2389 | i= (ob1->x - ob2->x)*(ob1->x - ob2->x)+ |
2373 | (ob1->y - ob2->y)*(ob1->y - ob2->y); |
2390 | (ob1->y - ob2->y)*(ob1->y - ob2->y); |
2374 | return i; |
2391 | return i; |
2375 | } |
2392 | } |
… | |
… | |
2540 | * core dumps if they do. |
2557 | * core dumps if they do. |
2541 | * |
2558 | * |
2542 | * Add a check so we can't pick up invisible objects (0.93.8) |
2559 | * Add a check so we can't pick up invisible objects (0.93.8) |
2543 | */ |
2560 | */ |
2544 | |
2561 | |
2545 | int can_pick(object *who,object *item) { |
2562 | int can_pick(const object *who, const object *item) { |
2546 | return /*QUERY_FLAG(who,FLAG_WIZ)||*/ |
2563 | return /*QUERY_FLAG(who,FLAG_WIZ)||*/ |
2547 | (item->weight>0&&!QUERY_FLAG(item,FLAG_NO_PICK)&& |
2564 | (item->weight>0&&!QUERY_FLAG(item,FLAG_NO_PICK)&& |
2548 | !QUERY_FLAG(item,FLAG_ALIVE)&&!item->invisible && |
2565 | !QUERY_FLAG(item,FLAG_ALIVE)&&!item->invisible && |
2549 | (who->type==PLAYER||item->weight<who->weight/3)); |
2566 | (who->type==PLAYER||item->weight<who->weight/3)); |
2550 | } |
2567 | } |
… | |
… | |
2585 | |
2602 | |
2586 | return dst; |
2603 | return dst; |
2587 | } |
2604 | } |
2588 | |
2605 | |
2589 | /* return true if the object was destroyed, 0 otherwise */ |
2606 | /* return true if the object was destroyed, 0 otherwise */ |
2590 | int was_destroyed (object *op, tag_t old_tag) |
2607 | int was_destroyed (const object *op, tag_t old_tag) |
2591 | { |
2608 | { |
2592 | /* checking for FLAG_FREED isn't necessary, but makes this function more |
2609 | /* checking for FLAG_FREED isn't necessary, but makes this function more |
2593 | * robust */ |
2610 | * robust */ |
2594 | return op->count != old_tag || QUERY_FLAG (op, FLAG_FREED); |
2611 | return op->count != old_tag || QUERY_FLAG (op, FLAG_FREED); |
2595 | } |
2612 | } |
… | |
… | |
2599 | /* load_object on it. I admit it is a highly inefficient way to make things, */ |
2616 | /* load_object on it. I admit it is a highly inefficient way to make things, */ |
2600 | /* but it was simple to make and allows reusing the load_object function. */ |
2617 | /* but it was simple to make and allows reusing the load_object function. */ |
2601 | /* Remember not to use load_object_str in a time-critical situation. */ |
2618 | /* Remember not to use load_object_str in a time-critical situation. */ |
2602 | /* Also remember that multiparts objects are not supported for now. */ |
2619 | /* Also remember that multiparts objects are not supported for now. */ |
2603 | |
2620 | |
2604 | object* load_object_str(char *obstr) |
2621 | object* load_object_str(const char *obstr) |
2605 | { |
2622 | { |
2606 | object *op; |
2623 | object *op; |
2607 | FILE *tempfile; |
2624 | FILE *tempfile; |
2608 | char filename[MAX_BUF]; |
2625 | char filename[MAX_BUF]; |
2609 | sprintf(filename,"%s/cfloadobstr2044",settings.tmpdir); |
2626 | sprintf(filename,"%s/cfloadobstr2044",settings.tmpdir); |
… | |
… | |
2633 | |
2650 | |
2634 | /* This returns the first object in who's inventory that |
2651 | /* This returns the first object in who's inventory that |
2635 | * has the same type and subtype match. |
2652 | * has the same type and subtype match. |
2636 | * returns NULL if no match. |
2653 | * returns NULL if no match. |
2637 | */ |
2654 | */ |
2638 | object *find_obj_by_type_subtype(object *who, int type, int subtype) |
2655 | object *find_obj_by_type_subtype(const object *who, int type, int subtype) |
2639 | { |
2656 | { |
2640 | object *tmp; |
2657 | object *tmp; |
2641 | |
2658 | |
2642 | for (tmp=who->inv; tmp; tmp=tmp->below) |
2659 | for (tmp=who->inv; tmp; tmp=tmp->below) |
2643 | if (tmp->type == type && tmp->subtype == subtype) return tmp; |
2660 | if (tmp->type == type && tmp->subtype == subtype) return tmp; |
… | |
… | |
2649 | * otherwise return NULL. |
2666 | * otherwise return NULL. |
2650 | * |
2667 | * |
2651 | * key must be a passed in shared string - otherwise, this won't |
2668 | * key must be a passed in shared string - otherwise, this won't |
2652 | * do the desired thing. |
2669 | * do the desired thing. |
2653 | */ |
2670 | */ |
2654 | key_value * get_ob_key_link(object * ob, const char * key) { |
2671 | key_value * get_ob_key_link(const object * ob, const char * key) { |
2655 | key_value * link; |
2672 | key_value * link; |
2656 | |
2673 | |
2657 | for (link = ob->key_values; link != NULL; link = link->next) { |
2674 | for (link = ob->key_values; link != NULL; link = link->next) { |
2658 | if (link->key == key) { |
2675 | if (link->key == key) { |
2659 | return link; |
2676 | return link; |
… | |
… | |
2668 | * |
2685 | * |
2669 | * The argument doesn't need to be a shared string. |
2686 | * The argument doesn't need to be a shared string. |
2670 | * |
2687 | * |
2671 | * The returned string is shared. |
2688 | * The returned string is shared. |
2672 | */ |
2689 | */ |
2673 | const char * get_ob_key_value(object * op, const char * const key) { |
2690 | const char * get_ob_key_value(const object * op, const char * const key) { |
2674 | key_value * link; |
2691 | key_value * link; |
2675 | const char * canonical_key; |
2692 | const char * canonical_key; |
2676 | |
2693 | |
2677 | canonical_key = find_string(key); |
2694 | canonical_key = find_string(key); |
2678 | |
2695 | |