Rev 1665 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1665 | pj | 1 | ////////////////////////////////////////////////////////////////// |
2 | // Pong |
||
3 | // Written for CS 324, UIUC |
||
4 | // Spencer Hoke |
||
5 | // James Kim |
||
6 | // Tao Luo |
||
7 | // |
||
8 | // Last Modified: April 29, 2004 |
||
9 | |||
10 | #include "pong.h" |
||
11 | |||
12 | /////////////////////////////////////// |
||
13 | // sets initial values of global variables |
||
14 | void setglobals() { |
||
15 | P_MASS = 100; |
||
16 | kp = 30; |
||
17 | kd = 20; // > sqrt(4*(XMAX - XMIN)* kp) |
||
18 | AI_VIEWING_RANGE = 250; // window = YMAX - this |
||
19 | |||
20 | balllist = NULL; |
||
21 | |||
22 | num_balls = 0; // number of balls currently in system |
||
23 | min_balls = 0; // minimum number of balls in the system |
||
24 | locked = 0; // 1 if #balls kept constant |
||
25 | ball_spd = 5; // ballspeed (default = 5) |
||
26 | |||
27 | p_speed = 10; // # pixels to move each keypress |
||
28 | p1_length = 150; // size of the paddles |
||
29 | p2_length = 75; // size of the paddles |
||
30 | |||
31 | p1_pos = (XMAX + XMIN - p1_length)/2; // initialize starting paddle positions |
||
32 | p2_pos = (XMAX + XMIN - p2_length)/2; |
||
33 | p2_target_pos = p2_pos; // initially no movement |
||
34 | |||
35 | points1 = 0; // scores for each side |
||
36 | points2 = 0; |
||
37 | } |
||
38 | |||
39 | /////////////////////////////////////// |
||
40 | // center at (x,y) with radius RAD and color c |
||
41 | void draw_ball(int x, int y, int c) { |
||
42 | mutex_lock(&draw_mutex); |
||
43 | grx_disc(x, y, RAD, c); |
||
44 | mutex_unlock(&draw_mutex); |
||
45 | } |
||
46 | |||
47 | /////////////////////////////////////// |
||
48 | // top left corner is (x,y), length is l, |
||
49 | // thickness is P_THICKNESS, and color is c |
||
50 | void draw_paddle(int x, int y, int l, int c) { |
||
51 | mutex_lock(&draw_mutex); |
||
52 | grx_box(x, y, x + l, y + P_THICKNESS, c); |
||
53 | mutex_unlock(&draw_mutex); |
||
54 | } |
||
55 | |||
56 | /////////////////////////////////////// |
||
57 | // draws a line where the computer's viewing window starts |
||
58 | void draw_viewwin(int col) { |
||
59 | mutex_lock(&draw_mutex); |
||
60 | grx_line(XMIN-RAD, AI_VIEWING_RANGE+YMIN, XMAX+RAD, AI_VIEWING_RANGE+YMIN, col); |
||
61 | mutex_unlock(&draw_mutex); |
||
62 | } |
||
63 | |||
64 | /////////////////////////////////////// |
||
65 | void print_scores() { |
||
66 | char st1[15], st2[15]; |
||
67 | |||
68 | sprintf(st1, "Player 1:%6d", points1); |
||
69 | sprintf(st2, "Player 2:%6d", points2); |
||
70 | mutex_lock(&draw_mutex); |
||
71 | grx_text(st1, XMIN-RAD-1, 20, blue, black); |
||
72 | grx_text(st2, XMIN-RAD-1, 30, red, black); |
||
73 | mutex_unlock(&draw_mutex); |
||
74 | } |
||
75 | |||
76 | /////////////////////////////////////// |
||
77 | void print_numballs() { |
||
78 | char st[15]; |
||
79 | |||
80 | sprintf(st, "Num balls:%3d", num_balls); |
||
81 | mutex_lock(&draw_mutex); |
||
82 | grx_text(st, XMAX-100, 20, magenta, black); |
||
83 | mutex_unlock(&draw_mutex); |
||
84 | } |
||
85 | |||
86 | /////////////////////////////////////// |
||
87 | void print_constants() { |
||
88 | char st[15]; |
||
89 | |||
90 | sprintf(st, "kp:%3d, kd:%3d, mass:%4d", kp, kd, P_MASS); |
||
91 | mutex_lock(&draw_mutex); |
||
92 | grx_text(st, XMIN-RAD-1, YMAX+20, magenta, black); |
||
93 | mutex_unlock(&draw_mutex); |
||
94 | } |
||
95 | |||
96 | /////////////////////////////////////// |
||
97 | TASK ball(void *arg) { |
||
98 | int x, y; // current position |
||
99 | int oldx, oldy; // last position |
||
100 | int dx, dy; // delta x, y |
||
101 | int theta, col; |
||
102 | double r; // theta in radians |
||
103 | int p1len, p2len, p1pos, p2pos; // temp storage of length and position |
||
104 | int outx; |
||
105 | int hitp1, hitp2; // 1 if ball has hit paddle |
||
106 | int in1, in2; // 1 if ball is currently inside paddle (error) |
||
107 | struct ballinfo myinfo; // shared x/y/theta |
||
108 | |||
109 | myinfo.x = x = oldx = XMIN; // start in middle of the left |
||
110 | myinfo.y = y = oldy = (YMIN+YMAX)/2; |
||
111 | col = rand()%14 + 2; // color ball |
||
112 | |||
113 | // insert myinfo into global list |
||
114 | mutex_lock(&list_mutex); |
||
115 | if(balllist != NULL) // update old first entry in list |
||
116 | balllist->prev = &myinfo; |
||
117 | myinfo.next = balllist; |
||
118 | myinfo.prev = NULL; |
||
119 | balllist = &myinfo; |
||
120 | mutex_unlock(&list_mutex); |
||
121 | |||
122 | // starting angle = [ANGMIN,ANGMAX] |
||
123 | theta = rand()%(ANGMAX - ANGMIN) + ANGMIN; |
||
124 | if (rand()%2 == 1) // random starting direction |
||
125 | theta *= -1; |
||
126 | if (theta > 360) theta -= 360; |
||
127 | if (theta < 0) theta += 360; |
||
128 | myinfo.theta = theta; |
||
129 | r = (double)theta * PI / 180.; |
||
130 | |||
131 | while (1) { |
||
132 | dx = (float)(ball_spd * cos(r)); |
||
133 | dy = (float)(ball_spd * sin(r)); |
||
134 | x += dx; |
||
135 | y += dy; |
||
136 | |||
137 | // check boundary conditions |
||
138 | if (y >= YMAX) { // end task and score point for player 2 |
||
139 | points1++; |
||
140 | break; |
||
141 | } |
||
142 | if (y <= YMIN) { // end task and score point for player 1 |
||
143 | points2++; |
||
144 | break; |
||
145 | } |
||
146 | |||
147 | p1len = p1_length; // copy globals |
||
148 | p1pos = p1_pos; |
||
149 | p2len = p2_length; |
||
150 | p2pos = p2_pos; |
||
151 | |||
152 | outx = (x >= XMAX) || (x <= XMIN); |
||
153 | hitp1 = (y <= (YMIN + 2*RAD + P_THICKNESS)) // y is within range of paddle |
||
154 | && (x >= (p1pos - RAD)) && (x <= (p1pos + p1len + RAD)); // x is within range of paddle |
||
155 | hitp2 = (y >= (YMAX - 2*RAD - P_THICKNESS)) // y is within range of paddle |
||
156 | && (x >= (p2pos - RAD)) && (x <= (p2pos + p2len + RAD)); // x is within range of paddle |
||
157 | |||
158 | // need these in case ball goes in the side of the paddle |
||
159 | in1 = (oldy <= (YMIN + 2*RAD + P_THICKNESS)) // oldy is within range of paddle |
||
160 | && (oldx >= (p1pos - RAD)) && (oldx <= (p1pos + p1len + RAD)); // oldx is within range of paddle |
||
161 | in2 = (oldy >= (YMAX - 2*RAD - P_THICKNESS)) // oldy is within range of paddle |
||
162 | && (oldx >= (p2pos - RAD)) && (oldx <= (p2pos + p2len + RAD)); // oldx is within range of paddle |
||
163 | |||
164 | if (outx || ((hitp1 || hitp2) && !in1 && !in2)) { // ball needs to bounce |
||
165 | x -= dx; |
||
166 | y -= dy; |
||
167 | if (outx) theta = 180 - theta; // bounce off wall |
||
168 | if ((hitp1 || hitp2) && !in1 && !in2) theta = -theta; // bounce off paddle |
||
169 | |||
170 | if (theta > 360) theta -= 360; |
||
171 | else if (theta < 0) theta += 360; |
||
172 | |||
173 | r = (double)theta * PI / 180.; |
||
174 | x += (float)(ball_spd * cos(r)); |
||
175 | y += (float)(ball_spd * sin(r)); |
||
176 | } |
||
177 | |||
178 | draw_ball(oldx, oldy, black); // clear old position |
||
179 | draw_ball(x, y, col); // draw new ball |
||
180 | oldx = x; oldy = y; |
||
181 | |||
182 | mutex_lock(&list_mutex); // updates values in list |
||
183 | myinfo.x = x; |
||
184 | myinfo.y = y; |
||
185 | myinfo.theta = theta; |
||
186 | mutex_unlock(&list_mutex); |
||
187 | |||
188 | task_endcycle(); |
||
189 | } |
||
190 | |||
191 | // remove myinfo from list |
||
192 | mutex_lock(&list_mutex); |
||
193 | if(myinfo.next != NULL) |
||
194 | (myinfo.next)->prev = myinfo.prev; |
||
195 | |||
196 | if(myinfo.prev != NULL) |
||
197 | (myinfo.prev)->next = myinfo.next; |
||
198 | else |
||
199 | balllist = myinfo.next; |
||
200 | mutex_unlock(&list_mutex); |
||
201 | |||
202 | draw_ball(oldx, oldy, 0); // clear ball |
||
203 | print_scores(); // update score |
||
204 | num_balls--; // remove ball from system |
||
205 | if(!locked) |
||
206 | print_numballs(); // update count of balls |
||
207 | return NULL; |
||
208 | } |
||
209 | |||
210 | /////////////////////////////////////// |
||
211 | void addball() { |
||
212 | HARD_TASK_MODEL m; |
||
213 | PID pid; |
||
214 | |||
215 | hard_task_default_model(m); |
||
216 | hard_task_def_ctrl_jet (m); |
||
217 | hard_task_def_wcet (m, BALL_WCET); |
||
218 | hard_task_def_mit (m, BALL_PER); |
||
219 | hard_task_def_group (m, BALLGROUP); |
||
220 | hard_task_def_usemath (m); |
||
221 | pid = task_create("ball", ball, &m, NULL); |
||
222 | if (pid == NIL) { |
||
223 | sys_shutdown_message("Could not create task <ball> errno=%d", errno); |
||
224 | sys_abort(errno); |
||
225 | } |
||
226 | task_activate(pid); |
||
227 | num_balls++; |
||
228 | print_numballs(); |
||
229 | } |
||
230 | |||
231 | /////////////////////////////////////// |
||
232 | // paddle 1 controller |
||
233 | TASK paddle1(void *arg) { |
||
234 | int oldpos, newpos; |
||
235 | int move, oldlength, length; |
||
236 | |||
237 | oldpos = newpos = p1_pos; |
||
238 | oldlength = -1; // force draw initially |
||
239 | |||
240 | while (1) { |
||
241 | length = p1_length; // need to copy in case they change |
||
242 | move = p1_move; |
||
243 | p1_move -= move; // update global variable |
||
244 | |||
245 | // get new position of ball |
||
246 | newpos += move * p_speed; |
||
247 | if(newpos < XMIN) // tried to move too far right |
||
248 | newpos = XMIN; |
||
249 | else if(newpos > (XMAX - length)) // tried to move too far left |
||
250 | newpos = XMAX - length; |
||
251 | |||
252 | if ((newpos != oldpos) || (length != oldlength)) { // need to redraw the paddle |
||
253 | p1_pos = newpos; // update global position |
||
254 | draw_paddle(oldpos, YMIN + RAD, oldlength, black); // clear old paddle |
||
255 | draw_paddle(newpos, YMIN + RAD, length, blue); // draw new one |
||
256 | oldpos = newpos; |
||
257 | oldlength = length; |
||
258 | } |
||
259 | else |
||
260 | draw_paddle(newpos, YMIN + RAD, length, blue); // refresh paddle |
||
261 | |||
262 | task_endcycle(); |
||
263 | } |
||
264 | } |
||
265 | |||
266 | /////////////////////////////////////// |
||
267 | // determines target position of paddle 2 |
||
268 | TASK p2ai(void *arg) { |
||
269 | int proj; // projected length to y-value of paddle |
||
270 | int closestBallY_Location = 0; |
||
271 | int closestBallX_Location = 0; |
||
272 | int closestBallY_Angle = 0; |
||
273 | int closestToPaddle; |
||
274 | int projectedX_Location = 0; |
||
275 | int foundBall; |
||
276 | double r; // angle in radians |
||
277 | struct ballinfo *cur; |
||
278 | char st[20]; |
||
279 | |||
280 | while(1) { |
||
281 | if (num_balls != 0) { // if there are balls |
||
282 | //finds the closest ball and its position and angle |
||
283 | closestBallY_Location = AI_VIEWING_RANGE + YMIN; |
||
284 | closestToPaddle = 1000000; // large default number |
||
285 | foundBall = 0; |
||
286 | |||
287 | mutex_lock(&list_mutex); |
||
288 | for (cur = balllist; cur != NULL; cur = cur->next) { |
||
289 | if (cur->y > closestBallY_Location // within window |
||
290 | && cur->y < (YMAX - RAD - P_THICKNESS) // not past paddle already |
||
291 | && cur->theta < 180) // going toward paddle |
||
292 | { |
||
293 | r = (double)(cur->theta) * PI / 180.; |
||
294 | proj = (float)( (YMAX - RAD - P_THICKNESS - cur->y) / sin(r) ); // geometry |
||
295 | if(proj < closestToPaddle) { // this is the closest one |
||
296 | foundBall = 1; |
||
297 | closestBallY_Location = cur->y; |
||
298 | closestBallX_Location = cur->x; |
||
299 | closestBallY_Angle = cur->theta; |
||
300 | closestToPaddle = proj; |
||
301 | } |
||
302 | } |
||
303 | } |
||
304 | mutex_unlock(&list_mutex); |
||
305 | |||
306 | //finds where it needs to move to |
||
307 | if (foundBall == 1) { |
||
308 | r = (double)closestBallY_Angle * PI / 180.; |
||
309 | projectedX_Location = (float)( (YMAX - RAD - P_THICKNESS - closestBallY_Location) / tan(r) ); // geometry |
||
310 | projectedX_Location += closestBallX_Location; |
||
311 | |||
312 | while(projectedX_Location < XMIN || projectedX_Location > XMAX) { // adjust for ball bounces |
||
313 | if(projectedX_Location < XMIN) |
||
314 | projectedX_Location = 2*XMIN - projectedX_Location; // bounce off left side |
||
315 | if(projectedX_Location > XMAX) |
||
316 | projectedX_Location = 2*XMAX - projectedX_Location; // bounce off right side |
||
317 | } |
||
318 | |||
319 | sprintf(st, "Proj X: %3d", projectedX_Location); |
||
320 | mutex_lock(&draw_mutex); |
||
321 | grx_text(st, XMAX-85, YMAX+20, magenta, black); |
||
322 | mutex_unlock(&draw_mutex); |
||
323 | |||
324 | p2_target_pos = projectedX_Location - p2_length/2; // copy into target for p2 |
||
325 | } |
||
326 | } |
||
327 | |||
328 | task_endcycle(); |
||
329 | } |
||
330 | } |
||
331 | |||
332 | /////////////////////////////////////// |
||
333 | // paddle 2 controller - applies forces and draws paddle |
||
334 | TASK paddle2(void *arg) { |
||
335 | int oldpos, newpos; |
||
336 | int positionErrorX, oldlength, length; |
||
337 | int force = 0, acceleration = 0, velocity = 0; // paddle movement |
||
338 | |||
339 | oldpos = newpos = p2_pos; |
||
340 | oldlength = -1; // force draw initially |
||
341 | |||
342 | while (1) { |
||
343 | length = p2_length; // need to copy in case they change |
||
344 | positionErrorX = p2_target_pos - oldpos; |
||
345 | |||
346 | //Applying force |
||
347 | force = kp * positionErrorX - kd * velocity; |
||
348 | acceleration = force / P_MASS; |
||
349 | |||
350 | velocity += acceleration; // new velocity |
||
351 | newpos = oldpos + velocity; // using new velocity, so incorporates acceleration |
||
352 | |||
353 | if(newpos < XMIN) // tried to move too far right |
||
354 | newpos = XMIN; |
||
355 | else if(newpos > (XMAX - length)) // tried to move too far left |
||
356 | newpos = XMAX - length; |
||
357 | |||
358 | if ((newpos != oldpos) || (length != oldlength)) { // need to redraw the paddle |
||
359 | p2_pos = newpos; // update global position |
||
360 | draw_paddle(oldpos, YMAX - P_THICKNESS - RAD, oldlength, black); // clear old paddle |
||
361 | draw_paddle(newpos, YMAX - P_THICKNESS - RAD, length, red); // draw new one |
||
362 | oldpos = newpos; |
||
363 | oldlength = length; |
||
364 | } |
||
365 | else |
||
366 | draw_paddle(newpos, YMAX - P_THICKNESS - RAD, length, red); // refresh paddle |
||
367 | |||
368 | task_endcycle(); |
||
369 | } |
||
370 | } |
||
371 | |||
372 | /////////////////////////////////////// |
||
373 | TASK countmon(void *arg) { |
||
374 | while(1) { |
||
375 | while(num_balls < min_balls) |
||
376 | addball(); |
||
377 | task_endcycle(); |
||
378 | } |
||
379 | } |
||
380 | |||
381 | /////////////////////////////////////// |
||
382 | int main(int argc, char **argv) { |
||
383 | HARD_TASK_MODEL m; |
||
384 | PID pid; |
||
385 | |||
386 | char c; |
||
387 | TIME seme; // used to init the random seed |
||
388 | PI_mutexattr_t a; // for PI mutex init |
||
389 | |||
390 | // initialize global variables |
||
391 | setglobals(); |
||
392 | |||
393 | // initialize PI mutexes |
||
394 | PI_mutexattr_default(a); |
||
395 | mutex_init(&draw_mutex, &a); |
||
396 | mutex_init(&list_mutex, &a); |
||
397 | |||
398 | // Draw initial screen layout and menu |
||
399 | grx_rect(XMIN-RAD-1, YMIN-RAD-1, XMAX+RAD+1, YMAX+RAD+1, yellow); |
||
400 | grx_text("Scores:", XMIN-RAD-1, 10, magenta, black); |
||
401 | |||
402 | grx_text("PONG", XMENU, YMENU, magenta, black); |
||
403 | grx_text("Create a ball: SPACE", XMENU, YMENU+15, redorange, black); |
||
404 | grx_text("Quit program: ESC", XMENU, YMENU+25, redorange, black); |
||
405 | grx_text("Move top paddle: z x", XMENU, YMENU+35, redorange, black); |
||
406 | grx_text("Change top size: a s", XMENU, YMENU+45, redorange, black); |
||
407 | grx_text("Change bottom size: q w", XMENU, YMENU+55, redorange, black); |
||
408 | grx_text("Keep # Balls Const: l", XMENU, YMENU+65, redorange, black); |
||
409 | grx_text("Change ball speed: 1 2", XMENU, YMENU+75, redorange, black); |
||
410 | grx_text("Change kp: 3 4", XMENU, YMENU+85, redorange, black); |
||
411 | grx_text("Change kd: 5 6", XMENU, YMENU+95, redorange, black); |
||
412 | grx_text("Change mass: 7 8", XMENU, YMENU+105, redorange, black); |
||
413 | grx_text("Change AI window: 9 0", XMENU, YMENU+115, redorange, black); |
||
414 | |||
415 | print_scores(); |
||
416 | print_numballs(); |
||
417 | print_constants(); |
||
418 | draw_viewwin(gray); |
||
419 | |||
420 | // randomize for ball starting angle |
||
421 | seme = sys_gettime(NULL); |
||
422 | srand(seme); |
||
423 | |||
424 | // set up the paddle tasks |
||
425 | hard_task_default_model(m); |
||
426 | hard_task_def_ctrl_jet (m); |
||
427 | hard_task_def_wcet (m, P_WCET); |
||
428 | hard_task_def_mit (m, P_PER); |
||
429 | hard_task_def_group (m, PGROUP); |
||
430 | hard_task_def_usemath (m); |
||
431 | pid = task_create("paddle1", paddle1, &m, NULL); |
||
432 | if (pid == NIL) { |
||
433 | sys_shutdown_message("Could not create task <paddle1> errno=%d", errno); |
||
434 | sys_abort(errno); |
||
435 | } |
||
436 | |||
437 | hard_task_default_model(m); |
||
438 | hard_task_def_ctrl_jet (m); |
||
1667 | giacomo | 439 | hard_task_def_level (m,1); |
1665 | pj | 440 | hard_task_def_wcet (m, P_WCET); |
441 | hard_task_def_mit (m, P_PER); |
||
442 | hard_task_def_group (m, PGROUP); |
||
443 | hard_task_def_usemath (m); |
||
444 | pid = task_create("p2ai", p2ai, &m, NULL); |
||
445 | if (pid == NIL) { |
||
446 | sys_shutdown_message("Could not create task <p2ai> errno=%d", errno); |
||
447 | sys_abort(errno); |
||
448 | } |
||
449 | |||
450 | hard_task_default_model(m); |
||
451 | hard_task_def_ctrl_jet (m); |
||
1667 | giacomo | 452 | hard_task_def_level (m,1); |
1665 | pj | 453 | hard_task_def_wcet (m, P_WCET); |
454 | hard_task_def_mit (m, P_PER); |
||
455 | hard_task_def_group (m, PGROUP); |
||
456 | hard_task_def_usemath (m); |
||
457 | pid = task_create("paddle2", paddle2, &m, NULL); |
||
458 | if (pid == NIL) { |
||
459 | sys_shutdown_message("Could not create task <paddle2> errno=%d", errno); |
||
460 | sys_abort(errno); |
||
461 | } |
||
462 | group_activate(PGROUP); |
||
463 | |||
464 | #ifdef JET_ON |
||
465 | scenario_jetcontrol(); |
||
466 | init_jetcontrol(); |
||
467 | group_activate(JET_GROUP); |
||
468 | #endif |
||
469 | |||
470 | hard_task_default_model(m); |
||
471 | hard_task_def_ctrl_jet (m); |
||
1667 | giacomo | 472 | hard_task_def_level (m,1); |
1665 | pj | 473 | hard_task_def_wcet (m, BALL_WCET); |
474 | hard_task_def_mit (m, BALL_PER); |
||
475 | hard_task_def_group (m, BALLGROUP); |
||
476 | hard_task_def_usemath (m); |
||
477 | pid = task_create("countmon", countmon, &m, NULL); |
||
478 | if (pid == NIL) { |
||
479 | sys_shutdown_message("Could not create task <countmonitor> errno=%d", errno); |
||
480 | sys_abort(errno); |
||
481 | } |
||
482 | task_activate(pid); |
||
483 | |||
484 | while(1) { // read in commands ( exit handled in handle_key() ) |
||
485 | c = keyb_getch(BLOCK); |
||
486 | switch (c) { |
||
487 | case ESC: // quit program |
||
488 | sys_abort(0); |
||
489 | break; |
||
490 | case ' ': // create a new ball |
||
491 | addball(); |
||
492 | if(locked == 1) // update min # balls if locked |
||
493 | min_balls++; |
||
494 | break; |
||
495 | case 'z': // move paddle1 left |
||
496 | p1_move--; |
||
497 | break; |
||
498 | case 'x': // move paddle1 right |
||
499 | p1_move++; |
||
500 | break; |
||
501 | case 's': // increase paddle1 length |
||
502 | if (p1_length < (XMAX - XMIN - P_DLENGTH)) |
||
503 | p1_length += P_DLENGTH; |
||
504 | break; |
||
505 | case 'a': // decrease paddle1 length |
||
506 | if (p1_length > (1 + P_DLENGTH)) |
||
507 | p1_length -= P_DLENGTH; |
||
508 | break; |
||
509 | case 'w': // increase paddle2 length |
||
510 | if (p2_length < (XMAX - XMIN - P_DLENGTH)) |
||
511 | p2_length += P_DLENGTH; |
||
512 | break; |
||
513 | case 'q': // decrease paddle2 length |
||
514 | if (p2_length > (1 + P_DLENGTH)) |
||
515 | p2_length -= P_DLENGTH; |
||
516 | break; |
||
517 | case 'l': // lock number of balls |
||
518 | if((locked = !locked)) { |
||
519 | min_balls = num_balls; |
||
520 | mutex_lock(&draw_mutex); |
||
521 | grx_text(" Locked", XMAX-100, 30, redorange, black); |
||
522 | mutex_unlock(&draw_mutex); |
||
523 | } |
||
524 | else { |
||
525 | min_balls = 0; |
||
526 | mutex_lock(&draw_mutex); |
||
527 | grx_text(" ", XMAX-100, 30, redorange, black); |
||
528 | mutex_unlock(&draw_mutex); |
||
529 | } |
||
530 | break; |
||
531 | case '1': // decrease ball speed |
||
532 | ball_spd--; |
||
533 | break; |
||
534 | case '2': // increase ball speed |
||
535 | ball_spd++; |
||
536 | break; |
||
537 | case '3': // decrease kp |
||
538 | if(kp > 0) |
||
539 | kp--; |
||
540 | print_constants(); |
||
541 | break; |
||
542 | case '4': // increase kp |
||
543 | kp++; |
||
544 | print_constants(); |
||
545 | break; |
||
546 | case '5': // decrease kd |
||
547 | if(kd > 0) |
||
548 | kd--; |
||
549 | print_constants(); |
||
550 | break; |
||
551 | case '6': // increase kd |
||
552 | kd++; |
||
553 | print_constants(); |
||
554 | break; |
||
555 | case '7': // decrease mass |
||
556 | if(P_MASS > 5) |
||
557 | P_MASS -= 5; |
||
558 | print_constants(); |
||
559 | break; |
||
560 | case '8': // increase mass |
||
561 | P_MASS += 5; |
||
562 | print_constants(); |
||
563 | break; |
||
564 | case '9': // decrease AI window |
||
565 | draw_viewwin(black); // clear old line |
||
566 | AI_VIEWING_RANGE += 5; |
||
567 | draw_viewwin(gray); // draw new one |
||
568 | break; |
||
569 | case '0': // increase AI window |
||
570 | draw_viewwin(black); // clear old line |
||
571 | AI_VIEWING_RANGE -= 5; |
||
572 | draw_viewwin(gray); // draw new one |
||
573 | break; |
||
574 | default: |
||
575 | break; |
||
576 | } |
||
577 | } |
||
578 | |||
579 | return 0; |
||
580 | } |
||
581 |