diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4131ba3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Object files +*.o + +# Libraries +*.lib +*.a + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib +*.bin + +# Executables +*.exe +*.out +*.app + +# Crap. +*.log +*.swp +*.txt +*.tsv +*.pdf +*bin/Lephisto + + diff --git a/bin/Makefile b/bin/Makefile new file mode 100644 index 0000000..c9a0063 --- /dev/null +++ b/bin/Makefile @@ -0,0 +1,26 @@ +DEBUG = 1 +APPNAME = Lephisto + +OBJ := ../src/main.o \ + ../src/physics.o \ + ../src/opengl.o \ + ../src/ship.o \ + ../src/pilot.o + +CFLAGS = -Wall `sdl-config --cflags` +ifdef DEBUG +CFLAGS += -g3 -DDEBUG +else +CFLAGS += -O2 +endif + +LDFLAGS = -lm `sdl-config --libs` -lSDL_image -lGL + +%.o: ../src/%.c + gcc -c $(CFLAGS) -o $@ $< + +all: $(OBJ) + gcc $(LDFLAGS) -o $(APPNAME) $(OBJ) + +clean: + rm -rf $(OBJ) $(APPNAME) diff --git a/gfx/ship.png b/gfx/ship.png new file mode 100644 index 0000000..4c845ef Binary files /dev/null and b/gfx/ship.png differ diff --git a/src/def.h b/src/def.h new file mode 100644 index 0000000..d90f00b --- /dev/null +++ b/src/def.h @@ -0,0 +1,6 @@ +#pragma once + +#define MALLOC_L(type)(malloc(sizeof(type))) + +typedef float FP; + diff --git a/src/log.h b/src/log.h new file mode 100644 index 0000000..58d599f --- /dev/null +++ b/src/log.h @@ -0,0 +1,14 @@ +#pragma once +#include + +#define LOG(str, args...)(fprintf(stdout, str"\n", ## args)) +#define WARN(str, args...)(fprintf(stderr, "[%d] "str"\n", 0, ## args)) + +#ifdef DEBUG +# undef DEBUG +# define DEBUG(str, args...) LOG(str, ## args) +# define DEBUGGING +#else +# define DEBUG(str, args...) do {;} while(0) +#endif + diff --git a/src/main.c b/src/main.c index 139597f..21161c1 100644 --- a/src/main.c +++ b/src/main.c @@ -1,2 +1,95 @@ +#include +#include +#include +#include "def.h" +#include "log.h" +#include "log.h" +#include "physics.h" +#include "opengl.h" +#include "ship.h" +#include "pilot.h" + +int main(int argc, const char** argv) { + int quit = 0; + SDL_Event event; + + gl_screen.w = 800; + gl_screen.h = 640; + gl_screen.fullscreen = 0; + + gl_init(); + + gl_texture* tex; + if((tex = gl_newSprite("../gfx/ship.png", 6, 6)) == NULL) { + WARN("Unable to load image"); + return -1; + } + Ship* ship = MALLOC_L(Ship); + ship->gfx_ship = tex; + ship->mass = 1; + ship->class = SHIP_CLASS_CIVILIAN; + Pilot* player = pilot_create(ship, "player", NULL, NULL, PILOT_PLAYER); + gl_bindCamera(&player->solid->pos); + + int tflag = 0; + unsigned int time = SDL_GetTicks(); + FP dt; + while(!quit) { + while(SDL_PollEvent(&event)) { + switch(event.type) { + case SDL_KEYDOWN: + switch(event.key.keysym.sym) { + case SDLK_q: + quit = 1; + break; + case SDLK_a: + tflag ^= 1; + break; + case SDLK_d: + tflag ^=2; + case SDLK_w: + tflag ^= 8; + break; + default: + break; + } + break; + case SDL_KEYUP: + switch(event.key.keysym.sym) { + case SDLK_a: + tflag ^= 1; + break; + case SDLK_d: + tflag ^= 2; + break; + case SDLK_w: + tflag ^= 8; + break; + default: + break; + } + break; + } + } + dt = (FP)(SDL_GetTicks() - time) / 1000.0; + if(tflag & 1) player->solid->dir += 200.0 / 180.0*M_PI*dt; + if(tflag & 2) player->solid->dir -= 200.0 / 180.0*M_PI*dt; + if(tflag & 8) player->solid->force = 340; + else player->solid->force = 0; + glClear(GL_COLOR_BUFFER_BIT); + player->update(player, dt); + SDL_GL_SwapBuffers(); + time = SDL_GetTicks(); + SDL_Delay(5); + } + + pilot_free(player); + free(ship); + gl_free(tex); + + gl_exit(); + + return 0; +} diff --git a/src/opengl.c b/src/opengl.c new file mode 100644 index 0000000..61cd30f --- /dev/null +++ b/src/opengl.c @@ -0,0 +1,302 @@ +#include +#include +#include "def.h" +#include "log.h" +#include "opengl.h" + +// Recommended for compatibility bullshit. +#if SDL_BYTEORDER == SDL_BIG_ENDIAN +# define RMASK 0xff000000 +# define GMASK 0x00ff0000 +# define BMASK 0x0000ff00 +# define AMASK 0x000000ff +#else +# define RMASK 0x000000ff +# define GMASK 0x0000ff00 +# define BMASK 0x00ff0000 +# define AMASK 0xff000000 +#endif +#define RGBMASK RMASK,GMASK,BMASK,AMASK + +// The screen info, gives data of current opengl settings. +gl_info gl_screen; + +// Our precious camera. +Vec2* gl_camera; + +static int flip_surface(SDL_Surface* surface); + +// Flips the surface vertically. Return 0 on success. +static int flip_surface(SDL_Surface* surface) { + // Flip the image. + Uint8* rowhi, *rowlo, *tmpbuf; + int y; + + tmpbuf = (Uint8*)malloc(surface->pitch); + if(tmpbuf == NULL) { + WARN("Out of memory"); + return -1; + } + + rowhi = (Uint8*)surface->pixels; + rowlo = rowhi + (surface->h * surface->pitch) - surface->pitch; + for(y = 0; y < surface->h / 2; ++y) { + memcpy(tmpbuf, rowhi, surface->pitch); + memcpy(rowhi, rowlo, surface->pitch); + memcpy(rowlo, tmpbuf, surface->pitch); + rowhi += surface->pitch; + rowlo -= surface->pitch; + } + free(tmpbuf); + // Might be obvious, but I'm done flipping. + return 0; +} + +// Load the image directly as an opengl texture. +gl_texture* gl_newImage(const char* path) { + SDL_Surface* tmp, *surface; + Uint32 saved_flags; + Uint8 saved_alpha; + int potw, poth; + + tmp = IMG_Load(path); // Load the surface. + if(tmp == 0) { + WARN("'%s' could not be opened: %s", path, IMG_GetError()); + return 0; + } + + surface = SDL_DisplayFormatAlpha(tmp); // Set the surface to what we use. + if(surface == 0) { + WARN("Error converting image to screen format: %s", SDL_GetError()); + return 0; + } + + SDL_FreeSurface(tmp); // Free the temp surface. + + flip_surface(surface); + + // Set up the texture defaults. + gl_texture* texture = MALLOC_L(gl_texture); + texture->w = (FP)surface->w; + texture->h = (FP)surface->h; + texture->sx = 1.0; + texture->sy = 1.0; + + // Ensure size is power of two. + potw = surface->w; + if((potw &(potw-1)) != 0) { + potw = 1; + while(potw < surface->w) + potw <<= 1; + } + texture->rw = potw; + + poth = surface->h; + if((poth &(poth-1)) != 0) { + poth = 1; + while(poth < surface->h) + poth <<= 1; + } + texture->rh = poth; + + if(surface->w != potw || surface->h != poth) { + // Size isn't original. + SDL_Rect rtemp; + rtemp.x = rtemp.y = 0; + rtemp.w = surface->w; + rtemp.h = surface->h; + + // Save alpha. + saved_flags = surface->flags & (SDL_SRCALPHA | SDL_RLEACCELOK); + saved_alpha = surface->format->alpha; + if((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA) + SDL_SetAlpha(surface, 0, 0); + + // Create the temp POT surface. + tmp = SDL_CreateRGBSurface(SDL_SRCCOLORKEY, + texture->rw, texture->rh, surface->format->BytesPerPixel*8, RGBMASK); + if(tmp == NULL) { + WARN("Unable to create POT surface %s", SDL_GetError()); + return 0; + } + if(SDL_FillRect(tmp, NULL, SDL_MapRGBA(surface->format, 0, 0, 0, SDL_ALPHA_TRANSPARENT))) { + WARN("Unable to fill rect: %s", SDL_GetError()); + return 0; + } + + SDL_BlitSurface(surface, &rtemp, tmp, &rtemp); + SDL_FreeSurface(surface); + + surface = tmp; + + // Set saved alpha. + if((saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA) + SDL_SetAlpha(surface, saved_flags, saved_alpha); + } + + glGenTextures(1, &texture->texture); // Create the texure. + glBindTexture(GL_TEXTURE_2D, texture->texture); // Load the texture. + + // Filtering, LINEAR is better for scaling, nearest looks nicer, LINEAR + // also seems to create a bit of artifacts around the edges. + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + SDL_LockSurface(surface); + glTexImage2D(GL_TEXTURE_2D, 0, surface->format->BytesPerPixel, + surface->w, surface->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surface->pixels); + + SDL_UnlockSurface(surface); + SDL_FreeSurface(surface); + + return texture; +} + +// Load the texture immediately, but also set is as a sprite. +gl_texture* gl_newSprite(const char* path, const int sx, const int sy) { + gl_texture* texture; + if((texture = gl_newImage(path)) == NULL) + return NULL; + texture->sx = (FP)sx; + texture->sy = (FP)sy; + texture->sw = texture->w/texture->sx; + texture->sh = texture->h/texture->sy; + return texture; +} + +// Free the texture. +void gl_free(gl_texture* texture) { + glDeleteTextures(1, &texture->texture); + free(texture); +} + +// Blit the sprite at given position. +void gl_blitSprite(gl_texture* sprite, Vec2* pos, const int sx, const int sy) { + glMatrixMode(GL_TEXTURE); + glTranslatef(sprite->sw * (FP)(sx)/sprite->rw, + sprite->sh*(sprite->sy-(FP)sy-1)/sprite->rh, 0.0f); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); // Projection translation matrix. + glTranslatef(gl_camera->x - pos->x - sprite->sw / 2.0, + gl_camera->y - pos->y - sprite->sh/2.0, 0.0f); + + // Actual blitting.... + glBindTexture(GL_TEXTURE_2D, sprite->texture); + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(0.0f, 0.0f); + glVertex2f(0.0f, 0.0f); + glTexCoord2f(sprite->sw/sprite->rw, 0.0f); + glVertex2f(sprite->sw, 0.0f); + glTexCoord2f(0.0f, sprite->sh/sprite->rh); + glVertex2f(0.0f, sprite->sh); + glTexCoord2f(sprite->sw/sprite->rw, sprite->sh/sprite->rh); + glVertex2f(sprite->sw, sprite->sh); + glEnd(); + + glPopMatrix(); // Projection translation matrix. + + glMatrixMode(GL_TEXTURE); + glPopMatrix(); // Sprite translation matrix. +} + +// Just straight out blit the thing at position. +void gl_blit(gl_texture* texture, Vec2* pos) { + glMatrixMode(GL_PROJECTION); + glPushMatrix(); // Set up translation matrix. + glTranslatef(pos->x, pos->y, 0); + + // Actual blitting.. + glBindTexture(GL_TEXTURE_2D, texture->texture); + glBegin(GL_TRIANGLE_STRIP); + glTexCoord2f(0.0f, 0.0f); + glVertex2f(0.0f, 0.0f); + glTexCoord2f(texture->w/texture->rw, 0.0f); + glVertex2f(texture->w, 0.0f); + glTexCoord2f(0.0f, texture->h/texture->rh); + glVertex2f(0.0f, texture->h); + glTexCoord2f(texture->w/texture->rw, texture->h/texture->rh); + glVertex2f(texture->w, texture->h); + glEnd(); + + glPopMatrix(); // Pop the translation matrix. +} + +// Bind our precious camera to a vector. +void gl_bindCamera(Vec2* pos) { + gl_camera = pos; +} + +// Initialize SDL/OpenGL etc. +int gl_init(void) { + int depth; + int flags = SDL_OPENGL; + + // Initializes video. + if(SDL_Init(SDL_INIT_VIDEO) < 0) { + WARN("Unable to initialize SDL: %s", SDL_GetError()); + return -1; + } + + // FFUUUU Ugly cursor thing. + SDL_ShowCursor(SDL_DISABLE); + + flags |= SDL_FULLSCREEN* gl_screen.fullscreen; + depth = SDL_VideoModeOK(gl_screen.w, gl_screen.h, gl_screen.depth, flags); // Test set up. + if(depth != gl_screen.depth) + WARN("Depth: %d bpp unavailable, will use %d bpp", gl_screen.depth, depth); + + gl_screen.depth = depth; + + // Actually creating the screen. + if(SDL_SetVideoMode(gl_screen.w, gl_screen.h, gl_screen.depth, flags) == NULL) { + WARN("Unable to create OpenGL window: %s", SDL_GetError()); + SDL_Quit(); + return -1; + } + + // Grab some info. + SDL_GL_GetAttribute(SDL_GL_RED_SIZE, &gl_screen.r); + SDL_GL_GetAttribute(SDL_GL_GREEN_SIZE, &gl_screen.g); + SDL_GL_GetAttribute(SDL_GL_BLUE_SIZE, &gl_screen.b); + SDL_GL_GetAttribute(SDL_GL_ALPHA_SIZE, &gl_screen.a); + SDL_GL_GetAttribute(SDL_GL_DOUBLEBUFFER, &gl_screen.doublebuf); + gl_screen.depth = gl_screen.r + gl_screen.g + gl_screen.b + gl_screen.a; + + // Debug heaven. + DEBUG("OpenGL Window Created: %dx%d@%dbpp %s", gl_screen.w, gl_screen.h, gl_screen.depth, + gl_screen.fullscreen ? "fullscreen" : "window"); + DEBUG("r: %d, g: %d, b: %d, a: %d, doublebuffer: %s", gl_screen.r, gl_screen.g, gl_screen.b, gl_screen.a, + gl_screen.doublebuf ? "yes" : "no"); + DEBUG("Renderer: %s", glGetString(GL_RENDERER)); + + // Some openGL options. + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glDisable(GL_DEPTH_TEST); // Set for doing 2D shidazles. + glEnable(GL_TEXTURE_2D); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(-gl_screen.w/2, // Left edge. + gl_screen.w/2, // Right edge. + -gl_screen.h/2, // Bottom edge. + gl_screen.h/2, // Top edge. + -1.0f, // Near. + 1.0f); // Far. + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Alpha. + glEnable(GL_BLEND); + + glClear(GL_COLOR_BUFFER_BIT); + + SDL_WM_SetCaption(WINDOW_CAPTION, NULL); + + return 0; +} + +// Clean up our mess. +void gl_exit(void) { + SDL_ShowCursor(SDL_ENABLE); + SDL_Quit(); +} + diff --git a/src/opengl.h b/src/opengl.h new file mode 100644 index 0000000..0a86287 --- /dev/null +++ b/src/opengl.h @@ -0,0 +1,40 @@ +#pragma once +#include "SDL_opengl.h" +#include "physics.h" + +#define WINDOW_CAPTION "Lephisto" + +// Info about opengl screen. +typedef struct { + int w, h; // Window dimensions. + int depth; // Depth in bpp. + int fullscreen; // 1 = fullscreen, 0 = windowed. + int r, g, b, a; // Framebuffer values in bits. + int doublebuf; // Double buffer. +} gl_info; + +extern gl_info gl_screen; // Local structure set with gl_init etc. + +// Spritesheet info. +typedef struct { + FP w, h; // Real size of the image (excluding POT buffer. + FP rw, rh; // Size of POT surface. + FP sx, sy; // Number of sprites on x and y axes. + FP sw, sh; // Size of each sprite. + GLuint texture; // The opengl texture itself. +} gl_texture; + +// gl_texute loading/freeing. +gl_texture* gl_newImage(const char* path); +gl_texture* gl_newSprite(const char* path, const int sx, const int sy); +void gl_free(gl_texture* texture); + +// Rendering. +void gl_blitSprite(gl_texture* sprite, Vec2* pos, const int sx, const int sy); +void gl_blit(gl_texture* texture, Vec2* pos); +void gl_bindCamera(Vec2* pos); + +// Initialize/cleanup. +int gl_init(void); +void gl_exit(void); + diff --git a/src/physics.c b/src/physics.c new file mode 100644 index 0000000..1db4525 --- /dev/null +++ b/src/physics.c @@ -0,0 +1,134 @@ +#include +#include +#include + +#include "physics.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846f +#endif + +// Pretty efficient, no need for sine table!! +#define SIN(dir)(sinf(dir)) +#define COS(dir)(cosf(dir)) + +// ==Update method.======================================== +// d^2 x(t) / d t^2 = a, a = constant (acceleration) +// x'(0) = v, x(0) = p +// +// d x(t) / d t = a*t + v, v = constant (initial velocity) +// x(t) = a/2*t + v*t + p, p = constant (initial position) +// +// Since dt isn't actually differential this gives us an +// error, so watch out with big values for dt. +// ======================================================== + +static void simple_update(Solid* obj, const FP dt) { + if(obj->force) { + Vec2 acc; + acc.x = obj->force / obj->mass * COS(obj->dir); + acc.y = obj->force / obj->mass * SIN(obj->dir); + + obj->pos.x += acc.x * dt; + obj->vel.y += acc.y * dt; + + obj->pos.x += obj->vel.x * dt + 0.5 * acc.x / obj->mass * dt * dt; + obj->pos.y += obj->vel.y * dt + 0.5 * acc.y / obj->mass * dt * dt; + } else { + obj->pos.x += obj->vel.x * dt; + obj->pos.y += obj->vel.y * dt; + } +} + +// ==Runge-Kutta 4th method.=============================== +// d^2 x(t) / d t^2 = a, a = constant(acceleration) +// x'(0) = v, x(0) = p +// x'' = f(t, x, x') = (x', a) +// +// x_ {n+1} = x_n + h/6 (k1 + 2*k2 + 3*k3 + k4) +// h = (b-a)/2 +// k1 = f(t_n, X_n), X_n = (x_n, x'_n) +// k2 = f(t_n + h/2, X_n + h/2*k1) +// k3 = f(t_n + h/2, X_n + h/2*k2) +// k4 = f(t_n + h, X_n + h*k3) +// +// x_{n+1} = x_n + h/6x'_n + 3*h*a, 4*a) +// ======================================================== + +#define RK4_N 4 +static void rk4_update(Solid* obj, const FP dt) { + FP h = dt / RK4_N; // Step. + + if(obj->force) { // Force applied on object. + int i; + Vec2 initial, tmp; + + Vec2 acc; + acc.x = obj->force / obj->mass * COS(obj->dir); + acc.y = obj->force / obj->mass * SIN(obj->dir); + + for(i = 0; i < RK4_N; i++) { + // X component. + tmp.x = initial.x = obj->vel.x; + tmp.x += 2*initial.x + h*tmp.x; + tmp.x += 2*initial.x + h*tmp.x; + tmp.x += initial.x + h*tmp.x; + tmp.x *= h/6; + + obj->pos.x += tmp.x; + obj->vel.x += acc.x*h; + + // Y component. + tmp.y = initial.y = obj->vel.y; + tmp.y += 2*(initial.y + h/2*tmp.y); + tmp.y += 2*(initial.y + h/2*tmp.y); + tmp.y += initial.y + h*tmp.y; + tmp.y *= h/6; + + obj->pos.y += tmp.y; + obj->pos.y += acc.y*h; + } + } else { + obj->pos.x += dt*obj->vel.x; + obj->pos.y += dt*obj->vel.y; + } +} + +// Initialize a new solid. +void solid_init(Solid* dest, const FP mass, const Vec2* vel, const Vec2* pos) { + dest->mass = mass; + + dest->force = 0; + dest->dir = 0; + + if(vel == NULL) + dest->vel.x = dest->vel.y = 0.0; + else { + dest->vel.x = vel->x; + dest->vel.y = vel->y; + } + + if(pos == NULL) + dest->pos.x = dest->pos.y = 0.0; + else { + dest->pos.x = pos->x; + dest->pos.y = pos->y; + } + + dest->update = rk4_update; +} + +// Create a new solid. +Solid* solid_create(const FP mass, const Vec2* vel, const Vec2* pos) { + Solid* dyn = MALLOC_L(Solid); + assert(dyn != NULL); + solid_init(dyn, mass, vel, pos); + return dyn; +} + +// Free an existing solid. +void solid_free(Solid* src) { + free(src); + src = NULL; +} + diff --git a/src/physics.h b/src/physics.h new file mode 100644 index 0000000..5c6b34f --- /dev/null +++ b/src/physics.h @@ -0,0 +1,21 @@ +#pragma once +#include "def.h" + +// Base of 2D vectors. +typedef struct { + FP x, y; // Basic 2D vector components. +} Vec2; + +// Describe any solid in 2D space. +struct Solid { + FP mass, force, dir; // Properties. + Vec2 vel, pos; // Position/velocity vectors. + void(*update)(struct Solid*, const FP); // Update method. +}; + +typedef struct Solid Solid; + +void solid_init(Solid* dest, const FP mass, const Vec2* vel, const Vec2* pos); +Solid* solid_create(const FP mass, const Vec2* vel, const Vec2* pos); +void solid_free(Solid* src); + diff --git a/src/pilot.c b/src/pilot.c new file mode 100644 index 0000000..f4787ae --- /dev/null +++ b/src/pilot.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include "pilot.h" + +// Stack of pilot id's to assure uniqueness. +static unsigned int pilot_id = 0; + +static void pilot_update(Pilot* pilot, const FP dt); +static void pilot_render(Pilot* pilot); + +// Render the pilot. +static void pilot_render(Pilot* pilot) { + int sprite; + Vec2 pos; + gl_texture* texture = pilot->ship->gfx_ship; + + pos.x = pilot->solid->pos.x; + pos.y = pilot->solid->pos.y; + + // Get the sprite corresponding to the direction facing. + sprite = (int)(pilot->solid->dir / (2.0*M_PI / (texture->sy * texture->sx))); + + gl_blitSprite(texture, &pos, sprite % (int)texture->sx, sprite / (int)texture->sy); +} + +// Update the pilot. +static void pilot_update(Pilot* pilot, const FP dt) { + if(pilot->solid->dir > 2*M_PI) pilot->solid->dir -= 2*M_PI; + if(pilot->solid->dir < 0.0) pilot->solid->dir += 2*M_PI; + + // Update the solid. + pilot->solid->update(pilot->solid, dt); + + pilot_render(pilot); +} + +// ==Init pilot.=========================================== +// ship : Ship pilot is flying. +// name : Pilot's name, if NULL, ships name will be used. +// vel : Initial velocity. +// pos : Initial position. +// flags : Tweaking the pilot. +// ======================================================== +void pilot_init(Pilot* pilot, Ship* ship, char* name, const Vec2* vel, const Vec2* pos, const int flags) { + pilot->id = pilot_id++; // New unique pilot id based on pilot_id. + + pilot->ship = ship; + if(name == NULL) + pilot->name = ship->name; + else + pilot->name = name; + + pilot->solid = solid_create(ship->mass, vel, pos); + + pilot->armor = ship->armor; + pilot->shield = ship->shield; + pilot->energy = ship->energy; + + if(flags & PILOT_PLAYER) + pilot->think = NULL; // Players don't need to thing! :P + + pilot->update = pilot_update; +} + +// Create a new pilot - Params are same as pilot_init. +Pilot* pilot_create(Ship* ship, char* name, const Vec2* vel, const Vec2* pos, const int flags) { + Pilot* dyn = MALLOC_L(Pilot); + assert(dyn != NULL); + pilot_init(dyn, ship, name, vel, pos, flags); + return dyn; +} + +// Free the prisoned pilot! +void pilot_free(Pilot* pilot) { + solid_free(pilot->solid); + free(pilot); + pilot = NULL; +} + diff --git a/src/pilot.h b/src/pilot.h new file mode 100644 index 0000000..16c6a14 --- /dev/null +++ b/src/pilot.h @@ -0,0 +1,32 @@ +#pragma once +#include "def.h" +#include "physics.h" +#include "ship.h" + +#define PILOT_PLAYER 1 // Pilot is a player. + +struct Pilot { + int id; // Pilot's id. + char* name; // Pilot's name (if unique). + + Ship* ship; // Pilots ship. + Solid* solid; // Associated solid (physics). + + // Current health. + FP armor, shield, energy; + + void (*update)(struct Pilot*, const FP); // Update the pilot. + void (*think)(struct Pilot*); // AI thinking for the pilot. + + unsigned int flags; // Used for AI etc. +}; +typedef struct Pilot Pilot; + +void pilot_init(Pilot* dest, Ship* ship, char* name, + const Vec2* vel, const Vec2* pos, const int flags); + +Pilot* pilot_create(Ship* ship, char* name, const Vec2* vel, + const Vec2* pos, const int flags); + +void pilot_free(Pilot* src); + diff --git a/src/ship.c b/src/ship.c new file mode 100644 index 0000000..77e2920 --- /dev/null +++ b/src/ship.c @@ -0,0 +1,2 @@ +#include "ship.h" + diff --git a/src/ship.h b/src/ship.h new file mode 100644 index 0000000..ee3db4f --- /dev/null +++ b/src/ship.h @@ -0,0 +1,30 @@ +#pragma once +#include "def.h" +#include "opengl.h" + +enum ship_class { SHIP_CLASS_NULL, SHIP_CLASS_CIVILIAN }; +typedef enum ship_class ship_class; + +typedef struct { + char* name; // Ship name. + ship_class class; // Ship class. + + // Movement. + FP thrust, turn, speed; + + // Graphics. + gl_texture* gfx_ship, *gfx_target; + + // Characteristics. + int crew; + int mass; + + // Health. + FP armor, armor_regen; + FP shield, shield_regen; + FP energy, energy_regen; + + // Capacity. + int cap_cargo, cap_weapon; +} Ship; +