Source:SLASH'EM 0.0.7E7F2/tech.c

From NetHackWiki
Revision as of 19:48, 7 March 2008 by Kernigh bot (talk | contribs) (SLASH'EM 0.0.7E7F2/tech.c moved to Source:SLASH'EM 0.0.7E7F2/tech.c: Robot: moved page)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Below is the full text to tech.c from the source code of SLASH'EM 0.0.7E7F2. To link to a particular line, write [[SLASH'EM 0.0.7E7F2/tech.c#line123]], for example.

The latest source code for vanilla NetHack is at Source code.


The NetHack General Public License applies to screenshots, source code and other content from NetHack.

This content was modified from the original NetHack source code distribution (by splitting up NetHack content between wiki pages, and possibly further editing). See the page history for a list of who changed it, and on what dates.

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
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
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
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
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
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
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
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 *
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
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.  			else {
709.  			    obj_extract_self(otmp);
710.  			    obfree(otmp, (struct obj *)0);
711.  			}
712.  			pline("Using %s, you dress your wounds.", yname(otmp));
713.  			healup(techlev(tech_no) * (rnd(2)+1) + rn1(5,5),
714.  			  0, FALSE, FALSE);
715.  		    } else {
716.  			You("strap your wounds as best you can.");
717.  			healup(techlev(tech_no) + rn1(5,5), 0, FALSE, FALSE);
718.  		    }
719.                      t_timeout = rn1(1000,500);
720.  		    flags.botl = TRUE;
721.  		} else You("don't need your healing powers!");
722.  		break;
723.              case T_HEAL_HANDS:
724.  		if (Slimed) {
725.  		    Your("body is on fire!");
726.  		    burn_away_slime();
727.  		    t_timeout = 3000;
728.  		} else if (Sick) {
729.  		    You("lay your hands on the foul sickness...");
730.  		    make_sick(0L, (char*)0, TRUE, SICK_ALL);
731.  		    t_timeout = 3000;
732.  		} else if (Upolyd ? u.mh < u.mhmax : u.uhp < u.uhpmax) {
733.  		    pline("A warm glow spreads through your body!");
734.  		    healup(techlev(tech_no) * 4, 0, FALSE, FALSE);
735.  		    t_timeout = 3000;
736.  		} else
737.  		    pline(nothing_happens);
738.  		break;
739.              case T_KIII:
740.  		You("scream \"KIIILLL!\"");
741.  		aggravate();
742.                  techt_inuse(tech_no) = rnd((int) (techlev(tech_no)/6 + 1)) + 2;
743.                  t_timeout = rn1(1000,500);
744.  		break;
745.  #ifdef STEED
746.  	    case T_CALM_STEED:
747.                  if (u.usteed) {
748.                          pline("%s gets tamer.", Monnam(u.usteed));
749.                          tamedog(u.usteed, (struct obj *) 0);
750.                          t_timeout = rn1(1000,500);
751.                  } else
752.                          Your("technique is only effective when riding a monster.");
753.                  break;
754.  #endif
755.              case T_TURN_UNDEAD:
756.                  return(turn_undead());
757.  	    case T_VANISH:
758.  		if (Invisible && Fast) {
759.  			You("are already quite nimble and undetectable.");
760.  		}
761.                  techt_inuse(tech_no) = rn1(50,50) + techlev(tech_no);
762.  		if (!Invisible) pline("In a puff of smoke,  you disappear!");
763.  		if (!Fast) You("feel more nimble!");
764.  		incr_itimeout(&HInvis, techt_inuse(tech_no));
765.  		incr_itimeout(&HFast, techt_inuse(tech_no));
766.  		newsym(u.ux,u.uy);      /* update position */
767.  		t_timeout = rn1(1000,500);
768.  		break;
769.  	    case T_CRIT_STRIKE:
770.  		if (!getdir((char *)0)) return(0);
771.  		if (!u.dx && !u.dy) {
772.  		    /* Hopefully a mistake ;B */
773.  		    You("decide against that idea.");
774.  		    return(0);
775.  		}
776.  		mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
777.  		if (!mtmp) {
778.  		    You("perform a flashy twirl!");
779.  		    return (0);
780.  		} else {
781.  		    int oldhp = mtmp->mhp;
782.  		    int tmp;
783.  
784.  		    if (!attack(mtmp)) return(0);
785.  		    if (!DEADMONSTER(mtmp) && mtmp->mhp < oldhp &&
786.  			    !noncorporeal(mtmp->data) && !unsolid(mtmp->data)) {
787.  			You("strike %s vital organs!", s_suffix(mon_nam(mtmp)));
788.  			/* Base damage is always something, though it may be
789.  			 * reduced to zero if the hero is hampered. However,
790.  			 * since techlev will never be zero, stiking vital
791.  			 * organs will always do _some_ damage.
792.  			 */
793.  			tmp = mtmp->mhp > 1 ? mtmp->mhp / 2 : 1;
794.  			if (!humanoid(mtmp->data) || is_golem(mtmp->data) ||
795.  				mtmp->data->mlet == S_CENTAUR) {
796.  			    You("are hampered by the differences in anatomy.");
797.  			    tmp /= 2;
798.  			}
799.  			tmp += techlev(tech_no);
800.  			t_timeout = rn1(1000, 500);
801.  			hurtmon(mtmp, tmp);
802.  		    }
803.  		}
804.  		break;
805.  	    case T_CUTTHROAT:
806.  		if (!is_blade(uwep)) {
807.  			You("need a blade to perform cutthroat!");
808.  			return (0);
809.  		}
810.  	    	if (!getdir((char *)0)) return(0);
811.  		if (!u.dx && !u.dy) {
812.  			/* Hopefully a mistake ;B */
813.  			pline("Things may be going badly,  but that's extreme.");
814.  			return(0);
815.  		}
816.  		mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
817.  		if (!mtmp) {
818.  			You("attack...nothing!");
819.  			return (0);
820.  		} else {
821.  			int oldhp = mtmp->mhp;
822.  			
823.  			if (!attack(mtmp)) return(0);
824.  			if (!DEADMONSTER(mtmp) && mtmp->mhp < oldhp) {
825.  				int tmp = 0;
826.  				if (!has_head(mtmp->data) || u.uswallow) {
827.  					You("can't perform cutthroat on %s!",mon_nam(mtmp));
828.  				}
829.  				if (rn2(5) < (techlev(tech_no)/10 + 1)) {
830.  					You("sever %s head!", s_suffix(mon_nam(mtmp)));
831.  					tmp = mtmp->mhp;
832.  				} else {
833.  					You("hurt %s badly!", s_suffix(mon_nam(mtmp)));
834.  					tmp = mtmp->mhp / 2;
835.  				}
836.  				tmp += techlev(tech_no);
837.  				t_timeout = rn1(1000,500);
838.  				hurtmon(mtmp, tmp);
839.  			}
840.  		}
841.  		break;
842.  	    case T_BLESSING:
843.  		allowall[0] = ALL_CLASSES; allowall[1] = '\0';
844.  		
845.  		if ( !(obj = getobj(allowall, "bless"))) return(0);
846.  		pline("An aura of holiness surrounds your hands!");
847.                  if (!Blind) (void) Shk_Your(Your_buf, obj);
848.  		if (obj->cursed) {
849.                  	if (!Blind)
850.                      		pline("%s %s %s.",Your_buf,
851.  						  aobjnam(obj, "softly glow"),
852.  						  hcolor(NH_AMBER));
853.  				uncurse(obj);
854.  				obj->bknown=1;
855.  		} else if(!obj->blessed) {
856.  			if (!Blind) {
857.  				str = hcolor(NH_LIGHT_BLUE);
858.  				pline("%s %s with a%s %s aura.",
859.  					  Your_buf,
860.  					  aobjnam(obj, "softly glow"),
861.  					  index(vowels, *str) ? "n" : "", str);
862.  			}
863.  			bless(obj);
864.  			obj->bknown=1;
865.  		} else {
866.  			if (obj->bknown) {
867.  				pline ("That object is already blessed!");
868.  				return(0);
869.  			}
870.  			obj->bknown=1;
871.  			pline("The aura fades.");
872.  		}
873.  		t_timeout = rn1(1000,500);
874.  		break;
875.  	    case T_E_FIST: 
876.  	    	blitz_e_fist();
877.  #if 0
878.  		str = makeplural(body_part(HAND));
879.                  You("focus the powers of the elements into your %s", str);
880.                  techt_inuse(tech_no) = rnd((int) (techlev(tech_no)/3 + 1)) + d(1,4) + 2;
881.  #endif
882.  		t_timeout = rn1(1000,500);
883.  	    	break;
884.  	    case T_PRIMAL_ROAR:	    	
885.  	    	You("let out a bloodcurdling roar!");
886.  	    	aggravate();
887.  
888.  		techt_inuse(tech_no) = d(2,6) + (techlev(tech_no)) + 2;
889.  
890.  		incr_itimeout(&HFast, techt_inuse(tech_no));
891.  
892.  	    	for(i = -5; i <= 5; i++) for(j = -5; j <= 5; j++)
893.  		    if(isok(u.ux+i, u.uy+j) && (mtmp = m_at(u.ux+i, u.uy+j))) {
894.  		    	if (mtmp->mtame != 0 && !mtmp->isspell) {
895.  		    	    struct permonst *ptr = mtmp->data;
896.  			    struct monst *mtmp2;
897.  		    	    int ttime = techt_inuse(tech_no);
898.  		    	    int type = little_to_big(monsndx(ptr));
899.  		    	    
900.  		    	    mtmp2 = tamedog(mtmp, (struct obj *) 0);
901.  			    if (mtmp2)
902.  				mtmp = mtmp2;
903.  
904.  		    	    if (type && type != monsndx(ptr)) {
905.  				ptr = &mons[type];
906.  		    	    	mon_spec_poly(mtmp, ptr, ttime, FALSE,
907.  					canseemon(mtmp), FALSE, TRUE);
908.  		    	    }
909.  		    	}
910.  		    }
911.  		t_timeout = rn1(1000,500);
912.  	    	break;
913.  	    case T_LIQUID_LEAP: {
914.  	    	coord cc;
915.  	    	int dx, dy, sx, sy, range;
916.  
917.  		pline("Where do you want to leap to?");
918.      		cc.x = sx = u.ux;
919.  		cc.y = sy = u.uy;
920.  
921.  		getpos(&cc, TRUE, "the desired position");
922.  		if (cc.x == -10) return 0; /* user pressed esc */
923.  
924.  		dx = cc.x - u.ux;
925.  		dy = cc.y - u.uy;
926.  		/* allow diagonals */
927.  	    	if (dx && dy && dx != dy && dx != -dy) {
928.  		    You("can only leap in straight lines!");
929.  		    return 0;
930.  	    	} else if (distu(cc.x, cc.y) > 19 + techlev(tech_no)) {
931.  		    pline("Too far!");
932.  		    return 0;
933.  		} else if (m_at(cc.x, cc.y) || !isok(cc.x, cc.y) ||
934.  			IS_ROCK(levl[cc.x][cc.y].typ) ||
935.  			sobj_at(BOULDER, cc.x, cc.y) ||
936.  			closed_door(cc.x, cc.y)) {
937.  		    You_cant("flow there!"); /* MAR */
938.  		    return 0;
939.  		} else {
940.  		    You("liquify!");
941.  		    if (Punished) {
942.  			You("slip out of the iron chain.");
943.  			unpunish();
944.  		    }
945.  		    if(u.utrap) {
946.  			switch(u.utraptype) {
947.  			    case TT_BEARTRAP: 
948.  				You("slide out of the bear trap.");
949.  				break;
950.  			    case TT_PIT:
951.  				You("leap from the pit!");
952.  				break;
953.  			    case TT_WEB:
954.  				You("flow through the web!");
955.  				break;
956.  			    case TT_LAVA:
957.  				You("separate from the lava!");
958.  				u.utrap = 0;
959.  				break;
960.  			    case TT_INFLOOR:
961.  				u.utrap = 0;
962.  				You("ooze out of the floor!");
963.  			}
964.  			u.utrap = 0;
965.  		    }
966.  		    /* Fry the things in the path ;B */
967.  		    if (dx) range = dx;
968.  		    else range = dy;
969.  		    if (range < 0) range = -range;
970.  		    
971.  		    dx = sgn(dx);
972.  		    dy = sgn(dy);
973.  		    
974.  		    while (range-- > 0) {
975.  		    	int tmp_invul = 0;
976.  		    	
977.  		    	if (!Invulnerable) Invulnerable = tmp_invul = 1;
978.  			sx += dx; sy += dy;
979.  			tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, AD_ACID-1));
980.  			tmp_at(sx,sy);
981.  			delay_output(); /* wait a little */
982.  		    	if ((mtmp = m_at(sx, sy)) != 0) {
983.  			    int chance;
984.  			    
985.  			    chance = rn2(20);
986.  		    	    if (!chance || (3 - chance) > AC_VALUE(find_mac(mtmp)))
987.  		    	    	break;
988.  			    setmangry(mtmp);
989.  		    	    You("catch %s in your acid trail!", mon_nam(mtmp));
990.  		    	    if (!resists_acid(mtmp)) {
991.  				int tmp = 1;
992.  				/* Need to add a to-hit */
993.  				tmp += d(2,4);
994.  				tmp += rn2((int) (techlev(tech_no)/5 + 1));
995.  				if (!Blind) pline_The("acid burns %s!", mon_nam(mtmp));
996.  				hurtmon(mtmp, tmp);
997.  			    } else if (!Blind) pline_The("acid doesn't affect %s!", mon_nam(mtmp));
998.  			}
999.  			/* Clean up */
1000. 			tmp_at(DISP_END,0);
1001. 			if (tmp_invul) Invulnerable = 0;
1002. 		    }
1003. 
1004. 		    /* A little Sokoban guilt... */
1005. 		    if (In_sokoban(&u.uz))
1006. 			change_luck(-1);
1007. 		    You("reform!");
1008. 		    teleds(cc.x, cc.y, FALSE);
1009. 		    nomul(-1);
1010. 		    nomovemsg = "";
1011. 	    	}
1012. 		t_timeout = rn1(1000,500);
1013. 	    	break;
1014. 	    }
1015.             case T_SIGIL_TEMPEST: 
1016. 		/* Have enough power? */
1017. 		num = 50 - techlev(tech_no)/5;
1018. 		if (u.uen < num) {
1019. 			You("don't have enough power to invoke the sigil!");
1020. 			return (0);
1021. 		}
1022. 		u.uen -= num;
1023. 
1024. 		/* Invoke */
1025. 		You("invoke the sigil of tempest!");
1026.                 techt_inuse(tech_no) = d(1,6) + rnd(techlev(tech_no)/5 + 1) + 2;
1027. 		u_wipe_engr(2);
1028. 		return(0);
1029. 		break;
1030.             case T_SIGIL_CONTROL:
1031. 		/* Have enough power? */
1032. 		num = 30 - techlev(tech_no)/5;
1033. 		if (u.uen < num) {
1034. 			You("don't have enough power to invoke the sigil!");
1035. 			return (0);
1036. 		}
1037. 		u.uen -= num;
1038. 
1039. 		/* Invoke */
1040. 		You("invoke the sigil of control!");
1041.                 techt_inuse(tech_no) = d(1,4) + rnd(techlev(tech_no)/5 + 1) + 2;
1042. 		u_wipe_engr(2);
1043. 		return(0);
1044. 		break;
1045.             case T_SIGIL_DISCHARGE:
1046. 		/* Have enough power? */
1047. 		num = 100 - techlev(tech_no)/5;
1048. 		if (u.uen < num) {
1049. 			You("don't have enough power to invoke the sigil!");
1050. 			return (0);
1051. 		}
1052. 		u.uen -= num;
1053. 
1054. 		/* Invoke */
1055. 		You("invoke the sigil of discharge!");
1056.                 techt_inuse(tech_no) = d(1,4) + rnd(techlev(tech_no)/5 + 1) + 2;
1057. 		u_wipe_engr(2);
1058. 		return(0);
1059. 		break;
1060.             case T_RAISE_ZOMBIES:
1061.             	You("chant the ancient curse...");
1062. 		for(i = -1; i <= 1; i++) for(j = -1; j <= 1; j++) {
1063. 		    int corpsenm;
1064. 
1065. 		    if (!isok(u.ux+i, u.uy+j)) continue;
1066. 		    for (obj = level.objects[u.ux+i][u.uy+j]; obj; obj = otmp) {
1067. 			otmp = obj->nexthere;
1068. 
1069. 			if (obj->otyp != CORPSE) continue;
1070. 			/* Only generate undead */
1071. 			corpsenm = mon_to_zombie(obj->corpsenm);
1072. 			if (corpsenm != -1 && !cant_create(&corpsenm, TRUE) &&
1073. 			  (!obj->oxlth || obj->oattached != OATTACHED_MONST)) {
1074. 			    /* Maintain approx. proportion of oeaten to cnutrit
1075. 			     * so that the zombie's HP relate roughly to how
1076. 			     * much of the original corpse was left.
1077. 			     */
1078. 			    if (obj->oeaten)
1079. 				obj->oeaten =
1080. 					eaten_stat(mons[corpsenm].cnutrit, obj);
1081. 			    obj->corpsenm = corpsenm;
1082. 			    mtmp = revive(obj);
1083. 			    if (mtmp) {
1084. 				if (!resist(mtmp, SPBOOK_CLASS, 0, TELL)) {
1085. 				   mtmp = tamedog(mtmp, (struct obj *) 0);
1086. 				   You("dominate %s!", mon_nam(mtmp));
1087. 				} else setmangry(mtmp);
1088. 			    }
1089. 			}
1090. 		    }
1091. 		}
1092. 		nomul(-2); /* You need to recover */
1093. 		nomovemsg = 0;
1094. 		t_timeout = rn1(1000,500);
1095. 		break;
1096.             case T_REVIVE: 
1097. 		if (u.uswallow) {
1098. 		    You(no_elbow_room);
1099. 		    return 0;
1100. 		}
1101.             	num = 100 - techlev(tech_no); /* WAC make this depend on mon? */
1102.             	if ((Upolyd && u.mh <= num) || (!Upolyd && u.uhp <= num)){
1103. 		    You("don't have the strength to perform revivification!");
1104. 		    return 0;
1105.             	}
1106. 
1107.             	obj = getobj((const char *)revivables, "revive");
1108.             	if (!obj) return (0);
1109.             	mtmp = revive(obj);
1110.             	if (mtmp) {
1111. #ifdef BLACKMARKET
1112. 		    if (Is_blackmarket(&u.uz))
1113. 			setmangry(mtmp);
1114. 		    else
1115. #endif
1116. 		    if (mtmp->isshk)
1117. 			make_happy_shk(mtmp, FALSE);
1118. 		    else if (!resist(mtmp, SPBOOK_CLASS, 0, NOTELL))
1119. 			(void) tamedog(mtmp, (struct obj *) 0);
1120. 		}
1121.             	if (Upolyd) u.mh -= num;
1122.             	else u.uhp -= num;
1123. 		t_timeout = rn1(1000,500);
1124.             	break;
1125. 	    case T_WARD_FIRE:
1126. 		/* Already have it intrinsically? */
1127. 		if (HFire_resistance & FROMOUTSIDE) return (0);
1128. 
1129. 		You("invoke the ward against flame!");
1130. 		HFire_resistance += rn1(100,50);
1131. 		HFire_resistance += techlev(tech_no);
1132. 		t_timeout = rn1(1000,500);
1133. 
1134. 	    	break;
1135. 	    case T_WARD_COLD:
1136. 		/* Already have it intrinsically? */
1137. 		if (HCold_resistance & FROMOUTSIDE) return (0);
1138. 
1139. 		You("invoke the ward against ice!");
1140. 		HCold_resistance += rn1(100,50);
1141. 		HCold_resistance += techlev(tech_no);
1142. 		t_timeout = rn1(1000,500);
1143. 
1144. 	    	break;
1145. 	    case T_WARD_ELEC:
1146. 		/* Already have it intrinsically? */
1147. 		if (HShock_resistance & FROMOUTSIDE) return (0);
1148. 
1149. 		You("invoke the ward against lightning!");
1150. 		HShock_resistance += rn1(100,50);
1151. 		HShock_resistance += techlev(tech_no);
1152. 		t_timeout = rn1(1000,500);
1153. 
1154. 	    	break;
1155. 	    case T_TINKER:
1156. 		if (Blind) {
1157. 			You("can't do any tinkering if you can't see!");
1158. 			return (0);
1159. 		}
1160. 		if (!uwep) {
1161. 			You("aren't holding an object to work on!");
1162. 			return (0);
1163. 		}
1164. 		You("are holding %s.", doname(uwep));
1165. 		if (yn("Start tinkering on this?") != 'y') return(0);
1166. 		You("start working on %s",doname(uwep));
1167. 		delay=-150 + techlev(tech_no);
1168. 		set_occupation(tinker, "tinkering", 0);
1169. 		break;
1170. 	    case T_RAGE:     	
1171. 		if (Upolyd) {
1172. 			You("cannot focus your anger!");
1173. 			return(0);
1174. 		}
1175. 	    	You("feel the anger inside you erupt!");
1176. 		num = 50 + (4 * techlev(tech_no));
1177. 	    	techt_inuse(tech_no) = num + 1;
1178. 		u.uhpmax += num;
1179. 		u.uhp += num;
1180. 		t_timeout = rn1(1000,500);
1181. 		break;	    
1182. 	    case T_BLINK:
1183. 	    	You("feel the flow of time slow down.");
1184.                 techt_inuse(tech_no) = rnd(techlev(tech_no) + 1) + 2;
1185. 		t_timeout = rn1(1000,500);
1186. 	    	break;
1187.             case T_CHI_STRIKE:
1188.             	if (!blitz_chi_strike()) return(0);
1189.                 t_timeout = rn1(1000,500);
1190. 		break;
1191.             case T_DRAW_ENERGY:
1192.             	if (u.uen == u.uenmax) {
1193.             		if (Hallucination) You("are fully charged!");
1194. 			else You("cannot hold any more energy!");
1195. 			return(0);           		
1196.             	}
1197.                 You("begin drawing energy from your surroundings!");
1198. 		delay=-15;
1199. 		set_occupation(draw_energy, "drawing energy", 0);                
1200.                 t_timeout = rn1(1000,500);
1201. 		break;
1202.             case T_CHI_HEALING:
1203.             	if (u.uen < 1) {
1204.             		You("are too weak to attempt this!");
1205.             		return(0);
1206.             	}
1207. 		You("direct your internal energy to restoring your body!");
1208.                 techt_inuse(tech_no) = techlev(tech_no)*2 + 4;
1209.                 t_timeout = rn1(1000,500);
1210. 		break;	
1211. 	    case T_DISARM:
1212. 	    	if (P_SKILL(weapon_type(uwep)) == P_NONE) {
1213. 	    		You("aren't wielding a proper weapon!");
1214. 	    		return(0);
1215. 	    	}
1216. 	    	if ((P_SKILL(weapon_type(uwep)) < P_SKILLED) || (Blind)) {
1217. 	    		You("aren't capable of doing this!");
1218. 	    		return(0);
1219. 	    	}
1220. 		if (u.uswallow) {
1221. 	    		pline("What do you think %s is?  A sword swallower?",
1222. 				mon_nam(u.ustuck));
1223. 	    		return(0);
1224. 		}
1225. 
1226. 	    	if (!getdir((char *)0)) return(0);
1227. 		if (!u.dx && !u.dy) {
1228. 			/* Hopefully a mistake ;B */
1229. 			pline("Why don't you try wielding something else instead.");
1230. 			return(0);
1231. 		}
1232. 		mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
1233. 		if (!mtmp || !canspotmon(mtmp)) {
1234. 			if (memory_is_invisible(u.ux + u.dx, u.uy + u.dy))
1235. 			    You("don't know where to aim for!");
1236. 			else
1237. 			    You("don't see anything there!");
1238. 			return (0);
1239. 		}
1240. 	    	obj = MON_WEP(mtmp);   /* can be null */
1241. 	    	if (!obj) {
1242. 	    		You_cant("disarm an unarmed foe!");
1243. 	    		return(0);
1244. 	    	}
1245. 		/* Blindness dealt with above */
1246. 		if (!mon_visible(mtmp)
1247. #ifdef INVISIBLE_OBJECTS
1248. 				|| obj->oinvis && !See_invisible
1249. #endif
1250. 				) {
1251. 	    		You_cant("see %s weapon!", s_suffix(mon_nam(mtmp)));
1252. 	    		return(0);
1253. 		}
1254. 		num = ((rn2(techlev(tech_no) + 15)) 
1255. 			* (P_SKILL(weapon_type(uwep)) - P_SKILLED + 1)) / 10;
1256. 
1257. 		You("attempt to disarm %s...",mon_nam(mtmp));
1258. 		/* WAC can't yank out cursed items */
1259.                 if (num > 0 && (!Fumbling || !rn2(10)) && !obj->cursed) {
1260. 		    int roll;
1261. 		    obj_extract_self(obj);
1262. 		    possibly_unwield(mtmp, FALSE);
1263. 		    setmnotwielded(mtmp, obj);
1264. 		    roll = rn2(num + 1);
1265. 		    if (roll > 3) roll = 3;
1266. 		    switch (roll) {
1267. 			case 2:
1268. 			    /* to floor near you */
1269. 			    You("knock %s %s to the %s!",
1270. 				s_suffix(mon_nam(mtmp)),
1271. 				xname(obj),
1272. 				surface(u.ux, u.uy));
1273. 			    if (obj->otyp == CRYSKNIFE &&
1274. 				    (!obj->oerodeproof || !rn2(10))) {
1275. 				obj->otyp = WORM_TOOTH;
1276. 				obj->oerodeproof = 0;
1277. 			    }
1278. 			    place_object(obj, u.ux, u.uy);
1279. 			    stackobj(obj);
1280. 			    break;
1281. 			case 3:
1282. #if 0
1283. 			    if (!rn2(25)) {
1284. 				/* proficient at disarming, but maybe not
1285. 				   so proficient at catching weapons */
1286. 				int hitu, hitvalu;
1287. 
1288. 				hitvalu = 8 + obj->spe;
1289. 				hitu = thitu(hitvalu,
1290. 					dmgval(obj, &youmonst),
1291. 					obj, xname(obj));
1292. 				if (hitu)
1293. 				    pline("%s hits you as you try to snatch it!",
1294. 					    The(xname(obj)));
1295. 				place_object(obj, u.ux, u.uy);
1296. 				stackobj(obj);
1297. 				break;
1298. 			    }
1299. #endif /* 0 */
1300. 			    /* right into your inventory */
1301. 			    You("snatch %s %s!", s_suffix(mon_nam(mtmp)),
1302. 				    xname(obj));
1303. 			    if (obj->otyp == CORPSE &&
1304. 				    touch_petrifies(&mons[obj->corpsenm]) &&
1305. 				    !uarmg && !Stone_resistance &&
1306. 				    !(poly_when_stoned(youmonst.data) &&
1307. 					polymon(PM_STONE_GOLEM))) {
1308. 				char kbuf[BUFSZ];
1309. 
1310. 				Sprintf(kbuf, "%s corpse",
1311. 					an(mons[obj->corpsenm].mname));
1312. 				pline("Snatching %s is a fatal mistake.", kbuf);
1313. 				instapetrify(kbuf);
1314. 			    }
1315. 			    obj = hold_another_object(obj, "You drop %s!",
1316. 				    doname(obj), (const char *)0);
1317. 			    break;
1318. 			default:
1319. 			    /* to floor beneath mon */
1320. 			    You("knock %s from %s grasp!", the(xname(obj)),
1321. 				    s_suffix(mon_nam(mtmp)));
1322. 			    if (obj->otyp == CRYSKNIFE &&
1323. 				    (!obj->oerodeproof || !rn2(10))) {
1324. 				obj->otyp = WORM_TOOTH;
1325. 				obj->oerodeproof = 0;
1326. 			    }
1327. 			    place_object(obj, mtmp->mx, mtmp->my);
1328. 			    stackobj(obj);
1329. 			    break;
1330. 		    }
1331. 		} else if (mtmp->mcanmove && !mtmp->msleeping)
1332. 		    pline("%s evades your attack.", Monnam(mtmp));
1333. 		else
1334. 		    You("fail to dislodge %s %s.", s_suffix(mon_nam(mtmp)),
1335. 			    xname(obj));
1336. 		wakeup(mtmp);
1337. 		if (!mtmp->mcanmove && !rn2(10)) {
1338. 		    mtmp->mcanmove = 1;
1339. 		    mtmp->mfrozen = 0;
1340. 		}
1341. 		break;
1342. 	    case T_DAZZLE:
1343. 	    	/* Short range stun attack */
1344. 	    	if (Blind) {
1345. 	    		You("can't see anything!");
1346. 	    		return(0);
1347. 	    	}
1348. 	    	if (!getdir((char *)0)) return(0);
1349. 		if (!u.dx && !u.dy) {
1350. 			/* Hopefully a mistake ;B */
1351. 			You("can't see yourself!");
1352. 			return(0);
1353. 		}
1354. 		for(i = 0; (i  <= ((techlev(tech_no) / 8) + 1) 
1355. 			&& isok(u.ux + (i*u.dx), u.uy + (i*u.dy))); i++) {
1356. 		    mtmp = m_at(u.ux + (i*u.dx), u.uy + (i*u.dy));
1357. 		    if (mtmp && canseemon(mtmp)) break;
1358. 		}
1359. 		if (!mtmp || !canseemon(mtmp)) {
1360. 			You("fail to make eye contact with anything!");
1361. 			return (0);
1362. 		}
1363.                 You("stare at %s.", mon_nam(mtmp));
1364.                 if (!haseyes(mtmp->data))
1365.                 	pline("..but %s has no eyes!", mon_nam(mtmp));
1366.                 else if (!mtmp->mcansee)
1367.                 	pline("..but %s cannot see you!", mon_nam(mtmp));
1368.                 if ((rn2(6) + rn2(6) + (techlev(tech_no) - mtmp->m_lev)) > 10) {
1369. 			You("dazzle %s!", mon_nam(mtmp));
1370. 			mtmp->mcanmove = 0;
1371. 			mtmp->mfrozen = rnd(10);
1372. 		} else {
1373.                        pline("%s breaks the stare!", Monnam(mtmp));
1374. 		}
1375.                	t_timeout = rn1(50,25);
1376. 	    	break;
1377. 	    case T_BLITZ:
1378. 	    	if (uwep || (u.twoweap && uswapwep)) {
1379. 			You("can't do this while wielding a weapon!");
1380. 	    		return(0);
1381. 	    	} else if (uarms) {
1382. 			You("can't do this while holding a shield!");
1383. 	    		return(0);
1384. 	    	}
1385. 	    	if (!doblitz()) return (0);		
1386. 		
1387.                 t_timeout = rn1(1000,500);
1388. 	    	break;
1389.             case T_PUMMEL:
1390. 	    	if (uwep || (u.twoweap && uswapwep)) {
1391. 			You("can't do this while wielding a weapon!");
1392. 	    		return(0);
1393. 	    	} else if (uarms) {
1394. 			You("can't do this while holding a shield!");
1395. 	    		return(0);
1396. 	    	}
1397. 		if (!getdir((char *)0)) return(0);
1398. 		if (!u.dx && !u.dy) {
1399. 			You("flex your muscles.");
1400. 			return(0);
1401. 		}
1402.             	if (!blitz_pummel()) return(0);
1403.                 t_timeout = rn1(1000,500);
1404. 		break;
1405.             case T_G_SLAM:
1406. 	    	if (uwep || (u.twoweap && uswapwep)) {
1407. 			You("can't do this while wielding a weapon!");
1408. 	    		return(0);
1409. 	    	} else if (uarms) {
1410. 			You("can't do this while holding a shield!");
1411. 	    		return(0);
1412. 	    	}
1413. 		if (!getdir((char *)0)) return(0);
1414. 		if (!u.dx && !u.dy) {
1415. 			You("flex your muscles.");
1416. 			return(0);
1417. 		}
1418.             	if (!blitz_g_slam()) return(0);
1419.                 t_timeout = rn1(1000,500);
1420. 		break;
1421.             case T_DASH:
1422. 		if (!getdir((char *)0)) return(0);
1423. 		if (!u.dx && !u.dy) {
1424. 			You("stretch.");
1425. 			return(0);
1426. 		}
1427.             	if (!blitz_dash()) return(0);
1428.                 t_timeout = rn1(50, 25);
1429. 		break;
1430.             case T_POWER_SURGE:
1431.             	if (!blitz_power_surge()) return(0);
1432. 		t_timeout = rn1(1000,500);
1433. 		break;            	
1434.             case T_SPIRIT_BOMB:
1435. 	    	if (uwep || (u.twoweap && uswapwep)) {
1436. 			You("can't do this while wielding a weapon!");
1437. 	    		return(0);
1438. 	    	} else if (uarms) {
1439. 			You("can't do this while holding a shield!");
1440. 	    		return(0);
1441. 	    	}
1442. 		if (!getdir((char *)0)) return(0);
1443.             	if (!blitz_spirit_bomb()) return(0);
1444. 		t_timeout = rn1(1000,500);
1445. 		break;            	
1446. 	    case T_DRAW_BLOOD:
1447. 		if (!maybe_polyd(is_vampire(youmonst.data),
1448. 		  Race_if(PM_VAMPIRE))) {
1449. 		    /* ALI
1450. 		     * Otherwise we get problems with what we create:
1451. 		     * potions of vampire blood would no longer be
1452. 		     * appropriate.
1453. 		     */
1454. 		    You("must be in your natural form to draw blood.");
1455. 		    return(0);
1456. 		}
1457. 		obj = use_medical_kit(PHIAL, TRUE, "draw blood with");
1458. 		if (!obj)
1459. 		    return 0;
1460. 		if (u.ulevel <= 1) {
1461. 		    You_cant("seem to find a vein.");
1462. 		    return 0;
1463. 		}
1464. 		check_unpaid(obj);
1465. 		if (obj->quan > 1L)
1466. 		    obj->quan--;
1467. 		else {
1468. 		    obj_extract_self(obj);
1469. 		    obfree(obj, (struct obj *)0);
1470. 		}
1471. 		pline("Using your medical kit, you draw off a phial of your blood.");
1472. 		losexp("drawing blood", TRUE);
1473. 		if (u.uexp > 0)
1474. 		    u.uexp = newuexp(u.ulevel - 1);
1475. 		otmp = mksobj(POT_VAMPIRE_BLOOD, FALSE, FALSE);
1476. 		otmp->cursed = obj->cursed;
1477. 		otmp->blessed = obj->blessed;
1478. 		(void) hold_another_object(otmp,
1479. 			"You fill, but have to drop, %s!", doname(otmp),
1480. 			(const char *)0);
1481. 		t_timeout = rn1(1000, 500);
1482. 		break;
1483. 	    default:
1484. 	    	pline ("Error!  No such effect (%i)", tech_no);
1485. 		break;
1486.         }
1487.         if (!can_limitbreak())
1488. 	    techtout(tech_no) = (t_timeout * (100 - techlev(tech_no))/100);
1489. 
1490. 	/*By default,  action should take a turn*/
1491. 	return(1);
1492. }
1493. 
1494. /* Whether or not a tech is in use.
1495.  * 0 if not in use, turns left if in use. Tech is done when techinuse == 1
1496.  */
1497. int
1498. tech_inuse(tech_id)
1499. int tech_id;
1500. {
1501.         int i;
1502. 
1503.         if (tech_id < 1 || tech_id > MAXTECH) {
1504.                 impossible ("invalid tech: %d", tech_id);
1505.                 return(0);
1506.         }
1507.         for (i = 0; i < MAXTECH; i++) {
1508.                 if (techid(i) == tech_id) {
1509.                         return (techt_inuse(i));
1510.                 }
1511.         }
1512. 	return (0);
1513. }
1514. 
1515. void
1516. tech_timeout()
1517. {
1518. 	int i;
1519. 	
1520.         for (i = 0; i < MAXTECH; i++) {
1521. 	    if (techid(i) == NO_TECH)
1522. 		continue;
1523. 	    if (techt_inuse(i)) {
1524. 	    	/* Check if technique is done */
1525. 	        if (!(--techt_inuse(i)))
1526. 	        switch (techid(i)) {
1527. 		    case T_EVISCERATE:
1528. 			You("retract your claws.");
1529. 			/* You're using bare hands now,  so new msg for next attack */
1530. 			unweapon=TRUE;
1531. 			/* Lose berserk status */
1532. 			repeat_hit = 0;
1533. 			break;
1534. 		    case T_BERSERK:
1535. 			The("red haze in your mind clears.");
1536. 			break;
1537. 		    case T_KIII:
1538. 			You("calm down.");
1539. 			break;
1540. 		    case T_FLURRY:
1541. 			You("relax.");
1542. 			break;
1543. 		    case T_E_FIST:
1544. 			You("feel the power dissipate.");
1545. 			break;
1546. 		    case T_SIGIL_TEMPEST:
1547. 			pline_The("sigil of tempest fades.");
1548. 			break;
1549. 		    case T_SIGIL_CONTROL:
1550. 			pline_The("sigil of control fades.");
1551. 			break;
1552. 		    case T_SIGIL_DISCHARGE:
1553. 			pline_The("sigil of discharge fades.");
1554. 			break;
1555. 		    case T_RAGE:
1556. 			Your("anger cools.");
1557. 			break;
1558. 		    case T_POWER_SURGE:
1559. 			pline_The("awesome power within you fades.");
1560. 			break;
1561. 		    case T_BLINK:
1562. 			You("sense the flow of time returning to normal.");
1563. 			break;
1564. 		    case T_CHI_STRIKE:
1565. 			You("feel the power in your hands dissipate.");
1566. 			break;
1567. 		    case T_CHI_HEALING:
1568. 			You("feel the healing power dissipate.");
1569. 			break;
1570. 	            default:
1571. 	            	break;
1572. 	        } else switch (techid(i)) {
1573. 	        /* During the technique */
1574. 		    case T_RAGE:
1575. 			/* Bleed but don't kill */
1576. 			if (u.uhpmax > 1) u.uhpmax--;
1577. 			if (u.uhp > 1) u.uhp--;
1578. 			break;
1579. 		    case T_POWER_SURGE:
1580. 			/* Bleed off power.  Can go to zero as 0 power is not fatal */
1581. 			if (u.uenmax > 1) u.uenmax--;
1582. 			if (u.uen > 0) u.uen--;
1583. 			break;
1584. 	            default:
1585. 	            	break;
1586. 	        }
1587. 	    } 
1588. 
1589. 	    if (techtout(i) > 0) techtout(i)--;
1590.         }
1591. }
1592. 
1593. void
1594. docalm()
1595. {
1596. 	int i, tech, n = 0;
1597. 
1598. 	for (i = 0; i < MAXTECH; i++) {
1599. 	    tech = techid(i);
1600. 	    if (tech != NO_TECH && techt_inuse(i)) {
1601. 		aborttech(tech);
1602. 		n++;
1603. 	    }
1604. 	}
1605. 	if (n)
1606. 	    You("calm down.");
1607. }
1608. 
1609. static void
1610. hurtmon(mtmp, tmp)
1611. struct monst *mtmp;
1612. int tmp;
1613. {
1614. 	mtmp->mhp -= tmp;
1615. 	if (mtmp->mhp < 1) killed (mtmp);
1616. #ifdef SHOW_DMG
1617. 	else showdmg(tmp);
1618. #endif
1619. }
1620. 
1621. static const struct 	innate_tech *
1622. role_tech()
1623. {
1624. 	switch (Role_switch) {
1625. 		case PM_ARCHEOLOGIST:	return (arc_tech);
1626. 		case PM_BARBARIAN:	return (bar_tech);
1627. 		case PM_CAVEMAN:	return (cav_tech);
1628. 		case PM_FLAME_MAGE:	return (fla_tech);
1629. 		case PM_HEALER:		return (hea_tech);
1630. 		case PM_ICE_MAGE:	return (ice_tech);
1631. 		case PM_KNIGHT:		return (kni_tech);
1632. 		case PM_MONK: 		return (mon_tech);
1633. 		case PM_NECROMANCER:	return (nec_tech);
1634. 		case PM_PRIEST:		return (pri_tech);
1635. 		case PM_RANGER:		return (ran_tech);
1636. 		case PM_ROGUE:		return (rog_tech);
1637. 		case PM_SAMURAI:	return (sam_tech);
1638. #ifdef TOURIST        
1639. 		case PM_TOURIST:	return (tou_tech);
1640. #endif        
1641. 		case PM_UNDEAD_SLAYER:	return (und_tech);
1642. 		case PM_VALKYRIE:	return (val_tech);
1643. 		case PM_WIZARD:		return (wiz_tech);
1644. #ifdef YEOMAN
1645. 		case PM_YEOMAN:		return (yeo_tech);
1646. #endif
1647. 		default: 		return ((struct innate_tech *) 0);
1648. 	}
1649. }
1650. 
1651. static const struct     innate_tech *
1652. race_tech()
1653. {
1654. 	switch (Race_switch) {
1655. 		case PM_DOPPELGANGER:	return (dop_tech);
1656. #ifdef DWARF
1657. 		case PM_DWARF:		return (dwa_tech);
1658. #endif
1659. 		case PM_ELF:
1660. 		case PM_DROW:		return (elf_tech);
1661. 		case PM_GNOME:		return (gno_tech);
1662. 		case PM_HOBBIT:		return (hob_tech);
1663. 		case PM_HUMAN_WEREWOLF:	return (lyc_tech);
1664. 		case PM_VAMPIRE:	return (vam_tech);
1665. 		default: 		return ((struct innate_tech *) 0);
1666. 	}
1667. }
1668. 
1669. void
1670. adjtech(oldlevel,newlevel)
1671. int oldlevel, newlevel;
1672. {
1673. 	const struct   innate_tech  
1674. 		*tech = role_tech(), *rtech = race_tech();
1675. 	long mask = FROMEXPER;
1676. 
1677. 	while (tech || rtech) {
1678. 	    /* Have we finished with the tech lists? */
1679. 	    if (!tech || !tech->tech_id) {
1680. 	    	/* Try the race intrinsics */
1681. 	    	if (!rtech || !rtech->tech_id) break;
1682. 	    	tech = rtech;
1683. 	    	rtech = (struct innate_tech *) 0;
1684. 		mask = FROMRACE;
1685. 	    }
1686. 		
1687. 	    for(; tech->tech_id; tech++)
1688. 		if(oldlevel < tech->ulevel && newlevel >= tech->ulevel) {
1689. 		    if (tech->ulevel != 1 && !tech_known(tech->tech_id))
1690. 			You("learn how to perform %s!",
1691. 			  tech_names[tech->tech_id]);
1692. 		    learntech(tech->tech_id, mask, tech->tech_lev);
1693. 		} else if (oldlevel >= tech->ulevel && newlevel < tech->ulevel
1694. 		    && tech->ulevel != 1) {
1695. 		    learntech(tech->tech_id, mask, -1);
1696. 		    if (!tech_known(tech->tech_id))
1697. 			You("lose the ability to perform %s!",
1698. 			  tech_names[tech->tech_id]);
1699. 		}
1700. 	}
1701. }
1702. 
1703. int
1704. mon_to_zombie(monnum)
1705. int monnum;
1706. {
1707. 	if ((&mons[monnum])->mlet == S_ZOMBIE) return monnum;  /* is already zombie */
1708. 	if ((&mons[monnum])->mlet == S_KOBOLD) return PM_KOBOLD_ZOMBIE;
1709. 	if ((&mons[monnum])->mlet == S_GNOME) return PM_GNOME_ZOMBIE;
1710. 	if (is_orc(&mons[monnum])) return PM_ORC_ZOMBIE;
1711. 	if (is_dwarf(&mons[monnum])) return PM_DWARF_ZOMBIE;
1712. 	if (is_elf(&mons[monnum])) return PM_ELF_ZOMBIE;
1713. 	if (is_human(&mons[monnum])) return PM_HUMAN_ZOMBIE;
1714. 	if (monnum == PM_ETTIN) return PM_ETTIN_ZOMBIE;
1715. 	if (is_giant(&mons[monnum])) return PM_GIANT_ZOMBIE;
1716. 	/* Is it humanoid? */
1717. 	if (!humanoid(&mons[monnum])) return (-1);
1718. 	/* Otherwise,  return a ghoul or ghast */
1719. 	if (!rn2(4)) return PM_GHAST;
1720. 	else return PM_GHOUL;
1721. }
1722. 
1723. 
1724. /*WAC tinker code*/
1725. STATIC_PTR int
1726. tinker()
1727. {
1728. 	int chance;
1729. 	struct obj *otmp = uwep;
1730. 
1731. 
1732. 	if (delay) {    /* not if (delay++), so at end delay == 0 */
1733. 		delay++;
1734. #if 0
1735. 		use_skill(P_TINKER, 1); /* Tinker skill */
1736. #endif
1737. 		/*WAC a bit of practice so even if you're interrupted
1738. 		you won't be wasting your time ;B*/
1739. 		return(1); /* still busy */
1740. 	}
1741. 
1742. 	if (!uwep)
1743. 		return (0);
1744. 
1745. 	You("finish your tinkering.");
1746. 	chance = 5;
1747. /*	chance += PSKILL(P_TINKER); */
1748. 	if (rnl(10) < chance) {		
1749. 		upgrade_obj(otmp);
1750. 	} else {
1751. 		/* object downgrade  - But for now,  nothing :) */
1752. 	}
1753. 
1754. 	setuwep(otmp, FALSE);
1755. 	You("now hold %s!", doname(otmp));
1756. 	return(0);
1757. }
1758. 
1759. /*WAC  draw energy from surrounding objects */
1760. STATIC_PTR int
1761. draw_energy()
1762. {
1763. 	int powbonus = 1;
1764. 	if (delay) {    /* not if (delay++), so at end delay == 0 */
1765. 		delay++;
1766. 		confdir();
1767. 		if(isok(u.ux + u.dx, u.uy + u.dy)) {
1768. 			switch((&levl[u.ux + u.dx][u.uy + u.dy])->typ) {
1769. 			    case ALTAR: /* Divine power */
1770. 			    	powbonus =  (u.uenmax > 28 ? u.uenmax / 4
1771. 			    			: 7);
1772. 				break;
1773. 			    case THRONE: /* Regal == pseudo divine */
1774. 			    	powbonus =  (u.uenmax > 36 ? u.uenmax / 6
1775. 			    			: 6);			    		 	
1776. 				break;
1777. 			    case CLOUD: /* Air */
1778. 			    case TREE: /* Earth */
1779. 			    case LAVAPOOL: /* Fire */
1780. 			    case ICE: /* Water - most ordered form */
1781. 			    	powbonus = 5;
1782. 				break;
1783. 			    case AIR:
1784. 			    case MOAT: /* Doesn't freeze */
1785. 			    case WATER:
1786. 			    	powbonus = 4;
1787. 				break;
1788. 			    case POOL: /* Can dry up */
1789. 			    	powbonus = 3;
1790. 				break;
1791. 			    case FOUNTAIN:
1792. 			    	powbonus = 2;
1793. 				break;
1794. 			    case SINK:  /* Cleansing water */
1795. 			    	if (!rn2(3)) powbonus = 2;
1796. 				break;
1797. 			    case TOILET: /* Water Power...but also waste! */
1798. 			    	if (rn2(100) < 50)
1799. 			    		powbonus = 2;
1800. 			    	else powbonus = -2;
1801. 				break;
1802. 			    case GRAVE:
1803. 			    	powbonus = -4;
1804. 				break;
1805. 			    default:
1806. 				break;
1807. 			}
1808. 		}
1809. 		u.uen += powbonus;
1810. 		if (u.uen > u.uenmax) {
1811. 			delay = 0;
1812. 			u.uen = u.uenmax;
1813. 		}
1814. 		if (u.uen < 1) u.uen = 0;
1815. 		flags.botl = 1;
1816. 		return(1); /* still busy */
1817. 	}
1818. 	You("finish drawing energy from your surroundings.");
1819. 	return(0);
1820. }
1821. 
1822. static const char 
1823. 	*Enter_Blitz = "Enter Blitz Command[. to end]: ";
1824. 
1825. /* Keep commands that reference the same blitz together 
1826.  * Keep the BLITZ_START before the BLITZ_CHAIN before the BLITZ_END
1827.  */
1828. static const struct blitz_tab blitzes[] = { 	
1829. 	{"LLDDR", 5, blitz_chi_strike, T_CHI_STRIKE, BLITZ_START},
1830. 	{"LLDDRDR", 7, blitz_chi_strike, T_CHI_STRIKE, BLITZ_START},
1831. 	{"RR",  2, blitz_dash, T_DASH, BLITZ_START},
1832. 	{"LL",  2, blitz_dash, T_DASH, BLITZ_START},
1833. 	{"UURRDDL", 7, blitz_e_fist, T_E_FIST, BLITZ_START},
1834. 	{"URURRDDLDL", 10, blitz_e_fist, T_E_FIST, BLITZ_START},
1835. 	{"DDRRDDRR", 8, blitz_power_surge, T_POWER_SURGE, BLITZ_START},
1836. 	{"DRDRDRDR", 8, blitz_power_surge, T_POWER_SURGE, BLITZ_START},
1837. 	{"LRL", 3, blitz_pummel, T_PUMMEL, BLITZ_CHAIN},
1838. 	{"RLR", 3, blitz_pummel, T_PUMMEL, BLITZ_CHAIN},
1839. 	{"DDDD", 4, blitz_g_slam, T_G_SLAM, BLITZ_END},
1840. 	{"DUDUUDDD", 8, blitz_spirit_bomb, T_SPIRIT_BOMB, BLITZ_END},
1841. 	{"", 0, (void *)0, 0, BLITZ_END} /* Array terminator */
1842. };
1843. 
1844. #define MAX_BLITZ 50
1845. #define MIN_CHAIN 2
1846. #define MAX_CHAIN 5
1847. 
1848. /* parse blitz input */
1849. static int
1850. doblitz()
1851. {
1852. 	int i, j, dx, dy, bdone = 0, tech_no;
1853. 	char buf[BUFSZ];
1854. 	char *bp;
1855. 	int blitz_chain[MAX_CHAIN], blitz_num;
1856.         
1857. 	tech_no = (get_tech_no(T_BLITZ));
1858. 
1859. 	if (tech_no == -1) {
1860. 		return(0);
1861. 	}
1862. 	
1863. 	if (u.uen < 10) {
1864. 		You("are too weak to attempt this!");
1865.             	return(0);
1866. 	}
1867. 
1868. 	bp = buf;
1869. 	
1870. 	if (!getdir((char *)0)) return(0);
1871. 	if (!u.dx && !u.dy) {
1872. 		return(0);
1873. 	}
1874. 	
1875. 	dx = u.dx;
1876. 	dy = u.dy;
1877. 
1878. 	doblitzlist();
1879. 
1880.     	for (i= 0; i < MAX_BLITZ; i++) {
1881. 		if (!getdir(Enter_Blitz)) return(0); /* Get directional input */
1882.     		if (!u.dx && !u.dy && !u.dz) break;
1883.     		if (u.dx == -1) {
1884.     			*(bp) = 'L';
1885.     			bp++;
1886.     		} else if (u.dx == 1) {
1887.     			*(bp) = 'R';
1888.     			bp++;
1889.     		}
1890.     		if (u.dy == -1) {
1891.     			*(bp) = 'U';
1892.     			bp++;
1893.     		} else if (u.dy == 1) {
1894.     			*(bp) = 'D';
1895.     			bp++;
1896.     		}
1897.     		if (u.dz == -1) {
1898.     			*(bp) = '>';
1899.     			bp++;
1900.     		} else if (u.dz == 1) {
1901.     			*(bp) = '<';
1902.     			bp++;
1903.     		}
1904.     	}
1905. 	*(bp) = '.';
1906. 	bp++;
1907. 	*(bp) = '\0';
1908. 	bp = buf;
1909. 
1910. 	/* Point of no return - You've entered and terminated a blitz, so... */
1911.     	u.uen -= 10;
1912. 
1913.     	/* parse input */
1914.     	/* You can't put two of the same blitz in a row */
1915.     	blitz_num = 0;
1916.     	while(strncmp(bp, ".", 1)) {
1917. 	    bdone = 0;
1918. 	    for (j = 0; blitzes[j].blitz_len; j++) {
1919. 	    	if (blitz_num >= MAX_CHAIN || 
1920. 	    	    blitz_num >= (MIN_CHAIN + (techlev(tech_no) / 10)))
1921. 	    		break; /* Trying to chain too many blitz commands */
1922. 		else if (!strncmp(bp, blitzes[j].blitz_cmd, blitzes[j].blitz_len)) {
1923. 	    		/* Trying to chain in a command you don't know yet */
1924. 			if (!tech_known(blitzes[j].blitz_tech))
1925. 				break;
1926. 	    		if (blitz_num) {
1927. 				/* Check if trying to chain two of the exact same 
1928. 				 * commands in a row 
1929. 				 */
1930. 	    			if (j == blitz_chain[(blitz_num - 1)]) 
1931. 	    				break;
1932. 	    			/* Trying to chain after chain finishing command */
1933. 	    			if (blitzes[blitz_chain[(blitz_num - 1)]].blitz_type 
1934. 	    							== BLITZ_END)
1935. 	    				break;
1936. 	    			/* Trying to put a chain starter after starting
1937. 	    			 * a chain
1938. 	    			 * Note that it's OK to put two chain starters in a 
1939. 	    			 * row
1940. 	    			 */
1941. 	    			if ((blitzes[j].blitz_type == BLITZ_START) &&
1942. 	    			    (blitzes[blitz_chain[(blitz_num - 1)]].blitz_type 
1943. 	    							!= BLITZ_START))
1944. 	    				break;
1945. 	    		}
1946. 			bp += blitzes[j].blitz_len;
1947. 			blitz_chain[blitz_num] = j;
1948. 			blitz_num++;
1949. 			bdone = 1;
1950. 			break;
1951. 		}
1952. 	    }
1953. 	    if (!bdone) {
1954. 		You("stumble!");
1955. 		return(1);
1956. 	    }
1957.     	}
1958. 	for (i = 0; i < blitz_num; i++) {
1959. 	    u.dx = dx;
1960. 	    u.dy = dy;
1961. 	    if (!( (*blitzes[blitz_chain[i]].blitz_funct)() )) break;
1962. 	}
1963. 	
1964.     	/* done */
1965. 	return(1);
1966. }
1967. 
1968. static void
1969. doblitzlist()
1970. {
1971. 	winid tmpwin;
1972. 	int i, n;
1973. 	char buf[BUFSZ];
1974. 	menu_item *selected;
1975. 	anything any;
1976. 
1977. 	tmpwin = create_nhwindow(NHW_MENU);
1978. 	start_menu(tmpwin);
1979. 	any.a_void = 0;         /* zero out all bits */
1980. 
1981.         Sprintf(buf, "%16s %10s %-17s", "[LU = Left Up]", "[U = Up]", "[RU = Right Up]");
1982. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
1983.         Sprintf(buf, "%16s %10s %-17s", "[L = Left]", "", "[R = Right]");
1984. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
1985.         Sprintf(buf, "%16s %10s %-17s", "[LD = Left Down]", "[D = Down]", "[RD = Right Down]");
1986. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);        
1987. 
1988.         Sprintf(buf, "%-30s %10s   %s", "Name", "Type", "Command");
1989. 	add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED);
1990. 
1991.         for (i = 0; blitzes[i].blitz_len; i++) {
1992. 	    if (tech_known(blitzes[i].blitz_tech)) {
1993.                 Sprintf(buf, "%-30s %10s   %s",
1994.                     (i && blitzes[i].blitz_tech == blitzes[(i-1)].blitz_tech ?
1995.                     	"" : tech_names[blitzes[i].blitz_tech]), 
1996.                     (blitzes[i].blitz_type == BLITZ_START ? 
1997.                     	"starter" :
1998.                     	(blitzes[i].blitz_type == BLITZ_CHAIN ? 
1999. 	                    	"chain" : 
2000. 	                    	(blitzes[i].blitz_type == BLITZ_END ? 
2001.                     			"finisher" : "unknown"))),
2002.                     blitzes[i].blitz_cmd);
2003. 
2004. 		add_menu(tmpwin, NO_GLYPH, &any,
2005.                          0, 0, ATR_NONE, buf, MENU_UNSELECTED);
2006. 	    }
2007. 	}
2008.         end_menu(tmpwin, "Currently known blitz manoeuvers");
2009. 
2010. 	n = select_menu(tmpwin, PICK_NONE, &selected);
2011. 	destroy_nhwindow(tmpwin);
2012. 	return;
2013. }
2014. 
2015. static int
2016. blitz_chi_strike()
2017. {
2018. 	int tech_no;
2019. 	
2020. 	tech_no = (get_tech_no(T_CHI_STRIKE));
2021. 
2022. 	if (tech_no == -1) {
2023. 		return(0);
2024. 	}
2025. 
2026. 	if (u.uen < 1) {
2027. 		You("are too weak to attempt this!");
2028.             	return(0);
2029. 	}
2030. 	You("feel energy surge through your hands!");
2031. 	techt_inuse(tech_no) = techlev(tech_no) + 4;
2032. 	return(1);
2033. }
2034. 
2035. static int
2036. blitz_e_fist()
2037. {
2038. 	int tech_no;
2039. 	const char *str;
2040. 	
2041. 	tech_no = (get_tech_no(T_E_FIST));
2042. 
2043. 	if (tech_no == -1) {
2044. 		return(0);
2045. 	}
2046. 	
2047. 	str = makeplural(body_part(HAND));
2048. 	You("focus the powers of the elements into your %s.", str);
2049. 	techt_inuse(tech_no) = rnd((int) (techlev(tech_no)/3 + 1)) + d(1,4) + 2;
2050. 	return 1;
2051. }
2052. 
2053. /* Assumes u.dx, u.dy already set up */
2054. static int
2055. blitz_pummel()
2056. {
2057. 	int i = 0, tech_no;
2058. 	struct monst *mtmp;
2059. 	tech_no = (get_tech_no(T_PUMMEL));
2060. 
2061. 	if (tech_no == -1) {
2062. 		return(0);
2063. 	}
2064. 
2065. 	You("let loose a barrage of blows!");
2066. 
2067. 	mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
2068. 	if (!mtmp) {
2069. 		You("strike nothing.");
2070. 		return (0);
2071. 	}
2072. 	if (!attack(mtmp)) return (0);
2073. 	
2074. 	/* Perform the extra attacks
2075. 	 */
2076. 	for (i = 0; (i < 4); i++) {
2077. 	    if (rn2(70) > (techlev(tech_no) + 30)) break;
2078. 	    mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
2079. 	    if (!mtmp) return (1);
2080. 	    if (!attack(mtmp)) return (1);
2081. 	} 
2082. 	
2083. 	return(1);
2084. }
2085. 
2086. /* Assumes u.dx, u.dy already set up */
2087. static int
2088. blitz_g_slam()
2089. {
2090. 	int tech_no, tmp, canhitmon, objenchant;
2091. 	struct monst *mtmp;
2092. 	struct trap *chasm;
2093. 
2094. 	tech_no = (get_tech_no(T_G_SLAM));
2095. 
2096. 	if (tech_no == -1) {
2097. 		return(0);
2098. 	}
2099. 
2100. 	mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
2101. 	if (!mtmp) {
2102. 		You("strike nothing.");
2103. 		return (0);
2104. 	}
2105. 	if (!attack(mtmp)) return (0);
2106. 
2107. 	/* Slam the monster into the ground */
2108. 	mtmp = m_at(u.ux + u.dx, u.uy + u.dy);
2109. 	if (!mtmp || u.uswallow) return(1);
2110. 
2111. 	You("hurl %s downwards...", mon_nam(mtmp));
2112. 	if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) return(1);
2113. 
2114. 	if (need_four(mtmp)) canhitmon = 4;
2115. 	else if (need_three(mtmp)) canhitmon = 3;
2116. 	else if (need_two(mtmp)) canhitmon = 2;
2117. 	else if (need_one(mtmp)) canhitmon = 1;
2118. 	else canhitmon = 0;
2119. 	if (Upolyd) {
2120. 	    if (hit_as_four(&youmonst))	objenchant = 4;
2121. 	    else if (hit_as_three(&youmonst)) objenchant = 3;
2122. 	    else if (hit_as_two(&youmonst)) objenchant = 2;
2123. 	    else if (hit_as_one(&youmonst)) objenchant = 1;
2124. 	    else if (need_four(&youmonst)) objenchant = 4;
2125. 	    else if (need_three(&youmonst)) objenchant = 3;
2126. 	    else if (need_two(&youmonst)) objenchant = 2;
2127. 	    else if (need_one(&youmonst)) objenchant = 1;
2128. 	    else objenchant = 0;
2129. 	} else
2130. 	    objenchant = u.ulevel / 4;
2131. 
2132. 	tmp = (5 + rnd(6) + (techlev(tech_no) / 5));
2133. 	
2134. 	chasm = maketrap(u.ux + u.dx, u.uy + u.dy, PIT);
2135. 	if (chasm) {
2136. 	    if (!is_flyer(mtmp->data) && !is_clinger(mtmp->data))
2137. 		mtmp->mtrapped = 1;
2138. 	    chasm->tseen = 1;
2139. 	    levl[u.ux + u.dx][u.uy + u.dy].doormask = 0;
2140. 	    pline("%s slams into the ground, creating a crater!", Monnam(mtmp));
2141. 	    tmp *= 2;
2142. 	}
2143. 
2144. 	mselftouch(mtmp, "Falling, ", TRUE);
2145. 	if (!DEADMONSTER(mtmp)) {
2146. 	    if (objenchant < canhitmon)
2147. 		pline("%s doesn't seem to be harmed.", Monnam(mtmp));
2148. 	    else if ((mtmp->mhp -= tmp) <= 0) {
2149. 		if(!cansee(u.ux + u.dx, u.uy + u.dy))
2150. 		    pline("It is destroyed!");
2151. 		else {
2152. 		    You("destroy %s!", 	
2153. 		    	mtmp->mtame
2154. 			    ? x_monnam(mtmp, ARTICLE_THE, "poor",
2155. 				mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE)
2156. 			    : mon_nam(mtmp));
2157. 		}
2158. 		xkilled(mtmp,0);
2159. 	    }
2160. 	}
2161. 
2162. 	return(1);
2163. }
2164. 
2165. /* Assumes u.dx, u.dy already set up */
2166. static int
2167. blitz_dash()
2168. {
2169. 	int tech_no;
2170. 	tech_no = (get_tech_no(T_DASH));
2171. 
2172. 	if (tech_no == -1) {
2173. 		return(0);
2174. 	}
2175. 	
2176. 	if ((!Punished || carried(uball)) && !u.utrap)
2177. 	    You("dash forwards!");
2178. 	hurtle(u.dx, u.dy, 2, FALSE);
2179. 	multi = 0;		/* No paralysis with dash */
2180. 	return 1;
2181. }
2182. 
2183. static int
2184. blitz_power_surge()
2185. {
2186. 	int tech_no, num;
2187. 	
2188. 	tech_no = (get_tech_no(T_POWER_SURGE));
2189. 
2190. 	if (tech_no == -1) {
2191. 		return(0);
2192. 	}
2193. 
2194. 	if (Upolyd) {
2195. 		You("cannot tap into your full potential in this form.");
2196. 		return(0);
2197. 	}
2198.     	You("tap into the full extent of your power!");
2199. 	num = 50 + (2 * techlev(tech_no));
2200.     	techt_inuse(tech_no) = num + 1;
2201. 	u.uenmax += num;
2202. 	u.uen = u.uenmax;
2203. 	return 1;
2204. }
2205. 
2206. /* Assumes u.dx, u.dy already set up */
2207. static int
2208. blitz_spirit_bomb()
2209. {
2210. 	int tech_no, num;
2211. 	int sx = u.ux, sy = u.uy, i;
2212. 	
2213. 	tech_no = (get_tech_no(T_SPIRIT_BOMB));
2214. 
2215. 	if (tech_no == -1) {
2216. 		return(0);
2217. 	}
2218. 
2219. 	You("gather your energy...");
2220. 	
2221. 	if (u.uen < 10) {
2222. 		pline("But it fizzles out.");
2223. 		u.uen = 0;
2224. 	}
2225. 
2226. 	num = 10 + (techlev(tech_no) / 5);
2227. 	num = (u.uen < num ? u.uen : num);
2228. 	
2229. 	u.uen -= num;
2230. 	
2231. 	for( i = 0; i < 2; i++) {		
2232. 	    if (!isok(sx,sy) || !cansee(sx,sy) || 
2233. 	    		IS_STWALL(levl[sx][sy].typ) || u.uswallow)
2234. 	    	break;
2235. 
2236. 	    /* Display the center of the explosion */
2237. 	    tmp_at(DISP_FLASH, explosion_to_glyph(EXPL_MAGICAL, S_explode5));
2238. 	    tmp_at(sx, sy);
2239. 	    delay_output();
2240. 	    tmp_at(DISP_END, 0);
2241. 
2242. 	    sx += u.dx;
2243. 	    sy += u.dy;
2244. 	}
2245. 	/* Magical Explosion */
2246. 	explode(sx, sy, 10, (d(3,6) + num), WAND_CLASS, EXPL_MAGICAL);
2247. 	return 1;
2248. }
2249. 
2250. #ifdef DEBUG
2251. void
2252. wiz_debug_cmd() /* in this case, allow controlled loss of techniques */
2253. {
2254. 	int tech_no, id, n = 0;
2255. 	long mask;
2256. 	if (gettech(&tech_no)) {
2257. 		id = techid(tech_no);
2258. 		if (id == NO_TECH) {
2259. 		    impossible("Unknown technique ([%d])?", tech_no);
2260. 		    return;
2261. 		}
2262. 		mask = tech_list[tech_no].t_intrinsic;
2263. 		if (mask & FROMOUTSIDE) n++;
2264. 		if (mask & FROMRACE) n++;
2265. 		if (mask & FROMEXPER) n++;
2266. 		if (!n) {
2267. 		    impossible("No intrinsic masks set (0x%lX).", mask);
2268. 		    return;
2269. 		}
2270. 		n = rn2(n);
2271. 		if (mask & FROMOUTSIDE && !n--) mask = FROMOUTSIDE;
2272. 		if (mask & FROMRACE && !n--) mask = FROMRACE;
2273. 		if (mask & FROMEXPER && !n--) mask = FROMEXPER;
2274. 		learntech(id, mask, -1);
2275. 		if (!tech_known(id))
2276. 		    You("lose the ability to perform %s.", tech_names[id]);
2277. 	}
2278. }
2279. #endif /* DEBUG */