static int sun_mixer_set_volume(int l, int r) { struct mixer_ctrl minf; int ovall, ovalr; if (sun_mixer_get_volume(&ovall, &ovalr) == -1) return -1; /* OpenBSD mixer values are `discrete' */ l = min_delta(ovall, l, sun_mixer_volume_delta); r = min_delta(ovalr, r, sun_mixer_volume_delta); minf.type = AUDIO_MIXER_VALUE; minf.dev = sun_mixer_device_id; if (sun_mixer_channels == 1) minf.un.value.level[AUDIO_MIXER_LEVEL_MONO] = l; else { minf.un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l; minf.un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r; } minf.un.value.num_channels = sun_mixer_channels; if (ioctl(mixer_fd, AUDIO_MIXER_WRITE, &minf) == -1) return -1; return 0; }
int TauFiend::handle_damage(SpaceLocation *source, int normal, int direct) { STACKTRACE; double alpha; if (source->isLine()) { Vector2 dpos = min_delta(source->normal_pos() + ((SpaceLine*)source)->edge(), map_size); //double dx = min_delta(source->normal_x() + ((SpaceLine*)source)->edge_x(), normal_x(), X_MAX); //double dy = min_delta(source->normal_y() + ((SpaceLine*)source)->edge_y(), normal_y(), Y_MAX); //alpha = fabs(normalize(atan3(dy, dx) * 180 / PI - angle, 360)); alpha = fabs(normalize(dpos.atan() - angle, PI2)); } else alpha = normalize(trajectory_angle(source) - angle, 360); if (alpha > 180) alpha -= 360; alpha = (90 - fabs(alpha)) / 90; alpha *= alpha; alpha *= alpha; alpha = normal * (alpha + (1-alpha)*(tw_random(1.0)) ); int d = normal; normal = (int)floor(alpha); if (alpha - normal >= 0.5) normal ++; d -= normal; if (d > 0) play_sound(data->sampleExtra[random(8)]); return Ship::handle_damage(source, normal, direct); }
double TauMCMissile::get_aim(SpaceObject *tgt) { STACKTRACE; Vector2 tv = tgt->get_vel(); //double tvy = tgt->get_vy(); //double rx = min_delta(tgt->normal_x(), normal_x(), X_MAX); //double ry = min_delta(tgt->normal_y(), normal_y(), Y_MAX); Vector2 r = min_delta(tgt->normal_pos(), normal_pos()); //rx*rx + ry*ry; double r2 = magnitude_sqr(r); double u2 = v * v; //(tvx*tvx + tvy*tvy); double d2v = u2 - magnitude_sqr(tv); double t = r.dot(tv); //(rx*tvx + ry*tvy); double q, p; if (fabs(d2v/u2) > 0.01 ) { q = t*t + r2*d2v; if (q > 0) q = sqrt(q); else return (1e10); p = (t+q)/d2v; q = (t-q)/d2v; if (p > 0) t = p; else t = q; if (t < 0) return (1e10); } else { if (fabs(t)<1e-6) return (1e10); else t = - 0.5 * r2 / t; if (t < 0) return (1e10); } t = normalize(atan3(tv.y*t + r.y, tv.x*t + r.x) - angle, PI2); if (t > PI) t -= PI2; return (t); }
int Hook2::handle_damage(SpaceLocation *src, double normal, double direct) { STACKTRACE; if ( src == hooktarget ) return 0; if ( src->isShip() || (bHitAsteroids && src->isAsteroid())) { if ( hooktarget ) // if it's already attached to another ship return 0; if ( src == ship ) return 0; // if it is the ship itself (doh) hooktarget = src; game->play_sound(data->sampleSpecial[1],this); hookfixdist = magnitude(min_delta(pos, src->pos, map_size)); hookfixorientation = atan(min_delta(pos, src->pos, map_size)) - src->angle; hookfixangle = angle - src->angle; collide_flag_anyone = 0; collide_flag_sameteam = 0; collide_flag_sameship = 0; hooklocked = 1; // stop unrolling any further if (src->isShip()) { src->ship->turn_rate *= 0.80; damage(src, 1.0, 0.0); } return 0; } else { SpaceObject::handle_damage(src, normal, direct); armour -= normal + direct; if ( armour <= 0 ) state = 0; return iround(normal + direct); } }
void Hook2::animate_ropeseg( Frame *space, Vector2 pos1, Vector2 pos2, int ropecol ) { STACKTRACE; int ix1, iy1, ix2, iy2; Vector2 co; co = corner(pos1); ix1 = int(co.x); iy1 = int(co.y); co = corner(pos2); ix2 = int(co.x); iy2 = int(co.y); int dx, dy; dx = iround(min_delta(ix2, ix1, map_size.x)); dy = iround(min_delta(iy2, iy1, map_size.y)); ix2 = ix1 + dx; iy2 = iy1 + dy; // simulate visibility of a glittering line in the sun ... double a, colscale; a = atan2((float)dy,(float)dx); colscale = fabs(sin(a)); // flat lying = less visible. int col, r, g, b; col = ropecol; r = iround(getr(col) * colscale); g = iround(getg(col) * colscale); b = iround(getb(col) * colscale); col = makecol(r, g, b); // draw the line line(space->surface, ix1, iy1, ix2, iy2, col); space->add_line(ix1, iy1, ix2, iy2); }
double VelronCruiser::get_aim(SpaceObject *tgt, double min_angle, double max_angle) { STACKTRACE; if (tgt == NULL) return (-1000); Vector2 tv = tgt->get_vel() - specialRelativity * vel; double tvx = tv.x; double tvy = tv.y; tv = min_delta(tgt->normal_pos(), pos); double rx = tv.x; double ry = tv.y; double r2 = rx*rx + ry*ry; double u2 = specialVelocity; u2 *= u2; double d2v = u2 - (tvx*tvx + tvy*tvy); double t = (rx*tvx + ry*tvy); double q, p; if (fabs(d2v/u2) > 0.01 ) { q = t*t + r2*d2v; if (q > 0) q = sqrt(q); else return (-1000); p = (t+q)/d2v; q = (t-q)/d2v; if (p > 0) t = p; else t = q; if (t < 0) return (-1000); } else { if (fabs(t)<1e-6) return (-1000); else t = - 0.5 * r2 / t; if (t < 0) return (-1000); } if (t * specialVelocity > specialRange) return(-1000); t = normalize((atan3(tvy*t + ry, tvx*t + rx)) - angle, PI2); double d_a = normalize(t - min_angle, PI2); if (d_a > PI) d_a -= PI2; if (d_a > 0) { d_a = normalize(t - max_angle, PI2); if (d_a > PI) d_a -= PI2; if (d_a < 0) return (t); } return (-1000); }
// an exact copy, with a small modification: it also return a boolean value int ShipPart::collide_SpaceObject(SpaceObject *other) { STACKTRACE; // double dx, dy; // double dvx, dvy; double tmp; // int x1, y1; // int x2, y2; if (this == other) {tw_error("SpaceObject::collide - self!");} if ((!canCollide(other)) || (!other->canCollide(this))) return 0; if (!exists() || !other->exists()) return 0; pos = normal_pos(); Vector2 p1, p2, dp, dv; p1 = pos; p2 = other->normal_pos(); dp.x = min_delta(p1.x, p2.x, map_size.x); dp.y = min_delta(p1.y, p2.y, map_size.y); p2 = p1 - dp - other->size / 2; p1 = p1 - size / 2; /* x1 = (int)(normal_x() - (w / 2.0)); y1 = (int)(normal_y() - (h / 2.0)); dx = min_delta(normal_x(), other->normal_x(), map_size.x); dy = min_delta(normal_y(), other->normal_y(), Y_MAX); x2 = (int)(normal_x() - dx - ((other->w) / 2.0)); y2 = (int)(normal_y() - dy - ((other->h) / 2.0));*/ if (!sprite->collide(iround(p1.x), iround(p1.y), sprite_index, iround(p2.x), iround(p2.y), other->get_sprite_index(), other->get_sprite() )) return 0; //sprite->collide(x1, y1, sprite_index, x2, y2, other->sprite_index, other->sprite); inflict_damage(other); other->inflict_damage(this); if (!mass || !other->mass) return 0; dv = vel - other->vel; p1 = pos; p2 = other->normal_pos(); dp.x = min_delta(p1.x, p2.x, map_size.x); dp.y = min_delta(p1.y, p2.y, map_size.y); p2 = p1 - dp - other->size / 2; p1 = p1 - size / 2; /*x1 = (int)(normal_x() - (w / 2.0)); y1 = (int)(normal_y() - (h / 2.0)); dx = min_delta(normal_x(), other->normal_x(), map_size.x); dy = min_delta(normal_y(), other->normal_y(), Y_MAX); x2 = (int)(normal_x() - dx - ((other->w) / 2.0)); y2 = (int)(normal_y() - dy - ((other->h) / 2.0));*/ while ((dp.x == 0) && (dp.y == 0)) { dp.x = (tw_random(5) - 2) / 99.0; dp.y = (tw_random(5) - 2) / 99.0; } Vector2 _dp = unit_vector(dp); tmp = dot_product(dv, _dp); tmp = ( -2 * tmp ); if (mass + other->mass > 1) tmp = tmp * (mass * other->mass) / (mass + other->mass); if (tmp >= 0) { if (mass > 1) vel += _dp * tmp / mass; if (other->mass > 1) other->change_vel (- _dp * tmp / other->mass ); } Vector2 nd; nd = unit_vector(dp); if (mass + other->mass > 1) nd /= (mass + other->mass); while (sprite->collide(iround(p1.x), iround(p1.y), sprite_index, iround(p2.x), iround(p2.y), other->get_sprite_index(), other->get_sprite() )) { pos = normalize(pos + nd * other->mass); other->pos = normalize(other->pos - nd * mass); p1 = pos; p2 = other->normal_pos(); dp.x = min_delta(p1.x, p2.x, map_size.x); dp.y = min_delta(p1.y, p2.y, map_size.y); p2 = p1 - dp - other->size / 2; p1 = p1 - size / 2; } #ifdef _DEBUG SpaceObject *c1 = this; SpaceObject *c2 = other; if (fabs(c1->vel.x) > 1E6 || fabs(c1->vel.y) > 1E6 || fabs(c2->vel.x) > 1E6 || fabs(c2->vel.y) > 1E6 ) { int a1 = c1->canCollide(c2); int a2 = c2->canCollide(c1); bool b = ((c1->canCollide(c2) & c2->canCollide(c1)) == 0 ); tw_error("velocity error in collision involving objects [%s] and [%s]", c1->get_identity(), c2->get_identity()); } #endif return 1; }
void Hook2::calculate() { STACKTRACE; exist_time += frame_time * 1E-3; if ( exist_time > life_time ) state = 0; // if it's completely unrolled ... if ( hooklocked && Nnodes <= 0 ) state = 0; // or if the host ship has gone if ( !(ship && ship->exists()) ) { ship = 0; state = 0; } if ( hooktarget && hooktarget->exists() ) { vel = hooktarget->vel; angle = hooktarget->angle + hookfixangle; sprite_index = get_index(angle); pos = hooktarget->pos + hookfixdist * unit_vector(hooktarget->angle + hookfixorientation); } else if (hooklocked) { state = 0; hooktarget = 0; } if ( state == 0 ) return; SpaceObject::calculate(); if ( !hooklocked) roll_time += frame_time * 1E-3; else // otherwise it keeps pumping energy into the line roll_time = 0.0; Vector2 hookendpos; hookendpos = pos - hooksize * unit_vector(angle); Vector2 ejpos; if (ship && ship->exists() ) { ejpos = ship->pos + ropestart * unit_vector(ship->angle) + 15 * sin(oscperiod*roll_time) * unit_vector(ship->angle + 0.5*PI); } else ejpos = 0; if (ship && ship->exists() && !hooklocked ) { // extend the elastic rope slowly double dL; if ( Nnodes > 0 ) dL = magnitude(min_delta(ropenode[Nnodes-1].pos, ejpos, map_size)); else dL = magnitude(min_delta(hookendpos, ejpos, map_size)); if ( dL > ropeseglen && Nnodes < maxnodes ) { ropenode[Nnodes].pos = ejpos; // *1E+3 because from now we do calculations in seconds instead of ms. ropenode[Nnodes].vel = (ship->vel + ejvel * unit_vector(ship->angle)) * 1E+3; // changes color every 4 pieces ? ropenode[Nnodes].col = pallete_color[11 + (Nnodes/4) % 3]; dL = ropeseglen; // relaxed length of the segment between nodes i and i-1. ropenode[Nnodes].dL = dL; ++ Nnodes; if ( Nnodes == maxnodes ) state = 0; // no target found ... poor thing ;) } } // calculate the nodes on the elastic rope (except the end-points, which are fixed: double k = springconst; // 250.0 int i; Vector2 D; double R; // ropenode[0].acc = ..; // ropenode[Nnodes-1].acc = ..; int Ninterpol, iinterpol; // this may be needed if values of the spring constant are high Ninterpol = 10; double dt = frame_time * 1E-3 / Ninterpol; for ( iinterpol = 0; iinterpol < Ninterpol; ++iinterpol ) { // reset forces for ( i = 0; i < Nnodes; ++i ) ropenode[i].acc = 0; // forces between rope nodes for ( i = 0; i < Nnodes; ++i ) { if ( i > 0 ) { D = min_delta(ropenode[i-1].pos - ropenode[i].pos, map_size); R = D.length(); L = ropenode[i].dL; if ( R != 0 ) ropenode[i].acc += k * (R - L) * D / R; } if ( i < Nnodes-1 ) { D = min_delta(ropenode[i+1].pos - ropenode[i].pos, map_size); R = D.length(); L = ropenode[i+1].dL; if ( R != 0 ) ropenode[i].acc += k * (R - L) * D / R; } } // attached to the hook Vector2 hookacc; hookacc = 0; if ( Nnodes > 0 ) { i = 0; D = min_delta(hookendpos - ropenode[i].pos, map_size); R = D.length(); L = ropenode[i].dL; hookacc = k * (R - L) * D / R; if ( R != 0 ) ropenode[i].acc += hookacc; } // attached to the ship, if it still exists... if ( ship && ship->exists() && Nnodes > 0 ) { i = Nnodes-1; D = min_delta(ejpos - ropenode[i].pos, map_size); R = D.length(); L = ropeseglen; // should be i+1, but that doesn't exist if ( R != 0 ) ropenode[i].acc += k * (R - L) * D / R;; } // slow down a little, for stability for ( i = 0; i < Nnodes; ++i ) ropenode[i].acc -= 10.0 * ropenode[i].vel * dt; // apply accelerations (also to the end points) for ( i = 0; i < Nnodes; ++i ) { ropenode[i].vel += ropenode[i].acc * dt; ropenode[i].pos += ropenode[i].vel * dt; } // apply acceleration to the target: if ( hooktarget && hooktarget->exists() ) { hooktarget->vel -= 0.1 * 1E-3 * hookacc * dt; // and also some deceleration ... double a = 1 - 0.1*dt; if ( a < 0 ) a = 0; if ( a > 1 ) a = 1; hooktarget->vel *= a; // influence the angle of the enemy ship: a = atan(hookendpos - hooktarget->pos); double b, da, rotacc; b = atan(hookacc); da = b - a; rotacc = magnitude(hookacc) * sin(da); hooktarget->angle -= 0.25 * 1E-3 * rotacc * dt; // angle must never exceed half PI with the end of the rope... b = atan(ropenode[0].pos - hookendpos); da = b - a; while ( da > PI ) da -= PI2; while ( da < -PI ) da += PI2; if ( da < -0.5*PI || da > 0.5*PI ) { double dacorr = fabs(da) - 0.5*PI; if ( dacorr > 5*PI2*dt ) dacorr = 5*PI2*dt; if ( da < 0.0 ) hooktarget->angle -= dacorr; else hooktarget->angle += dacorr; } // to stabilize, make sure neither vessels' speed ever exceeds the maximum: double V1, V2; if ( ship && ship->exists() ) { V1 = magnitude(ship->vel); V2 = 2 * ship->speed_max; if ( V1 > V2 ) ship->vel *= V2 / V1; } if ( hooktarget->isShip() ) { V1 = magnitude(hooktarget->vel); V2 = 2 * ((Ship*) hooktarget)->speed_max; if ( V1 > V2 ) hooktarget->vel *= V2 / V1; } } } }
// an exact copy, with a small modification: it also return a boolean value int ShipPart2::collide_SpaceObject(SpaceObject *other) { STACKTRACE; // double dx, dy; // double dvx, dvy; double tmp; // int x1, y1; // int x2, y2; if (this == other) { tw_error("SpaceObject::collide - self!"); } if ((!canCollide(other)) || (!other->canCollide(this))) return 0; if (!exists() || !other->exists()) return 0; pos = normal_pos(); Vector2 p1, p2, dp, dv; p1 = pos; p2 = other->normal_pos(); dp.x = min_delta(p1.x, p2.x, map_size.x); dp.y = min_delta(p1.y, p2.y, map_size.y); p2 = p1 - dp - other->size / 2; p1 = p1 - size / 2; /* x1 = (int)(normal_x() - (w / 2.0)); y1 = (int)(normal_y() - (h / 2.0)); dx = min_delta(normal_x(), other->normal_x(), map_size.x); dy = min_delta(normal_y(), other->normal_y(), Y_MAX); x2 = (int)(normal_x() - dx - ((other->w) / 2.0)); y2 = (int)(normal_y() - dy - ((other->h) / 2.0));*/ if (!sprite->collide(iround(p1.x), iround(p1.y), sprite_index, iround(p2.x), iround(p2.y), other->get_sprite_index(), other->get_sprite() )) return 0; //sprite->collide(x1, y1, sprite_index, x2, y2, other->sprite_index, other->sprite); inflict_damage(other); other->inflict_damage(this); if (!mass || !other->mass) return 0; dv = vel - other->vel; p1 = pos; p2 = other->normal_pos(); dp.x = min_delta(p1.x, p2.x, map_size.x); dp.y = min_delta(p1.y, p2.y, map_size.y); p2 = p1 - dp - other->size / 2; p1 = p1 - size / 2; /*x1 = (int)(normal_x() - (w / 2.0)); y1 = (int)(normal_y() - (h / 2.0)); dx = min_delta(normal_x(), other->normal_x(), map_size.x); dy = min_delta(normal_y(), other->normal_y(), Y_MAX); x2 = (int)(normal_x() - dx - ((other->w) / 2.0)); y2 = (int)(normal_y() - dy - ((other->h) / 2.0));*/ while ((dp.x == 0) && (dp.y == 0)) { dp.x = (tw_random(5) - 2) / 99.0; dp.y = (tw_random(5) - 2) / 99.0; } Vector2 _dp = unit_vector(dp); tmp = dot_product(dv, _dp); tmp = ( -2 * tmp ); tmp = tmp * (mass * other->mass) / (mass + other->mass); if (tmp >= 0) { vel += _dp * tmp / mass; other->vel -= _dp * tmp / other->mass; } Vector2 nd; nd = unit_vector(dp); nd /= (mass + other->mass); while (sprite->collide(iround(p1.x), iround(p1.y), sprite_index, iround(p2.x), iround(p2.y), other->get_sprite_index(), other->get_sprite() )) { pos = normalize(pos + nd * other->mass); other->pos = normalize(other->pos - nd * mass); p1 = pos; p2 = other->normal_pos(); dp.x = min_delta(p1.x, p2.x, map_size.x); dp.y = min_delta(p1.y, p2.y, map_size.y); p2 = p1 - dp - other->size / 2; p1 = p1 - size / 2; } return 1; }