/** * @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 Gets the outfit's range. * @param o Outfit to get information from. */ double outfit_range( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.range; else if (outfit_isBeam(o)) return o->u.bem.range; else if (outfit_isAmmo(o)) return 0.8*o->u.amm.speed*o->u.amm.duration; return -1.; }
/** * @brief Dumps ammo data to CSV. */ void dout_csvAmmo( const char *path ) { Outfit *o, *o_all; int i, j, n, l; SDL_RWops *rw; char buf[ 1024 ]; char *ai; Damage *dmg; /* File to output to. */ rw = SDL_RWFromFile( path, "w" ); if (rw == NULL) { WARN("Unable to open '%s' for writing: %s", path, SDL_GetError()); return; } /* Write "header" */ l = nsnprintf( buf, sizeof(buf), "name,type,license," "mass,price," "duration,resist,ai," "speed,turn,thrust,energy," "penetration,dtype,dmg,disable\n" ); SDL_RWwrite( rw, buf, l, 1 ); o_all = outfit_getAll( &n ); for (i=0; i<n; i++) { o = &o_all[i]; /* Only handle ammo. */ if (!outfit_isAmmo(o)) continue; dmg = &o->u.blt.dmg; /* Get AI name, in lower case. */ ai = strdup( outfit_getAmmoAI(o) ); for (j=0; j<(int)strlen(ai); j++) ai[j] = tolower(ai[j]); l = nsnprintf( buf, sizeof(buf), "%s,%s,%s," "%f,%"CREDITS_PRI"," "%f,%f,%s," "%f,%f,%f,%f," "%f,%s,%f,%f\n", o->name, outfit_getType(o), o->license, o->mass, o->price, o->u.amm.duration, o->u.amm.resist * 100, ai, o->u.amm.speed, o->u.amm.turn * 180 / M_PI, o->u.amm.thrust, o->u.amm.energy, dmg->penetration * 100, dtype_damageTypeToStr(dmg->type), dmg->damage, dmg->disable ); free(ai); SDL_RWwrite( rw, buf, l, 1 ); } /* Close file. */ SDL_RWclose( rw ); }
/** * @brief Gets the outfit's damage type. * @param o Outfit to get information from. */ DamageType outfit_damageType( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.dtype; else if (outfit_isBeam(o)) return o->u.bem.dtype; else if (outfit_isAmmo(o)) return o->u.amm.dtype; return DAMAGE_TYPE_NULL; }
/** * @brief Gets the outfit's energy usage. * @param o Outfit to get information from. */ double outfit_energy( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.energy; else if (outfit_isBeam(o)) return o->u.bem.energy; else if (outfit_isAmmo(o)) return o->u.amm.energy; return -1.; }
/** * @brief Gets the outfit's damage. * @param o Outfit to get information from. */ double outfit_damage( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.damage; else if (outfit_isBeam(o)) return o->u.bem.damage; else if (outfit_isAmmo(o)) return o->u.amm.damage; return -1.; }
/** * @brief Gets the outfit's sound effect. * @param o Outfit to get information from. */ int outfit_spfxShield( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.spfx_shield; else if (outfit_isBeam(o)) return o->u.bem.spfx_shield; else if (outfit_isAmmo(o)) return o->u.amm.spfx_shield; return -1; }
/** * @brief Gets the outfit's sound effect. * @param o Outfit to get information from. */ int outfit_spfxArmour( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.spfx_armour; else if (outfit_isBeam(o)) return o->u.bem.spfx_armour; else if (outfit_isAmmo(o)) return o->u.amm.spfx_armour; return -1; }
/** * @brief Gets the outfit's graphic effect. * @param o Outfit to get information from. */ glTexture* outfit_gfx( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.gfx_space; else if (outfit_isBeam(o)) return o->u.bem.gfx; else if (outfit_isAmmo(o)) return o->u.amm.gfx_space; return NULL; }
/** * @brief Creates a new weapon. * * @param outfit Outfit which spawns the weapon. * @param dir Direction of the shooter. * @param pos Position of the shooter. * @param vel Velocity of the shooter. * @param parent Pilot ID of the shooter. * @param target Target ID that is getting shot. */ void weapon_add( const Outfit* outfit, const double dir, const Vector2d* pos, const Vector2d* vel, unsigned int parent, unsigned int target ) { WeaponLayer layer; Weapon *w; Weapon **curLayer; int *mLayer, *nLayer; GLsizei size; if (!outfit_isBolt(outfit) && !outfit_isAmmo(outfit)) { ERR("Trying to create a Weapon from a non-Weapon type Outfit"); return; } layer = (parent==PLAYER_ID) ? WEAPON_LAYER_FG : WEAPON_LAYER_BG; w = weapon_create( outfit, dir, pos, vel, parent, target ); /* set the proper layer */ switch (layer) { case WEAPON_LAYER_BG: curLayer = wbackLayer; nLayer = &nwbackLayer; mLayer = &mwbacklayer; break; case WEAPON_LAYER_FG: curLayer = wfrontLayer; nLayer = &nwfrontLayer; mLayer = &mwfrontLayer; break; default: WARN("Unknown weapon layer!"); } if (*mLayer > *nLayer) /* more memory alloced than needed */ curLayer[(*nLayer)++] = w; else { /* need to allocate more memory */ switch (layer) { case WEAPON_LAYER_BG: (*mLayer) += WEAPON_CHUNK; curLayer = wbackLayer = realloc(curLayer, (*mLayer)*sizeof(Weapon*)); break; case WEAPON_LAYER_FG: (*mLayer) += WEAPON_CHUNK; curLayer = wfrontLayer = realloc(curLayer, (*mLayer)*sizeof(Weapon*)); break; } curLayer[(*nLayer)++] = w; /* Grow the vertex stuff. */ weapon_vboSize = mwfrontLayer + mwbacklayer; size = sizeof(GLfloat) * (2+4) * weapon_vboSize; weapon_vboData = realloc( weapon_vboData, size ); if (weapon_vbo == NULL) weapon_vbo = gl_vboCreateStream( size, NULL ); } }
/** * @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"; }
static void weapon_explodeLayer( WeaponLayer layer, double x, double y, double radius, unsigned int parent, int mode ) { (void)parent; int i; Weapon **curLayer; int *nLayer; double dist, rad2; /* set the proper layer */ switch (layer) { case WEAPON_LAYER_BG: curLayer = wbackLayer; nLayer = &nwbackLayer; break; case WEAPON_LAYER_FG: curLayer = wfrontLayer; nLayer = &nwfrontLayer; break; default: ERR("Invalid WEAPON_LAYER specified"); return; } rad2 = radius*radius; /* Now try to destroy the weapons affected. */ for (i=0; i<*nLayer; i++) { if (((mode & EXPL_MODE_MISSILE) && outfit_isAmmo(curLayer[i]->outfit)) || ((mode & EXPL_MODE_BOLT) && outfit_isBolt(curLayer[i]->outfit))) { dist = pow2(curLayer[i]->solid->pos.x - x) + pow2(curLayer[i]->solid->pos.y - y); if (dist < rad2) { weapon_destroy(curLayer[i], layer); i--; } } } }
/** * @brief Gets the outfit's animation spin. * @param o Outfit to get information from. */ double outfit_spin( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.spin; else if (outfit_isAmmo(o)) return o->u.amm.spin; return -1.; }
/** * @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; }