Atrinik Server 2.5
types/gate.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00031 #include <global.h>
00032 
00036 void move_gate(object *op)
00037 {
00038     object *tmp;
00039     /* default update is only face */
00040     int update = UP_OBJ_FACE;
00041 
00042     if (op->stats.wc < 0 || (int) op->stats.wc >= (NUM_ANIMATIONS(op) / NUM_FACINGS(op)))
00043     {
00044         LOG(llevBug, "move_gate(): Gate animation was %d, max=%d\n", op->stats.wc, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)));
00045         op->stats.wc = 0;
00046     }
00047 
00048     /* We're going down (or reverse up) */
00049     if (op->value)
00050     {
00051         /* Reached bottom, let's stop */
00052         if (--op->stats.wc <= 0)
00053         {
00054             op->stats.wc = 0;
00055 
00056             if (op->arch->clone.speed)
00057             {
00058                 op->value = 0;
00059             }
00060             else
00061             {
00062                 op->speed = 0;
00063                 update_ob_speed(op);
00064             }
00065         }
00066 
00067         if ((int) op->stats.wc < ((NUM_ANIMATIONS(op) / NUM_FACINGS(op)) / 2 + 1))
00068         {
00069             /* We do the QUERY_FLAG() here to check we must rebuild the tile flags or not,
00070              * if we don't change the object settings here, just change the face but
00071              * don't rebuild the flag tiles.
00072              * If != 0, we have a reversed timed gate, which starts open */
00073             if (op->last_heal)
00074             {
00075                 if (!QUERY_FLAG(op, FLAG_NO_PASS))
00076                 {
00077                     update = UP_OBJ_FLAGFACE;
00078                 }
00079 
00080                 /* The coast is clear, block the way */
00081                 SET_FLAG(op, FLAG_NO_PASS);
00082 
00083                 if (!op->arch->clone.stats.ac)
00084                 {
00085                     if (!QUERY_FLAG(op, FLAG_BLOCKSVIEW))
00086                     {
00087                         update = UP_OBJ_FLAGFACE;
00088                     }
00089 
00090                     SET_FLAG(op, FLAG_BLOCKSVIEW);
00091                 }
00092             }
00093             else
00094             {
00095                 if (QUERY_FLAG(op, FLAG_NO_PASS))
00096                 {
00097                     update = UP_OBJ_FLAGFACE;
00098                 }
00099 
00100                 CLEAR_FLAG(op, FLAG_NO_PASS);
00101 
00102                 if (QUERY_FLAG(op, FLAG_BLOCKSVIEW))
00103                 {
00104                     update = UP_OBJ_FLAGFACE;
00105                 }
00106 
00107                 CLEAR_FLAG(op, FLAG_BLOCKSVIEW);
00108             }
00109         }
00110 
00111         op->state = (uint8) op->stats.wc;
00112         SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction + op->state);
00113         update_object(op, update);
00114 
00115         return;
00116     }
00117 
00118     /* First, lets see if we are already at the top */
00119     if ((unsigned char) op->stats.wc == ((NUM_ANIMATIONS(op) / NUM_FACINGS(op)) - 1))
00120     {
00121         /* Check to make sure that only non pickable and non rollable
00122          * objects are above the gate. If so, we finish closing the gate,
00123          * otherwise, we fall through to the code below which should lower
00124          * the gate slightly. */
00125         for (tmp = GET_BOTTOM_MAP_OB(op); tmp; tmp = tmp->above)
00126         {
00127             if (QUERY_FLAG(tmp, FLAG_CAN_ROLL) || IS_LIVE(tmp))
00128             {
00129                 break;
00130             }
00131         }
00132 
00133         if (tmp == NULL)
00134         {
00135             if (op->arch->clone.speed)
00136             {
00137                 op->value = 1;
00138             }
00139             else
00140             {
00141                 op->speed = 0;
00142 
00143                 /* Reached top, let's stop */
00144                 update_ob_speed(op);
00145             }
00146 
00147             return;
00148         }
00149     }
00150 
00151     /* The gate is going temporarily down */
00152     if (op->stats.food)
00153     {
00154         /* Gone all the way down? */
00155         if (--op->stats.wc <= 0)
00156         {
00157             /* Then let's try again */
00158             op->stats.food = 0;
00159             op->stats.wc = 0;
00160         }
00161     }
00162     /* The gate is still going up */
00163     else
00164     {
00165         op->stats.wc++;
00166 
00167         if ((int) op->stats.wc >= ((NUM_ANIMATIONS(op) / NUM_FACINGS(op))))
00168         {
00169             op->stats.wc = (signed char) (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) - 1;
00170         }
00171 
00172         /* If there is something on top of the gate, we try to roll it off.
00173          * If a player/monster, we don't roll, we just hit them with damage */
00174         if ((int) op->stats.wc >= (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) / 2)
00175         {
00176             object *next;
00177 
00178             /* Halfway or further, check blocks */
00179             for (tmp = GET_BOTTOM_MAP_OB(op); tmp; tmp = next)
00180             {
00181                 next = tmp->above;
00182 
00183                 /* If the object is alive or the object rolls, move the object
00184                  * off the gate. */
00185                 if (QUERY_FLAG(tmp, FLAG_CAN_ROLL) || IS_LIVE(tmp))
00186                 {
00187                     int i;
00188 
00189                     if (IS_LIVE(tmp))
00190                     {
00191                         hit_player(tmp, 4, op, AT_PHYSICAL);
00192                         new_draw_info_format(0, COLOR_WHITE, tmp, "You are crushed by the %s!", op->name);
00193                     }
00194 
00195                     i = find_free_spot(tmp->arch, tmp, op->map, op->x, op->y, 1, 9);
00196 
00197                     /* If there is a free spot, move the object someplace. */
00198                     if (i != -1)
00199                     {
00200                         remove_ob(tmp);
00201                         check_walk_off(tmp, NULL, MOVE_APPLY_VANISHED);
00202                         tmp->x += freearr_x[i];
00203                         tmp->y += freearr_y[i];
00204                         insert_ob_in_map(tmp, op->map, op, 0);
00205                     }
00206                 }
00207             }
00208 
00209             /* If there is still something, start putting the gate down */
00210             if (tmp)
00211             {
00212                 op->stats.food = 1;
00213             }
00214             else
00215             {
00216                 /* If != 0, we have a reversed timed gate, which starts open */
00217                 if (op->last_heal)
00218                 {
00219                     if (QUERY_FLAG(op, FLAG_NO_PASS))
00220                     {
00221                         update = UP_OBJ_FLAGFACE;
00222                     }
00223 
00224                     CLEAR_FLAG(op, FLAG_NO_PASS);
00225 
00226                     if (QUERY_FLAG(op, FLAG_BLOCKSVIEW))
00227                     {
00228                         update = UP_OBJ_FLAGFACE;
00229                     }
00230 
00231                     CLEAR_FLAG(op, FLAG_BLOCKSVIEW);
00232                 }
00233                 else
00234                 {
00235                     if (!QUERY_FLAG(op, FLAG_NO_PASS))
00236                     {
00237                         update = UP_OBJ_FLAGFACE;
00238                     }
00239 
00240                     /* The coast is clear, block the way */
00241                     SET_FLAG(op, FLAG_NO_PASS);
00242 
00243                     if (!op->arch->clone.stats.ac)
00244                     {
00245                         if (!QUERY_FLAG(op, FLAG_BLOCKSVIEW))
00246                         {
00247                             update = UP_OBJ_FLAGFACE;
00248                         }
00249 
00250                         SET_FLAG(op, FLAG_BLOCKSVIEW);
00251                     }
00252                 }
00253             }
00254         }
00255 
00256         op->state = (uint8) op->stats.wc;
00257         SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction + op->state);
00258 
00259         /* Takes care about map tile and player los update! */
00260         update_object(op, update);
00261     }
00262 }
00263 
00267 void move_timed_gate(object *op)
00268 {
00269     int v = op->value;
00270 
00271     if (op->stats.sp)
00272     {
00273         move_gate(op);
00274 
00275         /* Change direction? */
00276         if (op->value != v)
00277         {
00278             op->stats.sp = 0;
00279         }
00280 
00281         return;
00282     }
00283 
00284     /* Keep gate down */
00285     if (--op->stats.hp <= 0)
00286     {
00287         move_gate(op);
00288 
00289         /* Ready? */
00290         if (op->value != v)
00291         {
00292             op->speed = 0;
00293             update_ob_speed(op);
00294         }
00295     }
00296 }