/** * @brief Frees the outfit stack. */ void outfit_free (void) { int i; Outfit *o; for (i=0; i < outfit_nstack; i++) { o = &outfit_stack[i]; /* free graphics */ if (outfit_gfx(&outfit_stack[i])) gl_freeTexture(outfit_gfx(&outfit_stack[i])); /* Type specific. */ if (outfit_isLauncher(o) && o->u.lau.ammo_name) free(o->u.lau.ammo_name); if (outfit_isFighterBay(o) && o->u.bay.ammo_name) free(o->u.bay.ammo_name); if (outfit_isFighter(o) && o->u.fig.ship) free(o->u.fig.ship); /* strings */ if (o->description) free(o->description); if (o->gfx_store) gl_freeTexture(o->gfx_store); if (o->license) free(o->license); free(o->name); } free(outfit_stack); }
/** * @brief Updates an individual weapon. * * @param w Weapon to update. * @param dt Current delta tick. * @param layer Layer to which the weapon belongs. */ static void weapon_update( Weapon* w, const double dt, WeaponLayer layer ) { int i, psx,psy; glTexture *gfx; Vector2d crash[2]; Pilot *p; /* Get the sprite direction to speed up calculations. */ if (!outfit_isBeam(w->outfit)) { gfx = outfit_gfx(w->outfit); gl_getSpriteFromDir( &w->sx, &w->sy, gfx, w->solid->dir ); } for (i=0; i<pilot_nstack; i++) { p = pilot_stack[i]; psx = pilot_stack[i]->tsx; psy = pilot_stack[i]->tsy; if (w->parent == pilot_stack[i]->id) continue; /* pilot is self */ /* Beam weapons have special collisions. */ if (outfit_isBeam(w->outfit)) { /* Check for collision. */ if (weapon_checkCanHit(w,p) && CollideLineSprite( &w->solid->pos, w->solid->dir, w->outfit->u.bem.range, p->ship->gfx_space, psx, psy, &p->solid->pos, crash)) { weapon_hitBeam( w, p, layer, crash, dt ); /* No return because beam can still think, it's not * destroyed like the other weapons.*/ } } /* smart weapons only collide with their target */ else if (weapon_isSmart(w)) { if ((pilot_stack[i]->id == w->target) && (w->status != WEAPON_STATUS_OK) && /* Must not be locking on. */ weapon_checkCanHit(w,p) && CollideSprite( gfx, w->sx, w->sy, &w->solid->pos, p->ship->gfx_space, psx, psy, &p->solid->pos, &crash[0] )) { weapon_hit( w, p, layer, &crash[0] ); return; /* Weapon is destroyed. */ } } /* dumb weapons hit anything not of the same faction */ else { if (weapon_checkCanHit(w,p) && CollideSprite( gfx, w->sx, w->sy, &w->solid->pos, p->ship->gfx_space, psx, psy, &p->solid->pos, &crash[0] )) { weapon_hit( w, p, layer, &crash[0] ); return; /* Weapon is destroyed. */ } } } /* smart weapons also get to think their next move */ if (weapon_isSmart(w)) (*w->think)(w,dt); /* Update the solid position. */ (*w->solid->update)(w->solid, dt); /* Update the sound. */ sound_updatePos(w->voice, w->solid->pos.x, w->solid->pos.y, w->solid->vel.x, w->solid->vel.y); }
/** * @brief Renders an individual weapon. * * @param w Weapon to render. * @param dt Current delta tick. */ static void weapon_render( Weapon* w, const double dt ) { double x,y, cx,cy, gx,gy; glTexture *gfx; double z; glColour c = { .r=1., .g=1., .b=1. }; switch (w->outfit->type) { /* Weapons that use sprites. */ case OUTFIT_TYPE_AMMO: case OUTFIT_TYPE_TURRET_AMMO: case OUTFIT_TYPE_BOLT: case OUTFIT_TYPE_TURRET_BOLT: gfx = outfit_gfx(w->outfit); /* Alpha based on strength. */ c.a = w->strength; /* Outfit spins around. */ if (outfit_isProp(w->outfit, OUTFIT_PROP_WEAP_SPIN)) { /* Check timer. */ w->anim -= dt; if (w->anim < 0.) { w->anim = outfit_spin(w->outfit); /* Increment sprite. */ w->sprite++; if (w->sprite >= gfx->sx*gfx->sy) w->sprite = 0; } /* Render. */ if (outfit_isBolt(w->outfit) && w->outfit->u.blt.gfx_end) gl_blitSpriteInterpolate( gfx, w->outfit->u.blt.gfx_end, w->timer / w->life, w->solid->pos.x, w->solid->pos.y, w->sprite % (int)gfx->sx, w->sprite / (int)gfx->sx, &c ); else gl_blitSprite( gfx, w->solid->pos.x, w->solid->pos.y, w->sprite % (int)gfx->sx, w->sprite / (int)gfx->sx, &c ); } /* Outfit faces direction. */ else { if (outfit_isBolt(w->outfit) && w->outfit->u.blt.gfx_end) gl_blitSpriteInterpolate( gfx, w->outfit->u.blt.gfx_end, w->timer / w->life, w->solid->pos.x, w->solid->pos.y, w->sx, w->sy, &c ); else gl_blitSprite( gfx, w->solid->pos.x, w->solid->pos.y, w->sx, w->sy, &c ); } break; /* Beam weapons. */ case OUTFIT_TYPE_BEAM: case OUTFIT_TYPE_TURRET_BEAM: gfx = outfit_gfx(w->outfit); /* Zoom. */ gl_cameraZoomGet( &z ); /* Position. */ gl_cameraGet( &cx, &cy ); gui_getOffset( &gx, &gy ); x = (w->solid->pos.x - cx)*z + gx; y = (w->solid->pos.y - cy)*z + gy; /* Set up the matrix. */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glTranslated( x, y, 0. ); glRotated( 270. + w->solid->dir / M_PI * 180., 0., 0., 1. ); /* Preparatives. */ glEnable(GL_TEXTURE_2D); glBindTexture( GL_TEXTURE_2D, gfx->texture); glShadeModel(GL_SMOOTH); /* Actual rendering. */ glBegin(GL_QUAD_STRIP); /* Start faded. */ ACOLOUR(cWhite, 0.); glTexCoord2d( w->anim, 0. ); glVertex2d( -gfx->sh/2.*z, 0. ); glTexCoord2d( w->anim, 1. ); glVertex2d( +gfx->sh/2.*z, 0. ); /* Full strength. */ COLOUR(cWhite); glTexCoord2d( w->anim + 10. / gfx->sw, 0. ); glVertex2d( -gfx->sh/2.*z, 10.*z ); glTexCoord2d( w->anim + 10. / gfx->sw, 1. ); glVertex2d( +gfx->sh/2.*z, 10.*z ); glTexCoord2d( w->anim + 0.8*w->outfit->u.bem.range / gfx->sw, 0. ); glVertex2d( -gfx->sh/2.*z, 0.8*w->outfit->u.bem.range*z ); glTexCoord2d( w->anim + 0.8*w->outfit->u.bem.range / gfx->sw, 1. ); glVertex2d( +gfx->sh/2.*z, 0.8*w->outfit->u.bem.range*z ); /* Fades out. */ ACOLOUR(cWhite, 0.); glTexCoord2d( w->anim + w->outfit->u.bem.range / gfx->sw, 0. ); glVertex2d( -gfx->sh/2.*z, w->outfit->u.bem.range*z ); glTexCoord2d( w->anim + w->outfit->u.bem.range / gfx->sw, 1. ); glVertex2d( +gfx->sh/2.*z, w->outfit->u.bem.range*z ); glEnd(); /* GL_QUAD_STRIP */ /* Do the beam movement. */ w->anim -= 5. * dt; if (w->anim <= -gfx->sw) w->anim += gfx->sw; /* Clean up. */ glDisable(GL_TEXTURE_2D); glShadeModel(GL_FLAT); glPopMatrix(); /* GL_PROJECTION */ gl_checkErr(); break; default: WARN("Weapon of type '%s' has no render implemented yet!", w->outfit->name); break; } } /** * @brief Checks to see if the weapon can hit the pilot. * * @param w Weapon to check if hits pilot. * @param p Pilot to check if is hit by weapon. * @return 1 if can be hit, 0 if can't. */ static int weapon_checkCanHit( Weapon* w, Pilot *p ) { Pilot *parent; /* Can't hit invincible stuff. */ if (pilot_isFlag(p, PILOT_INVINCIBLE)) return 0; /* Can never hit same faction. */ if (p->faction == w->faction) return 0; /* Go "through" dead pilots. */ if (pilot_isFlag(p, PILOT_DEAD)) return 0; /* Player behaves differently. */ if (w->faction == FACTION_PLAYER) { /* Always hit without safety. */ if (!weapon_safety) return 1; /* Always hit target. */ else if (w->target == p->id) return 1; /* Always hit hostiles. */ else if (pilot_isFlag(p, PILOT_HOSTILE)) return 1; /* Always hit unbribed enemies. */ else if (!pilot_isFlag(p, PILOT_BRIBED) && areEnemies(w->faction, p->faction)) return 1; /* Miss rest - can be neutral/ally. */ else return 0; } /* Let hostiles hit player. */ if (p->faction == FACTION_PLAYER) { parent = pilot_get(w->parent); if (parent != NULL) { if (pilot_isFlag(parent, PILOT_BRIBED)) return 0; if (pilot_isFlag(parent, PILOT_HOSTILE)) return 1; } } /* Hit non-allies. */ if (areEnemies(w->faction, p->faction)) return 1; return 0; }