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 #include "moves.h"
20 #include "game_display.h"
21 #include "explode.h"
22 #include "options.h"
23 #include "map.h"
24 
25 #include <stdlib.h>
26 
init_unsupported()27 void init_unsupported()
28 {
29     xy_t x,y;
30     xy_t nx,ny;
31     su_t i,ni;
32     su_t dir;
33     struct xor_move* xmv;
34     #ifdef MOVE_DEBUG
35     printf("init_unsupported()/*check for unsupported gravitating objects*/\n");
36     #endif
37     xmvlist_create();
38     for(y=1;y<map->height;y++){
39         for(x=1;x<map->width;x++){
40             i=map->data[y][x];
41             if(actions[i].mvini==MVI_GRAVITY){
42                 nx=0;ny=0;
43                 switch((dir=actions[i].mvi_dir)){
44                     case MV_UP:
45                         nx=x;ny=y-1;
46                         break;
47                     case MV_DOWN:
48                         nx=x;ny=y+1;
49                         break;
50                     case MV_LEFT:
51                         nx=x-1;ny=y;
52                         break;
53                     case MV_RIGHT:
54                         nx=x+1;ny=y;
55                         break;
56                     default:
57                         break;
58                 }
59                 if(nx>0&&ny>0&&nx<map->width&&ny<map->height){
60                     ni=map->data[ny][nx];
61                     xmv=create_xor_move(x,y,dir);
62                     if(move_object_init(xmv)==CT_PASS){
63                         if((create_gravity_chain(xmv))){
64                             xmvlist_append_xor_move(xmv);
65                             #ifdef MAP_DEBUG
66                             printf("reporting:Unsupported object in map x:%d y:%d char:%c\n",
67                                 x,y,icon_details[xmv->from_obj].mapchar);
68                             #endif
69                         }
70                         else
71                             free(xmv);
72                     }
73                     else free(xmv);
74                 }
75             }
76         }
77     }
78     if(xmvlist_first()){
79         if(!player.replay){
80             gfx_message("Get Ready");
81             game_win_display();
82         }
83         move_gravity_process();
84     }
85     xmvlist_destroy();
86 }
87 
move_object_init(struct xor_move * move)88 ct_t move_object_init(struct xor_move* move)
89 {
90     ct_t cont;
91     move->to_x=move->from_x;
92     move->to_y=move->from_y;
93     #ifdef MOVE_DEBUG
94     printf("move_object_init(xor_move* %lx)\n",(unsigned long)move);
95     #endif
96     switch(move->dir){
97         case MV_LEFT:   move->to_x--;   break;
98         case MV_RIGHT:  move->to_x++;   break;
99         case MV_UP:     move->to_y--;   break;
100         case MV_DOWN:   move->to_y++;   break;
101         default:
102             fprintf(stderr,
103                 "Invalid movement direction error! move:%d\n",move->dir);
104             return CT_BLOCK;
105     }
106     move->from_obj=map->data[move->from_y][move->from_x];
107     move->to_obj=map->data[move->to_y][move->to_x];
108     cont=actions[move->to_obj].cont;
109     /* ------------------------------------------ */
110     /* conditions apply both to player and object */
111     if(cont==CT_BLOCK||cont==CT_PASS)
112         return cont;
113     if(actions[move->from_obj].cont&CT_HARDPUSH){
114         if(move->dir&actions[move->from_obj].cont_dir){
115             /*fprintf(stderr,"hardpush causing blockage..\n");*/
116             return CT_BLOCK;
117         }
118     }
119     if(cont==CT_FILTER){
120         if(actions[move->to_obj].cont_dir&move->dir)
121             return CT_PASS;
122         return CT_BLOCK;
123     }
124     /* -------------------------------- */
125     /* conditions which apply to player */
126     if(actions[move->from_obj].mvini&MVI_PLAYER){
127         if(cont&CT_PUSH){
128             if(actions[move->to_obj].cont_dir&move->dir)
129                 return CT_PUSH;
130             else
131                 return CT_BLOCK;
132         }
133         if(cont&CT_PICKUP||cont&CT_TELEPORT||cont&CT_EXIT)
134             return cont;
135         if(cont&CT_HARDPUSH){
136             if(actions[move->to_obj].cont_dir&move->dir)
137                 return CT_HARDPUSH;
138             else
139                 return CT_BLOCK;
140         }
141         if(cont&CT_PUSH){
142             if(actions[move->to_obj].cont_dir&move->dir)
143                 return CT_PUSH;
144             else
145                 return CT_BLOCK;
146         }
147         return CT_ERROR;
148     }
149     /* -------------------------------- */
150     /* conditions which apply to object */
151     if(cont&CT_EXPLODE)
152         return CT_EXPLODE;
153     if(cont&CT_FLIP)
154         return CT_FLIP;
155     return CT_BLOCK;
156 }
157 
move_gravity_process()158 void move_gravity_process()
159 {
160     struct xor_move* xmv=0;
161     struct xor_move* tmp=0;
162     struct xor_move* cmv=0;
163     struct xor_move* cmv_next=0;
164     struct xmv_link* tmplnk=0;
165     ct_t cont;
166     xy_t tmpx,tmpy;
167     unsigned int flimit=SDL_GetTicks()+TICK_COUNT;
168     #ifdef MOVE_DEBUG
169     printf("\nmove_gravity_process()\n");
170     #endif
171     /*
172     rpause.tv_sec=0;
173     if(player.replay)
174         rpause.tv_nsec=options_replay_speed(options->replay_speed);
175     else
176         rpause.tv_nsec=20000000L;
177     */
178     xmvlist_first();
179     while(xmvlist->current){
180         xmv=xmvlist->current->xmv;
181         cmv=xmv;
182         #ifdef MOVE_DEBUG
183         printf("xmvlist->current=%lx->xmv=%lx\n",
184             (unsigned long)xmvlist->current,(unsigned long)xmv);
185         #endif
186         while(cmv){
187             delay(flimit);
188             flimit=SDL_GetTicks()+TICK_COUNT;
189             #ifdef MOVE_DEBUG
190             printf("mv_grv_proc:\n\t*(%lx)cmv->from_x:%d,from_y:%d,from_obj:%s\n",
191                 (unsigned long)cmv,cmv->from_x,cmv->from_y,
192                 icon_details[cmv->from_obj].fname);
193             #endif
194             switch(cmv->dir){
195                 case MV_UP:     cmv_next=cmv->down; break;
196                 case MV_DOWN:   cmv_next=cmv->up;   break;
197                 case MV_LEFT:   cmv_next=cmv->right;break;
198                 case MV_RIGHT:  cmv_next=cmv->left; break;
199                 default:
200                     break;
201             }
202             cont=move_object_init(cmv);
203             if(actions[cmv->to_obj].mvini==MVI_PLAYER){
204                 if(cmv->moves_count>0){
205                     player_death(cmv->to_obj);
206                     cont=CT_PASS;
207                 }
208             }
209             if(cont&CT_FLIP){
210                 if(cmv->moves_count>0){
211                     #ifdef MOVE_DEBUG
212                     printf("grav proc flipping..\n");
213                     #endif
214                     game_win_icon_display(
215                         cmv->to_x,cmv->to_y,
216                         (   map->data[cmv->to_y][cmv->to_x]=
217                             flip(cmv->to_obj,cmv->dir)  )      );
218                     cont=CT_BLOCK;
219                 }
220             }
221             if(cont&CT_EXPLODE){
222                 #ifdef MOVE_DEBUG
223                 printf("\nBANG!!!\n");
224                 #endif
225                 explode_process_detonator(xmvlist->current);
226                 cmv=cmv_next;
227                 #ifdef MOVE_DEBUG
228                 printf("\nreturn to move_gravity_process(xor_move* xmv=%lx)\n",(unsigned long) xmv);
229                 printf("\tcmv=cmv_next=%lx\n",(unsigned long)cmv);
230                 if(cmv)
231                     printf("\t*(%lx)cmv->from_x:%d,from_y:%d,from_obj:%s\n",
232                         (unsigned long)cmv,cmv->from_x,cmv->from_y,
233                             icon_details[cmv->from_obj].fname);
234                 #endif
235             }
236             else if(cont==CT_PASS)
237             {
238                 map->data[cmv->from_y][cmv->from_x]=ICON_FLOOR;
239                 map->data[cmv->to_y][cmv->to_x]=cmv->from_obj;
240                 game_win_move_object(cmv);
241                 tmpx=cmv->from_x;
242                 tmpy=cmv->from_y;
243                 cmv->from_x=cmv->to_x;
244                 cmv->from_y=cmv->to_y;
245                 cmv->moves_count++;
246                 if(cmv_next){
247                     cmv=cmv_next;
248                     /*rpause.tv_nsec/=1.1;*/
249                 }
250                 else{
251                     if(cmv->dir&MV_HORIZ){
252                         if((cmv=create_gravity_chain_xydir(tmpx,tmpy-1,MV_DOWN)))
253                             xmvlist_append_xor_move(cmv);
254                         if((tmp=create_gravity_chain_xydir(tmpx,tmpy+1,MV_UP))){
255                             xmvlist_append_xor_move(tmp);
256                             if(!cmv)
257                                 cmv=tmp;
258                         }
259                     }
260                     else{
261                         if((cmv=create_gravity_chain_xydir(tmpx+1,tmpy,MV_LEFT)))
262                             xmvlist_append_xor_move(cmv);
263                         if((tmp=create_gravity_chain_xydir(tmpx-1,tmpy,MV_RIGHT))){
264                             xmvlist_append_xor_move(tmp);
265                             if(!cmv)
266                                 cmv=tmp;
267                         }
268                     }
269                     /*
270                     if(cmv){
271                         rpause.tv_nsec/=1.1;
272                     }
273                     */
274                     xmvlist_cycle_next();
275                     cmv=xmv=xmvlist->current->xmv;
276                 }
277             }
278             else if ((cmv=move_unchain_blocked_bomb(xmvlist->current)))
279                 xmv=cmv;
280             else { /* chain blocked - remove it */
281                 #ifdef MOVE_DEBUG
282                 printf("mv_grav_proc() chain blocked removing...\n");
283                 #endif
284                 tmplnk=xmvlist->current;
285                 #ifdef MOVE_DEBUG
286                 if(tmplnk->xmv!=xmv)
287                     printf("\n***** current->xmv != xmv *******\n");
288                 #endif
289                 destroy_gravity_chain(xmv);
290                 if(xmvlist_cycle_next()==tmplnk)
291                     cmv=xmv=0; /* about to remove last chain */
292                 else
293                     cmv=xmv=xmvlist->current->xmv;
294                 xmvlist_unlink_xor_move(tmplnk);
295             }
296         }
297     }
298     #ifdef MOVE_DEBUG
299     printf("\nEXITING move_gravity_process(xor_move* xmv=%lx)\n",(unsigned long) xmv);
300     #endif
301 }
302 
move_unchain_blocked_bomb(struct xmv_link * lnk)303 struct xor_move* move_unchain_blocked_bomb(struct xmv_link* lnk)
304 {
305     struct xor_move* xmv=lnk->xmv;
306     struct xor_move* tmp;
307     if(xmv->moves_count==0)
308         return 0;
309     #ifdef MOVE_DEBUG
310     printf("move_unchain_blocked_bomb(xmv_link* lnk=%lx)\n",
311         (unsigned long)lnk);
312     printf("moves count:%d\n",xmv->moves_count);
313     #endif
314     switch(xmv->dir){
315         case MV_DOWN:
316             while(xmv){
317                 if(bomb_type(xmv->from_obj)==MV_HORIZ){
318                     if((tmp=xmv->up)){
319                         xmv->up=0;
320                         destroy_gravity_chain(lnk->xmv);
321                         return (lnk->xmv=tmp);
322                     }
323                     return 0;
324                 }
325                 else{
326                     tmp=xmv;
327                     xmv=xmv->up;
328                 }
329             }
330             return 0;
331         case MV_LEFT:
332             while(xmv){
333                 if(bomb_type(xmv->from_obj)==MV_VERT){
334                     if((tmp=xmv->right)){
335                         xmv->right=0;
336                         destroy_gravity_chain(lnk->xmv);
337                         return (lnk->xmv=tmp);
338                     }
339                     return 0;
340                 }
341                 else{
342                     tmp=xmv;
343                     xmv=xmv->right;
344                 }
345             }
346             return 0;
347         case MV_UP:
348             while(xmv){
349                 if(bomb_type(xmv->from_obj)==MV_HORIZ){
350                     if((tmp=xmv->down)){
351                         xmv->down=0;
352                         destroy_gravity_chain(lnk->xmv);
353                         return (lnk->xmv=tmp);
354                     }
355                     return 0;
356                 }
357                 else{
358                     tmp=xmv;
359                     xmv=xmv->down;
360                 }
361             }
362             return 0;
363         case MV_RIGHT:
364             while(xmv){
365                 if(bomb_type(xmv->from_obj)==MV_VERT){
366                     if((tmp=xmv->right)){
367                         xmv->left=0;
368                         destroy_gravity_chain(lnk->xmv);
369                         return (lnk->xmv=tmp);
370                     }
371                     return 0;
372                 }
373                 else{
374                     tmp=xmv;
375                     xmv=xmv->left;
376                 }
377             }
378             return 0;
379         default:
380             return 0;
381     }
382 }
383 
move_hard_push(struct xor_move * xmv)384 void move_hard_push(struct xor_move* xmv)
385 {
386     #ifdef MOVE_DEBUG
387     printf("move_hard_push (xor_move* %lx)\n",(unsigned long)xmv);
388     #endif
389     /*
390     rpause.tv_sec=0;
391     if(player.replay)
392         rpause.tv_nsec=options_replay_speed(options->replay_speed);
393     else
394         rpause.tv_nsec=20000000L;
395     */
396     #ifdef MOVE_DEBUG
397     if(!(actions[xmv->from_obj].cont_dir&xmv->dir))
398         printf("***** hard push direction mismatch! *****\n");
399     #endif
400     unsigned int flimit=SDL_GetTicks()+TICK_COUNT;
401     do{
402         map->data[xmv->from_y][xmv->from_x]=ICON_FLOOR;
403         map->data[xmv->to_y][xmv->to_x]=xmv->from_obj;
404         game_win_move_object(xmv);
405         xmv->from_x=xmv->to_x;
406         xmv->from_y=xmv->to_y;
407         switch(xmv->dir){
408             case MV_LEFT:   xmv->to_x--;   break;
409             case MV_RIGHT:  xmv->to_x++;   break;
410             case MV_UP:     xmv->to_y--;   break;
411             case MV_DOWN:   xmv->to_y++;   break;
412             default:
413                 fprintf(stderr,
414                     "***** hardpush object move non-direction *****\n");
415                 return;
416         }
417         delay(flimit);
418         flimit=SDL_GetTicks()+TICK_COUNT;
419         /*nanosleep(&rpause,&repause);*/
420     }
421     while(map->data[xmv->to_y][xmv->to_x]==ICON_FLOOR);
422 
423 /*
424     while(map->data[xmv->to_y][xmv->to_x]==ICON_FLOOR){
425         map->data[xmv->from_y][xmv->from_x]=ICON_FLOOR;
426         map->data[xmv->to_y][xmv->to_x]=xmv->from_obj;
427         game_win_move_object(xmv);
428         xmv->from_x=xmv->to_x;
429         xmv->from_y=xmv->to_y;
430         switch(xmv->dir){
431             case MV_LEFT:   xmv->to_x--;   break;
432             case MV_RIGHT:  xmv->to_x++;   break;
433             case MV_UP:     xmv->to_y--;   break;
434             case MV_DOWN:   xmv->to_y++;   break;
435             default:
436                 fprintf(stderr,
437                     "***** hardpush object move non-direction *****\n");
438                 return;
439         }
440         delay(flimit);
441         flimit=SDL_GetTicks()+TICK_COUNT;
442         */
443         /*nanosleep(&rpause,&repause);*/
444         /*
445     }
446 */
447 }
448 
flip(su_t obj,su_t dir)449 su_t flip(su_t obj, su_t dir)
450 {
451     switch(obj){
452         case ICON_B: return (dir&MV_VERT?ICON_P:ICON_D);
453         case ICON_D: return (dir&MV_VERT?ICON_Q:ICON_B);
454         case ICON_P: return (dir&MV_VERT?ICON_B:ICON_Q);
455         case ICON_Q: return (dir&MV_VERT?ICON_D:ICON_P);
456         case ICON_S: return ICON_Z;
457         case ICON_Z: return ICON_S;
458         case ICON_L: return ICON_J;
459         case ICON_J: return ICON_L;
460         default:
461             fprintf(stderr,"tried to flip non-flippable\n");
462             return obj;
463     }
464 }
465