Crossfire Server, Branch 1.12  R12190
gate.c
Go to the documentation of this file.
00001 /*
00002     CrossFire, A Multiplayer game for X-windows
00003 
00004     Copyright (C) 2007 Mark Wedel & Crossfire Development Team
00005     Copyright (C) 1992 Frank Tore Johansen
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 
00021     The authors can be reached via e-mail at crossfire-devel@real-time.com
00022 */
00023 
00028 #include <global.h>
00029 #include <ob_methods.h>
00030 #include <ob_types.h>
00031 #include <sounds.h>
00032 #include <sproto.h>
00033 
00034 static method_ret gate_type_process(ob_methods *context, object *op);
00035 static method_ret timed_gate_type_process(ob_methods *context, object *op);
00036 
00040 void init_type_gate(void) {
00041     register_process(GATE, gate_type_process);
00042     register_process(TIMED_GATE, timed_gate_type_process);
00043 }
00044 
00051 static method_ret gate_type_process(ob_methods *context, object *op) {
00052     object *tmp;
00053 
00054     if (op->stats.wc < 0 || (int)op->stats.wc >= NUM_ANIMATIONS(op)) {
00055         StringBuffer *sb;
00056         char *diff;
00057 
00058         LOG(llevError, "Gate error: animation was %d, max=%d\n", op->stats.wc, NUM_ANIMATIONS(op));
00059         sb = stringbuffer_new();
00060         dump_object(op, sb);
00061         diff = stringbuffer_finish(sb);
00062         LOG(llevError, "%s\n", diff);
00063         free(diff);
00064         op->stats.wc = 0;
00065     }
00066 
00067     /* We're going down */
00068     if (op->value) {
00069         if (--op->stats.wc <= 0) { /* Reached bottom, let's stop */
00070             op->stats.wc = 0;
00071             if (op->arch->clone.speed)
00072                 op->value = 0;
00073             else {
00074                 op->speed = 0;
00075                 update_ob_speed(op);
00076             }
00077         }
00078         if ((int)op->stats.wc < (NUM_ANIMATIONS(op)/2+1)) {
00079             op->move_block = 0;
00080             CLEAR_FLAG(op, FLAG_BLOCKSVIEW);
00081             update_all_los(op->map, op->x, op->y);
00082         }
00083         SET_ANIMATION(op, op->stats.wc);
00084         update_object(op, UP_OBJ_CHANGE);
00085         return METHOD_OK;
00086     }
00087 
00088     /* We're going up */
00089 
00090     /* First, lets see if we are already at the top */
00091     if ((unsigned char)op->stats.wc == (NUM_ANIMATIONS(op)-1)) {
00092         /* Check to make sure that only non pickable and non rollable
00093          * objects are above the gate.  If so, we finish closing the gate,
00094          * otherwise, we fall through to the code below which should lower
00095          * the gate slightly.
00096          */
00097 
00098         for (tmp = op->above; tmp != NULL; tmp = tmp->above)
00099             if (!QUERY_FLAG(tmp, FLAG_NO_PICK)
00100             || QUERY_FLAG(tmp, FLAG_CAN_ROLL)
00101             || QUERY_FLAG(tmp, FLAG_ALIVE))
00102                 break;
00103 
00104         if (tmp == NULL) {
00105             if (op->arch->clone.speed)
00106                 op->value = 1;
00107             else {
00108                 op->speed = 0;
00109                 update_ob_speed(op); /* Reached top, let's stop */
00110             }
00111             return METHOD_OK;
00112         }
00113     }
00114 
00115     if (op->stats.food) {    /* The gate is going temporarily down */
00116         if (--op->stats.wc <= 0) { /* Gone all the way down? */
00117             op->stats.food = 0;     /* Then let's try again */
00118             op->stats.wc = 0;
00119         }
00120     } else {                /* The gate is still going up */
00121         op->stats.wc++;
00122 
00123         if ((int)op->stats.wc >= (NUM_ANIMATIONS(op)))
00124             op->stats.wc = (signed char)NUM_ANIMATIONS(op)-1;
00125 
00126         /* If there is something on top of the gate, we try to roll it off.
00127          * If a player/monster, we don't roll, we just hit them with damage
00128          */
00129         if ((int)op->stats.wc >= NUM_ANIMATIONS(op)/2) {
00130             /* Halfway or further, check blocks */
00131             /* First, get the top object on the square. */
00132             for (tmp = op->above; tmp != NULL && tmp->above != NULL; tmp = tmp->above)
00133                 ;
00134 
00135             if (tmp != NULL) {
00136                 if (QUERY_FLAG(tmp, FLAG_ALIVE)) {
00137                     hit_player(tmp, random_roll(1, op->stats.dam, tmp, PREFER_LOW), op, AT_PHYSICAL, 1);
00138                     if (tmp->type == PLAYER)
00139                         draw_ext_info_format(NDI_UNIQUE, 0, tmp, MSG_TYPE_VICTIM, MSG_TYPE_VICTIM_WAS_HIT,
00140                                              "You are crushed by the %s!",
00141                                              "You are crushed by the %s!",
00142                                              op->name);
00143                 } else
00144                     /* If the object is not alive, and the object either can
00145                      * be picked up or the object rolls, move the object
00146                      * off the gate.
00147                      */
00148                     if (!QUERY_FLAG(tmp, FLAG_ALIVE)
00149                     && (!QUERY_FLAG(tmp, FLAG_NO_PICK) || QUERY_FLAG(tmp, FLAG_CAN_ROLL))) {
00150                     /* If it has speed, it should move itself, otherwise: */
00151                         int i = find_free_spot(tmp, op->map, op->x, op->y, 1, 9);
00152 
00153                         /* If there is a free spot, move the object someplace */
00154                         if (i != -1) {
00155                             remove_ob(tmp);
00156                             tmp->x += freearr_x[i],
00157                             tmp->y += freearr_y[i];
00158                             insert_ob_in_map(tmp, op->map, op, 0);
00159                         }
00160                     }
00161             }
00162 
00163             /* See if there is still anything blocking the gate */
00164             for (tmp = op->above; tmp != NULL; tmp = tmp->above)
00165                 if (!QUERY_FLAG(tmp, FLAG_NO_PICK)
00166                 || QUERY_FLAG(tmp, FLAG_CAN_ROLL)
00167                 || QUERY_FLAG(tmp, FLAG_ALIVE))
00168                     break;
00169 
00170             /* IF there is, start putting the gate down  */
00171             if (tmp) {
00172                 op->stats.food = 1;
00173             } else {
00174                 op->move_block = MOVE_ALL;
00175                 if (!op->arch->clone.stats.ac)
00176                     SET_FLAG(op, FLAG_BLOCKSVIEW);
00177                 update_all_los(op->map, op->x, op->y);
00178             }
00179         } /* gate is halfway up */
00180 
00181         SET_ANIMATION(op, op->stats.wc);
00182         update_object(op, UP_OBJ_CHANGE);
00183     } /* gate is going up */
00184 
00185     return METHOD_OK;
00186 }
00187 
00198 static method_ret timed_gate_type_process(ob_methods *context, object *op) {
00199     int v = op->value;
00200 
00201     if (op->stats.sp) {
00202         gate_type_process(context, op);
00203         if (op->value != v)   /* change direction ? */
00204             op->stats.sp = 0;
00205         return METHOD_OK;
00206     }
00207     if (--op->stats.hp <= 0) { /* keep gate down */
00208         gate_type_process(context, op);
00209         if (op->value != v) {  /* ready ? */
00210             op->speed = 0;
00211             update_ob_speed(op);
00212         }
00213     }
00214     return METHOD_OK;
00215 }