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