TEST_F(GameTest, InventoryForDiedAlien) { const char* mapName = "test_game"; ASSERT_NE(-1, FS_CheckFile("maps/%s.bsp", mapName)) << "Map resource '" << mapName << ".bsp' for test is missing."; Actor* diedEnt; Actor* actor; Edict* floorItems; Item* invlist; int count; SV_Map(true, mapName, nullptr); level.activeTeam = TEAM_ALIEN; /* first alien that should die and drop its inventory */ diedEnt = G_EdictsGetNextLivingActorOfTeam(nullptr, TEAM_ALIEN); ASSERT_TRUE(nullptr != diedEnt); diedEnt->HP = 0; ASSERT_TRUE(G_ActorDieOrStun(diedEnt, nullptr)); ASSERT_TRUE(diedEnt->isDead()); /* now try to collect the inventory with a second alien */ actor = G_EdictsGetNextLivingActorOfTeam(nullptr, TEAM_ALIEN); ASSERT_TRUE(nullptr != actor); /* move to the location of the first died alien to drop the inventory into the same floor container */ Player& player = actor->getPlayer(); ASSERT_TRUE(G_IsAIPlayer(&player)); G_ClientMove(player, 0, actor, diedEnt->pos); ASSERT_TRUE(VectorCompare(actor->pos, diedEnt->pos)); floorItems = G_GetFloorItems(actor); ASSERT_TRUE(nullptr != floorItems); ASSERT_EQ(floorItems->getFloor(), actor->getFloor()); /* drop everything to floor to make sure we have space in the backpack */ G_InventoryToFloor(actor); ASSERT_EQ(0, GAMETEST_GetItemCount(actor, CID_BACKPACK)); invlist = actor->getContainer(CID_BACKPACK); ASSERT_TRUE(nullptr == invlist); count = GAMETEST_GetItemCount(actor, CID_FLOOR); if (count > 0) { Item* entryToMove = actor->getFloor(); int tx, ty; actor->chr.inv.findSpace(INVDEF(CID_BACKPACK), entryToMove, &tx, &ty, entryToMove); if (tx == NONE) return; Com_Printf("trying to move item %s from floor into backpack to pos %i:%i\n", entryToMove->def()->name, tx, ty); ASSERT_TRUE(G_ActorInvMove(actor, INVDEF(CID_FLOOR), entryToMove, INVDEF(CID_BACKPACK), tx, ty, false)); ASSERT_EQ(count - 1, GAMETEST_GetItemCount(actor, CID_FLOOR)) << "item " << entryToMove->def()->name << " could not get moved successfully from floor into backpack"; Com_Printf("item %s was removed from floor\n", entryToMove->def()->name); ASSERT_EQ(1, GAMETEST_GetItemCount(actor, CID_BACKPACK)) << "item " << entryToMove->def()->name << " could not get moved successfully from floor into backpack"; Com_Printf("item %s was moved successfully into the backpack\n", entryToMove->def()->name); invlist = actor->getContainer(CID_BACKPACK); ASSERT_TRUE(nullptr != invlist); } }
/** * @brief Debug function to print a player's inventory */ void G_InvList_f (const Player& player) { Edict* ent = nullptr; gi.DPrintf("Print inventory for '%s'\n", player.pers.netname); while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, player.getTeam()))) { gi.DPrintf("actor: '%s'\n", ent->chr.name); const Container* cont = nullptr; while ((cont = ent->chr.inv.getNextCont(cont, true))) { Com_Printf("Container: %i\n", cont->id); Item* item = nullptr; while ((item = cont->getNextItem(item))) { Com_Printf(".. item.def(): %i, item.ammo: %i, item.ammoLeft: %i, x: %i, y: %i\n", (item->def() ? item->def()->idx : NONE), (item->ammoDef() ? item->ammoDef()->idx : NONE), item->getAmmoLeft(), item->getX(), item->getY()); if (item->def()) Com_Printf(".... weapon: %s\n", item->def()->id); if (item->ammoDef()) Com_Printf(".... ammo: %s (%i)\n", item->ammoDef()->id, item->getAmmoLeft()); } } const float invWeight = ent->chr.inv.getWeight(); const int maxWeight = ent->chr.score.skills[ABILITY_POWER]; const float penalty = GET_ENCUMBRANCE_PENALTY(invWeight, maxWeight); const int normalTU = GET_TU(ent->chr.score.skills[ABILITY_SPEED], 1.0f - WEIGHT_NORMAL_PENALTY); const int tus = GET_TU(ent->chr.score.skills[ABILITY_SPEED], penalty); const int tuPenalty = tus - normalTU; const char* penaltyStr = 1.0f - penalty < WEIGHT_NORMAL_PENALTY ? "'Light weight'" : (1.0f - penalty < WEIGHT_HEAVY_PENALTY ? "'Normal weight'" : "'Encumbered'"); Com_Printf("Weight: %g/%i, Encumbrance: %s (%.0f%%), TU's: %i (normal: %i, penalty/bonus: %+i)\n", invWeight, maxWeight, penaltyStr, invWeight / maxWeight * 100.0f, tus, normalTU, tuPenalty); } }
/** * @brief This function does not add statistical values. Because there is no attacker. * The same counts for morale states - they are not affected. * @note: This is a debug function to let a whole team die */ static void G_KillTeam_f (void) { /* default is to kill all teams */ int teamToKill = -1; edict_t *ent = NULL; int amount = -1; /* with a parameter we will be able to kill a specific team */ if (gi.Cmd_Argc() >= 2) { teamToKill = atoi(gi.Cmd_Argv(1)); if (gi.Cmd_Argc() == 3) amount = atoi(gi.Cmd_Argv(2)); } Com_DPrintf(DEBUG_GAME, "G_KillTeam: kill team %i\n", teamToKill); if (teamToKill >= 0) { while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, teamToKill))) { if (amount == 0) break; /* die */ ent->HP = 0; G_ActorDieOrStun(ent, NULL); if (teamToKill == TEAM_ALIEN) level.num_kills[TEAM_PHALANX][TEAM_ALIEN]++; else level.num_kills[TEAM_ALIEN][teamToKill]++; amount--; } } /* check for win conditions */ G_MatchEndCheck(); }
/** * @brief Stun all members of a giben team. */ static void G_StunTeam_f (void) { /* default is to kill all teams */ int teamToKill = -1; edict_t *ent = NULL; /* with a parameter we will be able to kill a specific team */ if (gi.Cmd_Argc() == 2) teamToKill = atoi(gi.Cmd_Argv(1)); if (teamToKill >= 0) { while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, teamToKill))) { /* stun */ G_ActorDieOrStun(ent, NULL); if (teamToKill == TEAM_ALIEN) level.num_stuns[TEAM_PHALANX][TEAM_ALIEN]++; else level.num_stuns[TEAM_ALIEN][teamToKill]++; } } /* check for win conditions */ G_MatchEndCheck(); }
/** * @brief Debug function to print a player's inventory */ void G_InvList_f (const player_t *player) { edict_t *ent = NULL; gi.DPrintf("Print inventory for '%s'\n", player->pers.netname); while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, player->pers.team))) { containerIndex_t container; gi.DPrintf("actor: '%s'\n", ent->chr.name); for (container = 0; container < gi.csi->numIDs; container++) { const invList_t *ic = CONTAINER(ent, container); Com_Printf("Container: %i\n", container); while (ic) { Com_Printf(".. item.item: %i, item.ammo: %i, item.ammoLeft: %i, x: %i, y: %i\n", (ic->item.item ? ic->item.item->idx : NONE), (ic->item.ammo ? ic->item.ammo->idx : NONE), ic->item.ammoLeft, ic->x, ic->y); if (ic->item.item) Com_Printf(".... weapon: %s\n", ic->item.item->id); if (ic->item.ammo) Com_Printf(".... ammo: %s (%i)\n", ic->item.ammo->id, ic->item.ammoLeft); ic = ic->next; } } } }
/** * @brief Test if point is "visible" from team. * @param[in] team A team to test. * @param[in] point A point to check. * @return true if point is "visible" */ static bool G_TeamPointVis (int team, const vec3_t point) { Edict *from = nullptr; vec3_t eye; /* test if point is visible from team */ while ((from = G_EdictsGetNextLivingActorOfTeam(from, team))) { if (G_FrustumVis(from, point)) { /* get viewers eye height */ G_ActorGetEyeVector(from, eye); /* line of sight */ if (!G_TestLine(eye, point)) { const float distance = VectorDist(from->origin, point); bool blocked = false; /* check visibility in the smoke */ if (distance >= UNIT_SIZE) { Edict *e = nullptr; while ((e = G_EdictsGetNextInUse(e))) { if (G_IsSmoke(e) && RayIntersectAABB(eye, point, e->absmin, e->absmax)) { blocked = true; break; } } } if (!blocked) return true; } } } /* not visible */ return false; }
/** * @brief Checks whether there are still actors to fight with left. If none * are the match end will be triggered. * @sa G_MatchEndTrigger */ void G_MatchEndCheck (void) { int activeTeams; int i, last; if (level.intermissionTime > 0.0) /* already decided */ return; if (!level.numplayers) { G_MatchEndTrigger(0, 0); return; } /** @todo count from 0 to get the civilians for objectives */ for (i = 1, activeTeams = 0, last = 0; i < MAX_TEAMS; i++) { edict_t *ent = NULL; /* search for living but not stunned actors - there must at least be one actor * that is still able to attack or defend himself */ while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, i)) != NULL) { if (!G_IsStunned(ent)) { last = i; activeTeams++; break; } } } /** @todo < 2 does not work when we count civilians */ /* prepare for sending results */ if (activeTeams < 2) { const int timeGap = (level.activeTeam == TEAM_ALIEN ? 10.0 : 3.0); G_MatchEndTrigger(activeTeams == 1 ? last : 0, timeGap); } }
TEST_F(GameTest, InventoryTempContainerLinks) { const char* mapName = "test_game"; ASSERT_NE(-1, FS_CheckFile("maps/%s.bsp", mapName)) << "Map resource '" << mapName << ".bsp' for test is missing."; SV_Map(true, mapName, nullptr); level.activeTeam = TEAM_ALIEN; /* first alien that should die and drop its inventory */ Actor* actor = G_EdictsGetNextLivingActorOfTeam(nullptr, TEAM_ALIEN); int nr = 0; const Container* cont = nullptr; while ((cont = actor->chr.inv.getNextCont(cont, true))) { if (cont->id == CID_ARMOUR || cont->id == CID_FLOOR) continue; nr += cont->countItems(); } ASSERT_TRUE(nr > 0) << "Could not find any items in the inventory of the actor"; ASSERT_TRUE(nullptr == actor->getFloor()); G_InventoryToFloor(actor); ASSERT_TRUE(nullptr != actor->getFloor()); ASSERT_EQ(G_GetFloorItemFromPos(actor->pos)->getFloor(), actor->getFloor()); nr = 0; cont = nullptr; while ((cont = actor->chr.inv.getNextCont(cont, true))) { if (cont->id == CID_ARMOUR || cont->id == CID_FLOOR) continue; nr += cont->countItems(); } ASSERT_EQ(0, nr); }
static void testVisFlags (void) { const char *mapName = "test_game"; if (FS_CheckFile("maps/%s.bsp", mapName) != -1) { edict_t *ent; int num; /* the other tests didn't call the server shutdown function to clean up */ OBJZERO(*sv); SV_Map(true, mapName, NULL); num = 0; ent = NULL; while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, TEAM_ALIEN))) { const teammask_t teamMask = G_TeamToVisMask(ent->team); const bool visible = ent->visflags & teamMask; char *visFlagsBuf = Mem_StrDup(Com_UnsignedIntToBinary(ent->visflags)); char *teamMaskBuf = Mem_StrDup(Com_UnsignedIntToBinary(teamMask)); CU_ASSERT_EQUAL(ent->team, TEAM_ALIEN); UFO_CU_ASSERT_TRUE_MSG(visible, va("visflags: %s, teamMask: %s", visFlagsBuf, teamMaskBuf)); Mem_Free(visFlagsBuf); Mem_Free(teamMaskBuf); num++; } SV_ShutdownGameProgs(); CU_ASSERT_TRUE(num > 0); } else { UFO_CU_FAIL_MSG(va("Map resource '%s.bsp' for test is missing.", mapName)); } }
/** * @brief Guess! Reset all "shaken" states on end of turn? * @note Normally called on end of turn. * @sa G_ClientStateChange * @param[in] team Index of team to loop through. */ void G_ReactionFireReset (int team) { Edict *ent = nullptr; while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, team))) { G_RemoveShaken(ent); } }
static void G_RoundTouchTriggers (int team) { Actor* actor = nullptr; while ((actor = G_EdictsGetNextLivingActorOfTeam(actor, team))) { G_TouchTriggers(actor); } }
/** * @brief Guess! Reset all "shaken" states on end of turn? * @note Normally called on end of turn. * @sa G_ClientStateChange * @param[in] team Index of team to loop through. */ void G_ReactionFireReset (int team) { Actor* actor = nullptr; while ((actor = G_EdictsGetNextLivingActorOfTeam(actor, team))) { actor->removeShaken(); } }
/** * @brief Network function to update the time units (TUs) for each team-member. * @param[in] team The index of the team to update the values for. * @sa G_SendStats */ void G_GiveTimeUnits (int team) { edict_t *ent = NULL; while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, team))) { G_ActorGiveTimeUnits(ent); G_SendStats(ent); } }
/** * @brief Uudates the weight carried for each team member. * @param[in] team The index of the team to update the values for. */ static void G_UpdateCarriedWeight (int team) { Edict* ent = nullptr; while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, team))) { if (ent->chr.scoreMission) { ent->chr.scoreMission->carriedWeight += ent->chr.inv.getWeight(); } } }
/** * @brief Updates the weight carried for each team member. * @param[in] team The index of the team to update the values for. */ static void G_UpdateCarriedWeight (int team) { Actor* actor = nullptr; while ((actor = G_EdictsGetNextLivingActorOfTeam(actor, team))) { if (actor->chr.scoreMission) { actor->chr.scoreMission->carriedWeight += actor->chr.inv.getWeight(); } } }
/** * @brief Applies morale behaviour on actors * @note only called when mor_panic is not zero * @sa G_MoralePanic * @sa G_MoraleRage * @sa G_MoraleStopRage * @sa G_MoraleStopPanic */ void G_MoraleBehaviour (int team) { bool enabled = G_IsMoraleEnabled(team); if (!enabled) return; Edict* ent = nullptr; while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, team)) != nullptr) { /* this only applies to ET_ACTOR but not to ET_ACTOR2x2 */ if (ent->type != ET_ACTOR || CHRSH_IsTeamDefRobot(ent->chr.teamDef)) continue; /* if panic, determine what kind of panic happens: */ if (!G_IsPanicked(ent) && !G_IsRaged(ent)) { if (ent->morale <= mor_panic->integer) { const float ratio = (float) ent->morale / mor_panic->value; const bool sanity = ratio > (m_sanity->value * frand()); if (!sanity) G_SetInsane(ent); if (ratio > (m_rage->value * frand())) G_MoralePanic(ent); else G_MoraleRage(ent); /* if shaken, well .. be shaken; */ } else if (ent->morale <= mor_shaken->integer) { /* shaken is later reset along with reaction fire */ G_SetShaken(ent); G_ClientStateChange(ent->getPlayer(), ent, STATE_REACTION, false); G_EventSendState(G_VisToPM(ent->visflags), *ent); G_ClientPrintf(ent->getPlayer(), PRINT_HUD, _("%s is currently shaken."), ent->chr.name); G_PrintStats("%s is shaken (entnum %i).", ent->chr.name, ent->getIdNum()); } } else { if (G_IsPanicked(ent)) G_MoraleStopPanic(ent); else if (G_IsRaged(ent)) G_MoraleStopRage(ent); } G_ActorSetMaxs(ent); /* morale-regeneration, capped at max: */ int newMorale = ent->morale + MORALE_RANDOM(mor_regeneration->value); const int maxMorale = GET_MORALE(ent->chr.score.skills[ABILITY_MIND]); if (newMorale > maxMorale) ent->morale = maxMorale; else ent->morale = newMorale; /* send phys data and state: */ G_SendStats(*ent); } }
/** * @brief Guess! Reset all "shaken" states on end of turn? * @note Normally called on end of turn. * @sa G_ClientStateChange * @param[in] team Index of team to loop through. */ void G_ReactionFireReset (int team) { edict_t *ent = NULL; while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, team))) { /** @todo why do we send the state here and why do we change the "shaken" * state? - see G_MoraleBehaviour */ G_RemoveShaken(ent); G_EventActorStateChange(G_TeamToPM(ent->team), ent); } }
/** * @brief Regenerate the "STUN" value of each (partly) stunned team member. * @note The values are @b not sent via network. This is done in * @c G_GiveTimeUnits. It @b has to be called afterwards. * @param[in] team The index of the team to update the values for. * @sa G_GiveTimeUnits * @todo Make this depend on the character-attributes. */ static void G_UpdateStunState (int team) { Edict* ent = nullptr; const int regen = 1; while ((ent = G_EdictsGetNextLivingActorOfTeam(ent, team))) { if (ent->STUN > 0) { if (regen > ent->STUN) ent->STUN = 0; else ent->STUN -= regen; G_ActorCheckRevitalise(ent); } } }
static void SVCmd_AddItem_f (void) { const int team = TEAM_DEFAULT; Actor* actor = G_EdictsGetNextLivingActorOfTeam(nullptr, team); if (gi.Cmd_Argc() < 3) { gi.DPrintf("Usage: %s <item-id>\n", gi.Cmd_Argv(1)); return; } if (!actor) { gi.DPrintf("Could not add item, no living members of team %i left\n", team); return; } G_AddItemToFloor(actor->pos, gi.Cmd_Argv(2)); }
/** * @brief Regenerate the "STUN" value of each (partly) stunned team member. * @note The values are @b not sent via network. This is done in * @c G_GiveTimeUnits. It @b has to be called afterwards. * @param[in] team The index of the team to update the values for. * @sa G_GiveTimeUnits * @todo Make this depend on the character-attributes. */ static void G_UpdateStunState (int team) { const int regen = 1; Actor* actor = nullptr; while ((actor = G_EdictsGetNextLivingActorOfTeam(actor, team))) { const int stun = actor->getStun(); if (stun > 0) { if (regen > stun) actor->setStun(0); else actor->addStun(-regen); G_ActorCheckRevitalise(actor); } } }
static void testInventoryTempContainerLinks (void) { const char *mapName = "test_game"; if (FS_CheckFile("maps/%s.bsp", mapName) != -1) { edict_t *ent; int nr; containerIndex_t container; const invList_t *ic; /* the other tests didn't call the server shutdown function to clean up */ OBJZERO(*sv); SV_Map(true, mapName, NULL); level.activeTeam = TEAM_ALIEN; /* first alien that should die and drop its inventory */ ent = G_EdictsGetNextLivingActorOfTeam(NULL, TEAM_ALIEN); nr = 0; for (container = 0; container < CID_MAX; container++) { if (container == CID_ARMOUR || container == CID_FLOOR) continue; for (ic = ent->getContainer(container); ic; ic = ic->getNext()) nr++; } CU_ASSERT_TRUE(nr > 0); CU_ASSERT_PTR_NULL(ent->getFloor()); G_InventoryToFloor(ent); CU_ASSERT_PTR_NOT_NULL(ent->getFloor()); CU_ASSERT_PTR_EQUAL(G_GetFloorItemFromPos(ent->pos)->getFloor(), ent->getFloor()); nr = 0; for (container = 0; container < CID_MAX; container++) { if (container == CID_ARMOUR || container == CID_FLOOR) continue; for (ic = ent->getContainer(container); ic; ic = ic->getNext()) nr++; } CU_ASSERT_EQUAL(nr, 0); SV_ShutdownGameProgs(); } else { UFO_CU_FAIL_MSG(va("Map resource '%s.bsp' for test is missing.", mapName)); } }
/** * @brief Deal damage to each wounded team member. * @param[in] team The index of the team to deal damage to. */ void G_BleedWounds (const int team) { Actor* actor = nullptr; while ((actor = G_EdictsGetNextLivingActorOfTeam(actor, team))) { if (CHRSH_IsTeamDefRobot(actor->chr.teamDef)) continue; const teamDef_t* const teamDef = actor->chr.teamDef; const woundInfo_t& wounds = actor->chr.wounds; int damage = 0; for (int bodyPart = 0; bodyPart < teamDef->bodyTemplate->numBodyParts(); ++bodyPart) if (wounds.woundLevel[bodyPart] > actor->chr.maxHP * teamDef->bodyTemplate->woundThreshold(bodyPart)) damage += wounds.woundLevel[bodyPart] * teamDef->bodyTemplate->bleedingFactor(bodyPart); if (damage > 0) { G_PrintStats("%s is bleeding (damage: %i)", actor->chr.name, damage); G_TakeDamage(actor, damage); G_CheckDeathOrKnockout(actor, nullptr, nullptr, damage); } } /* Maybe the last team member bled to death */ G_MatchEndCheck(); }
/** * @brief Test if point is "visible" from team. * @param[in] team A team to test. * @param[in] point A point to check. * @return true if point is "visible" */ static bool G_TeamPointVis (int team, const vec3_t point) { edict_t *from = NULL; vec3_t eye; /* test if point is visible from team */ while ((from = G_EdictsGetNextLivingActorOfTeam(from, team))) { if (G_FrustumVis(from, point)) { /* get viewers eye height */ VectorCopy(from->origin, eye); if (G_IsCrouched(from)) eye[2] += EYE_CROUCH; else eye[2] += EYE_STAND; /* line of sight */ if (!G_TestLine(eye, point)) return true; } } /* not visible */ return false; }
TEST_F(GameTest, VisFlags) { const char* mapName = "test_game"; ASSERT_NE(-1, FS_CheckFile("maps/%s.bsp", mapName)) << "Map resource '" << mapName << ".bsp' for test is missing."; int num; SV_Map(true, mapName, nullptr); num = 0; Actor* actor = nullptr; while ((actor = G_EdictsGetNextLivingActorOfTeam(actor, TEAM_ALIEN))) { const teammask_t teamMask = G_TeamToVisMask(actor->getTeam()); const bool visible = actor->visflags & teamMask; char* visFlagsBuf = Mem_StrDup(Com_UnsignedIntToBinary(actor->visflags)); char* teamMaskBuf = Mem_StrDup(Com_UnsignedIntToBinary(teamMask)); ASSERT_EQ(actor->getTeam(), TEAM_ALIEN); ASSERT_TRUE(visible) << "visflags: " << visFlagsBuf << ", teamMask: " << teamMaskBuf; Mem_Free(visFlagsBuf); Mem_Free(teamMaskBuf); num++; } ASSERT_TRUE(num > 0) << "No alien actors found"; }
static void testInventoryWithTwoDiedAliensOnTheSameGridTile (void) { const char *mapName = "test_game"; if (FS_CheckFile("maps/%s.bsp", mapName) != -1) { edict_t *diedEnt; edict_t *diedEnt2; edict_t *ent; edict_t *floorItems; invList_t *invlist; int count; /* the other tests didn't call the server shutdown function to clean up */ OBJZERO(*sv); SV_Map(true, mapName, NULL); level.activeTeam = TEAM_ALIEN; /* first alien that should die and drop its inventory */ diedEnt = G_EdictsGetNextLivingActorOfTeam(NULL, TEAM_ALIEN); CU_ASSERT_PTR_NOT_NULL_FATAL(diedEnt); diedEnt->HP = 0; G_ActorDieOrStun(diedEnt, NULL); CU_ASSERT_TRUE_FATAL(G_IsDead(diedEnt)); /* second alien that should die and drop its inventory */ diedEnt2 = G_EdictsGetNextLivingActorOfTeam(NULL, TEAM_ALIEN); CU_ASSERT_PTR_NOT_NULL_FATAL(diedEnt2); /* move to the location of the first died alien to drop the inventory into the same floor container */ Player &player = diedEnt2->getPlayer(); CU_ASSERT_TRUE_FATAL(G_IsAIPlayer(&player)); G_ClientMove(player, 0, diedEnt2, diedEnt->pos); CU_ASSERT_TRUE_FATAL(VectorCompare(diedEnt2->pos, diedEnt->pos)); diedEnt2->HP = 0; G_ActorDieOrStun(diedEnt2, NULL); CU_ASSERT_TRUE_FATAL(G_IsDead(diedEnt2)); /* now try to collect the inventory with a third alien */ ent = G_EdictsGetNextLivingActorOfTeam(NULL, TEAM_ALIEN); CU_ASSERT_PTR_NOT_NULL_FATAL(ent); player = ent->getPlayer(); CU_ASSERT_TRUE_FATAL(G_IsAIPlayer(&player)); G_ClientMove(player, 0, ent, diedEnt->pos); CU_ASSERT_TRUE_FATAL(VectorCompare(ent->pos, diedEnt->pos)); floorItems = G_GetFloorItems(ent); CU_ASSERT_PTR_NOT_NULL_FATAL(floorItems); CU_ASSERT_PTR_EQUAL(floorItems->getFloor(), ent->getFloor()); /* drop everything to floor to make sure we have space in the backpack */ G_InventoryToFloor(ent); CU_ASSERT_EQUAL(GAMETEST_GetItemCount(ent, CID_BACKPACK), 0); invlist = ent->getContainer(CID_BACKPACK); CU_ASSERT_PTR_NULL_FATAL(invlist); count = GAMETEST_GetItemCount(ent, CID_FLOOR); if (count > 0) { invList_t *entryToMove = ent->getFloor(); int tx, ty; ent->chr.inv.findSpace(INVDEF(CID_BACKPACK), entryToMove, &tx, &ty, entryToMove); if (tx != NONE) { Com_Printf("trying to move item %s from floor into backpack to pos %i:%i\n", entryToMove->def()->name, tx, ty); CU_ASSERT_TRUE(G_ActorInvMove(ent, INVDEF(CID_FLOOR), entryToMove, INVDEF(CID_BACKPACK), tx, ty, false)); UFO_CU_ASSERT_EQUAL_INT_MSG_FATAL(GAMETEST_GetItemCount(ent, CID_FLOOR), count - 1, va("item %s could not get moved successfully from floor into backpack", entryToMove->def()->name)); Com_Printf("item %s was removed from floor\n", entryToMove->def()->name); UFO_CU_ASSERT_EQUAL_INT_MSG_FATAL(GAMETEST_GetItemCount(ent, CID_BACKPACK), 1, va("item %s could not get moved successfully from floor into backpack", entryToMove->def()->name)); Com_Printf("item %s was moved successfully into the backpack\n", entryToMove->def()->name); invlist = ent->getContainer(CID_BACKPACK); CU_ASSERT_PTR_NOT_NULL_FATAL(invlist); } } SV_ShutdownGameProgs(); } else { UFO_CU_FAIL_MSG(va("Map resource '%s.bsp' for test is missing.", mapName)); } }