diff --git a/scripts/ai/test.lua b/scripts/ai/test.lua index 7b36389..5678824 100644 --- a/scripts/ai/test.lua +++ b/scripts/ai/test.lua @@ -11,9 +11,9 @@ function attack() target = 0 dir = face(target) dist = getdist(getpos(target)) - if dir < 10 and dist > 100 then + if dir < 10 and dist > 300 then accel() - elseif dir < 10 and dist < 100 then + elseif dir < 10 and dist < 300 then shoot() end end diff --git a/src/ai.c b/src/ai.c index 3e7642f..6b2feea 100644 --- a/src/ai.c +++ b/src/ai.c @@ -164,7 +164,11 @@ void ai_exit(void) { // Heart of hearts of the ai!! Brains of the pilot. void ai_think(Pilot* pilot) { cur_pilot = pilot; // Set current pilot being processed. - pilot_acc = pilot_turn = 0.; // Clean up some variables. + + // Clean up some variables. + pilot_acc = pilot_turn = 0.; + //pilot_primary = 0; + if(cur_pilot->task == NULL) // Idle git! AI_LCALL("control"); diff --git a/src/collision.c b/src/collision.c new file mode 100644 index 0000000..7fb6e5c --- /dev/null +++ b/src/collision.c @@ -0,0 +1,50 @@ +#include "main.h" +#include "log.h" +#include "collision.h" + +// Collide sprite at (asx, asy) int 'at' at pos 'ap' with sprite at (bsx,bsy) in 'bt' at 'bp' +// at - Texture a. +// asx - Position of x of sprite a. +// asy - Position of y of sprite a. +// ap - Position in space of sprite a. +// bt - Texture b. +// bsx - Position of x of sprite b. +// bsy - Position of y of sprite b. +// bp - Position in space of sprite b. +int CollideSprite(const gl_texture* at, const int asx, const int asy, const Vec2* ap, + const gl_texture* bt, const int bsx, const int bsy, const Vec2* bp) { + + int x,y; + + // a - cube coords. + int ax1 = (int)VX(*ap) - (int)(at->sw)/2; + int ay1 = (int)VY(*ap) - (int)(at->sh)/2; + int ax2 = ax1 + (int)(at->sw) - 1; + int ay2 = ay1 + (int)(at->sh) - 1; + + // b - cube coords. + int bx1 = (int)VX(*bp) - (int)(bt->sw)/2; + int by1 = (int)VY(*bp) - (int)(bt->sh)/2; + int bx2 = bx1 + (int)(bt->sw) - 1; + int by2 = by1 + (int)(bt->sh) - 1; + + // Check if bounding boxes intersect. + if((bx2 < ax1) || (ax2 < bx1)) return 0; + if((by2 < ay1) || (ay2 < by1)) return 0; + + // Define the remaining binding box. + int inter_x0 = MAX(ax1, bx1); + int inter_x1 = MIN(ax2, bx2); + int inter_y0 = MAX(ay1, by1); + int inter_y1 = MIN(ay2, by2); + + for(y = inter_y0; y <= inter_y1; y++) + for(x = inter_x0; x <= inter_x1; x++) + // Computer offsets for surface before passing to TransparentPixel test. + if((!gl_isTrans(at, asx*(int)(at->sw) + x-ax1, asy*(int)(at->sh) + y-ay1)) && + (!gl_isTrans(bt, bsx*(int)(bt->sw) + x-bx1, bsy*(int)(bt->sh) + y-by1))) + return 1; + + return 0; +} + diff --git a/src/collision.h b/src/collision.h new file mode 100644 index 0000000..1d9425b --- /dev/null +++ b/src/collision.h @@ -0,0 +1,7 @@ +#pragma once +#include "opengl.h" +#include "physics.h" + +int CollideSprite(const gl_texture* at, const int asx, const int asy, const Vec2* ap, + const gl_texture* bt, const int bsx, const int bsy, const Vec2* bp); + diff --git a/src/opengl.c b/src/opengl.c index 355f6d5..d7e053f 100644 --- a/src/opengl.c +++ b/src/opengl.c @@ -32,6 +32,8 @@ gl_font gl_defFont; // Misc. static int SDL_VFlipSurface(SDL_Surface* surface); +static int SDL_IsTrans(SDL_Surface* s, int x, int y); +static uint8_t* SDL_MapTrans(SDL_Surface* s); static int pot(int n); // gl_texture. static GLuint gl_loadSurface(SDL_Surface* surface, int* rw, int* rh); @@ -76,6 +78,57 @@ static int SDL_VFlipSurface(SDL_Surface* surface) { return 0; } +// Return true if position (x,y) of s is transparent. +static int SDL_IsTrans(SDL_Surface* s, int x, int y) { + int bpp = s->format->BytesPerPixel; + // p is the address to the pixel we want to retrieve. + Uint8* p = (Uint8*)s->pixels + y * s->pitch + x*bpp; + + Uint32 pixelcolor = 0; + + switch(bpp) { + case 1: + pixelcolor = *p; + break; + case 2: + pixelcolor = *(Uint16*)p; + break; + case 3: + if(SDL_BYTEORDER == SDL_BIG_ENDIAN) + pixelcolor = p[0] << 16 | p[1] << 8 | p[2]; + else + pixelcolor = p[0] | p[1] << 8 | p[2] << 16; + break; + case 4: + pixelcolor = *(Uint32*)p; + break; + } + // Test whetehr the pixels color is equal to color of + //transparent pixels for that surface. + return (pixelcolor == s->format->colorkey); +} + +// Map the surface transparancy. +// Return 0 on success. +static uint8_t* SDL_MapTrans(SDL_Surface* s) { + // Allocate memory for just enough bits to hold all the data we need. + int size = s->w*s->h/8 + ((s->w*s->h%8)?1:0); + uint8_t* t = malloc(size); + bzero(t, size); // *must* be set to zero. + + if(t == NULL) { + WARN("Out of memeory"); + return NULL; + } + + int i, j; + for(i = 0; i < s->h; i++) + for(j = 0; j < s->w; j++) // Set each bit to be 1 if not transparent or 0 if it is. + t[(i*s->w+j)/8] |= (SDL_IsTrans(s,j,i)) ? 0 : (1<<((i*s->w+j)%8)); + + return t; +} + // ================ // TEXTURE! // ================ @@ -187,12 +240,16 @@ gl_texture* gl_loadImage(SDL_Surface* surface) { texture->sw = texture->w; texture->sh = texture->h; + texture->trans = NULL; + return texture; } // Load the image directly as an opengl texture. gl_texture* gl_newImage(const char* path) { SDL_Surface* tmp, *surface; + gl_texture* t; + void* trans = NULL; uint32_t filesize; char* buf = pack_readfile(DATA, (char*)path, &filesize); if(buf == NULL) { @@ -216,11 +273,18 @@ gl_texture* gl_newImage(const char* path) { SDL_FreeSurface(tmp); // Free the temp surface. + SDL_LockSurface(surface); + trans = SDL_MapTrans(surface); + SDL_UnlockSurface(surface); + if(SDL_VFlipSurface(surface)) { WARN("Error flipping surface"); return NULL; } - return gl_loadImage(surface); + t = gl_loadImage(surface); + t->trans = trans; + + return t; } // Load the texture immediately, but also set is as a sprite. @@ -238,9 +302,26 @@ gl_texture* gl_newSprite(const char* path, const int sx, const int sy) { // Free the texture. void gl_freeTexture(gl_texture* texture) { glDeleteTextures(1, &texture->texture); + if(texture->trans) free(texture->trans); free(texture); } +// Return true if pixel at pos (x,y) is transparent. +int gl_isTrans(const gl_texture* t, const int x, const int y) { + return !(t->trans[(y*(int)(t->w)+x)/8] & (1<<((y*(int)(t->w)+x)%8))); +} + +// Set x and y to be the appropriate sprite for gl_texture using dir. +void gl_getSpriteFromDir(int* x, int* y, const gl_texture* t, const double dir) { + int s = (int)(dir / (2.0*M_PI / (t->sy*t->sx))); + + // Make sure the sprite is "in range". + if(s > (int)(t->sy*t->sx)-1) s = s % (int)(t->sy*t->sx); + + *x = s % (int)t->sx; + *y = s / (int)t->sy; +} + // ================ // BLITTING! // ================ diff --git a/src/opengl.h b/src/opengl.h index da45e6e..7981103 100644 --- a/src/opengl.h +++ b/src/opengl.h @@ -34,7 +34,8 @@ typedef struct { double rw, rh; // Size of POT surface. double sx, sy; // Number of sprites on x and y axes. double sw, sh; // Size of each sprite. - GLuint texture; // The opengl texture itself. + GLuint texture; // The opengl texture itself. + uint8_t* trans; // Maps the transparency. } gl_texture; // Font info. @@ -66,3 +67,7 @@ void gl_print(const gl_font* ft_font, const Vec2* pos, const char* fmt, ...); int gl_init(void); void gl_exit(void); +// Misc. +int gl_isTrans(const gl_texture* t, const int x, const int y); +void gl_getSpriteFromDir(int* x, int* y, const gl_texture* t, const double dir); + diff --git a/src/physics.c b/src/physics.c index e53ce8d..6b7ba13 100644 --- a/src/physics.c +++ b/src/physics.c @@ -57,6 +57,13 @@ double vect_angle(const Vec2* ref, const Vec2* v) { return ANGLE(VX(*v)-VX(*ref), VY(*v)-VY(*ref)); } +void vect_cadd(Vec2* v, const double x, const double y) { + v->x -= x; + v->y -= y; + v->mod = MOD(v->x, v->y); + v->angle = ANGLE(v->x, v->y); +} + // ================ // SOLID! diff --git a/src/physics.h b/src/physics.h index b95877d..9a2b109 100644 --- a/src/physics.h +++ b/src/physics.h @@ -28,6 +28,7 @@ void vect_pset(Vec2* v, const double mod, const double angle); void vectcpy(Vec2* dest, const Vec2* src); void vectnull(Vec2* v); double vect_angle(const Vec2* ref, const Vec2* v); +void vect_cadd(Vec2* v, const double x, const double y); // Describe any solid in 2D space. struct Solid { diff --git a/src/pilot.c b/src/pilot.c index e025219..c63c46e 100644 --- a/src/pilot.c +++ b/src/pilot.c @@ -120,16 +120,12 @@ void pilot_hit(Pilot* p, const double damage_shield, const double damage_armor) // Render the pilot. void pilot_render(Pilot* p) { - int sprite; - gl_texture* t = p->ship->gfx_space; + int sx, sy; // Get the sprite corresponding to the direction facing. - sprite = (int)(p->solid->dir / (2.0*M_PI / (t->sy * t->sx))); - - // Ugly hack to make sure it's always "inbound". - if(sprite > (int)(t->sy*t->sx)-1) sprite = (int)(t->sy*t->sx)-1; + gl_getSpriteFromDir(&sx, &sy, p->ship->gfx_space, p->solid->dir); - gl_blitSprite(t, &p->solid->pos, sprite % (int)t->sx, sprite / (int)t->sy); + gl_blitSprite(p->ship->gfx_space, &p->solid->pos, sx, sy); } // Update the pilot. diff --git a/src/space.c b/src/space.c index bf8077f..ae47341 100644 --- a/src/space.c +++ b/src/space.c @@ -196,6 +196,8 @@ static PlanetClass planetclass_get(const char a) { // Init the system. void space_init(const char* sysname) { int i, j; + Vec2 v, vn; + for(i = 0; i < nsystems; i++) if(strcmp(sysname, systems[i].name)==0) break; @@ -211,17 +213,22 @@ void space_init(const char* sysname) { stars[i].y = (double)RNG(-STAR_BUF, gl_screen.h + STAR_BUF); } // Set up fleets -> pilots. + vectnull(&vn); for(i = 0; i < cur_system->nfleets; i++) - if(RNG(0,100) <= cur_system->fleets[i].chance) // Check fleet. + if(RNG(0,100) <= cur_system->fleets[i].chance) {// Check fleet. + vect_pset(&v, 2*RNG(MIN_HYPERSPACE_DIST/2, MIN_HYPERSPACE_DIST), RNG(0, 360)*M_PI/180.); for(j = 0; j < cur_system->fleets[i].fleet->npilots; j++) - if(RNG(0,100) <= cur_system->fleets[i].fleet->pilots[j].chance) + if(RNG(0,100) <= cur_system->fleets[i].fleet->pilots[j].chance) { + vect_cadd(&v, RNG(-50, 50), RNG(-50, 50)); pilot_create(cur_system->fleets[i].fleet->pilots[j].ship, cur_system->fleets[i].fleet->pilots[j].name, cur_system->fleets[i].fleet->faction, - RNG(0,360), - NULL, + vect_angle(&v,&vn), + &v, NULL, 0); + } + } } // Load the planets of name 'name'. diff --git a/src/space.h b/src/space.h index d4f77e9..6d18bd3 100644 --- a/src/space.h +++ b/src/space.h @@ -1,5 +1,7 @@ #pragma once +#define MIN_HYPERSPACE_DIST 1500 + // Load/Exit. void space_init(const char* sysname); int space_load(void); diff --git a/src/weapon.c b/src/weapon.c index ed497d3..8cb34bb 100644 --- a/src/weapon.c +++ b/src/weapon.c @@ -8,6 +8,7 @@ #include "log.h" #include "rng.h" #include "pilot.h" +#include "collision.h" #include "weapon.h" // Some stuff from pilot. @@ -102,23 +103,27 @@ void weapons_update(const double dt, WeaponLayer layer) { // Render the weapons. static void weapon_render(const Weapon* w) { - int sprite; - gl_texture* t = w->outfit->gfx_space; + int sx, sy; // Get the sprite corresponding to the direction facing. - sprite = (int)(w->solid->dir / (2.0*M_PI / (t->sy*t->sx))); + gl_getSpriteFromDir(&sx, &sy, w->outfit->gfx_space, w->solid->dir); - gl_blitSprite(t, &w->solid->pos, sprite % (int)t->sx, sprite / (int)t->sy); + gl_blitSprite(w->outfit->gfx_space, &w->solid->pos, sx, sy); } // Update the weapon. static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) { - int i; + int i, wsx, wsy, psx, psy; + gl_getSpriteFromDir(&wsx, &wsy, w->outfit->gfx_space, w->solid->dir); + for(i = 0; i < pilots; i++) { + gl_getSpriteFromDir(&psx, &psy, pilot_stack[i]->ship->gfx_space, + pilot_stack[i]->solid->dir); + if((w->parent != pilot_stack[i]->id) && // The pilot hasn't shoot it. !areAllies(pilot_get(w->parent)->faction, pilot_stack[i]->faction) && - (DIST(w->solid->pos, pilot_stack[i]->solid->pos) < (PILOT_SIZE_APROX * - w->outfit->gfx_space->sw/2. + pilot_stack[i]->ship->gfx_space->sw/2.))) { + CollideSprite(w->outfit->gfx_space, wsx, wsy, &w->solid->pos, + pilot_stack[i]->ship->gfx_space, psx, psy, &pilot_stack[i]->solid->pos)) { pilot_hit(pilot_stack[i], w->outfit->damage_shield, w->outfit->damage_armor); weapon_destroy(w, layer); return;