//--------------------------------------------------------- gentity_t *WP_FireThermalDetonator( gentity_t *ent, qboolean altFire ) //--------------------------------------------------------- { gentity_t *bolt; vec3_t dir, start; float chargeAmount = 1.0f; // default of full charge VectorCopy( forward, dir ); VectorCopy( muzzle, start ); bolt = G_Spawn(); bolt->physicsObject = qtrue; bolt->classname = "thermal_detonator"; bolt->think = thermalThinkStandard; bolt->nextthink = level.time; bolt->touch = Thermal_Touch; // How 'bout we give this thing a size... VectorSet( bolt->r.mins, -3.0f, -3.0f, -3.0f ); VectorSet( bolt->r.maxs, 3.0f, 3.0f, 3.0f ); bolt->clipmask = MASK_SHOT; WP_TraceSetStart( ent, start, bolt->r.mins, bolt->r.maxs );//make sure our start point isn't on the other side of a wall if ( ent->client ) { chargeAmount = level.time - ent->client->ps.weaponChargeTime; } // get charge amount chargeAmount = chargeAmount / (float)TD_VELOCITY; if ( chargeAmount > 1.0f ) { chargeAmount = 1.0f; } else if ( chargeAmount < TD_MIN_CHARGE ) { chargeAmount = TD_MIN_CHARGE; } // normal ones bounce, alt ones explode on impact bolt->genericValue5 = level.time + TD_TIME; // How long 'til she blows bolt->s.pos.trType = TR_GRAVITY; bolt->parent = ent; bolt->r.ownerNum = ent->s.number; VectorScale( dir, TD_VELOCITY * chargeAmount, bolt->s.pos.trDelta ); if ( ent->health >= 0 ) { bolt->s.pos.trDelta[2] += 120; } if ( !altFire ) { bolt->flags |= FL_BOUNCE_HALF; } bolt->s.loopSound = G_SoundIndex( "sound/weapons/thermal/thermloop.wav" ); bolt->s.loopIsSoundset = qfalse; bolt->damage = TD_DAMAGE; bolt->dflags = 0; bolt->splashDamage = TD_SPLASH_DAM; bolt->splashRadius = TD_SPLASH_RAD; bolt->s.eType = ET_MISSILE; bolt->r.svFlags = SVF_USE_CURRENT_ORIGIN; bolt->s.weapon = WP_THERMAL; bolt->methodOfDeath = MOD_THERMAL; bolt->splashMethodOfDeath = MOD_THERMAL_SPLASH; bolt->s.pos.trTime = level.time; // move a bit on the very first frame VectorCopy( start, bolt->s.pos.trBase ); SnapVector( bolt->s.pos.trDelta ); // save net bandwidth VectorCopy (start, bolt->r.currentOrigin); VectorCopy( start, bolt->pos2 ); bolt->bounceCount = -5; return bolt; }
//=========================================================================== // // Parameter: - // Returns: - // Changes Globals: - //=========================================================================== void AAS_ShowReachability(aas_reachability_t *reach) { vec3_t dir, cmdmove, velocity; float speed, zvel; aas_clientmove_t move; AAS_ShowAreaPolygons(reach->areanum, 5, qtrue); //AAS_ShowArea(reach->areanum, qtrue); AAS_DrawArrow(reach->start, reach->end, LINECOLOR_BLUE, LINECOLOR_YELLOW); // if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP || (reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_WALKOFFLEDGE) { AAS_HorizontalVelocityForJump(aassettings.phys_jumpvel, reach->start, reach->end, &speed); // VectorSubtract(reach->end, reach->start, dir); dir[2] = 0; VectorNormalize(dir); //set the velocity VectorScale(dir, speed, velocity); //set the command movement VectorClear(cmdmove); cmdmove[2] = aassettings.phys_jumpvel; // AAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue, velocity, cmdmove, 3, 30, 0.1f, SE_HITGROUND|SE_ENTERWATER|SE_ENTERSLIME| SE_ENTERLAVA|SE_HITGROUNDDAMAGE, 0, qtrue); // if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMP) { AAS_JumpReachRunStart(reach, dir); AAS_DrawCross(dir, 4, LINECOLOR_BLUE); } //end if } //end if else if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_ROCKETJUMP) { zvel = AAS_RocketJumpZVelocity(reach->start); AAS_HorizontalVelocityForJump(zvel, reach->start, reach->end, &speed); // VectorSubtract(reach->end, reach->start, dir); dir[2] = 0; VectorNormalize(dir); //get command movement VectorScale(dir, speed, cmdmove); VectorSet(velocity, 0, 0, zvel); // AAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue, velocity, cmdmove, 30, 30, 0.1f, SE_ENTERWATER|SE_ENTERSLIME| SE_ENTERLAVA|SE_HITGROUNDDAMAGE| SE_TOUCHJUMPPAD|SE_HITGROUNDAREA, reach->areanum, qtrue); } //end else if else if ((reach->traveltype & TRAVELTYPE_MASK) == TRAVEL_JUMPPAD) { VectorSet(cmdmove, 0, 0, 0); // VectorSubtract(reach->end, reach->start, dir); dir[2] = 0; VectorNormalize(dir); //set the velocity //NOTE: the edgenum is the horizontal velocity VectorScale(dir, reach->edgenum, velocity); //NOTE: the facenum is the Z velocity velocity[2] = reach->facenum; // AAS_PredictClientMovement(&move, -1, reach->start, PRESENCE_NORMAL, qtrue, velocity, cmdmove, 30, 30, 0.1f, SE_ENTERWATER|SE_ENTERSLIME| SE_ENTERLAVA|SE_HITGROUNDDAMAGE| SE_TOUCHJUMPPAD|SE_HITGROUNDAREA, reach->areanum, qtrue); } //end else if } //end of the function AAS_ShowReachability
void AAS_AddTeleporterPortals(void) { int j, area2num, facenum, otherareanum; char *target, *targetname, *classname; bsp_entity_t *entities, *ent, *dest; vec3_t origin, destorigin, mins, maxs, end; vec3_t bbmins, bbmaxs; aas_area_t *area; aas_face_t *face; aas_trace_t trace; aas_link_t *areas, *link; entities = AAS_ParseBSPEntities(); for (ent = entities; ent; ent = ent->next) { classname = AAS_ValueForBSPEpairKey(ent, "classname"); if (classname && !strcmp(classname, "misc_teleporter")) { if (!AAS_VectorForBSPEpairKey(ent, "origin", origin)) { botimport.Print(PRT_ERROR, "teleporter (%s) without origin\n", target); continue; } //end if // target = AAS_ValueForBSPEpairKey(ent, "target"); if (!target) { botimport.Print(PRT_ERROR, "teleporter (%s) without target\n", target); continue; } //end if for (dest = entities; dest; dest = dest->next) { classname = AAS_ValueForBSPEpairKey(dest, "classname"); if (classname && !strcmp(classname, "misc_teleporter_dest")) { targetname = AAS_ValueForBSPEpairKey(dest, "targetname"); if (targetname && !strcmp(targetname, target)) { break; } //end if } //end if } //end for if (!dest) { botimport.Print(PRT_ERROR, "teleporter without destination (%s)\n", target); continue; } //end if if (!AAS_VectorForBSPEpairKey(dest, "origin", destorigin)) { botimport.Print(PRT_ERROR, "teleporter destination (%s) without origin\n", target); continue; } //end if destorigin[2] += 24; //just for q2e1m2, the dork has put the telepads in the ground VectorCopy(destorigin, end); end[2] -= 100; trace = AAS_TraceClientBBox(destorigin, end, PRESENCE_CROUCH, -1); if (trace.startsolid) { botimport.Print(PRT_ERROR, "teleporter destination (%s) in solid\n", target); continue; } //end if VectorCopy(trace.endpos, destorigin); area2num = AAS_PointAreaNum(destorigin); //reset all cluster fields for (j = 0; j < aasworld.numareas; j++) { aasworld.areasettings[j].cluster = 0; } //end for // VectorSet(mins, -8, -8, 8); VectorSet(maxs, 8, 8, 24); // AAS_PresenceTypeBoundingBox(PRESENCE_CROUCH, bbmins, bbmaxs); // VectorAdd(origin, mins, mins); VectorAdd(origin, maxs, maxs); //add bounding box size VectorSubtract(mins, bbmaxs, mins); VectorSubtract(maxs, bbmins, maxs); //link an invalid (-1) entity areas = AAS_AASLinkEntity(mins, maxs, -1); // for (link = areas; link; link = link->next_area) { if (!AAS_AreaGrounded(link->areanum)) continue; //add the teleporter portal mark aasworld.areasettings[link->areanum].contents |= AREACONTENTS_CLUSTERPORTAL | AREACONTENTS_TELEPORTAL; } //end for // for (link = areas; link; link = link->next_area) { if (!AAS_AreaGrounded(link->areanum)) continue; //find a non-portal area adjacent to the portal area and flood //the cluster from there area = &aasworld.areas[link->areanum]; for (j = 0; j < area->numfaces; j++) { facenum = abs(aasworld.faceindex[area->firstface + j]); face = &aasworld.faces[facenum]; // if (face->frontarea != link->areanum) otherareanum = face->frontarea; else otherareanum = face->backarea; // if (!otherareanum) continue; // if (aasworld.areasettings[otherareanum].contents & AREACONTENTS_CLUSTERPORTAL) { continue; } //end if // AAS_FloodCluster_r(otherareanum, 1); } //end for } //end for //if the teleport destination IS in the same cluster if (aasworld.areasettings[area2num].cluster) { for (link = areas; link; link = link->next_area) { if (!AAS_AreaGrounded(link->areanum)) continue; //add the teleporter portal mark aasworld.areasettings[link->areanum].contents &= ~(AREACONTENTS_CLUSTERPORTAL | AREACONTENTS_TELEPORTAL); } //end for } //end if } //end if } //end for AAS_FreeBSPEntities(entities); } //end of the function AAS_AddTeleporterPortals
/* =============== CG_OffsetFirstPersonView =============== */ static void CG_OffsetFirstPersonView( void ) { float *origin; float *angles; float bob; float ratio; float delta; float speed; float f; vec3_t predictedVelocity; int timeDelta; float bob2; vec3_t normal, baseOrigin; playerState_t *ps = &cg.predictedPlayerState; if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) { if( ps->stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) VectorSet( normal, 0.0f, 0.0f, -1.0f ); else VectorCopy( ps->grapplePoint, normal ); } else VectorSet( normal, 0.0f, 0.0f, 1.0f ); if( cg.snap->ps.pm_type == PM_INTERMISSION ) return; origin = cg.refdef.vieworg; angles = cg.refdefViewAngles; VectorCopy( origin, baseOrigin ); // if dead, fix the angle and don't add any kick if( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 ) { angles[ ROLL ] = 40; angles[ PITCH ] = -15; angles[ YAW ] = cg.snap->ps.stats[ STAT_VIEWLOCK ]; origin[ 2 ] += cg.predictedPlayerState.viewheight; return; } // add angles based on weapon kick VectorAdd( angles, cg.kick_angles, angles ); // add angles based on damage kick if( cg.damageTime ) { ratio = cg.time - cg.damageTime; if( ratio < DAMAGE_DEFLECT_TIME ) { ratio /= DAMAGE_DEFLECT_TIME; angles[ PITCH ] += ratio * cg.v_dmg_pitch; angles[ ROLL ] += ratio * cg.v_dmg_roll; } else { ratio = 1.0 - ( ratio - DAMAGE_DEFLECT_TIME ) / DAMAGE_RETURN_TIME; if( ratio > 0 ) { angles[ PITCH ] += ratio * cg.v_dmg_pitch; angles[ ROLL ] += ratio * cg.v_dmg_roll; } } } // add pitch based on fall kick #if 0 ratio = ( cg.time - cg.landTime) / FALL_TIME; if (ratio < 0) ratio = 0; angles[PITCH] += ratio * cg.fall_value; #endif // add angles based on velocity VectorCopy( cg.predictedPlayerState.velocity, predictedVelocity ); delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 0 ] ); angles[ PITCH ] += delta * cg_runpitch.value; delta = DotProduct( predictedVelocity, cg.refdef.viewaxis[ 1 ] ); angles[ ROLL ] -= delta * cg_runroll.value; // add angles based on bob // bob amount is class dependant if( cg.snap->ps.persistant[ PERS_TEAM ] == TEAM_SPECTATOR ) bob2 = 0.0f; else bob2 = BG_FindBobForClass( cg.predictedPlayerState.stats[ STAT_PCLASS ] ); #define LEVEL4_FEEDBACK 10.0f //give a charging player some feedback if( ps->weapon == WP_ALEVEL4 ) { if( ps->stats[ STAT_MISC ] > 0 ) { float fraction = (float)ps->stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME; if( fraction > 1.0f ) fraction = 1.0f; bob2 *= ( 1.0f + fraction * LEVEL4_FEEDBACK ); } } if( bob2 != 0.0f ) { // make sure the bob is visible even at low speeds speed = cg.xyspeed > 200 ? cg.xyspeed : 200; delta = cg.bobfracsin * ( bob2 ) * speed; if( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) delta *= 3; // crouching angles[ PITCH ] += delta; delta = cg.bobfracsin * ( bob2 ) * speed; if( cg.predictedPlayerState.pm_flags & PMF_DUCKED ) delta *= 3; // crouching accentuates roll if( cg.bobcycle & 1 ) delta = -delta; angles[ ROLL ] += delta; } #define LEVEL3_FEEDBACK 20.0f //provide some feedback for pouncing if( cg.predictedPlayerState.weapon == WP_ALEVEL3 || cg.predictedPlayerState.weapon == WP_ALEVEL3_UPG ) { if( cg.predictedPlayerState.stats[ STAT_MISC ] > 0 ) { float fraction1, fraction2; vec3_t forward; AngleVectors( angles, forward, NULL, NULL ); VectorNormalize( forward ); fraction1 = (float)( cg.time - cg.weapon2Time ) / (float)LEVEL3_POUNCE_CHARGE_TIME; if( fraction1 > 1.0f ) fraction1 = 1.0f; fraction2 = -sin( fraction1 * M_PI / 2 ); VectorMA( origin, LEVEL3_FEEDBACK * fraction2, forward, origin ); } } #define STRUGGLE_DIST 5.0f #define STRUGGLE_TIME 250 //allow the player to struggle a little whilst grabbed if( cg.predictedPlayerState.pm_type == PM_GRABBED ) { vec3_t forward, right, up; usercmd_t cmd; int cmdNum; float fFraction, rFraction, uFraction; float fFraction2, rFraction2, uFraction2; cmdNum = trap_GetCurrentCmdNumber(); trap_GetUserCmd( cmdNum, &cmd ); AngleVectors( angles, forward, right, up ); fFraction = (float)( cg.time - cg.forwardMoveTime ) / STRUGGLE_TIME; rFraction = (float)( cg.time - cg.rightMoveTime ) / STRUGGLE_TIME; uFraction = (float)( cg.time - cg.upMoveTime ) / STRUGGLE_TIME; if( fFraction > 1.0f ) fFraction = 1.0f; if( rFraction > 1.0f ) rFraction = 1.0f; if( uFraction > 1.0f ) uFraction = 1.0f; fFraction2 = -sin( fFraction * M_PI / 2 ); rFraction2 = -sin( rFraction * M_PI / 2 ); uFraction2 = -sin( uFraction * M_PI / 2 ); if( cmd.forwardmove > 0 ) VectorMA( origin, STRUGGLE_DIST * fFraction, forward, origin ); else if( cmd.forwardmove < 0 ) VectorMA( origin, -STRUGGLE_DIST * fFraction, forward, origin ); else cg.forwardMoveTime = cg.time; if( cmd.rightmove > 0 ) VectorMA( origin, STRUGGLE_DIST * rFraction, right, origin ); else if( cmd.rightmove < 0 ) VectorMA( origin, -STRUGGLE_DIST * rFraction, right, origin ); else cg.rightMoveTime = cg.time; if( cmd.upmove > 0 ) VectorMA( origin, STRUGGLE_DIST * uFraction, up, origin ); else if( cmd.upmove < 0 ) VectorMA( origin, -STRUGGLE_DIST * uFraction, up, origin ); else cg.upMoveTime = cg.time; } if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_POISONCLOUDED && !( cg.snap->ps.pm_flags & PMF_FOLLOW ) ) { float fraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 2 * PCLOUD_ROLL_FREQUENCY ); float pitchFraction = sin( ( (float)cg.time / 1000.0f ) * M_PI * 5 * PCLOUD_ROLL_FREQUENCY ); fraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME ); pitchFraction *= 1.0f - ( ( cg.time - cg.poisonedTime ) / (float)LEVEL1_PCLOUD_TIME ); angles[ ROLL ] += fraction * PCLOUD_ROLL_AMPLITUDE; angles[ YAW ] += fraction * PCLOUD_ROLL_AMPLITUDE; angles[ PITCH ] += pitchFraction * PCLOUD_ROLL_AMPLITUDE / 2.0f; } // this *feels* more realisitic for humans if( cg.predictedPlayerState.stats[ STAT_PTEAM ] == PTE_HUMANS ) { angles[PITCH] += cg.bobfracsin * bob2 * 0.5; // heavy breathing effects //FIXME: sound if( cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 ) { float deltaBreath = (float)( cg.predictedPlayerState.stats[ STAT_STAMINA ] < 0 ? -cg.predictedPlayerState.stats[ STAT_STAMINA ] : cg.predictedPlayerState.stats[ STAT_STAMINA ] ) / 200.0; float deltaAngle = cos( (float)cg.time/150.0 ) * deltaBreath; deltaAngle += ( deltaAngle < 0 ? -deltaAngle : deltaAngle ) * 0.5; angles[ PITCH ] -= deltaAngle; } //ZdrytchX: Personal view bug fix hack [see youtube.com/zdrytchx: mdriver false bullet physics test, //you'll see how annoying it is in sniping for me, turns out the correction value for myself is approx //-1.19 degrees that actualy changes with pitch... I need to find a way to fix this.] //@jkent: Thinking of which, I have an idea: facetracker compatability, haha... if( cg_firstpersonanglefix_yaw.value != 0) { if( cg_firstpersonanglefix_yaw.value > 20) //TODO: make sure we don't cheat here! (doesn't work) trap_Cvar_Set( "cg_firstpersonanglefix_yaw.value", "20" ); else if( cg_firstpersonanglefix_yaw.value < -20) trap_Cvar_Set( "cg_firstpersonanglefix_yaw.value", "-20" ); //Set angle fix! angles[ YAW ] += cg_firstpersonanglefix_yaw.value; //left is positive (backward people's tradition) } if( cg_firstpersonanglefix_pitch.value != 0) { if( cg_firstpersonanglefix_pitch.value > 20) //TODO: make sure we don't cheat here! (doesn't work) trap_Cvar_Set( "cg_firstpersonanglefix_pitch.value", "20" ); else if( cg_firstpersonanglefix_pitch.value < -20) trap_Cvar_Set( "cg_firstpersonanglefix_pitch.value", "-20" ); //Set angle fix! angles[ PITCH ] -= cg_firstpersonanglefix_pitch.value; //up is positive } } //=================================== // add view height // when wall climbing the viewheight is not straight up if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) VectorMA( origin, ps->viewheight, normal, origin ); else origin[ 2 ] += cg.predictedPlayerState.viewheight; // smooth out duck height changes timeDelta = cg.time - cg.duckTime; if( timeDelta < DUCK_TIME) { cg.refdef.vieworg[ 2 ] -= cg.duckChange * ( DUCK_TIME - timeDelta ) / DUCK_TIME; } // add bob height bob = cg.bobfracsin * cg.xyspeed * bob2; if( bob > 6 ) bob = 6; // likewise for bob if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) VectorMA( origin, bob, normal, origin ); else origin[ 2 ] += bob; // add fall height delta = cg.time - cg.landTime; if( delta < LAND_DEFLECT_TIME ) { f = delta / LAND_DEFLECT_TIME; cg.refdef.vieworg[ 2 ] += cg.landChange * f; } else if( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) { delta -= LAND_DEFLECT_TIME; f = 1.0 - ( delta / LAND_RETURN_TIME ); cg.refdef.vieworg[ 2 ] += cg.landChange * f; } // add step offset CG_StepOffset( ); // add kick offset VectorAdd (origin, cg.kick_origin, origin); }
/* ============== IsHeadShot ============== */ qboolean IsHeadShot( gentity_t *targ, gentity_t *attacker, vec3_t dir, vec3_t point, int mod ) { gentity_t *head; trace_t tr; vec3_t start, end; gentity_t *traceEnt; orientation_t or; qboolean head_shot_weapon = qfalse; // not a player or critter so bail if ( !( targ->client ) ) { return qfalse; } if ( targ->health <= 0 ) { return qfalse; } head_shot_weapon = IsHeadShotWeapon( mod, targ, attacker ); if ( head_shot_weapon ) { head = G_Spawn(); G_SetOrigin( head, targ->r.currentOrigin ); // RF, if there is a valid tag_head for this entity, then use that if ( ( targ->r.svFlags & SVF_CASTAI ) && trap_GetTag( targ->s.number, "tag_head", &or ) ) { VectorCopy( or.origin, head->r.currentOrigin ); VectorMA( head->r.currentOrigin, 6, or.axis[2], head->r.currentOrigin ); // tag is at base of neck } else if ( targ->client->ps.pm_flags & PMF_DUCKED ) { // closer fake offset for 'head' box when crouching head->r.currentOrigin[2] += targ->client->ps.crouchViewHeight + 8; // JPW NERVE 16 is kludge to get head height to match up } //else if(targ->client->ps.legsAnim == LEGS_IDLE && targ->aiCharacter == AICHAR_SOLDIER) // standing with legs bent (about a head shorter than other leg poses) // head->r.currentOrigin[2] += targ->client->ps.viewheight; else { head->r.currentOrigin[2] += targ->client->ps.viewheight; // JPW NERVE pulled this // 6 is fudged "head height" value } VectorCopy( head->r.currentOrigin, head->s.origin ); VectorCopy( targ->r.currentAngles, head->s.angles ); VectorCopy( head->s.angles, head->s.apos.trBase ); VectorCopy( head->s.angles, head->s.apos.trDelta ); VectorSet( head->r.mins, -6, -6, -6 ); // JPW NERVE changed this z from -12 to -6 for crouching, also removed standing offset VectorSet( head->r.maxs, 6, 6, 6 ); // changed this z from 0 to 6 head->clipmask = CONTENTS_SOLID; head->r.contents = CONTENTS_SOLID; trap_LinkEntity( head ); // trace another shot see if we hit the head VectorCopy( point, start ); VectorMA( start, 64, dir, end ); trap_Trace( &tr, start, NULL, NULL, end, targ->s.number, MASK_SHOT ); traceEnt = &g_entities[ tr.entityNum ]; if ( g_debugBullets.integer >= 3 ) { // show hit player head bb gentity_t *tent; vec3_t b1, b2; VectorCopy( head->r.currentOrigin, b1 ); VectorCopy( head->r.currentOrigin, b2 ); VectorAdd( b1, head->r.mins, b1 ); VectorAdd( b2, head->r.maxs, b2 ); tent = G_TempEntity( b1, EV_RAILTRAIL ); VectorCopy( b2, tent->s.origin2 ); tent->s.dmgFlags = 1; // show headshot trace // end the headshot trace at the head box if it hits if ( tr.fraction != 1 ) { VectorMA( start, ( tr.fraction * 64 ), dir, end ); } tent = G_TempEntity( start, EV_RAILTRAIL ); VectorCopy( end, tent->s.origin2 ); tent->s.dmgFlags = 0; } G_FreeEntity( head ); if ( traceEnt == head ) { return qtrue; } } return qfalse; }
/* ================= R_DrawAliasFrameLerp ================= */ void R_DrawAliasFrameLerp (maliasmodel_t *paliashdr, entity_t *e) { int i, j, k, meshnum; maliasframe_t *frame, *oldframe; maliasmesh_t mesh; maliasvertex_t *v, *ov; vec3_t move, delta, vectors[3]; vec3_t curScale, oldScale, curNormal, oldNormal; vec3_t tempNormalsArray[MD3_MAX_VERTS]; vec2_t tempSkinCoord; vec3_t meshlight, lightcolor; float alpha, meshalpha, thisalpha, shellscale, frontlerp, backlerp = e->backlerp; image_t *skin; renderparms_t skinParms; qboolean shellModel = e->flags & ( RF_SHELL_RED | RF_SHELL_GREEN | RF_SHELL_BLUE | RF_SHELL_DOUBLE | RF_SHELL_HALF_DAM); frontlerp = 1.0 - backlerp; if (e->flags & RF_TRANSLUCENT) alpha = e->alpha; else alpha = 1.0; frame = paliashdr->frames + e->frame; oldframe = paliashdr->frames + e->oldframe; VectorScale(frame->scale, frontlerp, curScale); VectorScale(oldframe->scale, backlerp, oldScale); // move should be the delta back to the previous frame * backlerp VectorSubtract (e->oldorigin, e->origin, delta); AngleVectors (e->angles, vectors[0], vectors[1], vectors[2]); move[0] = DotProduct (delta, vectors[0]); // forward move[1] = -DotProduct (delta, vectors[1]); // left move[2] = DotProduct (delta, vectors[2]); // up VectorAdd (move, oldframe->translate, move); for (i=0 ; i<3 ; i++) move[i] = backlerp*move[i] + frontlerp*frame->translate[i]; R_SetVertexOverbrights(true); R_SetShellBlend (true); // new outer loop for whole model for (k=0, meshnum=0; k < paliashdr->num_meshes; k++, meshnum++) { mesh = paliashdr->meshes[k]; skinParms = mesh.skins[e->skinnum].renderparms; // select skin if (e->skin) skin = e->skin; // custom player skin else skin = currentmodel->skins[k][e->skinnum]; if (!skin) skin = r_notexture; if ( !shellModel ) GL_Bind(skin->texnum); else if (FlowingShell()) alpha = 0.7; // md3 skin scripting if (skinParms.nodraw) continue; // skip this mesh for this skin if (skinParms.twosided) GL_Disable(GL_CULL_FACE); if (skinParms.alphatest && !shellModel) GL_Enable(GL_ALPHA_TEST); if (skinParms.fullbright) VectorSet(meshlight, 1.0f, 1.0f, 1.0f); else VectorCopy(shadelight, meshlight); meshalpha = alpha * skinParms.basealpha; if (meshalpha < 1.0f || skinParms.blend) GL_Enable (GL_BLEND); else GL_Disable (GL_BLEND); if (skinParms.blend && !shellModel) GL_BlendFunc (skinParms.blendfunc_src, skinParms.blendfunc_dst); else GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // md3 skin scripting v = mesh.vertexes + e->frame*mesh.num_verts; ov = mesh.vertexes + e->oldframe*mesh.num_verts; rb_vertex = 0; for (i=0; i<mesh.num_verts; i++, v++, ov++) { // lerp verts curNormal[0] = r_sinTable[v->normal[0]] * r_cosTable[v->normal[1]]; curNormal[1] = r_sinTable[v->normal[0]] * r_sinTable[v->normal[1]]; curNormal[2] = r_cosTable[v->normal[0]]; oldNormal[0] = r_sinTable[ov->normal[0]] * r_cosTable[ov->normal[1]]; oldNormal[1] = r_sinTable[ov->normal[0]] * r_sinTable[ov->normal[1]]; oldNormal[2] = r_cosTable[ov->normal[0]]; VectorSet ( tempNormalsArray[i], curNormal[0] + (oldNormal[0] - curNormal[0])*backlerp, curNormal[1] + (oldNormal[1] - curNormal[1])*backlerp, curNormal[2] + (oldNormal[2] - curNormal[2])*backlerp ); if (shellModel) shellscale = (e->flags & RF_WEAPONMODEL) ? WEAPON_SHELL_SCALE: POWERSUIT_SCALE; else shellscale = 0.0; VectorSet ( tempVertexArray[meshnum][i], move[0] + ov->point[0]*oldScale[0] + v->point[0]*curScale[0] + tempNormalsArray[i][0]*shellscale, move[1] + ov->point[1]*oldScale[1] + v->point[1]*curScale[1] + tempNormalsArray[i][1]*shellscale, move[2] + ov->point[2]*oldScale[2] + v->point[2]*curScale[2] + tempNormalsArray[i][2]*shellscale ); // calc lighting and alpha if (shellModel) VectorCopy(meshlight, lightcolor); else R_LightAliasModel(meshlight, tempNormalsArray[i], lightcolor, v->lightnormalindex, !skinParms.nodiffuse); //thisalpha = R_CalcEntAlpha(meshalpha, tempVertexArray[meshnum][i]); thisalpha = meshalpha; // get tex coords if (shellModel && FlowingShell()) { tempSkinCoord[0] = (tempVertexArray[meshnum][i][0] + tempVertexArray[meshnum][i][1]) / 40.0 + shellFlowH; tempSkinCoord[1] = tempVertexArray[meshnum][i][2] / 40.0 + shellFlowV; } else { tempSkinCoord[0] = mesh.stcoords[i].st[0]; tempSkinCoord[1] = mesh.stcoords[i].st[1]; } // add to arrays VA_SetElem2(texCoordArray[0][rb_vertex], tempSkinCoord[0], tempSkinCoord[1]); VA_SetElem3(vertexArray[rb_vertex], tempVertexArray[meshnum][i][0], tempVertexArray[meshnum][i][1], tempVertexArray[meshnum][i][2]); VA_SetElem4(colorArray[rb_vertex], lightcolor[0], lightcolor[1], lightcolor[2], thisalpha); rb_vertex++; } if (!shellModel) RB_ModifyTextureCoords (&texCoordArray[0][0][0], &vertexArray[0][0], rb_vertex, skinParms); // set indices for each triangle and draw rb_index = 0; for (j=0; j < mesh.num_tris; j++) { indexArray[rb_index++] = mesh.indexes[3*j+0]; indexArray[rb_index++] = mesh.indexes[3*j+1]; indexArray[rb_index++] = mesh.indexes[3*j+2]; } RB_DrawArrays (GL_TRIANGLES); // glow pass if (mesh.skins[e->skinnum].glowimage && !shellModel) { float glowcolor; if (skinParms.glow.type > -1) glowcolor = RB_CalcGlowColor (skinParms); else glowcolor = 1.0; qglDisableClientState (GL_COLOR_ARRAY); qglColor4f(glowcolor, glowcolor, glowcolor, 1.0); GL_Enable (GL_BLEND); GL_BlendFunc (GL_ONE, GL_ONE); GL_Bind(mesh.skins[e->skinnum].glowimage->texnum); RB_DrawArrays (GL_TRIANGLES); qglEnableClientState (GL_COLOR_ARRAY); qglColor4f(1.0, 1.0, 1.0, 1.0); } // envmap pass if (skinParms.envmap > 0.0f && !shellModel) { GL_Enable (GL_BLEND); GL_BlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); qglTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); qglTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); // apply alpha to array for (i=0; i<mesh.num_verts; i++) //colorArray[i][3] = R_CalcEntAlpha(meshalpha*skinParms.envmap, tempVertexArray[meshnum][i]); colorArray[i][3] = meshalpha*skinParms.envmap; GL_Bind(r_envmappic->texnum); qglEnable(GL_TEXTURE_GEN_S); qglEnable(GL_TEXTURE_GEN_T); RB_DrawArrays (GL_TRIANGLES); qglDisable(GL_TEXTURE_GEN_S); qglDisable(GL_TEXTURE_GEN_T); } RB_DrawMeshTris (GL_TRIANGLES, 1); // md3 skin scripting if (skinParms.twosided) GL_Enable(GL_CULL_FACE); if (skinParms.alphatest && !shellModel) GL_Disable(GL_ALPHA_TEST); GL_Disable (GL_BLEND); // md3 skin scripting } // end new outer loop R_SetShellBlend (false); R_SetVertexOverbrights(false); }
/* =============== CG_CalcViewValues Sets cg.refdef view values =============== */ static int CG_CalcViewValues( void ) { playerState_t *ps; memset( &cg.refdef, 0, sizeof( cg.refdef ) ); // calculate size of 3D view CG_CalcVrect( ); ps = &cg.predictedPlayerState; // intermission view if( ps->pm_type == PM_INTERMISSION ) { VectorCopy( ps->origin, cg.refdef.vieworg ); VectorCopy( ps->viewangles, cg.refdefViewAngles ); AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); return CG_CalcFov( ); } cg.bobcycle = ( ps->bobCycle & 128 ) >> 7; cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) ); cg.xyspeed = sqrt( ps->velocity[ 0 ] * ps->velocity[ 0 ] + ps->velocity[ 1 ] * ps->velocity[ 1 ] ); VectorCopy( ps->origin, cg.refdef.vieworg ); if( BG_ClassHasAbility( ps->stats[ STAT_PCLASS ], SCA_WALLCLIMBER ) ) CG_smoothWWTransitions( ps, ps->viewangles, cg.refdefViewAngles ); else if( BG_ClassHasAbility( ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) ) CG_smoothWJTransitions( ps, ps->viewangles, cg.refdefViewAngles ); else VectorCopy( ps->viewangles, cg.refdefViewAngles ); //clumsy logic, but it needs to be this way round because the CS propogation //delay screws things up otherwise if( !BG_ClassHasAbility( ps->stats[ STAT_PCLASS ], SCA_WALLJUMPER ) ) { if( !( ps->stats[ STAT_STATE ] & SS_WALLCLIMBING ) ) VectorSet( cg.lastNormal, 0.0f, 0.0f, 1.0f ); } // add error decay if( cg_errorDecay.value > 0 ) { int t; float f; t = cg.time - cg.predictedErrorTime; f = ( cg_errorDecay.value - t ) / cg_errorDecay.value; if( f > 0 && f < 1 ) VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg ); else cg.predictedErrorTime = 0; } //shut off the poison cloud effect if it's still on the go if( cg.snap->ps.stats[ STAT_HEALTH ] <= 0 ) { if( CG_IsParticleSystemValid( &cg.poisonCloudPS ) ) CG_DestroyParticleSystem( &cg.poisonCloudPS ); } if( cg.renderingThirdPerson ) { // back away from character CG_OffsetThirdPersonView( ); } else { // offset for local bobbing and kicks CG_OffsetFirstPersonView( ); } // position eye reletive to origin AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); if( cg.hyperspace ) cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE; //draw the surface normal looking at if( cg_drawSurfNormal.integer ) CG_DrawSurfNormal( ); // field of view return CG_CalcFov( ); }
/* ================== CM_Trace ================== */ void CM_Trace( trace_t *trace, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, clipHandle_t model, const vec3_t origin, int brushmask, int capsule, sphere_t *sphere ) { int i; traceWork_t tw; vec3_t offset; cmodel_t *cmod; clipMap_t *local = 0; cmod = CM_ClipHandleToModel( model, &local ); local->checkcount++; // for multi-check avoidance c_traces++; // for statistics, may be zeroed // fill in a default trace Com_Memset( &tw, 0, sizeof(tw) ); memset(trace, 0, sizeof(*trace)); trace->fraction = 1; // assume it goes the entire distance until shown otherwise VectorCopy(origin, tw.modelOrigin); if (!local->numNodes) { return; // map not loaded, shouldn't happen } // allow NULL to be passed in for 0,0,0 if ( !mins ) { mins = vec3_origin; } if ( !maxs ) { maxs = vec3_origin; } // set basic parms tw.contents = brushmask; // adjust so that mins and maxs are always symetric, which // avoids some complications with plane expanding of rotated // bmodels for ( i = 0 ; i < 3 ; i++ ) { offset[i] = ( mins[i] + maxs[i] ) * 0.5; tw.size[0][i] = mins[i] - offset[i]; tw.size[1][i] = maxs[i] - offset[i]; tw.start[i] = start[i] + offset[i]; tw.end[i] = end[i] + offset[i]; } // if a sphere is already specified if ( sphere ) { tw.sphere = *sphere; } else { tw.sphere.use = (qboolean)capsule; tw.sphere.radius = ( tw.size[1][0] > tw.size[1][2] ) ? tw.size[1][2]: tw.size[1][0]; tw.sphere.halfheight = tw.size[1][2]; VectorSet( tw.sphere.offset, 0, 0, tw.size[1][2] - tw.sphere.radius ); } tw.maxOffset = tw.size[1][0] + tw.size[1][1] + tw.size[1][2]; // tw.offsets[signbits] = vector to appropriately corner from origin tw.offsets[0][0] = tw.size[0][0]; tw.offsets[0][1] = tw.size[0][1]; tw.offsets[0][2] = tw.size[0][2]; tw.offsets[1][0] = tw.size[1][0]; tw.offsets[1][1] = tw.size[0][1]; tw.offsets[1][2] = tw.size[0][2]; tw.offsets[2][0] = tw.size[0][0]; tw.offsets[2][1] = tw.size[1][1]; tw.offsets[2][2] = tw.size[0][2]; tw.offsets[3][0] = tw.size[1][0]; tw.offsets[3][1] = tw.size[1][1]; tw.offsets[3][2] = tw.size[0][2]; tw.offsets[4][0] = tw.size[0][0]; tw.offsets[4][1] = tw.size[0][1]; tw.offsets[4][2] = tw.size[1][2]; tw.offsets[5][0] = tw.size[1][0]; tw.offsets[5][1] = tw.size[0][1]; tw.offsets[5][2] = tw.size[1][2]; tw.offsets[6][0] = tw.size[0][0]; tw.offsets[6][1] = tw.size[1][1]; tw.offsets[6][2] = tw.size[1][2]; tw.offsets[7][0] = tw.size[1][0]; tw.offsets[7][1] = tw.size[1][1]; tw.offsets[7][2] = tw.size[1][2]; // // calculate bounds // if ( tw.sphere.use ) { for ( i = 0 ; i < 3 ; i++ ) { if ( tw.start[i] < tw.end[i] ) { tw.bounds[0][i] = tw.start[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius; tw.bounds[1][i] = tw.end[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius; } else { tw.bounds[0][i] = tw.end[i] - fabs(tw.sphere.offset[i]) - tw.sphere.radius; tw.bounds[1][i] = tw.start[i] + fabs(tw.sphere.offset[i]) + tw.sphere.radius; } } } else { for ( i = 0 ; i < 3 ; i++ ) { if ( tw.start[i] < tw.end[i] ) { tw.bounds[0][i] = tw.start[i] + tw.size[0][i]; tw.bounds[1][i] = tw.end[i] + tw.size[1][i]; } else { tw.bounds[0][i] = tw.end[i] + tw.size[0][i]; tw.bounds[1][i] = tw.start[i] + tw.size[1][i]; } } } // // check for position test special case // if (start[0] == end[0] && start[1] == end[1] && start[2] == end[2] && tw.size[0][0] == 0 && tw.size[0][1] == 0 && tw.size[0][2] == 0) { if ( model && cmod->firstNode == -1) { #ifdef ALWAYS_BBOX_VS_BBOX // bk010201 - FIXME - compile time flag? if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) { tw.sphere.use = qfalse; CM_TestInLeaf( &tw, &cmod->leaf ); } else #elif defined(ALWAYS_CAPSULE_VS_CAPSULE) if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) { CM_TestCapsuleInCapsule( &tw, model ); } else #endif if ( model == CAPSULE_MODEL_HANDLE ) { if ( tw.sphere.use ) { CM_TestCapsuleInCapsule( &tw, *trace, model ); } else { CM_TestBoundingBoxInCapsule( &tw, *trace, model ); } } else { CM_TestInLeaf( &tw, *trace, &cmod->leaf, local ); } } else if (cmod->firstNode == -1) { CM_PositionTest( &tw, *trace ); } else { CM_TraceThroughTree( &tw, *trace, local, cmod->firstNode, 0, 1, tw.start, tw.end ); } } else { // // check for point special case // if ( tw.size[0][0] == 0 && tw.size[0][1] == 0 && tw.size[0][2] == 0 ) { tw.isPoint = qtrue; VectorClear( tw.extents ); } else { tw.isPoint = qfalse; tw.extents[0] = tw.size[1][0]; tw.extents[1] = tw.size[1][1]; tw.extents[2] = tw.size[1][2]; } // // general sweeping through world // if ( model && cmod->firstNode == -1) { #ifdef ALWAYS_BBOX_VS_BBOX if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) { tw.sphere.use = qfalse; CM_TraceThroughLeaf( &tw, &cmod->leaf ); } else #elif defined(ALWAYS_CAPSULE_VS_CAPSULE) if ( model == BOX_MODEL_HANDLE || model == CAPSULE_MODEL_HANDLE) { CM_TraceCapsuleThroughCapsule( &tw, model ); } else #endif if ( model == CAPSULE_MODEL_HANDLE ) { if ( tw.sphere.use ) { CM_TraceCapsuleThroughCapsule( &tw, *trace, model ); } else { CM_TraceBoundingBoxThroughCapsule( &tw, *trace, model ); } } else { CM_TraceThroughLeaf( &tw, *trace, local, &cmod->leaf ); } } else { CM_TraceThroughTree( &tw, *trace, local, cmod->firstNode, 0, 1, tw.start, tw.end ); } } // generate endpos from the original, unmodified start/end if ( trace->fraction == 1 ) { VectorCopy (end, trace->endpos); } else { for ( i=0 ; i<3 ; i++ ) { trace->endpos[i] = start[i] + trace->fraction * (end[i] - start[i]); } } // If allsolid is set (was entirely inside something solid), the plane is not valid. // If fraction == 1.0, we never hit anything, and thus the plane is not valid. // Otherwise, the normal on the plane should have unit length assert(trace->allsolid || trace->fraction == 1.0 || VectorLengthSquared(trace->plane.normal) > 0.9999); }
/* ================== CM_TransformedBoxTrace Handles offseting and rotation of the end points for moving and rotating entities ================== */ void CM_TransformedBoxTrace( trace_t *trace, const vec3_t start, const vec3_t end, const vec3_t mins, const vec3_t maxs, clipHandle_t model, int brushmask, const vec3_t origin, const vec3_t angles, int capsule ) { vec3_t start_l, end_l; qboolean rotated; vec3_t offset; vec3_t symetricSize[2]; matrix3_t matrix, transpose; int i; float halfwidth; float halfheight; float t; sphere_t sphere; if ( !mins ) { mins = vec3_origin; } if ( !maxs ) { maxs = vec3_origin; } // adjust so that mins and maxs are always symetric, which // avoids some complications with plane expanding of rotated // bmodels for ( i = 0 ; i < 3 ; i++ ) { offset[i] = ( mins[i] + maxs[i] ) * 0.5; symetricSize[0][i] = mins[i] - offset[i]; symetricSize[1][i] = maxs[i] - offset[i]; start_l[i] = start[i] + offset[i]; end_l[i] = end[i] + offset[i]; } // subtract origin offset VectorSubtract( start_l, origin, start_l ); VectorSubtract( end_l, origin, end_l ); // rotate start and end into the models frame of reference if ( model != BOX_MODEL_HANDLE && (angles[0] || angles[1] || angles[2]) ) { rotated = qtrue; } else { rotated = qfalse; } halfwidth = symetricSize[ 1 ][ 0 ]; halfheight = symetricSize[ 1 ][ 2 ]; sphere.use = (qboolean)capsule; sphere.radius = ( halfwidth > halfheight ) ? halfheight : halfwidth; sphere.halfheight = halfheight; t = halfheight - sphere.radius; if (rotated) { // rotation on trace line (start-end) instead of rotating the bmodel // NOTE: This is still incorrect for bounding boxes because the actual bounding // box that is swept through the model is not rotated. We cannot rotate // the bounding box or the bmodel because that would make all the brush // bevels invalid. // However this is correct for capsules since a capsule itself is rotated too. CreateRotationMatrix(angles, matrix); RotatePoint(start_l, matrix); RotatePoint(end_l, matrix); // rotated sphere offset for capsule sphere.offset[0] = matrix[0][ 2 ] * t; sphere.offset[1] = -matrix[1][ 2 ] * t; sphere.offset[2] = matrix[2][ 2 ] * t; } else { VectorSet( sphere.offset, 0, 0, t ); } // sweep the box through the model CM_Trace( trace, start_l, end_l, symetricSize[0], symetricSize[1], model, origin, brushmask, capsule, &sphere ); // if the bmodel was rotated and there was a collision if ( rotated && trace->fraction != 1.0 ) { // rotation of bmodel collision plane TransposeMatrix(matrix, transpose); RotatePoint(trace->plane.normal, transpose); } // re-calculate the end position of the trace because the trace.endpos // calculated by CM_Trace could be rotated and have an offset trace->endpos[0] = start[0] + trace->fraction * (end[0] - start[0]); trace->endpos[1] = start[1] + trace->fraction * (end[1] - start[1]); trace->endpos[2] = start[2] + trace->fraction * (end[2] - start[2]); }
/* ================= P_FallingDamage ================= */ void P_FallingDamage(edict_t *ent) { float delta; int damage; vec3_t dir; if (ent->s.modelindex != 255) return; // not in the player model if (ent->movetype == MOVETYPE_NOCLIP) return; if ((ent->client->oldvelocity[2] < 0) && (ent->velocity[2] > ent->client->oldvelocity[2]) && (!ent->groundentity)) { delta = ent->client->oldvelocity[2]; } else { if (!ent->groundentity) return; delta = ent->velocity[2] - ent->client->oldvelocity[2]; } delta = delta * delta * 0.0001f; // never take falling damage if completely underwater if (ent->waterlevel == 3) return; if (ent->waterlevel == 2) delta *= 0.25f; if (ent->waterlevel == 1) delta *= 0.5f; if (delta < 1) return; if (delta < 15) { ent->s.event = EV_FOOTSTEP; return; } ent->client->fall_value = delta * 0.5f; if (ent->client->fall_value > 40) ent->client->fall_value = 40; ent->client->fall_time = level.time + FALL_TIME; if (delta > 30) { if (ent->health > 0) { if (delta >= 55) ent->s.event = EV_FALLFAR; else ent->s.event = EV_FALL; } ent->pain_debounce_time = level.time; // no normal pain sound damage = (delta - 30) / 2; if (damage < 1) damage = 1; VectorSet(dir, 0, 0, 1); if (!deathmatch->value || !((int)dmflags->value & DF_NO_FALLING)) T_Damage(ent, world, world, dir, ent->s.origin, vec3_origin, damage, 0, 0, MOD_FALLING); } else { ent->s.event = EV_FALLSHORT; return; } }
void SP_monster_soldier_x (edict_t *self) { // Lazarus: special purpose skins if ( self->style ) PatchMonsterModel("models/monsters/soldier/tris.md2"); self->s.modelindex = gi.modelindex ("models/monsters/soldier/tris.md2"); self->monsterinfo.scale = MODEL_SCALE; VectorSet (self->mins, -16, -16, -24); VectorSet (self->maxs, 16, 16, 32); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; sound_idle = gi.soundindex ("soldier/solidle1.wav"); sound_sight1 = gi.soundindex ("soldier/solsght1.wav"); sound_sight2 = gi.soundindex ("soldier/solsrch1.wav"); sound_cock = gi.soundindex ("infantry/infatck3.wav"); if(!self->mass) self->mass = 100; self->pain = soldier_pain; self->die = soldier_die; self->monsterinfo.stand = soldier_stand; self->monsterinfo.walk = soldier_walk; self->monsterinfo.run = soldier_run; self->monsterinfo.dodge = soldier_dodge; self->monsterinfo.attack = soldier_attack; self->monsterinfo.melee = NULL; self->monsterinfo.sight = soldier_sight; if(monsterjump->value) { self->monsterinfo.jump = soldier_jump; self->monsterinfo.jumpup = 48; self->monsterinfo.jumpdn = 160; } // DWH if(self->powerarmor) { self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD; self->monsterinfo.power_armor_power = self->powerarmor; } // end DWH gi.linkentity (self); if(!self->monsterinfo.flies) self->monsterinfo.flies = 0.40; if(self->health < 0) { mmove_t *deathmoves[] = {&soldier_move_death1, &soldier_move_death2, &soldier_move_death3, &soldier_move_death4, &soldier_move_death5, &soldier_move_death6, NULL}; M_SetDeath(self,(mmove_t **)&deathmoves); } walkmonster_start (self); }
/* ==================== RE_GetViewFog ==================== */ void RE_GetViewFog( const vec3_t origin, fogType_t *type, vec3_t color, float *depthForOpaque, float *density, qboolean inwater ) { fogType_t fogType; vec3_t fogColor; float fogDepthForOpaque; float fogDensity; if ( inwater ) { fogType = tr.waterFogParms.fogType; VectorCopy( tr.waterFogParms.color, fogColor ); fogDepthForOpaque = tr.waterFogParms.depthForOpaque; fogDensity = tr.waterFogParms.density; } else { fogType = FT_NONE; VectorSet( fogColor, 0, 0, 0 ); fogDepthForOpaque = 0; fogDensity = 0; } if ( tr.world ) { int bmodelNum; int surfaceNum; const bmodel_t *bmodel; const msurface_t *surface; for ( bmodelNum = 0, bmodel = tr.world->bmodels; bmodelNum < tr.world->numBModels; bmodelNum++, bmodel++ ) { if ( !R_PointInBrush( origin, bmodel ) ) continue; for ( surfaceNum = 0, surface = bmodel->firstSurface; surfaceNum < bmodel->numSurfaces; surfaceNum++, surface++ ) { if ( !surface->shader ) { continue; } if ( surface->shader->viewFogParms.fogType != FT_NONE || surface->shader->viewFogParms.color[0] || surface->shader->viewFogParms.color[1] || surface->shader->viewFogParms.color[2] ) { fogType = surface->shader->viewFogParms.fogType; VectorCopy( surface->shader->viewFogParms.color, fogColor ); fogDepthForOpaque = surface->shader->viewFogParms.depthForOpaque; fogDensity = surface->shader->viewFogParms.density; break; } } if ( surfaceNum != bmodel->numSurfaces ) { break; } } } if (type) { *type = fogType; } if (color) { VectorCopy( fogColor, color ); } if (depthForOpaque) { *depthForOpaque = fogDepthForOpaque; } if (density) { *density = fogDensity; } }
AABB::AABB (const Line &line) { VectorSet(mins, std::min(line.start[0], line.stop[0]), std::min(line.start[1], line.stop[1]), std::min(line.start[2], line.stop[2])); VectorSet(maxs, std::max(line.start[0], line.stop[0]), std::max(line.start[1], line.stop[1]), std::max(line.start[2], line.stop[2])); }
/** * @brief Called before loading. Used to set default attribute values */ static void UI_ModelNodeLoading (uiNode_t *node) { Vector4Set(node->color, 1, 1, 1, 1); VectorSet(EXTRADATA(node).scale, 1, 1, 1); EXTRADATA(node).clipOverflow = qtrue; }
void DrawTerrain( terrainMesh_t *pm, bool bPoints, bool bShade ) { int i; int w; int h; int x; int y; //int n; //float x1; //float y1; float scale_x; float scale_y; //vec3_t pSelectedPoints[ MAX_TERRA_POINTS ]; //int nIndex; terravert_t a0; terravert_t a1; terravert_t a2; terravert_t b0; terravert_t b1; terravert_t b2; terrainVert_t *vert; qtexture_t *texture; h = pm->height - 1; w = pm->width - 1; scale_x = pm->scale_x; scale_y = pm->scale_y; qglShadeModel (GL_SMOOTH); if ( bShade ) { for( i = 0; i < pm->numtextures; i++ ) { texture = pm->textures[ i ]; qglBindTexture( GL_TEXTURE_2D, texture->texture_number ); vert = pm->heightmap; for( y = 0; y < h; y++ ) { qglBegin( GL_TRIANGLES ); for( x = 0; x < w; x++, vert++ ) { Terrain_GetTriangles( pm, x, y, &a0, &a1, &a2, &b0, &b1, &b2, texture ); // first tri if ( a0.rgba[ 3 ] || a1.rgba[ 3 ] || a2.rgba[ 3 ] ) { qglColor4fv( a0.rgba ); qglTexCoord2fv( a0.tc ); qglVertex3fv( a0.xyz ); qglColor4fv( a1.rgba ); qglTexCoord2fv( a1.tc ); qglVertex3fv( a1.xyz ); qglColor4fv( a2.rgba ); qglTexCoord2fv( a2.tc ); qglVertex3fv( a2.xyz ); } // second tri if ( b0.rgba[ 3 ] || b1.rgba[ 3 ] || b2.rgba[ 3 ] ) { qglColor4fv( b0.rgba ); qglTexCoord2fv( b0.tc ); qglVertex3fv( b0.xyz ); qglColor4fv( b1.rgba ); qglTexCoord2fv( b1.tc ); qglVertex3fv( b1.xyz ); qglColor4fv( b2.rgba ); qglTexCoord2fv( b2.tc ); qglVertex3fv( b2.xyz ); } } qglEnd (); } } } else { for( i = 0; i < pm->numtextures; i++ ) { texture = pm->textures[ i ]; qglBindTexture( GL_TEXTURE_2D, texture->texture_number ); vert = pm->heightmap; for( y = 0; y < h; y++ ) { qglBegin( GL_TRIANGLES ); for( x = 0; x < w; x++, vert++ ) { Terrain_GetTriangles( pm, x, y, &a0, &a1, &a2, &b0, &b1, &b2, texture ); // first tri if ( a0.rgba[ 3 ] || a1.rgba[ 3 ] || a2.rgba[ 3 ] ) { qglColor4fv( a0.rgba ); qglTexCoord2fv( a0.tc ); qglVertex3fv( a0.xyz ); qglColor4fv( a1.rgba ); qglTexCoord2fv( a1.tc ); qglVertex3fv( a1.xyz ); qglColor4fv( a2.rgba ); qglTexCoord2fv( a2.tc ); qglVertex3fv( a2.xyz ); } // second tri if ( b0.rgba[ 3 ] || b1.rgba[ 3 ] || b2.rgba[ 3 ] ) { qglColor4fv( b0.rgba ); qglTexCoord2fv( b0.tc ); qglVertex3fv( b0.xyz ); qglColor4fv( b1.rgba ); qglTexCoord2fv( b1.tc ); qglVertex3fv( b1.xyz ); qglColor4fv( b2.rgba ); qglTexCoord2fv( b2.tc ); qglVertex3fv( b2.xyz ); } } qglEnd (); } } } qglPushAttrib( GL_CURRENT_BIT ); bool bDisabledLighting = qglIsEnabled( GL_LIGHTING ); if ( bDisabledLighting ) { qglDisable( GL_LIGHTING ); } #if 0 terrainVert_t *currentrow; terrainVert_t *nextrow; float x2; float y2; // Draw normals qglDisable( GL_TEXTURE_2D ); qglDisable( GL_BLEND ); qglColor3f( 1, 1, 1 ); qglBegin( GL_LINES ); y2 = pm->origin[ 1 ]; nextrow = pm->heightmap; for( y = 0; y < h; y++ ) { y1 = y2; y2 += scale_y; x2 = pm->origin[ 0 ]; currentrow = nextrow; nextrow = currentrow + pm->width; for( x = 0; x < w; x++ ) { x1 = x2; x2 += scale_x; // normals qglVertex3f( x1, y1, pm->origin[ 2 ] + currentrow[ x ].height ); qglVertex3f( x1 + currentrow[ x ].normal[ 0 ] * 16.0f, y1 + currentrow[ x ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + currentrow[ x ].height + currentrow[ x ].normal[ 2 ] * 16.0f ); qglVertex3f( x2, y1, pm->origin[ 2 ] + currentrow[ x + 1 ].height ); qglVertex3f( x2 + currentrow[ x + 1 ].normal[ 0 ] * 16.0f, y1 + currentrow[ x + 1 ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + currentrow[ x + 1 ].height + currentrow[ x + 1 ].normal[ 2 ] * 16.0f ); qglVertex3f( x1, y2, pm->origin[ 2 ] + nextrow[ x ].height ); qglVertex3f( x1 + nextrow[ x ].normal[ 0 ] * 16.0f, y2 + nextrow[ x ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + nextrow[ x ].height + nextrow[ x ].normal[ 2 ] * 16.0f ); qglVertex3f( x2, y2, pm->origin[ 2 ] + nextrow[ x + 1 ].height ); qglVertex3f( x2 + nextrow[ x + 1 ].normal[ 0 ] * 16.0f, y2 + nextrow[ x + 1 ].normal[ 1 ] * 16.0f, pm->origin[ 2 ] + nextrow[ x + 1 ].height + nextrow[ x + 1 ].normal[ 2 ] * 16.0f ); } } qglEnd (); qglEnable( GL_TEXTURE_2D ); #endif #if 0 if ( bPoints && ( g_qeglobals.d_select_mode == sel_terrainpoint || g_qeglobals.d_select_mode == sel_area ) ) { qglPointSize( 6 ); qglDisable( GL_TEXTURE_2D ); qglDisable( GL_BLEND ); qglBegin( GL_POINTS ); nIndex = 0; qglColor4f( 1, 0, 1, 1 ); y1 = pm->origin[ 1 ]; for ( y = 0; y < pm->height; y++, y1 += pm->scale_y ) { x1 = pm->origin[ 0 ]; for( x = 0; x < pm->width; x++, x1 += pm->scale_x ) { // FIXME: need to not do loop lookups inside here n = Terrain_PointInMoveList( &pm->heightmap[ x + y * pm->width ] ); if ( n >= 0 ) { VectorSet( pSelectedPoints[ nIndex ], x1, y1, pm->heightmap[ x + y * pm->width ].height + pm->origin[ 2 ] ); nIndex++; } else { qglVertex3f( x1, y1, pm->origin[ 2 ] + pm->heightmap[ x + y * pm->width ].height ); } } } qglEnd(); qglEnable( GL_TEXTURE_2D ); if ( nIndex > 0 ) { qglBegin( GL_POINTS ); qglColor4f( 0, 0, 1, 1 ); while( nIndex-- > 0 ) { qglVertex3fv( pSelectedPoints[ nIndex ] ); } qglEnd(); } } #endif if ( g_qeglobals.d_numterrapoints && ( ( g_qeglobals.d_select_mode == sel_terrainpoint ) || ( g_qeglobals.d_select_mode == sel_terraintexture ) ) ) { #if 0 qglPointSize( 6 ); qglDisable( GL_TEXTURE_2D ); qglDisable( GL_BLEND ); qglBegin( GL_POINTS ); qglColor4f( 1, 0, 1, 1 ); for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) { qglVertex3fv( g_qeglobals.d_terrapoints[ i ]->xyz ); } qglEnd(); qglEnable( GL_TEXTURE_2D ); #endif brush_t *pb; terrainMesh_t *pm; pm = NULL; for( pb = active_brushes .next; pb != &active_brushes; pb = pb->next ) { if ( pb->terrainBrush ) { pm = pb->pTerrain; break; } } if ( pm ) { qglDisable( GL_TEXTURE_2D ); qglBegin( GL_TRIANGLES ); qglEnable( GL_BLEND ); qglColor4f( 0.25, 0.5, 1, 0.35 ); for( i = 0; i < g_qeglobals.d_numterrapoints; i++ ) { terravert_t a0; terravert_t a1; terravert_t a2; qglColor4f( 0.25, 0.5, 1, g_qeglobals.d_terrapoints[ i ]->scale * 0.75 + 0.25 ); Terrain_GetTriangle( pm, g_qeglobals.d_terrapoints[ i ]->tri.index * 2, &a0, &a1, &a2 ); qglVertex3fv( a0.xyz ); qglVertex3fv( a1.xyz ); qglVertex3fv( a2.xyz ); Terrain_GetTriangle( pm, g_qeglobals.d_terrapoints[ i ]->tri.index * 2 + 1, &a0, &a1, &a2 ); qglVertex3fv( a0.xyz ); qglVertex3fv( a1.xyz ); qglVertex3fv( a2.xyz ); } qglEnd(); qglDisable( GL_BLEND ); qglEnable( GL_TEXTURE_2D ); } } }
/* ================ CM_TraceThroughVerticalCylinder get the first intersection of the ray with the cylinder the cylinder extends halfheight above and below the origin ================ */ void CM_TraceThroughVerticalCylinder( traceWork_t *tw, trace_t &trace, vec3_t origin, float radius, float halfheight, vec3_t start, vec3_t end) { float length, scale, fraction, l1, l2; float /*a, */b, c, d, sqrtd; vec3_t v1, dir, start2d, end2d, org2d, intersection; // 2d coordinates VectorSet(start2d, start[0], start[1], 0); VectorSet(end2d, end[0], end[1], 0); VectorSet(org2d, origin[0], origin[1], 0); // if between lower and upper cylinder bounds if (start[2] <= origin[2] + halfheight && start[2] >= origin[2] - halfheight) { // if inside the cylinder VectorSubtract(start2d, org2d, dir); l1 = VectorLengthSquared(dir); if (l1 < Square(radius)) { trace.fraction = 0; trace.startsolid = qtrue; VectorSubtract(end2d, org2d, dir); l1 = VectorLengthSquared(dir); if (l1 < Square(radius)) { trace.allsolid = qtrue; } return; } } // VectorSubtract(end2d, start2d, dir); length = VectorNormalize(dir); // l1 = CM_DistanceFromLineSquared(org2d, start2d, end2d, dir); VectorSubtract(end2d, org2d, v1); l2 = VectorLengthSquared(v1); // if no intersection with the cylinder and the end point is at least an epsilon away if (l1 >= Square(radius) && l2 > Square(radius+SURFACE_CLIP_EPSILON)) { return; } // // // (start[0] - origin[0] - t * dir[0]) ^ 2 + (start[1] - origin[1] - t * dir[1]) ^ 2 = radius ^ 2 // (v1[0] + t * dir[0]) ^ 2 + (v1[1] + t * dir[1]) ^ 2 = radius ^ 2; // v1[0] ^ 2 + 2 * v1[0] * t * dir[0] + (t * dir[0]) ^ 2 + // v1[1] ^ 2 + 2 * v1[1] * t * dir[1] + (t * dir[1]) ^ 2 = radius ^ 2 // t ^ 2 * (dir[0] ^ 2 + dir[1] ^ 2) + t * (2 * v1[0] * dir[0] + 2 * v1[1] * dir[1]) + // v1[0] ^ 2 + v1[1] ^ 2 - radius ^ 2 = 0 // VectorSubtract(start, origin, v1); // dir is normalized so we can use a = 1 //a = 1.0f;// * (dir[0] * dir[0] + dir[1] * dir[1]); b = 2.0f * (v1[0] * dir[0] + v1[1] * dir[1]); c = v1[0] * v1[0] + v1[1] * v1[1] - (radius+RADIUS_EPSILON) * (radius+RADIUS_EPSILON); d = b * b - 4.0f * c;// * a; if (d > 0) { sqrtd = sqrtf(d); // = (- b + sqrtd) * 0.5f;// / (2.0f * a); fraction = (- b - sqrtd) * 0.5f;// / (2.0f * a); // if (fraction < 0) { fraction = 0; } else { fraction /= length; } if ( fraction < trace.fraction ) { VectorSubtract(end, start, dir); VectorMA(start, fraction, dir, intersection); // if the intersection is between the cylinder lower and upper bound if (intersection[2] <= origin[2] + halfheight && intersection[2] >= origin[2] - halfheight) { // trace.fraction = fraction; VectorSubtract(intersection, origin, dir); dir[2] = 0; #ifdef CAPSULE_DEBUG l2 = VectorLength(dir); if (l2 <= radius) { int bah = 1; } #endif scale = 1 / (radius+RADIUS_EPSILON); VectorScale(dir, scale, dir); VectorCopy(dir, trace.plane.normal); VectorAdd( tw->modelOrigin, intersection, intersection); trace.plane.dist = DotProduct(trace.plane.normal, intersection); trace.contents = CONTENTS_BODY; } } } else if (d == 0) { //t[0] = (- b ) / 2 * a; // slide along the cylinder } // no intersection at all }
/* ============= R_DrawAliasVolumeShadow based on code from BeefQuake R6 ============= */ void R_DrawAliasVolumeShadow (maliasmodel_t *paliashdr, vec3_t bbox[8]) { vec3_t light, temp, vecAdd; float dist, highest, lowest, projected_distance; float angle, cosp, sinp, cosy, siny, cosr, sinr, ix, iy, iz; int i, lnum; dlight_t *dl; dl = r_newrefdef.dlights; VectorSet(vecAdd, 680,0,1024); // set base vector, was 576,0,1024 // compute average light vector from dlights for (i=0, lnum=0; i<r_newrefdef.num_dlights; i++, dl++) { if (VectorCompare(dl->origin, currententity->origin)) continue; VectorSubtract(dl->origin, currententity->origin, temp); dist = dl->intensity - VectorLength(temp); if (dist <= 0) continue; lnum++; // Factor in the intensity of a dlight VectorScale (temp, dist*0.25, temp); VectorAdd (vecAdd, temp, vecAdd); } VectorNormalize(vecAdd); VectorScale(vecAdd, 1024, vecAdd); // get projection distance from lightspot height highest = lowest = bbox[0][2]; for (i=0; i<8; i++) { if (bbox[i][2] > highest) highest = bbox[i][2]; if (bbox[i][2] < lowest) lowest = bbox[i][2]; } projected_distance = (fabs(highest - lightspot[2]) + (highest-lowest)) / vecAdd[2]; VectorCopy(vecAdd, light); /*cosy = cos(-currententity->angles[YAW] / 180 * M_PI); siny = sin(-currententity->angles[YAW] / 180 * M_PI); ix = light[0], iy = light[1]; light[0] = (cosy * (ix - 0) + siny * (0 - iy) + 0); light[1] = (cosy * (iy - 0) + siny * (ix - 0) + 0); light[2] += 8;*/ // reverse-rotate light vector based on angles angle = -currententity->angles[PITCH] / 180 * M_PI; cosp = cos(angle), sinp = sin(angle); angle = -currententity->angles[YAW] / 180 * M_PI; cosy = cos(angle), siny = sin(angle); angle = currententity->angles[ROLL] / 180 * M_PI; // roll is backwards cosr = cos(angle), sinr = sin(angle); // rotate for yaw (z axis) ix = light[0], iy = light[1]; light[0] = cosy * ix - siny * iy + 0; light[1] = siny * ix + cosy * iy + 0; // rotate for pitch (y axis) ix = light[0], iz = light[2]; light[0] = cosp * ix + 0 + sinp * iz; light[2] = -sinp * ix + 0 + cosp * iz; // rotate for roll (x axis) iy = light[1], iz = light[2]; light[1] = 0 + cosr * iy - sinr * iz; light[2] = 0 + sinr * iy + cosr * iz; // set up stenciling if (!r_shadowvolumes->value) { qglPushAttrib(GL_STENCIL_BUFFER_BIT); // save stencil buffer qglClear(GL_STENCIL_BUFFER_BIT); qglColorMask(0,0,0,0); GL_DepthMask(0); GL_DepthFunc(GL_LESS); GL_Enable(GL_STENCIL_TEST); qglStencilFunc(GL_ALWAYS, 0, 255); // qglStencilOp (GL_KEEP, GL_KEEP, GL_KEEP); // qglStencilMask (255); } // build shadow volumes and render each to stencil buffer for (i=0; i<paliashdr->num_meshes; i++) { if (paliashdr->meshes[i].skins[currententity->skinnum].renderparms.nodraw || paliashdr->meshes[i].skins[currententity->skinnum].renderparms.alphatest || paliashdr->meshes[i].skins[currententity->skinnum].renderparms.noshadow) continue; R_BuildShadowVolume (paliashdr, i, light, projected_distance, r_shadowvolumes->value); GL_LockArrays (shadow_va); if (!r_shadowvolumes->value) { if (gl_config.atiSeparateStencil && gl_config.extStencilWrap) // Barnes ATI stenciling { GL_Disable(GL_CULL_FACE); qglStencilOpSeparateATI (GL_BACK, GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP); qglStencilOpSeparateATI (GL_FRONT, GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP); R_DrawShadowVolume (); GL_Enable(GL_CULL_FACE); } else if (gl_config.extStencilTwoSide && gl_config.extStencilWrap) // Echon's two-sided stenciling { GL_Disable(GL_CULL_FACE); qglEnable (GL_STENCIL_TEST_TWO_SIDE_EXT); qglActiveStencilFaceEXT (GL_BACK); qglStencilOp (GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP); qglActiveStencilFaceEXT (GL_FRONT); qglStencilOp (GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP); R_DrawShadowVolume (); qglDisable (GL_STENCIL_TEST_TWO_SIDE_EXT); GL_Enable(GL_CULL_FACE); } else { // increment stencil if backface is behind depthbuffer GL_CullFace(GL_BACK); // quake is backwards, this culls front faces qglStencilOp(GL_KEEP, GL_INCR, GL_KEEP); R_DrawShadowVolume (); // decrement stencil if frontface is behind depthbuffer GL_CullFace(GL_FRONT); // quake is backwards, this culls back faces qglStencilOp(GL_KEEP, GL_DECR, GL_KEEP); R_DrawShadowVolume (); } } else R_DrawShadowVolume (); GL_UnlockArrays (); } // end stenciling and draw stenciled volume if (!r_shadowvolumes->value) { GL_CullFace(GL_FRONT); GL_Disable(GL_STENCIL_TEST); GL_DepthFunc(GL_LEQUAL); GL_DepthMask(1); qglColorMask(1,1,1,1); // draw shadows for this model now R_ShadowBlend (aliasShadowAlpha * currententity->alpha); // was r_shadowalpha->value qglPopAttrib(); // restore stencil buffer } }
//--------------------------------------------------------- static void WP_BowcasterMainFire( gentity_t *ent ) //--------------------------------------------------------- { int damage = weaponData[WP_BOWCASTER].damage, count; float vel; vec3_t angs, dir, start; gentity_t *missile; VectorCopy( muzzle, start ); WP_TraceSetStart( ent, start, vec3_origin, vec3_origin );//make sure our start point isn't on the other side of a wall // Do the damages if ( ent->s.number != 0 ) { if ( g_spskill->integer == 0 ) { damage = BOWCASTER_NPC_DAMAGE_EASY; } else if ( g_spskill->integer == 1 ) { damage = BOWCASTER_NPC_DAMAGE_NORMAL; } else { damage = BOWCASTER_NPC_DAMAGE_HARD; } } count = ( level.time - ent->client->ps.weaponChargeTime ) / BOWCASTER_CHARGE_UNIT; if ( count < 1 ) { count = 1; } else if ( count > 5 ) { count = 5; } if ( !(count & 1 )) { // if we aren't odd, knock us down a level count--; } // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // // in overcharge mode, so doing double damage // damage *= 2; // } WP_MissileTargetHint(ent, start, forwardVec); for ( int i = 0; i < count; i++ ) { // create a range of different velocities vel = BOWCASTER_VELOCITY * ( Q_flrand(-1.0f, 1.0f) * BOWCASTER_VEL_RANGE + 1.0f ); vectoangles( forwardVec, angs ); if ( !(ent->client->ps.forcePowersActive&(1<<FP_SEE)) || ent->client->ps.forcePowerLevel[FP_SEE] < FORCE_LEVEL_2 ) {//force sight 2+ gives perfect aim //FIXME: maybe force sight level 3 autoaims some? // add some slop to the fire direction angs[PITCH] += Q_flrand(-1.0f, 1.0f) * BOWCASTER_ALT_SPREAD * 0.2f; angs[YAW] += ((i+0.5f) * BOWCASTER_ALT_SPREAD - count * 0.5f * BOWCASTER_ALT_SPREAD ); if ( ent->NPC ) { angs[PITCH] += ( Q_flrand(-1.0f, 1.0f) * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f) ); angs[YAW] += ( Q_flrand(-1.0f, 1.0f) * (BLASTER_NPC_SPREAD+(6-ent->NPC->currentAim)*0.25f) ); } } AngleVectors( angs, dir, NULL, NULL ); missile = CreateMissile( start, dir, vel, 10000, ent ); missile->classname = "bowcaster_proj"; missile->s.weapon = WP_BOWCASTER; VectorSet( missile->maxs, BOWCASTER_SIZE, BOWCASTER_SIZE, BOWCASTER_SIZE ); VectorScale( missile->maxs, -1, missile->mins ); // if ( ent->client && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > 0 && ent->client->ps.powerups[PW_WEAPON_OVERCHARGE] > cg.time ) // { // missile->flags |= FL_OVERCHARGED; // } missile->damage = damage; missile->dflags = DAMAGE_DEATH_KNOCKBACK; missile->methodOfDeath = MOD_BOWCASTER; missile->clipmask = MASK_SHOT | CONTENTS_LIGHTSABER; missile->splashDamage = weaponData[WP_BOWCASTER].splashDamage; missile->splashRadius = weaponData[WP_BOWCASTER].splashRadius; // we don't want it to bounce missile->bounceCount = 0; ent->client->sess.missionStats.shotsFired++; } }
static void ForwardDlight( void ) { int l; //vec3_t origin; //float scale; float radius; int deformGen; vec5_t deformParams; vec4_t fogDistanceVector, fogDepthVector = {0, 0, 0, 0}; float eyeT = 0; shaderCommands_t *input = &tess; shaderStage_t *pStage = tess.xstages[0]; if ( !backEnd.refdef.num_dlights ) { return; } ComputeDeformValues(&deformGen, deformParams); ComputeFogValues(fogDistanceVector, fogDepthVector, &eyeT, NULL); for ( l = 0 ; l < backEnd.refdef.num_dlights ; l++ ) { dlight_t *dl; shaderProgram_t *sp; vec4_t vector; vec4_t texMatrix; vec4_t texOffTurb; if ( !( tess.dlightBits & ( 1 << l ) ) ) { continue; // this surface definately doesn't have any of this light } dl = &backEnd.refdef.dlights[l]; //VectorCopy( dl->transformed, origin ); radius = dl->radius; //scale = 1.0f / radius; //if (pStage->glslShaderGroup == tr.lightallShader) { int index = pStage->glslShaderIndex; index &= ~LIGHTDEF_LIGHTTYPE_MASK; index |= LIGHTDEF_USE_LIGHT_VECTOR; sp = &tr.lightallShader[index]; } backEnd.pc.c_lightallDraws++; GLSL_BindProgram(sp); GLSL_SetUniformMat4(sp, UNIFORM_MODELVIEWPROJECTIONMATRIX, glState.modelviewProjection); GLSL_SetUniformVec3(sp, UNIFORM_VIEWORIGIN, backEnd.viewParms.or.origin); GLSL_SetUniformVec3(sp, UNIFORM_LOCALVIEWORIGIN, backEnd.or.viewOrigin); GLSL_SetUniformFloat(sp, UNIFORM_VERTEXLERP, glState.vertexAttribsInterpolation); GLSL_SetUniformInt(sp, UNIFORM_DEFORMGEN, deformGen); if (deformGen != DGEN_NONE) { GLSL_SetUniformFloat5(sp, UNIFORM_DEFORMPARAMS, deformParams); GLSL_SetUniformFloat(sp, UNIFORM_TIME, tess.shaderTime); } if ( input->fogNum ) { vec4_t fogColorMask; GLSL_SetUniformVec4(sp, UNIFORM_FOGDISTANCE, fogDistanceVector); GLSL_SetUniformVec4(sp, UNIFORM_FOGDEPTH, fogDepthVector); GLSL_SetUniformFloat(sp, UNIFORM_FOGEYET, eyeT); ComputeFogColorMask(pStage, fogColorMask); GLSL_SetUniformVec4(sp, UNIFORM_FOGCOLORMASK, fogColorMask); } { vec4_t baseColor; vec4_t vertColor; ComputeShaderColors(pStage, baseColor, vertColor, GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE); GLSL_SetUniformVec4(sp, UNIFORM_BASECOLOR, baseColor); GLSL_SetUniformVec4(sp, UNIFORM_VERTCOLOR, vertColor); } if (pStage->alphaGen == AGEN_PORTAL) { GLSL_SetUniformFloat(sp, UNIFORM_PORTALRANGE, tess.shader->portalRange); } GLSL_SetUniformInt(sp, UNIFORM_COLORGEN, pStage->rgbGen); GLSL_SetUniformInt(sp, UNIFORM_ALPHAGEN, pStage->alphaGen); GLSL_SetUniformVec3(sp, UNIFORM_DIRECTEDLIGHT, dl->color); VectorSet(vector, 0, 0, 0); GLSL_SetUniformVec3(sp, UNIFORM_AMBIENTLIGHT, vector); VectorCopy(dl->origin, vector); vector[3] = 1.0f; GLSL_SetUniformVec4(sp, UNIFORM_LIGHTORIGIN, vector); GLSL_SetUniformFloat(sp, UNIFORM_LIGHTRADIUS, radius); GLSL_SetUniformVec4(sp, UNIFORM_NORMALSCALE, pStage->normalScale); GLSL_SetUniformVec4(sp, UNIFORM_SPECULARSCALE, pStage->specularScale); // include GLS_DEPTHFUNC_EQUAL so alpha tested surfaces don't add light // where they aren't rendered GL_State( GLS_SRCBLEND_ONE | GLS_DSTBLEND_ONE | GLS_DEPTHFUNC_EQUAL ); GLSL_SetUniformMat4(sp, UNIFORM_MODELMATRIX, backEnd.or.transformMatrix); if (pStage->bundle[TB_DIFFUSEMAP].image[0]) R_BindAnimatedImageToTMU( &pStage->bundle[TB_DIFFUSEMAP], TB_DIFFUSEMAP); // bind textures that are sampled and used in the glsl shader, and // bind whiteImage to textures that are sampled but zeroed in the glsl shader // // alternatives: // - use the last bound texture // -> costs more to sample a higher res texture then throw out the result // - disable texture sampling in glsl shader with #ifdefs, as before // -> increases the number of shaders that must be compiled // if (pStage->bundle[TB_NORMALMAP].image[0]) { R_BindAnimatedImageToTMU( &pStage->bundle[TB_NORMALMAP], TB_NORMALMAP); } else if (r_normalMapping->integer) GL_BindToTMU( tr.whiteImage, TB_NORMALMAP ); if (pStage->bundle[TB_SPECULARMAP].image[0]) { R_BindAnimatedImageToTMU( &pStage->bundle[TB_SPECULARMAP], TB_SPECULARMAP); } else if (r_specularMapping->integer) GL_BindToTMU( tr.whiteImage, TB_SPECULARMAP ); { vec4_t enableTextures; VectorSet4(enableTextures, 0.0f, 0.0f, 0.0f, 0.0f); GLSL_SetUniformVec4(sp, UNIFORM_ENABLETEXTURES, enableTextures); } if (r_dlightMode->integer >= 2) { GL_SelectTexture(TB_SHADOWMAP); GL_Bind(tr.shadowCubemaps[l]); GL_SelectTexture(0); } ComputeTexMods( pStage, TB_DIFFUSEMAP, texMatrix, texOffTurb ); GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXMATRIX, texMatrix); GLSL_SetUniformVec4(sp, UNIFORM_DIFFUSETEXOFFTURB, texOffTurb); GLSL_SetUniformInt(sp, UNIFORM_TCGEN0, pStage->bundle[0].tcGen); // // draw // if (input->multiDrawPrimitives) { R_DrawMultiElementsVBO(input->multiDrawPrimitives, input->multiDrawMinIndex, input->multiDrawMaxIndex, input->multiDrawNumIndexes, input->multiDrawFirstIndex); } else { R_DrawElementsVBO(input->numIndexes, input->firstIndex, input->minIndex, input->maxIndex); } backEnd.pc.c_totalIndexes += tess.numIndexes; backEnd.pc.c_dlightIndexes += tess.numIndexes; backEnd.pc.c_dlightVertexes += tess.numVertexes; } }
/* =============== UI_PlayerInfo_SetInfo =============== */ void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) { int currentAnim; weapon_t weaponNum; int c; pi->chat = chat; c = (int)trap_Cvar_VariableValue( "color1" ); VectorClear( pi->color1 ); if( c < 1 || c > 7 ) { VectorSet( pi->color1, 1, 1, 1 ); } else { if( c & 1 ) { pi->color1[2] = 1.0f; } if( c & 2 ) { pi->color1[1] = 1.0f; } if( c & 4 ) { pi->color1[0] = 1.0f; } } pi->c1RGBA[0] = 255 * pi->color1[0]; pi->c1RGBA[1] = 255 * pi->color1[1]; pi->c1RGBA[2] = 255 * pi->color1[2]; pi->c1RGBA[3] = 255; // view angles VectorCopy( viewAngles, pi->viewAngles ); // move angles VectorCopy( moveAngles, pi->moveAngles ); if ( pi->newModel ) { pi->newModel = qfalse; jumpHeight = 0; pi->pendingLegsAnim = 0; UI_ForceLegsAnim( pi, legsAnim ); pi->legs.yawAngle = viewAngles[YAW]; pi->legs.yawing = qfalse; pi->pendingTorsoAnim = 0; UI_ForceTorsoAnim( pi, torsoAnim ); pi->torso.yawAngle = viewAngles[YAW]; pi->torso.yawing = qfalse; if ( weaponNumber != WP_NUM_WEAPONS ) { pi->weapon = weaponNumber; pi->currentWeapon = weaponNumber; pi->lastWeapon = weaponNumber; pi->pendingWeapon = WP_NUM_WEAPONS; pi->weaponTimer = 0; UI_PlayerInfo_SetWeapon( pi, pi->weapon ); } return; } // weapon if ( weaponNumber == WP_NUM_WEAPONS ) { pi->pendingWeapon = WP_NUM_WEAPONS; pi->weaponTimer = 0; } else if ( weaponNumber != WP_NONE ) { pi->pendingWeapon = weaponNumber; pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY; } weaponNum = pi->lastWeapon; pi->weapon = weaponNum; if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) { torsoAnim = legsAnim = BOTH_DEATH1; pi->weapon = pi->currentWeapon = WP_NONE; UI_PlayerInfo_SetWeapon( pi, pi->weapon ); jumpHeight = 0; pi->pendingLegsAnim = 0; UI_ForceLegsAnim( pi, legsAnim ); pi->pendingTorsoAnim = 0; UI_ForceTorsoAnim( pi, torsoAnim ); return; } // leg animation currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT; if ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) { pi->pendingLegsAnim = legsAnim; } else if ( legsAnim != currentAnim ) { jumpHeight = 0; pi->pendingLegsAnim = 0; UI_ForceLegsAnim( pi, legsAnim ); } // torso animation if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) { if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) { torsoAnim = TORSO_STAND2; } else { torsoAnim = TORSO_STAND; } } if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) { if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) { torsoAnim = TORSO_ATTACK2; } else { torsoAnim = TORSO_ATTACK; } pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH; //FIXME play firing sound here } currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT; if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) { pi->pendingTorsoAnim = torsoAnim; } else if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) { pi->pendingTorsoAnim = torsoAnim; } else if ( torsoAnim != currentAnim ) { pi->pendingTorsoAnim = 0; UI_ForceTorsoAnim( pi, torsoAnim ); } }
static void CG_OffsetThirdPersonView( void ) { vec3_t forward, right, up; vec3_t view; vec3_t focusAngles; trace_t trace; static vec3_t mins = { -8, -8, -8 }; static vec3_t maxs = { 8, 8, 8 }; vec3_t focusPoint; float focusDist; float forwardScale, sideScale; vec3_t surfNormal; if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBING ) { if( cg.predictedPlayerState.stats[ STAT_STATE ] & SS_WALLCLIMBINGCEILING ) VectorSet( surfNormal, 0.0f, 0.0f, -1.0f ); else VectorCopy( cg.predictedPlayerState.grapplePoint, surfNormal ); } else VectorSet( surfNormal, 0.0f, 0.0f, 1.0f ); VectorMA( cg.refdef.vieworg, cg.predictedPlayerState.viewheight, surfNormal, cg.refdef.vieworg ); VectorCopy( cg.refdefViewAngles, focusAngles ); // if dead, look at killer if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 ) { focusAngles[ YAW ] = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ]; cg.refdefViewAngles[ YAW ] = cg.predictedPlayerState.stats[ STAT_VIEWLOCK ]; } //if ( focusAngles[PITCH] > 45 ) { // focusAngles[PITCH] = 45; // don't go too far overhead //} AngleVectors( focusAngles, forward, NULL, NULL ); VectorMA( cg.refdef.vieworg, FOCUS_DISTANCE, forward, focusPoint ); VectorCopy( cg.refdef.vieworg, view ); VectorMA( view, cg_thirdpersonheight.integer, surfNormal, view ); //12 //cg.refdefViewAngles[PITCH] *= 0.5; AngleVectors( cg.refdefViewAngles, forward, right, up ); forwardScale = cos( cg_thirdPersonAngle.value / 180 * M_PI ); sideScale = sin( cg_thirdPersonAngle.value / 180 * M_PI ); VectorMA( view, -cg_thirdPersonRange.value * forwardScale, forward, view ); VectorMA( view, -cg_thirdPersonRange.value * sideScale, right, view ); // trace a ray from the origin to the viewpoint to make sure the view isn't // in a solid block. Use an 8 by 8 block to prevent the view from near clipping anything if( !cg_cameraMode.integer ) { CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID ); if( trace.fraction != 1.0 ) { VectorCopy( trace.endpos, view ); view[ 2 ] += ( 1.0 - trace.fraction ) * 32; // try another trace to this position, because a tunnel may have the ceiling // close enogh that this is poking out CG_Trace( &trace, cg.refdef.vieworg, mins, maxs, view, cg.predictedPlayerState.clientNum, MASK_SOLID ); VectorCopy( trace.endpos, view ); } } VectorCopy( view, cg.refdef.vieworg ); // select pitch to look at focus point from vieword VectorSubtract( focusPoint, cg.refdef.vieworg, focusPoint ); focusDist = sqrt( focusPoint[ 0 ] * focusPoint[ 0 ] + focusPoint[ 1 ] * focusPoint[ 1 ] ); if ( focusDist < 1 ) { focusDist = 1; // should never happen } cg.refdefViewAngles[ PITCH ] = -180 / M_PI * atan2( focusPoint[ 2 ], focusDist ); cg.refdefViewAngles[ YAW ] -= cg_thirdPersonAngle.value; }
void LoadJTRAIL(edict_t *ent,char filename[MAX_STR_LEN],qboolean pdm,int clean,int colorp,int sizep) { FILE *jtrail_file; char *token="\0"; char buf2[1000]; char message[256]; int lbuf2,color,mass; edict_t *laser = NULL; vec3_t start; int lasttrailnum=0; char JTRAILFile[MAX_STR_LEN]; int delcount=0; char tok[2]=""; int clean_count=0; int total_good_lines=0; if (TrailsBanned()) return; if (pdm) { if (!Q_stricmp(filename,"lastdemo")) sprintf(JTRAILFile, GAMEVERSION "/puppetdemo/%i.pdm",ent->client->resp.id); else sprintf(JTRAILFile, GAMEVERSION "/puppetdemo/%s-%s.pdm",level.mapname,filename); } else sprintf(JTRAILFile, GAMEVERSION "/jtrail/%s-%s.jtrail",level.mapname,filename); jtrail_file = fopen(JTRAILFile, "r"); if (jtrail_file == NULL) { if (pdm) { if (!Q_stricmp(filename,"lastdemo")) gi.cprintf(ent,PRINT_HIGH,"\"%i.pdm\" was not found!\n",ent->client->resp.id); else gi.cprintf(ent,PRINT_HIGH,"\"%s-%s.pdm\" was not found!\n",level.mapname,filename); } else gi.cprintf(ent,PRINT_HIGH,"\"%s-%s.jtrail\" was not found!\n",level.mapname,filename); return; } if (pdm) tok[0] = ','; //puppet demos parsed with ',' else tok[0] = ' '; //trail files parsed with ' ' tok[1] = '\0'; //grab the total good lines, for new clean-on-load usage while (fgets(buf2, 900, jtrail_file) != NULL) { if (!(((buf2[0] > '0') && (buf2[0] < '9')) || (buf2[0] == '-'))) continue; total_good_lines++; } fclose(jtrail_file); //reopen the file to start reading again... we know it exists so no check on that jtrail_file = fopen(JTRAILFile, "r"); jtrail_num_lines = 0; ltrails++; while (fgets(buf2, 900, jtrail_file) != NULL) { double time; if (!(((buf2[0] > '0') && (buf2[0] < '9')) || (buf2[0] == '-'))) continue; if (clean_count != clean) { if ((jtrail_num_lines != 0) && (jtrail_num_lines != total_good_lines)) { clean_count++; continue; } clean_count++; } else clean_count = 0; message[0]='\0'; lbuf2 = strlen(buf2); while (buf2[lbuf2-1] == '\r' || buf2[lbuf2-1] == '\n') { buf2[lbuf2-1] = 0; lbuf2--; } start[0] = start[1] = start[2] = color = mass = 0; if (ltnodes <= traillimit->value) { laser = G_Spawn(); // laser->owner = ent; ltnodes++; laser->classnum = jtrail_num_lines+1;//ltnodes; laser->classname = "LaserTrailLink"; laser->s.frame = 4; VectorSet (laser->mins, -8, -8, -8); VectorSet (laser->maxs, 8, 8, 8); //Load Coords token = strtok( buf2, tok ); start[0] = atoi(token); token = strtok( NULL, tok ); if ((token == NULL) && pdm) break; start[1] = atoi(token); token = strtok( NULL, tok ); start[2] = atoi(token); VectorCopy(start,laser->s.origin); if (pdm) { if (colorp == -1) laser->s.skinnum = NUMtoCOLOR(1); //color (green) else laser->s.skinnum = NUMtoCOLOR(colorp); if (sizep == -1) laser->s.frame = 4; //size else laser->s.frame = sizep; laser->mass = ltrails; //num (never gonna be multiple paths to load this way) } else { //Load Color token = strtok( NULL, tok ); color = atoi(token); laser->s.skinnum = color; //Load Size token = strtok( NULL, tok ); color = atoi(token); laser->s.frame = color; //Load Gravity token = strtok( NULL, tok ); color = atoi(token); if (lasttrailnum != color) { ltrails++; lasttrailnum = color; } laser->mass = color+ltrails; } time = level.time + (jtrail_num_lines/10); laser->think = DelayLaserLinkOn;//MODIFY ME!!!WHY?!!//DelayMarkerLoad_Think; laser->nextthink = time; gi.linkentity(laser); } else { delcount++; } jtrail_num_lines++; } fclose(jtrail_file); if (delcount !=0) { if (delcount == jtrail_num_lines) gi.bprintf(PRINT_HIGH,"%s: \"%s\" could not be loaded due to traillimit hit!\n",ent->client->pers.netname,JTRAILFile); else { gi.bprintf(PRINT_HIGH,"%s: \"%s\" was partially loaded due to traillimit hit! (%i/%i link",ent->client->pers.netname,JTRAILFile,jtrail_num_lines-delcount,jtrail_num_lines); if (jtrail_num_lines != 1) gi.bprintf(PRINT_HIGH,"s"); if (jtrail_num_lines-delcount > 10) gi.bprintf(PRINT_HIGH," (%i in queue))\n",jtrail_num_lines-delcount-10); else gi.bprintf(PRINT_HIGH,")\n"); } } else { gi.bprintf(PRINT_HIGH,"%s: \"%s\" was loaded successfully! (%i link",ent->client->pers.netname,JTRAILFile,jtrail_num_lines); if (jtrail_num_lines != 1) gi.bprintf(PRINT_HIGH,"s"); if (jtrail_num_lines > 10) gi.bprintf(PRINT_HIGH," (%i in queue))\n",jtrail_num_lines-10); else gi.bprintf(PRINT_HIGH,")\n"); } }
/* * G_Damage * targ entity that is being damaged * inflictor entity that is causing the damage * attacker entity that caused the inflictor to damage targ * example: targ=enemy, inflictor=rocket, attacker=player * * dir direction of the attack * point point at which the damage is being inflicted * normal normal vector from that point * damage amount of damage being inflicted * knockback force to be applied against targ as a result of the damage * * dflags these flags are used to control how T_Damage works */ void G_Damage( edict_t *targ, edict_t *inflictor, edict_t *attacker, const vec3_t pushdir, const vec3_t dmgdir, const vec3_t point, float damage, float knockback, float stun, int dflags, int mod ) { gclient_t *client; float take; float save; float asave; bool statDmg; if( !targ || !targ->takedamage ) return; if( !attacker ) { attacker = world; mod = MOD_TRIGGER_HURT; } meansOfDeath = mod; client = targ->r.client; // Cgg - race mode: players don't interact with one another if( GS_RaceGametype() ) { if( attacker->r.client && targ->r.client && attacker != targ ) return; } // push if( !( dflags & DAMAGE_NO_KNOCKBACK ) ) G_KnockBackPush( targ, attacker, pushdir, knockback, dflags ); // stun if( g_allow_stun->integer && !( dflags & (DAMAGE_NO_STUN|FL_GODMODE) ) && (int)stun > 0 && targ->r.client && targ->r.client->resp.takeStun && !GS_IsTeamDamage( &targ->s, &attacker->s ) && ( targ != attacker ) ) { if( dflags & DAMAGE_STUN_CLAMP ) { if( targ->r.client->ps.pmove.stats[PM_STAT_STUN] < (int)stun ) targ->r.client->ps.pmove.stats[PM_STAT_STUN] = (int)stun; } else targ->r.client->ps.pmove.stats[PM_STAT_STUN] += (int)stun; clamp( targ->r.client->ps.pmove.stats[PM_STAT_STUN], 0, MAX_STUN_TIME ); } // dont count self-damage cause it just adds the same to both stats statDmg = ( attacker != targ ) && ( mod != MOD_TELEFRAG ); // apply handicap on the damage given if( statDmg && attacker->r.client && !GS_Instagib() ) { // handicap is a percentage value if( attacker->r.client->handicap != 0 ) damage *= 1.0 - (attacker->r.client->handicap * 0.01f); } take = damage; save = 0; // check for cases where damage is protected if( !( dflags & DAMAGE_NO_PROTECTION ) ) { // check for godmode if( targ->flags & FL_GODMODE ) { take = 0; save = damage; } // never damage in timeout else if( GS_MatchPaused() ) { take = save = 0; } // ca has self splash damage disabled else if( ( dflags & DAMAGE_RADIUS ) && attacker == targ && !GS_SelfDamage() ) { take = save = 0; } // don't get damage from players in race else if( ( GS_RaceGametype() ) && attacker->r.client && targ->r.client && ( attacker->r.client != targ->r.client ) ) { take = save = 0; } // team damage avoidance else if( GS_IsTeamDamage( &targ->s, &attacker->s ) && !G_Gametype_CanTeamDamage( dflags ) ) { take = save = 0; } // apply warShell powerup protection else if( targ->r.client && targ->r.client->ps.inventory[POWERUP_SHELL] > 0 ) { // warshell offers full protection in instagib if( GS_Instagib() ) { take = 0; save = damage; } else { take = ( damage * 0.25f ); save = damage - take; } // todo : add protection sound } } asave = G_CheckArmor( targ, take, dflags ); take -= asave; //treat cheat/powerup savings the same as armor asave += save; // APPLY THE DAMAGES if( !take && !asave ) return; // do the damage if( take <= 0 ) return; // adding damage given/received to stats if( statDmg && attacker->r.client && !targ->deadflag && targ->movetype != MOVETYPE_PUSH && targ->s.type != ET_CORPSE ) { attacker->r.client->level.stats.total_damage_given += take + asave; teamlist[attacker->s.team].stats.total_damage_given += take + asave; if( GS_IsTeamDamage( &targ->s, &attacker->s ) ) { attacker->r.client->level.stats.total_teamdamage_given += take + asave; teamlist[attacker->s.team].stats.total_teamdamage_given += take + asave; } } G_Gametype_ScoreEvent( attacker->r.client, "dmg", va( "%i %f %i", targ->s.number, damage, attacker->s.number ) ); if( statDmg && client ) { client->level.stats.total_damage_received += take + asave; teamlist[targ->s.team].stats.total_damage_received += take + asave; if( GS_IsTeamDamage( &targ->s, &attacker->s ) ) { client->level.stats.total_teamdamage_received += take + asave; teamlist[targ->s.team].stats.total_teamdamage_received += take + asave; } } // accumulate received damage for snapshot effects { vec3_t dorigin; if( inflictor == world && mod == MOD_FALLING ) // it's fall damage targ->snap.damage_fall += take + save; if( point[0] != 0.0f || point[1] != 0.0f || point[2] != 0.0f ) VectorCopy( point, dorigin ); else VectorSet( dorigin, targ->s.origin[0], targ->s.origin[1], targ->s.origin[2] + targ->viewheight ); G_BlendFrameDamage( targ, take, &targ->snap.damage_taken, dorigin, dmgdir, targ->snap.damage_at, targ->snap.damage_dir ); G_BlendFrameDamage( targ, save, &targ->snap.damage_saved, dorigin, dmgdir, targ->snap.damage_at, targ->snap.damage_dir ); if( targ->r.client ) { if( mod != MOD_FALLING && mod != MOD_TELEFRAG && mod != MOD_SUICIDE ) { if( inflictor == world || attacker == world ) { // for world inflicted damage use always 'frontal' G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, NULL ); } else if( dflags & DAMAGE_RADIUS ) { // for splash hits the direction is from the inflictor origin G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, pushdir ); } else { // for direct hits the direction is the projectile direction G_ClientAddDamageIndicatorImpact( targ->r.client, take + save, dmgdir ); } } } } targ->health = targ->health - take; // add damage done to stats if( !GS_IsTeamDamage( &targ->s, &attacker->s ) && statDmg && G_ModToAmmo( mod ) != AMMO_NONE && client && attacker->r.client ) { attacker->r.client->level.stats.accuracy_hits[G_ModToAmmo( mod )-AMMO_GUNBLADE]++; attacker->r.client->level.stats.accuracy_damage[G_ModToAmmo( mod )-AMMO_GUNBLADE] += damage; teamlist[attacker->s.team].stats.accuracy_hits[G_ModToAmmo( mod )-AMMO_GUNBLADE]++; teamlist[attacker->s.team].stats.accuracy_damage[G_ModToAmmo( mod )-AMMO_GUNBLADE] += damage; G_AwardPlayerHit( targ, attacker, mod ); } // accumulate given damage for hit sounds if( ( take || asave ) && targ != attacker && client && !targ->deadflag ) { if( attacker ) { if( GS_IsTeamDamage( &targ->s, &attacker->s ) ) attacker->snap.damageteam_given += take + asave; // we want to know how good our hit was, so saved also matters else attacker->snap.damage_given += take + asave; } } if( G_IsDead( targ ) ) { if( client ) targ->flags |= FL_NO_KNOCKBACK; G_Killed( targ, inflictor, attacker, HEALTH_TO_INT( take ), point, mod ); } else { G_CallPain( targ, attacker, knockback, take ); } }
/*QUAKED monster_floater (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_floater(edict_t *self) { if (deathmatch->value) { G_FreeEdict(self); return; } sound_attack2 = gi.soundindex("floater/fltatck2.wav"); sound_attack3 = gi.soundindex("floater/fltatck3.wav"); sound_death1 = gi.soundindex("floater/fltdeth1.wav"); sound_idle = gi.soundindex("floater/fltidle1.wav"); sound_pain1 = gi.soundindex("floater/fltpain1.wav"); sound_pain2 = gi.soundindex("floater/fltpain2.wav"); sound_sight = gi.soundindex("floater/fltsght1.wav"); gi.soundindex("floater/fltatck1.wav"); self->s.sound = gi.soundindex("floater/fltsrch1.wav"); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; // Lazarus: special purpose skins if (self->style) { PatchMonsterModel("models/monsters/float/tris.md2"); self->s.skinnum = self->style * 2; } self->s.modelindex = gi.modelindex("models/monsters/float/tris.md2"); VectorSet(self->mins, -24, -24, -24); VectorSet(self->maxs, 24, 24, 32); // Lazarus: mapper-configurable health if (!self->health) self->health = 200; if (!self->gib_health) self->gib_health = -80; if (!self->mass) self->mass = 300; self->pain = floater_pain; self->die = floater_die; self->monsterinfo.stand = floater_stand; self->monsterinfo.walk = floater_walk; self->monsterinfo.run = floater_run; // self->monsterinfo.dodge = floater_dodge; self->monsterinfo.attack = floater_attack; self->monsterinfo.melee = floater_melee; self->monsterinfo.sight = floater_sight; self->monsterinfo.idle = floater_idle; // Knightmare- added sparks and blood type if (!self->blood_type) self->blood_type = 2; //sparks else self->fogclip |= 2; //custom bloodtype flag // Lazarus if (self->powerarmor) { self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD; self->monsterinfo.power_armor_power = self->powerarmor; } self->common_name = "Technician"; gi.linkentity(self); if (self->health < 0) { mmove_t *deathmoves[] = { &floater_move_death, NULL }; if (!M_SetDeath(self, (mmove_t **)&deathmoves)) self->monsterinfo.currentmove = &floater_move_stand1; } else { if (random() <= 0.5) self->monsterinfo.currentmove = &floater_move_stand1; else self->monsterinfo.currentmove = &floater_move_stand2; } self->monsterinfo.scale = MODEL_SCALE; flymonster_start(self); }
/*QUAKED monster_mytank_commander (1 .5 0) (-32 -32 -16) (32 32 72) Ambush Trigger_Spawn Sight */ void init_drone_tank (edict_t *self) { // if (deathmatch->value) // { // G_FreeEdict (self); // return; // } self->s.modelindex = gi.modelindex ("models/monsters/tank/tris.md2"); VectorSet (self->mins, -24, -24, -16); VectorSet (self->maxs, 24, 24, 64); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; sound_pain = gi.soundindex ("tank/tnkpain2.wav"); sound_thud = gi.soundindex ("tank/tnkdeth2.wav"); sound_idle = gi.soundindex ("tank/tnkidle1.wav"); sound_die = gi.soundindex ("tank/death.wav"); sound_step = gi.soundindex ("tank/step.wav"); sound_windup = gi.soundindex ("tank/tnkatck4.wav"); sound_strike = gi.soundindex ("tank/tnkatck5.wav"); sound_sight = gi.soundindex ("tank/sight1.wav"); gi.soundindex ("tank/tnkatck1.wav"); gi.soundindex ("tank/tnkatk2a.wav"); gi.soundindex ("tank/tnkatk2b.wav"); gi.soundindex ("tank/tnkatk2c.wav"); gi.soundindex ("tank/tnkatk2d.wav"); gi.soundindex ("tank/tnkatk2e.wav"); gi.soundindex ("tank/tnkatck3.wav"); // if (self->activator && self->activator->client) self->health = 100 + 65*self->monsterinfo.level; //else self->health = 100 + 65*self->monsterinfo.level; self->max_health = self->health; self->gib_health = -200; //if (self->activator && self->activator->client) self->monsterinfo.power_armor_power = 200 + 105*self->monsterinfo.level; //else self->monsterinfo.power_armor_power = 200 + 105*self->monsterinfo.level; self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD; self->monsterinfo.max_armor = self->monsterinfo.power_armor_power; self->monsterinfo.control_cost = M_TANK_CONTROL_COST; self->monsterinfo.cost = M_TANK_COST; self->mtype = M_TANK; if (random() > 0.5) self->item = FindItemByClassname("ammo_bullets"); else self->item = FindItemByClassname("ammo_rockets"); self->mass = 500; //self->pain = mytank_pain; self->die = mytank_die; //self->touch = mytank_touch; self->monsterinfo.stand = mytank_stand; self->monsterinfo.walk = tank_walk; self->monsterinfo.run = mytank_run; self->monsterinfo.dodge = NULL; self->monsterinfo.attack = mytank_attack; self->monsterinfo.melee = mytank_melee; self->monsterinfo.sight = mytank_sight; self->monsterinfo.idle = mytank_idle; self->monsterinfo.jumpup = 64; self->monsterinfo.jumpdn = 512; self->monsterinfo.aiflags |= AI_NO_CIRCLE_STRAFE; //self->monsterinfo.melee = 1; gi.linkentity (self); self->monsterinfo.currentmove = &mytank_move_stand; self->monsterinfo.scale = MODEL_SCALE; // walkmonster_start(self); self->nextthink = level.time + FRAMETIME; // self->activator->num_monsters += self->monsterinfo.control_cost; }
/* ================== PM_StepSlideMove ================== */ void PM_StepSlideMove( qboolean gravity ) { vec3_t start_o, start_v; vec3_t down_o, down_v; trace_t trace; // float down_dist, up_dist; // vec3_t delta, delta2; vec3_t up, down; float stepSize; qboolean isGiant = qfalse; bgEntity_t *pEnt; qboolean skipStep = qfalse; VectorCopy (pm->ps->origin, start_o); VectorCopy (pm->ps->velocity, start_v); if ( BG_InReboundHold( pm->ps->legsAnim ) ) { gravity = qfalse; } if ( PM_SlideMove( gravity ) == 0 ) { return; // we got exactly where we wanted to go first try } pEnt = pm_entSelf; if (pm->ps->clientNum >= MAX_CLIENTS) { if (pEnt && pEnt->s.NPC_class == CLASS_VEHICLE && pEnt->m_pVehicle && pEnt->m_pVehicle->m_pVehicleInfo->hoverHeight > 0) { return; } } VectorCopy(start_o, down); down[2] -= STEPSIZE; pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); VectorSet(up, 0, 0, 1); // never step up when you still have up velocity if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 || DotProduct(trace.plane.normal, up) < 0.7)) { return; } VectorCopy (pm->ps->origin, down_o); VectorCopy (pm->ps->velocity, down_v); VectorCopy (start_o, up); if (pm->ps->clientNum >= MAX_CLIENTS) { // apply ground friction, even if on ladder if (pEnt && pEnt->s.NPC_class == CLASS_ATST || (pEnt->s.NPC_class == CLASS_VEHICLE && pEnt->m_pVehicle && pEnt->m_pVehicle->m_pVehicleInfo->type == VH_WALKER) ) {//AT-STs can step high up[2] += 66.0f; isGiant = qtrue; } else if ( pEnt && pEnt->s.NPC_class == CLASS_RANCOR ) {//also can step up high up[2] += 64.0f; isGiant = qtrue; } else { up[2] += STEPSIZE; } } else { up[2] += STEPSIZE; } // test the player position if they were a stepheight higher pm->trace (&trace, start_o, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask); if ( trace.allsolid ) { if ( pm->debugLevel ) { Com_Printf("%i:bend can't step\n", c_pmove); } return; // can't step up } stepSize = trace.endpos[2] - start_o[2]; // try slidemove from this position VectorCopy (trace.endpos, pm->ps->origin); VectorCopy (start_v, pm->ps->velocity); PM_SlideMove( gravity ); // push down the final amount VectorCopy (pm->ps->origin, down); down[2] -= stepSize; pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask); if ( pm->stepSlideFix ) { if ( pm->ps->clientNum < MAX_CLIENTS && trace.plane.normal[2] < MIN_WALK_NORMAL ) {//normal players cannot step up slopes that are too steep to walk on! vec3_t stepVec; //okay, the step up ends on a slope that it too steep to step up onto, //BUT: //If the step looks like this: // (B)\__ // \_____(A) //Then it might still be okay, so we figure out the slope of the entire move //from (A) to (B) and if that slope is walk-upabble, then it's okay VectorSubtract( trace.endpos, down_o, stepVec ); VectorNormalize( stepVec ); if ( stepVec[2] > (1.0f-MIN_WALK_NORMAL) ) { skipStep = qtrue; } } } if ( !trace.allsolid && !skipStep ) //normal players cannot step up slopes that are too steep to walk on! { if ( pm->ps->clientNum >= MAX_CLIENTS//NPC && isGiant && trace.entityNum < MAX_CLIENTS && pEnt && pEnt->s.NPC_class == CLASS_RANCOR ) {//Rancor don't step on clients if ( pm->stepSlideFix ) { VectorCopy (down_o, pm->ps->origin); VectorCopy (down_v, pm->ps->velocity); } else { VectorCopy (start_o, pm->ps->origin); VectorCopy (start_v, pm->ps->velocity); } } /* else if ( pm->ps->clientNum >= MAX_CLIENTS//NPC && isGiant && trace.entityNum < MAX_CLIENTS && pEnt && pEnt->s.NPC_class == CLASS_ATST && OnSameTeam( pEnt, traceEnt) ) {//NPC AT-ST's don't step up on allies VectorCopy (start_o, pm->ps->origin); VectorCopy (start_v, pm->ps->velocity); } */ else { VectorCopy (trace.endpos, pm->ps->origin); if ( pm->stepSlideFix ) { if ( trace.fraction < 1.0 ) { PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP ); } } } } else { if ( pm->stepSlideFix ) { VectorCopy (down_o, pm->ps->origin); VectorCopy (down_v, pm->ps->velocity); } } if ( !pm->stepSlideFix ) { if ( trace.fraction < 1.0 ) { PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP ); } } #if 0 // if the down trace can trace back to the original position directly, don't step pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, start_o, pm->ps->clientNum, pm->tracemask); if ( trace.fraction == 1.0 ) { // use the original move VectorCopy (down_o, pm->ps->origin); VectorCopy (down_v, pm->ps->velocity); if ( pm->debugLevel ) { Com_Printf("%i:bend\n", c_pmove); } } else #endif { // use the step move float delta; delta = pm->ps->origin[2] - start_o[2]; if ( delta > 2 ) { if ( delta < 7 ) { PM_AddEvent( EV_STEP_4 ); } else if ( delta < 11 ) { PM_AddEvent( EV_STEP_8 ); } else if ( delta < 15 ) { PM_AddEvent( EV_STEP_12 ); } else { PM_AddEvent( EV_STEP_16 ); } } if ( pm->debugLevel ) { Com_Printf("%i:stepped\n", c_pmove); } } }
void SP_misc_gamemodel( void ) { char* model; char* skin; vec_t angle; vec3_t angles; vec_t scale; vec3_t vScale; vec3_t org; cg_gamemodel_t* gamemodel; int i; #if 0 // ZTM: Note: Spearmint's game always drops misc_gamemodels. Also, RTCW has targetname set though I'm not sure what, if anything, it's used for. if ( CG_SpawnString( "targetname", "", &model ) || CG_SpawnString( "scriptname", "", &model ) || CG_SpawnString( "spawnflags", "", &model ) ) { // Gordon: this model may not be static, so let the server handle it return; } #endif if ( cg.numMiscGameModels >= MAX_STATIC_GAMEMODELS ) { CG_Error( "^1MAX_STATIC_GAMEMODELS(%i) hit", MAX_STATIC_GAMEMODELS ); } CG_SpawnString( "model", "", &model ); CG_SpawnString( "skin", "", &skin ); CG_SpawnVector( "origin", "0 0 0", org ); if ( !CG_SpawnVector( "angles", "0 0 0", angles ) ) { if ( CG_SpawnFloat( "angle", "0", &angle ) ) { angles[YAW] = angle; } } if ( !CG_SpawnVector( "modelscale_vec", "1 1 1", vScale ) ) { if ( CG_SpawnFloat( "modelscale", "1", &scale ) ) { VectorSet( vScale, scale, scale, scale ); } } gamemodel = &cgs.miscGameModels[cg.numMiscGameModels++]; gamemodel->model = trap_R_RegisterModel( model ); if ( *skin ) { CG_RegisterSkin( skin, &gamemodel->skin, qfalse ); } AnglesToAxis( angles, gamemodel->axes ); for ( i = 0; i < 3; i++ ) { VectorScale( gamemodel->axes[i], vScale[i], gamemodel->axes[i] ); } VectorCopy( org, gamemodel->org ); if ( gamemodel->model ) { vec3_t mins, maxs; trap_R_ModelBounds( gamemodel->model, mins, maxs, 0, 0, 0 ); for ( i = 0; i < 3; i++ ) { mins[i] *= vScale[i]; maxs[i] *= vScale[i]; } gamemodel->radius = RadiusFromBounds( mins, maxs ); } else { gamemodel->radius = 0; } }
/* ================ LaunchItem Spawns an item and tosses it forward ================ */ gentity_t *LaunchItem( gitem_t *item, vec3_t origin, vec3_t velocity ) { gentity_t *dropped; dropped = G_Spawn(); dropped->s.eType = ET_ITEM; dropped->s.modelindex = item - bg_itemlist; // store item number in modelindex dropped->s.modelindex2 = 1; // This is non-zero is it's a dropped item dropped->classname = item->classname; dropped->item = item; VectorSet (dropped->r.mins, -ITEM_RADIUS, -ITEM_RADIUS, -ITEM_RADIUS); VectorSet (dropped->r.maxs, ITEM_RADIUS, ITEM_RADIUS, ITEM_RADIUS); // project higher...makes stuff easier to pick up while jumping.. //dropped->r.maxs[2] += 200; Doens't work? dropped->r.contents = CONTENTS_TRIGGER; dropped->touch = Touch_Item; G_SetOrigin( dropped, origin ); dropped->s.pos.trType = TR_GRAVITY; dropped->s.pos.trTime = level.time; VectorCopy( velocity, dropped->s.pos.trDelta ); dropped->s.eFlags |= EF_BOUNCE_HALF; #if 1 if ((g_gametype.integer == GT_CTF || g_gametype.integer == GT_1FCTF) && item->giType == IT_TEAM) { // Special case for CTF flags #else if (g_gametype.integer == GT_CTF && item->giType == IT_TEAM) { // Special case for CTF flags #endif dropped->think = Team_DroppedFlagThink; dropped->nextthink = level.time + 30000; Team_CheckDroppedItem( dropped ); } else { // auto-remove after 30 seconds dropped->think = G_FreeEntity; dropped->nextthink = level.time + 30000; } dropped->flags = FL_DROPPED_ITEM; trap_LinkEntity (dropped); return dropped; } /* ================ Drop_Item Spawns an item and tosses it forward ================ */ gentity_t *Drop_Item( gentity_t *ent, gitem_t *item, float angle ) { vec3_t velocity; vec3_t angles; VectorCopy( ent->s.apos.trBase, angles ); angles[YAW] += angle; angles[PITCH] = 0; // always forward AngleVectors( angles, velocity, NULL, NULL ); VectorScale( velocity, 150, velocity ); velocity[2] += 200 + crandom() * 50; return LaunchItem( item, ent->s.pos.trBase, velocity ); }
/*QUAKED monster_medic (1 .5 0) (-16 -16 -24) (16 16 32) Ambush Trigger_Spawn Sight */ void SP_monster_medic (edict_t *self) { if (deathmatch->value) { G_FreeEdict (self); return; } if (world->effects & FX_WORLDSPAWN_CORPSEFADE) { G_FreeEdict (self); return; } sound_idle1 = gi.soundindex ("medic/idle.wav"); sound_pain1 = gi.soundindex ("medic/medpain1.wav"); sound_pain2 = gi.soundindex ("medic/medpain2.wav"); sound_die = gi.soundindex ("medic/meddeth1.wav"); sound_sight = gi.soundindex ("medic/medsght1.wav"); sound_search = gi.soundindex ("medic/medsrch1.wav"); sound_hook_launch = gi.soundindex ("medic/medatck2.wav"); sound_hook_hit = gi.soundindex ("medic/medatck3.wav"); sound_hook_heal = gi.soundindex ("medic/medatck4.wav"); sound_hook_retract = gi.soundindex ("medic/medatck5.wav"); gi.soundindex ("medic/medatck1.wav"); self->movetype = MOVETYPE_STEP; self->solid = SOLID_BBOX; // Lazarus: special purpose skins if ( self->style ) { PatchMonsterModel("models/monsters/medic/tris.md2"); self->s.skinnum = self->style * 2; } self->s.modelindex = gi.modelindex ("models/monsters/medic/tris.md2"); VectorSet (self->mins, -24, -24, -24); VectorSet (self->maxs, 24, 24, 32); // Lazarus: mapper-configurable health if(!self->health) self->health = 300; if(!self->gib_health) self->gib_health = -130; if(!self->mass) self->mass = 400; self->pain = medic_pain; self->die = medic_die; self->monsterinfo.stand = medic_stand; self->monsterinfo.walk = medic_walk; self->monsterinfo.run = medic_run; self->monsterinfo.dodge = medic_dodge; self->monsterinfo.attack = medic_attack; self->monsterinfo.melee = NULL; self->monsterinfo.sight = medic_sight; self->monsterinfo.idle = medic_idle; self->monsterinfo.search = medic_search; self->monsterinfo.checkattack = medic_checkattack; // Knightmare- added sparks and blood type if (!self->blood_type) self->blood_type = 3; //sparks and blood // Lazarus if(self->powerarmor) { self->monsterinfo.power_armor_type = POWER_ARMOR_SHIELD; self->monsterinfo.power_armor_power = self->powerarmor; } if(!self->monsterinfo.flies) self->monsterinfo.flies = 0.15; gi.linkentity (self); self->monsterinfo.currentmove = &medic_move_stand; if(self->health < 0) { mmove_t *deathmoves[] = {&medic_move_death, NULL}; M_SetDeath(self,(mmove_t **)&deathmoves); } self->common_name = "Medic"; self->monsterinfo.scale = MODEL_SCALE; walkmonster_start (self); }
/* ===================== CG_AddParticleToScene ===================== */ void CG_AddParticleToScene (cparticle_t *p, vec3_t org, float alpha) { vec3_t point; polyVert_t verts[4]; float width; float height; float time, time2; float ratio; float invratio; vec3_t color; polyVert_t TRIverts[3]; vec3_t rright2, rup2; if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY || p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) {// create a front facing polygon if (p->type != P_WEATHER_FLURRY) { if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) { if (org[2] > p->end) { p->time = cg.time; VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground p->org[2] = ( p->start + crandom () * 4 ); if (p->type == P_BUBBLE_TURBULENT) { p->vel[0] = crandom() * 4; p->vel[1] = crandom() * 4; } } } else { if (org[2] < p->end) { p->time = cg.time; VectorCopy (org, p->org); // Ridah, fixes rare snow flakes that flicker on the ground while (p->org[2] < p->end) { p->org[2] += (p->start - p->end); } if (p->type == P_WEATHER_TURBULENT) { p->vel[0] = crandom() * 16; p->vel[1] = crandom() * 16; } } } // Rafael snow pvs check if (!p->link) return; p->alpha = 1; } // Ridah, had to do this or MAX_POLYS is being exceeded in village1.bsp if (Distance( cg.snap->ps.origin, org ) > 1024) { return; } // done. if (p->type == P_BUBBLE || p->type == P_BUBBLE_TURBULENT) { VectorMA (org, -p->height, pvup, point); VectorMA (point, -p->width, pvright, point); VectorCopy (point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255 * p->alpha; VectorMA (org, -p->height, pvup, point); VectorMA (point, p->width, pvright, point); VectorCopy (point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255 * p->alpha; VectorMA (org, p->height, pvup, point); VectorMA (point, p->width, pvright, point); VectorCopy (point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255 * p->alpha; VectorMA (org, p->height, pvup, point); VectorMA (point, -p->width, pvright, point); VectorCopy (point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255 * p->alpha; } else { VectorMA (org, -p->height, pvup, point); VectorMA (point, -p->width, pvright, point); VectorCopy( point, TRIverts[0].xyz ); TRIverts[0].st[0] = 1; TRIverts[0].st[1] = 0; TRIverts[0].modulate[0] = 255; TRIverts[0].modulate[1] = 255; TRIverts[0].modulate[2] = 255; TRIverts[0].modulate[3] = 255 * p->alpha; VectorMA (org, p->height, pvup, point); VectorMA (point, -p->width, pvright, point); VectorCopy (point, TRIverts[1].xyz); TRIverts[1].st[0] = 0; TRIverts[1].st[1] = 0; TRIverts[1].modulate[0] = 255; TRIverts[1].modulate[1] = 255; TRIverts[1].modulate[2] = 255; TRIverts[1].modulate[3] = 255 * p->alpha; VectorMA (org, p->height, pvup, point); VectorMA (point, p->width, pvright, point); VectorCopy (point, TRIverts[2].xyz); TRIverts[2].st[0] = 0; TRIverts[2].st[1] = 1; TRIverts[2].modulate[0] = 255; TRIverts[2].modulate[1] = 255; TRIverts[2].modulate[2] = 255; TRIverts[2].modulate[3] = 255 * p->alpha; } } else if (p->type == P_SPRITE) { vec3_t rr, ru; vec3_t rotate_ang; VectorSet (color, 1.0, 1.0, 0.5); time = cg.time - p->time; time2 = p->endtime - p->time; ratio = time / time2; width = p->width + ( ratio * ( p->endwidth - p->width) ); height = p->height + ( ratio * ( p->endheight - p->height) ); if (p->roll) { vectoangles( cg.refdef.viewaxis[0], rotate_ang ); rotate_ang[ROLL] += p->roll; AngleVectors ( rotate_ang, NULL, rr, ru); } if (p->roll) { VectorMA (org, -height, ru, point); VectorMA (point, -width, rr, point); } else { VectorMA (org, -height, pvup, point); VectorMA (point, -width, pvright, point); } VectorCopy (point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; if (p->roll) { VectorMA (point, 2*height, ru, point); } else { VectorMA (point, 2*height, pvup, point); } VectorCopy (point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; if (p->roll) { VectorMA (point, 2*width, rr, point); } else { VectorMA (point, 2*width, pvright, point); } VectorCopy (point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; if (p->roll) { VectorMA (point, -2*height, ru, point); } else { VectorMA (point, -2*height, pvup, point); } VectorCopy (point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255; } else if (p->type == P_SMOKE || p->type == P_SMOKE_IMPACT) {// create a front rotating facing polygon if ( p->type == P_SMOKE_IMPACT && Distance( cg.snap->ps.origin, org ) > 1024) { return; } if (p->color == BLOODRED) VectorSet (color, 0.22f, 0.0f, 0.0f); else if (p->color == GREY75) { float len; float greyit; float val; len = Distance (cg.snap->ps.origin, org); if (!len) len = 1; val = 4096/len; greyit = 0.25 * val; if (greyit > 0.5) greyit = 0.5; VectorSet (color, greyit, greyit, greyit); } else VectorSet (color, 1.0, 1.0, 1.0); time = cg.time - p->time; time2 = p->endtime - p->time; ratio = time / time2; if (cg.time > p->startfade) { invratio = 1 - ( (cg.time - p->startfade) / (p->endtime - p->startfade) ); if (p->color == EMISIVEFADE) { float fval; fval = (invratio * invratio); if (fval < 0) fval = 0; VectorSet (color, fval , fval , fval ); } invratio *= p->alpha; } else invratio = 1 * p->alpha; if (invratio > 1) invratio = 1; width = p->width + ( ratio * ( p->endwidth - p->width) ); height = p->height + ( ratio * ( p->endheight - p->height) ); if (p->type != P_SMOKE_IMPACT) { vec3_t temp; vectoangles (rforward, temp); p->accumroll += p->roll; temp[ROLL] += p->accumroll * 0.1; AngleVectors ( temp, NULL, rright2, rup2); } else { VectorCopy (rright, rright2); VectorCopy (rup, rup2); } if (p->rotate) { VectorMA (org, -height, rup2, point); VectorMA (point, -width, rright2, point); } else { VectorMA (org, -p->height, pvup, point); VectorMA (point, -p->width, pvright, point); } VectorCopy (point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255 * color[0]; verts[0].modulate[1] = 255 * color[1]; verts[0].modulate[2] = 255 * color[2]; verts[0].modulate[3] = 255 * invratio; if (p->rotate) { VectorMA (org, -height, rup2, point); VectorMA (point, width, rright2, point); } else { VectorMA (org, -p->height, pvup, point); VectorMA (point, p->width, pvright, point); } VectorCopy (point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255 * color[0]; verts[1].modulate[1] = 255 * color[1]; verts[1].modulate[2] = 255 * color[2]; verts[1].modulate[3] = 255 * invratio; if (p->rotate) { VectorMA (org, height, rup2, point); VectorMA (point, width, rright2, point); } else { VectorMA (org, p->height, pvup, point); VectorMA (point, p->width, pvright, point); } VectorCopy (point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255 * color[0]; verts[2].modulate[1] = 255 * color[1]; verts[2].modulate[2] = 255 * color[2]; verts[2].modulate[3] = 255 * invratio; if (p->rotate) { VectorMA (org, height, rup2, point); VectorMA (point, -width, rright2, point); } else { VectorMA (org, p->height, pvup, point); VectorMA (point, -p->width, pvright, point); } VectorCopy (point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255 * color[0]; verts[3].modulate[1] = 255 * color[1]; verts[3].modulate[2] = 255 * color[2]; verts[3].modulate[3] = 255 * invratio; } else if (p->type == P_BLEED) { vec3_t rr, ru; vec3_t rotate_ang; float alpha; alpha = p->alpha; if (p->roll) { vectoangles( cg.refdef.viewaxis[0], rotate_ang ); rotate_ang[ROLL] += p->roll; AngleVectors ( rotate_ang, NULL, rr, ru); } else { VectorCopy (pvup, ru); VectorCopy (pvright, rr); } VectorMA (org, -p->height, ru, point); VectorMA (point, -p->width, rr, point); VectorCopy (point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 111; verts[0].modulate[1] = 19; verts[0].modulate[2] = 9; verts[0].modulate[3] = 255 * alpha; VectorMA (org, -p->height, ru, point); VectorMA (point, p->width, rr, point); VectorCopy (point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 111; verts[1].modulate[1] = 19; verts[1].modulate[2] = 9; verts[1].modulate[3] = 255 * alpha; VectorMA (org, p->height, ru, point); VectorMA (point, p->width, rr, point); VectorCopy (point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 111; verts[2].modulate[1] = 19; verts[2].modulate[2] = 9; verts[2].modulate[3] = 255 * alpha; VectorMA (org, p->height, ru, point); VectorMA (point, -p->width, rr, point); VectorCopy (point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 111; verts[3].modulate[1] = 19; verts[3].modulate[2] = 9; verts[3].modulate[3] = 255 * alpha; } else if (p->type == P_FLAT_SCALEUP) { float width, height; float sinR, cosR; if (p->color == BLOODRED) VectorSet (color, 1, 1, 1); else VectorSet (color, 0.5, 0.5, 0.5); time = cg.time - p->time; time2 = p->endtime - p->time; ratio = time / time2; width = p->width + ( ratio * ( p->endwidth - p->width) ); height = p->height + ( ratio * ( p->endheight - p->height) ); if (width > p->endwidth) width = p->endwidth; if (height > p->endheight) height = p->endheight; sinR = height * sin(DEG2RAD(p->roll)) * sqrt(2); cosR = width * cos(DEG2RAD(p->roll)) * sqrt(2); VectorCopy (org, verts[0].xyz); verts[0].xyz[0] -= sinR; verts[0].xyz[1] -= cosR; verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255 * color[0]; verts[0].modulate[1] = 255 * color[1]; verts[0].modulate[2] = 255 * color[2]; verts[0].modulate[3] = 255; VectorCopy (org, verts[1].xyz); verts[1].xyz[0] -= cosR; verts[1].xyz[1] += sinR; verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255 * color[0]; verts[1].modulate[1] = 255 * color[1]; verts[1].modulate[2] = 255 * color[2]; verts[1].modulate[3] = 255; VectorCopy (org, verts[2].xyz); verts[2].xyz[0] += sinR; verts[2].xyz[1] += cosR; verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255 * color[0]; verts[2].modulate[1] = 255 * color[1]; verts[2].modulate[2] = 255 * color[2]; verts[2].modulate[3] = 255; VectorCopy (org, verts[3].xyz); verts[3].xyz[0] += cosR; verts[3].xyz[1] -= sinR; verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255 * color[0]; verts[3].modulate[1] = 255 * color[1]; verts[3].modulate[2] = 255 * color[2]; verts[3].modulate[3] = 255; } else if (p->type == P_FLAT) { VectorCopy (org, verts[0].xyz); verts[0].xyz[0] -= p->height; verts[0].xyz[1] -= p->width; verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; VectorCopy (org, verts[1].xyz); verts[1].xyz[0] -= p->height; verts[1].xyz[1] += p->width; verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; VectorCopy (org, verts[2].xyz); verts[2].xyz[0] += p->height; verts[2].xyz[1] += p->width; verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; VectorCopy (org, verts[3].xyz); verts[3].xyz[0] += p->height; verts[3].xyz[1] -= p->width; verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255; } // Ridah else if (p->type == P_ANIM) { vec3_t rr, ru; vec3_t rotate_ang; int i, j; time = cg.time - p->time; time2 = p->endtime - p->time; ratio = time / time2; if (ratio >= 1.0f) { ratio = 0.9999f; } width = p->width + ( ratio * ( p->endwidth - p->width) ); height = p->height + ( ratio * ( p->endheight - p->height) ); // if we are "inside" this sprite, don't draw if (Distance( cg.snap->ps.origin, org ) < width/1.5) { return; } i = p->shaderAnim; j = (int)floor(ratio * shaderAnimCounts[p->shaderAnim]); p->pshader = shaderAnims[i][j]; if (p->roll) { vectoangles( cg.refdef.viewaxis[0], rotate_ang ); rotate_ang[ROLL] += p->roll; AngleVectors ( rotate_ang, NULL, rr, ru); } if (p->roll) { VectorMA (org, -height, ru, point); VectorMA (point, -width, rr, point); } else { VectorMA (org, -height, pvup, point); VectorMA (point, -width, pvright, point); } VectorCopy (point, verts[0].xyz); verts[0].st[0] = 0; verts[0].st[1] = 0; verts[0].modulate[0] = 255; verts[0].modulate[1] = 255; verts[0].modulate[2] = 255; verts[0].modulate[3] = 255; if (p->roll) { VectorMA (point, 2*height, ru, point); } else { VectorMA (point, 2*height, pvup, point); } VectorCopy (point, verts[1].xyz); verts[1].st[0] = 0; verts[1].st[1] = 1; verts[1].modulate[0] = 255; verts[1].modulate[1] = 255; verts[1].modulate[2] = 255; verts[1].modulate[3] = 255; if (p->roll) { VectorMA (point, 2*width, rr, point); } else { VectorMA (point, 2*width, pvright, point); } VectorCopy (point, verts[2].xyz); verts[2].st[0] = 1; verts[2].st[1] = 1; verts[2].modulate[0] = 255; verts[2].modulate[1] = 255; verts[2].modulate[2] = 255; verts[2].modulate[3] = 255; if (p->roll) { VectorMA (point, -2*height, ru, point); } else { VectorMA (point, -2*height, pvup, point); } VectorCopy (point, verts[3].xyz); verts[3].st[0] = 1; verts[3].st[1] = 0; verts[3].modulate[0] = 255; verts[3].modulate[1] = 255; verts[3].modulate[2] = 255; verts[3].modulate[3] = 255; } // done. if (!p->pshader) { // (SA) temp commented out for DM // CG_Printf ("CG_AddParticleToScene type %d p->pshader == ZERO\n", p->type); return; } if (p->type == P_WEATHER || p->type == P_WEATHER_TURBULENT || p->type == P_WEATHER_FLURRY) trap_R_AddPolyToScene( p->pshader, 3, TRIverts ); else trap_R_AddPolyToScene( p->pshader, 4, verts ); }