Crossfire Server, Trunk
weapon_improver.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 
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(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 
50 static method_ret weapon_improver_type_apply(object *op, object *applier, int aflags) {
51  object *oop;
52  (void)aflags;
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 
100  if (strcmp(tmp->arch->name, item) == 0) {
101  if (!QUERY_FLAG(tmp, FLAG_CURSED)
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 }
PLAYER
@ PLAYER
Definition: object.h:112
global.h
settings
struct Settings settings
Definition: init.cpp:139
BOW
@ BOW
Definition: object.h:123
llevError
@ llevError
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:58
check_item
static int check_item(object *op, const char *item)
Definition: weapon_improver.cpp:93
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
IMPROVE_CHA
#define IMPROVE_CHA
Definition: weapon_improver.cpp:227
object::item_power
int8_t item_power
Definition: object.h:372
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:319
register_apply
void register_apply(int ob_type, apply_func method)
Definition: ob_types.cpp:62
FOR_BELOW_PREPARE
#define FOR_BELOW_PREPARE(op_, it_)
Definition: define.h:704
METHOD_OK
#define METHOD_OK
Definition: ob_methods.h:15
living::Dex
int8_t Dex
Definition: living.h:36
object::x
int16_t x
Definition: object.h:335
object::map
struct mapstruct * map
Definition: object.h:305
WEAPON
@ WEAPON
Definition: object.h:124
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
FLAG_WIZCAST
#define FLAG_WIZCAST
Definition: define.h:289
fix_object
void fix_object(object *op)
Definition: living.cpp:1132
Ice.tmp
int tmp
Definition: Ice.py:207
P_NO_MAGIC
#define P_NO_MAGIC
Definition: map.h:225
UPD_NROF
#define UPD_NROF
Definition: newclient.h:324
init_type_weapon_improver
void init_type_weapon_improver(void)
Definition: weapon_improver.cpp:38
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
object::level
int16_t level
Definition: object.h:361
buf
StringBuffer * buf
Definition: readable.cpp:1565
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2857
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Definition: define.h:711
object::y
int16_t y
Definition: object.h:335
check_sacrifice
static int check_sacrifice(object *op, const object *improver)
Definition: weapon_improver.cpp:165
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
IMPROVE_PREPARE
#define IMPROVE_PREPARE
Definition: weapon_improver.cpp:219
MSG_TYPE_APPLY_SUCCESS
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:606
eat_item
static void eat_item(object *op, const char *item, uint32_t nrof)
Definition: weapon_improver.cpp:130
object::last_eat
int32_t last_eat
Definition: object.h:366
isqrt
int isqrt(int n)
Definition: utils.cpp:562
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Definition: global.h:204
object::type
uint8_t type
Definition: object.h:348
IMPROVE_DAMAGE
#define IMPROVE_DAMAGE
Definition: weapon_improver.cpp:220
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:317
living::dam
int16_t dam
Definition: living.h:46
object::magic
int8_t magic
Definition: object.h:358
UPD_FLAGS
#define UPD_FLAGS
Definition: newclient.h:318
Settings::item_power_factor
float item_power_factor
Definition: global.h:303
IMPROVE_INT
#define IMPROVE_INT
Definition: weapon_improver.cpp:228
disinfect.count
int count
Definition: disinfect.py:7
sproto.h
statname
const char *const statname[NUM_STATS]
Definition: living.cpp:183
living::sp
int16_t sp
Definition: living.h:42
living::Int
int8_t Int
Definition: living.h:36
IMPROVE_DEX
#define IMPROVE_DEX
Definition: weapon_improver.cpp:224
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
weapon_improver_type_apply
static method_ret weapon_improver_type_apply(object *op, object *applier, int aflags)
Definition: weapon_improver.cpp:50
MAX_BUF
#define MAX_BUF
Definition: define.h:35
object::weight
int32_t weight
Definition: object.h:375
IMPROVE_WIS
#define IMPROVE_WIS
Definition: weapon_improver.cpp:226
living::Wis
int8_t Wis
Definition: living.h:36
IMPROVE_POW
#define IMPROVE_POW
Definition: weapon_improver.cpp:229
method_ret
char method_ret
Definition: ob_methods.h:14
prepare_weapon
static int prepare_weapon(object *op, object *improver, object *weapon)
Definition: weapon_improver.cpp:245
ob_types.h
IMPROVE_STR
#define IMPROVE_STR
Definition: weapon_improver.cpp:223
sounds.h
object_decrease_nrof
object * object_decrease_nrof(object *op, uint32_t i)
Definition: object.cpp:2676
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:265
object::slaying
sstring slaying
Definition: object.h:327
IMPROVE_CON
#define IMPROVE_CON
Definition: weapon_improver.cpp:225
get_map_flags
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, int16_t x, int16_t y, int16_t *nx, int16_t *ny)
Definition: map.cpp:300
item
Definition: item.py:1
apply_check_weapon_power
int apply_check_weapon_power(const object *who, int improves)
Definition: apply.cpp:1131
living::Cha
int8_t Cha
Definition: living.h:36
give.op
op
Definition: give.py:33
improve_weapon
static int improve_weapon(object *op, object *improver, object *weapon)
Definition: weapon_improver.cpp:332
object_split
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.cpp:2637
IMPROVE_WEIGHT
#define IMPROVE_WEIGHT
Definition: weapon_improver.cpp:221
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Definition: main.cpp:359
apply_special
int apply_special(object *who, object *op, int aflags)
Definition: apply.cpp:1156
UPD_NAME
#define UPD_NAME
Definition: newclient.h:321
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.cpp:308
IMPROVE_ENCHANT
#define IMPROVE_ENCHANT
Definition: weapon_improver.cpp:222
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
METHOD_ERROR
#define METHOD_ERROR
Definition: ob_methods.h:17
WEAPON_IMPROVER
@ WEAPON_IMPROVER
Definition: object.h:238
ob_methods.h
object::stats
living stats
Definition: object.h:378
AP_UNAPPLY
#define AP_UNAPPLY
Definition: define.h:575
MAX_WEAPON_ITEM_POWER
#define MAX_WEAPON_ITEM_POWER
Definition: define.h:459
living::Pow
int8_t Pow
Definition: living.h:36
MSG_TYPE_APPLY
#define MSG_TYPE_APPLY
Definition: newclient.h:411
FLAG_CURSED
#define FLAG_CURSED
Definition: define.h:316
MSG_TYPE_APPLY_ERROR
#define MSG_TYPE_APPLY_ERROR
Definition: newclient.h:604
find_marked_object
object * find_marked_object(object *op)
Definition: c_object.cpp:1520
improve_weapon_stat
static int improve_weapon_stat(object *op, object *improver, object *weapon, signed char *stat, int sacrifice_count, const char *statname)
Definition: weapon_improver.cpp:200
living::Con
int8_t Con
Definition: living.h:36
living::Str
int8_t Str
Definition: living.h:36