diff --git a/iw4x/iw4x_00/maps/mp/gametypes/_gamescore.gsc b/iw4x/iw4x_00/maps/mp/gametypes/_gamescore.gsc new file mode 100644 index 0000000..f149b35 --- /dev/null +++ b/iw4x/iw4x_00/maps/mp/gametypes/_gamescore.gsc @@ -0,0 +1,416 @@ +#include maps\mp\_utility; +#include maps\mp\gametypes\_hud_util; +#include common_scripts\utility; + + +getHighestScoringPlayer() +{ + updatePlacement(); + + if ( !level.placement["all"].size ) + return ( undefined ); + else + return ( level.placement["all"][0] ); +} + + +getLosingPlayers() +{ + updatePlacement(); + + players = level.placement["all"]; + losingPlayers = []; + + foreach ( player in players ) + { + if ( player == level.placement["all"][0] ) + continue; + + losingPlayers[losingPlayers.size] = player; + } + + return losingPlayers; +} + + +givePlayerScore( event, player, victim, overridePointsPopup ) +{ + if ( isDefined( level.nukeIncoming ) ) + return; + + if ( !isDefined( overridePointsPopup ) ) + overridePointsPopup = false; + + score = player.pers["score"]; + onPlayerScore( event, player, victim ); + + if ( score == player.pers["score"] ) + return; + + if ( !player rankingEnabled() && !level.hardcoreMode && !overridePointsPopup ) + player thread maps\mp\gametypes\_rank::scorePopup( (player.pers["score"] - score), false, (0.85,0.85,0.85), 0 ); + + player maps\mp\gametypes\_persistence::statAdd( "score", (player.pers["score"] - score) ); + + player.score = player.pers["score"]; + player maps\mp\gametypes\_persistence::statSetChild( "round", "score", player.score ); + + if ( !level.teambased ) + thread sendUpdatedDMScores(); + + player maps\mp\gametypes\_gamelogic::checkPlayerScoreLimitSoon(); + scoreEndedMatch = player maps\mp\gametypes\_gamelogic::checkScoreLimit(); + + if ( scoreEndedMatch && event == "kill" ) + player.finalKill = true; +} + + +onPlayerScore( event, player, victim ) +{ + score = maps\mp\gametypes\_rank::getScoreInfoValue( event ); + + assert( isDefined( score ) ); + + player.pers["score"] += score * level.objectivePointsMod; +} + + +// Seems to only be used for reducing a player's score due to suicide +_setPlayerScore( player, score ) +{ + if ( score == player.pers["score"] ) + return; + + player.pers["score"] = score; + player.score = player.pers["score"]; + + player thread maps\mp\gametypes\_gamelogic::checkScoreLimit(); +} + + +_getPlayerScore( player ) +{ + return player.pers["score"]; +} + + +giveTeamScoreForObjective( team, score ) +{ + if ( isDefined( level.nukeIncoming ) ) + return; + + score *= level.objectivePointsMod; + + teamScore = game["teamScores"][team]; + + otherTeam = level.otherTeam[team]; + + if ( game["teamScores"][team] > game["teamScores"][otherTeam] ) + level.wasWinning = team; + else if ( game["teamScores"][otherTeam] > game["teamScores"][team] ) + level.wasWinning = otherTeam; + + _setTeamScore( team, _getTeamScore( team ) + score ); + + isWinning = "none"; + if ( game["teamScores"][team] > game["teamScores"][otherTeam] ) + isWinning = team; + else if ( game["teamScores"][otherTeam] > game["teamScores"][team] ) + isWinning = otherTeam; + + if ( !level.splitScreen && isWinning != "none" && isWinning != level.wasWinning && getTime() - level.lastStatusTime > 5000 && getScoreLimit() != 1 ) + { + level.lastStatusTime = getTime(); + leaderDialog( "lead_taken", isWinning, "status" ); + if ( level.wasWinning != "none") + leaderDialog( "lead_lost", level.wasWinning, "status" ); + } + + if ( isWinning != "none" ) + level.wasWinning = isWinning; +} + + +getWinningTeam() +{ + if ( game["teamScores"]["allies"] > game["teamScores"]["axis"] ) + return ( "allies" ); + else if ( game["teamScores"]["allies"] < game["teamScores"]["axis"] ) + return ( "axis" ); + + return ( "none" ); +} + +_setTeamScore( team, teamScore ) +{ + if ( teamScore == game["teamScores"][team] ) + return; + + if ( isDefined( level.nukeIncoming ) ) + return; + + game["teamScores"][team] = teamScore; + + updateTeamScore( team ); + + if ( game["status"] == "overtime" ) + thread maps\mp\gametypes\_gamelogic::onScoreLimit(); + else + { + thread maps\mp\gametypes\_gamelogic::checkTeamScoreLimitSoon( team ); + thread maps\mp\gametypes\_gamelogic::checkScoreLimit(); + } +} + + +updateTeamScore( team ) +{ + assert( level.teamBased ); + + teamScore = 0; + if ( !isRoundBased() || !isObjectiveBased() ) + teamScore = _getTeamScore( team ); + else + teamScore = game["roundsWon"][team]; + + setTeamScore( team, teamScore ); + + //thread sendUpdatedTeamScores(); +} + + +_getTeamScore( team ) +{ + return game["teamScores"][team]; +} + + +sendUpdatedTeamScores() +{ + level notify("updating_scores"); + level endon("updating_scores"); + wait .05; + + WaitTillSlowProcessAllowed(); + + foreach ( player in level.players ) + player updateScores(); +} + +sendUpdatedDMScores() +{ + level notify("updating_dm_scores"); + level endon("updating_dm_scores"); + wait .05; + + WaitTillSlowProcessAllowed(); + + for ( i = 0; i < level.players.size; i++ ) + { + level.players[i] updateDMScores(); + level.players[i].updatedDMScores = true; + } +} + + +removeDisconnectedPlayerFromPlacement() +{ + offset = 0; + numPlayers = level.placement["all"].size; + found = false; + for ( i = 0; i < numPlayers; i++ ) + { + if ( level.placement["all"][i] == self ) + found = true; + + if ( found ) + level.placement["all"][i] = level.placement["all"][ i + 1 ]; + } + if ( !found ) + return; + + level.placement["all"][ numPlayers - 1 ] = undefined; + assert( level.placement["all"].size == numPlayers - 1 ); + + if ( level.teamBased ) + { + updateTeamPlacement(); + return; + } + + numPlayers = level.placement["all"].size; + for ( i = 0; i < numPlayers; i++ ) + { + player = level.placement["all"][i]; + player notify( "update_outcome" ); + } + +} + +updatePlacement() +{ + prof_begin("updatePlacement"); + + placementAll = []; + foreach ( player in level.players ) + { + if ( isDefined( player.connectedPostGame ) || (player.pers["team"] != "allies" && player.pers["team"] != "axis") ) + continue; + + placementAll[placementAll.size] = player; + } + + for ( i = 1; i < placementAll.size; i++ ) + { + player = placementAll[i]; + playerScore = player.score; +// for ( j = i - 1; j >= 0 && (player.score > placementAll[j].score || (player.score == placementAll[j].score && player.deaths < placementAll[j].deaths)); j-- ) + for ( j = i - 1; j >= 0 && getBetterPlayer( player, placementAll[j] ) == player; j-- ) + placementAll[j + 1] = placementAll[j]; + placementAll[j + 1] = player; + } + + level.placement["all"] = placementAll; + + if ( level.teamBased ) + updateTeamPlacement(); + + prof_end("updatePlacement"); +} + + +getBetterPlayer( playerA, playerB ) +{ + if ( playerA.score > playerB.score ) + return playerA; + + if ( playerB.score > playerA.score ) + return playerB; + + if ( playerA.deaths < playerB.deaths ) + return playerA; + + if ( playerB.deaths < playerA.deaths ) + return playerB; + + // TODO: more metrics for getting the better player + + if ( cointoss() ) + return playerA; + else + return playerB; +} + + +updateTeamPlacement() +{ + placement["allies"] = []; + placement["axis"] = []; + placement["spectator"] = []; + + assert( level.teamBased ); + + placementAll = level.placement["all"]; + placementAllSize = placementAll.size; + + for ( i = 0; i < placementAllSize; i++ ) + { + player = placementAll[i]; + team = player.pers["team"]; + + placement[team][ placement[team].size ] = player; + } + + level.placement["allies"] = placement["allies"]; + level.placement["axis"] = placement["axis"]; +} + + +initialDMScoreUpdate() +{ + // the first time we call updateDMScores on a player, we have to send them the whole scoreboard. + // by calling updateDMScores on each player one at a time, + // we can avoid having to send the entire scoreboard to every single player + // the first time someone kills someone else. + wait .2; + numSent = 0; + while(1) + { + didAny = false; + + players = level.players; + for ( i = 0; i < players.size; i++ ) + { + player = players[i]; + + if ( !isdefined( player ) ) + continue; + + if ( isdefined( player.updatedDMScores ) ) + continue; + + player.updatedDMScores = true; + player updateDMScores(); + + didAny = true; + wait .5; + } + + if ( !didAny ) + wait 3; // let more players connect + } +} + + +processAssist( killedplayer ) +{ + self endon("disconnect"); + killedplayer endon("disconnect"); + + wait .05; // don't ever run on the same frame as the playerkilled callback. + WaitTillSlowProcessAllowed(); + + if ( self.pers["team"] != "axis" && self.pers["team"] != "allies" ) + return; + + if ( self.pers["team"] == killedplayer.pers["team"] ) + return; + + self thread [[level.onXPEvent]]( "assist" ); + self incPersStat( "assists", 1 ); + self.assists = self getPersStat( "assists" ); + self incPlayerStat( "assists", 1 ); + + givePlayerScore( "assist", self, killedplayer ); + self thread giveAdrenaline( "assist" ); + + self thread maps\mp\gametypes\_missions::playerAssist(); +} + +processShieldAssist( killedPlayer ) +{ + self endon( "disconnect" ); + killedPlayer endon( "disconnect" ); + + wait .05; // don't ever run on the same frame as the playerkilled callback. + WaitTillSlowProcessAllowed(); + + if ( self.pers["team"] != "axis" && self.pers["team"] != "allies" ) + return; + + if ( self.pers["team"] == killedplayer.pers["team"] ) + return; + + self thread [[level.onXPEvent]]( "assist" ); + self thread [[level.onXPEvent]]( "assist" ); + self incPersStat( "assists", 1 ); + self.assists = self getPersStat( "assists" ); + self incPlayerStat( "assists", 1 ); + + givePlayerScore( "assist", self, killedplayer ); + + self thread maps\mp\gametypes\_hud_message::SplashNotifyDelayed( "shield_assist" ); + + self thread maps\mp\gametypes\_missions::playerAssist(); +} \ No newline at end of file diff --git a/iw4x/iw4x_00/maps/mp/gametypes/_rank.gsc b/iw4x/iw4x_00/maps/mp/gametypes/_rank.gsc new file mode 100644 index 0000000..7b42ff4 --- /dev/null +++ b/iw4x/iw4x_00/maps/mp/gametypes/_rank.gsc @@ -0,0 +1,763 @@ +#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.hud_xpEventPopup = player createXpEventPopup(); + + 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; +} + +createXpEventPopup() +{ + hud_xpEventPopup = newClientHudElem( self ); + hud_xpEventPopup.children = []; + hud_xpEventPopup.horzAlign = "center"; + hud_xpEventPopup.vertAlign = "middle"; + hud_xpEventPopup.alignX = "center"; + hud_xpEventPopup.alignY = "middle"; + hud_xpEventPopup.x = 55; + hud_xpEventPopup.y = -35; + hud_xpEventPopup.font = "hudbig"; + hud_xpEventPopup.fontscale = 0.65; + hud_xpEventPopup.archived = false; + hud_xpEventPopup.color = (0.5,0.5,0.5); + hud_xpEventPopup.sort = 10000; + hud_xpEventPopup.elemType = "msgText"; + hud_xpEventPopup maps\mp\gametypes\_hud::fontPulseInit( 3.0 ); + return hud_xpEventPopup; +} + +xpEventPopupFinalize( event, hudColor, glowAlpha ) +{ + self endon( "disconnect" ); + self endon( "joined_team" ); + self endon( "joined_spectators" ); + + self notify( "xpEventPopup" ); + self endon( "xpEventPopup" ); + + if ( level.hardcoremode ) + return; + + wait ( 0.05 ); + + if ( !isDefined( hudColor ) ) + hudColor = (1,1,0.5); + if ( !isDefined( glowAlpha ) ) + glowAlpha = 0; + + if ( !isDefined( self ) ) + return; + + self.hud_xpEventPopup.color = hudColor; + self.hud_xpEventPopup.glowColor = hudColor; + self.hud_xpEventPopup.glowAlpha = glowAlpha; + + self.hud_xpEventPopup setText(event); + self.hud_xpEventPopup.alpha = 0.85; + + wait ( 1.0 ); + + if ( !isDefined( self ) ) + return; + + self.hud_xpEventPopup fadeOverTime( 0.75 ); + self.hud_xpEventPopup.alpha = 0; + self notify( "PopComplete" ); +} + +xpEventPopupTerminate() +{ + self endon( "PopComplete" ); + + waittill_any( "joined_team", "joined_spectators" ); + + self.hud_xpEventPopup fadeOverTime( 0.05 ); + self.hud_xpEventPopup .alpha = 0; +} + +xpEventPopup( event, hudColor, glowAlpha ) +{ + thread xpEventPopupFinalize( event, hudColor, glowAlpha ); + thread xpEventPopupTerminate(); +} + +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 ); +} \ No newline at end of file diff --git a/iw4x/iw4x_00/maps/mp/gametypes/conf.gsc b/iw4x/iw4x_00/maps/mp/gametypes/conf.gsc index b67c725..8ecb0ea 100644 --- a/iw4x/iw4x_00/maps/mp/gametypes/conf.gsc +++ b/iw4x/iw4x_00/maps/mp/gametypes/conf.gsc @@ -103,8 +103,6 @@ onStartGameType() allowed[0] = level.gameType; maps\mp\gametypes\_gameobjects::main(allowed); - - level thread onPlayerConnect(); // Needed since we need to draw the hud. } @@ -129,16 +127,6 @@ getSpawnPoint() } -onPlayerConnect() -{ - for(;;) - { - level waittill( "connected", player ); - player.hud_EventPopup = player createEventPopup(); - } -} - - onNormalDeath( victim, attacker, lifeId ) { level thread spawnDogTags( victim, attacker ); @@ -259,7 +247,7 @@ onUse( player ) // tell the attacker their kill was denied if ( isDefined( self.attacker ) ) - self.attacker thread EventPopup( &"SPLASHES_DENIED_KILL", ( 1,0.5,0.5) ); + self.attacker thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_DENIED_KILL", ( 1,0.5,0.5) ); } // enemy pickup else @@ -290,8 +278,8 @@ onPickup( event, splash ) level endon( "game_ended" ); self endon( "disconnect" ); - self thread EventPopup( splash ); - maps\mp\gametypes\_gamescore::givePlayerScore( event, self ); + self thread maps\mp\gametypes\_rank::xpEventPopup( splash ); + maps\mp\gametypes\_gamescore::givePlayerScore( event, self, undefined, true ); self thread maps\mp\gametypes\_rank::giveRankXP( event ); } @@ -386,7 +374,7 @@ clearOnVictimDisconnect( victim ) // tell the attacker their kill was denied if ( isDefined( level.dogtags[guid].attacker ) ) - level.dogtags[guid].attacker thread EventPopup( &"SPLASHES_DENIED_KILL", (1,0.5,0.5) ); + level.dogtags[guid].attacker thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_DENIED_KILL", (1,0.5,0.5) ); // play vanish effect, reset, and wait for reset to process PlayFx( level.conf_fx["vanish"], level.dogtags[guid].curOrigin ); @@ -407,53 +395,4 @@ clearOnVictimDisconnect( victim ) level.dogtags[guid] = undefined; } } -} - - -createEventPopup() -{ - hud_EventPopup = newClientHudElem( self ); - hud_EventPopup.children = []; - hud_EventPopup.horzAlign = "center"; - hud_EventPopup.vertAlign = "middle"; - hud_EventPopup.alignX = "center"; - hud_EventPopup.alignY = "middle"; - hud_EventPopup.x = 50; - hud_EventPopup.y = -35; - hud_EventPopup.font = "hudbig"; - hud_EventPopup.fontscale = 0.65; - hud_EventPopup.archived = false; - hud_EventPopup.color = (0.5,0.5,0.5); - hud_EventPopup.sort = 10000; - hud_EventPopup.elemType = "msgText"; - hud_EventPopup maps\mp\gametypes\_hud::fontPulseInit( 3.0 ); - return hud_EventPopup; -} - - -EventPopup( event, hudColor, glowAlpha ) -{ - self endon( "disconnect" ); - - self notify( "EventPopup" ); - self endon( "EventPopup" ); - - wait ( 0.05 ); - - if ( !isDefined( hudColor ) ) - hudColor = (1,1,0.5); - if ( !isDefined( glowAlpha ) ) - glowAlpha = 0; - - self.hud_EventPopup.color = hudColor; - self.hud_EventPopup.glowColor = hudColor; - self.hud_EventPopup.glowAlpha = glowAlpha; - - self.hud_EventPopup setText(event); - self.hud_EventPopup.alpha = 0.85; - - wait ( 1.0 ); - - self.hud_EventPopup fadeOverTime( 0.75 ); - self.hud_EventPopup.alpha = 0; } \ No newline at end of file diff --git a/iw4x/iw4x_00/maps/mp/gametypes/gun.gsc b/iw4x/iw4x_00/maps/mp/gametypes/gun.gsc index 1fa528b..eb0669b 100644 --- a/iw4x/iw4x_00/maps/mp/gametypes/gun.gsc +++ b/iw4x/iw4x_00/maps/mp/gametypes/gun.gsc @@ -35,9 +35,9 @@ main() // must be done before scorelimit is set setGuns(); + registerTimeLimitDvar( level.gameType, 10 ); scoreLimit = level.gun_guns.size; - registerTimeLimitDvar( level.gameType, 10, 0, 20 ); - registerScoreLimitDvar( level.gameType, scoreLimit ); + SetDvar( "scr_gun_scorelimit", scoreLimit ); registerRoundLimitDvar( level.gameType, 1, 0, 10 ); registerWinLimitDvar( level.gameType, 1, 0, 10 ); registerNumLivesDvar( level.gameType, 0, 0, 10 ); @@ -139,8 +139,6 @@ onPlayerConnect() player.gunGamePrevGunIndex = 0; player initGunHUD(); - player.hud_xpEventPopup = player createXpEventPopup(); - player thread refillAmmo(); player thread refillSingleCountAmmo(); @@ -210,7 +208,7 @@ onPlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHi if ( self.gunGamePrevGunIndex > self.gunGameGunIndex ) { - self thread xpEventPopup( &"SPLASHES_DROPPED_GUN_RANK" ); + self thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_DROPPED_GUN_RANK" ); maps\mp\gametypes\_gamescore::givePlayerScore( "dropped_gun_score", self, undefined, true, true ); } @@ -218,7 +216,7 @@ onPlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHi { if ( self.gunGamePrevGunIndex ) { - attacker thread xpEventPopup( &"SPLASHES_DROPPED_ENEMY_GUN_RANK" ); + attacker thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_DROPPED_ENEMY_GUN_RANK" ); attacker thread maps\mp\gametypes\_rank::giveRankXP( "dropped_enemy_gun_rank" ); } } @@ -251,7 +249,7 @@ onPlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHi if ( attacker.gunGameGunIndex < level.gun_guns.size ) { - attacker thread xpEventPopup( &"SPLASHES_GAINED_GUN_RANK" ); + attacker thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_GAINED_GUN_RANK" ); attacker playLocalSound( "mp_war_objective_taken" ); attacker giveNextGun(); } @@ -288,12 +286,12 @@ giveNextGun( doSetSpawnWeapon ) if ( self.gunGamePrevGunIndex > self.gunGameGunIndex ) { // we dropped :( - self thread xpEventPopup( &"SPLASHES_DROPPED_GUN_RANK" ); + self thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_DROPPED_GUN_RANK" ); } else if ( self.gunGamePrevGunIndex < self.gunGameGunIndex ) { // we gained :) - self thread xpEventPopup( &"SPLASHES_GAINED_GUN_RANK" ); + self thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_GAINED_GUN_RANK" ); } self.gunGamePrevGunIndex = self.gunGameGunIndex; @@ -575,53 +573,4 @@ setSpecialLoadout() // FFA games don't have teams, but players are allowed to choose team on the way in // just for character model and announcer voice variety. Same loadout for both. level.gun_loadouts["allies"] = level.gun_loadouts["axis"]; -} - -createXpEventPopup() -{ - hud_xpEventPopup = newClientHudElem( self ); - hud_xpEventPopup.children = []; - hud_xpEventPopup.horzAlign = "center"; - hud_xpEventPopup.vertAlign = "middle"; - hud_xpEventPopup.alignX = "center"; - hud_xpEventPopup.alignY = "middle"; - hud_xpEventPopup.x = 55; - hud_xpEventPopup.y = -35; - hud_xpEventPopup.font = "hudbig"; - hud_xpEventPopup.fontscale = 0.65; - hud_xpEventPopup.archived = false; - hud_xpEventPopup.color = (0.5,0.5,0.5); - hud_xpEventPopup.sort = 10000; - hud_xpEventPopup.elemType = "msgText"; - hud_xpEventPopup maps\mp\gametypes\_hud::fontPulseInit( 3.0 ); - return hud_xpEventPopup; -} - -xpEventPopup( event, hudColor, glowAlpha ) -{ - self endon( "disconnect" ); - self endon( "joined_team" ); - self endon( "joined_spectators" ); - - self notify( "xpEventPopup" ); - self endon( "xpEventPopup" ); - - wait ( 0.05 ); - - if ( !isDefined( hudColor ) ) - hudColor = (1,1,0.5); - if ( !isDefined( glowAlpha ) ) - glowAlpha = 0; - - self.hud_xpEventPopup.color = hudColor; - self.hud_xpEventPopup.glowColor = hudColor; - self.hud_xpEventPopup.glowAlpha = glowAlpha; - - self.hud_xpEventPopup setText(event); - self.hud_xpEventPopup.alpha = 0.85; - - wait ( 1.0 ); - - self.hud_xpEventPopup fadeOverTime( 0.75 ); - self.hud_xpEventPopup.alpha = 0; } \ No newline at end of file diff --git a/iw4x/iw4x_00/maps/mp/gametypes/infect.gsc b/iw4x/iw4x_00/maps/mp/gametypes/infect.gsc index 1c4e962..47e92fc 100644 --- a/iw4x/iw4x_00/maps/mp/gametypes/infect.gsc +++ b/iw4x/iw4x_00/maps/mp/gametypes/infect.gsc @@ -122,7 +122,6 @@ onPlayerConnect() player.infect_firstSpawn = true; player.infected_Rejoined = false; player.infect_JoinedAtStart = true; - player.hud_EventPopup = player createXpEventPopup(); if( gameFlag( "prematch_done" ) ) { @@ -300,7 +299,7 @@ setInfectedMsg() if ( isDefined( self.isInitialInfected ) ) { - thread xpEventPopup( &"SPLASHES_FIRST_MERCENARY", ( 1, 0, 0 ), 0.3 ); + thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_FIRST_MERCENARY", ( 1, 0, 0 ), 0.3 ); } else if ( isDefined( self.changingToRegularInfected ) ) { @@ -308,14 +307,14 @@ setInfectedMsg() if ( isDefined( self.changingToRegularInfectedByKill ) ) { self.changingToRegularInfectedByKill = undefined; - thread xpEventPopup( &"SPLASHES_FIRSTBLOOD" ); + thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_FIRSTBLOOD" ); maps\mp\gametypes\_gamescore::givePlayerScore( "first_draft", self ); thread maps\mp\gametypes\_rank::giveRankXP( "first_draft" ); } } else { - thread xpEventPopup( &"SPLASHES_DRAFTED", ( 1, 0, 0 ), 0.3 ); + thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_DRAFTED", ( 1, 0, 0 ), 0.3 ); } } @@ -527,7 +526,7 @@ onPlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHi else { // regular attacker reward - attacker thread xpEventPopup( &"SPLASHES_DRAFTED" ); + attacker thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_DRAFTED" ); maps\mp\gametypes\_gamescore::givePlayerScore( "draft_rogue", attacker, self, true ); attacker thread maps\mp\gametypes\_rank::giveRankXP( "draft_rogue" ); } @@ -551,8 +550,8 @@ onPlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHi if ( player.team == "allies" && player != self && distance( player.infect_spawnPos, player.origin ) > 32 ) { - player thread xpEventPopup( &"SPLASHES_SURVIVOR" ); - maps\mp\gametypes\_gamescore::givePlayerScore( "survivor", player, undefined, 1 ); + player thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_SURVIVOR" ); + maps\mp\gametypes\_gamescore::givePlayerScore( "survivor", player, undefined, true ); player thread maps\mp\gametypes\_rank::giveRankXP( "survivor" ); } } @@ -582,12 +581,12 @@ onFinalSurvivor() if ( player.team == "allies" ) { - player thread xpEventPopup( &"SPLASHES_FINAL_ROGUE" ); + player thread maps\mp\gametypes\_rank::xpEventPopup( &"SPLASHES_FINAL_ROGUE" ); if ( !level.infect_awardedFinalSurvivor ) { if ( player.gameModeJoinedAtStart && isDefined( player.infect_spawnPos ) && distance( player.infect_spawnPos, player.origin ) > 32 ) { - maps\mp\gametypes\_gamescore::givePlayerScore( "final_rogue", player, undefined, 1 ); + maps\mp\gametypes\_gamescore::givePlayerScore( "final_rogue", player, undefined, true ); player thread maps\mp\gametypes\_rank::giveRankXP( "final_rogue" ); } @@ -837,79 +836,4 @@ setSpecialLoadouts() level.infect_loadouts["allies"]["loadoutPerk2"] = "specialty_lightweight"; level.infect_loadouts["allies"]["loadoutPerk3"] = "specialty_heartbreaker"; level.infect_loadouts["allies"]["loadoutDeathstreak"] = "specialty_null"; -} - -createXpEventPopup() -{ - hud_xpEventPopup = newClientHudElem( self ); - hud_xpEventPopup.children = []; - hud_xpEventPopup.horzAlign = "center"; - hud_xpEventPopup.vertAlign = "middle"; - hud_xpEventPopup.alignX = "center"; - hud_xpEventPopup.alignY = "middle"; - hud_xpEventPopup.x = 55; - hud_xpEventPopup.y = -35; - hud_xpEventPopup.font = "hudbig"; - hud_xpEventPopup.fontscale = 0.65; - hud_xpEventPopup.archived = false; - hud_xpEventPopup.color = (0.5,0.5,0.5); - hud_xpEventPopup.sort = 10000; - hud_xpEventPopup.elemType = "msgText"; - hud_xpEventPopup maps\mp\gametypes\_hud::fontPulseInit( 3.0 ); - return hud_xpEventPopup; -} - -xpEventPopupFinalize( event, hudColor, glowAlpha ) -{ - self endon( "disconnect" ); - self endon( "joined_team" ); - self endon( "joined_spectators" ); - - self notify( "xpEventPopup" ); - self endon( "xpEventPopup" ); - - if ( level.hardcoremode ) - return; - - wait ( 0.05 ); - - if ( !isDefined( hudColor ) ) - hudColor = (1,1,0.5); - if ( !isDefined( glowAlpha ) ) - glowAlpha = 0; - - if ( !isDefined( self ) ) - return; - - self.hud_xpEventPopup.color = hudColor; - self.hud_xpEventPopup.glowColor = hudColor; - self.hud_xpEventPopup.glowAlpha = glowAlpha; - - self.hud_xpEventPopup setText(event); - self.hud_xpEventPopup.alpha = 0.85; - - wait ( 1.0 ); - - if ( !isDefined( self ) ) - return; - - self.hud_xpEventPopup fadeOverTime( 0.75 ); - self.hud_xpEventPopup.alpha = 0; - self notify( "PopComplete" ); -} - -xpEventPopupTerminate() -{ - self endon( "PopComplete" ); - - waittill_any( "joined_team", "joined_spectators" ); - - self.hud_xpEventPopup fadeOverTime( 0.05 ); - self.hud_xpEventPopup .alpha = 0; -} - -xpEventPopup( event, hudColor, glowAlpha ) -{ - thread xpEventPopupFinalize( event, hudColor, glowAlpha ); - thread xpEventPopupTerminate(); } \ No newline at end of file