Crossfire Server, Trunk  1.75.0
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 
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 }
PLAYER
@ PLAYER
Definition: object.h:112
global.h
settings
struct Settings settings
Server settings.
Definition: init.cpp:139
BOW
@ BOW
Definition: object.h:123
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
check_item
static int check_item(object *op, const char *item)
Counts suitable items with specified archetype name.
Definition: weapon_improver.cpp:93
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
IMPROVE_CHA
#define IMPROVE_CHA
Increase charisma bonus.
Definition: weapon_improver.cpp:227
object::item_power
int8_t item_power
Power rating of the object.
Definition: object.h:372
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:319
register_apply
void register_apply(int ob_type, apply_func method)
Registers the apply method for the given type.
Definition: ob_types.cpp:62
FOR_BELOW_PREPARE
#define FOR_BELOW_PREPARE(op_, it_)
Constructs a loop iterating over all objects below an object.
Definition: define.h:698
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
Pointer to the map in which this object is present.
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
The wizard can cast spells in no-magic area.
Definition: define.h:289
fix_object
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.cpp:1132
P_NO_MAGIC
#define P_NO_MAGIC
Spells (some) can't pass this object.
Definition: map.h:227
UPD_NROF
#define UPD_NROF
Definition: newclient.h:324
init_type_weapon_improver
void init_type_weapon_improver(void)
Initializer for the WEAPON_IMPROVER object type.
Definition: weapon_improver.cpp:38
NROFATTACKS
#define NROFATTACKS
Definition: attack.h:17
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
buf
StringBuffer * buf
Definition: readable.cpp:1565
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2857
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Finishes FOR_BELOW_PREPARE().
Definition: define.h:705
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
check_sacrifice
static int check_sacrifice(object *op, const object *improver)
Returns how many items of type improver->slaying there are under op.
Definition: weapon_improver.cpp:165
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
IMPROVE_PREPARE
#define IMPROVE_PREPARE
Prepare the weapon.
Definition: weapon_improver.cpp:219
MSG_TYPE_APPLY_SUCCESS
#define MSG_TYPE_APPLY_SUCCESS
Was able to apply object.
Definition: newclient.h:606
object::below
object * below
Pointer to the object stacked below this one.
Definition: object.h:295
eat_item
static void eat_item(object *op, const char *item, uint32_t nrof)
This removes 'nrof' items with specified archetype.
Definition: weapon_improver.cpp:130
object::last_eat
int32_t last_eat
How long since we last ate.
Definition: object.h:366
isqrt
int isqrt(int n)
Compute the square root.
Definition: utils.cpp:562
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:206
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
IMPROVE_DAMAGE
#define IMPROVE_DAMAGE
Increase damage.
Definition: weapon_improver.cpp:220
FLAG_DAMNED
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:317
living::dam
int16_t dam
How much damage this object does when hitting.
Definition: living.h:46
object::magic
int8_t magic
Any magical bonuses to this item.
Definition: object.h:358
UPD_FLAGS
#define UPD_FLAGS
Definition: newclient.h:318
Settings::item_power_factor
float item_power_factor
See note in setings file.
Definition: global.h:305
IMPROVE_INT
#define IMPROVE_INT
Increase intelligence bonus.
Definition: weapon_improver.cpp:228
player::item_power
int16_t item_power
Total item power of objects equipped.
Definition: player.h:130
sproto.h
statname
const char *const statname[NUM_STATS]
Name of stats.
Definition: living.cpp:183
living::sp
int16_t sp
Spell points.
Definition: living.h:42
living::Int
int8_t Int
Definition: living.h:36
IMPROVE_DEX
#define IMPROVE_DEX
Increase dexterity bonus.
Definition: weapon_improver.cpp:224
weapon_improver_type_apply
static method_ret weapon_improver_type_apply(object *op, object *applier, int aflags)
Attempts to apply weapon_improver.
Definition: weapon_improver.cpp:50
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
object::weight
int32_t weight
Attributes of the object.
Definition: object.h:375
IMPROVE_WIS
#define IMPROVE_WIS
Increase wisdom bonus.
Definition: weapon_improver.cpp:226
living::Wis
int8_t Wis
Definition: living.h:36
IMPROVE_POW
#define IMPROVE_POW
Increase power bonus.
Definition: weapon_improver.cpp:229
method_ret
char method_ret
Define some standard return values for callbacks which don't need to return any other results.
Definition: ob_methods.h:14
prepare_weapon
static int prepare_weapon(object *op, object *improver, object *weapon)
This does the prepare weapon scroll.
Definition: weapon_improver.cpp:245
ob_types.h
IMPROVE_STR
#define IMPROVE_STR
Increase strength bonus.
Definition: weapon_improver.cpp:223
sounds.h
object_decrease_nrof
object * object_decrease_nrof(object *op, uint32_t i)
Decreases a specified number from the amount of an object.
Definition: object.cpp:2676
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:265
object::slaying
sstring slaying
Which race to do double damage to.
Definition: object.h:327
IMPROVE_CON
#define IMPROVE_CON
Increase constitution bonus.
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)
This rolls up wall, blocks_magic, blocks_view, etc, all into one function that just returns a P_.
Definition: map.cpp:300
apply_check_weapon_power
int apply_check_weapon_power(const object *who, int improves)
This checks to see of the player (who) is sufficient level to use a weapon with improves improvements...
Definition: apply.cpp:1131
living::Cha
int8_t Cha
Definition: living.h:36
improve_weapon
static int improve_weapon(object *op, object *improver, object *weapon)
Does the dirty job for 'improve weapon' scroll, prepare or add something.
Definition: weapon_improver.cpp:332
object_split
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
object_split(ob,nr) splits up ob into two parts.
Definition: object.cpp:2637
IMPROVE_WEIGHT
#define IMPROVE_WEIGHT
Decrease weight.
Definition: weapon_improver.cpp:221
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:359
apply_special
int apply_special(object *who, object *op, int aflags)
Apply an object.
Definition: apply.cpp:1156
UPD_NAME
#define UPD_NAME
Definition: newclient.h:321
IMPROVE_ENCHANT
#define IMPROVE_ENCHANT
Increase magic.
Definition: weapon_improver.cpp:222
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:236
METHOD_ERROR
#define METHOD_ERROR
Definition: ob_methods.h:17
WEAPON_IMPROVER
@ WEAPON_IMPROVER
Definition: object.h:238
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
object::nrof
uint32_t nrof
Number of objects.
Definition: object.h:342
ob_methods.h
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
AP_UNAPPLY
#define AP_UNAPPLY
Item is to be remvoed.
Definition: define.h:569
MAX_WEAPON_ITEM_POWER
#define MAX_WEAPON_ITEM_POWER
Maximum item power an item can have.
Definition: define.h:453
living::Pow
int8_t Pow
Definition: living.h:36
MSG_TYPE_APPLY
#define MSG_TYPE_APPLY
Applying objects.
Definition: newclient.h:411
FLAG_CURSED
#define FLAG_CURSED
The object is 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)
Return the object the player has marked with the 'mark' command below.
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)
Actually improves the weapon, and tells user.
Definition: weapon_improver.cpp:200
living::Con
int8_t Con
Definition: living.h:36
living::Str
int8_t Str
Definition: living.h:36