p_trail.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Copyright (c) ZeniMax Media Inc.
  2. // Licensed under the GNU General Public License 2.0.
  3. #include "g_local.h"
  4. /*
  5. ==============================================================================
  6. PLAYER TRAIL
  7. ==============================================================================
  8. This is a two-way list containing the a list of points of where
  9. the player has been recently. It is used by monsters for pursuit.
  10. This is improved from vanilla; now, the list itself is stored in
  11. client data so it can be stored for multiple clients.
  12. chain = next
  13. enemy = prev
  14. The head node will always have a null "chain", the tail node
  15. will always have a null "enemy".
  16. */
  17. constexpr size_t TRAIL_LENGTH = 8;
  18. // places a new entity at the head of the player trail.
  19. // the tail entity may be moved to the front if the length
  20. // is at the end.
  21. static edict_t *PlayerTrail_Spawn(edict_t *owner)
  22. {
  23. size_t len = 0;
  24. for (edict_t *tail = owner->client->trail_tail; tail; tail = tail->chain)
  25. len++;
  26. edict_t *trail;
  27. // move the tail to the head
  28. if (len == TRAIL_LENGTH)
  29. {
  30. // unlink the old tail
  31. trail = owner->client->trail_tail;
  32. owner->client->trail_tail = trail->chain;
  33. owner->client->trail_tail->enemy = nullptr;
  34. trail->chain = trail->enemy = nullptr;
  35. }
  36. else
  37. {
  38. // spawn a new head
  39. trail = G_Spawn();
  40. trail->classname = "player_trail";
  41. }
  42. // link as new head
  43. if (owner->client->trail_head)
  44. owner->client->trail_head->chain = trail;
  45. trail->enemy = owner->client->trail_head;
  46. owner->client->trail_head = trail;
  47. // if there's no tail, we become the tail too
  48. if (!owner->client->trail_tail)
  49. owner->client->trail_tail = trail;
  50. return trail;
  51. }
  52. // destroys all player trail entities in the map.
  53. // we don't want these to stay around across level loads.
  54. void PlayerTrail_Destroy(edict_t *player)
  55. {
  56. for (size_t i = 0; i < globals.num_edicts; i++)
  57. if (g_edicts[i].classname && strcmp(g_edicts[i].classname, "player_trail") == 0)
  58. if (!player || g_edicts[i].owner == player)
  59. G_FreeEdict(&g_edicts[i]);
  60. if (player)
  61. player->client->trail_head = player->client->trail_tail = nullptr;
  62. else for (size_t i = 0; i < game.maxclients; i++)
  63. game.clients[i].trail_head = game.clients[i].trail_tail = nullptr;
  64. }
  65. // check to see if we can add a new player trail spot
  66. // for this player.
  67. void PlayerTrail_Add(edict_t *player)
  68. {
  69. // if we can still see the head, we don't want a new one.
  70. if (player->client->trail_head && visible(player, player->client->trail_head))
  71. return;
  72. // don't spawn trails in intermission, if we're dead, if we're noclipping or not on ground yet
  73. else if (level.intermissiontime || player->health <= 0 || player->movetype == MOVETYPE_NOCLIP ||
  74. !player->groundentity)
  75. return;
  76. edict_t *trail = PlayerTrail_Spawn(player);
  77. trail->s.origin = player->s.old_origin;
  78. trail->timestamp = level.time;
  79. trail->owner = player;
  80. }
  81. // pick a trail node that matches the player
  82. // we're hunting that is visible to us.
  83. edict_t *PlayerTrail_Pick(edict_t *self, bool next)
  84. {
  85. // not player or doesn't have a trail yet
  86. if (!self->enemy->client || !self->enemy->client->trail_head)
  87. return nullptr;
  88. // find which marker head that was dropped while we
  89. // were searching for this enemy
  90. edict_t *marker;
  91. for (marker = self->enemy->client->trail_head; marker; marker = marker->enemy)
  92. {
  93. if (marker->timestamp <= self->monsterinfo.trail_time)
  94. continue;
  95. break;
  96. }
  97. if (next)
  98. {
  99. // find the marker we're closest to
  100. float closest_dist = std::numeric_limits<float>::infinity();
  101. edict_t *closest = nullptr;
  102. for (edict_t *m2 = marker; m2; m2 = m2->enemy)
  103. {
  104. float len = (m2->s.origin - self->s.origin).lengthSquared();
  105. if (len < closest_dist)
  106. {
  107. closest_dist = len;
  108. closest = m2;
  109. }
  110. }
  111. // should never happen
  112. if (!closest)
  113. return nullptr;
  114. // use the next one from the closest one
  115. marker = closest->chain;
  116. }
  117. else
  118. {
  119. // from that marker, find the first one we can see
  120. for (; marker && !visible(self, marker); marker = marker->enemy)
  121. continue;
  122. }
  123. return marker;
  124. }