1 /*
2 * xtrojka (c) 1994,1995,1996 Maarten Los
3 *
4 * #include "COPYRIGHT"
5 *
6 * created: 26.xi.1995
7 * modified: 7.ii.1996 Added update statistics
8 *
9 * This is the game module, doing everything that's not done
10 * in the trojka core.
11 */
12
13 #include <stdio.h>
14 #include <X11/Intrinsic.h>
15 #include <X11/StringDefs.h>
16 #include <X11/keysym.h>
17
18 #include "game.h"
19 #include "sh_main.h"
20 #include "sh_stat.h"
21 #include "scores.h"
22 #include "menu.h"
23
24 #include "debug.h"
25 #include "tr_core.h"
26 #include "xtrojka.h"
27 #include "screen.h"
28
29 extern XtAppContext app_context;
30
31 extern Widget main_screen; /* the mother of all widgets */
32 extern Widget screen;
33 extern Widget form;
34
35 extern flag is_wizard;
36
37 extern GAME_STATE game_state;
38
39 extern int starting_speed;
40 extern int speed;
41
42 static XtIntervalId clocker;
43
44 flag ignore_clock;
45 flag remove_clock;
46
47 tt_command CMD_DOWN = { tc_c_blockdown, 0 , 0 };
48 tt_command CMD_LEFT = { tc_c_blockleft, 0 , 0 };
49 tt_command CMD_RIGHT = { tc_c_blockright, 0 , 0 };
50 tt_command CMD_DROP = { tc_c_dropblock, 0 , 0 };
51 tt_command CMD_SPEEDUP = { tc_c_speedup, 0 , 0 };
52
53 /*
54 * source
55 */
mainloop(void)56 void mainloop(void)
57 {
58 /*
59 * this is the main loop where the game is played
60 */
61 XEvent event;
62
63 DEBUG("game.c", "mainloop")
64
65 set_state(st_idle);
66
67 for(;;) {
68 XtAppNextEvent(app_context, &event);
69 XtDispatchEvent(&event);
70 }
71 }
72
73
resetgame(void)74 void resetgame(void)
75 {
76 tt_command CMD_INIT;
77
78 DEBUG("game.c", "resetgame")
79
80 ignore_clock = False;
81
82 CMD_INIT.command = tc_c_init;
83 CMD_INIT.param1 = starting_speed;
84 CMD_INIT.param2 = is_wizard;
85 trojka_api(&CMD_INIT);
86
87 show_score();
88 set_speed_item(starting_speed);
89 draw_field();
90 }
91
92
set_state(gs)93 void set_state(gs)
94 GAME_STATE gs;
95 {
96 /*
97 * disables/enables menu's event- and update handlers
98 * depending on the game state.
99 */
100 DEBUG("game.c", "set_state")
101 game_state = gs;
102
103 set_menus(gs);
104 if(gs == st_playing) {
105
106 remove_clock = False;
107 resetgame();
108
109 /*
110 * start the clocker
111 */
112 clocker = XtAppAddTimeOut(app_context, tv_ticks,
113 (XtTimerCallbackProc)block_down_intr,
114 0);
115
116 }
117 else if(gs == st_idle) {
118
119 remove_clock = True;
120 draw_title();
121 }
122 }
123
124
125
init_event_handlers()126 void init_event_handlers()
127 {
128 DEBUG("game.c", "init_event_handlers")
129
130 /*
131 * catch moving main screen
132 */
133 XtAddEventHandler(main_screen, StructureNotifyMask, False,
134 (XtEventHandler)move_mainwindow_hlr, (Opaque)NULL);
135
136 /*
137 * catch enter/leave/focus events
138 */
139 XtAddEventHandler(screen,
140 LeaveWindowMask | EnterWindowMask,
141 False,
142 (XtEventHandler)std_window_hlr, (Opaque)NULL);
143
144 /*
145 * catch keyboard events
146 */
147 XtAddEventHandler(form, KeyPressMask, False,
148 (XtEventHandler)key_pressed_hlr, (Opaque)NULL);
149
150 }
151
152
153
block_down_intr(w,id)154 void block_down_intr(w, id)
155 Widget w;
156 XtIntervalId *id;
157 {
158 /*
159 * this function is called every n timer ticks depending
160 * on the game speed.
161 */
162 int res;
163
164 DEBUG("game.c", "block_down_intr")
165
166 if(!remove_clock)
167 clocker=XtAppAddTimeOut(app_context, tv_ticks,
168 (XtTimerCallbackProc)block_down_intr, 0);
169 else {
170 remove_clock = False;
171 return;
172 }
173
174 if(ignore_clock)
175 return;
176
177 if((res = trojka_api(&CMD_DOWN)) == tc_res_gameover) {
178 gameover();
179 }
180 else if(res == tc_res_touchdown) {
181 show_score();
182 update_stat();
183 }
184 }
185
186
187
key_pressed_hlr(w,unused,ke,continue_to_dispatch)188 void key_pressed_hlr(w, unused, ke, continue_to_dispatch)
189 Widget w;
190 XtPointer unused;
191 XKeyPressedEvent *ke;
192 Boolean *continue_to_dispatch;
193 {
194 extern tt_int tv_shape;
195 /*
196 * This function handles on pressing a key, and acts
197 * depending on the state the game is in.
198 */
199 Modifiers dum;
200 KeySym sym;
201
202 DEBUG("game.c", "game_key_pressed_hlr")
203
204 *continue_to_dispatch = TRUE;
205
206 if(ke->type != KeyPress)
207 return;
208
209 XtTranslateKeycode(ke->display, ke->keycode, 0, &dum, &sym);
210
211 /*
212 * act on 'st_playing'
213 */
214
215 if(game_state == st_playing) {
216
217 switch(sym) {
218
219 /*
220 * Dirty debug. Get any block you want
221 * case XK_b:
222 *
223 * tv_shape = (tv_shape + 1) % tc_blocks;
224 * break;
225 */
226
227 case XK_h:
228 case XK_Left:
229 if(ignore_clock)
230 return;
231 trojka_api(&CMD_LEFT);
232 break;
233
234 case XK_l:
235 case XK_Right:
236 if(ignore_clock)
237 return;
238 trojka_api(&CMD_RIGHT);
239 break;
240
241 case XK_space:
242 case XK_j:
243 case XK_Insert:
244 case XK_Down:
245 if(ignore_clock)
246 return;
247
248 trojka_api(&CMD_DROP);
249 break;
250
251 case XK_Up:
252 case XK_k:
253 trojka_api(&CMD_SPEEDUP);
254 speed = tv_speed;
255 set_speed_item(speed);
256 break;
257
258 default:
259 break;
260 }
261 }
262 if(game_state == st_idle) {
263 /* NOT NECCESARY YET */
264 /* MOST ARE COVERED BY ACTIONS */
265 }
266 }
267
268
move_mainwindow_hlr(w,unused,ce,continue_to_dispatch)269 void move_mainwindow_hlr(w, unused, ce, continue_to_dispatch)
270 Widget w;
271 XtPointer unused;
272 XConfigureEvent *ce;
273 Boolean *continue_to_dispatch;
274 {
275 *continue_to_dispatch = TRUE;
276
277 DEBUG("game.c", "move_mainwindow_hlr");
278 }
279
280
281
gameover_action(w,unused,event,continue_to_dispatch)282 void gameover_action(w, unused, event, continue_to_dispatch)
283 Widget w;
284 XtPointer unused;
285 XEvent *event;
286 Boolean *continue_to_dispatch;
287 {
288 DEBUG("game.c", "gameover_action");
289 gameover();
290 }
291
292
gameover(void)293 void gameover(void)
294 {
295 DEBUG("game.c", "gameover")
296
297 remove_clock = True;
298
299 do_hiscores();
300
301 speed = starting_speed;
302
303 set_state(st_idle);
304 }
305
306
new_game(void)307 void new_game(void)
308 {
309 DEBUG("game.c", "new_game");
310
311 if(game_state != st_playing)
312 set_state(st_playing);
313 }
314
315
std_window_hlr(w,unused,event,continue_to_dispatch)316 void std_window_hlr(w, unused, event, continue_to_dispatch)
317 Widget w;
318 XtPointer unused;
319 XAnyEvent *event;
320 Boolean *continue_to_dispatch;
321 {
322 /*
323 * this function is a callback function. It is called each time
324 * the mouse pointer enters the window
325 */
326 DEBUG("game.c", "std_window_hlr")
327
328 *continue_to_dispatch = TRUE;
329
330 if(game_state != st_playing)
331 return;
332
333 switch(event->type) {
334
335 case EnterNotify:
336 DEBUG("\tevent_type","EnterNotify");
337 ignore_clock = False;
338 break;
339
340 case LeaveNotify:
341 DEBUG("\tevent_type","LeaveNotify");
342 ignore_clock = True;
343 break;
344
345 }
346 }
347
348
349
350
351