xref: /original-bsd/games/rogue/throw.c (revision 3d751ffd)
1 /*
2  * Copyright (c) 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Timothy C. Stoehr.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20 
21 #ifndef lint
22 static char sccsid[] = "@(#)throw.c	5.2 (Berkeley) 02/07/89";
23 #endif /* not lint */
24 
25 /*
26  * throw.c
27  *
28  * This source herein may be modified and/or distributed by anybody who
29  * so desires, with the following restrictions:
30  *    1.)  No portion of this notice shall be removed.
31  *    2.)  Credit shall not be taken for the creation of this source.
32  *    3.)  This code is not to be traded, sold, or used for personal
33  *         gain or profit.
34  *
35  */
36 
37 #include "rogue.h"
38 
39 extern short cur_room;
40 extern char *curse_message;
41 extern char hit_message[];
42 
43 throw()
44 {
45 	short wch, d;
46 	boolean first_miss = 1;
47 	object *weapon;
48 	short dir, row, col;
49 	object *monster;
50 
51 	while (!is_direction(dir = rgetchar(), &d)) {
52 		sound_bell();
53 		if (first_miss) {
54 			message("direction? ", 0);
55 			first_miss = 0;
56 		}
57 	}
58 	check_message();
59 	if (dir == CANCEL) {
60 		return;
61 	}
62 	if ((wch = pack_letter("throw what?", WEAPON)) == CANCEL) {
63 		return;
64 	}
65 	check_message();
66 
67 	if (!(weapon = get_letter_object(wch))) {
68 		message("no such item.", 0);
69 		return;
70 	}
71 	if ((weapon->in_use_flags & BEING_USED) && weapon->is_cursed) {
72 		message(curse_message, 0);
73 		return;
74 	}
75 	row = rogue.row; col = rogue.col;
76 
77 	if ((weapon->in_use_flags & BEING_WIELDED) && (weapon->quantity <= 1)) {
78 		unwield(rogue.weapon);
79 	} else if (weapon->in_use_flags & BEING_WORN) {
80 		mv_aquatars();
81 		unwear(rogue.armor);
82 		print_stats(STAT_ARMOR);
83 	} else if (weapon->in_use_flags & ON_EITHER_HAND) {
84 		un_put_on(weapon);
85 	}
86 	monster = get_thrown_at_monster(weapon, d, &row, &col);
87 	mvaddch(rogue.row, rogue.col, rogue.fchar);
88 	refresh();
89 
90 	if (rogue_can_see(row, col) && ((row != rogue.row) || (col != rogue.col))){
91 		mvaddch(row, col, get_dungeon_char(row, col));
92 	}
93 	if (monster) {
94 		wake_up(monster);
95 		check_gold_seeker(monster);
96 
97 		if (!throw_at_monster(monster, weapon)) {
98 			flop_weapon(weapon, row, col);
99 		}
100 	} else {
101 		flop_weapon(weapon, row, col);
102 	}
103 	vanish(weapon, 1, &rogue.pack);
104 }
105 
106 throw_at_monster(monster, weapon)
107 object *monster, *weapon;
108 {
109 	short damage, hit_chance;
110 	short t;
111 
112 	hit_chance = get_hit_chance(weapon);
113 	damage = get_weapon_damage(weapon);
114 	if ((weapon->which_kind == ARROW) &&
115 		(rogue.weapon && (rogue.weapon->which_kind == BOW))) {
116 		damage += get_weapon_damage(rogue.weapon);
117 		damage = ((damage * 2) / 3);
118 		hit_chance += (hit_chance / 3);
119 	} else if ((weapon->in_use_flags & BEING_WIELDED) &&
120 		((weapon->which_kind == DAGGER) ||
121 		(weapon->which_kind == SHURIKEN) ||
122 		(weapon->which_kind == DART))) {
123 		damage = ((damage * 3) / 2);
124 		hit_chance += (hit_chance / 3);
125 	}
126 	t = weapon->quantity;
127 	weapon->quantity = 1;
128 	sprintf(hit_message, "the %s", name_of(weapon));
129 	weapon->quantity = t;
130 
131 	if (!rand_percent(hit_chance)) {
132 		(void) strcat(hit_message, "misses  ");
133 		return(0);
134 	}
135 	s_con_mon(monster);
136 	(void) strcat(hit_message, "hit  ");
137 	(void) mon_damage(monster, damage);
138 	return(1);
139 }
140 
141 object *
142 get_thrown_at_monster(obj, dir, row, col)
143 object *obj;
144 short dir;
145 short *row, *col;
146 {
147 	short orow, ocol;
148 	short i, ch;
149 
150 	orow = *row; ocol = *col;
151 
152 	ch = get_mask_char(obj->what_is);
153 
154 	for (i = 0; i < 24; i++) {
155 		get_dir_rc(dir, row, col, 0);
156 		if (	(((*col <= 0) || (*col >= DCOLS-1)) ||
157 				(dungeon[*row][*col] == NOTHING)) ||
158 				((dungeon[*row][*col] & (HORWALL | VERTWALL | HIDDEN)) &&
159 					(!(dungeon[*row][*col] & TRAP)))) {
160 			*row = orow;
161 			*col = ocol;
162 			return(0);
163 		}
164 		if ((i != 0) && rogue_can_see(orow, ocol)) {
165 			mvaddch(orow, ocol, get_dungeon_char(orow, ocol));
166 		}
167 		if (rogue_can_see(*row, *col)) {
168 			if (!(dungeon[*row][*col] & MONSTER)) {
169 				mvaddch(*row, *col, ch);
170 			}
171 			refresh();
172 		}
173 		orow = *row; ocol = *col;
174 		if (dungeon[*row][*col] & MONSTER) {
175 			if (!imitating(*row, *col)) {
176 				return(object_at(&level_monsters, *row, *col));
177 			}
178 		}
179 		if (dungeon[*row][*col] & TUNNEL) {
180 			i += 2;
181 		}
182 	}
183 	return(0);
184 }
185 
186 flop_weapon(weapon, row, col)
187 object *weapon;
188 short row, col;
189 {
190 	object *new_weapon, *monster;
191 	short i = 0;
192 	char msg[80];
193 	boolean found = 0;
194 	short mch, dch;
195 	unsigned short mon;
196 
197 	while ((i < 9) && dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER)) {
198 		rand_around(i++, &row, &col);
199 		if ((row > (DROWS-2)) || (row < MIN_ROW) ||
200 			(col > (DCOLS-1)) || (col < 0) || (!dungeon[row][col]) ||
201 			(dungeon[row][col] & ~(FLOOR | TUNNEL | DOOR | MONSTER))) {
202 			continue;
203 		}
204 		found = 1;
205 		break;
206 	}
207 
208 	if (found || (i == 0)) {
209 		new_weapon = alloc_object();
210 		*new_weapon = *weapon;
211 		new_weapon->in_use_flags = NOT_USED;
212 		new_weapon->quantity = 1;
213 		new_weapon->ichar = 'L';
214 		place_at(new_weapon, row, col);
215 		if (rogue_can_see(row, col) &&
216 				((row != rogue.row) || (col != rogue.col))) {
217 			mon = dungeon[row][col] & MONSTER;
218 			dungeon[row][col] &= (~MONSTER);
219 			dch = get_dungeon_char(row, col);
220 			if (mon) {
221 				mch = mvinch(row, col);
222 				if (monster = object_at(&level_monsters, row, col)) {
223 					monster->trail_char = dch;
224 				}
225 				if ((mch < 'A') || (mch > 'Z')) {
226 					mvaddch(row, col, dch);
227 				}
228 			} else {
229 				mvaddch(row, col, dch);
230 			}
231 			dungeon[row][col] |= mon;
232 		}
233 	} else {
234 		short t;
235 
236 		t = weapon->quantity;
237 		weapon->quantity = 1;
238 		sprintf(msg, "the %svanishes as it hits the ground",
239 		name_of(weapon));
240 		weapon->quantity = t;
241 		message(msg, 0);
242 	}
243 }
244 
245 rand_around(i, r, c)
246 short i, *r, *c;
247 {
248 	static char* pos = "\010\007\001\003\004\005\002\006\0";
249 	static short row, col;
250 	short j;
251 
252 	if (i == 0) {
253 		short x, y, o, t;
254 
255 		row = *r;
256 		col = *c;
257 
258 		o = get_rand(1, 8);
259 
260 		for (j = 0; j < 5; j++) {
261 			x = get_rand(0, 8);
262 			y = (x + o) % 9;
263 			t = pos[x];
264 			pos[x] = pos[y];
265 			pos[y] = t;
266 		}
267 	}
268 	switch((short)pos[i]) {
269 	case 0:
270 		*r = row + 1;
271 		*c = col + 1;
272 		break;
273 	case 1:
274 		*r = row + 1;
275 		*c = col - 1;
276 		break;
277 	case 2:
278 		*r = row - 1;
279 		*c = col + 1;
280 		break;
281 	case 3:
282 		*r = row - 1;
283 		*c = col - 1;
284 		break;
285 	case 4:
286 		*r = row;
287 		*c = col + 1;
288 		break;
289 	case 5:
290 		*r = row + 1;
291 		*c = col;
292 		break;
293 	case 6:
294 		*r = row;
295 		*c = col;
296 		break;
297 	case 7:
298 		*r = row - 1;
299 		*c = col;
300 		break;
301 	case 8:
302 		*r = row;
303 		*c = col - 1;
304 		break;
305 	}
306 }
307