1 /*
2     XorGramana Copyright 2009 James W. Morris, james@jwm-art.net
3 
4     This file is part of XorGramana.
5 
6     XorGramana is free software: you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation, either version 3 of the License, or
9     (at your option) any later version.
10 
11     XorGramana is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with XorGramana.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include "actions.h"
21 #include "map.h"
22 #include "gfx.h"
23 #include "options.h"
24 
25 #include <stdlib.h>
26 
27 struct xor_action actions[ICON_XXX]=
28 {
29   {/* FLOOR */      MVI_NONE,       CT_PASS,            MV_NONE,    MV_NONE     },
30   {/* WALL */       MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
31   {/* H_FIELD */    MVI_NONE,       CT_FILTER,          MV_NONE,    MV_HORIZ    },
32   {/* V_FIELD */    MVI_NONE,       CT_FILTER,          MV_NONE,    MV_VERT     },
33   {/* PLAYER0 */    MVI_PLAYER,     CT_BLOCK,           MV_ANY,     MV_NONE     },
34   {/* PLAYER1 */    MVI_PLAYER,     CT_BLOCK,           MV_ANY,     MV_NONE     },
35   {/* MAP */        MVI_NONE,       CT_PICKUP,          MV_NONE,    MV_NONE     },
36   {/* TELEPORT*/    MVI_NONE,       CT_TELEPORT,        MV_NONE,    MV_NONE     },
37   {/* EXIT_CLOSED */MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
38   {/* MASK */       MVI_NONE,       CT_PICKUP,          MV_NONE,    MV_NONE     },
39   {/* DOT */        MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
40   {/* BLANK */      MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
41   /* the following will have behavioural indicators overlaid upon them          */
42   {/* A (!fish)*/   MVI_GRAVITY,    CT_PUSH,            MV_UP,      MV_HORIZ    },
43   {/* B (flip-dpq)*/MVI_NONE,       CT_PUSH|CT_FLIP,    MV_NONE,    MV_ANY      },
44   {/* C (STATIC)*/  MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
45   {/* D (flip-bpq)*/MVI_NONE,       CT_PUSH|CT_FLIP,    MV_NONE,    MV_ANY      },
46   {/* E (v-doll)*/  MVI_NONE,       CT_HARDPUSH,        MV_NONE,    MV_VERT     },
47   {/* F (h-doll)*/  MVI_NONE,       CT_HARDPUSH,        MV_NONE,    MV_HORIZ    },
48   {/* G (doll)*/    MVI_NONE,       CT_HARDPUSH,        MV_NONE,    MV_ANY      },
49   {/* H (h-bomb)*/  MVI_GRAVITY,    CT_PUSH|CT_EXPLODE, MV_DOWN,    MV_HORIZ    },
50   {/* I (STATIC)*/  MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
51   {/* J (flip-j)*/  MVI_NONE,       CT_PUSH|CT_FLIP,    MV_NONE,    MV_HORIZ    },
52   {/* K (chick)*/   MVI_GRAVITY,    CT_PUSH,            MV_LEFT,    MV_VERT     },
53   {/* L (flip-j)*/  MVI_NONE,       CT_PUSH|CT_FLIP,    MV_NONE,    MV_VERT     },
54   {/* M (eeek)*/    MVI_GRAVITY,    CT_HARDPUSH,        MV_LEFT,    MV_VERT     },
55   {/* N (eeek)*/    MVI_GRAVITY,    CT_HARDPUSH,        MV_RIGHT,   MV_VERT     },
56   {/* O (!h-bomb)*/ MVI_GRAVITY,    CT_PUSH|CT_EXPLODE, MV_UP,      MV_HORIZ    },
57   {/* P (flip-bdq)*/MVI_NONE,       CT_PUSH|CT_FLIP,    MV_NONE,    MV_ANY      },
58   {/* Q (flip-bdp)*/MVI_NONE,       CT_PUSH|CT_FLIP,    MV_NONE,    MV_ANY      },
59   {/* R (eek)*/     MVI_GRAVITY,    CT_HARDPUSH,        MV_UP,      MV_HORIZ    },
60   {/* S (flip-z)*/  MVI_NONE,       CT_PUSH|CT_FLIP,    MV_NONE,    MV_HORIZ    },
61   {/* T (!v-bomb)*/ MVI_GRAVITY,    CT_PUSH|CT_EXPLODE, MV_RIGHT,   MV_VERT,    },
62   {/* U (eek)*/     MVI_GRAVITY,    CT_HARDPUSH,        MV_DOWN,    MV_HORIZ    },
63   {/* V (fish)*/    MVI_GRAVITY,    CT_PUSH,            MV_DOWN,    MV_HORIZ    },
64   {/* W (!chick)*/  MVI_GRAVITY,    CT_PUSH,            MV_RIGHT,   MV_VERT     },
65   {/* X (v-bomb)*/  MVI_GRAVITY,    CT_PUSH|CT_EXPLODE, MV_LEFT,    MV_VERT     },
66   {/* Y (switch)*/  MVI_NONE,       CT_PICKUP|CT_SWITCH,MV_NONE,    MV_NONE     },
67   {/* Z (flip-s)*/  MVI_NONE,       CT_PUSH|CT_FLIP,    MV_NONE,    MV_VERT     },
68   {/* 0 */          MVI_NONE, 0,0,0},
69   {/* 1 */          MVI_NONE, 0,0,0}, /* for these numerical icons no behaviour */
70   {/* 2 */          MVI_NONE, 0,0,0}, /* is yet defined - but will be sooner or */
71   {/* 3 */          MVI_NONE, 0,0,0}, /* later..                                */
72   {/* 4 */          MVI_NONE, 0,0,0},
73   {/* 5 */          MVI_NONE, 0,0,0},
74   {/* 6 */          MVI_NONE, 0,0,0},
75   {/* 7 */          MVI_NONE, 0,0,0},
76   {/* 8 */          MVI_NONE, 0,0,0},
77   {/* 9 */          MVI_NONE, 0,0,0},
78   /* the open exit cannot be specified in map file */
79   {/* OPEN_EXIT */  MVI_NONE,       CT_EXIT,            MV_NONE,    MV_NONE     },
80   /* the following are not ever appearing in map so have no defined behaviour   */
81   {/*space trans*/  0,0,0,0},
82   {/*space opaque*/ 0,0,0,0},
83   {/*explosion1*/   0,0,0,0},
84   {/*explosion2*/   0,0,0,0},
85   {/*explosion3*/   0,0,0,0},
86   {/*explosion4*/   0,0,0,0},
87   {/*explosion5*/   0,0,0,0},
88   {/*line_l*/       0,0,0,0},
89   {/*line_r*/       0,0,0,0},
90   {/*line_t*/       0,0,0,0},
91   {/*line_b*/       0,0,0,0},
92   {/*line_tl*/      0,0,0,0},
93   {/*line_tr*/      0,0,0,0},
94   {/*line_bl*/      0,0,0,0},
95   {/*line_br*/      0,0,0,0},
96   {/*loaded_xxx (MARKER) */ 0,0,0,0},
97   /* the following are generated wall icons with edging, (set to behave as wall)*/
98   {/*edge_t*/       MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
99   {/*edge_b*/       MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
100   {/*edge_l*/       MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
101   {/*edge_r*/       MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
102   {/*edge_tb*/      MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
103   {/*edge_lr*/      MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
104   {/*edge_tl*/      MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
105   {/*edge_tr*/      MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
106   {/*edge_bl*/      MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
107   {/*edge_br*/      MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
108   {/*edge_tbl*/     MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
109   {/*edge_tbr*/     MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
110   {/*edge_tlr*/     MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
111   {/*edge_blr*/     MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     },
112   {/*edge_tblr*/    MVI_NONE,       CT_BLOCK,           MV_NONE,    MV_NONE     }
113 };
114 
115 
icons_init_overlays()116 void icons_init_overlays()
117 {
118     int i;
119     int o;
120     for(i=ICON_A;i<=ICON_9;i++){
121         #ifdef ICON_DEBUG
122         printf("generating icon overlay for %d(%s)\n",i,icon_details[i].fname);
123         #endif
124         if(actions[i].mvini==MVI_GRAVITY){
125             icons_with_indicators[i]=icon_duplicate(icons[i],TRUE,0,0,0);
126             switch(actions[i].mvi_dir){
127                 case MV_LEFT:   o=DIRIND_GRAV_L;    break;
128                 case MV_RIGHT:  o=DIRIND_GRAV_R;    break;
129                 case MV_UP:     o=DIRIND_GRAV_U;    break;
130                 case MV_DOWN:   o=DIRIND_GRAV_D;    break;
131             }
132             overlay_image(icons_with_indicators[i],indicators[o],0,0);
133         }
134         if(actions[i].cont&CT_PUSH){
135             if(!icons_with_indicators[i])
136                 icons_with_indicators[i]=icon_duplicate(icons[i],TRUE,0,0,0);
137             if(actions[i].cont_dir&MV_LEFT)
138                 overlay_image(icons_with_indicators[i],indicators[DIRIND_PUSH_L],0,0);
139             if(actions[i].cont_dir&MV_RIGHT)
140                 overlay_image(icons_with_indicators[i],indicators[DIRIND_PUSH_R],0,0);
141             if(actions[i].cont_dir&MV_UP)
142                 overlay_image(icons_with_indicators[i],indicators[DIRIND_PUSH_U],0,0);
143             if(actions[i].cont_dir&MV_DOWN)
144                 overlay_image(icons_with_indicators[i],indicators[DIRIND_PUSH_D],0,0);
145         }
146         if(actions[i].cont&CT_HARDPUSH){
147             if(!icons_with_indicators[i])
148                 icons_with_indicators[i]=icon_duplicate(icons[i],TRUE,0,0,0);
149             if(actions[i].cont_dir&MV_LEFT)
150                 overlay_image(icons_with_indicators[i],indicators[DIRIND_HARDPUSH_L],0,0);
151             if(actions[i].cont_dir&MV_RIGHT)
152                 overlay_image(icons_with_indicators[i],indicators[DIRIND_HARDPUSH_R],0,0);
153             if(actions[i].cont_dir&MV_UP)
154                 overlay_image(icons_with_indicators[i],indicators[DIRIND_HARDPUSH_U],0,0);
155             if(actions[i].cont_dir&MV_DOWN)
156                 overlay_image(icons_with_indicators[i],indicators[DIRIND_HARDPUSH_D],0,0);
157         }
158         if(actions[i].cont&CT_EXPLODE){
159             if(!icons_with_indicators[i])
160                 icons_with_indicators[i]=icon_duplicate(icons[i],TRUE,0,0,0);
161             if(actions[i].cont_dir&MV_HORIZ)
162                 overlay_image(icons_with_indicators[i],indicators[DIRIND_EXPLODE_H],0,0);
163             if(actions[i].cont_dir&MV_VERT)
164                 overlay_image(icons_with_indicators[i],indicators[DIRIND_EXPLODE_V],0,0);
165         }
166     }
167 }
168 
create_xor_move(xy_t x,xy_t y,su_t move)169 struct xor_move* create_xor_move(xy_t x, xy_t y, su_t move)
170 {
171     struct xor_move* xmv;
172     if(!(xmv=malloc(sizeof(struct xor_move))))
173         return 0;
174     xmv->from_obj=map->data[y][x];
175     xmv->from_x=x;
176     xmv->from_y=y;
177     xmv->dir=move;
178     xmv->to_x=xmv->to_y=0;
179     xmv->up=xmv->down=xmv->right=xmv->left=0;
180     xmv->moves_count=0;
181     return xmv;
182 }
183 
184 /*
185     the following two functions are a bit cyclical in their
186     operation so think twice if you spot something seeming
187     at first glance nonsensical. (ie james morris, you/me,
188     we know we have a habbit of scanning our code and
189     thinking wtf!?!? and then editing without realising...
190     and we hate these comments which now seem obvious and
191     so untidy...
192 */
193 #include "player.h"
194 
create_gravity_chain_xydir(xy_t x,xy_t y,su_t dir)195 struct xor_move* create_gravity_chain_xydir(xy_t x, xy_t y, su_t dir)
196 {
197     struct xor_move* head=0;
198     struct xor_move* xmv=0;
199     struct xor_move* tmp=0;
200     int icon;
201     do{
202         icon=map->data[y][x];
203         if(actions[icon].mvini!=MVI_GRAVITY)
204             return head;
205         if(actions[icon].mvi_dir!=dir)
206             return head;
207         if(!(xmv=malloc(sizeof(struct xor_move))))
208             return head;
209         if(!head)
210             head=xmv;
211         if(tmp){
212             switch(dir){
213                 case MV_UP:     tmp->down=xmv;  break;
214                 case MV_DOWN:   tmp->up=xmv;    break;
215                 case MV_LEFT:   tmp->right=xmv; break;
216                 case MV_RIGHT:  tmp->left=xmv;  break;
217             }
218         }
219         xmv->from_obj=icon;
220         xmv->from_x=x;
221         xmv->from_y=y;
222         xmv->dir=dir;
223         xmv->to_x=xmv->to_y=0;
224         xmv->up=xmv->down=xmv->right=xmv->left=0;
225         xmv->moves_count=0;
226         tmp=xmv;
227         switch(dir){
228             case MV_UP:     y++;    break;
229             case MV_DOWN:   y--;    break;
230             case MV_LEFT:   x++;    break;
231             case MV_RIGHT:  x--;    break;
232         }
233     }while(TRUE);
234     return head;
235 }
236 
create_gravity_chain(struct xor_move * xmv)237 struct xor_move* create_gravity_chain(struct xor_move* xmv)
238 {
239     struct xor_move* head=0;
240     struct xor_move* tmp=0;
241     struct xor_move* oxmv=xmv;
242     su_t icon;
243     xy_t x, y;
244     su_t dir;
245     x=xmv->from_x;
246     y=xmv->from_y;
247     dir=xmv->dir;
248     do{
249         icon=map->data[y][x];
250         if(actions[icon].mvini!=MVI_GRAVITY){
251             if(xmv!=oxmv)
252                 free(xmv);
253             return head;
254         }
255         if(actions[icon].mvi_dir!=dir){
256             if(xmv!=oxmv)
257                 free(xmv);
258             return head;
259         }
260         if(!head)
261             head=xmv;
262         if(tmp){
263             switch(dir){
264                 case MV_UP:     tmp->down=xmv;  break;
265                 case MV_DOWN:   tmp->up=xmv;    break;
266                 case MV_LEFT:   tmp->right=xmv; break;
267                 case MV_RIGHT:  tmp->left=xmv;  break;
268             }
269         }
270         xmv->from_obj=icon; /* these are redundant */
271         xmv->from_x=x;      /* on the first pass   */
272         xmv->from_y=y;      /* oh well...          */
273         xmv->dir=dir;
274         xmv->to_x=xmv->to_y=0;
275         xmv->up=xmv->down=xmv->right=xmv->left=0;
276         xmv->moves_count=0;
277         tmp=xmv;
278         switch(dir){
279             case MV_UP:     y++;    break;
280             case MV_DOWN:   y--;    break;
281             case MV_LEFT:   x++;    break;
282             case MV_RIGHT:  x--;    break;
283         }
284         if(!(xmv=malloc(sizeof(struct xor_move))))
285             return head;
286     }while(TRUE);
287     return head;
288 }
289 
destroy_gravity_chain(struct xor_move * xmv)290 void destroy_gravity_chain(struct xor_move* xmv)
291 {
292     struct xor_move* tmp;
293     while(xmv){
294         tmp=xmv;
295         switch(xmv->dir){
296             case MV_UP:     xmv=xmv->down;  break;
297             case MV_DOWN:   xmv=xmv->up;    break;
298             case MV_LEFT:   xmv=xmv->right; break;
299             case MV_RIGHT:  xmv=xmv->left;  break;
300         }
301         free(tmp);
302     }
303 }
304 
bomb_type(su_t icon)305 su_t bomb_type(su_t icon)
306 {
307     if(actions[icon].cont&CT_EXPLODE)
308         return actions[icon].cont_dir;
309     return MV_NONE;
310 }
311