Crossfire Server, Trunk  R20805
transport.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
21 #include "global.h"
22 
23 #include <stdlib.h>
24 
25 #include "ob_methods.h"
26 #include "ob_types.h"
27 #include "shop.h"
28 #include "sounds.h"
29 #include "sproto.h"
30 
31 static method_ret transport_type_apply(ob_methods *context, object *op, object *applier, int aflags);
32 static method_ret transport_type_process(ob_methods *context, object *op);
33 
37 void init_type_transport(void) {
40 }
41 
54 static method_ret transport_type_apply(ob_methods *context, object *op, object *applier, int aflags) {
55  object *old_transport = applier->contr->transport;
56  object *inv;
57  char name_op[MAX_BUF], name_old[MAX_BUF];
58 
59  /* Only players can use transports right now */
60  if (applier->type != PLAYER)
61  return 0;
62 
63  query_name(op, name_op, MAX_BUF);
64 
65  /* If player is currently on a transport but not this transport, they need
66  * to exit first. Perhaps transport to transport transfers should be
67  * allowed.
68  */
69  if (old_transport && old_transport != op) {
70  query_name(old_transport, name_old, MAX_BUF);
72  "You must exit %s before you can board %s.",
73  name_old, name_op);
74  return 1;
75  }
76 
77  /* player is currently on a transport. This must mean he
78  * wants to exit.
79  */
80  if (old_transport) {
81  /* Should we print a message if the player only wants to
82  * apply?
83  */
84  if (aflags&AP_APPLY)
85  return 1;
86 
87  query_name(old_transport, name_old, MAX_BUF);
89  "You disembark from %s.",
90  name_old);
91  object_remove(applier);
92  if (applier->contr == old_transport->contr)
93  old_transport->contr = NULL;
94 
95  applier->contr->transport = NULL;
96  object_insert_in_map_at(applier, old_transport->map, applier, 0, old_transport->x, old_transport->y);
97  object_sum_weight(old_transport);
98 
99  /* Possible for more than one player to be using a transport.
100  * if that is the case, we don't want to reset the face, as the
101  * transport is still occupied.
102  */
103  inv = object_find_by_type(old_transport, PLAYER);
104  if (!inv) {
105  old_transport->face = old_transport->arch->clone.face;
106  old_transport->animation_id = old_transport->arch->clone.animation_id;
107  } else {
108  old_transport->contr = inv->contr;
110  "%s has disembarked. You are now the captain of %s",
111  applier->name, name_old);
112  }
113  return 1;
114  } else {
115  /* player is trying to board a transport */
116  int pc = 0, p_limit;
117  const char *kv;
118  int16_t ox, oy;
119 
120  if (aflags&AP_UNAPPLY)
121  return 1;
122 
123  /* Can this transport hold the weight of this player? */
124  if (!transport_can_hold(op, applier, 1)) {
126  "The %s is unable to hold your weight!",
127  name_op);
128  return 1;
129  }
130 
131  /* If the player is holding the transport, drop it. */
132  if (op->env == applier) {
133  old_transport = op;
134  /* Don't drop transports in shops. */
135  if (!shop_contains(applier)) {
136  op = drop_object(applier, op, 1);
137  } else {
139  "You cannot drop the %s in a shop to use it.",
140  name_old);
141  return 1;
142  }
143  /* Did it fail to drop? */
144  if (!op) {
146  "You need to drop the %s to use it.",
147  name_old);
148  return 1;
149  }
150  }
151 
152  /* Does this transport have space for more players? */
153  FOR_INV_PREPARE(op, inv)
154  if (inv->type == PLAYER)
155  pc++;
156  FOR_INV_FINISH();
157 
158  kv = object_get_value(op, "passenger_limit");
159  if (!kv)
160  p_limit = 1;
161  else
162  p_limit = atoi(kv);
163  if (pc >= p_limit) {
165  "The %s does not have space for any more people",
166  name_op);
167  return 1;
168  }
169 
170  /* Everything checks out OK - player can get on the transport */
171  applier->contr->transport = op;
172 
173  if (op->contr) {
175  "The %s's captain is currently %s",
176  name_op, op->contr->ob->name);
177  } else {
179  "You're the %s's captain",
180  name_op);
181  op->contr = applier->contr;
182  }
183 
184  object_remove(applier);
185  /* object_insert_in_ob clear applier->x and applier->y, so store them away */
186  ox = applier->x;
187  oy = applier->y;
188  object_insert_in_ob(applier, op);
189  object_sum_weight(op);
190  applier->map = op->map;
191  if (ox != op->x || oy != op->y) {
192  esrv_map_scroll(&applier->contr->socket, (ox-op->x), (oy-op->y));
193  }
194  applier->contr->socket.update_look = 1;
195  applier->contr->socket.look_position = 0;
196  applier->x = op->x;
197  applier->y = op->y;
198 
199  /* Might need to update face, animation info */
200  if (!pc) {
201  const char *str;
202 
203  str = object_get_value(op, "face_full");
204  if (str)
205  op->face = &new_faces[find_face(str, op->face->number)];
206  str = object_get_value(op, "anim_full");
207  if (str)
208  op->animation_id = find_animation(str);
209  }
210 
211  /* Does speed of this object change based on weight? */
212  kv = object_get_value(op, "weight_speed_ratio");
213  if (kv) {
214  int wsr = atoi(kv);
215  float base_speed;
216 
217  kv = object_get_value(op, "base_speed");
218  if (kv)
219  base_speed = atof(kv);
220  else
221  base_speed = op->arch->clone.speed;
222 
223  op->speed = base_speed-(base_speed*op->carrying*wsr)/(op->weight_limit*100);
224 
225  /* Put some limits on min/max speeds */
226  if (op->speed < 0.10)
227  op->speed = 0.10;
228  if (op->speed > 1.0)
229  op->speed = 1.0;
230  }
231  } /* else if player is boarding the transport */
232  return 1;
233 }
234 
242 static method_ret transport_type_process(ob_methods *context, object *op) {
243  /* Transports are directed by players - thus, there
244  * speed is reduced when the player moves them about.
245  * So give them back there speed here, since process_objects()
246  * has decremented it.
247  */
248  if (op->speed_left < 0.0) {
249  op->speed_left += 1.0;
250  return 1;
251  }
252  return 0;
253 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:315
#define AP_UNAPPLY
Definition: define.h:611
int32_t weight_limit
Definition: object.h:366
bool shop_contains(object *ob)
Definition: shop.c:1261
New_Face * new_faces
Definition: image.c:33
uint16_t animation_id
Definition: object.h:416
object * object_find_by_type(const object *who, int type)
Definition: object.c:3906
uint16_t look_position
Definition: newserver.h:126
signed long object_sum_weight(object *op)
Definition: object.c:311
const char * object_get_value(const object *op, const char *const key)
Definition: object.c:4249
object clone
Definition: object.h:470
socket_struct socket
Definition: player.h:94
static method_ret transport_type_apply(ob_methods *context, object *op, object *applier, int aflags)
Definition: transport.c:54
#define AP_APPLY
Definition: define.h:610
#define MSG_TYPE_APPLY
Definition: newclient.h:384
uint16_t number
Definition: face.h:15
char method_ret
Definition: ob_methods.h:14
uint32_t update_look
Definition: newserver.h:115
int16_t y
Definition: object.h:326
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1921
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2690
float speed_left
Definition: object.h:329
signed short int16_t
Definition: win32.h:160
struct mapdef * map
Definition: object.h:297
#define MSG_TYPE_APPLY_ERROR
Definition: newclient.h:596
object * transport
Definition: player.h:195
#define FOR_INV_FINISH()
Definition: define.h:712
int32_t carrying
Definition: object.h:367
const char * name
Definition: object.h:311
struct obj * env
Definition: object.h:293
int find_animation(const char *name)
Definition: anim.c:170
void register_apply(int ob_type, apply_func method)
Definition: ob_types.c:62
struct pl * contr
Definition: object.h:276
float speed
Definition: object.h:328
#define MSG_TYPE_APPLY_UNAPPLY
Definition: newclient.h:597
#define MAX_BUF
Definition: define.h:35
int16_t x
Definition: object.h:326
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.c:1510
object * ob
Definition: player.h:158
Definition: object.h:107
struct archt * arch
Definition: object.h:412
uint8_t type
Definition: object.h:338
int transport_can_hold(const object *transport, const object *op, int nrof)
Definition: apply.c:54
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:598
void register_process(int ob_type, process_func method)
Definition: ob_types.c:71
#define NDI_UNIQUE
Definition: newclient.h:245
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:626
const New_Face * face
Definition: object.h:332
void init_type_transport(void)
Definition: transport.c:37
object * drop_object(object *op, object *tmp, uint32_t nrof)
Definition: c_object.c:814
unsigned find_face(const char *name, unsigned error)
Definition: image.c:303
static method_ret transport_type_process(ob_methods *context, object *op)
Definition: transport.c:242
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:705
void object_remove(object *op)
Definition: object.c:1654