Atrinik Server 2.5
types/door.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 
00030 #include <global.h>
00031 
00042 int open_door(object *op, mapstruct *m, int x, int y, int mode)
00043 {
00044     object *tmp, *key = NULL;
00045 
00046     /* Make sure a monster/NPC can actually open doors */
00047     if (op->type == MONSTER && !(op->behavior & BEHAVIOR_OPEN_DOORS))
00048     {
00049         return 0;
00050     }
00051 
00052     /* Look for objects on layer 5. */
00053     for (tmp = GET_MAP_OB_LAYER(m, x, y, LAYER_WALL - 1); tmp && tmp->layer == LAYER_WALL; tmp = tmp->above)
00054     {
00055         if (tmp->type == DOOR)
00056         {
00057             /* Door needs a key? */
00058             if (tmp->slaying)
00059             {
00060                 if (!(key = find_key(op, tmp)))
00061                 {
00062                     if (op->type == PLAYER && mode)
00063                     {
00064                         new_draw_info(0, COLOR_NAVY, op, tmp->msg);
00065                     }
00066 
00067                     return 0;
00068                 }
00069             }
00070 
00071             /* If we are here, the door can be opened */
00072             if (mode)
00073             {
00074                 open_locked_door(tmp, op);
00075 
00076                 if (op->type == PLAYER && key)
00077                 {
00078                     if (key->type == KEY)
00079                     {
00080                         new_draw_info_format(0, COLOR_WHITE, op, "You open the door with the %s.", query_short_name(key, NULL));
00081                     }
00082                     else if (key->type == FORCE)
00083                     {
00084                         new_draw_info(0, COLOR_WHITE, op, "The door is opened for you.");
00085                     }
00086                 }
00087             }
00088 
00089             return 1;
00090         }
00091     }
00092 
00093     LOG(llevSystem, "open_door() - Door on wrong layer. Map: %s (%d, %d) (op: %s)\n", m->path, x, y, query_name(op, NULL));
00094     return 0;
00095 }
00096 
00102 object *find_key(object *op, object *door)
00103 {
00104     object *tmp, *key;
00105 
00106     /* First, let's try to find a key in the top level inventory. */
00107     for (tmp = op->inv; tmp; tmp = tmp->below)
00108     {
00109         if ((tmp->type == KEY || tmp->type == FORCE) && tmp->slaying == door->slaying)
00110         {
00111             return tmp;
00112         }
00113 
00114         /* Go through containers. */
00115         if (tmp->type == CONTAINER && tmp->inv)
00116         {
00117             key = find_key(tmp, door);
00118 
00119             if (key)
00120             {
00121                 return key;
00122             }
00123         }
00124     }
00125 
00126     return NULL;
00127 }
00128 
00135 void open_locked_door(object *op, object *opener)
00136 {
00137     object *tmp, *tmp2;
00138 
00139     /* If set, just exchange and delete old door */
00140     if (op->other_arch)
00141     {
00142         tmp = arch_to_object(op->other_arch);
00143         /* 0 = closed, 1 = opened */
00144         tmp->state = 0;
00145         tmp->x = op->x;
00146         tmp->y = op->y;
00147         tmp->map = op->map;
00148         tmp->level = op->level;
00149         tmp->direction = op->direction;
00150 
00151         if (QUERY_FLAG(tmp, FLAG_IS_TURNABLE) || QUERY_FLAG(tmp, FLAG_ANIMATE))
00152         {
00153             SET_ANIMATION(tmp, (NUM_ANIMATIONS(tmp) / NUM_FACINGS(tmp)) * tmp->direction + tmp->state);
00154         }
00155 
00156         insert_ob_in_map(tmp, op->map, op, 0);
00157 
00158         if (op->sub_type == ST1_DOOR_NORMAL)
00159         {
00160             play_sound_map(op->map, CMD_SOUND_EFFECT, "door.ogg", op->x, op->y, 0, 0);
00161         }
00162 
00163         remove_ob(op);
00164         check_walk_off(op, NULL, MOVE_APPLY_VANISHED);
00165     }
00166     /* If set, we have opened a closed door - now handle autoclose */
00167     else if (!op->last_eat)
00168     {
00169         remove_ob(op);
00170         check_walk_off(op, NULL, MOVE_APPLY_VANISHED);
00171 
00172         for (tmp2 = op->inv; tmp2; tmp2 = tmp2->below)
00173         {
00174             if (tmp2 && tmp2->type == RUNE && tmp2->level)
00175             {
00176                 spring_trap(tmp2, opener);
00177             }
00178         }
00179 
00180         /* Mark this door as "it's open" */
00181         op->last_eat = 1;
00182         /* Put it on active list, so it will close automatically */
00183         op->speed = 0.1f;
00184         update_ob_speed(op);
00185         op->speed_left= -0.2f;
00186         /* Change to "open door" faces */
00187         op->state = 1;
00188         /* Init "open" counter */
00189         op->last_sp = op->stats.sp;
00190 
00191         /* Save and clear blocksview and door_closed */
00192         op->stats.grace = QUERY_FLAG(op, FLAG_BLOCKSVIEW) ? 1 : 0;
00193         op->last_grace = QUERY_FLAG(op, FLAG_DOOR_CLOSED) ? 1 : 0;
00194 
00195         CLEAR_FLAG(op, FLAG_BLOCKSVIEW);
00196         CLEAR_FLAG(op, FLAG_DOOR_CLOSED);
00197 
00198         if (QUERY_FLAG(op, FLAG_IS_TURNABLE) || QUERY_FLAG(op, FLAG_ANIMATE))
00199         {
00200             SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction + op->state);
00201         }
00202 
00203         if (op->sub_type == ST1_DOOR_NORMAL)
00204         {
00205             play_sound_map(op->map, CMD_SOUND_EFFECT, "door.ogg", op->x, op->y, 0, 0);
00206         }
00207 
00208         insert_ob_in_map(op, op->map, op, 0);
00209     }
00210 
00211     /* Door has FLAG_CURSED set? */
00212     if (QUERY_FLAG(op, FLAG_CURSED))
00213     {
00214         int i;
00215 
00216         /* Let's search for a locked door on nearby tiles */
00217         for (i = 1; i < 9; i += 2)
00218         {
00219             tmp = present(DOOR, op->map, op->x + freearr_x[i], op->y + freearr_y[i]);
00220 
00221             /* Found it, slaying matches, it has FLAG_CURSED and not opened? */
00222             if (tmp && tmp->slaying == op->slaying && QUERY_FLAG(tmp, FLAG_CURSED) && tmp->state == 0)
00223             {
00224                 /* Open this door then! */
00225                 open_locked_door(tmp, opener);
00226             }
00227         }
00228     }
00229 }
00230 
00234 void close_locked_door(object *op)
00235 {
00236     /* This is a bug - active speed but not marked as active */
00237     if (!op->last_eat)
00238     {
00239         LOG(llevBug, "Door has speed but is not marked as active. (%s - map: %s (%d, %d))\n", query_name(op, NULL), op->map ? op->map->name : "(no map name!)", op->x, op->y);
00240         op->last_eat = 0;
00241         return;
00242     }
00243 
00244     if (!op->map)
00245     {
00246         LOG(llevBug, "Door with speed but no map (%s - (%d, %d))\n", query_name(op, NULL), op->x, op->y);
00247         remove_ob(op);
00248         check_walk_off(op, NULL, MOVE_APPLY_VANISHED);
00249         return;
00250     }
00251 
00252     /* Now check the door counter - if not <= 0 we're still open */
00253     if (op->last_sp-- > 0)
00254     {
00255         return;
00256     }
00257 
00258     /* Now we try to close the door. If the tile of the door is not blocked by
00259      * a no_pass object or a player or a monster, then we close the door.
00260      * If it is blocked - then restart a new "is open" phase. */
00261     if (blocked(NULL, op->map, op->x, op->y, TERRAIN_ALL) & (P_NO_PASS | P_IS_ALIVE | P_IS_PLAYER))
00262     {
00263         /* Let it open one more round. Re-init "open" counter. */
00264         op->last_sp = op->stats.sp;
00265     }
00266     else
00267     {
00268         remove_ob(op);
00269         check_walk_off(op, NULL, MOVE_APPLY_VANISHED);
00270 
00271         /* Mark this door as "it's closed" */
00272         op->last_eat = 0;
00273 
00274         /* Remove from active list */
00275         op->speed = 0.0f;
00276         op->speed_left = 0.0f;
00277         update_ob_speed(op);
00278 
00279         /* Change to "close door" faces */
00280         op->state = 0;
00281 
00282         if (op->stats.grace)
00283         {
00284             SET_FLAG(op, FLAG_BLOCKSVIEW);
00285         }
00286         else
00287         {
00288             CLEAR_FLAG(op, FLAG_BLOCKSVIEW);
00289         }
00290 
00291         op->stats.grace = 0;
00292 
00293         if (op->last_grace)
00294         {
00295             SET_FLAG(op, FLAG_DOOR_CLOSED);
00296         }
00297         else
00298         {
00299             CLEAR_FLAG(op, FLAG_DOOR_CLOSED);
00300         }
00301 
00302         op->last_grace = 0;
00303 
00304         if (QUERY_FLAG(op, FLAG_IS_TURNABLE) || QUERY_FLAG(op, FLAG_ANIMATE))
00305         {
00306             SET_ANIMATION(op, (NUM_ANIMATIONS(op) / NUM_FACINGS(op)) * op->direction + op->state);
00307         }
00308 
00309         if (op->sub_type == ST1_DOOR_NORMAL)
00310         {
00311             play_sound_map(op->map, CMD_SOUND_EFFECT, "door_close.ogg", op->x, op->y, 0, 0);
00312         }
00313 
00314         insert_ob_in_map(op, op->map, op, 0);
00315     }
00316 }