1 /* SCCS Id: @(#)tech.c 3.2 98/Oct/30 */
2 /* Original Code by Warren Cheung (Basis: spell.c, attrib.c) */
3 /* Copyright (c) M. Stephenson 1988 */
4 /* NetHack may be freely redistributed. See license for details. */
5
6 /* All of the techs from cmd.c are ported here */
7
8 #include "hack.h"
9
10 /* #define DEBUG */ /* turn on for diagnostics */
11
12 static boolean FDECL(gettech, (int *));
13 static boolean FDECL(dotechmenu, (int, int *));
14 static void NDECL(doblitzlist);
15 static int FDECL(get_tech_no,(int));
16 static int FDECL(techeffects, (int));
17 static void FDECL(hurtmon, (struct monst *,int));
18 static int FDECL(mon_to_zombie, (int));
19 STATIC_PTR int NDECL(tinker);
20 STATIC_PTR int NDECL(draw_energy);
21 static const struct innate_tech * NDECL(role_tech);
22 static const struct innate_tech * NDECL(race_tech);
23 static int NDECL(doblitz);
24 static int NDECL(blitz_chi_strike);
25 static int NDECL(blitz_e_fist);
26 static int NDECL(blitz_pummel);
27 static int NDECL(blitz_g_slam);
28 static int NDECL(blitz_dash);
29 static int NDECL(blitz_power_surge);
30 static int NDECL(blitz_spirit_bomb);
31
32 static NEARDATA schar delay; /* moves left for tinker/energy draw */
33 static NEARDATA const char revivables[] = { ALLOW_FLOOROBJ, FOOD_CLASS, 0 };
34
35 /*
36 * Do try to keep the names <= 25 chars long, or else the
37 * menu will look bad :B WAC
38 */
39
40 STATIC_OVL NEARDATA const char *tech_names[] = {
41 "no technique",
42 "berserk",
43 "kiii",
44 "research",
45 "surgery",
46 "reinforce memory",
47 "missile flurry",
48 "weapon practice",
49 "eviscerate",
50 "healing hands",
51 "calm steed",
52 "turn undead",
53 "vanish",
54 "cutthroat",
55 "blessing",
56 "elemental fist",
57 "primal roar",
58 "liquid leap",
59 "critical strike",
60 "sigil of control",
61 "sigil of tempest",
62 "sigil of discharge",
63 "raise zombies",
64 "revivification",
65 "ward against flame",
66 "ward against ice",
67 "ward against lightning",
68 "tinker",
69 "rage eruption",
70 "blink",
71 "chi strike",
72 "draw energy",
73 "chi healing",
74 "disarm",
75 "dazzle",
76 "chained blitz",
77 "pummel",
78 "ground slam",
79 "air dash",
80 "power surge",
81 "spirit bomb",
82 "draw blood",
83 ""
84 };
85
86 static const struct innate_tech
87 /* Roles */
88 arc_tech[] = { { 1, T_RESEARCH, 1},
89 { 0, 0, 0} },
90 bar_tech[] = { { 1, T_BERSERK, 1},
91 { 0, 0, 0} },
92 cav_tech[] = { { 1, T_PRIMAL_ROAR, 1},
93 { 0, 0, 0} },
94 fla_tech[] = { { 1, T_REINFORCE, 1},
95 { 3, T_POWER_SURGE, 1},
96 { 5, T_DRAW_ENERGY, 1},
97 { 10, T_SIGIL_TEMPEST, 1},
98 { 20, T_SIGIL_DISCHARGE, 1},
99 { 0, 0, 0} },
100 hea_tech[] = { { 1, T_SURGERY, 1},
101 { 20, T_REVIVE, 1},
102 { 0, 0, 0} },
103 ice_tech[] = { { 1, T_REINFORCE, 1},
104 { 5, T_DRAW_ENERGY, 1},
105 { 10, T_SIGIL_TEMPEST, 1},
106 { 12, T_POWER_SURGE, 1},
107 { 20, T_SIGIL_DISCHARGE, 1},
108 { 0, 0, 0} },
109 kni_tech[] = { { 1, T_TURN_UNDEAD, 1},
110 { 1, T_HEAL_HANDS, 1},
111 { 0, 0, 0} },
112 mon_tech[] = { { 1, T_PUMMEL, 1},
113 { 1, T_DASH, 1},
114 { 1, T_BLITZ, 1},
115 { 2, T_CHI_STRIKE, 1},
116 { 4, T_CHI_HEALING, 1},
117 { 6, T_E_FIST, 1},
118 { 8, T_DRAW_ENERGY, 1},
119 { 10, T_G_SLAM, 1},
120 { 11, T_WARD_FIRE, 1},
121 { 13, T_WARD_COLD, 1},
122 { 15, T_WARD_ELEC, 1},
123 { 17, T_SPIRIT_BOMB, 1},
124 { 20, T_POWER_SURGE, 1},
125 { 0, 0, 0} },
126 nec_tech[] = { { 1, T_REINFORCE, 1},
127 { 1, T_RAISE_ZOMBIES, 1},
128 { 10, T_POWER_SURGE, 1},
129 { 15, T_SIGIL_TEMPEST, 1},
130 { 0, 0, 0} },
131 pri_tech[] = { { 1, T_TURN_UNDEAD, 1},
132 { 1, T_BLESSING, 1},
133 { 0, 0, 0} },
134 ran_tech[] = { { 1, T_FLURRY, 1},
135 { 0, 0, 0} },
136 rog_tech[] = { { 1, T_CRIT_STRIKE, 1},
137 { 15, T_CUTTHROAT, 1},
138 { 0, 0, 0} },
139 sam_tech[] = { { 1, T_KIII, 1},
140 { 0, 0, 0} },
141 tou_tech[] = { /* Put Tech here */
142 { 0, 0, 0} },
143 und_tech[] = { { 1, T_TURN_UNDEAD, 1},
144 { 1, T_PRACTICE, 1},
145 { 0, 0, 0} },
146 val_tech[] = { { 1, T_PRACTICE, 1},
147 { 0, 0, 0} },
148 #ifdef YEOMAN
149 yeo_tech[] = {
150 #ifdef STEED
151 { 1, T_CALM_STEED, 1},
152 #endif
153 { 0, 0, 0} },
154 #endif
155 wiz_tech[] = { { 1, T_REINFORCE, 1},
156 { 3, T_DRAW_ENERGY, 1},
157 { 5, T_POWER_SURGE, 1},
158 { 7, T_SIGIL_CONTROL, 1},
159 { 14, T_SIGIL_TEMPEST, 1},
160 { 20, T_SIGIL_DISCHARGE, 1},
161 { 0, 0, 0} },
162 /* Races */
163 dop_tech[] = { { 1, T_LIQUID_LEAP, 1},
164 { 0, 0, 0} },
165 dwa_tech[] = { { 1, T_RAGE, 1},
166 { 0, 0, 0} },
167 elf_tech[] = { /* Put Tech here */
168 { 0, 0, 0} },
169 gno_tech[] = { { 1, T_VANISH, 1},
170 { 7, T_TINKER, 1},
171 { 0, 0, 0} },
172 hob_tech[] = { { 1, T_BLINK, 1},
173 { 0, 0, 0} },
174 lyc_tech[] = { { 1, T_EVISCERATE, 1},
175 { 10, T_BERSERK, 1},
176 { 0, 0, 0} },
177 vam_tech[] = { { 1, T_DAZZLE, 1},
178 { 1, T_DRAW_BLOOD, 1},
179 { 0, 0, 0} };
180 /* Orc */
181
182 /* Local Macros
183 * these give you direct access to the player's list of techs.
184 * Are you sure you don't want to use tech_inuse, which is the
185 * extern function for checking whether a fcn is inuse
186 */
187
188 #define techt_inuse(tech) tech_list[tech].t_inuse
189 #define techtout(tech) tech_list[tech].t_tout
190 #define techlev(tech) (u.ulevel - tech_list[tech].t_lev)
191 #define techid(tech) tech_list[tech].t_id
192 #define techname(tech) (tech_names[techid(tech)])
193 #define techlet(tech) \
194 ((char)((tech < 26) ? ('a' + tech) : ('A' + tech - 26)))
195
196 /* A simple pseudorandom number generator
197 *
198 * This should generate fairly random numbers that will be
199 * mod LP_HPMOD from 2 to 9, with 0 mod LP_HPMOD
200 * but can't use the normal RNG since can_limitbreak() must
201 * return the same state on the same turn.
202 * This also has to depend on things that do NOT change during
203 * save and restore, and also should only change between turns
204 */
205 #if 0 /* Probably overkill */
206 #define LB_CYCLE 259993L /* number of turns before the pattern repeats */
207 #define LB_BASE1 ((long) (monstermoves + u.uhpmax + 300L))
208 #define LB_BASE2 ((long) (moves + u.uenmax + u.ulevel + 300L))
209 #define LB_STRIP 6 /* Remove the last few bits as they tend to be less random */
210 #endif
211
212 #define LB_CYCLE 101L /* number of turns before the pattern repeats */
213 #define LB_BASE1 ((long) (monstermoves + u.uhpmax + 10L))
214 #define LB_BASE2 ((long) (moves + u.uenmax + u.ulevel + 10L))
215 #define LB_STRIP 3 /* Remove the last few bits as they tend to be less random */
216
217 #define LB_HPMOD ((long) ((u.uhp * 10 / u.uhpmax > 2) ? \
218 (u.uhp * 10 / u.uhpmax) : 2))
219
220 #define can_limitbreak() (!Upolyd && (u.uhp*10 < u.uhpmax) && \
221 (u.uhp == 1 || (!((((LB_BASE1 * \
222 LB_BASE2) % LB_CYCLE) >> LB_STRIP) \
223 % LB_HPMOD))))
224
225 /* Whether you know the tech */
226 boolean
tech_known(tech)227 tech_known(tech)
228 short tech;
229 {
230 int i;
231 for (i = 0; i < MAXTECH; i++) {
232 if (techid(i) == tech)
233 return TRUE;
234 }
235 return FALSE;
236 }
237
238 /* Called to prematurely stop a technique */
239 void
aborttech(tech)240 aborttech(tech)
241 {
242 int i;
243
244 i = get_tech_no(tech);
245 if (tech_list[i].t_inuse) {
246 switch (tech_list[i].t_id) {
247 case T_RAGE:
248 u.uhpmax -= tech_list[i].t_inuse - 1;
249 if (u.uhpmax < 1)
250 u.uhpmax = 0;
251 u.uhp -= tech_list[i].t_inuse - 1;
252 if (u.uhp < 1)
253 u.uhp = 1;
254 break;
255 case T_POWER_SURGE:
256 u.uenmax -= tech_list[i].t_inuse - 1;
257 if (u.uenmax < 1)
258 u.uenmax = 0;
259 u.uen -= tech_list[i].t_inuse - 1;
260 if (u.uen < 0)
261 u.uen = 0;
262 break;
263 }
264 tech_list[i].t_inuse = 0;
265 }
266 }
267
268 /* Called to teach a new tech. Level is starting tech level */
269 void
learntech(tech,mask,tlevel)270 learntech(tech, mask, tlevel)
271 short tech;
272 long mask;
273 int tlevel;
274 {
275 int i;
276 const struct innate_tech *tp;
277
278 i = get_tech_no(tech);
279 if (tlevel > 0) {
280 if (i < 0) {
281 i = get_tech_no(NO_TECH);
282 if (i < 0) {
283 impossible("No room for new technique?");
284 return;
285 }
286 }
287 tlevel = u.ulevel ? u.ulevel - tlevel : 0;
288 if (tech_list[i].t_id == NO_TECH) {
289 tech_list[i].t_id = tech;
290 tech_list[i].t_lev = tlevel;
291 tech_list[i].t_inuse = 0; /* not in use */
292 tech_list[i].t_intrinsic = 0;
293 }
294 else if (tech_list[i].t_intrinsic & mask) {
295 impossible("Tech already known.");
296 return;
297 }
298 if (mask == FROMOUTSIDE) {
299 tech_list[i].t_intrinsic &= ~OUTSIDE_LEVEL;
300 tech_list[i].t_intrinsic |= tlevel & OUTSIDE_LEVEL;
301 }
302 if (tlevel < tech_list[i].t_lev)
303 tech_list[i].t_lev = tlevel;
304 tech_list[i].t_intrinsic |= mask;
305 tech_list[i].t_tout = 0; /* Can use immediately*/
306 }
307 else if (tlevel < 0) {
308 if (i < 0 || !(tech_list[i].t_intrinsic & mask)) {
309 impossible("Tech not known.");
310 return;
311 }
312 tech_list[i].t_intrinsic &= ~mask;
313 if (!(tech_list[i].t_intrinsic & INTRINSIC)) {
314 if (tech_list[i].t_inuse)
315 aborttech(tech);
316 tech_list[i].t_id = NO_TECH;
317 return;
318 }
319 /* Re-calculate lowest t_lev */
320 if (tech_list[i].t_intrinsic & FROMOUTSIDE)
321 tlevel = tech_list[i].t_intrinsic & OUTSIDE_LEVEL;
322 if (tech_list[i].t_intrinsic & FROMEXPER) {
323 for(tp = role_tech(); tp->tech_id; tp++)
324 if (tp->tech_id == tech)
325 break;
326 if (!tp->tech_id)
327 impossible("No inate technique for role?");
328 else if (tlevel < 0 || tp->ulevel - tp->tech_lev < tlevel)
329 tlevel = tp->ulevel - tp->tech_lev;
330 }
331 if (tech_list[i].t_intrinsic & FROMRACE) {
332 for(tp = race_tech(); tp->tech_id; tp++)
333 if (tp->tech_id == tech)
334 break;
335 if (!tp->tech_id)
336 impossible("No inate technique for race?");
337 else if (tlevel < 0 || tp->ulevel - tp->tech_lev < tlevel)
338 tlevel = tp->ulevel - tp->tech_lev;
339 }
340 tech_list[i].t_lev = tlevel;
341 }
342 else
343 impossible("Invalid Tech Level!");
344 }
345
346 /*
347 * Return TRUE if a tech was picked, with the tech index in the return
348 * parameter. Otherwise return FALSE.
349 */
350 static boolean
gettech(tech_no)351 gettech(tech_no)
352 int *tech_no;
353 {
354 int i, ntechs, idx;
355 char ilet, lets[BUFSZ], qbuf[QBUFSZ];
356
357 for (ntechs = i = 0; i < MAXTECH; i++)
358 if (techid(i) != NO_TECH) ntechs++;
359 if (ntechs == 0) {
360 You("don't know any techniques right now.");
361 return FALSE;
362 }
363 if (flags.menu_style == MENU_TRADITIONAL) {
364 if (ntechs == 1) Strcpy(lets, "a");
365 else if (ntechs < 27) Sprintf(lets, "a-%c", 'a' + ntechs - 1);
366 else if (ntechs == 27) Sprintf(lets, "a-z A");
367 else Sprintf(lets, "a-z A-%c", 'A' + ntechs - 27);
368
369 for(;;) {
370 Sprintf(qbuf, "Perform which technique? [%s ?]", lets);
371 if ((ilet = yn_function(qbuf, (char *)0, '\0')) == '?')
372 break;
373
374 if (index(quitchars, ilet))
375 return FALSE;
376
377 if (letter(ilet) && ilet != '@') {
378 /* in a-zA-Z, convert back to an index */
379 if (lowc(ilet) == ilet) /* lower case */
380 idx = ilet - 'a';
381 else
382 idx = ilet - 'A' + 26;
383
384 if (idx < ntechs)
385 for(i = 0; i < MAXTECH; i++)
386 if (techid(i) != NO_TECH) {
387 if (idx-- == 0) {
388 *tech_no = i;
389 return TRUE;
390 }
391 }
392 }
393 You("don't know that technique.");
394 }
395 }
396 return dotechmenu(PICK_ONE, tech_no);
397 }
398
399 static boolean
dotechmenu(how,tech_no)400 dotechmenu(how, tech_no)
401 int how;
402 int *tech_no;
403 {
404 winid tmpwin;
405 int i, n, len, longest, techs_useable, tlevel;
406 char buf[BUFSZ], let = 'a';
407 const char *prefix;
408 menu_item *selected;
409 anything any;
410
411 tmpwin = create_nhwindow(NHW_MENU);
412 start_menu(tmpwin);
413 any.a_void = 0; /* zero out all bits */
414
415 techs_useable = 0;
416
417 if (!iflags.menu_tab_sep) {
418 /* find the length of the longest tech */
419 for (longest = 0, i = 0; i < MAXTECH; i++) {
420 if (techid(i) == NO_TECH) continue;
421 if ((len = strlen(techname(i))) > longest)
422 longest = len;
423 }
424 Sprintf(buf, " %-*s Level Status", longest, "Name");
425 } else
426 Sprintf(buf, "Name\tLevel\tStatus");
427
428 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
429
430 for (i = 0; i < MAXTECH; i++) {
431 if (techid(i) == NO_TECH)
432 continue;
433 tlevel = techlev(i);
434 if (!techtout(i) && tlevel > 0) {
435 /* Ready to use */
436 techs_useable++;
437 prefix = "";
438 any.a_int = i + 1;
439 } else {
440 prefix = " ";
441 any.a_int = 0;
442 }
443 #ifdef WIZARD
444 if (wizard)
445 if (!iflags.menu_tab_sep)
446 Sprintf(buf, "%s%-*s %2d%c%c%c %s(%i)",
447 prefix, longest, techname(i), tlevel,
448 tech_list[i].t_intrinsic & FROMEXPER ? 'X' : ' ',
449 tech_list[i].t_intrinsic & FROMRACE ? 'R' : ' ',
450 tech_list[i].t_intrinsic & FROMOUTSIDE ? 'O' : ' ',
451 tech_inuse(techid(i)) ? "Active" :
452 tlevel <= 0 ? "Beyond recall" :
453 can_limitbreak() ? "LIMIT" :
454 !techtout(i) ? "Prepared" :
455 techtout(i) > 100 ? "Not Ready" : "Soon",
456 techtout(i));
457 else
458 Sprintf(buf, "%s%s\t%2d%c%c%c\t%s(%i)",
459 prefix, techname(i), tlevel,
460 tech_list[i].t_intrinsic & FROMEXPER ? 'X' : ' ',
461 tech_list[i].t_intrinsic & FROMRACE ? 'R' : ' ',
462 tech_list[i].t_intrinsic & FROMOUTSIDE ? 'O' : ' ',
463 tech_inuse(techid(i)) ? "Active" :
464 tlevel <= 0 ? "Beyond recall" :
465 can_limitbreak() ? "LIMIT" :
466 !techtout(i) ? "Prepared" :
467 techtout(i) > 100 ? "Not Ready" : "Soon",
468 techtout(i));
469 else
470 #endif
471 if (!iflags.menu_tab_sep)
472 Sprintf(buf, "%s%-*s %5d %s",
473 prefix, longest, techname(i), tlevel,
474 tech_inuse(techid(i)) ? "Active" :
475 tlevel <= 0 ? "Beyond recall" :
476 can_limitbreak() ? "LIMIT" :
477 !techtout(i) ? "Prepared" :
478 techtout(i) > 100 ? "Not Ready" : "Soon");
479 else
480 Sprintf(buf, "%s%s\t%5d\t%s",
481 prefix, techname(i), tlevel,
482 tech_inuse(techid(i)) ? "Active" :
483 tlevel <= 0 ? "Beyond recall" :
484 can_limitbreak() ? "LIMIT" :
485 !techtout(i) ? "Prepared" :
486 techtout(i) > 100 ? "Not Ready" : "Soon");
487
488 add_menu(tmpwin, NO_GLYPH, &any,
489 techtout(i) ? 0 : let, 0, ATR_NONE, buf, MENU_UNSELECTED);
490 if (let++ == 'z') let = 'A';
491 }
492
493 if (!techs_useable)
494 how = PICK_NONE;
495
496 end_menu(tmpwin, how == PICK_ONE ? "Choose a technique" :
497 "Currently known techniques");
498
499 n = select_menu(tmpwin, how, &selected);
500 destroy_nhwindow(tmpwin);
501 if (n > 0) {
502 *tech_no = selected[0].item.a_int - 1;
503 free((genericptr_t)selected);
504 return TRUE;
505 }
506 return FALSE;
507 }
508
509 static int
get_tech_no(tech)510 get_tech_no(tech)
511 int tech;
512 {
513 int i;
514
515 for (i = 0; i < MAXTECH; i++) {
516 if (techid(i) == tech) {
517 return(i);
518 }
519 }
520 return (-1);
521 }
522
523 int
dotech()524 dotech()
525 {
526 int tech_no;
527
528 if (gettech(&tech_no))
529 return techeffects(tech_no);
530 return 0;
531 }
532
533 static NEARDATA const char kits[] = { TOOL_CLASS, 0 };
534
535 static struct obj *
use_medical_kit(type,feedback,verb)536 use_medical_kit(type, feedback, verb)
537 int type;
538 boolean feedback;
539 char *verb;
540 {
541 struct obj *obj, *otmp;
542 makeknown(MEDICAL_KIT);
543 if (!(obj = carrying(MEDICAL_KIT))) {
544 if (feedback) You("need a medical kit to do that.");
545 return (struct obj *)0;
546 }
547 for (otmp = invent; otmp; otmp = otmp->nobj)
548 if (otmp->otyp == MEDICAL_KIT && otmp != obj)
549 break;
550 if (otmp) { /* More than one medical kit */
551 obj = getobj(kits, verb);
552 if (!obj)
553 return (struct obj *)0;
554 }
555 for (otmp = obj->cobj; otmp; otmp = otmp->nobj)
556 if (otmp->otyp == type)
557 break;
558 if (!otmp) {
559 if (feedback)
560 You_cant("find any more %s in %s.",
561 makeplural(simple_typename(type)), yname(obj));
562 return (struct obj *)0;
563 }
564 return otmp;
565 }
566
567 /* gettech is reworked getspell */
568 /* reworked class special effects code */
569 /* adapted from specialpower in cmd.c */
570 static int
techeffects(tech_no)571 techeffects(tech_no)
572 int tech_no;
573 {
574 /* These variables are used in various techs */
575 struct obj *obj, *otmp;
576 const char *str;
577 struct monst *mtmp;
578 int num;
579 char Your_buf[BUFSZ];
580 char allowall[2];
581 int i, j, t_timeout = 0;
582
583
584 /* check timeout */
585 if (tech_inuse(techid(tech_no))) {
586 pline("This technique is already active!");
587 return (0);
588 }
589 if (techtout(tech_no) && !can_limitbreak()) {
590 You("have to wait %s before using your technique again.",
591 (techtout(tech_no) > 100) ?
592 "for a while" : "a little longer");
593 #ifdef WIZARD
594 if (!wizard || (yn("Use technique anyways?") == 'n'))
595 #endif
596 return(0);
597 }
598
599 /* switch to the tech and do stuff */
600 switch (techid(tech_no)) {
601 case T_RESEARCH:
602 /* WAC stolen from the spellcasters...'A' can identify from
603 historical research*/
604 if(Hallucination || Stunned || Confusion) {
605 You("can't concentrate right now!");
606 return(0);
607 } else if((ACURR(A_INT) + ACURR(A_WIS)) < rnd(60)) {
608 pline("Nothing in your pack looks familiar.");
609 t_timeout = rn1(500,500);
610 break;
611 } else if(invent) {
612 You("examine your possessions.");
613 identify_pack((int) ((techlev(tech_no) / 10) + 1));
614 } else {
615 /* KMH -- fixed non-compliant string */
616 You("are already quite familiar with the contents of your pack.");
617 break;
618 }
619 t_timeout = rn1(500,1500);
620 break;
621 case T_EVISCERATE:
622 /* only when empty handed, in human form */
623 if (Upolyd || uwep || uarmg) {
624 You_cant("do this while %s!", Upolyd ? "polymorphed" :
625 uwep ? "holding a weapon" : "wearing gloves");
626 return 0;
627 }
628 Your("fingernails extend into claws!");
629 aggravate();
630 techt_inuse(tech_no) = d(2,4) + techlev(tech_no)/5 + 2;
631 t_timeout = rn1(1000,1000);
632 break;
633 case T_BERSERK:
634 You("fly into a berserk rage!");
635 techt_inuse(tech_no) = d(2,8) +
636 (techlev(tech_no)/5) + 2;
637 incr_itimeout(&HFast, techt_inuse(tech_no));
638 t_timeout = rn1(1000,500);
639 break;
640 case T_REINFORCE:
641 /* WAC spell-users can study their known spells*/
642 if(Hallucination || Stunned || Confusion) {
643 You("can't concentrate right now!");
644 break;
645 } else {
646 You("concentrate...");
647 if (studyspell()) t_timeout = rn1(1000,500); /*in spell.c*/
648 }
649 break;
650 case T_FLURRY:
651 Your("%s %s become blurs as they reach for your quiver!",
652 uarmg ? "gloved" : "bare", /* Del Lamb */
653 makeplural(body_part(HAND)));
654 techt_inuse(tech_no) = rnd((int) (techlev(tech_no)/6 + 1)) + 2;
655 t_timeout = rn1(1000,500);
656 break;
657 case T_PRACTICE:
658 if(!uwep || (weapon_type(uwep) == P_NONE)) {
659 You("are not wielding a weapon!");
660 return(0);
661 } else if(uwep->known == TRUE) {
662 practice_weapon();
663 } else {
664 if (not_fully_identified(uwep)) {
665 You("examine %s.", doname(uwep));
666 if (rnd(15) <= ACURR(A_INT)) {
667 makeknown(uwep->otyp);
668 uwep->known = TRUE;
669 You("discover it is %s",doname(uwep));
670 } else
671 pline("Unfortunately, you didn't learn anything new.");
672 }
673 /*WAC Added practicing code - in weapon.c*/
674 practice_weapon();
675 }
676 t_timeout = rn1(500,500);
677 break;
678 case T_SURGERY:
679 if (Hallucination || Stunned || Confusion) {
680 You("are in no condition to perform surgery!");
681 break;
682 }
683 if (Sick || Slimed) {
684 if (carrying(SCALPEL)) {
685 pline("Using your scalpel (ow!), you cure your infection!");
686 make_sick(0L, (char *)0, TRUE, SICK_ALL);
687 Slimed = 0;
688 if (Upolyd) {
689 u.mh -= 5;
690 if (u.mh < 1)
691 rehumanize();
692 } else if (u.uhp > 6)
693 u.uhp -= 5;
694 else
695 u.uhp = 1;
696 t_timeout = rn1(500,500);
697 flags.botl = TRUE;
698 break;
699 } else pline("If only you had a scalpel...");
700 }
701 if (Upolyd ? u.mh < u.mhmax : u.uhp < u.uhpmax) {
702 otmp = use_medical_kit(BANDAGE, FALSE,
703 "dress your wounds with");
704 if (otmp) {
705 check_unpaid(otmp);
706 if (otmp->quan > 1L) {
707 otmp->quan--;
708 otmp->ocontainer->owt = weight(otmp->ocontainer);
709 } else {
710 obj_extract_self(otmp);
711 obfree(otmp, (struct obj *)0);
712 }
713 pline("Using %s, you dress your wounds.", yname(otmp));
714 healup(techlev(tech_no) * (rnd(2)+1) + rn1(5,5),
715 0, FALSE, FALSE);
716 } else {
717 You("strap your wounds as best you can.");
718 healup(techlev(tech_no) + rn1(5,5), 0, FALSE, FALSE);
719 }
720 t_timeout = rn1(1000,500);
721 flags.botl = TRUE;
722 } else You("don't need your healing powers!");
723 break;
724 case T_HEAL_HANDS:
725 if (Slimed) {
726 Your("body is on fire!");
727 burn_away_slime();
728 t_timeout = 3000;
729 } else if (Sick) {
730 You("lay your hands on the foul sickness...");
731 make_sick(0L, (char*)0, TRUE, SICK_ALL);
732 t_timeout = 3000;
733 } else if (Upolyd ? u.mh < u.mhmax : u.uhp < u.uhpmax) {
734 pline("A warm glow spreads through your body!");
735 healup(techlev(tech_no) * 4, 0, FALSE, FALSE);
736 t_timeout = 3000;
737 } else
738 pline(nothing_happens);
739 break;
740 case T_KIII:
741 You("scream \"KIIILLL!\"");
742 aggravate();
743 techt_inuse(tech_no) = rnd((int) (techlev(tech_no)/6 + 1)) + 2;
744 t_timeout = rn1(1000,500);
745 break;
746 #ifdef STEED
747 case T_CALM_STEED:
748 if (u.usteed) {
749 pline("%s gets tamer.", Monnam(u.usteed));
750 tamedog(u.usteed, (struct obj *) 0);
751 t_timeout = rn1(1000,500);
752 } else
753 Your("technique is only effective when riding a monster.");
754 break;
755 #endif
756 case T_TURN_UNDEAD:
757 return(turn_undead());
758 case T_VANISH:
759 if (Invisible && Fast) {
760 You("are already quite nimble and undetectable.");
761 }
762 techt_inuse(tech_no) = rn1(50,50) + techlev(tech_no);
763 if (!Invisible) pline("In a puff of smoke, you disappear!");
764 if (!Fast) You("feel more nimble!");
765 incr_itimeout(&HInvis, techt_inuse(tech_no));
766 incr_itimeout(&HFast, techt_inuse(tech_no));
767 newsym(u.ux,u.uy); /* update position */
768 t_timeout = rn1(1000,500);
769 break;
770 case T_CRIT_STRIKE:
771 if (!getdir((char *)0)) return(0);
772 if (!u.dx && !u.dy) {
773 /* Hopefully a mistake ;B */
774 You("decide against that idea.");
775 return(0);
776 }
777 mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
778 if (!mtmp) {
779 You("perform a flashy twirl!");
780 return (0);
781 } else {
782 int oldhp = mtmp->mhp;
783 int tmp;
784
785 if (!attack(mtmp)) return(0);
786 if (!DEADMONSTER(mtmp) && mtmp->mhp < oldhp &&
787 !noncorporeal(mtmp->data) && !unsolid(mtmp->data)) {
788 You("strike %s vital organs!", s_suffix(mon_nam(mtmp)));
789 /* Base damage is always something, though it may be
790 * reduced to zero if the hero is hampered. However,
791 * since techlev will never be zero, stiking vital
792 * organs will always do _some_ damage.
793 */
794 tmp = mtmp->mhp > 1 ? mtmp->mhp / 2 : 1;
795 if (!humanoid(mtmp->data) || is_golem(mtmp->data) ||
796 mtmp->data->mlet == S_CENTAUR) {
797 You("are hampered by the differences in anatomy.");
798 tmp /= 2;
799 }
800 tmp += techlev(tech_no);
801 t_timeout = rn1(1000, 500);
802 hurtmon(mtmp, tmp);
803 }
804 }
805 break;
806 case T_CUTTHROAT:
807 if (!is_blade(uwep)) {
808 You("need a blade to perform cutthroat!");
809 return 0;
810 }
811 if (!getdir((char *)0)) return 0;
812 if (!u.dx && !u.dy) {
813 /* Hopefully a mistake ;B */
814 pline("Things may be going badly, but that's extreme.");
815 return 0;
816 }
817 mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
818 if (!mtmp) {
819 You("attack...nothing!");
820 return 0;
821 } else {
822 int oldhp = mtmp->mhp;
823
824 if (!attack(mtmp)) return 0;
825 if (!DEADMONSTER(mtmp) && mtmp->mhp < oldhp) {
826 if (!has_head(mtmp->data) || u.uswallow)
827 You_cant("perform cutthroat on %s!", mon_nam(mtmp));
828 else {
829 int tmp = 0;
830
831 if (rn2(5) < (techlev(tech_no)/10 + 1)) {
832 You("sever %s head!", s_suffix(mon_nam(mtmp)));
833 tmp = mtmp->mhp;
834 } else {
835 You("hurt %s badly!", s_suffix(mon_nam(mtmp)));
836 tmp = mtmp->mhp / 2;
837 }
838 tmp += techlev(tech_no);
839 t_timeout = rn1(1000,500);
840 hurtmon(mtmp, tmp);
841 }
842 }
843 }
844 break;
845 case T_BLESSING:
846 allowall[0] = ALL_CLASSES; allowall[1] = '\0';
847
848 if ( !(obj = getobj(allowall, "bless"))) return(0);
849 pline("An aura of holiness surrounds your hands!");
850 if (!Blind) (void) Shk_Your(Your_buf, obj);
851 if (obj->cursed) {
852 if (!Blind)
853 pline("%s %s %s.",Your_buf,
854 aobjnam(obj, "softly glow"),
855 hcolor(NH_AMBER));
856 uncurse(obj);
857 obj->bknown=1;
858 } else if(!obj->blessed) {
859 if (!Blind) {
860 str = hcolor(NH_LIGHT_BLUE);
861 pline("%s %s with a%s %s aura.",
862 Your_buf,
863 aobjnam(obj, "softly glow"),
864 index(vowels, *str) ? "n" : "", str);
865 }
866 bless(obj);
867 obj->bknown=1;
868 } else {
869 if (obj->bknown) {
870 pline ("That object is already blessed!");
871 return(0);
872 }
873 obj->bknown=1;
874 pline("The aura fades.");
875 }
876 t_timeout = rn1(1000,500);
877 break;
878 case T_E_FIST:
879 blitz_e_fist();
880 #if 0
881 str = makeplural(body_part(HAND));
882 You("focus the powers of the elements into your %s", str);
883 techt_inuse(tech_no) = rnd((int) (techlev(tech_no)/3 + 1)) + d(1,4) + 2;
884 #endif
885 t_timeout = rn1(1000,500);
886 break;
887 case T_PRIMAL_ROAR:
888 You("let out a bloodcurdling roar!");
889 aggravate();
890
891 techt_inuse(tech_no) = d(2,6) + (techlev(tech_no)) + 2;
892
893 incr_itimeout(&HFast, techt_inuse(tech_no));
894
895 for(i = -5; i <= 5; i++) for(j = -5; j <= 5; j++)
896 if(isok(u.ux+i, u.uy+j) && (mtmp = m_at(u.ux+i, u.uy+j))) {
897 if (mtmp->mtame != 0 && !mtmp->isspell) {
898 struct permonst *ptr = mtmp->data;
899 struct monst *mtmp2;
900 int ttime = techt_inuse(tech_no);
901 int type = little_to_big(monsndx(ptr));
902
903 mtmp2 = tamedog(mtmp, (struct obj *) 0);
904 if (mtmp2)
905 mtmp = mtmp2;
906
907 if (type && type != monsndx(ptr)) {
908 ptr = &mons[type];
909 mon_spec_poly(mtmp, ptr, ttime, FALSE,
910 canseemon(mtmp), FALSE, TRUE);
911 }
912 }
913 }
914 t_timeout = rn1(1000,500);
915 break;
916 case T_LIQUID_LEAP: {
917 coord cc;
918 int dx, dy, sx, sy, range;
919
920 pline("Where do you want to leap to?");
921 cc.x = sx = u.ux;
922 cc.y = sy = u.uy;
923
924 getpos(&cc, TRUE, "the desired position");
925 if (cc.x == -10) return 0; /* user pressed esc */
926
927 dx = cc.x - u.ux;
928 dy = cc.y - u.uy;
929 /* allow diagonals */
930 if (dx && dy && dx != dy && dx != -dy) {
931 You("can only leap in straight lines!");
932 return 0;
933 } else if (distu(cc.x, cc.y) > 19 + techlev(tech_no)) {
934 pline("Too far!");
935 return 0;
936 } else if (m_at(cc.x, cc.y) || !isok(cc.x, cc.y) ||
937 IS_ROCK(levl[cc.x][cc.y].typ) ||
938 sobj_at(BOULDER, cc.x, cc.y) ||
939 closed_door(cc.x, cc.y)) {
940 You_cant("flow there!"); /* MAR */
941 return 0;
942 } else {
943 You("liquify!");
944 if (Punished) {
945 You("slip out of the iron chain.");
946 unpunish();
947 }
948 if(u.utrap) {
949 switch(u.utraptype) {
950 case TT_BEARTRAP:
951 You("slide out of the bear trap.");
952 break;
953 case TT_PIT:
954 You("leap from the pit!");
955 break;
956 case TT_WEB:
957 You("flow through the web!");
958 break;
959 case TT_LAVA:
960 You("separate from the lava!");
961 u.utrap = 0;
962 break;
963 case TT_INFLOOR:
964 u.utrap = 0;
965 You("ooze out of the floor!");
966 }
967 u.utrap = 0;
968 }
969 /* Fry the things in the path ;B */
970 if (dx) range = dx;
971 else range = dy;
972 if (range < 0) range = -range;
973
974 dx = sgn(dx);
975 dy = sgn(dy);
976
977 while (range-- > 0) {
978 int tmp_invul = 0;
979
980 if (!Invulnerable) Invulnerable = tmp_invul = 1;
981 sx += dx; sy += dy;
982 tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, AD_ACID-1));
983 tmp_at(sx,sy);
984 delay_output(); /* wait a little */
985 if ((mtmp = m_at(sx, sy)) != 0) {
986 int chance;
987
988 chance = rn2(20);
989 if (!chance || (3 - chance) > AC_VALUE(find_mac(mtmp)))
990 break;
991 setmangry(mtmp);
992 You("catch %s in your acid trail!", mon_nam(mtmp));
993 if (!resists_acid(mtmp)) {
994 int tmp = 1;
995 /* Need to add a to-hit */
996 tmp += d(2,4);
997 tmp += rn2((int) (techlev(tech_no)/5 + 1));
998 if (!Blind) pline_The("acid burns %s!", mon_nam(mtmp));
999 hurtmon(mtmp, tmp);
1000 } else if (!Blind) pline_The("acid doesn't affect %s!", mon_nam(mtmp));
1001 }
1002 /* Clean up */
1003 tmp_at(DISP_END,0);
1004 if (tmp_invul) Invulnerable = 0;
1005 }
1006
1007 /* A little Sokoban guilt... */
1008 if (In_sokoban(&u.uz))
1009 change_luck(-1);
1010 You("reform!");
1011 teleds(cc.x, cc.y, FALSE);
1012 nomul(-1);
1013 nomovemsg = "";
1014 }
1015 t_timeout = rn1(1000,500);
1016 break;
1017 }
1018 case T_SIGIL_TEMPEST:
1019 /* Have enough power? */
1020 num = 50 - techlev(tech_no)/5;
1021 if (u.uen < num) {
1022 You("don't have enough power to invoke the sigil!");
1023 return (0);
1024 }
1025 u.uen -= num;
1026
1027 /* Invoke */
1028 You("invoke the sigil of tempest!");
1029 techt_inuse(tech_no) = d(1,6) + rnd(techlev(tech_no)/5 + 1) + 2;
1030 u_wipe_engr(2);
1031 return(0);
1032 break;
1033 case T_SIGIL_CONTROL:
1034 /* Have enough power? */
1035 num = 30 - techlev(tech_no)/5;
1036 if (u.uen < num) {
1037 You("don't have enough power to invoke the sigil!");
1038 return (0);
1039 }
1040 u.uen -= num;
1041
1042 /* Invoke */
1043 You("invoke the sigil of control!");
1044 techt_inuse(tech_no) = d(1,4) + rnd(techlev(tech_no)/5 + 1) + 2;
1045 u_wipe_engr(2);
1046 return(0);
1047 break;
1048 case T_SIGIL_DISCHARGE:
1049 /* Have enough power? */
1050 num = 100 - techlev(tech_no)/5;
1051 if (u.uen < num) {
1052 You("don't have enough power to invoke the sigil!");
1053 return (0);
1054 }
1055 u.uen -= num;
1056
1057 /* Invoke */
1058 You("invoke the sigil of discharge!");
1059 techt_inuse(tech_no) = d(1,4) + rnd(techlev(tech_no)/5 + 1) + 2;
1060 u_wipe_engr(2);
1061 return(0);
1062 break;
1063 case T_RAISE_ZOMBIES:
1064 You("chant the ancient curse...");
1065 for(i = -1; i <= 1; i++) for(j = -1; j <= 1; j++) {
1066 int corpsenm;
1067
1068 if (!isok(u.ux+i, u.uy+j)) continue;
1069 for (obj = level.objects[u.ux+i][u.uy+j]; obj; obj = otmp) {
1070 otmp = obj->nexthere;
1071
1072 if (obj->otyp != CORPSE) continue;
1073 /* Only generate undead */
1074 corpsenm = mon_to_zombie(obj->corpsenm);
1075 if (corpsenm != -1 && !cant_create(&corpsenm, TRUE) &&
1076 (!obj->oxlth || obj->oattached != OATTACHED_MONST)) {
1077 /* Maintain approx. proportion of oeaten to cnutrit
1078 * so that the zombie's HP relate roughly to how
1079 * much of the original corpse was left.
1080 */
1081 if (obj->oeaten)
1082 obj->oeaten =
1083 eaten_stat(mons[corpsenm].cnutrit, obj);
1084 obj->corpsenm = corpsenm;
1085 mtmp = revive(obj);
1086 if (mtmp) {
1087 if (!resist(mtmp, SPBOOK_CLASS, 0, TELL)) {
1088 mtmp = tamedog(mtmp, (struct obj *) 0);
1089 You("dominate %s!", mon_nam(mtmp));
1090 } else setmangry(mtmp);
1091 }
1092 }
1093 }
1094 }
1095 nomul(-2); /* You need to recover */
1096 nomovemsg = 0;
1097 t_timeout = rn1(1000,500);
1098 break;
1099 case T_REVIVE:
1100 if (u.uswallow) {
1101 You(no_elbow_room);
1102 return 0;
1103 }
1104 num = 100 - techlev(tech_no); /* WAC make this depend on mon? */
1105 if ((Upolyd && u.mh <= num) || (!Upolyd && u.uhp <= num)){
1106 You("don't have the strength to perform revivification!");
1107 return 0;
1108 }
1109
1110 obj = getobj((const char *)revivables, "revive");
1111 if (!obj) return (0);
1112 mtmp = revive(obj);
1113 if (mtmp) {
1114 #ifdef BLACKMARKET
1115 if (Is_blackmarket(&u.uz))
1116 setmangry(mtmp);
1117 else
1118 #endif
1119 if (mtmp->isshk)
1120 make_happy_shk(mtmp, FALSE);
1121 else if (!resist(mtmp, SPBOOK_CLASS, 0, NOTELL))
1122 (void) tamedog(mtmp, (struct obj *) 0);
1123 }
1124 if (Upolyd) u.mh -= num;
1125 else u.uhp -= num;
1126 t_timeout = rn1(1000,500);
1127 break;
1128 case T_WARD_FIRE:
1129 /* Already have it intrinsically? */
1130 if (HFire_resistance & FROMOUTSIDE) return (0);
1131
1132 You("invoke the ward against flame!");
1133 HFire_resistance += rn1(100,50);
1134 HFire_resistance += techlev(tech_no);
1135 t_timeout = rn1(1000,500);
1136
1137 break;
1138 case T_WARD_COLD:
1139 /* Already have it intrinsically? */
1140 if (HCold_resistance & FROMOUTSIDE) return (0);
1141
1142 You("invoke the ward against ice!");
1143 HCold_resistance += rn1(100,50);
1144 HCold_resistance += techlev(tech_no);
1145 t_timeout = rn1(1000,500);
1146
1147 break;
1148 case T_WARD_ELEC:
1149 /* Already have it intrinsically? */
1150 if (HShock_resistance & FROMOUTSIDE) return (0);
1151
1152 You("invoke the ward against lightning!");
1153 HShock_resistance += rn1(100,50);
1154 HShock_resistance += techlev(tech_no);
1155 t_timeout = rn1(1000,500);
1156
1157 break;
1158 case T_TINKER:
1159 if (Blind) {
1160 You("can't do any tinkering if you can't see!");
1161 return (0);
1162 }
1163 if (!uwep) {
1164 You("aren't holding an object to work on!");
1165 return (0);
1166 }
1167 You("are holding %s.", doname(uwep));
1168 if (yn("Start tinkering on this?") != 'y') return(0);
1169 You("start working on %s",doname(uwep));
1170 delay=-150 + techlev(tech_no);
1171 set_occupation(tinker, "tinkering", 0);
1172 break;
1173 case T_RAGE:
1174 if (Upolyd) {
1175 You("cannot focus your anger!");
1176 return(0);
1177 }
1178 You("feel the anger inside you erupt!");
1179 num = 50 + (4 * techlev(tech_no));
1180 techt_inuse(tech_no) = num + 1;
1181 u.uhpmax += num;
1182 u.uhp += num;
1183 t_timeout = rn1(1000,500);
1184 break;
1185 case T_BLINK:
1186 You("feel the flow of time slow down.");
1187 techt_inuse(tech_no) = rnd(techlev(tech_no) + 1) + 2;
1188 t_timeout = rn1(1000,500);
1189 break;
1190 case T_CHI_STRIKE:
1191 if (!blitz_chi_strike()) return(0);
1192 t_timeout = rn1(1000,500);
1193 break;
1194 case T_DRAW_ENERGY:
1195 if (u.uen == u.uenmax) {
1196 if (Hallucination) You("are fully charged!");
1197 else You("cannot hold any more energy!");
1198 return(0);
1199 }
1200 You("begin drawing energy from your surroundings!");
1201 delay=-15;
1202 set_occupation(draw_energy, "drawing energy", 0);
1203 t_timeout = rn1(1000,500);
1204 break;
1205 case T_CHI_HEALING:
1206 if (u.uen < 1) {
1207 You("are too weak to attempt this!");
1208 return(0);
1209 }
1210 You("direct your internal energy to restoring your body!");
1211 techt_inuse(tech_no) = techlev(tech_no)*2 + 4;
1212 t_timeout = rn1(1000,500);
1213 break;
1214 case T_DISARM:
1215 if (P_SKILL(weapon_type(uwep)) == P_NONE) {
1216 You("aren't wielding a proper weapon!");
1217 return(0);
1218 }
1219 if ((P_SKILL(weapon_type(uwep)) < P_SKILLED) || (Blind)) {
1220 You("aren't capable of doing this!");
1221 return(0);
1222 }
1223 if (u.uswallow) {
1224 pline("What do you think %s is? A sword swallower?",
1225 mon_nam(u.ustuck));
1226 return(0);
1227 }
1228
1229 if (!getdir((char *)0)) return(0);
1230 if (!u.dx && !u.dy) {
1231 /* Hopefully a mistake ;B */
1232 pline("Why don't you try wielding something else instead.");
1233 return(0);
1234 }
1235 mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
1236 if (!mtmp || !canspotmon(mtmp)) {
1237 if (memory_is_invisible(u.ux + u.dx, u.uy + u.dy))
1238 You("don't know where to aim for!");
1239 else
1240 You("don't see anything there!");
1241 return (0);
1242 }
1243 obj = MON_WEP(mtmp); /* can be null */
1244 if (!obj) {
1245 You_cant("disarm an unarmed foe!");
1246 return(0);
1247 }
1248 /* Blindness dealt with above */
1249 if (!mon_visible(mtmp)
1250 #ifdef INVISIBLE_OBJECTS
1251 || obj->oinvis && !See_invisible
1252 #endif
1253 ) {
1254 You_cant("see %s weapon!", s_suffix(mon_nam(mtmp)));
1255 return(0);
1256 }
1257 num = ((rn2(techlev(tech_no) + 15))
1258 * (P_SKILL(weapon_type(uwep)) - P_SKILLED + 1)) / 10;
1259
1260 You("attempt to disarm %s...",mon_nam(mtmp));
1261 /* WAC can't yank out cursed items */
1262 if (num > 0 && (!Fumbling || !rn2(10)) && !obj->cursed) {
1263 int roll;
1264 obj_extract_self(obj);
1265 possibly_unwield(mtmp, FALSE);
1266 setmnotwielded(mtmp, obj);
1267 roll = rn2(num + 1);
1268 if (roll > 3) roll = 3;
1269 switch (roll) {
1270 case 2:
1271 /* to floor near you */
1272 You("knock %s %s to the %s!",
1273 s_suffix(mon_nam(mtmp)),
1274 xname(obj),
1275 surface(u.ux, u.uy));
1276 if (obj->otyp == CRYSKNIFE &&
1277 (!obj->oerodeproof || !rn2(10))) {
1278 obj->otyp = WORM_TOOTH;
1279 obj->oerodeproof = 0;
1280 }
1281 place_object(obj, u.ux, u.uy);
1282 stackobj(obj);
1283 break;
1284 case 3:
1285 #if 0
1286 if (!rn2(25)) {
1287 /* proficient at disarming, but maybe not
1288 so proficient at catching weapons */
1289 int hitu, hitvalu;
1290
1291 hitvalu = 8 + obj->spe;
1292 hitu = thitu(hitvalu,
1293 dmgval(obj, &youmonst),
1294 obj, xname(obj));
1295 if (hitu)
1296 pline("%s hits you as you try to snatch it!",
1297 The(xname(obj)));
1298 place_object(obj, u.ux, u.uy);
1299 stackobj(obj);
1300 break;
1301 }
1302 #endif /* 0 */
1303 /* right into your inventory */
1304 You("snatch %s %s!", s_suffix(mon_nam(mtmp)),
1305 xname(obj));
1306 if (obj->otyp == CORPSE &&
1307 touch_petrifies(&mons[obj->corpsenm]) &&
1308 !uarmg && !Stone_resistance &&
1309 !(poly_when_stoned(youmonst.data) &&
1310 polymon(PM_STONE_GOLEM))) {
1311 char kbuf[BUFSZ];
1312
1313 Sprintf(kbuf, "%s corpse",
1314 an(mons[obj->corpsenm].mname));
1315 pline("Snatching %s is a fatal mistake.", kbuf);
1316 instapetrify(kbuf);
1317 }
1318 obj = hold_another_object(obj, "You drop %s!",
1319 doname(obj), (const char *)0);
1320 break;
1321 default:
1322 /* to floor beneath mon */
1323 You("knock %s from %s grasp!", the(xname(obj)),
1324 s_suffix(mon_nam(mtmp)));
1325 if (obj->otyp == CRYSKNIFE &&
1326 (!obj->oerodeproof || !rn2(10))) {
1327 obj->otyp = WORM_TOOTH;
1328 obj->oerodeproof = 0;
1329 }
1330 place_object(obj, mtmp->mx, mtmp->my);
1331 stackobj(obj);
1332 break;
1333 }
1334 } else if (mtmp->mcanmove && !mtmp->msleeping)
1335 pline("%s evades your attack.", Monnam(mtmp));
1336 else
1337 You("fail to dislodge %s %s.", s_suffix(mon_nam(mtmp)),
1338 xname(obj));
1339 wakeup(mtmp);
1340 if (!mtmp->mcanmove && !rn2(10)) {
1341 mtmp->mcanmove = 1;
1342 mtmp->mfrozen = 0;
1343 }
1344 break;
1345 case T_DAZZLE:
1346 /* Short range stun attack */
1347 if (Blind) {
1348 You("can't see anything!");
1349 return(0);
1350 }
1351 if (!getdir((char *)0)) return(0);
1352 if (!u.dx && !u.dy) {
1353 /* Hopefully a mistake ;B */
1354 You("can't see yourself!");
1355 return(0);
1356 }
1357 for(i = 0; (i <= ((techlev(tech_no) / 8) + 1)
1358 && isok(u.ux + (i*u.dx), u.uy + (i*u.dy))); i++) {
1359 mtmp = m_at(u.ux + (i*u.dx), u.uy + (i*u.dy));
1360 if (mtmp && canseemon(mtmp)) break;
1361 }
1362 if (!mtmp || !canseemon(mtmp)) {
1363 You("fail to make eye contact with anything!");
1364 return (0);
1365 }
1366 You("stare at %s.", mon_nam(mtmp));
1367 if (!haseyes(mtmp->data))
1368 pline("..but %s has no eyes!", mon_nam(mtmp));
1369 else if (!mtmp->mcansee)
1370 pline("..but %s cannot see you!", mon_nam(mtmp));
1371 if ((rn2(6) + rn2(6) + (techlev(tech_no) - mtmp->m_lev)) > 10) {
1372 You("dazzle %s!", mon_nam(mtmp));
1373 mtmp->mcanmove = 0;
1374 mtmp->mfrozen = rnd(10);
1375 } else {
1376 pline("%s breaks the stare!", Monnam(mtmp));
1377 }
1378 t_timeout = rn1(50,25);
1379 break;
1380 case T_BLITZ:
1381 if (uwep || (u.twoweap && uswapwep)) {
1382 You("can't do this while wielding a weapon!");
1383 return(0);
1384 } else if (uarms) {
1385 You("can't do this while holding a shield!");
1386 return(0);
1387 }
1388 if (!doblitz()) return (0);
1389
1390 t_timeout = rn1(1000,500);
1391 break;
1392 case T_PUMMEL:
1393 if (uwep || (u.twoweap && uswapwep)) {
1394 You("can't do this while wielding a weapon!");
1395 return(0);
1396 } else if (uarms) {
1397 You("can't do this while holding a shield!");
1398 return(0);
1399 }
1400 if (!getdir((char *)0)) return(0);
1401 if (!u.dx && !u.dy) {
1402 You("flex your muscles.");
1403 return(0);
1404 }
1405 if (!blitz_pummel()) return(0);
1406 t_timeout = rn1(1000,500);
1407 break;
1408 case T_G_SLAM:
1409 if (uwep || (u.twoweap && uswapwep)) {
1410 You("can't do this while wielding a weapon!");
1411 return(0);
1412 } else if (uarms) {
1413 You("can't do this while holding a shield!");
1414 return(0);
1415 }
1416 if (!getdir((char *)0)) return(0);
1417 if (!u.dx && !u.dy) {
1418 You("flex your muscles.");
1419 return(0);
1420 }
1421 if (!blitz_g_slam()) return(0);
1422 t_timeout = rn1(1000,500);
1423 break;
1424 case T_DASH:
1425 if (!getdir((char *)0)) return(0);
1426 if (!u.dx && !u.dy) {
1427 You("stretch.");
1428 return(0);
1429 }
1430 if (!blitz_dash()) return(0);
1431 t_timeout = rn1(50, 25);
1432 break;
1433 case T_POWER_SURGE:
1434 if (!blitz_power_surge()) return(0);
1435 t_timeout = rn1(1000,500);
1436 break;
1437 case T_SPIRIT_BOMB:
1438 if (uwep || (u.twoweap && uswapwep)) {
1439 You("can't do this while wielding a weapon!");
1440 return(0);
1441 } else if (uarms) {
1442 You("can't do this while holding a shield!");
1443 return(0);
1444 }
1445 if (!getdir((char *)0)) return(0);
1446 if (!blitz_spirit_bomb()) return(0);
1447 t_timeout = rn1(1000,500);
1448 break;
1449 case T_DRAW_BLOOD:
1450 if (!maybe_polyd(is_vampire(youmonst.data),
1451 Race_if(PM_VAMPIRE))) {
1452 /* ALI
1453 * Otherwise we get problems with what we create:
1454 * potions of vampire blood would no longer be
1455 * appropriate.
1456 */
1457 You("must be in your natural form to draw blood.");
1458 return(0);
1459 }
1460 obj = use_medical_kit(PHIAL, TRUE, "draw blood with");
1461 if (!obj)
1462 return 0;
1463 if (u.ulevel <= 1) {
1464 You_cant("seem to find a vein.");
1465 return 0;
1466 }
1467 check_unpaid(obj);
1468 if (obj->quan > 1L)
1469 obj->quan--;
1470 else {
1471 obj_extract_self(obj);
1472 obfree(obj, (struct obj *)0);
1473 }
1474 pline("Using your medical kit, you draw off a phial of your blood.");
1475 losexp("drawing blood", TRUE);
1476 if (u.uexp > 0)
1477 u.uexp = newuexp(u.ulevel - 1);
1478 otmp = mksobj(POT_VAMPIRE_BLOOD, FALSE, FALSE);
1479 otmp->cursed = obj->cursed;
1480 otmp->blessed = obj->blessed;
1481 (void) hold_another_object(otmp,
1482 "You fill, but have to drop, %s!", doname(otmp),
1483 (const char *)0);
1484 t_timeout = rn1(1000, 500);
1485 break;
1486 default:
1487 pline ("Error! No such effect (%i)", tech_no);
1488 break;
1489 }
1490 if (!can_limitbreak())
1491 techtout(tech_no) = (t_timeout * (100 - techlev(tech_no))/100);
1492
1493 /*By default, action should take a turn*/
1494 return(1);
1495 }
1496
1497 /* Whether or not a tech is in use.
1498 * 0 if not in use, turns left if in use. Tech is done when techinuse == 1
1499 */
1500 int
tech_inuse(tech_id)1501 tech_inuse(tech_id)
1502 int tech_id;
1503 {
1504 int i;
1505
1506 if (tech_id < 1 || tech_id > MAXTECH) {
1507 impossible ("invalid tech: %d", tech_id);
1508 return(0);
1509 }
1510 for (i = 0; i < MAXTECH; i++) {
1511 if (techid(i) == tech_id) {
1512 return (techt_inuse(i));
1513 }
1514 }
1515 return (0);
1516 }
1517
1518 void
tech_timeout()1519 tech_timeout()
1520 {
1521 int i;
1522
1523 for (i = 0; i < MAXTECH; i++) {
1524 if (techid(i) == NO_TECH)
1525 continue;
1526 if (techt_inuse(i)) {
1527 /* Check if technique is done */
1528 if (!(--techt_inuse(i)))
1529 switch (techid(i)) {
1530 case T_EVISCERATE:
1531 You("retract your claws.");
1532 /* You're using bare hands now, so new msg for next attack */
1533 unweapon=TRUE;
1534 /* Lose berserk status */
1535 repeat_hit = 0;
1536 break;
1537 case T_BERSERK:
1538 The("red haze in your mind clears.");
1539 break;
1540 case T_KIII:
1541 You("calm down.");
1542 break;
1543 case T_FLURRY:
1544 You("relax.");
1545 break;
1546 case T_E_FIST:
1547 You("feel the power dissipate.");
1548 break;
1549 case T_SIGIL_TEMPEST:
1550 pline_The("sigil of tempest fades.");
1551 break;
1552 case T_SIGIL_CONTROL:
1553 pline_The("sigil of control fades.");
1554 break;
1555 case T_SIGIL_DISCHARGE:
1556 pline_The("sigil of discharge fades.");
1557 break;
1558 case T_RAGE:
1559 Your("anger cools.");
1560 break;
1561 case T_POWER_SURGE:
1562 pline_The("awesome power within you fades.");
1563 break;
1564 case T_BLINK:
1565 You("sense the flow of time returning to normal.");
1566 break;
1567 case T_CHI_STRIKE:
1568 You("feel the power in your hands dissipate.");
1569 break;
1570 case T_CHI_HEALING:
1571 You("feel the healing power dissipate.");
1572 break;
1573 default:
1574 break;
1575 } else switch (techid(i)) {
1576 /* During the technique */
1577 case T_RAGE:
1578 /* Bleed but don't kill */
1579 if (u.uhpmax > 1) u.uhpmax--;
1580 if (u.uhp > 1) u.uhp--;
1581 break;
1582 case T_POWER_SURGE:
1583 /* Bleed off power. Can go to zero as 0 power is not fatal */
1584 if (u.uenmax > 1) u.uenmax--;
1585 if (u.uen > 0) u.uen--;
1586 break;
1587 default:
1588 break;
1589 }
1590 }
1591
1592 if (techtout(i) > 0) techtout(i)--;
1593 }
1594 }
1595
1596 void
docalm()1597 docalm()
1598 {
1599 int i, tech, n = 0;
1600
1601 for (i = 0; i < MAXTECH; i++) {
1602 tech = techid(i);
1603 if (tech != NO_TECH && techt_inuse(i)) {
1604 aborttech(tech);
1605 n++;
1606 }
1607 }
1608 if (n)
1609 You("calm down.");
1610 }
1611
1612 static void
hurtmon(mtmp,tmp)1613 hurtmon(mtmp, tmp)
1614 struct monst *mtmp;
1615 int tmp;
1616 {
1617 mtmp->mhp -= tmp;
1618 if (mtmp->mhp < 1) killed (mtmp);
1619 #ifdef SHOW_DMG
1620 else showdmg(tmp);
1621 #endif
1622 }
1623
1624 static const struct innate_tech *
role_tech()1625 role_tech()
1626 {
1627 switch (Role_switch) {
1628 case PM_ARCHEOLOGIST: return (arc_tech);
1629 case PM_BARBARIAN: return (bar_tech);
1630 case PM_CAVEMAN: return (cav_tech);
1631 case PM_FLAME_MAGE: return (fla_tech);
1632 case PM_HEALER: return (hea_tech);
1633 case PM_ICE_MAGE: return (ice_tech);
1634 case PM_KNIGHT: return (kni_tech);
1635 case PM_MONK: return (mon_tech);
1636 case PM_NECROMANCER: return (nec_tech);
1637 case PM_PRIEST: return (pri_tech);
1638 case PM_RANGER: return (ran_tech);
1639 case PM_ROGUE: return (rog_tech);
1640 case PM_SAMURAI: return (sam_tech);
1641 #ifdef TOURIST
1642 case PM_TOURIST: return (tou_tech);
1643 #endif
1644 case PM_UNDEAD_SLAYER: return (und_tech);
1645 case PM_VALKYRIE: return (val_tech);
1646 case PM_WIZARD: return (wiz_tech);
1647 #ifdef YEOMAN
1648 case PM_YEOMAN: return (yeo_tech);
1649 #endif
1650 default: return ((struct innate_tech *) 0);
1651 }
1652 }
1653
1654 static const struct innate_tech *
race_tech()1655 race_tech()
1656 {
1657 switch (Race_switch) {
1658 case PM_DOPPELGANGER: return (dop_tech);
1659 #ifdef DWARF
1660 case PM_DWARF: return (dwa_tech);
1661 #endif
1662 case PM_ELF:
1663 case PM_DROW: return (elf_tech);
1664 case PM_GNOME: return (gno_tech);
1665 case PM_HOBBIT: return (hob_tech);
1666 case PM_HUMAN_WEREWOLF: return (lyc_tech);
1667 case PM_VAMPIRE: return (vam_tech);
1668 default: return ((struct innate_tech *) 0);
1669 }
1670 }
1671
1672 void
adjtech(oldlevel,newlevel)1673 adjtech(oldlevel,newlevel)
1674 int oldlevel, newlevel;
1675 {
1676 const struct innate_tech
1677 *tech = role_tech(), *rtech = race_tech();
1678 long mask = FROMEXPER;
1679
1680 while (tech || rtech) {
1681 /* Have we finished with the tech lists? */
1682 if (!tech || !tech->tech_id) {
1683 /* Try the race intrinsics */
1684 if (!rtech || !rtech->tech_id) break;
1685 tech = rtech;
1686 rtech = (struct innate_tech *) 0;
1687 mask = FROMRACE;
1688 }
1689
1690 for(; tech->tech_id; tech++)
1691 if(oldlevel < tech->ulevel && newlevel >= tech->ulevel) {
1692 if (tech->ulevel != 1 && !tech_known(tech->tech_id))
1693 You("learn how to perform %s!",
1694 tech_names[tech->tech_id]);
1695 learntech(tech->tech_id, mask, tech->tech_lev);
1696 } else if (oldlevel >= tech->ulevel && newlevel < tech->ulevel
1697 && tech->ulevel != 1) {
1698 learntech(tech->tech_id, mask, -1);
1699 if (!tech_known(tech->tech_id))
1700 You("lose the ability to perform %s!",
1701 tech_names[tech->tech_id]);
1702 }
1703 }
1704 }
1705
1706 int
mon_to_zombie(monnum)1707 mon_to_zombie(monnum)
1708 int monnum;
1709 {
1710 if ((&mons[monnum])->mlet == S_ZOMBIE) return monnum; /* is already zombie */
1711 if ((&mons[monnum])->mlet == S_KOBOLD) return PM_KOBOLD_ZOMBIE;
1712 if ((&mons[monnum])->mlet == S_GNOME) return PM_GNOME_ZOMBIE;
1713 if (is_orc(&mons[monnum])) return PM_ORC_ZOMBIE;
1714 if (is_dwarf(&mons[monnum])) return PM_DWARF_ZOMBIE;
1715 if (is_elf(&mons[monnum])) return PM_ELF_ZOMBIE;
1716 if (is_human(&mons[monnum])) return PM_HUMAN_ZOMBIE;
1717 if (monnum == PM_ETTIN) return PM_ETTIN_ZOMBIE;
1718 if (is_giant(&mons[monnum])) return PM_GIANT_ZOMBIE;
1719 /* Is it humanoid? */
1720 if (!humanoid(&mons[monnum])) return (-1);
1721 /* Otherwise, return a ghoul or ghast */
1722 if (!rn2(4)) return PM_GHAST;
1723 else return PM_GHOUL;
1724 }
1725
1726
1727 /*WAC tinker code*/
1728 STATIC_PTR int
tinker()1729 tinker()
1730 {
1731 int chance;
1732 struct obj *otmp = uwep;
1733
1734
1735 if (delay) { /* not if (delay++), so at end delay == 0 */
1736 delay++;
1737 #if 0
1738 use_skill(P_TINKER, 1); /* Tinker skill */
1739 #endif
1740 /*WAC a bit of practice so even if you're interrupted
1741 you won't be wasting your time ;B*/
1742 return(1); /* still busy */
1743 }
1744
1745 if (!uwep)
1746 return (0);
1747
1748 You("finish your tinkering.");
1749 chance = 5;
1750 /* chance += PSKILL(P_TINKER); */
1751 if (rnl(10) < chance) {
1752 upgrade_obj(otmp);
1753 } else {
1754 /* object downgrade - But for now, nothing :) */
1755 }
1756
1757 setuwep(otmp, FALSE);
1758 You("now hold %s!", doname(otmp));
1759 return(0);
1760 }
1761
1762 /*WAC draw energy from surrounding objects */
1763 STATIC_PTR int
draw_energy()1764 draw_energy()
1765 {
1766 int powbonus = 1;
1767 if (delay) { /* not if (delay++), so at end delay == 0 */
1768 delay++;
1769 confdir();
1770 if(isok(u.ux + u.dx, u.uy + u.dy)) {
1771 switch((&levl[u.ux + u.dx][u.uy + u.dy])->typ) {
1772 case ALTAR: /* Divine power */
1773 powbonus = (u.uenmax > 28 ? u.uenmax / 4
1774 : 7);
1775 break;
1776 case THRONE: /* Regal == pseudo divine */
1777 powbonus = (u.uenmax > 36 ? u.uenmax / 6
1778 : 6);
1779 break;
1780 case CLOUD: /* Air */
1781 case TREE: /* Earth */
1782 case LAVAPOOL: /* Fire */
1783 case ICE: /* Water - most ordered form */
1784 powbonus = 5;
1785 break;
1786 case AIR:
1787 case MOAT: /* Doesn't freeze */
1788 case WATER:
1789 powbonus = 4;
1790 break;
1791 case POOL: /* Can dry up */
1792 powbonus = 3;
1793 break;
1794 case FOUNTAIN:
1795 powbonus = 2;
1796 break;
1797 case SINK: /* Cleansing water */
1798 if (!rn2(3)) powbonus = 2;
1799 break;
1800 case TOILET: /* Water Power...but also waste! */
1801 if (rn2(100) < 50)
1802 powbonus = 2;
1803 else powbonus = -2;
1804 break;
1805 case GRAVE:
1806 powbonus = -4;
1807 break;
1808 default:
1809 break;
1810 }
1811 }
1812 u.uen += powbonus;
1813 if (u.uen > u.uenmax) {
1814 delay = 0;
1815 u.uen = u.uenmax;
1816 }
1817 if (u.uen < 1) u.uen = 0;
1818 flags.botl = 1;
1819 return(1); /* still busy */
1820 }
1821 You("finish drawing energy from your surroundings.");
1822 return(0);
1823 }
1824
1825 static const char
1826 *Enter_Blitz = "Enter Blitz Command[. to end]: ";
1827
1828 /* Keep commands that reference the same blitz together
1829 * Keep the BLITZ_START before the BLITZ_CHAIN before the BLITZ_END
1830 */
1831 static const struct blitz_tab blitzes[] = {
1832 {"LLDDR", 5, blitz_chi_strike, T_CHI_STRIKE, BLITZ_START},
1833 {"LLDDRDR", 7, blitz_chi_strike, T_CHI_STRIKE, BLITZ_START},
1834 {"RR", 2, blitz_dash, T_DASH, BLITZ_START},
1835 {"LL", 2, blitz_dash, T_DASH, BLITZ_START},
1836 {"UURRDDL", 7, blitz_e_fist, T_E_FIST, BLITZ_START},
1837 {"URURRDDLDL", 10, blitz_e_fist, T_E_FIST, BLITZ_START},
1838 {"DDRRDDRR", 8, blitz_power_surge, T_POWER_SURGE, BLITZ_START},
1839 {"DRDRDRDR", 8, blitz_power_surge, T_POWER_SURGE, BLITZ_START},
1840 {"LRL", 3, blitz_pummel, T_PUMMEL, BLITZ_CHAIN},
1841 {"RLR", 3, blitz_pummel, T_PUMMEL, BLITZ_CHAIN},
1842 {"DDDD", 4, blitz_g_slam, T_G_SLAM, BLITZ_END},
1843 {"DUDUUDDD", 8, blitz_spirit_bomb, T_SPIRIT_BOMB, BLITZ_END},
1844 {"", 0, (void *)0, 0, BLITZ_END} /* Array terminator */
1845 };
1846
1847 #define MAX_BLITZ 50
1848 #define MIN_CHAIN 2
1849 #define MAX_CHAIN 5
1850
1851 /* parse blitz input */
1852 static int
doblitz()1853 doblitz()
1854 {
1855 int i, j, dx, dy, bdone = 0, tech_no;
1856 char buf[BUFSZ];
1857 char *bp;
1858 int blitz_chain[MAX_CHAIN], blitz_num;
1859
1860 tech_no = (get_tech_no(T_BLITZ));
1861
1862 if (tech_no == -1) {
1863 return(0);
1864 }
1865
1866 if (u.uen < 10) {
1867 You("are too weak to attempt this!");
1868 return(0);
1869 }
1870
1871 bp = buf;
1872
1873 if (!getdir((char *)0)) return(0);
1874 if (!u.dx && !u.dy) {
1875 return(0);
1876 }
1877
1878 dx = u.dx;
1879 dy = u.dy;
1880
1881 doblitzlist();
1882
1883 for (i= 0; i < MAX_BLITZ; i++) {
1884 if (!getdir(Enter_Blitz)) return(0); /* Get directional input */
1885 if (!u.dx && !u.dy && !u.dz) break;
1886 if (u.dx == -1) {
1887 *(bp) = 'L';
1888 bp++;
1889 } else if (u.dx == 1) {
1890 *(bp) = 'R';
1891 bp++;
1892 }
1893 if (u.dy == -1) {
1894 *(bp) = 'U';
1895 bp++;
1896 } else if (u.dy == 1) {
1897 *(bp) = 'D';
1898 bp++;
1899 }
1900 if (u.dz == -1) {
1901 *(bp) = '>';
1902 bp++;
1903 } else if (u.dz == 1) {
1904 *(bp) = '<';
1905 bp++;
1906 }
1907 }
1908 *(bp) = '.';
1909 bp++;
1910 *(bp) = '\0';
1911 bp = buf;
1912
1913 /* Point of no return - You've entered and terminated a blitz, so... */
1914 u.uen -= 10;
1915
1916 /* parse input */
1917 /* You can't put two of the same blitz in a row */
1918 blitz_num = 0;
1919 while(strncmp(bp, ".", 1)) {
1920 bdone = 0;
1921 for (j = 0; blitzes[j].blitz_len; j++) {
1922 if (blitz_num >= MAX_CHAIN ||
1923 blitz_num >= (MIN_CHAIN + (techlev(tech_no) / 10)))
1924 break; /* Trying to chain too many blitz commands */
1925 else if (!strncmp(bp, blitzes[j].blitz_cmd, blitzes[j].blitz_len)) {
1926 /* Trying to chain in a command you don't know yet */
1927 if (!tech_known(blitzes[j].blitz_tech))
1928 break;
1929 if (blitz_num) {
1930 /* Check if trying to chain two of the exact same
1931 * commands in a row
1932 */
1933 if (j == blitz_chain[(blitz_num - 1)])
1934 break;
1935 /* Trying to chain after chain finishing command */
1936 if (blitzes[blitz_chain[(blitz_num - 1)]].blitz_type
1937 == BLITZ_END)
1938 break;
1939 /* Trying to put a chain starter after starting
1940 * a chain
1941 * Note that it's OK to put two chain starters in a
1942 * row
1943 */
1944 if ((blitzes[j].blitz_type == BLITZ_START) &&
1945 (blitzes[blitz_chain[(blitz_num - 1)]].blitz_type
1946 != BLITZ_START))
1947 break;
1948 }
1949 bp += blitzes[j].blitz_len;
1950 blitz_chain[blitz_num] = j;
1951 blitz_num++;
1952 bdone = 1;
1953 break;
1954 }
1955 }
1956 if (!bdone) {
1957 You("stumble!");
1958 return(1);
1959 }
1960 }
1961 for (i = 0; i < blitz_num; i++) {
1962 u.dx = dx;
1963 u.dy = dy;
1964 if (!( (*blitzes[blitz_chain[i]].blitz_funct)() )) break;
1965 }
1966
1967 /* done */
1968 return(1);
1969 }
1970
1971 static void
doblitzlist()1972 doblitzlist()
1973 {
1974 winid tmpwin;
1975 int i, n;
1976 char buf[BUFSZ];
1977 menu_item *selected;
1978 anything any;
1979
1980 tmpwin = create_nhwindow(NHW_MENU);
1981 start_menu(tmpwin);
1982 any.a_void = 0; /* zero out all bits */
1983
1984 Sprintf(buf, "%16s %10s %-17s", "[LU = Left Up]", "[U = Up]", "[RU = Right Up]");
1985 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
1986 Sprintf(buf, "%16s %10s %-17s", "[L = Left]", "", "[R = Right]");
1987 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
1988 Sprintf(buf, "%16s %10s %-17s", "[LD = Left Down]", "[D = Down]", "[RD = Right Down]");
1989 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
1990
1991 Sprintf(buf, "%-30s %10s %s", "Name", "Type", "Command");
1992 add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
1993
1994 for (i = 0; blitzes[i].blitz_len; i++) {
1995 if (tech_known(blitzes[i].blitz_tech)) {
1996 Sprintf(buf, "%-30s %10s %s",
1997 (i && blitzes[i].blitz_tech == blitzes[(i-1)].blitz_tech ?
1998 "" : tech_names[blitzes[i].blitz_tech]),
1999 (blitzes[i].blitz_type == BLITZ_START ?
2000 "starter" :
2001 (blitzes[i].blitz_type == BLITZ_CHAIN ?
2002 "chain" :
2003 (blitzes[i].blitz_type == BLITZ_END ?
2004 "finisher" : "unknown"))),
2005 blitzes[i].blitz_cmd);
2006
2007 add_menu(tmpwin, NO_GLYPH, &any,
2008 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
2009 }
2010 }
2011 end_menu(tmpwin, "Currently known blitz manoeuvers");
2012
2013 n = select_menu(tmpwin, PICK_NONE, &selected);
2014 destroy_nhwindow(tmpwin);
2015 return;
2016 }
2017
2018 static int
blitz_chi_strike()2019 blitz_chi_strike()
2020 {
2021 int tech_no;
2022
2023 tech_no = (get_tech_no(T_CHI_STRIKE));
2024
2025 if (tech_no == -1) {
2026 return(0);
2027 }
2028
2029 if (u.uen < 1) {
2030 You("are too weak to attempt this!");
2031 return(0);
2032 }
2033 You("feel energy surge through your hands!");
2034 techt_inuse(tech_no) = techlev(tech_no) + 4;
2035 return(1);
2036 }
2037
2038 static int
blitz_e_fist()2039 blitz_e_fist()
2040 {
2041 int tech_no;
2042 const char *str;
2043
2044 tech_no = (get_tech_no(T_E_FIST));
2045
2046 if (tech_no == -1) {
2047 return(0);
2048 }
2049
2050 str = makeplural(body_part(HAND));
2051 You("focus the powers of the elements into your %s.", str);
2052 techt_inuse(tech_no) = rnd((int) (techlev(tech_no)/3 + 1)) + d(1,4) + 2;
2053 return 1;
2054 }
2055
2056 /* Assumes u.dx, u.dy already set up */
2057 static int
blitz_pummel()2058 blitz_pummel()
2059 {
2060 int i = 0, tech_no;
2061 struct monst *mtmp;
2062 tech_no = (get_tech_no(T_PUMMEL));
2063
2064 if (tech_no == -1) {
2065 return(0);
2066 }
2067
2068 You("let loose a barrage of blows!");
2069
2070 if (u.uswallow)
2071 mtmp = u.ustuck;
2072 else
2073 mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
2074
2075 if (!mtmp) {
2076 You("strike nothing.");
2077 return (0);
2078 }
2079 if (!attack(mtmp)) return (0);
2080
2081 /* Perform the extra attacks
2082 */
2083 for (i = 0; (i < 4); i++) {
2084 if (rn2(70) > (techlev(tech_no) + 30)) break;
2085
2086 if (u.uswallow)
2087 mtmp = u.ustuck;
2088 else
2089 mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
2090
2091 if (!mtmp) return (1);
2092 if (!attack(mtmp)) return (1);
2093 }
2094
2095 return(1);
2096 }
2097
2098 /* Assumes u.dx, u.dy already set up */
2099 static int
blitz_g_slam()2100 blitz_g_slam()
2101 {
2102 int tech_no, tmp, canhitmon, objenchant;
2103 struct monst *mtmp;
2104 struct trap *chasm;
2105
2106 tech_no = (get_tech_no(T_G_SLAM));
2107
2108 if (tech_no == -1) {
2109 return(0);
2110 }
2111
2112 mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
2113 if (!mtmp) {
2114 You("strike nothing.");
2115 return (0);
2116 }
2117 if (!attack(mtmp)) return (0);
2118
2119 /* Slam the monster into the ground */
2120 mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
2121 if (!mtmp || u.uswallow) return(1);
2122
2123 You("hurl %s downwards...", mon_nam(mtmp));
2124 if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) return(1);
2125
2126 if (need_four(mtmp)) canhitmon = 4;
2127 else if (need_three(mtmp)) canhitmon = 3;
2128 else if (need_two(mtmp)) canhitmon = 2;
2129 else if (need_one(mtmp)) canhitmon = 1;
2130 else canhitmon = 0;
2131 if (Upolyd) {
2132 if (hit_as_four(&youmonst)) objenchant = 4;
2133 else if (hit_as_three(&youmonst)) objenchant = 3;
2134 else if (hit_as_two(&youmonst)) objenchant = 2;
2135 else if (hit_as_one(&youmonst)) objenchant = 1;
2136 else if (need_four(&youmonst)) objenchant = 4;
2137 else if (need_three(&youmonst)) objenchant = 3;
2138 else if (need_two(&youmonst)) objenchant = 2;
2139 else if (need_one(&youmonst)) objenchant = 1;
2140 else objenchant = 0;
2141 } else
2142 objenchant = u.ulevel / 4;
2143
2144 tmp = (5 + rnd(6) + (techlev(tech_no) / 5));
2145
2146 chasm = maketrap(u.ux + u.dx, u.uy + u.dy, PIT);
2147 if (chasm) {
2148 if (!is_flyer(mtmp->data) && !is_clinger(mtmp->data))
2149 mtmp->mtrapped = 1;
2150 chasm->tseen = 1;
2151 levl[u.ux + u.dx][u.uy + u.dy].doormask = 0;
2152 pline("%s slams into the ground, creating a crater!", Monnam(mtmp));
2153 tmp *= 2;
2154 }
2155
2156 mselftouch(mtmp, "Falling, ", TRUE);
2157 if (!DEADMONSTER(mtmp)) {
2158 if (objenchant < canhitmon)
2159 pline("%s doesn't seem to be harmed.", Monnam(mtmp));
2160 else if ((mtmp->mhp -= tmp) <= 0) {
2161 if(!cansee(u.ux + u.dx, u.uy + u.dy))
2162 pline("It is destroyed!");
2163 else {
2164 You("destroy %s!",
2165 mtmp->mtame
2166 ? x_monnam(mtmp, ARTICLE_THE, "poor",
2167 mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE)
2168 : mon_nam(mtmp));
2169 }
2170 xkilled(mtmp,0);
2171 }
2172 }
2173
2174 return(1);
2175 }
2176
2177 /* Assumes u.dx, u.dy already set up */
2178 static int
blitz_dash()2179 blitz_dash()
2180 {
2181 int tech_no;
2182 tech_no = (get_tech_no(T_DASH));
2183
2184 if (tech_no == -1) {
2185 return(0);
2186 }
2187
2188 if ((!Punished || carried(uball)) && !u.utrap)
2189 You("dash forwards!");
2190 hurtle(u.dx, u.dy, 2, FALSE);
2191 multi = 0; /* No paralysis with dash */
2192 return 1;
2193 }
2194
2195 static int
blitz_power_surge()2196 blitz_power_surge()
2197 {
2198 int tech_no, num;
2199
2200 tech_no = (get_tech_no(T_POWER_SURGE));
2201
2202 if (tech_no == -1) {
2203 return(0);
2204 }
2205
2206 if (Upolyd) {
2207 You("cannot tap into your full potential in this form.");
2208 return(0);
2209 }
2210 You("tap into the full extent of your power!");
2211 num = 50 + (2 * techlev(tech_no));
2212 techt_inuse(tech_no) = num + 1;
2213 u.uenmax += num;
2214 u.uen = u.uenmax;
2215 return 1;
2216 }
2217
2218 /* Assumes u.dx, u.dy already set up */
2219 static int
blitz_spirit_bomb()2220 blitz_spirit_bomb()
2221 {
2222 int tech_no, num;
2223 int sx = u.ux, sy = u.uy, i;
2224
2225 tech_no = (get_tech_no(T_SPIRIT_BOMB));
2226
2227 if (tech_no == -1) {
2228 return(0);
2229 }
2230
2231 You("gather your energy...");
2232
2233 if (u.uen < 10) {
2234 pline("But it fizzles out.");
2235 u.uen = 0;
2236 }
2237
2238 num = 10 + (techlev(tech_no) / 5);
2239 num = (u.uen < num ? u.uen : num);
2240
2241 u.uen -= num;
2242
2243 for( i = 0; i < 2; i++) {
2244 if (!isok(sx,sy) || !cansee(sx,sy) ||
2245 IS_STWALL(levl[sx][sy].typ) || u.uswallow)
2246 break;
2247
2248 /* Display the center of the explosion */
2249 tmp_at(DISP_FLASH, explosion_to_glyph(EXPL_MAGICAL, S_explode5));
2250 tmp_at(sx, sy);
2251 delay_output();
2252 tmp_at(DISP_END, 0);
2253
2254 sx += u.dx;
2255 sy += u.dy;
2256 }
2257 /* Magical Explosion */
2258 explode(sx, sy, 10, (d(3,6) + num), WAND_CLASS, EXPL_MAGICAL);
2259 return 1;
2260 }
2261
2262 #ifdef DEBUG
2263 void
wiz_debug_cmd()2264 wiz_debug_cmd() /* in this case, allow controlled loss of techniques */
2265 {
2266 int tech_no, id, n = 0;
2267 long mask;
2268 if (gettech(&tech_no)) {
2269 id = techid(tech_no);
2270 if (id == NO_TECH) {
2271 impossible("Unknown technique ([%d])?", tech_no);
2272 return;
2273 }
2274 mask = tech_list[tech_no].t_intrinsic;
2275 if (mask & FROMOUTSIDE) n++;
2276 if (mask & FROMRACE) n++;
2277 if (mask & FROMEXPER) n++;
2278 if (!n) {
2279 impossible("No intrinsic masks set (0x%lX).", mask);
2280 return;
2281 }
2282 n = rn2(n);
2283 if (mask & FROMOUTSIDE && !n--) mask = FROMOUTSIDE;
2284 if (mask & FROMRACE && !n--) mask = FROMRACE;
2285 if (mask & FROMEXPER && !n--) mask = FROMEXPER;
2286 learntech(id, mask, -1);
2287 if (!tech_known(id))
2288 You("lose the ability to perform %s.", tech_names[id]);
2289 }
2290 }
2291 #endif /* DEBUG */
2292