UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
g_client.cpp
Go to the documentation of this file.
1 
20 /*
21 Copyright (C) 2002-2020 UFO: Alien Invasion.
22 
23 This program is free software; you can redistribute it and/or
24 modify it under the terms of the GNU General Public License
25 as published by the Free Software Foundation; either version 2
26 of the License, or (at your option) any later version.
27 
28 This program is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
31 
32 See the GNU General Public License for more details.
33 
34 You should have received a copy of the GNU General Public License
35 along with this program; if not, write to the Free Software
36 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
37 */
38 
39 #include "g_client.h"
40 #include "g_actor.h"
41 #include "g_ai.h"
42 #include "g_combat.h"
43 #include "g_edicts.h"
44 #include "g_inventory.h"
45 #include "g_match.h"
46 #include "g_move.h"
47 #include "g_reaction.h"
48 #include "g_utils.h"
49 #include "g_vis.h"
50 
52 static int scoreMissionNum = 0;
53 
58 Player* G_PlayerGetNextHuman (Player* lastPlayer)
59 {
61  return nullptr;
62 
63  if (!lastPlayer)
64  return game.players;
65 
66  const Player* endOfPlayers = &game.players[game.sv_maxplayersperteam];
67 
68  assert(lastPlayer >= game.players);
69  assert(lastPlayer < endOfPlayers);
70 
71  Player* player = lastPlayer;
72 
73  player++;
74  if (player >= endOfPlayers)
75  return nullptr;
76  else
77  return player;
78 }
79 
84 Player* G_PlayerGetNextAI (Player* lastPlayer)
85 {
87  return nullptr;
88 
89  if (!lastPlayer)
91 
92  const Player* endOfPlayers = &game.players[game.sv_maxplayersperteam * 2]; /* two teams */
93 
94  assert(lastPlayer >= &game.players[game.sv_maxplayersperteam]); /* AI players are in the upper half of the players array */
95  assert(lastPlayer < endOfPlayers);
96 
97  Player* player = lastPlayer;
98 
99  player++;
100  if (player >= endOfPlayers)
101  return nullptr;
102  else
103  return player;
104 }
105 
110 Player* G_PlayerGetNextActiveHuman (Player* lastPlayer)
111 {
112  Player* player = lastPlayer;
113 
114  while ((player = G_PlayerGetNextHuman(player))) {
115  if (player->isInUse())
116  return player;
117  }
118 
119  return nullptr;
120 }
121 
126 Player* G_PlayerGetNextActiveAI (Player* lastPlayer)
127 {
128  Player* player = lastPlayer;
129 
130  while ((player = G_PlayerGetNextAI(player))) {
131  if (player->isInUse())
132  return player;
133  }
134 
135  return nullptr;
136 }
137 
145 {
146  playermask_t playerMask = 0;
147  Player* p = nullptr;
148 
149  /* don't handle the ai players, here */
150  while ((p = G_PlayerGetNextHuman(p))) {
151  if (p->isInUse() && team == p->getTeam())
152  playerMask |= G_PlayerToPM(*p);
153  }
154 
155  return playerMask;
156 }
157 
166 {
167  teammask_t teamMask = 0;
168  Player* p = nullptr;
169 
170  /* don't handle the ai players, here */
171  while ((p = G_PlayerGetNextActiveHuman(p))) {
172  if (playerMask & G_PlayerToPM(*p))
173  teamMask |= G_TeamToVisMask(p->getTeam());
174  }
175 
176  return teamMask;
177 }
178 
187 {
188  playermask_t playerMask = 0;
189  Player* p = nullptr;
190 
191  /* don't handle the ai players, here */
192  while ((p = G_PlayerGetNextActiveHuman(p))) {
193  if (teamMask & G_TeamToVisMask(p->getTeam()))
194  playerMask |= G_PlayerToPM(*p);
195  }
196 
197  return playerMask;
198 }
199 
206 void G_ClientPrintf (const Player& player, int printLevel, const char* fmt, ...)
207 {
208  /* there is no client for an AI controlled player on the server where we
209  * could send the message to */
210  if (G_IsAIPlayer(&player))
211  return;
212 
213  va_list ap;
214  va_start(ap, fmt);
215  gi.PlayerPrintf(&player, printLevel, fmt, ap);
216  va_end(ap);
217 }
218 
224 void G_GiveTimeUnits (int team)
225 {
226  Actor* actor = nullptr;
227 
228  while ((actor = G_EdictsGetNextLivingActorOfTeam(actor, team))) {
229  G_ActorGiveTimeUnits(actor);
230  G_SendStats(*actor);
231  }
232 }
233 
245 void G_AppearPerishEvent (playermask_t playerMask, bool appear, Edict& check, const Edict* ent)
246 {
247  /* test for pointless player mask */
248  if (!playerMask)
249  return;
250 
251  const teammask_t teamMaskDiff = G_PMToVis(playerMask);
252  G_VisFlagsSwap(check, teamMaskDiff);
253 
254  if (appear) {
255  /* appear */
256  switch (check.type) {
257  case ET_ACTOR:
258  case ET_ACTOR2x2: {
259  Actor* actor = makeActor(&check);
260  G_EventActorAppear(playerMask, *actor, ent);
261  break;
262  }
263 
264  case ET_CAMERA:
265  G_EventCameraAppear(playerMask, check);
266  break;
267 
268  case ET_ITEM:
269  G_EventEdictAppear(playerMask, check);
270  G_SendInventory(playerMask, check);
271  break;
272 
273  case ET_PARTICLE:
274  G_EventEdictAppear(playerMask, check);
275  G_EventSendParticle(playerMask, check);
276  break;
277 
278  case ET_TRIGGER_RESCUE:
279  G_EventAddBrushModel(playerMask, check);
280  break;
281 
282  default:
283  if (G_IsVisibleOnBattlefield(&check))
284  gi.Error("Missing edict type %i in G_AppearPerishEvent", check.type);
285  break;
286  }
287  } else if (G_IsVisibleOnBattlefield(&check)) {
288  G_EventEdictPerish(playerMask, check);
289  }
290 }
291 
302 void G_SendInvisible (const Player& player)
303 {
304  const int team = player.getTeam();
305 
306  assert(team != TEAM_NO_ACTIVE);
307  if (!level.num_alive[team])
308  return;
309 
310  Actor* actor = nullptr;
311  /* check visibility */
312  while ((actor = G_EdictsGetNextActor(actor))) {
313  if (actor->getTeam() == team)
314  continue;
315  /* not visible for this team - so add the le only */
316  if (!G_IsVisibleForTeam(actor, team)) {
317  G_EventActorAdd(G_PlayerToPM(player), *actor);
318  }
319  }
320 }
321 
327 int G_GetActiveTeam (void)
328 {
329  return level.activeTeam;
330 }
331 
337 static bool G_ActionCheck (const Player& player, Edict* ent)
338 {
339  if (!ent || !ent->inuse) {
340  G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - object not present!"));
341  return false;
342  }
343 
344  if (!G_IsActor(ent)) {
345  G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - not an actor!"));
346  return false;
347  }
348 
349  if (G_IsStunned(ent)) {
350  G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - actor is stunned!"));
351  return false;
352  }
353 
354  if (G_IsDead(ent)) {
355  G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - actor is dead!"));
356  return false;
357  }
358 
359  if (ent->getTeam() != player.getTeam()) {
360  G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - not on same team!"));
361  return false;
362  }
363 
364  if (ent->getPlayerNum() != player.getNum()) {
365  G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - no control over allied actors!"));
366  return false;
367  }
368 
369  /* could be possible */
370  return true;
371 }
372 
380 bool G_ActionCheckForCurrentTeam (const Player& player, Actor* ent, int TU)
381 {
382  /* a generic tester if an action could be possible */
383  if (level.activeTeam != player.getTeam()) {
384  G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - it is not your turn!"));
385  return false;
386  }
387 
388  if (TU > G_ActorUsableTUs(ent)) {
389  return false;
390  }
391 
392  return G_ActionCheck(player, ent);
393 }
394 
403 bool G_ActionCheckForReaction (const Player& player, Actor* actor, int TU)
404 {
405  if (TU > actor->getTus()) {
406  return false;
407  }
408 
409  return G_ActionCheck(player, actor);
410 }
411 
415 static void G_ClientTurn (Player& player, Actor* actor, dvec_t dvec)
416 {
417  /* check if action is possible */
418  if (!G_ActionCheckForCurrentTeam(player, actor, TU_TURN))
419  return;
420 
421  /* check if we're already facing that direction */
422  const int dir = getDVdir(dvec);
423  if (actor->dir == dir)
424  return;
425 
426  /* do the turn */
427  G_ActorDoTurn(actor, dir);
428  G_ActorUseTU(actor, TU_TURN);
429 
430  /* send the turn */
431  G_EventActorTurn(*actor);
432 
433  /* send the new TUs */
434  G_SendStats(*actor);
435 
436  /* end the event */
437  G_EventEnd();
438 }
439 
447 {
448  /* Send the state change. */
450 
451  /* Check if the player appears/perishes, seen from other teams. */
452  G_CheckVis(&ent);
453 
454  /* Calc new vis for this player. */
455  G_CheckVisTeamAll(ent.getTeam(), 0, &ent);
456 
457  /* Send the new TUs. */
458  G_SendStats(ent);
459 
460  /* End the event. */
461  G_EventEnd();
462 }
463 
473 void G_ClientStateChange (const Player& player, Actor* actor, int reqState, bool checkaction)
474 {
475  /* Check if any action is possible. */
476  if (checkaction && !G_ActionCheckForCurrentTeam(player, actor, 0))
477  return;
478 
479  if (!reqState)
480  return;
481 
482  switch (reqState) {
483  case STATE_CROUCHED: /* Toggle between crouch/stand. */
484  /* Check if player has enough TUs (TU_CROUCH TUs for crouch/uncrouch). */
485  if (!checkaction || G_ActionCheckForCurrentTeam(player, actor, TU_CROUCH)) {
486  if (actor->isCrouched()) {
487  if (!gi.CanActorStandHere(actor->fieldSize, actor->pos))
488  break;
489  }
490  G_ToggleCrouched(actor);
491  G_ActorUseTU(actor, TU_CROUCH);
492  G_ActorSetMaxs(actor);
493  }
494  break;
495  case ~STATE_REACTION: /* Request to turn off reaction fire. */
496  if (actor->isReaction()) {
497  if (actor->isShaken() && G_ReactionFireSettingsReserveTUs(actor)) {
498  G_ClientPrintf(player, PRINT_HUD, _("Currently shaken, won't let their guard down."));
499  } else {
500  /* Turn off reaction fire. */
501  actor->removeReaction();
502  G_ActorReserveTUs(actor, 0, actor->chr.reservedTus.shot, actor->chr.reservedTus.crouch);
503  if (!G_IsAI(actor))
505  }
506  }
507  break;
508  /* Request to turn on multi- or single-reaction fire mode. */
509  case STATE_REACTION:
510  /* Disable reaction fire. */
511  actor->removeReaction();
512 
514  /* Enable requested reaction fire. */
515  G_SetState(actor, reqState);
516  }
517  if (!G_IsAI(actor))
519  break;
520  default:
521  gi.DPrintf("G_ClientStateChange: unknown request %i, ignoring\n", reqState);
522  return;
523  }
524 
525  /* Only activate the events - network stuff is handled in the calling function */
526  if (!checkaction)
527  return;
528 
530 }
531 
536 bool G_ClientCanReload (Actor* actor, containerIndex_t containerID)
537 {
538  const objDef_t* weapon;
539 
540  if (actor->getContainer(containerID)) {
541  weapon = actor->getContainer(containerID)->def();
542  } else if (containerID == CID_LEFT && actor->getRightHandItem()->isHeldTwoHanded()) {
543  /* Check for two-handed weapon */
544  weapon = actor->getRightHandItem()->def();
545  } else
546  return false;
547 
548  assert(weapon);
549 
550  /* also try the temp containers */
551  const Container* cont = nullptr;
552  while ((cont = actor->chr.inv.getNextCont(cont, true))) {
553  Item* item = nullptr;
554  while ((item = cont->getNextItem(item))) {
555  if (item->def()->isLoadableInWeapon(weapon))
556  return true;
557  }
558  }
559  return false;
560 }
561 
569 {
570  /* e.g. bloodspiders are not allowed to carry or collect weapons */
571  if (!actor->chr.teamDef->weapons)
572  return false;
573 
574  /* search for weapons and select the one that is available easily */
575  const invDef_t* bestContainer = nullptr;
576  Item* theWeapon = nullptr;
577  int tu = 100;
578  const Container* cont = nullptr;
579  while ((cont = actor->chr.inv.getNextCont(cont, true))) {
580  if (cont->def()->out >= tu)
581  continue;
582  Item* item = nullptr;
583  while ((item = cont->getNextItem(item))) {
584  /* We are looking for the *fastest* way to get a weapon,
585  * no matter what kind of weapon it is. */
586  assert(item->def());
587  if (item->isWeapon() && !item->mustReload()) {
588  theWeapon = item;
589  bestContainer = cont->def();
590  tu = bestContainer->out;
591  break;
592  }
593  }
594  }
595 
596  /* send request */
597  const invDef_t* invDef = INVDEF(CID_RIGHT);
598  if (bestContainer) {
599  return G_ActorInvMove(actor, bestContainer, theWeapon, invDef, 0, 0, true);
600  }
601  return false; /* no weapon found */
602 }
603 
614 bool G_ClientUseEdict (const Player& player, Actor* actor, Edict* edict)
615 {
616  /* check whether the actor has sufficient TUs to 'use' this edicts */
617  if (!G_ActionCheckForCurrentTeam(player, actor, edict->TU))
618  return false;
619 
620  if (!G_UseEdict(edict, actor))
621  return false;
622 
623  /* using a group of edicts only costs TUs once (for the master) */
624  G_ActorUseTU(actor, edict->TU);
625  /* send the new TUs */
626  G_SendStats(*actor);
627 
628  G_EventEnd();
629 
630  return true;
631 }
632 
638 int G_ClientAction (Player& player)
639 {
640  pos3_t pos;
641  int i;
642  int from;
643 
644  /* read the header */
645  player_action_t action = (player_action_t)gi.ReadByte();
646  int num = gi.ReadShort();
647 
648  Edict* ent = G_EdictsGetByNum(num);
649  if (ent == nullptr)
650  return action;
651 
652  /* we expext this ent to be an Actor */
653  Actor* actor = makeActor(ent);
654 
655  const char* format = pa_format[action];
656 
657  switch (action) {
658  case PA_NULL:
659  /* do nothing on a null action */
660  break;
661 
662  case PA_TURN:
663  gi.ReadFormat(format, &i);
664  G_ClientTurn(player, actor, (dvec_t) i);
665  break;
666 
667  case PA_MOVE:
668  gi.ReadFormat(format, &pos);
669  G_ClientMove(player, player.getTeam(), actor, pos);
670  break;
671 
672  case PA_STATE:
673  gi.ReadFormat(format, &i);
674  G_ClientStateChange(player, actor, i, true);
675  break;
676 
677  case PA_SHOOT:
678  fireDefIndex_t firemode;
679  gi.ReadFormat(format, &pos, &i, &firemode, &from);
680  G_ClientShoot(player, actor, pos, i, firemode, nullptr, true, from);
681  break;
682 
683  case PA_INVMOVE:
684  int fx, fy, to, tx, ty;
685  gi.ReadFormat(format, &from, &fx, &fy, &to, &tx, &ty);
686 
687  if (!isValidContId(from) || !isValidContId(to)) {
688  gi.DPrintf("G_ClientAction: PA_INVMOVE Container index out of range. (from: %i, to: %i)\n", from, to);
689  } else {
690  const invDef_t* fromPtr = INVDEF(from);
691  const invDef_t* toPtr = INVDEF(to);
692  Item* fromItem = ent->chr.inv.getItemAtPos(fromPtr, fx, fy);
693  if (fromItem)
694  G_ActorInvMove(actor, fromPtr, fromItem, toPtr, tx, ty, true);
695  }
696  break;
697 
698  case PA_USE:
699  if (actor->clientAction) {
700  /* read the door the client wants to open */
701  gi.ReadFormat(format, &i);
702 
703  /* get the door edict */
704  Edict* actionEnt = G_EdictsGetByNum(i);
705 
706  /* maybe the door is no longer 'alive' because it was destroyed */
707  if (actionEnt && actor->clientAction == actionEnt) {
708  if (G_IsDoor(actionEnt)) {
709  G_ActorUseDoor(actor, actionEnt);
710  }
711  }
712  }
713  break;
714 
715  case PA_REACT_SELECT:
716  actorHands_t hand;
717  int fmIdx, objIdx;
718  gi.ReadFormat(format, &hand, &fmIdx, &objIdx);
719  G_ReactionFireSettingsUpdate(actor, fmIdx, hand, INVSH_GetItemByIDX(objIdx));
720  break;
721 
722  case PA_RESERVE_STATE:
723  int resCrouch, resShot;
724  gi.ReadFormat(format, &resShot, &resCrouch);
725 
726  G_ActorReserveTUs(ent, ent->chr.reservedTus.reaction, resShot, resCrouch);
727  break;
728 
729  default:
730  gi.Error("G_ClientAction: Unknown action!\n");
731  }
732  return action;
733 }
734 
740 static void G_GetTeam (Player& player)
741 {
742  /* player has already a team */
743  if (player.getTeam() > 0) {
744  Com_DPrintf(DEBUG_GAME, "Player %s is already on team %i\n", player.pers.netname, player.getTeam());
745  return;
746  }
747 
748  /* number of currently connected players (no ai players) */
749  int playersInGame = 0;
750  Player* p = nullptr;
751  while ((p = G_PlayerGetNextActiveHuman(p)))
752  playersInGame++;
753 
754  const int maxTeam = std::min(sv_maxteams->integer, TEAM_MAX_HUMAN);
755  /* randomly assign a teamnumber in deathmatch games */
756  if (playersInGame <= 1 && G_IsMultiPlayer() && !sv_teamplay->integer) {
757  int spawnCheck[MAX_TEAMS];
758  int spawnSpots = 0;
759  /* skip civilian teams */
760  for (int i = TEAM_PHALANX; i <= maxTeam; i++) {
761  spawnCheck[i] = 0;
762  /* check whether there are spawnpoints for this team */
763  if (level.num_spawnpoints[i])
764  spawnCheck[spawnSpots++] = i;
765  }
766  /* we need at least 2 different team spawnpoints for multiplayer in a death match game */
767  if (spawnSpots < 2)
768  gi.Error("G_GetTeam: Not enough spawn spots in map!");
769 
770  /* assign random valid team number */
771  int i = spawnSpots;
772  int randomSpot = rand() % spawnSpots;
773  for (;;) {
774  const int team = spawnCheck[randomSpot];
775  if (i == 0)
776  gi.Error("G_GetTeam: Could not assign a team!");
777  if (G_SetTeamForPlayer(player, team)) {
778  gi.DPrintf("%s has been randomly assigned to team %i\n",
779  player.pers.netname, G_ClientGetTeamNum(player));
780  break;
781  }
782  i--;
783  randomSpot = (randomSpot + 1) % spawnSpots;
784  }
785  return;
786  }
787 
788  /* find a team */
789  if (G_IsSinglePlayer()) {
791  } else if (sv_teamplay->integer) {
792  /* set the team specified in the userinfo */
793  const int i = G_ClientGetTeamNumPref(player);
794  gi.DPrintf("Get a team for teamplay for %s\n", player.pers.netname);
795  /* civilians are at team zero */
796  if (i > TEAM_CIVILIAN && sv_maxteams->integer >= i) {
797  G_SetTeamForPlayer(player, i);
798  gi.BroadcastPrintf(PRINT_CONSOLE, "serverconsole: %s has chosen team %i\n", player.pers.netname, i);
799  } else {
800  gi.DPrintf("Team %i is not valid - choose a team between 1 and %i\n", i, sv_maxteams->integer);
802  }
803  } else {
804  int i;
805  /* search team */
806  gi.DPrintf("Getting a multiplayer team for %s\n", player.pers.netname);
807  for (i = TEAM_CIVILIAN + 1; i <= maxTeam; i++) {
808  if (level.num_spawnpoints[i]) {
809  bool teamAvailable = true;
810 
811  p = nullptr;
812  /* check if team is in use (only human controlled players) */
813  while ((p = G_PlayerGetNextActiveHuman(p))) {
814  if (p->getTeam() == i) {
815  Com_DPrintf(DEBUG_GAME, "Team %i is already in use\n", i);
816  /* team already in use */
817  teamAvailable = false;
818  break;
819  }
820  }
821  if (teamAvailable)
822  break;
823  }
824  }
825 
826  /* set the team */
827  if (i <= maxTeam) {
828  /* remove ai player */
829  p = nullptr;
830  while ((p = G_PlayerGetNextActiveAI(p))) {
831  if (p->getTeam() == i) {
832  gi.BroadcastPrintf(PRINT_CONSOLE, "Removing ai player...");
833  p->setInUse(false);
834  break;
835  }
836  }
837  Com_DPrintf(DEBUG_GAME, "Assigning %s to team %i\n", player.pers.netname, i);
838  G_SetTeamForPlayer(player, i);
839  } else {
840  gi.DPrintf("No free team - disconnecting '%s'\n", player.pers.netname);
841  G_ClientDisconnect(player);
842  }
843  }
844 }
845 
852 bool G_SetTeamForPlayer (Player& player, const int team)
853 {
854  assert(team >= TEAM_NO_ACTIVE && team < MAX_TEAMS);
855 
856  if (G_IsAIPlayer(&player)) {
857  if (team != TEAM_ALIEN && team != TEAM_CIVILIAN)
858  return false;
859  } else {
860  if (!sv_teamplay->integer) {
861  Player* p = nullptr;
862  while ((p = G_PlayerGetNextHuman(p)) != nullptr) {
863  if (p->getTeam() == team)
864  return false;
865  }
866  }
867  }
868 
869  player.setTeam(team);
870 
871  /* if we started in dev mode, we maybe don't have a
872  * starting position in this map */
873  if (!g_nospawn->integer) {
874  if (team >= 0 && team < MAX_TEAMS) {
875  if (!level.num_spawnpoints[team])
876  gi.Error("No spawnpoints for team %i", team);
877  }
878  }
879 
880  if (!G_IsAIPlayer(&player))
881  Info_SetValueForKeyAsInteger(player.pers.userinfo, sizeof(player.pers.userinfo), "cl_team", team);
882 
883  return true;
884 }
885 
889 int G_ClientGetTeamNum (const Player& player)
890 {
891  return player.getTeam();
892 }
893 
897 int G_ClientGetTeamNumPref (const Player& player)
898 {
899  return Info_IntegerForKey(player.pers.userinfo, "cl_teamnum");
900 }
901 
905 bool G_ClientIsReady (const Player* player)
906 {
907  assert(player);
908  return player->isReady();
909 }
910 
916 static void G_GetStartingTeam (const Player& player)
917 {
918  /* return with no action if activeTeam already assigned or if are in single-player mode */
919  if (G_MatchIsRunning())
920  return;
921 
922  if (G_IsSinglePlayer()) {
923  level.activeTeam = player.getTeam();
925  return;
926  }
927 
928  /* count number of currently connected unique teams and players (human controlled players only) */
929  int knownTeams[MAX_TEAMS];
930  Player* p = nullptr;
931  int teamCount = 0;
932  int playerCount = 0;
933  while ((p = G_PlayerGetNextActiveHuman(p))) {
934  int j;
935  playerCount++;
936  for (j = 0; j < teamCount; j++) {
937  if (p->getTeam() == knownTeams[j])
938  break;
939  }
940  if (j == teamCount)
941  knownTeams[teamCount++] = p->getTeam();
942  }
943 
944  if (teamCount) {
945  const int teamIndex = (int) (frand() * (teamCount - 1) + 0.5);
946  G_PrintStats("Starting new game: %s with %i teams", level.mapname, teamCount);
947  level.activeTeam = knownTeams[teamIndex];
949  p = nullptr;
950  while ((p = G_PlayerGetNextActiveHuman(p)))
951  if (p->getTeam() != level.activeTeam)
952  p->roundDone = true;
953  }
954 }
955 
963 static Edict* G_ClientGetFreeSpawnPoint (const Player& player, int spawnType)
964 {
965  /* Abort for non-spawnpoints */
966  assert(spawnType == ET_ACTORSPAWN || spawnType == ET_ACTOR2x2SPAWN);
967 
968  Edict* ent = nullptr;
969  if (level.noRandomSpawn) {
970  while ((ent = G_EdictsGetNextInUse(ent)))
971  if (ent->type == spawnType && player.getTeam() == ent->getTeam()) {
973  continue;
974  return ent;
975  }
976  } else {
977  Edict* list[MAX_EDICTS];
978  int count = 0;
979  while ((ent = G_EdictsGetNextInUse(ent)))
980  if (ent->type == spawnType && player.getTeam() == ent->getTeam()) {
982  continue;
983  list[count++] = ent;
984  }
985 
986  if (count)
987  return list[rand() % count];
988  }
989 
990  return nullptr;
991 }
992 
1002 static inline bool G_ActorSpawnIsAllowed (const int num, const int team)
1003 {
1004  if (G_IsSinglePlayer())
1005  return true;
1006 
1008 }
1009 
1015 {
1016  /* We can safely assume that this is an Actor */
1017  Actor* actor = makeActor(ent);
1018  G_ActorDieOrStun(actor, nullptr);
1019  actor->think = nullptr;
1020 }
1021 
1026 static void G_ThinkActorGoCrouch (Edict* ent)
1027 {
1028  Actor* actor = makeActor(ent);
1029  G_ClientStateChange(actor->getPlayer(), actor, STATE_CROUCHED, true);
1030  actor->think = nullptr;
1031 }
1032 
1039 Actor* G_ClientGetFreeSpawnPointForActorSize (const Player& player, const actorSizeEnum_t actorSize)
1040 {
1041  Edict* ent;
1042 
1043  if (actorSize == ACTOR_SIZE_NORMAL) {
1044  /* Find valid actor spawn fields for this player. */
1046  if (ent) {
1047  /* preserve the spawpoint so we can later spawn more (alien rush) */
1048  Edict* copy = G_EdictDuplicate(ent);
1049  if (copy != nullptr)
1050  copy->type = ET_ACTOR;
1051  ent = copy;
1052  }
1053  } else if (actorSize == ACTOR_SIZE_2x2) {
1054  /* Find valid actor spawn fields for this player. */
1056  if (ent) {
1057  Edict* copy = G_EdictDuplicate(ent);
1058  if (copy != nullptr) {
1059  copy->type = ET_ACTOR2x2;
1060  copy->setMorale(100);
1061  }
1062  ent = copy;
1063  }
1064  } else {
1065  gi.Error("G_ClientGetFreeSpawnPointForActorSize: unknown fieldSize for actor edict (actorSize: %i)\n", actorSize);
1066  }
1067 
1068  if (!ent)
1069  return nullptr;
1070 
1071  level.num_spawned[ent->getTeam()]++;
1072  ent->setPlayerNum(player.getNum());
1073  ent->chr.fieldSize = actorSize;
1074  ent->fieldSize = ent->chr.fieldSize;
1075  ent->flags |= FL_DESTROYABLE;
1076  G_VisFlagsReset(*ent);
1077  gi.LinkEdict(ent);
1078 
1079  if (ent->spawnflags & STATE_CROUCHED) {
1080  ent->think = G_ThinkActorGoCrouch;
1081  ent->nextthink = 1;
1082  }
1083 
1084  if (ent->spawnflags & STATE_STUN) {
1085  if (ent->spawnflags & STATE_DEAD)
1086  ent->HP = 0;
1088  ent->nextthink = 1;
1089  }
1090 
1091  G_ActorModifyCounters(nullptr, ent, 1, 0, 0);
1092 
1094 
1095  return makeActor(ent);
1096 }
1097 
1102 static void G_ClientReadInventory (Edict* ent)
1103 {
1104  /* inventory */
1105  for (int nr = gi.ReadShort(); nr > 0; nr--) {
1106  const invDef_t* container;
1107  Item item;
1108  int x, y;
1109  G_ReadItem(&item, &container, &x, &y);
1110  if (container->temp)
1111  gi.Error("G_ClientReadInventory failed, tried to add '%s' to a temp container %i", item.def()->id, container->id);
1112  /* ignore the overload for now */
1113  if (!ent->chr.inv.canHoldItemWeight(CID_EQUIP, container->id, item, ent->chr.score.skills[ABILITY_POWER]))
1114  Com_Printf("G_ClientReadInventory: Item %s exceeds ent %i weight capacity\n", item.def()->id, ent->getIdNum());
1115  if (!level.noEquipment && game.invi.addToInventory(&ent->chr.inv, &item, container, x, y, 1) == nullptr)
1116  gi.Error("G_ClientReadInventory failed, could not add item '%s' to container %i (x:%i,y:%i)",
1117  item.def()->id, container->id, x, y);
1118  }
1119 }
1120 
1125 static void G_ClientReadCharacter (Edict* ent)
1126 {
1127  ent->chr.init();
1128  /* model */
1129  ent->chr.ucn = gi.ReadShort();
1130  gi.ReadString(ent->chr.name, sizeof(ent->chr.name));
1131  gi.ReadString(ent->chr.path, sizeof(ent->chr.path));
1132  gi.ReadString(ent->chr.body, sizeof(ent->chr.body));
1133  gi.ReadString(ent->chr.head, sizeof(ent->chr.head));
1134  ent->chr.bodySkin = gi.ReadByte();
1135  ent->chr.headSkin = gi.ReadByte();
1136 
1137  ent->chr.HP = gi.ReadShort();
1138  ent->chr.minHP = ent->chr.HP;
1139  ent->chr.maxHP = gi.ReadShort();
1140  const int teamDefIdx = gi.ReadByte();
1141  if (teamDefIdx < 0 || teamDefIdx >= MAX_TEAMDEFS)
1142  gi.Error("Invalid team definition index given: %i", teamDefIdx);
1143  ent->chr.teamDef = &gi.csi->teamDef[teamDefIdx];
1144 
1145  ent->chr.gender = gi.ReadByte();
1146  ent->chr.STUN = gi.ReadByte();
1147  ent->chr.morale = gi.ReadByte();
1148 
1149  for (int k = 0; k < ent->chr.teamDef->bodyTemplate->numBodyParts(); ++k)
1150  ent->chr.wounds.treatmentLevel[k] = gi.ReadByte();
1151 
1152  for (int k = 0; k < SKILL_NUM_TYPES + 1; k++) /* new attributes */
1153  ent->chr.score.experience[k] = gi.ReadLong();
1154  for (int k = 0; k < SKILL_NUM_TYPES; k++) /* new attributes */
1155  ent->chr.score.skills[k] = gi.ReadByte();
1156  for (int k = 0; k < KILLED_NUM_TYPES; k++)
1157  ent->chr.score.kills[k] = gi.ReadShort();
1158  for (int k = 0; k < KILLED_NUM_TYPES; k++)
1159  ent->chr.score.stuns[k] = gi.ReadShort();
1160  ent->chr.score.assignedMissions = gi.ReadShort();
1161 }
1162 
1168 static void G_ClientSkipActorInfo (void)
1169 {
1170  Edict ent;
1171  invDef_t container;
1172  Item item;
1173  int x, y;
1174  const invDef_t* c = &container;
1175 
1176  G_ClientReadCharacter(&ent);
1177 
1178  /* skip inventory */
1179  const int n = gi.ReadShort();
1180  for (int i = 0; i < n; i++) {
1181  G_ReadItem(&item, &c, &x, &y);
1182  }
1183 }
1184 
1191 {
1192  /* Mission Scores */
1193  scoreMission[scoreMissionNum].init();
1194  actor->chr.scoreMission = &scoreMission[scoreMissionNum];
1195  scoreMissionNum++;
1196 
1197  /* set initial vital statistics */
1198  actor->HP = actor->chr.HP;
1199  actor->setMorale(actor->chr.morale);
1200 
1202  actor->setMorale(GET_MORALE(actor->chr.score.skills[ABILITY_MIND]));
1203 
1204  /* set models */
1205  actor->setBody(gi.ModelIndex(CHRSH_CharGetBody(&actor->chr)));
1206  actor->setHead(gi.ModelIndex(CHRSH_CharGetHead(&actor->chr)));
1207 
1208  actor->chr.scoreMission->carriedWeight = actor->chr.inv.getWeight();
1209 }
1210 
1215 void G_ClientInitActorStates (const Player& player)
1216 {
1217  const int length = gi.ReadByte(); /* Get the actor amount that the client sent. */
1218 
1219  for (int i = 0; i < length; i++) {
1220  const int ucn = gi.ReadShort();
1221  Actor* actor = G_EdictsGetActorByUCN(ucn, player.getTeam());
1222  if (!actor) {
1223  gi.DPrintf("Could not find character on team %i with unique character number %i\n", player.getTeam(), ucn);
1224  /* Skip actor info */
1225  gi.ReadShort();
1226  gi.ReadShort();
1227  gi.ReadShort();
1228  gi.ReadShort();
1229  continue;
1230  }
1231 
1232  /* these state changes are not consuming any TUs */
1233  const int saveTU = actor->getTus();
1234  G_ClientStateChange(player, actor, gi.ReadShort(), false);
1235  const actorHands_t hand = (actorHands_t)gi.ReadShort();
1236  const fireDefIndex_t fmIdx = gi.ReadShort();
1237  const int objIdx = gi.ReadShort();
1238  G_ActorSetTU(actor, saveTU);
1239  if (objIdx != NONE) {
1240  if (fmIdx == NONE)
1242  else
1243  G_ReactionFireSettingsUpdate(actor, fmIdx, hand, INVSH_GetItemByIDX(objIdx));
1244  }
1245  G_ClientStateChangeUpdate(*actor);
1246  }
1247 }
1248 
1255 void G_ClientTeamInfo (const Player& player)
1256 {
1257  const int length = gi.ReadByte(); /* Get the actor amount that the client sent. */
1258 
1259  for (int i = 0; i < length; i++) {
1260  const actorSizeEnum_t actorFieldSize = gi.ReadByte();
1261  /* Search for a spawn point for each entry the client sent */
1262  if (player.getTeam() == TEAM_NO_ACTIVE || !G_ActorSpawnIsAllowed(i, player.getTeam()))
1264  else {
1265  Actor* actor = G_ClientGetFreeSpawnPointForActorSize(player, actorFieldSize);
1266  if (actor) {
1267  Com_DPrintf(DEBUG_GAME, "Player: %i - team %i - size: %i\n", player.getNum(), actor->getTeam(), actor->fieldSize);
1268 
1269  G_ClientReadCharacter(actor);
1270  G_ClientReadInventory(actor);
1272  G_ActorGiveTimeUnits(actor);
1273  G_TouchTriggers(actor);
1274  actor->contentFlags = G_ActorGetContentFlags(actor->origin);
1275  AIL_InitActor(actor);
1276  } else {
1277  gi.DPrintf("Not enough spawn points for team %i (actorsize: %i)\n", player.getTeam(), actorFieldSize);
1278 
1280  }
1281  }
1282  }
1283 
1284  Com_Printf("Used inventory slots client %s spawn: %i\n", player.pers.netname, game.invi.GetUsedSlots());
1285 }
1286 
1296 static void G_ClientSendEdictsAndBrushModels (const Player& player)
1297 {
1298  const int mask = G_PlayerToPM(player);
1299  /* skip the world */
1300  Edict* ent = G_EdictsGetFirst();
1301 
1302  /* make SOLID_BSP edicts visible to the client */
1303  while ((ent = G_EdictsGetNextInUse(ent))) {
1304  /* brush models that have a type - not the world - keep in
1305  * mind that there are several world edicts in the list in case of
1306  * a map assembly */
1307  if (ent->solid != SOLID_BSP)
1308  continue;
1309 
1310  /* skip the world(s) in case of map assembly */
1311  if (ent->type > ET_NULL) {
1312  G_EventAddBrushModel(mask, *ent);
1313  G_VisFlagsAdd(*ent, ~ent->visflags);
1314  }
1315  }
1316 }
1317 
1323 bool G_ClientBegin (Player& player)
1324 {
1325  player.began = true;
1326  level.numplayers++;
1327 
1328  /* find a team */
1329  G_GetTeam(player);
1330  if (!player.began)
1331  return false;
1332 
1333  gi.ConfigString(CS_PLAYERCOUNT, "%i", level.numplayers);
1334 
1335  /* spawn camera (starts client rendering) */
1336  G_EventStart(player, sv_teamplay->integer);
1337 
1338  /* send things like doors and breakables */
1340 
1341  /* ensure that the start event is send */
1342  G_EventEnd();
1343 
1344  /* set the net name */
1345  gi.ConfigString(CS_PLAYERNAMES + player.getNum(), "%s", player.pers.netname);
1346 
1347  /* inform all clients */
1348  gi.BroadcastPrintf(PRINT_CONSOLE, "%s has joined team %i\n", player.pers.netname, player.getTeam());
1349 
1350  return true;
1351 }
1352 
1361 void G_ClientStartMatch (Player& player)
1362 {
1363  G_GetStartingTeam(player);
1364 
1365  /* do all the init events here... */
1366  /* reset the data */
1367  G_EventReset(player, level.activeTeam);
1368 
1369  /* show visible actors and add invisible actor */
1370  G_VisFlagsClear(player.getTeam());
1371  G_CheckVisPlayer(player, false);
1372  G_SendInvisible(player);
1373 
1374  /* submit stats */
1375  G_SendPlayerStats(player);
1376 
1377  /* ensure that the last event is send, too */
1378  G_EventEnd();
1379 
1380  if (G_IsMultiPlayer()) {
1381  /* ensure that we restart the round time limit */
1382  sv_roundtimelimit->modified = true;
1383  }
1384 
1385  /* inform all clients */
1386  gi.BroadcastPrintf(PRINT_CONSOLE, "%s has taken control over team %i.\n", player.pers.netname, player.getTeam());
1387 }
1388 
1393 void G_ClientUserinfoChanged (Player& player, const char* userinfo)
1394 {
1395  const bool alreadyReady = player.isReady();
1396  const int oldTeamnum = Info_IntegerForKey(player.pers.userinfo, "cl_teamnum");
1397 
1398  /* check for malformed or illegal info strings */
1399  if (!Info_Validate(userinfo))
1400  userinfo = "\\cl_name\\badinfo";
1401 
1402  /* set name */
1403  Q_strncpyz(player.pers.netname, Info_ValueForKey(userinfo, "cl_name"), sizeof(player.pers.netname));
1404  Q_strncpyz(player.pers.userinfo, userinfo, sizeof(player.pers.userinfo));
1405  player.autostand = Info_IntegerForKey(userinfo, "cl_autostand");
1406  player.setReady(Info_IntegerForKey(userinfo, "cl_ready"));
1407 
1408  /* send the updated config string */
1409  gi.ConfigString(CS_PLAYERNAMES + player.getNum(), "%s", player.pers.netname);
1410 
1411  /* try to update to the preferred team */
1412  if (!G_MatchIsRunning() && oldTeamnum != Info_IntegerForKey(userinfo, "cl_teamnum")) {
1413  /* if the player is marked as ready he can't change his team */
1414  if (!alreadyReady || !player.isReady()) {
1415  player.setTeam(TEAM_NO_ACTIVE);
1416  G_GetTeam(player);
1417  } else {
1418  Com_DPrintf(DEBUG_GAME, "G_ClientUserinfoChanged: player %s is already marked as being ready\n",
1419  player.pers.netname);
1420  }
1421  }
1422 }
1423 
1436 bool G_ClientConnect (Player* player, char* userinfo, size_t userinfoSize)
1437 {
1438  const char* value = Info_ValueForKey(userinfo, "ip");
1439 
1440  Com_Printf("connection attempt from %s\n", value);
1441 
1442  /* check to see if they are on the banned IP list */
1443  if (SV_FilterPacket(value)) {
1444  Info_SetValueForKey(userinfo, userinfoSize, "rejmsg", REJ_BANNED);
1445  return false;
1446  }
1447 
1448  if (!G_PlayerToPM(*player)) {
1449  Info_SetValueForKey(userinfo, userinfoSize, "rejmsg", REJ_SERVER_FULL);
1450  return false;
1451  }
1452 
1453  value = Info_ValueForKey(userinfo, "password");
1454  if (password->string[0] != '\0' && !Q_streq(password->string, "none") && !Q_streq(password->string, value)) {
1455  Info_SetValueForKey(userinfo, userinfoSize, "rejmsg", REJ_PASSWORD_REQUIRED_OR_INCORRECT);
1456  return false;
1457  }
1458 
1459  /* fix for fast reconnects after a disconnect */
1460  if (player->isInUse()) {
1461  gi.BroadcastPrintf(PRINT_CONSOLE, "%s already in use.\n", player->pers.netname);
1462  G_ClientDisconnect(*player);
1463  }
1464 
1465  /* reset persistent data */
1466  OBJZERO(player->pers);
1467  G_ClientUserinfoChanged(*player, userinfo);
1468 
1469  gi.BroadcastPrintf(PRINT_CONSOLE, "%s is connecting...\n", player->pers.netname);
1470  return true;
1471 }
1472 
1476 void G_ClientDisconnect (Player& player)
1477 {
1478  /* only if the player already sent his began */
1479  if (player.began) {
1480  level.numplayers--;
1481  gi.ConfigString(CS_PLAYERCOUNT, "%i", level.numplayers);
1482 
1483  if (level.activeTeam == player.getTeam())
1484  G_ClientEndRound(player);
1485 
1486  /* if no more players are connected - stop the server */
1487  G_MatchEndCheck();
1488  }
1489 
1490 #if 0
1491  /* now let's remove all the edicts that belongs to this player */
1492  Actor* actor = nullptr;
1493  while ((actor = G_EdictsGetNextLivingActor(actor))) {
1494  if (actor->pnum == player.num)
1495  G_ActorDie(actor, STATE_DEAD, nullptr);
1496  }
1497  G_MatchEndCheck();
1498 #endif
1499 
1500  player.began = false;
1501  player.roundDone = false;
1502  player.setReady(false);
1503 
1504  gi.BroadcastPrintf(PRINT_CONSOLE, "%s disconnected.\n", player.pers.netname);
1505 }
1506 
1511 {
1512  scoreMissionNum = 0;
1513  OBJZERO(scoreMission);
1514 }
char mapname[MAX_QPATH]
Definition: g_local.h:85
Edict * G_EdictsGetFirst(void)
Returns the first entity.
Definition: g_edicts.cpp:98
void G_EventEnd(void)
Definition: g_events.cpp:711
void G_ClientPrintf(const Player &player, int printLevel, const char *fmt,...)
Definition: g_client.cpp:206
void Info_SetValueForKeyAsInteger(char *s, const size_t size, const char *key, const int value)
Definition: infostring.cpp:154
Edict * G_EdictsGetNextInUse(Edict *lastEnt)
Iterate through the entities that are in use.
Definition: g_edicts.cpp:166
int getIdNum() const
Definition: g_edict.h:231
bool mustReload() const
Definition: inv_shared.h:483
int G_TouchTriggers(Edict *ent, const entity_type_t type)
Check the world against triggers for the current entity.
Definition: g_utils.cpp:547
Reaction fire system.
void removeReaction()
Definition: g_edict.h:378
bool G_ClientGetWeaponFromInventory(Actor *actor)
Retrieve or collect a loaded weapon from any linked container for the actor's right hand...
Definition: g_client.cpp:568
char path[MAX_VAR]
Definition: chr_shared.h:372
void G_SendInvisible(const Player &player)
This function sends all the actors to the client that are not visible initially - this is needed beca...
Definition: g_client.cpp:302
solid_t solid
Definition: g_edict.h:58
static void G_ThinkActorDieAfterSpawn(Edict *ent)
Think function for actors that spawn dead.
Definition: g_client.cpp:1014
#define ACTOR_SIZE_2x2
Definition: defines.h:303
#define CID_EQUIP
Definition: inv_shared.h:56
Player * G_PlayerGetNextActiveHuman(Player *lastPlayer)
Iterate through the list of players.
Definition: g_client.cpp:110
Actor * G_EdictsGetActorByUCN(const int ucn, const int team)
Searches an actor by a unique character number.
Definition: g_edicts.cpp:254
cvar_t * sv_maxsoldiersperplayer
Definition: g_main.cpp:54
void G_ClientDisconnect(Player &player)
Definition: g_client.cpp:1476
chrScoreGlobal_t score
Definition: chr_shared.h:387
Actor * G_EdictsGetNextLivingActor(Actor *lastEnt)
Iterate through the living actor entities.
Definition: g_edicts.cpp:196
cvar_t * sv_maxteams
Definition: g_main.cpp:59
void init()
Definition: chr_shared.cpp:34
float nextthink
Definition: g_edict.h:149
#define TEAM_PHALANX
Definition: q_shared.h:62
#define MAX_TEAMS
Definition: defines.h:98
void G_PrintStats(const char *format,...)
Prints stats to game console and stats log file.
Definition: g_utils.cpp:304
void G_EventReset(const Player &player, int activeTeam)
Definition: g_events.cpp:669
#define G_IsStunned(ent)
Definition: g_actor.h:30
static void G_ClientAssignDefaultActorValues(Actor *actor)
Used after spawning an actor to set some default values that are not read from the network event...
Definition: g_client.cpp:1190
#define TEAM_ALIEN
Definition: q_shared.h:63
void G_CheckVis(Edict *check, const vischeckflags_t visFlags)
Check if the edict appears/perishes for the other teams. If they appear for other teams...
Definition: g_vis.cpp:409
void G_EventActorTurn(const Edict &ent)
Send the turn event for the given entity.
Definition: g_events.cpp:77
int G_ActorDoTurn(Edict *ent, byte dir)
Turns an actor around.
Definition: g_actor.cpp:154
int G_ActorUsableTUs(const Edict *ent)
Calculates the amount of usable TUs. This is without the reserved TUs.
Definition: g_actor.cpp:102
const teamDef_t * teamDef
Definition: chr_shared.h:394
Player * players
Definition: g_local.h:70
int experience[SKILL_NUM_TYPES+1]
Definition: chr_shared.h:120
Artificial Intelligence functions.
#define _(String)
Definition: cl_shared.h:43
Misc utility functions for game module.
void G_EventEdictAppear(playermask_t playerMask, const Edict &ent)
Send an appear event to the client.
Definition: g_events.cpp:563
static chrScoreMission_t scoreMission[MAX_EDICTS]
Definition: g_client.cpp:51
void G_ClientStateChange(const Player &player, Actor *actor, int reqState, bool checkaction)
Changes the state of a player/soldier.
Definition: g_client.cpp:473
teammask_t G_PMToVis(playermask_t playerMask)
Converts player mask to vis mask.
Definition: g_client.cpp:165
Actor * G_EdictsGetLivingActorFromPos(const pos3_t pos)
Searches an actor at the given grid location.
Definition: g_edicts.cpp:270
#define STATE_REACTION
Definition: q_shared.h:272
void G_VisFlagsSwap(Edict &ent, teammask_t teamMask)
Definition: g_vis.cpp:443
unsigned int playermask_t
Definition: g_events.h:34
int32_t actorSizeEnum_t
Definition: ufotypes.h:77
int activeTeam
Definition: g_local.h:101
character_t chr
Definition: g_edict.h:116
#define MAX_TEAMDEFS
Definition: chr_shared.h:217
Player * G_PlayerGetNextAI(Player *lastPlayer)
Iterate through the list of players.
Definition: g_client.cpp:84
bool G_SetTeamForPlayer(Player &player, const int team)
Set the used team for the given player.
Definition: g_client.cpp:852
#define TU_CROUCH
Definition: defines.h:72
#define CS_PLAYERCOUNT
Definition: q_shared.h:317
void G_ClientMove(const Player &player, int visTeam, Actor *actor, const pos3_t to)
Generates the client events that are send over the netchannel to move an actor.
Definition: g_move.cpp:307
bool inuse
Definition: g_edict.h:47
Structure of all stats collected in a mission.
Definition: chr_shared.h:75
void G_ClientEndRound(Player &player)
Definition: g_round.cpp:184
const objDef_t * def(void) const
Definition: inv_shared.h:469
void G_ActorReserveTUs(Edict *ent, int resReaction, int resShot, int resCrouch)
Reserves TUs for different actor actions.
Definition: g_actor.cpp:136
int G_ClientGetTeamNumPref(const Player &player)
Returns the preferred team number for the player.
Definition: g_client.cpp:897
bool G_ClientCanReload(Actor *actor, containerIndex_t containerID)
Returns true if actor can reload weapon.
Definition: g_client.cpp:536
void G_SendInventory(playermask_t playerMask, const Edict &ent)
Sends whole inventory through the network buffer.
void setBody(unsigned int body_)
Definition: g_edict.h:387
InventoryInterface invi
Definition: g_local.h:76
void G_EventCameraAppear(playermask_t playerMask, const Edict &ent)
Send an appear event to the client.
Definition: g_events.cpp:543
int stuns[KILLED_NUM_TYPES]
Definition: chr_shared.h:127
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
#define TEAM_CIVILIAN
Definition: q_shared.h:61
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
const char * CHRSH_CharGetBody(const character_t *const chr)
Returns the body model for the soldiers for armoured and non armoured soldiers.
Definition: chr_shared.cpp:296
byte dir
Definition: g_edict.h:86
void G_ClientUserinfoChanged(Player &player, const char *userinfo)
called whenever the player updates a userinfo variable.
Definition: g_client.cpp:1393
Edict * G_EdictDuplicate(const Edict *edict)
Definition: g_edicts.cpp:128
#define G_IsActor(ent)
Definition: g_local.h:127
bool G_ClientConnect(Player *player, char *userinfo, size_t userinfoSize)
Checks whether the connection is valid or invalid and set some user info keys.
Definition: g_client.cpp:1436
bool SV_FilterPacket(const char *from)
Definition: g_svcmds.cpp:104
Defines all attributes of objects used in the inventory.
Definition: inv_shared.h:264
#define STATE_CROUCHED
Definition: q_shared.h:263
static void G_ClientStateChangeUpdate(Edict &ent)
After an actor changed his state, he might get visible for other players. Check the vis here and send...
Definition: g_client.cpp:446
void G_AppearPerishEvent(playermask_t playerMask, bool appear, Edict &check, const Edict *ent)
Send the appear or perish event to the affected clients.
Definition: g_client.cpp:245
int integer
Definition: cvar.h:81
void G_ReactionFireSettingsUpdate(Actor *actor, fireDefIndex_t fmIdx, actorHands_t hand, const objDef_t *od)
Updates the reaction fire settings in case something was moved into a hand or from a hand that would ...
Definition: g_reaction.cpp:555
chrScoreMission_t * scoreMission
Definition: chr_shared.h:388
void G_VisFlagsClear(int team)
Reset the visflags for all edicts in the global list for the given team - and only for the given team...
Definition: g_vis.cpp:424
void G_ActorSetMaxs(Actor *actor)
Sets correct bounding box for actor (state dependent).
Definition: g_actor.cpp:226
static Edict * G_ClientGetFreeSpawnPoint(const Player &player, int spawnType)
Find valid actor spawn fields for this player.
Definition: g_client.cpp:963
const csi_t * csi
Definition: game.h:176
Actor * makeActor(Edict *ent)
Convert an Edict pointer into an Actor pointer.
Definition: g_edicts.cpp:327
void G_ReactionFireTargetsCreate(const Edict *shooter)
free function to create a table of reaction fire targets for the given edict.
Definition: g_reaction.cpp:436
Player & getPlayer() const
Definition: g_edict.h:265
#define TEAM_MAX_HUMAN
Definition: q_shared.h:64
Item * getContainer(const containerIndex_t idx) const
Definition: g_edict.h:243
bool isWeapon() const
Definition: inv_shared.h:486
void G_ActorGiveTimeUnits(Actor *actor)
Set time units for the given edict. Based on speed skills.
Definition: g_actor.cpp:260
int spawnflags
Definition: g_edict.h:118
Item * getRightHandItem() const
Definition: g_edict.h:249
void G_ClientStartMatch(Player &player)
Sets the team, init the TU and sends the player stats.
Definition: g_client.cpp:1361
game_locals_t game
Definition: g_main.cpp:37
const char * pa_format[]
Player action format strings for netchannel transfer.
Definition: q_shared.cpp:34
void G_EventSendState(playermask_t playerMask, const Edict &ent)
Definition: g_events.cpp:466
int getTeam() const
Definition: g_edict.h:269
#define CID_LEFT
Definition: inv_shared.h:48
bool G_MatchIsRunning(void)
Checks whether the game is running (active team and no intermission time)
Definition: g_match.cpp:320
#define CS_PLAYERNAMES
Definition: q_shared.h:328
const char * Info_ValueForKey(const char *s, const char *key)
Searches the string for the given key and returns the associated value, or an empty string...
Definition: infostring.cpp:39
item instance data, with linked list capability
Definition: inv_shared.h:402
Match related functions.
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
#define G_IsMultiPlayer()
Definition: g_local.h:145
Player * G_PlayerGetNextActiveAI(Player *lastPlayer)
Iterate through the list of players.
Definition: g_client.cpp:126
int treatmentLevel[BODYPART_MAXTYPE]
Definition: chr_shared.h:352
#define CID_RIGHT
Definition: inv_shared.h:47
game_import_t gi
Definition: g_main.cpp:39
void G_EventStart(const Player &player, bool teamplay)
Definition: g_events.cpp:662
int noRandomSpawn
Definition: g_local.h:108
#define OBJZERO(obj)
Definition: shared.h:178
cvar_t * sv_maxsoldiersperteam
Definition: g_main.cpp:53
void(* think)(Edict *self)
Definition: g_edict.h:150
void G_EventActorAppear(playermask_t playerMask, const Actor &check, const Edict *ent)
Definition: g_events.cpp:571
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition: r_gl.h:110
void G_EventReactionFireChange(const Edict &ent)
Definition: g_events.cpp:282
static void G_ClientSkipActorInfo(void)
Call this if you want to skip some actor netchannel data.
Definition: g_client.cpp:1168
byte num_spawnpoints[MAX_TEAMS]
Definition: g_local.h:116
static void G_GetTeam(Player &player)
Sets the teamnum var for this match.
Definition: g_client.cpp:740
#define REJ_PASSWORD_REQUIRED_OR_INCORRECT
Reject messages that are send to the client from the game module.
Definition: q_shared.h:580
int getWeight() const
Get the weight of the items in the given inventory (excluding those in temp containers).
Definition: inv_shared.cpp:937
int TU
Definition: g_edict.h:88
void G_ReadItem(Item *item, const invDef_t **container, int *x, int *y)
Read item from the network buffer.
int kills[KILLED_NUM_TYPES]
Definition: chr_shared.h:126
void G_ActorUseDoor(Actor *actor, Edict *door)
Make the actor use (as in open/close) a door edict.
Definition: g_actor.cpp:55
bool Info_Validate(const char *s)
Some characters are illegal in info strings because they can mess up the server's parsing...
Definition: infostring.cpp:142
teammask_t visflags
Definition: g_edict.h:82
static void G_ClientSendEdictsAndBrushModels(const Player &player)
Send brush models for entities like func_breakable and func_door and triggers with their bounding box...
Definition: g_client.cpp:1296
int AIL_InitActor(Actor *actor)
Initializes the lua AI for an actor.
Definition: g_ai_lua.cpp:2203
All parts of the main game logic that are combat related.
bool G_ClientBegin(Player &player)
This functions starts the client.
Definition: g_client.cpp:1323
#define G_PlayerToPM(player)
Definition: g_events.h:37
int32_t fireDefIndex_t
Definition: inv_shared.h:78
static void G_ClientTurn(Player &player, Actor *actor, dvec_t dvec)
Sends the actual actor turn event over the netchannel.
Definition: g_client.cpp:415
int G_ActorGetContentFlags(const vec3_t origin)
Get the content flags from where the actor is currently standing.
Definition: g_actor.cpp:484
player_action_t
Definition: q_shared.h:189
void G_EventEdictPerish(playermask_t playerMask, const Edict &ent)
Send disappear event.
Definition: g_events.cpp:624
pos3_t pos
Definition: g_edict.h:55
char head[MAX_VAR]
Definition: chr_shared.h:374
static void G_ThinkActorGoCrouch(Edict *ent)
Think function for actors that spawn crouched.
Definition: g_client.cpp:1026
void G_EventSendParticle(playermask_t playerMask, const Edict &ent)
Definition: g_events.cpp:529
actorHands_t
Definition: inv_shared.h:626
#define STATE_DEAD
Definition: q_shared.h:262
void G_ClientInitActorStates(const Player &player)
This is called after the actors are spawned and will set actor states without consuming TUs...
Definition: g_client.cpp:1215
static void G_ClientReadCharacter(Edict *ent)
Reads the character data from the netchannel that is needed to spawn an actor.
Definition: g_client.cpp:1125
An Edict of type Actor.
Definition: g_edict.h:348
static bool G_ActorDie(Actor *actor, const Edict *attacker)
Definition: g_actor.cpp:405
byte num_alive[MAX_TEAMS]
Definition: g_local.h:115
bool G_ClientIsReady(const Player *player)
Definition: g_client.cpp:905
#define TEAM_DEFAULT
Definition: defines.h:51
#define TU_TURN
Definition: defines.h:73
playermask_t G_VisToPM(teammask_t teamMask)
Converts vis mask to player mask.
Definition: g_client.cpp:186
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition: common.cpp:398
const invDef_t * def() const
Definition: inv_shared.cpp:667
Edict * clientAction
Definition: g_edict.h:113
teamDef_t teamDef[MAX_TEAMDEFS]
Definition: q_shared.h:548
#define INVDEF(containerID)
Definition: cl_shared.h:47
#define G_IsVisibleOnBattlefield(ent)
Definition: g_local.h:140
Item * getNextItem(const Item *prev) const
Definition: inv_shared.cpp:671
pos_t pos3_t[3]
Definition: ufotypes.h:58
#define STATE_STUN
Definition: q_shared.h:268
int flags
Definition: g_edict.h:169
void G_ActorModifyCounters(const Edict *attacker, const Edict *victim, int deltaAlive, int deltaKills, int deltaStuns)
Definition: g_actor.cpp:299
const char * CHRSH_CharGetHead(const character_t *const chr)
Returns the head model for the soldiers for armoured and non armoured soldiers.
Definition: chr_shared.cpp:318
bool G_ActorInvMove(Actor *actor, const invDef_t *fromContType, Item *fItem, const invDef_t *toContType, int tx, int ty, bool checkaction)
Moves an item inside an inventory. Floors are handled special.
Definition: g_actor.cpp:506
actorSizeEnum_t fieldSize
Definition: g_edict.h:141
#define REJ_BANNED
Definition: q_shared.h:582
bool canHoldItemWeight(containerIndex_t from, containerIndex_t to, const Item &item, int maxWeight) const
Check that adding an item to the inventory won't exceed the max permitted weight. ...
Definition: inv_shared.cpp:919
QGL_EXTERN GLuint count
Definition: r_gl.h:99
cvar_t * g_nospawn
Definition: g_main.cpp:118
woundInfo_t wounds
Definition: chr_shared.h:383
void G_EventAddBrushModel(playermask_t playerMask, const Edict &ent)
Definition: g_events.cpp:639
void G_ResetClientData(void)
Called after every player has joined.
Definition: g_client.cpp:1510
#define G_TeamToVisMask(team)
Definition: g_local.h:143
int32_t containerIndex_t
Definition: inv_shared.h:46
#define G_ToggleCrouched(ent)
Definition: g_actor.h:42
int G_CheckVisTeamAll(const int team, const vischeckflags_t visFlags, const Edict *ent)
Do G_CheckVisTeam for all entities ent is the one that is looking at the others.
Definition: g_vis.cpp:376
bool isLoadableInWeapon(const objDef_s *weapon) const
Checks if an item can be used to reload a weapon.
Definition: inv_shared.cpp:356
bool isShaken() const
Definition: g_edict.h:354
void Info_SetValueForKey(char *s, const size_t size, const char *key, const char *value)
Adds a new entry into string with given value.
Definition: infostring.cpp:169
Item * addToInventory(Inventory *const inv, const Item *const item, const invDef_t *container, int x, int y, int amount) __attribute__((warn_unused_result))
Add an item to a specified container in a given inventory.
Definition: inventory.cpp:91
void setMorale(int mor)
Definition: g_edict.h:311
#define G_IsSinglePlayer()
Definition: g_local.h:146
cvar_t * password
Definition: g_main.cpp:67
void G_ActorUseTU(Edict *ent, int tus)
Definition: g_actor.cpp:278
void G_GiveTimeUnits(int team)
Network function to update the time units (TUs) for each team-member.
Definition: g_client.cpp:224
short numBodyParts(void) const
Definition: chr_shared.cpp:388
#define G_IsAI(ent)
Definition: g_local.h:141
int contentFlags
Definition: g_edict.h:84
int sv_maxplayersperteam
Definition: g_local.h:73
bool G_ActionCheckForCurrentTeam(const Player &player, Actor *ent, int TU)
Checks whether the requested action is possible for the current active team.
Definition: g_client.cpp:380
bool G_ClientShoot(const Player &player, Actor *actor, const pos3_t at, shoot_types_t shootType, fireDefIndex_t firemode, shot_mock_t *mock, bool allowReaction, int z_align)
Setup for shooting, either real or mock.
Definition: g_combat.cpp:1183
void G_ClientTeamInfo(const Player &player)
The client lets the server spawn the actors for a given player by sending their information (models...
Definition: g_client.cpp:1255
Actor * G_EdictsGetNextLivingActorOfTeam(Actor *lastEnt, const int team)
Iterate through the living actor entities of the given team.
Definition: g_edicts.cpp:216
void G_VisFlagsReset(Edict &ent)
Definition: g_vis.cpp:438
float frand(void)
Return random values between 0 and 1.
Definition: mathlib.cpp:506
#define G_SetState(ent, s)
Definition: g_actor.h:36
QGL_EXTERN GLint i
Definition: r_gl.h:113
int getTus() const
Definition: g_edict.h:318
cvar_t * sv_roundtimelimit
Definition: g_main.cpp:56
char * string
Definition: cvar.h:73
int getPlayerNum() const
Definition: g_edict.h:234
#define G_IsDead(ent)
Definition: g_actor.h:34
bool isCrouched() const
Definition: g_edict.h:361
const Container * getNextCont(const Container *prev, bool inclTemp=false) const
Definition: inv_shared.cpp:722
Actor * G_EdictsGetNextActor(Actor *lastEnt)
Iterate through the actor entities (even the dead!)
Definition: g_edicts.cpp:231
#define FL_DESTROYABLE
If an edict is destroyable (like ET_BREAKABLE, ET_DOOR [if health set] or maybe a ET_MISSION [if heal...
Definition: g_local.h:287
entity_type_t type
Definition: g_edict.h:81
int noEquipment
Definition: g_local.h:109
#define G_IsDoor(ent)
Definition: g_local.h:135
void G_ActorSetTU(Edict *ent, int tus)
Definition: g_actor.cpp:267
const BodyData * bodyTemplate
Definition: chr_shared.h:339
bool temp
Definition: inv_shared.h:381
#define REJ_SERVER_FULL
Definition: q_shared.h:583
functions to handle the storage and lifecycle of all edicts in the game module.
Item * getItemAtPos(const invDef_t *container, const int x, const int y) const
Searches if there is an item at location (x,y) in a container.
Definition: inv_shared.cpp:844
unsigned num_spawned[MAX_TEAMS]
Definition: g_local.h:112
void G_CheckVisPlayer(Player &player, const vischeckflags_t visFlags)
Sets visible edict on player spawn.
Definition: g_vis.cpp:327
vec3_t origin
Definition: g_edict.h:53
bool G_UseEdict(Edict *ent, Edict *activator)
Call the 'use' function for the given edict and all its group members.
Definition: g_utils.cpp:117
bool isHeldTwoHanded() const
Definition: inv_shared.h:476
bool isReaction() const
Definition: g_edict.h:357
inventory definition for our menus
Definition: inv_shared.h:371
void G_EventActorAdd(playermask_t playerMask, const Edict &ent, const bool instant)
Definition: g_events.cpp:511
unsigned int teammask_t
Definition: g_vis.h:30
void setPlayerNum(int num)
Definition: g_edict.h:186
const objDef_t * INVSH_GetItemByIDX(int index)
Returns the item that belongs to the given index or nullptr if the index is invalid.
Definition: inv_shared.cpp:266
Inventory inv
Definition: chr_shared.h:392
bool G_ReactionFireSettingsReserveTUs(Actor *ent)
Set the reaction fire TU reservation for an actor.
Definition: g_reaction.cpp:665
bool G_ActorDieOrStun(Actor *actor, Edict *attacker)
Reports and handles death or stun of an actor. If the HP of an actor is zero the actor will die...
Definition: g_actor.cpp:435
containerIndex_t id
Definition: inv_shared.h:373
#define PRINT_CONSOLE
Definition: defines.h:108
char name[MAX_VAR]
Definition: chr_shared.h:371
#define getDVdir(dv)
Definition: mathlib.h:249
bool isValidContId(const containerIndex_t id)
Definition: inv_shared.h:59
void G_MatchEndCheck(void)
Checks whether there are still actors to fight with left. If none are the match end will be triggered...
Definition: g_match.cpp:280
int G_GetActiveTeam(void)
Returns the current active team to the server.
Definition: g_client.cpp:327
#define G_IsVisibleForTeam(ent, team)
Definition: g_local.h:144
int G_ClientAction(Player &player)
The client sent us a message that he did something. We now execute the related function(s) and notify...
Definition: g_client.cpp:638
static void G_GetStartingTeam(const Player &player)
Chose a team that should start the match.
Definition: g_client.cpp:916
static bool G_ActionCheck(const Player &player, Edict *ent)
Checks whether the requested action is possible.
Definition: g_client.cpp:337
short dvec_t
The direction vector tells us where the actor came from (in his previous step). The pathing table hol...
Definition: mathlib.h:236
#define GET_MORALE(ab)
Definition: q_shared.h:290
Edict * G_EdictsGetByNum(const int num)
Get an entity by it's number.
Definition: g_edicts.cpp:83
#define NONE
Definition: defines.h:68
#define Q_streq(a, b)
Definition: shared.h:136
void G_SendPlayerStats(const Player &player)
Write player stats to network buffer.
Definition: g_stats.cpp:49
int numplayers
Definition: g_local.h:100
void setHead(unsigned int head_)
Definition: g_edict.h:393
int G_ClientGetTeamNum(const Player &player)
Returns the assigned team number of the player.
Definition: g_client.cpp:889
#define TEAM_NO_ACTIVE
Definition: q_shared.h:60
bool modified
Definition: cvar.h:79
static bool G_ActorSpawnIsAllowed(const int num, const int team)
Checks whether the spawn of an actor is allowed for the current running match.
Definition: g_client.cpp:1002
void G_SendStats(Edict &ent)
Send stats to network buffer.
Definition: g_stats.cpp:34
void G_VisFlagsAdd(Edict &ent, teammask_t teamMask)
Definition: g_vis.cpp:433
Player * G_PlayerGetNextHuman(Player *lastPlayer)
Iterate through the list of players.
Definition: g_client.cpp:58
bool G_ClientUseEdict(const Player &player, Actor *actor, Edict *edict)
This function 'uses' the edict. E.g. it opens the door when the player wants it to open...
Definition: g_client.cpp:614
Definition: g_edict.h:45
Actor * G_ClientGetFreeSpawnPointForActorSize(const Player &player, const actorSizeEnum_t actorSize)
Searches a free spawning point for a given actor size and turns it into an actor. ...
Definition: g_client.cpp:1039
#define ACTOR_SIZE_NORMAL
Definition: defines.h:302
cvar_t * sv_teamplay
Definition: g_main.cpp:61
int pnum
Definition: g_edict.h:97
bool weapons
Definition: chr_shared.h:324
static void G_ClientReadInventory(Edict *ent)
Read the inventory from the clients team data.
Definition: g_client.cpp:1102
actorSizeEnum_t fieldSize
Definition: chr_shared.h:390
#define G_IsAIPlayer(player)
Definition: g_local.h:142
int skills[SKILL_NUM_TYPES]
Definition: chr_shared.h:122
static int scoreMissionNum
Definition: g_client.cpp:52
char body[MAX_VAR]
Definition: chr_shared.h:373
bool G_ActionCheckForReaction(const Player &player, Actor *actor, int TU)
Checks whether the requested action is possible.
Definition: g_client.cpp:403
const char * id
Definition: inv_shared.h:268
Interface for g_client.cpp.
playermask_t G_TeamToPM(int team)
Generates the player bit mask for a given team.
Definition: g_client.cpp:144
void format(__printf__, 1, 2)))
#define DEBUG_GAME
Definition: defines.h:61
int Info_IntegerForKey(const char *s, const char *key)
Definition: infostring.cpp:84
level_locals_t level
Definition: g_main.cpp:38
int HP
Definition: g_edict.h:89
#define PRINT_HUD
Definition: defines.h:107
chrReservations_t reservedTus
Definition: chr_shared.h:396
int GetUsedSlots()
Calculate the number of used inventory slots.
Definition: inventory.cpp:966
#define MAX_EDICTS
Definition: defines.h:99