Crossfire Server, Trunk
transport.cpp
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(object *op, object *applier, int aflags);
32 static method_ret transport_type_process(object *op);
33 
37 void init_type_transport(void) {
40 }
41 
51 static method_ret transport_type_apply(object *op, object *applier, int aflags) {
52  object *old_transport = applier->contr->transport;
53  object *inv;
54  char name_op[MAX_BUF], name_old[MAX_BUF];
55 
56  /* Only players can use transports right now */
57  if (applier->type != PLAYER)
58  return METHOD_UNHANDLED;
59 
60  query_name(op, name_op, MAX_BUF);
61 
62  /* If player is currently on a transport but not this transport, they need
63  * to exit first. Perhaps transport to transport transfers should be
64  * allowed.
65  */
66  if (old_transport && old_transport != op) {
67  query_name(old_transport, name_old, MAX_BUF);
69  "You must exit %s before you can board %s.",
70  name_old, name_op);
71  return METHOD_SILENT_ERROR;
72  }
73 
74  /* player is currently on a transport. This must mean he
75  * wants to exit.
76  */
77  if (old_transport) {
78  /* Should we print a message if the player only wants to
79  * apply?
80  */
81  if (aflags&AP_APPLY)
82  return 1;
83 
84  query_name(old_transport, name_old, MAX_BUF);
86  "You disembark from %s.",
87  name_old);
88  object_remove(applier);
89  if (applier->contr == old_transport->contr)
90  old_transport->contr = NULL;
91 
92  applier->contr->transport = NULL;
93  object_insert_in_map_at(applier, old_transport->map, applier, 0, old_transport->x, old_transport->y);
94  if ( applier->map ) applier->map->players--; // Incremented player count incorrectly; adjust to correct
95  object_sum_weight(old_transport);
96 
97  /* Possible for more than one player to be using a transport.
98  * if that is the case, we don't want to reset the face, as the
99  * transport is still occupied.
100  */
101  inv = object_find_by_type(old_transport, PLAYER);
102  if (!inv) {
103  old_transport->face = old_transport->arch->clone.face;
104  old_transport->animation = old_transport->arch->clone.animation;
105  } else {
106  old_transport->contr = inv->contr;
108  "%s has disembarked. You are now the captain of %s",
109  applier->name, name_old);
110  }
111  return METHOD_OK;
112  } else {
113  /* player is trying to board a transport */
114  int pc = 0, p_limit;
115  const char *kv;
116  int16_t ox, oy;
117 
118  if (aflags&AP_UNAPPLY)
119  return 1;
120 
121  /* Can this transport hold the weight of this player? */
122  if (!transport_can_hold(op, applier, 1)) {
124  "The %s is unable to hold your weight!",
125  name_op);
126  return METHOD_SILENT_ERROR;
127  }
128 
129  /* If the player is holding the transport, drop it. */
130  if (op->env == applier) {
131  old_transport = op;
132  /* Don't drop transports in shops. */
133  if (!shop_contains(applier)) {
134  op = drop_object(applier, op, 1);
135  } else {
137  "You cannot drop the %s in a shop to use it.",
138  name_old);
139  return METHOD_SILENT_ERROR;
140  }
141  /* Did it fail to drop? */
142  if (!op) {
144  "You need to drop the %s to use it.",
145  name_old);
146  return METHOD_SILENT_ERROR;
147  }
148  }
149 
150  /* Does this transport have space for more players? */
152  if (inv->type == PLAYER)
153  pc++;
154  FOR_INV_FINISH();
155 
156  kv = object_get_value(op, "passenger_limit");
157  if (!kv)
158  p_limit = 1;
159  else
160  p_limit = atoi(kv);
161  if (pc >= p_limit) {
163  "The %s does not have space for any more people",
164  name_op);
165  return METHOD_SILENT_ERROR;
166  }
167 
168  /* Everything checks out OK - player can get on the transport */
169  applier->contr->transport = op;
170 
171  if (op->contr) {
173  "The %s's captain is currently %s",
174  name_op, op->contr->ob->name);
175  } else {
177  "You're the %s's captain",
178  name_op);
179  op->contr = applier->contr;
180  }
181 
182  if ( applier->map ) applier->map->players++; // About to subtract the player incorrectly
183  object_remove(applier);
184  /* object_insert_in_ob clear applier->x and applier->y, so store them away */
185  ox = applier->x;
186  oy = applier->y;
187  object_insert_in_ob(applier, op);
189  applier->map = op->map;
190  if (ox != op->x || oy != op->y) {
191  esrv_map_scroll(applier->contr->socket, (op->x - ox), (op->y - oy));
192  }
193  applier->contr->socket->update_look = 1;
194  applier->contr->socket->look_position = 0;
195  applier->x = op->x;
196  applier->y = op->y;
197 
198  /* Might need to update face, animation info */
199  if (!pc) {
200  const char *str;
201 
202  str = object_get_value(op, "face_full");
203  if (str)
204  op->face = try_find_face(str, op->face);
205  str = object_get_value(op, "anim_full");
206  if (str)
207  op->animation = find_animation(str);
208  }
209 
210  /* Does speed of this object change based on weight? */
211  kv = object_get_value(op, "weight_speed_ratio");
212  if (kv) {
213  int wsr = atoi(kv);
214  float base_speed;
215 
216  kv = object_get_value(op, "base_speed");
217  if (kv)
218  base_speed = atof(kv);
219  else
220  base_speed = op->arch->clone.speed;
221 
222  op->speed = base_speed-(base_speed*op->carrying*wsr)/(op->weight_limit*100);
223 
224  /* Put some limits on min/max speeds */
225  if (op->speed < 0.10)
226  op->speed = 0.10;
227  if (op->speed > 1.0)
228  op->speed = 1.0;
229  }
230  } /* else if player is boarding the transport */
231  return METHOD_OK;
232 }
233 
241  /* Transports are directed by players - thus, there
242  * speed is reduced when the player moves them about.
243  * So give them back there speed here, since process_objects()
244  * has decremented it.
245  */
246  if (op->speed_left < 0.0) {
247  op->speed_left += 1.0;
248  return 1;
249  }
250  return 0;
251 }
PLAYER
@ PLAYER
Definition: object.h:112
global.h
AP_APPLY
#define AP_APPLY
Definition: define.h:574
esrv_map_scroll
void esrv_map_scroll(socket_struct *ns, int dx, int dy)
Definition: request.cpp:1709
socket_struct::look_position
uint16_t look_position
Definition: newserver.h:114
init_type_transport
void init_type_transport(void)
Definition: transport.cpp:37
object::arch
struct archetype * arch
Definition: object.h:424
mapstruct::players
int16_t players
Definition: map.h:332
register_apply
void register_apply(int ob_type, apply_func method)
Definition: ob_types.cpp:62
METHOD_OK
#define METHOD_OK
Definition: ob_methods.h:15
object::x
int16_t x
Definition: object.h:335
player::transport
object * transport
Definition: player.h:214
object::map
struct mapstruct * map
Definition: object.h:305
commongive.inv
inv
Definition: commongive.py:29
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
TRANSPORT
@ TRANSPORT
Definition: object.h:113
register_process
void register_process(int ob_type, process_func method)
Definition: ob_types.cpp:71
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4346
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2857
socket_struct::update_look
uint32_t update_look
Definition: newserver.h:104
METHOD_UNHANDLED
#define METHOD_UNHANDLED
Definition: ob_methods.h:16
object::y
int16_t y
Definition: object.h:335
object::contr
struct player * contr
Definition: object.h:284
MSG_TYPE_APPLY_SUCCESS
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:606
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:588
archetype::clone
object clone
Definition: object.h:487
transport_can_hold
int transport_can_hold(const object *transport, const object *op, int nrof)
Definition: apply.cpp:54
make_face_from_files.str
str
Definition: make_face_from_files.py:30
object::face
const Face * face
Definition: object.h:341
object::type
uint8_t type
Definition: object.h:348
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
sproto.h
object::animation
const Animations * animation
Definition: object.h:428
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.cpp:2100
MAX_BUF
#define MAX_BUF
Definition: define.h:35
drop_object
object * drop_object(object *op, object *tmp, uint32_t nrof)
Definition: c_object.cpp:1073
method_ret
char method_ret
Definition: ob_methods.h:14
ob_types.h
sounds.h
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:265
transport_type_process
static method_ret transport_type_process(object *op)
Definition: transport.cpp:240
object::name
sstring name
Definition: object.h:319
object_find_by_type
object * object_find_by_type(const object *who, int type)
Definition: object.cpp:3980
give.op
op
Definition: give.py:33
shop.h
transport_type_apply
static method_ret transport_type_apply(object *op, object *applier, int aflags)
Definition: transport.cpp:51
find_animation
Animations * find_animation(const char *name)
Definition: assets.cpp:274
object_remove
void object_remove(object *op)
Definition: object.cpp:1833
object_sum_weight
signed long object_sum_weight(object *op)
Definition: object.cpp:568
try_find_face
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:286
player::socket
socket_struct * socket
Definition: player.h:107
ob_methods.h
AP_UNAPPLY
#define AP_UNAPPLY
Definition: define.h:575
shop_contains
bool shop_contains(object *ob)
Definition: shop.cpp:1296
MSG_TYPE_APPLY
#define MSG_TYPE_APPLY
Definition: newclient.h:411
MSG_TYPE_APPLY_ERROR
#define MSG_TYPE_APPLY_ERROR
Definition: newclient.h:604
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
METHOD_SILENT_ERROR
#define METHOD_SILENT_ERROR
Definition: ob_methods.h:18
MSG_TYPE_APPLY_UNAPPLY
#define MSG_TYPE_APPLY_UNAPPLY
Definition: newclient.h:605