diff --git a/userraw/maps/mp/gametypes/_damage.gsc b/userraw/maps/mp/gametypes/_damage.gsc index c9d6fde..96051e8 100644 --- a/userraw/maps/mp/gametypes/_damage.gsc +++ b/userraw/maps/mp/gametypes/_damage.gsc @@ -1,3 +1,12 @@ +/* + _gamelogic modded + Author: INeedGames + Date: 09/22/2020 + Adds force final killcam, extra hitmarkers, etc. + + Thanks: banz +*/ + #include maps\mp\_utility; #include maps\mp\gametypes\_hud_util; #include common_scripts\utility; @@ -202,7 +211,8 @@ handleNormalDeath( lifeId, attacker, eInflictor, sWeapon, sMeansOfDeath ) else value = undefined; - attacker playLocalSound( "bullet_impact_headshot_2" ); + if( !level.extraDamageFeedback ) + attacker playLocalSound( "bullet_impact_headshot_2" ); } else { @@ -237,19 +247,19 @@ handleNormalDeath( lifeId, attacker, eInflictor, sWeapon, sMeansOfDeath ) if ( isAlive( attacker ) ) { // killstreaks only advance from kills earned this life - if ( isDefined( level.killStreakSpecialCaseWeapons[sWeapon] ) ) // this is an optimization + if ( isDefined( level.killStreakSpecialCaseWeapons[sWeapon] ) || sWeapon == "nuke_mp" ) // this is an optimization { switch ( sWeapon ) { case "ac130_105mm_mp": case "ac130_40mm_mp": case "ac130_25mm_mp": - if ( attacker.ac130LifeId == attacker.pers["deaths"] ) + if ( attacker.ac130LifeId == attacker.pers["deaths"] && !level.scriptIncKillstreak ) attacker.pers["cur_kill_streak"]++; break; case "cobra_player_minigun_mp": case "weapon_cobra_mk19_mp": - if ( attacker.heliRideLifeId == attacker.pers["deaths"] ) + if ( attacker.heliRideLifeId == attacker.pers["deaths"] && !level.scriptIncKillstreak ) attacker.pers["cur_kill_streak"]++; break; case "cobra_20mm_mp": @@ -259,22 +269,25 @@ handleNormalDeath( lifeId, attacker, eInflictor, sWeapon, sMeansOfDeath ) case "sentry_minigun_mp": case "harrier_20mm_mp": case "pavelow_minigun_mp": + case "nuke_mp": if ( isDefined( eInflictor ) && isDefined( eInflictor.lifeId ) ) killstreakLifeId = eInflictor.lifeId; else killstreakLifeId = attacker.lifeId; - if ( killstreakLifeId == attacker.pers["deaths"] ) + if ( killstreakLifeId == attacker.pers["deaths"] && !level.scriptIncKillstreak && (level.nukeIncreasesStreak || sWeapon != "nuke_mp") ) attacker.pers["cur_kill_streak"]++; break; default: - attacker.pers["cur_kill_streak"]++; + if( !level.scriptIncKillstreak ) + attacker.pers["cur_kill_streak"]++; break; } } else { - attacker.pers["cur_kill_streak"]++; + if( !level.scriptIncKillstreak ) + attacker.pers["cur_kill_streak"]++; } attacker setPlayerStatIfGreater( "killstreak", attacker.pers["cur_kill_streak"] ); @@ -321,6 +334,9 @@ handleNormalDeath( lifeId, attacker, eInflictor, sWeapon, sMeansOfDeath ) if ( isDefined( level.onNormalDeath ) && attacker.pers[ "team" ] != "spectator" ) [[ level.onNormalDeath ]]( self, attacker, lifeId ); + + if ( isDefined( level.onNormalDeath2 ) && attacker.pers[ "team" ] != "spectator" ) + [[ level.onNormalDeath2 ]]( self, attacker, sMeansOfDeath ); level thread maps\mp\gametypes\_battlechatter_mp::sayLocalSoundDelayed( attacker, "kill", 0.75 ); @@ -425,7 +441,7 @@ PlayerKilled_internal( eInflictor, attacker, victim, iDamage, sMeansOfDeath, sWe victim.idFlags = 0; else if ( sMeansOfDeath == "MOD_GRENADE" && isSubstr( sWeapon, "frag_grenade" ) && iDamage == 100000 ) victim.idFlags = 0; - else if ( sWeapon == "nuke_mp" ) + else if ( sWeapon == "nuke_mp" && !level.forceFinalKillcam ) victim.idFlags = 0; else if ( level.friendlyfire >= 2) victim.idFlags = 0; @@ -543,7 +559,11 @@ PlayerKilled_internal( eInflictor, attacker, victim, iDamage, sMeansOfDeath, sWe // override MOD if ( isHeadShot( sWeapon, sHitLoc, sMeansOfDeath, attacker ) ) + { sMeansOfDeath = "MOD_HEAD_SHOT"; + if( level.headShotDetachHead ) + victim detach(victim.headmodel); + } else if ( sMeansOfDeath != "MOD_MELEE" && !isDefined( victim.nuked ) ) victim playDeathSound(); @@ -634,10 +654,14 @@ PlayerKilled_internal( eInflictor, attacker, victim, iDamage, sMeansOfDeath, sWe else if ( !isPlayer( attacker ) || (isPlayer( attacker ) && sMeansOfDeath == "MOD_FALLING") ) { handleWorldDeath( attacker, lifeId, sMeansOfDeath, sHitLoc ); + if ( level.failCam ) + doKillcam = true; } else if ( attacker == victim ) { handleSuicideDeath( sMeansOfDeath, sHitLoc ); + if ( level.failCam ) + doKillcam = true; } else if ( friendlyFire ) { @@ -645,6 +669,8 @@ PlayerKilled_internal( eInflictor, attacker, victim, iDamage, sMeansOfDeath, sWe { handleFriendlyFireDeath( attacker ); } + if ( level.failCam ) + doKillcam = true; } else { @@ -694,12 +720,14 @@ PlayerKilled_internal( eInflictor, attacker, victim, iDamage, sMeansOfDeath, sWe // allow per gametype death handling victim thread [[ level.onPlayerKilled ]]( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration, lifeId ); - + if ( isPlayer( attacker ) ) attackerNum = attacker getEntityNumber(); + else if ( (sMeansOfDeath == "MOD_FALLING" || eInflictor.classname == "trigger_hurt") && level.failCam )//banz + attackerNum = victim getEntityNumber(); else attackerNum = -1; - killcamentity = victim getKillcamEntity( attacker, eInflictor, sWeapon ); + killcamentity = victim getKillcamEntity( attacker, eInflictor, sWeapon, sMeansOfDeath ); killcamentityindex = -1; killcamentitystarttime = 0; @@ -710,24 +738,31 @@ PlayerKilled_internal( eInflictor, attacker, victim, iDamage, sMeansOfDeath, sWe if ( !isdefined( killcamentitystarttime ) ) killcamentitystarttime = 0; } - + /# if ( getDvarInt( "scr_forcekillcam" ) != 0 ) doKillcam = true; #/ - - if ( isDefined( attacker.finalKill ) ) - maps\mp\_awards::addAwardWinner( "finalkill", attacker.clientid ); - //prof_end( " PlayerKilled_5" ); - //prof_begin( " PlayerKilled_6" ); + // record the kill cam values for the final kill cam + if ( level.forceFinalKillcam && doKillcam ) + maps\mp\gametypes\_gamelogic::recordFinalKillCam( 5.0, victim, attacker, attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, deathTimeOffset, psOffsetTime ); - if ( isDefined( attacker.finalKill ) && doKillcam && !isDefined( level.nukeDetonated ) ) + if ( !level.forceFinalKillcam && level.allowFinalKillcam ) { - level thread doFinalKillcam( 5.0, victim, attacker, attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, deathTimeOffset, psOffsetTime ); + if ( isDefined( attacker.finalKill ) ) + maps\mp\_awards::addAwardWinner( "finalkill", attacker.clientid ); + + //prof_end( " PlayerKilled_5" ); + //prof_begin( " PlayerKilled_6" ); + + if ( isDefined( attacker.finalKill ) && doKillcam && !isDefined( level.nukeDetonated ) ) + { + level thread doFinalKillcam( 5.0, victim, attacker, attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, deathTimeOffset, psOffsetTime ); - if ( !isFauxDeath ) - wait ( 1.0 ); + if ( !isFauxDeath ) + wait ( 1.0 ); + } } if ( !isFauxDeath ) @@ -925,11 +960,14 @@ resetPlayerVariables() } -getKillcamEntity( attacker, eInflictor, sWeapon ) +getKillcamEntity( attacker, eInflictor, sWeapon, sMeansOfDeath ) { if ( !isDefined( eInflictor ) ) return undefined; + if( (sMeansOfDeath == "MOD_FALLING" || eInflictor.classname == "trigger_hurt") && level.failCam ) + return attacker; + if ( eInflictor == attacker ) return undefined; @@ -1052,6 +1090,12 @@ giveRecentShieldXP() Callback_PlayerDamage_internal( eInflictor, eAttacker, victim, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime ) { + if( level.disableKnife && sMeansOfDeath == "MOD_MELEE" && sWeapon != "riotshield_mp" ) + return; + + if( level.disableTurret && sWeapon == "turret_minigun_mp" ) + return; + if ( !isReallyAlive( victim ) ) return; @@ -1402,6 +1446,8 @@ Callback_PlayerDamage_internal( eInflictor, eAttacker, victim, iDamage, iDFlags, if ( attackerIsNPC && isDefined( eAttacker.gunner ) ) damager = eAttacker.gunner; + else if( level.extraDamageFeedback && isDefined( eAttacker.owner ) ) + damager = eAttacker.owner; else damager = eAttacker; @@ -1409,7 +1455,7 @@ Callback_PlayerDamage_internal( eInflictor, eAttacker, victim, iDamage, iDFlags, { if ( iDFlags & level.iDFLAGS_STUN ) typeHit = "stun"; - else if ( victim hasPerk( "specialty_armorvest", true ) || (isExplosiveDamage( sMeansOfDeath ) && victim _hasPerk( "_specialty_blastshield" )) ) + else if ( victim _hasPerk( "specialty_armorvest" ) || (isExplosiveDamage( sMeansOfDeath ) && victim _hasPerk( "_specialty_blastshield" )) ) typeHit = "hitBodyArmor"; else if ( victim _hasPerk( "specialty_combathigh") ) typeHit = "hitEndGame"; @@ -1534,6 +1580,37 @@ Callback_PlayerDamage( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, s finishPlayerDamageWrapper( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, psOffsetTime, stunFraction ) { + if( level.allowPrintDamage ) + { + if ( isDefined( eAttacker ) && isPlayer( eAttacker ) && eAttacker.printDamage ) + eAttacker iPrintLnBold( iDamage ); + else if( isDefined( eAttacker.owner ) && isPlayer( eAttacker.owner ) && eAttacker.owner.printDamage ) + eAttacker.owner iPrintLnBold( iDamage ); + } + + if( level.extraDamageFeedback ) + { + if( sWeapon == "nuke_mp" ) + { + if ( self _hasPerk( "specialty_armorvest" ) || self _hasPerk( "_specialty_blastshield") ) + typeHit = "hitBodyArmor"; + else if ( self _hasPerk( "specialty_combathigh") ) + typeHit = "hitEndGame"; + else + typeHit = "standard"; + + eAttacker thread maps\mp\gametypes\_damagefeedback::updateDamageFeedback( typeHit ); + } + + if( sHitLoc == "head" || sHitLoc == "helmet" ) + { + if ( isDefined( eAttacker ) && isPlayer( eAttacker ) ) + eAttacker playLocalSound( "bullet_impact_headshot_2" ); + else if( isDefined( eAttacker.owner ) && isPlayer( eAttacker.owner ) ) + eAttacker.owner playLocalSound( "bullet_impact_headshot_2" ); + } + } + if ( (self isUsingRemote() ) && (iDamage >= self.health) && !(iDFlags & level.iDFLAGS_STUN) ) { if ( !isDefined( vDir ) ) diff --git a/userraw/maps/mp/gametypes/_gamelogic.gsc b/userraw/maps/mp/gametypes/_gamelogic.gsc index 21e849a..1b4c728 100644 --- a/userraw/maps/mp/gametypes/_gamelogic.gsc +++ b/userraw/maps/mp/gametypes/_gamelogic.gsc @@ -1,3 +1,64 @@ +/* + _gamelogic modded + Author: INeedGames + Date: 09/22/2020 + Adds DVARs for customization. + + DVARS: + - scr_extraDamageFeedback + false - (default) players receive hitmarkers for helicopters, hitting equipment, etc. + + - scr_printDamage + false - (default) allows players to receive numbered feedback how much damage they delt + + - scr_disableKnife + false - (default) disables knife damage + + - scr_intermissionTime + 30.0 - (default) how long to wait in intermission after a match completes + + - scr_forceKillcam + false - (default) show final killcams even if a kill didn't end the game + + - scr_forceKillcam_winnersKill + true - (default) only show the winner's killcam as a final killcam + + - scr_game_allowFinalKillcam + true - (default) allows if a final killcam is shown + + - scr_disableTurret + false - (default) disables mountable turret damage + + - scr_failCam + false - (default) show suicides as killcams + + - scr_voting + false - (default) allow players to vote for a map at the end of a match + + - scr_voting_maps + "mp_rust,mp_terminal" - (default) list of maps to be allowed for voting + + - scr_voting_time + 26.0 - (default) how long should polls be open for + + - scr_voting_winTime + 4.0 - (default) how long to show the winning map for + + - scr_allow_intermission + false - (default) allow an intermission time after a match ends + + - scr_voting_bots + false - (default) bots are allowed to pick a map to vote + + - scr_nuke_increases_streak + true - (default) nukes (if they don't end the game) increase a player's killstreak + + - headshot_detach_head + false - (default) headshots dismember the victim's head + + Thanks: banz +*/ + #include maps\mp\_utility; #include maps\mp\gametypes\_hud_util; #include common_scripts\utility; @@ -365,30 +426,65 @@ updateGameEvents() waittillFinalKillcamDone() { - if ( !level.showingFinalKillcam ) - return false; + if ( level.forceFinalKillcam ) + { + waittillframeend; // give "round_end_finished" notifies time to process + + if( level.showingFinalKillcam ) + { + foreach ( player in level.players ) + player notify( "reset_outcome" ); + + level notify( "game_cleanup" ); + + while ( level.showingFinalKillcam ) + wait ( 0.05 ); + } + } + else + { + if ( !level.showingFinalKillcam ) + return false; - while ( level.showingFinalKillcam ) - wait ( 0.05 ); - - return true; + while ( level.showingFinalKillcam ) + wait ( 0.05 ); + + return true; + } } - -timeLimitClock_Intermission( waitTime ) +timeLimitClock_Intermission( waitTime, clockColor ) { - setGameEndTime( getTime() + int(waitTime*1000) ); + if( !isDefined( clockColor ) ) + clockColor = (0, 0, 0); + + NewWaitTime = waitTime*1000; + + setGameEndTime( getTime() + int(NewWaitTime) ); clockObject = spawn( "script_origin", (0,0,0) ); clockObject hide(); - if ( waitTime >= 10.0 ) - wait ( waitTime - 10.0 ); - - for ( ;; ) + matchStartTimer = createServerTimer("objective", 1.4); + matchStartTimer setPoint( "TOPRIGHT", "TOPRIGHT", -5, 0 ); //("CENTER", "CENTER", 0, -45); + matchStartTimer setTimer( waitTime - 1 ); + matchStartTimer.sort = 1001; + matchStartTimer.foreground = false; + matchStartTimer.hideWhenInMenu = false; + matchStartTimer.color = clockColor; + + currentTime = getTime(); + timeRunning = ( getTime() - currentTime ); + while ( timeRunning <= NewWaitTime ) { - clockObject playSound( "ui_mp_timer_countdown" ); - wait ( 1.0 ); - } + wait 0.05; + if ( (timeRunning - NewWaitTime) >= -10000 && timeRunning%1000 == 0 ) + clockObject playSound( "ui_mp_timer_countdown" ); + + timeRunning = ( getTime() - currentTime ); + } + + clockObject delete(); + matchStartTimer destroyElem(); } @@ -530,6 +626,9 @@ updateTieStats( loser ) updateWinLossStats( winner ) { + //if ( privateMatch() ) + // return; + if ( !wasLastRound() ) return; @@ -607,6 +706,9 @@ updateMatchBonusScores( winner ) if ( !game["timePassed"] ) return; + //if ( !matchMakingGame() ) + // return; + if ( !getTimeLimit() || level.forcedEnd ) { gameLength = getTimePassed() / 1000; @@ -1226,6 +1328,36 @@ roundEndDOF( time ) self setDepthOfField( 0, 128, 512, 4000, 6, 1.8 ); } +randomizeMaps() +{ + tok = strTok( level.votingMaps, "," ); + + randomArray = []; + for( i = 0; i < 9; i++ ) + { + selectedRand = randomint( tok.size ); + randomArray[ i ] = tok[ selectedRand ]; + tok = restructMapArray( tok, selectedRand ); + } + + return randomArray; +} + +restructMapArray(oldArray, index) +{ + restructArray = []; + + for( i=0; i < oldArray.size; i++ ) + { + if( i < index ) + restructArray[ i ] = oldArray[ i ]; + else if( i > index ) + restructArray[ i - 1 ] = oldArray[ i ]; + } + + return restructArray; +} + Callback_StartGameType() { @@ -1241,6 +1373,60 @@ Callback_StartGameType() level.intermission = false; + + setDvarIfUninitialized( "scr_extraDamageFeedback", false ); + setDvarIfUninitialized( "scr_printDamage", false ); + setDvarIfUninitialized( "scr_disableKnife", false ); + setDvarIfUninitialized( "scr_intermissionTime", 30.0 ); + setDvarIfUninitialized( "scr_forceKillcam", false ); + setDvarIfUninitialized( "scr_forceKillcam_winnersKill", true ); + setDvarIfUninitialized( "scr_game_allowFinalKillcam", true ); + setDvarIfUninitialized( "scr_disableTurret", false ); + setDvarIfUninitialized( "scr_failCam", false ); + setDvarIfUninitialized( "scr_voting", false ); + setDvarIfUninitialized( "scr_voting_maps", "mp_rust,mp_terminal" ); + setDvarIfUninitialized( "scr_voting_time", 26.0 ); + setDvarIfUninitialized( "scr_voting_winTime", 4.0 ); + setDvarIfUninitialized( "scr_allow_intermission", false );//vanilla as possible + setDvarIfUninitialized( "scr_voting_bots", false ); + setDvarIfUninitialized( "scr_nuke_increases_streak", true ); + setDvarIfUninitialized( "headshot_detach_head", false ); + + level.extraDamageFeedback = getDvarInt("scr_extraDamageFeedback"); + level.allowPrintDamage = getDvarInt("scr_printDamage"); + level.disableKnife = getDvarInt("scr_disableKnife"); + level.intermissionTime = getDvarFloat("scr_intermissionTime"); + level.forceFinalKillcam = getDvarInt("scr_forceKillcam"); + level.forceFinalKillcamWinnersKill = getDvarInt("scr_forceKillcam_winnersKill"); + level.allowFinalKillcam = getDvarInt("scr_game_allowFinalKillcam"); + level.disableTurret = getDvarInt( "scr_disableTurret" ); + level.failCam = getDvarInt( "scr_failCam" ); + level.voting = getDvarInt( "scr_voting" ); + level.votingMaps = getDvar( "scr_voting_maps" ); + level.voteWinTime = getDvarInt( "scr_voting_winTime" ); + level.voteTime = getDvarInt( "scr_voting_time" ); + level.allowIntermission = getDvarInt( "scr_allow_intermission" ); + level.botsVote = getDvarInt( "scr_voting_bots" ); + level.headShotDetachHead = getDvarInt("headshot_detach_head"); + level.nukeIncreasesStreak = getDvarInt( "scr_nuke_increases_streak" ); + + if ( level.voting ) + level.votingMapsTok = randomizeMaps(); + else + level.votingMapsTok = strTok( level.votingMaps, "," ); + + level.scriptIncKillstreak = false; + + level.mapVotes = []; + for( i=0; i < level.votingMapsTok.size; i++ ) + level.mapVotes[ i ] = 0; + + level.inVoting = false; + level.inShowingWinner = false; + level.inIntermission = false; + level.highestVotedMap = -1; + + makeDvarServerInfo( "cg_thirdPersonAngle", 356 ); makeDvarServerInfo( "scr_gameended", 0 ); @@ -1290,8 +1476,17 @@ Callback_StartGameType() precacheShader( "white" ); precacheShader( "black" ); - //precacheMenu("popup_summary"); - + + game["menu_vote"] = "vote"; + + if ( level.voting && level.voteTime > 0.0 && level.votingMapsTok.size ) + precacheMenu( game["menu_vote"] ); + + game["menu_popup_summary"] = "popup_summary"; + + if ( level.allowIntermission && level.intermissionTime > 0.0 ) + precacheMenu( game["menu_popup_summary"] ); + game["strings"]["press_to_spawn"] = &"PLATFORM_PRESS_TO_SPAWN"; if ( level.teamBased ) { @@ -1473,6 +1668,8 @@ Callback_StartGameType() thread maps\mp\_events::init(); thread maps\mp\_defcon::init(); + level thread onPlayerConnect(); + if ( level.teamBased ) thread maps\mp\gametypes\_friendicons::init(); @@ -1557,6 +1754,99 @@ Callback_StartGameType() level thread updateWatchedDvars(); level thread timeLimitThread(); + + level thread doFinalKillcam(); +} + +onPlayerConnect() +{ + for(;;) + { + level waittill( "connected", player ); + + player thread onPlayerSpawned(); + + player thread watchIntermissionAfterConnect(); + } +} + +watchIntermissionAfterConnect() +{ + self endon("disconnect"); + + wait 0.05; + + self notify("kill_menus_on_connect"); + if(level.inVoting || level.inShowingWinner) + { + self.sessionstate = "spectator";//allow player to leave while in intermission and make voting options + self thread watchVoting(); + + if(level.inVoting) + { + self setClientDvars( "hud_ShowWinner", "0", + "hud_voteText", "^3Vote for new map:", + "vote_map", "" ); + } + else if(level.inShowingWinner) + { + self setClientDvars( "hud_WinningName", "preview_" + level.votingMapsTok[ level.highestVotedMap ], + "hud_WinningMap", consoleMapNameToMapName( level.votingMapsTok[ level.highestVotedMap ] ), + "hud_voteText", "^3Next Map:", + "hud_ShowWinner", "1" ); + } + + self openPopupMenu( game["menu_vote"] ); + } + else if(level.inIntermission) + { + self.sessionstate = "spectator";//allow player to leave while in intermission + self thread openSummaryOnMenuClose(); + self openPopupMenu( game["menu_popup_summary"] ); + } +} + +onPlayerSpawned() +{ + self endon("disconnect"); + self.printDamage = false; + firstTime = false; + for(;;) + { + self waittill("spawned_player"); + if( !firstTime && level.allowPrintDamage ) + { + firstTime = true; + self iPrintlnBold( "^7Press ^3[{+actionslot 2}] ^7to toggle ^3Print Damage" ); + } + self thread printDamage(); + } +} + +printDamage() +{ + if( !level.allowPrintDamage ) + return; + + self endon("disconnect"); + self endon("death"); + + self notifyOnPlayerCommand("printDamage", "+actionslot 2"); + for(;;) + { + self waittill("printDamage"); + self playSound( "semtex_warning" ); + if(self.printDamage) + { + self iPrintlnBold("^7Print Damage ^1Disabled"); + self.printDamage = false; + } + else + { + self iPrintlnBold("^7Print Damage ^1Enabled"); + self.printDamage = true; + } + } } @@ -1842,9 +2132,19 @@ getBetterTeam() rankedMatchUpdates( winner ) { - setXenonRanks(); + //if ( matchMakingGame() ) + //{ + setXenonRanks(); - updateMatchBonusScores( winner ); + //if ( hostIdledOut() ) + //{ + // level.hostForcedEnd = true; + // logString( "host idled out" ); + // endLobby(); + //} + + updateMatchBonusScores( winner ); + //} updateWinLossStats( winner ); } @@ -1934,6 +2234,8 @@ displayRoundSwitch() endGameOvertime( winner, endReasonText ) { + visionSetNaked( "mpOutro", 0.5 ); + setDvar( "scr_gameended", 2 ); // freeze players foreach ( player in level.players ) { @@ -1965,6 +2267,9 @@ endGameOvertime( winner, endReasonText ) } roundEndWait( level.roundEndDelay, false ); + + if ( level.forceFinalKillcam ) + waittillFinalKillcamDone(); game["status"] = "overtime"; level notify ( "restarting" ); @@ -2011,6 +2316,9 @@ endGameHalfTime() } roundEndWait( level.roundEndDelay, false ); + + if ( level.forceFinalKillcam ) + waittillFinalKillcamDone(); game["status"] = "halftime"; level notify ( "restarting" ); @@ -2021,6 +2329,11 @@ endGameHalfTime() endGame( winner, endReasonText, nukeDetonated ) { + if( !level.forceFinalKillcamWinnersKill || !isDefined( winner ) || !isString( winner ) || ( winner != "axis" && winner != "allies" ) ) + level.finalKillCam_winner = "none"; + else + level.finalKillCam_winner = winner; + if ( !isDefined(nukeDetonated) ) nukeDetonated = false; @@ -2109,15 +2422,22 @@ endGame( winner, endReasonText, nukeDetonated ) displayRoundEnd( winner, endReasonText ); - if ( level.showingFinalKillcam ) + if ( level.forceFinalKillcam ) { - foreach ( player in level.players ) - player notify ( "reset_outcome" ); - - level notify ( "game_cleanup" ); - waittillFinalKillcamDone(); } + else + { + if ( level.showingFinalKillcam ) + { + foreach ( player in level.players ) + player notify ( "reset_outcome" ); + + level notify ( "game_cleanup" ); + + waittillFinalKillcamDone(); + } + } if ( !wasLastRound() ) { @@ -2148,17 +2468,30 @@ endGame( winner, endReasonText, nukeDetonated ) maps\mp\gametypes\_missions::roundEnd( winner ); + if( isRoundBased() ) + winner = getWinningTeam(); + displayGameEnd( winner, endReasonText ); - if ( level.showingFinalKillcam && wasOnlyRound() ) + if( wasOnlyRound() ) { - foreach ( player in level.players ) - player notify ( "reset_outcome" ); + if ( level.forceFinalKillcam ) + { + waittillFinalKillcamDone(); + } + else + { + if ( level.showingFinalKillcam ) + { + foreach ( player in level.players ) + player notify ( "reset_outcome" ); - level notify ( "game_cleanup" ); + level notify ( "game_cleanup" ); - waittillFinalKillcamDone(); - } + waittillFinalKillcamDone(); + } + } + } levelFlagClear( "block_notifies" ); @@ -2196,28 +2529,407 @@ endGame( winner, endReasonText, nukeDetonated ) { wait ( min( 10.0, 4.0 + level.postGameNotifies ) ); } - if (!matchmakingGame()) + + if ( level.voting && level.voteTime > 0.0 && level.votingMapsTok.size ) { + level.inVoting = true; foreach (player in level.players) { - //player openPopupMenu("popup_summary"); + player.sessionstate = "spectator";//allow player to leave while in intermission and make voting options + player thread watchVoting(); + + player setClientDvars( "hud_ShowWinner", "0", + "hud_voteText", "^3Vote for new map:", + "vote_map", "" ); + + player openPopupMenu( game["menu_vote"] ); } + + level thread doBotVoting(); + thread timeLimitClock_Intermission( level.voteTime, (84.7, 100, 0) ); + wait level.voteTime; + level.inVoting = false; - intermissionTime = 30.0; + level.highestVotedMap = getHighestVotedMap(); - if(getDvarInt( "party_host" )) + if ( level.voteWinTime > 0.0 ) { - intermissionTime = 10.0; + level.inShowingWinner = true; + foreach (player in level.players) + { + player setClientDvars( "hud_WinningName", "preview_" + level.votingMapsTok[ level.highestVotedMap ], + "hud_WinningMap", consoleMapNameToMapName( level.votingMapsTok[ level.highestVotedMap ] ), + "hud_voteText", "^3Next Map:", + "hud_ShowWinner", "1" ); + } + + thread timeLimitClock_Intermission( level.voteWinTime, (84.7, 100, 0) ); + wait level.voteWinTime; + level.inShowingWinner = false; } - thread timeLimitClock_Intermission( intermissionTime ); - wait intermissionTime; + foreach (player in level.players) + player closeMenu( game["menu_vote"] ); + + level notify( "voting_finished" ); + + level setVoteVars( level.highestVotedMap ); + } + + if ( level.allowIntermission && level.intermissionTime > 0.0 ) + { + level.inIntermission = true; + foreach (player in level.players) + { + player.sessionstate = "spectator";//allow player to leave while in intermission + player thread openSummaryOnMenuClose(); + player openPopupMenu( game["menu_popup_summary"] ); + } + + thread timeLimitClock_Intermission( level.intermissionTime ); + wait level.intermissionTime; + level.inIntermission = false; + + level notify( "intermission_finished" ); } level notify( "exitLevel_called" ); exitLevel( false ); } +setVoteVars( highestVotedMap ) +{ + setDvar( "sv_maprotation", "map " + level.votingMapsTok[ highestVotedMap ] ); + setDvar( "sv_maprotationCurrent", "map " + level.votingMapsTok[ highestVotedMap ] ); +} + +getHighestVotedMap() +{ + highest = 0; + for( i = 0; i < level.mapVotes.size; i++ ) + if( level.mapVotes[ i ] > highest && i < 9 ) + highest = level.mapVotes[ i ]; + + votes = []; + for( i = 0; i < level.mapVotes.size; i++ ) + if( level.mapVotes[ i ] == highest && i < 9 ) + votes[votes.size] = i; + + if ( votes.size ) + return votes[ randomInt( votes.size ) ]; + else if ( level.mapVotes.size > 9 ) + return randomIntRange( 0, 8 ); + else + return randomInt( level.mapVotes.size ); +} + +doBotVoting() +{ + if(!level.botsVote) + return; + + level endon("voting_finished"); + + bots = []; + + foreach(player in level.players) + { + if(!isDefined(player.pers["isBot"]) || !player.pers["isBot"]) + continue; + + player.botWillVoteFor = bots.size; + bots[bots.size] = player; + } + + while(bots.size) + { + wait 0.05; + bot = bots[randomInt(bots.size)]; + if(!bot.hasVoted) + { + bot castMap(bot.botWillVoteFor); + wait randomInt(3); + } + } +} + +ridVoteOnDisconnect() +{ + level endon("voting_finished"); + + self waittill_either( "disconnect", "kill_menus_on_connect" ); + + if ( self.votedNum > -1 ) + level.mapVotes[ self.votedNum ]--; +} + +updateVoteMenu() +{ + self endon("disconnect"); + self endon("kill_menus_on_connect"); + level endon("voting_finished"); + + for(i = 0; i < 9; i++) + { + if( i >= level.votingMapsTok.size ) + { + self setClientDvar( "hud_picName" + i, "white" ); + } + else + { + self setClientDvars( "hud_mapName" + i, consoleMapNameToMapName( level.votingMapsTok[ i ] ), + "hud_mapVotes" + i, level.mapVotes[ i ], + "hud_picName" + i, "preview_" + level.votingMapsTok[ i ] ); + } + } + + for(;;) + { + wait 0.5; + + for( i = 0; i < level.votingMapsTok.size; i++ ) + self setClientDvar( "hud_mapVotes" + i, level.mapVotes[ i ] ); + + highestVotedMap = getHighestVotedMap(); + self setClientDvars( "hud_gamesize", level.players.size, + "hud_mapVotes" + highestVotedMap, "^3" + level.mapVotes[ highestVotedMap ] ); + } +} + +watchVoting() +{ + self endon("disconnect"); + self endon("kill_menus_on_connect"); + level endon("voting_finished"); + + self thread ridVoteOnDisconnect(); + self thread updateVoteMenu(); + + self.hasVoted = false; + self.votedNum = -1; + + for(;;) + { + self waittill("menuresponse", menu, response); + + if( menu == game["menu_vote"] ) + { + switch(response) + { + case "map1": + self castMap(0); + break; + case "map2": + self castMap(1); + break; + case "map3": + self castMap(2); + break; + case "map4": + self castMap(3); + break; + case "map5": + self castMap(4); + break; + case "map6": + self castMap(5); + break; + case "map7": + self castMap(6); + break; + case "map8": + self castMap(7); + break; + case "map9": + self castMap(8); + break; + default: + break; + } + } + else if ( response == "back" ) + { + self closepopupMenu(); + self closeInGameMenu(); + wait 0.25; + self openPopupMenu( game["menu_vote"] ); + continue; + } + } +} + +castMap( number ) +{ + if ( !isDefined( level.votingMapsTok[ number ] ) || level.votingMapsTok[ number ] == "" ) + { + if ( self.hasVoted ) + { + self.hasVoted = false; + level.mapVotes[ self.votedNum ]--; + self.votedNum = -1; + } + self iprintln( "Invalid map selection" ); + return; + } + + if( !self.hasVoted ) + { + self.hasVoted = true; + level.mapVotes[ number ]++; + self.votedNum = number; + self iprintln( "You voted for ^3" + consoleMapNameToMapName( level.votingMapsTok[ number ] ) ); + } + else if( self.votedNum != number ) + { + level.mapVotes[ self.votedNum ]--; + level.mapVotes[ number ]++; + self.votedNum = number; + self iprintln( "You ^3re-voted ^7for ^3" + consoleMapNameToMapName( level.votingMapsTok[ number ] ) ); + } +} + +consoleMapNameToMapName(mapname) +{ + switch(mapname) + { + case "mp_abandon": + return "Carnival"; + case "mp_rundown": + return "Rundown"; + case "mp_afghan": + return "Afghan"; + case "mp_boneyard": + return "Scrapyard"; + case "mp_brecourt": + return "Wasteland"; + case "mp_cargoship": + return "Wetwork"; + case "mp_checkpoint": + return "Karachi"; + case "mp_compact": + return "Salvage"; + case "mp_complex": + return "Bailout"; + case "mp_crash": + return "Crash"; + case "mp_cross_fire": + return "Crossfire"; + case "mp_derail": + return "Derail"; + case "mp_estate": + return "Estate"; + case "mp_favela": + return "Favela"; + case "mp_fuel2": + return "Fuel"; + case "mp_highrise": + return "Highrise"; + case "mp_invasion": + return "Invasion"; + case "mp_killhouse": + return "Killhouse"; + case "mp_nightshift": + return "Skidrow"; + case "mp_nuked": + return "Nuketown"; + case "oilrig": + return "Oilrig"; + case "mp_quarry": + return "Quarry"; + case "mp_rust": + return "Rust"; + case "mp_storm": + return "Storm"; + case "mp_strike": + return "Strike"; + case "mp_subbase": + return "Subbase"; + case "mp_terminal": + return "Terminal"; + case "mp_trailerpark": + return "Trailer Park"; + case "mp_overgrown": + return "Overgrown"; + case "mp_underpass": + return "Underpass"; + case "mp_vacant": + return "Vacant"; + case "iw4_credits": + return "IW4 Test Map"; + case "airport": + return "Airport"; + case "co_hunted": + return "Hunted"; + case "invasion": + return "Burgertown"; + case "mp_bloc": + return "Bloc"; + case "mp_bog_sh": + return "Bog"; + case "contingency": + return "Contingency"; + case "gulag": + return "Gulag"; + case "so_ghillies": + return "Pripyat"; + case "ending": + return "Museum"; + case "af_chase": + return "Afghan Chase"; + case "af_caves": + return "Afghan Caves"; + case "arcadia": + return "Arcadia"; + case "boneyard": + return "Boneyard"; + case "cliffhanger": + return "Cliffhanger"; + case "dcburning": + return "DCBurning"; + case "dcemp": + return "DCEMP"; + case "downtown": + return "Downtown"; + case "estate": + return "EstateSP"; + case "favela": + return "FavelaSP"; + case "favela_escape": + return "Favela Escape"; + case "roadkill": + return "Roadkill"; + case "trainer": + return "TH3 PIT"; + case "so_bridge": + return "Bridge"; + case "dc_whitehouse": + return "Whitehouse"; + default: + return mapname; + } +} + +openSummaryOnMenuClose() +{ + self endon("disconnect"); + self endon("kill_menus_on_connect"); + level endon("intermission_finished"); + + for(;;) + { + self waittill("menuresponse", menu, response); + + if ( response == "back" && menu != game["menu_popup_summary"] ) + { + self closepopupMenu(); + self closeInGameMenu(); + wait 0.25; + self openPopupMenu( game["menu_popup_summary"] ); + continue; + } + } +} + updateEndReasonText( winner ) { if ( !level.teamBased ) @@ -2326,4 +3038,106 @@ processLobbyData() maps\mp\_scoreboard::processLobbyScoreboards(); sendClientMatchData(); -} \ No newline at end of file +} + +getWinningTeam() +{ + if ( game["roundsWon"]["allies"] == game["roundsWon"]["axis"] ) + winner = "tie"; + else if ( game["roundsWon"]["axis"] > game["roundsWon"]["allies"] ) + winner = "axis"; + else + winner = "allies"; + + return winner; +} + +doFinalKillCam() +{ + level waittill ( "round_end_finished" ); + + winner = level.finalKillCam_winner; // we want to show the winner's final kill cam + delay = level.finalKillCam_delay[ winner ]; + victim = level.finalKillCam_victim[ winner ]; + attacker = level.finalKillCam_attacker[ winner ]; + attackerNum = level.finalKillCam_attackerNum[ winner ]; + killCamEntityIndex = level.finalKillCam_killCamEntityIndex[ winner ]; + killCamEntityStartTime = level.finalKillCam_killCamEntityStartTime[ winner ]; + sWeapon = level.finalKillCam_sWeapon[ winner ]; + deathTimeOffset = level.finalKillCam_deathTimeOffset[ winner ]; + psOffsetTime = level.finalKillCam_psOffsetTime[ winner ]; + timeRecorded = level.finalKillCam_timeRecorded[ winner ]/1000; + timeGameEnded = level.gameEndTime/1000; + + if( !isDefined( victim ) || !isDefined( attacker ) ) + return; + + if( !level.forceFinalKillcam || !level.allowFinalKillcam ) + return; + + // if the killcam happened longer than 15 seconds ago, don't show it + killCamBufferTime = 15; + killCamOffsetTime = timeGameEnded - timeRecorded; + + if( killCamOffsetTime > killCamBufferTime ) + return; + + level.showingFinalKillcam = true; + + if ( isDefined( attacker ) ) + { + maps\mp\_awards::addAwardWinner( "finalkill", attacker.clientid ); + attacker.finalKill = true; + } + + postDeathDelay = (( getTime() - victim.deathTime ) / 1000); + + foreach ( player in level.players ) + { + player closePopupMenu(); + player closeInGameMenu(); + + if( isDefined( level.nukeDetonated ) ) + player VisionSetNakedForPlayer( "mpnuke_aftermath", 0 ); + else + player VisionSetNakedForPlayer( getDvar( "mapname" ), 0 ); + + player.killcamentitylookat = victim getEntityNumber(); + + if ( (player != victim || (!isRoundBased() || isLastRound())) && player _hasPerk( "specialty_copycat" ) ) + player _unsetPerk( "specialty_copycat" ); + + player thread maps\mp\gametypes\_killcam::killcam( attackerNum, killcamentityindex, killcamentitystarttime, sWeapon, postDeathDelay + deathTimeOffset, psOffsetTime, 0, 10000, attacker, victim ); + } + + wait( 0.1 ); + + while ( maps\mp\gametypes\_damage::anyPlayersInKillcam() ) + wait( 0.05 ); + + level.showingFinalKillcam = false; +} + +recordFinalKillCam( delay, victim, attacker, attackerNum, killCamEntityIndex, killCamEntityStartTime, sWeapon, deathTimeOffset, psOffsetTime ) +{ + teams[0] = "none"; // none gets filled just in case we need something without a team or this is ffa + + if( level.teambased && IsDefined( attacker.team ) ) + teams[1] = attacker.team; // we want to save each team seperately so we can show the winning team's kill when applicable + + for( i = 0; i < teams.size; i++ ) + { + team = teams[i]; + + level.finalKillCam_delay[ team ] = delay; + level.finalKillCam_victim[ team ] = victim; + level.finalKillCam_attacker[ team ] = attacker; + level.finalKillCam_attackerNum[ team ] = attackerNum; + level.finalKillCam_killCamEntityIndex[ team ] = killCamEntityIndex; + level.finalKillCam_killCamEntityStartTime[ team ] = killCamEntityStartTime; + level.finalKillCam_sWeapon[ team ] = sWeapon; + level.finalKillCam_deathTimeOffset[ team ] = deathTimeOffset; + level.finalKillCam_psOffsetTime[ team ] = psOffsetTime; + level.finalKillCam_timeRecorded[ team ] = getTime(); + } +} diff --git a/userraw/maps/mp/gametypes/_rank.gsc b/userraw/maps/mp/gametypes/_rank.gsc index ca57b97..c8a1ee6 100644 --- a/userraw/maps/mp/gametypes/_rank.gsc +++ b/userraw/maps/mp/gametypes/_rank.gsc @@ -1,686 +1,693 @@ -#include common_scripts\utility; -#include maps\mp\_utility; -#include maps\mp\gametypes\_hud_util; - - -init() -{ - level.scoreInfo = []; - level.xpScale = getDvarInt( "scr_xpscale" ); - - if ( level.xpScale > 4 || level.xpScale < 0) - exitLevel( false ); - - level.xpScale = min( level.xpScale, 4 ); - level.xpScale = max( level.xpScale, 0 ); - - level.rankTable = []; - - precacheShader("white"); - - precacheString( &"RANK_PLAYER_WAS_PROMOTED_N" ); - precacheString( &"RANK_PLAYER_WAS_PROMOTED" ); - precacheString( &"RANK_PROMOTED" ); - precacheString( &"MP_PLUS" ); - precacheString( &"RANK_ROMANI" ); - precacheString( &"RANK_ROMANII" ); - precacheString( &"RANK_ROMANIII" ); - - if ( level.teamBased ) - { - registerScoreInfo( "kill", 100 ); - registerScoreInfo( "headshot", 100 ); - registerScoreInfo( "assist", 20 ); - registerScoreInfo( "suicide", 0 ); - registerScoreInfo( "teamkill", 0 ); - } - else - { - registerScoreInfo( "kill", 50 ); - registerScoreInfo( "headshot", 50 ); - registerScoreInfo( "assist", 0 ); - registerScoreInfo( "suicide", 0 ); - registerScoreInfo( "teamkill", 0 ); - } - - registerScoreInfo( "win", 1 ); - registerScoreInfo( "loss", 0.5 ); - registerScoreInfo( "tie", 0.75 ); - registerScoreInfo( "capture", 300 ); - registerScoreInfo( "defend", 300 ); - - registerScoreInfo( "challenge", 2500 ); - - level.maxRank = int(tableLookup( "mp/rankTable.csv", 0, "maxrank", 1 )); - level.maxPrestige = int(tableLookup( "mp/rankIconTable.csv", 0, "maxprestige", 1 )); - - pId = 0; - rId = 0; - for ( pId = 0; pId <= level.maxPrestige; pId++ ) - { - for ( rId = 0; rId <= level.maxRank; rId++ ) - precacheShader( tableLookup( "mp/rankIconTable.csv", 0, rId, pId+1 ) ); - } - - rankId = 0; - rankName = tableLookup( "mp/ranktable.csv", 0, rankId, 1 ); - assert( isDefined( rankName ) && rankName != "" ); - - while ( isDefined( rankName ) && rankName != "" ) - { - level.rankTable[rankId][1] = tableLookup( "mp/ranktable.csv", 0, rankId, 1 ); - level.rankTable[rankId][2] = tableLookup( "mp/ranktable.csv", 0, rankId, 2 ); - level.rankTable[rankId][3] = tableLookup( "mp/ranktable.csv", 0, rankId, 3 ); - level.rankTable[rankId][7] = tableLookup( "mp/ranktable.csv", 0, rankId, 7 ); - - precacheString( tableLookupIString( "mp/ranktable.csv", 0, rankId, 16 ) ); - - rankId++; - rankName = tableLookup( "mp/ranktable.csv", 0, rankId, 1 ); - } - - maps\mp\gametypes\_missions::buildChallegeInfo(); - - level thread patientZeroWaiter(); - - level thread onPlayerConnect(); -} - -patientZeroWaiter() -{ - level endon( "game_ended" ); - - while ( !isDefined( level.players ) || !level.players.size ) - wait ( 0.05 ); - - if ( !matchMakingGame() ) - { - if ( (getDvar( "mapname" ) == "mp_rust" && randomInt( 1000 ) == 999) ) - level.patientZeroName = level.players[0].name; - } - else - { - if ( getDvar( "scr_patientZero" ) != "" ) - level.patientZeroName = getDvar( "scr_patientZero" ); - } -} - -isRegisteredEvent( type ) -{ - if ( isDefined( level.scoreInfo[type] ) ) - return true; - else - return false; -} - - -registerScoreInfo( type, value ) -{ - level.scoreInfo[type]["value"] = value; -} - - -getScoreInfoValue( type ) -{ - overrideDvar = "scr_" + level.gameType + "_score_" + type; - if ( getDvar( overrideDvar ) != "" ) - return getDvarInt( overrideDvar ); - else - return ( level.scoreInfo[type]["value"] ); -} - - -getScoreInfoLabel( type ) -{ - return ( level.scoreInfo[type]["label"] ); -} - - -getRankInfoMinXP( rankId ) -{ - return int(level.rankTable[rankId][2]); -} - - -getRankInfoXPAmt( rankId ) -{ - return int(level.rankTable[rankId][3]); -} - - -getRankInfoMaxXp( rankId ) -{ - return int(level.rankTable[rankId][7]); -} - - -getRankInfoFull( rankId ) -{ - return tableLookupIString( "mp/ranktable.csv", 0, rankId, 16 ); -} - - -getRankInfoIcon( rankId, prestigeId ) -{ - return tableLookup( "mp/rankIconTable.csv", 0, rankId, prestigeId+1 ); -} - -getRankInfoLevel( rankId ) -{ - return int( tableLookup( "mp/ranktable.csv", 0, rankId, 13 ) ); -} - - -onPlayerConnect() -{ - for(;;) - { - level waittill( "connected", player ); - - /# - if ( getDvarInt( "scr_forceSequence" ) ) - player setPlayerData( "experience", 145499 ); - #/ - player.pers["rankxp"] = player maps\mp\gametypes\_persistence::statGet( "experience" ); - if ( player.pers["rankxp"] < 0 ) // paranoid defensive - player.pers["rankxp"] = 0; - - rankId = player getRankForXp( player getRankXP() ); - player.pers[ "rank" ] = rankId; - player.pers[ "participation" ] = 0; - - player.xpUpdateTotal = 0; - player.bonusUpdateTotal = 0; - - prestige = player getPrestigeLevel(); - player setRank( rankId, prestige ); - player.pers["prestige"] = prestige; - - player.postGamePromotion = false; - if ( !isDefined( player.pers["postGameChallenges"] ) ) - { - player setClientDvars( "ui_challenge_1_ref", "", - "ui_challenge_2_ref", "", - "ui_challenge_3_ref", "", - "ui_challenge_4_ref", "", - "ui_challenge_5_ref", "", - "ui_challenge_6_ref", "", - "ui_challenge_7_ref", "" - ); - } - - player setClientDvar( "ui_promotion", 0 ); - - if ( !isDefined( player.pers["summary"] ) ) - { - player.pers["summary"] = []; - player.pers["summary"]["xp"] = 0; - player.pers["summary"]["score"] = 0; - player.pers["summary"]["challenge"] = 0; - player.pers["summary"]["match"] = 0; - player.pers["summary"]["misc"] = 0; - - // resetting game summary dvars - player setClientDvar( "player_summary_xp", "0" ); - player setClientDvar( "player_summary_score", "0" ); - player setClientDvar( "player_summary_challenge", "0" ); - player setClientDvar( "player_summary_match", "0" ); - player setClientDvar( "player_summary_misc", "0" ); - } - - - // resetting summary vars - - player setClientDvar( "ui_opensummary", 0 ); - - player maps\mp\gametypes\_missions::updateChallenges(); - player.explosiveKills[0] = 0; - player.xpGains = []; - - player.hud_scorePopup = newClientHudElem( player ); - player.hud_scorePopup.horzAlign = "center"; - player.hud_scorePopup.vertAlign = "middle"; - player.hud_scorePopup.alignX = "center"; - player.hud_scorePopup.alignY = "middle"; - player.hud_scorePopup.x = 0; - if ( level.splitScreen ) - player.hud_scorePopup.y = -40; - else - player.hud_scorePopup.y = -60; - player.hud_scorePopup.font = "hudbig"; - player.hud_scorePopup.fontscale = 0.75; - player.hud_scorePopup.archived = false; - player.hud_scorePopup.color = (0.5,0.5,0.5); - player.hud_scorePopup.sort = 10000; - player.hud_scorePopup maps\mp\gametypes\_hud::fontPulseInit( 3.0 ); - - player thread onPlayerSpawned(); - player thread onJoinedTeam(); - player thread onJoinedSpectators(); - } -} - - -onJoinedTeam() -{ - self endon("disconnect"); - - for(;;) - { - self waittill( "joined_team" ); - self thread removeRankHUD(); - } -} - - -onJoinedSpectators() -{ - self endon("disconnect"); - - for(;;) - { - self waittill( "joined_spectators" ); - self thread removeRankHUD(); - } -} - - -onPlayerSpawned() -{ - self endon("disconnect"); - - for(;;) - { - self waittill("spawned_player"); - } -} - - -roundUp( floatVal ) -{ - if ( int( floatVal ) != floatVal ) - return int( floatVal+1 ); - else - return int( floatVal ); -} - - -giveRankXP( type, value ) -{ - self endon("disconnect"); - - lootType = "none"; - - if ( !self rankingEnabled() ) - return; - - if ( level.teamBased && (!level.teamCount["allies"] || !level.teamCount["axis"]) ) - return; - else if ( !level.teamBased && (level.teamCount["allies"] + level.teamCount["axis"] < 2) ) - return; - - if ( !isDefined( value ) ) - value = getScoreInfoValue( type ); - - if ( !isDefined( self.xpGains[type] ) ) - self.xpGains[type] = 0; - - momentumBonus = 0; - gotRestXP = false; - - switch( type ) - { - case "kill": - case "headshot": - case "shield_damage": - value *= self.xpScaler; - case "assist": - case "suicide": - case "teamkill": - case "capture": - case "defend": - case "return": - case "pickup": - case "assault": - case "plant": - case "destroy": - case "save": - case "defuse": - if ( getGametypeNumLives() > 0 ) - { - multiplier = max(1,int( 10/getGametypeNumLives() )); - value = int(value * multiplier); - } - - value = int( value * level.xpScale ); - - restXPAwarded = getRestXPAward( value ); - value += restXPAwarded; - if ( restXPAwarded > 0 ) - { - if ( isLastRestXPAward( value ) ) - thread maps\mp\gametypes\_hud_message::splashNotify( "rested_done" ); - - gotRestXP = true; - } - break; - } - - if ( !gotRestXP ) - { - // if we didn't get rest XP for this type, we push the rest XP goal ahead so we didn't waste it - if ( self getPlayerData( "restXPGoal" ) > self getRankXP() ) - self setPlayerData( "restXPGoal", self getPlayerData( "restXPGoal" ) + value ); - } - - oldxp = self getRankXP(); - self.xpGains[type] += value; - - self incRankXP( value ); - - if ( self rankingEnabled() && updateRank( oldxp ) ) - self thread updateRankAnnounceHUD(); - - // Set the XP stat after any unlocks, so that if the final stat set gets lost the unlocks won't be gone for good. - self syncXPStat(); - - if ( !level.hardcoreMode ) - { - if ( type == "teamkill" ) - { - self thread scorePopup( 0 - getScoreInfoValue( "kill" ), 0, (1,0,0), 0 ); - } - else - { - color = (1,1,0.5); - if ( gotRestXP ) - color = (1,.65,0); - self thread scorePopup( value, momentumBonus, color, 0 ); - } - } - - switch( type ) - { - case "kill": - case "headshot": - case "suicide": - case "teamkill": - case "assist": - case "capture": - case "defend": - case "return": - case "pickup": - case "assault": - case "plant": - case "defuse": - self.pers["summary"]["score"] += value; - self.pers["summary"]["xp"] += value; - break; - - case "win": - case "loss": - case "tie": - self.pers["summary"]["match"] += value; - self.pers["summary"]["xp"] += value; - break; - - case "challenge": - self.pers["summary"]["challenge"] += value; - self.pers["summary"]["xp"] += value; - break; - - default: - self.pers["summary"]["misc"] += value; //keeps track of ungrouped match xp reward - self.pers["summary"]["match"] += value; - self.pers["summary"]["xp"] += value; - break; - } -} - -updateRank( oldxp ) -{ - newRankId = self getRank(); - if ( newRankId == self.pers["rank"] ) - return false; - - oldRank = self.pers["rank"]; - rankId = self.pers["rank"]; - self.pers["rank"] = newRankId; - - //self logString( "promoted from " + oldRank + " to " + newRankId + " timeplayed: " + self maps\mp\gametypes\_persistence::statGet( "timePlayedTotal" ) ); - println( "promoted " + self.name + " from rank " + oldRank + " to " + newRankId + ". Experience went from " + oldxp + " to " + self getRankXP() + "." ); - - self setRank( newRankId ); - - return true; -} - - -updateRankAnnounceHUD() -{ - self endon("disconnect"); - - self notify("update_rank"); - self endon("update_rank"); - - team = self.pers["team"]; - if ( !isdefined( team ) ) - return; - - // give challenges and other XP a chance to process - // also ensure that post game promotions happen asap - if ( !levelFlag( "game_over" ) ) - level waittill_notify_or_timeout( "game_over", 0.25 ); - - - newRankName = self getRankInfoFull( self.pers["rank"] ); - rank_char = level.rankTable[self.pers["rank"]][1]; - subRank = int(rank_char[rank_char.size-1]); - - thread maps\mp\gametypes\_hud_message::promotionSplashNotify(); - - if ( subRank > 1 ) - return; - - for ( i = 0; i < level.players.size; i++ ) - { - player = level.players[i]; - playerteam = player.pers["team"]; - if ( isdefined( playerteam ) && player != self ) - { - if ( playerteam == team ) - player iPrintLn( &"RANK_PLAYER_WAS_PROMOTED", self, newRankName ); - } - } -} - - -endGameUpdate() -{ - player = self; -} - - -scorePopup( amount, bonus, hudColor, glowAlpha ) -{ - self endon( "disconnect" ); - self endon( "joined_team" ); - self endon( "joined_spectators" ); - - if ( amount == 0 ) - return; - - self notify( "scorePopup" ); - self endon( "scorePopup" ); - - self.xpUpdateTotal += amount; - self.bonusUpdateTotal += bonus; - - wait ( 0.05 ); - - if ( self.xpUpdateTotal < 0 ) - self.hud_scorePopup.label = &""; - else - self.hud_scorePopup.label = &"MP_PLUS"; - - self.hud_scorePopup.color = hudColor; - self.hud_scorePopup.glowColor = hudColor; - self.hud_scorePopup.glowAlpha = glowAlpha; - - self.hud_scorePopup setValue(self.xpUpdateTotal); - self.hud_scorePopup.alpha = 0.85; - self.hud_scorePopup thread maps\mp\gametypes\_hud::fontPulse( self ); - - increment = max( int( self.bonusUpdateTotal / 20 ), 1 ); - - if ( self.bonusUpdateTotal ) - { - while ( self.bonusUpdateTotal > 0 ) - { - self.xpUpdateTotal += min( self.bonusUpdateTotal, increment ); - self.bonusUpdateTotal -= min( self.bonusUpdateTotal, increment ); - - self.hud_scorePopup setValue( self.xpUpdateTotal ); - - wait ( 0.05 ); - } - } - else - { - wait ( 1.0 ); - } - - self.hud_scorePopup fadeOverTime( 0.75 ); - self.hud_scorePopup.alpha = 0; - - self.xpUpdateTotal = 0; -} - -removeRankHUD() -{ - self.hud_scorePopup.alpha = 0; -} - -getRank() -{ - rankXp = self.pers["rankxp"]; - rankId = self.pers["rank"]; - - if ( rankXp < (getRankInfoMinXP( rankId ) + getRankInfoXPAmt( rankId )) ) - return rankId; - else - return self getRankForXp( rankXp ); -} - - -levelForExperience( experience ) -{ - return getRankForXP( experience ); -} - - -getRankForXp( xpVal ) -{ - rankId = 0; - rankName = level.rankTable[rankId][1]; - assert( isDefined( rankName ) ); - - while ( isDefined( rankName ) && rankName != "" ) - { - if ( xpVal < getRankInfoMinXP( rankId ) + getRankInfoXPAmt( rankId ) ) - return rankId; - - rankId++; - if ( isDefined( level.rankTable[rankId] ) ) - rankName = level.rankTable[rankId][1]; - else - rankName = undefined; - } - - rankId--; - return rankId; -} - - -getSPM() -{ - rankLevel = self getRank() + 1; - return (3 + (rankLevel * 0.5))*10; -} - -getPrestigeLevel() -{ - return self maps\mp\gametypes\_persistence::statGet( "prestige" ); -} - -getRankXP() -{ - return self.pers["rankxp"]; -} - -incRankXP( amount ) -{ - if ( !self rankingEnabled() ) - return; - - if ( isDefined( self.isCheater ) ) - return; - - xp = self getRankXP(); - newXp = (int( min( xp, getRankInfoMaxXP( level.maxRank ) ) ) + amount); - - if ( self.pers["rank"] == level.maxRank && newXp >= getRankInfoMaxXP( level.maxRank ) ) - newXp = getRankInfoMaxXP( level.maxRank ); - - self.pers["rankxp"] = newXp; -} - -getRestXPAward( baseXP ) -{ - if ( !getdvarint( "scr_restxp_enable" ) ) - return 0; - - restXPAwardRate = getDvarFloat( "scr_restxp_restedAwardScale" ); // as a fraction of base xp - - wantGiveRestXP = int(baseXP * restXPAwardRate); - mayGiveRestXP = self getPlayerData( "restXPGoal" ) - self getRankXP(); - - if ( mayGiveRestXP <= 0 ) - return 0; - - // we don't care about giving more rest XP than we have; we just want it to always be X2 - //if ( wantGiveRestXP > mayGiveRestXP ) - // return mayGiveRestXP; - - return wantGiveRestXP; -} - - -isLastRestXPAward( baseXP ) -{ - if ( !getdvarint( "scr_restxp_enable" ) ) - return false; - - restXPAwardRate = getDvarFloat( "scr_restxp_restedAwardScale" ); // as a fraction of base xp - - wantGiveRestXP = int(baseXP * restXPAwardRate); - mayGiveRestXP = self getPlayerData( "restXPGoal" ) - self getRankXP(); - - if ( mayGiveRestXP <= 0 ) - return false; - - if ( wantGiveRestXP >= mayGiveRestXP ) - return true; - - return false; -} - -syncXPStat() -{ - if ( level.xpScale > 4 || level.xpScale <= 0) - exitLevel( false ); - - xp = self getRankXP(); - - self maps\mp\gametypes\_persistence::statSet( "experience", xp ); -} +/* + _rank modded + Author: INeedGames + Date: 09/22/2020 + Removes the level.xpScale check, good old 2010 infinity ward under a law suite logic here +*/ + +#include common_scripts\utility; +#include maps\mp\_utility; +#include maps\mp\gametypes\_hud_util; + + +init() +{ + level.scoreInfo = []; + level.xpScale = getDvarInt( "scr_xpscale" ); + + // if ( level.xpScale > 4 || level.xpScale < 0) + // exitLevel( false ); + + // level.xpScale = min( level.xpScale, 4 ); + // level.xpScale = max( level.xpScale, 0 ); + + level.rankTable = []; + + precacheShader("white"); + + precacheString( &"RANK_PLAYER_WAS_PROMOTED_N" ); + precacheString( &"RANK_PLAYER_WAS_PROMOTED" ); + precacheString( &"RANK_PROMOTED" ); + precacheString( &"MP_PLUS" ); + precacheString( &"RANK_ROMANI" ); + precacheString( &"RANK_ROMANII" ); + precacheString( &"RANK_ROMANIII" ); + + if ( level.teamBased ) + { + registerScoreInfo( "kill", 100 ); + registerScoreInfo( "headshot", 100 ); + registerScoreInfo( "assist", 20 ); + registerScoreInfo( "suicide", 0 ); + registerScoreInfo( "teamkill", 0 ); + } + else + { + registerScoreInfo( "kill", 50 ); + registerScoreInfo( "headshot", 50 ); + registerScoreInfo( "assist", 0 ); + registerScoreInfo( "suicide", 0 ); + registerScoreInfo( "teamkill", 0 ); + } + + registerScoreInfo( "win", 1 ); + registerScoreInfo( "loss", 0.5 ); + registerScoreInfo( "tie", 0.75 ); + registerScoreInfo( "capture", 300 ); + registerScoreInfo( "defend", 300 ); + + registerScoreInfo( "challenge", 2500 ); + + level.maxRank = int(tableLookup( "mp/rankTable.csv", 0, "maxrank", 1 )); + level.maxPrestige = int(tableLookup( "mp/rankIconTable.csv", 0, "maxprestige", 1 )); + + pId = 0; + rId = 0; + for ( pId = 0; pId <= level.maxPrestige; pId++ ) + { + for ( rId = 0; rId <= level.maxRank; rId++ ) + precacheShader( tableLookup( "mp/rankIconTable.csv", 0, rId, pId+1 ) ); + } + + rankId = 0; + rankName = tableLookup( "mp/ranktable.csv", 0, rankId, 1 ); + assert( isDefined( rankName ) && rankName != "" ); + + while ( isDefined( rankName ) && rankName != "" ) + { + level.rankTable[rankId][1] = tableLookup( "mp/ranktable.csv", 0, rankId, 1 ); + level.rankTable[rankId][2] = tableLookup( "mp/ranktable.csv", 0, rankId, 2 ); + level.rankTable[rankId][3] = tableLookup( "mp/ranktable.csv", 0, rankId, 3 ); + level.rankTable[rankId][7] = tableLookup( "mp/ranktable.csv", 0, rankId, 7 ); + + precacheString( tableLookupIString( "mp/ranktable.csv", 0, rankId, 16 ) ); + + rankId++; + rankName = tableLookup( "mp/ranktable.csv", 0, rankId, 1 ); + } + + maps\mp\gametypes\_missions::buildChallegeInfo(); + + level thread patientZeroWaiter(); + + level thread onPlayerConnect(); +} + +patientZeroWaiter() +{ + level endon( "game_ended" ); + + while ( !isDefined( level.players ) || !level.players.size ) + wait ( 0.05 ); + + if ( !matchMakingGame() ) + { + if ( (getDvar( "mapname" ) == "mp_rust" && randomInt( 1000 ) == 999) ) + level.patientZeroName = level.players[0].name; + } + else + { + if ( getDvar( "scr_patientZero" ) != "" ) + level.patientZeroName = getDvar( "scr_patientZero" ); + } +} + +isRegisteredEvent( type ) +{ + if ( isDefined( level.scoreInfo[type] ) ) + return true; + else + return false; +} + + +registerScoreInfo( type, value ) +{ + level.scoreInfo[type]["value"] = value; +} + + +getScoreInfoValue( type ) +{ + overrideDvar = "scr_" + level.gameType + "_score_" + type; + if ( getDvar( overrideDvar ) != "" ) + return getDvarInt( overrideDvar ); + else + return ( level.scoreInfo[type]["value"] ); +} + + +getScoreInfoLabel( type ) +{ + return ( level.scoreInfo[type]["label"] ); +} + + +getRankInfoMinXP( rankId ) +{ + return int(level.rankTable[rankId][2]); +} + + +getRankInfoXPAmt( rankId ) +{ + return int(level.rankTable[rankId][3]); +} + + +getRankInfoMaxXp( rankId ) +{ + return int(level.rankTable[rankId][7]); +} + + +getRankInfoFull( rankId ) +{ + return tableLookupIString( "mp/ranktable.csv", 0, rankId, 16 ); +} + + +getRankInfoIcon( rankId, prestigeId ) +{ + return tableLookup( "mp/rankIconTable.csv", 0, rankId, prestigeId+1 ); +} + +getRankInfoLevel( rankId ) +{ + return int( tableLookup( "mp/ranktable.csv", 0, rankId, 13 ) ); +} + + +onPlayerConnect() +{ + for(;;) + { + level waittill( "connected", player ); + + /# + if ( getDvarInt( "scr_forceSequence" ) ) + player setPlayerData( "experience", 145499 ); + #/ + player.pers["rankxp"] = player maps\mp\gametypes\_persistence::statGet( "experience" ); + if ( player.pers["rankxp"] < 0 ) // paranoid defensive + player.pers["rankxp"] = 0; + + rankId = player getRankForXp( player getRankXP() ); + player.pers[ "rank" ] = rankId; + player.pers[ "participation" ] = 0; + + player.xpUpdateTotal = 0; + player.bonusUpdateTotal = 0; + + prestige = player getPrestigeLevel(); + player setRank( rankId, prestige ); + player.pers["prestige"] = prestige; + + player.postGamePromotion = false; + if ( !isDefined( player.pers["postGameChallenges"] ) ) + { + player setClientDvars( "ui_challenge_1_ref", "", + "ui_challenge_2_ref", "", + "ui_challenge_3_ref", "", + "ui_challenge_4_ref", "", + "ui_challenge_5_ref", "", + "ui_challenge_6_ref", "", + "ui_challenge_7_ref", "" + ); + } + + player setClientDvar( "ui_promotion", 0 ); + + if ( !isDefined( player.pers["summary"] ) ) + { + player.pers["summary"] = []; + player.pers["summary"]["xp"] = 0; + player.pers["summary"]["score"] = 0; + player.pers["summary"]["challenge"] = 0; + player.pers["summary"]["match"] = 0; + player.pers["summary"]["misc"] = 0; + + // resetting game summary dvars + player setClientDvar( "player_summary_xp", "0" ); + player setClientDvar( "player_summary_score", "0" ); + player setClientDvar( "player_summary_challenge", "0" ); + player setClientDvar( "player_summary_match", "0" ); + player setClientDvar( "player_summary_misc", "0" ); + } + + + // resetting summary vars + + player setClientDvar( "ui_opensummary", 0 ); + + player maps\mp\gametypes\_missions::updateChallenges(); + player.explosiveKills[0] = 0; + player.xpGains = []; + + player.hud_scorePopup = newClientHudElem( player ); + player.hud_scorePopup.horzAlign = "center"; + player.hud_scorePopup.vertAlign = "middle"; + player.hud_scorePopup.alignX = "center"; + player.hud_scorePopup.alignY = "middle"; + player.hud_scorePopup.x = 0; + if ( level.splitScreen ) + player.hud_scorePopup.y = -40; + else + player.hud_scorePopup.y = -60; + player.hud_scorePopup.font = "hudbig"; + player.hud_scorePopup.fontscale = 0.75; + player.hud_scorePopup.archived = false; + player.hud_scorePopup.color = (0.5,0.5,0.5); + player.hud_scorePopup.sort = 10000; + player.hud_scorePopup maps\mp\gametypes\_hud::fontPulseInit( 3.0 ); + + player thread onPlayerSpawned(); + player thread onJoinedTeam(); + player thread onJoinedSpectators(); + } +} + + +onJoinedTeam() +{ + self endon("disconnect"); + + for(;;) + { + self waittill( "joined_team" ); + self thread removeRankHUD(); + } +} + + +onJoinedSpectators() +{ + self endon("disconnect"); + + for(;;) + { + self waittill( "joined_spectators" ); + self thread removeRankHUD(); + } +} + + +onPlayerSpawned() +{ + self endon("disconnect"); + + for(;;) + { + self waittill("spawned_player"); + } +} + + +roundUp( floatVal ) +{ + if ( int( floatVal ) != floatVal ) + return int( floatVal+1 ); + else + return int( floatVal ); +} + + +giveRankXP( type, value ) +{ + self endon("disconnect"); + + lootType = "none"; + + if ( !self rankingEnabled() ) + return; + + if ( level.teamBased && (!level.teamCount["allies"] || !level.teamCount["axis"]) ) + return; + else if ( !level.teamBased && (level.teamCount["allies"] + level.teamCount["axis"] < 2) ) + return; + + if ( !isDefined( value ) ) + value = getScoreInfoValue( type ); + + if ( !isDefined( self.xpGains[type] ) ) + self.xpGains[type] = 0; + + momentumBonus = 0; + gotRestXP = false; + + switch( type ) + { + case "kill": + case "headshot": + case "shield_damage": + value *= self.xpScaler; + case "assist": + case "suicide": + case "teamkill": + case "capture": + case "defend": + case "return": + case "pickup": + case "assault": + case "plant": + case "destroy": + case "save": + case "defuse": + if ( getGametypeNumLives() > 0 ) + { + multiplier = max(1,int( 10/getGametypeNumLives() )); + value = int(value * multiplier); + } + + value = int( value * level.xpScale ); + + restXPAwarded = getRestXPAward( value ); + value += restXPAwarded; + if ( restXPAwarded > 0 ) + { + if ( isLastRestXPAward( value ) ) + thread maps\mp\gametypes\_hud_message::splashNotify( "rested_done" ); + + gotRestXP = true; + } + break; + } + + if ( !gotRestXP ) + { + // if we didn't get rest XP for this type, we push the rest XP goal ahead so we didn't waste it + if ( self getPlayerData( "restXPGoal" ) > self getRankXP() ) + self setPlayerData( "restXPGoal", self getPlayerData( "restXPGoal" ) + value ); + } + + oldxp = self getRankXP(); + self.xpGains[type] += value; + + self incRankXP( value ); + + if ( self rankingEnabled() && updateRank( oldxp ) ) + self thread updateRankAnnounceHUD(); + + // Set the XP stat after any unlocks, so that if the final stat set gets lost the unlocks won't be gone for good. + self syncXPStat(); + + if ( !level.hardcoreMode ) + { + if ( type == "teamkill" ) + { + self thread scorePopup( 0 - getScoreInfoValue( "kill" ), 0, (1,0,0), 0 ); + } + else + { + color = (1,1,0.5); + if ( gotRestXP ) + color = (1,.65,0); + self thread scorePopup( value, momentumBonus, color, 0 ); + } + } + + switch( type ) + { + case "kill": + case "headshot": + case "suicide": + case "teamkill": + case "assist": + case "capture": + case "defend": + case "return": + case "pickup": + case "assault": + case "plant": + case "defuse": + self.pers["summary"]["score"] += value; + self.pers["summary"]["xp"] += value; + break; + + case "win": + case "loss": + case "tie": + self.pers["summary"]["match"] += value; + self.pers["summary"]["xp"] += value; + break; + + case "challenge": + self.pers["summary"]["challenge"] += value; + self.pers["summary"]["xp"] += value; + break; + + default: + self.pers["summary"]["misc"] += value; //keeps track of ungrouped match xp reward + self.pers["summary"]["match"] += value; + self.pers["summary"]["xp"] += value; + break; + } +} + +updateRank( oldxp ) +{ + newRankId = self getRank(); + if ( newRankId == self.pers["rank"] ) + return false; + + oldRank = self.pers["rank"]; + rankId = self.pers["rank"]; + self.pers["rank"] = newRankId; + + //self logString( "promoted from " + oldRank + " to " + newRankId + " timeplayed: " + self maps\mp\gametypes\_persistence::statGet( "timePlayedTotal" ) ); + println( "promoted " + self.name + " from rank " + oldRank + " to " + newRankId + ". Experience went from " + oldxp + " to " + self getRankXP() + "." ); + + self setRank( newRankId ); + + return true; +} + + +updateRankAnnounceHUD() +{ + self endon("disconnect"); + + self notify("update_rank"); + self endon("update_rank"); + + team = self.pers["team"]; + if ( !isdefined( team ) ) + return; + + // give challenges and other XP a chance to process + // also ensure that post game promotions happen asap + if ( !levelFlag( "game_over" ) ) + level waittill_notify_or_timeout( "game_over", 0.25 ); + + + newRankName = self getRankInfoFull( self.pers["rank"] ); + rank_char = level.rankTable[self.pers["rank"]][1]; + subRank = int(rank_char[rank_char.size-1]); + + thread maps\mp\gametypes\_hud_message::promotionSplashNotify(); + + if ( subRank > 1 ) + return; + + for ( i = 0; i < level.players.size; i++ ) + { + player = level.players[i]; + playerteam = player.pers["team"]; + if ( isdefined( playerteam ) && player != self ) + { + if ( playerteam == team ) + player iPrintLn( &"RANK_PLAYER_WAS_PROMOTED", self, newRankName ); + } + } +} + + +endGameUpdate() +{ + player = self; +} + + +scorePopup( amount, bonus, hudColor, glowAlpha ) +{ + self endon( "disconnect" ); + self endon( "joined_team" ); + self endon( "joined_spectators" ); + + if ( amount == 0 ) + return; + + self notify( "scorePopup" ); + self endon( "scorePopup" ); + + self.xpUpdateTotal += amount; + self.bonusUpdateTotal += bonus; + + wait ( 0.05 ); + + if ( self.xpUpdateTotal < 0 ) + self.hud_scorePopup.label = &""; + else + self.hud_scorePopup.label = &"MP_PLUS"; + + self.hud_scorePopup.color = hudColor; + self.hud_scorePopup.glowColor = hudColor; + self.hud_scorePopup.glowAlpha = glowAlpha; + + self.hud_scorePopup setValue(self.xpUpdateTotal); + self.hud_scorePopup.alpha = 0.85; + self.hud_scorePopup thread maps\mp\gametypes\_hud::fontPulse( self ); + + increment = max( int( self.bonusUpdateTotal / 20 ), 1 ); + + if ( self.bonusUpdateTotal ) + { + while ( self.bonusUpdateTotal > 0 ) + { + self.xpUpdateTotal += min( self.bonusUpdateTotal, increment ); + self.bonusUpdateTotal -= min( self.bonusUpdateTotal, increment ); + + self.hud_scorePopup setValue( self.xpUpdateTotal ); + + wait ( 0.05 ); + } + } + else + { + wait ( 1.0 ); + } + + self.hud_scorePopup fadeOverTime( 0.75 ); + self.hud_scorePopup.alpha = 0; + + self.xpUpdateTotal = 0; +} + +removeRankHUD() +{ + self.hud_scorePopup.alpha = 0; +} + +getRank() +{ + rankXp = self.pers["rankxp"]; + rankId = self.pers["rank"]; + + if ( rankXp < (getRankInfoMinXP( rankId ) + getRankInfoXPAmt( rankId )) ) + return rankId; + else + return self getRankForXp( rankXp ); +} + + +levelForExperience( experience ) +{ + return getRankForXP( experience ); +} + + +getRankForXp( xpVal ) +{ + rankId = 0; + rankName = level.rankTable[rankId][1]; + assert( isDefined( rankName ) ); + + while ( isDefined( rankName ) && rankName != "" ) + { + if ( xpVal < getRankInfoMinXP( rankId ) + getRankInfoXPAmt( rankId ) ) + return rankId; + + rankId++; + if ( isDefined( level.rankTable[rankId] ) ) + rankName = level.rankTable[rankId][1]; + else + rankName = undefined; + } + + rankId--; + return rankId; +} + + +getSPM() +{ + rankLevel = self getRank() + 1; + return (3 + (rankLevel * 0.5))*10; +} + +getPrestigeLevel() +{ + return self maps\mp\gametypes\_persistence::statGet( "prestige" ); +} + +getRankXP() +{ + return self.pers["rankxp"]; +} + +incRankXP( amount ) +{ + if ( !self rankingEnabled() ) + return; + + if ( isDefined( self.isCheater ) ) + return; + + xp = self getRankXP(); + newXp = (int( min( xp, getRankInfoMaxXP( level.maxRank ) ) ) + amount); + + if ( self.pers["rank"] == level.maxRank && newXp >= getRankInfoMaxXP( level.maxRank ) ) + newXp = getRankInfoMaxXP( level.maxRank ); + + self.pers["rankxp"] = newXp; +} + +getRestXPAward( baseXP ) +{ + if ( !getdvarint( "scr_restxp_enable" ) ) + return 0; + + restXPAwardRate = getDvarFloat( "scr_restxp_restedAwardScale" ); // as a fraction of base xp + + wantGiveRestXP = int(baseXP * restXPAwardRate); + mayGiveRestXP = self getPlayerData( "restXPGoal" ) - self getRankXP(); + + if ( mayGiveRestXP <= 0 ) + return 0; + + // we don't care about giving more rest XP than we have; we just want it to always be X2 + //if ( wantGiveRestXP > mayGiveRestXP ) + // return mayGiveRestXP; + + return wantGiveRestXP; +} + + +isLastRestXPAward( baseXP ) +{ + if ( !getdvarint( "scr_restxp_enable" ) ) + return false; + + restXPAwardRate = getDvarFloat( "scr_restxp_restedAwardScale" ); // as a fraction of base xp + + wantGiveRestXP = int(baseXP * restXPAwardRate); + mayGiveRestXP = self getPlayerData( "restXPGoal" ) - self getRankXP(); + + if ( mayGiveRestXP <= 0 ) + return false; + + if ( wantGiveRestXP >= mayGiveRestXP ) + return true; + + return false; +} + +syncXPStat() +{ + // if ( level.xpScale > 4 || level.xpScale <= 0) + // exitLevel( false ); + + xp = self getRankXP(); + + self maps\mp\gametypes\_persistence::statSet( "experience", xp ); +} diff --git a/userraw/maps/mp/gametypes/_weapons.gsc b/userraw/maps/mp/gametypes/_weapons.gsc index f00e142..b2fa47c 100644 --- a/userraw/maps/mp/gametypes/_weapons.gsc +++ b/userraw/maps/mp/gametypes/_weapons.gsc @@ -1,3 +1,33 @@ +/* + _weapons modded + Author: INeedGames + Date: 09/22/2020 + Adds dropping weapon, picking up equipment and friendly fire grenade team switching exploit fix. + Fixes the semtex 'STUCK' challenge when the thrower dies. + Fixes claymores from tripping when the victim is elevated from the claymore. + Fixes stuns and flashes friendly fire on claymores and c4s. + Fixes direct impact stun stunning the victim. + + DVARS: + - scr_allowDropWeaponOnCommand + false - (default) allows the player to drop their weapon + + - scr_allowPickUpEquipment + false - (default) allows the player to pick up their equipment once placed + + - scr_allowDropWeaponOnDeath + true - (default) allows player dropping their weapon on death + + - scr_allowClaymoreBounces + true - (default) allows players to use claymores from an elevated area, and the claymore will be placed far below the player. + + - scr_extraTeamIcons + false - (default) adds team icons to more objects such as grenades + + - scr_deleteNadeOnTeamChange + false - (default) deletes a grenade when it's owner changes team +*/ + #include common_scripts\utility; #include maps\mp\_utility; @@ -50,6 +80,20 @@ init() break; } + setDvarIfUninitialized("scr_allowDropWeaponOnCommand", false); + setDvarIfUninitialized("scr_allowPickUpEquipment", false); + setDvarIfUninitialized("scr_allowDropWeaponOnDeath", true); + setDvarIfUninitialized("scr_allowClaymoreBounces", true); + setDvarIfUninitialized("scr_extraTeamIcons", false); + setDvarIfUninitialized("scr_deleteNadeOnTeamChange", false); + + level.allowDropWeaponOnCommand = getDvarInt("scr_allowDropWeaponOnCommand"); + level.allowDropWeaponOnDeath = getDvarInt("scr_allowDropWeaponOnDeath"); + level.allowPickUpEquipment = getDvarInt("scr_allowPickUpEquipment"); + level.allowExtendedClaymoreTrace = getDvarInt("scr_allowClaymoreBounces"); + level.extraTeamIcons = getDvarInt("scr_extraTeamIcons"); + level.deleteNadeOnTeamChange = getDvarInt("scr_deleteNadeOnTeamChange"); + attachmentList = getAttachmentList(); // assigns weapons with stat numbers from 0-149 @@ -216,6 +260,8 @@ init() level thread onPlayerConnect(); + level thread watchSentryLimit(); + level.c4explodethisframe = false; array_thread( getEntArray( "misc_turret", "classname" ), ::turret_monitorUse ); @@ -224,6 +270,19 @@ init() } +watchSentryLimit() +{ + for(;;) + { + sentries = getentarray( "misc_turret", "classname" ); + if(sentries.size > 30) + sentries[0] delete(); + + wait 0.05; + } +} + + dumpIt() { @@ -397,6 +456,7 @@ onPlayerConnect() player thread onPlayerSpawned(); player thread bombSquadWaiter(); + player thread monitorSemtex(); } } @@ -423,6 +483,7 @@ onPlayerSpawned() self thread watchSentryUsage(); self thread watchWeaponReload(); self thread maps\mp\gametypes\_class::trackRiotShield(); + self thread watchDropWeaponOnCommand(); self.lastHitTime = []; @@ -433,13 +494,88 @@ onPlayerSpawned() self thread updateSavedLastWeapon(); - if ( self hasWeapon( "semtex_mp" ) ) - self thread monitorSemtex(); - self.currentWeaponAtSpawn = undefined; } } +watchDropWeaponOnCommand() +{ + if( !level.allowDropWeaponOnCommand ) + return; + + self endon( "disconnect" ); + self endon( "death" ); + + self notifyOnPlayerCommand( "drop_weapon_on_cmd", "+actionslot 2" ); + for(;;) + { + self waittill( "drop_weapon_on_cmd" ); + weapon = self GetCurrentWeapon(); + + if ( !gameFlag( "prematch_done" ) || !isDefined( weapon ) ) + continue; + + if( level.gameEnded ) + continue; + + if( !mayDropWeapon( weapon ) ) + continue; + + if ( !self hasWeapon( weapon ) ) + continue; + + if ( weapon != "riotshield_mp" ) + { + if ( !(self AnyAmmoForWeaponModes( weapon )) ) + { + continue; + } + + clipAmmoR = self GetWeaponAmmoClip( weapon, "right" ); + clipAmmoL = self GetWeaponAmmoClip( weapon, "left" ); + if ( !clipAmmoR && !clipAmmoL ) + { + continue; + } + + stockAmmo = self GetWeaponAmmoStock( weapon ); + stockMax = WeaponMaxAmmo( weapon ); + if ( stockAmmo > stockMax ) + stockAmmo = stockMax; + + item = self dropItem( weapon ); + item ItemWeaponSetAmmo( clipAmmoR, stockAmmo, clipAmmoL ); + } + else + { + item = self dropItem( weapon ); + if ( !isDefined( item ) ) + continue; + item ItemWeaponSetAmmo( 1, 1, 0 ); + } + item.owner = self; + + item thread maps\mp\gametypes\_weapons::watchPickup(); + + //deletes dropped weapon after 30 sec. + item thread maps\mp\gametypes\_weapons::deletePickupAfterAWhile(); + + detach_model = getWeaponModel( weapon ); + + if ( !isDefined( detach_model ) ) + continue; + + if( isDefined( self.tag_stowed_back ) && detach_model == self.tag_stowed_back ) + self maps\mp\gametypes\_weapons::detach_back_weapon(); + + if ( !isDefined( self.tag_stowed_hip ) ) + continue; + + if( detach_model == self.tag_stowed_hip ) + self maps\mp\gametypes\_weapons::detach_hip_weapon(); + } +} + WatchStingerUsage() { self maps\mp\_stinger::StingerUsageLoop(); @@ -598,6 +734,9 @@ mayDropWeapon( weapon ) dropWeaponForDeath( attacker ) { + if( !level.allowDropWeaponOnDeath ) + return; + weapon = self.lastDroppableWeapon; if ( isdefined( self.droppedDeathWeapon ) ) @@ -1106,6 +1245,17 @@ watchGrenadeUsage() } } +deleteOnOwnerTeamChange( owner ) +{ + self endon( "delete_on_team_overlap" ); + + self endon( "death" ); + + owner waittill_any( "disconnect", "joined_team", "joined_spectators" ); + + self delete(); +} + beginGrenadeTracking() { self endon( "death" ); @@ -1121,17 +1271,43 @@ beginGrenadeTracking() grenade.isCooked = true; self.changingWeapon = undefined; - - if ( weaponName == "frag_grenade_mp" || weaponName == "semtex_mp" ) + + grenade.owner = self; + + switch( weaponName ) { - grenade thread maps\mp\gametypes\_shellshock::grenade_earthQuake(); - grenade.originalOwner = self; - } - - if ( weaponName == "flash_grenade_mp" || weaponName == "concussion_grenade_mp" ) - { - grenade.owner = self; - grenade thread empExplodeWaiter(); + case "frag_grenade_mp": + case "semtex_mp": + grenade thread maps\mp\gametypes\_shellshock::grenade_earthQuake(); + grenade.originalOwner = self; + + if ( level.deleteNadeOnTeamChange ) + grenade thread deleteOnOwnerTeamChange( self ); + + if( level.extraTeamIcons ) + grenade thread setClaymoreTeamHeadIcon( self.pers[ "team" ] ); + break; + case "flash_grenade_mp": + case "concussion_grenade_mp": + grenade thread empExplodeWaiter(); + + if ( level.deleteNadeOnTeamChange ) + grenade thread deleteOnOwnerTeamChange( self ); + + if( level.extraTeamIcons ) + grenade thread setClaymoreTeamHeadIcon( self.pers[ "team" ] ); + break; + case "smoke_grenade_mp": + if( level.extraTeamIcons ) + grenade thread setClaymoreTeamHeadIcon( self.pers[ "team" ] ); + break; + case "throwingknife_mp": + if ( level.deleteNadeOnTeamChange ) + grenade thread deleteOnOwnerTeamChange( self ); + + if( level.extraTeamIcons ) + grenade thread setClaymoreTeamHeadIcon( self.pers[ "team" ] ); + break; } } @@ -1193,6 +1369,10 @@ watchMissileUsage() default: break; } + if( level.extraTeamIcons && weaponName != "remotemissile_projectile_mp" ) + missile thread setClaymoreTeamHeadIcon( self.pers[ "team" ] ); + if ( level.deleteNadeOnTeamChange ) + missile thread deleteOnOwnerTeamChange( self ); } } @@ -1262,6 +1442,14 @@ watchForThrowbacks() grenade thread maps\mp\gametypes\_shellshock::grenade_earthQuake(); grenade.originalOwner = self; + + if( level.extraTeamIcons ) + grenade thread setClaymoreTeamHeadIcon( self.pers[ "team" ] ); + if ( level.deleteNadeOnTeamChange ) + { + grenade notify( "delete_on_team_overlap" ); + grenade thread deleteOnOwnerTeamChange( self ); + } } } @@ -1302,7 +1490,12 @@ watchC4() c4 thread c4Damage(); c4 thread c4EMPDamage(); c4 thread c4EMPKillstreakWait(); + if( level.extraTeamIcons ) + c4 thread setClaymoreTeamHeadIcon( self.pers[ "team" ] ); //c4 thread c4DetectionTrigger( self.pers[ "team" ] ); + c4 thread c4WatchPickup(); + if ( level.deleteNadeOnTeamChange ) + c4 thread deleteOnOwnerTeamChange( self ); } } } @@ -1316,6 +1509,9 @@ c4EMPDamage() { self waittill( "emp_damage", attacker, duration ); + if ( isPlayer(attacker) && !friendlyFireCheck( self.owner, attacker ) ) + continue; + playfxOnTag( getfx( "sentry_explode_mp" ), self, "tag_origin" ); self.disabled = true; @@ -1350,15 +1546,44 @@ c4EMPKillstreakWait() } } +deleteTeamHeadIconOnUndefined(ent, hud) +{ + ent endon( "death" ); + + while ( isDefined(ent) ) + wait 0.05; + + hud destroy(); + hud = undefined; + ent notify( "kill_entity_headicon_thread" ); +} setClaymoreTeamHeadIcon( team ) { self endon( "death" ); - wait .05; + + if ( self.weaponname == "claymore_mp" && !level.allowExtendedClaymoreTrace ) + { + self waittill( "missile_stuck" ); + self waittill( "claymore_trace_fixed" ); + } + else + wait 0.05; + + if ( isDefined( self.entityHeadIcon ) ) + { + self.entityHeadIconTeam = "none"; + self.entityHeadIcon destroy(); + self.entityHeadIcon = undefined; + self notify( "kill_entity_headicon_thread" ); + } + if ( level.teamBased ) self maps\mp\_entityheadicons::setTeamHeadIcon( team, ( 0, 0, 20 ) ); else if ( isDefined( self.owner ) ) self maps\mp\_entityheadicons::setPlayerHeadIcon( self.owner, (0,0,20) ); + + thread deleteTeamHeadIconOnUndefined(self, self.entityHeadIcon); } @@ -1367,7 +1592,6 @@ watchClaymores() self endon( "spawned_player" ); self endon( "disconnect" ); - self.claymorearray = []; while ( 1 ) { self waittill( "grenade_fire", claymore, weapname ); @@ -1389,7 +1613,10 @@ watchClaymores() claymore thread claymoreDetonation(); //claymore thread claymoreDetectionTrigger_wait( self.pers[ "team" ] ); claymore thread setClaymoreTeamHeadIcon( self.pers[ "team" ] ); - + claymore thread c4WatchPickup(); + claymore thread claymoreWatchTrace(); + if ( level.deleteNadeOnTeamChange ) + claymore thread deleteOnOwnerTeamChange( self ); /# if ( getdvarint( "scr_claymoredebug" ) ) { @@ -1400,6 +1627,96 @@ watchClaymores() } } +claymoreWatchTrace() +{ + if( level.allowExtendedClaymoreTrace ) + return; + + self endon( "death" ); + + // need to see if this is being placed far away from the player and not let it do that + // this will fix a legacy bug where you can stand on a ledge and plant a claymore down on the ground far below you + self Hide(); + + self waittill( "missile_stuck" ); + wait 0.05;//wait for threads + + distanceZ = 40; + + if( distanceZ * distanceZ < DistanceSquared( self.origin, self.owner.origin ) ) + { + secTrace = bulletTrace( self.owner.origin, self.owner.origin - (0, 0, distanceZ), false, self ); + + if( secTrace["fraction"] == 1 ) + { + self.owner SetWeaponAmmoStock( self.weaponname, self.owner GetWeaponAmmoStock( self.weaponname ) + 1 ); + self delete(); + return; + } + self.origin = secTrace["position"]; + } + self Show(); + self notify( "claymore_trace_fixed" ); +} + +_notUsableForJoiningPlayers( owner ) +{ + self endon ( "death" ); + level endon ( "game_ended" ); + owner endon ( "disconnect" ); + + // as players join they need to be set to not be able to use this + while( true ) + { + level waittill( "player_spawned", player ); + if( IsDefined( player ) && player != owner ) + { + self disablePlayerUse( player ); + } + } +} + +c4WatchPickup() +{ + if( !level.allowPickUpEquipment ) + return; + + self endon( "death" ); + + self waittill( "missile_stuck" ); + if( !level.allowExtendedClaymoreTrace && self.weaponname == "claymore_mp" ) + self waittill( "claymore_trace_fixed" ); + + trigger = spawn( "script_origin", self.origin ); + self thread deleteOnDeath( trigger ); + + trigger setCursorHint( "HINT_NOICON" ); + + if ( self.weaponname == "c4_mp" ) + trigger setHintString( &"MP_PICKUP_C4" ); + else if (self.weaponname == "claymore_mp" ) + trigger setHintString( &"MP_PICKUP_CLAYMORE" ); + + trigger setSelfUsable( self.owner ); + trigger thread _notUsableForJoiningPlayers( self ); + + for ( ;; ) + { + trigger waittillmatch( "trigger", self.owner ); + usePressTime = getTime(); + while( self.owner UseButtonPressed() && (getTime() - usePressTime) < 500 ) + wait .05; + + if( self.owner UseButtonPressed() ) + { + self.owner playLocalSound( "scavenger_pack_pickup" ); + self.owner SetWeaponAmmoStock( self.weaponname, self.owner GetWeaponAmmoStock( self.weaponname ) + 1 ); + + self delete(); + } + } +} + /# claymoreDebug() { @@ -1449,6 +1766,9 @@ claymoreDetonation() self endon( "death" ); self waittill( "missile_stuck" ); + + if( !level.allowExtendedClaymoreTrace ) + self waittill( "claymore_trace_fixed" ); damagearea = spawn( "trigger_radius", self.origin + ( 0, 0, 0 - level.claymoreDetonateRadius ), 0, level.claymoreDetonateRadius, level.claymoreDetonateRadius * 2 ); self thread deleteOnDeath( damagearea ); @@ -1466,6 +1786,9 @@ claymoreDetonation() } if ( lengthsquared( player getVelocity() ) < 10 ) continue; + + if ( abs( player.origin[2] - self.origin[2] ) > 128 ) + continue; if ( !player shouldAffectClaymore( self ) ) continue; @@ -1658,7 +1981,7 @@ c4Damage() while ( 1 ) { - self waittill( "damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, iDFlags ); + self waittill( "damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, iDFlags, weapon ); if ( !isPlayer( attacker ) ) continue; @@ -1666,8 +1989,22 @@ c4Damage() if ( !friendlyFireCheck( self.owner, attacker ) ) continue; - if ( damage < 5 )// ignore concussion grenades - continue; + + if( isDefined( weapon ) ) + { + switch( weapon ) + { + case "concussion_grenade_mp": + case "flash_grenade_mp": + case "smoke_grenade_mp": + continue; + } + } + else + { + if( damage < 5 ) + continue; + } break; } @@ -1691,6 +2028,14 @@ c4Damage() self.wasDamagedFromBulletPenetration = true; self.wasDamaged = true; + + if( isPlayer( attacker ) ) + { + if( isDefined( level.extraDamageFeedback ) && level.extraDamageFeedback ) + attacker maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "c4" ); + if( isDefined( level.allowPrintDamage ) && level.allowPrintDamage && attacker.printDamage ) + attacker iPrintLnBold( damage ); + } if ( level.teamBased ) { @@ -2071,10 +2416,10 @@ damageEnt( eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, damagepos, da else { // destructable walls and such can only be damaged in certain ways. - if ( self.isADestructable && ( sWeapon == "artillery_mp" || sWeapon == "claymore_mp" ) || sWeapon == "stealth_bomb_mp" ) + if ( self.isADestructable && ( sWeapon == "artillery_mp" || sWeapon == "claymore_mp" || sWeapon == "stealth_bomb_mp" ) ) return; - self.entity notify( "damage", iDamage, eAttacker, ( 0, 0, 0 ), ( 0, 0, 0 ), "mod_explosive", "", "" ); + self.entity notify( "damage", iDamage, eAttacker, ( 0, 0, 0 ), ( 0, 0, 0 ), "MOD_EXPLOSIVE", "", "", "", undefined, sWeapon ); } } @@ -2107,6 +2452,12 @@ onWeaponDamage( eInflictor, sWeapon, meansOfDeath, damage, eAttacker ) { case "concussion_grenade_mp": // should match weapon settings in gdt + if ( !isDefined( eInflictor ) )//check to ensure inflictor wasnt destroyed. + return; + + if( meansOfDeath == "MOD_IMPACT" ) // do not cause stun effect if it was direct hit + return; + radius = 512; scale = 1 - ( distance( self.origin, eInflictor.origin ) / radius ); @@ -2115,10 +2466,18 @@ onWeaponDamage( eInflictor, sWeapon, meansOfDeath, damage, eAttacker ) time = 2 + ( 4 * scale ); + if ( isDefined( self.stunScaler ) ) + time = time * self.stunScaler; + wait( 0.05 ); eAttacker notify( "stun_hit" ); + self notify( "concussed", eAttacker ); + if( eAttacker != self ) + eAttacker maps\mp\gametypes\_missions::processChallenge( "ch_alittleconcussed" ); self shellShock( "concussion_grenade_mp", time ); self.concussionEndTime = getTime() + ( time * 1000 ); + if( IsDefined( eInflictor.owner ) && eInflictor.owner == eAttacker && isDefined( level.extraDamageFeedback ) && level.extraDamageFeedback ) + eAttacker thread maps\mp\gametypes\_damagefeedback::updateDamageFeedback( "stun" ); break; case "weapon_cobra_mk19_mp": @@ -2649,7 +3008,6 @@ buildWeaponData( filterPerks ) monitorSemtex() { self endon( "disconnect" ); - self endon( "death" ); for( ;; ) { @@ -2676,7 +3034,7 @@ monitorSemtex() self thread maps\mp\gametypes\_hud_message::SplashNotify( "stuck_semtex", 100 ); self notify( "process", "ch_bullseye" ); - } + } } diff --git a/userraw/maps/mp/killstreaks/_emp.gsc b/userraw/maps/mp/killstreaks/_emp.gsc index d74558a..4b3fd3d 100644 --- a/userraw/maps/mp/killstreaks/_emp.gsc +++ b/userraw/maps/mp/killstreaks/_emp.gsc @@ -1,3 +1,21 @@ +/* + _emp modded + Author: INeedGames + Date: 09/22/2020 + Adds a friendly fire check when destroying killstreaks and a duration dvar. + > gets emp'd + > hears on an electric radio: WE'VE BEEN EMP'D ELECTRONICS ARE DOWN! + + DVARS: + - scr_emp_duration + 60 - (default) amount of seconds for an emp to last + + - scr_emp_doesFriendlyFire + true - (default) whether or not if an emp destroies all killstreaks reguardless of friendly fire + + Thanks: H3X1C, Emosewaj +*/ + #include maps\mp\_utility; #include common_scripts\utility; @@ -17,8 +35,13 @@ init() level.killstreakFuncs["emp"] = ::EMP_Use; - level thread onPlayerConnect(); + setDvarIfUninitialized( "scr_emp_duration", 60 ); + setDvarIfUninitialized( "scr_emp_doesFriendlyFire", true ); + + level.empduration = getDvarInt( "scr_emp_duration" ); + level.empDoesFriendlyFire = getDvarInt( "scr_emp_doesFriendlyFire" ); + level thread onPlayerConnect(); } @@ -58,9 +81,9 @@ EMP_Use( lifeId, delay ) otherTeam = level.otherTeam[myTeam]; if ( level.teamBased ) - self thread EMP_JamTeam( otherTeam, 60.0, delay ); + self thread EMP_JamTeam( otherTeam, level.empduration, delay ); else - self thread EMP_JamPlayers( self, 60.0, delay ); + self thread EMP_JamPlayers( self, level.empduration, delay ); self maps\mp\_matchdata::logKillstreakEvent( "emp", self.origin ); self notify( "used_emp" ); @@ -69,7 +92,7 @@ EMP_Use( lifeId, delay ) } -EMP_JamTeam( teamName, duration, delay ) +EMP_JamTeam( teamName, duration, delay, silent ) { level endon ( "game_ended" ); @@ -77,7 +100,8 @@ EMP_JamTeam( teamName, duration, delay ) //wait ( delay ); - thread teamPlayerCardSplash( "used_emp", self ); + if (!isDefined(silent)) + thread teamPlayerCardSplash( "used_emp", self ); level notify ( "EMP_JamTeam" + teamName ); level endon ( "EMP_JamTeam" + teamName ); @@ -93,21 +117,24 @@ EMP_JamTeam( teamName, duration, delay ) player RadarJamOff(); } - visionSetNaked( "coup_sunblind", 0.1 ); - thread empEffects(); - - wait ( 0.1 ); - - // resetting the vision set to the same thing won't normally have an effect. - // however, if the client receives the previous visionset change in the same packet as this one, - // this will force them to lerp from the bright one to the normal one. - visionSetNaked( "coup_sunblind", 0 ); - visionSetNaked( getDvar( "mapname" ), 3.0 ); + if (!isDefined(silent)) + { + visionSetNaked( "coup_sunblind", 0.1 ); + thread empEffects(); + + wait ( 0.1 ); + + // resetting the vision set to the same thing won't normally have an effect. + // however, if the client receives the previous visionset change in the same packet as this one, + // this will force them to lerp from the bright one to the normal one. + visionSetNaked( "coup_sunblind", 0 ); + visionSetNaked( getDvar( "mapname" ), 3.0 ); + } level.teamEMPed[teamName] = true; level notify ( "emp_update" ); - level destroyActiveVehicles( self ); + level destroyActiveVehicles( self, !level.empEffectsAll ); maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( duration ); @@ -125,7 +152,7 @@ EMP_JamTeam( teamName, duration, delay ) level notify ( "emp_update" ); } -EMP_JamPlayers( owner, duration, delay ) +EMP_JamPlayers( owner, duration, delay, silent ) { level notify ( "EMP_JamPlayers" ); level endon ( "EMP_JamPlayers" ); @@ -145,22 +172,25 @@ EMP_JamPlayers( owner, duration, delay ) player RadarJamOff(); } - visionSetNaked( "coup_sunblind", 0.1 ); - thread empEffects(); + if (!isDefined(silent)) + { + visionSetNaked( "coup_sunblind", 0.1 ); + thread empEffects(); - wait ( 0.1 ); - - // resetting the vision set to the same thing won't normally have an effect. - // however, if the client receives the previous visionset change in the same packet as this one, - // this will force them to lerp from the bright one to the normal one. - visionSetNaked( "coup_sunblind", 0 ); - visionSetNaked( getDvar( "mapname" ), 3.0 ); + wait ( 0.1 ); + + // resetting the vision set to the same thing won't normally have an effect. + // however, if the client receives the previous visionset change in the same packet as this one, + // this will force them to lerp from the bright one to the normal one. + visionSetNaked( "coup_sunblind", 0 ); + visionSetNaked( getDvar( "mapname" ), 3.0 ); + } level notify ( "emp_update" ); level.empPlayer = owner; level.empPlayer thread empPlayerFFADisconnect(); - level destroyActiveVehicles( owner ); + level destroyActiveVehicles( owner, !level.empDoesFriendlyFire ); level notify ( "emp_update" ); @@ -254,38 +284,49 @@ EMP_PlayerTracker() } } -destroyActiveVehicles( attacker ) +destroyActiveVehicles( attacker, friendlyFireCheck ) { + if (!isDefined(friendlyFireCheck)) + friendlyFireCheck = false; + if ( isDefined( attacker ) ) { foreach ( heli in level.helis ) - radiusDamage( heli.origin, 384, 5000, 5000, attacker ); + if (!friendlyFireCheck || (level.teamBased && heli.team != attacker.team) || (!level.teamBased && (!isDefined(heli.owner) || heli.owner != attacker))) + radiusDamage( heli.origin, 384, 5000, 5000, attacker ); foreach ( littleBird in level.littleBird ) - radiusDamage( littleBird.origin, 384, 5000, 5000, attacker ); + if (!friendlyFireCheck || (level.teamBased && littleBird.team != attacker.team) || (!level.teamBased && (!isDefined(littleBird.owner) || littleBird.owner != attacker))) + radiusDamage( littleBird.origin, 384, 5000, 5000, attacker ); foreach ( turret in level.turrets ) - radiusDamage( turret.origin, 16, 5000, 5000, attacker ); + if (!friendlyFireCheck || (level.teamBased && turret.team != attacker.team) || (!level.teamBased && (!isDefined(turret.owner) || turret.owner != attacker))) + radiusDamage( turret.origin, 16, 5000, 5000, attacker ); foreach ( rocket in level.rockets ) - rocket notify ( "death" ); + if (!friendlyFireCheck || (level.teamBased && rocket.team != attacker.team) || (!level.teamBased && (!isDefined(rocket.owner) || rocket.owner != attacker))) + rocket notify ( "death" ); if ( level.teamBased ) { foreach ( uav in level.uavModels["allies"] ) - radiusDamage( uav.origin, 384, 5000, 5000, attacker ); + if (!friendlyFireCheck || uav.team != attacker.team) + radiusDamage( uav.origin, 384, 5000, 5000, attacker ); foreach ( uav in level.uavModels["axis"] ) - radiusDamage( uav.origin, 384, 5000, 5000, attacker ); + if (!friendlyFireCheck || uav.team != attacker.team) + radiusDamage( uav.origin, 384, 5000, 5000, attacker ); } else { foreach ( uav in level.uavModels ) - radiusDamage( uav.origin, 384, 5000, 5000, attacker ); + if (!friendlyFireCheck || !isDefined(uav.owner) || uav.owner != attacker) + radiusDamage( uav.origin, 384, 5000, 5000, attacker ); } if ( isDefined( level.ac130player ) ) - radiusDamage( level.ac130.planeModel.origin+(0,0,10), 1000, 5000, 5000, attacker ); + if (!friendlyFireCheck || (level.teamBased && level.ac130player.team != attacker.team) || (!level.teamBased && level.ac130player != attacker)) + radiusDamage( level.ac130.planeModel.origin+(0,0,10), 1000, 5000, 5000, attacker ); } else { diff --git a/userraw/maps/mp/killstreaks/_killstreaks.gsc b/userraw/maps/mp/killstreaks/_killstreaks.gsc index 20ce9a0..f651f51 100644 --- a/userraw/maps/mp/killstreaks/_killstreaks.gsc +++ b/userraw/maps/mp/killstreaks/_killstreaks.gsc @@ -1,3 +1,29 @@ +/* + _killstreaks modded + Author: INeedGames + Date: 09/22/2020 + Adds killstreak rollover and killstreak HUD.origin + + DVARS: + - scr_killstreak_rollover + 0 - (default) killstreaks do not rollover, only get one set of killstreaks + 1 - killstreaks rollover, earn killstreaks over again without dying + 2 - killstreaks rollover only with hardline pro + + - scr_maxKillstreakRollover + 10 - (default) allow to rollover killstreaks times. (remember you are limited to 10 rollovers as defined in _class.gsc) + + - scr_killstreak_mod + 0 - (default) offsets all killstreaks reward costs by amount + + - scr_killstreakHud + 0 - (default) no HUD + 1 - use Puffiamo's killstreak HUD + 2 - use NoFate's MW3 killstreak HUD + + Thanks: H3X1C, Emosewaj, NoFate, Puffiamo +*/ + #include maps\mp\_utility; #include maps\mp\gametypes\_hud_util; #include common_scripts\utility; @@ -20,8 +46,6 @@ init() level.killstreakFuncs = []; level.killstreakSetupFuncs = []; level.killstreakWeapons = []; - - level.killStreakMod = 0; thread maps\mp\killstreaks\_ac130::init(); thread maps\mp\killstreaks\_remotemissile::init(); @@ -36,6 +60,16 @@ init() level.killstreakRoundDelay = getIntProperty( "scr_game_killstreakdelay", 8 ); + setDvarIfUninitialized( "scr_killstreak_rollover", false ); + setDvarIfUninitialized( "scr_maxKillstreakRollover", 10 ); + setDvarIfUninitialized( "scr_killstreakHud", false ); + setDvarIfUninitialized( "scr_killstreak_mod", 0 ); + + level.killstreaksRollOver = getDvarInt("scr_killstreak_rollover"); + level.maxKillstreakRollover = getDvarInt("scr_maxKillstreakRollover"); + level.killstreakHud = getDvarInt("scr_killstreakHud"); + level.killStreakMod = getDvarInt( "scr_killstreak_mod" ); + level thread onPlayerConnect(); } @@ -124,6 +158,11 @@ onPlayerSpawned() self thread killstreakUseWaiter(); self thread waitForChangeTeam(); + if (level.killstreakHud == 1) + self thread initKillstreakHud( 145 ); + else if (level.killstreakHud == 2) + self thread initMW3KillstreakHud(); + self giveOwnedKillstreakItem( true ); } } @@ -284,10 +323,10 @@ shuffleKillStreaksFILO( streakName, kID ) { if ( self.pers["killstreaks"][i].streakName != streakName ) continue; - + if ( isDefined( kID ) && self.pers["killstreaks"][i].kID != kID ) continue; - + streakIndex = i; break; } @@ -460,16 +499,22 @@ checkKillstreakReward( streakCount ) if ( isSubStr( streakName, "-rollover" ) ) { - continue; - /* - if ( game["defcon"] > 2 ) - { - self.pers["lastEarnedStreak"] = streakName; + if (!level.killstreaksRollover || (level.killstreaksRollover == 2 && !self _hasPerk("specialty_rollover"))) continue; + else + { + curRollover = int(strtok(strtok(streakName, "-")[1], "rollover")[0]); + if (curRollover > level.maxKillstreakRollover) + continue; + + if ( isDefined( game["defcon"] ) && game["defcon"] > 2 ) + { + self.pers["lastEarnedStreak"] = streakName; + continue; + } + + useStreakName = strTok( streakName, "-" )[0]; } - - useStreakName = strTok( streakName, "-" )[0]; - */ } else { @@ -711,4 +756,204 @@ clearRideIntro( delay ) self VisionSetNakedForPlayer( getDvar( "mapname" ), 0 ); } +destroyOnEvents(elem) +{ + self waittill_either("disconnect", "spawned_player"); + elem destroy(); +} +initKillstreakHud(inity) +{ + self endon( "death" ); + self endon( "disconnect" ); + + streakVals = GetArrayKeys(self.killStreaks); + hasHardline = self _hasPerk("specialty_hardline"); + + self.killStreakHudElems = []; + + // the killstreak counter + index = self.killStreakHudElems.size; + self.killStreakHudElems[index] = self createFontString( "objective", 2 ); + self.killStreakHudElems[index].foreground = false; + self.killStreakHudElems[index].hideWhenInMenu = true; + self.killStreakHudElems[index].fontScale = 0.60; + self.killStreakHudElems[index].font = "hudbig"; + self.killStreakHudElems[index].alpha = 1; + self.killStreakHudElems[index].glow = 1; + self.killStreakHudElems[index].glowColor = ( 0, 0, 1 ); + self.killStreakHudElems[index].glowAlpha = 1; + self.killStreakHudElems[index].color = ( 1.0, 1.0, 1.0 ); + self thread destroyOnEvents(self.killStreakHudElems[index]); + highestStreak = -1; + + for (i = 0; i < streakVals.size; i++) + { + streakVal = streakVals[i]; + streakName = self.killStreaks[streakVal]; + + if (isSubStr(streakName, "-rollover")) + continue; + + streakShader = maps\mp\killstreaks\_killstreaks::getKillstreakIcon( streakName ); + streakCost = maps\mp\killstreaks\_killstreaks::getStreakCost( streakName ); + if (hasHardline) + streakCost--; + + // each killstreak icon + index = self.killStreakHudElems.size; + self.killStreakHudElems[index] = self createFontString( "objective", 2 ); + self.killStreakHudElems[index].foreground = false; + self.killStreakHudElems[index].hideWhenInMenu = true; + self.killStreakHudElems[index].fontScale = 0.60; + self.killStreakHudElems[index].font = "hudbig"; + self.killStreakHudElems[index].alpha = 1; + self.killStreakHudElems[index].glow = 1; + self.killStreakHudElems[index].glowColor = ( 0, 0, 1 ); + self.killStreakHudElems[index].glowAlpha = 1; + self.killStreakHudElems[index].color = ( 1.0, 1.0, 1.0 ); + self.killStreakHudElems[index] setPoint( "RIGHT", "RIGHT", 0, inity - 25 * i ); + self.killStreakHudElems[index] setShader( streakShader, 20, 20 ); + self.killStreakHudElems[index].ks_cost = streakCost; + self thread destroyOnEvents(self.killStreakHudElems[index]); + + if (streakCost > highestStreak) + highestStreak = streakCost; + } + + for(first=true;;) + { + if (first) + first = false; + else + self waittill( "killed_enemy" ); + + curStreak = self.pers["cur_kill_streak"]; + timesRolledOver = int(curStreak / highestStreak); + if (level.killstreaksRollover == 1 || (level.killstreaksRollover == 2 && self _hasPerk("specialty_rollover"))) + curStreak %= highestStreak; + + if (timesRolledOver > level.maxKillstreakRollover) + curStreak = highestStreak; + + isUnderAStreak = false; + + for (i = self.killStreakHudElems.size - 1; i >= 1; i--) + { + streakElem = self.killStreakHudElems[i]; + if (curStreak < streakElem.ks_cost) + { + isUnderAStreak = true; + self.killStreakHudElems[0] setPoint( "RIGHT", "RIGHT", -25, inity - 25 * (i - 1) ); + self.killStreakHudElems[0] setText( streakElem.ks_cost - curStreak ); + } + } + + if (!isUnderAStreak && self.killStreakHudElems.size) + { + self.killStreakHudElems[0] setPoint( "RIGHT", "RIGHT", -25, inity - 25 * (self.killStreakHudElems.size - 1 - 1) ); + self.killStreakHudElems[0] setText( "Done" ); + } + } +} + +initMW3KillstreakHud() +{ + self endon( "death" ); + self endon( "disconnect" ); + + streakVals = GetArrayKeys(self.killStreaks); + hasHardline = self _hasPerk("specialty_hardline"); + + self.killStreakHudElems = []; + self.killStreakShellsElems = []; + highestStreak = -1; + + for (i = 0; i < streakVals.size; i++) + { + streakVal = streakVals[i]; + streakName = self.killStreaks[streakVal]; + + if (isSubStr(streakName, "-rollover")) + continue; + + streakShader = maps\mp\killstreaks\_killstreaks::getKillstreakIcon( streakName ); + streakCost = maps\mp\killstreaks\_killstreaks::getStreakCost( streakName ); + if (hasHardline) + streakCost--; + + if (streakCost > highestStreak) + highestStreak = streakCost; + + // the shader + ksIcon = createIcon( streakShader, 20, 20 ); + ksIcon setPoint( "BOTTOM RIGHT", "BOTTOM RIGHT", -32, -90 + -25 * i ); + ksIcon.alpha = 0.4; + ksIcon.hideWhenInMenu = true; + ksIcon.foreground = true; + ksIcon.ks_cost = streakCost; + self thread destroyOnEvents(ksIcon); + self.killStreakHudElems[self.killStreakHudElems.size] = ksIcon; + } + + // the shells + if (highestStreak > 0) + { + h = -53; + for(i = 0; i < highestStreak; i++) + { + ksShell = NewClientHudElem( self ); + ksShell.x = 40; + ksShell.y = h; + ksShell.alignX = "right"; + ksShell.alignY = "bottom"; + ksShell.horzAlign = "right"; + ksShell.vertAlign = "bottom"; + ksShell setshader("white", 10, 2); + ksShell.alpha = 0.3; + ksShell.hideWhenInMenu = true; + ksShell.foreground = false; + self thread destroyOnEvents(ksShell); + self.killStreakShellsElems[i] = ksShell; + + h -= 4; + } + } + + for(first=true;;) + { + if (first) + first = false; + else + self waittill( "killed_enemy" ); + + curStreak = self.pers["cur_kill_streak"]; + timesRolledOver = int(curStreak / highestStreak); + if (level.killstreaksRollover == 1 || (level.killstreaksRollover == 2 && self _hasPerk("specialty_rollover"))) + curStreak %= highestStreak; + + if (timesRolledOver > level.maxKillstreakRollover) + curStreak = highestStreak; + + // update the shells + for (i = 0; i < self.killStreakShellsElems.size; i++) + { + elem = self.killStreakShellsElems[i]; + if (curStreak > i) + elem.alpha = 0.85; + else + elem.alpha = 0.3; + } + + // update the ks icons + for (i = 0; i < self.killStreakHudElems.size; i++) + { + elem = self.killStreakHudElems[i]; + + if (curStreak >= elem.ks_cost) + elem.alpha = 0.9; + else + elem.alpha = 0.4; + } + } +} diff --git a/userraw/maps/mp/perks/_perkfunctions.gsc b/userraw/maps/mp/perks/_perkfunctions.gsc index 9548905..1334274 100644 --- a/userraw/maps/mp/perks/_perkfunctions.gsc +++ b/userraw/maps/mp/perks/_perkfunctions.gsc @@ -1,3 +1,10 @@ +/* + _perkfunctions modded + Author: INeedGames + Date: 09/22/2020 + Readds optional painkiller and one man army refills noobtubes. +*/ + /******************************************************************* // _perkfunctions.gsc // @@ -121,8 +128,11 @@ setCombatHigh() level endon( "end_game" ); self.damageBlockedTotal = 0; - self.moveSpeedScaler = 1.25; - self maps\mp\gametypes\_weapons::updateMoveSpeedScale( "primary" ); + if (level.combathighIsJuiced) + { + self.moveSpeedScaler = 1.25; + self maps\mp\gametypes\_weapons::updateMoveSpeedScale( "primary" ); + } //self visionSetNakedForPlayer( "end_game", 1 ); if ( level.splitscreen ) @@ -149,7 +159,11 @@ setCombatHigh() self.combatHighTimer = createTimer( "hudsmall", 1.0 ); self.combatHighTimer setPoint( "CENTER", "CENTER", 0, yOffset ); - self.combatHighTimer setTimer( 7.0 ); + if (level.combathighIsJuiced) + self.combatHighTimer setTimer( 7.0 ); + else + self.combatHighTimer setTimer( 10.0 ); + self.combatHighTimer.color = (.8,.8,0); self.combatHighTimer.archived = false; self.combatHighTimer.foreground = true; @@ -170,7 +184,10 @@ setCombatHigh() self thread unsetCombatHighOnDeath(); - wait( 5 ); + if (level.combathighIsJuiced) + wait( 5 ); + else + wait( 8 ); self.combatHighIcon fadeOverTime( 2.0 ); self.combatHighIcon.alpha = 0.0; @@ -184,14 +201,17 @@ setCombatHigh() wait( 2 ); self.damageBlockedTotal = undefined; - self.moveSpeedScaler = 1; - - if (self _hasperk( "specialty_lightweight" )) + if (level.combathighIsJuiced) { - self.moveSpeedScaler = 1.07; - } + self.moveSpeedScaler = 1; - self maps\mp\gametypes\_weapons::updateMoveSpeedScale( "primary" ); + if (self _hasperk( "specialty_lightweight" )) + { + self.moveSpeedScaler = 1.07; + } + + self maps\mp\gametypes\_weapons::updateMoveSpeedScale( "primary" ); + } self _unsetPerk( "specialty_combathigh" ); } @@ -203,11 +223,14 @@ unsetCombatHighOnDeath() self waittill ( "death" ); - self.moveSpeedScaler = 1; - - if (self _hasperk( "specialty_lightweight" )) + if (level.combathighIsJuiced) { - self.moveSpeedScaler = 1.07; + self.moveSpeedScaler = 1; + + if (self _hasperk( "specialty_lightweight" )) + { + self.moveSpeedScaler = 1.07; + } } self thread _unsetPerk( "specialty_combathigh" ); @@ -220,11 +243,14 @@ unsetCombatHigh() self.combatHighIcon destroy(); self.combatHighTimer destroy(); - self.moveSpeedScaler = 1; - - if (self _hasperk( "specialty_lightweight" )) + if (level.combathighIsJuiced) { - self.moveSpeedScaler = 1.07; + self.moveSpeedScaler = 1; + + if (self _hasperk( "specialty_lightweight" )) + { + self.moveSpeedScaler = 1.07; + } } } @@ -366,9 +392,12 @@ setLightWeight() { self.moveSpeedScaler = 1.07; - if (self _hasperk( "specialty_combathigh" )) + if (level.combathighIsJuiced) { - self.moveSpeedScaler = 1.4; + if (self _hasperk( "specialty_combathigh" )) + { + self.moveSpeedScaler = 1.4; + } } self maps\mp\gametypes\_weapons::updateMoveSpeedScale( "primary" ); @@ -693,6 +722,9 @@ giveOneManArmyClass( className ) self notify ( "changed_kit" ); level notify ( "changed_kit" ); + if (level.onemanarmyRefillsTubes) + return; + weaponNameSize = self getCurrentWeapon().size; if( getSubStr( self getCurrentWeapon(), weaponNameSize - 6, weaponNameSize ) == "_gl_mp" ) diff --git a/userraw/maps/mp/perks/_perks.gsc b/userraw/maps/mp/perks/_perks.gsc index 86e39f6..44aa4fb 100644 --- a/userraw/maps/mp/perks/_perks.gsc +++ b/userraw/maps/mp/perks/_perks.gsc @@ -1,3 +1,19 @@ +/* + _perks modded + Author: INeedGames + Date: 09/22/2020 + Readds optional painkiller and one man army refills noobtubes. + + DVARS: + - combathighIsJuiced + false - painkiller is in the game + true - (default) replaces painkiller with juiced from mw3 + + - onemanarmyRefillsTubes + false - (default) One Man Army does not refill the gl attachment + true - it does +*/ + #include common_scripts\utility; #include maps\mp\_utility; #include maps\mp\gametypes\_hud_util; @@ -178,6 +194,12 @@ init() level.perkSetFuncs["specialty_tacticalinsertion"] = ::setTacticalInsertion; level.perkUnsetFuncs["specialty_tacticalinsertion"] = ::unsetTacticalInsertion; + setDvarIfUninitialized( "combathighIsJuiced", true ); + level.combathighIsJuiced = getDvarInt( "combathighIsJuiced" ); + + setDvarIfUninitialized( "onemanarmyRefillsTubes", false ); + level.onemanarmyRefillsTubes = getDvarInt( "onemanarmyRefillsTubes" ); + initPerkDvars(); level thread onPlayerConnect(); @@ -320,10 +342,10 @@ cac_modified_damage( victim, attacker, damage, meansofdeath, weapon, impactPoint } } - if ( ( victim.xpScaler == 2 && isDefined( attacker ) ) && ( isPlayer( attacker ) || attacker.classname == "scrip_vehicle" ) ) - damageAdd += 200; + //if ( ( victim.xpScaler == 2 && isDefined( attacker ) ) && ( isPlayer( attacker ) || attacker.classname == "scrip_vehicle" ) ) + // damageAdd += 200; - /*if ( victim _hasperk( "specialty_combathigh" ) ) + if ( victim _hasperk( "specialty_combathigh" ) && !level.combathighIsJuiced ) { if ( IsDefined( self.damageBlockedTotal ) && (!level.teamBased || (isDefined( attacker ) && isDefined( attacker.team ) && victim.team != attacker.team)) ) { @@ -351,7 +373,7 @@ cac_modified_damage( victim, attacker, damage, meansofdeath, weapon, impactPoint break; } } - }*/ + } return int( damage + damageAdd ); }