diff --git a/iw4x/iw4x_00/images/dogtags_col.iwi b/iw4x/iw4x_00/images/dogtags_col.iwi new file mode 100644 index 0000000..106ed24 Binary files /dev/null and b/iw4x/iw4x_00/images/dogtags_col.iwi differ diff --git a/iw4x/iw4x_00/images/dogtags_nml.iwi b/iw4x/iw4x_00/images/dogtags_nml.iwi new file mode 100644 index 0000000..c13944f Binary files /dev/null and b/iw4x/iw4x_00/images/dogtags_nml.iwi differ diff --git a/iw4x/iw4x_00/images/waypoint_dogtags.iwi b/iw4x/iw4x_00/images/waypoint_dogtags.iwi index decda32..4b57ddf 100644 Binary files a/iw4x/iw4x_00/images/waypoint_dogtags.iwi and b/iw4x/iw4x_00/images/waypoint_dogtags.iwi differ diff --git a/iw4x/iw4x_00/images/~dogtags_spc-rgb&dogtags_cos-l-67.iwi b/iw4x/iw4x_00/images/~dogtags_spc-rgb&dogtags_cos-l-67.iwi new file mode 100644 index 0000000..47dcae8 Binary files /dev/null and b/iw4x/iw4x_00/images/~dogtags_spc-rgb&dogtags_cos-l-67.iwi differ diff --git a/iw4x/iw4x_00/localizedstrings/iw4x_english.str b/iw4x/iw4x_00/localizedstrings/iw4x_english.str index dbac326..855aeb7 100644 --- a/iw4x/iw4x_00/localizedstrings/iw4x_english.str +++ b/iw4x/iw4x_00/localizedstrings/iw4x_english.str @@ -16,6 +16,21 @@ LANG_ENGLISH "GUN GAME" REFERENCE MENU_GUNGAME_DESC LANG_ENGLISH "Be the first to dominate with every gun." +REFERENCE SPLASHES_DROPPED_ENEMY_GUN_RANK +LANG_ENGLISH "Dropped Enemy Gun Rank!" + +REFERENCE SPLASHES_DROPPED_GUN_RANK +LANG_ENGLISH "Dropped Gun Rank!" + +REFERENCE SPLASHES_GAINED_GUN_RANK +LANG_ENGLISH "Gained Gun Rank!" + +REFERENCE SPLASHES_TOP_GUN_RANK +LANG_ENGLISH "Top Gun Rank!" + +REFERENCE MP_WEAPON +LANG_ENGLISH "Weapon:" + REFERENCE MPUI_SHARPSHOOTER LANG_ENGLISH "Sharpshooter" @@ -40,11 +55,32 @@ LANG_ENGLISH "Kill Confirmed" REFERENCE MPUI_CONF_CAPS LANG_ENGLISH "KILL CONFIRMED" +REFERENCE CONF_KILL_CONFIRMED +LANG_ENGLISH "KILL CONFIRMED" + REFERENCE MENU_CONF LANG_ENGLISH "Recover Dog Tags to score for your team and deny enemy scores." -REFERENCE CONF_GAME_DESC -LANG_ENGLISH "Collect Dog Tags to win." +REFERENCE OBJECTIVES_CONF +LANG_ENGLISH "Recover Dog Tags for the win." + +REFERENCE OBJECTIVES_CONF_SCORE +LANG_ENGLISH "Recover Dog Tags to score for your team and deny enemy score. First team to &&1 wins." + +REFERENCE OBJECTIVES_CONF_HINT +LANG_ENGLISH "Recover Dog Tags for the win." + +REFERENCE SPLASHES_TAGS_RETRIEVED +LANG_ENGLISH "Got Your Tags!" + +REFERENCE SPLASHES_KILL_DENIED +LANG_ENGLISH "Kill Denied!" + +REFERENCE SPLASHES_DENIED_KILL +LANG_ENGLISH "Denied Kill!" + +REFERENCE SPLASHES_KILL_CONFIRMED +LANG_ENGLISH "Kill Confirmed!" REFERENCE MPUI_INF LANG_ENGLISH "Infected" @@ -55,35 +91,36 @@ LANG_ENGLISH "INFECTED" REFERENCE MENU_INF LANG_ENGLISH "Eliminated Survivors become Infected. Infect everyone, or survive the game to win." -REFERENCE INF_GAME_DESC +REFERENCE OBJECTIVES_INFECT LANG_ENGLISH "Eliminated Survivors become Infected. Infect everyone, or survive the game to win." -REFERENCE INF_WAIT_FOR_PLAYERS -LANG_ENGLISH "Waiting for more players..." +REFERENCE OBJECTIVES_INFECT_SCORE +LANG_ENGLISH "Survivors become Infected. Infect everyone, or survive the game to win." -REFERENCE INF_COUNTDOWN -LANG_ENGLISH "Infection countdown: " +REFERENCE OBJECTIVES_INFECT_HINT +LANG_ENGLISH "Watch your back." -REFERENCE INF_ALLIES_ELIM -LANG_ENGLISH "Survivors eliminated." +REFERENCE MP_DRAFT_STARTS_IN +LANG_ENGLISH "Infection countdown: &&1" -REFERENCE INF_GOT_INFECTED -LANG_ENGLISH "Infected!" - -REFERENCE INF_LAST_ALIVE -LANG_ENGLISH "Last Alive!" - -REFERENCE INF_SURVIVOR +REFERENCE SPLASHES_SURVIVOR LANG_ENGLISH "Survivor!" -REFERENCE CONF_PICKEDUP_TAGS -LANG_ENGLISH "RETREIVED TAGS" +REFERENCE SPLASHES_FIRST_MERCENARY +LANG_ENGLISH "First Infected!" -REFERENCE CONF_KILL_DENIED -LANG_ENGLISH "KILL DENIED" +REFERENCE SPLASHES_DRAFTED +LANG_ENGLISH "Infected!" + +REFERENCE SPLASHES_FINAL_ROGUE +LANG_ENGLISH "Final Survivor!" + +REFERENCE SPLASHES_GOT_DRAFTED +LANG_ENGLISH "Got Infected!" + +REFERENCE SPLASHES_DRAFTED_ROGUE +LANG_ENGLISH "Got Infected!" -REFERENCE CONF_KILL_CONFIRMED -LANG_ENGLISH "KILL CONFIRMED" REFERENCE MPUI_CRANKED LANG_ENGLISH "Cranked" diff --git a/iw4x/iw4x_00/maps/mp/gametypes/_gametypes.txt b/iw4x/iw4x_00/maps/mp/gametypes/_gametypes.txt new file mode 100644 index 0000000..bb66fb4 --- /dev/null +++ b/iw4x/iw4x_00/maps/mp/gametypes/_gametypes.txt @@ -0,0 +1,14 @@ +dm +dom +sd +sab +war +koth +oneflag +arena +dd +ctf +gtnw +conf +gun +infect \ 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 new file mode 100644 index 0000000..db8fda5 --- /dev/null +++ b/iw4x/iw4x_00/maps/mp/gametypes/conf.gsc @@ -0,0 +1,483 @@ +#include maps\mp\_utility; +#include maps\mp\gametypes\_hud_util; +#include common_scripts\utility; +/* + Confirmed Kill + Objective: Score points for your team by eliminating players on the opposing team. + Score bonus points for picking up dogtags from downed enemies. + Map ends: When one team reaches the score limit, or time limit is reached + Respawning: No wait / Near teammates + + Level requirementss + ------------------ + Spawnpoints: + classname mp_tdm_spawn + All players spawn from these. The spawnpoint chosen is dependent on the current locations of teammates and enemies + at the time of spawn. Players generally spawn behind their teammates relative to the direction of enemies. + + Spectator Spawnpoints: + classname mp_global_intermission + Spectators spawn from these and intermission is viewed from these positions. + Atleast one is required, any more and they are randomly chosen between. +*/ + + +main() +{ + if(getdvar("mapname") == "mp_background") + return; + + maps\mp\gametypes\_globallogic::init(); + maps\mp\gametypes\_callbacksetup::SetupCallbacks(); + maps\mp\gametypes\_globallogic::SetupCallbacks(); + + registerRoundSwitchDvar( level.gameType, 0, 0, 9 ); + registerTimeLimitDvar( level.gameType, 5, 0, 20 ); + registerScoreLimitDvar( level.gameType, 65, 0, 100 ); + registerRoundLimitDvar( level.gameType, 1, 0, 10 ); + registerWinLimitDvar( level.gameType, 1, 0, 10 ); + registerRoundSwitchDvar( level.gameType, 3, 0, 30 ); + registerNumLivesDvar( level.gameType, 0, 0, 10 ); + registerHalfTimeDvar( level.gameType, 0, 0, 1 ); + + level.teamBased = true; + level.onStartGameType = ::onStartGameType; + level.getSpawnPoint = ::getSpawnPoint; + level.onNormalDeath = ::onNormalDeath; + level.onPrecacheGameType = ::onPrecacheGameType; + + //game["dialog"]["gametype"] = "kill_confirmed"; + + //level.conf_vo["axis"] = "RU_1mc_kill_confirmed"; + //level.conf_vo["allies"] = "US_1mc_kill_confirmed"; + + level.conf_fx["vanish"] = loadFx( "impacts/small_snowhit" ); +} + +onPrecacheGameType() +{ + precachemodel( "prop_dogtags_friend" ); + precachemodel( "prop_dogtags_foe" ); + precacheshader( "waypoint_dogtags" ); +} + + +onStartGameType() +{ + setClientNameMode("auto_change"); + + if ( !isdefined( game["switchedsides"] ) ) + game["switchedsides"] = false; + + if ( game["switchedsides"] ) + { + oldAttackers = game["attackers"]; + oldDefenders = game["defenders"]; + game["attackers"] = oldDefenders; + game["defenders"] = oldAttackers; + } + + setObjectiveText( "allies", &"OBJECTIVES_CONF" ); + setObjectiveText( "axis", &"OBJECTIVES_CONF" ); + + setObjectiveScoreText( "allies", &"OBJECTIVES_CONF_SCORE" ); + setObjectiveScoreText( "axis", &"OBJECTIVES_CONF_SCORE" ); + + setObjectiveHintText( "allies", &"OBJECTIVES_CONF_HINT" ); + setObjectiveHintText( "axis", &"OBJECTIVES_CONF_HINT" ); + + level.spawnMins = ( 0, 0, 0 ); + level.spawnMaxs = ( 0, 0, 0 ); + maps\mp\gametypes\_spawnlogic::placeSpawnPoints( "mp_tdm_spawn_allies_start" ); + maps\mp\gametypes\_spawnlogic::placeSpawnPoints( "mp_tdm_spawn_axis_start" ); + maps\mp\gametypes\_spawnlogic::addSpawnPoints( "allies", "mp_tdm_spawn" ); + maps\mp\gametypes\_spawnlogic::addSpawnPoints( "axis", "mp_tdm_spawn" ); + + level.mapCenter = maps\mp\gametypes\_spawnlogic::findBoxCenter( level.spawnMins, level.spawnMaxs ); + setMapCenter( level.mapCenter ); + + maps\mp\gametypes\_rank::registerScoreInfo( "kill", 50 ); + maps\mp\gametypes\_rank::registerScoreInfo( "kill_confirmed", 50 ); + maps\mp\gametypes\_rank::registerScoreInfo( "kill_denied", 50 ); + maps\mp\gametypes\_rank::registerScoreInfo( "tags_retrieved", 250 ); + + level.dogtags = []; + + allowed[0] = level.gameType; + + maps\mp\gametypes\_gameobjects::main(allowed); + + level thread onPlayerConnect(); // Needed since we need to draw the hud. +} + + +getSpawnPoint() +{ + spawnteam = self.pers["team"]; + if ( game["switchedsides"] ) + spawnteam = getOtherTeam( spawnteam ); + + if ( level.inGracePeriod ) + { + spawnPoints = maps\mp\gametypes\_spawnlogic::getSpawnpointArray( "mp_tdm_spawn_" + spawnteam + "_start" ); + spawnPoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_Random( spawnPoints ); + } + else + { + spawnPoints = maps\mp\gametypes\_spawnlogic::getTeamSpawnPoints( spawnteam ); + spawnPoint = maps\mp\gametypes\_spawnlogic::getSpawnpoint_NearTeam( spawnPoints ); + } + + return spawnPoint; +} + + +onPlayerConnect() +{ + for(;;) + { + level waittill( "connected", player ); + player.hud_EventPopup = player createEventPopup(); + } +} + + +onNormalDeath( victim, attacker, lifeId ) +{ + level thread spawnDogTags( victim, attacker ); + + if ( game["state"] == "postgame" && game["teamScores"][attacker.team] > game["teamScores"][level.otherTeam[attacker.team]] ) + attacker.finalKill = true; +} + + +spawnDogTags( victim, attacker ) +{ + if ( isDefined( level.dogtags[victim.guid] ) ) + { + PlayFx( level.conf_fx["vanish"], level.dogtags[victim.guid].curOrigin ); + level.dogtags[victim.guid] notify( "reset" ); + } + else + { + visuals[0] = spawn( "script_model", (0,0,0) ); + visuals[0] setModel( "prop_dogtags_foe" ); + visuals[1] = spawn( "script_model", (0,0,0) ); + visuals[1] setModel( "prop_dogtags_friend" ); + + trigger = spawn( "trigger_radius", (0,0,0), 0, 32, 32 ); + + level.dogtags[victim.guid] = maps\mp\gametypes\_gameobjects::createUseObject( "any", trigger, visuals, (0,0,16) ); + + // we don't need these + _objective_delete( level.dogtags[victim.guid].objIDAllies ); + _objective_delete( level.dogtags[victim.guid].objIDAxis ); + maps\mp\gametypes\_objpoints::deleteObjPoint( level.dogtags[victim.guid].objPoints["allies"] ); + maps\mp\gametypes\_objpoints::deleteObjPoint( level.dogtags[victim.guid].objPoints["axis"] ); + + level.dogtags[victim.guid] maps\mp\gametypes\_gameobjects::setUseTime( 0 ); + level.dogtags[victim.guid].onUse = ::onUse; + level.dogtags[victim.guid].victim = victim; + level.dogtags[victim.guid].victimTeam = victim.pers["team"]; + + level.dogtags[victim.guid].objId = maps\mp\gametypes\_gameobjects::getNextObjID(); + objective_add( level.dogtags[victim.guid].objId, "invisible", (0,0,0) ); + objective_icon( level.dogtags[victim.guid].objId, "waypoint_dogtags" ); + + level thread clearOnVictimDisconnect( victim ); + victim thread tagTeamUpdater( level.dogtags[victim.guid] ); + } + + pos = victim.origin + (0,0,14); + level.dogtags[victim.guid].curOrigin = pos; + level.dogtags[victim.guid].trigger.origin = pos; + level.dogtags[victim.guid].visuals[0].origin = pos; + level.dogtags[victim.guid].visuals[1].origin = pos; + + level.dogtags[victim.guid] maps\mp\gametypes\_gameobjects::allowUse( "any" ); + + level.dogtags[victim.guid].visuals[0] thread showToTeam( level.dogtags[victim.guid], getOtherTeam( victim.pers["team"] ) ); + level.dogtags[victim.guid].visuals[1] thread showToTeam( level.dogtags[victim.guid], victim.pers["team"] ); + + level.dogtags[victim.guid].attacker = attacker; + //level.dogtags[victim.guid] thread timeOut( victim ); + + objective_position( level.dogtags[victim.guid].objId, pos ); + objective_state( level.dogtags[victim.guid].objId, "active" ); + //objective_player( level.dogtags[victim.guid].objId, attacker getEntityNumber() ); + + playSoundAtPos( pos, "mp_killconfirm_tags_drop" ); + + level.dogtags[victim.guid] thread bounce(); +} + + +showToTeam( gameObject, team ) +{ + gameObject endon ( "death" ); + gameObject endon( "reset" ); + + self hide(); + + foreach ( player in level.players ) + { + if( player.team == team ) + self ShowToPlayer( player ); + } + + for ( ;; ) + { + level waittill ( "joined_team" ); + + self hide(); + foreach ( player in level.players ) + { + if ( player.team == team ) + self ShowToPlayer( player ); + + if ( gameObject.victimTeam == player.team && player == gameObject.attacker ) + objective_state( gameObject.objId, "invisible" ); + } + } +} + + +onUse( player ) +{ + pos = self.curOrigin; + + self notify( "reset" ); + self.visuals[0] hide(); + self.visuals[1] hide(); + self.curOrigin = (0,0,1000); + self.trigger.origin = (0,0,1000); + self.visuals[0].origin = (0,0,1000); + self.visuals[1].origin = (0,0,1000); + self maps\mp\gametypes\_gameobjects::allowUse( "none" ); + objective_state( self.objId, "invisible" ); + + // friendly pickup + if ( player.pers["team"] == self.victimTeam ) + { + self.trigger playSound( "mp_killconfirm_tags_deny" ); + + player incPlayerStat( "killsdenied", 1 ); + player incPersStat( "denied", 1 ); + player maps\mp\gametypes\_persistence::statSetChild( "round", "denied", player.pers["denied"] ); + + if ( self.victim == player ) + { + event = "tags_retrieved"; + splash = &"SPLASHES_TAGS_RETRIEVED"; + } + else + { + event = "kill_denied"; + splash = &"SPLASHES_KILL_DENIED"; + } + + // tell the attacker their kill was denied + if ( isDefined( self.attacker ) ) + self.attacker thread EventPopup( &"SPLASHES_DENIED_KILL", (1,0.5,0.5) ); + } + // enemy pickup + else + { + self.trigger playSound( "mp_killconfirm_tags_pickup" ); + + event = "kill_confirmed"; + splash = &"SPLASHES_KILL_CONFIRMED"; + + player incPlayerStat( "killsconfirmed", 1 ); + player incPersStat( "confirmed", 1 ); + player maps\mp\gametypes\_persistence::statSetChild( "round", "confirmed", player.pers["confirmed"] ); + + // if not us, tell the attacker their kill was confirmed + if ( self.attacker != player ) + self.attacker onPickup( event, splash ); + + player playLocalSound( game["voice"][player.pers["team"]] + "kill_confirmed" ); + + player maps\mp\gametypes\_gamescore::giveTeamScoreForObjective( player.pers["team"], 1 ); + } + + player onPickup( event, splash ); + + // do all this at the end now so the location doesn't change before playing the sound on the entity + self resetTags(); +} + + +onPickup( event, splash, stat ) +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + + self thread EventPopup( splash ); + maps\mp\gametypes\_gamescore::givePlayerScore( event, self, undefined, true ); + self thread maps\mp\gametypes\_rank::giveRankXP( event ); +} + + +resetTags() +{ + self.attacker = undefined; + self notify( "reset" ); + self.visuals[0] hide(); + self.visuals[1] hide(); + self.curOrigin = (0,0,1000); + self.trigger.origin = (0,0,1000); + self.visuals[0].origin = (0,0,1000); + self.visuals[1].origin = (0,0,1000); + self maps\mp\gametypes\_gameobjects::allowUse( "none" ); + objective_state( self.objId, "invisible" ); +} + + + +bounce() +{ + level endon( "game_ended" ); + self endon( "reset" ); + + bottomPos = self.curOrigin; + topPos = self.curOrigin + (0,0,12); + + while( true ) + { + self.visuals[0] moveTo( topPos, 0.5, 0.15, 0.15 ); + self.visuals[0] rotateYaw( 180, 0.5 ); + self.visuals[1] moveTo( topPos, 0.5, 0.15, 0.15 ); + self.visuals[1] rotateYaw( 180, 0.5 ); + + wait( 0.5 ); + + self.visuals[0] moveTo( bottomPos, 0.5, 0.15, 0.15 ); + self.visuals[0] rotateYaw( 180, 0.5 ); + self.visuals[1] moveTo( bottomPos, 0.5, 0.15, 0.15 ); + self.visuals[1] rotateYaw( 180, 0.5 ); + + wait( 0.5 ); + } +} + + +timeOut( victim ) +{ + level endon( "game_ended" ); + victim endon( "disconnect" ); + self notify( "timeout" ); + self endon( "timeout" ); + + level maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( 30.0 ); + + self.visuals[0] hide(); + self.visuals[1] hide(); + self.curOrigin = (0,0,1000); + self.trigger.origin = (0,0,1000); + self.visuals[0].origin = (0,0,1000); + self.visuals[1].origin = (0,0,1000); + self maps\mp\gametypes\_gameobjects::allowUse( "none" ); +} + + +tagTeamUpdater( tags ) +{ + level endon( "game_ended" ); + self endon( "disconnect" ); + + while( true ) + { + self waittill( "joined_team" ); + + tags.victimTeam = self.pers["team"]; + tags resetTags(); + } +} + + +clearOnVictimDisconnect( victim ) +{ + level endon( "game_ended" ); + + guid = victim.guid; + victim waittill( "disconnect" ); + + if ( isDefined( level.dogtags[guid] ) ) + { + // block further use + level.dogtags[guid] maps\mp\gametypes\_gameobjects::allowUse( "none" ); + + // 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) ); + + // play vanish effect, reset, and wait for reset to process + PlayFx( level.conf_fx["vanish"], level.dogtags[guid].curOrigin ); + level.dogtags[guid] notify( "reset" ); + wait( 0.05 ); + + // sanity check before removal + if ( isDefined( level.dogtags[guid] ) ) + { + // delete objective and visuals + objective_delete( level.dogtags[guid].objId ); + level.dogtags[guid].trigger delete(); + for ( i=0; i