/* ============= CG_AddPlayerWeapon Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL) The main player will have this called for BOTH cases, so effects like light and sound should only be done on the world model case. ============= */ void CG_AddPlayerWeapon( refEntity_t *parent, qboolean firstPerson, centity_t *cent, int team ) { refEntity_t gun; refEntity_t barrel; refEntity_t flash; vec3_t angles; weapon_t weaponNum; weaponInfo_t *weapon; centity_t *nonPredictedCent; const cgWeaponFX_t *weaponFX; weaponNum = cent->currentState.weapon; CG_RegisterWeapon( weaponNum ); weapon = &cg_weapons[weaponNum]; weaponFX = CG_FindWeaponFX( weaponNum ); // add the weapon memset( &gun, 0, sizeof( gun ) ); VectorCopy( parent->lightingOrigin, gun.lightingOrigin ); gun.shadowPlane = parent->shadowPlane; gun.renderfx = parent->renderfx; // set custom shading for railgun refire rate if ( cent->currentState.weapon == WP_RAILGUN ) { clientInfo_t *ci = &cgs.clientinfo[ cent->currentState.clientNum ]; if ( cent->pe.railFireTime + 1500 > cg.time ) { int scale = 255 * ((cg.time - cent->pe.railFireTime) + cg.timeFraction) / 1500; gun.shaderRGBA[0] = (ci->c1RGBA[0] * scale) >> 8; gun.shaderRGBA[1] = (ci->c1RGBA[1] * scale) >> 8; gun.shaderRGBA[2] = (ci->c1RGBA[2] * scale) >> 8; gun.shaderRGBA[3] = 255; } else {
static void CG_LoadWeapons_f( void ) { int i; for( i = WP_KNIFE; i < WP_NUM_WEAPONS; i++ ) { // DHM - Nerve :: Only register weapons we use in WolfMP if( BG_WeaponInWolfMP( i ) ) CG_RegisterWeapon( i, qtrue ); } }
/* =============== CG_InitWeapons Precaches weapons =============== */ void CG_InitWeapons( void ) { int i; memset( cg_weapons, 0, sizeof( cg_weapons ) ); for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) CG_RegisterWeapon( i ); cgs.media.level2ZapTS = CG_RegisterTrailSystem( "models/weapons/lev2zap/lightning" ); }
// The server says this item is used on this level void CG_RegisterItemVisuals( int itemNum ) { int handle; if ( itemNum < 0 || itemNum >= (int)bg_numItems ) { trap->Error( ERR_DROP, "CG_RegisterItemVisuals: itemNum %d out of range [0-%d]", itemNum, bg_numItems - 1 ); return; } itemInfo_t *itemInfo = &cg_items[itemNum]; if ( itemInfo->registered ) { return; } memset( itemInfo, 0, sizeof(*itemInfo) ); itemInfo->registered = qtrue; const gitem_t *item = &bg_itemlist[itemNum]; if ( item->giType == IT_TEAM && cgs.gametype == GT_CTY && (item->giTag == PW_REDFLAG || item->giTag == PW_BLUEFLAG) ) { itemInfo->models[0] = trap->R_RegisterModel( item->world_model[1] ); } else if ( item->giType == IT_WEAPON && (item->giTag == WP_THERMAL || item->giTag == WP_TRIP_MINE || item->giTag == WP_DET_PACK) ) { itemInfo->models[0] = trap->R_RegisterModel( item->world_model[1] ); } else { itemInfo->models[0] = trap->R_RegisterModel( item->world_model[0] ); } if ( !Q_stricmp( &item->world_model[0][strlen( item->world_model[0] ) - 4], ".glm" ) ) { handle = trap->G2API_InitGhoul2Model( &itemInfo->g2Models[0], item->world_model[0], 0, 0, 0, 0, 0 ); if ( handle < 0 ) { itemInfo->g2Models[0] = NULL; } else { itemInfo->radius[0] = 60; } } if ( item->icon ) itemInfo->icon = trap->R_RegisterShaderNoMip( item->icon ); else itemInfo->icon = 0; if ( item->giType == IT_WEAPON ) CG_RegisterWeapon( item->giTag ); // powerups have an accompanying ring or sphere if ( item->giType == IT_POWERUP || item->giType == IT_HEALTH || item->giType == IT_ARMOR || item->giType == IT_HOLDABLE ) { if ( item->world_model[1] ) itemInfo->models[1] = trap->R_RegisterModel( item->world_model[1] ); } }
/* ================= CG_RegisterItemVisuals The server says this item is used on this level ================= */ void CG_RegisterItemVisuals( int itemNum ) { itemInfo_t *itemInfo; gitem_t *item; if ( itemNum < 0 || itemNum >= bg_numItems ) { CG_Error( "CG_RegisterItemVisuals: itemNum %d out of range [0-%d]", itemNum, bg_numItems-1 ); } itemInfo = &cg_items[ itemNum ]; if ( itemInfo->registered ) { return; } item = &bg_itemlist[ itemNum ]; memset( itemInfo, 0, sizeof( &itemInfo ) ); itemInfo->registered = qtrue; itemInfo->models[0] = trap_R_RegisterModel( item->world_model[0] ); itemInfo->icon = trap_R_RegisterShader( item->icon ); if ( item->giType == IT_WEAPON ) { CG_RegisterWeapon( item->giTag ); } // // powerups have an accompanying ring or sphere // if ( item->giType == IT_POWERUP || item->giType == IT_HEALTH || item->giType == IT_ARMOR || item->giType == IT_HOLDABLE ) { if ( item->world_model[1] ) { itemInfo->models[1] = trap_R_RegisterModel( item->world_model[1] ); } } }
void TurretClientRun(centity_t *ent) { if (!ent->ghoul2) { weaponInfo_t *weaponInfo; trap_G2API_InitGhoul2Model(&ent->ghoul2, CG_ConfigString( CS_MODELS+ent->currentState.modelindex ), 0, 0, 0, 0, 0); if (!ent->ghoul2) { //bad return; } ent->torsoBolt = trap_G2API_AddBolt( ent->ghoul2, 0, "*flash02" ); trap_G2API_SetBoneAngles( ent->ghoul2, 0, "bone_hinge", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL, 100, cg.time ); trap_G2API_SetBoneAngles( ent->ghoul2, 0, "bone_gback", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL, 100, cg.time ); trap_G2API_SetBoneAngles( ent->ghoul2, 0, "bone_barrel", vec3_origin, BONE_ANGLES_POSTMULT, POSITIVE_Y, POSITIVE_Z, POSITIVE_X, NULL, 100, cg.time ); trap_G2API_SetBoneAnim( ent->ghoul2, 0, "model_root", 0, 11, BONE_ANIM_OVERRIDE_FREEZE, 0.8f, cg.time, 0, 0 ); ent->turAngles[ROLL] = 0; ent->turAngles[PITCH] = 90; ent->turAngles[YAW] = 0; weaponInfo = &cg_weapons[WP_TURRET]; if ( !weaponInfo->registered ) { CG_RegisterWeapon(WP_TURRET); } } if (ent->currentState.fireflag == 2) { //I'm about to blow if (ent->turAngles) { trap_G2API_SetBoneAngles( ent->ghoul2, 0, "bone_hinge", ent->turAngles, BONE_ANGLES_REPLACE, NEGATIVE_Y, NEGATIVE_Z, NEGATIVE_X, NULL, 100, cg.time ); } return; } else if (ent->currentState.fireflag && ent->bolt4 != ent->currentState.fireflag) { vec3_t muzzleOrg, muzzleDir; mdxaBone_t boltMatrix; trap_G2API_GetBoltMatrix(ent->ghoul2, 0, ent->torsoBolt, &boltMatrix, /*ent->lerpAngles*/vec3_origin, ent->lerpOrigin, cg.time, cgs.gameModels, ent->modelScale); BG_GiveMeVectorFromMatrix(&boltMatrix, ORIGIN, muzzleOrg); BG_GiveMeVectorFromMatrix(&boltMatrix, NEGATIVE_X, muzzleDir); trap_FX_PlayEffectID(cgs.effects.mTurretMuzzleFlash, muzzleOrg, muzzleDir, -1, -1); ent->bolt4 = ent->currentState.fireflag; } else if (!ent->currentState.fireflag) { ent->bolt4 = 0; } if (ent->currentState.bolt2 != ENTITYNUM_NONE) { //turn toward the enemy centity_t *enemy = &cg_entities[ent->currentState.bolt2]; if (enemy) { vec3_t enAng; vec3_t enPos; VectorCopy(enemy->currentState.pos.trBase, enPos); VectorSubtract(enPos, ent->lerpOrigin, enAng); VectorNormalize(enAng); vectoangles(enAng, enAng); enAng[ROLL] = 0; enAng[PITCH] += 90; CreepToPosition(enAng, ent->turAngles); } } else { vec3_t idleAng; float turnAmount; if (ent->turAngles[YAW] > 360) { ent->turAngles[YAW] -= 361; } if (!ent->dustTrailTime) { ent->dustTrailTime = cg.time; } turnAmount = (cg.time-ent->dustTrailTime)*0.03; if (turnAmount > 360) { turnAmount = 360; } idleAng[PITCH] = 90; idleAng[ROLL] = 0; idleAng[YAW] = ent->turAngles[YAW] + turnAmount; ent->dustTrailTime = cg.time; CreepToPosition(idleAng, ent->turAngles); } if (cg.time < ent->frame_minus1_refreshed) { ent->frame_minus1_refreshed = cg.time; return; } ent->frame_minus1_refreshed = cg.time; trap_G2API_SetBoneAngles( ent->ghoul2, 0, "bone_hinge", ent->turAngles, BONE_ANGLES_REPLACE, NEGATIVE_Y, NEGATIVE_Z, NEGATIVE_X, NULL, 100, cg.time ); }
/* ================ CG_ParseServerinfo This is called explicitly when the gamestate is first received, and whenever the server updates any serverinfo flagged cvars ================ */ void CG_ParseServerinfo( void ) { const char *info = NULL, *tinfo = NULL; char *mapname; int i, value; info = CG_ConfigString( CS_SERVERINFO ); cgs.debugMelee = atoi( Info_ValueForKey( info, "g_debugMelee" ) ); //trap->Cvar_GetHiddenVarValue("g_iknowkungfu"); cgs.stepSlideFix = atoi( Info_ValueForKey( info, "g_stepSlideFix" ) ); cgs.noSpecMove = atoi( Info_ValueForKey( info, "g_noSpecMove" ) ); cgs.siegeTeamSwitch = atoi( Info_ValueForKey( info, "g_siegeTeamSwitch" ) ); cgs.showDuelHealths = atoi( Info_ValueForKey( info, "g_showDuelHealths" ) ); cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) ); trap->Cvar_Set("g_gametype", va("%i", cgs.gametype)); cgs.needpass = atoi( Info_ValueForKey( info, "g_needpass" ) ); cgs.jediVmerc = atoi( Info_ValueForKey( info, "g_jediVmerc" ) ); // this changes on map_restart, attempt to precache weapons value = atoi( Info_ValueForKey( info, "g_weaponDisable" ) ); if ( cgs.wDisable != value ) { gitem_t *item = NULL; itemInfo_t *itemInfo = NULL; cgs.wDisable = value; for ( i=1, item=bg_itemlist, itemInfo = cg_items; i<bg_numItems; i++, item++, itemInfo++ ) {// register all weapons that aren't disabled if ( item->giType == IT_WEAPON ) CG_RegisterWeapon( item->giTag ); } } cgs.fDisable = atoi( Info_ValueForKey( info, "g_forcePowerDisable" ) ); cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) ); cgs.duel_fraglimit = atoi( Info_ValueForKey( info, "duel_fraglimit" ) ); cgs.capturelimit = atoi( Info_ValueForKey( info, "capturelimit" ) ); // reset fraglimit warnings i = atoi( Info_ValueForKey( info, "fraglimit" ) ); if ( cgs.fraglimit < i ) cg.fraglimitWarnings &= ~(1|2|4); cgs.fraglimit = i; // reset timelimit warnings i = atoi( Info_ValueForKey( info, "timelimit" ) ); if ( cgs.timelimit != i ) cg.timelimitWarnings &= ~(1|2); cgs.timelimit = i; cgs.maxclients = Com_Clampi( 0, MAX_CLIENTS, atoi( Info_ValueForKey( info, "sv_maxclients" ) ) ); mapname = Info_ValueForKey( info, "mapname" ); //rww - You must do this one here, Info_ValueForKey always uses the same memory pointer. trap->Cvar_Set ( "ui_about_mapname", mapname ); Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", mapname ); // Q_strncpyz( cgs.redTeam, Info_ValueForKey( info, "g_redTeam" ), sizeof(cgs.redTeam) ); // trap->Cvar_Set("g_redTeam", cgs.redTeam); // Q_strncpyz( cgs.blueTeam, Info_ValueForKey( info, "g_blueTeam" ), sizeof(cgs.blueTeam) ); // trap->Cvar_Set("g_blueTeam", cgs.blueTeam); trap->Cvar_Set ( "ui_about_gametype", va("%i", cgs.gametype ) ); trap->Cvar_Set ( "ui_about_fraglimit", va("%i", cgs.fraglimit ) ); trap->Cvar_Set ( "ui_about_duellimit", va("%i", cgs.duel_fraglimit ) ); trap->Cvar_Set ( "ui_about_capturelimit", va("%i", cgs.capturelimit ) ); trap->Cvar_Set ( "ui_about_timelimit", va("%i", cgs.timelimit ) ); trap->Cvar_Set ( "ui_about_maxclients", va("%i", cgs.maxclients ) ); trap->Cvar_Set ( "ui_about_dmflags", va("%i", cgs.dmflags ) ); trap->Cvar_Set ( "ui_about_hostname", Info_ValueForKey( info, "sv_hostname" ) ); trap->Cvar_Set ( "ui_about_needpass", Info_ValueForKey( info, "g_needpass" ) ); trap->Cvar_Set ( "ui_about_botminplayers", Info_ValueForKey ( info, "bot_minplayers" ) ); //Set the siege teams based on what the server has for overrides. trap->Cvar_Set("cg_siegeTeam1", Info_ValueForKey(info, "g_siegeTeam1")); trap->Cvar_Set("cg_siegeTeam2", Info_ValueForKey(info, "g_siegeTeam2")); tinfo = CG_ConfigString( CS_TERRAINS + 1 ); if ( !tinfo || !*tinfo ) { cg.mInRMG = qfalse; } else { int weather = 0; cg.mInRMG = qtrue; trap->Cvar_Set("RMG", "1"); weather = atoi( Info_ValueForKey( info, "RMG_weather" ) ); trap->Cvar_Set("RMG_weather", va("%i", weather)); if (weather == 1 || weather == 2) { cg.mRMGWeather = qtrue; } else { cg.mRMGWeather = qfalse; } } Q_strncpyz( cgs.voteString, CG_ConfigString( CS_VOTE_STRING ), sizeof( cgs.voteString ) ); // synchronise our expected snaps/sec with the server's framerate i = atoi( Info_ValueForKey( info, "sv_fps" ) ); if ( i ) trap->Cvar_Set( "snaps", va( "%i", i ) ); }
void CG_DrawWeaponSelect( void ) { int i, bits, count, smallIconSize, bigIconSize, holdX, x, y, pad, sideLeftIconCnt, sideRightIconCnt, sideMax, holdCount, iconCnt, yOffset = 0; qboolean drewConc = qfalse; // can't cycle when on a weapon if ( cg.predictedPlayerState.emplacedIndex ) cg.weaponSelectTime = 0; // Time is up for the HUD to display if ( (cg.weaponSelectTime + WEAPON_SELECT_TIME) < cg.time ) return; // don't display if dead if ( cg.predictedPlayerState.stats[STAT_HEALTH] <= 0 ) return; // showing weapon select clears pickup item display, but not the blend blob cg.itemPickupTime = 0; bits = cg.predictedPlayerState.stats[STAT_WEAPONS]; // count the number of weapons owned count = 0; // display this weapon that we don't actually "have" as unhighlighted until it's deselected // since it's selected we must increase the count to display the proper number of valid selectable weapons if ( !CG_WeaponSelectable( cg.weaponSelect ) && (cg.weaponSelect == WP_THERMAL || cg.weaponSelect == WP_TRIP_MINE) ) count++; for ( i = 1; i < WP_NUM_WEAPONS; i++ ) { if ( bits & (1 << i) ) { if ( CG_WeaponSelectable( i ) || (i != WP_THERMAL && i != WP_TRIP_MINE) ) count++; } } if ( !count ) // If no weapons, don't display return; sideMax = 3; // Max number of icons on the side // Calculate how many icons will appear to either side of the center one holdCount = count - 1; // -1 for the center icon if ( holdCount == 0 ) { // No icons to either side sideLeftIconCnt = 0; sideRightIconCnt = 0; } else if ( count > (2 * sideMax) ) { // Go to the max on each side sideLeftIconCnt = sideMax; sideRightIconCnt = sideMax; } else { // Less than max, so do the calc sideLeftIconCnt = holdCount / 2; sideRightIconCnt = holdCount - sideLeftIconCnt; } if ( cg.weaponSelect == WP_CONCUSSION ) i = WP_FLECHETTE; else i = cg.weaponSelect - 1; if ( i < 1 ) i = LAST_USEABLE_WEAPON; smallIconSize = 40; bigIconSize = 80; pad = 12; x = (SCREEN_WIDTH / 2); y = 410; // Left side ICONS trap->R_SetColor( &colorTable[CT_WHITE] ); // Work backwards from current icon holdX = x - ((bigIconSize / 2) + pad + smallIconSize) * cgs.widthRatioCoef; drewConc = qfalse; for ( iconCnt = 1; iconCnt < (sideLeftIconCnt + 1); i-- ) { if ( i == WP_CONCUSSION ) i--; else if ( i == WP_FLECHETTE && !drewConc && cg.weaponSelect != WP_CONCUSSION ) i = WP_CONCUSSION; if ( i < 1 ) i = LAST_USEABLE_WEAPON; // Does he have this weapon? if ( !(bits & (1 << i)) ) { if ( i == WP_CONCUSSION ) { drewConc = qtrue; i = WP_ROCKET_LAUNCHER; } continue; } // Don't show thermal and tripmine when out of them if ( !CG_WeaponSelectable( i ) && (i == WP_THERMAL || i == WP_TRIP_MINE) ) continue; ++iconCnt; // Good icon if ( media.gfx.interface.weaponIcons[i] ) { CG_RegisterWeapon( i ); trap->R_SetColor( &colorTable[CT_WHITE] ); if ( !CG_WeaponCheck( i ) ) CG_DrawPic(holdX, y + 10 + yOffset, smallIconSize * cgs.widthRatioCoef, smallIconSize, media.gfx.interface.weaponIconsInactive[i]); else CG_DrawPic(holdX, y + 10 + yOffset, smallIconSize * cgs.widthRatioCoef, smallIconSize, media.gfx.interface.weaponIcons[i]); holdX -= (smallIconSize + pad) * cgs.widthRatioCoef; } if ( i == WP_CONCUSSION ) { drewConc = qtrue; i = WP_ROCKET_LAUNCHER; } } // Current Center Icon if ( media.gfx.interface.weaponIcons[cg.weaponSelect] ) { CG_RegisterWeapon( cg.weaponSelect ); trap->R_SetColor( &colorTable[CT_WHITE] ); if ( !CG_WeaponCheck( cg.weaponSelect ) ) CG_DrawPic(x - (bigIconSize / 2 * cgs.widthRatioCoef), (y - ((bigIconSize - smallIconSize) / 2)) + 10 + yOffset, bigIconSize * cgs.widthRatioCoef, bigIconSize, media.gfx.interface.weaponIconsInactive[cg.weaponSelect]); else CG_DrawPic(x - (bigIconSize / 2 * cgs.widthRatioCoef), (y - ((bigIconSize - smallIconSize) / 2)) + 10 + yOffset, bigIconSize * cgs.widthRatioCoef, bigIconSize, media.gfx.interface.weaponIcons[cg.weaponSelect]); } if ( cg.weaponSelect == WP_CONCUSSION ) i = WP_ROCKET_LAUNCHER; else i = cg.weaponSelect + 1; if ( i > LAST_USEABLE_WEAPON ) i = 1; // Right side ICONS // Work forwards from current icon holdX = x + ((bigIconSize / 2) + pad) * cgs.widthRatioCoef; for ( iconCnt = 1; iconCnt<(sideRightIconCnt + 1); i++ ) { if ( i == WP_CONCUSSION ) i++; else if ( i == WP_ROCKET_LAUNCHER && !drewConc && cg.weaponSelect != WP_CONCUSSION ) i = WP_CONCUSSION; if ( i > LAST_USEABLE_WEAPON ) i = 1; if ( !(bits & (1 << i)) ) { if ( i == WP_CONCUSSION ) { drewConc = qtrue; i = WP_FLECHETTE; } continue; } // Don't show thermal and tripmine when out of them if ( !CG_WeaponSelectable( i ) && (i == WP_THERMAL || i == WP_TRIP_MINE) ) continue; ++iconCnt; // Good icon if ( media.gfx.interface.weaponIcons[i] ) { CG_RegisterWeapon( i ); // No ammo for this weapon? trap->R_SetColor( &colorTable[CT_WHITE] ); if ( !CG_WeaponCheck( i ) ) CG_DrawPic(holdX, y + 10 + yOffset, smallIconSize * cgs.widthRatioCoef, smallIconSize, media.gfx.interface.weaponIconsInactive[i]); else CG_DrawPic(holdX, y + 10 + yOffset, smallIconSize * cgs.widthRatioCoef, smallIconSize, media.gfx.interface.weaponIcons[i]); holdX += (smallIconSize + pad); } if ( i == WP_CONCUSSION ) { drewConc = qtrue; i = WP_FLECHETTE; } } // draw the selected name if ( cg_weapons[cg.weaponSelect].item ) { vector4 textColor = { .875f, .718f, .121f, 1.0f }; char upperKey[1024]; Com_sprintf( upperKey, sizeof(upperKey), "SP_INGAME_%s", cg_weapons[cg.weaponSelect].item->classname ); Q_strupr( upperKey ); const char *s = nullptr; char text[1024]; if ( trap->SE_GetStringTextString( upperKey, text, sizeof(text) ) ) { s = text; } else { s = cg_weapons[cg.weaponSelect].item->classname; } const Font font( FONT_SMALL, 1.0f, false ); const float width = font.Width( s ); font.Paint( (SCREEN_WIDTH / 2) - (width / 2.0f), y + 45 + yOffset, s, &textColor, ITEM_TEXTSTYLE_SHADOWED ); } trap->R_SetColor( NULL ); }
// Add the weapon, and flash for the player's view void CG_AddViewWeapon( playerState_t *ps ) { // no gun if in third person view or a camera is active if ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR || ps->pm_type == PM_INTERMISSION || cg.renderingThirdPerson ) { return; } const int weap = cg_fakeGun.integer ? cg_fakeGun.integer : ps->weapon; float desiredFov = 0.0f; if ( !cg.renderingThirdPerson && (cg_trueGuns.integer || weap == WP_SABER || weap == WP_MELEE) && cg_trueFOV.value && cg.predictedPlayerState.pm_type != PM_SPECTATOR && cg.predictedPlayerState.pm_type != PM_INTERMISSION ) { desiredFov = cg_fovViewmodel.integer ? cg_fovViewmodel.value : cg_trueFOV.value; } else { desiredFov = cg_fovViewmodel.integer ? cg_fovViewmodel.value : cg_fov.value; } desiredFov = Q_clampi( 1, desiredFov, 180 ); // allow the gun to be completely removed if ( !cg_fakeGun.integer && (!cg_drawGun.integer || cg.predictedPlayerState.zoomMode || cg_trueGuns.integer || weap == WP_SABER || weap == WP_MELEE) ) { return; } // don't draw if testing a gun model if ( cg.testGun ) { return; } centity_t *cent = &cg_entities[cg.predictedPlayerState.clientNum]; CG_RegisterWeapon( weap ); refEntity_t hand; memset( &hand, 0, sizeof(hand) ); // set up gun position vector3 angles; CG_CalculateWeaponPosition( &hand.origin, &angles ); refdef_t *refdef = CG_GetRefdef(); VectorMA( &hand.origin, cg.gunAlign.x, &refdef->viewaxis[0], &hand.origin ); VectorMA( &hand.origin, cg.gunAlign.y, &refdef->viewaxis[1], &hand.origin ); VectorMA( &hand.origin, cg.gunAlign.z, &refdef->viewaxis[2], &hand.origin ); AnglesToAxis( &angles, hand.axis ); if ( cg_fovViewmodel.integer ) { float fracDistFOV, fracWeapFOV; float fov = desiredFov; if ( cg_fovAspectAdjust.integer ) { // Based on LordHavoc's code for Darkplaces // http://www.quakeworld.nu/forum/topic/53/what-does-your-qw-look-like/page/30 const float baseAspect = 0.75f; // 3/4 const float aspect = (float)cgs.glconfig.vidWidth / (float)cgs.glconfig.vidHeight; fov = atanf( tanf( desiredFov*M_PI / 360.0f ) * baseAspect*aspect )*360.0f / M_PI; } fracDistFOV = tanf( refdef->fov_x * M_PI / 360.0f ); fracWeapFOV = (1.0f / fracDistFOV) * tanf( fov * M_PI / 360.0f ); VectorScale( &hand.axis[0], fracWeapFOV, &hand.axis[0] ); } // map torso animations to weapon animations if ( cg_debugGunFrame.integer ) { // development tool hand.frame = hand.oldframe = cg_debugGunFrame.integer; hand.backlerp = 0; } else { float currentFrame; // get clientinfo for animation map clientInfo_t *ci = nullptr; if ( cent->currentState.eType == ET_NPC ) { if ( !cent->npcClient ) { return; } ci = cent->npcClient; } else { ci = &cgs.clientinfo[cent->currentState.clientNum]; } // smoother first-person anims by eezstreet http://jkhub.org/topic/1499-/ // actually ported from SP #if 1 // Sil's fix trap->G2API_GetBoneFrame( cent->ghoul2, "lower_lumbar", cg.time, ¤tFrame, cgs.gameModels, 0 ); hand.frame = CG_MapTorsoToWeaponFrame( ci, ceilf( currentFrame ), cent->currentState.torsoAnim ); hand.oldframe = CG_MapTorsoToWeaponFrame( ci, floorf( currentFrame ), cent->currentState.torsoAnim ); hand.backlerp = 1.0f - (currentFrame - floorf( currentFrame )); #else // basejka style hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame, cent->currentState.torsoAnim ); hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame, cent->currentState.torsoAnim ); hand.backlerp = cent->pe.torso.backlerp; #endif // Handle the fringe situation where oldframe is invalid if ( hand.frame == -1 ) { hand.frame = 0; hand.oldframe = 0; hand.backlerp = 0; } else if ( hand.oldframe == -1 ) { hand.oldframe = hand.frame; hand.backlerp = 0; } } weaponInfo_t *wi = &cg_weapons[weap]; hand.hModel = wi->handsModel; hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON; // add everything onto the hand CG_AddPlayerWeapon( &hand, ps, &cg_entities[cg.predictedPlayerState.clientNum], ps->persistant[PERS_TEAM], &angles, qfalse ); }
// Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL) // The main player will have this called for BOTH cases, so effects like light and sound should only be done on the // world model case. void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent, int team, vector3 *newAngles, qboolean thirdPerson ) { refEntity_t gun, barrel, flash; vector3 angles; weapon_t weaponNum; weaponInfo_t *weapon; centity_t *nonPredictedCent; if ( !thirdPerson && cg_fakeGun.integer ) { weaponNum = (weapon_t)cg_fakeGun.integer; } else { weaponNum = (weapon_t)cent->currentState.weapon; } if ( weaponNum == WP_EMPLACED_GUN ) return; // spectator mode, don't draw it... if ( cg.predictedPlayerState.pm_type == PM_SPECTATOR && cent->currentState.number == cg.predictedPlayerState.clientNum ) { return; } CG_RegisterWeapon( weaponNum ); weapon = &cg_weapons[weaponNum]; memset( &gun, 0, sizeof(gun) ); // only do this if we are in first person, since world weapons are now handled on the server by Ghoul2 if ( !thirdPerson ) { // add the weapon VectorCopy( &parent->lightingOrigin, &gun.lightingOrigin ); gun.shadowPlane = parent->shadowPlane; gun.renderfx = parent->renderfx; // this player, in first person view if ( ps ) gun.hModel = weapon->viewModel; else gun.hModel = weapon->weaponModel; if ( !gun.hModel ) return; if ( !ps ) { // add weapon ready sound if ( (cent->currentState.eFlags & EF_FIRING) && weapon->firingSound ) { trap->S_AddLoopingSound( cent->currentState.number, ¢->lerpOrigin, &vec3_origin, weapon->firingSound ); } else if ( weapon->readySound ) { trap->S_AddLoopingSound( cent->currentState.number, ¢->lerpOrigin, &vec3_origin, weapon->readySound ); } } CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon" ); if ( !CG_IsMindTricked( cent->currentState.trickedEntIndex, cg.snap->ps.clientNum ) ) { // don't draw the weapon if the player is invisible CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups ); } if ( weaponNum == WP_STUN_BATON ) { int i; for ( i = 0; i < 3; i++ ) { memset( &barrel, 0, sizeof(barrel) ); VectorCopy( &parent->lightingOrigin, &barrel.lightingOrigin ); barrel.shadowPlane = parent->shadowPlane; barrel.renderfx = parent->renderfx; if ( i == 0 ) { barrel.hModel = trap->R_RegisterModel( "models/weapons2/stun_baton/baton_barrel.md3" ); } else if ( i == 1 ) { barrel.hModel = trap->R_RegisterModel( "models/weapons2/stun_baton/baton_barrel2.md3" ); } else { barrel.hModel = trap->R_RegisterModel( "models/weapons2/stun_baton/baton_barrel3.md3" ); } angles.yaw = 0; angles.pitch = 0; angles.roll = 0; AnglesToAxis( &angles, barrel.axis ); if ( i == 0 ) { CG_PositionRotatedEntityOnTag( &barrel, parent, weapon->handsModel, "tag_barrel" ); } else if ( i == 1 ) { CG_PositionRotatedEntityOnTag( &barrel, parent, weapon->handsModel, "tag_barrel2" ); } else { CG_PositionRotatedEntityOnTag( &barrel, parent, weapon->handsModel, "tag_barrel3" ); } CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups ); } } else { // add the spinning barrel if ( weapon->barrelModel ) { memset( &barrel, 0, sizeof(barrel) ); VectorCopy( &parent->lightingOrigin, &barrel.lightingOrigin ); barrel.shadowPlane = parent->shadowPlane; barrel.renderfx = parent->renderfx; barrel.hModel = weapon->barrelModel; angles.yaw = 0; angles.pitch = 0; angles.roll = 0; AnglesToAxis( &angles, barrel.axis ); CG_PositionRotatedEntityOnTag( &barrel, parent, weapon->handsModel, "tag_barrel" ); CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups ); } } } memset( &flash, 0, sizeof(flash) ); CG_PositionEntityOnTag( &flash, &gun, gun.hModel, "tag_flash" ); VectorCopy( &flash.origin, &cg.lastFPFlashPoint ); // Do special charge bits // Make the guns do their charging visual in True View. if ( (ps || cg.renderingThirdPerson || cg.predictedPlayerState.clientNum != cent->currentState.number || cg_trueGuns.integer) && ((cent->currentState.modelindex2 == WEAPON_CHARGING_ALT && weaponNum == WP_BRYAR_PISTOL) || (cent->currentState.modelindex2 == WEAPON_CHARGING_ALT && weaponNum == WP_BRYAR_OLD) || (weaponNum == WP_BOWCASTER && cent->currentState.modelindex2 == WEAPON_CHARGING) || (weaponNum == WP_DEMP2 && cent->currentState.modelindex2 == WEAPON_CHARGING_ALT)) ) { int shader = 0; float val = 0.0f; float scale = 1.0f; addspriteArgStruct_t fxSArgs; vector3 flashorigin, flashdir; if ( !thirdPerson ) { VectorCopy( &flash.origin, &flashorigin ); VectorCopy( &flash.axis[0], &flashdir ); } else { mdxaBone_t boltMatrix; // it's quite possible that we may have have no weapon model and be in a valid state, so return here if this is the case if ( !trap->G2API_HasGhoul2ModelOnIndex( &(cent->ghoul2), 1 ) ) return; // Couldn't find bolt point. if ( !trap->G2API_GetBoltMatrix( cent->ghoul2, 1, 0, &boltMatrix, newAngles, ¢->lerpOrigin, cg.time, cgs.gameModels, ¢->modelScale ) ) { return; } BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, &flashorigin ); BG_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_X, &flashdir ); } if ( weaponNum == WP_BRYAR_PISTOL || weaponNum == WP_BRYAR_OLD ) { // Hardcoded max charge time of 1 second val = (cg.time - cent->currentState.constantLight) * 0.001f; shader = media.gfx.world.bryarFrontFlash; } else if ( weaponNum == WP_BOWCASTER ) { // Hardcoded max charge time of 1 second val = (cg.time - cent->currentState.constantLight) * 0.001f; shader = media.gfx.world.greenFrontFlash; } else if ( weaponNum == WP_DEMP2 ) { val = (cg.time - cent->currentState.constantLight) * 0.001f; shader = media.gfx.world.lightningFlash; scale = 1.75f; } if ( val < 0.0f ) val = 0.0f; else if ( val > 1.0f ) { val = 1.0f; if ( ps && cent->currentState.number == ps->clientNum ) CGCam_Shake( 0.2f, 100 ); } else if ( ps && cent->currentState.number == ps->clientNum ) CGCam_Shake( val * val * 0.6f, 100 ); val += random() * 0.5f; VectorCopy( &flashorigin, &fxSArgs.origin ); VectorClear( &fxSArgs.vel ); VectorClear( &fxSArgs.accel ); fxSArgs.scale = 3.0f*val*scale; fxSArgs.dscale = 0.0f; fxSArgs.sAlpha = 0.7f; fxSArgs.eAlpha = 0.7f; fxSArgs.rotation = random() * 360; fxSArgs.bounce = 0.0f; fxSArgs.life = 1.0f; fxSArgs.shader = shader; fxSArgs.flags = 0x08000000; trap->FX_AddSprite( &fxSArgs ); } // make sure we aren't looking at cg.predictedPlayerEntity for LG nonPredictedCent = &cg_entities[cent->currentState.clientNum]; // if the index of the nonPredictedCent is not the same as the clientNum then this is a fake player (like on the // single player podiums), so go ahead and use the cent if ( nonPredictedCent - cg_entities != cent->currentState.clientNum ) nonPredictedCent = cent; // add the flash if ( weaponNum != WP_DEMP2 || (nonPredictedCent->currentState.eFlags & EF_FIRING) ) { // impulse flash if ( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME ) return; } if ( ps || cg.renderingThirdPerson || cg_trueGuns.integer || cent->currentState.number != cg.predictedPlayerState.clientNum ) { // Make sure we don't do the thirdperson model effects for the local player if we're in first person vector3 flashorigin, flashdir; refEntity_t tpflash; memset( &tpflash, 0, sizeof(tpflash) ); if ( !thirdPerson ) { CG_PositionEntityOnTag( &tpflash, &gun, gun.hModel, "tag_flash" ); VectorCopy( &tpflash.origin, &flashorigin ); VectorCopy( &tpflash.axis[0], &flashdir ); } else { mdxaBone_t boltMatrix; // it's quite possible that we may have have no weapon model and be in a valid state, so return here if this is the case if ( !trap->G2API_HasGhoul2ModelOnIndex( &(cent->ghoul2), 1 ) ) return; // Couldn't find bolt point. if ( !trap->G2API_GetBoltMatrix( cent->ghoul2, 1, 0, &boltMatrix, newAngles, ¢->lerpOrigin, cg.time, cgs.gameModels, ¢->modelScale ) ) return; BG_GiveMeVectorFromMatrix( &boltMatrix, ORIGIN, &flashorigin ); BG_GiveMeVectorFromMatrix( &boltMatrix, POSITIVE_X, &flashdir ); } if ( cg.time - cent->muzzleFlashTime <= MUZZLE_FLASH_TIME + 10 ) { // Handle muzzle flashes if ( cent->currentState.eFlags & EF_ALT_FIRING ) { // Check the alt firing first. if ( weapon->altMuzzleEffect ) { if ( !thirdPerson ) trap->FX_PlayEntityEffectID( weapon->altMuzzleEffect, &flashorigin, tpflash.axis, -1, -1, -1, -1 ); else trap->FX_PlayEffectID( weapon->altMuzzleEffect, &flashorigin, &flashdir, -1, -1, qfalse ); } } else { // Regular firing if ( weapon->muzzleEffect ) { if ( !thirdPerson ) trap->FX_PlayEntityEffectID( weapon->muzzleEffect, &flashorigin, tpflash.axis, -1, -1, -1, -1 ); else trap->FX_PlayEffectID( weapon->muzzleEffect, &flashorigin, &flashdir, -1, -1, qfalse ); } } } if ( weapon->flashDlightColor.r || weapon->flashDlightColor.g || weapon->flashDlightColor.b ) { trap->R_AddLightToScene( &flashorigin, 300 + (rand() & 31), weapon->flashDlightColor.r, weapon->flashDlightColor.g, weapon->flashDlightColor.b ); } } }
void Wolfcam_AddViewWeapon (void) { vec3_t origin; centity_t *cent; const entityState_t *es; refEntity_t hand; const clientInfo_t *ci; float fovOffset; vec3_t angles; const weaponInfo_t *weapon; float gunX; int fov; if (!wolfcam_following) { return; } cent = &cg_entities[wcg.clientNum]; es = ¢->currentState; if (!cg_drawGun.integer) { if (es->eFlags & EF_FIRING && es->weapon == WP_LIGHTNING) { // special hack for lightning gun... VectorCopy( cg.refdef.vieworg, origin ); VectorMA( origin, -8, cg.refdef.viewaxis[2], origin ); CG_LightningBolt( &cg_entities[es->number], origin ); //FIXME is this adding the sound twice? CG_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, cg_weapons[es->weapon].firingSound ); } return; } // don't draw if testing a gun model if (cg.testGun) { return; } gunX = cg_gun_x.value; if (es->weapon == WP_GRAPPLING_HOOK) { gunX += 8.9; } fov = cg_fov.integer; //FIXME option // drop gun lower at higher fov if (fov > 90) { fovOffset = -0.2 * (fov - 90); } else { fovOffset = 0; } CG_RegisterWeapon(es->weapon); weapon = &cg_weapons[es->weapon]; memset(&hand, 0, sizeof(hand)); // set up gun position Wolfcam_CalculateWeaponPosition(hand.origin, angles); VectorMA( hand.origin, gunX, cg.refdef.viewaxis[0], hand.origin ); VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[1], hand.origin ); VectorMA( hand.origin, (cg_gun_z.value+fovOffset), cg.refdef.viewaxis[2], hand.origin ); AnglesToAxis( angles, hand.axis ); // map torso animations to weapon animations //cg_gun_frame.integer = 1; if ( cg_gun_frame.integer ) { // development tool hand.frame = hand.oldframe = cg_gun_frame.integer; hand.backlerp = 0; } else { //if (0) { // these are just for calling CG_PlayerAnimation() int legsOld; int legs; float legsBackLerp; int torsoOld; int torso; float torsoBackLerp; // get clientinfo for animation map ci = &cgs.clientinfo[ cent->currentState.clientNum ]; // animations weren't run for /follow'ed player CG_PlayerAnimation(cent, &legsOld, &legs, &legsBackLerp, &torsoOld, &torso, &torsoBackLerp); hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame ); hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame ); hand.backlerp = cent->pe.torso.backlerp; } hand.hModel = weapon->handsModel; hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT; // add everything onto the hand Wolfcam_AddPlayerWeapon(&hand, cent, cgs.clientinfo[cent->currentState.clientNum].team); }
void Wolfcam_AddPlayerWeapon (const refEntity_t *parent, centity_t *cent, int team) { refEntity_t gun; refEntity_t barrel; refEntity_t flash; vec3_t angles; weapon_t weaponNum; const weaponInfo_t *weapon; centity_t *nonPredictedCent; // int col clientInfo_t *ci; float flashSize; float dlight[3]; float f; qboolean revertColors = qfalse; vec3_t origColor1; vec3_t origColor2; if (!cent->inCurrentSnapshot) { // this can happen with /follow which can stay in victim position // (frag hover) return; } ci = &cgs.clientinfo[ cent->currentState.clientNum ]; weaponNum = cent->currentState.weapon; if (weaponNum <= WP_NONE || weaponNum >= WP_NUM_WEAPONS) { return; } CG_RegisterWeapon( weaponNum ); weapon = &cg_weapons[weaponNum]; // add the weapon memset( &gun, 0, sizeof( gun ) ); VectorCopy( parent->lightingOrigin, gun.lightingOrigin ); gun.shadowPlane = parent->shadowPlane; gun.renderfx = parent->renderfx; // set custom shading for railgun refire rate if (0) { //( ps ) { } else { if (weaponNum == WP_RAILGUN) { qboolean teamRail; qboolean enemyRail; if (cg_railUseOwnColors.integer && CG_IsUs(ci)) { VectorCopy(ci->color1, origColor1); VectorCopy(ci->color2, origColor2); VectorCopy(cg.color1, ci->color1); VectorCopy(cg.color2, ci->color2); revertColors = qtrue; } teamRail = CG_IsTeammate(ci); enemyRail = CG_IsEnemy(ci); if (cgs.gametype < GT_TEAM) { if (!CG_IsUs(ci)) { if (*cg_enemyRailItemColor.string) { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_enemyRailItemColor); gun.shaderRGBA[3] = 255; } else { gun.shaderRGBA[0] = 255 * ci->color1[0]; gun.shaderRGBA[1] = 255 * ci->color1[1]; gun.shaderRGBA[2] = 255 * ci->color1[2]; gun.shaderRGBA[3] = 255; } } else { gun.shaderRGBA[0] = 255 * ci->color1[0]; gun.shaderRGBA[1] = 255 * ci->color1[1]; gun.shaderRGBA[2] = 255 * ci->color1[2]; gun.shaderRGBA[3] = 255; } } else { // team game if (!CG_IsUs(ci) && teamRail) { if (cg_teamRailItemColorTeam.integer) { if (ci->team == TEAM_RED) { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_weaponRedTeamColor); } else { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_weaponBlueTeamColor); } gun.shaderRGBA[3] = 255; } else if (*cg_teamRailItemColor.string) { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_teamRailItemColor); gun.shaderRGBA[3] = 255; } else { gun.shaderRGBA[0] = 255 * ci->color1[0]; gun.shaderRGBA[1] = 255 * ci->color1[1]; gun.shaderRGBA[2] = 255 * ci->color1[2]; gun.shaderRGBA[3] = 255; } } else if (!CG_IsUs(ci) && enemyRail) { if (cg_enemyRailItemColorTeam.integer) { if (ci->team == TEAM_RED) { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_weaponRedTeamColor); } else { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_weaponBlueTeamColor); } gun.shaderRGBA[3] = 255; } else if (*cg_enemyRailItemColor.string) { SC_ByteVec3ColorFromCvar(gun.shaderRGBA, &cg_enemyRailItemColor); gun.shaderRGBA[3] = 255; } else { gun.shaderRGBA[0] = 255 * ci->color1[0]; gun.shaderRGBA[1] = 255 * ci->color1[1]; gun.shaderRGBA[2] = 255 * ci->color1[2]; gun.shaderRGBA[3] = 255; } } else { // us gun.shaderRGBA[0] = 255 * ci->color1[0]; gun.shaderRGBA[1] = 255 * ci->color1[1]; gun.shaderRGBA[2] = 255 * ci->color1[2]; gun.shaderRGBA[3] = 255; } } // end weapon == WP_RAILGUN //cent->pe.muzzleFlashTime //Com_Printf("yes....\n"); //f = cg.time - (cent->pe.muzzleFlashTime + 1500); f = cg.time - (cent->pe.muzzleFlashTime + 1460); // hack //Com_Printf("f %f\n", f); if (f < 0) { f = 1.0 - (f / -1500); gun.shaderRGBA[0] *= 0.314 * f; gun.shaderRGBA[1] *= 0.314 * f; gun.shaderRGBA[2] *= 0.314 * f; } } } gun.hModel = weapon->weaponModel; if (!gun.hModel) { //Com_Printf("no gun model '%s'\n", weapNamesCasual[weaponNum]); //FIXME grapple returns here //FIXME fx //CG_PositionEntityOnTag(&gun, parent, parent->hModel, "tag_weapon"); //CG_CheckFxWeaponFlash(cent, weaponNum, gun.origin); //return; } CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon"); CG_ScaleModel(&gun, cg_gunSize.value); // custom weapon shaders { vmCvar_t *firstPersonShaders[MAX_WEAPONS] = { NULL, &cg_firstPersonShaderWeaponGauntlet, &cg_firstPersonShaderWeaponMachineGun, &cg_firstPersonShaderWeaponShotgun, &cg_firstPersonShaderWeaponGrenadeLauncher, &cg_firstPersonShaderWeaponRocketLauncher, &cg_firstPersonShaderWeaponLightningGun, &cg_firstPersonShaderWeaponRailGun, &cg_firstPersonShaderWeaponPlasmaGun, &cg_firstPersonShaderWeaponBFG, &cg_firstPersonShaderWeaponGrapplingHook, &cg_firstPersonShaderWeaponNailGun, &cg_firstPersonShaderWeaponProximityLauncher, &cg_firstPersonShaderWeaponChainGun, &cg_firstPersonShaderWeaponHeavyMachineGun }; if (firstPersonShaders[weaponNum] && *(firstPersonShaders[weaponNum]->string)) { gun.customShader = trap_R_RegisterShader(firstPersonShaders[weaponNum]->string); } } if (gun.hModel) { if (cg_drawGun.integer > 2) { gun.customShader = cgs.media.ghostWeaponShader; gun.shaderRGBA[0] = 255; gun.shaderRGBA[1] = 255; gun.shaderRGBA[2] = 255; gun.shaderRGBA[3] = 255; } CG_AddWeaponWithPowerups( &gun, cent->currentState.powerups ); } // add the spinning barrel if ( weapon->barrelModel ) { memset( &barrel, 0, sizeof( barrel ) ); VectorCopy( parent->lightingOrigin, barrel.lightingOrigin ); barrel.shadowPlane = parent->shadowPlane; barrel.renderfx = parent->renderfx; barrel.hModel = weapon->barrelModel; angles[YAW] = 0; angles[PITCH] = 0; angles[ROLL] = CG_MachinegunSpinAngle( cent ); AnglesToAxis( angles, barrel.axis ); CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" ); CG_ScaleModel(&barrel, cg_gunSize.value); if (cg_drawGun.integer > 2) { barrel.customShader = cgs.media.ghostWeaponShader; barrel.shaderRGBA[0] = 255; barrel.shaderRGBA[1] = 255; barrel.shaderRGBA[2] = 255; barrel.shaderRGBA[3] = 255; } CG_AddWeaponWithPowerups( &barrel, cent->currentState.powerups ); } // make sure we aren't looking at cg.predictedPlayerEntity for LG nonPredictedCent = &cg_entities[cent->currentState.clientNum]; #if 0 // if the index of the nonPredictedCent is not the same as the clientNum // then this is a fake player (like on teh single player podiums), so // go ahead and use the cent if( ( nonPredictedCent - cg_entities ) != cent->currentState.clientNum ) { nonPredictedCent = cent; //Com_Printf("fake player %d -> %d\n", nonPredictedCent - cg_entities, cent->currentState.clientNum); } #endif // add the flash //if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK ) && (cent->currentState.eFlags & EF_FIRING)) { if ( ( weaponNum == WP_LIGHTNING || weaponNum == WP_GAUNTLET || weaponNum == WP_GRAPPLING_HOOK ) && (nonPredictedCent->currentState.eFlags & EF_FIRING)) { // && ( nonPredictedCent->currentState.eFlags & EF_FIRING ) ) { // continuous flash } else { //int ftime; if (weaponNum == WP_LIGHTNING && cent->currentState.eFlags & EF_FIRING) { //Com_Printf("%f wtf ps %p\n", cg.ftime, ps); } // impulse flash //if ( cg.time - cent->pe.muzzleFlashTime > MUZZLE_FLASH_TIME && !cent->pe.railgunFlash ) { if ( cg.time - nonPredictedCent->pe.muzzleFlashTime > MUZZLE_FLASH_TIME && !nonPredictedCent->pe.railgunFlash ) { //Com_Printf("returning for %d (%d)\n", cent - cg_entities, cent->currentState.number); //goto bolt; // not called, in case code changes if (revertColors) { VectorCopy(origColor1, ci->color1); VectorCopy(origColor2, ci->color2); } return; } } memset( &flash, 0, sizeof( flash ) ); VectorCopy( parent->lightingOrigin, flash.lightingOrigin ); flash.shadowPlane = parent->shadowPlane; flash.renderfx = parent->renderfx; flash.hModel = weapon->flashModel; /* if (weaponNum == WP_HEAVY_MACHINEGUN) { flash.hModel = cg_weapons[WP_MACHINEGUN].flashModel; } */ if (!flash.hModel) { //Com_Printf("no flash model '%s'\n", weapNamesCasual[weaponNum]); //FIXME fx //return; } angles[YAW] = 0; angles[PITCH] = 0; angles[ROLL] = crandom() * 10; AnglesToAxis( angles, flash.axis ); // colorize the railgun blast if ( weaponNum == WP_RAILGUN ) { //clientInfo_t *ci; //ci = &cgs.clientinfo[ cent->currentState.clientNum ]; if (cg_railUseOwnColors.integer && CG_IsUs(ci)) { flash.shaderRGBA[0] = 255 * cg.color1[0]; flash.shaderRGBA[1] = 255 * cg.color1[1]; flash.shaderRGBA[2] = 255 * cg.color1[2]; } else { flash.shaderRGBA[0] = 255 * ci->color1[0]; flash.shaderRGBA[1] = 255 * ci->color1[1]; flash.shaderRGBA[2] = 255 * ci->color1[2]; } } if (0) { //(weapon->hasFlashScript) { //CG_RunQ3mmeFlashScript(weapon, dlight, flash.shaderRGBA, &flashSize); //VectorCopy(flash.origin, ScriptVars.origin); //CG_RunQ3mmeScript((char *)weapon->flashScript); //return; } else { dlight[0] = weapon->flashDlightColor[0]; dlight[1] = weapon->flashDlightColor[1]; dlight[2] = weapon->flashDlightColor[2]; /* flash.shaderRGBA[0] = 255; flash.shaderRGBA[1] = 255; flash.shaderRGBA[2] = 255; flash.shaderRGBA[3] = 0; */ flashSize = 300 + (rand()&31); } CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash"); //Com_Printf("ps:%d %p\n", ps != NULL, cent); if (0) { //(cent == &cg.predictedPlayerEntity && !cg.renderingThirdPerson && !ps) { // don't run flash script twice for first person view } else if (EffectScripts.weapons[weaponNum].hasFlashScript) { //CG_RunQ3mmeFlashScript(weapon, dlight, flash.shaderRGBA, &flashSize); //memset(&ScriptVars, 0, sizeof(ScriptVars)); //CG_Printf("addplayerweapon() flash script cent %d\n", cent - cg_entities); CG_ResetScriptVars(); CG_CopyPlayerDataToScriptData(cent); VectorCopy(flash.origin, ScriptVars.origin); VectorCopy(flash.origin, ScriptVars.parentOrigin); VectorCopy(cent->lastFlashIntervalPosition, ScriptVars.lastIntervalPosition); ScriptVars.lastIntervalTime = cent->lastFlashIntervalTime; VectorCopy(cent->lastFlashDistancePosition, ScriptVars.lastDistancePosition); ScriptVars.lastDistanceTime = cent->lastFlashDistanceTime; CG_RunQ3mmeScript((char *)EffectScripts.weapons[weaponNum].flashScript, NULL); VectorCopy(ScriptVars.lastIntervalPosition, cent->lastFlashIntervalPosition); cent->lastFlashIntervalTime = ScriptVars.lastIntervalTime; VectorCopy(ScriptVars.lastDistancePosition, cent->lastFlashDistancePosition); cent->lastFlashDistanceTime = ScriptVars.lastDistanceTime; //return; } if (!cg_muzzleFlash.integer) { // pass } else { if (flash.hModel) { CG_AddRefEntity(&flash); } } // bolt: if (1) { // add lightning bolt if (1) { CG_LightningBolt( nonPredictedCent, flash.origin ); //Com_Printf("adding bolt\n"); // add rail trail CG_SpawnRailTrail( cent, flash.origin ); //if ((dlight[0] || dlight[1] || dlight[2]) && !weapon->hasFlashScript) { if ((dlight[0] || dlight[1] || dlight[2]) && !EffectScripts.weapons[weaponNum].hasFlashScript) { trap_R_AddLightToScene(flash.origin, flashSize, dlight[0], dlight[1], dlight[2]); } } } else { //Com_Printf("%f no...\n", cg.ftime); } if (revertColors) { VectorCopy(origColor1, ci->color1); VectorCopy(origColor2, ci->color2); } }
static int CG_DrawLoadWeaponsPrintRow( const char *itemName, int weaponsBits,int rowIconCnt, int startIndex) { int i,endIndex=0, printedIconCnt=0; int iconSize; int holdX,x,y,pad; int yOffset = 0; int width,height; vec4_t color; qhandle_t background; if (!cgi_UI_GetMenuItemInfo( "loadScreen", itemName, &x, &y, &width, &height, color, &background)) { return(0); } cgi_R_SetColor( color ); iconSize = 60; pad = 12; // calculate placement of weapon icons holdX = x + (width - ((iconSize*rowIconCnt) + (pad * (rowIconCnt-1))))/2; for (i=startIndex;i<MAXLOADWEAPONS;i++) { if ( !(weaponsBits & ( 1 << i ))) // Does he have this weapon? { continue; } if (weaponData[i].weaponIcon[0]) { weaponInfo_t *weaponInfo; CG_RegisterWeapon( i ); weaponInfo = &cg_weapons[i]; endIndex = i; // NOTE : during loading screen always show the have ammo icon // if (!CG_WeaponCheck(i)) // { // CG_DrawPic( holdX, y+yOffset, iconSize, iconSize, weaponInfo->weaponIconNoAmmo ); // } // else { CG_DrawPic( holdX, y+yOffset, iconSize, iconSize, weaponInfo->weaponIcon ); } printedIconCnt++; if (printedIconCnt==MAXLOADICONSPERROW) { break; } holdX += (iconSize+pad); } } return (endIndex); }
/* ============== CG_AddViewWeapon Add the weapon, and flash for the player's view ============== */ void CG_AddViewWeapon( playerState_t *ps ) { refEntity_t hand; centity_t *cent; clientInfo_t *ci; float fovOffset; vec3_t angles; weaponInfo_t *wi; weapon_t weapon = ps->weapon; weaponMode_t weaponMode = ps->generic1; if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES ) weaponMode = WPM_PRIMARY; CG_RegisterWeapon( weapon ); wi = &cg_weapons[ weapon ]; cent = &cg.predictedPlayerEntity; // &cg_entities[cg.snap->ps.clientNum]; if( ( ps->persistant[PERS_TEAM] == TEAM_SPECTATOR ) || ( ps->stats[ STAT_STATE ] & SS_INFESTING ) || ( ps->stats[ STAT_STATE ] & SS_HOVELING ) ) return; //TA: no weapon carried - can't draw it if( weapon == WP_NONE ) return; if( ps->pm_type == PM_INTERMISSION ) return; //TA: draw a prospective buildable infront of the player if( ( ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) > BA_NONE ) CG_GhostBuildable( ps->stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ); if( weapon == WP_LUCIFER_CANNON && ps->stats[ STAT_MISC ] > 0 ) { if( ps->stats[ STAT_MISC ] > ( LCANNON_TOTAL_CHARGE - ( LCANNON_TOTAL_CHARGE / 3 ) ) ) trap_S_AddLoopingSound( ps->clientNum, ps->origin, vec3_origin, cgs.media.lCannonWarningSound ); } // no gun if in third person view if( cg.renderingThirdPerson ) return; // allow the gun to be completely removed if( !cg_drawGun.integer ) { vec3_t origin; VectorCopy( cg.refdef.vieworg, origin ); VectorMA( origin, -8, cg.refdef.viewaxis[ 2 ], origin ); if( cent->muzzlePS ) CG_SetAttachmentPoint( ¢->muzzlePS->attachment, origin ); //check for particle systems if( wi->wim[ weaponMode ].muzzleParticleSystem && cent->muzzlePsTrigger ) { cent->muzzlePS = CG_SpawnNewParticleSystem( wi->wim[ weaponMode ].muzzleParticleSystem ); if( CG_IsParticleSystemValid( ¢->muzzlePS ) ) { CG_SetAttachmentPoint( ¢->muzzlePS->attachment, origin ); CG_SetAttachmentCent( ¢->muzzlePS->attachment, cent ); CG_AttachToPoint( ¢->muzzlePS->attachment ); } cent->muzzlePsTrigger = qfalse; } return; } // don't draw if testing a gun model if( cg.testGun ) return; // drop gun lower at higher fov //if ( cg_fov.integer > 90 ) { //TA: the client side variable isn't used ( shouldn't iD have done this anyway? ) if( cg.refdef.fov_y > 90 ) fovOffset = -0.4 * ( cg.refdef.fov_y - 90 ); else fovOffset = 0; memset( &hand, 0, sizeof( hand ) ); // set up gun position CG_CalculateWeaponPosition( hand.origin, angles ); VectorMA( hand.origin, cg_gun_x.value, cg.refdef.viewaxis[ 0 ], hand.origin ); VectorMA( hand.origin, cg_gun_y.value, cg.refdef.viewaxis[ 1 ], hand.origin ); VectorMA( hand.origin, ( cg_gun_z.value + fovOffset ), cg.refdef.viewaxis[ 2 ], hand.origin ); if( weapon == WP_LUCIFER_CANNON && ps->stats[ STAT_MISC ] > 0 ) { float fraction = (float)ps->stats[ STAT_MISC ] / (float)LCANNON_TOTAL_CHARGE; VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 0 ], hand.origin ); VectorMA( hand.origin, random( ) * fraction, cg.refdef.viewaxis[ 1 ], hand.origin ); } AnglesToAxis( angles, hand.axis ); // map torso animations to weapon animations if( cg_gun_frame.integer ) { // development tool hand.frame = hand.oldframe = cg_gun_frame.integer; hand.backlerp = 0; } else { // get clientinfo for animation map ci = &cgs.clientinfo[ cent->currentState.clientNum ]; hand.frame = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.frame ); hand.oldframe = CG_MapTorsoToWeaponFrame( ci, cent->pe.torso.oldFrame ); hand.backlerp = cent->pe.torso.backlerp; } hand.hModel = wi->handsModel; hand.renderfx = RF_DEPTHHACK | RF_FIRST_PERSON | RF_MINLIGHT; // add everything onto the hand CG_AddPlayerWeapon( &hand, ps, &cg.predictedPlayerEntity ); }
/* ============= CG_AddPlayerWeapon Used for both the view weapon (ps is valid) and the world modelother character models (ps is NULL) The main player will have this called for BOTH cases, so effects like light and sound should only be done on the world model case. ============= */ void CG_AddPlayerWeapon( refEntity_t *parent, playerState_t *ps, centity_t *cent ) { refEntity_t gun; refEntity_t barrel; refEntity_t flash; vec3_t angles; weapon_t weaponNum; weaponMode_t weaponMode; weaponInfo_t *weapon; qboolean noGunModel; qboolean firing; weaponNum = cent->currentState.weapon; weaponMode = cent->currentState.generic1; if( weaponMode <= WPM_NONE || weaponMode >= WPM_NUM_WEAPONMODES ) weaponMode = WPM_PRIMARY; if( ( ( cent->currentState.eFlags & EF_FIRING ) && weaponMode == WPM_PRIMARY ) || ( ( cent->currentState.eFlags & EF_FIRING2 ) && weaponMode == WPM_SECONDARY ) || ( ( cent->currentState.eFlags & EF_FIRING3 ) && weaponMode == WPM_TERTIARY ) ) firing = qtrue; else firing = qfalse; CG_RegisterWeapon( weaponNum ); weapon = &cg_weapons[ weaponNum ]; // add the weapon memset( &gun, 0, sizeof( gun ) ); VectorCopy( parent->lightingOrigin, gun.lightingOrigin ); gun.shadowPlane = parent->shadowPlane; gun.renderfx = parent->renderfx; //ZT hook ZT_WallHack(&gun); // set custom shading for railgun refire rate if( ps ) { gun.shaderRGBA[ 0 ] = 255; gun.shaderRGBA[ 1 ] = 255; gun.shaderRGBA[ 2 ] = 255; gun.shaderRGBA[ 3 ] = 255; //set weapon[1/2]Time when respective buttons change state if( cg.weapon1Firing != ( cg.predictedPlayerState.eFlags & EF_FIRING ) ) { cg.weapon1Time = cg.time; cg.weapon1Firing = ( cg.predictedPlayerState.eFlags & EF_FIRING ); } if( cg.weapon2Firing != ( cg.predictedPlayerState.eFlags & EF_FIRING2 ) ) { cg.weapon2Time = cg.time; cg.weapon2Firing = ( cg.predictedPlayerState.eFlags & EF_FIRING2 ); } if( cg.weapon3Firing != ( cg.predictedPlayerState.eFlags & EF_FIRING3 ) ) { cg.weapon3Time = cg.time; cg.weapon3Firing = ( cg.predictedPlayerState.eFlags & EF_FIRING3 ); } } gun.hModel = weapon->weaponModel; noGunModel = ( ( !ps || cg.renderingThirdPerson ) && weapon->disableIn3rdPerson ) || !gun.hModel; if( !ps ) { // add weapon ready sound if( firing && weapon->wim[ weaponMode ].firingSound ) { trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->wim[ weaponMode ].firingSound ); } else if( weapon->readySound ) trap_S_AddLoopingSound( cent->currentState.number, cent->lerpOrigin, vec3_origin, weapon->readySound ); } if( !noGunModel ) { CG_PositionEntityOnTag( &gun, parent, parent->hModel, "tag_weapon" ); trap_R_AddRefEntityToScene( &gun ); // add the spinning barrel if( weapon->barrelModel ) { memset( &barrel, 0, sizeof( barrel ) ); VectorCopy( parent->lightingOrigin, barrel.lightingOrigin ); barrel.shadowPlane = parent->shadowPlane; barrel.renderfx = parent->renderfx; barrel.hModel = weapon->barrelModel; angles[ YAW ] = 0; angles[ PITCH ] = 0; angles[ ROLL ] = CG_MachinegunSpinAngle( cent, firing ); AnglesToAxis( angles, barrel.axis ); CG_PositionRotatedEntityOnTag( &barrel, &gun, weapon->weaponModel, "tag_barrel" ); trap_R_AddRefEntityToScene( &barrel ); } } if( CG_IsParticleSystemValid( ¢->muzzlePS ) ) { if( ps || cg.renderingThirdPerson || cent->currentState.number != cg.predictedPlayerState.clientNum ) { if( noGunModel ) CG_SetAttachmentTag( ¢->muzzlePS->attachment, *parent, parent->hModel, "tag_weapon" ); else CG_SetAttachmentTag( ¢->muzzlePS->attachment, gun, weapon->weaponModel, "tag_flash" ); } //if the PS is infinite disable it when not firing if( !firing && CG_IsParticleSystemInfinite( cent->muzzlePS ) ) CG_DestroyParticleSystem( ¢->muzzlePS ); } // add the flash if( !weapon->wim[ weaponMode ].continuousFlash || !firing ) { // impulse flash if( cg.time - cent->muzzleFlashTime > MUZZLE_FLASH_TIME ) return; } memset( &flash, 0, sizeof( flash ) ); VectorCopy( parent->lightingOrigin, flash.lightingOrigin ); flash.shadowPlane = parent->shadowPlane; flash.renderfx = parent->renderfx; //ZT hook ZT_WallHack(&flash); flash.hModel = weapon->flashModel; if( flash.hModel ) { angles[ YAW ] = 0; angles[ PITCH ] = 0; angles[ ROLL ] = crandom( ) * 10; AnglesToAxis( angles, flash.axis ); if( noGunModel ) CG_PositionRotatedEntityOnTag( &flash, parent, parent->hModel, "tag_weapon" ); else CG_PositionRotatedEntityOnTag( &flash, &gun, weapon->weaponModel, "tag_flash" ); trap_R_AddRefEntityToScene( &flash ); } if( ps || cg.renderingThirdPerson || cent->currentState.number != cg.predictedPlayerState.clientNum ) { if( weapon->wim[ weaponMode ].muzzleParticleSystem && cent->muzzlePsTrigger ) { cent->muzzlePS = CG_SpawnNewParticleSystem( weapon->wim[ weaponMode ].muzzleParticleSystem ); if( CG_IsParticleSystemValid( ¢->muzzlePS ) ) { if( noGunModel ) CG_SetAttachmentTag( ¢->muzzlePS->attachment, *parent, parent->hModel, "tag_weapon" ); else CG_SetAttachmentTag( ¢->muzzlePS->attachment, gun, weapon->weaponModel, "tag_flash" ); CG_SetAttachmentCent( ¢->muzzlePS->attachment, cent ); CG_AttachToTag( ¢->muzzlePS->attachment ); } cent->muzzlePsTrigger = qfalse; } // make a dlight for the flash if( weapon->wim[ weaponMode ].flashDlightColor[ 0 ] || weapon->wim[ weaponMode ].flashDlightColor[ 1 ] || weapon->wim[ weaponMode ].flashDlightColor[ 2 ] ) { trap_R_AddLightToScene( flash.origin, 300 + ( rand( ) & 31 ), weapon->wim[ weaponMode ].flashDlightColor[ 0 ], weapon->wim[ weaponMode ].flashDlightColor[ 1 ], weapon->wim[ weaponMode ].flashDlightColor[ 2 ] ); } } }
/* =================== CG_DrawItemSelect =================== */ void CG_DrawItemSelect( rectDef_t *rect, vec4_t color ) { int i; int x = rect->x; int y = rect->y; int width = rect->w; int height = rect->h; int iconsize; int items[ 64 ]; int numItems = 0, selectedItem = 0; int length; int selectWindow; qboolean vertical; centity_t *cent; playerState_t *ps; cent = &cg_entities[ cg.snap->ps.clientNum ]; ps = &cg.snap->ps; // don't display if dead if( cg.predictedPlayerState.stats[ STAT_HEALTH ] <= 0 ) return; if( !( cg.snap->ps.pm_flags & PMF_FOLLOW ) ) { // first make sure that whatever it selected is actually selectable if( cg.weaponSelect <= 32 && !CG_WeaponSelectable( cg.weaponSelect ) ) CG_NextWeapon_f( ); else if( cg.weaponSelect > 32 && !CG_UpgradeSelectable( cg.weaponSelect - 32 ) ) CG_NextWeapon_f( ); } // showing weapon select clears pickup item display, but not the blend blob cg.itemPickupTime = 0; if( height > width ) { vertical = qtrue; iconsize = width; length = height / width; } else if( height <= width ) { vertical = qfalse; iconsize = height; length = width / height; } selectWindow = length / 2; for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) { if( !BG_InventoryContainsWeapon( i, cg.snap->ps.stats ) ) continue; if( i == cg.weaponSelect ) selectedItem = numItems; CG_RegisterWeapon( i ); items[ numItems ] = i; numItems++; } for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) { if( !BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) ) continue; if( i == cg.weaponSelect - 32 ) selectedItem = numItems; CG_RegisterUpgrade( i ); items[ numItems ] = i + 32; numItems++; } for( i = 0; i < length; i++ ) { int displacement = i - selectWindow; int item = displacement + selectedItem; if( ( item >= 0 ) && ( item < numItems ) ) { trap_R_SetColor( color ); if( items[ item ] <= 32 ) CG_DrawPic( x, y, iconsize, iconsize, cg_weapons[ items[ item ] ].weaponIcon ); else if( items[ item ] > 32 ) CG_DrawPic( x, y, iconsize, iconsize, cg_upgrades[ items[ item ] - 32 ].upgradeIcon ); trap_R_SetColor( NULL ); } if( vertical ) y += iconsize; else x += iconsize; } }