/** * @brief Load callback for savegames in XML Format * @param[in] parent XML Node structure, where we get the information from */ bool AIRFIGHT_LoadXML (xmlNode_t* parent) { int i; xmlNode_t* node; for (i = 0, node = cgi->XML_GetNode(parent, SAVE_AIRFIGHT_PROJECTILE); i < MAX_PROJECTILESONGEOSCAPE && node; node = cgi->XML_GetNextNode(node, parent, SAVE_AIRFIGHT_PROJECTILE), i++) { technology_t* tech = RS_GetTechByProvided(cgi->XML_GetString(node, SAVE_AIRFIGHT_ITEMID)); int j; xmlNode_t* positions; xmlNode_t* attackingAircraft; xmlNode_t* aimedAircraft; aircraftProjectile_t* projectile = &ccs.projectiles[i]; if (!tech) { Com_Printf("AIR_Load: Could not get technology of projectile %i\n", i); return false; } projectile->aircraftItem = INVSH_GetItemByID(tech->provides); for (j = 0, positions = cgi->XML_GetPos2(node, SAVE_AIRFIGHT_POS, projectile->pos[0]); j < MAX_MULTIPLE_PROJECTILES && positions; j++, positions = cgi->XML_GetNextPos2(positions, node, SAVE_AIRFIGHT_POS, projectile->pos[j])) ; projectile->numProjectiles = j; cgi->XML_GetPos3(node, SAVE_AIRFIGHT_IDLETARGET, projectile->idleTarget); projectile->time = cgi->XML_GetInt(node, SAVE_AIRFIGHT_TIME, 0); projectile->angle = cgi->XML_GetFloat(node, SAVE_AIRFIGHT_ANGLE, 0.0); projectile->bullets = cgi->XML_GetBool(node, SAVE_AIRFIGHT_BULLET, false); projectile->beam = cgi->XML_GetBool(node, SAVE_AIRFIGHT_BEAM, false); if ((attackingAircraft = cgi->XML_GetNode(node, SAVE_AIRFIGHT_ATTACKINGAIRCRAFT))) { if (cgi->XML_GetBool(attackingAircraft, SAVE_AIRFIGHT_ISUFO, false)) /** @todo 0 as default might be incorrect */ projectile->attackingAircraft = UFO_GetByIDX(cgi->XML_GetInt(attackingAircraft, SAVE_AIRFIGHT_AIRCRAFTIDX, 0)); else projectile->attackingAircraft = AIR_AircraftGetFromIDX(cgi->XML_GetInt(attackingAircraft, SAVE_AIRFIGHT_AIRCRAFTIDX, AIRCRAFT_INVALID)); } else { projectile->attackingAircraft = nullptr; } cgi->XML_GetPos3(node, SAVE_AIRFIGHT_ATTACKERPOS, projectile->attackerPos); if ((aimedAircraft = cgi->XML_GetNode(node, SAVE_AIRFIGHT_AIMEDAIRCRAFT))) { if (cgi->XML_GetBool(aimedAircraft, SAVE_AIRFIGHT_ISUFO, false)) /** @todo 0 as default might be incorrect */ projectile->aimedAircraft = UFO_GetByIDX(cgi->XML_GetInt(aimedAircraft, SAVE_AIRFIGHT_AIRCRAFTIDX, 0)); else projectile->aimedAircraft = AIR_AircraftGetFromIDX(cgi->XML_GetInt(aimedAircraft, SAVE_AIRFIGHT_AIRCRAFTIDX, AIRCRAFT_INVALID)); } else { projectile->aimedAircraft = nullptr; } } ccs.numProjectiles = i; return true; }
/** * @brief Notify to UFOs that a Phalanx aircraft has been destroyed. * @param[in] aircraft Pointer to the Phalanx aircraft that has been removed. */ void UFO_NotifyPhalanxAircraftRemoved (const aircraft_t * const aircraft) { int ufoIdx; assert(aircraft); for (ufoIdx = 0; ufoIdx < ccs.numUFOs; ufoIdx++) { aircraft_t *ufo = UFO_GetByIDX(ufoIdx); if (ufo->aircraftTarget == aircraft) ufo->aircraftTarget = NULL; } }
/** * @brief Make the UFOs run * @param[in] campaign The campaign data structure * @param[in] deltaTime The time passed since last call */ void UFO_CampaignRunUFOs (const campaign_t* campaign, int deltaTime) { int ufoIdx, k; /* now the ufos are flying around, too - cycle backward - ufo might be destroyed */ for (ufoIdx = ccs.numUFOs - 1; ufoIdx >= 0; ufoIdx--) { aircraft_t *ufo = UFO_GetByIDX(ufoIdx); /* don't run a landed ufo */ if (ufo->landed) continue; /* Every UFO on geoscape should have a mission assigned */ assert(ufo->mission); /* reached target and not following a phalanx aircraft? then we need a new destination */ if (AIR_AircraftMakeMove(deltaTime, ufo) && ufo->status != AIR_UFO) { float *end; end = ufo->route.point[ufo->route.numPoints - 1]; Vector2Copy(end, ufo->pos); MAP_CheckPositionBoundaries(ufo->pos); if (ufo->mission->stage == STAGE_INTERCEPT && ufo->mission->data.aircraft) { /* Attacking an installation: fly over this installation */ UFO_SetRandomDestAround(ufo, ufo->mission->pos); } else UFO_SetRandomDest(ufo); if (CP_CheckNextStageDestination(campaign, ufo)) /* UFO has been removed from game */ continue; /* UFO was destroyed (maybe because the mission was removed) */ if (ufoIdx == ccs.numUFOs) continue; } /* is there a PHALANX aircraft to shoot at ? */ UFO_SearchAircraftTarget(campaign, ufo); /* antimatter tanks */ if (ufo->fuel <= 0) ufo->fuel = ufo->stats[AIR_STATS_FUELSIZE]; /* Update delay to launch next projectile */ for (k = 0; k < ufo->maxWeapons; k++) { aircraftSlot_t *slot = &ufo->weapons[k]; if (slot->delayNextShot > 0) slot->delayNextShot -= deltaTime; } } }
/** * @brief Creates a new ufo on the geoscape from the given aircraft template * @param ufoTemplate The aircraft template to create the ufo from. * @return @c NULL if the max allowed amount of ufos are already on the geoscape, otherwise * the newly created ufo pointer */ static aircraft_t* UFO_CreateFromTemplate (const aircraft_t *ufoTemplate) { aircraft_t *ufo; /* check max amount */ if (ccs.numUFOs >= MAX_UFOONGEOSCAPE) return NULL; /* must be an ufo */ assert(ufoTemplate->type == AIRCRAFT_UFO); /* must be allowed to be on the geoscape */ assert(!ufoTemplate->notOnGeoscape); /* get a new free slot */ ufo = UFO_GetByIDX(ccs.numUFOs); /* copy the data */ *ufo = *ufoTemplate; /* assign an unique index */ ufo->idx = ccs.numUFOs++; return ufo; }
/** * @brief Creates a new ufo on the geoscape from the given aircraft template * @param ufoTemplate The aircraft template to create the ufo from. * @return @c nullptr if the max allowed amount of ufos are already on the geoscape, otherwise * the newly created ufo pointer */ aircraft_t* UFO_CreateFromTemplate (const aircraft_t* ufoTemplate) { aircraft_t* ufo; if (ufoTemplate == nullptr) return nullptr; /* check max amount */ if (ccs.numUFOs >= MAX_UFOONGEOSCAPE) return nullptr; /* must be an ufo */ assert(ufoTemplate->type == AIRCRAFT_UFO); /* get a new free slot */ ufo = UFO_GetByIDX(ccs.numUFOs); /* copy the data */ *ufo = *ufoTemplate; /* assign an unique index */ ufo->idx = ccs.numUFOs++; return ufo; }