Beispiel #1
0
        /*
         * ================
         * G_BounceMissile
         *
         * ================
         */
        void G_BounceMissile(gentity_t *ent, trace_t *trace)
        {
            vec3_t velocity;
            float  dot;
            int    hitTime;

            // reflect the velocity on the trace plane
            hitTime = level.previousTime + (level.time - level.previousTime) * trace->fraction;
            BG_EvaluateTrajectoryDelta(&ent->s.pos, hitTime, velocity);
            dot = DotProduct(velocity, trace->plane.normal);
            VectorMA(velocity, -2 * dot, trace->plane.normal, ent->s.pos.trDelta);

            if (ent->s.eFlags & EF_BOUNCE_HALF)
            {
                VectorScale(ent->s.pos.trDelta, 0.65, ent->s.pos.trDelta);
                // check for stop
                if (trace->plane.normal[2] > 0.2 && VectorLength(ent->s.pos.trDelta) < 40)
                {
                    G_SetOrigin(ent, trace->endpos);
                    return;
                }
            }

            VectorAdd(ent->r.currentOrigin, trace->plane.normal, ent->r.currentOrigin);
            VectorCopy(ent->r.currentOrigin, ent->s.pos.trBase);
            ent->s.pos.trTime = level.time;
        }
Beispiel #2
0
        /*
         * ==============================================================================
         *
         * trigger_teleport
         *
         * ==============================================================================
         */

        void trigger_teleporter_touch(gentity_t *self, gentity_t *other, trace_t *trace)
        {
            gentity_t *dest;

            if (!other->client)
            {
                return;
            }
            if (other->client->ps.pm_type == PM_DEAD)
            {
                return;
            }
            // Spectators only?
            if ((self->spawnflags & 1) &&
                other->client->sess.sessionTeam != TEAM_SPECTATOR)
            {
                return;
            }


            dest = G_PickTarget(self->target);
            if (!dest)
            {
                G_Printf("Couldn't find teleporter destination\n");
                return;
            }

            TeleportPlayer(other, dest->s.origin, dest->s.angles);
        }
Beispiel #3
0
        /*
         * ================
         * CG_ReflectVelocity
         * ================
         */
        void CG_ReflectVelocity(localEntity_t *le, trace_t *trace)
        {
            vec3_t velocity;
            float  dot;
            int    hitTime;

            // reflect the velocity on the trace plane
            hitTime = cg.time - cg.frametime + cg.frametime * trace->fraction;
            BG_EvaluateTrajectoryDelta(&le->pos, hitTime, velocity);
            dot = DotProduct(velocity, trace->plane.normal);
            VectorMA(velocity, -2 * dot, trace->plane.normal, le->pos.trDelta);

            VectorScale(le->pos.trDelta, le->bounceFactor, le->pos.trDelta);

            VectorCopy(trace->endpos, le->pos.trBase);
            le->pos.trTime = cg.time;


            // check for stop, making sure that even on low FPS systems it doesn't bobble
            if (trace->allsolid ||
                (trace->plane.normal[2] > 0 &&
                 (le->pos.trDelta[2] < 40 || le->pos.trDelta[2] < -cg.frametime * le->pos.trDelta[2])))
            {
                le->pos.trType = TR_STATIONARY;
            }
            else
            {
            }
        }
Beispiel #4
0
        /*
         * ================
         * CG_FragmentBounceSound
         * ================
         */
        void CG_FragmentBounceSound(localEntity_t *le, trace_t *trace)
        {
            if (le->leBounceSoundType == LEBS_BLOOD)
            {
                // half the gibs will make splat sounds
                if (rand() & 1)
                {
                    int         r = rand() & 3;
                    sfxHandle_t s;

                    if (r == 0)
                    {
                        s = cgs.media.gibBounce1Sound;
                    }
                    else if (r == 1)
                    {
                        s = cgs.media.gibBounce2Sound;
                    }
                    else
                    {
                        s = cgs.media.gibBounce3Sound;
                    }
                    trap_S_StartSound(trace->endpos, ENTITYNUM_WORLD, CHAN_AUTO, s);
                }
            }
            else if (le->leBounceSoundType == LEBS_BRASS)
            {
            }

            // don't allow a fragment to make multiple bounce sounds,
            // or it gets too noisy as they settle
            le->leBounceSoundType = LEBS_NONE;
        }
Beispiel #5
0
 void Touch_Multi(gentity_t *self, gentity_t *other, trace_t *trace)
 {
     if (!other->client)
     {
         return;
     }
     multi_trigger(self, other);
 }
Beispiel #6
0
        /*
         * ==============================================================================
         *
         * trigger_push
         *
         * ==============================================================================
         */

        void trigger_push_touch(gentity_t *self, gentity_t *other, trace_t *trace)
        {
            if (!other->client)
            {
                return;
            }

            BG_TouchJumpPad(&other->client->ps, &self->s);
        }
Beispiel #7
0
        void hurt_touch(gentity_t *self, gentity_t *other, trace_t *trace)
        {
            int dflags;

            if (!other->takedamage)
            {
                return;
            }

            if (self->timestamp > level.time)
            {
                return;
            }

            if (self->spawnflags & 16)
            {
                self->timestamp = level.time + 1000;
            }
            else
            {
                self->timestamp = level.time + FRAMETIME;
            }

            // play sound
            if (!(self->spawnflags & 4))
            {
                G_Sound(other, CHAN_AUTO, self->noise_index);
            }

            if (self->spawnflags & 8)
            {
                dflags = DAMAGE_NO_PROTECTION;
            }
            else
            {
                dflags = 0;
            }
            G_Damage(other, self, self, NULL, NULL, self->damage, dflags, MOD_TRIGGER_HURT);
        }
Beispiel #8
0
        /*
         * ================
         * CG_FragmentBounceMark
         * ================
         */
        void CG_FragmentBounceMark(localEntity_t *le, trace_t *trace)
        {
            int radius;

            if (le->leMarkType == LEMT_BLOOD)
            {
                radius = 16 + (rand() & 31);
                CG_ImpactMark(cgs.media.bloodMarkShader, trace->endpos, trace->plane.normal, random() * 360,
                              1, 1, 1, 1, true, radius, false);
            }
            else if (le->leMarkType == LEMT_BURN)
            {
                radius = 8 + (rand() & 15);
                CG_ImpactMark(cgs.media.burnMarkShader, trace->endpos, trace->plane.normal, random() * 360,
                              1, 1, 1, 1, true, radius, false);
            }


            // don't allow a fragment to make multiple marks, or they
            // pile up while settling
            le->leMarkType = LEMT_NONE;
        }
Beispiel #9
0
        /*
         * ================
         * G_MissileImpact
         * ================
         */
        void G_MissileImpact(gentity_t *ent, trace_t *trace)
        {
            gentity_t *other;
            bool       hitClient = false;

            other = &g_entities[trace->entityNum];

            // check for bounce
            if (!other->takedamage &&
                (ent->s.eFlags & (EF_BOUNCE | EF_BOUNCE_HALF)))
            {
                G_BounceMissile(ent, trace);
                G_AddEvent(ent, EV_GRENADE_BOUNCE, 0);
                return;
            }

            // impact damage
            if (other->takedamage)
            {
                // FIXME: wrong damage direction?
                if (ent->damage)
                {
                    vec3_t velocity;

                    if (LogAccuracyHit(other, &g_entities[ent->r.ownerNum]))
                    {
                        g_entities[ent->r.ownerNum].client->accuracy_hits++;
                        hitClient = true;
                    }
                    BG_EvaluateTrajectoryDelta(&ent->s.pos, level.time, velocity);
                    if (VectorLength(velocity) == 0)
                    {
                        velocity[2] = 1;                                // stepped on a grenade
                    }
                    G_Damage(other, ent, &g_entities[ent->r.ownerNum], velocity,
                             ent->s.origin, ent->damage,
                             0, ent->methodOfDeath);
                }
            }

            if (!strcmp(ent->classname, "hook"))
            {
                gentity_t *nent;
                vec3_t     v;

                nent = G_Spawn();
                if (other->takedamage && other->client)
                {
                    G_AddEvent(nent, EV_MISSILE_HIT, DirToByte(trace->plane.normal));
                    nent->s.otherEntityNum = other->s.number;

                    ent->enemy = other;

                    v[0] = other->r.currentOrigin[0] + (other->r.mins[0] + other->r.maxs[0]) * 0.5;
                    v[1] = other->r.currentOrigin[1] + (other->r.mins[1] + other->r.maxs[1]) * 0.5;
                    v[2] = other->r.currentOrigin[2] + (other->r.mins[2] + other->r.maxs[2]) * 0.5;

                    SnapVectorTowards(v, ent->s.pos.trBase);                            // save net bandwidth
                }
                else
                {
                    VectorCopy(trace->endpos, v);
                    G_AddEvent(nent, EV_MISSILE_MISS, DirToByte(trace->plane.normal));
                    ent->enemy = NULL;
                }

                SnapVectorTowards(v, ent->s.pos.trBase);                        // save net bandwidth

                nent->freeAfterEvent = true;
                // change over to a normal entity right at the point of impact
                nent->s.eType = ET_GENERAL;
                ent->s.eType  = ET_GRAPPLE;

                G_SetOrigin(ent, v);
                G_SetOrigin(nent, v);

                ent->think     = Weapon_HookThink;
                ent->nextthink = level.time + FRAMETIME;

                ent->parent->client->ps.pm_flags |= PMF_GRAPPLE_PULL;
                VectorCopy(ent->r.currentOrigin, ent->parent->client->ps.grapplePoint);

                trap_LinkEntity(ent);
                trap_LinkEntity(nent);

                return;
            }

            // is it cheaper in bandwidth to just remove this ent and create a new
            // one, rather than changing the missile into the explosion?

            if (other->takedamage && other->client)
            {
                G_AddEvent(ent, EV_MISSILE_HIT, DirToByte(trace->plane.normal));
                ent->s.otherEntityNum = other->s.number;
            }
            else if (trace->surfaceFlags & SURF_METALSTEPS)
            {
                G_AddEvent(ent, EV_MISSILE_MISS_METAL, DirToByte(trace->plane.normal));
            }
            else
            {
                G_AddEvent(ent, EV_MISSILE_MISS, DirToByte(trace->plane.normal));
            }

            ent->freeAfterEvent = true;

            // change over to a normal entity right at the point of impact
            ent->s.eType = ET_GENERAL;

            SnapVectorTowards(trace->endpos, ent->s.pos.trBase);                // save net bandwidth

            G_SetOrigin(ent, trace->endpos);

            // splash damage (doesn't apply to person directly hit)
            if (ent->splashDamage)
            {
                if (G_RadiusDamage(trace->endpos, ent->parent, ent->splashDamage, ent->splashRadius,
                                   other, ent->splashMethodOfDeath))
                {
                    if (!hitClient)
                    {
                        g_entities[ent->r.ownerNum].client->accuracy_hits++;
                    }
                }
            }

            trap_LinkEntity(ent);
        }
Beispiel #10
0
        /*
         * ===============
         * Touch_Item
         * ===============
         */
        void Touch_Item(gentity_t *ent, gentity_t *other, trace_t *trace)
        {
            int  respawn;
            bool predict;

            if (!other->client)
            {
                return;
            }
            if (other->health < 1)
            {
                return;                         // dead people can't pickup
            }
            // the same pickup rules are used for client side and server side
            if (!BG_CanItemBeGrabbed(g_gametype.integer, &ent->s, &other->client->ps))
            {
                return;
            }

            G_LogPrintf("Item: %i %s\n", other->s.number, ent->item->classname);

            predict = other->client->pers.predictItemPickup;

            // call the item-specific pickup function
            switch (ent->item->giType)
            {
            case IT_WEAPON:
                respawn = Pickup_Weapon(ent, other);
                //		predict = false;
                break;

            case IT_AMMO:
                respawn = Pickup_Ammo(ent, other);
                //		predict = false;
                break;

            case IT_ARMOR:
                respawn = Pickup_Armor(ent, other);
                break;

            case IT_HEALTH:
                respawn = Pickup_Health(ent, other);
                break;

            case IT_POWERUP:
                respawn = Pickup_Powerup(ent, other);
                predict = false;
                break;

            case IT_TEAM:
                respawn = Pickup_Team(ent, other);
                break;

            case IT_HOLDABLE:
                respawn = Pickup_Holdable(ent, other);
                break;

            default:
                return;
            }

            if (!respawn)
            {
                return;
            }

            // play the normal pickup sound
            if (predict)
            {
                G_AddPredictableEvent(other, EV_ITEM_PICKUP, ent->s.modelindex);
            }
            else
            {
                G_AddEvent(other, EV_ITEM_PICKUP, ent->s.modelindex);
            }

            // powerup pickups are global broadcasts
            if (ent->item->giType == IT_POWERUP || ent->item->giType == IT_TEAM)
            {
                // if we want the global sound to play
                if (!ent->speed)
                {
                    gentity_t *te;

                    te = G_TempEntity(ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP);
                    te->s.eventParm = ent->s.modelindex;
                    te->r.svFlags  |= SVF_BROADCAST;
                }
                else
                {
                    gentity_t *te;

                    te = G_TempEntity(ent->s.pos.trBase, EV_GLOBAL_ITEM_PICKUP);
                    te->s.eventParm = ent->s.modelindex;
                    // only send this temp entity to a single client
                    te->r.svFlags     |= SVF_SINGLECLIENT;
                    te->r.singleClient = other->s.number;
                }
            }

            // fire item targets
            G_UseTargets(ent, other);

            // wait of -1 will not respawn
            if (ent->wait == -1)
            {
                ent->r.svFlags       |= SVF_NOCLIENT;
                ent->s.eFlags        |= EF_NODRAW;
                ent->r.contents       = 0;
                ent->unlinkAfterEvent = true;
                return;
            }

            // non zero wait overrides respawn time
            if (ent->wait)
            {
                respawn = ent->wait;
            }

            // random can be used to vary the respawn time
            if (ent->random)
            {
                respawn += crandom() * ent->random;
                if (respawn < 1)
                {
                    respawn = 1;
                }
            }

            // dropped items will not respawn
            if (ent->flags & FL_DROPPED_ITEM)
            {
                ent->freeAfterEvent = true;
            }

            // picked up items still stay around, they just don't
            // draw anything.  This allows respawnable items
            // to be placed on movers.
            ent->r.svFlags |= SVF_NOCLIENT;
            ent->s.eFlags  |= EF_NODRAW;
            ent->r.contents = 0;

            // ZOID
            // A negative respawn times means to never respawn this item (but don't
            // delete it).  This is used by items that are respawned by third party
            // events such as ctf flags
            if (respawn <= 0)
            {
                ent->nextthink = 0;
                ent->think     = 0;
            }
            else
            {
                ent->nextthink = level.time + respawn * 1000;
                ent->think     = RespawnItem;
            }
            trap_LinkEntity(ent);
        }