Crossfire Server, Branches 1.12  R18729
weapon_improver.c
Go to the documentation of this file.
1 /*
2  CrossFire, A Multiplayer game for X-windows
3 
4  Copyright (C) 2007 Mark Wedel & Crossfire Development Team
5  Copyright (C) 1992 Frank Tore Johansen
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21  The authors can be reached via e-mail at crossfire-devel@real-time.com
22 */
23 
27 #include <global.h>
28 #include <ob_methods.h>
29 #include <ob_types.h>
30 #include <sounds.h>
31 #include <sproto.h>
32 
33 static method_ret weapon_improver_type_apply(ob_methods *context, object *op, object *applier, int aflags);
34 static int check_item(object *op, const char *item);
35 static void eat_item(object *op, const char *item, uint32 nrof);
36 static int check_sacrifice(object *op, const object *improver);
37 static int improve_weapon_stat(object *op, object *improver, object *weapon, signed char *stat, int sacrifice_count, const char *statname);
38 static int prepare_weapon(object *op, object *improver, object *weapon);
39 static int improve_weapon(object *op, object *improver, object *weapon);
40 
46 }
47 
57 static method_ret weapon_improver_type_apply(ob_methods *context, object *op, object *applier, int aflags) {
58  object *oop;
59 
60  if (applier->type != PLAYER)
61  return METHOD_ERROR;
62  if (!QUERY_FLAG(applier, FLAG_WIZCAST)
63  && (get_map_flags(applier->map, NULL, applier->x, applier->y, NULL, NULL)&P_NO_MAGIC)) {
65  "Something blocks the magic of the scroll.", NULL);
66  return METHOD_ERROR;
67  }
68 
69  oop = find_marked_object(applier);
70  if (!oop) {
72  "You need to mark a weapon object.", NULL);
73  return METHOD_ERROR;
74  }
75  if (oop->type != WEAPON && oop->type != BOW) {
77  "Marked item is not a weapon or bow", NULL);
78  return METHOD_ERROR;
79  }
81  "Applied weapon builder.", NULL);
82  improve_weapon(applier, op, oop);
84  return METHOD_OK;
85 }
86 
99 static int check_item(object *op, const char *item) {
100  int count = 0;
101 
102  if (item == NULL)
103  return 0;
104  op = op->below;
105  while (op != NULL) {
106  if (strcmp(op->arch->name, item) == 0) {
107  if (!QUERY_FLAG(op, FLAG_CURSED)
108  && !QUERY_FLAG(op, FLAG_DAMNED)
109  /* Loophole bug? -FD- */ && !QUERY_FLAG(op, FLAG_UNPAID)) {
110  if (op->nrof == 0)/* this is necessary for artifact sacrifices --FD-- */
111  count++;
112  else
113  count += op->nrof;
114  }
115  }
116  op = op->below;
117  }
118  return count;
119 }
120 
137 static void eat_item(object *op, const char *item, uint32 nrof) {
138  object *prev;
139 
140  prev = op;
141  op = op->below;
142 
143  while (op != NULL) {
144  if (strcmp(op->arch->name, item) == 0) {
145  if (op->nrof >= nrof) {
146  decrease_ob_nr(op, nrof);
147  return;
148  } else {
149  decrease_ob_nr(op, op->nrof);
150  nrof -= op->nrof;
151  }
152  op = prev;
153  }
154  prev = op;
155  op = op->below;
156  }
157 }
158 
172 static int check_sacrifice(object *op, const object *improver) {
173  int count = 0;
174 
175  if (improver->slaying != NULL) {
176  count = check_item(op, improver->slaying);
177  if (count < 1) {
179  "The gods want more %ss",
180  "The gods want more %ss",
181  improver->slaying);
182  return 0;
183  }
184  } else
185  count = 1;
186 
187  return count;
188 }
189 
208 static int improve_weapon_stat(object *op, object *improver, object *weapon, signed char *stat, int sacrifice_count, const char *statname) {
209 
211  "Your sacrifice was accepted.", NULL);
212 
213  *stat += sacrifice_count;
214  weapon->last_eat++;
215 
217  "Weapon's bonus to %s improved by %d",
218  "Weapon's bonus to %s improved by %d",
219  statname, sacrifice_count);
220 
221  decrease_ob(improver);
222 
223  /* So it updates the players stats and the window */
224  fix_object(op);
225  return 1;
226 }
227 
228 /* Types of improvements, hidden in the sp field. */
229 #define IMPROVE_PREPARE 1
230 #define IMPROVE_DAMAGE 2
231 #define IMPROVE_WEIGHT 3
232 #define IMPROVE_ENCHANT 4
233 #define IMPROVE_STR 5
234 #define IMPROVE_DEX 6
235 #define IMPROVE_CON 7
236 #define IMPROVE_WIS 8
237 #define IMPROVE_CHA 9
238 #define IMPROVE_INT 10
239 #define IMPROVE_POW 11
255 static int prepare_weapon(object *op, object *improver, object *weapon) {
256  int sacrifice_count, i;
257  char buf[MAX_BUF];
258 
259  if (weapon->level != 0) {
261  "Weapon already prepared.", NULL);
262  return 0;
263  }
264  for (i = 0; i < NROFATTACKS; i++)
265  if (weapon->resist[i])
266  break;
267 
268  /* If we break out, i will be less than nrofattacks, preventing
269  * improvement of items that already have protections.
270  */
271  if (i < NROFATTACKS
272  || weapon->stats.hp /* regeneration */
273  || (weapon->stats.sp && weapon->type == WEAPON) /* sp regeneration */
274  || weapon->stats.exp /* speed */
275  || weapon->stats.ac) { /* AC - only taifu's I think */
277  "Cannot prepare magic weapons.", NULL);
278  return 0;
279  }
280 
281  sacrifice_count = check_sacrifice(op, improver);
282  if (sacrifice_count <= 0)
283  return 0;
284 
285  /* We do not allow improving stacks, so split this off from
286  * stack. Only need to do this if weapon is part of a stack.
287  * We set nrof of weapon to zero so it can not merge with other
288  * items, so one can not do further improvements on a stack.
289  * side effect of doing it before the insert_ob_in_ob is that
290  * it won't merge back in. We know from the code that marked
291  * objects must be in the players inventory, so we know where
292  * to put this.
293  */
294  if (weapon->nrof >1) {
295  weapon = get_split_ob(weapon,1, NULL, 0);
296  weapon->nrof = 0;
297  insert_ob_in_ob(weapon, op);
298  } else {
299  weapon->nrof = 0;
300  }
301 
302 
303  weapon->level = isqrt(sacrifice_count);
305  "Your sacrifice was accepted.", NULL);
306  eat_item(op, improver->slaying, sacrifice_count);
307 
308 
309  snprintf(buf, sizeof(buf), "%s's %s", op->name, weapon->name);
310  FREE_AND_COPY(weapon->name, buf);
311  FREE_AND_COPY(weapon->name_pl, buf);
312 
314  "Your %s may be improved %d times.",
315  "Your %s may be improved %d times.",
316  weapon->name, weapon->level);
317 
318  decrease_ob(improver);
319  weapon->last_eat = 0;
320  esrv_update_item(UPD_NAME | UPD_NROF, op, weapon);
321  return 1;
322 }
323 
343 static int improve_weapon(object *op, object *improver, object *weapon) {
344  int sacrifice_count, sacrifice_needed = 0;
345 
346  if (improver->stats.sp == IMPROVE_PREPARE) {
347  return prepare_weapon(op, improver, weapon);
348  }
349 
350  if (weapon->level == 0) {
352  "This weapon has not been prepared.", NULL);
353  return 0;
354  }
355 
356  if (weapon->level == weapon->last_eat && weapon->item_power >= MAX_WEAPON_ITEM_POWER) {
358  "This weapon cannot be improved any more.", NULL);
359  return 0;
360  }
361 
362  if (QUERY_FLAG(weapon, FLAG_APPLIED)
363  && !check_weapon_power(op, weapon->last_eat+1)) {
365  "Improving the weapon will make it too powerful for you to use. Unready it if you really want to improve it.", NULL);
366  return 0;
367  }
368 
369  /* All improvements add to item power, so check if player can
370  * still wear the weapon after improvement.
371  */
372  if (QUERY_FLAG(weapon, FLAG_APPLIED)
373  && op->type == PLAYER
374  && (op->contr->item_power+1) > (settings.item_power_factor*op->level)) {
375  apply_special(op, weapon, AP_UNAPPLY);
376  if (QUERY_FLAG(weapon, FLAG_APPLIED)) {
377  /* Weapon is cursed, too bad */
379  "You can't enchant this weapon without unapplying it because it would consume your soul!", NULL);
380  return 0;
381  }
382  }
383 
384  /* This just increases damage by 5 points, no matter what. No
385  * sacrifice is needed. Since stats.dam is now a 16 bit value and
386  * not 8 bit, don't put any maximum value on damage - the limit is
387  * how much the weapon can be improved.
388  */
389  if (improver->stats.sp == IMPROVE_DAMAGE) {
390  weapon->stats.dam += 5;
391  weapon->weight += 5000; /* 5 KG's */
393  "Damage has been increased by 5 to %d",
394  "Damage has been increased by 5 to %d",
395  weapon->stats.dam);
396  weapon->last_eat++;
397 
398  weapon->item_power++;
399  decrease_ob(improver);
400  return 1;
401  }
402 
403  if (improver->stats.sp == IMPROVE_WEIGHT) {
404  /* Reduce weight by 20% */
405  weapon->weight = (weapon->weight*8)/10;
406  if (weapon->weight < 1)
407  weapon->weight = 1;
409  "Weapon weight reduced to %6.1f kg",
410  "Weapon weight reduced to %6.1f kg",
411  (float)weapon->weight/1000.0);
412  weapon->last_eat++;
413  weapon->item_power++;
414  decrease_ob(improver);
415  return 1;
416  }
417 
418  if (improver->stats.sp == IMPROVE_ENCHANT) {
419  weapon->magic++;
420  weapon->last_eat++;
422  "Weapon magic increased to %d",
423  "Weapon magic increased to %d",
424  weapon->magic);
425  decrease_ob(improver);
426  weapon->item_power++;
427  return 1;
428  }
429 
430  sacrifice_needed = weapon->stats.Str
431  +weapon->stats.Int
432  +weapon->stats.Dex
433  +weapon->stats.Pow
434  +weapon->stats.Con
435  +weapon->stats.Cha
436  +weapon->stats.Wis;
437 
438  if (sacrifice_needed < 1)
439  sacrifice_needed = 1;
440  sacrifice_needed *= 2;
441 
442  sacrifice_count = check_sacrifice(op, improver);
443  if (sacrifice_count < sacrifice_needed) {
445  "You need at least %d %s",
446  "You need at least %d %s",
447  sacrifice_needed, improver->slaying);
448  return 0;
449  }
450  eat_item(op, improver->slaying, sacrifice_needed);
451  weapon->item_power++;
452 
453  switch (improver->stats.sp) {
454  case IMPROVE_STR:
455  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Str), 1, "strength");
456 
457  case IMPROVE_DEX:
458  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Dex), 1, "dexterity");
459 
460  case IMPROVE_CON:
461  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Con), 1, "constitution");
462 
463  case IMPROVE_WIS:
464  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Wis), 1, "wisdom");
465 
466  case IMPROVE_CHA:
467  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Cha), 1, "charisma");
468 
469  case IMPROVE_INT:
470  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Int), 1, "intelligence");
471 
472  case IMPROVE_POW:
473  return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Pow), 1, "power");
474 
475  default:
477  "Unknown improvement type.", NULL);
478  }
479 
480  LOG(llevError, "improve_weapon: Got to end of function\n");
481  return 0;
482 }
#define AP_UNAPPLY
Definition: define.h:1010
#define UPD_FLAGS
Definition: newclient.h:255
int get_map_flags(mapstruct *oldmap, mapstruct **newmap, sint16 x, sint16 y, sint16 *nx, sint16 *ny)
Definition: map.c:330
sint8 Int
Definition: living.h:78
int apply_special(object *who, object *op, int aflags)
Definition: apply.c:1139
#define FLAG_DAMNED
Definition: define.h:614
#define FLAG_UNPAID
Definition: define.h:532
#define IMPROVE_INT
#define UPD_NAME
Definition: newclient.h:258
#define METHOD_ERROR
Definition: ob_methods.h:44
#define P_NO_MAGIC
Definition: map.h:248
#define IMPROVE_WEIGHT
void esrv_update_item(int flags, object *pl, object *op)
Definition: standalone.c:200
static int improve_weapon(object *op, object *improver, object *weapon)
void draw_ext_info(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *message, const char *oldmessage)
Definition: standalone.c:171
const char * slaying
Definition: object.h:172
#define IMPROVE_ENCHANT
#define IMPROVE_PREPARE
static int prepare_weapon(object *op, object *improver, object *weapon)
sint16 x
Definition: object.h:179
sint16 sp
Definition: living.h:83
#define IMPROVE_CHA
void init_type_weapon_improver(void)
#define IMPROVE_WIS
void draw_ext_info_format(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *new_format, const char *old_format,...)
Definition: standalone.c:175
#define PLAYER
Definition: define.h:113
sint8 Con
Definition: living.h:78
char method_ret
Definition: ob_methods.h:41
static int check_sacrifice(object *op, const object *improver)
#define IMPROVE_CON
#define IMPROVE_DAMAGE
#define WEAPON_IMPROVER
Definition: define.h:308
sint32 weight
Definition: object.h:216
#define IMPROVE_POW
#define METHOD_OK
Definition: ob_methods.h:42
const char *const statname[NUM_STATS]
Definition: living.c:273
sint8 Wis
Definition: living.h:78
static void eat_item(object *op, const char *item, uint32 nrof)
sint16 item_power
Definition: player.h:171
struct mapdef * map
Definition: object.h:155
sint16 dam
Definition: living.h:87
struct obj * below
Definition: object.h:145
#define MAX_WEAPON_ITEM_POWER
Definition: define.h:768
uint32 nrof
Definition: object.h:184
sint8 Cha
Definition: living.h:78
sint16 y
Definition: object.h:179
void register_apply(int ob_type, apply_func method)
Definition: ob_types.c:79
struct pl * contr
Definition: object.h:134
sint8 item_power
Definition: object.h:213
#define WEAPON
Definition: define.h:127
#define UPD_NROF
Definition: newclient.h:261
object * find_marked_object(object *op)
Definition: c_object.c:1339
#define QUERY_FLAG(xyz, p)
Definition: define.h:514
#define MSG_TYPE_APPLY
Definition: newclient.h:330
object * insert_ob_in_ob(object *op, object *where)
Definition: object.c:2510
#define MAX_BUF
Definition: define.h:81
sint32 last_eat
Definition: object.h:207
sint8 Str
Definition: living.h:78
#define FLAG_CURSED
Definition: define.h:613
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
#define decrease_ob(xyz)
Definition: global.h:276
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:518
#define FREE_AND_COPY(sv, nv)
Definition: global.h:288
living stats
Definition: object.h:219
#define FLAG_WIZCAST
Definition: define.h:586
sint8 Dex
Definition: living.h:78
struct archt * arch
Definition: object.h:263
object * decrease_ob_nr(object *op, uint32 i)
Definition: object.c:2345
#define IMPROVE_DEX
struct Settings settings
Definition: init.c:48
int isqrt(int n)
Definition: porting.c:573
#define FLAG_APPLIED
Definition: define.h:531
#define NROFATTACKS
Definition: attack.h:45
#define MSG_TYPE_APPLY_ERROR
Definition: newclient.h:516
int check_weapon_power(const object *who, int improvs)
Definition: apply.c:1076
#define BOW
Definition: define.h:126
sint8 Pow
Definition: living.h:78
#define NDI_UNIQUE
Definition: newclient.h:219
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
object * get_split_ob(object *orig_ob, uint32 nr, char *err, size_t size)
Definition: object.c:2313
unsigned int uint32
Definition: global.h:58
static method_ret weapon_improver_type_apply(ob_methods *context, object *op, object *applier, int aflags)
static int check_item(object *op, const char *item)
sint16 level
Definition: object.h:202
void fix_object(object *op)
Definition: living.c:900
#define IMPROVE_STR
sint8 magic
Definition: object.h:199
float item_power_factor
Definition: global.h:392
const char * name
Definition: object.h:322
uint8 type
Definition: object.h:189
static int improve_weapon_stat(object *op, object *improver, object *weapon, signed char *stat, int sacrifice_count, const char *statname)