Annotation of quake2/game/g_turret.c, revision 1.1.1.2

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.