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