1 /*
2  * Functions for dealing with problems brought about by weapons
3  *
4  * weapons.c	1.4 (AI Design)	12/22/84
5  */
6 
7 #include "rogue.h"
8 #include "curses.h"
9 
10 #define NONE 100
11 
12 static struct init_weps {
13     char *iw_dam;	/* Damage when wielded */
14     char *iw_hrl;	/* Damage when thrown */
15     char iw_launch;	/* Launching weapon */
16     int iw_flags;	/* Miscellaneous flags */
17 } init_dam[MAXWEAPONS] = {
18     "2d4",	"1d3",	NONE, 		0,		/* Mace */
19     "3d4",	"1d2",	NONE,		0,		/* Long sword */
20     "1d1",	"1d1",	NONE,		0,		/* Bow */
21     "1d1",	"2d3",	BOW,		ISMANY|ISMISL,	/* Arrow */
22     "1d6",	"1d4",	NONE,		ISMISL,		/* Dagger */
23     "4d4",	"1d2",	NONE,		0,		/* 2h sword */
24     "1d1",	"1d3",	NONE,		ISMANY|ISMISL,	/* Dart */
25     "1d1",	"1d1",	NONE,		0,		/* Crossbow */
26     "1d2",	"2d5",	CROSSBOW,	ISMANY|ISMISL,	/* Crossbow bolt */
27     "2d3",	"1d6",	NONE,		ISMISL		/* Spear */
28 };
29 
30 /*
31  * missile:
32  *	Fire a missile in a given direction
33  */
34 missile(ydelta, xdelta)
35 int ydelta, xdelta;
36 {
37     register THING *obj, *nitem;
38 
39     /*
40      * Get which thing we are hurling
41      */
42     if ((obj = get_item("throw", WEAPON)) == NULL)
43 		return;
44     if (!can_drop(obj) || is_current(obj))
45 		return;
46     /*
47      * Get rid of the thing.  If it is a non-multiple item object, or
48      * if it is the last thing, just drop it.  Otherwise, create a new
49      * item with a count of one.
50      */
51     hack:
52     if (obj->o_count < 2) {
53 		detach(pack, obj);
54 		inpack--;
55     } else {
56     	/*
57     	 * here is a quick hack to check if we can get a new item
58     	 */
59 		if ((nitem = new_item()) == NULL) {
60 		    obj->o_count = 1;
61 		    msg("something in your pack explodes!!!");
62 		    goto hack;
63 		}
64 		obj->o_count--;
65 		if (obj->o_group == 0)
66 		    inpack--;
67 		bcopy(*nitem,*obj);
68 		nitem->o_count = 1;
69 		obj = nitem;
70     }
71     do_motion(obj, ydelta, xdelta);
72     /*
73      * AHA! Here it has hit something.  If it is a wall or a door,
74      * or if it misses (combat) the monster, put it on the floor
75      */
76     if (moat(obj->o_pos.y, obj->o_pos.x) == NULL
77 		|| !hit_monster(unc(obj->o_pos), obj))
78 		    fall(obj, TRUE);
79 }
80 
81 /*
82  * do_motion:
83  *	Do the actual motion on the screen done by an object traveling
84  *	across the room
85  */
86 do_motion(obj, ydelta, xdelta)
87 THING *obj;
88 register int ydelta, xdelta;
89 {
90 	register byte under = '@';
91 
92     /*
93      * Come fly with us ...
94      */
95     bcopy(obj->o_pos,hero);
96     for (;;) {
97 		register int ch;
98 
99 		/*
100 		 * Erase the old one
101 		 */
102 		if (under != '@' && !ce(obj->o_pos, hero) && cansee(unc(obj->o_pos)))
103 		    mvaddch(obj->o_pos.y, obj->o_pos.x, under);
104 		/*
105 		 * Get the new position
106 		 */
107 		obj->o_pos.y += ydelta;
108 		obj->o_pos.x += xdelta;
109 
110 		if (step_ok(ch = winat(obj->o_pos.y, obj->o_pos.x)) && ch != DOOR) {
111 		    /*
112 		     * It hasn't hit anything yet, so display it
113 		     * If it alright.
114 		     */
115 		    if (cansee(unc(obj->o_pos))) {
116 				under = chat(obj->o_pos.y, obj->o_pos.x);
117 				mvaddch(obj->o_pos.y, obj->o_pos.x, obj->o_type);
118 				tick_pause();
119 			} else
120 				under = '@';
121 		    continue;
122 		}
123 		break;
124     }
125 }
126 
127 char *
128 short_name(obj)
129 THING *obj;
130 {
131 	switch (obj->o_type) {
132 		case WEAPON: return w_names[obj->o_which];
133 		case ARMOR: return a_names[obj->o_which];
134 		case FOOD: return "food";
135 		case POTION:
136 		case SCROLL:
137 		case AMULET:
138 		case STICK:
139 		case RING:
140 			return index(inv_name(obj, TRUE), ' ') + 1;
141 		default:
142 			return "bizzare thing";
143 	}
144 }
145 
146 /*
147  * fall:
148  *	Drop an item someplace around here.
149  */
150 fall(obj, pr)
151 THING *obj;
152 bool pr;
153 {
154     static coord fpos;
155     register int index;
156 
157     switch (fallpos(obj, &fpos))
158     {
159 	case 1:
160 	    index = INDEX(fpos.y, fpos.x);
161 	    _level[index] = obj->o_type;
162 	    bcopy(obj->o_pos,fpos);
163 	    if (cansee(fpos.y, fpos.x))
164 	    {
165 		if ((flat(obj->o_pos.y, obj->o_pos.x) & F_PASS) ||
166 		               (flat(obj->o_pos.y, obj->o_pos.x) & F_MAZE))
167 		    standout();
168 		mvaddch(fpos.y, fpos.x, obj->o_type);
169 		standend();
170 		if (moat(fpos.y,fpos.x) != NULL)
171 		    moat(fpos.y,fpos.x)->t_oldch = obj->o_type;
172 	    }
173 	    attach(lvl_obj, obj);
174 	    return;
175 	case 2:
176 	    pr = 0;
177     }
178     if (pr)
179 		msg("the %s vanishes%s.", short_name(obj),
180 								  noterse(" as it hits the ground"));
181     discard(obj);
182 }
183 
184 /*
185  * init_weapon:
186  *	Set up the initial goodies for a weapon
187  */
188 init_weapon(weap, type)
189 register THING *weap;
190 byte type;
191 {
192     register struct init_weps *iwp;
193 
194     iwp = &init_dam[type];
195     weap->o_damage = iwp->iw_dam;
196     weap->o_hurldmg = iwp->iw_hrl;
197     weap->o_launch = iwp->iw_launch;
198     weap->o_flags = iwp->iw_flags;
199     if (weap->o_flags & ISMANY)
200     {
201 	weap->o_count = rnd(8) + 8;
202 	weap->o_group = group++;
203     }
204     else
205 	weap->o_count = 1;
206 }
207 
208 /*
209  * hit_monster:
210  *	Does the missile hit the monster?
211  */
212 hit_monster(y, x, obj)
213 register int y, x;
214 THING *obj;
215 {
216     static coord mp;
217 	register THING *mo;
218 
219 	if (mo = moat(y, x)) {
220 	    mp.y = y;
221 	    mp.x = x;
222 	    return fight(&mp, mo->t_type, obj, TRUE);
223 	}
224 	return FALSE;
225 }
226 
227 /*
228  * num:
229  *	Figure out the plus number for armor/weapons
230  */
231 char *
232 num(n1, n2, type)
233 register int n1, n2;
234 register char type;
235 {
236     static char numbuf[10];
237 
238     sprintf(numbuf, "%s%d", n1 < 0 ? "" : "+", n1);
239     if (type == WEAPON)
240 	sprintf(&numbuf[strlen(numbuf)], ",%s%d", n2 < 0 ? "" : "+", n2);
241     return numbuf;
242 }
243 
244 /*
245  * wield:
246  *	Pull out a certain weapon
247  */
248 wield()
249 {
250     register THING *obj, *oweapon;
251     register char *sp;
252 
253     oweapon = cur_weapon;
254     if (!can_drop(cur_weapon))
255     {
256 	cur_weapon = oweapon;
257 	return;
258     }
259     cur_weapon = oweapon;
260     if ((obj = get_item("wield", WEAPON)) == NULL)
261     {
262 bad:
263 	after = FALSE;
264 	return;
265     }
266 
267     if (obj->o_type == ARMOR)
268     {
269 	msg("you can't wield armor");
270 	goto bad;
271     }
272     if (is_current(obj))
273         goto bad;
274 
275     sp = inv_name(obj, TRUE);
276     cur_weapon = obj;
277     ifterse2("now wielding %s (%c)","you are now wielding %s (%c)", sp, pack_char(obj));
278 }
279 
280 /*
281  * fallpos:
282  *	Pick a random position around the given (y, x) coordinates
283  */
284 fallpos(obj, newpos)
285 register coord *newpos;
286 THING *obj;
287 {
288     register int y, x, cnt = 0, ch;
289     THING *onfloor;
290 
291     for (y = obj->o_pos.y - 1; y <= obj->o_pos.y + 1; y++)
292 		for (x = obj->o_pos.x - 1; x <= obj->o_pos.x + 1; x++) {
293 		    /*
294 		     * check to make certain the spot is empty, if it is,
295 		     * put the object there, set it in the level list
296 		     * and re-draw the room if he can see it
297 		     */
298 		    if ((y == hero.y && x == hero.x) || offmap(y,x))
299 				continue;
300 		    if ((ch = chat(y, x)) == FLOOR || ch == PASSAGE) {
301 				if (rnd(++cnt) == 0) {
302 				    newpos->y = y;
303 				    newpos->x = x;
304 				}
305 				continue;
306 		    }
307 		    if (step_ok(ch)
308 				&& (onfloor = find_obj(y, x))
309 				&& onfloor->o_type == obj->o_type
310 				&& onfloor->o_group
311 				&& onfloor->o_group == obj->o_group)
312 		    {
313 				onfloor->o_count += obj->o_count;
314 				return 2;
315 		    }
316 		}
317 		return(cnt != 0);
318 }
319 
320 tick_pause()
321 {
322 	register int otick;
323 	extern int tick;
324 
325 	otick = tick;
326 	while (otick == tick)
327 		;
328 }
329 