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