Annotation of quake2/xatrix/g_turret.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

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