00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00027 #include <global.h>
00028 #include <ob_methods.h>
00029 #include <ob_types.h>
00030 #include <sounds.h>
00031 #include <sproto.h>
00032
00033 static method_ret weapon_improver_type_apply(ob_methods *context, object *op, object *applier, int aflags);
00034 static int check_item(object *op, const char *item);
00035 static void eat_item(object *op, const char *item, uint32 nrof);
00036 static int check_sacrifice(object *op, const object *improver);
00037 static int improve_weapon_stat(object *op, object *improver, object *weapon, signed char *stat, int sacrifice_count, const char *statname);
00038 static int prepare_weapon(object *op, object *improver, object *weapon);
00039 static int improve_weapon(object *op, object *improver, object *weapon);
00040
00044 void init_type_weapon_improver(void) {
00045 register_apply(WEAPON_IMPROVER, weapon_improver_type_apply);
00046 }
00047
00057 static method_ret weapon_improver_type_apply(ob_methods *context, object *op, object *applier, int aflags) {
00058 object *oop;
00059
00060 if (applier->type != PLAYER)
00061 return METHOD_ERROR;
00062 if (!QUERY_FLAG(applier, FLAG_WIZCAST)
00063 && (get_map_flags(applier->map, NULL, applier->x, applier->y, NULL, NULL)&P_NO_MAGIC)) {
00064 draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00065 "Something blocks the magic of the scroll.", NULL);
00066 return METHOD_ERROR;
00067 }
00068
00069 oop = find_marked_object(applier);
00070 if (!oop) {
00071 draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00072 "You need to mark a weapon object.", NULL);
00073 return METHOD_ERROR;
00074 }
00075 if (oop->type != WEAPON && oop->type != BOW) {
00076 draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00077 "Marked item is not a weapon or bow", NULL);
00078 return METHOD_ERROR;
00079 }
00080 draw_ext_info(NDI_UNIQUE, 0, applier, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00081 "Applied weapon builder.", NULL);
00082 improve_weapon(applier, op, oop);
00083 esrv_update_item(UPD_NAME|UPD_NROF|UPD_FLAGS, applier, oop);
00084 return METHOD_OK;
00085 }
00086
00099 static int check_item(object *op, const char *item) {
00100 int count = 0;
00101
00102 if (item == NULL)
00103 return 0;
00104 op = op->below;
00105 while (op != NULL) {
00106 if (strcmp(op->arch->name, item) == 0) {
00107 if (!QUERY_FLAG(op, FLAG_CURSED)
00108 && !QUERY_FLAG(op, FLAG_DAMNED)
00109 && !QUERY_FLAG(op, FLAG_UNPAID)) {
00110 if (op->nrof == 0)
00111 count++;
00112 else
00113 count += op->nrof;
00114 }
00115 }
00116 op = op->below;
00117 }
00118 return count;
00119 }
00120
00137 static void eat_item(object *op, const char *item, uint32 nrof) {
00138 object *prev;
00139
00140 prev = op;
00141 op = op->below;
00142
00143 while (op != NULL) {
00144 if (strcmp(op->arch->name, item) == 0) {
00145 if (op->nrof >= nrof) {
00146 decrease_ob_nr(op, nrof);
00147 return;
00148 } else {
00149 decrease_ob_nr(op, op->nrof);
00150 nrof -= op->nrof;
00151 }
00152 op = prev;
00153 }
00154 prev = op;
00155 op = op->below;
00156 }
00157 }
00158
00172 static int check_sacrifice(object *op, const object *improver) {
00173 int count = 0;
00174
00175 if (improver->slaying != NULL) {
00176 count = check_item(op, improver->slaying);
00177 if (count < 1) {
00178 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00179 "The gods want more %ss",
00180 "The gods want more %ss",
00181 improver->slaying);
00182 return 0;
00183 }
00184 } else
00185 count = 1;
00186
00187 return count;
00188 }
00189
00208 static int improve_weapon_stat(object *op, object *improver, object *weapon, signed char *stat, int sacrifice_count, const char *statname) {
00209
00210 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00211 "Your sacrifice was accepted.", NULL);
00212
00213 *stat += sacrifice_count;
00214 weapon->last_eat++;
00215
00216 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00217 "Weapon's bonus to %s improved by %d",
00218 "Weapon's bonus to %s improved by %d",
00219 statname, sacrifice_count);
00220
00221 decrease_ob(improver);
00222
00223
00224 fix_object(op);
00225 return 1;
00226 }
00227
00228
00229 #define IMPROVE_PREPARE 1
00230 #define IMPROVE_DAMAGE 2
00231 #define IMPROVE_WEIGHT 3
00232 #define IMPROVE_ENCHANT 4
00233 #define IMPROVE_STR 5
00234 #define IMPROVE_DEX 6
00235 #define IMPROVE_CON 7
00236 #define IMPROVE_WIS 8
00237 #define IMPROVE_CHA 9
00238 #define IMPROVE_INT 10
00239 #define IMPROVE_POW 11
00255 static int prepare_weapon(object *op, object *improver, object *weapon) {
00256 int sacrifice_count, i;
00257 char buf[MAX_BUF];
00258
00259 if (weapon->level != 0) {
00260 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00261 "Weapon already prepared.", NULL);
00262 return 0;
00263 }
00264 for (i = 0; i < NROFATTACKS; i++)
00265 if (weapon->resist[i])
00266 break;
00267
00268
00269
00270
00271 if (i < NROFATTACKS
00272 || weapon->stats.hp
00273 || (weapon->stats.sp && weapon->type == WEAPON)
00274 || weapon->stats.exp
00275 || weapon->stats.ac) {
00276 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00277 "Cannot prepare magic weapons.", NULL);
00278 return 0;
00279 }
00280
00281 sacrifice_count = check_sacrifice(op, improver);
00282 if (sacrifice_count <= 0)
00283 return 0;
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294 if (weapon->nrof >1) {
00295 weapon = get_split_ob(weapon,1, NULL, 0);
00296 weapon->nrof = 0;
00297 insert_ob_in_ob(weapon, op);
00298 } else {
00299 weapon->nrof = 0;
00300 }
00301
00302
00303 weapon->level = isqrt(sacrifice_count);
00304 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00305 "Your sacrifice was accepted.", NULL);
00306 eat_item(op, improver->slaying, sacrifice_count);
00307
00308
00309 snprintf(buf, sizeof(buf), "%s's %s", op->name, weapon->name);
00310 FREE_AND_COPY(weapon->name, buf);
00311 FREE_AND_COPY(weapon->name_pl, buf);
00312
00313 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00314 "Your %s may be improved %d times.",
00315 "Your %s may be improved %d times.",
00316 weapon->name, weapon->level);
00317
00318 decrease_ob(improver);
00319 weapon->last_eat = 0;
00320 esrv_update_item(UPD_NAME | UPD_NROF, op, weapon);
00321 return 1;
00322 }
00323
00343 static int improve_weapon(object *op, object *improver, object *weapon) {
00344 int sacrifice_count, sacrifice_needed = 0;
00345
00346 if (improver->stats.sp == IMPROVE_PREPARE) {
00347 return prepare_weapon(op, improver, weapon);
00348 }
00349
00350 if (weapon->level == 0) {
00351 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00352 "This weapon has not been prepared.", NULL);
00353 return 0;
00354 }
00355
00356 if (weapon->level == weapon->last_eat && weapon->item_power >= MAX_WEAPON_ITEM_POWER) {
00357 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00358 "This weapon cannot be improved any more.", NULL);
00359 return 0;
00360 }
00361
00362 if (QUERY_FLAG(weapon, FLAG_APPLIED)
00363 && !check_weapon_power(op, weapon->last_eat+1)) {
00364 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00365 "Improving the weapon will make it too powerful for you to use. Unready it if you really want to improve it.", NULL);
00366 return 0;
00367 }
00368
00369
00370
00371
00372 if (QUERY_FLAG(weapon, FLAG_APPLIED)
00373 && op->type == PLAYER
00374 && (op->contr->item_power+1) > (settings.item_power_factor*op->level)) {
00375 apply_special(op, weapon, AP_UNAPPLY);
00376 if (QUERY_FLAG(weapon, FLAG_APPLIED)) {
00377
00378 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00379 "You can't enchant this weapon without unapplying it because it would consume your soul!", NULL);
00380 return 0;
00381 }
00382 }
00383
00384
00385
00386
00387
00388
00389 if (improver->stats.sp == IMPROVE_DAMAGE) {
00390 weapon->stats.dam += 5;
00391 weapon->weight += 5000;
00392 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00393 "Damage has been increased by 5 to %d",
00394 "Damage has been increased by 5 to %d",
00395 weapon->stats.dam);
00396 weapon->last_eat++;
00397
00398 weapon->item_power++;
00399 decrease_ob(improver);
00400 return 1;
00401 }
00402
00403 if (improver->stats.sp == IMPROVE_WEIGHT) {
00404
00405 weapon->weight = (weapon->weight*8)/10;
00406 if (weapon->weight < 1)
00407 weapon->weight = 1;
00408 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00409 "Weapon weight reduced to %6.1f kg",
00410 "Weapon weight reduced to %6.1f kg",
00411 (float)weapon->weight/1000.0);
00412 weapon->last_eat++;
00413 weapon->item_power++;
00414 decrease_ob(improver);
00415 return 1;
00416 }
00417
00418 if (improver->stats.sp == IMPROVE_ENCHANT) {
00419 weapon->magic++;
00420 weapon->last_eat++;
00421 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_SUCCESS,
00422 "Weapon magic increased to %d",
00423 "Weapon magic increased to %d",
00424 weapon->magic);
00425 decrease_ob(improver);
00426 weapon->item_power++;
00427 return 1;
00428 }
00429
00430 sacrifice_needed = weapon->stats.Str
00431 +weapon->stats.Int
00432 +weapon->stats.Dex
00433 +weapon->stats.Pow
00434 +weapon->stats.Con
00435 +weapon->stats.Cha
00436 +weapon->stats.Wis;
00437
00438 if (sacrifice_needed < 1)
00439 sacrifice_needed = 1;
00440 sacrifice_needed *= 2;
00441
00442 sacrifice_count = check_sacrifice(op, improver);
00443 if (sacrifice_count < sacrifice_needed) {
00444 draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00445 "You need at least %d %s",
00446 "You need at least %d %s",
00447 sacrifice_needed, improver->slaying);
00448 return 0;
00449 }
00450 eat_item(op, improver->slaying, sacrifice_needed);
00451 weapon->item_power++;
00452
00453 switch (improver->stats.sp) {
00454 case IMPROVE_STR:
00455 return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Str), 1, "strength");
00456
00457 case IMPROVE_DEX:
00458 return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Dex), 1, "dexterity");
00459
00460 case IMPROVE_CON:
00461 return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Con), 1, "constitution");
00462
00463 case IMPROVE_WIS:
00464 return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Wis), 1, "wisdom");
00465
00466 case IMPROVE_CHA:
00467 return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Cha), 1, "charisma");
00468
00469 case IMPROVE_INT:
00470 return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Int), 1, "intelligence");
00471
00472 case IMPROVE_POW:
00473 return improve_weapon_stat(op, improver, weapon, (signed char *)&(weapon->stats.Pow), 1, "power");
00474
00475 default:
00476 draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_APPLY, MSG_TYPE_APPLY_ERROR,
00477 "Unknown improvement type.", NULL);
00478 }
00479
00480 LOG(llevError, "improve_weapon: Got to end of function\n");
00481 return 0;
00482 }