/war.c

https://github.com/jwhite66/geled · C · 593 lines · 486 code · 107 blank · 0 comment · 120 complexity · 61423e04398c1451ea2b9009a067682a MD5 · raw file

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <math.h>
  8. #include <sys/param.h>
  9. #if defined(SIMULATOR)
  10. #include <X11/keysym.h>
  11. #endif
  12. #include "led.h"
  13. #include "fifo.h"
  14. typedef struct
  15. {
  16. int bright;
  17. int r;
  18. int g;
  19. int b;
  20. } pixel_t;
  21. #define ORIENT_NORTH 0
  22. #define ORIENT_EAST 1
  23. #define ORIENT_SOUTH 2
  24. #define ORIENT_WEST 3
  25. #define X_ORIENT(o) ((o) == ORIENT_EAST ? 1 : (o) == ORIENT_WEST ? -1 : 0)
  26. #define Y_ORIENT(o) ((o) == ORIENT_SOUTH ? 1 : (o) == ORIENT_NORTH ? -1 : 0)
  27. typedef struct
  28. {
  29. double x;
  30. double y;
  31. int orientation;
  32. double dx;
  33. double dy;
  34. int id;
  35. int hits;
  36. } dude_t;
  37. typedef struct
  38. {
  39. double x;
  40. double y;
  41. double dx;
  42. double dy;
  43. int id;
  44. } bullet_t;
  45. typedef struct
  46. {
  47. int x;
  48. int y;
  49. int type;
  50. int tick;
  51. } explosion_t;
  52. #define BLUE_DUDE 0
  53. #define RED_DUDE 1
  54. #define MAX_HITS 3
  55. dude_t g_dudes[2];
  56. int g_quit = 0;
  57. #define MAX_BULLETS 10
  58. #define BULLET_SPEED 0.2
  59. #define MAX_SPEED 1.5
  60. #define FRICTION .005
  61. #define ACCELERATION .2
  62. bullet_t g_bullets[MAX_BULLETS];
  63. int g_bullet_count = 0;
  64. #define MAX_EXPLOSIONS 10
  65. #define EXPLOSION_RADIUS 1
  66. #define EXPLOSION_LIFE_CYCLE 10
  67. explosion_t g_explosions[MAX_EXPLOSIONS];
  68. int g_explosion_count = 0;
  69. int g_wide = 0;
  70. int g_high = 0;
  71. void reset_field(LED_HANDLE_T h)
  72. {
  73. int x, y;
  74. g_bullet_count = g_explosion_count = 0;
  75. memset(&g_dudes[BLUE_DUDE], 0, sizeof(g_dudes[BLUE_DUDE]));
  76. memset(&g_dudes[RED_DUDE], 0, sizeof(g_dudes[RED_DUDE]));
  77. memset(&g_bullets, 0, sizeof(g_bullets));
  78. g_dudes[BLUE_DUDE].id = BLUE_DUDE;
  79. g_dudes[BLUE_DUDE].orientation = ORIENT_EAST;
  80. g_dudes[RED_DUDE].id = RED_DUDE;
  81. g_dudes[RED_DUDE].orientation = ORIENT_WEST;
  82. g_dudes[RED_DUDE].y = g_high - 1;
  83. g_dudes[RED_DUDE].x = g_wide - 1;
  84. for (y = 0; y < g_high; y++)
  85. for (x = 0; x < g_wide; x++)
  86. led_set_pixel(h, x, y, 0, 0, 0, 0);
  87. }
  88. double wrap_x(double x, double dx)
  89. {
  90. x += dx;
  91. while (((int) x) >= g_wide)
  92. x -= g_wide;
  93. while ( x < 0.0)
  94. x += g_wide;
  95. return x;
  96. }
  97. double wrap_y(double y, double dy)
  98. {
  99. y += dy;
  100. while (((int) y) >= g_high)
  101. y -= g_high;
  102. while (y < 0.0)
  103. y += g_high;
  104. return y;
  105. }
  106. pixel_t *get_dude_color(dude_t *dude)
  107. {
  108. static pixel_t colors[2][MAX_HITS] =
  109. {
  110. {
  111. { 0xc0, 0, 0, 0xf },
  112. { 0xc0, 5, 0, 0xf },
  113. { 0xc0, 15, 2, 0 }
  114. },
  115. {
  116. { 0xc0, 0xf, 0, 0 },
  117. { 0xc0, 15, 2, 0 },
  118. { 0xc0, 5, 0, 0xf }
  119. }
  120. };
  121. return (&colors[dude->id][dude->hits]);
  122. }
  123. pixel_t *get_bullet_color(bullet_t *bullet)
  124. {
  125. static pixel_t colors[2] =
  126. {
  127. { 0xc0, 0, 0, 0xf },
  128. { 0xc0, 0xf, 0, 0 }
  129. };
  130. return (&colors[bullet->id]);
  131. }
  132. void erase_dude(LED_HANDLE_T h, dude_t *dude)
  133. {
  134. led_set_pixel(h, (int) dude->x, (int) dude->y, 0, 0, 0, 0);
  135. led_set_pixel(h, (int) wrap_x(((int) dude->x), X_ORIENT(dude->orientation)),
  136. (int) wrap_y(((int) dude->y), Y_ORIENT(dude->orientation)),
  137. 0, 0, 0, 0);
  138. }
  139. void draw_dude(LED_HANDLE_T h, dude_t *dude)
  140. {
  141. pixel_t *pixel = get_dude_color(dude);
  142. led_set_pixel(h, (int) dude->x, (int) dude->y,
  143. pixel->bright, pixel->r,
  144. pixel->g, pixel->b);
  145. led_set_pixel(h, (int) wrap_x(((int) dude->x), X_ORIENT(dude->orientation)),
  146. (int) wrap_y(((int) dude->y), Y_ORIENT(dude->orientation)),
  147. 0x30, pixel->r, pixel->g, pixel->b);
  148. }
  149. void draw_dudes(LED_HANDLE_T h)
  150. {
  151. int i;
  152. for (i = 0; i < sizeof(g_dudes) / sizeof(g_dudes[0]); i++)
  153. draw_dude(h, &g_dudes[i]);
  154. }
  155. void move_dude(LED_HANDLE_T h, dude_t *dude)
  156. {
  157. double newx, newy;
  158. newx = wrap_x(dude->x, dude->dx);
  159. newy = wrap_y(dude->y, dude->dy);
  160. if ((int) newx != (int) dude->x ||
  161. (int) newy != (int) dude->y)
  162. {
  163. erase_dude(h, dude);
  164. dude->x = newx;
  165. dude->y = newy;
  166. draw_dude(h, dude);
  167. }
  168. else
  169. {
  170. dude->x = newx;
  171. dude->y = newy;
  172. }
  173. }
  174. void accelerate_dude(LED_HANDLE_T h, dude_t *dude)
  175. {
  176. if (dude->orientation == ORIENT_NORTH)
  177. dude->dy -= ACCELERATION;
  178. if (dude->orientation == ORIENT_SOUTH)
  179. dude->dy += ACCELERATION;
  180. if (dude->orientation == ORIENT_EAST)
  181. dude->dx += ACCELERATION;
  182. if (dude->orientation == ORIENT_WEST)
  183. dude->dx -= ACCELERATION;
  184. if (dude->dx > MAX_SPEED)
  185. dude->dx = MAX_SPEED;
  186. if (dude->dy > MAX_SPEED)
  187. dude->dy = MAX_SPEED;
  188. if (dude->dx < (-1 * MAX_SPEED))
  189. dude->dx = (-1 * MAX_SPEED);
  190. if (dude->dy < (-1 * MAX_SPEED))
  191. dude->dy = (-1 * MAX_SPEED);
  192. }
  193. void friction_dude(dude_t *dude)
  194. {
  195. if (dude->dx < 0)
  196. dude->dx += FRICTION;
  197. if (dude->dy < 0)
  198. dude->dy += FRICTION;
  199. if (dude->dx > 0)
  200. dude->dx -= FRICTION;
  201. if (dude->dy > 0)
  202. dude->dy -= FRICTION;
  203. }
  204. void erase_bullet(LED_HANDLE_T h, bullet_t *bullet)
  205. {
  206. led_set_pixel(h, (int) bullet->x, (int) bullet->y, 0, 0, 0, 0);
  207. }
  208. void draw_bullet(LED_HANDLE_T h, bullet_t *bullet)
  209. {
  210. pixel_t *pixel = get_bullet_color(bullet);
  211. led_set_pixel(h, (int) bullet->x, (int) bullet->y,
  212. pixel->bright, pixel->r,
  213. pixel->g, pixel->b);
  214. }
  215. int move_bullet(LED_HANDLE_T h, bullet_t *bullet)
  216. {
  217. double newx, newy;
  218. newx = bullet->x + bullet->dx;
  219. newy = bullet->y + bullet->dy;
  220. if (newx >= g_wide || newx < 0.0 ||
  221. newy >= g_high || newy < 0.0)
  222. {
  223. erase_bullet(h, bullet);
  224. return 1;
  225. }
  226. if ((int) newx != (int) bullet->x ||
  227. (int) newy != (int) bullet->y)
  228. {
  229. erase_bullet(h, bullet);
  230. bullet->x = newx;
  231. bullet->y = newy;
  232. draw_bullet(h, bullet);
  233. draw_dudes(h);
  234. }
  235. else
  236. {
  237. bullet->x = newx;
  238. bullet->y = newy;
  239. }
  240. return 0;
  241. }
  242. void position_bullet(dude_t *dude, bullet_t *bullet)
  243. {
  244. bullet->dx = dude->dx + BULLET_SPEED * X_ORIENT(dude->orientation);
  245. bullet->dy = dude->dy + BULLET_SPEED * Y_ORIENT(dude->orientation);
  246. bullet->x = round(wrap_x(dude->x, X_ORIENT(dude->orientation)));
  247. bullet->y = round(wrap_y(dude->y, Y_ORIENT(dude->orientation)));
  248. }
  249. int limit_bullet(dude_t *dude)
  250. {
  251. int me;
  252. int i;
  253. for (i = 0, me = 0; i < g_bullet_count; i++)
  254. if (g_bullets[i].id == dude->id)
  255. {
  256. me++;
  257. if (me >= (MAX_BULLETS / 2))
  258. return 1;
  259. }
  260. return 0;
  261. }
  262. void fire_bullet(LED_HANDLE_T h, dude_t *dude)
  263. {
  264. if (g_bullet_count == MAX_BULLETS)
  265. return;
  266. if (limit_bullet(dude))
  267. return;
  268. bullet_t *bullet = &g_bullets[g_bullet_count++];
  269. bullet->id = dude->id;
  270. position_bullet(dude, bullet);
  271. }
  272. void change_orientation(dude_t *dude, int o)
  273. {
  274. dude->orientation += o;
  275. if (dude->orientation < 0)
  276. dude->orientation = ORIENT_WEST;
  277. if (dude->orientation > ORIENT_WEST)
  278. dude->orientation = ORIENT_NORTH;
  279. }
  280. void left(LED_HANDLE_T h, dude_t *dude)
  281. {
  282. erase_dude(h, dude);
  283. change_orientation(dude, -1);
  284. }
  285. void right(LED_HANDLE_T h, dude_t *dude)
  286. {
  287. erase_dude(h, dude);
  288. change_orientation(dude, 1);
  289. }
  290. #if defined(SIMULATOR)
  291. void my_callback(LED_HANDLE_T h, unsigned long key)
  292. {
  293. if (key == 'q')
  294. g_quit++;
  295. if (key == 'd')
  296. right(h, &g_dudes[BLUE_DUDE]);
  297. if (key == 'a')
  298. left(h, &g_dudes[BLUE_DUDE]);
  299. if (key == 'w')
  300. accelerate_dude(h, &g_dudes[BLUE_DUDE]);
  301. if (key == ' ' || key == 's')
  302. fire_bullet(h, &g_dudes[BLUE_DUDE]);
  303. if (key == XK_Right)
  304. right(h, &g_dudes[RED_DUDE]);
  305. if (key == XK_Left)
  306. left(h, &g_dudes[RED_DUDE]);
  307. if (key == XK_Up)
  308. accelerate_dude(h, &g_dudes[RED_DUDE]);
  309. if (key == XK_Down)
  310. fire_bullet(h, &g_dudes[RED_DUDE]);
  311. draw_dudes(h);
  312. }
  313. #endif
  314. pixel_t * compute_explosion(explosion_t *exp, int x, int y)
  315. {
  316. static pixel_t color;
  317. if (x == 0 && y == 0)
  318. color.bright = 0xc0;
  319. else
  320. color.bright = 0x80;
  321. color.r = (rand() % 4) + 12;
  322. color.g = rand() % 4;
  323. color.b = 0;
  324. color.bright -= exp->tick * 8;
  325. if (color.bright < 0)
  326. color.bright = 0;
  327. return &color;
  328. }
  329. int draw_explosion(LED_HANDLE_T h, explosion_t *exp)
  330. {
  331. int i, j;
  332. for (i = -1 * EXPLOSION_RADIUS; i <= EXPLOSION_RADIUS; i++)
  333. for (j = -1 * EXPLOSION_RADIUS; j <= EXPLOSION_RADIUS; j++)
  334. {
  335. pixel_t *pixel = compute_explosion(exp, i, j);
  336. if (exp->tick == (EXPLOSION_LIFE_CYCLE - 1))
  337. pixel->bright = pixel->r = pixel->g = pixel->b = 0;
  338. if (exp->x + i >= 0 && exp->x + i < g_wide &&
  339. exp->y + j >= 0 && exp->y + j < g_high)
  340. led_set_pixel(h, exp->x + i, exp->y + j,
  341. pixel->bright, pixel->r, pixel->g, pixel->b);
  342. }
  343. exp->tick++;
  344. if (exp->tick >= EXPLOSION_LIFE_CYCLE)
  345. return 1;
  346. return 0;
  347. }
  348. void delete_bullet(int bullno)
  349. {
  350. if (g_bullet_count == 0)
  351. return;
  352. if (bullno < (g_bullet_count - 1))
  353. memcpy(g_bullets + bullno, g_bullets + bullno + 1,
  354. (g_bullet_count - bullno) * sizeof(g_bullets[0]));
  355. g_bullet_count--;
  356. }
  357. int bullets_collide(bullet_t *a, bullet_t *b)
  358. {
  359. if (a->id != b->id && (int) a->x == (int) b->x &&
  360. (int) a->y == (int) b->y)
  361. return 1;
  362. return 0;
  363. }
  364. int hit_dude(bullet_t *b, dude_t *d)
  365. {
  366. if (b->id != d->id &&
  367. (int) b->x == (int) d->x &&
  368. (int) b->y == (int) d->y)
  369. {
  370. d->hits++;
  371. return 1;
  372. }
  373. return 0;
  374. }
  375. void show_loser(LED_HANDLE_T h, int dude)
  376. {
  377. int x, y;
  378. for (y = 0; y < g_high; y++)
  379. for (x = 0; x < g_wide; x++)
  380. {
  381. led_set_pixel(h, x, y, MAX_BRIGHT, dude == BLUE_DUDE ? 15 : 0, 0, dude == BLUE_DUDE ? 0 : 15);
  382. usleep(20000);
  383. }
  384. reset_field(h);
  385. }
  386. void move_stuff(LED_HANDLE_T h)
  387. {
  388. int i, j;
  389. for (i = 0; i < g_explosion_count; i++)
  390. {
  391. if (draw_explosion(h, &g_explosions[i]))
  392. {
  393. if (i < (g_explosion_count - 1))
  394. g_explosions[i] = g_explosions[g_explosion_count - 1];
  395. g_explosion_count--;
  396. }
  397. }
  398. move_dude(h, &g_dudes[BLUE_DUDE]);
  399. move_dude(h, &g_dudes[RED_DUDE]);
  400. for (i = 0; i < g_bullet_count; i++)
  401. {
  402. if (move_bullet(h, &g_bullets[i]))
  403. {
  404. delete_bullet(i);
  405. }
  406. }
  407. for (i = 0; i < g_bullet_count; i++)
  408. {
  409. for (j = 0; j < g_bullet_count; j++)
  410. if (i == j)
  411. break;
  412. else
  413. {
  414. if (bullets_collide(&g_bullets[i], &g_bullets[j]))
  415. {
  416. if (g_explosion_count < MAX_EXPLOSIONS)
  417. {
  418. g_explosions[g_explosion_count].x = (int) g_bullets[i].x;
  419. g_explosions[g_explosion_count].y = (int) g_bullets[i].y;
  420. g_explosions[g_explosion_count].tick = 0;
  421. g_explosion_count++;
  422. }
  423. delete_bullet(MAX(i, j));
  424. delete_bullet(MIN(i, j));
  425. }
  426. }
  427. }
  428. for (i = 0; i < g_bullet_count; i++)
  429. {
  430. for (j = 0; j < sizeof(g_dudes) / sizeof(g_dudes[0]); j++)
  431. if (hit_dude(&g_bullets[i], &g_dudes[j]))
  432. {
  433. delete_bullet(i);
  434. if (g_dudes[j].hits >= MAX_HITS)
  435. {
  436. show_loser(h, j);
  437. break;
  438. }
  439. }
  440. }
  441. friction_dude(&g_dudes[BLUE_DUDE]);
  442. friction_dude(&g_dudes[RED_DUDE]);
  443. }
  444. void fifo_callback(void *parm, void *p)
  445. {
  446. LED_HANDLE_T h = (LED_HANDLE_T) parm;
  447. int dude;
  448. char buf[MAX_COMMAND_LEN];
  449. sscanf(p, "%d-%s\n", &dude, buf);
  450. if (strcasecmp(buf, "left") == 0)
  451. left(h, &g_dudes[dude]);
  452. if (strcasecmp(buf, "right") == 0)
  453. right(h, &g_dudes[dude]);
  454. if (strcasecmp(buf, "up") == 0)
  455. accelerate_dude(h, &g_dudes[dude]);
  456. if (strcasecmp(buf, "fire") == 0)
  457. fire_bullet(h, &g_dudes[dude]);
  458. draw_dudes(h);
  459. }
  460. int main (int argc, char *argv[])
  461. {
  462. LED_HANDLE_T p;
  463. fifo_t f;
  464. p = led_init();
  465. #if defined(SIMULATOR)
  466. ledsim_set_x_callback(p, my_callback);
  467. #endif
  468. led_get_size(p, &g_wide, &g_high);
  469. umask(0);
  470. if (fifo_init(FIFO_PATH, &fifo_callback, &f, p) != 0)
  471. {
  472. fprintf(stderr, "Error opening command fifo\n");
  473. exit(1);
  474. }
  475. reset_field(p);
  476. draw_dudes(p);
  477. while (! g_quit)
  478. {
  479. usleep(100000);
  480. move_stuff(p);
  481. draw_dudes(p);
  482. }
  483. led_term(p);
  484. fifo_term(&f);
  485. return 0;
  486. }