/** * @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(); }
void G_CheckDeathOrKnockout (edict_t *target, edict_t *attacker, const fireDef_t *fd, int damage) { /* Check death/knockout. */ if (target->HP == 0 || target->HP <= target->STUN) { G_SendStats(target); if (G_ActorDieOrStun(target, attacker)) { G_PrintActorStats(target, attacker, fd); /* apply morale changes */ if (mor_panic->integer) G_Morale(ML_DEATH, target, attacker, damage); /* Update number of killed/stunned actors for this attacker. */ G_UpdateCharacterBodycount(attacker, fd, target); } } else { target->chr.minHP = std::min(target->chr.minHP, target->HP); if (damage > 0) { if (mor_panic->integer) G_Morale(ML_WOUND, target, attacker, damage); } else { /* medikit, etc. */ const int hp = GET_HP(target->chr.score.skills[ABILITY_POWER]); if (target->HP > hp) { target->HP = std::min(std::max(hp, 0), target->chr.maxHP); } } G_SendStats(target); } }
/** * @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(); }
void G_CheckDeathOrKnockout (Edict* target, Edict* attacker, const fireDef_t* fd, int damage) { /* Sanity check */ target->HP = std::min(std::max(target->HP, 0), target->chr.maxHP); /* Check death/knockout. */ if (target->HP == 0 || target->HP <= target->STUN) { G_SendStats(*target); if (G_ActorDieOrStun(target, attacker)) { G_PrintActorStats(target, attacker, fd); /* apply morale changes */ if (mor_panic->integer) G_Morale(ML_DEATH, target, attacker, damage); /* Update number of killed/stunned actors for this attacker. */ G_UpdateCharacterBodycount(attacker, fd, target); } } else { target->chr.minHP = std::min(target->chr.minHP, target->HP); if (damage > 0) { if (mor_panic->integer) G_Morale(ML_WOUND, target, attacker, damage); } G_SendStats(*target); } }
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 Think function for actors that spawn dead * @param ent The actor */ static void G_ThinkActorDieAfterSpawn (edict_t *ent) { G_ActorDieOrStun(ent, NULL); ent->think = NULL; }
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)); } }
/** * @brief Handles the end of a match * @param[in] team The winning team number * @param[in] nextmap Is there a follow-up map within the same match ? * @sa G_RunFrame * @sa CL_ParseResults */ static void G_MatchSendResults (int team, bool nextmap) { edict_t *ent, *attacker; int i, j = 0; attacker = NULL; ent = NULL; /* Calculate new scores/skills for the soldiers. */ while ((ent = G_EdictsGetNextLivingActor(ent))) { if (!G_IsAI(ent)) G_UpdateCharacterExperience(ent); else if (ent->team == team) attacker = ent; } /* if aliens won, make sure every soldier that is not in the rescue zone dies */ if (team == TEAM_ALIEN) { ent = NULL; while ((ent = G_EdictsGetNextLivingActor(ent))) if (ent->team != team && !G_ActorIsInRescueZone(ent)) { ent->HP = 0; G_ActorDieOrStun(ent, attacker); } } G_VisMakeEverythingVisible(); /* send results */ G_EventAdd(PM_ALL, EV_RESULTS, -1); gi.WriteByte(MAX_TEAMS); gi.WriteByte(team); gi.WriteByte(nextmap); for (i = 0; i < MAX_TEAMS; i++) { gi.WriteByte(level.num_spawned[i]); gi.WriteByte(level.num_alive[i]); } for (i = 0; i <= MAX_TEAMS; i++) for (j = 0; j < MAX_TEAMS; j++) gi.WriteByte(level.num_kills[i][j]); for (i = 0; i <= MAX_TEAMS; i++) for (j = 0; j < MAX_TEAMS; j++) gi.WriteByte(level.num_stuns[i][j]); /* how many actors */ j = 0; ent = NULL; while ((ent = G_EdictsGetNextActor(ent))) if (!G_IsAI(ent)) j++; /* number of soldiers */ gi.WriteByte(j); if (j) { ent = NULL; while ((ent = G_EdictsGetNextActor(ent))) { if (!G_IsAI(ent)) { G_SendCharacterData(ent); } } } G_EventEnd(); }
/** * @brief Handles the end of a match * @param[in] team The winning team number * @param[in] nextmap Is there a follow-up map within the same match ? * @sa G_RunFrame * @sa CL_ParseResults */ static void G_MatchSendResults (int team, bool nextmap) { Edict* attacker = nullptr; Actor* actor = nullptr; /* Calculate new scores/skills for the soldiers. */ while ((actor = G_EdictsGetNextLivingActor(actor))) { if (!G_IsAI(actor)) G_UpdateCharacterExperience(actor); else if (actor->getTeam() == team) attacker = actor; } /* if aliens won, make sure every soldier that is not in the rescue zone dies */ if (team == TEAM_ALIEN) { actor = nullptr; while ((actor = G_EdictsGetNextLivingActor(actor))) if (actor->getTeam() != team && !actor->isInRescueZone()) { actor->HP = 0; G_ActorDieOrStun(actor, attacker); } } G_VisMakeEverythingVisible(); /* send results */ G_EventAdd(PM_ALL, EV_RESULTS, -1); gi.WriteByte(MAX_TEAMS); gi.WriteByte(team); gi.WriteByte(nextmap); for (int i = 0; i < MAX_TEAMS; i++) { gi.WriteByte(level.num_spawned[i]); gi.WriteByte(level.num_alive[i]); } for (int i = 0; i <= MAX_TEAMS; i++) for (int j = 0; j < MAX_TEAMS; j++) gi.WriteByte(level.num_kills[i][j]); for (int i = 0; i <= MAX_TEAMS; i++) for (int j = 0; j < MAX_TEAMS; j++) gi.WriteByte(level.num_stuns[i][j]); /* how many actors */ int n = 0; actor = nullptr; while ((actor = G_EdictsGetNextActor(actor))) if (!G_IsAI(actor)) n++; /* number of soldiers */ gi.WriteByte(n); if (n) { actor = nullptr; while ((actor = G_EdictsGetNextActor(actor))) { if (!G_IsAI(actor)) { G_SendCharacterData(actor); } } } G_EventEnd(); }