Remove one last goto from actions2.c
[open-adventure.git] / actions2.c
1 #include "advent.h"
2 #include "database.h"
3
4 /*  Carry an object.  Special cases for bird and cage (if bird in cage, can't
5  *  take one without the other).  Liquids also special, since they depend on
6  *  status of bottle.  Also various side effects, etc. */
7
8 int carry(long obj)
9 {
10     if (TOTING(obj)) return(2011);
11     SPK=25;
12     if (obj == PLANT && game.prop[PLANT] <= 0)SPK=115;
13     if (obj == BEAR && game.prop[BEAR] == 1)SPK=169;
14     if (obj == CHAIN && game.prop[BEAR] != 0)SPK=170;
15     if (obj == URN)SPK=215;
16     if (obj == CAVITY)SPK=217;
17     if (obj == BLOOD)SPK=239;
18     if (obj == RUG && game.prop[RUG] == 2)SPK=222;
19     if (obj == SIGN)SPK=196;
20     if (obj == MESSAG) {
21         SPK=190;
22         DSTROY(MESSAG);
23     }
24     if (game.fixed[obj] != 0)
25         return(2011);
26     if (obj == WATER || obj == OIL) {
27         if (!HERE(BOTTLE) || LIQ(0) != obj) {
28             if (TOTING(BOTTLE) && game.prop[BOTTLE] == 1)
29                 return(fill(BOTTLE));
30             if (game.prop[BOTTLE] != 1)SPK=105;
31             if (!TOTING(BOTTLE))SPK=104;
32             return(2011);
33         }
34         obj = BOTTLE;
35     }
36
37     SPK=92;
38     if (game.holdng >= INVLIMIT)
39         return(2011);
40     if (obj == BIRD && game.prop[BIRD] != 1 && -1-game.prop[BIRD] != 1) {
41         if (game.prop[BIRD] == 2) {
42             SPK=238;
43             DSTROY(BIRD);
44             return(2011);
45         }
46         if (!TOTING(CAGE))SPK=27;
47         if (TOTING(ROD))SPK=26;
48         if (SPK/2 == 13) return(2011);
49         game.prop[BIRD]=1;
50     }
51     if ((obj==BIRD || obj==CAGE) && (game.prop[BIRD]==1 || -1-game.prop[BIRD]==1))
52         CARRY(BIRD+CAGE-obj,game.loc);
53     CARRY(obj,game.loc);
54     if (obj == BOTTLE && LIQ(0) != 0)
55         game.place[LIQ(0)] = -1;
56     if (!GSTONE(obj) || game.prop[obj] == 0)
57         return(2009);
58     game.prop[obj]=0;
59     game.prop[CAVITY]=1;
60     return(2009);
61 }
62
63 /*  Discard object.  "Throw" also comes here for most objects.  Special cases for
64  *  bird (might attack snake or dragon) and cage (might contain bird) and vase.
65  *  Drop coins at vending machine for extra batteries. */
66
67 int discard(long obj, bool just_do_it) {
68     if (!just_do_it) {
69         if (TOTING(ROD2) && obj == ROD && !TOTING(ROD))obj=ROD2;
70         if (!TOTING(obj)) return(2011);
71         if (obj == BIRD && HERE(SNAKE)) {
72             RSPEAK(30);
73             if (game.closed) return(19000);
74             DSTROY(SNAKE);
75             /* Set game.prop for use by travel options */
76             game.prop[SNAKE]=1;
77
78         } else if ((GSTONE(obj) && AT(CAVITY) && game.prop[CAVITY] != 0)) {
79             RSPEAK(218);
80             game.prop[obj]=1;
81             game.prop[CAVITY]=0;
82             if (HERE(RUG) && ((obj == EMRALD && game.prop[RUG] != 2) || (obj == RUBY &&
83                     game.prop[RUG] == 2))) {
84                 SPK=219;
85                 if (TOTING(RUG))SPK=220;
86                 if (obj == RUBY)SPK=221;
87                 RSPEAK(SPK);
88                 if (SPK != 220) {
89                     K=2-game.prop[RUG];
90                     game.prop[RUG]=K;
91                     if (K == 2)K=PLAC[SAPPH];
92                     MOVE(RUG+NOBJECTS,K);
93                 }
94             }
95         } else if (obj == COINS && HERE(VEND)) {
96             DSTROY(COINS);
97             DROP(BATTER,game.loc);
98             PSPEAK(BATTER,0);
99             return(2012);
100         } else if (obj == BIRD && AT(DRAGON) && game.prop[DRAGON] == 0) {
101             RSPEAK(154);
102             DSTROY(BIRD);
103             game.prop[BIRD]=0;
104             return(2012);
105         } else if (obj == BEAR && AT(TROLL)) {
106             RSPEAK(163);
107             MOVE(TROLL,0);
108             MOVE(TROLL+NOBJECTS,0);
109             MOVE(TROLL2,PLAC[TROLL]);
110             MOVE(TROLL2+NOBJECTS,FIXD[TROLL]);
111             JUGGLE(CHASM);
112             game.prop[TROLL]=2;
113         } else if (obj != VASE || game.loc == PLAC[PILLOW]) {
114             RSPEAK(54);
115         } else {
116             game.prop[VASE]=2;
117             if (AT(PILLOW))game.prop[VASE]=0;
118             PSPEAK(VASE,game.prop[VASE]+1);
119             if (game.prop[VASE] != 0)game.fixed[VASE]= -1;
120         }
121     }
122     K=LIQ(0);
123     if (K == obj)obj=BOTTLE;
124     if (obj == BOTTLE && K != 0)game.place[K]=0;
125     if (obj == CAGE && game.prop[BIRD] == 1)DROP(BIRD,game.loc);
126     DROP(obj,game.loc);
127     if (obj != BIRD) return(2012);
128     game.prop[BIRD]=0;
129     if (FOREST(game.loc))game.prop[BIRD]=2;
130     return(2012);
131 }
132
133 /*  Attack.  Assume target if unambiguous.  "Throw" also links here.  Attackable
134  *  objects fall into two categories: enemies (snake, dwarf, etc.)  and others
135  *  (bird, clam, machine).  Ambiguous if 2 enemies, or no enemies but 2 others. */
136
137 int attack(FILE *input, long obj, long verb) {
138         int i =ATDWRF(game.loc);
139         if (obj == 0) {
140             if (i > 0)
141                 obj=DWARF;
142             if (HERE(SNAKE))obj=obj*NOBJECTS+SNAKE;
143             if (AT(DRAGON) && game.prop[DRAGON] == 0)obj=obj*NOBJECTS+DRAGON;
144             if (AT(TROLL))obj=obj*NOBJECTS+TROLL;
145             if (AT(OGRE))obj=obj*NOBJECTS+OGRE;
146             if (HERE(BEAR) && game.prop[BEAR] == 0)obj=obj*NOBJECTS+BEAR;
147             if (obj > NOBJECTS) return(8000);
148             if (obj == 0) {
149                 /* Can't attack bird or machine by throwing axe. */
150                 if (HERE(BIRD) && verb != THROW)obj=BIRD;
151                 if (HERE(VEND) && verb != THROW)obj=obj*NOBJECTS+VEND;
152                 /* Clam and oyster both treated as clam for intransitive case;
153                  * no harm done. */
154                 if (HERE(CLAM) || HERE(OYSTER))obj=NOBJECTS*obj+CLAM;
155                 if (obj > NOBJECTS) return(8000);
156             }
157         }
158         if (obj == BIRD) {
159                 SPK=137;
160                 if (game.closed) return(2011);
161                 DSTROY(BIRD);
162                 game.prop[BIRD]=0;
163                 SPK=45;
164         }
165         if (obj == VEND) {
166             PSPEAK(VEND,game.prop[VEND]+2);
167             game.prop[VEND]=3-game.prop[VEND];
168             return(2012);
169         }
170
171         if (obj == 0)SPK=44;
172         if (obj == CLAM || obj == OYSTER)SPK=150;
173         if (obj == SNAKE)SPK=46;
174         if (obj == DWARF)SPK=49;
175         if (obj == DWARF && game.closed) return(19000);
176         if (obj == DRAGON)SPK=167;
177         if (obj == TROLL)SPK=157;
178         if (obj == OGRE)SPK=203;
179         if (obj == OGRE && i > 0) {
180             RSPEAK(SPK);
181             RSPEAK(6);
182             DSTROY(OGRE);
183             int k=0;
184             for (i=1; i < PIRATE; i++) {
185                 if (game.dloc[i] == game.loc) {
186                     ++k;
187                     game.dloc[i]=61;
188                     game.dseen[i]=false;
189                 }
190             }
191             SPK=SPK+1+1/k;
192             return(2011);
193         }
194         if (obj == BEAR)SPK=165+(game.prop[BEAR]+1)/2;
195         if (obj != DRAGON || game.prop[DRAGON] != 0) return(2011);
196         /*  Fun stuff for dragon.  If he insists on attacking it, win!
197          *  Set game.prop to dead, move dragon to central loc (still
198          *  fixed), move rug there (not fixed), and move him there,
199          *  too.  Then do a null motion to get new description. */
200         RSPEAK(49);
201         GETIN(input,WD1,WD1X,WD2,WD2X);
202         if (WD1 != MAKEWD(25) && WD1 != MAKEWD(250519)) return(2607);
203         PSPEAK(DRAGON,3);
204         game.prop[DRAGON]=1;
205         game.prop[RUG]=0;
206         K=(PLAC[DRAGON]+FIXD[DRAGON])/2;
207         MOVE(DRAGON+NOBJECTS,-1);
208         MOVE(RUG+NOBJECTS,0);
209         MOVE(DRAGON,K);
210         MOVE(RUG,K);
211         DROP(BLOOD,K);
212         for (obj=1; obj<=NOBJECTS; obj++) {
213         if (game.place[obj] == PLAC[DRAGON] || game.place[obj] == FIXD[DRAGON])MOVE(obj,K);
214         /*etc*/ ;
215         } /* end loop */
216         game.loc=K;
217         K=NUL;
218         return(8);
219 }
220
221 int throw_support(long spk)
222 {
223     RSPEAK(spk);
224     DROP(AXE,game.loc);
225     K=NUL;
226     return(8);
227 }
228
229 int throw(FILE *cmdin, long obj, long verb)
230 /*  Throw.  Same as discard unless axe.  Then same as attack except
231  *  ignore bird, and if dwarf is present then one might be killed.
232  *  (Only way to do so!)  Axe also special for dragon, bear, and
233  *  troll.  Treasures special for troll. */
234 {
235     if (TOTING(ROD2) && obj == ROD && !TOTING(ROD))obj=ROD2;
236     if (!TOTING(obj))
237         return(2011);
238     if (obj >= 50 && obj <= MAXTRS && AT(TROLL)) {
239         SPK=159;
240         /*  Snarf a treasure for the troll. */
241         DROP(obj,0);
242         MOVE(TROLL,0);
243         MOVE(TROLL+NOBJECTS,0);
244         DROP(TROLL2,PLAC[TROLL]);
245         DROP(TROLL2+NOBJECTS,FIXD[TROLL]);
246         JUGGLE(CHASM);
247         return(2011);
248     }
249     if (obj == FOOD && HERE(BEAR)) {
250     /* But throwing food is another story. */
251         obj=BEAR;
252         return(feed(obj));
253     }
254     if (obj != AXE)
255         return(discard(obj, false));
256     I=ATDWRF(game.loc);
257     if (I <= 0) {
258         if (AT(DRAGON) && game.prop[DRAGON] == 0) {
259             SPK=152;
260             return throw_support(SPK);
261         }
262         if (AT(TROLL)) {
263             SPK=158;
264             return throw_support(SPK);
265         }
266         if (AT(OGRE)) {
267             SPK=203;
268             return throw_support(SPK);
269         }
270         if (HERE(BEAR) && game.prop[BEAR] == 0) {
271             /* This'll teach him to throw the axe at the bear! */
272             SPK=164;
273             DROP(AXE,game.loc);
274             game.fixed[AXE]= -1;
275             game.prop[AXE]=1;
276             JUGGLE(BEAR);
277             return(2011);
278         }
279         return(attack(cmdin, 0, verb));
280     }
281
282     if (randrange(NDWARVES+1) < game.dflag) {
283         SPK=48;
284         return throw_support(SPK);
285     }
286     game.dseen[I]=false;
287     game.dloc[I]=0;
288     SPK=47;
289     game.dkill=game.dkill+1;
290     if (game.dkill == 1)SPK=149;
291
292     return throw_support(SPK);
293 }
294
295 int feed(long obj)
296 /*  Feed.  If bird, no seed.  Snake, dragon, troll: quip.  If dwarf, make him
297  *  mad.  Bear, special. */
298 {
299     if (obj == BIRD) {
300         SPK=100;
301         return(2011);
302     }
303
304     if (!(obj != SNAKE && obj != DRAGON && obj != TROLL)) {
305         SPK=102;
306         if (obj == DRAGON && game.prop[DRAGON] != 0)SPK=110;
307         if (obj == TROLL)SPK=182;
308         if (obj != SNAKE || game.closed || !HERE(BIRD))
309             return(2011);
310         SPK=101;
311         DSTROY(BIRD);
312         game.prop[BIRD]=0;
313         return(2011);
314     }
315
316     if (obj == DWARF) {
317         if (!HERE(FOOD))
318             return(2011);
319         SPK=103;
320         game.dflag=game.dflag+2;
321         return(2011);
322     }
323
324     if (obj == BEAR) {
325         if (game.prop[BEAR] == 0)SPK=102;
326         if (game.prop[BEAR] == 3)SPK=110;
327         if (!HERE(FOOD))
328             return(2011);
329         DSTROY(FOOD);
330         game.prop[BEAR]=1;
331         game.fixed[AXE]=0;
332         game.prop[AXE]=0;
333         SPK=168;
334         return(2011);
335     }
336
337     if (obj == OGRE) {
338         if (HERE(FOOD))
339             SPK=202;
340         return(2011);
341     }
342
343     SPK=14;
344     return(2011);
345 }
346
347 int fill(long obj)
348 /*  Fill.  Bottle or urn must be empty, and liquid available.  (Vase
349  *  is nasty.) */
350 {
351     int k;
352     if (obj == VASE) {
353         SPK=29;
354         if (LIQLOC(game.loc) == 0)SPK=144;
355         if (LIQLOC(game.loc) == 0 || !TOTING(VASE))
356             return(2011);
357         RSPEAK(145);
358         game.prop[VASE]=2;
359         game.fixed[VASE]= -1;
360         return(discard(obj, true));
361     }
362
363     if (obj == URN){
364         SPK=213;
365         if (game.prop[URN] != 0) return(2011);
366         SPK=144;
367         k=LIQ(0);
368         if (k == 0 || !HERE(BOTTLE)) return(2011);
369         game.place[k]=0;
370         game.prop[BOTTLE]=1;
371         if (k == OIL)game.prop[URN]=1;
372         SPK=211+game.prop[URN];
373         return(2011);
374     }
375
376     if (obj != 0 && obj != BOTTLE)
377         return(2011);
378     if (obj == 0 && !HERE(BOTTLE))
379         return(8000);
380     SPK=107;
381     if (LIQLOC(game.loc) == 0)
382         SPK=106;
383     if (HERE(URN) && game.prop[URN] != 0)
384         SPK=214;
385     if (LIQ(0) != 0)
386         SPK=105;
387     if (SPK != 107)
388         return(2011);
389     game.prop[BOTTLE]=MOD(COND[game.loc],4)/2*2;
390     k=LIQ(0);
391     if (TOTING(BOTTLE))
392         game.place[k]= -1;
393     if (k == OIL)
394         SPK=108;
395     return(2011);
396 }