--- deliantra/server/common/button.C 2006/08/29 08:01:35 1.2 +++ deliantra/server/common/button.C 2006/08/29 17:29:27 1.3 @@ -1,6 +1,6 @@ /* * static char *rcsid_button_c = - * "$Id: button.C,v 1.2 2006/08/29 08:01:35 root Exp $"; + * "$Id: button.C,v 1.3 2006/08/29 17:29:27 elmex Exp $"; */ /* @@ -34,120 +34,171 @@ */ /* - * Push the specified object. This can affect other buttons/gates/handles - * altars/pedestals/holes in the whole map. - * Changed the routine to loop through _all_ objects. - * Better hurry with that linked list... + * elmex: + * This function takes a objectlink list with all the objects are going to be activated. + * state is a true/false flag that will actiavte objects that have FLAG_ACTIVATE_ON_PUSH/RELEASE set. + * The source argument can be 0 or the source object for this activation. */ +void activate_connection_link (objectlink *ol, bool state, object *source = 0) +{ + object *tmp = 0; -void push_button(object *op) { - object *tmp; - objectlink *ol; - -/* LOG(llevDebug, "push_button: %s (%d)\n", op->name, op->count); */ - for (ol = get_button_links(op); ol; ol = ol->next) { - if (!ol->ob || ol->ob->count != ol->id) { - LOG(llevError, "Internal error in push_button (%s).\n", op->name); - continue; + for (; ol; ol = ol->next) + { + if (!ol->ob || ol->ob->count != ol->id) + { + LOG (llevError, "Internal error in activate_connection_link (%ld).\n", ol->id); + continue; } - /* a button link object can become freed when the map is saving. As - * a map is saved, objects are removed and freed, and if an object is - * on top of a button, this function is eventually called. If a map - * is getting moved out of memory, the status of buttons and levers - * probably isn't important - it will get sorted out when the map is - * re-loaded. As such, just exit this function if that is the case. - */ - - if (QUERY_FLAG(ol->ob, FLAG_FREED)) return; - tmp = ol->ob; - - /* if the criteria isn't appropriate, don't do anything */ - if (op->value && !QUERY_FLAG(tmp, FLAG_ACTIVATE_ON_PUSH)) continue; - if (!op->value && !QUERY_FLAG(tmp, FLAG_ACTIVATE_ON_RELEASE)) continue; - - switch(tmp->type) { - - case GATE: - case HOLE: - tmp->value=tmp->stats.maxsp?!op->value:op->value; - tmp->speed=0.5; - update_ob_speed(tmp); - break; + /* a button link object can become freed when the map is saving. As + * a map is saved, objects are removed and freed, and if an object is + * on top of a button, this function is eventually called. If a map + * is getting moved out of memory, the status of buttons and levers + * probably isn't important - it will get sorted out when the map is + * re-loaded. As such, just exit this function if that is the case. + */ - case CF_HANDLE: - SET_ANIMATION(tmp, (tmp->value=tmp->stats.maxsp?!op->value:op->value)); - update_object(tmp,UP_OBJ_FACE); - break; + if (QUERY_FLAG (ol->ob, FLAG_FREED)) + return; + tmp = ol->ob; - case SIGN: - if (!tmp->stats.food || tmp->last_eat < tmp->stats.food) { - new_info_map(NDI_UNIQUE | NDI_NAVY,tmp->map,tmp->msg); - if (tmp->stats.food) tmp->last_eat++; - } - break; + /* if the criteria isn't appropriate, don't do anything */ + if (state && !QUERY_FLAG (tmp, FLAG_ACTIVATE_ON_PUSH)) + continue; + if (!state && !QUERY_FLAG (tmp, FLAG_ACTIVATE_ON_RELEASE)) + continue; - case ALTAR: - tmp->value = 1; - SET_ANIMATION(tmp, tmp->value); - update_object(tmp,UP_OBJ_FACE); - break; + switch (tmp->type) + { + case GATE: + case HOLE: + tmp->value = tmp->stats.maxsp ? !state : state; + tmp->speed = 0.5; + update_ob_speed (tmp); + break; + + case CF_HANDLE: + SET_ANIMATION (tmp, + (tmp->value = + tmp->stats.maxsp ? !state : state)); + update_object (tmp, UP_OBJ_FACE); + break; + + case SIGN: + if (!tmp->stats.food || tmp->last_eat < tmp->stats.food) + { + new_info_map (NDI_UNIQUE | NDI_NAVY, tmp->map, tmp->msg); + if (tmp->stats.food) + tmp->last_eat++; + } + break; - case BUTTON: - case PEDESTAL: - tmp->value=op->value; - SET_ANIMATION(tmp, tmp->value); - update_object(tmp,UP_OBJ_FACE); - break; + case ALTAR: + tmp->value = 1; + SET_ANIMATION (tmp, tmp->value); + update_object (tmp, UP_OBJ_FACE); + break; + + case BUTTON: + case PEDESTAL: + tmp->value = state; + SET_ANIMATION (tmp, tmp->value); + update_object (tmp, UP_OBJ_FACE); + break; + + case MOOD_FLOOR: + do_mood_floor (tmp, source); + break; + + case TIMED_GATE: + tmp->speed = tmp->arch->clone.speed; + update_ob_speed (tmp); /* original values */ + tmp->value = tmp->arch->clone.value; + tmp->stats.sp = 1; + tmp->stats.hp = tmp->stats.maxhp; + /* Handle multipart gates. We copy the value for the other parts + * from the head - this ensures that the data will consistent + */ + for (tmp = tmp->more; tmp != NULL; tmp = tmp->more) + { + tmp->speed = tmp->head->speed; + tmp->value = tmp->head->value; + tmp->stats.sp = tmp->head->stats.sp; + tmp->stats.hp = tmp->head->stats.hp; + update_ob_speed (tmp); + } + break; - case MOOD_FLOOR: - do_mood_floor(tmp, op); - break; + case DIRECTOR: + case FIREWALL: + if (!QUERY_FLAG (tmp, FLAG_ANIMATE) && tmp->type == FIREWALL) + move_firewall (tmp); + else + { + if ((tmp->stats.sp += tmp->stats.maxsp) > 8) /* next direction */ + tmp->stats.sp = ((tmp->stats.sp - 1) % 8) + 1; + animate_turning (tmp); + } + break; - case TIMED_GATE: - tmp->speed = tmp->arch->clone.speed; - update_ob_speed(tmp); /* original values */ - tmp->value = tmp->arch->clone.value; - tmp->stats.sp = 1; - tmp->stats.hp = tmp->stats.maxhp; - /* Handle multipart gates. We copy the value for the other parts - * from the head - this ensures that the data will consistent - */ - for (tmp=tmp->more; tmp!=NULL; tmp=tmp->more) { - tmp->speed = tmp->head->speed; - tmp->value = tmp->head->value; - tmp->stats.sp = tmp->head->stats.sp; - tmp->stats.hp = tmp->head->stats.hp; - update_ob_speed(tmp); - } - break; + case TELEPORTER: + move_teleporter (tmp); + break; + + case CREATOR: + move_creator (tmp); + break; + + case TRIGGER_MARKER: + move_marker (tmp); + break; + + case DUPLICATOR: + move_duplicator (tmp); + break; + } + } +} - case DIRECTOR: - case FIREWALL: - if(!QUERY_FLAG(tmp,FLAG_ANIMATE)&&tmp->type==FIREWALL) move_firewall(tmp); - else { - if ((tmp->stats.sp += tmp->stats.maxsp) > 8) /* next direction */ - tmp->stats.sp = ((tmp->stats.sp-1)%8)+1; - animate_turning(tmp); - } - break; +/* + * elmex: + * This is the new push_button function, it got split up so that + * you can activate connections without a button now! + * old but still valid comment: + * + * Push the specified object. This can affect other buttons/gates/handles + * altars/pedestals/holes in the whole map. + * Changed the routine to loop through _all_ objects. + * Better hurry with that linked list... + * + */ +void push_button (object *op) +{ + oblinkpt *obp = get_button_links (op); - case TELEPORTER: - move_teleporter(tmp); - break; + if (INVOKE_MAP (TRIGGER, op->map, ARG_INT64(obp->value), ARG_INT(op->value))) + return; - case CREATOR: - move_creator(tmp); - break; - - case TRIGGER_MARKER: - move_marker(tmp); - break; + if (obp && obp->link) + activate_connection_link (obp->link, op->value, op); +} - case DUPLICATOR: - move_duplicator(tmp); - break; - } - } +/* + * elmex: + * This activates a connection, similar to push_button (object *op) but it takes + * only a map, a connection value and a true or false flag that indicated whether + * the connection was 'state' or 'released'. So that you can activate objects + * who have FLAG_ACTIVATE_ON_PUSH/RELEASE set properly. + * + */ +void activate_connection (mapstruct *map, long connection, bool state) +{ + if (INVOKE_MAP (TRIGGER, map, ARG_INT64(connection), ARG_INT(state))) + return; + + oblinkpt *obp = get_connection_links (map, connection); + if (obp && obp->link) + activate_connection_link (obp->link, state); } /* @@ -160,52 +211,55 @@ void update_button(object *op) { object *ab,*tmp,*head; int tot,any_down=0, old_value=op->value; + oblinkpt *obp = 0; objectlink *ol; + obp = get_button_links (op); /* LOG(llevDebug, "update_button: %s (%d)\n", op->name, op->count); */ - for (ol = get_button_links(op); ol; ol = ol->next) { - if (!ol->ob || ol->ob->count != ol->id) { - LOG(llevDebug, "Internal error in update_button (%s).\n", op->name); - continue; - } - tmp = ol->ob; - if (tmp->type==BUTTON) { - for(ab=tmp->above,tot=0;ab!=NULL;ab=ab->above) - /* Bug? The pedestal code below looks for the head of - * the object, this bit doesn't. I'd think we should check - * for head here also. Maybe it also makese sense to - * make the for ab=tmp->above loop common, and alter - * behaviour based on object within that loop? - */ - - /* Basically, if the move_type matches that on what the - * button wants, we count it. The second check is so that - * objects don't move (swords, etc) will count. Note that - * this means that more work is needed to make buttons - * that are only triggered by flying objects. - */ - if ((ab->move_type & tmp->move_on) || ab->move_type==0 ) - tot+=ab->weight*(ab->nrof?ab->nrof:1)+ab->carrying; - - tmp->value=(tot>=tmp->weight)?1:0; - if(tmp->value) - any_down=1; - } else if (tmp->type == PEDESTAL) { - tmp->value = 0; - for(ab=tmp->above; ab!=NULL; ab=ab->above) { - head = ab->head ? ab->head : ab; - /* Same note regarding move_type for buttons above apply here. */ - if ( ((head->move_type & tmp->move_on) || ab->move_type==0) && - (head->race==tmp->slaying || - ((head->type==SPECIAL_KEY) && (head->slaying==tmp->slaying)) || - (!strcmp (tmp->slaying, "player") && - head->type == PLAYER))) - tmp->value = 1; - } - if(tmp->value) - any_down=1; - } - } + if (obp) + for (ol = obp->link; ol; ol = ol->next) { + if (!ol->ob || ol->ob->count != ol->id) { + LOG(llevDebug, "Internal error in update_button (%s).\n", op->name); + continue; + } + tmp = ol->ob; + if (tmp->type==BUTTON) { + for(ab=tmp->above,tot=0;ab!=NULL;ab=ab->above) + /* Bug? The pedestal code below looks for the head of + * the object, this bit doesn't. I'd think we should check + * for head here also. Maybe it also makese sense to + * make the for ab=tmp->above loop common, and alter + * behaviour based on object within that loop? + */ + + /* Basically, if the move_type matches that on what the + * button wants, we count it. The second check is so that + * objects don't move (swords, etc) will count. Note that + * this means that more work is needed to make buttons + * that are only triggered by flying objects. + */ + if ((ab->move_type & tmp->move_on) || ab->move_type==0 ) + tot+=ab->weight*(ab->nrof?ab->nrof:1)+ab->carrying; + + tmp->value=(tot>=tmp->weight)?1:0; + if(tmp->value) + any_down=1; + } else if (tmp->type == PEDESTAL) { + tmp->value = 0; + for(ab=tmp->above; ab!=NULL; ab=ab->above) { + head = ab->head ? ab->head : ab; + /* Same note regarding move_type for buttons above apply here. */ + if ( ((head->move_type & tmp->move_on) || ab->move_type==0) && + (head->race==tmp->slaying || + ((head->type==SPECIAL_KEY) && (head->slaying==tmp->slaying)) || + (!strcmp (tmp->slaying, "player") && + head->type == PLAYER))) + tmp->value = 1; + } + if(tmp->value) + any_down=1; + } + } if(any_down) /* If any other buttons were down, force this to remain down */ op->value=1; @@ -569,12 +623,23 @@ LOG(llevError, "remove_button_linked(): couldn't find object.\n"); CLEAR_FLAG(op,FLAG_IS_LINKED); } - + +/* + * Gets the objectlink for this connection from the map. + */ +oblinkpt *get_connection_links (mapstruct *map, long connection) +{ + for (oblinkpt *obp = map->buttons; obp; obp = obp->next) + if (obp->value == connection) + return obp; + return 0; +} + /* * Return the first objectlink in the objects linked to this one */ -objectlink *get_button_links(const object *button) { +oblinkpt *get_button_links(const object *button) { oblinkpt *obp; objectlink *ol; @@ -583,7 +648,7 @@ for (obp = button->map->buttons; obp; obp = obp->next) for (ol = obp->link; ol; ol = ol->next) if (ol->ob == button && ol->id == button->count) - return obp->link; + return obp; return NULL; } @@ -613,10 +678,13 @@ * by b.t. thomas@nomad.astro.psu.edu */ -void do_mood_floor(object *op, object *op2) { +void do_mood_floor(object *op, object *source) { object *tmp; object *tmp2; + if (!source) + source = op; + for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp; tmp=tmp->above) if (QUERY_FLAG(tmp, FLAG_MONSTER)) break; @@ -658,10 +726,9 @@ SET_FLAG(tmp, FLAG_SLEEP); break; case 4: /* charm all monsters */ + if (op == source) break; /* only if 'connected' */ - if(op == op2) break; /* only if 'connected' */ - - for(tmp2=get_map_ob(op2->map,op2->x,op2->y); /* finding an owner */ + for(tmp2=get_map_ob(source->map,source->x,source->y); /* finding an owner */ tmp2->type!=PLAYER;tmp2=tmp2->above) if(tmp2->above==NULL) break;