De-gotoified actions2.c functions.
[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         I=ATDWRF(game.loc);
139         if (obj == 0) {
140             if (I > 0)obj=DWARF;
141             if (HERE(SNAKE))obj=obj*NOBJECTS+SNAKE;
142             if (AT(DRAGON) && game.prop[DRAGON] == 0)obj=obj*NOBJECTS+DRAGON;
143             if (AT(TROLL))obj=obj*NOBJECTS+TROLL;
144             if (AT(OGRE))obj=obj*NOBJECTS+OGRE;
145             if (HERE(BEAR) && game.prop[BEAR] == 0)obj=obj*NOBJECTS+BEAR;
146             if (obj > NOBJECTS) return(8000);
147             if (obj == 0) {
148                 /* Can't attack bird or machine by throwing axe. */
149                 if (HERE(BIRD) && verb != THROW)obj=BIRD;
150                 if (HERE(VEND) && verb != THROW)obj=obj*NOBJECTS+VEND;
151                 /* Clam and oyster both treated as clam for intransitive case;
152                  * no harm done. */
153                 if (HERE(CLAM) || HERE(OYSTER))obj=NOBJECTS*obj+CLAM;
154                 if (obj > NOBJECTS) return(8000);
155             }
156         }
157         if (obj == BIRD) {
158                 SPK=137;
159                 if (game.closed) return(2011);
160                 DSTROY(BIRD);
161                 game.prop[BIRD]=0;
162                 SPK=45;
163         }
164         if (obj == VEND) {
165             PSPEAK(VEND,game.prop[VEND]+2);
166             game.prop[VEND]=3-game.prop[VEND];
167             return(2012);
168         }
169
170         if (obj == 0)SPK=44;
171         if (obj == CLAM || obj == OYSTER)SPK=150;
172         if (obj == SNAKE)SPK=46;
173         if (obj == DWARF)SPK=49;
174         if (obj == DWARF && game.closed) return(19000);
175         if (obj == DRAGON)SPK=167;
176         if (obj == TROLL)SPK=157;
177         if (obj == OGRE)SPK=203;
178         if (obj == OGRE && I > 0) goto L9128;
179         if (obj == BEAR)SPK=165+(game.prop[BEAR]+1)/2;
180         if (obj != DRAGON || game.prop[DRAGON] != 0) return(2011);
181         /*  Fun stuff for dragon.  If he insists on attacking it, win!
182          *  Set game.prop to dead, move dragon to central loc (still
183          *  fixed), move rug there (not fixed), and move him there,
184          *  too.  Then do a null motion to get new description. */
185         RSPEAK(49);
186         GETIN(input,WD1,WD1X,WD2,WD2X);
187         if (WD1 != MAKEWD(25) && WD1 != MAKEWD(250519)) return(2607);
188         PSPEAK(DRAGON,3);
189         game.prop[DRAGON]=1;
190         game.prop[RUG]=0;
191         K=(PLAC[DRAGON]+FIXD[DRAGON])/2;
192         MOVE(DRAGON+NOBJECTS,-1);
193         MOVE(RUG+NOBJECTS,0);
194         MOVE(DRAGON,K);
195         MOVE(RUG,K);
196         DROP(BLOOD,K);
197         for (obj=1; obj<=NOBJECTS; obj++) {
198         if (game.place[obj] == PLAC[DRAGON] || game.place[obj] == FIXD[DRAGON])MOVE(obj,K);
199         /*etc*/ ;
200         } /* end loop */
201         game.loc=K;
202         K=NUL;
203          return(8);
204
205 L9128:  RSPEAK(SPK);
206         RSPEAK(6);
207         DSTROY(OGRE);
208         K=0;
209         for (I=1; I < PIRATE; I++) {
210                 if (game.dloc[I] == game.loc) {
211                         K=K+1;
212                         game.dloc[I]=61;
213                         game.dseen[I]=false;
214                 }
215         }
216         SPK=SPK+1+1/K;
217         return(2011);
218 }
219
220 int throw_support(long spk)
221 {
222     RSPEAK(spk);
223     DROP(AXE,game.loc);
224     K=NUL;
225     return(8);
226 }
227
228 int throw(FILE *cmdin, long obj, long verb)
229 /*  Throw.  Same as discard unless axe.  Then same as attack except
230  *  ignore bird, and if dwarf is present then one might be killed.
231  *  (Only way to do so!)  Axe also special for dragon, bear, and
232  *  troll.  Treasures special for troll. */
233 {
234     if (TOTING(ROD2) && obj == ROD && !TOTING(ROD))obj=ROD2;
235     if (!TOTING(obj))
236         return(2011);
237     if (obj >= 50 && obj <= MAXTRS && AT(TROLL)) {
238         SPK=159;
239         /*  Snarf a treasure for the troll. */
240         DROP(obj,0);
241         MOVE(TROLL,0);
242         MOVE(TROLL+NOBJECTS,0);
243         DROP(TROLL2,PLAC[TROLL]);
244         DROP(TROLL2+NOBJECTS,FIXD[TROLL]);
245         JUGGLE(CHASM);
246         return(2011);
247     }
248     if (obj == FOOD && HERE(BEAR)) {
249     /* But throwing food is another story. */
250         obj=BEAR;
251         return(feed(obj));
252     }
253     if (obj != AXE)
254         return(discard(obj, false));
255     I=ATDWRF(game.loc);
256     if (I <= 0) {
257         if (AT(DRAGON) && game.prop[DRAGON] == 0) {
258             SPK=152;
259             return throw_support(SPK);
260         }
261         if (AT(TROLL)) {
262             SPK=158;
263             return throw_support(SPK);
264         }
265         if (AT(OGRE)) {
266             SPK=203;
267             return throw_support(SPK);
268         }
269         if (HERE(BEAR) && game.prop[BEAR] == 0) {
270             /* This'll teach him to throw the axe at the bear! */
271             SPK=164;
272             DROP(AXE,game.loc);
273             game.fixed[AXE]= -1;
274             game.prop[AXE]=1;
275             JUGGLE(BEAR);
276             return(2011);
277         }
278         return(attack(cmdin, 0, verb));
279     }
280
281     if (randrange(NDWARVES+1) < game.dflag) {
282         SPK=48;
283         return throw_support(SPK);
284     }
285     game.dseen[I]=false;
286     game.dloc[I]=0;
287     SPK=47;
288     game.dkill=game.dkill+1;
289     if (game.dkill == 1)SPK=149;
290
291     return throw_support(SPK);
292 }
293
294 int feed(long obj)
295 /*  Feed.  If bird, no seed.  Snake, dragon, troll: quip.  If dwarf, make him
296  *  mad.  Bear, special. */
297 {
298     if (obj == BIRD) {
299         SPK=100;
300         return(2011);
301     }
302
303     if (!(obj != SNAKE && obj != DRAGON && obj != TROLL)) {
304         SPK=102;
305         if (obj == DRAGON && game.prop[DRAGON] != 0)SPK=110;
306         if (obj == TROLL)SPK=182;
307         if (obj != SNAKE || game.closed || !HERE(BIRD))
308             return(2011);
309         SPK=101;
310         DSTROY(BIRD);
311         game.prop[BIRD]=0;
312         return(2011);
313     }
314
315     if (obj == DWARF) {
316         if (!HERE(FOOD))
317             return(2011);
318         SPK=103;
319         game.dflag=game.dflag+2;
320         return(2011);
321     }
322
323     if (obj == BEAR) {
324         if (game.prop[BEAR] == 0)SPK=102;
325         if (game.prop[BEAR] == 3)SPK=110;
326         if (!HERE(FOOD))
327             return(2011);
328         DSTROY(FOOD);
329         game.prop[BEAR]=1;
330         game.fixed[AXE]=0;
331         game.prop[AXE]=0;
332         SPK=168;
333         return(2011);
334     }
335
336     if (obj == OGRE) {
337         if (HERE(FOOD))
338             SPK=202;
339         return(2011);
340     }
341
342     SPK=14;
343     return(2011);
344 }
345
346 int fill(long obj)
347 /*  Fill.  Bottle or urn must be empty, and liquid available.  (Vase
348  *  is nasty.) */
349 {
350     int k;
351     if (obj == VASE) {
352         SPK=29;
353         if (LIQLOC(game.loc) == 0)SPK=144;
354         if (LIQLOC(game.loc) == 0 || !TOTING(VASE))
355             return(2011);
356         RSPEAK(145);
357         game.prop[VASE]=2;
358         game.fixed[VASE]= -1;
359         return(discard(obj, true));
360     }
361
362     if (obj == URN){
363         SPK=213;
364         if (game.prop[URN] != 0) return(2011);
365         SPK=144;
366         k=LIQ(0);
367         if (k == 0 || !HERE(BOTTLE)) return(2011);
368         game.place[k]=0;
369         game.prop[BOTTLE]=1;
370         if (k == OIL)game.prop[URN]=1;
371         SPK=211+game.prop[URN];
372         return(2011);
373     }
374
375     if (obj != 0 && obj != BOTTLE)
376         return(2011);
377     if (obj == 0 && !HERE(BOTTLE))
378         return(8000);
379     SPK=107;
380     if (LIQLOC(game.loc) == 0)
381         SPK=106;
382     if (HERE(URN) && game.prop[URN] != 0)
383         SPK=214;
384     if (LIQ(0) != 0)
385         SPK=105;
386     if (SPK != 107)
387         return(2011);
388     game.prop[BOTTLE]=MOD(COND[game.loc],4)/2*2;
389     k=LIQ(0);
390     if (TOTING(BOTTLE))
391         game.place[k]= -1;
392     if (k == OIL)
393         SPK=108;
394     return(2011);
395 }