//=========================================================
// BG_ParseWeaponStats
//---------------------------------------------------------
// Description:
// Parses the stats block of a weapons file.
//=========================================================
static void BG_ParseWeaponStats ( weaponData_t *weaponData, cJSON *statsNode )
{
    cJSON *node;
    const char *flags[4];
    const char *ammo;
    
    if ( statsNode == NULL )
    {
        return;
    }

    node = cJSON_GetObjectItem (statsNode, "slot");
    weaponData->weaponSlot = (unsigned char)cJSON_ToIntegerOpt (node, 0);

    node = cJSON_GetObjectItem (statsNode, "reloadtime");
    weaponData->weaponReloadTime = (unsigned short)cJSON_ToIntegerOpt (node, 0);

    node = cJSON_GetObjectItem (statsNode, "ammoIndex");
    ammo = cJSON_ToStringOpt (node, "AMMO_NONE");
	weaponData->ammoIndex = BG_GetAmmo(ammo)->ammoIndex;

	node = cJSON_GetObjectItem (statsNode, "ammoOnSpawn");
	weaponData->ammoOnSpawn = (unsigned int)cJSON_ToIntegerOpt (node, ((weaponData->ammoIndex < AMMO_ROCKETS) ? 400 : ((weaponData->ammoIndex != AMMO_ROCKETS) ? 444 : 10)));	// Gives 300 ammo for non-explosives

	node = cJSON_GetObjectItem (statsNode, "ammoOnPickup");
	weaponData->ammoOnPickup = (unsigned int)cJSON_ToIntegerOpt (node, ((weaponData->ammoIndex < AMMO_ROCKETS) ? 20 : 1));	// Gives 20 ammo for non-explosives

	node = cJSON_GetObjectItem (statsNode, "clipSize");
	weaponData->clipSize = (unsigned int)cJSON_ToIntegerOpt (node, 0);

    node = cJSON_GetObjectItem (statsNode, "flags");
    if ( node != NULL )
    {
        int numFlags = cJSON_ReadStringArray (node, 4, flags);
        int i;

        for ( i = 0; i < numFlags; i++ )
        {
            BG_ParseWeaponStatsFlags (weaponData, flags[i]);
        }
    }

    node = cJSON_GetObjectItem (statsNode, "speed");
    weaponData->speedModifier = (float)cJSON_ToNumberOpt (node, 1.0);
        
    node = cJSON_GetObjectItem (statsNode, "reloadmodifier");
    weaponData->reloadModifier = (float)cJSON_ToNumberOpt (node, 1.0);
    
    node = cJSON_GetObjectItem (statsNode, "startzoomfov");
    weaponData->startZoomFov = (float)cJSON_ToNumberOpt (node, 50.0);
    
    node = cJSON_GetObjectItem (statsNode, "endzoomfov");
    weaponData->endZoomFov = (float)cJSON_ToNumberOpt (node, weaponData->zoomType == ZOOM_TOGGLE ? weaponData->startZoomFov : 5.0);
    
    node = cJSON_GetObjectItem (statsNode, "zoomtime");
    weaponData->zoomTime = cJSON_ToIntegerOpt (node, 2000);

	node = cJSON_GetObjectItem (statsNode, "ironsightsTime");
	weaponData->ironsightsTime = cJSON_ToIntegerOpt (node, IRONSIGHTS_TIME);
}
Ejemplo n.º 2
0
/*
============================
JKG_ParseSingleAmmo

Reads a single ammo entry from a .ammo file
============================
*/
static qboolean JKG_ParseSingleAmmo(cJSON* json) {
	const char* name = cJSON_GetItemKey(json);
	ammo_t* ammo = &ammoTable[numAmmoLoaded];
	cJSON* child;

	ammo->ammoIndex = numAmmoLoaded;
	Q_strncpyz(ammo->name, name, sizeof(ammo->name));

	Q_strncpyz(ammo->shortname, cJSON_ToStringOpt(cJSON_GetObjectItem(json, "shortname"), ""), sizeof(ammo->shortname));

	// Parse substitutes (we need to establish the link later)
	ammo->pSub = nullptr;
	child = cJSON_GetObjectItem(json, "basedOn");
	if (child) {
		Q_strncpyz(ammo->substitute, cJSON_ToString(child), sizeof(ammo->substitute));
	}
	else {
		Q_strncpyz(ammo->substitute, ammo->name, sizeof(ammo->substitute));
	}

	child = cJSON_GetObjectItem(json, "max");
	ammo->ammoMax = cJSON_ToIntegerOpt(child, 999);

	child = cJSON_GetObjectItem(json, "pricePerUnit");
	ammo->pricePerUnit = cJSON_ToNumberOpt(child, 1.0);

	child = cJSON_GetObjectItem(json, "overrides");
	if (child) {
		JKG_ParseAmmoOverrides(ammo, child);
	}

	return qtrue;
}
Ejemplo n.º 3
0
int termsMasterFinalFunc (asyncTask_t *task) {
	cJSON *data = (cJSON *)task->finalData;
	
	if (task->errorCode == 0) {
		Com_Printf("Terms of use:\n%s\n", cJSON_ToStringOpt(cJSON_GetObjectItem(data, "message"), ""));
	} else {
		Com_Printf("Could not obtain terms of use!\n");
	}
	return 0;
}
Ejemplo n.º 4
0
static int GLua_JSON_ToStringOpt( lua_State *L )
{
	// Check and make sure we're using a valid index
	if( !FJSON_ValidateNode( L, 1 ) )
	{
		lua_pushnil(L);
		return 1;
	}

	cJSON *node = FJSON_RetrieveNode( L, 1 );
	lua_pushstring( L, cJSON_ToStringOpt( node, luaL_checkstring( L, 2 ) ) );

	return 1;
}
Ejemplo n.º 5
0
/*
===================
CG_ParseLoadingScreenTips
===================
*/
void CG_ParseLoadingScreenTips(void)
{
	fileHandle_t f;
	int len = trap->FS_Open("ext_data/tables/loadingTips.json", &f, FS_READ);
	char* buffer;
	char error[1024];

	memset(error, 0, sizeof(error));

	if (len == 0 || f == NULL_HANDLE)
	{
		Com_Printf("No loading tips to display\n");
		return;
	}

	trap->TrueMalloc((void**)&buffer, len);
	if (buffer == nullptr)
	{
		return;
	}
	trap->FS_Read(buffer, len, f);
	trap->FS_Close(f);

	cJSON* json = cJSON_ParsePooled(buffer, error, 1024);
	if (json == nullptr)
	{
		Com_Printf("Couldn't parse loading tips: %s\n", error);
		trap->TrueFree((void**)&buffer);
		return;
	}

	cJSON* child = cJSON_GetObjectItem(json, "tips");
	if (child)
	{
		int arraySize = cJSON_GetArraySize(child);
		for (int i = 0; i < arraySize; i++)
		{
			cJSON* arrayItem = cJSON_GetArrayItem(child, i);
			loadingTip_t tip;

			Q_strncpyz(tip.tipText, cJSON_ToStringOpt(arrayItem, ""), sizeof(tip));
			cg_loadingTips.push_back(tip);
		}
	}
	trap->TrueFree((void**)&buffer);

	// Display this tip
	cg_displayTipNumber = rand() % (cg_loadingTips.size() - 1);
	//cg_displayTipNumber = Q_irand(0, cg_loadingTips.size() - 1);
}
Ejemplo n.º 6
0
/*
============================
JKG_ParseJetpackVisuals

Parses the visual elements of a jetpack.
FIXME: Should precache?
============================
*/
static void JKG_ParseJetpackVisuals(cJSON* jsonNode, jetpackData_t& jetpackData) {
	cJSON* child;
	int boltSize;

	child = cJSON_GetObjectItem(jsonNode, "modelName");
	Q_strncpyz(jetpackData.visuals.modelName, cJSON_ToStringOpt(child, ""), MAX_QPATH);

	child = cJSON_GetObjectItem(jsonNode, "effectBolts");
	boltSize = cJSON_GetArraySize(child);
	for (int i = 0; i < boltSize; i++) {
		cJSON* arrayObj = cJSON_GetArrayItem(child, i);
		std::string bolt = cJSON_ToString(arrayObj);
		jetpackData.visuals.effectBolts.push_back(bolt);
	}

	child = cJSON_GetObjectItem(jsonNode, "hoverEffect");
	Q_strncpyz(jetpackData.visuals.hoverEffect, cJSON_ToStringOpt(child, ""), MAX_QPATH);

	child = cJSON_GetObjectItem(jsonNode, "thrustEffect");
	Q_strncpyz(jetpackData.visuals.thrustEffect, cJSON_ToStringOpt(child, ""), MAX_QPATH);

	child = cJSON_GetObjectItem(jsonNode, "jetEffect");
	Q_strncpyz(jetpackData.visuals.jetEffect, cJSON_ToStringOpt(child, ""), MAX_QPATH);

	child = cJSON_GetObjectItem(jsonNode, "idleSound");
	Q_strncpyz(jetpackData.visuals.idleSound, cJSON_ToStringOpt(child, ""), MAX_QPATH);

	child = cJSON_GetObjectItem(jsonNode, "thrustSound");
	Q_strncpyz(jetpackData.visuals.thrustSound, cJSON_ToStringOpt(child, ""), MAX_QPATH);

	child = cJSON_GetObjectItem(jsonNode, "activateSound");
	Q_strncpyz(jetpackData.visuals.activateSound, cJSON_ToStringOpt(child, ""), MAX_QPATH);

	child = cJSON_GetObjectItem(jsonNode, "deactivateSound");
	Q_strncpyz(jetpackData.visuals.deactivateSound, cJSON_ToStringOpt(child, ""), MAX_QPATH);

	child = cJSON_GetObjectItem(jsonNode, "sputterSound");
	Q_strncpyz(jetpackData.visuals.sputterSound, cJSON_ToStringOpt(child, ""), MAX_QPATH);
}
static void BG_ParseAnimationObject ( cJSON *animationNode, int *torsoAnimation, int *legsAnimation )
{
    cJSON *node = cJSON_GetObjectItem (animationNode, "torso");
    const char *anim = cJSON_ToStringOpt (node, "BOTH_STAND1");
    
    *torsoAnimation = GetIDForString (animTable, anim);
    
    node = cJSON_GetObjectItem (animationNode, "legs");
    if ( node == NULL )
    {
        *legsAnimation = *torsoAnimation;
        return;
    }
    
    anim = cJSON_ToString (node);
    *legsAnimation = GetIDForString (animTable, anim);
}
Ejemplo n.º 8
0
/*
=====================
JKG_ParseArmorVisuals

=====================
*/
void JKG_ParseArmorVisuals(cJSON* json, armorData_t& armor) {
	char ghoul2Ref[MAX_QPATH] {0};
	char ghoul2Model[MAX_QPATH]{0};
	std::string ghoul2Surface;
	cJSON* jsonNode;
	cJSON* child;
	int count;

	// FIXME: is this really needed on the server?
	jsonNode = cJSON_GetObjectItem(json, "model");
	Q_strncpyz(ghoul2Model, cJSON_ToStringOpt(jsonNode, ""), MAX_QPATH);
	jsonNode = cJSON_GetObjectItem(json, "modelGroup");
	Q_strncpyz(ghoul2Ref, cJSON_ToStringOpt(jsonNode, ""), MAX_QPATH);
	if (ghoul2Ref[0]) {
		armor.visuals.pGHOUL2 = JKG_RegisterArmorGhoul2(ghoul2Ref, ghoul2Model);
	}

	jsonNode = cJSON_GetObjectItem(json, "motionBone");
	Q_strncpyz(armor.visuals.motionBone, cJSON_ToStringOpt(jsonNode, ""), MAX_QPATH);

	// Handle surfaces to turn on/off.
	// These are handled as an array in the JSON file
	jsonNode = cJSON_GetObjectItem(json, "armorOnSurfaces");
	if (jsonNode) {
		count = cJSON_GetArraySize(jsonNode);
		for (int i = 0; i < count; i++) {
			child = cJSON_GetArrayItem(jsonNode, i);
			ghoul2Surface = cJSON_ToStringOpt(child, "");
			armor.visuals.armorOnSurfs.push_back(ghoul2Surface);
		}
	}

	jsonNode = cJSON_GetObjectItem(json, "bodyOffSurfaces");
	if (jsonNode) {
		count = cJSON_GetArraySize(jsonNode);
		for (int i = 0; i < count; i++) {
			child = cJSON_GetArrayItem(jsonNode, i);
			ghoul2Surface = cJSON_ToStringOpt(child, "");
			armor.visuals.bodyOffSurfs.push_back(ghoul2Surface);
		}
	}

	// The sound for equipping the piece
	jsonNode = cJSON_GetObjectItem(json, "equippedSound");
	Q_strncpyz(armor.visuals.equipSound, cJSON_ToStringOpt(jsonNode, ""), MAX_QPATH);
}
Ejemplo n.º 9
0
/*
=====================
JKG_ParseArmorFile

=====================
*/
static qboolean JKG_ParseArmorFile(char* buffer, const char* fileName, armorData_t& armorData) {
	char errorBuffer[ARMOR_ERRBUFFER] {0};
	cJSON* json;
	cJSON* jsonNode;

	json = cJSON_ParsePooled(buffer, errorBuffer, sizeof(errorBuffer));
	if (json == nullptr) {
		Com_Printf(S_COLOR_RED "%s: %s\n", fileName, errorBuffer);
		return qfalse;
	}

	// Basic information
	jsonNode = cJSON_GetObjectItem(json, "ref");
	if (!jsonNode) {
		Com_Printf(S_COLOR_RED "%s doesn't contain a valid ref name!\n", fileName);
		cJSON_Delete(json);
		return qfalse;
	}
	Q_strncpyz(armorData.ref, cJSON_ToString(jsonNode), sizeof(armorData.ref));

	jsonNode = cJSON_GetObjectItem(json, "slot");
	armorData.slot = JKG_ArmorSlotFromText(cJSON_ToStringOpt(jsonNode, ""));

	jsonNode = cJSON_GetObjectItem(json, "armor");
	armorData.armor = cJSON_ToIntegerOpt(jsonNode, 0);

	jsonNode = cJSON_GetObjectItem(json, "hp");
	armorData.hp = cJSON_ToIntegerOpt(jsonNode, 0);

	jsonNode = cJSON_GetObjectItem(json, "movemodifier");
	armorData.movemodifier = cJSON_ToNumberOpt(jsonNode, 1.0);

	jsonNode = cJSON_GetObjectItem(json, "visuals");
	JKG_ParseArmorVisuals(jsonNode, armorData);

	cJSON_Delete(json);
	return qtrue;
}
Ejemplo n.º 10
0
static void JKG_ParseBuffOverrides(ammo_t* ammo, cJSON* json, const char* nodeName)
{
	cJSON* child = cJSON_GetObjectItem(json, nodeName);
	if (child == nullptr)
	{
		return;
	}

	int elemCount = cJSON_GetArraySize(child);
	if (elemCount <= 0)
	{
		return; // not actually an array
	}

	// Iterate through each buff array item
	for (int i = 0; i < elemCount; i++)
	{
		cJSON* buff = cJSON_GetArrayItem(child, i);
		complexAmmoBuffOverride buffOverride = { 0 };

		cJSON* buffChild = cJSON_GetObjectItem(buff, "buff");
		if (buffChild == nullptr)
		{	// JSON doesn't contain a "buff" field. Continue.
			continue;
		}

		buffOverride.buff = JKG_ResolveBuffName(cJSON_ToStringOpt(buffChild, ""));
		if (buffOverride.buff < 0)
		{	// A buff by this name doesn't exist, continue.
			continue;
		}

		buffChild = cJSON_GetObjectItem(buff, "remove");
		buffOverride.bRemove = cJSON_ToBooleanOpt(buffChild, qfalse);

		buffChild = cJSON_GetObjectItem(buff, "addbuff");
		buffOverride.bAddBuff = cJSON_ToBooleanOpt(buffChild, qfalse);

		buffChild = cJSON_GetObjectItem(buff, "duration");
		if (buffChild != nullptr)
		{
			cJSON* childProps;

			childProps = cJSON_GetObjectItem(buffChild, "add");
			if (childProps != nullptr)
			{
				buffOverride.bAddDuration = qtrue;
				buffOverride.addDuration = cJSON_ToInteger(childProps);
			}

			childProps = cJSON_GetObjectItem(buffChild, "multiply");
			if (childProps != nullptr)
			{
				buffOverride.bMultiplyDuration = qtrue;
				buffOverride.multiplyDuration = cJSON_ToNumber(childProps);
			}

			childProps = cJSON_GetObjectItem(buffChild, "set");
			if (childProps != nullptr)
			{
				buffOverride.bSetDuration = qtrue;
				buffOverride.setDuration = cJSON_ToInteger(childProps);
			}
		}

		buffChild = cJSON_GetObjectItem(buff, "intensity");
		if (buffChild != nullptr)
		{
			cJSON* childProps;

			childProps = cJSON_GetObjectItem(buffChild, "add");
			if (childProps != nullptr)
			{
				buffOverride.bAddIntensity = qtrue;
				buffOverride.addIntensity = cJSON_ToNumber(childProps);
			}

			childProps = cJSON_GetObjectItem(buffChild, "multiply");
			if (childProps != nullptr)
			{
				buffOverride.bMultiplyIntensity = qtrue;
				buffOverride.multiplyIntensity = cJSON_ToNumber(childProps);
			}

			childProps = cJSON_GetObjectItem(buffChild, "set");
			if (childProps != nullptr)
			{
				buffOverride.bSetIntensity = qtrue;
				buffOverride.setIntensity = cJSON_ToNumber(childProps);
			}
		}

		// Add the override to the list of buff overrides
		ammo->overrides.buffs.emplace_back(buffOverride);
	}
}
static void BG_ParseWeaponFireMode ( weaponFireModeStats_t *fireModeStats, cJSON *fireModeNode )
{
    cJSON *node;
    const char *str = NULL;
    
    if ( fireModeNode == NULL )
    {
        return;
    }
    
    node = cJSON_GetObjectItem (fireModeNode, "ammo");
    str = cJSON_ToString (node);
    if ( str && str[0] )
    {
        fireModeStats->ammo = BG_GetAmmo (str);
    }

    node = cJSON_GetObjectItem (fireModeNode, "damage");
#ifdef QAGAME
    BG_ParseDamage (fireModeStats, node, qfalse);
    
    node = cJSON_GetObjectItem (fireModeNode, "secondarydamage");
    BG_ParseDamage (fireModeStats, node, qtrue);
#else
	fireModeStats->baseDamage = cJSON_ToInteger (node);
#endif
    
    node = cJSON_GetObjectItem (fireModeNode, "grenade");
    fireModeStats->isGrenade = (qboolean)cJSON_ToBooleanOpt (node, 0);

	node = cJSON_GetObjectItem (fireModeNode, "grenadeBounces");
    fireModeStats->grenadeBounces = (qboolean)cJSON_ToBooleanOpt (node, 1);

	node = cJSON_GetObjectItem (fireModeNode, "grenadeBounceDMG");
    fireModeStats->grenadeBounceDMG = (char)cJSON_ToIntegerOpt (node, 10);
    
    node = cJSON_GetObjectItem (fireModeNode, "ballistic");
    fireModeStats->applyGravity = (char)cJSON_ToBooleanOpt (node, 0);
    
    node = cJSON_GetObjectItem (fireModeNode, "bounces");
    fireModeStats->bounceCount = (char)cJSON_ToIntegerOpt (node, 0);
    
    node = cJSON_GetObjectItem (fireModeNode, "hitscan");
    fireModeStats->hitscan = (char)cJSON_ToBooleanOpt (node, 0);
    
    node = cJSON_GetObjectItem (fireModeNode, "projectiles");
    fireModeStats->shotCount = (char)cJSON_ToIntegerOpt (node, 0);
    
    node = cJSON_GetObjectItem (fireModeNode, "collisionsize");
    fireModeStats->boxSize = (float)cJSON_ToNumberOpt (node, 0.0);
    
    node = cJSON_GetObjectItem (fireModeNode, "maxchargetime");
    fireModeStats->chargeMaximum = (short)cJSON_ToIntegerOpt (node, 0);
    
    node = cJSON_GetObjectItem (fireModeNode, "chargedamage");
    fireModeStats->chargeMultiplier = (float)cJSON_ToNumberOpt (node, 0);
    
    node = cJSON_GetObjectItem (fireModeNode, "chargedelay");
    fireModeStats->chargeTime = (short)cJSON_ToIntegerOpt (node, 0);
    
    node = cJSON_GetObjectItem (fireModeNode, "ammocost");
    fireModeStats->cost = (char)cJSON_ToIntegerOpt (node, 0);
    
    node = cJSON_GetObjectItem (fireModeNode, "firingtype");
    BG_ParseFireModeFiringType (fireModeStats, cJSON_ToStringOpt (node, "auto"));
    
    // 0 means fully automatic, otherwise one burst will fire weapon n times.
    node = cJSON_GetObjectItem (fireModeNode, "shotsperburst");
    fireModeStats->shotsPerBurst = (char)cJSON_ToIntegerOpt (node, 0);
    
    // 0 means infinite delay (semi-automatic), otherwise n milliseconds between
    // rounds in a burst.
    node = cJSON_GetObjectItem (fireModeNode, "burstshotdelay");
    fireModeStats->burstFireDelay = (short)cJSON_ToIntegerOpt (node, 0);
    
    node = cJSON_GetObjectItem (fireModeNode, "firedelay");
    fireModeStats->delay = (short)cJSON_ToIntegerOpt (node, 0);
    
    node = cJSON_GetObjectItem (fireModeNode, "range");
    fireModeStats->range = (float)cJSON_ToIntegerOpt (node, WPR_M);
    
    node = cJSON_GetObjectItem (fireModeNode, "splashrange");
    fireModeStats->rangeSplash = (float)cJSON_ToNumberOpt (node, 0.0);
    
    node = cJSON_GetObjectItem (fireModeNode, "recoil");
    fireModeStats->recoil = (float)cJSON_ToNumberOpt (node, 0.0);
    
    //node = cJSON_GetObjectItem (fireModeNode, "spread");
    //fireModeStats->spread = (float)cJSON_ToNumberOpt (node, 0.0);

	node = cJSON_GetObjectItem (fireModeNode, "accuracy");
	if( node )
	{
		cJSON *child = NULL;

		child = cJSON_GetObjectItem( node, "accuracyRating" );
		fireModeStats->weaponAccuracy.accuracyRating = (vec_t)cJSON_ToNumberOpt( child, 32.0f );

		child = cJSON_GetObjectItem( node, "crouchModifier" );
		fireModeStats->weaponAccuracy.crouchModifier = (float)cJSON_ToNumberOpt( child, 0.8f );

		child = cJSON_GetObjectItem( node, "runModifier" );
		fireModeStats->weaponAccuracy.runModifier = (float)cJSON_ToNumberOpt( child, 2.0f );

		child = cJSON_GetObjectItem( node, "sightsModifier" );
		fireModeStats->weaponAccuracy.sightsModifier = (float)cJSON_ToNumberOpt( child, 0.2f );

		child = cJSON_GetObjectItem( node, "walkModifier" );
		fireModeStats->weaponAccuracy.walkModifier = (float)cJSON_ToNumberOpt( child, 1.55f );

		child = cJSON_GetObjectItem( node, "inAirModifier" );
		fireModeStats->weaponAccuracy.inAirModifier = (float)cJSON_ToNumberOpt( child, 3.0f );

		child = cJSON_GetObjectItem( node, "accuracyRatingPerShot" );
		fireModeStats->weaponAccuracy.accuracyRatingPerShot = (int)cJSON_ToNumberOpt( child, 2 );

		child = cJSON_GetObjectItem( node, "msToDrainAccuracy" );
		fireModeStats->weaponAccuracy.msToDrainAccuracy = (int)cJSON_ToNumberOpt( child, 200 );

		child = cJSON_GetObjectItem( node, "maxAccuracyAdd" );
		fireModeStats->weaponAccuracy.maxAccuracyAdd = (int)cJSON_ToNumberOpt( child, 128 );
	}
	else
	{
		fireModeStats->weaponAccuracy.accuracyRating = 32.0f;
		fireModeStats->weaponAccuracy.crouchModifier = 0.8f;
		fireModeStats->weaponAccuracy.runModifier = 2.0f;
		fireModeStats->weaponAccuracy.sightsModifier = 0.2f;
		fireModeStats->weaponAccuracy.walkModifier = 1.55f;
		fireModeStats->weaponAccuracy.inAirModifier = 3.0f;
		fireModeStats->weaponAccuracy.accuracyRatingPerShot = 2;
		fireModeStats->weaponAccuracy.msToDrainAccuracy = 200;
		fireModeStats->weaponAccuracy.maxAccuracyAdd = 128;
	}
    
    node = cJSON_GetObjectItem (fireModeNode, "projectilespeed");
    fireModeStats->speed = (float)cJSON_ToNumberOpt (node, 0.0);
    
    node = cJSON_GetObjectItem (fireModeNode, "projectileclass");
    str = cJSON_ToStringOpt (node, "unknown_proj");
    Q_strncpyz (fireModeStats->weaponClass, str, sizeof (fireModeStats->weaponClass));
    
    node = cJSON_GetObjectItem (fireModeNode, "meansofdeath");
    str = cJSON_ToStringOpt (node, "MOD_UNKNOWN");
    fireModeStats->weaponMOD = GetIDForString (MODTable, str);
    
    node = cJSON_GetObjectItem (fireModeNode, "splashmeansofdeath");
    str = cJSON_ToStringOpt (node, "MOD_UNKNOWN");
    fireModeStats->weaponSplashMOD = GetIDForString (MODTable, str);
}
static void BG_ParseDamage ( weaponFireModeStats_t *fireModeStats, cJSON *damageNode, qboolean secondary )
{
    if ( !damageNode )
    {
        return;
    }
    
    if ( !secondary && cJSON_IsNumber (damageNode) )
    {
        fireModeStats->baseDamage = (short)cJSON_ToIntegerOpt (damageNode, 0);
    }
    else if ( cJSON_IsObject (damageNode) )
    {
        damageSettings_t darea;
        cJSON *node = NULL;
        qhandle_t areaHandle = 0;
        
        memset (&darea, 0, sizeof (darea));
        
        node = cJSON_GetObjectItem (damageNode, "damageradius");
        if ( node )
        {
            cJSON *child = NULL;
            const char *s = NULL;
            
            darea.radial = qtrue;
            
            child = cJSON_GetObjectItem (node, "start");
            darea.radiusParams.startRadius = (float)cJSON_ToNumber (child);
            
            child = cJSON_GetObjectItem (node, "end");
            darea.radiusParams.endRadius = (float)cJSON_ToNumber (child);
            
            child = cJSON_GetObjectItem (node, "parm");
            darea.radiusParams.generic1 = cJSON_ToInteger (child);
            
            child = cJSON_GetObjectItem (node, "falloff");
            s = cJSON_ToStringOpt (child, "constant");
            if ( Q_stricmp (s, "constant") == 0 )
                darea.radiusParams.damageFunc = DF_CONSTANT;
            else if ( Q_stricmp (s, "linear") == 0 )
                darea.radiusParams.damageFunc = DF_LINEAR;
            else if ( Q_stricmp (s, "gaussian") == 0 )
                darea.radiusParams.damageFunc = DF_GAUSSIAN;
            else
            {
                darea.radiusParams.damageFunc = DF_CONSTANT;
                Com_Printf ("Unknown damage falloff type used: %s. Defaulting to linear falloff.\n", s);
            }
                
            child = cJSON_GetObjectItem (node, "function");
            s = cJSON_ToStringOpt (child, "constant");
            if ( Q_stricmp (s, "linear") == 0 )
                darea.radiusParams.radiusFunc = RF_LINEAR;
            else if ( Q_stricmp (s, "nonlinear") == 0 )
                darea.radiusParams.radiusFunc = RF_NONLINEAR;
            else if ( Q_stricmp (s, "clamp") == 0 )
                darea.radiusParams.radiusFunc = RF_CLAMP;
            else if ( Q_stricmp (s, "wave") == 0 )
                darea.radiusParams.radiusFunc = RF_WAVE;
            else if ( Q_stricmp (s, "constant") == 0 )
                darea.radiusParams.radiusFunc = RF_CONSTANT;
            else
            {
                darea.radiusParams.radiusFunc = RF_CONSTANT;
                Com_Printf ("Unknown radius function used: %s; Defaulting to constant radius.\n", s);
            }
        }
        
        node = cJSON_GetObjectItem (damageNode, "duration");
        darea.lifetime = cJSON_ToIntegerOpt (node, 0);
        
        node = cJSON_GetObjectItem (damageNode, "delay");
        darea.delay = cJSON_ToIntegerOpt (node, 0);
        
        node = cJSON_GetObjectItem (damageNode, "damage");
        darea.damage = cJSON_ToIntegerOpt (node, 0);
        fireModeStats->baseDamage = darea.damage;
        
        node = cJSON_GetObjectItem (damageNode, "damagedelay");
        darea.damageDelay = cJSON_ToIntegerOpt (node, 0);
        
        node = cJSON_GetObjectItem (damageNode, "penetration");
        switch ( cJSON_ToIntegerOpt (node, 0) )
        {
            default:
            case 0: darea.penetrationType = PT_NONE; break;
            case 1: darea.penetrationType = PT_SHIELD; break;
            case 2: darea.penetrationType = PT_SHIELD_ARMOR; break;
            case 3: darea.penetrationType = PT_SHIELD_ARMOR_BUILDING; break;
        }
        
        node = cJSON_GetObjectItem (damageNode, "damagetype");
        if ( node )
        {
            int i = 0;
            const char *types[NUM_DAMAGE_TYPES];
            int numTypes = cJSON_ReadStringArray (node, NUM_DAMAGE_TYPES, types);
            
            for ( i = 0; i < numTypes; i++ )
            {
                if ( Q_stricmp (types[i], "annihilate") == 0 )
				{
					int dType = (int)darea.damageType;
					dType |= (1 << DT_ANNIHILATION);
                    darea.damageType = dType;
				}
                else if ( Q_stricmp (types[i], "concussion") == 0 )
				{
					int dType = (int)darea.damageType;
					dType |= (1 << DT_CONCUSSION);
                    darea.damageType = dType;
				}
                else if ( Q_stricmp (types[i], "cut") == 0 )
				{
					int dType = (int)darea.damageType;
					dType |= (1 << DT_CUT);
                    darea.damageType = dType;
				}
                else if ( Q_stricmp (types[i], "disintegrate") == 0 )
				{
					int dType = (int)darea.damageType;
					dType |= (1 << DT_DISINTEGRATE);
                    darea.damageType = dType;
				}
                else if ( Q_stricmp (types[i], "electric") == 0 )
				{
					int dType = (int)darea.damageType;
					dType |= (1 << DT_ELECTRIC);
                    darea.damageType = dType;
				}
                else if ( Q_stricmp (types[i], "explosion") == 0 )
				{
					int dType = (int)darea.damageType;
					dType |= (1 << DT_EXPLOSION);
                    darea.damageType = dType;
				}
                else if ( Q_stricmp (types[i], "fire") == 0 )
				{
					int dType = (int)darea.damageType;
					dType |= ( 1 << DT_FIRE );
                    darea.damageType = dType;
				}
                else if ( Q_stricmp (types[i], "freeze") == 0 )
				{
					int dType = (int)darea.damageType;
					dType |= (1 << DT_FREEZE);
                    darea.damageType = dType;
				}
                else if ( Q_stricmp (types[i], "implosion") == 0 )
				{
					int dType = (int)darea.damageType;
					dType |= (1 << DT_IMPLOSION);
                    darea.damageType = dType;
				}
                else if ( Q_stricmp (types[i], "stun") == 0 )
				{
					int dType = (int)darea.damageType;
					dType |= (1 << DT_STUN);
                    darea.damageType = dType;
				}
                else if ( Q_stricmp (types[i], "carbonite") == 0 )
				{
					int dType = (int)darea.damageType;
					dType |= (1 << DT_CARBONITE);
                    darea.damageType = dType;
				}
                else
				{
                    Com_Printf ("Unknown damage type used: %s.\n", types[i]);
				}
            }
        }
        
        areaHandle = JKG_RegisterDamageSettings (&darea);
        if ( !secondary )
        {
            fireModeStats->damageTypeHandle = areaHandle;
        }
        else
        {
            fireModeStats->secondaryDmgHandle = areaHandle;
        }
    }
}