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