Atrinik Server  4.0
arrow.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
30 #include <global.h>
31 #include <player.h>
32 #include <object.h>
33 #include <object_methods.h>
34 #include <arrow.h>
35 #include <bow.h>
36 
38 
40 static int
41 ranged_fire_func (object *op, object *shooter, int dir, double *delay)
42 {
43  HARD_ASSERT(op != NULL);
44  HARD_ASSERT(shooter != NULL);
45 
46  if (dir == 0) {
47  draw_info(COLOR_WHITE, shooter, "You can't throw that at yourself.");
49  }
50 
51  if (QUERY_FLAG(op, FLAG_STARTEQUIP)) {
52  draw_info(COLOR_WHITE, shooter, "The gods won't let you throw that.");
54  }
55 
56  if (op->weight <= 0 || QUERY_FLAG(op, FLAG_NO_DROP)) {
57  char *name = object_get_base_name_s(op, shooter);
58  draw_info_format(COLOR_WHITE, shooter, "You can't throw %s.", name);
59  efree(name);
61  }
62 
63  if (QUERY_FLAG(op, FLAG_APPLIED) && OBJECT_CURSED(op)) {
64  char *name = object_get_base_name_s(op, shooter);
65  draw_info_format(COLOR_WHITE, shooter, "The %s sticks to your hand!",
66  name);
67  efree(name);
69  }
70 
71  op = object_stack_get_removed(op, 1);
72 
73  /* Save original WC, damage and range. */
74  op->last_heal = op->stats.wc;
75  op->stats.hp = op->stats.dam;
76  op->stats.sp = op->last_sp;
77 
78  /* Calculate moving speed. */
79  int str = shooter->type == PLAYER ? shooter->stats.Str : MAX_STAT / 2;
80  op->speed = MIN(1.0f, (speed_bonus[str] + 1.0) / 1.5);
81 
82  /* Get the used skill. */
83  object *skill = SK_skill(shooter);
84  /* If we got the skill, add in the skill's modifiers. */
85  if (skill != NULL) {
86  /* Add WC. */
87  op->stats.wc += skill->last_heal;
88  /* Add tiles range. */
89  op->last_sp += skill->last_sp;
90  }
91 
92  op->stats.dam += op->magic;
93  op->stats.wc += SK_level(shooter);
94  op->stats.wc += op->magic;
95 
96  if (shooter->type == PLAYER) {
97  op->stats.dam += dam_bonus[shooter->stats.Str] / 2;
98  op->stats.wc += wc_bonus[shooter->stats.Dex];
99  } else {
100  op->stats.wc += 5;
101  }
102 
103  double dam = op->stats.dam * LEVEL_DAMAGE(SK_level(shooter));
104  if (op->item_quality) {
105  dam *= op->item_condition / 100.0;
106  }
107  op->stats.dam = MAX(1.0, dam);
108 
109  if (delay != NULL) {
110  *delay = op->last_grace;
111  }
112 
113  op = object_projectile_fire(op, shooter, dir);
114  if (op == NULL) {
115  return OBJECT_METHOD_OK;
116  }
117 
118  if (shooter->type == PLAYER) {
119  CONTR(shooter)->stat_missiles_thrown++;
120  }
121 
122  play_sound_map(shooter->map,
123  CMD_SOUND_EFFECT,
124  "throw.ogg",
125  shooter->x,
126  shooter->y,
127  0,
128  0);
129  return OBJECT_METHOD_OK;
130 }
131 
133 static int
135  object **ret,
136  int difficulty,
137  treasure_affinity_t *affinity,
138  int flags)
139 {
140  HARD_ASSERT(op != NULL);
141  HARD_ASSERT(difficulty > 0);
142 
143  /* Avoid processing if the item is not special. */
144  if (!process_treasure_is_special(op)) {
146  }
147 
148  /* Only handle adding a slaying race for arrows of assassination or
149  * slaying. */
150  if (op->slaying != shstr_cons.none) {
152  }
153 
154  ob_race *race = race_get_random();
155  if (race != NULL) {
156  FREE_AND_COPY_HASH(op->slaying, race->name);
157  }
158 
159  return OBJECT_METHOD_OK;
160 }
161 
166 {
167  OBJECT_METHODS(ARROW)->apply_func =
169  OBJECT_METHODS(ARROW)->ranged_fire_func =
171  OBJECT_METHODS(ARROW)->projectile_stop_func =
173  OBJECT_METHODS(ARROW)->process_func =
175  OBJECT_METHODS(ARROW)->projectile_move_func =
177  OBJECT_METHODS(ARROW)->projectile_fire_func =
179  OBJECT_METHODS(ARROW)->projectile_hit_func =
181  OBJECT_METHODS(ARROW)->move_on_func =
183  OBJECT_METHODS(ARROW)->process_treasure_func =
185 }
186 
199 int16_t
200 arrow_get_wc (object *op, object *bow, object *arrow)
201 {
202  HARD_ASSERT(op != NULL);
203  HARD_ASSERT(bow != NULL);
204  HARD_ASSERT(arrow != NULL);
205 
206  op = HEAD(op);
207 
208  int level;
209  if (op->type == PLAYER) {
210  object *skill = CONTR(op)->skill_ptr[bow_get_skill(bow)];
211  if (skill == NULL) {
212  return 0;
213  }
214 
215  level = skill->level;
216  } else {
217  level = op->level;
218  }
219 
220  return (arrow->stats.wc + bow->magic + arrow->magic + level +
221  wc_bonus[op->stats.Dex] + bow->stats.wc);
222 }
223 
236 int16_t
237 arrow_get_damage (object *op, object *bow, object *arrow)
238 {
239  HARD_ASSERT(op != NULL);
240  HARD_ASSERT(bow != NULL);
241  HARD_ASSERT(arrow != NULL);
242 
243  op = HEAD(op);
244 
245  int level;
246  if (op->type == PLAYER) {
247  object *skill = CONTR(op)->skill_ptr[bow_get_skill(bow)];
248  if (skill == NULL) {
249  return 0;
250  }
251 
252  level = skill->level;
253  } else {
254  level = op->level;
255  }
256 
257  double dam = arrow->stats.dam + arrow->magic;
258  dam += bow->stats.dam + bow->magic;
259  if (op->type == PLAYER) {
260  dam += CONTR(op)->dam_bonus;
261  }
262  dam *= LEVEL_DAMAGE(level);
263  dam = ABS(dam);
264  if (op->type == PLAYER) {
265  dam += dam * dam_bonus[op->stats.Str] / 10.0;
266  }
267 
268  int item_condition;
269  if (bow->item_condition > arrow->item_condition) {
270  item_condition = bow->item_condition;
271  } else {
272  item_condition = arrow->item_condition;
273  }
274 
275  dam = dam / 100.0 * item_condition;
276 
277  return dam;
278 }
279 
293 object *
294 arrow_find (object *op, shstr *type)
295 {
296  HARD_ASSERT(op != NULL);
297 
298  /* For non-players, little more work is necessary to find an arrow. */
299  if (op->type != PLAYER) {
300  FOR_INV_PREPARE(op, tmp) {
301  if (tmp->type == ARROW && tmp->race == type) {
302  return tmp;
303  }
304 
305  if (tmp->type == CONTAINER && tmp->race == type) {
306  object *arrow = arrow_find(tmp, type);
307  if (arrow != NULL) {
308  return arrow;
309  }
310  }
311  } FOR_INV_FINISH();
312 
313  return NULL;
314  }
315 
316  object *tmp = CONTR(op)->equipment[PLAYER_EQUIP_AMMO];
317  /* Nothing readied. */
318  if (tmp == NULL) {
319  return NULL;
320  }
321 
322  /* The type does not match the arrow/quiver. */
323  if (tmp->race != type) {
324  return NULL;
325  }
326 
327  /* The readied item is an arrow, so simply return it. */
328  if (tmp->type == ARROW) {
329  return tmp;
330  } else if (tmp->type == CONTAINER) {
331  /* A quiver, search through it for arrows. */
332  return arrow_find(tmp, type);
333  }
334 
335  return NULL;
336 }
#define FREE_AND_COPY_HASH(_sv_, _nv_)
Definition: global.h:100
static int process_treasure_func(object *op, object **ret, int difficulty, treasure_affinity_t *affinity, int flags)
Definition: arrow.c:134
const char * race
Definition: object.h:174
uint8_t type
One of operation types.
Definition: sound_ambient.c:45
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:1691
#define FOR_INV_FINISH()
Definition: define.h:1698
object * common_object_projectile_move(object *op)
Definition: projectile.c:152
int SK_level(object *op)
Definition: skill_util.c:470
int16_t last_heal
Definition: object.h:310
int16_t arrow_get_wc(object *op, object *bow, object *arrow)
Definition: arrow.c:200
object * arrow_find(object *op, shstr *type)
Definition: arrow.c:294
const char * slaying
Definition: object.h:180
int16_t last_sp
Definition: object.h:313
int common_object_projectile_move_on(object *op, object *victim, object *originator, int state)
Definition: projectile.c:376
object * object_stack_get_removed(object *op, uint32_t nrof)
Definition: object.c:2078
uint8_t item_quality
Definition: object.h:366
#define PLAYER
Definition: define.h:122
#define FLAG_NO_DROP
Definition: define.h:1070
int16_t sp
Definition: living.h:78
#define QUERY_FLAG(xyz, p)
Definition: define.h:761
int16_t arrow_get_damage(object *op, object *bow, object *arrow)
Definition: arrow.c:237
int32_t hp
Definition: living.h:72
#define FLAG_STARTEQUIP
Definition: define.h:1004
int16_t y
Definition: object.h:276
OBJECT_TYPE_INIT_DEFINE(arrow)
Definition: arrow.c:165
char * object_get_base_name_s(const object *op, const object *caller)
Definition: item.c:534
uint8_t item_condition
Definition: object.h:369
uint32_t weight
Definition: object.h:246
struct mapdef * map
Definition: object.h:139
int16_t dam
Definition: living.h:87
#define CONTAINER
Definition: define.h:493
int16_t last_grace
Definition: object.h:316
int bow_get_skill(object *bow)
Definition: bow.c:158
object * SK_skill(object *op)
Definition: skill_util.c:496
object * common_object_projectile_stop_missile(object *op, int reason)
Definition: projectile.c:182
#define ARROW
Definition: define.h:170
object * object_projectile_fire(object *op, object *shooter, int dir)
static int ranged_fire_func(object *op, object *shooter, int dir, double *delay)
Definition: arrow.c:41
double speed
Definition: object.h:469
int common_object_projectile_hit(object *op, object *victim)
Definition: projectile.c:344
#define HEAD(op)
Definition: object.h:657
#define OBJECT_METHOD_UNHANDLED
shstr * name
Definition: race.h:40
int16_t x
Definition: object.h:273
int16_t wc
Definition: living.h:90
Definition: race.h:36
void play_sound_map(mapstruct *map, int type, const char *filename, int x, int y, int loop, int volume)
Definition: sounds.c:159
#define LEVEL_DAMAGE(level)
Definition: living.h:61
#define FLAG_APPLIED
Definition: define.h:1182
int wc_bonus[MAX_STAT+1]
Definition: living.c:57
bool process_treasure_is_special(object *op)
int object_apply_item(object *op, object *applier, int aflags)
Definition: apply.c:110
object * common_object_projectile_fire_missile(object *op, object *shooter, int dir)
Definition: projectile.c:301
shstr_constants shstr_cons
Definition: init.c:58
living stats
Definition: object.h:481
int8_t Dex
Definition: living.h:106
float speed_bonus[MAX_STAT+1]
Definition: living.c:97
uint8_t type
Definition: object.h:360
#define OBJECT_METHODS(type)
ob_race * race_get_random(void)
Definition: race.c:175
#define OBJECT_METHOD_OK
int8_t Str
Definition: living.h:103
double dam_bonus[MAX_STAT+1]
Definition: living.c:44
int8_t level
Definition: object.h:347
int8_t magic
Definition: object.h:341
void common_object_projectile_process(object *op)
Definition: projectile.c:68
#define OBJECT_CURSED(ob)
Definition: object.h:690
#define MAX_STAT
Definition: define.h:47