version 1.72 | | version 1.73 |
---|
| | |
/* | | /* |
* static char *rcsid_object_c = | | * static char *rcsid_object_c = |
* "$Id: object.c,v 1.72 2003/09/04 06:25:32 temitchell Exp $"; | | * "$Id: object.c,v 1.73 2003/09/13 05:01:29 mwedel Exp $"; |
*/ | | */ |
| | |
/* | | /* |
| | |
if (!QUERY_FLAG(ob1,FLAG_ANIMATE) && FABS((ob1)->speed) > MIN_ACTIVE_SPEED) | | if (!QUERY_FLAG(ob1,FLAG_ANIMATE) && FABS((ob1)->speed) > MIN_ACTIVE_SPEED) |
return 0; | | return 0; |
| | |
| | /* This is really a spellbook check - really, we should |
| | * check all objects in the inventory. |
| | */ |
| | if (ob1->inv || ob2->inv) { |
| | /* if one object has inventory but the other doesn't, not equiv */ |
| | if ((ob1->inv && !ob2->inv) || (ob2->inv && !ob1->inv)) return 0; |
| | |
| | /* Now check to see if the two inventory objects could merge */ |
| | if (!CAN_MERGE(ob1->inv, ob2->inv)) return 0; |
| | |
| | /* inventory ok - still need to check rest of this object to see |
| | * if it is valid. |
| | */ |
| | } |
| | |
/* If the objects have been identified, set the BEEN_APPLIED flag. | | /* If the objects have been identified, set the BEEN_APPLIED flag. |
* This is to the comparison of the flags below will be OK. We | | * This is to the comparison of the flags below will be OK. We |
| | |
(ob1->attacktype != ob2->attacktype) || | | (ob1->attacktype != ob2->attacktype) || |
(ob1->magic != ob2->magic) || | | (ob1->magic != ob2->magic) || |
(ob1->slaying != ob2->slaying) || | | (ob1->slaying != ob2->slaying) || |
| | (ob1->skill != ob2->skill) || |
(ob1->value != ob2->value) || | | (ob1->value != ob2->value) || |
(ob1->animation_id != ob2->animation_id) || | | (ob1->animation_id != ob2->animation_id) || |
(ob1->client_type != ob2->client_type) || | | (ob1->client_type != ob2->client_type) || |
| | |
} | | } |
| | |
| | |
| | |
/* | | /* |
* Sets the owner of the first object to the second object. | | * Sets the owner and sets the skill and exp pointers to owner's current |
* Also checkpoints a backup id-scheme which detects freeing (and reusage) | | * skill and experience objects. |
* of the owner object. | | |
* See also get_owner() | | |
*/ | | */ |
| | void set_owner (object *op, object *owner) |
static void set_owner_simple (object *op, object *owner) | | |
{ | | { |
| | if(owner==NULL||op==NULL) |
| | return; |
| | |
/* next line added to allow objects which own objects */ | | /* next line added to allow objects which own objects */ |
/* Add a check for ownercounts in here, as I got into an endless loop | | /* Add a check for ownercounts in here, as I got into an endless loop |
* with the fireball owning a poison cloud which then owned the | | * with the fireball owning a poison cloud which then owned the |
| | |
| | |
op->ownercount=owner->count; | | op->ownercount=owner->count; |
owner->refcount++; | | owner->refcount++; |
} | | |
| | |
static void set_skill_pointers (object *op, object *chosen_skill, | | |
object *exp_obj) | | |
{ | | |
op->chosen_skill = chosen_skill; | | |
op->exp_obj = exp_obj; | | |
| | |
/* unfortunately, we can't allow summoned monsters skill use | | |
* because we will need the chosen_skill field to pick the | | |
* right skill/stat modifiers for calc_skill_exp(). See | | |
* hit_player() in server/attack.c -b.t. | | |
*/ | | |
CLEAR_FLAG (op, FLAG_CAN_USE_SKILL); | | |
CLEAR_FLAG (op, FLAG_READY_SKILL); | | |
} | | |
| | |
| | |
/* | | |
* Sets the owner and sets the skill and exp pointers to owner's current | | |
* skill and experience objects. | | |
*/ | | |
void set_owner (object *op, object *owner) | | |
{ | | |
if(owner==NULL||op==NULL) | | |
return; | | |
set_owner_simple (op, owner); | | |
| | |
if (owner->type == PLAYER && owner->chosen_skill) | | |
set_skill_pointers (op, owner->chosen_skill, | | |
owner->chosen_skill->exp_obj); | | |
else if (op->type != PLAYER) | | |
CLEAR_FLAG (op, FLAG_READY_SKILL); | | |
} | | } |
| | |
/* Set the owner to clone's current owner and set the skill and experience | | /* Set the owner to clone's current owner and set the skill and experience |
| | |
if (clone->type == PLAYER) owner=clone; | | if (clone->type == PLAYER) owner=clone; |
else return; | | else return; |
} | | } |
set_owner_simple (op, owner); | | set_owner(op, owner); |
| | |
if (clone->chosen_skill) | | |
set_skill_pointers (op, clone->chosen_skill, clone->exp_obj); | | |
else if (op->type != PLAYER) | | |
CLEAR_FLAG (op, FLAG_READY_SKILL); | | |
} | | } |
| | |
/* | | /* |
| | |
op->title = NULL; | | op->title = NULL; |
op->race = NULL; | | op->race = NULL; |
op->slaying = NULL; | | op->slaying = NULL; |
| | op->skill = NULL; |
op->msg = NULL; | | op->msg = NULL; |
op->materialname = NULL; | | op->materialname = NULL; |
op->lore = NULL; | | op->lore = NULL; |
| | |
if (op->title != NULL) FREE_AND_CLEAR_STR(op->title); | | if (op->title != NULL) FREE_AND_CLEAR_STR(op->title); |
if (op->race!=NULL) FREE_AND_CLEAR_STR(op->race); | | if (op->race!=NULL) FREE_AND_CLEAR_STR(op->race); |
if (op->slaying!=NULL) FREE_AND_CLEAR_STR(op->slaying); | | if (op->slaying!=NULL) FREE_AND_CLEAR_STR(op->slaying); |
| | if (op->skill!=NULL) FREE_AND_CLEAR_STR(op->skill); |
if (op->msg!=NULL) FREE_AND_CLEAR_STR(op->msg); | | if (op->msg!=NULL) FREE_AND_CLEAR_STR(op->msg); |
if (op->lore!=NULL) FREE_AND_CLEAR_STR(op->lore); | | if (op->lore!=NULL) FREE_AND_CLEAR_STR(op->lore); |
if (op->materialname!= NULL) FREE_AND_CLEAR_STR(op->materialname); | | if (op->materialname!= NULL) FREE_AND_CLEAR_STR(op->materialname); |
| | |
op->expmul=1.0; | | op->expmul=1.0; |
op->face = blank_face; | | op->face = blank_face; |
op->attacked_by_count= -1; | | op->attacked_by_count= -1; |
if (settings.casting_time == TRUE) | | if (settings.casting_time) |
op->casting = -1; | | op->casting_time = -1; |
| | |
/* Clean the events list */ | | /* Clean the events list */ |
while (op->events != NULL) | | while (op->events != NULL) |
{ | | { |
| | |
else | | else |
op->events = NULL; | | op->events = NULL; |
} | | } |
| | |
} | | } |
| | |
/* | | /* |
| | |
free_string(op->race); | | free_string(op->race); |
if(op->slaying!=NULL) | | if(op->slaying!=NULL) |
free_string(op->slaying); | | free_string(op->slaying); |
| | if(op->skill!=NULL) |
| | free_string(op->skill); |
if(op->lore!=NULL) | | if(op->lore!=NULL) |
free_string(op->lore); | | free_string(op->lore); |
if(op->msg!=NULL) | | if(op->msg!=NULL) |
| | |
add_refcount(op->race); | | add_refcount(op->race); |
if(op->slaying!=NULL) | | if(op->slaying!=NULL) |
add_refcount(op->slaying); | | add_refcount(op->slaying); |
| | if(op->skill!=NULL) |
| | add_refcount(op->skill); |
if(op->lore!=NULL) | | if(op->lore!=NULL) |
add_refcount(op->lore); | | add_refcount(op->lore); |
if(op->msg!=NULL) | | if(op->msg!=NULL) |
| | |
op->title=NULL; | | op->title=NULL; |
op->race=NULL; | | op->race=NULL; |
op->slaying=NULL; | | op->slaying=NULL; |
| | op->skill = NULL; |
op->lore=NULL; | | op->lore=NULL; |
op->msg=NULL; | | op->msg=NULL; |
op->materialname=NULL; | | op->materialname=NULL; |
| | |
*/ | | */ |
| | |
void update_object(object *op, int action) { | | void update_object(object *op, int action) { |
int update_now, flags; | | int update_now=0, flags; |
| | |
if (op == NULL) { | | if (op == NULL) { |
/* this should never happen */ | | /* this should never happen */ |
| | |
| | |
if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags & P_IS_ALIVE)) | | if (QUERY_FLAG(op, FLAG_ALIVE) && !(flags & P_IS_ALIVE)) |
update_now=1; | | update_now=1; |
| | } |
} else if (action == UP_OBJ_REMOVE) { | | /* if the object is being removed, we can't make intelligent |
if (QUERY_FLAG(op, FLAG_BLOCKSVIEW) && (flags & P_BLOCKSVIEW)) | | * decisions, because remove_ob can't really pass the object |
update_now=1; | | * that is being removed. |
| | */ |
if (QUERY_FLAG(op, FLAG_NO_MAGIC) && (flags & P_NO_MAGIC)) | | else if (action == UP_OBJ_CHANGE || action == UP_OBJ_REMOVE) { |
update_now=1; | | |
| | |
if (QUERY_FLAG(op, FLAG_DAMNED) && (flags & P_NO_CLERIC)) | | |
update_now=1; | | |
| | |
if (QUERY_FLAG(op, FLAG_NO_PASS) && (flags & P_NO_PASS)) | | |
update_now=1; | | |
| | |
if (QUERY_FLAG(op, FLAG_ALIVE) && (flags & P_IS_ALIVE)) | | |
update_now=1; | | |
| | |
} else if (action == UP_OBJ_CHANGE) { | | |
update_now=1; | | update_now=1; |
} else if (action == UP_OBJ_FACE) { | | } else if (action == UP_OBJ_FACE) { |
/* Nothing to do for that case */ | | /* Nothing to do for that case */ |
| | |
if(ob->title!=NULL) FREE_AND_CLEAR_STR(ob->title); | | if(ob->title!=NULL) FREE_AND_CLEAR_STR(ob->title); |
if(ob->race!=NULL) FREE_AND_CLEAR_STR(ob->race); | | if(ob->race!=NULL) FREE_AND_CLEAR_STR(ob->race); |
if(ob->slaying!=NULL) FREE_AND_CLEAR_STR(ob->slaying); | | if(ob->slaying!=NULL) FREE_AND_CLEAR_STR(ob->slaying); |
| | if(ob->skill!=NULL) FREE_AND_CLEAR_STR(ob->skill); |
if(ob->lore!=NULL) FREE_AND_CLEAR_STR(ob->lore); | | if(ob->lore!=NULL) FREE_AND_CLEAR_STR(ob->lore); |
if(ob->msg!=NULL) FREE_AND_CLEAR_STR(ob->msg); | | if(ob->msg!=NULL) FREE_AND_CLEAR_STR(ob->msg); |
if(ob->materialname!=NULL) FREE_AND_CLEAR_STR(ob->materialname); | | if(ob->materialname!=NULL) FREE_AND_CLEAR_STR(ob->materialname); |
| | |
} | | } |
} | | } |
newob->nrof=nr; | | newob->nrof=nr; |
| | |
| | /* Need to preserve spell information for multiple objects, eg, |
| | * books. |
| | */ |
| | if (orig_ob->inv && orig_ob->inv->type == SPELL) { |
| | object *tmp = get_object(); |
| | copy_object(orig_ob->inv, tmp); |
| | insert_ob_in_ob(tmp, newob); |
| | } |
| | |
return newob; | | return newob; |
} | | } |
| | |
| | |
} | | } |
| | |
/* | | /* |
| | * present_in_ob (type, str, object) searches for any objects with |
| | * a matching type & name variable in the inventory of the given object. |
| | * The first matching object is returned, or NULL if none. |
| | * This is mostly used by spell effect code, so that we only |
| | * have one spell effect at a time. |
| | * type can be used to narrow the search - if type is set, |
| | * the type must also match. -1 can be passed for the type, |
| | * in which case the type does not need to pass. |
| | * str is the string to match against. Note that we match against |
| | * the object name, not the archetype name. this is so that the |
| | * spell code can use one object type (force), but change it's name |
| | * to be unique. |
| | */ |
| | |
| | object *present_in_ob_by_name(int type, char *str,object *op) { |
| | object *tmp; |
| | |
| | for(tmp=op->inv; tmp!=NULL; tmp=tmp->below) { |
| | if ((type==-1 || tmp->type==type) && (!strcmp(str, tmp->name))) |
| | return tmp; |
| | } |
| | return NULL; |
| | } |
| | |
| | /* |
* present_arch_in_ob(archetype, object) searches for any objects with | | * present_arch_in_ob(archetype, object) searches for any objects with |
* a matching archetype in the inventory of the given object. | | * a matching archetype in the inventory of the given object. |
* The first matching object is returned, or NULL if none. | | * The first matching object is returned, or NULL if none. |
| | |
return d; | | return d; |
} | | } |
| | |
| | /* peterm: |
| | * do LOS stuff for ball lightning. Go after the closest VISIBLE monster. |
| | * Basically, this is a table of directions, and what directions |
| | * one could go to go back to us. Eg, entry 15 below is 4, 14, 16. |
| | * This basically means that if direction is 15, then it could either go |
| | * direction 4, 14, or 16 to get back to where we are. |
| | * Moved from spell_util.c to object.c with the other related direction |
| | * functions. |
| | */ |
| | |
| | int reduction_dir[SIZEOFFREE][3] = { |
| | {0,0,0}, /* 0 */ |
| | {0,0,0}, /* 1 */ |
| | {0,0,0}, /* 2 */ |
| | {0,0,0}, /* 3 */ |
| | {0,0,0}, /* 4 */ |
| | {0,0,0}, /* 5 */ |
| | {0,0,0}, /* 6 */ |
| | {0,0,0}, /* 7 */ |
| | {0,0,0}, /* 8 */ |
| | {8,1,2}, /* 9 */ |
| | {1,2,-1}, /* 10 */ |
| | {2,10,12}, /* 11 */ |
| | {2,3,-1}, /* 12 */ |
| | {2,3,4}, /* 13 */ |
| | {3,4,-1}, /* 14 */ |
| | {4,14,16}, /* 15 */ |
| | {5,4,-1}, /* 16 */ |
| | {4,5,6}, /* 17 */ |
| | {6,5,-1}, /* 18 */ |
| | {6,20,18}, /* 19 */ |
| | {7,6,-1}, /* 20 */ |
| | {6,7,8}, /* 21 */ |
| | {7,8,-1}, /* 22 */ |
| | {8,22,24}, /* 23 */ |
| | {8,1,-1}, /* 24 */ |
| | {24,9,10}, /* 25 */ |
| | {9,10,-1}, /* 26 */ |
| | {10,11,-1}, /* 27 */ |
| | {27,11,29}, /* 28 */ |
| | {11,12,-1}, /* 29 */ |
| | {12,13,-1}, /* 30 */ |
| | {12,13,14}, /* 31 */ |
| | {13,14,-1}, /* 32 */ |
| | {14,15,-1}, /* 33 */ |
| | {33,15,35}, /* 34 */ |
| | {16,15,-1}, /* 35 */ |
| | {17,16,-1}, /* 36 */ |
| | {18,17,16}, /* 37 */ |
| | {18,17,-1}, /* 38 */ |
| | {18,19,-1}, /* 39 */ |
| | {41,19,39}, /* 40 */ |
| | {19,20,-1}, /* 41 */ |
| | {20,21,-1}, /* 42 */ |
| | {20,21,22}, /* 43 */ |
| | {21,22,-1}, /* 44 */ |
| | {23,22,-1}, /* 45 */ |
| | {45,47,23}, /* 46 */ |
| | {23,24,-1}, /* 47 */ |
| | {24,9,-1}}; /* 48 */ |
| | |
| | /* Recursive routine to step back and see if we can |
| | * find a path to that monster that we found. If not, |
| | * we don't bother going toward it. Returns 1 if we |
| | * can see a direct way to get it |
| | * Modified to be map tile aware -.MSW |
| | */ |
| | |
| | |
| | int can_see_monsterP(mapstruct *m, int x, int y,int dir) { |
| | sint16 dx, dy; |
| | int mflags; |
| | |
| | if(dir<0) return 0; /* exit condition: invalid direction */ |
| | |
| | dx = x + freearr_x[dir]; |
| | dy = y + freearr_y[dir]; |
| | |
| | mflags = get_map_flags(m, &m, dx, dy, &dx, &dy); |
| | |
| | if (mflags & (P_OUT_OF_MAP | P_WALL)) return 0; |
| | |
| | /* yes, can see. */ |
| | if(dir < 9) return 1; |
| | return can_see_monsterP(m, x, y, reduction_dir[dir][0]) | |
| | can_see_monsterP(m,x,y, reduction_dir[dir][1]) | |
| | can_see_monsterP(m,x,y, reduction_dir[dir][2]); |
| | } |
| | |
| | |
| | |
/* | | /* |
* can_pick(picker, item): finds out if an object is possible to be | | * can_pick(picker, item): finds out if an object is possible to be |
* picked up by the picker. Returnes 1 if it can be | | * picked up by the picker. Returnes 1 if it can be |
| | |
return dst; | | return dst; |
} | | } |
| | |
| | /* return true if the object was destroyed, 0 otherwise */ |
int was_destroyed (object *op, tag_t old_tag) | | int was_destroyed (object *op, tag_t old_tag) |
{ | | { |
/* checking for FLAG_FREED isn't necessary, but makes this function more | | /* checking for FLAG_FREED isn't necessary, but makes this function more |
| | |
/* but it was simple to make and allows reusing the load_object function. */ | | /* but it was simple to make and allows reusing the load_object function. */ |
/* Remember not to use load_object_str in a time-critical situation. */ | | /* Remember not to use load_object_str in a time-critical situation. */ |
/* Also remember that multiparts objects are not supported for now. */ | | /* Also remember that multiparts objects are not supported for now. */ |
| | |
object* load_object_str(char *obstr) | | object* load_object_str(char *obstr) |
{ | | { |
object *op; | | object *op; |
| | |
return op; | | return op; |
} | | } |
| | |
/*** end of object.c ***/ | | /* This returns the first object in who's inventory that |
| | * has the same type and subtype match. |
| | * returns NULL if no match. |
| | */ |
| | object *find_obj_by_type_subtype(object *who, int type, int subtype) |
| | { |
| | object *tmp; |
| | |
| | for (tmp=who->inv; tmp; tmp=tmp->below); |
| | if (tmp->type == type && tmp->subtype == subtype) return tmp; |
| | |
| | return NULL; |
| | } |
| | |