/** * @brief Informs the AI if needed that it's been hit. * * @param p Pilot being hit. * @param shooter Pilot that shot. * @param dmg Damage done to p. */ static void weapon_hitAI( Pilot *p, Pilot *shooter, double dmg ) { /* Must be a valid shooter. */ if (shooter == NULL) return; /* Player is handled differently. */ if (shooter->faction == FACTION_PLAYER) { /* Increment damage done to by player. */ p->player_damage += dmg / (p->shield_max + p->armour_max); /* If damage is over threshold, inform pilot or if is targetted. */ if ((p->player_damage > PILOT_HOSTILE_THRESHOLD) || (shooter->target==p->id)) { /* Inform attacked. */ ai_attacked( p, shooter->id ); /* Set as hostile. */ pilot_setHostile(p); pilot_rmFlag( p, PILOT_BRIBED ); pilot_rmFlag( p, PILOT_FRIENDLY ); } } /* Otherwise just inform of being attacked. */ else ai_attacked( p, shooter->id ); }
/** * @brief Deactivates the afterburner. */ void pilot_afterburnOver (Pilot *p) { if (p == NULL) return; if (p->afterburner == NULL) return; if (p->afterburner->state == PILOT_OUTFIT_ON) { p->afterburner->state = PILOT_OUTFIT_OFF; pilot_rmFlag(p,PILOT_AFTERBURNER); pilot_calcStats( p ); /* @todo Make this part of a more dynamic activated outfit sound system. */ sound_play(p->afterburner->outfit->u.afb.sound_off); } }
/** * @brief Finishes the boarding. * * @param p Pilot to finish the boarding. */ void pilot_boardComplete( Pilot *p ) { int ret; Pilot *target; /* Make sure target is sane. */ target = pilot_get(p->target); if (target == NULL) return; /* Steal stuff, we only do credits for now. */ ret = board_trySteal(p); if (ret == 0) { p->credits += target->credits; target->credits = 0.; } /* Finish the boarding. */ pilot_rmFlag(p, PILOT_BOARDING); }
/** * @brief Teleports the player to a new system (only if not landed). * * Does not change the position nor velocity of the player.p, which will probably be wrong in the new system. * * @usage player.teleport( system.get("Arcanis") ) -- Teleports the player to arcanis. * @usage player.teleport( "Arcanis" ) -- Teleports the player to arcanis. * * @luaparam sys System or name of a system to teleport the player to. * @luafunc teleport( sys ) */ static int playerL_teleport( lua_State *L ) { LuaSystem *sys; const char *name; /* Must not be landed. */ if (landed) NLUA_ERROR(L,"Can not teleport the player while landed!"); if (comm_isOpen()) NLUA_ERROR(L,"Can not teleport the player while the comm is open!"); if (player_isBoarded()) NLUA_ERROR(L,"Can not teleport the player while he is boarded!"); /* Get a system. */ if (lua_issystem(L,1)) { sys = lua_tosystem(L,1); name = system_getIndex(sys->id)->name; } else if (lua_isstring(L,1)) name = lua_tostring(L,1); else NLUA_INVALID_PARAMETER(L); /* Check if system exists. */ if (!system_exists( name )) { NLUA_ERROR( L, "System '%s' does not exist.", name ); return 0; } /* Jump out hook is run first. */ hooks_run( "jumpout" ); /* Just in case remove hyperspace flags. */ pilot_rmFlag( player.p, PILOT_HYPERSPACE ); pilot_rmFlag( player.p, PILOT_HYP_BEGIN ); pilot_rmFlag( player.p, PILOT_HYP_BRAKE ); pilot_rmFlag( player.p, PILOT_HYP_PREP ); /* Free graphics. */ space_gfxUnload( cur_system ); /* Go to the new system. */ space_init( name ); /* Map gets deformed when jumping this way. */ map_clear(); /* Add the escorts. */ player_addEscorts(); /* Run hooks - order is important. */ hooks_run( "jumpin" ); hooks_run( "enter" ); events_trigger( EVENT_TRIGGER_ENTER ); /* Reset targets when teleporting */ player_targetPlanetSet( -1 ); player_targetHyperspaceSet( -1 ); gui_setNav(); return 0; }
/** * @brief Teleports the player to a new planet or system (only if not landed). * * If the destination is a system, the coordinates of the player will not change. * If the destination is a planet, the player will be placed over that planet. * * @usage player.teleport( system.get("Arcanis") ) -- Teleports the player to Arcanis. * @usage player.teleport( "Arcanis" ) -- Teleports the player to Arcanis. * @usage player.teleport( "Dvaer Prime" ) -- Teleports the player to Dvaer, and relocates him to Dvaer Prime. * * @luaparam dest System or name of a system or planet or name of a planet to teleport the player to. * @luafunc teleport( dest ) */ static int playerL_teleport( lua_State *L ) { Planet *pnt; StarSystem *sys; const char *name, *pntname; /* Must not be landed. */ if (landed) NLUA_ERROR(L,"Can not teleport the player while landed!"); if (comm_isOpen()) NLUA_ERROR(L,"Can not teleport the player while the comm is open!"); if (player_isBoarded()) NLUA_ERROR(L,"Can not teleport the player while he is boarded!"); pnt = NULL; /* Get a system. */ if (lua_issystem(L,1)) { sys = luaL_validsystem(L,1); name = system_getIndex(sys->id)->name; } /* Get a planet. */ else if (lua_isplanet(L,1)) { pnt = luaL_validplanet(L,1); name = planet_getSystem( pnt->name ); if (name == NULL) { NLUA_ERROR( L, "Planet '%s' does not belong to a system..", pnt->name ); return 0; } } /* Get destination from string. */ else if (lua_isstring(L,1)) { name = lua_tostring(L,1); if (!system_exists( name )) { if (!planet_exists( name )) { NLUA_ERROR( L, "'%s' is not a valid teleportation target.", name ); return 0; } /* No system found, assume destination string is the name of a planet. */ pntname = name; name = planet_getSystem( name ); pnt = planet_get( pntname ); if (name == NULL) { NLUA_ERROR( L, "Planet '%s' does not belong to a system..", pntname ); return 0; } } } else NLUA_INVALID_PARAMETER(L); /* Check if system exists. */ if (!system_exists( name )) { NLUA_ERROR( L, "System '%s' does not exist.", name ); return 0; } /* Jump out hook is run first. */ hooks_run( "jumpout" ); /* Just in case remove hyperspace flags. */ pilot_rmFlag( player.p, PILOT_HYPERSPACE ); pilot_rmFlag( player.p, PILOT_HYP_BEGIN ); pilot_rmFlag( player.p, PILOT_HYP_BRAKE ); pilot_rmFlag( player.p, PILOT_HYP_PREP ); /* Free graphics. */ space_gfxUnload( cur_system ); /* Go to the new system. */ space_init( name ); /* Map gets deformed when jumping this way. */ map_clear(); /* Add the escorts. */ player_addEscorts(); /* Run hooks - order is important. */ hooks_run( "jumpin" ); hooks_run( "enter" ); events_trigger( EVENT_TRIGGER_ENTER ); missions_run( MIS_AVAIL_SPACE, -1, NULL, NULL ); /* Reset targets when teleporting */ player_targetPlanetSet( -1 ); player_targetHyperspaceSet( -1 ); gui_setNav(); /* Move to planet. */ if (pnt != NULL) vectcpy( &player.p->solid->pos, &pnt->pos ); return 0; }
/** * @brief Makes the player take off if landed. * * @param delay Whether or not to have time pass as if the player landed normally. */ void takeoff( int delay ) { int h; char *nt; double a, r; if (!landed) return; /* Clear queued takeoff. */ land_takeoff = 0; /* Refuel if needed. */ land_checkAddRefuel(); /* In case we had paused messy sounds. */ sound_stopAll(); /* ze music */ music_choose("takeoff"); /* to randomize the takeoff a bit */ a = RNGF() * 2. * M_PI; r = RNGF() * land_planet->radius; /* no longer authorized to land */ player_rmFlag(PLAYER_LANDACK); pilot_rmFlag(player.p,PILOT_LANDING); /* No longer landing. */ /* set player to another position with random facing direction and no vel */ player_warp( land_planet->pos.x + r * cos(a), land_planet->pos.y + r * sin(a) ); vect_pset( &player.p->solid->vel, 0., 0. ); player.p->solid->dir = RNGF() * 2. * M_PI; cam_setTargetPilot( player.p->id, 0 ); /* heal the player */ player.p->armour = player.p->armour_max; player.p->shield = player.p->shield_max; player.p->energy = player.p->energy_max; player.p->stimer = 0.; /* initialize the new space */ h = player.p->nav_hyperspace; space_init(NULL); player.p->nav_hyperspace = h; /* cleanup */ if (save_all() < 0) { /* must be before cleaning up planet */ dialogue_alert( "Failed to save game! You should exit and check the log to see what happened and then file a bug report!" ); } /* time goes by, triggers hook before takeoff */ if (delay) ntime_inc( ntime_create( 0, 1, 0 ) ); /* 1 STP */ nt = ntime_pretty( 0, 2 ); player_message("\epTaking off from %s on %s.", land_planet->name, nt); free(nt); /* Hooks and stuff. */ land_cleanup(); /* Cleanup stuff */ hooks_run("takeoff"); /* Must be run after cleanup since we don't want the missions to think we are landed. */ if (menu_isOpen(MENU_MAIN)) return; player_addEscorts(); hooks_run("enter"); if (menu_isOpen(MENU_MAIN)) return; events_trigger( EVENT_TRIGGER_ENTER ); if (menu_isOpen(MENU_MAIN)) return; player.p->ptimer = PILOT_TAKEOFF_DELAY; pilot_setFlag( player.p, PILOT_TAKEOFF ); pilot_setThrust( player.p, 0. ); pilot_setTurn( player.p, 0. ); }
/** * @brief Recalculates the pilot's stats based on his outfits. * * @param pilot Pilot to recalculate his stats. */ void pilot_calcStats( Pilot* pilot ) { int i; Outfit* o; PilotOutfitSlot *slot; double ac, sc, ec, fc; /* temporary health coefficients to set */ double arel, srel, erel; /* relative health bonuses. */ ShipStats amount, *s; /* @TODO remove old school PILOT_AFTERBURN flags. */ pilot_rmFlag( pilot, PILOT_AFTERBURNER ); /* * set up the basic stuff */ /* mass */ pilot->solid->mass = pilot->ship->mass; /* movement */ pilot->thrust = pilot->ship->thrust; pilot->turn_base = pilot->ship->turn; pilot->speed = pilot->ship->speed; /* cpu */ pilot->cpu_max = pilot->ship->cpu; pilot->cpu = pilot->cpu_max; /* crew */ pilot->crew = pilot->ship->crew; /* health */ ac = pilot->armour / pilot->armour_max; sc = pilot->shield / pilot->shield_max; ec = pilot->energy / pilot->energy_max; fc = pilot->fuel / pilot->fuel_max; pilot->armour_max = pilot->ship->armour; pilot->shield_max = pilot->ship->shield; pilot->fuel_max = pilot->ship->fuel; pilot->armour_regen = pilot->ship->armour_regen; pilot->shield_regen = pilot->ship->shield_regen; /* Absorption. */ pilot->dmg_absorb = pilot->ship->dmg_absorb; /* Energy. */ pilot->energy_max = pilot->ship->energy; pilot->energy_regen = pilot->ship->energy_regen; pilot->energy_loss = 0.; /* Initially no net loss. */ /* Stats. */ memcpy( &pilot->stats, &pilot->ship->stats_array, sizeof(ShipStats) ); memset( &amount, 0, sizeof(ShipStats) ); /* cargo has to be reset */ pilot_cargoCalc(pilot); /* Slot voodoo. */ s = &pilot->stats; /* * Electronic warfare setting base parameters. * @TODO ew_hide and ew_detect should be squared so XML-sourced values are linear. */ s->ew_hide = 1. + (s->ew_hide-1.) * exp( -0.2 * (double)(MAX(amount.ew_hide-1,0)) ); s->ew_detect = 1. + (s->ew_detect-1.) * exp( -0.2 * (double)(MAX(amount.ew_detect-1,0)) ); s->ew_jumpDetect = 1. + (s->ew_jumpDetect-1.) * exp( -0.2 * (double)(MAX(amount.ew_jumpDetect-1,0)) ); pilot->ew_base_hide = s->ew_hide; pilot->ew_detect = s->ew_detect; pilot->ew_jumpDetect = pow2(s->ew_jumpDetect); /* * now add outfit changes */ pilot->mass_outfit = 0.; pilot->jamming = 0; arel = 0.; srel = 0.; erel = 0.; for (i=0; i<pilot->noutfits; i++) { slot = pilot->outfits[i]; o = slot->outfit; /* Outfit must exist. */ if (o==NULL) continue; /* Subtract CPU. */ pilot->cpu -= outfit_cpu(o); if (outfit_cpu(o) < 0.) pilot->cpu_max -= outfit_cpu(o); /* Add mass. */ pilot->mass_outfit += o->mass; /* Add ammo mass. */ if (outfit_ammo(o) != NULL) if (slot->u.ammo.outfit != NULL) pilot->mass_outfit += slot->u.ammo.quantity * slot->u.ammo.outfit->mass; /* Set afterburner. */ if (outfit_isAfterburner(o)) pilot->afterburner = pilot->outfits[i]; /* Active outfits must be on to affect stuff. */ if (slot->active && !(slot->state==PILOT_OUTFIT_ON)) continue; if (outfit_isMod(o)) { /* Modification */ /* movement */ pilot->thrust += o->u.mod.thrust * pilot->ship->mass; pilot->thrust += o->u.mod.thrust_rel * pilot->ship->thrust; pilot->turn_base += o->u.mod.turn; pilot->turn_base += o->u.mod.turn_rel * pilot->ship->turn; pilot->speed += o->u.mod.speed; pilot->speed += o->u.mod.speed_rel * pilot->ship->speed; /* health */ pilot->armour_max += o->u.mod.armour; pilot->armour_regen += o->u.mod.armour_regen; arel += o->u.mod.armour_rel; pilot->shield_max += o->u.mod.shield; pilot->shield_regen += o->u.mod.shield_regen; srel += o->u.mod.shield_rel; pilot->energy_max += o->u.mod.energy; pilot->energy_regen += o->u.mod.energy_regen; erel += o->u.mod.energy_rel; /* fuel */ pilot->fuel_max += o->u.mod.fuel; /* misc */ pilot->cargo_free += o->u.mod.cargo; pilot->mass_outfit += o->u.mod.mass_rel * pilot->ship->mass; pilot->crew += o->u.mod.crew_rel * pilot->ship->crew; pilot->ew_base_hide += o->u.mod.hide_rel * pilot->ew_base_hide; /* * Stats. */ ss_statsModFromList( &pilot->stats, o->u.mod.stats, &amount ); } else if (outfit_isAfterburner(o)) { /* Afterburner */ pilot_setFlag( pilot, PILOT_AFTERBURNER ); /* We use old school flags for this still... */ pilot->energy_loss += pilot->afterburner->outfit->u.afb.energy; /* energy loss */ pilot->solid->speed_max = pilot->speed + pilot->speed * pilot->afterburner->outfit->u.afb.speed * MIN( 1., pilot->afterburner->outfit->u.afb.mass_limit/pilot->solid->mass); } else if (outfit_isJammer(o)) { /* Jammer */ pilot->jamming = 1; pilot->energy_loss += o->u.jam.energy; } } if (!pilot_isFlag( pilot, PILOT_AFTERBURNER )) pilot->solid->speed_max = pilot->speed; /* Set final energy tau. */ pilot->energy_tau = pilot->energy_max / pilot->energy_regen; /* Fire rate: * amount = p * exp( -0.15 * (n-1) ) * 1x 15% -> 15% * 2x 15% -> 25.82% * 3x 15% -> 33.33% * 6x 15% -> 42.51% */ if (amount.fwd_firerate > 0) { s->fwd_firerate = 1. + (s->fwd_firerate-1.) * exp( -0.15 * (double)(MAX(amount.fwd_firerate-1,0)) ); } /* Cruiser. */ if (amount.tur_firerate > 0) { s->tur_firerate = 1. + (s->tur_firerate-1.) * exp( -0.15 * (double)(MAX(amount.tur_firerate-1,0)) ); } /* Increase health by relative bonuses. */ pilot->armour_max += arel * pilot->ship->armour; pilot->armour_max *= pilot->stats.armour_mod; pilot->shield_max += srel * pilot->ship->shield; pilot->shield_max *= pilot->stats.shield_mod; pilot->energy_max += erel * pilot->ship->energy; /* pilot->energy_max *= pilot->stats.energy_mod; */ /* Give the pilot his health proportion back */ pilot->armour = ac * pilot->armour_max; pilot->shield = sc * pilot->shield_max; pilot->energy = ec * pilot->energy_max; pilot->fuel = fc * pilot->fuel_max; /* Calculate the heat. */ pilot_heatCalc( pilot ); /* Modulate by mass. */ pilot_updateMass( pilot ); /* Update GUI as necessary. */ gui_setGeneric( pilot ); }
/** * @brief Makes the player take off if landed. * * @param delay Whether or not to have time pass as if the player landed normally. */ void takeoff( int delay ) { int h; char *nt; double a, r; if (!landed) return; /* Player's ship is not able to fly. */ if (!player_canTakeoff()) { char message[512]; pilot_reportSpaceworthy( player.p, message, sizeof(message) ); dialogue_msg( "Ship not fit for flight", message ); /* Check whether the player needs rescuing. */ land_stranded(); return; } /* Clear queued takeoff. */ land_takeoff = 0; /* Refuel if needed. */ land_refuel(); /* In case we had paused messy sounds. */ sound_stopAll(); /* ze music */ music_choose("takeoff"); /* to randomize the takeoff a bit */ a = RNGF() * 2. * M_PI; r = RNGF() * land_planet->radius; /* no longer authorized to land */ player_rmFlag(PLAYER_LANDACK); pilot_rmFlag(player.p,PILOT_LANDING); /* No longer landing. */ /* set player to another position with random facing direction and no vel */ player_warp( land_planet->pos.x + r * cos(a), land_planet->pos.y + r * sin(a) ); vect_pset( &player.p->solid->vel, 0., 0. ); player.p->solid->dir = RNGF() * 2. * M_PI; cam_setTargetPilot( player.p->id, 0 ); /* heal the player */ pilot_healLanded( player.p ); /* Clear planet target. Allows for easier autonav out of the system. */ player_targetPlanetSet( -1 ); /* initialize the new space */ h = player.p->nav_hyperspace; space_init(NULL); player.p->nav_hyperspace = h; /* cleanup */ if (save_all() < 0) /* must be before cleaning up planet */ dialogue_alert( "Failed to save game! You should exit and check the log to see what happened and then file a bug report!" ); /* time goes by, triggers hook before takeoff */ if (delay) ntime_inc( ntime_create( 0, 1, 0 ) ); /* 1 STP */ nt = ntime_pretty( 0, 2 ); player_message("\epTaking off from %s on %s.", land_planet->name, nt); free(nt); /* Hooks and stuff. */ land_cleanup(); /* Cleanup stuff */ hooks_run("takeoff"); /* Must be run after cleanup since we don't want the missions to think we are landed. */ if (menu_isOpen(MENU_MAIN)) return; player_addEscorts(); hooks_run("enter"); if (menu_isOpen(MENU_MAIN)) return; events_trigger( EVENT_TRIGGER_ENTER ); missions_run( MIS_AVAIL_SPACE, -1, NULL, NULL ); if (menu_isOpen(MENU_MAIN)) return; player.p->ptimer = PILOT_TAKEOFF_DELAY; pilot_setFlag( player.p, PILOT_TAKEOFF ); pilot_setThrust( player.p, 0. ); pilot_setTurn( player.p, 0. ); }