|
Atrinik Server 2.5
|
00001 /************************************************************************ 00002 * Atrinik, a Multiplayer Online Role Playing Game * 00003 * * 00004 * Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team * 00005 * * 00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game) * 00007 * and Crossfire (Multiplayer game for X-windows). * 00008 * * 00009 * This program is free software; you can redistribute it and/or modify * 00010 * it under the terms of the GNU General Public License as published by * 00011 * the Free Software Foundation; either version 2 of the License, or * 00012 * (at your option) any later version. * 00013 * * 00014 * This program is distributed in the hope that it will be useful, * 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 00017 * GNU General Public License for more details. * 00018 * * 00019 * You should have received a copy of the GNU General Public License * 00020 * along with this program; if not, write to the Free Software * 00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * 00022 * * 00023 * The author can be reached at admin@atrinik.org * 00024 ************************************************************************/ 00025 00032 #include <global.h> 00033 00040 #define IMPROVE_PREPARE 1 00041 00042 #define IMPROVE_DAMAGE 2 00043 00044 #define IMPROVE_WEIGHT 3 00045 00046 #define IMPROVE_ENCHANT 4 00047 00048 #define IMPROVE_STR 5 00049 00050 #define IMPROVE_DEX 6 00051 00052 #define IMPROVE_CON 7 00053 00054 #define IMPROVE_WIS 8 00055 00056 #define IMPROVE_CHA 9 00057 00058 #define IMPROVE_INT 10 00059 00060 #define IMPROVE_POW 11 00061 00063 static int improve_weapon_stat(object *op, object *improver, object *weapon, signed char *stat, int sacrifice_count, char *statname); 00064 static int prepare_weapon(object *op, object *improver, object *weapon); 00065 static int improve_weapon(object *op, object *improver, object *weapon); 00066 static void eat_item(object *op, const char *item); 00067 static int check_item(object *op, const char *item); 00068 static int check_sacrifice(object *op, object *improver); 00069 00074 void apply_weapon_improver(object *op, object *tmp) 00075 { 00076 object *otmp; 00077 00078 if (op->type != PLAYER) 00079 { 00080 return; 00081 } 00082 00083 if (blocks_magic(op->map, op->x, op->y)) 00084 { 00085 new_draw_info(0, COLOR_WHITE, op, "Something blocks the magic of the scroll."); 00086 return; 00087 } 00088 00089 otmp = find_marked_object(op); 00090 00091 if (!otmp || otmp->type != WEAPON) 00092 { 00093 new_draw_info(0, COLOR_WHITE, op, "You need to mark a weapon object."); 00094 return; 00095 } 00096 00097 new_draw_info(0, COLOR_WHITE, op, "Applied weapon builder."); 00098 improve_weapon(op, tmp, otmp); 00099 esrv_send_item(op, otmp); 00100 } 00101 00112 int check_weapon_power(object *who, int improvs) 00113 { 00114 int level = who->level; 00115 00116 /* The skill system hands out wc and dam bonuses to fighters 00117 * more generously than the old system (see fix_player). Thus 00118 * we need to curtail the power of player enchanted weapons. 00119 * I changed this to 1 improvement per "fighter" level/5 -b.t. 00120 * Note: Nothing should break by allowing this ratio to be different or 00121 * using normal level - it is just a matter of play balance. */ 00122 if (who->type == PLAYER) 00123 { 00124 object *wc_obj = NULL; 00125 00126 for (wc_obj = who->inv; wc_obj; wc_obj = wc_obj->below) 00127 { 00128 if (wc_obj->type == EXPERIENCE && wc_obj->stats.Str) 00129 { 00130 break; 00131 } 00132 } 00133 00134 if (!wc_obj) 00135 { 00136 LOG(llevBug, "Player: %s lacks wc experience object.\n", who->name); 00137 } 00138 else 00139 { 00140 level = wc_obj->level; 00141 } 00142 } 00143 00144 return (improvs <= ((level / 5) + 5)); 00145 } 00146 00156 static int improve_weapon_stat(object *op, object *improver, object *weapon, signed char *stat_id, int sacrifice_count, char *stat_name) 00157 { 00158 new_draw_info(0, COLOR_WHITE, op, "Your sacrifice was accepted."); 00159 *stat_id += sacrifice_count; 00160 weapon->last_eat++; 00161 new_draw_info_format(0, COLOR_WHITE, op, "Weapon's bonus to %s improved by %d.", stat_name, sacrifice_count); 00162 decrease_ob(improver); 00163 00164 /* So it updates the players stats and the window */ 00165 fix_player(op); 00166 return 1; 00167 } 00168 00178 static int prepare_weapon(object *op, object *improver, object *weapon) 00179 { 00180 int sacrifice_count, i; 00181 char buf[MAX_BUF]; 00182 00183 if (weapon->level != 0) 00184 { 00185 new_draw_info(0, COLOR_WHITE, op, "Weapon already prepared."); 00186 return 0; 00187 } 00188 00189 for (i = 0; i < NROFATTACKS; i++) 00190 { 00191 if (weapon->protection[i]) 00192 { 00193 break; 00194 } 00195 } 00196 00197 /* If we break out, i will be less than nrofattacks, preventing 00198 * improvement of items that already have protections. */ 00199 if (i < NROFATTACKS || weapon->stats.hp || weapon->stats.sp || weapon->stats.exp || weapon->stats.ac) 00200 { 00201 new_draw_info(0, COLOR_WHITE, op, "Cannot prepare magic weapons."); 00202 return 0; 00203 } 00204 00205 sacrifice_count = check_sacrifice(op, improver); 00206 00207 if (sacrifice_count <= 0) 00208 { 00209 return 0; 00210 } 00211 00212 sacrifice_count = isqrt(sacrifice_count); 00213 weapon->level = sacrifice_count; 00214 new_draw_info(0, COLOR_WHITE, op, "Your sacrifice was accepted."); 00215 eat_item(op, improver->slaying); 00216 new_draw_info_format(0, COLOR_WHITE, op, "Your *%s may be improved %d times.", weapon->name, sacrifice_count); 00217 snprintf(buf, sizeof(buf), "%s's %s", op->name, weapon->name); 00218 FREE_AND_COPY_HASH(weapon->name, buf); 00219 00220 /* prevents preparing n weapons in the same slot at once! */ 00221 weapon->nrof = 0; 00222 decrease_ob(improver); 00223 weapon->last_eat = 0; 00224 return 1; 00225 } 00226 00241 static int improve_weapon(object *op, object *improver, object *weapon) 00242 { 00243 int sacrifice_count, sacrifice_needed = 0; 00244 00245 if (improver->stats.sp == IMPROVE_PREPARE) 00246 { 00247 return prepare_weapon(op, improver, weapon); 00248 } 00249 00250 if (weapon->level==0) 00251 { 00252 new_draw_info(0, COLOR_WHITE, op, "This weapon has not been prepared."); 00253 return 0; 00254 } 00255 00256 if (weapon->level == weapon->last_eat) 00257 { 00258 new_draw_info(0, COLOR_WHITE, op, "This weapon cannot be improved any more."); 00259 return 0; 00260 } 00261 00262 if (QUERY_FLAG(weapon, FLAG_APPLIED) && !check_weapon_power(op, weapon->last_eat + 1)) 00263 { 00264 new_draw_info(0, COLOR_WHITE, op, "Improving the weapon will make it too powerful for you to use.\nUnready it if you really want to improve it."); 00265 return 0; 00266 } 00267 00268 /* This just increases damage by 5 points, no matter what. No sacrifice 00269 * is needed. Since stats.dam is now a 16 bit value and not 8 bit, 00270 * don't put any maximum value on damage - the limit is how much the 00271 * weapon can be improved. */ 00272 if (improver->stats.sp == IMPROVE_DAMAGE) 00273 { 00274 weapon->stats.dam += 5; 00275 /* 5 KG's */ 00276 weapon->weight += 5000; 00277 new_draw_info_format(0, COLOR_WHITE, op, "Damage has been increased by 5 to %d", weapon->stats.dam); 00278 weapon->last_eat++; 00279 decrease_ob(improver); 00280 00281 return 1; 00282 } 00283 00284 if (improver->stats.sp == IMPROVE_WEIGHT) 00285 { 00286 /* Reduce weight by 20% */ 00287 weapon->weight = (weapon->weight * 8) / 10; 00288 00289 if (weapon->weight < 1) 00290 { 00291 weapon->weight = 1; 00292 } 00293 00294 new_draw_info_format(0, COLOR_WHITE, op, "Weapon weight reduced to %6.1f kg", (float)weapon->weight / 1000.0); 00295 weapon->last_eat++; 00296 decrease_ob(improver); 00297 return 1; 00298 } 00299 00300 if (improver->stats.sp == IMPROVE_ENCHANT) 00301 { 00302 weapon->magic++; 00303 weapon->last_eat++; 00304 new_draw_info_format(0, COLOR_WHITE, op, "Weapon magic increased to %d", weapon->magic); 00305 decrease_ob(improver); 00306 return 1; 00307 } 00308 00309 sacrifice_needed = weapon->stats.Str + weapon->stats.Int + weapon->stats.Dex + weapon->stats.Pow + weapon->stats.Con + weapon->stats.Cha + weapon->stats.Wis; 00310 00311 if (sacrifice_needed < 1) 00312 { 00313 sacrifice_needed = 1; 00314 } 00315 00316 sacrifice_needed *= 2; 00317 00318 sacrifice_count = check_sacrifice(op, improver); 00319 00320 if (sacrifice_count < sacrifice_needed) 00321 { 00322 new_draw_info_format(0, COLOR_WHITE, op, "You need at least %d %s", sacrifice_needed, improver->slaying); 00323 return 0; 00324 } 00325 00326 eat_item(op, improver->slaying); 00327 00328 switch (improver->stats.sp) 00329 { 00330 case IMPROVE_STR: 00331 return improve_weapon_stat(op, improver, weapon, (signed char *) &(weapon->stats.Str), 1, "strength"); 00332 00333 case IMPROVE_DEX: 00334 return improve_weapon_stat(op, improver, weapon, (signed char *) &(weapon->stats.Dex), 1, "dexterity"); 00335 00336 case IMPROVE_CON: 00337 return improve_weapon_stat(op, improver, weapon, (signed char *) &(weapon->stats.Con), 1, "constitution"); 00338 00339 case IMPROVE_WIS: 00340 return improve_weapon_stat(op, improver, weapon, (signed char *) &(weapon->stats.Wis), 1, "wisdom"); 00341 00342 case IMPROVE_CHA: 00343 return improve_weapon_stat(op, improver, weapon, (signed char *) &(weapon->stats.Cha), 1, "charisma"); 00344 00345 case IMPROVE_INT: 00346 return improve_weapon_stat(op, improver, weapon, (signed char *) &(weapon->stats.Int), 1, "intelligence"); 00347 00348 case IMPROVE_POW: 00349 return improve_weapon_stat(op, improver, weapon, (signed char *) &(weapon->stats.Pow), 1, "power"); 00350 00351 default: 00352 new_draw_info(0, COLOR_WHITE, op, "Unknown improvement type."); 00353 } 00354 00355 LOG(llevBug, "improve_weapon(): Got to end of function!\n"); 00356 00357 return 0; 00358 } 00359 00364 static void eat_item(object *op, const char *item) 00365 { 00366 object *prev = op; 00367 00368 op = op->below; 00369 00370 while (op != NULL) 00371 { 00372 if (strcmp(op->arch->name, item) == 0) 00373 { 00374 decrease_ob_nr(op, op->nrof); 00375 op = prev; 00376 } 00377 00378 prev = op; 00379 op = op->below; 00380 } 00381 } 00382 00390 static int check_item(object *op, const char *item) 00391 { 00392 int count = 0; 00393 00394 if (item == NULL) 00395 { 00396 return 0; 00397 } 00398 00399 op = op->below; 00400 00401 while (op != NULL) 00402 { 00403 if (strcmp(op->arch->name, item) == 0) 00404 { 00405 if (!QUERY_FLAG(op, FLAG_CURSED) && !QUERY_FLAG(op, FLAG_DAMNED) && !QUERY_FLAG(op, FLAG_UNPAID)) 00406 { 00407 /* this is necessary for artifact sacrifices --FD-- */ 00408 if (op->nrof == 0) 00409 { 00410 count++; 00411 } 00412 else 00413 { 00414 count += op->nrof; 00415 } 00416 } 00417 } 00418 00419 op = op->below; 00420 } 00421 00422 return count; 00423 } 00424 00432 static int check_sacrifice(object *op, object *improver) 00433 { 00434 int count = 0; 00435 00436 if (improver->slaying != NULL) 00437 { 00438 count = check_item(op, improver->slaying); 00439 00440 if (count < 1) 00441 { 00442 new_draw_info_format(0, COLOR_WHITE, op, "The gods want more %ss.", improver->slaying); 00443 return 0; 00444 } 00445 } 00446 else 00447 { 00448 count = 1; 00449 } 00450 00451 return count; 00452 }
1.7.4