예제 #1
0
/*
===============
RespawnItem
===============
*/
void RespawnItem( gentity_t *ent ) {
	// randomly select from teamed entities
	if (ent->team) {
		gentity_t	*master;
		int	count;
		int choice;

		if ( !ent->teammaster ) {
			G_Error( "RespawnItem: bad teammaster");
		}
		master = ent->teammaster;

		for (count = 0, ent = master; ent; ent = ent->teamchain, count++)
			;

		choice = Q_rand() % count;

		for (count = 0, ent = master; count < choice; ent = ent->teamchain, count++)
			;
	}

	ent->r.contents = CONTENTS_TRIGGER;
	ent->s.eFlags &= ~EF_NODRAW;
	ent->r.svFlags &= ~SVF_NOCLIENT;
	trap_LinkEntity (ent);

	// play the normal respawn sound only to nearby clients
	G_AddEvent( ent, EV_ITEM_RESPAWN, 0 );

	ent->nextthink = 0;
}
예제 #2
0
void chick_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
{
    int     n;

// check for gib
    if (self->health <= self->gib_health) {
        gi.sound(self, CHAN_VOICE, gi.soundindex("misc/udeath.wav"), 1, ATTN_NORM, 0);
        for (n = 0; n < 2; n++)
            ThrowGib(self, "models/objects/gibs/bone/tris.md2", damage, GIB_ORGANIC);
        for (n = 0; n < 4; n++)
            ThrowGib(self, "models/objects/gibs/sm_meat/tris.md2", damage, GIB_ORGANIC);
        ThrowHead(self, "models/objects/gibs/head2/tris.md2", damage, GIB_ORGANIC);
        self->deadflag = DEAD_DEAD;
        return;
    }

    if (self->deadflag == DEAD_DEAD)
        return;

// regular death
    self->deadflag = DEAD_DEAD;
    self->takedamage = DAMAGE_YES;

    n = Q_rand() % 2;
    if (n == 0) {
        self->monsterinfo.currentmove = &chick_move_death1;
        gi.sound(self, CHAN_VOICE, sound_death1, 1, ATTN_NORM, 0);
    } else {
        self->monsterinfo.currentmove = &chick_move_death2;
        gi.sound(self, CHAN_VOICE, sound_death2, 1, ATTN_NORM, 0);
    }
}
예제 #3
0
void ChickSlash(edict_t *self)
{
    vec3_t  aim;

    VectorSet(aim, MELEE_DISTANCE, self->mins[0], 10);
    gi.sound(self, CHAN_WEAPON, sound_melee_swing, 1, ATTN_NORM, 0);
    fire_hit(self, aim, (10 + (Q_rand() % 6)), 100);
}
예제 #4
0
void GaldiatorMelee(edict_t *self)
{
    vec3_t  aim;

    VectorSet(aim, MELEE_DISTANCE, self->mins[0], -4);
    if (fire_hit(self, aim, (20 + (Q_rand() % 5)), 300))
        gi.sound(self, CHAN_AUTO, sound_cleaver_hit, 1, ATTN_NORM, 0);
    else
        gi.sound(self, CHAN_AUTO, sound_cleaver_miss, 1, ATTN_NORM, 0);
}
예제 #5
0
void SP_misc_banner(edict_t *ent)
{
    ent->movetype = MOVETYPE_NONE;
    ent->solid = SOLID_NOT;
    ent->s.modelindex = gi.modelindex("models/objects/banner/tris.md2");
    ent->s.frame = Q_rand() % 16;
    gi.linkentity(ent);

    ent->think = misc_banner_think;
    ent->nextthink = level.time + FRAMETIME;
}
예제 #6
0
/*
======================
M_MoveToGoal
======================
*/
void M_MoveToGoal(edict_t *ent, float dist)
{
    edict_t     *goal;

    goal = ent->goalentity;

    if (!ent->groundentity && !(ent->flags & (FL_FLY | FL_SWIM)))
        return;

// if the next step hits the enemy, return immediately
    if (ent->enemy &&  SV_CloseEnough(ent, ent->enemy, dist))
        return;

// bump around...
    if ((Q_rand() & 3) == 1 || !SV_StepDirection(ent, ent->ideal_yaw, dist)) {
        if (ent->inuse)
            SV_NewChaseDir(ent, goal, dist);
    }
}
예제 #7
0
파일: tent.c 프로젝트: AndreyNazarov/q2pro
static explosion_t *CL_PlainExplosion(void)
{
    explosion_t *ex;

    ex = CL_AllocExplosion();
    VectorCopy(te.pos1, ex->ent.origin);
    ex->type = ex_poly;
    ex->ent.flags = RF_FULLBRIGHT;
    ex->start = cl.servertime - CL_FRAMETIME;
    ex->light = 350;
    VectorSet(ex->lightcolor, 1.0f, 0.5f, 0.5f);
    ex->ent.angles[1] = Q_rand() % 360;
    ex->ent.model = cl_mod_explo4;
    if (frand() < 0.5f)
        ex->baseframe = 15;
    ex->frames = 15;

    return ex;
}
예제 #8
0
gentity_t *SelectRandomTeamSpawnPoint( int teamstate, team_t team ) {
	gentity_t	*spot;
	int			count;
	int			selection;
	gentity_t	*spots[MAX_TEAM_SPAWN_POINTS];
	char		*classname;

	if (teamstate == TEAM_BEGIN) {
		if (team == TEAM_RED)
			classname = "team_CTF_redplayer";
		else if (team == TEAM_BLUE)
			classname = "team_CTF_blueplayer";
		else
			return NULL;
	} else {
		if (team == TEAM_RED)
			classname = "team_CTF_redspawn";
		else if (team == TEAM_BLUE)
			classname = "team_CTF_bluespawn";
		else
			return NULL;
	}
	count = 0;

	spot = NULL;

	while ((spot = G_Find (spot, FOFS(classname), classname)) != NULL) {
		if ( SpotWouldTelefrag( spot->s.origin ) ) {
			continue;
		}
		spots[ count ] = spot;
		if (++count == MAX_TEAM_SPAWN_POINTS)
			break;
	}

	if ( !count ) {	// no spots that won't telefrag
		return G_Find( NULL, FOFS(classname), classname);
	}

	selection = Q_rand() % count;
	return spots[ selection ];
}
예제 #9
0
void ThrowClientHead(edict_t *self, int damage)
{
    vec3_t  vd;
    char    *gibname;

    if (Q_rand() & 1) {
        gibname = "models/objects/gibs/head2/tris.md2";
        self->s.skinnum = 1;        // second skin is player
    } else {
        gibname = "models/objects/gibs/skull/tris.md2";
        self->s.skinnum = 0;
    }

    self->s.origin[2] += 32;
    self->s.frame = 0;
    gi.setmodel(self, gibname);
    VectorSet(self->mins, -16, -16, 0);
    VectorSet(self->maxs, 16, 16, 16);

    self->takedamage = DAMAGE_NO;
    self->solid = SOLID_NOT;
    self->s.effects = EF_GIB;
    self->s.sound = 0;
    self->flags |= FL_NO_KNOCKBACK;

    self->movetype = MOVETYPE_BOUNCE;
    VelocityForDamage(damage, vd);
    VectorAdd(self->velocity, vd, self->velocity);

    if (self->client) { // bodies in the queue don't have a client anymore
        self->client->anim_priority = ANIM_DEATH;
        self->client->anim_end = self->s.frame;
    } else {
        self->think = NULL;
        self->nextthink = 0;
    }

    gi.linkentity(self);
}
예제 #10
0
// an entity has just been parsed that has an event value
static void entity_event(int number)
{
    centity_t *cent = &cl_entities[number];

    // EF_TELEPORTER acts like an event, but is not cleared each frame
    if ((cent->current.effects & EF_TELEPORTER) && CL_FRAMESYNC) {
        CL_TeleporterParticles(cent->current.origin);
    }

#if USE_FPS
    if (cent->event_frame != cl.frame.number)
        return;
#endif

    switch (cent->current.event) {
    case EV_ITEM_RESPAWN:
        S_StartSound(NULL, number, CHAN_WEAPON, S_RegisterSound("items/respawn1.wav"), 1, ATTN_IDLE, 0);
        CL_ItemRespawnParticles(cent->current.origin);
        break;
    case EV_PLAYER_TELEPORT:
        S_StartSound(NULL, number, CHAN_WEAPON, S_RegisterSound("misc/tele1.wav"), 1, ATTN_IDLE, 0);
        CL_TeleportParticles(cent->current.origin);
        break;
    case EV_FOOTSTEP:
        if (cl_footsteps->integer)
            S_StartSound(NULL, number, CHAN_BODY, cl_sfx_footsteps[Q_rand() & 3], 1, ATTN_NORM, 0);
        break;
    case EV_FALLSHORT:
        S_StartSound(NULL, number, CHAN_AUTO, S_RegisterSound("player/land1.wav"), 1, ATTN_NORM, 0);
        break;
    case EV_FALL:
        S_StartSound(NULL, number, CHAN_AUTO, S_RegisterSound("*fall2.wav"), 1, ATTN_NORM, 0);
        break;
    case EV_FALLFAR:
        S_StartSound(NULL, number, CHAN_AUTO, S_RegisterSound("*fall1.wav"), 1, ATTN_NORM, 0);
        break;
    }
}
예제 #11
0
void SV_NewChaseDir(edict_t *actor, edict_t *enemy, float dist)
{
    float   deltax, deltay;
    float   d[3];
    float   tdir, olddir, turnaround;

    //FIXME: how did we get here with no enemy
    if (!enemy)
        return;

    olddir = anglemod((int)(actor->ideal_yaw / 45) * 45);
    turnaround = anglemod(olddir - 180);

    deltax = enemy->s.origin[0] - actor->s.origin[0];
    deltay = enemy->s.origin[1] - actor->s.origin[1];
    if (deltax > 10)
        d[1] = 0;
    else if (deltax < -10)
        d[1] = 180;
    else
        d[1] = DI_NODIR;
    if (deltay < -10)
        d[2] = 270;
    else if (deltay > 10)
        d[2] = 90;
    else
        d[2] = DI_NODIR;

// try direct route
    if (d[1] != DI_NODIR && d[2] != DI_NODIR) {
        if (d[1] == 0)
            tdir = d[2] == 90 ? 45 : 315;
        else
            tdir = d[2] == 90 ? 135 : 215;

        if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
            return;
    }

// try other directions
    if (((Q_rand() & 3) & 1) || fabsf(deltay) > fabsf(deltax)) {
        tdir = d[1];
        d[1] = d[2];
        d[2] = tdir;
    }

    if (d[1] != DI_NODIR && d[1] != turnaround
        && SV_StepDirection(actor, d[1], dist))
        return;

    if (d[2] != DI_NODIR && d[2] != turnaround
        && SV_StepDirection(actor, d[2], dist))
        return;

    /* there is no direct path to the player, so pick another direction */

    if (olddir != DI_NODIR && SV_StepDirection(actor, olddir, dist))
        return;

    if (Q_rand() & 1) { /*randomly determine direction of search*/
        for (tdir = 0 ; tdir <= 315 ; tdir += 45)
            if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
                return;
    } else {
        for (tdir = 315 ; tdir >= 0 ; tdir -= 45)
            if (tdir != turnaround && SV_StepDirection(actor, tdir, dist))
                return;
    }

    if (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist))
        return;

    actor->ideal_yaw = olddir;      // can't move

// if a bridge was pulled out from underneath a monster, it may not have
// a valid standing position at all

    if (!M_CheckBottom(actor))
        SV_FixCheckBottom(actor);
}
예제 #12
0
float	Q_random( int *seed ) {
	return (Q_rand( seed ) & 0xffff) / (float)0x10000;
}
예제 #13
0
/*
===============
CL_AddPacketEntities

===============
*/
static void CL_AddPacketEntities(void)
{
    entity_t            ent;
    entity_state_t      *s1;
    float               autorotate;
    int                 i;
    int                 pnum;
    centity_t           *cent;
    int                 autoanim;
    clientinfo_t        *ci;
    unsigned int        effects, renderfx;

    // bonus items rotate at a fixed rate
    autorotate = anglemod(cl.time * 0.1f);

    // brush models can auto animate their frames
    autoanim = 2 * cl.time / 1000;

    memset(&ent, 0, sizeof(ent));

    for (pnum = 0; pnum < cl.frame.numEntities; pnum++) {
        i = (cl.frame.firstEntity + pnum) & PARSE_ENTITIES_MASK;
        s1 = &cl.entityStates[i];

        cent = &cl_entities[s1->number];

        effects = s1->effects;
        renderfx = s1->renderfx;

        // set frame
        if (effects & EF_ANIM01)
            ent.frame = autoanim & 1;
        else if (effects & EF_ANIM23)
            ent.frame = 2 + (autoanim & 1);
        else if (effects & EF_ANIM_ALL)
            ent.frame = autoanim;
        else if (effects & EF_ANIM_ALLFAST)
            ent.frame = cl.time / 100;
        else
            ent.frame = s1->frame;

        // quad and pent can do different things on client
        if (effects & EF_PENT) {
            effects &= ~EF_PENT;
            effects |= EF_COLOR_SHELL;
            renderfx |= RF_SHELL_RED;
        }

        if (effects & EF_QUAD) {
            effects &= ~EF_QUAD;
            effects |= EF_COLOR_SHELL;
            renderfx |= RF_SHELL_BLUE;
        }

        if (effects & EF_DOUBLE) {
            effects &= ~EF_DOUBLE;
            effects |= EF_COLOR_SHELL;
            renderfx |= RF_SHELL_DOUBLE;
        }

        if (effects & EF_HALF_DAMAGE) {
            effects &= ~EF_HALF_DAMAGE;
            effects |= EF_COLOR_SHELL;
            renderfx |= RF_SHELL_HALF_DAM;
        }

        // optionally remove the glowing effect
        if (cl_noglow->integer)
            renderfx &= ~RF_GLOW;

        ent.oldframe = cent->prev.frame;
        ent.backlerp = 1.0f - cl.lerpfrac;

        if (renderfx & RF_FRAMELERP) {
            // step origin discretely, because the frames
            // do the animation properly
            VectorCopy(cent->current.origin, ent.origin);
            VectorCopy(cent->current.old_origin, ent.oldorigin);  // FIXME
        } else if (renderfx & RF_BEAM) {
            // interpolate start and end points for beams
            LerpVector(cent->prev.origin, cent->current.origin,
                       cl.lerpfrac, ent.origin);
            LerpVector(cent->prev.old_origin, cent->current.old_origin,
                       cl.lerpfrac, ent.oldorigin);
        } else {
            if (s1->number == cl.frame.clientNum + 1) {
                // use predicted origin
                VectorCopy(cl.playerEntityOrigin, ent.origin);
                VectorCopy(cl.playerEntityOrigin, ent.oldorigin);
            } else {
                // interpolate origin
                LerpVector(cent->prev.origin, cent->current.origin,
                           cl.lerpfrac, ent.origin);
                VectorCopy(ent.origin, ent.oldorigin);
            }

#if USE_FPS
            // run alias model animation
            if (cent->prev_frame != s1->frame) {
                int delta = cl.time - cent->anim_start;
                float frac;

                if (delta > BASE_FRAMETIME) {
                    Com_DDDDPrintf("[%d] anim end %d: %d --> %d\n",
                                   cl.time, s1->number,
                                   cent->prev_frame, s1->frame);
                    cent->prev_frame = s1->frame;
                    frac = 1;
                } else if (delta > 0) {
                    frac = delta * BASE_1_FRAMETIME;
                    Com_DDDDPrintf("[%d] anim run %d: %d --> %d [%f]\n",
                                   cl.time, s1->number,
                                   cent->prev_frame, s1->frame,
                                   frac);
                } else {
                    frac = 0;
                }

                ent.oldframe = cent->prev_frame;
                ent.backlerp = 1.0f - frac;
            }
#endif
        }

        if ((effects & EF_GIB) && !cl_gibs->integer) {
            goto skip;
        }

        // create a new entity

        // tweak the color of beams
        if (renderfx & RF_BEAM) {
            // the four beam colors are encoded in 32 bits of skinnum (hack)
            ent.alpha = 0.30f;
            ent.skinnum = (s1->skinnum >> ((Q_rand() % 4) * 8)) & 0xff;
            ent.model = 0;
        } else {
            // set skin
            if (s1->modelindex == 255) {
예제 #14
0
파일: ui_menu.c 프로젝트: Kaperstone/warsow
/*
* UI_Init
*/
void UI_Init( int vidWidth, int vidHeight, int protocol, int sharedSeed )
{
	m_active = NULL;
	m_cursoritem = NULL;
	m_drawfunc = NULL;
	m_keyfunc = NULL;
	m_entersound = qfalse;
	m_keypressed = 0;

	memset( &uis, 0, sizeof( uis ) );

	uis.vidWidth = vidWidth;
	uis.vidHeight = vidHeight;
	uis.gameProtocol = protocol;

#if 0
	uis.scaleX = UI_WIDTHSCALE;
	uis.scaleY = UI_HEIGHTSCALE;
#else
	uis.scaleX = 1;
	uis.scaleY = 1;
#endif

	uis.cursorX = uis.vidWidth / 2;
	uis.cursorY = uis.vidHeight / 2;

	uis.initialSharedSeed = sharedSeed;
	uis.sharedSeed = uis.initialSharedSeed;

	uis.backgroundNum = Q_rand( &uis.sharedSeed ) % UI_SHADER_MAX_BACKGROUNDS;

	developer =	trap_Cvar_Get( "developer", "0", CVAR_CHEAT );

	// wsw/Mokshu : test svn addin for VS 2005 and what about a "help/news" menu (latest news from website for example)
	trap_Cmd_AddCommand( "menu_main", M_Menu_Main_f );
	trap_Cmd_AddCommand( "menu_main_sbar", M_Menu_Main_Statusbar_f );
	trap_Cmd_AddCommand( "menu_setup", M_Menu_Setup_f );
	trap_Cmd_AddCommand( "menu_joinserver", M_Menu_JoinServer_f );
	trap_Cmd_AddCommand( "menu_matchmaker", M_Menu_MatchMaker_f );
#ifdef AUTH_CODE
	trap_Cmd_AddCommand( "menu_login", M_Menu_Login_f );
	trap_Cmd_AddCommand( "menu_register", M_Menu_Register_f );
#endif
	trap_Cmd_AddCommand( "menu_playerconfig", M_Menu_PlayerConfig_f );
	trap_Cmd_AddCommand( "menu_startserver", M_Menu_StartServer_f );
	trap_Cmd_AddCommand( "menu_sound", M_Menu_Sound_f );
	trap_Cmd_AddCommand( "menu_options", M_Menu_Options_f );
	trap_Cmd_AddCommand( "menu_performance", M_Menu_Performance_f );
	trap_Cmd_AddCommand( "menu_performanceadv", M_Menu_PerformanceAdv_f );
	trap_Cmd_AddCommand( "menu_keys", M_Menu_Keys_f );
	trap_Cmd_AddCommand( "menu_vsays", M_Menu_Vsays_f );
	trap_Cmd_AddCommand( "menu_quit", M_Menu_Quit_f );
	trap_Cmd_AddCommand( "menu_reset", M_Menu_Reset_f );
	trap_Cmd_AddCommand( "menu_demos", M_Menu_Demos_f );
	trap_Cmd_AddCommand( "menu_mods", M_Menu_Mods_f );
	trap_Cmd_AddCommand( "menu_game", M_Menu_Game_f );
	trap_Cmd_AddCommand( "menu_tv", M_Menu_TV_f );
	trap_Cmd_AddCommand( "menu_tv_channel_add", M_Menu_TV_ChannelAdd_f );
	trap_Cmd_AddCommand( "menu_tv_channel_remove", M_Menu_TV_ChannelRemove_f );
	trap_Cmd_AddCommand( "menu_failed", M_Menu_Failed_f );
	trap_Cmd_AddCommand( "menu_msgbox", M_Menu_MsgBox_f );
	trap_Cmd_AddCommand( "menu_custom", M_Menu_Custom_f );
	trap_Cmd_AddCommand( "menu_chasecam", M_Menu_Chasecam_f );
	trap_Cmd_AddCommand( "menu_teamconfig", M_Menu_TeamConfig_f );
	trap_Cmd_AddCommand( "menu_force", UI_Force_f );
	trap_Cmd_AddCommand( "menu_tutorials", M_Menu_Tutorials_f );
	trap_Cmd_AddCommand( "menu_demoplay", M_Menu_Demoplay_f );
	trap_Cmd_AddCommand( "menu_pop", Cmd_PopMenu_f );

	M_Cache();
	UI_Playermodel_Init(); // create a list with the available player models
	UI_InitTemporaryBoneposesCache();

	uis.backGroundTrackStarted = qfalse;

	// jal: this is a small trick to assign userinfo flag to cg_oldMovement before cgame is loaded
	trap_Cvar_Get( "cg_oldMovement", "0", CVAR_USERINFO | CVAR_ARCHIVE );
	trap_Cvar_Get( "cg_noAutohop", "0", CVAR_USERINFO | CVAR_ARCHIVE );
}
예제 #15
0
/*
===============
P_DamageFeedback

Handles color blends and view kicks
===============
*/
void P_DamageFeedback(edict_t *player)
{
    gclient_t   *client;
    float   side;
    float   realcount, count, kick;
    vec3_t  v;
    int     r, l;
    static  vec3_t  power_color = {0.0, 1.0, 0.0};
    static  vec3_t  acolor = {1.0, 1.0, 1.0};
    static  vec3_t  bcolor = {1.0, 0.0, 0.0};

    client = player->client;

    // flash the backgrounds behind the status numbers
    client->ps.stats[STAT_FLASHES] = 0;
    if (client->damage_blood)
        client->ps.stats[STAT_FLASHES] |= 1;
    if (client->damage_armor && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum))
        client->ps.stats[STAT_FLASHES] |= 2;

    // total points of damage shot at the player this frame
    count = (client->damage_blood + client->damage_armor + client->damage_parmor);
    if (count == 0)
        return;     // didn't take any damage

    // start a pain animation if still in the player model
    if (client->anim_priority < ANIM_PAIN && player->s.modelindex == 255) {
        static int      i;

        client->anim_priority = ANIM_PAIN;
        if (client->ps.pmove.pm_flags & PMF_DUCKED) {
            player->s.frame = FRAME_crpain1 - 1;
            client->anim_end = FRAME_crpain4;
        } else {
            i = (i + 1) % 3;
            switch (i) {
            case 0:
                player->s.frame = FRAME_pain101 - 1;
                client->anim_end = FRAME_pain104;
                break;
            case 1:
                player->s.frame = FRAME_pain201 - 1;
                client->anim_end = FRAME_pain204;
                break;
            case 2:
                player->s.frame = FRAME_pain301 - 1;
                client->anim_end = FRAME_pain304;
                break;
            }
        }
    }

    realcount = count;
    if (count < 10)
        count = 10; // always make a visible effect

    // play an apropriate pain sound
    if ((level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum)) {
        r = 1 + (Q_rand() & 1);
        player->pain_debounce_time = level.time + 0.7f;
        if (player->health < 25)
            l = 25;
        else if (player->health < 50)
            l = 50;
        else if (player->health < 75)
            l = 75;
        else
            l = 100;
        gi.sound(player, CHAN_VOICE, gi.soundindex(va("*pain%i_%i.wav", l, r)), 1, ATTN_NORM, 0);
    }

    // the total alpha of the blend is always proportional to count
    if (client->damage_alpha < 0)
        client->damage_alpha = 0;
    client->damage_alpha += count * 0.01f;
    if (client->damage_alpha < 0.2f)
        client->damage_alpha = 0.2f;
    if (client->damage_alpha > 0.6f)
        client->damage_alpha = 0.6f;    // don't go too saturated

    // the color of the blend will vary based on how much was absorbed
    // by different armors
    VectorClear(v);
    if (client->damage_parmor)
        VectorMA(v, (float)client->damage_parmor / realcount, power_color, v);
    if (client->damage_armor)
        VectorMA(v, (float)client->damage_armor / realcount,  acolor, v);
    if (client->damage_blood)
        VectorMA(v, (float)client->damage_blood / realcount,  bcolor, v);
    VectorCopy(v, client->damage_blend);


    //
    // calculate view angle kicks
    //
    kick = abs(client->damage_knockback);
    if (kick && player->health > 0) { // kick of 0 means no view adjust at all
        kick = kick * 100 / player->health;

        if (kick < count * 0.5f)
            kick = count * 0.5f;
        if (kick > 50)
            kick = 50;

        VectorSubtract(client->damage_from, player->s.origin, v);
        VectorNormalize(v);

        side = DotProduct(v, right);
        client->v_dmg_roll = kick * side * 0.3f;

        side = -DotProduct(v, forward);
        client->v_dmg_pitch = kick * side * 0.3f;

        client->v_dmg_time = level.time + DAMAGE_TIME;
    }

    //
    // clear totals
    //
    client->damage_blood = 0;
    client->damage_armor = 0;
    client->damage_parmor = 0;
    client->damage_knockback = 0;
}
예제 #16
0
/*
=============
P_WorldEffects
=============
*/
void P_WorldEffects(void)
{
    bool        breather;
    bool        envirosuit;
    int         waterlevel, old_waterlevel;

    if (current_player->movetype == MOVETYPE_NOCLIP) {
        current_player->air_finished = level.time + 12; // don't need air
        return;
    }

    waterlevel = current_player->waterlevel;
    old_waterlevel = current_client->old_waterlevel;
    current_client->old_waterlevel = waterlevel;

    breather = current_client->breather_framenum > level.framenum;
    envirosuit = current_client->enviro_framenum > level.framenum;

    //
    // if just entered a water volume, play a sound
    //
    if (!old_waterlevel && waterlevel) {
        PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
        if (current_player->watertype & CONTENTS_LAVA)
            gi.sound(current_player, CHAN_BODY, gi.soundindex("player/lava_in.wav"), 1, ATTN_NORM, 0);
        else if (current_player->watertype & CONTENTS_SLIME)
            gi.sound(current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
        else if (current_player->watertype & CONTENTS_WATER)
            gi.sound(current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
        current_player->flags |= FL_INWATER;

        // clear damage_debounce, so the pain sound will play immediately
        current_player->damage_debounce_time = level.time - 1;
    }

    //
    // if just completely exited a water volume, play a sound
    //
    if (old_waterlevel && ! waterlevel) {
        PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
        gi.sound(current_player, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
        current_player->flags &= ~FL_INWATER;
    }

    //
    // check for head just going under water
    //
    if (old_waterlevel != 3 && waterlevel == 3) {
        gi.sound(current_player, CHAN_BODY, gi.soundindex("player/watr_un.wav"), 1, ATTN_NORM, 0);
    }

    //
    // check for head just coming out of water
    //
    if (old_waterlevel == 3 && waterlevel != 3) {
        if (current_player->air_finished < level.time) {
            // gasp for air
            gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0);
            PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
        } else  if (current_player->air_finished < level.time + 11) {
            // just break surface
            gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0);
        }
    }

    //
    // check for drowning
    //
    if (waterlevel == 3) {
        // breather or envirosuit give air
        if (breather || envirosuit) {
            current_player->air_finished = level.time + 10;

            if (((int)(current_client->breather_framenum - level.framenum) % 25) == 0) {
                if (!current_client->breather_sound)
                    gi.sound(current_player, CHAN_AUTO, gi.soundindex("player/u_breath1.wav"), 1, ATTN_NORM, 0);
                else
                    gi.sound(current_player, CHAN_AUTO, gi.soundindex("player/u_breath2.wav"), 1, ATTN_NORM, 0);
                current_client->breather_sound ^= 1;
                PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
                //FIXME: release a bubble?
            }
        }

        // if out of air, start drowning
        if (current_player->air_finished < level.time) {
            // drown!
            if (current_player->client->next_drown_time < level.time
                && current_player->health > 0) {
                current_player->client->next_drown_time = level.time + 1;

                // take more damage the longer underwater
                current_player->dmg += 2;
                if (current_player->dmg > 15)
                    current_player->dmg = 15;

                // play a gurp sound instead of a normal pain sound
                if (current_player->health <= current_player->dmg)
                    gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0);
                else if (Q_rand() & 1)
                    gi.sound(current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0);
                else
                    gi.sound(current_player, CHAN_VOICE, gi.soundindex("*gurp2.wav"), 1, ATTN_NORM, 0);

                current_player->pain_debounce_time = level.time;

                T_Damage(current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, current_player->dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
            }
        }
    } else {
        current_player->air_finished = level.time + 12;
        current_player->dmg = 2;
    }

    //
    // check for sizzle damage
    //
    if (waterlevel && (current_player->watertype & (CONTENTS_LAVA | CONTENTS_SLIME))) {
        if (current_player->watertype & CONTENTS_LAVA) {
            if (current_player->health > 0
                && current_player->pain_debounce_time <= level.time
                && current_client->invincible_framenum < level.framenum) {
                if (Q_rand() & 1)
                    gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0);
                else
                    gi.sound(current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0);
                current_player->pain_debounce_time = level.time + 1;
            }

            if (envirosuit) // take 1/3 damage with envirosuit
                T_Damage(current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1 * waterlevel, 0, 0, MOD_LAVA);
            else
                T_Damage(current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 3 * waterlevel, 0, 0, MOD_LAVA);
        }

        if (current_player->watertype & CONTENTS_SLIME) {
            if (!envirosuit) {
                // no damage from slime with envirosuit
                T_Damage(current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1 * waterlevel, 0, 0, MOD_SLIME);
            }
        }
    }
}