Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / games / rogue / spec_hit.c
blobeb0b418e4085993d7637ff38e0f1f0037e9e3d8e
1 /* $NetBSD: spec_hit.c,v 1.7 2008/01/14 00:23:53 dholland Exp $ */
3 /*
4 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Timothy C. Stoehr.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
35 #include <sys/cdefs.h>
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)spec_hit.c 8.1 (Berkeley) 5/31/93";
39 #else
40 __RCSID("$NetBSD: spec_hit.c,v 1.7 2008/01/14 00:23:53 dholland Exp $");
41 #endif
42 #endif /* not lint */
45 * special_hit.c
47 * This source herein may be modified and/or distributed by anybody who
48 * so desires, with the following restrictions:
49 * 1.) No portion of this notice shall be removed.
50 * 2.) Credit shall not be taken for the creation of this source.
51 * 3.) This code is not to be traded, sold, or used for personal
52 * gain or profit.
56 #include "rogue.h"
58 static void disappear(object *);
59 static void drain_life(void);
60 static void drop_level(void);
61 static void freeze(object *);
62 static int get_dir(short, short, short, short);
63 static boolean gold_at(short, short);
64 static void steal_gold(object *);
65 static void steal_item(object *);
66 static void sting(object *);
67 static boolean try_to_cough(short, short, object *);
69 short less_hp = 0;
70 boolean being_held;
72 void
73 special_hit(object *monster)
75 if ((monster->m_flags & CONFUSED) && rand_percent(66)) {
76 return;
78 if (monster->m_flags & RUSTS) {
79 rust(monster);
81 if ((monster->m_flags & HOLDS) && !levitate) {
82 being_held = 1;
84 if (monster->m_flags & FREEZES) {
85 freeze(monster);
87 if (monster->m_flags & STINGS) {
88 sting(monster);
90 if (monster->m_flags & DRAINS_LIFE) {
91 drain_life();
93 if (monster->m_flags & DROPS_LEVEL) {
94 drop_level();
96 if (monster->m_flags & STEALS_GOLD) {
97 steal_gold(monster);
98 } else if (monster->m_flags & STEALS_ITEM) {
99 steal_item(monster);
103 void
104 rust(object *monster)
106 if ((!rogue.armor) || (get_armor_class(rogue.armor) <= 1) ||
107 (rogue.armor->which_kind == LEATHER)) {
108 return;
110 if ((rogue.armor->is_protected) || maintain_armor) {
111 if (monster && (!(monster->m_flags & RUST_VANISHED))) {
112 messagef(0, "the rust vanishes instantly");
113 monster->m_flags |= RUST_VANISHED;
115 } else {
116 rogue.armor->d_enchant--;
117 messagef(0, "your armor weakens");
118 print_stats(STAT_ARMOR);
122 void
123 freeze(object *monster)
125 short freeze_percent = 99;
126 short i, n;
128 if (rand_percent(12)) {
129 return;
131 freeze_percent -= (rogue.str_current+(rogue.str_current / 2));
132 freeze_percent -= ((rogue.exp + ring_exp) * 4);
133 freeze_percent -= (get_armor_class(rogue.armor) * 5);
134 freeze_percent -= (rogue.hp_max / 3);
136 if (freeze_percent > 10) {
137 monster->m_flags |= FREEZING_ROGUE;
138 messagef(1, "you are frozen");
140 n = get_rand(4, 8);
141 for (i = 0; i < n; i++) {
142 mv_mons();
144 if (rand_percent(freeze_percent)) {
145 for (i = 0; i < 50; i++) {
146 mv_mons();
148 killed_by(NULL, HYPOTHERMIA);
150 messagef(1, you_can_move_again);
151 monster->m_flags &= (~FREEZING_ROGUE);
155 void
156 steal_gold(object *monster)
158 int amount;
160 if ((rogue.gold <= 0) || rand_percent(10)) {
161 return;
164 amount = get_rand((cur_level * 10), (cur_level * 30));
166 if (amount > rogue.gold) {
167 amount = rogue.gold;
169 rogue.gold -= amount;
170 messagef(0, "your purse feels lighter");
171 print_stats(STAT_GOLD);
172 disappear(monster);
175 void
176 steal_item(object *monster)
178 object *obj;
179 short i, n, t = 0;
180 char desc[80];
181 boolean has_something = 0;
183 if (rand_percent(15)) {
184 return;
186 obj = rogue.pack.next_object;
188 if (!obj) {
189 goto DSPR;
191 while (obj) {
192 if (!(obj->in_use_flags & BEING_USED)) {
193 has_something = 1;
194 break;
196 obj = obj->next_object;
198 if (!has_something) {
199 goto DSPR;
201 n = get_rand(0, MAX_PACK_COUNT);
202 obj = rogue.pack.next_object;
204 for (i = 0; i <= n; i++) {
205 obj = obj->next_object;
206 while ((!obj) || (obj->in_use_flags & BEING_USED)) {
207 if (!obj) {
208 obj = rogue.pack.next_object;
209 } else {
210 obj = obj->next_object;
214 if (obj->what_is != WEAPON) {
215 t = obj->quantity;
216 obj->quantity = 1;
218 get_desc(obj, desc, sizeof(desc));
219 messagef(0, "she stole %s", desc);
221 obj->quantity = ((obj->what_is != WEAPON) ? t : 1);
223 vanish(obj, 0, &rogue.pack);
224 DSPR:
225 disappear(monster);
228 static void
229 disappear(object *monster)
231 short row, col;
233 row = monster->row;
234 col = monster->col;
236 dungeon[row][col] &= ~MONSTER;
237 if (rogue_can_see(row, col)) {
238 mvaddch(row, col, get_dungeon_char(row, col));
240 take_from_pack(monster, &level_monsters);
241 free_object(monster);
242 mon_disappeared = 1;
245 void
246 cough_up(object *monster)
248 object *obj;
249 short row, col, i, n;
251 if (cur_level < max_level) {
252 return;
255 if (monster->m_flags & STEALS_GOLD) {
256 obj = alloc_object();
257 obj->what_is = GOLD;
258 obj->quantity = get_rand((cur_level * 15), (cur_level * 30));
259 } else {
260 if (!rand_percent((int)monster->drop_percent)) {
261 return;
263 obj = gr_object();
265 row = monster->row;
266 col = monster->col;
268 for (n = 0; n <= 5; n++) {
269 for (i = -n; i <= n; i++) {
270 if (try_to_cough(row+n, col+i, obj)) {
271 return;
273 if (try_to_cough(row-n, col+i, obj)) {
274 return;
277 for (i = -n; i <= n; i++) {
278 if (try_to_cough(row+i, col-n, obj)) {
279 return;
281 if (try_to_cough(row+i, col+n, obj)) {
282 return;
286 free_object(obj);
289 static boolean
290 try_to_cough(short row, short col, object *obj)
292 if ((row < MIN_ROW) ||
293 (row > (DROWS-2)) || (col < 0) || (col>(DCOLS-1))) {
294 return(0);
296 if ((!(dungeon[row][col] & (OBJECT | STAIRS | TRAP))) &&
297 (dungeon[row][col] & (TUNNEL | FLOOR | DOOR))) {
298 place_at(obj, row, col);
299 if (((row != rogue.row) || (col != rogue.col)) &&
300 (!(dungeon[row][col] & MONSTER))) {
301 mvaddch(row, col, get_dungeon_char(row, col));
303 return(1);
305 return(0);
308 boolean
309 seek_gold(object *monster)
311 short i, j, rn, s;
313 if ((rn = get_room_number(monster->row, monster->col)) < 0) {
314 return(0);
316 for (i = rooms[rn].top_row+1; i < rooms[rn].bottom_row; i++) {
317 for (j = rooms[rn].left_col+1; j < rooms[rn].right_col; j++) {
318 if ((gold_at(i, j)) && !(dungeon[i][j] & MONSTER)) {
319 monster->m_flags |= CAN_FLIT;
320 s = mon_can_go(monster, i, j);
321 monster->m_flags &= (~CAN_FLIT);
322 if (s) {
323 move_mon_to(monster, i, j);
324 monster->m_flags |= ASLEEP;
325 monster->m_flags &= (~(WAKENS | SEEKS_GOLD));
326 return(1);
328 monster->m_flags &= (~SEEKS_GOLD);
329 monster->m_flags |= CAN_FLIT;
330 mv_1_monster(monster, i, j);
331 monster->m_flags &= (~CAN_FLIT);
332 monster->m_flags |= SEEKS_GOLD;
333 return(1);
337 return(0);
340 static boolean
341 gold_at(short row, short col)
343 if (dungeon[row][col] & OBJECT) {
344 object *obj;
346 if ((obj = object_at(&level_objects, row, col)) &&
347 (obj->what_is == GOLD)) {
348 return(1);
351 return(0);
354 void
355 check_gold_seeker(object *monster)
357 monster->m_flags &= (~SEEKS_GOLD);
360 boolean
361 check_imitator(object *monster)
363 if (monster->m_flags & IMITATES) {
364 wake_up(monster);
365 if (!blind) {
366 mvaddch(monster->row, monster->col,
367 get_dungeon_char(monster->row, monster->col));
368 check_message();
369 messagef(1, "wait, that's a %s!", mon_name(monster));
371 return(1);
373 return(0);
376 boolean
377 imitating(short row, short col)
379 if (dungeon[row][col] & MONSTER) {
380 object *monster;
382 if ((monster = object_at(&level_monsters, row, col)) != NULL) {
383 if (monster->m_flags & IMITATES) {
384 return(1);
388 return(0);
391 static void
392 sting(object *monster)
394 short sting_chance = 35;
396 if ((rogue.str_current <= 3) || sustain_strength) {
397 return;
399 sting_chance += (6 * (6 - get_armor_class(rogue.armor)));
401 if ((rogue.exp + ring_exp) > 8) {
402 sting_chance -= (6 * ((rogue.exp + ring_exp) - 8));
404 if (rand_percent(sting_chance)) {
405 messagef(0, "the %s's bite has weakened you",
406 mon_name(monster));
407 rogue.str_current--;
408 print_stats(STAT_STRENGTH);
412 static void
413 drop_level(void)
415 int hp;
417 if (rand_percent(80) || (rogue.exp <= 5)) {
418 return;
420 rogue.exp_points = level_points[rogue.exp-2] - get_rand(9, 29);
421 rogue.exp -= 2;
422 hp = hp_raise();
423 if ((rogue.hp_current -= hp) <= 0) {
424 rogue.hp_current = 1;
426 if ((rogue.hp_max -= hp) <= 0) {
427 rogue.hp_max = 1;
429 add_exp(1, 0);
432 void
433 drain_life(void)
435 short n;
437 if (rand_percent(60) || (rogue.hp_max <= 30) || (rogue.hp_current < 10)) {
438 return;
440 n = get_rand(1, 3); /* 1 Hp, 2 Str, 3 both */
442 if ((n != 2) || (!sustain_strength)) {
443 messagef(0, "you feel weaker");
445 if (n != 2) {
446 rogue.hp_max--;
447 rogue.hp_current--;
448 less_hp++;
450 if (n != 1) {
451 if ((rogue.str_current > 3) && (!sustain_strength)) {
452 rogue.str_current--;
453 if (coin_toss()) {
454 rogue.str_max--;
458 print_stats((STAT_STRENGTH | STAT_HP));
461 boolean
462 m_confuse(object *monster)
464 if (!rogue_can_see(monster->row, monster->col)) {
465 return(0);
467 if (rand_percent(45)) {
468 monster->m_flags &= (~CONFUSES); /* will not confuse the rogue */
469 return(0);
471 if (rand_percent(55)) {
472 monster->m_flags &= (~CONFUSES);
473 messagef(1, "the gaze of the %s has confused you",
474 mon_name(monster));
475 cnfs();
476 return(1);
478 return(0);
481 boolean
482 flame_broil(object *monster)
484 short row, col, dir;
486 if ((!mon_sees(monster, rogue.row, rogue.col)) || coin_toss()) {
487 return(0);
489 row = rogue.row - monster->row;
490 col = rogue.col - monster->col;
491 if (row < 0) {
492 row = -row;
494 if (col < 0) {
495 col = -col;
497 if (((row != 0) && (col != 0) && (row != col)) ||
498 ((row > 7) || (col > 7))) {
499 return(0);
501 dir = get_dir(monster->row, monster->col, row, col);
502 bounce(FIRE, dir, monster->row, monster->col, 0);
504 return(1);
507 static int
508 get_dir(short srow, short scol, short drow, short dcol)
510 if (srow == drow) {
511 if (scol < dcol) {
512 return(RIGHT);
513 } else {
514 return(LEFT);
517 if (scol == dcol) {
518 if (srow < drow) {
519 return(DOWN);
520 } else {
521 return(UPWARD);
524 if ((srow > drow) && (scol > dcol)) {
525 return(UPLEFT);
527 if ((srow < drow) && (scol < dcol)) {
528 return(DOWNRIGHT);
530 if ((srow < drow) && (scol > dcol)) {
531 return(DOWNLEFT);
533 /*if ((srow > drow) && (scol < dcol)) {*/
534 return(UPRIGHT);
535 /*}*/