132689Sbostic /*
2*60842Sbostic * Copyright (c) 1988, 1993
3*60842Sbostic * The Regents of the University of California. All rights reserved.
436704Sbostic *
536704Sbostic * This code is derived from software contributed to Berkeley by
636704Sbostic * Timothy C. Stoehr.
736704Sbostic *
842604Sbostic * %sccs.include.redist.c%
936704Sbostic */
1036704Sbostic
1136704Sbostic #ifndef lint
12*60842Sbostic static char sccsid[] = "@(#)spec_hit.c 8.1 (Berkeley) 05/31/93";
1336704Sbostic #endif /* not lint */
1436704Sbostic
1536704Sbostic /*
1632689Sbostic * special_hit.c
1732689Sbostic *
1832689Sbostic * This source herein may be modified and/or distributed by anybody who
1932689Sbostic * so desires, with the following restrictions:
2032689Sbostic * 1.) No portion of this notice shall be removed.
2132689Sbostic * 2.) Credit shall not be taken for the creation of this source.
2232689Sbostic * 3.) This code is not to be traded, sold, or used for personal
2332689Sbostic * gain or profit.
2432689Sbostic *
2532689Sbostic */
2632689Sbostic
2732689Sbostic #include "rogue.h"
2832689Sbostic
2932689Sbostic short less_hp = 0;
3032689Sbostic boolean being_held;
3132689Sbostic
3232689Sbostic extern short cur_level, max_level, blind, levitate, ring_exp;
3332689Sbostic extern long level_points[];
3432689Sbostic extern boolean detect_monster, mon_disappeared;
3532689Sbostic extern boolean sustain_strength, maintain_armor;
3632689Sbostic extern char *you_can_move_again;
3732689Sbostic
special_hit(monster)3832689Sbostic special_hit(monster)
3932689Sbostic object *monster;
4032689Sbostic {
4132689Sbostic if ((monster->m_flags & CONFUSED) && rand_percent(66)) {
4232689Sbostic return;
4332689Sbostic }
4432689Sbostic if (monster->m_flags & RUSTS) {
4532689Sbostic rust(monster);
4632689Sbostic }
4732689Sbostic if ((monster->m_flags & HOLDS) && !levitate) {
4832689Sbostic being_held = 1;
4932689Sbostic }
5032689Sbostic if (monster->m_flags & FREEZES) {
5132689Sbostic freeze(monster);
5232689Sbostic }
5332689Sbostic if (monster->m_flags & STINGS) {
5432689Sbostic sting(monster);
5532689Sbostic }
5632689Sbostic if (monster->m_flags & DRAINS_LIFE) {
5732689Sbostic drain_life();
5832689Sbostic }
5932689Sbostic if (monster->m_flags & DROPS_LEVEL) {
6032689Sbostic drop_level();
6132689Sbostic }
6232689Sbostic if (monster->m_flags & STEALS_GOLD) {
6332689Sbostic steal_gold(monster);
6432689Sbostic } else if (monster->m_flags & STEALS_ITEM) {
6532689Sbostic steal_item(monster);
6632689Sbostic }
6732689Sbostic }
6832689Sbostic
rust(monster)6932689Sbostic rust(monster)
7032689Sbostic object *monster;
7132689Sbostic {
7232689Sbostic if ((!rogue.armor) || (get_armor_class(rogue.armor) <= 1) ||
7332689Sbostic (rogue.armor->which_kind == LEATHER)) {
7432689Sbostic return;
7532689Sbostic }
7632689Sbostic if ((rogue.armor->is_protected) || maintain_armor) {
7732689Sbostic if (monster && (!(monster->m_flags & RUST_VANISHED))) {
7832689Sbostic message("the rust vanishes instantly", 0);
7932689Sbostic monster->m_flags |= RUST_VANISHED;
8032689Sbostic }
8132689Sbostic } else {
8232689Sbostic rogue.armor->d_enchant--;
8332689Sbostic message("your armor weakens", 0);
8432689Sbostic print_stats(STAT_ARMOR);
8532689Sbostic }
8632689Sbostic }
8732689Sbostic
freeze(monster)8832689Sbostic freeze(monster)
8932689Sbostic object *monster;
9032689Sbostic {
9132689Sbostic short freeze_percent = 99;
9232689Sbostic short i, n;
9332689Sbostic
9432689Sbostic if (rand_percent(12)) {
9532689Sbostic return;
9632689Sbostic }
9732689Sbostic freeze_percent -= (rogue.str_current+(rogue.str_current / 2));
9832689Sbostic freeze_percent -= ((rogue.exp + ring_exp) * 4);
9932689Sbostic freeze_percent -= (get_armor_class(rogue.armor) * 5);
10032689Sbostic freeze_percent -= (rogue.hp_max / 3);
10132689Sbostic
10232689Sbostic if (freeze_percent > 10) {
10332689Sbostic monster->m_flags |= FREEZING_ROGUE;
10432689Sbostic message("you are frozen", 1);
10532689Sbostic
10632689Sbostic n = get_rand(4, 8);
10732689Sbostic for (i = 0; i < n; i++) {
10832689Sbostic mv_mons();
10932689Sbostic }
11032689Sbostic if (rand_percent(freeze_percent)) {
11132689Sbostic for (i = 0; i < 50; i++) {
11232689Sbostic mv_mons();
11332689Sbostic }
11432689Sbostic killed_by((object *)0, HYPOTHERMIA);
11532689Sbostic }
11632689Sbostic message(you_can_move_again, 1);
11732689Sbostic monster->m_flags &= (~FREEZING_ROGUE);
11832689Sbostic }
11932689Sbostic }
12032689Sbostic
steal_gold(monster)12132689Sbostic steal_gold(monster)
12232689Sbostic object *monster;
12332689Sbostic {
12432689Sbostic int amount;
12532689Sbostic
12632689Sbostic if ((rogue.gold <= 0) || rand_percent(10)) {
12732689Sbostic return;
12832689Sbostic }
12932689Sbostic
13032689Sbostic amount = get_rand((cur_level * 10), (cur_level * 30));
13132689Sbostic
13232689Sbostic if (amount > rogue.gold) {
13332689Sbostic amount = rogue.gold;
13432689Sbostic }
13532689Sbostic rogue.gold -= amount;
13632689Sbostic message("your purse feels lighter", 0);
13732689Sbostic print_stats(STAT_GOLD);
13832689Sbostic disappear(monster);
13932689Sbostic }
14032689Sbostic
steal_item(monster)14132689Sbostic steal_item(monster)
14232689Sbostic object *monster;
14332689Sbostic {
14432689Sbostic object *obj;
14532689Sbostic short i, n, t;
14632689Sbostic char desc[80];
14732689Sbostic boolean has_something = 0;
14832689Sbostic
14932689Sbostic if (rand_percent(15)) {
15032689Sbostic return;
15132689Sbostic }
15232689Sbostic obj = rogue.pack.next_object;
15332689Sbostic
15432689Sbostic if (!obj) {
15532689Sbostic goto DSPR;
15632689Sbostic }
15732689Sbostic while (obj) {
15832689Sbostic if (!(obj->in_use_flags & BEING_USED)) {
15932689Sbostic has_something = 1;
16032689Sbostic break;
16132689Sbostic }
16232689Sbostic obj = obj->next_object;
16332689Sbostic }
16432689Sbostic if (!has_something) {
16532689Sbostic goto DSPR;
16632689Sbostic }
16732689Sbostic n = get_rand(0, MAX_PACK_COUNT);
16832689Sbostic obj = rogue.pack.next_object;
16932689Sbostic
17032689Sbostic for (i = 0; i <= n; i++) {
17132689Sbostic obj = obj->next_object;
17232689Sbostic while ((!obj) || (obj->in_use_flags & BEING_USED)) {
17332689Sbostic if (!obj) {
17432689Sbostic obj = rogue.pack.next_object;
17532689Sbostic } else {
17632689Sbostic obj = obj->next_object;
17732689Sbostic }
17832689Sbostic }
17932689Sbostic }
18032689Sbostic (void) strcpy(desc, "she stole ");
18132689Sbostic if (obj->what_is != WEAPON) {
18232689Sbostic t = obj->quantity;
18332689Sbostic obj->quantity = 1;
18432689Sbostic }
18532689Sbostic get_desc(obj, desc+10);
18632689Sbostic message(desc, 0);
18732689Sbostic
18832689Sbostic obj->quantity = ((obj->what_is != WEAPON) ? t : 1);
18932689Sbostic
19032689Sbostic vanish(obj, 0, &rogue.pack);
19132689Sbostic DSPR:
19232689Sbostic disappear(monster);
19332689Sbostic }
19432689Sbostic
disappear(monster)19532689Sbostic disappear(monster)
19632689Sbostic object *monster;
19732689Sbostic {
19832689Sbostic short row, col;
19932689Sbostic
20032689Sbostic row = monster->row;
20132689Sbostic col = monster->col;
20232689Sbostic
20332689Sbostic dungeon[row][col] &= ~MONSTER;
20432689Sbostic if (rogue_can_see(row, col)) {
20532689Sbostic mvaddch(row, col, get_dungeon_char(row, col));
20632689Sbostic }
20732689Sbostic take_from_pack(monster, &level_monsters);
20832689Sbostic free_object(monster);
20932689Sbostic mon_disappeared = 1;
21032689Sbostic }
21132689Sbostic
cough_up(monster)21232689Sbostic cough_up(monster)
21332689Sbostic object *monster;
21432689Sbostic {
21532689Sbostic object *obj;
21632689Sbostic short row, col, i, n;
21732689Sbostic
21832689Sbostic if (cur_level < max_level) {
21932689Sbostic return;
22032689Sbostic }
22132689Sbostic
22232689Sbostic if (monster->m_flags & STEALS_GOLD) {
22332689Sbostic obj = alloc_object();
22432689Sbostic obj->what_is = GOLD;
22532689Sbostic obj->quantity = get_rand((cur_level * 15), (cur_level * 30));
22632689Sbostic } else {
22732689Sbostic if (!rand_percent((int) monster->drop_percent)) {
22832689Sbostic return;
22932689Sbostic }
23032689Sbostic obj = gr_object();
23132689Sbostic }
23232689Sbostic row = monster->row;
23332689Sbostic col = monster->col;
23432689Sbostic
23532689Sbostic for (n = 0; n <= 5; n++) {
23632689Sbostic for (i = -n; i <= n; i++) {
23732689Sbostic if (try_to_cough(row+n, col+i, obj)) {
23832689Sbostic return;
23932689Sbostic }
24032689Sbostic if (try_to_cough(row-n, col+i, obj)) {
24132689Sbostic return;
24232689Sbostic }
24332689Sbostic }
24432689Sbostic for (i = -n; i <= n; i++) {
24532689Sbostic if (try_to_cough(row+i, col-n, obj)) {
24632689Sbostic return;
24732689Sbostic }
24832689Sbostic if (try_to_cough(row+i, col+n, obj)) {
24932689Sbostic return;
25032689Sbostic }
25132689Sbostic }
25232689Sbostic }
25332689Sbostic free_object(obj);
25432689Sbostic }
25532689Sbostic
try_to_cough(row,col,obj)25632689Sbostic try_to_cough(row, col, obj)
25732689Sbostic short row, col;
25832689Sbostic object *obj;
25932689Sbostic {
26032689Sbostic if ((row < MIN_ROW) || (row > (DROWS-2)) || (col < 0) || (col>(DCOLS-1))) {
26132689Sbostic return(0);
26232689Sbostic }
26332689Sbostic if ((!(dungeon[row][col] & (OBJECT | STAIRS | TRAP))) &&
26432689Sbostic (dungeon[row][col] & (TUNNEL | FLOOR | DOOR))) {
26532689Sbostic place_at(obj, row, col);
26632689Sbostic if (((row != rogue.row) || (col != rogue.col)) &&
26732689Sbostic (!(dungeon[row][col] & MONSTER))) {
26832689Sbostic mvaddch(row, col, get_dungeon_char(row, col));
26932689Sbostic }
27032689Sbostic return(1);
27132689Sbostic }
27232689Sbostic return(0);
27332689Sbostic }
27432689Sbostic
seek_gold(monster)27532689Sbostic seek_gold(monster)
27632689Sbostic object *monster;
27732689Sbostic {
27832689Sbostic short i, j, rn, s;
27932689Sbostic
28032689Sbostic if ((rn = get_room_number(monster->row, monster->col)) < 0) {
28132689Sbostic return(0);
28232689Sbostic }
28332689Sbostic for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
28432689Sbostic for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
28532689Sbostic if ((gold_at(i, j)) && !(dungeon[i][j] & MONSTER)) {
28632689Sbostic monster->m_flags |= CAN_FLIT;
28732689Sbostic s = mon_can_go(monster, i, j);
28832689Sbostic monster->m_flags &= (~CAN_FLIT);
28932689Sbostic if (s) {
29032689Sbostic move_mon_to(monster, i, j);
29132689Sbostic monster->m_flags |= ASLEEP;
29232689Sbostic monster->m_flags &= (~(WAKENS | SEEKS_GOLD));
29332689Sbostic return(1);
29432689Sbostic }
29532689Sbostic monster->m_flags &= (~SEEKS_GOLD);
29632689Sbostic monster->m_flags |= CAN_FLIT;
29732689Sbostic mv_1_monster(monster, i, j);
29832689Sbostic monster->m_flags &= (~CAN_FLIT);
29932689Sbostic monster->m_flags |= SEEKS_GOLD;
30032689Sbostic return(1);
30132689Sbostic }
30232689Sbostic }
30332689Sbostic }
30432689Sbostic return(0);
30532689Sbostic }
30632689Sbostic
gold_at(row,col)30732689Sbostic gold_at(row, col)
30832689Sbostic short row, col;
30932689Sbostic {
31032689Sbostic if (dungeon[row][col] & OBJECT) {
31132689Sbostic object *obj;
31232689Sbostic
31332689Sbostic if ((obj = object_at(&level_objects, row, col)) &&
31432689Sbostic (obj->what_is == GOLD)) {
31532689Sbostic return(1);
31632689Sbostic }
31732689Sbostic }
31832689Sbostic return(0);
31932689Sbostic }
32032689Sbostic
check_gold_seeker(monster)32132689Sbostic check_gold_seeker(monster)
32232689Sbostic object *monster;
32332689Sbostic {
32432689Sbostic monster->m_flags &= (~SEEKS_GOLD);
32532689Sbostic }
32632689Sbostic
check_imitator(monster)32732689Sbostic check_imitator(monster)
32832689Sbostic object *monster;
32932689Sbostic {
33032689Sbostic char msg[80];
33132689Sbostic
33232689Sbostic if (monster->m_flags & IMITATES) {
33332689Sbostic wake_up(monster);
33432689Sbostic if (!blind) {
33532689Sbostic mvaddch(monster->row, monster->col,
33632689Sbostic get_dungeon_char(monster->row, monster->col));
33732689Sbostic check_message();
33832689Sbostic sprintf(msg, "wait, that's a %s!", mon_name(monster));
33932689Sbostic message(msg, 1);
34032689Sbostic }
34132689Sbostic return(1);
34232689Sbostic }
34332689Sbostic return(0);
34432689Sbostic }
34532689Sbostic
imitating(row,col)34632689Sbostic imitating(row, col)
34732689Sbostic register short row, col;
34832689Sbostic {
34932689Sbostic if (dungeon[row][col] & MONSTER) {
35032689Sbostic object *object_at(), *monster;
35132689Sbostic
35232689Sbostic if (monster = object_at(&level_monsters, row, col)) {
35332689Sbostic if (monster->m_flags & IMITATES) {
35432689Sbostic return(1);
35532689Sbostic }
35632689Sbostic }
35732689Sbostic }
35832689Sbostic return(0);
35932689Sbostic }
36032689Sbostic
sting(monster)36132689Sbostic sting(monster)
36232689Sbostic object *monster;
36332689Sbostic {
36432689Sbostic short sting_chance = 35;
36532689Sbostic char msg[80];
36632689Sbostic
36732689Sbostic if ((rogue.str_current <= 3) || sustain_strength) {
36832689Sbostic return;
36932689Sbostic }
37032689Sbostic sting_chance += (6 * (6 - get_armor_class(rogue.armor)));
37132689Sbostic
37232689Sbostic if ((rogue.exp + ring_exp) > 8) {
37332689Sbostic sting_chance -= (6 * ((rogue.exp + ring_exp) - 8));
37432689Sbostic }
37532689Sbostic if (rand_percent(sting_chance)) {
37632689Sbostic sprintf(msg, "the %s's bite has weakened you",
37732689Sbostic mon_name(monster));
37832689Sbostic message(msg, 0);
37932689Sbostic rogue.str_current--;
38032689Sbostic print_stats(STAT_STRENGTH);
38132689Sbostic }
38232689Sbostic }
38332689Sbostic
drop_level()38432689Sbostic drop_level()
38532689Sbostic {
38632689Sbostic int hp;
38732689Sbostic
38832689Sbostic if (rand_percent(80) || (rogue.exp <= 5)) {
38932689Sbostic return;
39032689Sbostic }
39132689Sbostic rogue.exp_points = level_points[rogue.exp-2] - get_rand(9, 29);
39232689Sbostic rogue.exp -= 2;
39332689Sbostic hp = hp_raise();
39432689Sbostic if ((rogue.hp_current -= hp) <= 0) {
39532689Sbostic rogue.hp_current = 1;
39632689Sbostic }
39732689Sbostic if ((rogue.hp_max -= hp) <= 0) {
39832689Sbostic rogue.hp_max = 1;
39932689Sbostic }
40032689Sbostic add_exp(1, 0);
40132689Sbostic }
40232689Sbostic
drain_life()40332689Sbostic drain_life()
40432689Sbostic {
40532689Sbostic short n;
40632689Sbostic
40732689Sbostic if (rand_percent(60) || (rogue.hp_max <= 30) || (rogue.hp_current < 10)) {
40832689Sbostic return;
40932689Sbostic }
41032689Sbostic n = get_rand(1, 3); /* 1 Hp, 2 Str, 3 both */
41132689Sbostic
41232689Sbostic if ((n != 2) || (!sustain_strength)) {
41332689Sbostic message("you feel weaker", 0);
41432689Sbostic }
41532689Sbostic if (n != 2) {
41632689Sbostic rogue.hp_max--;
41732689Sbostic rogue.hp_current--;
41832689Sbostic less_hp++;
41932689Sbostic }
42032689Sbostic if (n != 1) {
42132689Sbostic if ((rogue.str_current > 3) && (!sustain_strength)) {
42232689Sbostic rogue.str_current--;
42332689Sbostic if (coin_toss()) {
42432689Sbostic rogue.str_max--;
42532689Sbostic }
42632689Sbostic }
42732689Sbostic }
42832689Sbostic print_stats((STAT_STRENGTH | STAT_HP));
42932689Sbostic }
43032689Sbostic
m_confuse(monster)43132689Sbostic m_confuse(monster)
43232689Sbostic object *monster;
43332689Sbostic {
43432689Sbostic char msg[80];
43532689Sbostic
43632689Sbostic if (!rogue_can_see(monster->row, monster->col)) {
43732689Sbostic return(0);
43832689Sbostic }
43932689Sbostic if (rand_percent(45)) {
44032689Sbostic monster->m_flags &= (~CONFUSES); /* will not confuse the rogue */
44132689Sbostic return(0);
44232689Sbostic }
44332689Sbostic if (rand_percent(55)) {
44432689Sbostic monster->m_flags &= (~CONFUSES);
44532689Sbostic sprintf(msg, "the gaze of the %s has confused you", mon_name(monster));
44632689Sbostic message(msg, 1);
44732689Sbostic cnfs();
44832689Sbostic return(1);
44932689Sbostic }
45032689Sbostic return(0);
45132689Sbostic }
45232689Sbostic
flame_broil(monster)45332689Sbostic flame_broil(monster)
45432689Sbostic object *monster;
45532689Sbostic {
45632689Sbostic short row, col, dir;
45732689Sbostic
45832689Sbostic if ((!mon_sees(monster, rogue.row, rogue.col)) || coin_toss()) {
45932689Sbostic return(0);
46032689Sbostic }
46132689Sbostic row = rogue.row - monster->row;
46232689Sbostic col = rogue.col - monster->col;
46332689Sbostic if (row < 0) {
46432689Sbostic row = -row;
46532689Sbostic }
46632689Sbostic if (col < 0) {
46732689Sbostic col = -col;
46832689Sbostic }
46932689Sbostic if (((row != 0) && (col != 0) && (row != col)) ||
47032689Sbostic ((row > 7) || (col > 7))) {
47132689Sbostic return(0);
47232689Sbostic }
47332689Sbostic dir = get_dir(monster->row, monster->col, row, col);
47432689Sbostic bounce(FIRE, dir, monster->row, monster->col, 0);
47532689Sbostic
47632689Sbostic return(1);
47732689Sbostic }
47832689Sbostic
get_dir(srow,scol,drow,dcol)47932689Sbostic get_dir(srow, scol, drow, dcol)
48032689Sbostic short srow, scol, drow, dcol;
48132689Sbostic {
48232689Sbostic if (srow == drow) {
48332689Sbostic if (scol < dcol) {
48432689Sbostic return(RIGHT);
48532689Sbostic } else {
48632689Sbostic return(LEFT);
48732689Sbostic }
48832689Sbostic }
48932689Sbostic if (scol == dcol) {
49032689Sbostic if (srow < drow) {
49132689Sbostic return(DOWN);
49232689Sbostic } else {
49332689Sbostic return(UPWARD);
49432689Sbostic }
49532689Sbostic }
49632689Sbostic if ((srow > drow) && (scol > dcol)) {
49732689Sbostic return(UPLEFT);
49832689Sbostic }
49932689Sbostic if ((srow < drow) && (scol < dcol)) {
50032689Sbostic return(DOWNRIGHT);
50132689Sbostic }
50232689Sbostic if ((srow < drow) && (scol > dcol)) {
50332689Sbostic return(DOWNLEFT);
50432689Sbostic }
50532689Sbostic /*if ((srow > drow) && (scol < dcol)) {*/
50632689Sbostic return(UPRIGHT);
50732689Sbostic /*}*/
50832689Sbostic }
509