/* * Given a 'brush' that's pushing things out of the way (possibly already * cut down to just the part relevant to our line) and a line that * intersects it on some layer, find the 45/90 lines required to go around * the brush on the named side. Create them and remove the original. */ static int MakeBypassingLines(POLYAREA *brush, LayerType *layer, LineType *line, int side, POLYAREA **expandp) { Vector pA, pB, flatA, flatB, qA, qB; Vector lA, lB; Vector a, b, c, d, junk; int hits; SET_FLAG(DRCFLAG, line); /* will cause sublines to inherit */ lA[0] = line->Point1.X; lA[1] = line->Point1.Y; lB[0] = line->Point2.X; lB[1] = line->Point2.Y; /* * Imagine side = north: * * / \ * ----b##FLAT##c---- * Q P * lA-ORIG####a d####ORIG-lB * / \ * * First find the extended three lines that go around the brush. * Then intersect them with each other and the original to find * points a, b, c, d. Finally connect the dots and remove the * old straight line. */ POLYAREA_findXmostLine(brush, side, flatA, flatB, line->Thickness / 2); POLYAREA_findXmostLine(brush, rotateSide(side, 1), pA, pB, line->Thickness / 2); POLYAREA_findXmostLine(brush, rotateSide(side, -1), qA, qB, line->Thickness / 2); hits = vect_inters2(lA, lB, qA, qB, a, junk) + vect_inters2(qA, qB, flatA, flatB, b, junk) + vect_inters2(pA, pB, flatA, flatB, c, junk) + vect_inters2(lA, lB, pA, pB, d, junk); if (hits != 4) { return 0; } /* flip the line endpoints to match up with a/b */ if (vect_dist2(lA, d) < vect_dist2(lA, a)) { Vswp2(lA, lB); } MakeBypassLine(layer, lA, a, line, NULL); MakeBypassLine(layer, a, b, line, expandp); MakeBypassLine(layer, b, c, line, expandp); MakeBypassLine(layer, c, d, line, expandp); MakeBypassLine(layer, d, lB, line, NULL); RemoveLine(layer, line); return 1; }
/** * @brief Check to see if a planet is in sensor range of the pilot. * * @param p Pilot who is trying to check to see if the planet is in sensor range. * @param target Planet to see if is in sensor range. * @return 1 if they are in range, 0 if they aren't. */ int pilot_inRangePlanet( const Pilot *p, int target ) { double d; Planet *pnt; double sense; /* pilot must exist */ if ( p == NULL ) return 0; /* Get the planet. */ pnt = cur_system->planets[target]; /* target must not be virtual */ if ( !pnt->real ) return 0; /* @TODO ew_detect should be squared upon being set. */ sense = sensor_curRange * pow2(p->ew_detect); /* Get distance. */ d = vect_dist2( &p->solid->pos, &pnt->pos ); if (d * pnt->hide < sense ) return 1; return 0; }
/** * @brief Check to see if a jump point is in sensor range of the pilot. * * @param p Pilot who is trying to check to see if the jump point is in sensor range. * @param target Jump point to see if is in sensor range. * @return 1 if they are in range, 0 if they aren't. */ int pilot_inRangeJump( const Pilot *p, int i ) { double d; JumpPoint *jp; double sense; double hide; /* pilot must exist */ if ( p == NULL ) return 0; /* Get the jump point. */ jp = &cur_system->jumps[i]; /* We don't want exit-only or unknown hidden jumps. */ if ((jp_isFlag(jp, JP_EXITONLY)) || ((jp_isFlag(jp, JP_HIDDEN)) && (!jp_isKnown(jp)) )) return 0; sense = sensor_curRange * p->ew_jumpDetect; hide = jp->hide; /* Get distance. */ d = vect_dist2( &p->solid->pos, &jp->pos ); if (d * hide < sense) return 1; return 0; }
/** * @brief Check to see if a jump point is in sensor range of the pilot. * * @param p Pilot who is trying to check to see if the jump point is in sensor range. * @param target Jump point to see if is in sensor range. * @return 1 if they are in range, 0 if they aren't. */ int pilot_inRangeJump( const Pilot *p, int i ) { double d; JumpPoint *jp; double sense; double hide; /* pilot must exist */ if ( p == NULL ) return 0; /* Get the jump point. */ jp = &cur_system->jumps[i]; /* We don't want exit-only jumps. */ if (jp_isFlag(jp, JP_EXITONLY)) return 0; /* Handle hidden jumps separately, as they use a special range parameter. */ if (jp_isFlag(jp, JP_HIDDEN)) sense = pow(p->stats.misc_hidden_jump_detect, 2); else sense = sensor_curRange * p->ew_jump_detect; hide = jp->hide; /* Get distance. */ d = vect_dist2( &p->solid->pos, &jp->pos ); if (d * hide < sense) return 1; return 0; }
/** * @brief Check to see if a planet is in sensor range of the pilot. * * @param p Pilot who is trying to check to see if the planet is in sensor range. * @param target Planet to see if is in sensor range. * @return 1 if they are in range, 0 if they aren't. */ int pilot_inRangePlanet( const Pilot *p, int target ) { (void)p; (void)target; /* Always consider planets in range. */ return 1; #if 0 double d; Planet *pnt; if (cur_system->interference == 0.) return 1; /* Get the planet. */ pnt = cur_system->planets[target]; /* Get distance. */ d = vect_dist2( &p->solid->pos, &pnt->pos ); if (d < sensor_curRange) return 1; return 0; #endif }
/** * @brief Check to see if a pilot is in sensor range of another. * * @param p Pilot who is trying to check to see if other is in sensor range. * @param target Target of p to check to see if is in sensor range. * @return 1 if they are in range, 0 if they aren't and -1 if they are detected fuzzily. */ int pilot_inRangePilot( const Pilot *p, const Pilot *target ) { double d, sense; /* Special case player or omni-visible. */ if ((pilot_isPlayer(p) && pilot_isFlag(target, PILOT_VISPLAYER)) || pilot_isFlag(target, PILOT_VISIBLE)) return 1; /* Get distance. */ d = vect_dist2( &p->solid->pos, &target->solid->pos ); sense = sensor_curRange * p->ew_detect; if (d * target->ew_evasion < sense) return 1; else if (d * target->ew_hide < sense) return -1; return 0; }
/** * @brief Handles the autonav braking. * * @return 1 on completion. */ static int player_autonavBrake (void) { int ret; JumpPoint *jp; Vector2d pos; if ((player.autonav == AUTONAV_JUMP_BRAKE) && (player.p->nav_hyperspace != -1)) { jp = &cur_system->jumps[ player.p->nav_hyperspace ]; pilot_brakeDist( player.p, &pos ); if (vect_dist2( &pos, &jp->pos ) > pow2(jp->radius)) ret = pilot_interceptPos( player.p, jp->pos.x, jp->pos.y ); else ret = pilot_brake( player.p ); } else ret = pilot_brake(player.p); player_acc = player.p->solid->thrust / player.p->thrust; return ret; }
/** * @brief Gets the squared distance from the Vec2 (saves a sqrt()) * * @usage my_vec:dist2() -- Gets squared length of the vector (distance squared from origin). * @usage my_vec:dist2( your_vec ) -- Gets squared distance from both vectors (your_vec - my_vec)^2. * * @luaparam v Vector to act as origin. * @luaparam v2 Vector to get squared distance from, uses origin (0,0) if not set. * @luareturn The distance calculated. * @luafunc dist2( v, v2 ) */ static int vectorL_distance2( lua_State *L ) { LuaVector *v1, *v2; double dist2; /* Get self. */ v1 = luaL_checkvector(L,1); /* Get rest of parameters. */ v2 = NULL; if (lua_gettop(L) > 1) { v2 = luaL_checkvector(L,2); } /* Get distance. */ if (v2 == NULL) dist2 = vect_odist2(&v1->vec); else dist2 = vect_dist2(&v1->vec, &v2->vec); /* Return the distance. */ lua_pushnumber(L, dist2); return 1; }
/** * @brief Fires a weapon set. * * @param p Pilot firing weaponsets. * @param ws Weapon set to fire. * @param level Level of the firing weapon set. */ static int pilot_weapSetFire( Pilot *p, PilotWeaponSet *ws, int level ) { int i, j, ret, s; Pilot *pt; double dist2; Outfit *o; /* Case no outfits. */ if (ws->slots == NULL) return 0; /* If inrange is set we only fire at targets in range. */ dist2 = INFINITY; /* With no target we just set distance to infinity. */ if (ws->inrange) { if (p->target != p->id) { pt = pilot_get( p->target ); if (pt != NULL) dist2 = vect_dist2( &p->solid->pos, &pt->solid->pos ); } } /* Fire. */ ret = 0; for (i=0; i<array_size(ws->slots); i++) { o = ws->slots[i].slot->outfit; /* Ignore NULL outfits. */ if (o == NULL) continue; /* Only "active" outfits. */ if ((level != -1) && (ws->slots[i].level != level)) continue; /* Only run once for each weapon type in the group. */ s = 0; for (j=0; j<i; j++) { /* Only active outfits. */ if ((level != -1) && (ws->slots[j].level != level)) continue; /* Found a match. */ if (ws->slots[j].slot->outfit == o) { s = 1; break; } } if (s!=0) continue; /* Only "locked on" outfits. */ if (outfit_isSeeker(o) && (ws->slots[i].slot->u.ammo.lockon_timer > 0.)) continue; /* Only "inrange" outfits. */ if (!outfit_isFighterBay(o) && (ws->inrange && (dist2 > ws->slots[i].range2))) continue; /* Shoot the weapon of the weaponset. */ ret += pilot_shootWeaponSetOutfit( p, ws, o, level ); } return ret; }
/** * @brief Handles a click event. */ static void input_clickevent( SDL_Event* event ) { unsigned int pid; Pilot *p; int mx, my, mxr, myr, pntid, jpid; int rx, ry, rh, rw, res; double x, y, m, r, rp, d, dp, px, py; double ang, angp, mouseang; Planet *pnt; JumpPoint *jp; HookParam hparam[2]; /* Generate hook. */ hparam[0].type = HOOK_PARAM_NUMBER; hparam[0].u.num = event->button.button; hparam[1].type = HOOK_PARAM_SENTINEL; hooks_runParam( "mouse", hparam ); /* Handle zoom. */ if (event->button.button == SDL_BUTTON_WHEELUP) { input_clickZoom( 1.1 ); return; } else if (event->button.button == SDL_BUTTON_WHEELDOWN) { input_clickZoom( 0.9 ); return; } /* Middle mouse enables mouse flying. */ if (event->button.button == SDL_BUTTON_MIDDLE) { player_toggleMouseFly(); return; } /* Mouse targeting is left only. */ if (event->button.button != SDL_BUTTON_LEFT) return; /* Player must not be NULL. */ if (player_isFlag(PLAYER_DESTROYED) || (player.p == NULL)) return; px = player.p->solid->pos.x; py = player.p->solid->pos.y; gl_windowToScreenPos( &mx, &my, event->button.x, event->button.y ); gl_screenToGameCoords( &x, &y, (double)mx, (double)my ); if ((mx <= 15 || my <= 15 ) || (my >= gl_screen.h - 15 || mx >= gl_screen.w - 15)) { /* Border */ x = (mx - (gl_screen.w / 2.)) + px; y = (my - (gl_screen.h / 2.)) + py; mouseang = atan2(py - y, px - x); angp = pilot_getNearestAng( player.p, &pid, mouseang, 1 ); ang = system_getClosestAng( cur_system, &pntid, &jpid, x, y, mouseang ); if ((ABS(angle_diff(mouseang, angp)) > M_PI / 64) || ABS(angle_diff(mouseang, ang)) < ABS(angle_diff(mouseang, angp))) pid = PLAYER_ID; /* Pilot angle is too great, or planet/jump is closer. */ if (ABS(angle_diff(mouseang, ang)) > M_PI / 64 ) jpid = pntid = -1; /* Asset angle difference is too great. */ } else { /* Radar targeting requires raw coordinates. */ mxr = event->button.x; myr = gl_screen.rh - event->button.y; gui_radarGetPos( &rx, &ry ); gui_radarGetDim( &rw, &rh ); if ((mxr > rx && mxr <= rx + rw ) && (myr > ry && myr <= ry + rh )) { /* Radar */ m = 1; gui_radarGetRes( &res ); x = (mxr - (rx + rw / 2.)) * res + px; y = (myr - (ry + rh / 2.)) * res + py; } else /* Visual (on-screen) */ m = res = 1. / cam_getZoom(); dp = pilot_getNearestPos( player.p, &pid, x, y, 1 ); d = system_getClosest( cur_system, &pntid, &jpid, x, y ); rp = MAX( 1.5 * PILOT_SIZE_APROX * pilot_get(pid)->ship->gfx_space->sw / 2 * m, 10. * res); if (pntid >=0) { /* Planet is closer. */ pnt = cur_system->planets[ pntid ]; r = MAX( 1.5 * pnt->radius, 100. ); } else if (jpid >= 0) { jp = &cur_system->jumps[ jpid ]; r = MAX( 1.5 * jp->radius, 100. ); } else { r = 0.; } /* Reject pilot if it's too far or a valid asset is closer. */ if (dp > pow2(rp) || (d < pow2(r) && dp < pow2(rp) && dp > d)) pid = PLAYER_ID; if (d > pow2(r)) /* Planet or jump point is too far. */ jpid = pntid = -1; } if (pid != PLAYER_ID) { /* Apply an action if already selected. */ if (!pilot_isFlag(player.p, PILOT_DEAD) && (pid == player.p->target)) { p = pilot_get(pid); if (pilot_isDisabled(p) || pilot_isFlag(p, PILOT_BOARDABLE)) player_board(); else player_hail(); } else player_targetSet( pid ); } else if (pntid >= 0) { /* Planet is closest. */ if (pntid == player.p->nav_planet) { pnt = cur_system->planets[ pntid ]; player_hyperspacePreempt(0); if (planet_hasService(pnt, PLANET_SERVICE_LAND)) { if ((pnt->faction >= 0) && (areEnemies( player.p->faction, pnt->faction ) && !pnt->bribed)) player_hailPlanet(); else if (vect_dist2(&player.p->solid->pos,&pnt->pos) > pow2(pnt->radius)) player_autonavStart(); else player_land(); } else player_autonavStart(); } else player_targetPlanetSet( pntid ); } else if (jpid >= 0) { /* Jump point is closest. */ if (jpid == player.p->nav_hyperspace) { if (space_canHyperspace(player.p)) player_jump(); else { player_hyperspacePreempt(1); player_autonavStart(); } } else player_targetHyperspaceSet( jpid ); } }