Crossfire Server, Branch 1.12  R12190
transport.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 
00029 #include <global.h>
00030 #include <ob_methods.h>
00031 #include <ob_types.h>
00032 #include <sounds.h>
00033 #include <sproto.h>
00034 
00035 static method_ret transport_type_apply(ob_methods *context, object *op, object *applier, int aflags);
00036 static method_ret transport_type_process(ob_methods *context, object *op);
00037 
00041 void init_type_transport(void) {
00042     register_apply(TRANSPORT, transport_type_apply);
00043     register_process(TRANSPORT, transport_type_process);
00044 }
00045 
00058 static method_ret transport_type_apply(ob_methods *context, object *op, object *applier, int aflags) {
00059     object *old_transport = applier->contr->transport;
00060     object *inv;
00061     char name_op[MAX_BUF], name_old[MAX_BUF];
00062 
00063     /* Only players can use transports right now */
00064     if (applier->type != PLAYER)
00065         return 0;
00066 
00067     query_name(op, name_op, MAX_BUF);
00068 
00069     /* If player is currently on a transport but not this transport, they need
00070      * to exit first.  Perhaps transport to transport transfers should be
00071      * allowed.
00072      */
00073     if (old_transport && old_transport != op) {
00074         query_name(old_transport, name_old, MAX_BUF);
00075         draw_ext_info_format(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00076             "You must exit %s before you can board %s.",
00077             "You must exit %s before you can board %s.",
00078             name_old, name_op);
00079         return 1;
00080     }
00081 
00082     /* player is currently on a transport.  This must mean he
00083      * wants to exit.
00084      */
00085     if (old_transport) {
00086         /* Should we print a message if the player only wants to
00087          * apply?
00088          */
00089         if (aflags&AP_APPLY)
00090             return 1;
00091 
00092         query_name(old_transport, name_old, MAX_BUF);
00093         draw_ext_info_format(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_UNAPPLY,
00094             "You disembark from %s.", "You disembark from %s.",
00095             name_old);
00096         remove_ob(applier);
00097         applier->map = old_transport->map;
00098         applier->x = old_transport->x;
00099         applier->y = old_transport->y;
00100         if (applier->contr == old_transport->contr)
00101             old_transport->contr = NULL;
00102 
00103         applier->contr->transport = NULL;
00104         insert_ob_in_map(applier, applier->map, applier, 0);
00105         sum_weight(old_transport);
00106 
00107         /* Possible for more than one player to be using a transport.
00108          * if that is the case, we don't want to reset the face, as the
00109          * transport is still occupied.
00110          */
00111         for (inv = old_transport->inv; inv; inv = inv->below)
00112             if (inv->type == PLAYER)
00113                 break;
00114         if (!inv) {
00115             old_transport->face = old_transport->arch->clone.face;
00116             old_transport->animation_id = old_transport->arch->clone.animation_id;
00117         } else {
00118             old_transport->contr = inv->contr;
00119             draw_ext_info_format(NDI_UNIQUE, 0, inv, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00120                 "%s has disembarked.  You are now the captain of %s",
00121                 "%s has disembarked.  You are now the captain of %s",
00122                 applier->name, name_old);
00123         }
00124         return 1;
00125     } else {
00126         /* player is trying to board a transport */
00127         int pc = 0, p_limit;
00128         const char *kv;
00129         sint16 ox, oy;
00130 
00131         if (aflags&AP_UNAPPLY)
00132             return 1;
00133 
00134         /* Can this transport hold the weight of this player? */
00135         if (!transport_can_hold(op, applier, 1)) {
00136             draw_ext_info_format(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00137                 "The %s is unable to hold your weight!",
00138                 "The %s is unable to hold your weight!",
00139                 name_op);
00140             return 1;
00141         }
00142 
00143         /* If the player is holding the transport, drop it. */
00144         if (op->env == applier) {
00145             old_transport = op;
00146             /* Don't drop transports in shops. */
00147             if (!is_in_shop(applier)) {
00148                 op = drop_object(applier, op, 1);
00149             } else {
00150                 draw_ext_info_format(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00151                     "You cannot drop the %s in a shop to use it.",
00152                     "You cannot drop the %s in a shop to use it.",
00153                     name_old);
00154                 return 1;
00155             }
00156             /* Did it fail to drop? */
00157             if (!op) {
00158                 draw_ext_info_format(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00159                     "You need to drop the %s to use it.",
00160                     "You need to drop the %s to use it.",
00161                     name_old);
00162                 return 1;
00163             }
00164         }
00165 
00166         /* Does this transport have space for more players? */
00167         for (inv = op->inv; inv; inv = inv->below)
00168             if (inv->type == PLAYER)
00169                 pc++;
00170 
00171         kv = get_ob_key_value(op, "passenger_limit");
00172         if (!kv)
00173             p_limit = 1;
00174         else
00175             p_limit = atoi(kv);
00176         if (pc >= p_limit) {
00177             draw_ext_info_format(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00178                 "The %s does not have space for any more people",
00179                 "The %s does not have space for any more people",
00180                 name_op);
00181             return 1;
00182         }
00183 
00184         /* Everything checks out OK - player can get on the transport */
00185         applier->contr->transport = op;
00186 
00187         if (op->contr) {
00188             draw_ext_info_format(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00189                 "The %s's captain is currently %s",
00190                 "The %s's captain is currently %s",
00191                 name_op, op->contr->ob->name);
00192         } else {
00193             draw_ext_info_format(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00194                 "You're the %s's captain",
00195                 "You're the %s's captain",
00196                 name_op);
00197             op->contr = applier->contr;
00198         }
00199 
00200         remove_ob(applier);
00201         /* insert_ob_in_ob clear applier->x and applier->y, so store them away */
00202         ox = applier->x;
00203         oy = applier->y;
00204         insert_ob_in_ob(applier, op);
00205         sum_weight(op);
00206         applier->map = op->map;
00207         if (ox != op->x || oy != op->y) {
00208             esrv_map_scroll(&applier->contr->socket, (ox-op->x), (oy-op->y));
00209         }
00210         applier->contr->socket.update_look = 1;
00211         applier->contr->socket.look_position = 0;
00212         applier->x = op->x;
00213         applier->y = op->y;
00214 
00215         /* Might need to update face, animation info */
00216         if (!pc) {
00217             const char *str;
00218 
00219             str = get_ob_key_value(op, "face_full");
00220             if (str)
00221                 op->face = &new_faces[find_face(str, op->face->number)];
00222             str = get_ob_key_value(op, "anim_full");
00223             if (str)
00224                 op->animation_id = find_animation(str);
00225         }
00226 
00227         /* Does speed of this object change based on weight? */
00228         kv = get_ob_key_value(op, "weight_speed_ratio");
00229         if (kv) {
00230             int wsr = atoi(kv);
00231             float base_speed;
00232 
00233             kv = get_ob_key_value(op, "base_speed");
00234             if (kv)
00235                 base_speed = atof(kv);
00236             else
00237                 base_speed = op->arch->clone.speed;
00238 
00239             op->speed = base_speed-(base_speed*op->carrying*wsr)/(op->weight_limit*100);
00240 
00241             /* Put some limits on min/max speeds */
00242             if (op->speed < 0.10)
00243                 op->speed = 0.10;
00244             if (op->speed > 1.0)
00245                 op->speed = 1.0;
00246         }
00247     } /* else if player is boarding the transport */
00248     return 1;
00249 }
00250 
00258 static method_ret transport_type_process(ob_methods *context, object *op) {
00259     /* Transports are directed by players - thus, there
00260      * speed is reduced when the player moves them about.
00261      * So give them back there speed here, since process_objects()
00262      * has decremented it.
00263      */
00264     if (op->speed_left < 0.0) {
00265         op->speed_left += 1.0;
00266         return 1;
00267     }
00268     return 0;
00269 }