Changeset 400
- Timestamp:
- 07/28/07 17:05:56 (1 year ago)
- Files:
-
- trunk/src/Makefile.src (modified) (1 diff)
- trunk/src/attack.c (added)
- trunk/src/cmd1.c (modified) (2 diffs)
- trunk/src/cmd2.c (modified) (1 diff)
- trunk/src/cmds.h (modified) (1 diff)
- trunk/src/externs.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/src/Makefile.src
r399 r400 19 19 20 20 ANGFILES = \ 21 attack.o \ 21 22 birth.o \ 22 23 cave.o \ trunk/src/cmd1.c
r399 r400 13 13 14 14 15 /*16 * Determine if the player "hits" a monster.17 *18 * Note -- Always miss 5%, always hit 5%, otherwise random.19 */20 bool test_hit(int chance, int ac, int vis)21 {22 int k;23 24 /* Percentile dice */25 k = rand_int(100);26 27 /* Hack -- Instant miss or hit */28 if (k < 10) return (k < 5);29 30 /* Penalize invisible targets */31 if (!vis) chance = chance / 2;32 33 /* Power competes against armor */34 if ((chance > 0) && (rand_int(chance) >= (ac * 3 / 4))) return (TRUE);35 36 /* Assume miss */37 return (FALSE);38 }39 40 41 42 /*43 * Critical hits (from objects thrown by player)44 * Factor in item weight, total plusses, and player level.45 */46 int critical_shot(int weight, int plus, int dam)47 {48 int i, k;49 50 /* Extract "shot" power */51 i = (weight + ((p_ptr->to_h + plus) * 4) + (p_ptr->lev * 2));52 53 /* Critical hit */54 if (randint(5000) <= i)55 {56 k = weight + randint(500);57 58 if (k < 500)59 {60 msg_print("It was a good hit!");61 dam = 2 * dam + 5;62 }63 else if (k < 1000)64 {65 msg_print("It was a great hit!");66 dam = 2 * dam + 10;67 }68 else69 {70 msg_print("It was a superb hit!");71 dam = 3 * dam + 15;72 }73 }74 75 return (dam);76 }77 78 79 80 /*81 * Critical hits (by player)82 *83 * Factor in weapon weight, total plusses, player level.84 */85 int critical_norm(int weight, int plus, int dam)86 {87 int i, k;88 89 /* Extract "blow" power */90 i = (weight + ((p_ptr->to_h + plus) * 5) + (p_ptr->lev * 3));91 92 /* Chance */93 if (randint(5000) <= i)94 {95 k = weight + randint(650);96 97 if (k < 400)98 {99 sound(MSG_HIT_GOOD);100 msg_print("It was a good hit!");101 dam = 2 * dam + 5;102 }103 else if (k < 700)104 {105 sound(MSG_HIT_GREAT);106 msg_print("It was a great hit!");107 dam = 2 * dam + 10;108 }109 else if (k < 900)110 {111 sound(MSG_HIT_SUPERB);112 msg_print("It was a superb hit!");113 dam = 3 * dam + 15;114 }115 else if (k < 1300)116 {117 sound(MSG_HIT_HI_GREAT);118 msg_print("It was a *GREAT* hit!");119 dam = 3 * dam + 20;120 }121 else122 {123 sound(MSG_HIT_HI_SUPERB);124 msg_print("It was a *SUPERB* hit!");125 dam = ((7 * dam) / 2) + 25;126 }127 }128 else129 {130 sound(MSG_HIT);131 }132 133 return (dam);134 }135 136 137 138 /*139 * Extract the "total damage" from a given object hitting a given monster.140 *141 * Note that "flasks of oil" do NOT do fire damage, although they142 * certainly could be made to do so. XXX XXX143 *144 * Note that most brands and slays are x3, except Slay Animal (x2),145 * Slay Evil (x2), and Kill dragon (x5).146 */147 int tot_dam_aux(const object_type *o_ptr, int tdam, const monster_type *m_ptr)148 {149 int mult = 1;150 151 monster_race *r_ptr = &r_info[m_ptr->r_idx];152 monster_lore *l_ptr = &l_list[m_ptr->r_idx];153 154 u32b f1, f2, f3;155 156 /* Extract the flags */157 object_flags(o_ptr, &f1, &f2, &f3);158 159 /* Some "weapons" and "ammo" do extra damage */160 switch (o_ptr->tval)161 {162 case TV_SHOT:163 case TV_ARROW:164 case TV_BOLT:165 case TV_HAFTED:166 case TV_POLEARM:167 case TV_SWORD:168 case TV_DIGGING:169 {170 /* Slay Animal */171 if ((f1 & (TR1_SLAY_ANIMAL)) &&172 (r_ptr->flags3 & (RF3_ANIMAL)))173 {174 if (m_ptr->ml)175 {176 l_ptr->flags3 |= (RF3_ANIMAL);177 }178 179 if (mult < 2) mult = 2;180 }181 182 /* Slay Evil */183 if ((f1 & (TR1_SLAY_EVIL)) &&184 (r_ptr->flags3 & (RF3_EVIL)))185 {186 if (m_ptr->ml)187 {188 l_ptr->flags3 |= (RF3_EVIL);189 }190 191 if (mult < 2) mult = 2;192 }193 194 /* Slay Undead */195 if ((f1 & (TR1_SLAY_UNDEAD)) &&196 (r_ptr->flags3 & (RF3_UNDEAD)))197 {198 if (m_ptr->ml)199 {200 l_ptr->flags3 |= (RF3_UNDEAD);201 }202 203 if (mult < 3) mult = 3;204 }205 206 /* Slay Demon */207 if ((f1 & (TR1_SLAY_DEMON)) &&208 (r_ptr->flags3 & (RF3_DEMON)))209 {210 if (m_ptr->ml)211 {212 l_ptr->flags3 |= (RF3_DEMON);213 }214 215 if (mult < 3) mult = 3;216 }217 218 /* Slay Orc */219 if ((f1 & (TR1_SLAY_ORC)) &&220 (r_ptr->flags3 & (RF3_ORC)))221 {222 if (m_ptr->ml)223 {224 l_ptr->flags3 |= (RF3_ORC);225 }226 227 if (mult < 3) mult = 3;228 }229 230 /* Slay Troll */231 if ((f1 & (TR1_SLAY_TROLL)) &&232 (r_ptr->flags3 & (RF3_TROLL)))233 {234 if (m_ptr->ml)235 {236 l_ptr->flags3 |= (RF3_TROLL);237 }238 239 if (mult < 3) mult = 3;240 }241 242 /* Slay Giant */243 if ((f1 & (TR1_SLAY_GIANT)) &&244 (r_ptr->flags3 & (RF3_GIANT)))245 {246 if (m_ptr->ml)247 {248 l_ptr->flags3 |= (RF3_GIANT);249 }250 251 if (mult < 3) mult = 3;252 }253 254 /* Slay Dragon */255 if ((f1 & (TR1_SLAY_DRAGON)) &&256 (r_ptr->flags3 & (RF3_DRAGON)))257 {258 if (m_ptr->ml)259 {260 l_ptr->flags3 |= (RF3_DRAGON);261 }262 263 if (mult < 3) mult = 3;264 }265 266 /* Execute Dragon */267 if ((f1 & (TR1_KILL_DRAGON)) &&268 (r_ptr->flags3 & (RF3_DRAGON)))269 {270 if (m_ptr->ml)271 {272 l_ptr->flags3 |= (RF3_DRAGON);273 }274 275 if (mult < 5) mult = 5;276 }277 278 /* Execute demon */279 if ((f1 & (TR1_KILL_DEMON)) &&280 (r_ptr->flags3 & (RF3_DEMON)))281 {282 if (m_ptr->ml)283 {284 l_ptr->flags3 |= (RF3_DEMON);285 }286 287 if (mult < 5) mult = 5;288 }289 290 /* Execute undead */291 if ((f1 & (TR1_KILL_UNDEAD)) &&292 (r_ptr->flags3 & (RF3_UNDEAD)))293 {294 if (m_ptr->ml)295 {296 l_ptr->flags3 |= (RF3_UNDEAD);297 }298 299 if (mult < 5) mult = 5;300 }301 302 /* Brand (Acid) */303 if (f1 & (TR1_BRAND_ACID))304 {305 /* Notice immunity */306 if (r_ptr->flags3 & (RF3_IM_ACID))307 {308 if (m_ptr->ml)309 {310 l_ptr->flags3 |= (RF3_IM_ACID);311 }312 }313 314 /* Otherwise, take the damage */315 else316 {317 if (mult < 3) mult = 3;318 }319 }320 321 /* Brand (Elec) */322 if (f1 & (TR1_BRAND_ELEC))323 {324 /* Notice immunity */325 if (r_ptr->flags3 & (RF3_IM_ELEC))326 {327 if (m_ptr->ml)328 {329 l_ptr->flags3 |= (RF3_IM_ELEC);330 }331 }332 333 /* Otherwise, take the damage */334 else335 {336 if (mult < 3) mult = 3;337 }338 }339 340 /* Brand (Fire) */341 if (f1 & (TR1_BRAND_FIRE))342 {343 /* Notice immunity */344 if (r_ptr->flags3 & (RF3_IM_FIRE))345 {346 if (m_ptr->ml)347 {348 l_ptr->flags3 |= (RF3_IM_FIRE);349 }350 }351 352 /* Otherwise, take the damage */353 else354 {355 if (mult < 3) mult = 3;356 }357 }358 359 /* Brand (Cold) */360 if (f1 & (TR1_BRAND_COLD))361 {362 /* Notice immunity */363 if (r_ptr->flags3 & (RF3_IM_COLD))364 {365 if (m_ptr->ml)366 {367 l_ptr->flags3 |= (RF3_IM_COLD);368 }369 }370 371 /* Otherwise, take the damage */372 else373 {374 if (mult < 3) mult = 3;375 }376 }377 378 /* Brand (Poison) */379 if (f1 & (TR1_BRAND_POIS))380 {381 /* Notice immunity */382 if (r_ptr->flags3 & (RF3_IM_POIS))383 {384 if (m_ptr->ml)385 {386 l_ptr->flags3 |= (RF3_IM_POIS);387 }388 }389 390 /* Otherwise, take the damage */391 else392 {393 if (mult < 3) mult = 3;394 }395 }396 397 break;398 }399 }400 401 402 /* Return the total damage */403 return (tdam * mult);404 }405 15 406 16 … … 1229 839 } 1230 840 } 1231 1232 1233 1234 /*1235 * Attack the monster at the given location1236 *1237 * If no "weapon" is available, then "punch" the monster one time.1238 */1239 void py_attack(int y, int x)1240 {1241 int num = 0, k, bonus, chance;1242 1243 monster_type *m_ptr;1244 monster_race *r_ptr;1245 monster_lore *l_ptr;1246 1247 object_type *o_ptr;1248 1249 char m_name[80];1250 1251 bool fear = FALSE;1252 1253 bool do_quake = FALSE;1254 1255 1256 /* Get the monster */1257 m_ptr = &mon_list[cave_m_idx[y][x]];1258 r_ptr = &r_info[m_ptr->r_idx];1259 l_ptr = &l_list[m_ptr->r_idx];1260 1261 1262 /* Disturb the player */1263 disturb(0, 0);1264 1265 1266 /* Disturb the monster */1267 m_ptr->csleep = 0;1268 1269 1270 /* Extract monster name (or "it") */1271 monster_desc(m_name, sizeof(m_name), m_ptr, 0);1272 1273 1274 /* Auto-Recall if possible and visible */1275 if (m_ptr->ml) monster_race_track(m_ptr->r_idx);1276 1277 /* Track a new monster */1278 if (m_ptr->ml) health_track(cave_m_idx[y][x]);1279 1280 1281 /* Handle player fear */1282 if (p_ptr->timed[TMD_AFRAID])1283 {1284 /* Message */1285 msg_format("You are too afraid to attack %s!", m_name);1286 1287 /* Done */1288 return;1289 }1290 1291 1292 /* Get the weapon */1293 o_ptr = &inventory[INVEN_WIELD];1294 1295 /* Calculate the "attack quality" */1296 bonus = p_ptr->to_h + o_ptr->to_h;1297 chance = (p_ptr->skills[SKILL_THN] + (bonus * BTH_PLUS_ADJ));1298 1299 1300 /* Attack once for each legal blow */1301 while (num++ < p_ptr->num_blow)1302 {1303 /* Test for hit */1304 if (test_hit(chance, r_ptr->ac, m_ptr->ml))1305 {1306 /* Message */1307 message_format(MSG_GENERIC, m_ptr->r_idx, "You hit %s.", m_name);1308 1309 /* Hack -- bare hands do one damage */1310 k = 1;1311 1312 /* Handle normal weapon */1313 if (o_ptr->k_idx)1314 {1315 k = damroll(o_ptr->dd, o_ptr->ds);1316 k = tot_dam_aux(o_ptr, k, m_ptr);1317 if (p_ptr->impact && (k > 50)) do_quake = TRUE;1318 k = critical_norm(o_ptr->weight, o_ptr->to_h, k);1319 k += o_ptr->to_d;1320 }1321 1322 /* Apply the player damage bonuses */1323 k += p_ptr->to_d;1324 1325 /* No negative damage */1326 if (k < 0) k = 0;1327 1328 /* Complex message */1329 if (p_ptr->wizard)1330 {1331 msg_format("You do %d (out of %d) damage.", k, m_ptr->hp);1332 }1333 1334 /* Damage, check for fear and death */1335 if (mon_take_hit(cave_m_idx[y][x], k, &fear, NULL)) break;1336 1337 /* Confusion attack */1338 if (p_ptr->confusing)1339 {1340 /* Cancel glowing hands */1341 p_ptr->confusing = FALSE;1342 1343 /* Message */1344 msg_print("Your hands stop glowing.");1345 1346 /* Confuse the monster */1347 if (r_ptr->flags3 & (RF3_NO_CONF))1348 {1349 if (m_ptr->ml)1350 {1351 l_ptr->flags3 |= (RF3_NO_CONF);1352 }1353 1354 msg_format("%^s is unaffected.", m_name);1355 }1356 else if (rand_int(100) < r_ptr->level)1357 {1358 msg_format("%^s is unaffected.", m_name);1359 }1360 else1361 {1362 msg_format("%^s appears confused.", m_name);1363 m_ptr->confused += 10 + rand_int(p_ptr->lev) / 5;1364 }1365 }1366 }1367 1368 /* Player misses */1369 else1370 {1371 /* Message */1372 message_format(MSG_MISS, m_ptr->r_idx, "You miss %s.", m_name);1373 }1374 }1375 1376 1377 /* Hack -- delay fear messages */1378 if (fear && m_ptr->ml)1379 {1380 /* Message */1381 message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!", m_name);1382 }1383 1384 1385 /* Mega-Hack -- apply earthquake brand */1386 if (do_quake) earthquake(p_ptr->py, p_ptr->px, 10);1387 }1388 1389 841 1390 842 trunk/src/cmd2.c
r399 r400 2322 2322 2323 2323 2324 2325 2326 2327 /*2328 * Determines the odds of an object breaking when thrown at a monster2329 *2330 * Note that artifacts never break, see the "drop_near()" function.2331 */2332 static int breakage_chance(const object_type *o_ptr)2333 {2334 /* Examine the item type */2335 switch (o_ptr->tval)2336 {2337 /* Always break */2338 case TV_FLASK:2339 case TV_POTION:2340 case TV_BOTTLE:2341 case TV_FOOD:2342 case TV_JUNK:2343 {2344 return (100);2345 }2346 2347 /* Often break */2348 case TV_LITE:2349 case TV_SCROLL:2350 case TV_SKELETON:2351 {2352 return (50);2353 }2354 2355 /* Sometimes break */2356 case TV_ARROW:2357 {2358 return (35);2359 }2360 2361 /* Sometimes break */2362 case TV_WAND:2363 case TV_SHOT:2364 case TV_BOLT:2365 case TV_SPIKE:2366 {2367 return (25);2368 }2369 }2370 2371 /* Rarely break */2372 return (10);2373 }2374 2375 2376 /*2377 * Fire an object from the pack or floor.2378 *2379 * You may only fire items that "match" your missile launcher.2380 *2381 * You must use slings + pebbles/shots, bows + arrows, xbows + bolts.2382 *2383 * See "calc_bonuses()" for more calculations and such.2384 *2385 * Note that "firing" a missile is MUCH better than "throwing" it.2386 *2387 * Note: "unseen" monsters are very hard to hit.2388 *2389 * Objects are more likely to break if they "attempt" to hit a monster.2390 *2391 * Rangers (with Bows) and Anyone (with "Extra Shots") get extra shots.2392 *2393 * The "extra shot" code works by decreasing the amount of energy2394 * required to make each shot, spreading the shots out over time.2395 *2396 * Note that when firing missiles, the launcher multiplier is applied2397 * after all the bonuses are added in, making multipliers very useful.2398 *2399 * Note that Bows of "Extra Might" get extra range and an extra bonus2400 * for the damage multiplier.2401 *2402 * Note that Bows of "Extra Shots" give an extra shot.2403 */2404 void do_cmd_fire(void)2405 {2406 int dir, item;2407 int i, j, y, x, ty, tx;2408 int tdam, tdis, thits, tmul;2409 int bonus, chance;2410 2411 object_type *o_ptr;2412 object_type *j_ptr;2413 2414 object_type *i_ptr;2415 object_type object_type_body;2416 2417 bool hit_body = FALSE;2418 2419 byte missile_attr;2420 char missile_char;2421 2422 char o_name[80];2423 2424 int path_n;2425 u16b path_g[256];2426 2427 cptr q, s;2428 2429 int msec = op_ptr->delay_factor * op_ptr->delay_factor;2430 2431 2432 /* Get the "bow" (if any) */2433 j_ptr = &inventory[INVEN_BOW];2434 2435 /* Require a usable launcher */2436 if (!j_ptr->tval || !p_ptr->ammo_tval)2437 {2438 msg_print("You have nothing to fire with.");2439 return;2440 }2441 2442 2443 /* Require proper missile */2444 item_tester_tval = p_ptr->ammo_tval;2445 2446 /* Get an item */2447 q = "Fire which item? ";2448 s = "You have nothing to fire.";2449 if (!get_item(&item, q, s, (USE_INVEN | USE_FLOOR))) return;2450 2451 /* Get the object */2452 if (item >= 0)2453 {2454 o_ptr = &inventory[item];2455 }2456 else2457 {2458 o_ptr = &o_list[0 - item];2459 }2460 2461 2462 /* Get a direction (or cancel) */2463 if (!get_aim_dir(&dir)) return;2464 2465 2466 /* Get local object */2467 i_ptr = &object_type_body;2468 2469 /* Obtain a local object */2470 object_copy(i_ptr, o_ptr);2471 2472 /* Single object */2473 i_ptr->number = 1;2474 2475 /* Reduce and describe inventory */2476 if (item >= 0)2477 {2478 inven_item_increase(item, -1);2479 inven_item_describe(item);2480 inven_item_optimize(item);2481 }2482 2483 /* Reduce and describe floor item */2484 else2485 {2486 floor_item_increase(0 - item, -1);2487 floor_item_optimize(0 - item);2488 }2489 2490 2491 /* Sound */2492 sound(MSG_SHOOT);2493 2494 2495 /* Describe the object */2496 object_desc(o_name, sizeof(o_name), i_ptr, FALSE, 3);2497 2498 /* Find the color and symbol for the object for throwing */2499 missile_attr = object_attr(i_ptr);2500 missile_char = object_char(i_ptr);2501 2502 2503 /* Use the proper number of shots */2504 thits = p_ptr->num_fire;2505 2506 /* Base damage from thrown object plus launcher bonus */2507 tdam = damroll(i_ptr->dd, i_ptr->ds) + i_ptr->to_d + j_ptr->to_d;2508 2509 /* Actually "fire" the object */2510 bonus = (p_ptr->to_h + i_ptr->to_h + j_ptr->to_h);2511 chance = (p_ptr->skills[SKILL_THB] + (bonus * BTH_PLUS_ADJ));2512 2513 /* Assume a base multiplier */2514 tmul = p_ptr->ammo_mult;2515 2516 /* Boost the damage */2517 tdam *= tmul;2518 2519 /* Base range XXX XXX */2520 tdis = 10 + 5 * tmul;2521 2522 2523 /* Take a (partial) turn */2524 p_ptr->energy_use = (100 / thits);2525 2526 2527 /* Start at the player */2528 y = p_ptr->py;2529 x = p_ptr->px;2530 2531 /* Predict the "target" location */2532 ty = p_ptr->py + 99 * ddy[dir];2533 tx = p_ptr->px + 99 * ddx[dir];2534 2535 /* Check for "target request" */2536 if ((dir == 5) && target_okay())2537 {2538 tx = p_ptr->target_col;2539 ty = p_ptr->target_row;2540 }2541 2542 /* Calculate the path */2543 path_n = project_path(path_g, tdis, p_ptr->py, p_ptr->px, ty, tx, 0);2544 2545 2546 /* Hack -- Handle stuff */2547 handle_stuff();2548 2549 /* Project along the path */2550 for (i = 0; i < path_n; ++i)2551 {2552 int ny = GRID_Y(path_g[i]);2553 int nx = GRID_X(path_g[i]);2554 2555 /* Hack -- Stop before hitting walls */2556 if (!cave_floor_bold(ny, nx)) break;2557 2558 /* Advance */2559 x = nx;2560 y = ny;2561 2562 /* Only do visuals if the player can "see" the missile */2563 if (player_can_see_bold(y, x))2564 {2565 /* Visual effects */2566 print_rel(missile_char, missile_attr, y, x);2567 move_cursor_relative(y, x);2568 2569 Term_fresh();2570 if (p_ptr->window) window_stuff();2571 2572 Term_xtra(TERM_XTRA_DELAY, msec);2573 lite_spot(y, x);2574 2575 Term_fresh();2576 if (p_ptr->window) window_stuff();2577 }2578 2579 /* Delay anyway for consistency */2580 else2581 {2582 /* Pause anyway, for consistancy */2583 Term_xtra(TERM_XTRA_DELAY, msec);2584 }2585 2586 /* Handle monster */2587 if (cave_m_idx[y][x] > 0)2588 {2589 monster_type *m_ptr = &mon_list[cave_m_idx[y][x]];2590 monster_race *r_ptr = &r_info[m_ptr->r_idx];2591 2592 int chance2 = chance - distance(p_ptr->py, p_ptr->px, y, x);2593 2594 int visible = m_ptr->ml;2595 2596 /* Note the collision */2597 hit_body = TRUE;2598 2599 /* Did we hit it (penalize distance travelled) */2600 if (test_hit(chance2, r_ptr->ac, m_ptr->ml))2601 {2602 bool fear = FALSE;2603 2604 /* Assume a default death */2605 cptr note_dies = " dies.";2606 2607 /* Some monsters get "destroyed" */2608 if ((r_ptr->flags3 & (RF3_DEMON)) ||2609 (r_ptr->flags3 & (RF3_UNDEAD)) ||2610 (r_ptr->flags2 & (RF2_STUPID)) ||2611 (strchr("Evg", r_ptr->d_char)))2612 {2613 /* Special note at death */2614 note_dies = " is destroyed.";2615 }2616 2617 2618 /* Handle unseen monster */2619 if (!visible)2620 {2621 /* Invisible monster */2622 message_format(MSG_SHOOT_HIT, 0, "The %s finds a mark.", o_name);2623 }2624 2625 /* Handle visible monster */2626 else2627 {2628 char m_name[80];2629 2630
