Example #1
0
/**
 * @brief Make sure equipment definitions used to generate teams are proper.
 * @note Check that the sum of all probabilities is smaller or equal to 100 for a weapon type.
 * @sa INVSH_EquipActor
 */
static bool INV_EquipmentDefSanityCheck (void)
{
	int i, j;
	int sum;
	bool result = true;

	for (i = 0; i < csi.numEDs; i++) {
		const equipDef_t *const ed = &csi.eds[i];
		/* only check definitions used for generating teams */
		if (!Q_strstart(ed->id, "alien") && !Q_strstart(ed->id, "phalanx"))
			continue;

		/* Check primary */
		sum = 0;
		for (j = 0; j < csi.numODs; j++) {
			const objDef_t *const obj = INVSH_GetItemByIDX(j);
			if (obj->weapon && obj->fireTwoHanded
			 && (INV_ItemMatchesFilter(obj, FILTER_S_PRIMARY) || INV_ItemMatchesFilter(obj, FILTER_S_HEAVY)))
				sum += ed->numItems[j];
		}
		if (sum > 100) {
			Com_Printf("INV_EquipmentDefSanityCheck: Equipment Def '%s' has a total probability for primary weapons greater than 100\n", ed->id);
			result = false;
		}

		/* Check secondary */
		sum = 0;
		for (j = 0; j < csi.numODs; j++) {
			const objDef_t *const obj = INVSH_GetItemByIDX(j);
			if (obj->weapon && obj->reload && !obj->deplete && INV_ItemMatchesFilter(obj, FILTER_S_SECONDARY))
				sum += ed->numItems[j];
		}
		if (sum > 100) {
			Com_Printf("INV_EquipmentDefSanityCheck: Equipment Def '%s' has a total probability for secondary weapons greater than 100\n", ed->id);
			result = false;
		}

		/* Check armour */
		sum = 0;
		for (j = 0; j < csi.numODs; j++) {
			const objDef_t *const obj = INVSH_GetItemByIDX(j);
			if (INV_ItemMatchesFilter(obj, FILTER_S_ARMOUR))
				sum += ed->numItems[j];
		}
		if (sum > 100) {
			Com_Printf("INV_EquipmentDefSanityCheck: Equipment Def '%s' has a total probability for armours greater than 100\n", ed->id);
			result = false;
		}

		/* Don't check misc: the total probability can be greater than 100 */
	}

	return result;
}
Example #2
0
/**
 * @brief Remove items until everything fits in storage.
 * @note items will be randomly selected for removal.
 * @param[in] base Pointer to the base
 */
void CAP_RemoveItemsExceedingCapacity (base_t *base)
{
	int i;
	int objIdx[MAX_OBJDEFS];	/**< Will contain idx of items that can be removed */
	int num, cnt;

	if (CAP_GetFreeCapacity(base, CAP_ITEMS) >= 0)
		return;

	for (i = 0, num = 0; i < cgi->csi->numODs; i++) {
		const objDef_t *obj = INVSH_GetItemByIDX(i);

		if (!B_ItemIsStoredInBaseStorage(obj))
			continue;

		/* Don't count item that we don't have in base */
		if (B_ItemInBase(obj, base) <= 0)
			continue;

		objIdx[num++] = i;
	}

	cnt = E_CountHired(base, EMPL_ROBOT);
	/* UGV takes room in storage capacity: we store them with a value MAX_OBJDEFS that can't be used by objIdx */
	for (i = 0; i < cnt; i++) {
		objIdx[num++] = MAX_OBJDEFS;
	}

	while (num && CAP_GetFreeCapacity(base, CAP_ITEMS) < 0) {
		/* Select the item to remove */
		const int randNumber = rand() % num;
		if (objIdx[randNumber] >= MAX_OBJDEFS) {
			/* A UGV is destroyed: get first one */
			Employee* employee = E_GetHiredRobot(base, 0);
			/* There should be at least a UGV */
			assert(employee);
			E_DeleteEmployee(employee);
		} else {
			/* items are destroyed. We guess that all items of a given type are stored in the same location
			 *	=> destroy all items of this type */
			const int idx = objIdx[randNumber];
			const objDef_t *od = INVSH_GetItemByIDX(idx);
			B_UpdateStorageAndCapacity(base, od, -B_ItemInBase(od, base), false);
		}
		REMOVE_ELEM(objIdx, randNumber, num);

		/* Make sure that we don't have an infinite loop */
		if (num <= 0)
			break;
	}
	Com_DPrintf(DEBUG_CLIENT, "B_RemoveItemsExceedingCapacity: Remains %i in storage for a maximum of %i\n",
		CAP_GetCurrent(base, CAP_ITEMS), CAP_GetMax(base, CAP_ITEMS));
}
Example #3
0
/**
 * @note Called at precache phase - only load these soundfiles once at startup or on sound restart
 * @sa S_Restart_f
 */
void S_PrecacheSamples (void)
{
	int i, j, k;

	if (!s_env.initialized)
		return;

	/* load weapon sounds */
	for (i = 0; i < csi.numODs; i++) { /* i = obj */
		const objDef_t *od = INVSH_GetItemByIDX(i);
		for (j = 0; j < od->numWeapons; j++) {	/* j = weapon-entry per obj */
			for (k = 0; k < od->numFiredefs[j]; k++) { /* k = firedef per weapon */
				const fireDef_t *fd = &od->fd[j][k];
				if (fd->fireSound[0] != '\0')
					S_LoadSample(fd->fireSound);
				if (fd->impactSound[0] != '\0')
					S_LoadSample(fd->impactSound);
				if (fd->hitBodySound[0] != '\0')
					S_LoadSample(fd->hitBodySound);
				if (fd->bounceSound[0] != '\0')
					S_LoadSample(fd->bounceSound);
			}
		}
	}

	/* precache the sound pool */
	stdSoundPool[SOUND_WATER_IN] = S_LoadSample("footsteps/water_in");
	stdSoundPool[SOUND_WATER_OUT] = S_LoadSample("footsteps/water_out");
	stdSoundPool[SOUND_WATER_MOVE] = S_LoadSample("footsteps/water_under");
}
Example #4
0
void CL_InvAmmo (const eventRegister_t* self, dbuffer* msg)
{
	int		number;
	int		ammo, type, x, y;
	containerIndex_t container;

	NET_ReadFormat(msg, self->formatString, &number, &ammo, &type, &container, &x, &y);

	le_t* le = LE_Get(number);
	if (!le) {
		Com_DPrintf(DEBUG_CLIENT, "InvAmmo message ignored... LE not found\n");
		return;
	}

	if (le->team != cls.team)
		return;

	assert(container >= 0);
	assert(container < MAX_INVDEFS);
	Item* item = le->inv.getItemAtPos(INVDEF(container), x, y);
	if (!item)
		return;

	/* set new ammo */
	item->setAmmoLeft(ammo);
	item->setAmmoDef(INVSH_GetItemByIDX(type));
}
/**
 * @brief Throw item with actor.
 * @param[in] self Pointer to the event structure that is currently executed
 * @param[in] msg The netchannel message
 * @sa EV_ACTOR_THROW
 */
void CL_ActorDoThrow (const eventRegister_t *self, dbuffer *msg)
{
	vec3_t muzzle, v0;
	int flags;
	int dtime;
	int objIdx;
	weaponFireDefIndex_t weapFdsIdx;
	fireDefIndex_t fdIdx;

	/* read data */
	NET_ReadFormat(msg, self->formatString, &dtime, &objIdx, &weapFdsIdx, &fdIdx, &flags, &muzzle, &v0);

	/* get the fire def */
	const objDef_t *obj = INVSH_GetItemByIDX(objIdx);
	const fireDef_t *fd = FIRESH_GetFiredef(obj, weapFdsIdx, fdIdx);

	/* add effect le (local entity) */
	/** @todo add victim support for blood and hurt sounds */
	LE_AddGrenade(fd, flags, muzzle, v0, dtime, nullptr);

	/* start the sound */
	if (fd->fireSound != nullptr && !(flags & SF_BOUNCED)) {
		S_LoadAndPlaySample(fd->fireSound, muzzle, SOUND_ATTN_IDLE, SND_VOLUME_DEFAULT);
	}
}
void CL_InvAmmo (const eventRegister_t *self, dbuffer *msg)
{
    invList_t	*ic;
    le_t	*le;
    int		number;
    int		ammo, type, x, y;
    containerIndex_t container;

    NET_ReadFormat(msg, self->formatString, &number, &ammo, &type, &container, &x, &y);

    le = LE_Get(number);
    if (!le) {
        Com_DPrintf(DEBUG_CLIENT, "InvAmmo message ignored... LE not found\n");
        return;
    }

    if (le->team != cls.team)
        return;

    assert(container >= 0);
    assert(container < MAX_INVDEFS);
    ic = INVSH_SearchInInventory(&le->i, INVDEF(container), x, y);
    if (!ic)
        return;

    /* set new ammo */
    ic->item.ammoLeft = ammo;
    ic->item.ammo = INVSH_GetItemByIDX(type);
}
Example #7
0
/**
 * @brief This is called after the actors are spawned and will set actor states without consuming TUs
 * @param player The player to perform the action for
 */
void G_ClientInitActorStates (const player_t * player)
{
	const int length = gi.ReadByte(); /* Get the actor amount that the client sent. */
	int i;

	for (i = 0; i < length; i++) {
		const int ucn = gi.ReadShort();
		int saveTU;
		actorHands_t hand;
		int fmIdx, objIdx;
		edict_t *ent = G_EdictsGetActorByUCN(ucn, player->pers.team);
		if (!ent)
			gi.Error("Could not find character on team %i with unique character number %i", player->pers.team, ucn);

		/* these state changes are not consuming any TUs */
		saveTU = ent->TU;
		G_ClientStateChange(player, ent, gi.ReadShort(), false);
		hand = (actorHands_t)gi.ReadShort();
		fmIdx = gi.ReadShort();
		objIdx = gi.ReadShort();
		G_ActorSetTU(ent, saveTU);
		if (objIdx != NONE) {
			G_ReactionFireSettingsUpdate(ent, fmIdx, hand, INVSH_GetItemByIDX(objIdx));
		}
		G_ClientStateChangeUpdate(ent);
	}
}
Example #8
0
/**
 * @brief Save callback for savegames
 * @param[out] parent XML Node structure, where we write the information to
 * @sa BS_LoadXML
 * @sa SAV_GameSaveXML
 */
bool BS_SaveXML (xmlNode_t* parent)
{
	int i;
	xmlNode_t* node;
	const market_t* market = BS_GetMarket();

	/* store market */
	node = cgi->XML_AddNode(parent, SAVE_MARKET_MARKET);
	for (i = 0; i < cgi->csi->numODs; i++) {
		const objDef_t* od = INVSH_GetItemByIDX(i);
		if (BS_IsOnMarket(od)) {
			xmlNode_t* snode = cgi->XML_AddNode(node, SAVE_MARKET_ITEM);
			cgi->XML_AddString(snode, SAVE_MARKET_ID, od->id);
			cgi->XML_AddIntValue(snode, SAVE_MARKET_NUM, market->numItems[i]);
			cgi->XML_AddIntValue(snode, SAVE_MARKET_BID, market->bidItems[i]);
			cgi->XML_AddIntValue(snode, SAVE_MARKET_ASK, market->askItems[i]);
			cgi->XML_AddDoubleValue(snode, SAVE_MARKET_EVO, market->currentEvolutionItems[i]);
			cgi->XML_AddBoolValue(snode, SAVE_MARKET_AUTOSELL, market->autosell[i]);
		}
	}
	for (i = 0; i < AIRCRAFTTYPE_MAX; i++) {
		if (market->bidAircraft[i] > 0 || market->askAircraft[i] > 0) {
			xmlNode_t* snode = cgi->XML_AddNode(node, SAVE_MARKET_AIRCRAFT);
			const char* shortName = cgi->Com_DropShipTypeToShortName((humanAircraftType_t)i);
			cgi->XML_AddString(snode, SAVE_MARKET_ID, shortName);
			cgi->XML_AddIntValue(snode, SAVE_MARKET_NUM, market->numAircraft[i]);
			cgi->XML_AddIntValue(snode, SAVE_MARKET_BID, market->bidAircraft[i]);
			cgi->XML_AddIntValue(snode, SAVE_MARKET_ASK, market->askAircraft[i]);
			cgi->XML_AddDoubleValue(snode, SAVE_MARKET_EVO, market->currentEvolutionAircraft[i]);
		}
	}
	return true;
}
/**
 * @brief Decides if following events should be delayed
 */
int CL_ActorShootHiddenTime (const eventRegister_t *self, dbuffer *msg, eventTiming_t *eventTiming)
{
	int first;
	int objIdx;
	const objDef_t *obj;
	weaponFireDefIndex_t weapFdsIdx;
	fireDefIndex_t fireDefIndex;
	const int eventTime = eventTiming->shootTime;

	NET_ReadFormat(msg, self->formatString, &first, &objIdx, &weapFdsIdx, &fireDefIndex);

	obj = INVSH_GetItemByIDX(objIdx);
	if (first) {
		eventTiming->nextTime += 500;
		eventTiming->impactTime = eventTiming->shootTime = eventTiming->nextTime;
	} else {
		const fireDef_t *fd = FIRESH_GetFiredef(obj, weapFdsIdx, fireDefIndex);
		/* impact right away - we don't see it at all
		 * bouncing is not needed here, too (we still don't see it) */
		eventTiming->impactTime = eventTiming->shootTime;
		eventTiming->nextTime = CL_GetNextTime(self, eventTiming, eventTiming->shootTime + 1400);
		if (fd->delayBetweenShots > 0.0)
			eventTiming->shootTime += 1000 / fd->delayBetweenShots;
	}
	eventTiming->parsedDeath = false;

	return eventTime;
}
Example #10
0
/**
 * @brief Precaches all models at game startup - for faster access
 */
void CL_ViewPrecacheModels (void)
{
	float percent = 30.0f;
	float alreadyLoadedPercent = 30.0f;

	float loaded = CL_PrecacheCharacterModels(alreadyLoadedPercent);
	alreadyLoadedPercent += loaded;
	if (loaded == 0)
		percent = 100 - alreadyLoadedPercent;

	for (int i = 0; i < csi.numODs; i++) {
		const objDef_t* od = INVSH_GetItemByIDX(i);

		alreadyLoadedPercent += percent / csi.numODs;
		SCR_DrawLoadingScreen(true, alreadyLoadedPercent);

		if (od->type[0] == '\0' || od->isDummy)
			continue;

		if (od->model[0] != '\0') {
			cls.modelPool[i] = R_FindModel(od->model);
			if (cls.modelPool[i])
				Com_DPrintf(DEBUG_CLIENT, "CL_PrecacheModels: Registered object model: '%s' (%i)\n", od->model, i);
		}
	}

	/* now make sure that all the precached models are stored until we quit the game
	 * otherwise they would be freed with every map change */
	R_SwitchModelMemPoolTag();

	SCR_DrawLoadingScreen(false, 100.f);
}
Example #11
0
/**
 * @brief Make sure values of items after parsing are proper.
 */
static qboolean CP_ItemsSanityCheck (void)
{
	int i;
	qboolean result = qtrue;

	for (i = 0; i < csi.numODs; i++) {
		const objDef_t *item = INVSH_GetItemByIDX(i);

		/* Warn if item has no size set. */
		if (item->size <= 0 && B_ItemIsStoredInBaseStorage(item)) {
			result = qfalse;
			Com_Printf("CP_ItemsSanityCheck: Item %s has zero size set.\n", item->id);
		}

		/* Warn if no price is set. */
		if (item->price <= 0 && BS_IsOnMarket(item)) {
			result = qfalse;
			Com_Printf("CP_ItemsSanityCheck: Item %s has zero price set.\n", item->id);
		}

		if (item->price > 0 && !BS_IsOnMarket(item) && !PR_ItemIsProduceable(item)) {
			result = qfalse;
			Com_Printf("CP_ItemsSanityCheck: Item %s has a price set though it is neither available on the market and production.\n", item->id);
		}

		/* extension and headgear are mutual exclusive */
		if (item->extension && item->headgear) {
			result = qfalse;
			Com_Printf("CP_ItemsSanityCheck: Item %s has both extension and headgear set.\n",  item->id);
		}
	}

	return result;
}
Example #12
0
/**
 * @brief Draw an item node
 */
void uiItemNode::draw (uiNode_t *node)
{
	const objDef_t *od;
	const char* ref = UI_GetReferenceString(node, EXTRADATA(node).model);
	vec2_t pos;

	if (Q_strnull(ref))
		return;

	UI_GetNodeAbsPos(node, pos);
	R_CleanupDepthBuffer(pos[0], pos[1], node->box.size[0], node->box.size[1]);

	od = INVSH_GetItemByIDSilent(ref);
	if (od) {
		item_t item = {1, NULL, NULL, 0, 0}; /* 1 so it's not reddish; fake item anyway */
		item.t = INVSH_GetItemByIDX(od->idx);

		if (EXTRADATA(node).containerLike || INV_IsArmour(item.t)) {
			const vec4_t color = {1, 1, 1, 1};
			vec3_t itemNodePos;
			/* We position the model of the item ourself (in the middle of the item
			 * node). See the "-1, -1" parameter of UI_DrawItem. */
			UI_GetNodeAbsPos(node, itemNodePos);
			itemNodePos[0] += node->box.size[0] / 2.0;
			itemNodePos[1] += node->box.size[1] / 2.0;
			itemNodePos[2] = 0;
			/** @todo we should not use DrawItem but draw the image with render function (remove dependency with container) */
			UI_DrawItem(node, itemNodePos, &item, -1, -1, EXTRADATA(node).scale, color);
		} else {
			UI_DrawModelNode(node, GAME_GetModelForItem(item.t, NULL));
		}
	} else {
		GAME_DisplayItemInfo(node, ref);
	}
}
Example #13
0
/**
 * @brief Fills the ground container of the ui_inventory with unused items from a given
 * equipment definition
 * @note Keep in mind that @c ed is changed here - so items are removed and the ground container
 * of a inventory definition is in general a temp container - that means you should make a copy
 * of the @c equipDef_t you want to add to the temp ground container of the given @c inv
 * @todo it's not obvious for the caller that @c ui_inventory pointer must be set
 * @param[in,out] inv The inventory to add the unused items from @c ed to
 * @param[in,out] ed The equipment definition to get the used items from that should be added
 * to the ground container of @c inv
 * @todo not used nor called by the container node; should be move somewhere else
 */
void UI_ContainerNodeUpdateEquipment (inventory_t *inv, const equipDef_t *ed)
{
	int i;
	int *const numItems = Mem_Dup(int, ed->numItems, lengthof(ed->numItems));

	/* a 'tiny hack' to add the remaining equipment (not carried)
	 * correctly into buy categories, reloading at the same time;
	 * it is valid only due to the following property: */
	assert(MAX_CONTAINERS >= FILTER_AIRCRAFT);

	for (i = 0; i < csi.numODs; i++) {
		const objDef_t *od = INVSH_GetItemByIDX(i);
		/* Don't allow to show unuseable items. */
		if (!GAME_ItemIsUseable(od))
			continue;

		while (numItems[i]) {
			const item_t item = {NONE_AMMO, NULL, od, 0, 0};
			if (!cls.i.AddToInventory(&cls.i, inv, &item, INVDEF(csi.idEquip), NONE, NONE, 1)) {
				/* no space left in the inventory */
				break;
			}
			numItems[item.item->idx]--;
		}
	}

	Mem_Free(numItems);

	/* First-time linking of ui_inventory. */
	if (ui_inventory && !ui_inventory->c[csi.idEquip]) {
		ui_inventory->c[csi.idEquip] = inv->c[csi.idEquip];
	}
}
Example #14
0
/**
 * @sa G_WriteItem
 * @sa G_ReadItem
 * @note The amount of the item_t struct should not be needed here - because
 * the amount is only valid for idFloor and idEquip
 */
static void CL_NetReceiveItem (dbuffer *buf, item_t *item, containerIndex_t *container, int *x, int *y)
{
	const eventRegister_t *eventData = CL_GetEvent(EV_INV_TRANSFER);

	/* reset */
	int t, m;
	item->item = item->ammo = NULL;
	item->ammoLeft = NONE_AMMO;
	NET_ReadFormat(buf, eventData->formatString, &t, &item->ammoLeft, &m, container, x, y, &item->rotated, &item->amount);

	item->item = INVSH_GetItemByIDX(t);
	item->ammo = INVSH_GetItemByIDX(m);

	if (!item->item)
		Com_Error(ERR_DROP, "no weapon given for item");
}
/**
 * @brief Update the GUI with the selected item
 */
static void INV_UpdateObject_f (void)
{
    /* check syntax */
    if (Cmd_Argc() < 3) {
        Com_Printf("Usage: %s <objectid> <confunc> [mustwechangetab]\n", Cmd_Argv(0));
        return;
    }

    bool changeTab = true;
    if (Cmd_Argc() == 4)
        changeTab = atoi(Cmd_Argv(3)) >= 1;

    const int num = atoi(Cmd_Argv(1));
    if (num < 0 || num >= csi.numODs) {
        Com_Printf("Id %i out of range 0..%i\n", num, csi.numODs);
        return;
    }
    const objDef_t* obj = INVSH_GetItemByIDX(num);

    /* update tab */
    if (changeTab) {
        const cvar_t* var = Cvar_FindVar("mn_equiptype");
        const int filter = INV_GetFilterFromItem(obj);
        if (var && var->integer != filter) {
            Cvar_SetValue("mn_equiptype", filter);
            UI_ExecuteConfunc("%s", Cmd_Argv(2));
        }
    }

    /* update item description */
    INV_ItemDescription(obj);
}
Example #16
0
/**
 * @brief Get the correct animation for the given actor state and weapons
 * @param[in] anim Type of animation (for example "stand", "walk")
 * @param[in] right ods index to determine the weapon in the actors right hand
 * @param[in] left ods index to determine the weapon in the actors left hand
 * @param[in] state the actors state - e.g. STATE_CROUCHED (crouched animations)
 * have a 'c' in front of their animation definitions (see *.anm files for
 * characters)
 */
const char* LE_GetAnim (const char* anim, int right, int left, int state)
{
	if (!anim)
		return "";

	static char retAnim[MAX_VAR];
	char* mod = retAnim;
	size_t length = sizeof(retAnim);

	/* add crouched flag */
	if (state & STATE_CROUCHED) {
		*mod++ = 'c';
		length--;
	}

	/* determine relevant data */
	char animationIndex;
	char const* type;
	if (right == NONE) {
		animationIndex = '0';
		if (left == NONE)
			type = "item";
		else {
			type = INVSH_GetItemByIDX(left)->type;
			/* left hand grenades look OK with default anim; others don't */
			if (!Q_streq(type, "grenade")) {
				type = "pistol_d";
			}
		}
	} else {
		const objDef_t* od = INVSH_GetItemByIDX(right);
		animationIndex = od->animationIndex;
		type = od->type;
		if (left != NONE && Q_streq(od->type, "pistol") && Q_streq(INVSH_GetItemByIDX(left)->type, "pistol")) {
			type = "pistol_d";
		}
	}

	if (Q_strstart(anim, "stand") || Q_strstart(anim, "walk")) {
		Com_sprintf(mod, length, "%s%c", anim, animationIndex);
	} else {
		Com_sprintf(mod, length, "%s_%s", anim, type);
	}

	return retAnim;
}
Example #17
0
/**
 * @sa G_WriteItem
 * @sa G_ReadItem
 * @note The amount of the Item should not be needed here - because
 * the amount is only valid for CID_FLOOR and CID_EQUIP
 */
static void CL_NetReceiveItem (dbuffer* buf, Item* item, containerIndex_t* container, int* x, int* y)
{
	const eventRegister_t* eventData = CL_GetEvent(EV_INV_TRANSFER);

	/* reset */
	int itemIdx, ammoIdx;
	int ammoleft = NONE_AMMO;
	int amount = 0;
	item->setDef(nullptr);
	item->setAmmoDef(nullptr);
	NET_ReadFormat(buf, eventData->formatString, &itemIdx, &ammoleft, &ammoIdx, container, x, y, &item->rotated, &amount);
	item->setAmmoLeft(ammoleft);
	item->setAmount(amount);
	item->setDef(INVSH_GetItemByIDX(itemIdx));
	item->setAmmoDef(INVSH_GetItemByIDX(ammoIdx));

	if (!item->def())
		Com_Error(ERR_DROP, "no weapon given for item");
}
Example #18
0
static void testItemMassActions (void)
{
	ResetInventoryList();

	const objDef_t* od = INVSH_GetItemByIDSilent("assault");
	CU_ASSERT_PTR_NOT_NULL_FATAL(od);

	const invDef_t* container = INVSH_GetInventoryDefinitionByID("right");
	CU_ASSERT_PTR_NOT_NULL_FATAL(container);

	Inventory inv;
	bool addedItem = testAddSingle(&inv, od, container);
	CU_ASSERT(addedItem == true);

	/* second try should fail as the right container is a single container */
	addedItem = testAddSingle(&inv, od, container);
	CU_ASSERT(addedItem == false);

	container = INVSH_GetInventoryDefinitionByID("left");
	CU_ASSERT_PTR_NOT_NULL_FATAL(container);

	od = INVSH_GetItemByIDSilent("fraggrenade");
	CU_ASSERT_PTR_NOT_NULL_FATAL(od);

	addedItem = testAddSingle(&inv, od, container);
	CU_ASSERT(addedItem == true);

	container = INVSH_GetInventoryDefinitionByID("equip");
	CU_ASSERT_PTR_NOT_NULL_FATAL(container);

	for (int i = 0; i < csi.numODs; i++) {
		od = INVSH_GetItemByIDX(i);
		/* every item should be placable on the ground container and there should really be enough space */
		addedItem = testAddSingle(&inv, od, container);
		CU_ASSERT(addedItem == true);
		addedItem = testAddSingle(&inv, od, container);
		CU_ASSERT(addedItem == true);
		addedItem = testAddSingle(&inv, od, container);
		CU_ASSERT(addedItem == true);
		for (int j = 0; j < od->numAmmos; j++) {
			addedItem = testAddSingle(&inv, od->ammos[j], container);
			CU_ASSERT(addedItem == true);
			addedItem = testAddSingle(&inv, od->ammos[j], container);
			CU_ASSERT(addedItem == true);
			addedItem = testAddSingle(&inv, od->ammos[j], container);
			CU_ASSERT(addedItem == true);
			addedItem = testAddSingle(&inv, od->ammos[j], container);
			CU_ASSERT(addedItem == true);
			addedItem = testAddSingle(&inv, od->ammos[j], container);
			CU_ASSERT(addedItem == true);
			addedItem = testAddSingle(&inv, od->ammos[j], container);
			CU_ASSERT(addedItem == true);
		}
	}
}
Example #19
0
static void testTeamDefsModelScriptData (void)
{
	int i;
	linkedList_t *armourPaths = NULL;

	for (i = 0; i < csi.numTeamDefs; i++) {
		int j;
		const teamDef_t *teamDef = &csi.teamDef[i];
		if (!teamDef->armour)
			continue;

		for (j = 0; j < csi.numODs; j++) {
			const objDef_t *od = INVSH_GetItemByIDX(j);
			if (!INV_IsArmour(od))
				continue;

			/* not for this team */
			if (!CHRSH_IsArmourUseableForTeam(od, teamDef))
				continue;

			if (!LIST_ContainsString(armourPaths, od->armourPath))
				LIST_AddString(&armourPaths, od->armourPath);
		}

		UFO_CU_ASSERT_TRUE_MSG(!LIST_IsEmpty(armourPaths), va("no armour definitions found for team %s - but armour is set to true",
				teamDef->id));

		LIST_Foreach(armourPaths, char const, armourPath) {
			int l;

			for (l = NAME_NEUTRAL; l < NAME_LAST; l++) {
				/* no models for this gender */
				if (!teamDef->numModels[l])
					continue;

				CU_ASSERT_PTR_NOT_NULL_FATAL(teamDef->models[l]);

				for (linkedList_t const* list = teamDef->models[l]; list; list = list->next) {
					teamDef_t::model_t const& m = *static_cast<teamDef_t::model_t const*>(list->data);

					UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s/%s", m.path, m.body)), va("%s does not exist in models/%s (teamDef: %s)",
							m.body, m.path, teamDef->id));
					UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s%s/%s", m.path, armourPath, m.body)), va("%s does not exist in models/%s%s (teamDef: %s)",
							m.body, m.path, armourPath, teamDef->id));

					UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s/%s", m.path, m.head)), va("%s does not exist in models/%s (teamDef: %s)",
							m.head, m.path, teamDef->id));
					UFO_CU_ASSERT_TRUE_MSG(TEST_CheckModel(va("%s%s/%s", m.path, armourPath, m.head)), va("%s does not exist in models/%s%s (teamDef: %s)",
							m.head, m.path, armourPath, teamDef->id));
				}
			}
		}

		LIST_Delete(&armourPaths);
	}
Example #20
0
/**
 * @brief Compute the next itemID
 * @note If something found, item type can be find with iterator->itemID
 * @note If item is available into the container iterator->itemFound point to this element
 * @note If nothing found (no next element) then iterator->itemID >= csi.numODs
 */
static void UI_ContainerItemIteratorNext (containerItemIterator_t* iterator)
{
	assert(iterator->groupSteps[iterator->groupID] != CII_END);

	/* iterate each groups */
	for (; iterator->groupSteps[iterator->groupID] != CII_END; iterator->groupID++) {
		int filter = iterator->groupSteps[iterator->groupID];
		/* next */
		iterator->itemID++;

		/* iterate all item type*/
		for (;iterator->itemID < csi.numODs; iterator->itemID++) {
			const objDef_t* obj = INVSH_GetItemByIDX(iterator->itemID);

			/* gameplay filter */
			if (!GAME_ItemIsUseable(obj))
				continue;

			/* type filter */
			/** @todo not sure its the right check */
			const bool isArmour = obj->isArmour();
			const bool isAmmo = obj->numWeapons != 0 && obj->isAmmo();
			const bool isWeapon = obj->weapon || obj->isMisc || isArmour;
			const bool isImplant = obj->implant;

			if ((filter & CII_WEAPONONLY) && !isWeapon)
				continue;
			if ((filter & CII_AMMOONLY) && !isAmmo)
				continue;
			if ((filter & CII_IMPLANTONLY) && !isImplant)
				continue;
			if (!INV_ItemMatchesFilter(obj, iterator->filterEquipType))
				continue;

			/* exists in inventory filter */
			iterator->itemFound = UI_ContainerNodeGetExistingItem(iterator->node, obj, iterator->filterEquipType);
			if ((filter & CII_AVAILABLEONLY) && iterator->itemFound == nullptr)
				continue;
			if ((filter & CII_NOTAVAILABLEONLY) && iterator->itemFound != nullptr)
				continue;

			/* we found something */
			return;
		}

		/* can we search into another group? */
		if (iterator->groupSteps[iterator->groupID + 1] != CII_END)
			iterator->itemID = -1;
	}

	/* clean up */
	iterator->itemFound = nullptr;
}
Example #21
0
/**
 * @brief Unloads transfer cargo when finishing the transfer or destroys it when no buildings/base.
 * @param[in,out] destination The destination base - might be NULL in case the base
 * is already destroyed
 * @param[in] transfer Pointer to transfer in ccs.transfers.
 * @param[in] success True if the transfer reaches dest base, false if the base got destroyed.
 * @sa TR_TransferEnd
 */
static void TR_EmptyTransferCargo (base_t *destination, transfer_t *transfer, qboolean success)
{
	assert(transfer);

	if (transfer->hasItems && success) {	/* Items. */
		const objDef_t *od = INVSH_GetItemByID(ANTIMATTER_TECH_ID);
		int i;

		/* antimatter */
		if (transfer->itemAmount[od->idx] > 0) {
			if (B_GetBuildingStatus(destination, B_ANTIMATTER)) {
				B_ManageAntimatter(destination, transfer->itemAmount[od->idx], qtrue);
			} else {
				Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s does not have Antimatter Storage, antimatter are removed!"), destination->name);
				MSO_CheckAddNewMessage(NT_TRANSFER_LOST, _("Transport mission"), cp_messageBuffer, qfalse, MSG_TRANSFERFINISHED, NULL);
			}
		}
		/* items */
		for (i = 0; i < csi.numODs; i++) {
			od = INVSH_GetItemByIDX(i);

			if (transfer->itemAmount[od->idx] <= 0)
				continue;
			if (!B_ItemIsStoredInBaseStorage(od))
				continue;
			if (!B_GetBuildingStatus(destination, B_STORAGE)) {
				Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s does not have Storage, items are removed!"), destination->name);
				MSO_CheckAddNewMessage(NT_TRANSFER_LOST, _("Transport mission"), cp_messageBuffer, qfalse, MSG_TRANSFERFINISHED, NULL);
				break;
			}
			B_UpdateStorageAndCapacity(destination, od, transfer->itemAmount[od->idx], qfalse, qtrue);
		}
	}

	if (transfer->hasEmployees && transfer->srcBase) {	/* Employees. (cannot come from a mission) */
		if (!success || !B_GetBuildingStatus(destination, B_QUARTERS)) {	/* Employees will be unhired. */
			employeeType_t i;
			if (success) {
				Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s does not have Living Quarters, employees got unhired!"), destination->name);
				MSO_CheckAddNewMessage(NT_TRANSFER_LOST, _("Transport mission"), cp_messageBuffer, qfalse, MSG_TRANSFERFINISHED, NULL);
			}
			for (i = EMPL_SOLDIER; i < MAX_EMPL; i++) {
				employee_t *employee;
				TR_ForeachEmployee(employee, transfer, i) {
					employee->baseHired = transfer->srcBase;	/* Restore back the original baseid. */
					employee->transfer = qfalse;
					E_UnhireEmployee(employee);
				}
			}
		} else {
Example #22
0
/**
 * @brief Update Storage Capacity.
 * @param[in] base Pointer to the base
 * @sa B_ResetAllStatusAndCapacities_f
 */
void CAP_UpdateStorageCap (base_t* base)
{
	CAP_SetCurrent(base, CAP_ITEMS, 0);

	for (int i = 0; i < cgi->csi->numODs; i++) {
		const objDef_t* obj = INVSH_GetItemByIDX(i);

		if (!B_ItemIsStoredInBaseStorage(obj))
			continue;

		CAP_AddCurrent(base, CAP_ITEMS, B_ItemInBase(obj, base) * obj->size);
	}

	/* UGV takes room in storage capacity */
	CAP_AddCurrent(base, CAP_ITEMS, UGV_SIZE * E_CountHired(base, EMPL_ROBOT));
}
/**
 * @brief Shoot with weapon but don't bother with animations - actor is hidden.
 * @sa CL_ActorShoot
 */
void CL_ActorShootHidden (const eventRegister_t* self, dbuffer* msg)
{
	int first;
	int objIdx;
	weaponFireDefIndex_t weapFdsIdx;
	fireDefIndex_t fdIdx;

	NET_ReadFormat(msg, self->formatString, &first, &objIdx, &weapFdsIdx, &fdIdx);

	/* get the fire def */
	const objDef_t* obj = INVSH_GetItemByIDX(objIdx);
	const fireDef_t* fd = FIRESH_GetFiredef(obj, weapFdsIdx, fdIdx);

	/* start the sound */
	if ((first || !fd->soundOnce) && fd->fireSound != nullptr)
		S_StartLocalSample(fd->fireSound, SND_VOLUME_WEAPONS);
}
Example #24
0
/**
 * @brief sets market prices at start of the game
 * @sa CP_CampaignInit
 * @sa B_SetUpFirstBase
 * @sa BS_Load (Market load function)
 */
void BS_InitMarket (const campaign_t* campaign)
{
	int i;
	market_t* market = BS_GetMarket();

	for (i = 0; i < cgi->csi->numODs; i++) {
		const objDef_t* od = INVSH_GetItemByIDX(i);
		if (market->askItems[i] == 0) {
			market->askItems[i] = od->price;
			market->bidItems[i] = floor(market->askItems[i] * BID_FACTOR);
		}

		if (campaign->marketDef->numItems[i] <= 0)
			continue;

		if (RS_IsResearched_ptr(RS_GetTechForItem(od))) {
			/* the other relevant values were already set above */
			market->numItems[i] = campaign->marketDef->numItems[i];
		} else {
			Com_Printf("BS_InitMarket: Could not add item %s to the market - not marked as researched in campaign %s\n",
					od->id, campaign->id);
		}
	}

	for (i = 0; i < AIRCRAFTTYPE_MAX; i++) {
		const char* name = cgi->Com_DropShipTypeToShortName((humanAircraftType_t)i);
		const aircraft_t* aircraft = AIR_GetAircraft(name);
		if (market->askAircraft[i] == 0) {
			market->askAircraft[i] = aircraft->price;
			market->bidAircraft[i] = floor(market->askAircraft[i] * BID_FACTOR);
		}

		if (campaign->marketDef->numAircraft[i] <= 0)
			continue;

		if (RS_IsResearched_ptr(aircraft->tech)) {
			/* the other relevant values were already set above */
			market->numAircraft[i] = campaign->marketDef->numAircraft[i];
		} else {
			Com_Printf("BS_InitMarket: Could not add aircraft %s to the market - not marked as researched in campaign %s\n",
					aircraft->id, campaign->id);
		}
	}
}
/**
 * @brief Network event function for reaction fire mode changes. Responsible for updating
 * the HUD with the information that were received from the server
 * @param self The event pointer
 * @param msg The network message to parse the event data from
 * @sa HUD_UpdateReactionFiremodes
 */
void CL_ActorReactionFireChange (const eventRegister_t* self, dbuffer* msg)
{
	actorHands_t hand;
	int entnum, fmIdx, odIdx;

	NET_ReadFormat(msg, self->formatString, &entnum, &fmIdx, &hand, &odIdx);

	const le_t* le = LE_Get(entnum);
	if (!le)
		LE_NotFoundError(entnum);

	character_t* chr = CL_ActorGetChr(le);
	if (!chr)
		return;

	const objDef_t* od = INVSH_GetItemByIDX(odIdx);
	chr->RFmode.set(hand, fmIdx, od);

	UI_ExecuteConfunc("reactionfire_updated");
}
Example #26
0
/**
 * @brief Unloads transfer cargo when finishing the transfer or destroys it when no buildings/base.
 * @param[in,out] destination The destination base - might be nullptr in case the base
 * is already destroyed
 * @param[in] transfer Pointer to transfer in ccs.transfers.
 * @param[in] success True if the transfer reaches dest base, false if the base got destroyed.
 * @sa TR_TransferEnd
 */
static void TR_EmptyTransferCargo (base_t* destination, transfer_t* transfer, bool success)
{
	assert(transfer);

	if (transfer->hasItems && success) {	/* Items. */
		const objDef_t* od = INVSH_GetItemByID(ANTIMATTER_ITEM_ID);
		int i;

		/* antimatter */
		if (transfer->itemAmount[od->idx] > 0) {
			if (B_GetBuildingStatus(destination, B_ANTIMATTER)) {
				B_ManageAntimatter(destination, transfer->itemAmount[od->idx], true);
			} else {
				Com_sprintf(cp_messageBuffer, sizeof(cp_messageBuffer), _("%s does not have Antimatter Storage, antimatter are removed!"), destination->name);
				MSO_CheckAddNewMessage(NT_TRANSFER_LOST, _("Transport mission"), cp_messageBuffer, MSG_TRANSFERFINISHED);
			}
		}
		/* items */
		for (i = 0; i < cgi->csi->numODs; i++) {
			od = INVSH_GetItemByIDX(i);

			if (transfer->itemAmount[od->idx] <= 0)
				continue;
			if (!B_ItemIsStoredInBaseStorage(od))
				continue;
			B_AddToStorage(destination, od, transfer->itemAmount[od->idx]);
		}
	}

	if (transfer->hasEmployees && transfer->srcBase) {	/* Employees. (cannot come from a mission) */
		if (!success) {	/* Employees will be unhired. */
			for (int i = EMPL_SOLDIER; i < MAX_EMPL; i++) {
				const employeeType_t type = (employeeType_t)i;
				TR_ForeachEmployee(employee, transfer, type) {
					employee->baseHired = transfer->srcBase;	/* Restore back the original baseid. */
					employee->transfer = false;
					employee->unhire();
				}
			}
		} else {
			for (int i = EMPL_SOLDIER; i < MAX_EMPL; i++) {
Example #27
0
/**
 * @brief Decides if following events should be delayed. If the projectile has a speed value assigned, the
 * delay is relative to the distance the projectile flies. There are other fire definition related options
 * that might delay the execution of further events.
 */
int CL_ActorDoShootTime (const eventRegister_t* self, dbuffer* msg, eventTiming_t* eventTiming)
{
	int flags, dummy;
	int objIdx, surfaceFlags;
	int weap_fds_idx, fd_idx;
	shoot_types_t shootType;
	vec3_t muzzle, impact;
	int eventTime = eventTiming->shootTime;

	/* read data */
	NET_ReadFormat(msg, self->formatString, &dummy, &dummy, &dummy, &objIdx, &weap_fds_idx, &fd_idx, &shootType, &flags,
			&surfaceFlags, &muzzle, &impact, &dummy);

	const objDef_t* obj = INVSH_GetItemByIDX(objIdx);
	const fireDef_t* fd = FIRESH_GetFiredef(obj, weap_fds_idx, fd_idx);

	if (!(flags & SF_BOUNCED)) {
		/* shooting */
		if (fd->speed > 0.0 && !CL_OutsideMap(impact, UNIT_SIZE * 10)) {
			eventTiming->impactTime = eventTiming->shootTime + 1000 * VectorDist(muzzle, impact) / fd->speed;
		} else {
			eventTiming->impactTime = eventTiming->shootTime;
		}
		if (!cls.isOurRound())
			eventTiming->nextTime = CL_GetNextTime(self, eventTiming, eventTiming->impactTime + 1400);
		else
			eventTiming->nextTime = CL_GetNextTime(self, eventTiming, eventTiming->impactTime + 400);
		if (fd->delayBetweenShots > 0.0)
			eventTiming->shootTime += 1000 / fd->delayBetweenShots;
	} else {
		/* only a bounced shot */
		eventTime = eventTiming->impactTime;
		if (fd->speed > 0.0) {
			eventTiming->impactTime += 1000 * VectorDist(muzzle, impact) / fd->speed;
			eventTiming->nextTime = CL_GetNextTime(self, eventTiming, eventTiming->impactTime);
		}
	}
	eventTiming->parsedDeath = false;

	return eventTime;
}
Example #28
0
void CL_InvReload (const eventRegister_t* self, dbuffer* msg)
{
	int		number;
	int		ammo, type, x, y;
	containerIndex_t container;

	NET_ReadFormat(msg, self->formatString, &number, &ammo, &type, &container, &x, &y);

	le_t* le = LE_Get(number);
	if (!le)
		return;

	if (le->team != cls.team)
		return;

	assert(container >= 0);
	assert(container < MAX_INVDEFS);
	Item* ic = le->inv.getItemAtPos(INVDEF(container), x, y);
	if (!ic)
		return;

	S_LoadAndPlaySample(ic->def()->reloadSound, le->origin, ic->def()->reloadAttenuation, SND_VOLUME_WEAPONS);

	/* if the displaced clip had any remaining bullets
	 * store them as loose, unless the removed clip was full */
	equipDef_t* ed = GAME_GetEquipmentDefinition();
	if (ed && ic->getAmmoLeft() > 0 && ic->getAmmoLeft() != ic->def()->ammo) {
		assert(ammo == ic->def()->ammo);
		/* Accumulate loose ammo into clips (only accessible post-mission) */
		ed->addClip(ic);
	}

	/* set new ammo */
	ic->setAmmoLeft(ammo);
	ic->setAmmoDef(INVSH_GetItemByIDX(type));

	if (le == selActor)
		Cmd_ExecuteString("hud_updateactorload");
}
Example #29
0
/**
 * @brief Lists all object definitions.
 * @note called with debug_listinventory
 */
static void INV_InventoryList_f (void)
{
	int i;

	for (i = 0; i < csi.numODs; i++) {
		int j;
		const objDef_t *od = INVSH_GetItemByIDX(i);

		Com_Printf("Item: %s\n", od->id);
		Com_Printf("... name          -> %s\n", od->name);
		Com_Printf("... type          -> %s\n", od->type);
		Com_Printf("... category      -> %i\n", od->animationIndex);
		Com_Printf("... weapon        -> %i\n", od->weapon);
		Com_Printf("... holdtwohanded -> %i\n", od->holdTwoHanded);
		Com_Printf("... firetwohanded -> %i\n", od->fireTwoHanded);
		Com_Printf("... thrown        -> %i\n", od->thrown);
		Com_Printf("... usable for weapon (if type is ammo):\n");
		for (j = 0; j < od->numWeapons; j++) {
			if (od->weapons[j])
				Com_Printf("    ... %s\n", od->weapons[j]->name);
		}
		Com_Printf("\n");
	}
}
Example #30
0
/**
 * @brief make number of items change every day.
 * @sa CP_CampaignRun
 * @sa daily called
 * @note This function makes items number on market slowly reach the asymptotic number of items defined in equipment.ufo
 * If an item has just been researched, it's not available on market until RESEARCH_LIMIT_DELAY days is reached.
 */
void CP_CampaignRunMarket (campaign_t* campaign)
{
	int i;
	const float TYPICAL_TIME = 10.f;			/**< Number of days to reach the asymptotic number of items */
	const int RESEARCH_LIMIT_DELAY = 30;		/**< Numbers of days after end of research to wait in order to have
												 * items added on market */
	market_t* market = BS_GetMarket();

	assert(campaign->marketDef);
	assert(campaign->asymptoticMarketDef);

	for (i = 0; i < cgi->csi->numODs; i++) {
		const objDef_t* od = INVSH_GetItemByIDX(i);
		const technology_t* tech = RS_GetTechForItem(od);
		int asymptoticNumber;

		if (RS_IsResearched_ptr(tech) && (campaign->marketDef->numItems[i] != 0 || ccs.date.day > tech->researchedDate.day + RESEARCH_LIMIT_DELAY)) {
			/* if items are researched for more than RESEARCH_LIMIT_DELAY or was on the initial market,
			 * there number tend to the value defined in equipment.ufo.
			 * This value is the asymptotic value if it is not 0, or initial value else */
			asymptoticNumber = campaign->asymptoticMarketDef->numItems[i] ? campaign->asymptoticMarketDef->numItems[i] : campaign->marketDef->numItems[i];
		} else {
			/* items that have just been researched don't appear on market, but they can disappear */
			asymptoticNumber = 0;
		}

		/* Store the evolution of the market in currentEvolution */
		market->currentEvolutionItems[i] += (asymptoticNumber - market->numItems[i]) / TYPICAL_TIME;

		/* Check if new items appeared or disappeared on market */
		if (fabs(market->currentEvolutionItems[i]) >= 1.0f) {
			const int num = (int)(market->currentEvolutionItems[i]);
			if (num >= 0)
				BS_AddItemToMarket(od, num);
			else
				BS_RemoveItemFromMarket(od, -num);
			market->currentEvolutionItems[i] -= num;
		}
	}

	for (i = 0; i < AIRCRAFTTYPE_MAX; i++) {
		const humanAircraftType_t type = (humanAircraftType_t)i;
		const char* aircraftID = cgi->Com_DropShipTypeToShortName(type);
		const aircraft_t* aircraft = AIR_GetAircraft(aircraftID);
		const technology_t* tech = aircraft->tech;
		int asymptoticNumber;

		if (RS_IsResearched_ptr(tech) && (campaign->marketDef->numAircraft[i] != 0 || ccs.date.day > tech->researchedDate.day + RESEARCH_LIMIT_DELAY)) {
			/* if aircraft is researched for more than RESEARCH_LIMIT_DELAY or was on the initial market,
			 * there number tend to the value defined in equipment.ufo.
			 * This value is the asymptotic value if it is not 0, or initial value else */
			asymptoticNumber = campaign->asymptoticMarketDef->numAircraft[i] ? campaign->asymptoticMarketDef->numAircraft[i] : campaign->marketDef->numAircraft[i];
		} else {
			/* items that have just been researched don't appear on market, but they can disappear */
			asymptoticNumber = 0;
		}
		/* Store the evolution of the market in currentEvolution */
		market->currentEvolutionAircraft[i] += (asymptoticNumber - market->numAircraft[i]) / TYPICAL_TIME;

		/* Check if new items appeared or disappeared on market */
		if (fabs(market->currentEvolutionAircraft[i]) >= 1.0f) {
			const int num = (int)(market->currentEvolutionAircraft[i]);
			if (num >= 0)
				BS_AddAircraftToMarket(aircraft, num);
			else
				BS_RemoveAircraftFromMarket(aircraft, -num);
			market->currentEvolutionAircraft[i] -= num;
		}
	}
}