--- /dev/null
+/* $Id: dlist.h,v 1.1 2007/01/07 07:51:12 mmondor Exp $ */
+
+/*
+ * Copyright (C) 2001-2006, Matthew Mondor
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Matthew Mondor.
+ * 4. The name of Matthew Mondor may not be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ * 5. Redistribution of source code may not be released under the terms of
+ * any GNU Public License derivate.
+ *
+ * THIS SOFTWARE IS PROVIDED BY MATTHEW MONDOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL MATTHEW MONDOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+#ifndef DLIST_H
+#define DLIST_H
+
+
+
+typedef struct list list_t;
+typedef struct node node_t;
+
+
+
+struct node {
+ node_t *prev, *next;
+};
+
+struct list {
+ node_t *top, *bottom;
+ int nodes;
+};
+
+
+
+/* Some macros to optimize operations on doubly linked lists */
+#define DLIST_INITIALIZER {NULL, NULL, 0}
+
+#define DLIST_INIT(lst) do { \
+ (lst)->top = (lst)->bottom = NULL; \
+ (lst)->nodes = 0; \
+} while (/* CONSTCOND */0)
+
+#define DLIST_UNLINK(lst, nod) do { \
+ register node_t *prev = (nod)->prev, *next = (nod)->next; \
+ \
+ if (prev != NULL) \
+ prev->next = next; \
+ else \
+ (lst)->top = next; \
+ if (next != NULL) \
+ next->prev = prev; \
+ else \
+ (lst)->bottom = prev; \
+ (lst)->nodes--; \
+} while (/* CONSTCOND */0)
+
+#define DLIST_APPEND(lst, nod) do { \
+ register node_t *tmp = (lst)->bottom; \
+ \
+ if (tmp != NULL) { \
+ tmp->next = (nod); \
+ (nod)->prev = tmp; \
+ (nod)->next = NULL; \
+ (lst)->bottom = (nod); \
+ } else { \
+ (lst)->bottom = (lst)->top = (nod); \
+ (nod)->next = (nod)->prev = NULL; \
+ } \
+ (lst)->nodes++; \
+} while (/* CONSTCOND */0)
+
+#define DLIST_INSERT(lst, nod) do { \
+ register node_t *tmp = (lst)->top; \
+ \
+ if (tmp != NULL) { \
+ tmp->prev = (nod); \
+ (nod)->prev = NULL; \
+ (nod)->next = tmp; \
+ (lst)->top = (nod); \
+ } else { \
+ (lst)->top = (lst)->bottom = (nod); \
+ (nod)->next = (nod)->prev = NULL; \
+ } \
+ (lst)->nodes++; \
+} while (/* CONSTCOND */0)
+
+#define DLIST_INSERTAT(lst, atnode, nod) do { \
+ register node_t *prev = (atnode)->prev, *next = (atnode); \
+ \
+ (nod)->next = next; \
+ next->prev = (nod); \
+ if (prev != NULL) { \
+ prev->next = (nod); \
+ (nod)->prev = prev; \
+ } else { \
+ (lst)->top = (nod); \
+ (nod)->prev = NULL; \
+ } \
+ (lst)->nodes++; \
+} while (/* CONSTCOND */0)
+
+#define DLIST_SWAP(dst, src, nod, ins) do { \
+ register node_t *prev = (nod)->prev, *next = (nod)->next; \
+ \
+ if (prev != NULL) \
+ prev->next = next; \
+ else \
+ (src)->top = next; \
+ if (next != NULL) \
+ next->prev = prev; \
+ else \
+ (src)->bottom = prev; \
+ (src)->nodes--; \
+ if ((ins)) { \
+ if ((prev = (dst)->top) != NULL) { \
+ prev->prev = (nod); \
+ (nod)->prev = NULL; \
+ (nod)->next = prev; \
+ (dst)->top = (nod); \
+ } else { \
+ (dst)->top = (dst)->bottom = (nod); \
+ (nod)->next = (nod)->prev = NULL; \
+ } \
+ } else { \
+ if ((prev = (dst)->bottom) != NULL) { \
+ prev->next = (nod); \
+ (nod)->prev = prev; \
+ (nod)->next = NULL; \
+ (dst)->bottom = (nod); \
+ } else { \
+ (dst)->bottom = (dst)->top = (nod); \
+ (nod)->next = (nod)->prev = NULL; \
+ } \
+ } \
+ (dst)->nodes++; \
+} while (/* CONSTCOND */0)
+
+#define DLIST_TOP(lst) ((void *)((list_t *)(lst))->top)
+#define DLIST_BOTTOM(lst) ((void *)((list_t *)(lst))->bottom)
+#define DLIST_NEXT(var) ((void *)((node_t *)(var))->next)
+#define DLIST_PREV(var) ((void *)((node_t *)(var))->prev)
+
+#define DLIST_FOREACH(lst, var) \
+ for ((var) = DLIST_TOP((lst)); (var) != NULL; (var) = DLIST_NEXT((var)))
+
+#define DLIST_NODES(lst) (((list_t *)(lst))->nodes)
+
+
+
+#endif
--- /dev/null
+/* $Id: main.c,v 1.1 2007/01/07 07:51:12 mmondor Exp $ */
+
+/*
+ * Copyright (c) 2006, Matthew Mondor
+ * ALL RIGHTS RESERVED.
+ */
+
+
+
+/* STANDARD HEADERS */
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* THIRD PARTY LIBRARY HEADERS */
+#include <SDL.h>
+#include <SDL_image.h>
+#include <SDL_mixer.h>
+
+/* APPLICATION HEADERS */
+#include <main.h>
+#include <debug.h>
+#include <screen.h>
+
+
+
+/* DEFINITIONS */
+
+
+
+/* PRIVATE PROTOTYPES */
+
+int main(int, char **);
+
+
+
+/* PUBLIC GLOBALS */
+
+
+
+/* PRIVATE GLOBALS */
+
+static int main_quit = 0;
+
+static SDL_Surface *img_border = NULL, *img_textarea = NULL,
+ *img_painting = NULL;
+
+static Mix_Music *music = NULL;
+
+static char *painting_file = NULL, *music_file = NULL;
+
+
+
+/* PRIVATE FUNCTIONS */
+
+/* ARGSUSED */
+int
+main(int argc, char **argv)
+{
+ Mix_Music *mus;
+
+ /* Initialization */
+ screen_init();
+
+ (void) SDL_ShowCursor(0);
+ (void) SDL_EnableKeyRepeat(0, 0);
+
+ /*
+ * Ignore a few events with potentially high frequency but which
+ * we don't need
+ */
+ (void) SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE);
+ (void) SDL_EventState(SDL_JOYAXISMOTION, SDL_IGNORE);
+ (void) SDL_EventState(SDL_JOYBALLMOTION, SDL_IGNORE);
+ (void) SDL_EventState(SDL_JOYHATMOTION, SDL_IGNORE);
+ (void) SDL_EventState(SDL_KEYUP, SDL_IGNORE);
+
+ /*
+ * Audio
+ */
+ if (Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 1024) != 0) {
+ (void) fprintf(stderr, "main() - Mix_OpenAudio() - %s\n",
+ Mix_GetError());
+ exit(EXIT_FAILURE);
+ }
+ snd_test = sample_load("snd/test.wav");
+ (void) Mix_AllocateChannels(4);
+ (void) Mix_ReserveChannels(2);
+ if ((mus = Mix_LoadMUS("mus/1.ogg")) == NULL) {
+ (void) fprintf(stderr, "main() - Mix_LoadMUS() - %s\n",
+ Mix_GetError());
+ exit(EXIT_FAILURE);
+ }
+ if (Mix_PlayMusic(mus, -1) != 0) {
+ (void) fprintf(stderr, "main() - Mix_PlayMusic() - %s\n",
+ Mix_GetError());
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Main loop.
+ */
+ while (!main_quit) {
+ SDL_Event ev;
+
+ while (SDL_PollEvent(&ev)) {
+ handle_uevent(&ev);
+ }
+ }
+
+ /* Fadeout music */
+ (void) Mix_FadeOutMusic(1000);
+ SDL_Delay(1000);
+
+ exit(EXIT_SUCCESS);
+}
+
+static void
+handle_uevent(SDL_Event *ev)
+{
+
+ if (ev->type == SDL_MOUSEMOTION)
+ return;
+
+ /*
+ * Quit commands events.
+ */
+ if ((ev->type == SDL_KEYDOWN && ev->key.keysym.sym == SDLK_ESCAPE) ||
+ ev->type == SDL_QUIT) {
+ main_quit = 1;
+ return;
+ }
+
+ /*
+ * Button events. joy_angle affects several of them.
+ * We currently ignore release events.
+ */
+ if (ev->type == SDL_JOYBUTTONDOWN) {
+
+ if (ev->jbutton.state != 1)
+ return;
+
+ switch (ev->jbutton.button) {
+ case 0:
+ send_event(UE_TORP);
+ break;
+ case 1:
+ send_event(UE_PHASER);
+ break;
+ case 2:
+ send_event(UE_DIRECTION, joy_angle);
+ break;
+ case 3:
+ send_event(UE_PLASMA);
+ break;
+ case 4:
+ send_event(UE_SHIELD);
+ break;
+ case 5:
+ send_event(UE_CLOAK);
+ break;
+ case 6:
+ send_event(UE_THRUST_ACC);
+ break;
+ case 7:
+ send_event(UE_THRUST_DEC);
+ break;
+ }
+
+ return;
+ }
+
+ /*
+ * Keyboard events
+ */
+ if (ev->type == SDL_KEYDOWN) {
+ int angle = joy_angle;
+
+ switch (ev->key.keysym.sym) {
+ /* Angle changes */
+ case SDLK_i:
+ angle = 192;
+ break;
+ case SDLK_o:
+ angle = 224;
+ break;
+ case SDLK_l:
+ angle = 0;
+ break;
+ case SDLK_PERIOD:
+ angle = 32;
+ break;
+ case SDLK_COMMA:
+ angle = 64;
+ break;
+ case SDLK_m:
+ angle = 96;
+ break;
+ case SDLK_j:
+ angle = 128;
+ break;
+ case SDLK_u:
+ angle = 160;
+ break;
+ /* Navigation change */
+ case SDLK_d:
+ send_event(UE_DIRECTION, joy_angle);
+ break;
+ case SDLK_z:
+ send_event(UE_THRUST_ACC);
+ break;
+ case SDLK_a:
+ send_event(UE_THRUST_DEC);
+ break;
+ /* Weapons */
+ case SDLK_SPACE:
+ send_event(UE_TORP);
+ break;
+ case SDLK_f:
+ send_event(UE_PHASER);
+ break;
+ case SDLK_g:
+ send_event(UE_PLASMA);
+ break;
+ /* Toggles */
+ case SDLK_s:
+ send_event(UE_SHIELD);
+ break;
+ case SDLK_w:
+ send_event(UE_CLOAK);
+ break;
+ default:
+ break;
+ }
+
+ if (joy_angle != angle)
+ joy_angle = angle;
+ return;
+ }
+
+ return;
+}
+
+static void
+send_event(int type, ...)
+{
+ int ch, err = 0;
+
+ switch (type) {
+ case UE_DIRECTION:
+ err = cpacket_direction_send(((int *)&type)[1]);
+ break;
+ case UE_TORP:
+ if ((ch = Mix_PlayChannel(-1, snd_torp, 0)) != -1)
+ Mix_SetPosition(ch, joy_angle, 50);
+ err = cpacket_torp_send(joy_angle);
+ break;
+ case UE_PHASER:
+ /* XXX */
+ if ((ch = Mix_PlayChannel(-1, snd_hit, 0)) != -1)
+ Mix_SetPosition(ch, joy_angle, 50);
+ break;
+ case UE_PLASMA:
+ /* XXX */
+ if ((ch = Mix_PlayChannel(-1, snd_explode, 0)) != -1)
+ Mix_SetPosition(ch, joy_angle, 50);
+ break;
+ case UE_SHIELD:
+ shields = (shields == 0 ? 1 : 0);
+ Mix_PlayChannel(1,
+ (shields == 1 ? snd_shield : snd_unshield), 0);
+ err = cpacket_shield_send();
+ break;
+ case UE_CLOAK:
+ cloaked = (cloaked == 0 ? 1 : 0);
+ Mix_PlayChannel(2,
+ (cloaked == 1 ? snd_cloak : snd_uncloak), 0);
+ err = cpacket_cloak_send();
+ break;
+ case UE_THRUST_ACC:
+ err = cpacket_thrust_acc_send();
+ break;
+ case UE_THRUST_DEC:
+ err = cpacket_thrust_dec_send();
+ break;
+ }
+
+ if (err == -1) {
+ (void) fprintf(stderr, "Error writing to server socket\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+/* Extern, called by spacket_eof_handler */
+void
+frame_switch(void)
+{
+
+ /* Draw text stats */
+ font_blit_string(font, 17, 461, fpsstr, 0x00, 0x00, 0x00, 0xff);
+ font_blit_string(font, 16, 460, fpsstr, 0xff, 0xff, 0xff, 0xff);
+ font_blit_string(font, 101, 461, pingstr, 0x00, 0x00, 0x00, 0xff);
+ font_blit_string(font, 100, 460, pingstr, 0xff, 0xff, 0xff, 0xff);
+ font_blit_string(font, 201, 461, shipinfostr, 0x00, 0x00, 0x00, 0xff);
+ font_blit_string(font, 200, 460, shipinfostr, 0xff, 0xff, 0xff, 0xff);
+
+ /* Switch buffers */
+ (void) SDL_Flip(screen_surface);
+
+ /* Clear new buffer */
+ /*
+ {
+ uint32_t *ptr, *tptr;
+
+ if (SDL_MUSTLOCK(screen_surface))
+ SDL_LockSurface(screen_surface);
+ for (ptr = screen_surface->pixels,
+ tptr = &ptr[screen_width * screen_height];
+ ptr < tptr; ptr = &ptr[8]) {
+ ptr[0] = 0x00000000;
+ ptr[1] = 0x00000000;
+ ptr[2] = 0x00000000;
+ ptr[3] = 0x00000000;
+ ptr[4] = 0x00000000;
+ ptr[5] = 0x00000000;
+ ptr[6] = 0x00000000;
+ ptr[7] = 0x00000000;
+ }
+ if (SDL_MUSTLOCK(screen_surface))
+ SDL_UnlockSurface(screen_surface);
+ }
+ */
+ (void) SDL_FillRect(screen_surface, NULL, 0x00000000);
+
+ /* Update fps counter for stats */
+ fpscnt++;
+}
+
+void
+ship_draw(int id, int x, int y, double angle, uint8_t flags)
+{
+ char str[8];
+
+ (void) surface_blit_angle(rship, x, y, angle);
+ if ((flags & SHIPF_CLOAK) != 0)
+ filledCircleRGBA(screen_surface, x, y, 25,
+ 0x00, 0x00, 0x00, 0x80);
+ if ((flags & SHIPF_SHIELD) != 0) {
+ aacircleRGBA(screen_surface, x, y, 25,
+ 0xf0, 0xf0, 0x20, 0xb0);
+ filledCircleRGBA(screen_surface, x, y, 25,
+ 0x20, 0x50, 0xf0, 0x50);
+ }
+
+ x -= 24;
+ y -= 24;
+ (void) snprintf(str, 8, "%d", id);
+ font_blit_string(font, x, y, str, 0x00, 0x00, 0x00, 0xff);
+ font_blit_string(font, x + 1, y + 1, str, 0xff, 0xff, 0xff, 0xff);
+}
+
+void
+torp_draw(int x, int y, int r)
+{
+ static const uint8_t torp_colors[3][3] = {
+ { 0xff, 0xff, 0x00 }, /* 90% */
+ { 0xff, 0x30, 0x00 }, /* 5% */
+ { 0x00, 0x30, 0xff } /* 5% */
+ };
+ int rnd, c;
+
+ rnd = rand() % 100;
+ if (rnd < 5)
+ c = 2;
+ else if (rnd < 10)
+ c = 1;
+ else
+ c = 0;
+
+ filledCircleRGBA(screen_surface, x, y, 1 + (rand() % r),
+ torp_colors[c][0], torp_colors[c][1], torp_colors[c][2],
+ 0x7f + (rand() % 0x80));
+}
+
+static SDL_Surface *
+bmp_load_key(void *data, size_t size)
+{
+ SDL_RWops *rwo;
+ SDL_Surface *s;
+ Uint32 c;
+ void *ndata;
+ size_t nsize;
+
+ decode(&ndata, &nsize, data, size);
+
+ if ((rwo = SDL_RWFromMem(ndata, nsize)) == NULL)
+ goto err;
+ if ((s = IMG_LoadBMP_RW(rwo)) == NULL)
+ goto err;
+ SDL_FreeRW(rwo);
+
+ c = SDL_MapRGB(s->format, 0, 0, 0);
+ if (SDL_SetColorKey(s, SDL_SRCCOLORKEY | SDL_RLEACCEL, c) == -1)
+ goto err;
+
+ return s;
+
+err:
+ (void) fprintf(stderr, "bmp_load_key() - %s\n", SDL_GetError());
+ exit(EXIT_FAILURE);
+}
+
+static int
+surface_blit_angle(SDL_Surface *s, int x, int y, int a)
+{
+ SDL_Surface *t;
+ SDL_Rect d;
+ int r;
+
+ ASSERT(a > -1 && a < 256);
+
+ /*
+ * Convert 0-255 angle to 0-359 and add 90 degrees so that shapes
+ * bitmaps can point upwards, although angle 0 should point
+ * rightwards,
+ */
+ a = (a * 360 / 256) + 90;
+
+ /* Interestingly, the angle has to be reversed... */
+ if ((t = rotozoomSurface(s, -a, 1.0, 1)) != NULL) {
+ d = (SDL_Rect){x - (t->w / 2), y - (t->h / 2), 0, 0};
+ r = SDL_BlitSurface(t, NULL, screen_surface, &d);
+ SDL_FreeSurface(t);
+ } else
+ r = -1;
+
+ return r;
+}
+
+static Mix_Chunk *
+sample_load(void *data, size_t size)
+{
+ SDL_RWops *rwo;
+ Mix_Chunk *c;
+ void *ndata;
+ size_t nsize;
+
+ decode(&ndata, &nsize, data, size);
+
+ if ((rwo = SDL_RWFromMem(ndata, nsize)) == NULL)
+ goto err;
+
+ if ((c = Mix_LoadWAV_RW(rwo, 0)) == NULL)
+ goto err;
+
+ SDL_FreeRW(rwo);
+ return c;
+
+err:
+ (void) fprintf(stderr, "sample_load() - %s\n", SDL_GetError());
+ exit(EXIT_FAILURE);
+}