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 "player.h"
20 #include "moves.h"
21 #include "game_display.h"
22 #include "actions.h"
23 #include "moves.h"
24 #include "movelist.h"
25 #include "teleport.h"
26 #include "play_xor.h"
27 #include "options.h"
28 
29 #include <stdlib.h>
30 
player_init()31 void player_init()
32 {
33     player.move_no=0;
34     player.masks_collected=0;
35     player.have_map=0;
36     player.p0_alive=1;
37     player.p1_alive=1;
38     player.player=0;
39     player.wall_vis=TRUE;
40 }
41 
player_move(su_t move)42 enum PLAY_STATE player_move(su_t move)
43 {
44     struct xor_move* pmv;
45     struct xor_move* omv;
46     ct_t cont;
47     if(player.move_no==map->max_moves)
48         return PLAY_ZERO_MOVES|PLAY_RECORD;
49     if(move==MV_PLAYER_QUIT)
50         return (player.move_no==map->max_moves)
51             ?PLAY_QUIT
52             :PLAY_QUIT|PLAY_RECORD;
53     if(move==MV_PLAYER_SWAP){
54         if((player.player?player.p0_alive:player.p1_alive)){
55             player.player^=1;
56             game_win_swap_update();
57             game_win_display();
58             return PLAY_CONTINUE|PLAY_RECORD;
59         }
60         return PLAY_CONTINUE;
61     }
62     pmv=create_xor_move(map->player[player.player].x,
63                         map->player[player.player].y, move);
64     cont=move_object_init(pmv);
65     switch(cont)
66     {
67         case CT_BLOCK:
68             free(pmv);
69             return PLAY_CONTINUE;
70         case CT_EXIT:
71             free(pmv);
72             return PLAY_COMPLETE|PLAY_RECORD;
73         case CT_TELEPORT:
74             if(player_teleport(pmv)){
75                 player_process_old_pos(pmv);
76                 free(pmv);
77                 return PLAY_CONTINUE|PLAY_RECORD;
78             }
79             free(pmv);
80             return PLAY_CONTINUE;
81             break;
82         default:
83             break;
84     }
85     if((omv=player_process_move(pmv))){
86         if(omv==pmv){
87             game_win_move_player(pmv);
88             if(cont&CT_PICKUP)
89                 player_process_collect(pmv);
90             player_process_old_pos(pmv);
91         }
92         else{
93             game_win_move_object(omv);
94             game_win_move_player(pmv);
95             pushed_process_new_pos(omv);
96             player_process_old_pos(pmv);
97         }
98         free(pmv);
99         return PLAY_PROCESS_MOVE|PLAY_RECORD;
100     }
101     free(pmv);
102     return PLAY_CONTINUE;
103 }
104 
player_process_move(struct xor_move * pmv)105 struct xor_move* player_process_move(struct xor_move* pmv)
106 {
107     struct xor_move* omv = pmv;
108     enum CONTACT cont, ncont;
109     cont=actions[pmv->to_obj].cont;
110     #ifdef MOVE_DEBUG
111     printf("player process move(xor_move* %lx)\n",(unsigned long)pmv);
112     printf("cont:%d\n",cont);
113     #endif
114     if(cont!=CT_PASS){
115         if (cont&CT_PUSH||cont&CT_HARDPUSH){
116             omv=create_xor_move(pmv->to_x,pmv->to_y,pmv->dir);
117             if((ncont=move_object_init(omv))!=CT_PASS){
118                 free(omv);
119                 return 0;
120             }
121             map->data[omv->from_y][omv->from_x]=ICON_FLOOR;
122             if(cont&CT_FLIP)
123                 omv->from_obj=flip(omv->from_obj,omv->dir);
124             map->data[omv->to_y][omv->to_x]=omv->from_obj;
125         }
126     }
127     map->player[player.player].x=pmv->to_x;
128     map->player[player.player].y=pmv->to_y;
129     map->data[pmv->to_y][pmv->to_x]=pmv->from_obj;
130     map->data[pmv->from_y][pmv->from_x]=ICON_FLOOR;
131     return omv;
132 }
133 
134 
player_process_old_pos(struct xor_move * pmv)135 enum PLAY_STATE player_process_old_pos(struct xor_move* pmv)
136 {
137     struct xor_move* gravmv;
138     xy_t x,y;
139     su_t gdir[3];
140     su_t check[3];
141     su_t n;
142     #ifdef MOVE_DEBUG
143     printf("\nplayer_process_old_pos(xor_move* pmv=%lx)\n",
144         (unsigned long)pmv);
145     #endif
146     if(pmv->dir&MV_HORIZ){
147         check[0]=gdir[1]=MV_UP;
148         check[1]=gdir[0]=MV_DOWN;
149         if(pmv->dir&MV_LEFT){
150             check[2]=MV_RIGHT;
151             gdir[2]=MV_LEFT;
152         }
153         else{
154             check[2]=MV_LEFT;
155             gdir[2]=MV_RIGHT;
156         }
157     }
158     else{
159         check[0]=gdir[1]=MV_RIGHT;
160         check[1]=gdir[0]=MV_LEFT;
161         if(pmv->dir&MV_DOWN){
162             check[2]=MV_UP;
163             gdir[2]=MV_DOWN;
164         }
165         else{
166             check[2]=MV_DOWN;
167             gdir[2]=MV_UP;
168         }
169     }
170     for(n=0;n<3;n++){
171         x=pmv->from_x;
172         y=pmv->from_y;
173         switch(check[n]){
174             case MV_LEFT:   x-=1;   break;
175             case MV_RIGHT:  x+=1;   break;
176             case MV_UP:     y-=1;   break;
177             case MV_DOWN:   y+=1;   break;
178             default:
179                 break;
180         }
181         if((gravmv=create_gravity_chain_xydir(x,y,gdir[n]))){
182             xmvlist_create();
183             xmvlist_append_xor_move(gravmv);
184             move_gravity_process();
185         }
186     }
187     return PLAY_PROCESS_MOVE;
188 }
189 
pushed_process_new_pos(struct xor_move * omv)190 enum PLAY_STATE pushed_process_new_pos(struct xor_move* omv)
191 {
192     omv->from_x=omv->to_x;
193     omv->from_y=omv->to_y;
194     if(actions[omv->from_obj].cont&CT_PUSH){
195         #ifdef MOVE_DEBUG
196         printf("pushed object & CT_PUSH\n");
197         #endif
198         /* although create_gravity_chain() detects the same two conditions  *
199          * below, having them here also, creates the correct behaviour...   *
200          * a bomb should only detonate if an object has gravitated onto it, *
201          * not if an object was pushed onto it.                             */
202         if(actions[omv->from_obj].mvini==MVI_GRAVITY){
203             omv->dir=actions[omv->from_obj].mvi_dir;
204             if(move_object_init(omv)==CT_PASS){
205                 if(create_gravity_chain(omv)){
206                     xmvlist_create();
207                     xmvlist_append_xor_move(omv);
208                     move_gravity_process();
209                     return PLAY_PROCESS_MOVE;
210                 }
211             }
212         }
213         free(omv);
214         return PLAY_PROCESS_MOVE;
215     }
216     if(actions[omv->from_obj].cont&CT_HARDPUSH){
217         #ifdef MOVE_DEBUG
218         printf("pushed object & CT_HARDPUSH\n");
219         #endif
220         move_hard_push(omv);
221         if(actions[omv->from_obj].mvini==MVI_GRAVITY){
222             omv->dir=actions[omv->from_obj].mvi_dir;
223             if(move_object_init(omv)==CT_PASS){
224                 if(create_gravity_chain(omv)){
225                     xmvlist_create();
226                     xmvlist_append_xor_move(omv);
227                     move_gravity_process();
228                     return PLAY_PROCESS_MOVE;
229                 }
230             }
231         }
232         free(omv);
233         return PLAY_PROCESS_MOVE;
234     }
235     #ifdef MOVE_DEBUG
236     printf("non gravitating or hard-pusha\n");
237     #endif
238     free(omv);
239     return PLAY_PROCESS_MOVE;
240 }
241 
242 /*
243     if(move_object_init(omv)==CT_PASS){
244         if(actions[omv->from_obj].cont==CT_HARDPUSH){
245             move_hard_push(omv);
246             omv->dir=actions[omv->from_obj].mvi_dir;
247             if(move_object_init(omv)!=CT_PASS){
248                 free(omv);
249                 return PLAY_PROCESS_MOVE;
250             }
251         }
252         if(create_gravity_chain(omv)){
253             xmvlist_create();
254             xmvlist_append_xor_move(omv);
255             move_gravity_process();
256         }
257         else
258             free(omv);
259     }
260     else if(actions[omv->from_obj].cont==CT_HARDPUSH
261           &&actions[omv->from_obj].mvini==MVI_GRAVITY)
262     {
263         omv->dir=actions[omv->from_obj].mvi_dir;
264         if(move_object_init(omv)!=CT_PASS){
265             free(omv);
266             return PLAY_PROCESS_MOVE;
267         }
268         if(create_gravity_chain(omv)){
269             xmvlist_create();
270             xmvlist_append_xor_move(omv);
271             move_gravity_process();
272         }
273         else
274             free(omv);
275     }
276     else
277         free(omv);
278     return PLAY_PROCESS_MOVE;
279 */
280 
281 
player_process_collect(struct xor_move * pmv)282 void player_process_collect(struct xor_move* pmv)
283 {
284     #ifdef MOVE_DEBUG
285     printf("player process collect(xor_move* %lx)\n",(unsigned long)pmv);
286     #endif
287     switch(pmv->to_obj){
288         case ICON_MASK:
289             player.masks_collected++;
290             if(!options->game)
291                 inc_max_moves();
292             break;
293         case ICON_MAP:
294             player_process_map_pc(pmv);
295             break;
296         default:
297             if(actions[pmv->to_obj].cont&CT_SWITCH){
298                 player.wall_vis=(player.wall_vis?FALSE:TRUE);
299                 init_wall(map->level,player.wall_vis);
300                 game_win_display();
301             }
302     }
303 }
304 
player_death(su_t icon)305 void player_death(su_t icon)
306 {
307     su_t p=(icon==ICON_PLAYER0)?0:1;
308     char* msg[2]={" Oops! ","Gotcha!"};
309     map->data[map->player[p].y][map->player[p].x]=ICON_FLOOR;
310     if(p)
311         player.p1_alive=0;
312     else
313         player.p0_alive=0;
314     if(p==player.player){
315         if((p?player.p0_alive:player.p1_alive))
316             player.player^=1;
317     }
318     gfx_message(msg[p]);
319     game_win_display();
320 }
321 
player_process_map_pc(struct xor_move * pmv)322 void player_process_map_pc(struct xor_move* pmv)
323 {
324     su_t i;
325     su_t mb=1;
326     for(i=0;i<4;i++,mb*=2){
327         if(pmv->to_x==map->mappc[i].x
328          &&pmv->to_y==map->mappc[i].y){
329             player.have_map|=mb;
330             #ifdef MAP_DEBUG
331             printf("Map collected:(section %d bit)%d have_map:%d",i,mb,player.have_map);
332             #endif
333         }
334     }
335 }
336