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