/** * @brief Prints the UFOpaedia description for aircraft * @note Also checks whether the aircraft tech is already researched or collected * @sa BS_MarketAircraftDescription * @sa UP_Article */ void UP_AircraftDescription (const technology_t* tech) { cgi->INV_ItemDescription(nullptr); /* ensure that the buffer is emptied in every case */ upBuffer[0] = '\0'; if (RS_IsResearched_ptr(tech)) { const aircraft_t* aircraft = AIR_GetAircraft(tech->provides); for (int i = 0; i < AIR_STATS_MAX; i++) { switch (i) { case AIR_STATS_SPEED: /* speed may be converted to km/h : multiply by pi / 180 * earth_radius */ Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i km/h\n"), UP_AircraftStatToName(i), AIR_AircraftMenuStatsValues(aircraft->stats[i], i)); break; case AIR_STATS_MAXSPEED: /* speed may be converted to km/h : multiply by pi / 180 * earth_radius */ Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i km/h\n"), UP_AircraftStatToName(i), AIR_AircraftMenuStatsValues(aircraft->stats[i], i)); break; case AIR_STATS_FUELSIZE: Q_strcat(upBuffer, sizeof(upBuffer), _("Operational range:\t%i km\n"), AIR_GetOperationRange(aircraft)); break; case AIR_STATS_ACCURACY: Q_strcat(upBuffer, sizeof(upBuffer), _("%s:\t%i\n"), UP_AircraftStatToName(i), AIR_AircraftMenuStatsValues(aircraft->stats[i], i)); break; default: break; } } const baseCapacities_t cap = AIR_GetCapacityByAircraftWeight(aircraft); const buildingType_t buildingType = B_GetBuildingTypeByCapacity(cap); const building_t* building = B_GetBuildingTemplateByType(buildingType); Q_strcat(upBuffer, sizeof(upBuffer), _("Required Hangar:\t%s\n"), _(building->name)); /* @note: while MAX_ACTIVETEAM limits the number of soldiers on a craft * there is no use to show this in case of an UFO (would be misleading): */ if (!AIR_IsUFO(aircraft)) Q_strcat(upBuffer, sizeof(upBuffer), _("Max. soldiers:\t%i\n"), aircraft->maxTeamSize); } else if (RS_Collected_(tech)) { /** @todo Display crippled info and pre-research text here */ Com_sprintf(upBuffer, sizeof(upBuffer), _("Unknown - need to research this")); } else { Com_sprintf(upBuffer, sizeof(upBuffer), _("Unknown - need to research this")); } cgi->Cvar_Set("mn_upmetadata", "1"); cgi->UI_RegisterText(TEXT_ITEMDESCRIPTION, upBuffer); UP_DisplayTechTree(tech); }
/** * @brief Set all projectile aiming a given aircraft to an idle destination. * @param[in] aircraft Pointer to the aimed aircraft. * @note This function is called when @c aircraft is destroyed. * @sa AIRFIGHT_ActionsAfterAirfight */ void AIRFIGHT_RemoveProjectileAimingAircraft (const aircraft_t* aircraft) { aircraftProjectile_t* projectile; int idx = 0; if (!aircraft) return; for (projectile = ccs.projectiles; idx < ccs.numProjectiles; projectile++, idx++) { if (projectile->aimedAircraft != aircraft) continue; AIRFIGHT_MissTarget(projectile); if (projectile->attackingAircraft && projectile->attackingAircraft->homebase) { assert(!AIR_IsUFO(projectile->attackingAircraft)); AIR_AircraftReturnToBase(projectile->attackingAircraft); } } }
/** * @brief Change destination of projectile to an idle point of the map, close to its former target. * @param[in] projectile The projectile to update */ static void AIRFIGHT_MissTarget (aircraftProjectile_t *projectile, qboolean returnToBase) { vec3_t newTarget; float distance; float offset; assert(projectile); if (projectile->aimedAircraft) { VectorCopy(projectile->aimedAircraft->pos, newTarget); projectile->aimedAircraft = NULL; } else { VectorCopy(projectile->idleTarget, newTarget); } /* get the distance between the projectile and target */ distance = GetDistanceOnGlobe(projectile->pos[0], newTarget); /* Work out how much the projectile should miss the target by. We dont want it too close * or too far from the original target. * * 1/3 distance between target and projectile * random (range -0.5 to 0.5) * * Then make sure the value is at least greater than 0.1 or less than -0.1 so that * the projectile doesn't land too close to the target. */ offset = (distance / 3) * (frand() - 0.5f); if (abs(offset) < 0.1f) offset = 0.1f; newTarget[0] = newTarget[0] + offset; newTarget[1] = newTarget[1] + offset; VectorCopy(newTarget, projectile->idleTarget); if (returnToBase && projectile->attackingAircraft) { if (projectile->attackingAircraft->homebase) { assert(!AIR_IsUFO(projectile->attackingAircraft)); AIR_AircraftReturnToBase(projectile->attackingAircraft); } } }