comparison urogue/weapons.c @ 256:c495a4f288c6

Import UltraRogue from the Roguelike Restoration Project (r1490)
author John "Elwin" Edwards
date Tue, 31 Jan 2017 19:56:04 -0500
parents
children
comparison
equal deleted inserted replaced
253:d9badb9c0179 256:c495a4f288c6
1 /*
2 weapons.c - Functions for dealing with problems brought about by weapons
3
4 UltraRogue: The Ultimate Adventure in the Dungeons of Doom
5 Copyright (C) 1985, 1986, 1992, 1993, 1995 Herb Chong
6 All rights reserved.
7
8 Based on "Advanced Rogue"
9 Copyright (C) 1984, 1985 Michael Morgan, Ken Dalka
10 All rights reserved.
11
12 Based on "Rogue: Exploring the Dungeons of Doom"
13 Copyright (C) 1980, 1981 Michael Toy, Ken Arnold and Glenn Wichman
14 All rights reserved.
15
16 See the file LICENSE.TXT for full copyright and licensing information.
17 */
18
19 #include <ctype.h>
20 #include <string.h>
21 #include "rogue.h"
22
23 /*
24 missile()
25 Fire a missile in a given direction
26 */
27
28 void
29 missile(int ydelta, int xdelta, struct linked_list *item, struct thing *tp)
30 {
31 struct object *obj;
32 struct linked_list *nitem;
33
34 if (item == NULL) /* Get which thing we are hurling */
35 return;
36
37 obj = OBJPTR(item);
38
39 if (!dropcheck(obj) || is_current(obj))
40 return;
41
42 /*
43 * Get rid of the thing. If it is a non-multiple item object, or if
44 * it is the last thing, just drop it. Otherwise, create a new item
45 * with a count of one.
46 */
47
48 if (obj->o_count < 2)
49 {
50 if (tp->t_pack == pack)
51 rem_pack(obj);
52 else
53 detach(tp->t_pack, item);
54 }
55 else
56 {
57 obj->o_count--;
58 nitem = (struct linked_list *) new_item(sizeof *obj);
59 obj = OBJPTR(nitem);
60 *obj = *(OBJPTR(item));
61 obj->o_count = 1;
62 item = nitem;
63 }
64
65 switch (obj->o_type)
66 {
67 case ARTIFACT:
68 has_artifact &= ~(1 << obj->o_which);
69 break;
70
71 case SCROLL:
72 if (obj->o_which == S_SCARE && obj->o_flags & ISBLESSED)
73 obj->o_flags &= ~ISBLESSED;
74 else
75 obj->o_flags |= ISCURSED;
76 }
77
78 updpack();
79 obj->o_pos = do_motion(obj->o_type, ydelta, xdelta, tp);
80
81 /*
82 * AHA! Here it has hit something. If it is a wall or a door, or if
83 * it misses (combat) the monster, put it on the floor
84 */
85
86 if (!hit_monster(obj->o_pos.y, obj->o_pos.x, obj, tp))
87 {
88 if (obj->o_type == WEAPON && obj->o_which == GRENADE)
89 {
90 hearmsg("BOOOM!");
91 aggravate();
92
93 if (ntraps + 1 < 2 * MAXTRAPS &&
94 fallpos(obj->o_pos, &traps[ntraps].tr_pos))
95 {
96 mvaddch(traps[ntraps].tr_pos.y, traps[ntraps].tr_pos.x,
97 TRAPDOOR);
98 traps[ntraps].tr_type = TRAPDOOR;
99 traps[ntraps].tr_flags = ISFOUND;
100 traps[ntraps].tr_show = TRAPDOOR;
101 ntraps++;
102 light(&hero);
103 }
104 discard(item);
105 }
106 else if (obj->o_flags & ISLOST)
107 {
108 if (obj->o_type == WEAPON)
109 addmsg("The %s", weaps[obj->o_which].w_name);
110 else
111 addmsg(inv_name(obj, LOWERCASE));
112
113 msg(" vanishes in a puff of greasy smoke.");
114 discard(item);
115 }
116 else
117 {
118 fall(&player, item, TRUE, TRUE);
119
120 if (obj->o_flags & CANRETURN)
121 msg("You have %s.", inv_name(obj, LOWERCASE));
122 }
123 }
124 else if (obj->o_flags & ISOWNED)
125 {
126 add_pack(item, NOMESSAGE);
127 msg("You have %s.", inv_name(obj, LOWERCASE));
128 }
129
130 mvwaddch(cw, hero.y, hero.x, PLAYER);
131 }
132
133 /*
134 do_motion()
135 do the actual motion on the screen done by an object
136 traveling across the room
137 */
138
139 coord
140 do_motion(int ob, int ydelta, int xdelta, struct thing *tp)
141 {
142 coord pos;
143 /* Come fly with us ... */
144
145 pos = tp->t_pos;
146
147 for (;;)
148 {
149 int ch;
150
151 /* Erase the old one */
152
153 if (!ce(pos, tp->t_pos) &&
154 cansee(pos.y, pos.x) &&
155 mvwinch(cw, pos.y, pos.x) != ' ')
156 {
157 mvwaddch(cw, pos.y, pos.x, show(pos.y, pos.x));
158 }
159
160 /* Get the new position */
161
162 pos.y += ydelta;
163 pos.x += xdelta;
164
165 if (shoot_ok(ch = winat(pos.y, pos.x)) &&
166 ch != DOOR && !ce(pos, hero))
167 {
168 /* It hasn't hit anything yet, so display it if it alright. */
169
170 if (cansee(pos.y, pos.x) &&
171 mvwinch(cw, pos.y, pos.x) != ' ')
172 {
173 mvwaddch(cw, pos.y, pos.x, ob);
174 wrefresh(cw);
175 }
176
177 continue;
178
179 }
180 break;
181 }
182
183 return(pos);
184 }
185
186 /*
187 fall()
188 Drop an item someplace around here.
189 */
190
191 void
192 fall(struct thing *tp, struct linked_list *item, int pr, int player_owned)
193 {
194 struct object *obj;
195 struct room *rp;
196 coord fpos;
197
198 obj = OBJPTR(item);
199 rp = roomin(tp->t_pos);
200
201 if (player_owned && obj->o_flags & CANRETURN)
202 {
203 add_pack(item, NOMESSAGE);
204 msg("You have %s.", inv_name(obj, LOWERCASE));
205 return;
206 }
207 else if (fallpos(obj->o_pos, &fpos))
208 {
209 if (obj->o_flags & CANBURN && obj->o_type == WEAPON
210 && obj->o_which == MOLOTOV
211 && ntraps + 1 < 2 * MAXTRAPS)
212 {
213 mvaddch(fpos.y, fpos.x, FIRETRAP);
214 traps[ntraps].tr_type = FIRETRAP;
215 traps[ntraps].tr_flags = ISFOUND;
216 traps[ntraps].tr_show = FIRETRAP;
217 traps[ntraps].tr_pos = fpos;
218 ntraps++;
219
220 if (rp != NULL)
221 rp->r_flags &= ~ISDARK;
222 }
223 else
224 {
225 obj->o_pos = fpos;
226 add_obj(item, fpos.y, fpos.x);
227 }
228
229 if (rp != NULL &&
230 (!(rp->r_flags & ISDARK) ||
231 (rp->r_flags & HASFIRE)))
232 {
233 light(&hero);
234 mvwaddch(cw, hero.y, hero.x, PLAYER);
235 }
236 return;
237 }
238
239 /* get here only if there isn't a place to put it */
240
241 if (pr)
242 {
243 if (cansee(obj->o_pos.y, obj->o_pos.x))
244 {
245 if (obj->o_type == WEAPON)
246 addmsg("The %s", weaps[obj->o_which].w_name);
247 else
248 addmsg(inv_name(obj, LOWERCASE));
249
250 msg(" vanishes as it hits the ground.");
251 }
252 }
253 discard(item);
254 }
255
256 /*
257 init_weapon()
258 Set up the initial goodies for a weapon
259 */
260
261 void
262 init_weapon(struct object *weap, int type)
263 {
264 struct init_weps *iwp = &weaps[type];
265
266 weap->o_damage = iwp->w_dam;
267 weap->o_hurldmg = iwp->w_hrl;
268 weap->o_launch = iwp->w_launch;
269 weap->o_flags = iwp->w_flags;
270 weap->o_weight = iwp->w_wght;
271
272 if (weap->o_flags & ISMANY)
273 {
274 weap->o_count = rnd(8) + 8;
275 weap->o_group = ++group;
276 }
277 else
278 weap->o_count = 1;
279 }
280
281 /*
282 hit_monster()
283 does the missile hit the target?
284 */
285
286 int
287 hit_monster(int y, int x, struct object *weapon, struct thing *thrower)
288 {
289 struct linked_list *mon;
290 coord target;
291
292 target.y = y;
293 target.x = x;
294
295 if (thrower == &player)
296 return(fight(&target, weapon, THROWN));
297
298 if (ce(target, hero))
299 {
300 if (good_monster(*thrower))
301 {
302 if (on(*thrower, ISFAMILIAR))
303 msg("Please get out of the way, Master! I nearly hit you.");
304 else
305 msg("Get out of the way %s!", whoami);
306
307 return(FALSE);
308 }
309
310 return(attack(thrower, weapon, THROWN));
311 }
312
313 if ((mon = find_mons(y, x)) != NULL)
314 return(mon_mon_attack(thrower, mon, weapon, THROWN));
315 else
316 return(FALSE);
317 }
318
319
320 /*
321 num()
322 Figure out the plus number for armor/weapons
323 */
324
325 char *
326 num(int n1, int n2, char *buf)
327 {
328 if (buf == NULL)
329 return("UltraRogue Error #104");
330
331 if (n1 == 0 && n2 == 0)
332 {
333 strcpy(buf,"+0");
334 return(buf);
335 }
336
337 if (n2 == 0)
338 sprintf(buf, "%s%d", n1 < 0 ? "" : "+", n1);
339 else
340 sprintf(buf, "%s%d, %s%d", n1 < 0 ? "" : "+",
341 n1, n2 < 0 ? "" : "+", n2);
342
343 return(buf);
344 }
345
346 /*
347 wield()
348 Pull out a certain weapon
349 */
350
351 void
352 wield(void)
353 {
354 struct linked_list *item;
355 struct object *obj, *oweapon;
356
357 oweapon = cur_weapon;
358
359 if (!dropcheck(cur_weapon))
360 {
361 cur_weapon = oweapon;
362 return;
363 }
364
365 cur_weapon = oweapon;
366
367 if ((item = get_item("wield", WEAPON)) == NULL)
368 {
369 after = FALSE;
370 return;
371 }
372
373 obj = OBJPTR(item);
374
375 if (is_current(obj))
376 {
377 after = FALSE;
378 return;
379 }
380
381 wield_ok(&player, obj, TRUE);
382
383 msg("You are now wielding %s.", inv_name(obj, LOWERCASE));
384
385 cur_weapon = obj;
386 }
387
388 /*
389 fallpos()
390 pick a random position around the given (y, x) coordinates
391 */
392
393 int
394 fallpos(coord pos, coord *newpos) /*ARGSUSED*/
395 {
396 int y, x, cnt;
397 coord places[9];
398
399 cnt = 0;
400
401 /* look for all the places that qualify */
402
403 for (y = pos.y - 1; y <= pos.y + 1; y++)
404 {
405 for (x = pos.x - 1; x <= pos.x + 1; x++)
406 {
407 switch(CCHAR(mvwinch(stdscr,y,x)))
408 {
409 case GOLD:
410 case POTION:
411 case SCROLL:
412 case FOOD:
413 case WEAPON:
414 case ARMOR:
415 case RING:
416 case STICK:
417 case FLOOR:
418 case PASSAGE:
419 case ARTIFACT:
420 places[cnt].y = y;
421 places[cnt].x = x;
422 cnt++;
423 }
424 }
425 }
426
427 /* now, pick one of the places, if there are any */
428
429 if (cnt > 0)
430 {
431 int which = rnd(cnt);
432
433 newpos->y = places[which].y;
434 newpos->x = places[which].x;
435
436 debug("Dropping object at %d, %d", newpos->y, newpos->x);
437 }
438
439 return(cnt);
440 }
441
442 /*
443 wield_ok()
444 enforce player class weapons restrictions
445 */
446
447 int
448 wield_ok(struct thing *wieldee, struct object *obj, int print_message)
449 {
450 int ret_val = TRUE;
451 int class_type = wieldee->t_ctype;
452
453 if (obj->o_type != WEAPON)
454 {
455 ret_val = FALSE;
456 return(ret_val);
457 }
458 else
459 switch (class_type)
460 {
461 case C_MAGICIAN: /* need one hand free */
462 case C_ILLUSION:
463 if (obj->o_flags & ISTWOH)
464 ret_val = FALSE;
465 break;
466
467 case C_THIEF: /* need portable weapon */
468 case C_ASSASIN:
469 case C_NINJA:
470 if (obj->o_flags & ISTWOH)
471 ret_val = FALSE;
472 break;
473
474 case C_CLERIC: /* No sharp weapons */
475 if (obj->o_flags & ISSHARP)
476 ret_val = FALSE;
477 break;
478
479 case C_DRUID: /* No non-silver metal weapons */
480 if (obj->o_flags & ISMETAL && !(obj->o_flags & ISSILVER))
481 ret_val = FALSE;
482 break;
483
484 case C_PALADIN: /* must wield sharp stuff */
485 if ((obj->o_flags & ISSHARP) == FALSE)
486 ret_val = FALSE;
487 break;
488
489 case C_FIGHTER: /* wield anything */
490 case C_RANGER:
491 case C_MONSTER:
492 break;
493
494 default: /* Unknown class */
495 debug("Unknown class %d.", class_type);
496 break;
497 }
498
499 if (itemweight(obj) > 18 * pstats.s_str)
500 {
501 if (wieldee == &player && print_message == TRUE)
502 msg("That is too heavy for you to swing effectively!");
503
504 ret_val = FALSE;
505 return(ret_val);
506 }
507
508 if (ret_val == FALSE && print_message == MESSAGE)
509 switch (class_type)
510 {
511 case C_MAGICIAN:
512 case C_ILLUSION:
513 msg("You'll find it hard to cast spells while wielding that!");
514 break;
515
516 case C_THIEF:
517 case C_ASSASIN:
518 case C_NINJA:
519 msg("Don't expect to backstab anyone while wielding that!");
520 break;
521
522 case C_CLERIC:
523 case C_DRUID:
524 case C_PALADIN:
525 msg("Your god strongly disapproves of your wielding that!");
526 break;
527
528 case C_FIGHTER:
529 case C_RANGER:
530 case C_MONSTER:
531 break;
532 }
533
534 return(ret_val);
535 }
536
537 /*
538 shoot_ok()
539 returns true if it is ok for type to shoot over ch
540 */
541
542 int
543 shoot_ok(int ch)
544 {
545 switch(ch)
546 {
547 case ' ':
548 case '|':
549 case '-':
550 case SECRETDOOR:
551 return(FALSE);
552
553 default:
554 return(!isalpha(ch));
555 }
556 }