Script:Files:script/util.script

From Mod Wiki
/***********************************************************************

util.script

This defines utility functions for scripts

***********************************************************************/

object rules {
}

rules    gameRules;

vector    g_colorGreen;
vector    g_colorRed;
vector    g_colorLtGray;
vector    g_colorWhite;
vector    g_colorYellow;
vector    g_colorBlue;

vector    g_vectorDown;
vector    g_vectorUp;
vector    g_vectorZero;

float    g_radarMaterial;

vector    vec3_origin;
vector    vec3_up;
vector    vec3_down;

wstring    wstr_empty;
handle    invalid_handle;

float    g_ammoStroyent;
float    g_ammoStroyentPacket;
float    g_ammoMachinePistol;
float    g_ammoGrenade;
float    g_ammoAssaultRifle;
float    g_ammoShotgun;
float    g_ammoSniperRifle;
float    g_ammoPistol;
float    g_ammoRocketLauncher;
float    g_ammoGPMG;

float    g_proficiencyLightWeapons;

float    g_proficiencyFieldOps;
float    g_proficiencyMedic;
float    g_proficiencyEngineer;
float    g_proficiencyCovertOps;
float    g_proficiencySoldier;

float    g_proficiencyTechnician;
float    g_proficiencyOppressor;
float    g_proficiencyConstructor;
float    g_proficiencyInfiltrator;
float    g_proficiencyAggressor;

float    g_proficiencyBattleSense;
float    g_proficiencyVehicle;

float    g_playerClassSoldier;
float    g_playerClassMedic;
float    g_playerClassCovertOps;
float    g_playerClassEngineer;
float    g_playerClassFieldOps;

float    g_playerClassAggressor;
float    g_playerClassTechnician;
float    g_playerClassConstructor;
float    g_playerClassOppressor;
float    g_playerClassInfiltrator;

handle    g_locStr_Destroyed;
handle    g_locStr_Disabled;
handle     g_locStr_Range;
handle     g_locStr_Meters;
handle     g_locStr_Capture;
handle     g_locStr_SpawnHost;
handle     g_locStr_Supplies;
handle    g_locStr_SupplyCrate;
handle     g_locStr_Unconscious;
handle     g_locStr_Dead;
handle     g_locStr_Hacking;
handle     g_locStr_Arming;
handle     g_locStr_Disarming;
handle     g_locStr_Repairing;
handle     g_locStr_Constructing;
handle     g_locStr_Capturing;
handle     g_locStr_Liberating;
handle     g_locStr_Implanting;
handle     g_locStr_Disguising;
handle     g_locStr_Charge;
handle     g_locStr_Landmine;
handle     g_locStr_Tripmine;
handle     g_locStr_Proxmine;
handle     g_locStr_Scrambler;
handle     g_locStr_DoNotOwnTerritory;
handle     g_locStr_NoCharge;
handle     g_locStr_Dismantle;
handle     g_locStr_Drone;
handle     g_locStr_Scud;
handle     g_locStr_Airstrike;
handle     g_locStr_Completed;
handle     g_locStr_Objective;
handle    g_locStr_UnarmedMine;
handle    g_locStr_SelfArmingTripmine;
handle    g_locStr_SelfArmingProxymine;
handle    g_locStr_UnarmedTripmine;
handle    g_locStr_UnarmedProxymine;
handle    g_locStr_Spotting;
handle    g_locStr_Reviving;
handle    g_locStr_BadObjective;
handle    g_locStr_Someone;
handle    g_locStr_TeleportBeacon;

float     g_primaryObjectiveIndex;

object task {
}

object team_base {
    float    GetFireSupportDelayScale() { return 1.f; }
}

object cvar {
}

team_base stroggTeam;
team_base gdfTeam;

cvar    g_disableVehicleSpawns;
cvar    pm_thirdperson;
cvar    bse_projectileEffect;
cvar    g_friendlyColor;
cvar    g_neutralColor;
cvar    g_enemyColor;
cvar    g_maxProficiency;
cvar    g_fasterSpawn;

object gameplay_base;
gameplay_base gameplayManager;

/*
==================
abs

Returns the absolute value of a number
==================
*/
float abs( float value ) {
    if ( value < 0 ) {
        return value * -1;
    }

    return value;
}

/*
==================
rint

Returns the nearest integer value of a number
==================
*/
float rint( float value ) {
    return sys.floor( value + 0.5f );
}

/*
==================
min

Returns the lowest of two numbers
==================
*/
float min( float value1, float value2 ) {
    if ( value1 < value2 ) {
        return value1;
    }
    return value2;
}

/*
==================
max

Returns the highest of two numbers
==================
*/
float max( float value1, float value2 ) {
    if ( value1 > value2 ) {
        return value1;
    }
    return value2;
}

/*
==================
delayRemoveThread

Service thread for delayRemove.
==================
*/
void delayRemoveThread( entity ent, float mytime ) {
    sys.wait( mytime );
    ent.remove();
}

/*
==================
delayRemove

Causes an entity to be removed after a specified amount of time.
==================
*/
void delayRemove( entity ent, float mytime ) {
    thread delayRemoveThread( ent, mytime );
}

#define InchesToMetres( value ) ( ( value ) * 0.0254f )
#define MetresToInches( value ) ( ( value ) * 39.37f )
#define UPStoKPH( value ) ( InchesToMetres( value ) * 3.6f )
#define KPHtoUPS( value ) ( MetresToInches( value ) / 3.6f )

/*
==================
GetQuickChat
==================
*/
float GetQuickChat( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "quickChatDef" ), value );
}

/*
==================
GetStringMap
==================
*/
float GetStringMap( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "stringMap" ), value );
}

/*
==================
GetTargetFilter
==================
*/
float GetTargetFilter( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "targetInfo" ), value );
}

/*
==================
GetEntityDef
==================
*/
float GetEntityDef( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "entityDef" ), value );
}

/*
==================
GetToolTip
==================
*/
float GetToolTip( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "toolTip" ), value );
}

/*
==================
GetMaterial
==================
*/
float GetMaterial( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "material" ), value );
}

/*
==================
GetTable
==================
*/
float GetTable( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "table" ), value );
}


/*
==================
GetProficiency
==================
*/
float GetProficiency( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "proficiencyItem" ), value );
}

/*
==================
GetProficiencyType
==================
*/
float GetProficiencyType( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "proficiencyType" ), value );
}

/*
==================
GetPlayerClass
==================
*/
float GetPlayerClass( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "playerClass" ), value );
}

/*
==================
GetAmmoType
==================
*/
float GetAmmoType( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "ammoDef" ), value );
}

/*
==================
GetDamage
==================
*/
float GetDamage( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "damageDef" ), value );
}

/*
==================
GetDeployObject
==================
*/
float GetDeployObject( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "deployObject" ), value );
}

/*
==================
GetPlayerTask
==================
*/
float GetPlayerTask( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "task" ), value );
}

/*
==================
GetNumDeployObjects
==================
*/
float GetNumDeployObjects() {
    return sys.getDeclCount( sys.getDeclType( "deployObject" ) );
}

/*
==================
GetSoundShader
==================
*/
float GetSoundShader( string value ) {
    return sys.getDeclIndex( sys.getDeclType( "sound" ), value );
}

/*
==================
GetSoundShaderName
==================
*/
string GetSoundShaderName( float index ) {
    return sys.getDeclName( sys.getDeclType( "sound" ), index );
}


/*
==================
SetupColors
==================
*/
void SetupColors() {
    g_colorGreen = '0 1 0';
    g_colorRed = '1 0 0';
    g_colorLtGray = '0.75 0.75 0.75';
    g_colorWhite = '1 1 1';
    g_colorYellow = '1 1 0';
    g_colorBlue = '0 0 1';
    g_radarMaterial = GetMaterial( "_white_depth" );
    g_vectorUp = '0 0 1';
    g_vectorDown = '0 0 -1';
    g_vectorZero = g_vectorZero;
}


/*
==================
GetAllegianceColor
==================
*/

vector GetAllegianceColor( float allegiance ) {
    if ( allegiance == TA_FRIEND ) {
        return g_friendlyColor.getVectorValue();
    }

    if ( allegiance == TA_ENEMY ) {
        return g_enemyColor.getVectorValue();
    }

    return g_neutralColor.getVectorValue();
}

#define AngleDiff( a1, a2 ) sys.angleNormalize180( a1 - a2 )

string GetGlobalString( string key ) {
    float def = GetEntityDef( "globalConstants" );
    return sys.getEntityDefKey( def, key );
}

float GetGlobalInt( string key ) {
    float def = GetEntityDef( "globalConstants" );
    return sys.getEntityDefIntKey( def, key );
}

float GetGlobalFloat( string key ) {
    float def = GetEntityDef( "globalConstants" );
    return sys.getEntityDefFloatKey( def, key );
}

vector GetGlobalVector( string key ) {
    float def = GetEntityDef( "globalConstants" );
    return sys.getEntityDefVectorKey( def, key );
}

float MakeTerritoryIcon( entity ent ) {
    float materialHandle = GetMaterial( ent.getKey( "mtr_territory" ) );
    if ( materialHandle == -1 ) {
        return -1;
    }

    vector worldMins;
    vector worldMaxs;

    entity other = ent.getEntityKey( "target_playzone" );
    if ( other == $null_entity ) {
        worldMins    = sys.getWorldMins();
        worldMaxs    = sys.getWorldMaxs();
    } else {    
        worldMins    = other.getMins();
        worldMaxs    = other.getMaxs();
        worldMins    = sys.toWorldSpace( worldMins, other );
        worldMaxs    = sys.toWorldSpace( worldMaxs, other );
    }

    float territoryIconHandle    = sys.allocCMIcon( ent, 100 );

    vector worldSize = worldMaxs - worldMins;

    vector temp;

    temp = ent.getVectorKey( "territory_start" );

    vector objectStart;
    objectStart_x = worldMins_x + ( temp_x * worldSize_x );
    objectStart_y = worldMins_y + ( temp_y * worldSize_y );

    temp = ent.getVectorKey( "territory_end" );

    vector objectEnd;
    objectEnd_x = worldMins_x + ( temp_x * worldSize_x );
    objectEnd_y = worldMins_y + ( temp_y * worldSize_y );

//	sys.println( objectStart );
//	sys.println( objectEnd );

    vector objectSize = objectEnd - objectStart;

    sys.setCMIconSize2d( territoryIconHandle, objectSize_x, objectSize_y );
    sys.setCMIconSizeMode( territoryIconHandle, SM_WORLD );
    sys.setCMIconFlag( territoryIconHandle, CMF_ALWAYSKNOWN );
    sys.setCMIconFlag( territoryIconHandle, CMF_NOADJUST );
    sys.setCMIconColorMode( territoryIconHandle, CM_ALLEGIANCE );
    sys.setCMIconPositionMode( territoryIconHandle, PM_FIXED );
    sys.setCMIconOrigin( territoryIconHandle, ( objectStart + objectEnd ) * 0.5f );
    sys.setCMIconMaterial( territoryIconHandle, materialHandle );

    return territoryIconHandle;
}

void FreeTerritoryIcon( entity territory, float territoryIconHandle ) {
    if ( territoryIconHandle != -1 ) {
        sys.freeCMIcon( territory, territoryIconHandle );
        territoryIconHandle = -1;
    }
}

void G_ProjectCircleDecal( float decalHandle, vector size, float depth, vector position, vector color ) {
    vector startPos    = position + ( g_vectorUp * depth * 0.5f );

    vector forward;
    forward_x        = size_x * 0.5f;

    vector side;
    side_y            = size_y * 0.5f;

    sys.resetDecal( decalHandle );
    sys.projectDecal( decalHandle, startPos + ( forward + side ), g_vectorDown, depth, 1, size, 0.f, color );
    sys.projectDecal( decalHandle, startPos + ( forward - side ), g_vectorDown, depth, 1, size, 90.f, color );
    sys.projectDecal( decalHandle, startPos + ( -forward + side ), g_vectorDown, depth, 1, size, 180.f, color );
    sys.projectDecal( decalHandle, startPos + ( -forward + -side ), g_vectorDown, depth, 1, size, 270.f, color );    
}

handle g_fireSupportStateStr;
void G_StringForFireSupportState( float state ) {
    // todo: move the calls to localizeString to (even more!) globals?
    // (yes)
    if ( state == MPS_OUT_OF_RANGE ) {
        g_fireSupportStateStr        = sys.localizeString( "game/fire_sup/out_of_range" );
        return;
    }
    if ( state == MPS_READY || state == MPS_NOT_LOCKED ) {
        g_fireSupportStateStr        = sys.localizeString( "game/fire_sup/ready" );
        return;
    }
    if ( state == MPS_RELOADING ) {
        g_fireSupportStateStr        = sys.localizeString( "game/fire_sup/reloading" );
        return;
    }
    if ( state == MPS_WAITING ) {
        g_fireSupportStateStr        = sys.localizeString( "game/fire_sup/waiting" );
        return;
    }
    if ( state == MPS_DISABLED ) {
        g_fireSupportStateStr        = sys.localizeString( "game/fire_sup/disabled" );
        return;
    }
    if ( state == MPS_NONE_ACTIVE ) {
        g_fireSupportStateStr        = sys.localizeString( "game/fire_sup/not_deployed" );
        return;
    }
    if ( state == MPS_FIRING_PREPARE || state == MPS_FIRING ) {
        g_fireSupportStateStr        = sys.localizeString( "game/fire_sup/firing" );
        return;
    }
    if ( state == MPS_LOCKING ) {
        g_fireSupportStateStr        = sys.localizeString( "game/fire_sup/locking" );
        return;
    }
    if ( state == MPS_LOCKED ) {
        g_fireSupportStateStr        = sys.localizeString( "game/fire_sup/acquired" );
        return;
    }

    if ( state == MPS_INVALID ) {
        g_fireSupportStateStr        = sys.localizeString( "game/fire_sup/invalid" );
        return;
    }

    if ( state == MPS_LOCKED_ROCKETS ) {
        g_fireSupportStateStr        = sys.localizeString( "game/fire_sup/acquired/rockets" );
        return;
    }

    g_fireSupportStateStr = sys.localizeString( "game/misc/unknown" );
}

void G_DelayRemoveEntity( entity ent, float delay ) {
    sys.wait( delay );
    ent.remove();
}

void G_DelayFireSupport( entity p, entity other, float delay ) {
    team_base team = other.getGameTeam();
    sys.setTargetTimerValue( sys.allocTargetTimer( FIRESUPPORT_TIMER_NAME ), p, sys.getTime() + ( delay * team.GetFireSupportDelayScale() ) );
    sys.setTargetTimerValue( sys.allocTargetTimer( FIRESUPPORT_TIMER_START_NAME ), p, sys.getTime() );
}

/*
============
Localization
============
*/

// build the localized range string, e.g. "Range: 42m"
wstring G_BuildRangeStr( float range ) {
    sys.pushLocString( int( range ) ); 
    sys.pushLocStringIndex( g_locStr_Meters );
    return sys.localizeStringArgs( "game/range" );
}

#define CLAMP( value, min, max ) \
if ( value < ( min ) ) value = ( min ); \
else if ( value > ( max ) ) value = ( max );

/*
==================

CallManualDeploy

bypasses the code, directly calls in a deployable

==================
*/
entity CallManualDeploy( string deployObject, string deployItem, object deployTeam, vector location, float angle ) {
    if ( sys.isClient() ) {
        return $null_entity;
    }

    float itemDef = GetEntityDef( deployItem );

    entity obj = sys.spawn( deployObject );
    obj.setGameTeam( deployTeam );
    obj.vSetDeploymentParms( itemDef, -1, location, angle );

    return obj.vGetItem();
}

/*
==================

G_TryFireScud

finds a scud launcher and attempts to fire at an entity

==================
*/
boolean G_TryFireScud( entity firer, entity targetEnt ) {

    // TODO: Make it so that you can use sys to do entitiesOfCollection type stuff
    entity worldspawn = sys.getEntity( "worldspawn" );

    // set any MCP up to fire
    float count = worldspawn.entitiesOfCollection( "mcp" );

    float i;
    for ( i = 0; i < count; i++ ) {
        entity ent = worldspawn.getBoundsCacheEntity( i );

        if ( ent.vFireScud( firer, targetEnt ) ) {
            return true;
        }
    }

    return false;
}

float G_CountMinesOwnedByEntity( entity p ) {
    p.entitiesOfCollection( "mine" );
    float count = p.filterEntitiesByAllegiance( TA_FLAG_FRIEND, 1 );

    float number;
    float index;
    for ( index = 0; index < count; index++ ) {
        entity mine = p.getBoundsCacheEntity( index );

        if ( mine.vGetOwner() == p ) {
            number++;
        }
    }
    return number;
}



object firesupport_marker {
    void        preinit();
    void        DoWarning();

    float        range;
    float        endTime;
    float        nextPlayTime;
    float        warningRange;
    string        warningSound;
}

void firesupport_marker::preinit() {
    range = getFloatKey( "range" );
    endTime = sys.getTime() + getFloatKey( "warning_time" );
    nextPlayTime = getFloatKey( "next_play_time" );
    warningRange = getFloatKey( "warning_range" );
    warningSound = getKey( "snd_ff_warning" );

    thread DoWarning();
}

void firesupport_marker::DoWarning() {
    while ( true ) {
        entitiesOfCollection( "players" );
        float playerCount = filterEntitiesByRadius( getWorldOrigin(), warningRange, 1 );

        float i = 0;
        for( i = 0; i < playerCount; i++ ) {
            entity p = getBoundsCacheEntity( i );
            if ( getEntityAllegiance( p ) == TA_FRIEND ) {
                p.vPlayFFWarning( warningSound, nextPlayTime );
            }
        }

        if ( sys.getTime() > endTime ) {
            break;
        }

        sys.wait( 1.f );
    }
}



boolean G_CheckFireSupportBlock( vector location, entity myPlayer ) {
    myPlayer.entitiesOfCollection( "fs_block" );
    float count = myPlayer.filterEntitiesByAllegiance( TA_FLAG_FRIEND, 1 );

    float index;
    for ( index = 0; index < count; index++ ) {
        firesupport_marker marker = myPlayer.getBoundsCacheEntity( index );
        if ( marker == $null_entity ) {
            continue;
        }

        float range = marker.range * marker.range;

        if ( sys.vecLengthSquared( location - marker.getWorldOrigin() ) < range ) {
            return false;
        }
    }

    return true;
}

entity G_CreateFiringMarker( entity ent, entity current, vector location ) {
    if ( current == $null_entity ) {
        string marker = ent.getKey( "def_firesupport_marker" );
        if ( marker != "" ) {
            current = sys.spawn( marker );
        }
    }
    if ( current != $null_entity ) {
        current.setOrigin( location );
        current.setGameTeam( ent.getGameTeam() );
    }
    return current;
}

void G_NotifyNoCharge( entity p ) {
    if( p == sys.getLocalViewPlayer() ) {
        sys.setGUIFloat( GUI_GLOBALS_HANDLE, "gameHud.needsCharge", 1 );
    }
}

/*
==================
BoundsDamage
==================
*/
void BoundsDamage( entity self, float dmgIndex ) {
    vector mins = self.getAbsMins();
    vector maxs = self.getAbsMaxs();
    mins_z = mins_z - 64;

    //sys.debugBounds( g_colorRed, mins, maxs, 0 );

    float count = self.entitiesInBounds( mins, maxs, MASK_SHOT_RENDERMODEL | MASK_SHOT_BOUNDINGBOX, 1 );
    float index;
    for ( index = 0; index < count; index++ ) {
        entity other = self.getBoundsCacheEntity( index );
        if ( other == self ) {
            continue;
        }
        if ( other != $null_entity ) {
            if ( self.touchesBounds( other ) ) {
                other.applyDamage( $null_entity, self, vec3_down, dmgIndex, 1.f, $null_entity );
            }
        }
    }
}

/*
==================
LocalBoundsDamage
==================
*/
void LocalBoundsDamage( vector mins, vector maxs, entity self, entity inflictor, float dmgIndex ) {
    float count = self.entitiesInLocalBounds( mins, maxs, MASK_SHOT_RENDERMODEL | MASK_SHOT_BOUNDINGBOX );
    float index;
    for ( index = 0; index < count; index++ ) {
        entity other = self.getBoundsCacheEntity( index );
        if ( other == self ) {
            continue;
        }
        if ( other == inflictor ) {
            continue;
        }
        if ( other != $null_entity ) {
            other.applyDamage( $null_entity, inflictor, vec3_down, dmgIndex, 1.f, $null_entity );
        }
    }
}

// more util files
#include "script/misc/zoomwidget.script"

void G_GiveSpottingProficiency( entity spotter ) {
    spotter.vGiveSpotProficiency();
}

// Gordon: FIXME: These wont work, as many places they are being called from map scripts, which aren't run on the client, I also don't like the way this is set up anyway
void G_PlayObjectiveCompletedRoll( float team ) {
    sys.assert( team == GDF || team == STROGG );
    if ( team == GDF ) {
        sys.startSoundDirect( gdfTeam.getKey( "snd_objective_complete_roll" ), SND_ANY );
    } else {
        sys.startSoundDirect( stroggTeam.getKey( "snd_objective_complete_roll" ), SND_ANY );
    }
}

void G_PlayObjectiveCompletedRollEnt( entity ent ) {
    sys.assert( ent != $null_entity && ent.getGameTeam() != $null_entity );
    if ( ent.getGameTeam() == stroggTeam ) {
        G_PlayObjectiveCompletedRoll( GDF );
    } else {
        G_PlayObjectiveCompletedRoll( STROGG );
    }
}

void G_GiveDeployBonus( entity owner, entity item ) {
    entity territory = sys.getTerritoryForPoint( item.getWorldOrigin(), $null_entity, 0.f, item.getIntKey( "deploybonus_requireactive" ) );
    if ( territory != $null_entity ) {
        owner.giveProficiency( GetProficiency( item.getKey( "prof_deploybonus" ) ), 1.f, $null, "item deployed" );
    }
}

void G_SetPrimaryObjectiveIndex( float objIndex ) {
    entity worldspawn = sys.getEntity( "worldspawn" );

    g_primaryObjectiveIndex = objIndex;

    float count = worldspawn.entitiesOfCollection( "objective_markers" );
    float index;
    for ( index = 0; index < count; index++ ) {
        entity other = worldspawn.getBoundsCacheEntity( index );
        other.vOnDeploy();
    }
}

/*
==================
RangeUpdateThread
low frequency updates if crosshair distance is larger than CROSSHAIR_TRACE_DIST.
==================
*/
void RangeUpdateThread( player p, float maxDist ) {
    vector forward;
    vector tStart;
    vector tEnd;
    float dist;

    if ( maxDist <= 0 || maxDist < CROSSHAIR_TRACE_DIST ) {
        sys.warning( "Unexpected maxDist value: " + maxDist );
        return;
    }

    while ( true ) {
        sys.wait( 1.0f );
        if ( !p.IsSniperScopeUp() ) {
            continue;
        }

        dist = p.getCrosshairDistance( false );
        if ( dist >= CROSSHAIR_TRACE_DIST ) {
            forward = sys.angToForward( p.getViewAngles() );
            tStart = ( forward * ( CROSSHAIR_TRACE_DIST - 128 ) ) + p.getViewOrigin();
            tEnd = forward * maxDist + p.getViewOrigin();
            sys.tracePoint( tStart, tEnd, MASK_SHOT_RENDERMODEL | CONTENTS_SHADOWCOLLISION | CONTENTS_SLIDEMOVER | CONTENTS_BODY | CONTENTS_PROJECTILE | CONTENTS_CROSSHAIRSOLID, p );
            dist = CROSSHAIR_TRACE_DIST + sys.getTraceFraction() * ( maxDist - ( CROSSHAIR_TRACE_DIST - 128 ) );
            if ( sys.getTraceFraction() == 1.0f || ( sys.getTraceSurfaceFlags() & SURF_NOIMPACT ) ) {
                sys.setGUIFloat( GUI_GLOBALS_HANDLE, "weapons.distance", -1 );
            } else {
                sys.setGUIFloat( GUI_GLOBALS_HANDLE, "weapons.distance", dist );
            }
        } else {
            // reset distance value
            sys.setGUIFloat( GUI_GLOBALS_HANDLE, "weapons.distance", -2 );
        }
    }
}

/*
==================
G_ContainsBounds
Check if one set of bounds is completely inside another set of bounds
==================
*/
boolean G_ContainsBounds( vector aMins, vector aMaxs, vector bMins, vector bMaxs, float epsilon ) {
    // check mins
    if ( aMins_x > bMins_x + epsilon ) {
        return false;
    }

    if ( aMins_y > bMins_y + epsilon ) {
        return false;
    }

    if ( aMins_z > bMins_z + epsilon ) {
        return false;
    }

    // check maxs
    if ( aMaxs_x < bMaxs_x - epsilon ) {
        return false;
    }

    if ( aMaxs_y < bMaxs_y - epsilon ) {
        return false;
    }

    if ( aMaxs_z < bMaxs_z - epsilon ) {
        return false;
    }

    return true;
}