observ.qc 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /* Copyright (C) 1996-2022 id Software LLC
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; either version 2 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program; if not, write to the Free Software
  12. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  13. See file, 'COPYING', for details.
  14. */
  15. void() respawn;
  16. entity() SelectSpawnPoint;
  17. void(entity player,entity door) ObserverDoor =
  18. {
  19. local entity d,d_master;
  20. local vector dmin,dmax;
  21. local float is_x,is_y,is_z,set;
  22. local vector dir,or;
  23. d_master = d = door.owner;
  24. if (d_master) {
  25. dmin = d_master.absmin;
  26. dmax = d_master.absmax;
  27. } else {
  28. dmin = dmax = '0 0 0';
  29. }
  30. if (dmin != dmax) {
  31. // regular doors
  32. if (d_master.state != STATE_BOTTOM) return;
  33. do {
  34. // dprint (vtos(d.absmin)); dprint (" "); dprint (vtos(d.absmax)); dprint ("\n");
  35. if (d.absmin_x < dmin_x) { dmin_x = d.absmin_x; }
  36. if (d.absmax_x > dmax_x) { dmax_x = d.absmax_x; }
  37. if (d.absmin_y < dmin_y) { dmin_y = d.absmin_y; }
  38. if (d.absmax_y > dmax_y) { dmax_y = d.absmax_y; }
  39. if (d.absmin_z < dmin_z) { dmin_z = d.absmin_z; }
  40. if (d.absmax_z > dmax_z) { dmax_z = d.absmax_z; }
  41. d = d.enemy; // next linked door;
  42. } while ((d != d_master) && (d != world));
  43. }
  44. else {
  45. // secret doors
  46. // we ignore these currently
  47. return;
  48. }
  49. set = is_x = is_y = is_z = FALSE;
  50. or = player.origin;
  51. if (dmin_x + 15 < player.absmin_x && player.absmax_x < dmax_x - 15) is_x = TRUE;
  52. if (dmin_y + 15 < player.absmin_y && player.absmax_y < dmax_y - 15) is_y = TRUE;
  53. if (dmin_z + 15 < player.absmin_z && player.absmax_z < dmax_z - 15) is_z = TRUE;
  54. // dprint("doors: "); dprint (vtos(dmin)); dprint (" "); dprint (vtos(dmax)); dprint ("\n");
  55. // dprint("player: "); dprint (vtos(player.absmin)); dprint (" "); dprint (vtos(player.absmax)); dprint ("\n");
  56. if (is_x && is_y) {
  57. // dprint("door is in xy plane\n");
  58. if (or_z < dmin_z) { dir = '0 0 1'; or_z = dmax_z + 25; }
  59. else if (or_z > dmax_z) { dir = '0 0 -1'; or_z = dmin_z - 25; }
  60. set = TRUE;
  61. }
  62. else if (is_x && is_z) {
  63. // dprint("door is in xz plane\n");
  64. if (or_y < dmin_y) { dir = '0 1 0'; or_y = dmax_y + 25; }
  65. else if (or_y > dmax_y) { dir = '0 -1 0'; or_y = dmin_y - 25; }
  66. set = TRUE;
  67. }
  68. else if (is_y && is_z) {
  69. // dprint("door is in yz plane\n");
  70. if (or_x < dmin_x) { dir = ' 1 0 0'; or_x = dmax_x + 25; }
  71. else if (or_x > dmax_x) { dir = '-1 0 0'; or_x = dmin_x - 25; }
  72. set = TRUE;
  73. }
  74. if (set) {
  75. local vector v;
  76. v = normalize(player.velocity);
  77. if (dir * v < 0.5) return;
  78. player.origin = or;
  79. setorigin (player, player.origin);
  80. }
  81. };
  82. void(entity player,entity tele) ObserverTeleporter =
  83. {
  84. local entity targ;
  85. local vector v1,v2;
  86. v1 = ((tele.absmax + tele.absmin) * 0.5) - player.origin; normalize(v1);
  87. v2 = player.velocity; normalize(v2);
  88. if (v1 * v2 <= 0.1) return;
  89. targ = find (world, targetname, tele.target);
  90. if (!targ) {
  91. dprint("ObserverTeleportThroughTeleporter: couldn't find teleporter target\n");
  92. return;
  93. }
  94. makevectors (targ.mangle);
  95. setorigin (player, targ.origin);
  96. player.angles = targ.mangle;
  97. player.fixangle = TRUE; // turn this way immediately
  98. player.teleport_time = time + 0.7;
  99. player.velocity = v_forward * 300;
  100. // player.flags = player.flags - player.flags & FL_ONGROUND;
  101. };
  102. float() DoObserverImpulse =
  103. {
  104. local float teamImpulse = FALSE;
  105. if (!PromptSupported() && self.observer && (self.impulse == 1 || self.impulse == 2 || self.impulse == 3 || self.button2)) {
  106. teamImpulse = TRUE;
  107. } else if (self.impulse >= 100 && self.impulse <= 104) {
  108. teamImpulse = TRUE;
  109. }
  110. if (!teamImpulse) {
  111. return FALSE;
  112. }
  113. if (self.impulse == 100 && teamplay & TEAM_STATIC_TEAMS) {
  114. centerprint(self, "$qc_ctf_teams_locked");
  115. return TRUE;
  116. }
  117. if (!self.observer) {
  118. T_Damage(self,self,self,1000);
  119. }
  120. self.observer = 0;
  121. SetChangeParms ();
  122. self.killed = 0;
  123. if (self.impulse == 100) { // put the player into observer and send the team selection
  124. self.team = self.lastteam = 0;
  125. self.do_observer = 1;
  126. self.observer = 1;
  127. self.motd_sent = 0;
  128. }
  129. if (self.impulse == 1 || self.impulse == 101 ) // red
  130. self.team = self.lastteam = TEAM_COLOR1;
  131. else if (self.impulse == 2 || self.impulse == 102) // blue
  132. self.team = self.lastteam = TEAM_COLOR2;
  133. else if (self.impulse == 103) { // automatic
  134. self.lastteam = -50;
  135. TeamCheckTeam();
  136. }
  137. else if (self.impulse == 104) { // observer
  138. self.team = self.lastteam = 0;
  139. self.do_observer = 1;
  140. self.observer = 1;
  141. }
  142. if (PromptSupported()) {
  143. clearprompt(self);
  144. }
  145. if (self.lastteam == TEAM_COLOR1) {
  146. bprint("$qc_ks_joined_red", self.netname); // red
  147. } else if (self.lastteam == TEAM_COLOR2) {
  148. bprint("$qc_ks_joined_blue", self.netname); // blue
  149. }
  150. self.impulse = 0;
  151. self.player_flag = self.player_flag | TEAM_STUFF_COLOR;
  152. // disable skin swaps since we don't have those skins in the md5
  153. // if (self.lastteam == TEAM_COLOR1)
  154. // self.skin = 1;
  155. // else
  156. // self.skin = 3;
  157. // if (random() < 0.5)
  158. // self.skin = self.skin + 1; // visor dude
  159. self.player_flag = self.player_flag - (self.player_flag & 65280);
  160. self.player_flag = self.player_flag | (self.skin * 256);
  161. self.weapon = W_BestWeapon();
  162. respawn();
  163. W_SetCurrentAmmo();
  164. TeamSetColor(self, self.lastteam - 1, self.lastteam - 1);
  165. return TRUE;
  166. };
  167. void () ObserverThink =
  168. {
  169. local entity e;
  170. local float cont;
  171. self.weaponmodel = "";
  172. self.weaponframe = 0;
  173. self.flags = self.flags | FL_ONGROUND;
  174. {
  175. local float invcos,nv,nvp,nvpmax,nvs,nsp,sp,svz;
  176. local vector f,vp,vs;
  177. svz = self.velocity_z * 0.75;
  178. self.velocity_z = 0;
  179. // v_forward is already normalized
  180. f_x = v_forward_x;
  181. f_y = v_forward_y;
  182. f_z = 0;
  183. invcos = vlen(f); if (invcos) invcos= 1/invcos; else invcos=0;
  184. f = f*invcos; // normalize f
  185. sp = f * self.velocity;
  186. vp = sp*f;
  187. nvp = vlen(vp); if (sp<0) nvp = nvp*(-1);
  188. vs = self.velocity - vp;
  189. vp = v_forward * (nvp * invcos);
  190. vp_z = vp_z + svz;
  191. nvp = vlen(vp);
  192. nvpmax = (320 - 100*(v_forward * '0 0 1'));
  193. if (nvp > nvpmax) { vp = vp * (nvpmax/nvp); }
  194. // swap z if going straight up and down due to 90/-90 deg
  195. if (fabs(self.angles_x) == 30)
  196. vp_z *= -1;
  197. self.velocity = vp + vs;
  198. }
  199. // look for doors, etc.
  200. e = findradius(self.origin,75);
  201. while (e != world) {
  202. if (e.classname == "func_door") {
  203. ObserverDoor(self, e);
  204. e = world;
  205. }
  206. if (e.classname == "trigger_teleport") {
  207. ObserverTeleporter(self,e);
  208. e = world;
  209. }
  210. e = e.chain;
  211. if (!e) e = world;
  212. }
  213. if (self.button2 && !self.obs_fire_held) {
  214. local entity spot = SelectSpawnPoint();
  215. self.origin = spot.origin + '0 0 1';
  216. self.angles = spot.angles;
  217. self.fixangle = TRUE;
  218. self.obs_fire_held = 1;
  219. }
  220. if (!self.button2 && self.obs_fire_held) {
  221. self.obs_fire_held = 0;
  222. }
  223. };
  224. void(entity player) BecomeObserver =
  225. {
  226. player.health = 999;
  227. player.takedamage = DAMAGE_NO;
  228. player.solid = SOLID_NOT;
  229. player.movetype = MOVETYPE_FLY;
  230. player.deadflag = DEAD_NO;
  231. setmodel (player, string_null);
  232. player.weaponmodel = "";
  233. player.weaponframe = 0;
  234. player.weapon = 0;
  235. setsize(player, '-12 -12 -12', '12 12 12');
  236. player.view_ofs = '0 0 10';
  237. player.observer = 1;
  238. player.do_observer = 0;
  239. };