void G_EventSendState (playermask_t playerMask, const Edict& ent) { G_EventActorStateChange(playerMask & G_TeamToPM(ent.getTeam()), ent); G_EventAdd(playerMask & ~G_TeamToPM(ent.getTeam()), EV_ACTOR_STATECHANGE, ent.getIdNum()); gi.WriteShort(ent.state & STATE_PUBLIC); G_EventEnd(); }
/** * @brief Informs the client that an interaction with the world is possible * @note It's assumed that the clientAction is already set * @param[in] ent The edict that can execute the action (an actor) */ void G_EventSetClientAction (const Edict& ent) { assert(ent.clientAction); assert(ent.clientAction->flags & FL_CLIENTACTION); /* tell the hud to show the door buttons */ G_EventAdd(G_TeamToPM(ent.getTeam()), EV_CLIENT_ACTION, ent.getIdNum()); gi.WriteShort(ent.clientAction->getIdNum()); G_EventEnd(); }
/** * @brief Make everything visible to anyone who can't already see it */ void G_VisMakeEverythingVisible (void) { Edict* ent = nullptr; while ((ent = G_EdictsGetNextInUse(ent))) { const int playerMask = G_VisToPM(ent->visflags); G_AppearPerishEvent(~playerMask, true, *ent, nullptr); if (G_IsActor(ent)) G_SendInventory(~G_TeamToPM(ent->getTeam()), *ent); } }
/** * @brief Send an appear event to the client. * @param playerMask The players to send the event to * @param ent The camera that should appear to the players included in the given mask. */ void G_EventCameraAppear (playermask_t playerMask, const Edict& ent) { G_EventAdd(playerMask, EV_CAMERA_APPEAR, ent.getIdNum()); gi.WritePos(ent.origin); gi.WriteByte(ent.getTeam()); gi.WriteByte(ent.dir); gi.WriteByte(ent.camera.cameraType); /* strip the higher bits - only send levelflags */ gi.WriteByte(ent.spawnflags & 0xFF); gi.WriteByte(ent.camera.rotate); G_EventEnd(); }
/** * @sa CL_ActorAdd */ void G_EventActorAdd (playermask_t playerMask, const Edict& ent) { G_EventAdd(playerMask, EV_ACTOR_ADD, ent.getIdNum()); gi.WriteByte(ent.getTeam()); gi.WriteByte(ent.chr.teamDef ? ent.chr.teamDef->idx : NONE); gi.WriteByte(ent.chr.gender); gi.WriteByte(ent.getPlayerNum()); gi.WriteGPos(ent.pos); gi.WriteShort(ent.state & STATE_PUBLIC); gi.WriteByte(ent.fieldSize); G_EventEnd(); }
/** * @brief Triggers the end of the game. Will be executed in the next server (or game) frame. * @param[in] team The winning team * @param[in] timeGap Second to wait before really ending the game. Useful if you want to allow a last view on the scene */ void G_MatchEndTrigger (int team, int timeGap) { bool foundNextMap = false; Edict* ent = nullptr; while ((ent = G_EdictsGetTriggerNextMaps(ent)) != nullptr) { if (ent->getTeam() == team) { ent->think = Think_NextMapTrigger; ent->nextthink = 1; foundNextMap = true; } } if (!foundNextMap) { const int realTimeGap = timeGap > 0 ? level.time + timeGap : 1; level.winningTeam = team; level.intermissionTime = realTimeGap; } }
static void SVCmd_ListEdicts_f (void) { Edict* ent = nullptr; int i = 0; Com_Printf("number | entnum | mapnum | type | inuse | pnum | team | size | HP | state | classname | model/ptl | pos\n"); while ((ent = G_EdictsGetNext(ent))) { char buf[128]; const char* model; if (ent->type == ET_PARTICLE) model = ent->particle; else if (ent->model) model = ent->model; else model = "no mdl"; Com_sprintf(buf, sizeof(buf), "#%5i | #%5i | #%5i | %4i | %5i | %4i | %4i | %4i | %3i | %5i | %14s | %21s | %i:%i:%i", i, ent->getIdNum(), ent->mapNum, ent->type, ent->inuse, ent->getPlayerNum(), ent->getTeam(), ent->fieldSize, ent->HP, ent->state, ent->classname, model, ent->pos[0], ent->pos[1], ent->pos[2]); Com_Printf("%s\n", buf); i++; } }
/** * @note Think functions are only executed when the match is running * or in other word, the game has started */ void G_MissionThink (Edict* self) { if (!G_MatchIsRunning()) return; /* when every player has joined the match - spawn the mission target * particle (if given) to mark the trigger */ if (self->particle) { self->link = G_SpawnParticle(self->origin, self->spawnflags, self->particle); /* This is automatically freed on map shutdown */ self->particle = nullptr; } Edict* chain = self->groupMaster; if (!chain) chain = self; while (chain) { if (chain->type == ET_MISSION) { if (chain->item) { const Item* ic; G_GetFloorItems(chain); ic = chain->getFloor(); if (!ic) { /* reset the counter if there is no item */ chain->count = 0; return; } for (; ic; ic = ic->getNext()) { const objDef_t* od = ic->def(); assert(od); /* not the item we are looking for */ if (Q_streq(od->id, chain->item)) break; } if (!ic) { /* reset the counter if it's not the searched item */ chain->count = 0; return; } } if (chain->time) { /* Check that the target zone is still occupied (last defender might have died) */ if (!chain->item && !G_MissionIsTouched(chain)) { chain->count = 0; } const int endTime = level.actualRound - chain->count; const int spawnIndex = (chain->getTeam() + level.teamOfs) % MAX_TEAMS; const int currentIndex = (level.activeTeam + level.teamOfs) % MAX_TEAMS; /* not every edict in the group chain has * been occupied long enough */ if (!chain->count || endTime < chain->time || (endTime == chain->time && spawnIndex < currentIndex)) return; } if (chain->target && !chain->time && !chain->item) { if (!G_MissionIsTouched(chain)) return; } } chain = chain->groupChain; } const bool endMission = self->target == nullptr; /* store team before the edict is released */ const int team = self->getTeam(); chain = self->groupMaster; if (!chain) chain = self; while (chain) { if (chain->type == ET_MISSION) { G_UseEdict(chain, nullptr); if (chain->item != nullptr) { Edict* item = G_GetEdictFromPos(chain->pos, ET_ITEM); if (item != nullptr) { if (!G_InventoryRemoveItemByID(chain->item, item, CID_FLOOR)) { Com_Printf("Could not remove item '%s' from floor edict %i\n", chain->item, item->getIdNum()); } else if (!item->getFloor()) { G_EventPerish(*item); G_FreeEdict(item); } } } if (chain->link != nullptr) { Edict* particle = G_GetEdictFromPos(chain->pos, ET_PARTICLE); if (particle != nullptr) { G_AppearPerishEvent(G_VisToPM(particle->visflags), false, *particle, nullptr); G_FreeEdict(particle); } chain->link = nullptr; } /* Display mission message */ if (G_ValidMessage(chain)) { const char* msg = chain->message; if (msg[0] == '_') ++msg; gi.BroadcastPrintf(PRINT_HUD, "%s", msg); } } Edict* ent = chain->groupChain; /* free the group chain */ G_FreeEdict(chain); chain = ent; } if (endMission) G_MatchEndTrigger(team, level.activeTeam == TEAM_ALIEN ? 10 : 3); }
/** * @note Think functions are only executed when the match is running * or in other word, the game has started */ void G_MissionThink (Edict* self) { if (!G_MatchIsRunning()) return; /* when every player has joined the match - spawn the mission target * particle (if given) to mark the trigger */ if (self->particle) { self->link = G_SpawnParticle(self->origin, self->spawnflags, self->particle); /* This is automatically freed on map shutdown */ self->particle = nullptr; } Edict* chain = self->groupMaster; if (!chain) chain = self; while (chain) { if (chain->type == ET_MISSION) { if (chain->item) { const Item* ic; G_GetFloorItems(chain); ic = chain->getFloor(); if (!ic) { /* reset the counter if there is no item */ chain->count = 0; return; } for (; ic; ic = ic->getNext()) { const objDef_t* od = ic->def(); assert(od); /* not the item we are looking for */ if (Q_streq(od->id, chain->item)) break; } if (!ic) { /* reset the counter if it's not the searched item */ chain->count = 0; return; } } if (chain->time) { const int endTime = level.actualRound - chain->count; const int spawnIndex = (self->getTeam() + level.teamOfs) % MAX_TEAMS; const int currentIndex = (level.activeTeam + level.teamOfs) % MAX_TEAMS; /* not every edict in the group chain has * been occupied long enough */ if (!chain->count || endTime < chain->time || (endTime == level.actualRound && spawnIndex <= currentIndex)) return; } /* not destroyed yet */ if ((chain->flags & FL_DESTROYABLE) && chain->HP) return; } chain = chain->groupChain; } if (self->use) self->use(self, nullptr); /* store team before the edict is released */ const int team = self->getTeam(); chain = self->groupMaster; if (!chain) chain = self; while (chain) { if (chain->item != nullptr) { Edict* item = G_GetEdictFromPos(chain->pos, ET_ITEM); if (item != nullptr) { if (!G_InventoryRemoveItemByID(chain->item, item, CID_FLOOR)) { Com_Printf("Could not remove item '%s' from floor edict %i\n", chain->item, item->getIdNum()); } else if (!item->getFloor()) { G_EventPerish(*item); G_FreeEdict(item); } } } if (chain->link != nullptr) { Edict* particle = G_GetEdictFromPos(chain->pos, ET_PARTICLE); if (particle != nullptr) { G_AppearPerishEvent(PM_ALL, false, *particle, nullptr); G_FreeEdict(particle); } chain->link = nullptr; } Edict* ent = chain->groupChain; /* free the trigger */ if (chain->child()) G_FreeEdict(chain->child()); /* free the group chain */ G_FreeEdict(chain); chain = ent; } self = nullptr; /* still active mission edicts left */ Edict* ent = nullptr; while ((ent = G_EdictsGetNextInUse(ent))) if (ent->type == ET_MISSION && ent->getTeam() == team) return; G_MatchEndTrigger(team, 10); }