Crossfire Server, Trunk  R21041
weapon_improver.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 
18 #include "global.h"
19 
20 #include <string.h>
21 
22 #include "ob_methods.h"
23 #include "ob_types.h"
24 #include "sounds.h"
25 #include "sproto.h"
26 
27 static method_ret weapon_improver_type_apply(ob_methods *context, object *op, object *applier, int aflags);
28 static int check_item(object *op, const char *item);
29 static void eat_item(object *op, const char *item, uint32_t nrof);
30 static int check_sacrifice(object *op, const object *improver);
31 static int improve_weapon_stat(object *op, object *improver, object *weapon, signed char *stat, int sacrifice_count, const char *statname);
32 static int prepare_weapon(object *op, object *improver, object *weapon);
33 static int improve_weapon(object *op, object *improver, object *weapon);
34 
40 }
41 
51 static method_ret weapon_improver_type_apply(ob_methods *context, object *op, object *applier, int aflags) {
52  object *oop;
53 
54  if (applier->type != PLAYER)
55  return METHOD_ERROR;
56  if (!QUERY_FLAG(applier, FLAG_WIZCAST)
57  && (get_map_flags(applier->map, NULL, applier->x, applier->y, NULL, NULL)&P_NO_MAGIC)) {
59  "Something blocks the magic of the scroll.");
60  return METHOD_ERROR;
61  }
62 
63  oop = find_marked_object(applier);
64  if (!oop) {
66  "You need to mark a weapon object.");
67  return METHOD_ERROR;
68  }
69  if (oop->type != WEAPON && oop->type != BOW) {
71  "Marked item is not a weapon or bow");
72  return METHOD_ERROR;
73  }
75  "Applied weapon builder.");
76  improve_weapon(applier, op, oop);
78  return METHOD_OK;
79 }
80 
93 static int check_item(object *op, const char *item) {
94  int count = 0;
95 
96  if (item == NULL)
97  return 0;
98 
99  FOR_BELOW_PREPARE(op, tmp) {
100  if (strcmp(tmp->arch->name, item) == 0) {
101  if (!QUERY_FLAG(tmp, FLAG_CURSED)
102  && !QUERY_FLAG(tmp, FLAG_DAMNED)
103  /* Loophole bug? -FD- */ && !QUERY_FLAG(tmp, FLAG_UNPAID)) {
104  if (tmp->nrof == 0)/* this is necessary for artifact sacrifices --FD-- */
105  count++;
106  else
107  count += tmp->nrof;
108  }
109  }
110  } FOR_BELOW_FINISH();
111  return count;
112 }
113 
130 static void eat_item(object *op, const char *item, uint32_t nrof) {
131  object *prev;
132 
133  prev = op;
134  op = op->below;
135 
136  while (op != NULL) {
137  if (strcmp(op->arch->name, item) == 0) {
138  if (op->nrof >= nrof) {
139  object_decrease_nrof(op, nrof);
140  return;
141  } else {
142  object_decrease_nrof(op, op->nrof);
143  nrof -= op->nrof;
144  }
145  op = prev;
146  }
147  prev = op;
148  op = op->below;
149  }
150 }
151 
165 static int check_sacrifice(object *op, const object *improver) {
166  int count = 0;
167 
168  if (improver->slaying != NULL) {
169  count = check_item(op, improver->slaying);
170  if (count < 1) {
172  "The gods want more %ss",
173  improver->slaying);
174  return 0;
175  }
176  } else
177  count = 1;
178 
179  return count;
180 }
181 
200 static int improve_weapon_stat(object *op, object *improver, object *weapon, signed char *stat, int sacrifice_count, const char *statname) {
202  "Your sacrifice was accepted.");
203 
204  *stat += sacrifice_count;
205  weapon->last_eat++;
206 
208  "Weapon's bonus to %s improved by %d",
209  statname, sacrifice_count);
210 
211  object_decrease_nrof_by_one(improver);
212 
213  /* So it updates the players stats and the window */
214  fix_object(op);
215  return 1;
216 }
217 
218 /* Types of improvements, hidden in the sp field. */
219 #define IMPROVE_PREPARE 1
220 #define IMPROVE_DAMAGE 2
221 #define IMPROVE_WEIGHT 3
222 #define IMPROVE_ENCHANT 4
223 #define IMPROVE_STR 5
224 #define IMPROVE_DEX 6
225 #define IMPROVE_CON 7
226 #define IMPROVE_WIS 8
227 #define IMPROVE_CHA 9
228 #define IMPROVE_INT 10
229 #define IMPROVE_POW 11
245 static int prepare_weapon(object *op, object *improver, object *weapon) {
246  int sacrifice_count, i;
247  char buf[MAX_BUF];
248 
249  if (weapon->level != 0) {
251  "Weapon already prepared.");
252  return 0;
253  }
254  for (i = 0; i < NROFATTACKS; i++)
255  if (weapon->resist[i])
256  break;
257 
258  /* If we break out, i will be less than nrofattacks, preventing
259  * improvement of items that already have protections.
260  */
261  if (i < NROFATTACKS
262  || weapon->stats.hp /* regeneration */
263  || (weapon->stats.sp && weapon->type == WEAPON) /* sp regeneration */
264  || weapon->stats.exp /* speed */
265  || weapon->stats.ac) { /* AC - only taifu's I think */
267  "Cannot prepare magic weapons.");
268  return 0;
269  }
270 
271  sacrifice_count = check_sacrifice(op, improver);
272  if (sacrifice_count <= 0)
273  return 0;
274 
275  /* We do not allow improving stacks, so split this off from
276  * stack. Only need to do this if weapon is part of a stack.
277  * We set nrof of weapon to zero so it can not merge with other
278  * items, so one can not do further improvements on a stack.
279  * side effect of doing it before the object_insert_in_ob() is that
280  * it won't merge back in. We know from the code that marked
281  * objects must be in the players inventory, so we know where
282  * to put this.
283  */
284  if (weapon->nrof >1) {
285  weapon = object_split(weapon,1, NULL, 0);
286  weapon->nrof = 0;
287  object_insert_in_ob(weapon, op);
288  } else {
289  weapon->nrof = 0;
290  }
291 
292 
293  weapon->level = isqrt(sacrifice_count);
295  "Your sacrifice was accepted.");
296  eat_item(op, improver->slaying, sacrifice_count);
297 
298 
299  snprintf(buf, sizeof(buf), "%s's %s", op->name, weapon->name);
300  FREE_AND_COPY(weapon->name, buf);
301  FREE_AND_COPY(weapon->name_pl, buf);
302 
304  "Your %s may be improved %d times.",
305  weapon->name, weapon->level);
306 
307  object_decrease_nrof_by_one(improver);
308  weapon->last_eat = 0;
309  esrv_update_item(UPD_NAME | UPD_NROF, op, weapon);
310  return 1;
311 }
312 
332 static int improve_weapon(object *op, object *improver, object *weapon) {
333  int sacrifice_count, sacrifice_needed = 0;
334 
335  if (improver->stats.sp == IMPROVE_PREPARE) {
336  return prepare_weapon(op, improver, weapon);
337  }
338 
339  if (weapon->level == 0) {
341  "This weapon has not been prepared.");
342  return 0;
343  }
344 
345  if (weapon->level == weapon->last_eat && weapon->item_power >= MAX_WEAPON_ITEM_POWER) {
347  "This weapon cannot be improved any more.");
348  return 0;
349  }
350 
351  if (QUERY_FLAG(weapon, FLAG_APPLIED)
352  && !apply_check_weapon_power(op, weapon->last_eat+1)) {
354  "Improving the weapon will make it too powerful for you to use. Unready it if you really want to improve it.");
355  return 0;
356  }
357 
358  /* All improvements add to item power, so check if player can
359  * still wear the weapon after improvement.
360  */
361  if (QUERY_FLAG(weapon, FLAG_APPLIED)
362  && op->type == PLAYER
363  && (op->contr->item_power+1) > (settings.item_power_factor*op->level)) {
364  apply_special(op, weapon, AP_UNAPPLY);
365  if (QUERY_FLAG(weapon, FLAG_APPLIED)) {
366  /* Weapon is cursed, too bad */
368  "You can't enchant this weapon without unapplying it because it would consume your soul!");
369  return 0;
370  }
371  }
372 
373  /* This just increases damage by 5 points, no matter what. No
374  * sacrifice is needed. Since stats.dam is now a 16 bit value and
375  * not 8 bit, don't put any maximum value on damage - the limit is
376  * how much the weapon can be improved.
377  */
378  if (improver->stats.sp == IMPROVE_DAMAGE) {
379  weapon->stats.dam += 5;
380  weapon->weight += 5000; /* 5 KG's */
382  "Damage has been increased by 5 to %d",
383  weapon->stats.dam);
384  weapon->last_eat++;
385 
386  weapon->item_power++;
387  object_decrease_nrof_by_one(improver);
388  esrv_update_item(UPD_WEIGHT, op, weapon);
389  return 1;
390  }
391 
392  if (improver->stats.sp == IMPROVE_WEIGHT) {
393  /* Reduce weight by 20% */
394  weapon->weight = (weapon->weight*8)/10;
395  if (weapon->weight < 1)
396  weapon->weight = 1;
398  "Weapon weight reduced to %6.1f kg",
399  (float)weapon->weight/1000.0);
400  weapon->last_eat++;
401  weapon->item_power++;
402  object_decrease_nrof_by_one(improver);
403  esrv_update_item(UPD_WEIGHT, op, weapon);
404  return 1;
405  }
406 
407  if (improver->stats.sp == IMPROVE_ENCHANT) {
408  weapon->magic++;
409  weapon->last_eat++;
411  "Weapon magic increased to %d",
412  weapon->magic);
413  object_decrease_nrof_by_one(improver);
414  weapon->item_power++;
415  return 1;
416  }
417 
418  sacrifice_needed = weapon->stats.Str
419  +weapon->stats.Int
420  +weapon->stats.Dex
421  +weapon->stats.Pow
422  +weapon->stats.Con
423  +weapon->stats.Cha
424  +weapon->stats.Wis;
425 
426  if (sacrifice_needed < 1)
427  sacrifice_needed = 1;
428  sacrifice_needed *= 2;
429 
430  sacrifice_count = check_sacrifice(op, improver);
431  if (sacrifice_count < sacrifice_needed) {
433  "You need at least %d %s",
434  sacrifice_needed, improver->slaying);
435  return 0;
436  }
437  eat_item(op, improver->slaying, sacrifice_needed);
438  weapon->item_power++;
439 
440  switch (improver->stats.sp) {
441  case IMPROVE_STR:
442  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Str), 1, "strength");
443 
444  case IMPROVE_DEX:
445  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Dex), 1, "dexterity");
446 
447  case IMPROVE_CON:
448  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Con), 1, "constitution");
449 
450  case IMPROVE_WIS:
451  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Wis), 1, "wisdom");
452 
453  case IMPROVE_CHA:
454  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Cha), 1, "charisma");
455 
456  case IMPROVE_INT:
457  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Int), 1, "intelligence");
458 
459  case IMPROVE_POW:
460  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Pow), 1, "power");
461 
462  default:
464  "Unknown improvement type.");
465  }
466 
467  LOG(llevError, "improve_weapon: Got to end of function\n");
468  return 0;
469 }
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:613
int8_t Int
Definition: living.h:36
int apply_special(object *who, object *op, int aflags)
Definition: apply.c:1082
#define FLAG_DAMNED
Definition: define.h:318
#define FLAG_UNPAID
Definition: define.h:236
#define IMPROVE_INT
#define METHOD_ERROR
Definition: ob_methods.h:17
#define P_NO_MAGIC
Definition: map.h:227
#define IMPROVE_WEIGHT
void esrv_update_item(int flags, object *pl, object *op)
Definition: main.c:342
static int improve_weapon(object *op, object *improver, object *weapon)
Definition: object.h:119
int isqrt(int n)
Definition: utils.c:586
const char * slaying
Definition: object.h:319
#define IMPROVE_ENCHANT
#define IMPROVE_PREPARE
static int prepare_weapon(object *op, object *improver, object *weapon)
int16_t sp
Definition: living.h:42
#define IMPROVE_CHA
void init_type_weapon_improver(void)
#define IMPROVE_WIS
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:310
#define MSG_TYPE_APPLY
Definition: newclient.h:384
int8_t Con
Definition: living.h:36
char method_ret
Definition: ob_methods.h:14
int apply_check_weapon_power(const object *who, int improves)
Definition: apply.c:1057
static int check_sacrifice(object *op, const object *improver)
int16_t y
Definition: object.h:326
Definition: object.h:118
#define IMPROVE_CON
#define IMPROVE_DAMAGE
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2705
static void eat_item(object *op, const char *item, uint32_t nrof)
int32_t weight
Definition: object.h:365
#define IMPROVE_POW
#define METHOD_OK
Definition: ob_methods.h:15
const char *const statname[NUM_STATS]
Definition: living.c:183
int8_t Wis
Definition: living.h:36
struct mapdef * map
Definition: object.h:297
#define snprintf
Definition: win32.h:46
#define MSG_TYPE_APPLY_ERROR
Definition: newclient.h:596
int16_t dam
Definition: living.h:46
struct obj * below
Definition: object.h:287
#define MAX_WEAPON_ITEM_POWER
Definition: define.h:475
uint32_t nrof
Definition: object.h:333
int8_t Cha
Definition: living.h:36
#define UPD_FLAGS
Definition: newclient.h:290
void register_apply(int ob_type, apply_func method)
Definition: ob_types.c:62
struct pl * contr
Definition: object.h:276
int8_t item_power
Definition: object.h:362
object * find_marked_object(object *op)
Definition: c_object.c:1256
#define UPD_WEIGHT
Definition: newclient.h:291
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define MAX_BUF
Definition: define.h:35
int16_t x
Definition: object.h:326
int32_t last_eat
Definition: object.h:356
int8_t Str
Definition: living.h:36
#define FLAG_CURSED
Definition: define.h:317
Definition: object.h:107
unsigned int uint32_t
Definition: win32.h:162
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.c:2478
object * object_decrease_nrof(object *op, uint32_t i)
Definition: object.c:2520
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:28
#define FREE_AND_COPY(sv, nv)
Definition: global.h:211
#define UPD_NROF
Definition: newclient.h:296
living stats
Definition: object.h:368
#define FLAG_WIZCAST
Definition: define.h:290
int8_t Dex
Definition: living.h:36
struct archt * arch
Definition: object.h:412
#define IMPROVE_DEX
uint8_t type
Definition: object.h:338
struct Settings settings
Definition: init.c:40
#define FLAG_APPLIED
Definition: define.h:235
#define NROFATTACKS
Definition: attack.h:17
#define UPD_NAME
Definition: newclient.h:293
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:598
int8_t Pow
Definition: living.h:36
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.c:300
#define NDI_UNIQUE
Definition: newclient.h:245
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
int16_t item_power
Definition: player.h:117
static method_ret weapon_improver_type_apply(ob_methods *context, object *op, object *applier, int aflags)
#define FOR_BELOW_PREPARE(op_, it_)
Definition: define.h:741
static int check_item(object *op, const char *item)
int16_t level
Definition: object.h:351
void fix_object(object *op)
Definition: living.c:1119
#define IMPROVE_STR
int8_t magic
Definition: object.h:348
float item_power_factor
Definition: global.h:300
const char * name
Definition: object.h:466
#define FOR_BELOW_FINISH()
Definition: define.h:748
static int improve_weapon_stat(object *op, object *improver, object *weapon, signed char *stat, int sacrifice_count, const char *statname)