ts/src/client/hud_crosshair.qc

277 lines
9.3 KiB
Plaintext

/*
* Copyright (c) 2016-2019 Marco Hladik <marco@icculus.org>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//it's ok for this to go here, right?
CREATE_imageFileRef_t(img_player_stuntmeter1, "sprites/player/divestept.spr", 40, 80)
CREATE_imageFileRef_t(img_player_stuntmeter2, "sprites/player/divestepc.spr", 40, 80)
CREATE_imageFileRef_t(img_player_stuntmeter3, "sprites/player/divestepb.spr", 40, 80)
CREATE_imageFileRef_raw_t(img_quadgraphic, "textures/cross2.tga", 64, 64)
/*
=================
HUD_DrawCrosshair
Draws the cursor every frame, unless spectator
=================
*/
void
HUD_DrawCrosshair(void){
player pl = (player)pSeat->m_ePlayer;
weapondynamic_t dynaRef;
weapondata_gun_t* gunPointer;
weapondata_gun_t gunRef;
vector vCenter = video_mins + [video_res[0]/2, video_res[1]/2];
// only TRUE for guns, melee stuff doesn't get this.
BOOL hasWeaponCrosshair = FALSE;
// only TRUE if the gun has lasersight, of course.
BOOL hasLasersight = FALSE;
int drawLaserDots = 0;
BOOL trackLaserDots = FALSE; //only applicable with lasersight on of course.
if(pl.inventoryEquippedIndex != -1){
//get that weapon.
dynaRef = pl.ary_myWeapons[pl.inventoryEquippedIndex];
if(dynaRef.weaponTypeID == WEAPONDATA_TYPEID_GUN || dynaRef.weaponTypeID == WEAPONDATA_TYPEID_IRONSIGHT){
gunPointer = (weapondata_gun_t*) pl.getEquippedWeaponData();
gunRef = *(gunPointer);
// We probably have a "drawCrosshair" variable in our weapon struct.
// probaly not even necessary really, since we could infer that property fine anyway from the
// weaponTypeID.
// One more check... we can explicitly forbid drawing the crosshair ever for a weapon too.
// Example is the barrett sniper rifle, even hip-fire has no crosshair like other weapons.
if(gunRef.fDrawCrosshair){
hasWeaponCrosshair = TRUE;
}
//we could very well need the lasersight drawn without the crosshair
// (example: barrett sniper rifle)
int iBitsUpgradeSafe_on = dynaRef.iBitsUpgrade_on & (dynaRef.iBitsUpgrade & gunRef.iBitsUpgrade);
//do we have a lasersight though?
if(iBitsUpgradeSafe_on & BITS_WEAPONOPT_LASERSIGHT){
// why yes, we got it
hasLasersight = TRUE;
int reloadSeq = -1;
//what is my reload sequence?
if(dynaRef.weaponTypeID == WEAPONDATA_TYPEID_IRONSIGHT){
//it's from the
weapondata_ironsight_t* ironsightPointer = (weapondata_ironsight_t*)gunPointer;
weapondata_ironsight_t ironsightRef = (*ironsightPointer);
if(!dynaRef.iIronSight){
reloadSeq = ironsightRef.iAnim_Reload_Index;
}else{
reloadSeq = ironsightRef.ironsightdata.iAnim_Reload_Index;
}
}else{
reloadSeq = gunRef.iAnim_Reload_Index;
}
if(!pl.weaponEquippedAkimbo){
drawLaserDots = 1;
}else{
drawLaserDots = 2;
}
// Is this a condition that forbids drawing the laser dot on the screen?
if(
/*
!pl.isReloading &&
!(
pSeat->m_eViewModel.frame == gunRef.iAnim_Deploy_Index &&
pl.w_attack_next > 0
) &&
!pl.lasersightUnlockTime
*/
!(pl.isReloading || (pl.lasersightUnlockTime && pl.w_idle_next <= 0))
){
trackLaserDots = FALSE; // force them to the center on the screen.
}else{
// Track their positions on the ingame world. Weird, I know.
trackLaserDots = TRUE;
}
}//END OF lasersight check
}
}//END OF inventoryEquippedIndex check
// Draw some things unconditionally.
// (we only even reached this point if not zoomed through a scope with the overlay of course)
/*
0 - 21 slots: all thirds clear.
22 - 41 slots: top third orange.
42 - 71 slots: top, middle thirds orange.
72 - 81 slots: all thirds orange.
*/
int thirdBelongingTo = 0;
// pl.pitch is only updated on server pings, might not be wise to use here,
// looks choppy with any kind of ping time
float ratioNumber = getViewPitchRelativeRatio(view_angles.x);
float newDegreeRad = (ratioNumber * (270 - 90) + 90) * (M_PI/180);
//printfline("MY ANGLE? %.2f", (ratioNumber * (270 - 90) + 90) );
//check for the degree, set thirdBelongingTo...
if(ratioNumber <= 0.3333){
thirdBelongingTo = 0;
}else if(ratioNumber <= 0.6667){
thirdBelongingTo = 1;
}else{ // <= 1.0
thirdBelongingTo = 2;
}
// we could make this a property (ts/src/server/init.qc) to be set by the client and read
// by the server, but this might be really inefficient. May as well use the v_angle
// already available serverside to determine what third we're looking at.
// top = 90 degrees for safePlayerViewPitch of -31.
// bottom = 270 degrees for safePlayerViewPitch of 30.
//Max upwards: -31
//mid: 0
//Max downwards: 30
//check for belingong to each of the thirds for which to light up, if applicable. Above that is.
float modder;
vector clrColor;
modder = 0.56f;
if(pl.iTotalSlots <= 21){clrColor = clrPaleBlue;if(thirdBelongingTo==0){modder = 1.0f;}}else{clrColor = clrFailedSlotbarColor;}
DRAW_IMAGE_ADDITIVE(img_player_stuntmeter1, ([vCenter[0] - 40, vCenter[1] - 40]), clrColor, modder)
modder = 0.56f;
if(pl.iTotalSlots <= 41){clrColor = clrPaleBlue;if(thirdBelongingTo==1){modder = 1.0f;}}else{clrColor = clrFailedSlotbarColor;}
DRAW_IMAGE_ADDITIVE(img_player_stuntmeter2, ([vCenter[0] - 40, vCenter[1] - 40]), clrColor, modder)
modder = 0.56f;
if(pl.iTotalSlots <= 71){clrColor = clrPaleBlue;if(thirdBelongingTo==2){modder = 1.0f;}}else{clrColor = clrFailedSlotbarColor;}
DRAW_IMAGE_ADDITIVE(img_player_stuntmeter3, ([vCenter[0] - 40, vCenter[1] - 40]), clrColor, modder)
vector resultArcPoint = vCenter + [cos(newDegreeRad), -sin(newDegreeRad)] * 32;
drawfill( resultArcPoint, [2, 2], clrPaleBlue, 0.7f, DRAWFLAG_NORMAL );
if(hasWeaponCrosshair){
int startCrosshairDist;
int maxCrosshairDelta; //how much the crosshair can move outwards at most. 0 is no change!
int crosshairDist;
if(!hasLasersight){
startCrosshairDist = 22;
maxCrosshairDelta = 15;
}else{
startCrosshairDist = 12;
maxCrosshairDelta = 14;
}
//can expand up to +14 beyond.
float facto = (bound(0, pl.fAccuracyKickback, 0.1) ) / 0.1;
//scale it.
crosshairDist = startCrosshairDist + facto * maxCrosshairDelta;
//printfline("pl.fAccuracyKickback:%.4f", pl.fAccuracyKickback);
clrColor = [0/255.0f, 0/255.0f, 0/255.0f];
DRAW_IMAGE_NORMAL(img_quadgraphic, ([vCenter[0] - 32, vCenter[1] - 32]), clrColor, 1.00f)
// * 0.86 ???
drawfill( [vCenter[0] - crosshairDist, vCenter[1] - 1], [5, 2], clrPaleBlue, 0.70f, DRAWFLAG_NORMAL );
drawfill( [vCenter[0] + (crosshairDist - 5), vCenter[1] - 1], [5, 2], clrPaleBlue, 0.70f, DRAWFLAG_NORMAL );
drawfill( [vCenter[0] - 1, vCenter[1] - crosshairDist], [2, 5], clrPaleBlue, 0.7f, DRAWFLAG_NORMAL );
drawfill( [vCenter[0] - 1, vCenter[1] + (crosshairDist - 5)], [2, 5], clrPaleBlue, 0.70f, DRAWFLAG_NORMAL );
}// ranged weapon check
if(hasLasersight){
if(!trackLaserDots){
// draw it straight at the HUD center.
// TODO - add a very slight, slow random offset from the given point.
// Why? BECAUSE KHORNE MUST BE PLEASED.
// ...I mean, because original TS did it. okay.
vector lasDot;
if(drawLaserDots == 1){
// dot in the center and the range number fresh from the server, probably.
// -1. 5. 2.
lasDot = vCenter + [-1, -1];
drawfill( lasDot, [2, 2], clrLaserHUDDot, 0.83f, DRAWFLAG_NORMAL );
}else if(drawLaserDots == 2){
lasDot = vCenter + [-1 + -4, -1];
drawfill( lasDot, [2, 2], clrLaserHUDDot, 0.83f, DRAWFLAG_NORMAL );
lasDot = vCenter + [-1 + 4, -1];
drawfill( lasDot, [2, 2], clrLaserHUDDot, 0.83f, DRAWFLAG_NORMAL );
}
}else{
if(pl.recentLaserHitPosSet){
if(drawLaserDots == 1){
// dot in the center and the range number fresh from the server, probably.
// -1. 5. 2.
//trust "recentLaserHit" then!
lasDot = project(pl.recentLaserHitPos);
drawfill( lasDot, [2, 2], clrLaserHUDDot, 0.83f, DRAWFLAG_NORMAL );
}else if(drawLaserDots == 2){
lasDot = project(pl.recentLaserHitPos);
drawfill( lasDot, [2, 2], clrLaserHUDDot, 0.83f, DRAWFLAG_NORMAL );
lasDot = project(pl.recentLaserHitPos2);
drawfill( lasDot, [2, 2], clrLaserHUDDot, 0.83f, DRAWFLAG_NORMAL );
}
}
}
if(drawLaserDots != 0){
if(hasWeaponCrosshair){
if(pl.recentLaserHitPosSet){
vector vDistNumberLoc = vCenter + [28, -8];
drawSpriteNumber(ary_LCD_numberSet, vDistNumberLoc.x, vDistNumberLoc.y, pl.recentLaserDistanceDisplay, 3, BITS_DIGITOPT_NONE, clrPaleBlue, 0.91f);
}
}
}// flat drawLaserDots check
}// lasersight check
}// HUD_DrawCrosshair