Crossfire Server, Trunk  R21569
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 
52 static method_ret transport_type_apply(ob_methods *context, object *op, object *applier, int aflags) {
53  object *old_transport = applier->contr->transport;
54  object *inv;
55  char name_op[MAX_BUF], name_old[MAX_BUF];
56 
57  /* Only players can use transports right now */
58  if (applier->type != PLAYER)
59  return METHOD_UNHANDLED;
60 
61  query_name(op, name_op, MAX_BUF);
62 
63  /* If player is currently on a transport but not this transport, they need
64  * to exit first. Perhaps transport to transport transfers should be
65  * allowed.
66  */
67  if (old_transport && old_transport != op) {
68  query_name(old_transport, name_old, MAX_BUF);
70  "You must exit %s before you can board %s.",
71  name_old, name_op);
72  return METHOD_SILENT_ERROR;
73  }
74 
75  /* player is currently on a transport. This must mean he
76  * wants to exit.
77  */
78  if (old_transport) {
79  /* Should we print a message if the player only wants to
80  * apply?
81  */
82  if (aflags&AP_APPLY)
83  return 1;
84 
85  query_name(old_transport, name_old, MAX_BUF);
87  "You disembark from %s.",
88  name_old);
89  object_remove(applier);
90  if (applier->contr == old_transport->contr)
91  old_transport->contr = NULL;
92 
93  applier->contr->transport = NULL;
94  object_insert_in_map_at(applier, old_transport->map, applier, 0, old_transport->x, old_transport->y);
95  if ( applier->map ) applier->map->players--; // Incremented player count incorrectly; adjust to correct
96  object_sum_weight(old_transport);
97 
98  /* Possible for more than one player to be using a transport.
99  * if that is the case, we don't want to reset the face, as the
100  * transport is still occupied.
101  */
102  inv = object_find_by_type(old_transport, PLAYER);
103  if (!inv) {
104  old_transport->face = old_transport->arch->clone.face;
105  old_transport->animation = old_transport->arch->clone.animation;
106  } else {
107  old_transport->contr = inv->contr;
109  "%s has disembarked. You are now the captain of %s",
110  applier->name, name_old);
111  }
112  return METHOD_OK;
113  } else {
114  /* player is trying to board a transport */
115  int pc = 0, p_limit;
116  const char *kv;
117  int16_t ox, oy;
118 
119  if (aflags&AP_UNAPPLY)
120  return 1;
121 
122  /* Can this transport hold the weight of this player? */
123  if (!transport_can_hold(op, applier, 1)) {
125  "The %s is unable to hold your weight!",
126  name_op);
127  return METHOD_SILENT_ERROR;
128  }
129 
130  /* If the player is holding the transport, drop it. */
131  if (op->env == applier) {
132  old_transport = op;
133  /* Don't drop transports in shops. */
134  if (!shop_contains(applier)) {
135  op = drop_object(applier, op, 1);
136  } else {
138  "You cannot drop the %s in a shop to use it.",
139  name_old);
140  return METHOD_SILENT_ERROR;
141  }
142  /* Did it fail to drop? */
143  if (!op) {
145  "You need to drop the %s to use it.",
146  name_old);
147  return METHOD_SILENT_ERROR;
148  }
149  }
150 
151  /* Does this transport have space for more players? */
152  FOR_INV_PREPARE(op, inv)
153  if (inv->type == PLAYER)
154  pc++;
155  FOR_INV_FINISH();
156 
157  kv = object_get_value(op, "passenger_limit");
158  if (!kv)
159  p_limit = 1;
160  else
161  p_limit = atoi(kv);
162  if (pc >= p_limit) {
164  "The %s does not have space for any more people",
165  name_op);
166  return METHOD_SILENT_ERROR;
167  }
168 
169  /* Everything checks out OK - player can get on the transport */
170  applier->contr->transport = op;
171 
172  if (op->contr) {
174  "The %s's captain is currently %s",
175  name_op, op->contr->ob->name);
176  } else {
178  "You're the %s's captain",
179  name_op);
180  op->contr = applier->contr;
181  }
182 
183  if ( applier->map ) applier->map->players++; // About to subtract the player incorrectly
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 = find_face(str, op->face);
206  str = object_get_value(op, "anim_full");
207  if (str)
208  op->animation = 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 METHOD_OK;
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:316
#define AP_UNAPPLY
Definition: define.h:612
int32_t weight_limit
Definition: object.h:368
bool shop_contains(object *ob)
Definition: shop.c:1274
object * object_find_by_type(const object *who, int type)
Definition: object.c:3769
uint16_t look_position
Definition: newserver.h:114
int16_t players
Definition: map.h:344
signed long object_sum_weight(object *op)
Definition: object.c:338
const char * object_get_value(const object *op, const char *const key)
Definition: object.c:4135
object clone
Definition: object.h:473
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:52
#define AP_APPLY
Definition: define.h:611
#define MSG_TYPE_APPLY
Definition: newclient.h:384
char method_ret
Definition: ob_methods.h:14
uint32_t update_look
Definition: newserver.h:104
int16_t y
Definition: object.h:327
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1848
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2601
float speed_left
Definition: object.h:330
signed short int16_t
Definition: win32.h:160
#define METHOD_OK
Definition: ob_methods.h:15
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:714
int32_t carrying
Definition: object.h:369
const char * name
Definition: object.h:311
struct obj * env
Definition: object.h:293
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:329
#define MSG_TYPE_APPLY_UNAPPLY
Definition: newclient.h:597
#define MAX_BUF
Definition: define.h:35
#define METHOD_UNHANDLED
Definition: ob_methods.h:16
const Animations * animation
Definition: object.h:419
int16_t x
Definition: object.h:327
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.c:1525
object * ob
Definition: player.h:158
Definition: object.h:107
const Animations * find_animation(const char *name)
Definition: anim.c:173
struct archt * arch
Definition: object.h:415
uint8_t type
Definition: object.h:340
#define METHOD_SILENT_ERROR
Definition: ob_methods.h:18
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:580
const Face * find_face(const char *name, const Face *error)
Definition: image.c:316
const Face * face
Definition: object.h:333
void init_type_transport(void)
Definition: transport.c:37
object * drop_object(object *op, object *tmp, uint32_t nrof)
Definition: c_object.c:828
static method_ret transport_type_process(ob_methods *context, object *op)
Definition: transport.c:242
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:707
void object_remove(object *op)
Definition: object.c:1587