g_turret.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. // g_turret.c
  16. #include "g_local.h"
  17. void AnglesNormalize(vec3_t vec)
  18. {
  19. while(vec[0] > 360)
  20. vec[0] -= 360;
  21. while(vec[0] < 0)
  22. vec[0] += 360;
  23. while(vec[1] > 360)
  24. vec[1] -= 360;
  25. while(vec[1] < 0)
  26. vec[1] += 360;
  27. }
  28. float SnapToEights(float x)
  29. {
  30. x *= 8.0;
  31. if (x > 0.0)
  32. x += 0.5;
  33. else
  34. x -= 0.5;
  35. return 0.125 * (int)x;
  36. }
  37. void turret_blocked(edict_t *self, edict_t *other)
  38. {
  39. edict_t *attacker;
  40. if (other->takedamage)
  41. {
  42. if (self->teammaster->owner)
  43. attacker = self->teammaster->owner;
  44. else
  45. attacker = self->teammaster;
  46. T_Damage (other, self, attacker, vec3_origin, other->s.origin, vec3_origin, self->teammaster->dmg, 10, 0, MOD_CRUSH);
  47. }
  48. }
  49. /*QUAKED turret_breach (0 0 0) ?
  50. This portion of the turret can change both pitch and yaw.
  51. The model should be made with a flat pitch.
  52. It (and the associated base) need to be oriented towards 0.
  53. Use "angle" to set the starting angle.
  54. "speed" default 50
  55. "dmg" default 10
  56. "angle" point this forward
  57. "target" point this at an info_notnull at the muzzle tip
  58. "minpitch" min acceptable pitch angle : default -30
  59. "maxpitch" max acceptable pitch angle : default 30
  60. "minyaw" min acceptable yaw angle : default 0
  61. "maxyaw" max acceptable yaw angle : default 360
  62. */
  63. void turret_breach_fire (edict_t *self)
  64. {
  65. vec3_t f, r, u;
  66. vec3_t start;
  67. int damage;
  68. int speed;
  69. AngleVectors (self->s.angles, f, r, u);
  70. VectorMA (self->s.origin, self->move_origin[0], f, start);
  71. VectorMA (start, self->move_origin[1], r, start);
  72. VectorMA (start, self->move_origin[2], u, start);
  73. damage = 100 + random() * 50;
  74. speed = 550 + 50 * skill->value;
  75. fire_rocket (self->teammaster->owner, start, f, damage, speed, 150, damage);
  76. gi.positioned_sound (start, self, CHAN_WEAPON, gi.soundindex("weapons/rocklf1a.wav"), 1, ATTN_NORM, 0);
  77. }
  78. void turret_breach_think (edict_t *self)
  79. {
  80. edict_t *ent;
  81. vec3_t current_angles;
  82. vec3_t delta;
  83. VectorCopy (self->s.angles, current_angles);
  84. AnglesNormalize(current_angles);
  85. AnglesNormalize(self->move_angles);
  86. if (self->move_angles[PITCH] > 180)
  87. self->move_angles[PITCH] -= 360;
  88. // clamp angles to mins & maxs
  89. if (self->move_angles[PITCH] > self->pos1[PITCH])
  90. self->move_angles[PITCH] = self->pos1[PITCH];
  91. else if (self->move_angles[PITCH] < self->pos2[PITCH])
  92. self->move_angles[PITCH] = self->pos2[PITCH];
  93. if ((self->move_angles[YAW] < self->pos1[YAW]) || (self->move_angles[YAW] > self->pos2[YAW]))
  94. {
  95. float dmin, dmax;
  96. dmin = fabs(self->pos1[YAW] - self->move_angles[YAW]);
  97. if (dmin < -180)
  98. dmin += 360;
  99. else if (dmin > 180)
  100. dmin -= 360;
  101. dmax = fabs(self->pos2[YAW] - self->move_angles[YAW]);
  102. if (dmax < -180)
  103. dmax += 360;
  104. else if (dmax > 180)
  105. dmax -= 360;
  106. if (fabs(dmin) < fabs(dmax))
  107. self->move_angles[YAW] = self->pos1[YAW];
  108. else
  109. self->move_angles[YAW] = self->pos2[YAW];
  110. }
  111. VectorSubtract (self->move_angles, current_angles, delta);
  112. if (delta[0] < -180)
  113. delta[0] += 360;
  114. else if (delta[0] > 180)
  115. delta[0] -= 360;
  116. if (delta[1] < -180)
  117. delta[1] += 360;
  118. else if (delta[1] > 180)
  119. delta[1] -= 360;
  120. delta[2] = 0;
  121. if (delta[0] > self->speed * FRAMETIME)
  122. delta[0] = self->speed * FRAMETIME;
  123. if (delta[0] < -1 * self->speed * FRAMETIME)
  124. delta[0] = -1 * self->speed * FRAMETIME;
  125. if (delta[1] > self->speed * FRAMETIME)
  126. delta[1] = self->speed * FRAMETIME;
  127. if (delta[1] < -1 * self->speed * FRAMETIME)
  128. delta[1] = -1 * self->speed * FRAMETIME;
  129. VectorScale (delta, 1.0/FRAMETIME, self->avelocity);
  130. self->nextthink = level.time + FRAMETIME;
  131. for (ent = self->teammaster; ent; ent = ent->teamchain)
  132. ent->avelocity[1] = self->avelocity[1];
  133. // if we have adriver, adjust his velocities
  134. if (self->owner)
  135. {
  136. float angle;
  137. float target_z;
  138. float diff;
  139. vec3_t target;
  140. vec3_t dir;
  141. // angular is easy, just copy ours
  142. self->owner->avelocity[0] = self->avelocity[0];
  143. self->owner->avelocity[1] = self->avelocity[1];
  144. // x & y
  145. angle = self->s.angles[1] + self->owner->move_origin[1];
  146. angle *= (M_PI*2 / 360);
  147. target[0] = SnapToEights(self->s.origin[0] + cos(angle) * self->owner->move_origin[0]);
  148. target[1] = SnapToEights(self->s.origin[1] + sin(angle) * self->owner->move_origin[0]);
  149. target[2] = self->owner->s.origin[2];
  150. VectorSubtract (target, self->owner->s.origin, dir);
  151. self->owner->velocity[0] = dir[0] * 1.0 / FRAMETIME;
  152. self->owner->velocity[1] = dir[1] * 1.0 / FRAMETIME;
  153. // z
  154. angle = self->s.angles[PITCH] * (M_PI*2 / 360);
  155. target_z = SnapToEights(self->s.origin[2] + self->owner->move_origin[0] * tan(angle) + self->owner->move_origin[2]);
  156. diff = target_z - self->owner->s.origin[2];
  157. self->owner->velocity[2] = diff * 1.0 / FRAMETIME;
  158. if (self->spawnflags & 65536)
  159. {
  160. turret_breach_fire (self);
  161. self->spawnflags &= ~65536;
  162. }
  163. }
  164. }
  165. void turret_breach_finish_init (edict_t *self)
  166. {
  167. // get and save info for muzzle location
  168. if (!self->target)
  169. {
  170. gi.dprintf("%s at %s needs a target\n", self->classname, vtos(self->s.origin));
  171. }
  172. else
  173. {
  174. self->target_ent = G_PickTarget (self->target);
  175. VectorSubtract (self->target_ent->s.origin, self->s.origin, self->move_origin);
  176. G_FreeEdict(self->target_ent);
  177. }
  178. self->teammaster->dmg = self->dmg;
  179. self->think = turret_breach_think;
  180. self->think (self);
  181. }
  182. void SP_turret_breach (edict_t *self)
  183. {
  184. self->solid = SOLID_BSP;
  185. self->movetype = MOVETYPE_PUSH;
  186. gi.setmodel (self, self->model);
  187. if (!self->speed)
  188. self->speed = 50;
  189. if (!self->dmg)
  190. self->dmg = 10;
  191. if (!st.minpitch)
  192. st.minpitch = -30;
  193. if (!st.maxpitch)
  194. st.maxpitch = 30;
  195. if (!st.maxyaw)
  196. st.maxyaw = 360;
  197. self->pos1[PITCH] = -1 * st.minpitch;
  198. self->pos1[YAW] = st.minyaw;
  199. self->pos2[PITCH] = -1 * st.maxpitch;
  200. self->pos2[YAW] = st.maxyaw;
  201. self->ideal_yaw = self->s.angles[YAW];
  202. self->move_angles[YAW] = self->ideal_yaw;
  203. self->blocked = turret_blocked;
  204. self->think = turret_breach_finish_init;
  205. self->nextthink = level.time + FRAMETIME;
  206. gi.linkentity (self);
  207. }
  208. /*QUAKED turret_base (0 0 0) ?
  209. This portion of the turret changes yaw only.
  210. MUST be teamed with a turret_breach.
  211. */
  212. void SP_turret_base (edict_t *self)
  213. {
  214. self->solid = SOLID_BSP;
  215. self->movetype = MOVETYPE_PUSH;
  216. gi.setmodel (self, self->model);
  217. self->blocked = turret_blocked;
  218. gi.linkentity (self);
  219. }
  220. /*QUAKED turret_driver (1 .5 0) (-16 -16 -24) (16 16 32)
  221. Must NOT be on the team with the rest of the turret parts.
  222. Instead it must target the turret_breach.
  223. */
  224. void infantry_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage);
  225. void infantry_stand (edict_t *self);
  226. void monster_use (edict_t *self, edict_t *other, edict_t *activator);
  227. void turret_driver_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
  228. {
  229. edict_t *ent;
  230. // level the gun
  231. self->target_ent->move_angles[0] = 0;
  232. // remove the driver from the end of them team chain
  233. for (ent = self->target_ent->teammaster; ent->teamchain != self; ent = ent->teamchain)
  234. ;
  235. ent->teamchain = NULL;
  236. self->teammaster = NULL;
  237. self->flags &= ~FL_TEAMSLAVE;
  238. self->target_ent->owner = NULL;
  239. self->target_ent->teammaster->owner = NULL;
  240. infantry_die (self, inflictor, attacker, damage);
  241. }
  242. qboolean FindTarget (edict_t *self);
  243. void turret_driver_think (edict_t *self)
  244. {
  245. vec3_t target;
  246. vec3_t dir;
  247. float reaction_time;
  248. self->nextthink = level.time + FRAMETIME;
  249. if (self->enemy && (!self->enemy->inuse || self->enemy->health <= 0))
  250. self->enemy = NULL;
  251. if (!self->enemy)
  252. {
  253. if (!FindTarget (self))
  254. return;
  255. self->monsterinfo.trail_time = level.time;
  256. self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
  257. }
  258. else
  259. {
  260. if (visible (self, self->enemy))
  261. {
  262. if (self->monsterinfo.aiflags & AI_LOST_SIGHT)
  263. {
  264. self->monsterinfo.trail_time = level.time;
  265. self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
  266. }
  267. }
  268. else
  269. {
  270. self->monsterinfo.aiflags |= AI_LOST_SIGHT;
  271. return;
  272. }
  273. }
  274. // let the turret know where we want it to aim
  275. VectorCopy (self->enemy->s.origin, target);
  276. target[2] += self->enemy->viewheight;
  277. VectorSubtract (target, self->target_ent->s.origin, dir);
  278. vectoangles (dir, self->target_ent->move_angles);
  279. // decide if we should shoot
  280. if (level.time < self->monsterinfo.attack_finished)
  281. return;
  282. reaction_time = (3 - skill->value) * 1.0;
  283. if ((level.time - self->monsterinfo.trail_time) < reaction_time)
  284. return;
  285. self->monsterinfo.attack_finished = level.time + reaction_time + 1.0;
  286. //FIXME how do we really want to pass this along?
  287. self->target_ent->spawnflags |= 65536;
  288. }
  289. void turret_driver_link (edict_t *self)
  290. {
  291. vec3_t vec;
  292. edict_t *ent;
  293. self->think = turret_driver_think;
  294. self->nextthink = level.time + FRAMETIME;
  295. self->target_ent = G_PickTarget (self->target);
  296. self->target_ent->owner = self;
  297. self->target_ent->teammaster->owner = self;
  298. VectorCopy (self->target_ent->s.angles, self->s.angles);
  299. vec[0] = self->target_ent->s.origin[0] - self->s.origin[0];
  300. vec[1] = self->target_ent->s.origin[1] - self->s.origin[1];
  301. vec[2] = 0;
  302. self->move_origin[0] = VectorLength(vec);
  303. VectorSubtract (self->s.origin, self->target_ent->s.origin, vec);
  304. vectoangles (vec, vec);
  305. AnglesNormalize(vec);
  306. self->move_origin[1] = vec[1];
  307. self->move_origin[2] = self->s.origin[2] - self->target_ent->s.origin[2];
  308. // add the driver to the end of them team chain
  309. for (ent = self->target_ent->teammaster; ent->teamchain; ent = ent->teamchain)
  310. ;
  311. ent->teamchain = self;
  312. self->teammaster = self->target_ent->teammaster;
  313. self->flags |= FL_TEAMSLAVE;
  314. }
  315. void SP_turret_driver (edict_t *self)
  316. {
  317. if (deathmatch->value)
  318. {
  319. G_FreeEdict (self);
  320. return;
  321. }
  322. self->movetype = MOVETYPE_PUSH;
  323. self->solid = SOLID_BBOX;
  324. self->s.modelindex = gi.modelindex("models/monsters/infantry/tris.md2");
  325. VectorSet (self->mins, -16, -16, -24);
  326. VectorSet (self->maxs, 16, 16, 32);
  327. self->health = 100;
  328. self->gib_health = 0;
  329. self->mass = 200;
  330. self->viewheight = 24;
  331. self->die = turret_driver_die;
  332. self->monsterinfo.stand = infantry_stand;
  333. self->flags |= FL_NO_KNOCKBACK;
  334. level.total_monsters++;
  335. self->svflags |= SVF_MONSTER;
  336. self->s.renderfx |= RF_FRAMELERP;
  337. self->takedamage = DAMAGE_AIM;
  338. self->use = monster_use;
  339. self->clipmask = MASK_MONSTERSOLID;
  340. VectorCopy (self->s.origin, self->s.old_origin);
  341. self->monsterinfo.aiflags |= AI_STAND_GROUND|AI_DUCKED;
  342. if (st.item)
  343. {
  344. self->item = FindItemByClassname (st.item);
  345. if (!self->item)
  346. gi.dprintf("%s at %s has bad item: %s\n", self->classname, vtos(self->s.origin), st.item);
  347. }
  348. self->think = turret_driver_link;
  349. self->nextthink = level.time + FRAMETIME;
  350. gi.linkentity (self);
  351. }