/* ================= CG_RegisterUpgrade The server says this item is used on this level ================= */ void CG_RegisterUpgrade( int upgradeNum ) { upgradeInfo_t *upgradeInfo; char *icon; if( upgradeNum <= UP_NONE || upgradeNum >= UP_NUM_UPGRADES ) { CG_Error( "CG_RegisterUpgrade: out of range: %d", upgradeNum ); return; } upgradeInfo = &cg_upgrades[ upgradeNum ]; if( upgradeInfo->registered ) { CG_Printf( "CG_RegisterUpgrade: already registered: (%d) %s\n", upgradeNum, BG_Upgrade( upgradeNum )->name ); return; } upgradeInfo->registered = qtrue; if( !BG_Upgrade( upgradeNum )->name[ 0 ] ) CG_Error( "Couldn't find upgrade %i", upgradeNum ); upgradeInfo->humanName = BG_Upgrade( upgradeNum )->humanName; //la la la la la, i'm not listening! if( upgradeNum == UP_GRENADE ) upgradeInfo->upgradeIcon = cg_weapons[ WP_GRENADE ].weaponIcon; else if( ( icon = BG_Upgrade( upgradeNum )->icon ) ) upgradeInfo->upgradeIcon = trap_R_RegisterShader( icon ); }
static void CG_CompleteItem( void ) { int i = 0; if( cgs.clientinfo[ cg.clientNum ].team == TEAM_ALIENS ) { return; } trap_CompleteCallback( "weapon" ); for( i = 0; i < UP_NUM_UPGRADES; i++ ) { const upgradeAttributes_t *item = BG_Upgrade( i ); if ( item->usable ) { trap_CompleteCallback( item->name ); } } for( i = 0; i < WP_NUM_WEAPONS; i++ ) { const weaponAttributes_t *item = BG_Weapon( i ); if( item->team == TEAM_HUMANS ) { trap_CompleteCallback( item->name ); } } }
static void CG_CompleteBuy( void ) { int i; if( cgs.clientinfo[ cg.clientNum ].team != TEAM_HUMANS ) { return; } for( i = 0; i < UP_NUM_UPGRADES; i++ ) { const upgradeAttributes_t *item = BG_Upgrade( i ); if ( item->purchasable && item->team == TEAM_HUMANS ) { trap_CompleteCallback( item->name ); } } trap_CompleteCallback( "grenade" ); // called "gren" elsewhere, so special-case it for( i = 0; i < WP_NUM_WEAPONS; i++ ) { const weaponAttributes_t *item = BG_Weapon( i ); if ( item->purchasable && item->team == TEAM_HUMANS ) { trap_CompleteCallback( item->name ); } } }
/* =============== CG_UpgradeSelectable =============== */ static qboolean CG_UpgradeSelectable( upgrade_t upgrade ) { if( !BG_InventoryContainsUpgrade( upgrade, cg.snap->ps.stats ) ) return qfalse; return BG_Upgrade( upgrade )->usable; }
static const char *UnlockableHumanName( unlockable_t *unlockable ) { switch ( unlockable->type ) { case UNLT_WEAPON: return BG_Weapon( unlockable->num )->humanName; case UNLT_UPGRADE: return BG_Upgrade( unlockable->num )->humanName; case UNLT_BUILDABLE: return BG_Buildable( unlockable->num )->humanName; case UNLT_CLASS: return BG_ClassModelConfig( unlockable->num )->humanName; } Com_Error( ERR_FATAL, "UnlockableHumanName: Unlockable has unknown type" ); return nullptr; }
static void CG_Rocket_DFCMArmouryBuyUpgrade( int handle, const char *data ) { upgrade_t upgrade = (upgrade_t) atoi( Info_ValueForKey( data, "1" ) ); const char *Class = ""; const char *Icon = ""; const char *action = ""; playerState_t *ps = &cg.snap->ps; int credits = ps->persistant[ PERS_CREDIT ]; if( BG_InventoryContainsUpgrade( upgrade, cg.predictedPlayerState.stats ) ){ Class = "active"; action = va( "onClick='Cmd.exec(\"sell %s\")'", BG_Upgrade( upgrade )->name ); //Check mark icon. UTF-8 encoding of \uf00c Icon = "<icon class=\"current\">\xEF\x80\x8C</icon>"; } else if ( !BG_UpgradeUnlocked( upgrade ) || BG_UpgradeDisabled( upgrade ) ) { Class = "locked"; //Padlock icon. UTF-8 encoding of \uf023 Icon = "<icon>\xEF\x80\xA3</icon>"; } else if ( !trap_Cvar_VariableIntegerValue( "x_freeUpgrades" ) && BG_Upgrade( upgrade )->price > credits ) { Class = "expensive"; //$1 bill icon. UTF-8 encoding of \uf0d6 Icon = "<icon>\xEF\x83\x96</icon>"; } else { Class = "available"; action = va( "onClick='Cmd.exec(\"buy +%s\")'", BG_Upgrade( upgrade )->name ); } Rocket_DataFormatterFormattedData( handle, va( "<button class='armourybuy %s' onMouseover='Events.pushevent(\"setDS armouryBuyList upgrades %s\", event)' %s>%s<img src='/%s'/></button>", Class, Info_ValueForKey( data, "2" ), action, Icon, CG_GetShaderNameFromHandle( cg_upgrades[ upgrade ].upgradeIcon)), false ); }
static void CG_CompleteBuy_internal( bool negatives ) { int i; for( i = 0; i < UP_NUM_UPGRADES; i++ ) { const upgradeAttributes_t *item = BG_Upgrade( i ); if ( item->purchasable && item->team == TEAM_HUMANS ) { trap_CompleteCallback( item->name ); if ( negatives ) { trap_CompleteCallback( va( "-%s", item->name ) ); } } } trap_CompleteCallback( "grenade" ); // called "gren" elsewhere, so special-case it if ( negatives ) { trap_CompleteCallback( "-grenade" ); i = BG_GetPlayerWeapon( &cg.snap->ps ); } for( i = 0; i < WP_NUM_WEAPONS; i++ ) { const weaponAttributes_t *item = BG_Weapon( i ); if ( item->purchasable && item->team == TEAM_HUMANS ) { trap_CompleteCallback( item->name ); if ( negatives ) { trap_CompleteCallback( va( "-%s", BG_Weapon( i )->name ) ); } } } }
/* ================== G_RewardAttackers Function to distribute rewards to entities that killed this one. ================== */ void G_RewardAttackers( gentity_t *self ) { float value, reward; int playerNum, enemyDamage, maxHealth, damageShare; gentity_t *player; team_t ownTeam, playerTeam; confidence_reason_t reason; confidence_qualifier_t qualifier; // Only reward killing players and buildables if ( self->client ) { ownTeam = self->client->pers.teamSelection; maxHealth = self->client->ps.stats[ STAT_MAX_HEALTH ]; value = ( float )BG_GetValueOfPlayer( &self->client->ps ); } else if ( self->s.eType == ET_BUILDABLE ) { ownTeam = self->buildableTeam; maxHealth = BG_Buildable( self->s.modelindex )->health; value = ( float )BG_Buildable( self->s.modelindex )->value; // Give partial credits for buildables in construction if ( !self->spawned ) { value *= ( float )( level.time - self->creationTime ) / BG_Buildable( self->s.modelindex )->buildTime; } } else { return; } enemyDamage = 0; // Sum up damage dealt by enemies for ( playerNum = 0; playerNum < level.maxclients; playerNum++ ) { player = &g_entities[ playerNum ]; playerTeam = player->client->pers.teamSelection; // Player must be on the other team if ( playerTeam == ownTeam || playerTeam <= TEAM_NONE || playerTeam >= NUM_TEAMS ) { continue; } enemyDamage += self->credits[ playerNum ]; } if ( enemyDamage <= 0 ) { return; } // Give individual rewards for ( playerNum = 0; playerNum < level.maxclients; playerNum++ ) { player = &g_entities[ playerNum ]; playerTeam = player->client->pers.teamSelection; damageShare = self->credits[ playerNum ]; // Clear reward array self->credits[ playerNum ] = 0; // Player must be on the other team if ( playerTeam == ownTeam || playerTeam <= TEAM_NONE || playerTeam >= NUM_TEAMS ) { continue; } // Player must have dealt damage if ( damageShare <= 0 ) { continue; } reward = value * ( damageShare / ( float )maxHealth ); if ( reward <= 0.0f ) { continue; } if ( self->s.eType == ET_BUILDABLE ) { G_AddConfidenceToScore( player, reward ); switch ( self->s.modelindex ) { case BA_A_OVERMIND: case BA_H_REACTOR: reason = CONF_REAS_DESTR_CRUCIAL; break; case BA_A_ACIDTUBE: case BA_A_TRAPPER: case BA_A_HIVE: case BA_H_MGTURRET: case BA_H_TESLAGEN: reason = CONF_REAS_DESTR_AGGRESSIVE; break; default: reason = CONF_REAS_DESTR_SUPPORT; } qualifier = CONF_QUAL_NONE; G_AddConfidence( playerTeam, CONFIDENCE_DESTRUCTION, reason, qualifier, reward, player ); } else { G_AddCreditsToScore( player, ( int )reward ); G_AddCreditToClient( player->client, ( short )reward, qtrue ); // Give confidence for killing non-naked players outside the friendly base switch ( self->client->ps.stats[ STAT_CLASS ] ) { case PCL_ALIEN_LEVEL0: case PCL_ALIEN_BUILDER0: case PCL_ALIEN_BUILDER0_UPG: break; case PCL_HUMAN: // Treat a human just wearing light armor as naked if ( ( int )value <= BG_Class( PCL_HUMAN )->value + ( BG_Upgrade( UP_LIGHTARMOUR )->price / 2 ) ) { break; } default: if ( G_InsideBase( player, qtrue ) || G_InsideBase( self, qfalse ) ) { break; } qualifier = CONF_QUAL_OUTSIDE_OWN_BASE; G_AddConfidence( playerTeam, CONFIDENCE_KILLING, CONF_REAS_KILLING, qualifier, reward * CONFIDENCE_PER_CREDIT, player ); } } } }
/* =============== CG_HumanText =============== */ static void CG_HumanText( char *text, playerState_t *ps ) { const char *name; upgrade_t upgrade = UP_NONE; if ( cg.weaponSelect < 32 ) { name = cg_weapons[ cg.weaponSelect ].humanName; } else { name = cg_upgrades[ cg.weaponSelect - 32 ].humanName; upgrade = (upgrade_t) ( cg.weaponSelect - 32 ); } if ( !ps->ammo && !ps->clips && !BG_Weapon( ps->weapon )->infiniteAmmo ) { //no ammo switch ( ps->weapon ) { case WP_MACHINEGUN: case WP_CHAINGUN: case WP_SHOTGUN: case WP_FLAMER: Q_strcat( text, MAX_TUTORIAL_TEXT, _( "Find an Armoury for more ammo\n" ) ); break; case WP_LAS_GUN: case WP_PULSE_RIFLE: case WP_MASS_DRIVER: case WP_LUCIFER_CANNON: Q_strcat( text, MAX_TUTORIAL_TEXT, _( "Find an Armoury, Reactor, or Repeater for more ammo\n" ) ); break; default: break; } } else { switch ( ps->weapon ) { case WP_BLASTER: case WP_MACHINEGUN: case WP_SHOTGUN: case WP_LAS_GUN: case WP_CHAINGUN: case WP_PULSE_RIFLE: case WP_FLAMER: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to fire the %s\n" ), CG_KeyNameForCommand( "+attack" ), _( BG_Weapon( ps->weapon )->humanName ) ) ); break; case WP_MASS_DRIVER: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to fire the %s\n" ), CG_KeyNameForCommand( "+attack" ), _( BG_Weapon( ps->weapon )->humanName ) ) ); Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Hold %s to zoom\n" ), CG_KeyNameForCommand( "+attack2" ) ) ); break; case WP_PAIN_SAW: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Hold %s to activate the %s\n" ), CG_KeyNameForCommand( "+attack" ), _( BG_Weapon( ps->weapon )->humanName ) ) ); break; case WP_LUCIFER_CANNON: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Hold and release %s to fire a charged shot\n" ), CG_KeyNameForCommand( "+attack" ) ) ); Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to fire the %s\n" ), CG_KeyNameForCommand( "+attack2" ), _( BG_Weapon( ps->weapon )->humanName ) ) ); break; case WP_HBUILD: CG_HumanCkitText( text, ps ); break; default: break; } } if ( upgrade == UP_NONE || ( upgrade > UP_NONE && BG_Upgrade( upgrade )->usable ) ) { Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to use the %s\n" ), CG_KeyNameForCommand( "+useitem" ), name ) ); } if ( ps->stats[ STAT_HEALTH ] <= 35 && BG_InventoryContainsUpgrade( UP_MEDKIT, ps->stats ) ) { Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to use your %s\n" ), CG_KeyNameForCommand( "itemact medkit" ), _( BG_Upgrade( UP_MEDKIT )->humanName ) ) ); } switch ( cg.nearUsableBuildable ) { case BA_H_ARMOURY: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to buy equipment upgrades at the %s\n" ), CG_KeyNameForCommand( "+activate" ), _( BG_Buildable( cg.nearUsableBuildable )->humanName ) ) ); break; case BA_NONE: break; default: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to use the %s\n" ), CG_KeyNameForCommand( "+activate" ), _( BG_Buildable( cg.nearUsableBuildable )->humanName ) ) ); break; } Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s and any direction to sprint\n" ), CG_KeyNameForCommand( "+sprint" ) ) ); if ( BG_InventoryContainsUpgrade( UP_FIREBOMB, ps->stats ) || BG_InventoryContainsUpgrade( UP_GRENADE, ps->stats ) ) { Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to throw a grenade\n" ), CG_KeyNameForCommand( "itemact grenade" ) )); } }
void G_UpdateUnlockables() { int itemNum = 0, unlockableNum, unlockThreshold; float momentum; unlockable_t *unlockable; int unlockableType = 0; team_t team; for ( unlockableNum = 0; unlockableNum < NUM_UNLOCKABLES; unlockableNum++ ) { unlockable = &unlockables[ unlockableNum ]; // also iterate over item types, itemNum is a per-type counter while ( unlockableType < UNLT_NUM_UNLOCKABLETYPES - 1 && unlockableNum == unlockablesTypeOffset[ unlockableType + 1 ] ) { unlockableType++; itemNum = 0; } switch ( unlockableType ) { case UNLT_WEAPON: team = BG_Weapon( itemNum )->team; unlockThreshold = BG_Weapon( itemNum )->unlockThreshold; break; case UNLT_UPGRADE: team = TEAM_HUMANS; unlockThreshold = BG_Upgrade( itemNum )->unlockThreshold; break; case UNLT_BUILDABLE: team = BG_Buildable( itemNum )->team; unlockThreshold = BG_Buildable( itemNum )->unlockThreshold; break; case UNLT_CLASS: team = TEAM_ALIENS; unlockThreshold = BG_Class( itemNum )->unlockThreshold; break; default: Com_Error( ERR_FATAL, "G_UpdateUnlockables: Unknown unlockable type" ); } unlockThreshold = MAX( unlockThreshold, 0 ); momentum = level.team[ team ].momentum; unlockable->type = unlockableType; unlockable->num = itemNum; unlockable->team = team; unlockable->statusKnown = true; unlockable->unlockThreshold = unlockThreshold; unlockable->lockThreshold = UnlockToLockThreshold( unlockThreshold ); // calculate the item's locking state unlockable->unlocked = ( !unlockThreshold || momentum >= unlockThreshold || ( unlockable->unlocked && momentum >= unlockable->lockThreshold ) ); itemNum++; /*Com_Printf( "G_UpdateUnlockables: Team %s, Type %s, Item %s, Momentum %d, Threshold %d, " "Unlocked %d, Synchronize %d\n", BG_TeamName( team ), UnlockableTypeName( unlockable ), UnlockableName( unlockable ), momentum, unlockThreshold, unlockable->unlocked, unlockable->synchronize );*/ } // GAME knows about all teams unlockablesDataAvailable = true; unlockablesTeamKnowledge = TEAM_ALL; // generate masks for network transmission UpdateUnlockablesMask(); }
void BG_ImportUnlockablesFromMask( int team, int mask ) { int unlockableNum, teamUnlockableNum = 0, itemNum = 0, unlockThreshold; unlockable_t *unlockable; int unlockableType = 0; team_t currentTeam; bool newStatus; int statusChanges[ NUM_UNLOCKABLES ]; #ifdef BUILD_CGAME int statusChangeCount = 0; #endif // maintain a cache to prevent redundant imports static int lastMask = 0; static team_t lastTeam = TEAM_NONE; // just import if data is unavailable, cached mask is outdated or team has changed if ( unlockablesDataAvailable && team == lastTeam && mask == lastMask ) { return; } // cache input lastMask = mask; lastTeam = (team_t) team; // no status change yet memset( statusChanges, 0, sizeof( statusChanges ) ); for ( unlockableNum = 0; unlockableNum < NUM_UNLOCKABLES; unlockableNum++ ) { unlockable = &unlockables[ unlockableNum ]; // also iterate over item types, itemNum is a per-type counter if ( unlockableType < UNLT_NUM_UNLOCKABLETYPES - 1 && unlockableNum == unlockablesTypeOffset[ unlockableType + 1 ] ) { unlockableType++; itemNum = 0; } switch ( unlockableType ) { case UNLT_WEAPON: currentTeam = BG_Weapon( itemNum )->team; unlockThreshold = BG_Weapon( itemNum )->unlockThreshold; break; case UNLT_UPGRADE: currentTeam = TEAM_HUMANS; unlockThreshold = BG_Upgrade( itemNum )->unlockThreshold; break; case UNLT_BUILDABLE: currentTeam = BG_Buildable( itemNum )->team; unlockThreshold = BG_Buildable( itemNum )->unlockThreshold; break; case UNLT_CLASS: currentTeam = TEAM_ALIENS; unlockThreshold = BG_Class( itemNum )->unlockThreshold; break; default: Com_Error( ERR_FATAL, "BG_ImportUnlockablesFromMask: Unknown unlockable type" ); } unlockThreshold = MAX( unlockThreshold, 0 ); unlockable->type = unlockableType; unlockable->num = itemNum; unlockable->team = currentTeam; unlockable->unlockThreshold = unlockThreshold; unlockable->lockThreshold = UnlockToLockThreshold( unlockThreshold ); // retrieve the item's locking state if ( !unlockThreshold ) { unlockable->statusKnown = true; unlockable->unlocked = true; } else if ( currentTeam == team ) { newStatus = mask & ( 1 << teamUnlockableNum ); #ifdef BUILD_CGAME // notify client about single status change if ( unlockablesTeamKnowledge == team && unlockable->statusKnown && unlockable->unlocked != newStatus ) { InformUnlockableStatusChange( unlockable, newStatus ); statusChanges[ unlockableNum ] = newStatus ? 1 : -1; statusChangeCount++; } #endif unlockable->statusKnown = true; unlockable->unlocked = newStatus; teamUnlockableNum++; } else { unlockable->statusKnown = false; unlockable->unlocked = false; } itemNum++; } #ifdef BUILD_CGAME // notify client about all status changes if ( statusChangeCount ) { InformUnlockableStatusChanges( statusChanges, statusChangeCount ); } // export team and mask into cvar for UI trap_Cvar_Set( "ui_unlockables", va( "%d %d", team, mask ) ); #endif // we only know the state for one team unlockablesDataAvailable = true; unlockablesTeamKnowledge = (team_t) team; // save mask for later use unlockablesMask[ team ] = mask; }
static void CG_Rocket_DFUpgradeName( int handle, const char *data ) { Rocket_DataFormatterFormattedData( handle, BG_Upgrade( atoi( Info_ValueForKey( data, "1" ) ) )->humanName, true ); }
/* =============== CG_HumanText =============== */ static void CG_HumanText( char *text, playerState_t *ps ) { const char *name; upgrade_t upgrade = UP_NONE; if ( cg.weaponSelect < 32 ) { name = cg_weapons[ cg.weaponSelect ].humanName; } else { name = cg_upgrades[ cg.weaponSelect - 32 ].humanName; upgrade = cg.weaponSelect - 32; } if ( !ps->ammo && !ps->clips && !BG_Weapon( ps->weapon )->infiniteAmmo ) { //no ammo switch ( ps->weapon ) { case WP_MACHINEGUN: case WP_CHAINGUN: case WP_SHOTGUN: case WP_FLAMER: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Find an Armoury and press %s for more ammo\n" ), CG_KeyNameForCommand( "buy ammo" ) ) ); break; case WP_LAS_GUN: case WP_PULSE_RIFLE: case WP_MASS_DRIVER: case WP_LUCIFER_CANNON: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Find an Armoury, Reactor, or Repeater and press %s for more ammo\n" ), CG_KeyNameForCommand( "buy ammo" ) ) ); break; default: break; } } else { switch ( ps->weapon ) { case WP_BLASTER: case WP_MACHINEGUN: case WP_SHOTGUN: case WP_LAS_GUN: case WP_CHAINGUN: case WP_PULSE_RIFLE: case WP_FLAMER: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to fire the %s\n" ), CG_KeyNameForCommand( "+attack" ), _( BG_Weapon( ps->weapon )->humanName ) ) ); break; case WP_MASS_DRIVER: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to fire the %s\n" ), CG_KeyNameForCommand( "+attack" ), _( BG_Weapon( ps->weapon )->humanName ) ) ); Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Hold %s to zoom\n" ), CG_KeyNameForCommand( "+attack2" ) ) ); break; case WP_PAIN_SAW: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Hold %s to activate the %s\n" ), CG_KeyNameForCommand( "+attack" ), _( BG_Weapon( ps->weapon )->humanName ) ) ); break; case WP_LUCIFER_CANNON: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Hold and release %s to fire a charged shot\n" ), CG_KeyNameForCommand( "+attack" ) ) ); Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to fire the %s\n" ), CG_KeyNameForCommand( "+attack2" ), _( BG_Weapon( ps->weapon )->humanName ) ) ); break; case WP_HBUILD: CG_HumanCkitText( text, ps ); break; default: break; } } Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Use %s and %s to select an upgrade\n" ), CG_KeyNameForCommand( "weapprev" ), CG_KeyNameForCommand( "weapnext" ) ) ); if ( upgrade == UP_NONE || ( upgrade > UP_NONE && BG_Upgrade( upgrade )->usable ) ) { Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to use the %s\n" ), CG_KeyNameForCommand( "+useitem" ), name ) ); } if ( ps->stats[ STAT_HEALTH ] <= 35 && BG_InventoryContainsUpgrade( UP_MEDKIT, ps->stats ) ) { Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to use your %s\n" ), CG_KeyNameForCommand( "itemact medkit" ), _( BG_Upgrade( UP_MEDKIT )->humanName ) ) ); } if ( ps->stats[ STAT_STAMINA ] <= STAMINA_BLACKOUT_LEVEL ) { Q_strcat( text, MAX_TUTORIAL_TEXT, _( "You are blacking out. Stop sprinting to recover stamina\n" ) ); } else if ( ps->stats[ STAT_STAMINA ] <= STAMINA_SLOW_LEVEL ) { Q_strcat( text, MAX_TUTORIAL_TEXT, _( "Your stamina is low. Stop sprinting to recover\n" ) ); } switch ( cg.nearUsableBuildable ) { case BA_H_ARMOURY: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to buy equipment upgrades at the %s. Sell your old weapon first!\n" ), CG_KeyNameForCommand( "+activate" ), _( BG_Buildable( cg.nearUsableBuildable )->humanName ) ) ); break; case BA_H_REPEATER: case BA_H_REACTOR: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to refill your energy weapon's ammo at the %s\n" ), CG_KeyNameForCommand( "+activate" ), _( BG_Buildable( cg.nearUsableBuildable )->humanName ) ) ); break; case BA_NONE: break; default: Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s to use the %s\n" ), CG_KeyNameForCommand( "+activate" ), _( BG_Buildable( cg.nearUsableBuildable )->humanName ) ) ); break; } Q_strcat( text, MAX_TUTORIAL_TEXT, va( _( "Press %s and any direction to sprint\n" ), CG_KeyNameForCommand( "+sprint" ) ) ); }
/* =============== CG_HumanText =============== */ static void CG_HumanText( char *text, playerState_t *ps ) { char *name; upgrade_t upgrade = UP_NONE; if( cg.weaponSelect < 32 ) name = cg_weapons[ cg.weaponSelect ].humanName; else { name = cg_upgrades[ cg.weaponSelect - 32 ].humanName; upgrade = cg.weaponSelect - 32; } if( !ps->ammo && !ps->clips && !BG_Weapon( ps->weapon )->infiniteAmmo ) { //no ammo switch( ps->weapon ) { case WP_MACHINEGUN: case WP_CHAINGUN: case WP_SHOTGUN: case WP_FLAMER: Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Find an Armoury and press %s for more ammo\n", CG_KeyNameForCommand( "buy ammo" ) ) ); break; case WP_LAS_GUN: case WP_PULSE_RIFLE: case WP_MASS_DRIVER: case WP_LUCIFER_CANNON: Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Find a Reactor or Repeater and press %s for more ammo\n", CG_KeyNameForCommand( "buy ammo" ) ) ); break; default: break; } } else { switch( ps->weapon ) { case WP_BLASTER: case WP_MACHINEGUN: case WP_SHOTGUN: case WP_LAS_GUN: case WP_CHAINGUN: case WP_PULSE_RIFLE: case WP_FLAMER: Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Press %s to fire the %s\n", CG_KeyNameForCommand( "+attack" ), BG_Weapon( ps->weapon )->humanName ) ); break; case WP_MASS_DRIVER: Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Press %s to fire the %s\n", CG_KeyNameForCommand( "+attack" ), BG_Weapon( ps->weapon )->humanName ) ); Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Hold %s to zoom\n", CG_KeyNameForCommand( "+button5" ) ) ); break; case WP_PAIN_SAW: Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Hold %s to activate the %s\n", CG_KeyNameForCommand( "+attack" ), BG_Weapon( ps->weapon )->humanName ) ); break; case WP_LUCIFER_CANNON: Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Hold and release %s to fire a charged shot\n", CG_KeyNameForCommand( "+attack" ) ) ); Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Press %s to fire the %s\n", CG_KeyNameForCommand( "+button5" ), BG_Weapon( ps->weapon )->humanName ) ); break; case WP_HBUILD: CG_HumanCkitText( text, ps ); break; default: break; } } Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Press %s and ", CG_KeyNameForCommand( "weapprev" ) ) ); Q_strcat( text, MAX_TUTORIAL_TEXT, va( "%s to select an upgrade\n", CG_KeyNameForCommand( "weapnext" ) ) ); if( upgrade == UP_NONE || ( upgrade > UP_NONE && BG_Upgrade( upgrade )->usable ) ) { Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Press %s to use the %s\n", CG_KeyNameForCommand( "+button2" ), name ) ); } if( ps->stats[ STAT_HEALTH ] <= 35 && BG_InventoryContainsUpgrade( UP_MEDKIT, ps->stats ) ) { Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Press %s to use your %s\n", CG_KeyNameForCommand( "itemact medkit" ), BG_Upgrade( UP_MEDKIT )->humanName ) ); } if( ps->stats[ STAT_STAMINA ] <= STAMINA_BLACKOUT_LEVEL ) { Q_strcat( text, MAX_TUTORIAL_TEXT, "You are blacking out. Stop sprinting to recover stamina.\n" ); } else if( ps->stats[ STAT_STAMINA ] <= STAMINA_SLOW_LEVEL ) { Q_strcat( text, MAX_TUTORIAL_TEXT, "Your stamina is low. Stop sprinting to recover.\n" ); } if( cg.nearUsableBuildable ) { Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Press %s to use this structure\n", CG_KeyNameForCommand( "+button7" ) ) ); } Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Press %s and any direction to sprint\n", CG_KeyNameForCommand( "+button8" ) ) ); Q_strcat( text, MAX_TUTORIAL_TEXT, va( "Press %s and back or strafe to dodge\n", CG_KeyNameForCommand( "+button6" ) ) ); }
/* =================== CG_DrawItemSelect =================== */ void CG_DrawItemSelect( rectDef_t *rect, vec4_t color ) { int i; float x = rect->x; float y = rect->y; float width = rect->w; float height = rect->h; float iconWidth; float iconHeight; int items[ 64 ]; int colinfo[ 64 ]; int numItems = 0, selectedItem = 0; int length; 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 ) { if( !CG_WeaponSelectable( cg.weaponSelect ) ) CG_NextWeapon_f( ); } else { if( !CG_UpgradeSelectable( cg.weaponSelect - 32 ) ) CG_NextWeapon_f( ); } } // showing weapon select clears pickup item display, but not the blend blob cg.itemPickupTime = 0; // put all weapons in the items list for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) { if( !BG_InventoryContainsWeapon( i, cg.snap->ps.stats ) ) continue; if( !ps->ammo && !ps->clips && !BG_Weapon( i )->infiniteAmmo ) colinfo[ numItems ] = 1; else colinfo[ numItems ] = 0; if( i == cg.weaponSelect ) selectedItem = numItems; if( !cg_weapons[ i ].registered ) { Com_Printf( S_COLOR_YELLOW "WARNING: CG_DrawItemSelect: weapon %d (%s) " "is not registered\n", i, BG_Weapon( i )->name ); continue; } items[ numItems ] = i; numItems++; } // put all upgrades in the weapons list for( i = UP_NONE + 1; i < UP_NUM_UPGRADES; i++ ) { if( !BG_InventoryContainsUpgrade( i, cg.snap->ps.stats ) ) continue; colinfo[ numItems ] = 0; if( !BG_Upgrade( i )->usable ) colinfo[ numItems ] = 2; if( i == cg.weaponSelect - 32 ) selectedItem = numItems; if( !cg_upgrades[ i ].registered ) { Com_Printf( S_COLOR_YELLOW "WARNING: CG_DrawItemSelect: upgrade %d (%s) " "is not registered\n", i, BG_Upgrade( i )->name ); continue; } items[ numItems ] = i + 32; numItems++; } // compute the length of the display window and determine orientation vertical = height > width; if( vertical ) { iconWidth = width * cgDC.aspectScale; iconHeight = width; length = height / ( width * cgDC.aspectScale ); } else { iconWidth = height * cgDC.aspectScale; iconHeight = height; length = width / ( height * cgDC.aspectScale ); } // render icon ring for( i = 0; i < length; i++ ) { int item = i - length / 2 + selectedItem; if( item < 0 ) item += length; else if( item >= length ) item -= length; if( item >= 0 && item < numItems ) { switch( colinfo[ item ] ) { case 0: color = colorCyan; break; case 1: color = colorRed; break; case 2: color = colorMdGrey; break; } color[3] = 0.5; trap_R_SetColor( color ); if( items[ item ] < 32 ) CG_DrawPic( x, y, iconWidth, iconHeight, cg_weapons[ items[ item ] ].weaponIcon ); else CG_DrawPic( x, y, iconWidth, iconHeight, cg_upgrades[ items[ item ] - 32 ].upgradeIcon ); } if( vertical ) y += iconHeight; else x += iconWidth; } trap_R_SetColor( NULL ); }