Give killstreak
-
Hi i made a gungame script, i want the last "weapon" to be the moab but i can't figure out how. anybody know what the function to give killstreaks in chaiscript is?
-
The answer is simple - it's impossible...
Why?
Everything is simple too: the game uses field pers which regulates killstreaks and not only that.
(Field pers is currently not implemented in this version of PlutoniumIW5, but this is not implemented on Addon (Steam ver.) and InfinityScript (4D1/TeknoGods))At the moment, you can rewrite the MOAB logic from the GSC file, but it is worth noting that some functions on ChaiScript do not work yet (either nothing will happen, either you will get a server crash, or the function will work adequately)
Example(with using pers field on GSC):
giveKillstreak( streakName, isEarned, awardXp, owner, skipMiniSplash ) { if ( !IsDefined( level.killstreakFuncs[streakName] ) || tableLookup( KILLSTREAK_STRING_TABLE, 1, streakName, 0 ) == "" ) { AssertMsg( "giveKillstreak() called with invalid killstreak: " + streakName ); return; } // for devmenu give with spectators in match if( !IsDefined( self.pers["killstreaks"] ) ) return; self endon ( "disconnect" ); if( !IsDefined( skipMiniSplash ) ) skipMiniSplash = false; // streaks given from crates go in the gimme index = undefined; if ( !IsDefined( isEarned ) || isEarned == false ) { // put this killstreak in the next available position // 0 - gimme slot (that will index stacked killstreaks) // 1-3 - cac selected killstreaks // 4 - specialist all perks bonus // 5 or more - stacked killstreaks nextSlot = self.pers[ "killstreaks" ].size; // the size should be 5 by default, it will grow as they get stacked killstreaks if( !IsDefined( self.pers[ "killstreaks" ][ nextSlot ] ) ) self.pers[ "killstreaks" ][ nextSlot ] = spawnStruct(); self.pers[ "killstreaks" ][ nextSlot ].available = false; self.pers[ "killstreaks" ][ nextSlot ].streakName = streakName; self.pers[ "killstreaks" ][ nextSlot ].earned = false; self.pers[ "killstreaks" ][ nextSlot ].awardxp = IsDefined( awardXp ) && awardXp; self.pers[ "killstreaks" ][ nextSlot ].owner = owner; self.pers[ "killstreaks" ][ nextSlot ].kID = self.pers["kID"]; self.pers[ "killstreaks" ][ nextSlot ].lifeId = -1; self.pers[ "killstreaks" ][ nextSlot ].isGimme = true; self.pers[ "killstreaks" ][ nextSlot ].isSpecialist = false; self.pers[ "killstreaks" ][ KILLSTREAK_GIMME_SLOT ].nextSlot = nextSlot; self.pers[ "killstreaks" ][ KILLSTREAK_GIMME_SLOT ].streakName = streakName; index = KILLSTREAK_GIMME_SLOT; streakIndex = getKillstreakIndex( streakName ); self setPlayerData( "killstreaksState", "icons", KILLSTREAK_GIMME_SLOT, streakIndex ); // some things may need to skip the mini-splash, like deathstreaks that give killstreaks if( !skipMiniSplash ) { showSelectedStreakHint( streakName ); } } else { for( i = KILLSTREAK_SLOT_1; i < KILLSTREAK_SLOT_3 + 1; i++ ) { if( IsDefined( self.pers["killstreaks"][i] ) && IsDefined( self.pers["killstreaks"][i].streakName ) && streakName == self.pers["killstreaks"][i].streakName ) { index = i; break; } } if ( !IsDefined( index ) ) { AssertMsg( "earnKillstreak() trying to give unearnable killstreak with giveKillstreak(): " + streakName ); return; } } self.pers["killstreaks"][index].available = true; self.pers["killstreaks"][index].earned = IsDefined( isEarned ) && isEarned; self.pers["killstreaks"][index].awardxp = IsDefined( awardXp ) && awardXp; self.pers["killstreaks"][index].owner = owner; self.pers["killstreaks"][index].kID = self.pers["kID"]; //self.pers["kIDs_valid"][self.pers["kID"]] = true; self.pers["kID"]++; if ( !self.pers["killstreaks"][index].earned ) self.pers["killstreaks"][index].lifeId = -1; else self.pers["killstreaks"][index].lifeId = self.pers["deaths"]; // the specialist streak type automatically turns on and there is no weapon to use if( self.streakType == "specialist" && index != KILLSTREAK_GIMME_SLOT ) { self.pers[ "killstreaks" ][ index ].isSpecialist = true; if( IsDefined( level.killstreakFuncs[ streakName ] ) ) self [[ level.killstreakFuncs[ streakName ] ]](); //self thread updateKillstreaks(); self usedKillstreak( streakName, awardXp ); } else { weapon = getKillstreakWeapon( streakName ); self giveKillstreakWeapon( weapon ); // NOTE_A (also see NOTE_B): before we change the killstreakIndexWeapon, let's make sure it's not the one we're holding // if we're currently holding something like an airdrop marker and we earned a killstreak while holding it then we want that to remain the weapon index // because if it's not, then when you throw it, it'll think we're using a different killstreak and not take it away but it'll take away the other one if( IsDefined( self.killstreakIndexWeapon ) ) { streakName = self.pers["killstreaks"][self.killstreakIndexWeapon].streakName; killstreakWeapon = getKillstreakWeapon( streakName ); if( self GetCurrentWeapon() != killstreakWeapon ) { self.killstreakIndexWeapon = index; } } else { self.killstreakIndexWeapon = index; } } self updateStreakSlots(); if ( IsDefined( level.killstreakSetupFuncs[ streakName ] ) ) self [[ level.killstreakSetupFuncs[ streakName ] ]](); if ( IsDefined( isEarned ) && isEarned && IsDefined( awardXp ) && awardXp ) self notify( "received_earned_killstreak" ); }
_nuke.gsc
#include common_scripts\utility; #include maps\mp\_utility; // the nuke ended the game in MW2, for MW3 it will be an MOAB, not end the game but kill the other team and emp them for 60 seconds, it will also change the visionset for the level init() { precacheItem( "nuke_mp" ); precacheLocationSelector( "map_nuke_selector" ); precacheString( &"MP_TACTICAL_NUKE_CALLED" ); precacheString( &"MP_FRIENDLY_TACTICAL_NUKE" ); precacheString( &"MP_TACTICAL_NUKE" ); level.nukeVisionSet = "aftermath"; level._effect[ "nuke_player" ] = loadfx( "explosions/player_death_nuke" ); level._effect[ "nuke_flash" ] = loadfx( "explosions/player_death_nuke_flash" ); level._effect[ "nuke_aftermath" ] = loadfx( "dust/nuke_aftermath_mp" ); game["strings"]["nuclear_strike"] = &"MP_TACTICAL_NUKE"; level.killstreakFuncs["nuke"] = ::tryUseNuke; SetDvarIfUninitialized( "scr_nukeTimer", 10 ); SetDvarIfUninitialized( "scr_nukeCancelMode", 0 ); level.nukeTimer = getDvarInt( "scr_nukeTimer" ); level.cancelMode = getDvarInt( "scr_nukeCancelMode" ); level.teamNukeEMPed["allies"] = false; level.teamNukeEMPed["axis"] = false; level.nukeEmpTimeout = 60.0; level.nukeEmpTimeRemaining = int( level.nukeEmpTimeout ); level.nukeInfo = spawnStruct(); level.nukeDetonated = undefined; level thread nuke_EMPTeamTracker(); level thread onPlayerConnect(); /# SetDevDvarIfUninitialized( "scr_nuke_empTimeout", 60.0 ); SetDevDvarIfUninitialized( "scr_nukeDistance", 5000 ); SetDevDvarIfUninitialized( "scr_nukeEndsGame", true ); SetDevDvarIfUninitialized( "scr_nukeDebugPosition", false ); #/ } tryUseNuke( lifeId, allowCancel ) { if( isDefined( level.nukeIncoming ) ) { self iPrintLnBold( &"MP_NUKE_ALREADY_INBOUND" ); return false; } if ( self isUsingRemote() && ( !isDefined( level.gtnw ) || !level.gtnw ) ) return false; if ( !isDefined( allowCancel ) ) allowCancel = true; self thread doNuke( allowCancel ); self notify( "used_nuke" ); self maps\mp\_matchdata::logKillstreakEvent( "nuke", self.origin ); return true; } delaythread_nuke( delay, func ) { level endon ( "nuke_cancelled" ); maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( delay ); thread [[ func ]](); } doNuke( allowCancel ) { level endon ( "nuke_cancelled" ); level.nukeInfo.player = self; level.nukeInfo.team = self.pers["team"]; level.nukeIncoming = true; //maps\mp\gametypes\_gamelogic::pauseTimer(); //level.timeLimitOverride = true; //setGameEndTime( int( gettime() + (level.nukeTimer * 1000) ) ); SetDvar( "ui_bomb_timer", 4 ); // Nuke sets '4' to avoid briefcase icon showing if( level.teambased ) { thread teamPlayerCardSplash( "used_nuke", self, self.team ); } else { if( !level.hardcoreMode ) self IPrintLnBold( &"MP_FRIENDLY_TACTICAL_NUKE" ); } level thread delaythread_nuke( (level.nukeTimer - 3.3), ::nukeSoundIncoming ); level thread delaythread_nuke( level.nukeTimer, ::nukeSoundExplosion ); level thread delaythread_nuke( level.nukeTimer, ::nukeSlowMo ); level thread delaythread_nuke( level.nukeTimer, ::nukeEffects ); level thread delaythread_nuke( (level.nukeTimer + 0.25), ::nukeVision ); level thread delaythread_nuke( (level.nukeTimer + 1.5), ::nukeDeath ); level thread delaythread_nuke( (level.nukeTimer + 1.5), ::nukeEarthquake ); level thread nukeAftermathEffect(); level thread update_ui_timers(); if ( level.cancelMode && allowCancel ) level thread cancelNukeOnDeath( self ); // leaks if lots of nukes are called due to endon above. clockObject = spawn( "script_origin", (0,0,0) ); clockObject hide(); nukeTimer = level.nukeTimer; while( nukeTimer > 0 ) { // TODO: get a new sound for this so we don't remind people of the old nuke clockObject playSound( "ui_mp_nukebomb_timer" ); wait( 1.0 ); nukeTimer--; } } cancelNukeOnDeath( player ) { player waittill_any( "death", "disconnect" ); if ( isDefined( player ) && level.cancelMode == 2 ) player thread maps\mp\killstreaks\_emp::EMP_Use( 0, 0 ); //maps\mp\gametypes\_gamelogic::resumeTimer(); //level.timeLimitOverride = false; SetDvar( "ui_bomb_timer", 0 ); // Nuke sets '4' to avoid briefcase icon showing level.nukeIncoming = undefined; level notify ( "nuke_cancelled" ); } nukeSoundIncoming() { level endon ( "nuke_cancelled" ); foreach( player in level.players ) player playlocalsound( "nuke_incoming" ); } nukeSoundExplosion() { level endon ( "nuke_cancelled" ); foreach( player in level.players ) { player playlocalsound( "nuke_explosion" ); player playlocalsound( "nuke_wave" ); } } nukeEffects() { level endon ( "nuke_cancelled" ); SetDvar( "ui_bomb_timer", 0 ); //setGameEndTime( 0 ); level.nukeDetonated = true; foreach( player in level.players ) { playerForward = anglestoforward( player.angles ); playerForward = ( playerForward[0], playerForward[1], 0 ); playerForward = VectorNormalize( playerForward ); nukeDistance = 5000; /# nukeDistance = getDvarInt( "scr_nukeDistance" ); #/ nukeEnt = Spawn( "script_model", player.origin + ( playerForward * nukeDistance ) ); nukeEnt setModel( "tag_origin" ); nukeEnt.angles = ( 0, (player.angles[1] + 180), 90 ); /# if ( getDvarInt( "scr_nukeDebugPosition" ) ) { lineTop = ( nukeEnt.origin[0], nukeEnt.origin[1], (nukeEnt.origin[2] + 500) ); thread draw_line_for_time( nukeEnt.origin, lineTop, 1, 0, 0, 10 ); } #/ nukeEnt thread nukeEffect( player ); //player.nuked = true; } } nukeEffect( player ) { level endon ( "nuke_cancelled" ); player endon( "disconnect" ); waitframe(); PlayFXOnTagForClients( level._effect[ "nuke_flash" ], self, "tag_origin", player ); } nukeAftermathEffect() { level endon ( "nuke_cancelled" ); level waittill ( "spawning_intermission" ); afermathEnt = getEntArray( "mp_global_intermission", "classname" ); afermathEnt = afermathEnt[0]; up = anglestoup( afermathEnt.angles ); right = anglestoright( afermathEnt.angles ); PlayFX( level._effect[ "nuke_aftermath" ], afermathEnt.origin, up, right ); } nukeSlowMo() { level endon ( "nuke_cancelled" ); //SetSlowMotion( <startTimescale>, <endTimescale>, <deltaTime> ) SetSlowMotion( 1.0, 0.25, 0.5 ); level waittill( "nuke_death" ); SetSlowMotion( 0.25, 1, 2.0 ); } nukeVision() { level endon ( "nuke_cancelled" ); level.nukeVisionInProgress = true; VisionSetNaked( "mpnuke", 3 ); level waittill( "nuke_death" ); VisionSetNaked( level.nukeVisionSet, 5 ); VisionSetPain( level.nukeVisionSet ); } nukeDeath() { level endon ( "nuke_cancelled" ); level notify( "nuke_death" ); maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone(); AmbientStop(1); foreach( player in level.players ) { // don't kill teammates if( level.teambased ) { if( IsDefined( level.nukeInfo.team ) && player.team == level.nukeInfo.team ) continue; } // ffa, don't kill the player who called it else { if( IsDefined( level.nukeInfo.player ) && player == level.nukeInfo.player ) continue; } player.nuked = true; if ( isAlive( player ) ) player thread maps\mp\gametypes\_damage::finishPlayerDamageWrapper( level.nukeInfo.player, level.nukeInfo.player, 999999, 0, "MOD_EXPLOSIVE", "nuke_mp", player.origin, player.origin, "none", 0, 0 ); } //level.postRoundTime = 10; //nukeEndsGame = true; //if ( level.teamBased ) // thread maps\mp\gametypes\_gamelogic::endGame( level.nukeInfo.team, game["strings"]["nuclear_strike"], true ); //else //{ // if ( isDefined( level.nukeInfo.player ) ) // thread maps\mp\gametypes\_gamelogic::endGame( level.nukeInfo.player, game["strings"]["nuclear_strike"], true ); // else // thread maps\mp\gametypes\_gamelogic::endGame( level.nukeInfo, game["strings"]["nuclear_strike"], true ); //} // emp jam them after death, if we do before then the timing is off level thread nuke_EMPJam(); // since the nuke death happened, the nuke is no longer incoming level.nukeIncoming = undefined; } nukeEarthquake() { level endon ( "nuke_cancelled" ); level waittill( "nuke_death" ); // TODO: need to get a different position to call this on //earthquake( 0.6, 10, nukepos, 100000 ); //foreach( player in level.players ) //player PlayRumbleOnEntity( "damage_heavy" ); } //waitForNukeCancel() //{ // self waittill( "cancel_location" ); // self setblurforplayer( 0, 0.3 ); //} // //endSelectionOn( waitfor ) //{ // self endon( "stop_location_selection" ); // self waittill( waitfor ); // self thread stopNukeLocationSelection( (waitfor == "disconnect") ); //} // //endSelectionOnGameEnd() //{ // self endon( "stop_location_selection" ); // level waittill( "game_ended" ); // self thread stopNukeLocationSelection( false ); //} // //stopNukeLocationSelection( disconnected ) //{ // if ( !disconnected ) // { // self setblurforplayer( 0, 0.3 ); // self endLocationSelection(); // self.selectingLocation = undefined; // } // self notify( "stop_location_selection" ); //} nuke_EMPJam() { level endon ( "game_ended" ); level maps\mp\killstreaks\_emp::destroyActiveVehicles( level.nukeInfo.player, getOtherTeam( level.nukeInfo.team ) ); // since nukes do emp damage, might as well emp jam for a little while also // end emp threads if( level.teambased ) { level notify( "EMP_JamTeam" + "axis" ); level notify( "EMP_JamTeam" + "allies" ); } else { level notify( "EMP_JamPlayers" ); } // set this up to end itself if called again level notify( "nuke_EMPJam" ); level endon( "nuke_EMPJam" ); if( level.teambased ) { level.teamNukeEMPed[ getOtherTeam( level.nukeInfo.team ) ] = true; } else { level.teamNukeEMPed[ level.nukeInfo.team ] = true; level.teamNukeEMPed[ getOtherTeam( level.nukeInfo.team ) ] = true; } level notify( "nuke_emp_update" ); /# level.nukeEmpTimeout = GetDvarFloat( "scr_nuke_empTimeout" ); #/ level thread keepNukeEMPTimeRemaining(); maps\mp\gametypes\_hostmigration::waitLongDurationWithHostMigrationPause( level.nukeEmpTimeout ); if( level.teambased ) { level.teamNukeEMPed[ getOtherTeam( level.nukeInfo.team ) ] = false; } else { level.teamNukeEMPed[ level.nukeInfo.team ] = false; level.teamNukeEMPed[ getOtherTeam( level.nukeInfo.team ) ] = false; } foreach( player in level.players ) { if( level.teambased && player.team == level.nukeInfo.team ) continue; player.nuked = undefined; } // we want the nuke vision to last the rest of this match, leaving here in case we change our minds :) //level.nukeVisionInProgress = undefined; //VisionSetNaked( "", 5.0 ); // go to default visionset level notify( "nuke_emp_update" ); level notify ( "nuke_emp_ended" ); } keepNukeEMPTimeRemaining() { level notify( "keepNukeEMPTimeRemaining" ); level endon( "keepNukeEMPTimeRemaining" ); level endon( "nuke_emp_ended" ); // we need to know how much time is left for the unavailable string level.nukeEmpTimeRemaining = int( level.nukeEmpTimeout ); while( level.nukeEmpTimeRemaining ) { wait( 1.0 ); level.nukeEmpTimeRemaining--; } } nuke_EMPTeamTracker() { level endon ( "game_ended" ); for ( ;; ) { level waittill_either ( "joined_team", "nuke_emp_update" ); foreach ( player in level.players ) { if ( player.team == "spectator" ) continue; if( level.teambased ) { if( IsDefined( level.nukeInfo.team ) && player.team == level.nukeInfo.team ) continue; } else { if( IsDefined( level.nukeInfo.player ) && player == level.nukeInfo.player ) continue; } player SetEMPJammed( level.teamNukeEMPed[ player.team ] ); } } } onPlayerConnect() { for(;;) { level waittill("connected", player); player thread onPlayerSpawned(); } } onPlayerSpawned() { self endon("disconnect"); for(;;) { self waittill( "spawned_player" ); if( level.teamNukeEMPed[ self.team ] ) { if( level.teambased ) self SetEMPJammed( true ); else { if( !IsDefined( level.nukeInfo.player ) || ( IsDefined( level.nukeInfo.player ) && self != level.nukeInfo.player ) ) self SetEMPJammed( true ); } } // make sure the vision set stays on between deaths if( IsDefined( level.nukeDetonated ) ) self VisionSetNakedForPlayer( level.nukeVisionSet, 0 ); } } update_ui_timers() { level endon ( "game_ended" ); level endon ( "disconnect" ); level endon ( "nuke_cancelled" ); level endon ( "nuke_death" ); nukeEndMilliseconds = (level.nukeTimer * 1000) + gettime(); SetDvar( "ui_nuke_end_milliseconds", nukeEndMilliseconds ); level waittill( "host_migration_begin" ); timePassed = maps\mp\gametypes\_hostmigration::waitTillHostMigrationDone(); if ( timePassed > 0 ) { SetDvar( "ui_nuke_end_milliseconds", nukeEndMilliseconds + timePassed ); } }
-
Thanks for the very detailed answer, i guess ill just make my own nuke
-
Alright so this is what I came up with, its not perfect but works.
Only needs the aftermath effect or whatever its called// player is the player that got the nuke def nukePlayers(player) { gsc.setDvar("ui_bomb_timer", 4); gsc.setDvar("ui_nuke_end_milliseconds", gsc.gettime() + 10 * 1000); gsc.iPrintlnBold("^1TACTICAL NUKE INCOMING"); var count = 0; gsc.playsound("ui_mp_nukebomb_timer"); setInterval(fun[count]() { if (count < 10) { gsc.playsound("ui_mp_nukebomb_timer"); ++count; } }, 1000); setTimeout(fun[player]() { gsc.playsound("nuke_explosion"); gsc.playsound("nuke_wave"); gsc.SetSlowMotion( 1.0, 0.25, 0.5 ); gsc.setDvar("ui_bomb_timer", 0); setTimeout(fun[player]() { // kills all players except the one that got the nuke for (var i = 0; i < players.size; ++i) { if (players[i].getGuid() == player.getGuid()) { continue; } explodePlayer(players[i], player); var playerN = players[i]; playerN.onNotify("death", fun[playerN](arguments) { playerN.setempjammed(true); gsc.SetSlowMotion( 0.25, 1, 2.0 ); }); } endMatch(); }, 2000); }, 10000); } // shoots an ac130 round at the player def explodePlayer(player, attacker) { var eye = player.getEye(); var end = player.getOrigin(); gsc.MagicBullet("ac130_105mm_mp", [eye[0], eye[1], eye[2] + 70 ], eye, attacker); } def endMatch() { gsc.setDvar("scr_dm_timelimit", 0.001); }
-
This is not explosion effect, it's effect red vision and smoke
// Aftematch smoke and vision effect var effect = gsc.loadFX("dust/nuke_aftermath_mp"); var aftermathEnt = gsc.GetEnt("mp_global_intermission", "classname"); var up = gsc.anglesToUp(aftermathEnt.get("angles")); var right = gsc.anglesToRight(aftermathEnt.get("angles")); gsc.PlayFX(effect, aftermathEnt.getOrigin(), up, right); // vison effect needs update setInterval(fun() { gsc.VisionSetNaked("aftermath", 5); gsc.VisionSetPain("aftermath"); }, 1000);
-
S3VDITO dope thanks!