/** * @brief Adds some ammo to the pilot stock. * * @param pilot Pilot to add ammo to. * @param s Slot to add ammo to. * @param ammo Ammo to add. * @param quantity Amount to add. * @return Amount actually added. */ int pilot_addAmmo( Pilot* pilot, PilotOutfitSlot *s, Outfit* ammo, int quantity ) { int q, max; (void) pilot; /* Failure cases. */ if (s->outfit == NULL) { WARN("Pilot '%s': Trying to add ammo to unequiped slot.", pilot->name ); return 0; } else if (!outfit_isLauncher(s->outfit) && !outfit_isFighterBay(s->outfit)) { WARN("Pilot '%s': Trying to add ammo to non-launcher/fighterbay type outfit '%s'", pilot->name, s->outfit->name); return 0; } else if (!outfit_isAmmo(ammo) && !outfit_isFighter(ammo)) { WARN( "Pilot '%s': Trying to add non-ammo/fighter type outfit '%s' as ammo.", pilot->name, ammo->name ); return 0; } else if (outfit_isLauncher(s->outfit) && outfit_isFighter(ammo)) { WARN("Pilot '%s': Trying to add fighter '%s' as launcher '%s' ammo", pilot->name, ammo->name, s->outfit->name ); return 0; } else if (outfit_isFighterBay(s->outfit) && outfit_isAmmo(ammo)) { WARN("Pilot '%s': Trying to add ammo '%s' as fighter bay '%s' ammo", pilot->name, ammo->name, s->outfit->name ); return 0; } else if ((s->u.ammo.outfit != NULL) && (s->u.ammo.quantity > 0) && (s->u.ammo.outfit != ammo)) { WARN("Pilot '%s': Trying to add ammo to outfit that already has ammo.", pilot->name ); return 0; } /* Set the ammo type. */ s->u.ammo.outfit = ammo; /* Add the ammo. */ max = outfit_amount(s->outfit) - s->u.ammo.deployed; q = s->u.ammo.quantity; /* Amount have. */ s->u.ammo.quantity += quantity; s->u.ammo.quantity = MIN( max, s->u.ammo.quantity ); q = s->u.ammo.quantity - q; /* Amount actually added. */ pilot->mass_outfit += q * s->u.ammo.outfit->mass; pilot_updateMass( pilot ); return q; }
/** * @brief Frees the outfit stack. */ void outfit_free (void) { int i; Outfit *o; for (i=0; i < outfit_nstack; i++) { o = &outfit_stack[i]; /* free graphics */ if (outfit_gfx(&outfit_stack[i])) gl_freeTexture(outfit_gfx(&outfit_stack[i])); /* Type specific. */ if (outfit_isLauncher(o) && o->u.lau.ammo_name) free(o->u.lau.ammo_name); if (outfit_isFighterBay(o) && o->u.bay.ammo_name) free(o->u.bay.ammo_name); if (outfit_isFighter(o) && o->u.fig.ship) free(o->u.fig.ship); /* strings */ if (o->description) free(o->description); if (o->gfx_store) gl_freeTexture(o->gfx_store); if (o->license) free(o->license); free(o->name); } free(outfit_stack); }
/** * @brief Gets the outfit's broad type. * * @param o Outfit to get the type of. * @return The outfit's broad type in human readable form. */ const char* outfit_getTypeBroad( const Outfit* o ) { if (outfit_isBolt(o)) return "Bolt Weapon"; else if (outfit_isBeam(o)) return "Beam Weapon"; else if (outfit_isLauncher(o)) return "Launcher"; else if (outfit_isAmmo(o)) return "Ammo"; else if (outfit_isTurret(o)) return "Turret"; else if (outfit_isMod(o)) return "Modification"; else if (outfit_isAfterburner(o)) return "Afterburner"; else if (outfit_isJammer(o)) return "Jammer"; else if (outfit_isFighterBay(o)) return "Fighter Bay"; else if (outfit_isFighter(o)) return "Fighter"; else if (outfit_isMap(o)) return "Map"; else if (outfit_isLicense(o)) return "License"; else return "Unknown"; }
/** * @brief Docks the pilot on its target pilot. * * @param p Pilot that wants to dock. * @param target Pilot to dock on. * @param deployed Was pilot already deployed? * @return 0 on successful docking. */ int pilot_dock( Pilot *p, Pilot *target, int deployed ) { int i; Outfit *o = NULL; /* Must be close. */ if (vect_dist(&p->solid->pos, &target->solid->pos) > target->ship->gfx_space->sw * PILOT_SIZE_APROX ) return -1; /* Cannot be going much faster. */ if ((pow2(VX(p->solid->vel)-VX(target->solid->vel)) + pow2(VY(p->solid->vel)-VY(target->solid->vel))) > (double)pow2(MAX_HYPERSPACE_VEL)) return -1; /* Check to see if target has an available bay. */ for (i=0; i<target->noutfits; i++) { /* Must have outfit. */ if (target->outfits[i]->outfit == NULL) continue; /* Must be fighter bay. */ if (!outfit_isFighterBay(target->outfits[i]->outfit)) continue; /* Must have deployed. */ if (deployed && (target->outfits[i]->u.ammo.deployed <= 0)) continue; o = outfit_ammo(target->outfits[i]->outfit); /* Try to add fighter. */ if (outfit_isFighter(o) && (strcmp(p->ship->name,o->u.fig.ship)==0)) { if (deployed) target->outfits[i]->u.ammo.deployed -= 1; break; } } if ((o==NULL) || (i >= target->noutfits)) return -1; /* Add the pilot's outfit. */ if (pilot_addAmmo(target, target->outfits[i], o, 1) != 1) return -1; /* Remove from pilot's escort list. */ if (deployed) { for (i=0; i<target->nescorts; i++) { if ((target->escorts[i].type == ESCORT_TYPE_BAY) && (target->escorts[i].id == p->id)) break; } /* Not found as pilot's escorts. */ if (i >= target->nescorts) return -1; /* Free if last pilot. */ if (target->nescorts == 1) { free(target->escorts); target->escorts = NULL; target->nescorts = 0; } else { memmove( &target->escorts[i], &target->escorts[i+1], sizeof(Escort_t) * (target->nescorts-i-1) ); target->nescorts--; } } /* Destroy the pilot. */ pilot_delete(p); return 0; }
/** * @brief Parses and returns Outfit from parent node. * * @param temp Outfit to load into. * @param parent Parent node to parse outfit from. * @return 0 on success. */ static int outfit_parse( Outfit* temp, const xmlNodePtr parent ) { xmlNodePtr cur, node; char *prop; /* Clear data. */ memset( temp, 0, sizeof(Outfit) ); temp->name = xml_nodeProp(parent,"name"); /* already mallocs */ if (temp->name == NULL) WARN("Outfit in "OUTFIT_DATA" has invalid or no name"); node = parent->xmlChildrenNode; do { /* load all the data */ if (xml_isNode(node,"general")) { cur = node->children; do { xmlr_int(cur,"max",temp->max); xmlr_int(cur,"tech",temp->tech); xmlr_strd(cur,"license",temp->license); xmlr_int(cur,"mass",temp->mass); xmlr_int(cur,"price",temp->price); xmlr_strd(cur,"description",temp->description); if (xml_isNode(cur,"gfx_store")) { temp->gfx_store = xml_parseTexture( cur, OUTFIT_GFX"store/%s.png", 1, 1, 0 ); } } while (xml_nextNode(cur)); } else if (xml_isNode(node,"specific")) { /* has to be processed seperately */ /* get the type */ prop = xml_nodeProp(node,"type"); if (prop == NULL) ERR("Outfit '%s' element 'specific' missing property 'type'",temp->name); temp->type = outfit_strToOutfitType(prop); free(prop); /* is secondary weapon? */ prop = xml_nodeProp(node,"secondary"); if (prop != NULL) { if ((int)atoi(prop)) outfit_setProp(temp, OUTFIT_PROP_WEAP_SECONDARY); free(prop); } if (temp->type==OUTFIT_TYPE_NULL) WARN("Outfit '%s' is of type NONE", temp->name); else if (outfit_isBolt(temp)) outfit_parseSBolt( temp, node ); else if (outfit_isBeam(temp)) outfit_parseSBeam( temp, node ); else if (outfit_isLauncher(temp)) outfit_parseSLauncher( temp, node ); else if (outfit_isAmmo(temp)) outfit_parseSAmmo( temp, node ); else if (outfit_isMod(temp)) outfit_parseSMod( temp, node ); else if (outfit_isAfterburner(temp)) outfit_parseSAfterburner( temp, node ); else if (outfit_isJammer(temp)) outfit_parseSJammer( temp, node ); else if (outfit_isFighterBay(temp)) outfit_parseSFighterBay( temp, node ); else if (outfit_isFighter(temp)) outfit_parseSFighter( temp, node ); else if (outfit_isMap(temp)) outfit_parseSMap( temp, node ); else if (outfit_isLicense(temp)) outfit_parseSLicense( temp, node ); } } while (xml_nextNode(node)); #define MELEMENT(o,s) \ if (o) WARN("Outfit '%s' missing/invalid '"s"' element", temp->name) /**< Define to help check for data errors. */ MELEMENT(temp->name==NULL,"name"); MELEMENT(temp->max==0,"max"); MELEMENT(temp->tech==0,"tech"); MELEMENT(temp->gfx_store==NULL,"gfx_store"); /*MELEMENT(temp->mass==0,"mass"); Not really needed */ MELEMENT(temp->type==0,"type"); MELEMENT(temp->price==0,"price"); MELEMENT(temp->description==NULL,"description"); #undef MELEMENT return 0; }