UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
g_actor.cpp
Go to the documentation of this file.
1 
5 /*
6 Copyright (C) 2002-2020 UFO: Alien Invasion.
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 
17 See the GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23 */
24 
25 #include "g_actor.h"
26 #include "g_client.h"
27 #include "g_edicts.h"
28 #include "g_health.h"
29 #include "g_inventory.h"
30 #include "g_reaction.h"
31 #include "g_spawn.h"
32 #include "g_utils.h"
33 #include "g_vis.h"
34 
35 /* however we manipulate TUs, this value must never be exceeded */
36 #define MAX_TU (ROUTING_NOT_REACHABLE - 1)
37 
43 bool G_IsLivingActor (const Edict* ent)
44 {
45  return G_IsActor(ent) && (G_IsStunned(ent) || !G_IsDead(ent));
46 }
47 
55 void G_ActorUseDoor (Actor* actor, Edict* door)
56 {
57  /* check whether it's part of an edict group but not the master */
58  if (door->flags & FL_GROUPSLAVE)
59  door = door->groupMaster;
60 
61  if (!G_ClientUseEdict(actor->getPlayer(), actor, door))
62  return;
63 
64  /* end this loop here, for the AI this is a) not interesting,
65  * and b) could result in endless loops */
66  if (G_IsAI(actor))
67  return;
68 
69  Edict* closeActor = nullptr;
70  while ((closeActor = G_FindRadius(closeActor, door->origin, UNIT_SIZE * 3))) {
71  /* check whether the door is still reachable (this might have
72  * changed due to the rotation) or whether an actor can reach it now */
73  G_TouchTriggers(closeActor);
74  }
75 }
76 
82 void G_ActorSetClientAction (Edict* actor, Edict* ent)
83 {
84  if (actor->clientAction == ent)
85  return;
86 
87  assert(ent == nullptr || (ent->flags & FL_CLIENTACTION));
88  actor->clientAction = ent;
89  if (ent == nullptr) {
91  } else {
92  G_EventSetClientAction(*actor);
93  }
94 }
95 
102 int G_ActorUsableTUs (const Edict* ent)
103 {
104  if (!ent)
105  return 0;
106 
107  return ent->getTus() - ent->getReservedTUs();
108 }
109 
117 {
118  const FiremodeSettings* fm = &ent->chr.RFmode;
119 
120  const Item* weapon = ent->getHandItem(fm->getHand());
121  assert(weapon);
122  assert(weapon->def());
123 
124  const fireDef_t* fd = weapon->getFiredefs();
125  assert(fd);
126  return G_ActorGetModifiedTimeForFiredef(ent, &fd[fm->getFmIdx()], false);
127 }
128 
136 void G_ActorReserveTUs (Edict* ent, int resReaction, int resShot, int resCrouch)
137 {
138  if (ent->getTus() >= resReaction + resShot + resCrouch) {
139  ent->chr.reservedTus.reaction = resReaction;
140  ent->chr.reservedTus.shot = resShot;
141  ent->chr.reservedTus.crouch = resCrouch;
142  }
143 
145 }
146 
154 int G_ActorDoTurn (Edict* ent, byte dir)
155 {
156  assert(ent->dir < CORE_DIRECTIONS);
157  assert(dir < PATHFINDING_DIRECTIONS);
158 
159  /*
160  * If dir is at least CORE_DIRECTIONS but less than FLYING_DIRECTIONS,
161  * then the direction is an action.
162  */
166  if (dir >= CORE_DIRECTIONS && dir < FLYING_DIRECTIONS)
167  return 0;
168 
169  /* Clamp dir between 0 and CORE_DIRECTIONS - 1. */
170  dir &= (CORE_DIRECTIONS - 1);
171  assert(dir < CORE_DIRECTIONS);
172 
173  /* Return if no rotation needs to be done. */
174  if (ent->dir == dir)
175  return 0;
176 
177  /* calculate angle difference */
178  float angleDiv = directionAngles[dir] - directionAngles[ent->dir];
179  if (angleDiv > 180.0)
180  angleDiv -= 360.0;
181  if (angleDiv < -180.0)
182  angleDiv += 360.0;
183 
184  /* prepare rotation - decide whether the actor turns around the left
185  * shoulder or the right - this is needed the get the rotation vector
186  * that is used below to check in each of the rotation steps
187  * (1/8, 22.5 degree) whether something became visible while turning */
188  const byte* rot;
189  int num;
190  if (angleDiv > 0) {
191  const int angleStep = (360.0 / CORE_DIRECTIONS);
192  rot = dvleft;
193  num = (angleDiv + angleStep / 2) / angleStep;
194  } else {
195  const int angleStep = (360.0 / CORE_DIRECTIONS);
196  rot = dvright;
197  num = (-angleDiv + angleStep / 2) / angleStep;
198  }
199 
200  /* do rotation and vis checks */
201  int status = 0;
202 
203  /* check every angle (1/8 steps - on the way to the end direction) in the rotation
204  * whether something becomes visible and stop before reaching the final direction
205  * if this happened */
206  for (int i = 0; i < num; i++) {
207  ent->dir = rot[ent->dir];
208  assert(ent->dir < CORE_DIRECTIONS);
209  status |= G_CheckVisTeamAll(ent->getTeam(), 0, ent);
210  }
211 
212  if (status & VIS_STOP) {
213  /* send the turn */
214  G_EventActorTurn(*ent);
215  }
216 
217  return status;
218 }
219 
226 void G_ActorSetMaxs (Actor* actor)
227 {
228  switch (actor->type) {
229  case ET_ACTOR:
231  break;
232  case ET_ACTOR2x2:
234  break;
235  default:
236  gi.Error("G_ActorSetMaxs: Unknown actor type: %i (ent %i)", actor->type, actor->getIdNum());
237  }
238  if (actor->isCrouched())
239  actor->entBox.setMaxZ(PLAYER_CROUCH);
240  else if (actor->isDead() && !CHRSH_IsTeamDefRobot(actor->chr.teamDef))
241  actor->entBox.setMaxZ(PLAYER_DEAD);
242 
243  /* Link it. */
244  gi.LinkEdict(actor);
245 }
246 
247 int G_ActorCalculateMaxTU (const Edict* ent)
248 {
249  const int invWeight = ent->chr.inv.getWeight();
250  const int currentMaxTU = GET_TU(ent->chr.score.skills[ABILITY_SPEED], GET_ENCUMBRANCE_PENALTY(invWeight,
252 
253  return std::min(currentMaxTU, MAX_TU);
254 }
255 
261 {
262  const int tus = actor->isDazed() ? 0 : G_ActorCalculateMaxTU(actor);
263  G_ActorSetTU(actor, tus);
264  actor->removeDazed();
265 }
266 
267 void G_ActorSetTU (Edict* ent, int tus)
268 {
269  if (tus > 0 && tus < ent->getTus()) {
270  if (g_notu != nullptr && g_notu->integer) {
271  ent->setTus(G_ActorCalculateMaxTU(ent));
272  return;
273  }
274  }
275  ent->setTus(std::max(tus, 0));
276 }
277 
278 void G_ActorUseTU (Edict* ent, int tus)
279 {
280  G_ActorSetTU(ent, ent->getTus() - tus);
281 }
282 
283 static bool G_ActorStun (Actor* actor, const Edict* attacker)
284 {
285  /* already dead or stunned? */
286  if (actor->isDead())
287  return false;
288 
289  /* no other state should be set here */
290  actor->state = STATE_STUN;
291  G_ActorSetMaxs(actor);
292  actor->link = attacker;
293 
294  G_ActorModifyCounters(attacker, actor, -1, 0, 1);
295 
296  return true;
297 }
298 
299 void G_ActorModifyCounters (const Edict* attacker, const Edict* victim, int deltaAlive, int deltaKills, int deltaStuns)
300 {
301  const int victimTeam = victim->getTeam();
302  const unsigned spawned = level.num_spawned[victimTeam];
303  const int attackerTeam = (attacker != nullptr ? attacker->getTeam() : MAX_TEAMS);
304  byte* alive = level.num_alive;
305 
306  alive[victimTeam] += deltaAlive;
307  if (alive[victimTeam] > spawned)
308  gi.Error("alive counter out of sync");
309 
310  if (deltaStuns != 0) {
311  unsigned* stuns = level.num_stuns[attackerTeam];
312  stuns[victimTeam] += deltaStuns;
313  if (stuns[victimTeam] > spawned)
314  gi.Error("stuns counter out of sync");
315  }
316 
317  if (deltaKills != 0) {
318  unsigned* kills = level.num_kills[attackerTeam];
319  kills[victimTeam] += deltaKills;
320  if (kills[victimTeam] > spawned)
321  gi.Error("kills counter out of sync");
322  }
323 #if 0
324  {
325  Com_Printf("num_spawned: %i\n", spawned);
326 
327  if (attacker)
328  for (int i = 0; i < MAX_TEAMS; i++) {
329  if (i == victimTeam) {
330  Com_Printf("^2num_alive (team %i): %i\n", i, level.num_alive[i]);
331  } else {
332  Com_Printf("num_alive (team %i): %i\n", i, level.num_alive[i]);
333  }
334 
335  for (int j = 0; j < MAX_TEAMS; j++) {
336  if (j == victimTeam) {
337  Com_Printf("^2num_kills (team %i killed %i): %i\n", i, j, level.num_kills[i][j]);
338  Com_Printf("^2num_stuns (team %i stunned %i): %i\n", i, j, level.num_stuns[i][j]);
339  } else if (i == attacker->team) {
340  Com_Printf("^3num_kills (team %i killed %i): %i\n", i, j, level.num_kills[i][j]);
341  Com_Printf("^3num_stuns (team %i stunned %i): %i\n", i, j, level.num_stuns[i][j]);
342  } else {
343  Com_Printf("num_kills (team %i killed %i): %i\n", i, j, level.num_kills[i][j]);
344  Com_Printf("num_stuns (team %i stunned %i): %i\n", i, j, level.num_stuns[i][j]);
345  }
346  }
347  }
348  }
349 #endif
350 }
351 
357 void G_ActorGetEyeVector (const Edict* actor, vec3_t eye)
358 {
359  VectorCopy(actor->origin, eye);
360  if (G_IsCrouched(actor) || G_IsPanicked(actor))
361  eye[2] += EYE_CROUCH;
362  else
363  eye[2] += EYE_STAND;
364 }
365 
366 static void G_ActorRevitalise (Actor* actor)
367 {
368  if (actor->isStunned()) {
369  actor->removeStunned();
372  G_ActorModifyCounters(actor->link, actor, 1, 0, -1);
373  G_GetFloorItems(actor);
374  }
375  G_ActorSetMaxs(actor);
376 
377  /* check if the player appears/perishes, seen from other teams */
378  G_CheckVis(actor);
379 
380  /* calc new vis for this player */
381  G_CheckVisTeamAll(actor->getTeam(), 0, actor);
382 
383  G_PrintStats("%s is revitalized.", actor->chr.name);
384 }
385 
387 {
388  if (actor->isStunned() && actor->getStun() < actor->HP) {
389  /* check that we could move after we stood up */
390  Edict* otherActor = nullptr;
391  while ((otherActor = G_EdictsGetNextInUse(otherActor))) {
392  if (!VectorCompare(actor->pos, otherActor->pos))
393  continue;
394  if (G_IsBlockingMovementActor(otherActor))
395  return;
396  }
397 
398  G_ActorRevitalise(actor);
399  G_EventActorRevitalise(*actor);
400  G_EventActorStateChange(~G_VisToPM(actor->visflags), *actor);
401  G_SendStats(*actor);
402  }
403 }
404 
405 static bool G_ActorDie (Actor* actor, const Edict* attacker)
406 {
407  const bool stunned = actor->isStunned();
408 
409  actor->removeStunned();
410 
411  if (actor->isDead())
412  return false;
413 
414  G_SetState(actor, 1 + rand() % MAX_DEATH);
415  G_ActorSetMaxs(actor);
416 
417  if (stunned) {
418  G_ActorModifyCounters(attacker, actor, 0, 1, 0);
419  G_ActorModifyCounters(actor->link, actor, 0, 0, -1);
420  } else {
421  G_ActorModifyCounters(attacker, actor, -1, 1, 0);
422  }
423 
424  return true;
425 }
426 
435 bool G_ActorDieOrStun (Actor* actor, Edict* attacker)
436 {
437  bool state;
438 
439  if (actor->HP == 0)
440  state = G_ActorDie(actor, attacker);
441  else
442  state = G_ActorStun(actor, attacker);
443 
444  /* no state change performed? */
445  if (!state) {
446  gi.DPrintf("G_ActorDieOrStun: State wasn't changed\n");
447  return false;
448  }
449 
450  if (!actor->isStunned())
451  actor->solid = SOLID_NOT;
452 
453  /* send death */
454  G_EventActorDie(*actor, attacker != nullptr);
455  G_EventActorStateChange(~G_VisToPM(actor->visflags), *actor);
456 
457  /* handle inventory - drop everything but the armour to the floor */
458  G_InventoryToFloor(actor);
459  G_ClientStateChange(actor->getPlayer(), actor, ~STATE_REACTION, false);
460 
461  /* check if the player appears/perishes, seen from other teams */
462  G_CheckVis(actor);
463 
464  /* check if the attacker appears/perishes, seen from other teams */
465  if (attacker)
466  G_CheckVis(attacker);
467 
468  /* calc new vis for this player */
469  G_CheckVisTeamAll(actor->getTeam(), 0, attacker);
470 
471  /* unlink the floor container */
472  actor->resetFloor();
473 
474  G_ReactionFireOnDead(actor);
475  if (!actor->isStunned())
477 
478  return true;
479 }
480 
485 {
486  vec3_t pointTrace;
487 
488  VectorCopy(origin, pointTrace);
489  pointTrace[2] += PLAYER_MIN;
490 
491  return gi.PointContents(pointTrace);
492 }
493 
506 bool G_ActorInvMove (Actor* actor, const invDef_t* fromContType, Item* fItem, const invDef_t* toContType, int tx, int ty, bool checkaction)
507 {
508  assert(fItem);
509  assert(fItem->def());
510 
511  /* Store the location/item of 'from' BEFORE actually moving items with moveInInventory. */
512  Item fromItemBackup = *fItem;
513 
514  /* Store the location of 'to' BEFORE actually moving items with moveInInventory
515  * so in case we swap ammo the client can be updated correctly */
516  Item* tc = actor->chr.inv.getItemAtPos(toContType, tx, ty);
517  Item toItemBackup;
518  if (tc)
519  toItemBackup = *tc;
520  else
521  toItemBackup = *fItem;
522 
523  /* Get first used bit in item. */
524  int fx, fy;
525  fItem->getFirstShapePosition(&fx, &fy);
526  fx += fItem->getX();
527  fy += fItem->getY();
528 
529  /* Check if action is possible */
530  /* TUs are 1 here - but this is only a dummy - the real TU check is done in the inventory functions below */
531  Player& player = actor->getPlayer();
532  if (checkaction && !G_ActionCheckForCurrentTeam(player, actor, 1))
533  return false;
534 
535  if (!actor->chr.inv.canHoldItemWeight(fromContType->id, toContType->id, *fItem, actor->chr.score.skills[ABILITY_POWER])) {
536  G_ClientPrintf(player, PRINT_HUD, _("This soldier can not carry anything else."));
537  return false;
538  }
539 
540  /* "get floor ready" - searching for existing floor-edict */
541  Edict* floor = G_GetFloorItems(actor);
542  bool newFloor = false;
543  if (toContType->isFloorDef() && !floor) {
544  /* We are moving to the floor, but no existing edict for this floor-tile found -> create new one */
545  floor = G_SpawnFloor(actor->pos);
546  newFloor = true;
547  } else if (fromContType->isFloorDef() && !floor) {
548  /* We are moving from the floor, but no existing edict for this floor-tile found -> this should never be the case. */
549  gi.DPrintf("G_ClientInvMove: No source-floor found.\n");
550  return false;
551  }
552 
553  /* search for space */
554  Item* item2;
555  if (tx == NONE) {
556  item2 = actor->chr.inv.getItemAtPos(fromContType, fItem->getX(), fItem->getY());
557  if (item2)
558  actor->chr.inv.findSpace(toContType, item2, &tx, &ty, fItem);
559  if (tx == NONE)
560  return false;
561  }
562 
564  /* Because moveInInventory don't know anything about character_t and it updates actor->TU,
565  * we need to save original actor->TU for the sake of checking TU reservations. */
566  int originalTU = actor->getTus();
567  int reservedTU = actor->getReservedTUs();
568  /* Temporary decrease actor->TU to make moveInInventory do what expected. */
569  G_ActorUseTU(actor, reservedTU);
570  /* Try to actually move the item and check the return value after restoring valid actor->TU. */
572  ia = game.invi.moveInInventory(&actor->chr.inv, fromContType, fItem, toContType, tx, ty, checkaction ? &actor->TU : nullptr, &item2);
573  /* Now restore the original actor->TU and decrease it for TU used for inventory move. */
574  G_ActorSetTU(actor, originalTU - (originalTU - reservedTU - actor->getTus()));
575 
576  switch (ia) {
577  case IA_NONE:
578  /* No action possible - abort */
579  return false;
580  case IA_NOTIME:
581  G_ClientPrintf(player, PRINT_HUD, _("Can't perform action - not enough TUs!"));
582  /* New floor was created, inventory move was aborted, delete empty the floor */
583  if (newFloor) {
584  G_FreeEdict(floor);
585  }
586  return false;
587  case IA_NORELOAD:
588  G_ClientPrintf(player, PRINT_HUD,
589  _("Can't perform action - weapon already fully loaded with the same ammunition!"));
590  return false;
591  default:
592  /* Continue below. */
593  break;
594  }
595 
596  /* successful inventory change; remove the item in clients */
597  if (fromContType->isFloorDef()) {
598  /* We removed an item from the floor - check how the client
599  * needs to be updated. */
600  assert(!newFloor);
601  if (actor->getFloor()) {
602  /* There is still something on the floor. */
603  floor->setFloor(actor);
604  /* Delay this if swapping ammo, otherwise the le will be removed in the client before we can add back
605  * the current ammo because removeNextFrame is set in LE_PlaceItem() if the floor le has no items */
606  if (ia != IA_RELOAD_SWAP)
607  G_EventInventoryDelete(*floor, G_VisToPM(floor->visflags), fromContType->id, fx, fy);
608  } else {
609  /* Floor is empty, remove the edict (from server + client) if we are
610  * not moving to it. */
611  if (!toContType->isFloorDef()) {
612  G_EventPerish(*floor);
613  G_FreeEdict(floor);
614  } else
615  G_EventInventoryDelete(*floor, G_VisToPM(floor->visflags), fromContType->id, fx, fy);
616  }
617  } else {
618  G_EventInventoryDelete(*actor, G_TeamToPM(actor->getTeam()), fromContType->id, fx, fy);
619  }
620 
621  /* send tu's */
622  G_SendStats(*actor);
623 
624  assert(item2);
625  Item item = *item2;
626  playermask_t mask;
627 
628  if (ia == IA_RELOAD || ia == IA_RELOAD_SWAP) {
629  /* reload */
630  if (toContType->isFloorDef())
631  mask = G_VisToPM(floor->visflags);
632  else
633  mask = G_TeamToPM(actor->getTeam());
634 
635  G_EventInventoryReload(toContType->isFloorDef() ? *floor : *actor, mask, &item, toContType, item2);
636 
637  if (ia == IA_RELOAD) {
638  return true;
639  } else { /* ia == IA_RELOAD_SWAP */
640  item.setAmmoLeft(NONE_AMMO);
641  item.setAmmoDef(nullptr);
642  item.setDef(toItemBackup.ammoDef());
643  item.rotated = fromItemBackup.rotated;
644  item.setAmount(toItemBackup.getAmount());
645  toContType = fromContType;
646  if (toContType->isFloorDef()) {
647  /* moveInInventory placed the swapped ammo in an available space, check where it was placed
648  * so we can place it at the same place in the client, otherwise since fItem hasn't been removed
649  * this could end in a different place in the client - will cause an error if trying to use it again */
650  item2 = actor->chr.inv.findInContainer(toContType->id, &item);
651  assert(item2);
652  fromItemBackup = item;
653  fromItemBackup.setX(item2->getX());
654  fromItemBackup.setY(item2->getY());
655  }
656  tx = fromItemBackup.getX();
657  ty = fromItemBackup.getY();
658  }
659  }
660 
661  /* We moved an item to the floor - check how the client needs to be updated. */
662  if (toContType->isFloorDef()) {
663  /* we have to link the temp floor container to the new floor edict or add
664  * the item to an already existing floor edict - the floor container that
665  * is already linked might be from a different entity (this might happen
666  * in case of a throw by another actor) */
667  floor->setFloor(actor);
668 
669  /* A new container was created for the floor. */
670  if (newFloor) {
671  /* Send item info to the clients */
672  G_CheckVis(floor);
673  } else {
674  /* use the backup item to use the old amount values, because the clients have to use the same actions
675  * on the original amount. Otherwise they would end in a different amount of items as the server (+1) */
676  G_EventInventoryAdd(*floor, G_VisToPM(floor->visflags), 1);
677  G_WriteItem(fromItemBackup, toContType->id, tx, ty);
678  G_EventEnd();
679  /* Couldn't remove it before because that would remove the le from the client and would cause battlescape to crash
680  * when trying to add back the swapped ammo above */
681  if (ia == IA_RELOAD_SWAP)
682  G_EventInventoryDelete(*floor, G_VisToPM(floor->visflags), fromContType->id, fx, fy);
683  }
684  } else {
685  G_EventInventoryAdd(*actor, G_TeamToPM(actor->getTeam()), 1);
686  G_WriteItem(item, toContType->id, tx, ty);
687  G_EventEnd();
688  }
689 
690  G_ReactionFireSettingsUpdate(actor, actor->chr.RFmode.getFmIdx(), actor->chr.RFmode.getHand(), actor->chr.RFmode.getWeapon());
691 
692  /* Other players receive weapon info only. */
693  mask = G_VisToPM(actor->visflags) & ~G_TeamToPM(actor->getTeam());
694  if (mask) {
695  if (fromContType->isRightDef() || fromContType->isLeftDef()) {
696  G_EventInventoryDelete(*actor, mask, fromContType->id, fx, fy);
697  }
698  if (toContType->isRightDef() || toContType->isLeftDef()) {
699  G_EventInventoryAdd(*actor, mask, 1);
700  G_WriteItem(item, toContType->id, tx, ty);
701  G_EventEnd();
702  }
703  }
704 
705  return true;
706 }
707 
714 bool G_ActorReload (Actor* actor, const invDef_t* invDef)
715 {
716  const objDef_t* weapon;
717 
718  if (actor->getContainer(invDef->id)) {
719  weapon = actor->getContainer(invDef->id)->def();
720  } else if (invDef->isLeftDef() && actor->getRightHandItem()->isHeldTwoHanded()) {
721  /* Check for two-handed weapon */
722  invDef = INVDEF(CID_RIGHT);
723  weapon = actor->getRightHandItem()->def();
724  } else
725  return false;
726 
727  assert(weapon);
728 
729  /* LordHavoc: Check if item is researched when in singleplayer? I don't think this is really a
730  * cheat issue as in singleplayer there is no way to inject fake client commands in the virtual
731  * network buffer, and in multiplayer everything is researched */
732 
733  /* search for clips and select the one that is available easily */
734  /* also try the temp containers */
735  const invDef_t* bestContainer = nullptr;
736  Item* ammoItem = nullptr;
737  int tu = 100;
738  const Container* cont = nullptr;
739  while ((cont = actor->chr.inv.getNextCont(cont, true))) {
740  if (cont->def()->out >= tu)
741  continue;
742  /* Once we've found at least one clip, there's no point
743  * searching other containers if it would take longer
744  * to retrieve the ammo from them than the one
745  * we've already found. */
746  Item* item = nullptr;
747  while ((item = cont->getNextItem(item))) {
748  if (item->def()->isLoadableInWeapon(weapon)) {
749  ammoItem = item;
750  bestContainer = INVDEF(cont->id);
751  tu = bestContainer->out;
752  break;
753  }
754  }
755  }
756 
757  /* send request */
758  if (bestContainer)
759  return G_ActorInvMove(actor, bestContainer, ammoItem, invDef, 0, 0, true);
760  /* No ammo found */
761  return false;
762 }
763 
764 int G_ActorGetModifiedTimeForFiredef (const Edict* const ent, const fireDef_t* const fd, const bool reaction)
765 {
766  return fd->time * G_ActorGetInjuryPenalty(ent, reaction ? MODIFIER_REACTION : MODIFIER_SHOOTING);
767 }
void G_EventEnd(void)
Definition: g_events.cpp:711
Edict * G_SpawnFloor(const pos3_t pos)
Spawns a new entity at the floor.
Definition: g_spawn.cpp:535
void G_ClientPrintf(const Player &player, int printLevel, const char *fmt,...)
Definition: g_client.cpp:206
inventory_action_t
Possible inventory actions for moving items between containers.
Definition: inv_shared.h:65
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
#define PLAYER_WIDTH
Definition: q_sizes.h:10
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.
#define VectorCopy(src, dest)
Definition: vector.h:51
Item * getFloor() const
Definition: g_edict.h:262
const objDef_t * getWeapon() const
Definition: chr_shared.h:154
solid_t solid
Definition: g_edict.h:58
chrScoreGlobal_t score
Definition: chr_shared.h:387
void G_EventActorStateChange(playermask_t playerMask, const Edict &ent)
Definition: g_events.cpp:632
#define MAX_TEAMS
Definition: defines.h:98
int getStun() const
Definition: g_edict.h:308
void G_PrintStats(const char *format,...)
Prints stats to game console and stats log file.
Definition: g_utils.cpp:304
this is a fire definition for our weapons/ammo
Definition: inv_shared.h:110
void G_EventInventoryReload(const Edict &ent, playermask_t playerMask, const Item *item, const invDef_t *invDef, const Item *ic)
Definition: g_events.cpp:421
#define G_IsStunned(ent)
Definition: g_actor.h:30
void G_ReactionFireOnDead(const Actor *target)
Removes the given target from the reaction fire lists.
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
unsigned num_stuns[MAX_TEAMS+1][MAX_TEAMS]
Definition: g_local.h:114
#define _(String)
Definition: cl_shared.h:43
Misc utility functions for game module.
#define FL_CLIENTACTION
Edict flag to indicate, that the edict can be used in the context of a client action.
Definition: g_local.h:296
void G_ClientStateChange(const Player &player, Actor *actor, int reqState, bool checkaction)
Changes the state of a player/soldier.
Definition: g_client.cpp:473
voidpf uLong int origin
Definition: ioapi.h:45
#define STATE_REACTION
Definition: q_shared.h:272
unsigned int playermask_t
Definition: g_events.h:34
bool isDead() const
Definition: g_edict.h:362
character_t chr
Definition: g_edict.h:116
inventory_action_t moveInInventory(Inventory *const inv, const invDef_t *from, Item *item, const invDef_t *to, int tx, int ty, int *TU, Item **icp)
Conditions for moving items between containers.
Definition: inventory.cpp:239
const fireDef_t * getFiredefs() const
Returns the firedefinitions for a given weapon/ammo.
Definition: inv_shared.cpp:576
AABB entBox
Definition: g_edict.h:60
bool isRightDef() const
Checks whether the inventory definition is the right Hand.
Definition: inv_shared.cpp:57
bool isStunned() const
Definition: g_edict.h:355
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
bool isLeftDef() const
Checks whether a given inventory definition is of special type.
Definition: inv_shared.cpp:66
void removeDazed()
Definition: g_edict.h:381
InventoryInterface invi
Definition: g_local.h:76
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
int getFmIdx() const
Definition: chr_shared.h:150
#define G_IsCrouched(ent)
Definition: g_actor.h:32
#define MAX_TU
Definition: g_actor.cpp:36
byte dir
Definition: g_edict.h:86
#define G_IsActor(ent)
Definition: g_local.h:127
Defines all attributes of objects used in the inventory.
Definition: inv_shared.h:264
int integer
Definition: cvar.h:81
const byte dvleft[CORE_DIRECTIONS]
Definition: mathlib.cpp:119
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
cvar_t * g_notu
Definition: g_main.cpp:117
void G_ActorSetMaxs(Actor *actor)
Sets correct bounding box for actor (state dependent).
Definition: g_actor.cpp:226
bool G_IsLivingActor(const Edict *ent)
Checks whether the given edict is a living actor.
Definition: g_actor.cpp:43
Player & getPlayer() const
Definition: g_edict.h:265
#define FL_GROUPSLAVE
not the first on the team
Definition: g_local.h:292
unsigned num_kills[MAX_TEAMS+1][MAX_TEAMS]
Definition: g_local.h:113
Item * getContainer(const containerIndex_t idx) const
Definition: g_edict.h:243
void G_ActorGiveTimeUnits(Actor *actor)
Set time units for the given edict. Based on speed skills.
Definition: g_actor.cpp:260
Item * getRightHandItem() const
Definition: g_edict.h:249
game_locals_t game
Definition: g_main.cpp:37
Item * findInContainer(const containerIndex_t contId, const Item *const item) const
Searches a specific item in the inventory&container.
int getTeam() const
Definition: g_edict.h:269
void G_EventResetClientAction(const Edict &ent)
Reset the client actions for the given entity.
Definition: g_events.cpp:376
item instance data, with linked list capability
Definition: inv_shared.h:402
void getFirstShapePosition(int *const x, int *const y) const
Calculates the first "true" bit in the shape and returns its position in the item.
Definition: inv_shared.cpp:557
#define PLAYER_DEAD
Definition: q_sizes.h:8
void G_InventoryToFloor(Edict *ent)
Move items to adjacent locations if the containers on the current floor edict are full...
#define FLYING_DIRECTIONS
Definition: mathlib.h:89
#define CID_RIGHT
Definition: inv_shared.h:47
#define PLAYER_MIN
Definition: q_sizes.h:9
game_import_t gi
Definition: g_main.cpp:39
void setMaxZ(float zVal)
Definition: aabb.h:80
#define PATHFINDING_DIRECTIONS
Definition: mathlib.h:87
void findSpace(const invDef_t *container, const Item *item, int *const px, int *const py, const Item *ignoredItem) const
Finds space for item in inv at container.
Definition: inv_shared.cpp:876
void setFloor(const Edict *other)
Definition: g_edict.h:207
#define GET_TU(ab, md)
Definition: q_shared.h:291
int getWeight() const
Get the weight of the items in the given inventory (excluding those in temp containers).
Definition: inv_shared.cpp:937
static void G_ActorRevitalise(Actor *actor)
Definition: g_actor.cpp:366
int TU
Definition: g_edict.h:88
Edict * G_FindRadius(Edict *from, const vec3_t org, float rad, entity_type_t type)
Returns entities that have origins within a spherical area.
Definition: g_utils.cpp:408
void G_ActorUseDoor(Actor *actor, Edict *door)
Make the actor use (as in open/close) a door edict.
Definition: g_actor.cpp:55
teammask_t visflags
Definition: g_edict.h:82
int G_ActorGetModifiedTimeForFiredef(const Edict *const ent, const fireDef_t *const fd, const bool reaction)
Definition: g_actor.cpp:764
int G_ActorGetContentFlags(const vec3_t origin)
Get the content flags from where the actor is currently standing.
Definition: g_actor.cpp:484
pos3_t pos
Definition: g_edict.h:55
Edict * groupMaster
Definition: g_edict.h:168
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 CHRSH_IsTeamDefRobot(const teamDef_t *const td)
Check if a team definition is a robot.
Definition: chr_shared.cpp:102
void G_ActorSetClientAction(Edict *actor, Edict *ent)
Handles the client actions (interaction with the world)
Definition: g_actor.cpp:82
void G_EventActorRevitalise(const Edict &ent)
Announce the actor revitalize event for the clients that are seeing the actor.
Definition: g_events.cpp:102
playermask_t G_VisToPM(teammask_t teamMask)
Converts vis mask to player mask.
Definition: g_client.cpp:186
const invDef_t * def() const
Definition: inv_shared.cpp:667
int getAmount() const
Definition: inv_shared.h:463
Edict * clientAction
Definition: g_edict.h:113
#define INVDEF(containerID)
Definition: cl_shared.h:47
Item * getNextItem(const Item *prev) const
Definition: inv_shared.cpp:671
int state
Definition: g_edict.h:93
void G_WriteItem(const Item &item, const containerIndex_t contId, int x, int y)
Write an item to the network buffer.
#define STATE_STUN
Definition: q_shared.h:268
void removeStunned()
Definition: g_edict.h:376
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
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
bool G_ActorReload(Actor *actor, const invDef_t *invDef)
Reload weapon with actor.
Definition: g_actor.cpp:714
#define UNIT_SIZE
Definition: defines.h:121
#define G_IsBlockingMovementActor(ent)
Definition: g_local.h:150
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
#define PLAYER_STAND
Definition: q_sizes.h:6
#define VectorCompare(a, b)
Definition: vector.h:63
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 isFloorDef() const
Checks whether the inventory definition is the floor.
Definition: inv_shared.cpp:48
Item * getHandItem(actorHands_t hand) const
Definition: g_edict.h:255
bool isDazed() const
Definition: g_edict.h:360
static bool G_ActorStun(Actor *actor, const Edict *attacker)
Definition: g_actor.cpp:283
void G_ReactionFireTargetsDestroy(const Edict *shooter)
free function to destroy the table of reaction fire targets for the given edict.
Definition: g_reaction.cpp:445
#define GET_ENCUMBRANCE_PENALTY(weight, max)
Definition: q_shared.h:287
int team
Definition: g_edict.h:96
#define PLAYER2x2_WIDTH
Definition: q_sizes.h:23
void G_ActorUseTU(Edict *ent, int tus)
Definition: g_actor.cpp:278
#define MAX_DEATH
Definition: q_shared.h:257
FiremodeSettings RFmode
Definition: chr_shared.h:397
#define G_IsAI(ent)
Definition: g_local.h:141
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
void G_EventActorSendReservations(const Edict &ent)
Will inform the player about the real TU reservation.
Definition: g_events.cpp:113
#define G_SetState(ent, s)
Definition: g_actor.h:36
QGL_EXTERN GLint i
Definition: r_gl.h:113
const byte dvright[CORE_DIRECTIONS]
Definition: mathlib.cpp:116
int getTus() const
Definition: g_edict.h:318
#define G_IsDead(ent)
Definition: g_actor.h:34
void G_EventInventoryDelete(const Edict &ent, playermask_t playerMask, const containerIndex_t containerId, int x, int y)
Tell the client to remove the item from the container.
Definition: g_events.cpp:131
bool isCrouched() const
Definition: g_edict.h:361
const Container * getNextCont(const Container *prev, bool inclTemp=false) const
Definition: inv_shared.cpp:722
void G_EventSetClientAction(const Edict &ent)
Informs the client that an interaction with the world is possible.
Definition: g_events.cpp:360
Brings new objects into the world.
entity_type_t type
Definition: g_edict.h:81
void resetFloor()
Definition: g_edict.h:210
void G_ActorSetTU(Edict *ent, int tus)
Definition: g_actor.cpp:267
#define CORE_DIRECTIONS
Definition: mathlib.h:88
void G_ActorCheckRevitalise(Actor *actor)
Definition: g_actor.cpp:386
#define EYE_STAND
Definition: q_sizes.h:4
void G_EventPerish(const Edict &ent)
Send an event to all clients that are seeing the given edict, that it just has disappeared.
Definition: g_events.cpp:158
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
vec3_t origin
Definition: g_edict.h:53
const Edict * link
Definition: g_edict.h:80
void G_EventInventoryAdd(const Edict &ent, playermask_t playerMask, int itemAmount)
Tell the client to add the item from the container.
Definition: g_events.cpp:147
bool isHeldTwoHanded() const
Definition: inv_shared.h:476
#define NONE_AMMO
Definition: defines.h:69
const objDef_t * ammoDef(void) const
Definition: inv_shared.h:460
vec_t vec3_t[3]
Definition: ufotypes.h:39
inventory definition for our menus
Definition: inv_shared.h:371
void G_EventActorDie(const Edict &ent, bool attacker)
Announce the actor die event for the clients that are seeing the actor.
Definition: g_events.cpp:89
void G_ActorGetEyeVector(const Edict *actor, vec3_t eye)
Fills a vector with the eye position of a given actor.
Definition: g_actor.cpp:357
Inventory inv
Definition: chr_shared.h:392
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
int getX() const
Definition: inv_shared.h:454
void setTus(int tus)
Definition: g_edict.h:315
containerIndex_t id
Definition: inv_shared.h:373
char name[MAX_VAR]
Definition: chr_shared.h:371
Edict * G_GetFloorItems(Edict *ent)
Prepares a list of items on the floor at given entity position.
Definition: g_inventory.cpp:59
const float directionAngles[CORE_DIRECTIONS]
Definition: mathlib.cpp:105
#define NONE
Definition: defines.h:68
actorHands_t getHand() const
Definition: chr_shared.h:158
void G_SendStats(Edict &ent)
Send stats to network buffer.
Definition: g_stats.cpp:34
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
void setMaxs(const vec3_t maxi)
Definition: aabb.h:71
uint8_t byte
Definition: ufotypes.h:34
int getReservedTUs() const
Calculates the amount of all currently reserved TUs.
Definition: g_edict.h:336
int G_ActorCalculateMaxTU(const Edict *ent)
Definition: g_actor.cpp:247
float G_ActorGetInjuryPenalty(const Edict *const ent, const modifier_types_t type)
Returns the penalty to the given stat caused by the actor wounds.
Definition: g_health.cpp:177
int skills[SKILL_NUM_TYPES]
Definition: chr_shared.h:122
void G_FreeEdict(Edict *ent)
Marks the edict as free.
Definition: g_utils.cpp:41
#define PLAYER_CROUCH
Definition: q_sizes.h:7
Interface for g_client.cpp.
int getY() const
Definition: inv_shared.h:457
playermask_t G_TeamToPM(int team)
Generates the player bit mask for a given team.
Definition: g_client.cpp:144
#define G_IsPanicked(ent)
Definition: g_actor.h:31
#define VIS_STOP
Definition: g_vis.h:40
#define EYE_CROUCH
Definition: q_sizes.h:5
level_locals_t level
Definition: g_main.cpp:38
int HP
Definition: g_edict.h:89
#define PRINT_HUD
Definition: defines.h:107
int G_ActorGetTUForReactionFire(const Edict *ent)
Calculates the amount of TUs that are needed for the current selected reaction fire mode...
Definition: g_actor.cpp:116
chrReservations_t reservedTus
Definition: chr_shared.h:396