├── README.md ├── actions_on_button_press ├── README.md ├── camera_switch_vote_on_button_press.gsc ├── sniper_attachment_switch_on_button_press.gsc └── suicide_on_button_press.gsc ├── chat_commands ├── README.md ├── chat_command_balance_teams.gsc ├── chat_command_change_team.gsc ├── chat_command_dvars.gsc ├── chat_command_freeze.gsc ├── chat_command_give.gsc ├── chat_command_god_mode.gsc ├── chat_command_invisible.gsc ├── chat_command_kick.gsc ├── chat_command_kill.gsc ├── chat_command_map_mode.gsc ├── chat_command_norecoil.gsc ├── chat_command_permissions.gsc ├── chat_command_suicide.gsc ├── chat_command_teleport.gsc ├── chat_command_text_help.gsc ├── chat_command_text_rules.gsc ├── chat_command_unfair_aimbot.gsc ├── chat_command_unlimited_ammo.gsc ├── chat_command_wallhack.gsc └── chat_commands.gsc ├── cover.jpg ├── custom_killstreaks_rewards ├── README.md ├── automatic_weapons_rewards.gsc └── launchers_weapons_rewards.gsc ├── disable_nuke_effects ├── README.md ├── disable_nuke_effects_all.gsc ├── disable_nuke_effects_all_but_fog.gsc ├── disable_nuke_effects_emp.gsc ├── disable_nuke_effects_slowmo.gsc └── disable_nuke_effects_vision.gsc ├── gamemodes ├── README.md ├── all_or_nothing.gsc ├── chaos.gsc ├── gun_game.gsc ├── kamikaze.gsc └── one_in_the_chamber.gsc ├── mapvote ├── README.md ├── images │ ├── mapvote1.png │ └── mapvote2.png └── mapvote.gsc ├── replace_weapon_on_spawn ├── README.md ├── replace_rsass_with_intervention.gsc └── replace_with_snipers.gsc └── small_scripts ├── README.md ├── anti_hardscope.gsc ├── autoassign_team.gsc ├── change_team_names.gsc ├── disable_damages.gsc ├── disable_nuke_killstreak.gsc ├── display_player_stats.gsc ├── get_player_guid.gsc ├── give_perks_on_spawn.gsc ├── hardcore_tweaks.gsc ├── images ├── display_player_stats.png └── welcome_message.png ├── jump_monitor.gsc ├── kill_players_under_map.gsc ├── kill_stuck_bots.gsc ├── manage_bots_fill.gsc ├── remove_heavy_weapon_slow.gsc ├── show_text_on_first_spawn.gsc └── welcome_message.gsc /README.md: -------------------------------------------------------------------------------- 1 | # Plutonium-IW5-Scripts 2 | 3 | [![image](cover.jpg)](https://plutonium.pw/) 4 | 5 | ## What is this? 6 | 7 | This is a collection of [Plutonium](https://plutonium.pw/docs/intro/) IW5/MW3 scripts I created, written in [GSC](https://plutonium.pw/docs/modding/gsc/). 8 | Some scripts (mostly older ones) have specific use cases and some others were made to be as generic as possible so you might find something useful. 9 | 10 | Some scripts were made when I was still fairly new to GSC so some scripts might not be perfectly optimized or done the proper way but they do their job and should at least give you an idea of how to do certain things or work well enough for you to use them. 11 | 12 | Huge thanks to everyone who helped me learn GSC: Birchy, DoktorSAS, FutureRave and other people on Discord. 13 | 14 | ## How do I download a script? 15 | 16 | - [Download this repository](https://github.com/Resxt/Plutonium-IW5-Scripts/archive/refs/heads/master.zip) 17 | - Open the downloaded ZIP file 18 | - Drag and drop the script(s) you want in the folder they need to be placed in. 19 | If no instructions are provided for the script you want then simply follow the instructions given in [How do I use a script?](#how-do-i-use-a-script) 20 | 21 | Just keep in mind that this downloads a copy of this repository at the moment you download it. 22 | If a script is updated after you downloaded this repository and you want the new version then you will need to download this repository again. 23 | 24 | ## How do I use a script? 25 | 26 | [Follow the instructions in the documentation](https://plutonium.pw/docs/modding/loading-mods/#loading-existing-scripts-on-iw5) 27 | 28 | Simply drop a `.gsc` file inside `%localappdata%\Plutonium\storage\iw5\scripts`. 29 | 30 | Note that you can use `map_restart` in the [console](https://plutonium.pw/docs/opening-console/) to quickly restart your current game and reload scripts. 31 | -------------------------------------------------------------------------------- /actions_on_button_press/README.md: -------------------------------------------------------------------------------- 1 | # Actions On Button Press 2 | 3 | These scripts allow players on the server to press a button (displayed on screen) to trigger a function. 4 | Note that if you combine several scripts you will have to change the texts positions so that they don't overlap by changing the last value in `setPoint()` 5 | You can also change the size and font type in `createServerFontString()` 6 | 7 | Changing the button in `Init()` will change both the button displayed on screen and the button used to trigger the function. 8 | Here is a non-exhaustive list of buttons you can use 9 | ``` 10 | "+usereload" 11 | "weapnext" 12 | "+gostand" 13 | "+melee" 14 | "+actionslot 1" 15 | "+actionslot 2" 16 | "+actionslot 3" 17 | "+actionslot 4" 18 | "+actionslot 5" 19 | "+actionslot 6" 20 | "+actionslot 7" 21 | "+frag" 22 | "+smoke" 23 | "+attack" 24 | "+speed_throw" 25 | "+stance" 26 | "+breathe_sprint" 27 | ``` 28 | 29 | ## camera_switch_vote_on_button_press.gsc 30 | 31 | Allows the players to toggle their vote to change the `camera_thirdPerson` dvar on the server (players vote no by default) 32 | When enough players vote yes the server changes the dvar and resets the vote counts. 33 | The amount of votes required is more than 50% of the players: 1/1 | 2/2 | 3/4 | 3/5 | 4/6 etc. 34 | Bots are ignored for the votes. 35 | 36 | ## sniper_attachment_switch_on_button_press.gsc 37 | 38 | Allows the player to cycle between several attachments for a list of weapons. 39 | Displays the key to press to switch to the next attachment as well as the current attachment selected top right. 40 | Whenever the player press the key, re-spawns or switches to another class with a valid weapon it will give him the attachment he wants. 41 | 42 | This script has been written for the L118A, MSR and Intervention but can easily be modified or even optimized to support more weapons. 43 | 44 | ## suicide_on_button_press.gsc 45 | 46 | The player dies when pressing the button -------------------------------------------------------------------------------- /actions_on_button_press/camera_switch_vote_on_button_press.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\gametypes\_hud_util; 2 | 3 | Init() 4 | { 5 | level.camera_switch_vote_button = "+actionslot 6"; 6 | 7 | DisplayButtonsText(); 8 | 9 | level thread DisplayVoteCount(); 10 | level thread OnPlayerConnected(); 11 | } 12 | 13 | OnPlayerConnected() 14 | { 15 | for(;;) 16 | { 17 | level waittill("connected", player); 18 | 19 | player.pers["camera_switch_vote"] = false; 20 | 21 | player thread OnCameraSwitchVoteButtonPressed(level.camera_switch_vote_button); 22 | 23 | player thread OnPlayerSpawned(player); 24 | } 25 | } 26 | 27 | OnPlayerSpawned(player) 28 | { 29 | self endon("disconnect"); 30 | 31 | for(;;) 32 | { 33 | self waittill("spawned_player"); 34 | 35 | player DisableDof(); 36 | } 37 | } 38 | 39 | OnCameraSwitchVoteButtonPressed(button) 40 | { 41 | self endon("disconnect"); 42 | level endon("game_ended"); 43 | 44 | self notifyOnPlayerCommand("camera_switch_vote_button", button); 45 | while(1) 46 | { 47 | self waittill("camera_switch_vote_button"); 48 | self.pers["camera_switch_vote"] = !self.pers["camera_switch_vote"]; 49 | if (self.pers["camera_switch_vote"]) 50 | { 51 | CustomPrintLn(self.name + " voted to switch the camera"); 52 | } 53 | else 54 | { 55 | CustomPrintLn(self.name + " removed his vote to switch the camera"); 56 | } 57 | } 58 | } 59 | 60 | DisplayButtonsText() 61 | { 62 | camera_switch_vote_text = level createServerFontString( "Objective", 0.65 ); 63 | camera_switch_vote_text setPoint( "RIGHT", "RIGHT", -4, -227.5 ); 64 | camera_switch_vote_text setText("^1Press [{" + level.camera_switch_vote_button + "}] to toggle vote for camera switch"); 65 | } 66 | 67 | DisplayVoteCount() 68 | { 69 | level.camera_switch_vote_count_text = level createServerFontString( "Objective", 0.65 ); 70 | level.camera_switch_vote_count_text setPoint( "RIGHT", "RIGHT", -4, -220 ); 71 | 72 | while(true) 73 | { 74 | yes_votes = 0; 75 | human_players = []; 76 | 77 | foreach (player in level.players) 78 | { 79 | if (player.pers["camera_switch_vote"]) 80 | { 81 | yes_votes++; 82 | } 83 | 84 | if (!isDefined(player.pers["isBot"])) 85 | { 86 | human_players[human_players.size] = player; 87 | } 88 | else 89 | { 90 | if (!player.pers["isBot"]) 91 | { 92 | human_players[human_players.size] = player; 93 | } 94 | } 95 | } 96 | 97 | votes_required = 0; 98 | 99 | // Votes required = more than 50% of the players: 1/1 | 2/2 | 3/4 | 3/5 | 4/6 etc. 100 | if (human_players.size % 2 == 1) 101 | { 102 | votes_required = (human_players.size / 2 + 0.5); 103 | } 104 | else if (human_players.size % 2 == 0) 105 | { 106 | votes_required = (human_players.size / 2 + 1); 107 | } 108 | 109 | level.camera_switch_vote_count_text setText("^1Votes to switch camera: " + yes_votes + "/" + votes_required); 110 | 111 | if (yes_votes >= votes_required && human_players.size > 0) 112 | { 113 | // Logic here 114 | setDvar( "camera_thirdPerson", !getDvarInt( "camera_thirdPerson" ) ); 115 | 116 | // Mention changes to all players (if there is more than one player) 117 | if (human_players.size > 1) 118 | { 119 | if (getDvarInt( "camera_thirdPerson" ) == 0) 120 | { 121 | CustomPrintLn("Switching to 1st person (+50% votes)"); 122 | } 123 | else 124 | { 125 | CustomPrintLn("Switching to 3rd person (+50% votes)"); 126 | } 127 | } 128 | 129 | // Reset votes variables 130 | yes_votes = 0; 131 | 132 | foreach (player in human_players) 133 | { 134 | player.pers["camera_switch_vote"] = false; 135 | } 136 | } 137 | 138 | wait 0.01; 139 | } 140 | } 141 | 142 | EnableDof() 143 | { 144 | self setDepthOfField( 0, 110, 512, 4096, 6, 1.8 ); 145 | } 146 | 147 | DisableDof() 148 | { 149 | self setDepthOfField( 0, 0, 512, 512, 4, 0 ); 150 | } 151 | 152 | CustomPrintLn(text) 153 | { 154 | IPrintLn("^1" + text); 155 | } 156 | 157 | Debug(text) 158 | { 159 | print(text); 160 | } -------------------------------------------------------------------------------- /actions_on_button_press/sniper_attachment_switch_on_button_press.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\_utility; 2 | #include maps\mp\gametypes\_hud_util; 3 | 4 | Init() 5 | { 6 | level.attachment_switch_button = "+actionslot 5"; 7 | level.available_attachments = ["scope", "scope_silencer", "acog", "acog_silencer", "thermal", "thermal_silencer", "none", "silencer"]; 8 | 9 | InitWeaponVariants(); 10 | 11 | level thread OnPlayerConnect(); 12 | 13 | DisplayButtonsText(); 14 | } 15 | 16 | OnPlayerConnect() 17 | { 18 | for(;;) 19 | { 20 | level waittill("connected", player); 21 | 22 | player.pers["attachment_variant_name"] = "scope"; 23 | player.pers["attachment_variant_index"] = 0; 24 | 25 | player thread OnAttachmentSwitchButtonPressed(level.attachment_switch_button); 26 | 27 | player thread OnPlayerSpawned(); 28 | 29 | // Don't thread DisplayCurrentAttachment() on bots 30 | if (isDefined(player.pers["isBot"])) 31 | { 32 | if (player.pers["isBot"]) 33 | { 34 | continue; // skip 35 | } 36 | } 37 | 38 | player thread DisplayCurrentAttachment(); 39 | } 40 | } 41 | 42 | OnPlayerSpawned() 43 | { 44 | self endon("disconnect"); 45 | for(;;) 46 | { 47 | self waittill("changed_kit"); 48 | 49 | current_weapon = self GetCurrentWeapon(); 50 | 51 | // Whenever the player spawns check if his weapon is a sniper we want and replace his weapon with the attachment he asked for 52 | if (IsValidWeapon(current_weapon)) 53 | { 54 | ReplaceWeapon(level.snipers_variants[current_weapon][self.pers["attachment_variant_name"]]); 55 | } 56 | } 57 | } 58 | 59 | DisplayButtonsText() 60 | { 61 | attachment_switch_text = level createServerFontString( "Objective", 0.65 ); 62 | attachment_switch_text setPoint( "RIGHT", "RIGHT", -4, -227.5 ); 63 | attachment_switch_text setText("^1Press [{" + level.attachment_switch_button + "}] to switch attachment"); 64 | } 65 | 66 | DisplayCurrentAttachment() 67 | { 68 | self endon ("disconnect"); 69 | level endon("game_ended"); 70 | 71 | self.attachment_text = createFontString( "Objective", 0.65 ); 72 | self.attachment_text setPoint( "RIGHT", "RIGHT", -4, -220 ); 73 | self.current_attachment_text = ""; 74 | 75 | while(true) 76 | { 77 | if (IsDefined(self.pers["attachment_variant_name"])) 78 | { 79 | self.new_attachment_text = "^1Current attachement: " + self.pers["attachment_variant_name"]; 80 | 81 | // Only update when necessary, setText() is an expensive function 82 | if (self.current_attachment_text != self.new_attachment_text) 83 | { 84 | self.current_attachment_text = self.new_attachment_text; 85 | self.attachment_text setText(self.new_attachment_text); 86 | } 87 | } 88 | 89 | wait 0.01; 90 | } 91 | } 92 | 93 | OnAttachmentSwitchButtonPressed(button) 94 | { 95 | self endon("disconnect"); 96 | level endon("game_ended"); 97 | 98 | self notifyOnPlayerCommand("attachment_switch_button", button); 99 | while(1) 100 | { 101 | self waittill("attachment_switch_button"); 102 | 103 | if (self.pers["attachment_variant_index"] < level.available_attachments.size - 1) 104 | { 105 | self.pers["attachment_variant_index"] = self.pers["attachment_variant_index"] + 1; 106 | } 107 | else 108 | { 109 | self.pers["attachment_variant_index"] = 0; 110 | } 111 | 112 | self.pers["attachment_variant_name"] = level.available_attachments[self.pers["attachment_variant_index"]]; 113 | 114 | // Here we give the weapon right when the player ask for a new attachement. 115 | // If you don't want that remove this line and the new weapon will only be given on next spawn 116 | if (IsDefined(self.primaryWeapon)) 117 | { 118 | ReplaceWeapon(level.snipers_variants[self.primaryWeapon][self.pers["attachment_variant_name"]]); 119 | } 120 | } 121 | } 122 | 123 | IsValidWeapon(weapon) 124 | { 125 | switch (weapon) 126 | { 127 | case "iw5_l96a1_mp_l96a1scope": 128 | case "iw5_msr_mp_msrscope": 129 | case "iw5_rsass_mp_rsassscope": 130 | return true; 131 | } 132 | 133 | return false; 134 | } 135 | 136 | ReplaceWeapon(new_weapon) 137 | { 138 | secondary_weapon = self.secondaryWeapon; 139 | new_weapon = new_weapon + "_camo11"; // Change/remove this line to change the camo or have none 140 | 141 | self TakeAllWeapons(); 142 | self GiveWeapon(new_weapon); 143 | self GiveWeapon(secondary_weapon); // Re-give secondary weapon because TakeAllWeapons() removes it 144 | self SetSpawnWeapon(secondary_weapon); // This ensures we don't have the animation when switching to the secondary weapon 145 | self SetSpawnWeapon(new_weapon); // This gives the weapon without playing the animation 146 | 147 | GiveLethalAndTactical(); 148 | } 149 | 150 | // TakeAllWeapons() removes lethal and tactical as well so we give default items after calling it 151 | GiveLethalAndTactical() 152 | { 153 | self GiveWeapon("throwingknife_mp"); // Found in dsr files 154 | self GiveWeapon("flare_mp"); // Tactical insertion - found in common_mp.ff 155 | } 156 | 157 | // For each weapon we want we declare an array with every possible value as key, example: l188a["scope"] and then we put the full weapon code as the value 158 | // Then once that array has been filled with all possible values we add it to the level.snipers_variants array 159 | // This could be optimized by having a generic function that builds those arrays by passing the base weapon name (example: iw5_l96a1) as parameter but this was enough for my use case 160 | InitWeaponVariants() 161 | { 162 | level.snipers_variants = []; 163 | 164 | l118a = []; 165 | l118a["scope"] = "iw5_l96a1_mp_l96a1scope"; 166 | l118a["scope_silencer"] = "iw5_l96a1_mp_l96a1scope_silencer03"; 167 | l118a["acog"] = "iw5_l96a1_mp_acog"; 168 | l118a["acog_silencer"] = "iw5_l96a1_mp_acog_silencer03"; 169 | l118a["thermal"] = "iw5_l96a1_mp_thermal"; 170 | l118a["thermal_silencer"] = "iw5_l96a1_mp_silencer03_thermal"; 171 | l118a["none"] = "iw5_l96a1_mp"; 172 | l118a["silencer"] = "iw5_l96a1_mp_silencer03"; 173 | level.snipers_variants["iw5_l96a1_mp_l96a1scope"] = l118a; 174 | 175 | msr = []; 176 | msr["scope"] = "iw5_msr_mp_msrscope"; 177 | msr["scope_silencer"] = "iw5_msr_mp_msrscope_silencer03"; 178 | msr["acog"] = "iw5_msr_mp_acog"; 179 | msr["acog_silencer"] = "iw5_msr_mp_acog_silencer03"; 180 | msr["thermal"] = "iw5_msr_mp_thermal"; 181 | msr["thermal_silencer"] = "iw5_msr_mp_silencer03_thermal"; 182 | msr["none"] = "iw5_msr_mp"; 183 | msr["silencer"] = "iw5_msr_mp_silencer03"; 184 | level.snipers_variants["iw5_msr_mp_msrscope"] = msr; 185 | 186 | intervention = []; 187 | intervention["scope"] = "iw5_cheytac_mp_cheytacscope"; 188 | intervention["scope_silencer"] = "iw5_cheytac_mp_cheytacscope_silencer03"; 189 | intervention["acog"] = "iw5_cheytac_mp_acog"; 190 | intervention["acog_silencer"] = "iw5_cheytac_mp_acog_silencer03"; 191 | intervention["thermal"] = "iw5_cheytac_mp_thermal"; 192 | intervention["thermal_silencer"] = "iw5_cheytac_mp_silencer03_thermal"; 193 | intervention["none"] = "iw5_cheytac_mp"; 194 | intervention["silencer"] = "iw5_cheytac_mp_silencer03"; 195 | level.snipers_variants["iw5_rsass_mp_rsassscope"] = intervention; 196 | } -------------------------------------------------------------------------------- /actions_on_button_press/suicide_on_button_press.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\gametypes\_hud_util; 2 | 3 | Init() 4 | { 5 | level.suicide_button = "+actionslot 7"; 6 | 7 | DisplayButtonsText(); 8 | 9 | level thread OnPlayerConnected(); 10 | } 11 | 12 | OnPlayerConnected() 13 | { 14 | for(;;) 15 | { 16 | level waittill("connected", player); 17 | 18 | player thread OnSuicideButtonPressed(level.suicide_button); 19 | } 20 | } 21 | 22 | OnSuicideButtonPressed(button) 23 | { 24 | self endon("disconnect"); 25 | level endon("game_ended"); 26 | 27 | self notifyOnPlayerCommand("suicide_button", button); 28 | while(1) 29 | { 30 | self waittill("suicide_button"); 31 | 32 | self Suicide(); 33 | } 34 | } 35 | 36 | DisplayButtonsText() 37 | { 38 | suicide_text = level createServerFontString( "Objective", 0.65 ); 39 | suicide_text setPoint( "RIGHT", "RIGHT", -4, -227.5 ); 40 | suicide_text setText("^1Press [{" + level.suicide_button + "}] to suicide"); 41 | } 42 | 43 | Debug(text) 44 | { 45 | print(text); 46 | } -------------------------------------------------------------------------------- /chat_commands/README.md: -------------------------------------------------------------------------------- 1 | # Chat commands 2 | 3 | Let players execute commands by typing in the chat. 4 | This can be used to display text to the player, for example the server rules or execute GSC code, just like console commands. 5 | This works in private games, on dedicated servers that use [IW4MAdmin](https://github.com/RaidMax/IW4M-Admin) and those that don't. 6 | If you do monitor your server with [IW4MAdmin](https://github.com/RaidMax/IW4M-Admin) then make sure to read the [notes section](#notes). 7 | 8 | ## chat_commands.gsc 9 | 10 | The core script that holds the configuration, runs all the chat logic and holds utils function that are shared between all the `chat_command` scripts. 11 | **[IMPORTANT]** Installing `chat_commands.gsc` is **mandatory** to make the commands work as this is the core of this whole system and all the command scripts depend on it. 12 | 13 | Also note that this script doesn't provide any command on its own. 14 | You must install at least one command script to be able to use commands. Otherwise it will always say that you don't have any command. 15 | 16 | ### Main features 17 | 18 | - Easy per server (port) commands configuration. You can either pass an array of one server port, or multiple, or the `level.chat_commands["ports"]` array to easily add a command to one/multiple/all servers 19 | - Chat text print and functions support 20 | - Optional permissions level system to restrict commands to players with a certain permission level (disabled by default) 21 | - All exceptions are handled with error messages (no commands on the server, not enough arguments, command doesn't exist, command doesn't have any help message, player doesn't exist etc.) 22 | - A `commands` command that lists all available commands on the server you're on dynamically (only lists commands you have access to if the permission system is enabled) 23 | - A `help` command that explains how to use a given command. For example `help map` (only works on commands you have access to if the permission system is enabled) 24 | - `alias` and `aliases` commands that list the available aliases for a command. For example `alias godmode` (only works on commands you have access to if the permission system is enabled) 25 | - All commands that require a target work with `me`. Also it doesn't matter how you type the player's name as long as you type his full name or type the beginning of his username (has to be unique, see [#3](https://github.com/Resxt/Plutonium-IW5-Scripts/pull/3/commits/2efa784709b5c42811510c67c3e6a2fc5eb3fc70)). 26 | - Configurable command prefix. Set to `!` by default 27 | - A plugin system to easily allow adding/removing commands. Each command has its own GSC file to easily add/remove/review/configure your commands. This also makes contributing by creating a PR to add a command a lot easier 28 | 29 | ### Dvars 30 | 31 | Here are the dvars you can configure: 32 | 33 | | Name | Description | Default value | Accepted values | 34 | |---|---|---|---| 35 | | cc_debug | Toggle whether the script is in debug mode or not. This is used to print players GUID in the console when they connect | 0 | 0 or 1 | 36 | | cc_prefix | The symbol to type before the command name in the chat. Only one character is supported. The `/` symbol won't work normally as it's reserved by the game. If you use the `/` symbol as prefix you will need to type double slash in the game | ! | Any working symbol | 37 | | cc_permission_enabled | Toggle whether the permission system is enabled or not. If it's disabled any player can run any available command | 0 | 0 or 1 | 38 | | cc_permission_mode | Changes whether the permission dvars values are names or guids | name | name or guid | 39 | | cc_permission_default | The default permission level players who aren't found in the permission dvars will be granted | 1 | Any plain number from 0 to `cc_permission_max` | 40 | | cc_permission_max | The maximum/most elevated permission level | 4 | Any plain number above 0 | 41 | | cc_permission_0 | A list of names or guids of players who will be granted the permission level 0 when connecting (no access to any command) | "" | Names or guids (depending on `cc_permission_mode`). Each value is separated with a colon (:) | 42 | | cc_permission_1 | A list of names or guids of players who will be granted the permission level 1 when connecting | "" | Names or guids (depending on `cc_permission_mode`). Each value is separated with a colon (:) | 43 | | cc_permission_2 | A list of names or guids of players who will be granted the permission level 2 when connecting | "" | Names or guids (depending on `cc_permission_mode`). Each value is separated with a colon (:) | 44 | | cc_permission_3 | A list of names or guids of players who will be granted the permission level 3 when connecting | "" | Names or guids (depending on `cc_permission_mode`). Each value is separated with a colon (:) | 45 | | cc_permission_4 | A list of names or guids of players who will be granted the permission level 4 when connecting | "" | Names or guids (depending on `cc_permission_mode`). Each value is separated with a colon (:) | 46 | 47 | ### Configuration 48 | 49 | Below is an example CFG showing how each dvars can be configured. 50 | The values you see are the default values that will be used if you don't set a dvar. 51 | 52 | ```c 53 | set cc_debug 0 54 | set cc_prefix "!" 55 | set cc_permission_enabled 0 56 | set cc_permission_mode "name" 57 | set cc_permission_default 1 58 | set cc_permission_max 4 59 | set cc_permission_0 "" 60 | set cc_permission_1 "" 61 | set cc_permission_2 "" 62 | set cc_permission_3 "" 63 | set cc_permission_4 "" 64 | ``` 65 | 66 | ### Notes 67 | 68 | - To pass an argument with a space you need to put `'` around it. For example if a player name is `The Moonlight` then you would write `!teleport 'The Moonlight' Resxt` 69 | - If you use [IW4MAdmin](https://github.com/RaidMax/IW4M-Admin) make sure you have a different commands prefix to avoid conflicts. For example `!` for IW4MAdmin commands and `.` for this script. The commands prefix can be modified by changing the value of the `cc_prefix` dvar. As for [IW4MAdmin](https://github.com/RaidMax/IW4M-Admin), at the time of writing, if you want to change it you'll need to change the value of [CommandPrefix](https://github.com/RaidMax/IW4M-Admin/wiki/Configuration#advanced-configuration) 70 | - If you prefer to display information (error messages, status change etc.) on the player's screen rather than in the chat you can edit the `TellPlayer` function. For this you simply need to change `self tell(message);` to `self IPrintLnBold(message);` 71 | 72 | ## chat_command_balance_teams.gsc 73 | 74 | Balances the teams so that both teams have a fair amount of players. 75 | This also counts bots but most likely doesn't differentiate bots and players. 76 | 77 | [Credits](https://github.com/Resxt/Plutonium-IW5-Scripts/issues/2) 78 | 79 | | Example | 80 | |---| 81 | | `!balanceteams` | 82 | 83 | | Permission level | 84 | |---| 85 | | 3 | 86 | 87 | ## chat_command_change_team.gsc 88 | 89 | The player affected by the command dies and swaps to the other team. 90 | 91 | | # | Argument | Mandatory | 92 | |---|---|---| 93 | | 1 | The name of the player to swap to the other team | :white_check_mark: | 94 | 95 | | Examples | 96 | |---| 97 | | `!changeteam me` | 98 | | `!changeteam Resxt` | 99 | 100 | | Permission level | 101 | |---| 102 | | 3 | 103 | 104 | ## chat_command_dvars.gsc 105 | 106 | 3 related commands in one file: 107 | 108 | - Print server dvar 109 | - Change server dvar 110 | - Change client dvar 111 | 112 | | Name | Description | Arguments expected | Example | Permission level | 113 | |---|---|---|---|---| 114 | | getdvar | Prints the (server) dvar value in the player's chat | (1) the dvar name | `!getdvar g_speed` | 2 | 115 | | setdvar | Changes a dvar on the server | (1) the dvar name (2) the new dvar value | `!setdvar jump_height 500` | 4 | 116 | | setclientdvar | Changes a dvar on the targeted player | (1) the name of the player (2) the dvar name (3) the new dvar value | `!setclientdvar Resxt cg_thirdperson 1` | 4 | 117 | 118 | ## chat_command_freeze.gsc 119 | 120 | Toggles whether the targeted player can move or not. 121 | Note that this does not work during the prematch period. 122 | 123 | | # | Argument | Mandatory | 124 | |---|---|---| 125 | | 1 | The name of the player to freeze/unfreeze | :white_check_mark: | 126 | 127 | | Examples | 128 | |---| 129 | | `!freeze me` | 130 | | `!freeze Resxt` | 131 | 132 | | Permission level | 133 | |---| 134 | | 3 | 135 | 136 | ## chat_command_give.gsc 137 | 138 | 3 related commands in one file: 139 | 140 | - Give weapon 141 | - Give killstreak 142 | - Give camo 143 | 144 | | Name | Description | Arguments expected | Example | Permission level | 145 | |---|---|---|---|---| 146 | | giveweapon | Gives the specified weapon to the targeted player. Removes the current weapon and plays the switch animation by default | (1) the name of the targeted player (2) the weapon code name (attachments and camos accepted too) | `!giveweapon me iw5_acr_mp_reflex_camo11` | 2 | 147 | | givekillstreak | Gives the specified killstreak to the targeted player | (1) the name of the targeted player (2) the killstreak code name | `!givekillstreak me predator_missile` | 3 | 148 | | givecamo | Changes the camo of all the primary weapons the targeted player has to the specified camo. Plays the switch animation by default | (1) the name of the targeted player (2) the name of the camo or its index | `!givecamo me gold` | 2 | 149 | 150 | You can check [this](https://www.itsmods.com/forum/Thread-Tutorial-MW3-weapons-perks-camos-attachments.html) to get weapon/killstreak/camos names. 151 | 152 | Note that for weapons you need to add `_mp` at the end of the weapon name. 153 | So for example if the website says `iw5_scar` you would replace it with `iw5_scar_mp`. 154 | This is only for the weapon name, if you add an attachment and/or a camo `_mp` would still be at the same position, it wouldn't be at the end. 155 | For example a SCAR-L with an acog sight and the red camo would be `iw5_scar_mp_acog_camo09`. 156 | 157 | The format is `__`. 158 | 159 | Note that default snipers scope are considered as attachments. 160 | You can find the list of sniper scopes by taking a look at the `GetDefaultWeaponScope` function of my [gun game script](https://github.com/Resxt/Plutonium-IW5-Scripts/blob/main/gamemodes/gun_game.gsc). 161 | 162 | If you add multiple attachments then you need to respect an order that entirely depends on the weapon and attachments. 163 | It would be too long to explain so I would recommend simply not bothering with multiple attachments or taking a look at the `FixReversedAttachments` function of my [gun game script](https://github.com/Resxt/Plutonium-IW5-Scripts/blob/main/gamemodes/gun_game.gsc) 164 | 165 | | More examples | 166 | |---| 167 | | `!giveweapon me iw5_fad_mp` | 168 | | `!giveweapon me iw5_ak74u_mp_reflexsmg_camo11` | 169 | | `!giveweapon Resxt iw5_cheytac_mp_cheytacscope_camo08` | 170 | | `!givecamo me red` | 171 | | `!givecamo me none` | 172 | | `!givecamo Resxt 11` | 173 | 174 | ## chat_command_god_mode.gsc 175 | 176 | Toggles whether the targeted player is in god mode (invincible) or not. 177 | 178 | | # | Argument | Mandatory | 179 | |---|---|---| 180 | | 1 | The name of the player to toggle god mode for | :white_check_mark: | 181 | 182 | | Examples | 183 | |---| 184 | | `!god me` | 185 | | `!god Resxt` | 186 | 187 | | Permission level | 188 | |---| 189 | | 3 | 190 | 191 | ## chat_command_invisible.gsc 192 | 193 | Toggles invisibility on the targeted player. 194 | Note that this does not make the player invisible to bots in the sense that even if they can't see the player, they will still know his position and shoot him. 195 | 196 | | # | Argument | Mandatory | 197 | |---|---|---| 198 | | 1 | The name of the player to make invisible/visible | :white_check_mark: | 199 | 200 | | Examples | 201 | |---| 202 | | `!invisible me` | 203 | | `!invisible Resxt` | 204 | 205 | | Permission level | 206 | |---| 207 | | 3 | 208 | 209 | ## chat_command_kick.gsc 210 | 211 | Kicks the targeted player. 212 | Note that due to some game limitations you cannot kick the host 213 | 214 | | # | Argument | Mandatory | 215 | |---|---|---| 216 | | 1 | The name of the player to kick | :white_check_mark: | 217 | 218 | | Examples | 219 | |---| 220 | | `!kick Resxt` | 221 | 222 | | Permission level | 223 | |---| 224 | | 4 | 225 | 226 | ## chat_command_kill.gsc 227 | 228 | The player who runs the command kills the targeted player (no matter if they're in the same team or not) 229 | 230 | | # | Argument | Mandatory | 231 | |---|---|---| 232 | | 1 | The name of the player to kill | :white_check_mark: | 233 | 234 | | Examples | 235 | |---| 236 | | `!kill me` | 237 | | `!kill Resxt` | 238 | 239 | | Permission level | 240 | |---| 241 | | 3 | 242 | 243 | ## chat_command_map_mode.gsc 244 | 245 | 3 related commands in one file: 246 | 247 | - Change map 248 | - Change mode 249 | - Change map and mode 250 | 251 | | Name | Description | Arguments expected | Example | Permission level | 252 | |---|---|---|---|---| 253 | | map | Changes the map on the server | (1) the map codename | `!map mp_dome` | 4 | 254 | | mode | Charges a new DSR/mode on the server and restarts the current map | (1) the DSR file name, found in the `admin` folder of your game | `!mode FFA_default` | 4 | 255 | | mapmode | Charges a new DSR/mode on the server and rotates to the requested map | (1) the map codename (2) the DSR file name, found in the `admin` folder of your game | `!mapmode mp_seatown TDM_default` | 4 | 256 | 257 | ## chat_command_norecoil.gsc 258 | 259 | Toggles norecoil on the targeted player 260 | 261 | | # | Argument | Mandatory | 262 | |---|---|---| 263 | | 1 | The name of the player to toggle norecoil for | :white_check_mark: | 264 | 265 | | Examples | 266 | |---| 267 | | `!norecoil me` | 268 | | `!norecoil Resxt` | 269 | 270 | | Permission level | 271 | |---| 272 | | 3 | 273 | 274 | ## chat_command_permissions.gsc 275 | 276 | 2 related commands in one file: 277 | 278 | - Get permission level 279 | - Set permission level 280 | 281 | | Name | Description | Arguments expected | Example | Permission level | 282 | |---|---|---|---|---| 283 | | getpermission | Prints the targeted player's current permission level in the player's chat | (1) the name of the targeted player | `!getpermission me` | 2 | 284 | | setpermission | Changes the targeted player's permission level (for the current game only) | (1) the name of the targeted player (2) the permission level to grant | `!setpermission Resxt 4` | 4 | 285 | 286 | ## chat_command_suicide.gsc 287 | 288 | The player who runs the command dies. 289 | 290 | | Example | 291 | |---| 292 | | `!suicide` | 293 | 294 | | Permission level | 295 | |---| 296 | | 1 | 297 | 298 | ## chat_command_teleport.gsc 299 | 300 | Teleports a player to the position of another player. 301 | 302 | | # | Argument | Mandatory | 303 | |---|---|---| 304 | | 1 | The name of the player to teleport | :white_check_mark: | 305 | | 2 | The name of the player to teleport to | :white_check_mark: | 306 | 307 | | Examples | 308 | |---| 309 | | `!teleport me Eldor` | 310 | | `!teleport Eldor me` | 311 | | `!teleport Eldor Rektinator` | 312 | 313 | | Permission level | 314 | |---| 315 | | 2 | 316 | 317 | ## chat_command_text_help.gsc 318 | 319 | Prints how to use the `commands` and the `help command` commands in the player's chat. 320 | 321 | | Example | 322 | |---| 323 | | `!help` | 324 | 325 | | Permission level | 326 | |---| 327 | | 1 | 328 | 329 | ## chat_command_text_rules.gsc 330 | 331 | Prints the server rules in the player's chat. 332 | 333 | | Example | 334 | |---| 335 | | `!rules` | 336 | 337 | | Permission level | 338 | |---| 339 | | 1 | 340 | 341 | ## chat_command_unfair_aimbot.gsc 342 | 343 | Toggles unfair aimbot on the targeted player. 344 | 345 | | # | Argument | Mandatory | 346 | |---|---|---| 347 | | 1 | The name of the player to toggle unfair aimbot for | :white_check_mark: | 348 | 349 | | Examples | 350 | |---| 351 | | `!unfairaimbot me` | 352 | | `!unfairaimbot Resxt` | 353 | 354 | | Permission level | 355 | |---| 356 | | 4 | 357 | 358 | ## chat_command_unlimited_ammo.gsc 359 | 360 | Toggles unlimited ammo on the targeted player. 361 | 362 | | # | Argument | Mandatory | 363 | |---|---|---| 364 | | 1 | The name of the player to toggle unlimited ammo for | :white_check_mark: | 365 | 366 | | Examples | 367 | |---| 368 | | `!unlimitedammo me` | 369 | | `!unlimitedammo Resxt` | 370 | 371 | | Permission level | 372 | |---| 373 | | 3 | 374 | 375 | ## chat_command_wallhack.gsc 376 | 377 | Toggles wallhack (red boxes) on the targeted player. 378 | 379 | | # | Argument | Mandatory | 380 | |---|---|---| 381 | | 1 | The name of the player to toggle wallhack for | :white_check_mark: | 382 | 383 | | Examples | 384 | |---| 385 | | `!wallhack me` | 386 | | `!wallhack Resxt` | 387 | 388 | | Permission level | 389 | |---| 390 | | 4 | 391 | -------------------------------------------------------------------------------- /chat_commands/chat_command_balance_teams.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "balanceteams", "function", ::BalanceTeamsCommand, 3, [], ["bt"]); 6 | } 7 | 8 | 9 | 10 | /* Command section */ 11 | 12 | BalanceTeamsCommand(args) 13 | { 14 | BalanceTeams(); 15 | } 16 | 17 | 18 | 19 | /* Logic section */ 20 | 21 | BalanceTeams() 22 | { 23 | if (!maps\mp\gametypes\_teams::getteambalance()) 24 | { 25 | self thread TellPlayer(["Balancing teams"], 1); 26 | level maps\mp\gametypes\_teams::balanceteams(); 27 | } 28 | else 29 | { 30 | self thread TellPlayer(["Teams are already balanced"], 1); 31 | } 32 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_change_team.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "changeteam", "function", ::ChangeTeamCommand, 3, ["default_help_one_player"], ["ct"]); 6 | } 7 | 8 | 9 | 10 | /* Command section */ 11 | 12 | ChangeTeamCommand(args) 13 | { 14 | if (args.size < 1) 15 | { 16 | return NotEnoughArgsError(1); 17 | } 18 | 19 | error = ChangeTeam(args[0]); 20 | 21 | if (IsDefined(error)) 22 | { 23 | return error; 24 | } 25 | } 26 | 27 | 28 | 29 | /* Logic section */ 30 | 31 | ChangeTeam(playerName) 32 | { 33 | player = FindPlayerByName(playerName); 34 | 35 | if (!IsDefined(player)) 36 | { 37 | return PlayerDoesNotExistError(playerName); 38 | } 39 | 40 | if (player.team == "axis") 41 | { 42 | player [[level.allies]](); 43 | } 44 | else if (player.team == "allies") 45 | { 46 | player [[level.axis]](); 47 | } 48 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_dvars.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "getdvar", "function", ::GetDvarCommand, 2, [], ["gd"]); 6 | CreateCommand(level.chat_commands["ports"], "setdvar", "function", ::SetDvarCommand, 4, [], ["sd"]); 7 | CreateCommand(level.chat_commands["ports"], "setclientdvar", "function", ::SetPlayerDvarCommand, 4, [], ["scd"]); 8 | } 9 | 10 | 11 | 12 | /* Command section */ 13 | 14 | GetDvarCommand(args) 15 | { 16 | if (args.size < 1) 17 | { 18 | return NotEnoughArgsError(1); 19 | } 20 | 21 | error = GetServerDvar(args[0]); 22 | 23 | if (IsDefined(error)) 24 | { 25 | return error; 26 | } 27 | } 28 | 29 | SetDvarCommand(args) 30 | { 31 | if (args.size < 2) 32 | { 33 | return NotEnoughArgsError(2); 34 | } 35 | 36 | error = SetServerDvar(args[0], args[1], false); 37 | 38 | if (IsDefined(error)) 39 | { 40 | return error; 41 | } 42 | } 43 | 44 | SetPlayerDvarCommand(args) 45 | { 46 | if (args.size < 3) 47 | { 48 | return NotEnoughArgsError(3); 49 | } 50 | 51 | error = SetPlayerDvar(args[0], args[1], args[2]); 52 | 53 | if (IsDefined(error)) 54 | { 55 | return error; 56 | } 57 | } 58 | 59 | 60 | 61 | /* Logic section */ 62 | 63 | GetServerDvar(dvarName) 64 | { 65 | if (DvarIsInitialized(dvarName)) 66 | { 67 | self thread TellPlayer(["^5" + dvarName + " ^7is currently set to ^5" + GetDvar(dvarName)], 1); 68 | } 69 | else 70 | { 71 | return DvarDoesNotExistError(dvarName); 72 | } 73 | } 74 | 75 | SetServerDvar(dvarName, dvarValue, canSetUndefinedDvar) 76 | { 77 | if (IsDefined(canSetUndefinedDvar) && canSetUndefinedDvar) 78 | { 79 | SetDvar(dvarName, dvarValue); 80 | } 81 | else 82 | { 83 | if (DvarIsInitialized(dvarName)) 84 | { 85 | SetDvar(dvarName, dvarValue); 86 | } 87 | else 88 | { 89 | return DvarDoesNotExistError(dvarName); 90 | } 91 | } 92 | } 93 | 94 | SetPlayerDvar(playerName, dvarName, dvarValue) 95 | { 96 | player = FindPlayerByName(playerName); 97 | 98 | if (!IsDefined(player)) 99 | { 100 | return PlayerDoesNotExistError(playerName); 101 | } 102 | 103 | player SetClientDvar(dvarName, dvarValue); 104 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_freeze.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "freeze", "function", ::FreezeCommand, 3, ["default_help_one_player"]); 6 | } 7 | 8 | 9 | 10 | /* Command section */ 11 | 12 | FreezeCommand(args) 13 | { 14 | if (args.size < 1) 15 | { 16 | return NotEnoughArgsError(1); 17 | } 18 | 19 | error = ToggleFreeze(args[0]); 20 | 21 | if (IsDefined(error)) 22 | { 23 | return error; 24 | } 25 | } 26 | 27 | 28 | 29 | /* Logic section */ 30 | 31 | ToggleFreeze(playerName) 32 | { 33 | player = FindPlayerByName(playerName); 34 | 35 | if (!IsDefined(player)) 36 | { 37 | return PlayerDoesNotExistError(playerName); 38 | } 39 | 40 | commandName = "freeze"; 41 | 42 | ToggleStatus(commandName, "Freeze", player); 43 | 44 | if (GetStatus(commandName, player)) 45 | { 46 | player DoFreeze(true); 47 | player thread ThreadFreeze(); 48 | } 49 | else 50 | { 51 | player DoFreeze(false); 52 | player notify("chat_commands_freeze_off"); 53 | } 54 | } 55 | 56 | ThreadFreeze() 57 | { 58 | self endon("disconnect"); 59 | self endon("chat_commands_freeze_off"); 60 | 61 | for(;;) 62 | { 63 | self waittill("spawned_player"); 64 | 65 | self DoFreeze(true); 66 | } 67 | } 68 | 69 | DoFreeze(enabled) 70 | { 71 | if (enabled) 72 | { 73 | self freezecontrols(1); 74 | } 75 | else 76 | { 77 | self freezecontrols(0); 78 | } 79 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_give.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "giveweapon", "function", ::GiveWeaponCommand, 2); 6 | CreateCommand(level.chat_commands["ports"], "givekillstreak", "function", ::GiveKillstreakCommand, 3); 7 | CreateCommand(level.chat_commands["ports"], "givecamo", "function", ::GiveCamoCommand, 2); 8 | } 9 | 10 | 11 | 12 | /* Command section */ 13 | 14 | GiveWeaponCommand(args) 15 | { 16 | if (args.size < 2) 17 | { 18 | return NotEnoughArgsError(2); 19 | } 20 | 21 | error = GivePlayerWeapon(args[0], args[1], true, true); 22 | 23 | if (IsDefined(error)) 24 | { 25 | return error; 26 | } 27 | } 28 | 29 | GiveKillstreakCommand(args) 30 | { 31 | if (args.size < 2) 32 | { 33 | return NotEnoughArgsError(2); 34 | } 35 | 36 | error = GivePlayerKillstreak(args[0], args[1]); 37 | 38 | if (IsDefined(error)) 39 | { 40 | return error; 41 | } 42 | } 43 | 44 | GiveCamoCommand(args) 45 | { 46 | if (args.size < 2) 47 | { 48 | return NotEnoughArgsError(2); 49 | } 50 | 51 | error = GivePlayerCamo(args[0], args[1], true); 52 | 53 | if (IsDefined(error)) 54 | { 55 | return error; 56 | } 57 | } 58 | 59 | 60 | 61 | /* Logic section */ 62 | 63 | GivePlayerWeapon(targetedPlayerName, weaponName, takeCurrentWeapon, playSwitchAnimation) 64 | { 65 | player = FindPlayerByName(targetedPlayerName); 66 | 67 | if (!IsDefined(player)) 68 | { 69 | return PlayerDoesNotExistError(targetedPlayerName); 70 | } 71 | 72 | if (IsDefined(takeCurrentWeapon) && takeCurrentWeapon) 73 | { 74 | player TakeWeapon(player GetCurrentWeapon()); 75 | } 76 | 77 | player GiveWeapon(weaponName); 78 | 79 | if (IsDefined(playSwitchAnimation) && playSwitchAnimation) 80 | { 81 | player SwitchToWeapon(weaponName); 82 | } 83 | else 84 | { 85 | player SetSpawnWeapon(weaponName); 86 | } 87 | } 88 | 89 | GivePlayerKillstreak(targetedPlayerName, killstreakName) 90 | { 91 | player = FindPlayerByName(targetedPlayerName); 92 | 93 | if (!IsDefined(player)) 94 | { 95 | return PlayerDoesNotExistError(targetedPlayerName); 96 | } 97 | 98 | player maps\mp\killstreaks\_killstreaks::giveKillstreak(killstreakName, false); 99 | } 100 | 101 | GivePlayerCamo(targetedPlayerName, camoName, playSwitchAnimation) 102 | { 103 | player = FindPlayerByName(targetedPlayerName); 104 | 105 | if (!IsDefined(player)) 106 | { 107 | return PlayerDoesNotExistError(targetedPlayerName); 108 | } 109 | 110 | finalCamoName = GetCamoNameFromNameOrIndex(camoName); 111 | 112 | if (!IsDefined(finalCamoName)) 113 | { 114 | return CamoDoesNotExistError(camoName); 115 | } 116 | 117 | foreach (weapon in player GetWeaponsList("primary")) 118 | { 119 | if (maps\mp\_utility::iscacprimaryweapon(weapon) && !IsSubStr(weapon, "alt_iw5")) 120 | { 121 | player TakeWeapon(weapon); 122 | 123 | finalWeaponName = GetWeaponNameWithoutCamo(weapon) + finalCamoName; 124 | 125 | player GiveWeapon(finalWeaponName); 126 | 127 | if (IsDefined(playSwitchAnimation) && playSwitchAnimation) 128 | { 129 | player SwitchToWeapon(finalWeaponname); 130 | } 131 | else 132 | { 133 | player SetSpawnWeapon(finalWeaponname); 134 | } 135 | } 136 | } 137 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_god_mode.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "godmode", "function", ::GodModeCommand, 3, ["default_help_one_player"], ["god"]); 6 | } 7 | 8 | 9 | 10 | /* Command section */ 11 | 12 | GodModeCommand(args) 13 | { 14 | if (args.size < 1) 15 | { 16 | return NotEnoughArgsError(1); 17 | } 18 | 19 | error = ToggleGodMode(args[0]); 20 | 21 | if (IsDefined(error)) 22 | { 23 | return error; 24 | } 25 | } 26 | 27 | 28 | 29 | /* Logic section */ 30 | 31 | ToggleGodMode(playerName) 32 | { 33 | player = FindPlayerByName(playerName); 34 | 35 | if (!IsDefined(player)) 36 | { 37 | return PlayerDoesNotExistError(playerName); 38 | } 39 | 40 | commandName = "god"; 41 | 42 | ToggleStatus(commandName, "God Mode", player); 43 | 44 | if (GetStatus(commandName, player)) 45 | { 46 | player DoGodMode(true); 47 | player thread ThreadGodMode(); 48 | } 49 | else 50 | { 51 | player DoGodMode(false); 52 | player notify("chat_commands_god_mode_off"); 53 | } 54 | } 55 | 56 | ThreadGodMode() 57 | { 58 | self endon("disconnect"); 59 | self endon("chat_commands_god_mode_off"); 60 | 61 | for(;;) 62 | { 63 | self waittill("spawned_player"); 64 | 65 | self DoGodMode(true); 66 | } 67 | } 68 | 69 | DoGodMode(enabled) 70 | { 71 | health = 99999; 72 | 73 | if (!enabled) 74 | { 75 | health = GetDvarInt("scr_player_maxhealth"); 76 | } 77 | 78 | deadSilencePro = "specialty_falldamage"; 79 | 80 | if (enabled && !self maps\mp\_utility::_hasPerk(deadSilencePro)) // if god mode is on and player doesn't have dead silence pro 81 | { 82 | self maps\mp\_utility::givePerk(deadSilencePro, false); // give dead silence pro 83 | self.pers["god_mode_gave_perk"] = true; 84 | } 85 | else if (!enabled && self maps\mp\_utility::_hasPerk(deadSilencePro) && self.pers["god_mode_gave_perk"]) // if god mode is off and player has dead silence pro and it was given by god mode on 86 | { 87 | self maps\mp\_utility::_unsetperk(deadSilencePro); // remove dead silence pro 88 | self.pers["god_mode_gave_perk"] = false; 89 | } 90 | 91 | self.maxhealth = health; 92 | self.health = health; 93 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_invisible.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "invisible", "function", ::InvisibleCommand, 3, ["default_help_one_player"]); 6 | } 7 | 8 | 9 | 10 | /* Command section */ 11 | 12 | InvisibleCommand(args) 13 | { 14 | if (args.size < 1) 15 | { 16 | return NotEnoughArgsError(1); 17 | } 18 | 19 | error = ToggleInvisible(args[0]); 20 | 21 | if (IsDefined(error)) 22 | { 23 | return error; 24 | } 25 | } 26 | 27 | 28 | 29 | /* Logic section */ 30 | 31 | ToggleInvisible(playerName) 32 | { 33 | player = FindPlayerByName(playerName); 34 | 35 | if (!IsDefined(player)) 36 | { 37 | return PlayerDoesNotExistError(playerName); 38 | } 39 | 40 | commandName = "invisible"; 41 | 42 | ToggleStatus(commandName, "Invisible", player); 43 | 44 | if (GetStatus(commandName, player)) 45 | { 46 | player hide(); 47 | } 48 | else 49 | { 50 | player show(); 51 | } 52 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_kick.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "kick", "function", ::KickCommand, 4, ["default_help_one_player"], ["k"]); 6 | } 7 | 8 | 9 | 10 | /* Command section */ 11 | 12 | KickCommand(args) 13 | { 14 | if (args.size < 1) 15 | { 16 | return NotEnoughArgsError(1); 17 | } 18 | 19 | error = KickPlayer(args[0]); 20 | 21 | if (IsDefined(error)) 22 | { 23 | return error; 24 | } 25 | } 26 | 27 | 28 | 29 | /* Logic section */ 30 | 31 | KickPlayer(playerName) 32 | { 33 | player = FindPlayerByName(playerName); 34 | 35 | if (!IsDefined(player)) 36 | { 37 | return PlayerDoesNotExistError(playerName); 38 | } 39 | 40 | Kick(player GetEntityNumber()); 41 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_kill.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "kill", "function", ::KillCommand, 3, ["default_help_one_player"]); 6 | } 7 | 8 | 9 | 10 | /* Command section */ 11 | 12 | KillCommand(args) 13 | { 14 | if (args.size < 1) 15 | { 16 | return NotEnoughArgsError(1); 17 | } 18 | 19 | error = KillPlayer(args[0]); 20 | 21 | if (IsDefined(error)) 22 | { 23 | return error; 24 | } 25 | } 26 | 27 | 28 | 29 | /* Logic section */ 30 | 31 | KillPlayer(targetedPlayerName) 32 | { 33 | if (self TargetIsMyself(targetedPlayerName)) 34 | { 35 | self Suicide(); 36 | } 37 | else 38 | { 39 | player = FindPlayerByName(targetedPlayerName); 40 | 41 | if (!IsDefined(player)) 42 | { 43 | return PlayerDoesNotExistError(targetedPlayerName); 44 | } 45 | 46 | playerTeam = self.team; 47 | self.team = "noteam"; // we change the player's team to bypass the friendly fire limitation 48 | 49 | player thread [[level.callbackPlayerDamage]]( self, self, 2147483600, 8, "MOD_SUICIDE", self getCurrentWeapon(), (0,0,0), (0,0,0), "torso", 0 ); 50 | 51 | self.team = playerTeam; // sets the player's team to his original team again 52 | } 53 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_map_mode.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "map", "function", ::ChangeMapCommand, 4, ["Example: " + GetDvar("cc_prefix") + "map mp_dome"]); 6 | CreateCommand(level.chat_commands["ports"], "mode", "function", ::ChangeModeCommand, 4, ["Example: " + GetDvar("cc_prefix") + "mode FFA_default"]); 7 | CreateCommand(level.chat_commands["ports"], "mapmode", "function", ::ChangeMapAndModeCommand, 4, ["Example: " + GetDvar("cc_prefix") + "mapmode mp_seatown TDM_default"], ["mm"]); 8 | } 9 | 10 | 11 | 12 | /* Command section */ 13 | 14 | ChangeMapCommand(args) 15 | { 16 | if (args.size < 1) 17 | { 18 | return NotEnoughArgsError(1); 19 | } 20 | 21 | ChangeMap(args[0]); 22 | } 23 | 24 | ChangeModeCommand(args) 25 | { 26 | if (args.size < 1) 27 | { 28 | return NotEnoughArgsError(1); 29 | } 30 | 31 | ChangeMode(args[0], true); 32 | } 33 | 34 | ChangeMapAndModeCommand(args) 35 | { 36 | if (args.size < 2) 37 | { 38 | return NotEnoughArgsError(2); 39 | } 40 | 41 | ChangeMode(args[1], false); 42 | ChangeMap(args[0]); 43 | } 44 | 45 | 46 | 47 | /* Logic section */ 48 | 49 | ChangeMap(mapName) 50 | { 51 | cmdexec("map " + mapName); 52 | } 53 | 54 | ChangeMode(modeName, restart) 55 | { 56 | cmdexec("load_dsr " + modeName + ";"); 57 | 58 | if (restart) 59 | { 60 | cmdexec("map_restart"); 61 | } 62 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_norecoil.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "norecoil", "function", ::NoRecoilCommand, 3, ["default_help_one_player"], ["nr"]); 6 | } 7 | 8 | 9 | 10 | /* Command section */ 11 | 12 | NoRecoilCommand(args) 13 | { 14 | if (args.size < 1) 15 | { 16 | return NotEnoughArgsError(1); 17 | } 18 | 19 | error = ToggleNoRecoil(args[0]); 20 | 21 | if (IsDefined(error)) 22 | { 23 | return error; 24 | } 25 | } 26 | 27 | 28 | 29 | /* Logic section */ 30 | 31 | ToggleNoRecoil(playerName) 32 | { 33 | player = FindPlayerByName(playerName); 34 | 35 | if (!IsDefined(player)) 36 | { 37 | return PlayerDoesNotExistError(playerName); 38 | } 39 | 40 | recoilModifier = 100; 41 | 42 | if (IsDefined(player.recoilscale) && player.recoilscale == 100) 43 | { 44 | recoilModifier = 0; 45 | } 46 | 47 | player maps\mp\_utility::setrecoilscale( recoilModifier, recoilModifier ); 48 | player.recoilscale = recoilModifier; 49 | 50 | ToggleStatus("no_recoil", "No Recoil", player); 51 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_permissions.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | if (PermissionIsEnabled()) 6 | { 7 | CreateCommand(level.chat_commands["ports"], "getpermission", "function", ::GetPlayerPermissionCommand, 2, ["default_help_one_player"], ["gp"]); 8 | CreateCommand(level.chat_commands["ports"], "setpermission", "function", ::SetPlayerPermissionCommand, 4, [], ["sp"]); 9 | } 10 | } 11 | 12 | 13 | 14 | /* Command section */ 15 | 16 | GetPlayerPermissionCommand(args) 17 | { 18 | if (args.size < 1) 19 | { 20 | return NotEnoughArgsError(1); 21 | } 22 | 23 | error = GetPlayerPermission(args[0]); 24 | 25 | if (IsDefined(error)) 26 | { 27 | return error; 28 | } 29 | } 30 | 31 | SetPlayerPermissionCommand(args) 32 | { 33 | if (args.size < 2) 34 | { 35 | return NotEnoughArgsError(2); 36 | } 37 | 38 | error = SetPlayerPermission(args[0], args[1]); 39 | 40 | if (IsDefined(error)) 41 | { 42 | return error; 43 | } 44 | } 45 | 46 | 47 | 48 | /* Logic section */ 49 | 50 | GetPlayerPermission(playerName) 51 | { 52 | player = FindPlayerByName(playerName); 53 | 54 | if (!IsDefined(player)) 55 | { 56 | return PlayerDoesNotExistError(playerName); 57 | } 58 | 59 | self thread TellPlayer(["^5" + player.name + " ^7permission level is ^5" + player GetPlayerPermissionLevel()], 1); 60 | } 61 | 62 | SetPlayerPermission(playerName, newPermissionLevel) 63 | { 64 | player = FindPlayerByName(playerName); 65 | 66 | if (!IsDefined(player)) 67 | { 68 | return PlayerDoesNotExistError(playerName); 69 | } 70 | 71 | newPermissionLevel = int(newPermissionLevel); 72 | 73 | if (newPermissionLevel < 0 || newPermissionLevel > GetDvarInt("cc_permission_max")) 74 | { 75 | return InvalidPermissionLevelError(newPermissionLevel); 76 | } 77 | 78 | player SetPlayerPermissionLevel(newPermissionLevel); 79 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_suicide.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "suicide", "function", ::SuicideCommand, 1, [], ["s"]); 6 | } 7 | 8 | 9 | 10 | /* Command section */ 11 | 12 | SuicideCommand(args) 13 | { 14 | self Suicide(); 15 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_teleport.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "teleport", "function", ::TeleportCommand, 2, ["default_help_two_players"], ["tp"]); 6 | } 7 | 8 | 9 | 10 | /* Command section */ 11 | 12 | TeleportCommand(args) 13 | { 14 | if (args.size < 2) 15 | { 16 | return NotEnoughArgsError(2); 17 | } 18 | 19 | error = TeleportPlayer(args[0], args[1]); 20 | 21 | if (IsDefined(error)) 22 | { 23 | return error; 24 | } 25 | } 26 | 27 | 28 | 29 | /* Logic section */ 30 | 31 | TeleportPlayer(teleportedPlayerName, destinationPlayerName) 32 | { 33 | players = []; 34 | names = [teleportedPlayerName, destinationPlayerName]; 35 | 36 | for (i = 0; i < names.size; i++) 37 | { 38 | name = names[i]; 39 | 40 | player = FindPlayerByName(name); 41 | 42 | if (!IsDefined(player)) 43 | { 44 | return PlayerDoesNotExistError(name); 45 | } 46 | 47 | players = AddElementToArray(players, player); 48 | } 49 | 50 | players[0] SetOrigin(players[1].origin); 51 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_text_help.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "help", "text", ["Type " + GetDvar("cc_prefix") + "commands to get a list of commands", "Type " + GetDvar("cc_prefix") + "help followed by a command name to see how to use it"], 1); 6 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_text_rules.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(["27016", "27017"], "rules", "text", ["Do not camp", "Do not spawnkill", "Do not disrespect other players"], 1); 6 | CreateCommand(["27018"], "rules", "text", ["Leave your spot and don't camp after using a M.O.A.B", "Don't leave while being infected", "Do not disrespect other players"], 1); 7 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_unfair_aimbot.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "unfairaimbot", "function", ::UnfairAimbotCommand, 4, ["default_help_one_player"], ["aimbot"]); 6 | } 7 | 8 | 9 | 10 | /* Command section */ 11 | 12 | UnfairAimbotCommand(args) 13 | { 14 | if (args.size < 1) 15 | { 16 | return NotEnoughArgsError(1); 17 | } 18 | 19 | error = ToggleUnfairAimbot(args[0]); 20 | 21 | if (IsDefined(error)) 22 | { 23 | return error; 24 | } 25 | } 26 | 27 | 28 | 29 | /* Logic section */ 30 | 31 | ToggleUnfairAimbot(playerName) 32 | { 33 | player = FindPlayerByName(playerName); 34 | 35 | if (!IsDefined(player)) 36 | { 37 | return PlayerDoesNotExistError(playerName); 38 | } 39 | 40 | commandName = "unfairaimbot"; 41 | 42 | ToggleStatus(commandName, "Unfair Aimbot", player); 43 | 44 | if (GetStatus(commandName, player)) 45 | { 46 | player thread DoUnfairAimbot(true); 47 | player thread ThreadUnfairAimbot(); 48 | } 49 | else 50 | { 51 | player notify("chat_commands_unfair_aimbot_off"); 52 | } 53 | } 54 | 55 | ThreadUnfairAimbot() 56 | { 57 | self endon("disconnect"); 58 | self endon("chat_commands_unfair_aimbot_off"); 59 | 60 | for(;;) 61 | { 62 | self waittill("spawned_player"); 63 | 64 | self thread DoUnfairAimbot(true); 65 | } 66 | } 67 | 68 | DoUnfairAimbot(requiresAiming) 69 | { 70 | self endon("death"); 71 | self endon("disconnect"); 72 | self endon("chat_commands_unfair_aimbot_off"); 73 | 74 | while (true) 75 | { 76 | targetedPlayer = undefined; 77 | 78 | foreach(player in level.players) 79 | { 80 | if((player == self) || (level.teamBased && self.pers["team"] == player.pers["team"]) || (!isAlive(player))) // don't aim at yourself, allies and player that aren't spawned 81 | { 82 | continue; // skip 83 | } 84 | 85 | if(IsDefined(targetedPlayer)) 86 | { 87 | if(Closer( self getTagOrigin( "j_head" ), player getTagOrigin( "j_head" ), targetedPlayer getTagOrigin( "j_head" ))) 88 | { 89 | targetedPlayer = player; 90 | } 91 | } 92 | else 93 | { 94 | targetedPlayer = player; 95 | } 96 | } 97 | 98 | if(IsDefined( targetedPlayer )) 99 | { 100 | if (!IsDefined(requiresAiming) || !requiresAiming || requiresAiming && self AdsButtonPressed()) 101 | { 102 | self SetPlayerAngles(VectorToAngles(( targetedPlayer getTagOrigin( "j_head" )) - (self getTagOrigin( "j_head" )))); 103 | 104 | if(self AttackButtonPressed()) 105 | { 106 | // for normal (non headshot) kills replace "MOD_HEAD_SHOT" with "MOD_RIFLE_BULLET" and replace "head" with "torso" 107 | targetedPlayer thread [[level.callbackPlayerDamage]]( self, self, 2147483600, 8, "MOD_HEAD_SHOT", self getCurrentWeapon(), (0,0,0), (0,0,0), "head", 0 ); 108 | } 109 | } 110 | } 111 | 112 | wait 0.05; 113 | } 114 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_unlimited_ammo.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "unlimitedammo", "function", ::UnlimitedAmmoCommand, 3, ["default_help_one_player"], ["ammo", "ua"]); 6 | } 7 | 8 | 9 | 10 | /* Command section */ 11 | 12 | UnlimitedAmmoCommand(args) 13 | { 14 | if (args.size < 1) 15 | { 16 | return NotEnoughArgsError(1); 17 | } 18 | 19 | error = ToggleUnlimitedAmmo(args[0]); 20 | 21 | if (IsDefined(error)) 22 | { 23 | return error; 24 | } 25 | } 26 | 27 | 28 | 29 | /* Logic section */ 30 | 31 | ToggleUnlimitedAmmo(playerName) 32 | { 33 | player = FindPlayerByName(playerName); 34 | 35 | if (!IsDefined(player)) 36 | { 37 | return PlayerDoesNotExistError(playerName); 38 | } 39 | 40 | commandName = "unlimitedammo"; 41 | 42 | ToggleStatus(commandName, "Unlimited Ammo", player); 43 | 44 | if (GetStatus(commandName, player)) 45 | { 46 | player thread DoUnlimitedAmmo(); 47 | player thread ThreadUnlimitedAmmo(); 48 | } 49 | else 50 | { 51 | player notify("chat_commands_unlimited_ammo_off"); 52 | } 53 | } 54 | 55 | ThreadUnlimitedAmmo() 56 | { 57 | self endon("disconnect"); 58 | self endon("chat_commands_unlimited_ammo_off"); 59 | 60 | for(;;) 61 | { 62 | self waittill("spawned_player"); 63 | 64 | self thread DoUnlimitedAmmo(); 65 | } 66 | } 67 | 68 | DoUnlimitedAmmo() 69 | { 70 | self endon("chat_commands_unlimited_ammo_off"); 71 | 72 | while (true) 73 | { 74 | currentWeapon = self getCurrentWeapon(); 75 | currentoffhand = self GetCurrentOffhand(); 76 | 77 | if (currentWeapon != "none") 78 | { 79 | self SetWeaponAmmoClip(currentWeapon, 9999); 80 | } 81 | 82 | if (IsSubStr(currentWeapon, "akimbo")) 83 | { 84 | self SetWeaponAmmoClip(currentWeapon, 9999, "left"); 85 | self SetWeaponAmmoClip(currentWeapon, 9999, "right"); 86 | } 87 | 88 | if ( currentoffhand != "none" ) 89 | { 90 | self setWeaponAmmoClip( currentoffhand, 9999 ); 91 | self GiveMaxAmmo( currentoffhand ); 92 | } 93 | 94 | wait 0.05; 95 | } 96 | } -------------------------------------------------------------------------------- /chat_commands/chat_command_wallhack.gsc: -------------------------------------------------------------------------------- 1 | #include scripts\chat_commands; 2 | 3 | Init() 4 | { 5 | CreateCommand(level.chat_commands["ports"], "wallhack", "function", ::WallhackCommand, 4, ["default_help_one_player"], ["wh", "wall"]); 6 | } 7 | 8 | 9 | 10 | /* Command section */ 11 | 12 | WallhackCommand(args) 13 | { 14 | if (args.size < 1) 15 | { 16 | return NotEnoughArgsError(1); 17 | } 18 | 19 | error = ToggleWallhack(args[0]); 20 | 21 | if (IsDefined(error)) 22 | { 23 | return error; 24 | } 25 | } 26 | 27 | 28 | 29 | /* Logic section */ 30 | 31 | ToggleWallhack(playerName) 32 | { 33 | player = FindPlayerByName(playerName); 34 | 35 | if (!IsDefined(player)) 36 | { 37 | return PlayerDoesNotExistError(playerName); 38 | } 39 | 40 | commandName = "wallhack"; 41 | 42 | ToggleStatus(commandName, "Wallhack", player); 43 | 44 | if (GetStatus(commandName, player)) 45 | { 46 | player DoWallhack(true); 47 | player thread ThreadWallhack(); 48 | } 49 | else 50 | { 51 | player DoWallhack(false); 52 | player notify("chat_commands_wallhack_off"); 53 | } 54 | } 55 | 56 | ThreadWallhack() 57 | { 58 | self endon("disconnect"); 59 | self endon("chat_commands_wallhack_off"); 60 | 61 | for(;;) 62 | { 63 | self waittill("spawned_player"); 64 | 65 | DoWallhack(true); 66 | } 67 | } 68 | 69 | DoWallhack(enabled) 70 | { 71 | if (enabled) 72 | { 73 | self ThermalVisionFOFOverlayOn(); 74 | } 75 | else 76 | { 77 | self ThermalVisionFOFOverlayOff(); 78 | } 79 | } -------------------------------------------------------------------------------- /chat_commands/chat_commands.gsc: -------------------------------------------------------------------------------- 1 | /* 2 | ========================================================================== 3 | | Game: Plutonium IW5 | 4 | | Description : Display text and run GSC code | 5 | | by typing commands in the chat | 6 | | Author: Resxt | 7 | ========================================================================== 8 | | https://github.com/Resxt/Plutonium-IW5-Scripts/tree/main/chat_commands | 9 | ========================================================================== 10 | */ 11 | 12 | 13 | 14 | /* Init section */ 15 | 16 | Main() 17 | { 18 | InitChatCommands(); 19 | } 20 | 21 | InitChatCommands() 22 | { 23 | InitChatCommandsDvars(); 24 | 25 | level.chat_commands = []; // don't touch 26 | level.chat_commands["ports"] = ["27016", "27017"]; // an array of the ports of all your servers you want to have the script running on. This is useful to easily pass this array as first arg of CreateCommand to have the command on all your servers 27 | level.chat_commands["no_commands_message"] = ["^1No commands found", "You either ^1didn't add any chat_command file ^7to add a new command ^1or ^7there are ^1no command configured on this port", "chat_commands.gsc is ^1just the base system. ^7It doesn't provide any command on its own", "Also ^1make sure the ports are configured properly ^7in the CreateCommand function of your command file(s)"]; // the lines to print in the chat when the server doesn't have any command added 28 | level.chat_commands["no_commands_wait"] = 6; // time to wait between each line in when printing that specific message in the chat 29 | 30 | level thread OnPlayerConnect(); 31 | level thread ChatListener(); 32 | } 33 | 34 | InitChatCommandsDvars() 35 | { 36 | SetDvarIfNotInitialized("cc_debug", 0); 37 | SetDvarIfNotInitialized("cc_prefix", "!"); 38 | 39 | SetDvarIfNotInitialized("cc_permission_enabled", 0); 40 | SetDvarIfNotInitialized("cc_permission_mode", "name"); 41 | SetDvarIfNotInitialized("cc_permission_default", 1); 42 | SetDvarIfNotInitialized("cc_permission_max", 4); 43 | 44 | for (i = 0; i <= GetDvarInt("cc_permission_max"); i++) 45 | { 46 | SetDvarIfNotInitialized("cc_permission_" + i, ""); 47 | } 48 | } 49 | 50 | 51 | 52 | /* Commands section */ 53 | 54 | /* 55 | the ports of the servers this command will be created for 56 | the name of the command, this is what players will type in the chat 57 | the type of the command: is for arrays of text to display text in the player's chat and is to execute a function 58 | when is "text" this is an array of lines to print in the chat. When is "function" this is a function pointer (a reference to a function) 59 | (optional, if no value is provided then anyone who's permission level is default or above can run the command) the minimum permission level required to run this command. For example if this is set to 3 then any user with permission level 3 or 4 will be able to run this command 60 | (optional) an array of the lines to print when typing the help command in the chat followed by a command name. You can also pass an array of one preset string to have it auto generated, for example: ["default_help_one_player"] 61 | */ 62 | CreateCommand(serverPorts, commandName, commandType, commandValue, commandMinimumPermission, commandHelp, commandAliases) 63 | { 64 | currentPort = GetDvar("net_port"); 65 | commandName = ToLower(commandName); // always create commands in lower case to avoid any potential casing issue 66 | 67 | foreach (serverPort in serverPorts) 68 | { 69 | if (serverPort == currentPort) 70 | { 71 | level.commands[serverPort][commandName]["type"] = commandType; 72 | 73 | if (IsDefined(commandHelp) && commandHelp.size > 0) 74 | { 75 | commandHelpMessage = commandHelp; 76 | commandHelpString = commandHelp[0]; 77 | 78 | if (commandHelpString == "default_help_one_player") 79 | { 80 | commandHelpMessage = ["Example: " + GetDvar("cc_prefix") + commandName + " me", "Example: " + GetDvar("cc_prefix") + commandName + " Resxt"]; 81 | } 82 | else if (commandHelpString == "default_help_two_players") 83 | { 84 | commandHelpMessage = ["Example: " + GetDvar("cc_prefix") + commandName + " me Resxt", "Example: " + GetDvar("cc_prefix") + commandName + " Resxt me", "Example: " + GetDvar("cc_prefix") + commandName + " Resxt Eldor"]; 85 | } 86 | 87 | level.commands[serverPort][commandName]["help"] = commandHelpMessage; 88 | } 89 | 90 | if (commandType == "text") 91 | { 92 | level.commands[serverPort][commandName]["text"] = commandValue; 93 | } 94 | else if (commandType == "function") 95 | { 96 | level.commands[serverPort][commandName]["function"] = commandValue; 97 | } 98 | 99 | if (IsDefined(commandAliases) && commandAliases.size > 0) 100 | { 101 | level.commands[serverPort][commandName]["aliases"] = commandAliases; 102 | } 103 | 104 | if (IsDefined(commandMinimumPermission)) 105 | { 106 | level.commands[serverPort][commandName]["permission"] = commandMinimumPermission; 107 | } 108 | else 109 | { 110 | level.commands[serverPort][commandName]["permission"] = GetDvarInt("cc_permission_default"); 111 | } 112 | } 113 | } 114 | } 115 | 116 | ExecuteChatCommand(command, args, player) 117 | { 118 | if (command["type"] == "text") 119 | { 120 | player thread TellPlayer(command["text"], 2); 121 | } 122 | else if (command["type"] == "function") 123 | { 124 | error = player [[command["function"]]](args); 125 | 126 | if (IsDefined(error)) 127 | { 128 | player thread TellPlayer(error, 1.5); 129 | } 130 | } 131 | } 132 | 133 | TryExecuteChatCommand(commandValue, commandName, args, player) 134 | { 135 | if (!PermissionIsEnabled() || PlayerHasSufficientPermissions(player, commandValue["permission"])) 136 | { 137 | ExecuteChatCommand(commandValue, args, player); 138 | } 139 | else 140 | { 141 | player thread TellPlayer(InsufficientPermissionError(player GetPlayerPermissionLevel(), commandName, commandValue["permission"]), 1.5); 142 | } 143 | } 144 | 145 | 146 | 147 | /* Chat section */ 148 | 149 | ChatListener() 150 | { 151 | while (true) 152 | { 153 | level waittill("say", message, player); 154 | 155 | if (message[0] != GetDvar("cc_prefix")) // For some reason checking for the buggy character doesn't work so we start at the second character if the first isn't the command prefix 156 | { 157 | message = GetSubStr(message, 1); // Remove the random/buggy character at index 0, get the real message 158 | } 159 | 160 | if (message[0] != GetDvar("cc_prefix")) // If the message doesn't start with the command prefix 161 | { 162 | continue; // stop 163 | } 164 | 165 | if (PermissionIsEnabled() && player GetPlayerPermissionLevel() == 0) 166 | { 167 | player thread TellPlayer(InsufficientPermissionError(0), 1); 168 | continue; // stop 169 | } 170 | 171 | commandArray = StrTok(message, " "); // Separate the command by space character. Example: ["!map", "mp_dome"] 172 | command = ToLower(commandArray[0]); // The command as text in lower text to support any casing. Example: !map 173 | args = []; // The arguments passed to the command. Example: ["mp_dome"] 174 | arg = ""; 175 | 176 | for (i = 1; i < commandArray.size; i++) 177 | { 178 | checkedArg = commandArray[i]; 179 | 180 | if (checkedArg[0] != "'" && arg == "") 181 | { 182 | args = AddElementToArray(args, checkedArg); 183 | } 184 | else if (checkedArg[0] == "'") 185 | { 186 | arg = StrTok(checkedArg, "'")[0] + " "; 187 | } 188 | else if (checkedArg[checkedArg.size - 1] == "'") 189 | { 190 | args = AddElementToArray(args, (arg + StrTok(checkedArg, "'")[0])); 191 | arg = ""; 192 | } 193 | else 194 | { 195 | arg += (checkedArg + " "); 196 | } 197 | } 198 | 199 | if (IsDefined(level.commands[GetDvar("net_port")])) 200 | { 201 | if (command == GetDvar("cc_prefix") + "commands") // commands command 202 | { 203 | if (GetDvarInt("cc_permission_enabled")) 204 | { 205 | playerCommands = []; 206 | 207 | foreach (commandName in GetArrayKeys(level.commands[GetDvar("net_port")])) 208 | { 209 | if (PlayerHasSufficientPermissions(player, level.commands[GetDvar("net_port")][commandName]["permission"])) 210 | { 211 | playerCommands = AddElementToArray(playerCommands, commandName); 212 | } 213 | } 214 | 215 | player thread TellPlayer(playerCommands, 2, true); 216 | } 217 | else 218 | { 219 | player thread TellPlayer(GetArrayKeys(level.commands[GetDvar("net_port")]), 2, true); 220 | } 221 | } 222 | // help command (with args, for example help godmode) 223 | else if (command == GetDvar("cc_prefix") + "help" && !IsDefined(level.commands[GetDvar("net_port")]["help"]) || command == GetDvar("cc_prefix") + "help" && IsDefined(level.commands[GetDvar("net_port")]["help"]) && args.size >= 1) 224 | { 225 | if (args.size < 1) 226 | { 227 | player thread TellPlayer(NotEnoughArgsError(1), 1.5); 228 | } 229 | else 230 | { 231 | commandValue = level.commands[GetDvar("net_port")][args[0]]; 232 | 233 | if (IsDefined(commandValue)) 234 | { 235 | if (!PermissionIsEnabled() || PlayerHasSufficientPermissions(player, commandValue["permission"])) 236 | { 237 | commandHelp = commandValue["help"]; 238 | 239 | if (IsDefined(commandHelp)) 240 | { 241 | player thread TellPlayer(commandHelp, 1.5); 242 | } 243 | else 244 | { 245 | player thread TellPlayer(CommandHelpDoesNotExistError(args[0]), 1); 246 | } 247 | } 248 | else 249 | { 250 | player thread TellPlayer(InsufficientPermissionError(player GetPlayerPermissionLevel(), args[0], commandValue["permission"]), 1.5); 251 | } 252 | } 253 | else 254 | { 255 | originalCommandName = ToLower(GetCommandNameFromAlias(args[0])); 256 | 257 | if (args[0] == "commands" || args[0] == "help" || args[0] == "aliases" || args[0] == "alias") 258 | { 259 | player thread TellPlayer(CommandHelpDoesNotExistError(args[0]), 1); 260 | } 261 | else if (args[0] == originalCommandName) // the command wasn't found while searching by its name and all the commands aliases 262 | { 263 | player thread TellPlayer(CommandDoesNotExistError(args[0]), 1); 264 | } 265 | else 266 | { 267 | commandHelp = level.commands[GetDvar("net_port")][originalCommandName]["help"]; 268 | 269 | if (IsDefined(commandHelp)) 270 | { 271 | if (!PermissionIsEnabled() || PlayerHasSufficientPermissions(player, level.commands[GetDvar("net_port")][originalCommandName]["permission"])) 272 | { 273 | player thread TellPlayer(commandHelp, 1.5); 274 | } 275 | else 276 | { 277 | player thread TellPlayer(InsufficientPermissionError(player GetPlayerPermissionLevel(), args[0], level.commands[GetDvar("net_port")][originalCommandName]["permission"]), 1.5); 278 | } 279 | } 280 | else 281 | { 282 | player thread TellPlayer(CommandHelpDoesNotExistError(args[0]), 1); 283 | } 284 | } 285 | } 286 | } 287 | } 288 | else if (command == GetDvar("cc_prefix") + "alias" || command == GetDvar("cc_prefix") + "aliases") // alias/aliases command 289 | { 290 | if (args.size < 1) 291 | { 292 | player thread TellPlayer(NotEnoughArgsError(1), 1.5); 293 | } 294 | else 295 | { 296 | commandValue = level.commands[GetDvar("net_port")][args[0]]; 297 | 298 | if (IsDefined(commandValue)) 299 | { 300 | if (!PermissionIsEnabled() || PlayerHasSufficientPermissions(player, commandValue["permission"])) 301 | { 302 | commandAliases = commandValue["aliases"]; 303 | 304 | if (IsDefined(commandAliases) && commandAliases.size > 0) 305 | { 306 | player thread TellPlayer(commandAliases, 1.5); 307 | } 308 | else 309 | { 310 | player thread TellPlayer(CommandAliasesDoesNotExistError(args[0]), 1); 311 | } 312 | } 313 | else 314 | { 315 | player thread TellPlayer(InsufficientPermissionError(player GetPlayerPermissionLevel(), args[0], commandValue["permission"]), 1.5); 316 | } 317 | } 318 | else 319 | { 320 | originalCommandName = ToLower(GetCommandNameFromAlias(args[0])); 321 | 322 | if (args[0] == "commands" || args[0] == "help" || args[0] == "aliases" || args[0] == "alias") 323 | { 324 | player thread TellPlayer(CommandAliasesDoesNotExistError(args[0]), 1); 325 | } 326 | else if (args[0] == originalCommandName) // the command wasn't found while searching by its name and all the commands aliases 327 | { 328 | player thread TellPlayer(CommandDoesNotExistError(args[0]), 1); 329 | } 330 | else 331 | { 332 | commandAliases = level.commands[GetDvar("net_port")][originalCommandName]["aliases"]; 333 | 334 | if (IsDefined(commandAliases)) 335 | { 336 | if (!PermissionIsEnabled() || PlayerHasSufficientPermissions(player, level.commands[GetDvar("net_port")][originalCommandName]["permission"])) 337 | { 338 | commandAliases = AddElementToArray(commandAliases, originalCommandName); 339 | 340 | player thread TellPlayer(commandAliases, 1.5); 341 | } 342 | else 343 | { 344 | player thread TellPlayer(InsufficientPermissionError(player GetPlayerPermissionLevel(), args[0], level.commands[GetDvar("net_port")][originalCommandName]["permission"]), 1.5); 345 | } 346 | } 347 | else 348 | { 349 | player thread TellPlayer(CommandAliasesDoesNotExistError(args[0]), 1); 350 | } 351 | } 352 | } 353 | } 354 | } 355 | else // any other command 356 | { 357 | inputCommandName = GetSubStr(command, 1); 358 | commandValue = level.commands[GetDvar("net_port")][inputCommandName]; 359 | 360 | if (IsDefined(commandValue)) // try to find the command by its original name 361 | { 362 | TryExecuteChatCommand(commandValue, inputCommandName, args, player); 363 | } 364 | else // try to find the command by one of its aliases 365 | { 366 | originalCommandName = ToLower(GetCommandNameFromAlias(inputCommandName)); 367 | 368 | if (inputCommandName == originalCommandName) // the command wasn't found while searching by its name and all the commands aliases 369 | { 370 | player thread TellPlayer(CommandDoesNotExistError(inputCommandName), 1); 371 | } 372 | else 373 | { 374 | TryExecuteChatCommand(level.commands[GetDvar("net_port")][originalCommandName], inputCommandName, args, player); 375 | } 376 | } 377 | } 378 | } 379 | else 380 | { 381 | player thread TellPlayer(level.chat_commands["no_commands_message"], level.chat_commands["no_commands_wait"], false); 382 | } 383 | } 384 | } 385 | 386 | TellPlayer(messages, waitTime, isCommand) 387 | { 388 | for (i = 0; i < messages.size; i++) 389 | { 390 | message = messages[i]; 391 | 392 | if (IsDefined(isCommand) && isCommand) 393 | { 394 | message = GetDvar("cc_prefix") + message; 395 | } 396 | 397 | self tell(message); 398 | 399 | if (i < (messages.size - 1)) // Don't unnecessarily wait after the last message has been displayed 400 | { 401 | wait waitTime; 402 | } 403 | } 404 | } 405 | 406 | 407 | 408 | /* Player section */ 409 | 410 | OnPlayerConnect() 411 | { 412 | for(;;) 413 | { 414 | level waittill("connected", player); 415 | 416 | if (player IsBot()) 417 | { 418 | continue; // stop 419 | } 420 | 421 | if (!IsDefined(player.pers["chat_commands"])) 422 | { 423 | player.pers["chat_commands"] = []; 424 | 425 | if (DebugIsOn()) 426 | { 427 | Print("GUID of " + player.name + ": " + player.guid); 428 | } 429 | } 430 | 431 | player SetPlayerPermissionLevel(player GetPlayerPermissionLevelFromDvar()); 432 | } 433 | } 434 | 435 | 436 | 437 | /* Error functions section */ 438 | 439 | CommandDoesNotExistError(commandName) 440 | { 441 | return ["The command " + commandName + " doesn't exist", "Type " + GetDvar("cc_prefix") + "commands to get a list of commands"]; 442 | } 443 | 444 | CommandHelpDoesNotExistError(commandName) 445 | { 446 | return ["The command " + commandName + " doesn't have any help message"]; 447 | } 448 | 449 | CommandAliasesDoesNotExistError(commandName) 450 | { 451 | return ["The command " + commandName + " doesn't have any alias"]; 452 | } 453 | 454 | InsufficientPermissionError(playerPermissionLevel, commandName, requiredPermissionLevel) 455 | { 456 | if (playerPermissionLevel == 0) 457 | { 458 | return ["You don't have the permissions to run any command"]; 459 | } 460 | 461 | return ["Access to the ^5" + commandName + " ^7command refused", "Your permission level is ^5" + playerPermissionLevel + " ^7and the minimum permission level for this command is ^5" + requiredPermissionLevel]; 462 | } 463 | 464 | InvalidPermissionLevelError(requestedPermissionLevel) 465 | { 466 | return ["^5" + requestedPermissionLevel + " ^7is not a valid permission level", "Permission levels range from ^50 ^7to ^5" + GetDvarInt("cc_permission_max")]; 467 | } 468 | 469 | NotEnoughArgsError(minimumArgs) 470 | { 471 | return ["Not enough arguments supplied", "At least " + minimumArgs + " argument expected"]; 472 | } 473 | 474 | PlayerDoesNotExistError(playerName) 475 | { 476 | return ["Player " + playerName + " was not found"]; 477 | } 478 | 479 | DvarDoesNotExistError(dvarName) 480 | { 481 | return ["The dvar " + dvarName + " doesn't exist"]; 482 | } 483 | 484 | CamoDoesNotExistError(camoName) 485 | { 486 | return ["The camo " + camoName + " doesn't exist"]; 487 | } 488 | 489 | 490 | 491 | /* Utils section */ 492 | 493 | FindPlayerByName(name) 494 | { 495 | if (ToLower(name) == "me") 496 | { 497 | return self; 498 | } 499 | 500 | potentialPlayersFound = 0; 501 | foundPlayer = undefined; 502 | 503 | foreach (player in level.players) 504 | { 505 | if (ToLower(player.name) == ToLower(name)) // if we get an exact match return the player 506 | { 507 | return player; 508 | } 509 | 510 | if (ToLower(GetSubStr(player.name, 0, name.size)) == ToLower(name)) // found a player who's name starts with the given text 511 | { 512 | potentialPlayersFound++; 513 | } 514 | 515 | if (potentialPlayersFound == 1 && !IsDefined(foundPlayer)) // store the first player we find, since we only return one if and only if it only finds one 516 | { 517 | foundPlayer = player; 518 | } 519 | } 520 | 521 | if (potentialPlayersFound == 1) // we only found one player who's name starts with the given text so it's safe to return the player we found 522 | { 523 | return foundPlayer; 524 | } 525 | } 526 | 527 | ToggleStatus(commandName, commandDisplayName, player) 528 | { 529 | SetStatus(commandName, player, !GetStatus(commandName, player)); 530 | 531 | statusMessage = "^2ON"; 532 | 533 | if (!GetStatus(commandName, player)) 534 | { 535 | statusMessage = "^1OFF"; 536 | } 537 | 538 | if (self.name == player.name) 539 | { 540 | self TellPlayer(["You changed your " + commandDisplayName + " status to " + statusMessage], 1); 541 | } 542 | else 543 | { 544 | self TellPlayer([player.name + " " + commandDisplayName + " status changed to " + statusMessage], 1); 545 | player TellPlayer([self.name + " changed your " + commandDisplayName + " status to " + statusMessage], 1); 546 | } 547 | } 548 | 549 | GetStatus(commandName, player) 550 | { 551 | if (!IsDefined(player.pers["chat_commands"])) // avoid undefined errors in the console 552 | { 553 | player.pers["chat_commands"] = []; 554 | } 555 | 556 | if (!IsDefined(player.pers["chat_commands"]["status"])) // avoid undefined errors in the console 557 | { 558 | player.pers["chat_commands"]["status"] = []; 559 | } 560 | 561 | if (!IsDefined(player.pers["chat_commands"]["status"][commandName])) // status is set to OFF/false by default 562 | { 563 | SetStatus(commandName, player, false); 564 | } 565 | 566 | return player.pers["chat_commands"]["status"][commandName]; 567 | } 568 | 569 | SetStatus(commandName, player, status) 570 | { 571 | player.pers["chat_commands"]["status"][commandName] = status; 572 | } 573 | 574 | GetPlayerPermissionLevelFromDvar() 575 | { 576 | for (dvarIndex = GetDvarInt("cc_permission_max"); dvarIndex > 0; dvarIndex--) 577 | { 578 | dvarName = "cc_permission_" + dvarIndex; 579 | 580 | foreach (value in StrTok(GetDvar(dvarName), ":")) 581 | { 582 | if (GetDvar("cc_permission_mode") == "name") 583 | { 584 | if (ToLower(value) == ToLower(self.name)) 585 | { 586 | return dvarIndex; 587 | } 588 | } 589 | else 590 | { 591 | if (value == self.guid) 592 | { 593 | return dvarIndex; 594 | } 595 | } 596 | } 597 | } 598 | 599 | return GetDvarInt("cc_permission_default"); 600 | } 601 | 602 | GetPlayerPermissionLevel() 603 | { 604 | return self.pers["chat_commands"]["permission_level"]; 605 | } 606 | 607 | SetPlayerPermissionLevel(newPermissionLevel) 608 | { 609 | self.pers["chat_commands"]["permission_level"] = newPermissionLevel; 610 | } 611 | 612 | PlayerHasSufficientPermissions(player, targetedPermissionLevel) 613 | { 614 | playerPermissionLevel = player GetPlayerPermissionLevel(); 615 | 616 | if (playerPermissionLevel == 0) 617 | { 618 | return false; 619 | } 620 | 621 | if (!IsDefined(targetedPermissionLevel)) 622 | { 623 | return true; 624 | } 625 | 626 | return playerPermissionLevel >= targetedPermissionLevel; 627 | } 628 | 629 | /* 630 | Returns the original command name of if it exists 631 | If is not a valid alias then it just returns itself meaning it didn't find a related command 632 | */ 633 | GetCommandNameFromAlias(aliasToFind) 634 | { 635 | aliasToFind = ToLower(aliasToFind); 636 | 637 | foreach (commandName in GetArrayKeys(level.commands[GetDvar("net_port")])) 638 | { 639 | if (IsDefined(level.commands[GetDvar("net_port")][commandName]["aliases"])) 640 | { 641 | foreach (alias in level.commands[GetDvar("net_port")][commandName]["aliases"]) 642 | { 643 | if (alias == aliasToFind) 644 | { 645 | return commandName; 646 | } 647 | } 648 | } 649 | } 650 | 651 | return aliasToFind; 652 | } 653 | 654 | DvarIsInitialized(dvarName) 655 | { 656 | result = GetDvar(dvarName); 657 | return result != ""; 658 | } 659 | 660 | SetDvarIfNotInitialized(dvarName, dvarValue) 661 | { 662 | if (!DvarIsInitialized(dvarName)) 663 | { 664 | SetDvar(dvarName, dvarValue); 665 | } 666 | } 667 | 668 | IsBot() 669 | { 670 | return IsDefined(self.pers["isBot"]) && self.pers["isBot"]; 671 | } 672 | 673 | TargetIsMyself(targetName) 674 | { 675 | return ToLower(targetName) == "me" || ToLower(targetName) == ToLower(self.name); 676 | } 677 | 678 | GetWeaponNameWithoutCamo(weaponName) 679 | { 680 | return (IsSubStr(weaponName, "_camo") ? GetSubStr(weaponName, 0, weaponName.size - 7) : weaponName); 681 | } 682 | 683 | GetCamoNameFromNameOrIndex(camoNameOrIndex) 684 | { 685 | switch(camoNameOrIndex) 686 | { 687 | case "none": 688 | case "0": 689 | return ""; 690 | 691 | case "classic": 692 | case "1": 693 | return "_camo01"; 694 | 695 | case "snow": 696 | case "2": 697 | return "_camo02"; 698 | 699 | case "multicam": 700 | case "3": 701 | return "_camo03"; 702 | 703 | case "digitalurban": 704 | case "digital urban": 705 | case "digital": 706 | case "urban": 707 | case "4": 708 | return "_camo04"; 709 | 710 | case "hex": 711 | case "5": 712 | return "_camo05"; 713 | 714 | case "choco": 715 | case "6": 716 | return "_camo06"; 717 | 718 | case "snake": 719 | case "7": 720 | return "_camo07"; 721 | 722 | case "blue": 723 | case "8": 724 | return "_camo08"; 725 | 726 | case "red": 727 | case "9": 728 | return "_camo09"; 729 | 730 | case "autumn": 731 | case "10": 732 | return "_camo10"; 733 | 734 | case "gold": 735 | case "11": 736 | return "_camo11"; 737 | 738 | case "marine": 739 | case "12": 740 | return "_camo12"; 741 | 742 | case "winter": 743 | case "13": 744 | return "_camo13"; 745 | } 746 | } 747 | 748 | AddElementToArray(array, element) 749 | { 750 | array[array.size] = element; 751 | return array; 752 | } 753 | 754 | DebugIsOn() 755 | { 756 | return GetDvarInt("cc_debug"); 757 | } 758 | 759 | PermissionIsEnabled() 760 | { 761 | return GetDvarInt("cc_permission_enabled"); 762 | } 763 | -------------------------------------------------------------------------------- /cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Resxt/Plutonium-IW5-Scripts/082c3b53fadcb16b3294cf7f183db2cb8d87c45c/cover.jpg -------------------------------------------------------------------------------- /custom_killstreaks_rewards/README.md: -------------------------------------------------------------------------------- 1 | # Custom Killstreak Rewards 2 | 3 | Scripts that give the players different weapons or perks depending on their current killstreak or total kills count 4 | 5 | ## launchers_weapons_rewards.gsc 6 | 7 | Gives the player a new weapon every time he reaches a new tier. 8 | `WeaponIsValid()` ensures that the rewards are only given if the player's spawn weapon is a launcher. 9 | If the player reaches the last tier the loop restarts allowing players to get tiers several time per life if they ever get enough kills. 10 | For example with this script if you get 50 kills in a row you would get the AC130 105mm two times. 11 | This is how the script is configured 12 | 13 | * 5 kills: M320 14 | * 10 kills: RPG 15 | * 15 kills: AC130 40mm 16 | * 25 kills: AC130 105mm 17 | * 35 kills: Spawn weapon 18 | 19 | This script also whitelists the AC130 for the kill counts. 20 | This is useful to make sure kills are properly tracked on kill counters scripts. 21 | This also removes the killstreak protection players have after spawning. 22 | 23 | ## automatic_weapons_rewards.gsc 24 | 25 | A re-creation of the gun game mode with a bit more configuration. 26 | Every game the script picks random (and unique) weapons from `level.available_weapon_rewards` to populate `weapon_rewards`. 27 | Whenever a player reaches a new tier (defined with `weapon_switch_kills`) he will get the next weapon. 28 | 29 | If you ask for more weapon than the max amount of available weapons then the unique check is removed when all weapons were given. 30 | This ensures that all weapons are unique and that if you want more weapons than the max amount available you have each weapon at least once. 31 | 32 | `InitWeaponRewards()` allow you to have random weapons only or to hard code the last weapon in your games. 33 | You can also enable or disable `bots_earn_rewards` to change whether bots can earn weapons too. 34 | 35 | Because this is based around the server's kill limit and the player's current total kills this only works on kill based game modes (FFA, TDM etc.) 36 | If you want to use this on objective based game modes you will have to read the script and make some modifications. 37 | 38 | By default the script sets the score limit to 80 kills and the time limit to 10 minutes and gives you a new weapon every 10 kills. 39 | Whenever you reach 70 kills it will always give you the `ac130_25mm_mp` weapon. -------------------------------------------------------------------------------- /custom_killstreaks_rewards/automatic_weapons_rewards.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\_utility; 2 | 3 | // This is required by killShouldAddToKillstreak() 4 | KILLSTREAK_GIMME_SLOT = 0; 5 | KILLSTREAK_SLOT_1 = 1; 6 | KILLSTREAK_SLOT_2 = 2; 7 | KILLSTREAK_SLOT_3 = 3; 8 | KILLSTREAK_ALL_PERKS_SLOT = 4; 9 | KILLSTREAK_STACKING_START_SLOT = 5; 10 | 11 | Main() 12 | { 13 | replacefunc(maps\mp\_utility::killShouldAddToKillstreak, ::WhitelistKillstreaksInKillsCount); 14 | } 15 | 16 | Init() 17 | { 18 | kills_limit = 80; // Override score limit (required to make the script sync with how much kills is the limit) 19 | time_limit = 10; // Override time limit (optional, see SetLimits() reference) 20 | weapon_switch_kills = 10; // Every weapon_switch_kills the player's weapon will change (this is total kills, not killstreak) 21 | 22 | // Note that if you want to let bots earn rewards you need to disable custom classes or remove/change the WeaponIsValid() check in WeaponReward() 23 | level.bots_earn_rewards = true; 24 | // Create a class with the weapon and attachements you want and uncomment the Debug() line in OnPlayerSpawned() to get the full weapon name with attachments when you spawn 25 | level.available_weapon_rewards = [ 26 | "iw5_m4_mp_reflex_silencer", 27 | "iw5_scar_mp_reflex_silencer", 28 | "iw5_cm901_mp_reflex_silencer", 29 | "iw5_g36c_mp_reflex_silencer", 30 | "iw5_acr_mp_reflex_silencer", 31 | "iw5_ak47_mp_reflex_silencer", 32 | "iw5_fad_mp_reflex_silencer", 33 | "iw5_mp5_mp_reflexsmg_silencer", 34 | "iw5_ump45_mp_reflexsmg_silencer", 35 | "iw5_pp90m1_mp_reflexsmg_silencer", 36 | "iw5_p90_mp_reflexsmg_silencer", 37 | "iw5_m9_mp_reflexsmg_silencer", 38 | "iw5_mp7_mp_reflexsmg_silencer", 39 | "iw5_ak74u_mp_reflexsmg_silencer", 40 | "iw5_sa80_mp_reflexlmg_silencer", 41 | "iw5_mg36_mp_reflexlmg_silencer", 42 | "iw5_pecheneg_mp_reflexlmg_silencer", 43 | "iw5_mk46_mp_reflexlmg_silencer", 44 | "iw5_m60_mp_reflexlmg_silencer", 45 | "iw5_dragunov_mp_acog_silencer03", 46 | "iw5_rsass_mp_acog_silencer03" 47 | ]; 48 | 49 | level.killstreakSpawnShield = 0; // Disable anti killstreak protection on player spawn 50 | level.weapon_rewards = []; 51 | 52 | SetLimits(kills_limit, time_limit); 53 | InitWeaponRewards(kills_limit, weapon_switch_kills, "ac130_25mm_mp"); 54 | 55 | level thread OnPlayerConnect(); 56 | } 57 | 58 | OnPlayerConnect() 59 | { 60 | for(;;) 61 | { 62 | level waittill("connected", player); 63 | player thread OnPlayerSpawned(); 64 | } 65 | } 66 | 67 | OnPlayerSpawned() 68 | { 69 | self endon("disconnect"); 70 | for(;;) 71 | { 72 | self waittill("spawned_player"); 73 | 74 | if (!level.bots_earn_rewards) 75 | { 76 | if (isDefined(self.pers["isBot"])) 77 | { 78 | if (self.pers["isBot"]) 79 | { 80 | return; 81 | } 82 | } 83 | } 84 | 85 | // Debug(self GetCurrentWeapon()); 86 | 87 | self thread WeaponReward(); 88 | } 89 | } 90 | 91 | // time_limit is optional 92 | SetLimits(kills_limit, time_limit) 93 | { 94 | score_multiplier = 0; 95 | 96 | switch (level.gameType) 97 | { 98 | case "dm": 99 | score_multiplier = 50; 100 | break; 101 | case "war": 102 | score_multiplier = 100; 103 | break; 104 | default: 105 | score_multiplier = 50; 106 | break; 107 | } 108 | 109 | SetDvar("scr_" + level.gameType + "_scorelimit", kills_limit * score_multiplier); 110 | SetDvar("scorelimit", kills_limit * score_multiplier); 111 | 112 | if (IsDefined(time_limit)) 113 | { 114 | SetDvar("scr_" + level.gameType + "_timelimit", time_limit); 115 | SetDvar("timelimit", time_limit); 116 | } 117 | } 118 | 119 | // The third parameter is optional. Without this parameter all weapons will be random. With a weapon passed as third parameter the last weapon will be the weapon of your choice 120 | InitWeaponRewards(kills_limit, weapon_switch_kills, last_weapon) 121 | { 122 | condition = kills_limit; 123 | if (IsDefined(last_weapon)) 124 | { 125 | condition = kills_limit - weapon_switch_kills; 126 | } 127 | 128 | for (i = 0; i < condition; i = i + weapon_switch_kills) 129 | { 130 | is_unique = false; 131 | 132 | while (!is_unique) 133 | { 134 | random_weapon = GetRandomElementFromArray(level.available_weapon_rewards); 135 | 136 | weapon_already_exist = false; 137 | 138 | foreach (value in level.weapon_rewards) 139 | { 140 | if (value[1] == random_weapon) 141 | { 142 | weapon_already_exist = true; 143 | break; 144 | } 145 | } 146 | 147 | // If we already gave all the available weapons force the unique check to false so that we can keep giving weapons 148 | if (level.weapon_rewards.size >= level.available_weapon_rewards.size) 149 | { 150 | weapon_already_exist = false; 151 | } 152 | 153 | if (weapon_already_exist) 154 | { 155 | weapon_already_exist = false; 156 | } 157 | else 158 | { 159 | is_unique = true; 160 | level.weapon_rewards[level.weapon_rewards.size] = [i, random_weapon]; 161 | } 162 | } 163 | } 164 | 165 | if (IsDefined(last_weapon)) 166 | { 167 | level.weapon_rewards[level.weapon_rewards.size] = [kills_limit - weapon_switch_kills, last_weapon]; 168 | 169 | // Because CheckWeaponReward() always excepts a next element we have to add a fake element so that the last element can still be compared with something, ignore this 170 | level.weapon_rewards[level.weapon_rewards.size] = [kills_limit, last_weapon]; 171 | } 172 | else 173 | { 174 | // Because CheckWeaponReward() always excepts a next element we have to add a fake element so that the last element can still be compared with something, ignore this 175 | level.weapon_rewards[level.weapon_rewards.size] = [kills_limit, "none"]; 176 | } 177 | } 178 | 179 | WeaponReward() 180 | { 181 | self endon ("disconnect"); 182 | level endon("game_ended"); 183 | 184 | spawn_weapon = self GetCurrentWeapon(); 185 | 186 | if (WeaponIsValid(spawn_weapon)) 187 | { 188 | while(true) 189 | { 190 | CheckWeaponReward(level.weapon_rewards, spawn_weapon); 191 | wait 0.01; 192 | } 193 | } 194 | } 195 | 196 | CheckWeaponReward(weapon_rewards, spawn_weapon) 197 | { 198 | player_kills = self.pers["kills"]; 199 | 200 | for (i = 0; i < weapon_rewards.size; i++) 201 | { 202 | if (player_kills >= weapon_rewards[i][0] && player_kills < weapon_rewards[i+1][0]) 203 | { 204 | if (self GetCurrentWeapon() == spawn_weapon) 205 | { 206 | self.pers["weapons_reward_tier"] = weapon_rewards[i][0]; 207 | ReplaceWeapon(weapon_rewards[i][1]); 208 | break; 209 | } 210 | else if (i > 0 && self GetCurrentWeapon() == weapon_rewards[i-1][1]) 211 | { 212 | self.pers["weapons_reward_tier"] = weapon_rewards[i][0]; 213 | ReplaceWeapon(weapon_rewards[i][1]); 214 | break; 215 | } 216 | } 217 | } 218 | } 219 | 220 | ReplaceWeapon(new_weapon) 221 | { 222 | self TakeAllWeapons(); 223 | self GiveWeapon(new_weapon); 224 | self GiveWeapon("flare_mp"); // Tactical insertion - weapon_already_exist in common_mp.ff 225 | self SetSpawnWeapon(new_weapon); // This gives the weapon without playing the animation 226 | } 227 | 228 | WeaponIsValid(weapon) 229 | { 230 | switch (weapon) 231 | { 232 | case "iw5_m4_mp_shotgun_thermal": 233 | return true; 234 | default: 235 | return false; 236 | } 237 | } 238 | 239 | GetRandomElementFromArray( array ) 240 | { 241 | new_array = []; 242 | foreach ( index, value in array ) 243 | { 244 | new_array[ new_array.size ] = value; 245 | } 246 | 247 | if ( !new_array.size ) 248 | return undefined; 249 | 250 | return new_array[ randomint( new_array.size ) ]; 251 | } 252 | 253 | // Allow the AC-130 kills to be counted in player.pers["cur_kill_streak"] 254 | WhitelistKillstreaksInKillsCount( weapon ) 255 | { 256 | if ( self _hasPerk( "specialty_explosivebullets" ) ) 257 | return false; 258 | 259 | if ( IsDefined( self.isJuggernautRecon ) && self.isJuggernautRecon == true ) 260 | return false; 261 | 262 | if (weapon == "ac130_25mm_mp") 263 | return true; 264 | 265 | if ( IsDefined( level.killstreakChainingWeapons[weapon] ) ) 266 | { 267 | for( i = KILLSTREAK_SLOT_1; i < KILLSTREAK_SLOT_3 + 1; i++ ) 268 | { 269 | if( IsDefined( self.pers["killstreaks"][i] ) && 270 | IsDefined( self.pers["killstreaks"][i].streakName ) && 271 | self.pers["killstreaks"][i].streakName == level.killstreakChainingWeapons[weapon] && 272 | IsDefined( self.pers["killstreaks"][i].lifeId ) && 273 | self.pers["killstreaks"][i].lifeId == self.pers["deaths"] ) 274 | { 275 | return self streakShouldChain( level.killstreakChainingWeapons[weapon] ); 276 | } 277 | } 278 | return false; 279 | } 280 | 281 | return !isKillstreakWeapon( weapon ); 282 | } 283 | 284 | // Prints text in the bootstrapper 285 | Debug(text) 286 | { 287 | Print(text); 288 | } -------------------------------------------------------------------------------- /custom_killstreaks_rewards/launchers_weapons_rewards.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\_utility; 2 | 3 | KILLSTREAK_GIMME_SLOT = 0; 4 | KILLSTREAK_SLOT_1 = 1; 5 | KILLSTREAK_SLOT_2 = 2; 6 | KILLSTREAK_SLOT_3 = 3; 7 | KILLSTREAK_ALL_PERKS_SLOT = 4; 8 | KILLSTREAK_STACKING_START_SLOT = 5; 9 | 10 | Main() 11 | { 12 | replacefunc(maps\mp\_utility::killShouldAddToKillstreak, ::WhitelistKillstreaksInKillsCount); 13 | } 14 | 15 | Init() 16 | { 17 | kills_limit = 120; // Override score limit 18 | time_limit = 10; // Override time limit 19 | 20 | level.killstreakSpawnShield = 0; // Disable anti killstreak protection on player spawn 21 | 22 | SetLimits(kills_limit, time_limit); // This is optional 23 | 24 | level thread OnPlayerConnect(); 25 | } 26 | 27 | OnPlayerConnect() 28 | { 29 | for(;;) 30 | { 31 | level waittill("connected", player); 32 | player thread OnPlayerSpawned(); 33 | } 34 | } 35 | 36 | OnPlayerSpawned() 37 | { 38 | self endon("disconnect"); 39 | for(;;) 40 | { 41 | self waittill("spawned_player"); 42 | 43 | if (isDefined(self.pers["isBot"])) 44 | { 45 | if (self.pers["isBot"]) 46 | { 47 | return; 48 | } 49 | } 50 | 51 | self thread WeaponReward(); 52 | } 53 | } 54 | 55 | WeaponReward() 56 | { 57 | self endon ("disconnect"); 58 | level endon("game_ended"); 59 | 60 | spawn_weapon = self GetCurrentWeapon(); 61 | 62 | if (WeaponIsValid(spawn_weapon)) 63 | { 64 | while(true) 65 | { 66 | weapon_rewards = [[5, "m320_mp"], [10, "rpg_mp"], [15, "ac130_40mm_mp"], [25, "ac130_105mm_mp"], [35, spawn_weapon]]; // [kills_required, weapon_reward] 67 | CheckWeaponReward(weapon_rewards); 68 | wait 0.01; 69 | } 70 | } 71 | } 72 | 73 | CheckWeaponReward(weapon_rewards) 74 | { 75 | current_kill_streak = self.pers["cur_kill_streak"]; 76 | 77 | // Whenever a player got all the rewards we force current_kill_streak to still be synchronized with weapon_rewards kills requirements. 78 | // If our last weapon_rewards kill requirement is 35 and current_kill_streak is 36 then current_kill_streak will be changed to 1 (so at 40 kills we'll get the reward for 5 kills again and so on) 79 | last_reward_kills = weapon_rewards[weapon_rewards.size-1][0]; 80 | if (current_kill_streak > last_reward_kills) 81 | { 82 | current_kill_streak = current_kill_streak - (last_reward_kills * floor(current_kill_streak / last_reward_kills)) + 1; 83 | } 84 | 85 | for (i = 0; i < weapon_rewards.size; i++) 86 | { 87 | next_reward = weapon_rewards[i][1]; 88 | if (current_kill_streak >= weapon_rewards[i][0] && current_kill_streak < weapon_rewards[i+1][0] && self GetCurrentWeapon() != next_reward) 89 | { 90 | ReplaceWeapon(next_reward); 91 | break; 92 | } 93 | } 94 | } 95 | 96 | ReplaceWeapon(new_weapon) 97 | { 98 | self TakeAllWeapons(); 99 | self GiveWeapon(new_weapon); 100 | self GiveWeapon("semtex_mp"); // Found in dsr files 101 | self GiveWeapon("flare_mp"); // Tactical insertion - found in common_mp.ff 102 | self SetSpawnWeapon(new_weapon); // This gives the weapon without playing the animation 103 | } 104 | 105 | WeaponIsValid(weapon) 106 | { 107 | switch (weapon) 108 | { 109 | case "iw5_smaw_mp": 110 | return true; 111 | case "rpg_mp": 112 | return true; 113 | case "m320_mp": 114 | return true; 115 | case "xm25_mp": 116 | return true; 117 | case "javelin_mp": 118 | return true; 119 | default: 120 | return false; 121 | } 122 | } 123 | 124 | SetLimits(kills_limit, time_limit) 125 | { 126 | score_multiplier = 0; 127 | 128 | switch (level.gameType) 129 | { 130 | case "dm": 131 | score_multiplier = 50; 132 | break; 133 | case "war": 134 | score_multiplier = 100; 135 | break; 136 | default: 137 | score_multiplier = 50; 138 | break; 139 | } 140 | 141 | SetDvar("scr_" + level.gameType + "_scorelimit", kills_limit * score_multiplier); 142 | SetDvar("scorelimit", kills_limit * score_multiplier); 143 | 144 | if (IsDefined(time_limit)) 145 | { 146 | SetDvar("scr_" + level.gameType + "_timelimit", time_limit); 147 | SetDvar("timelimit", time_limit); 148 | } 149 | } 150 | 151 | // Allow the AC-130 kills to be counted in player.pers["cur_kill_streak"] 152 | WhitelistKillstreaksInKillsCount( weapon ) 153 | { 154 | if ( self _hasPerk( "specialty_explosivebullets" ) ) 155 | return false; 156 | 157 | if ( IsDefined( self.isJuggernautRecon ) && self.isJuggernautRecon == true ) 158 | return false; 159 | 160 | if (weapon == "ac130_40mm_mp") 161 | return true; 162 | 163 | if (weapon == "ac130_105mm_mp") 164 | return true; 165 | 166 | if ( IsDefined( level.killstreakChainingWeapons[weapon] ) ) 167 | { 168 | for( i = KILLSTREAK_SLOT_1; i < KILLSTREAK_SLOT_3 + 1; i++ ) 169 | { 170 | // only if it was earned this life 171 | if( IsDefined( self.pers["killstreaks"][i] ) && 172 | IsDefined( self.pers["killstreaks"][i].streakName ) && 173 | self.pers["killstreaks"][i].streakName == level.killstreakChainingWeapons[weapon] && 174 | IsDefined( self.pers["killstreaks"][i].lifeId ) && 175 | self.pers["killstreaks"][i].lifeId == self.pers["deaths"] ) 176 | { 177 | return self streakShouldChain( level.killstreakChainingWeapons[weapon] ); 178 | } 179 | } 180 | return false; 181 | } 182 | 183 | return !isKillstreakWeapon( weapon ); 184 | } 185 | 186 | // Prints text in the bootstrapper 187 | Debug(text) 188 | { 189 | Print(text); 190 | } -------------------------------------------------------------------------------- /disable_nuke_effects/README.md: -------------------------------------------------------------------------------- 1 | # Disable Nuke Effects 2 | 3 | Using several `disable_nuke_effects` scripts at the same time hasn't been tested but should work as long as they don't replace the same functions. 4 | 5 | ## disable_nuke_effects_vision.gsc 6 | Disables the brown-ish vision applied after a M.O.A.B detonates 7 | 8 | ## disable_nuke_effects_slowmo.gsc 9 | Disables the slow motion effect happening while a M.O.A.B is detonating 10 | 11 | ## disable_nuke_effects_emp.gsc 12 | Disables the EMP effect applied to the losing team for 60 seconds after an enemy M.O.A.B has been detonated 13 | 14 | ## disable_nuke_effects_all_but_fog.gsc 15 | Disables the 3 effects listed above while keeping the fog/smoke that appears in the map for a few second after a M.O.A.B detonates 16 | 17 | ## disable_nuke_effects_all.gsc 18 | Disables all the effects listed above. When a M.O.A.B detonates it will only kill all the players on the other team without any added visual effect -------------------------------------------------------------------------------- /disable_nuke_effects/disable_nuke_effects_all.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\killstreaks\_nuke; 2 | 3 | main() 4 | { 5 | replacefunc(maps\mp\killstreaks\_nuke::nukeVision, ::disableNukeVision); 6 | replacefunc(maps\mp\killstreaks\_nuke::nukeSlowMo, ::disableNukeSlowMo); 7 | replacefunc(maps\mp\killstreaks\_nuke::nuke_EMPJam, ::disableNukeEmp); 8 | replacefunc(maps\mp\killstreaks\_nuke::nukeEffects, ::disableNukeEffects); 9 | } 10 | 11 | disableNukeVision() 12 | { 13 | 14 | } 15 | 16 | disableNukeSlowMo() 17 | { 18 | 19 | } 20 | 21 | disableNukeEmp() 22 | { 23 | 24 | } 25 | 26 | disableNukeEffects() 27 | { 28 | level endon( "nuke_cancelled" ); 29 | setdvar( "ui_bomb_timer", 0 ); 30 | } -------------------------------------------------------------------------------- /disable_nuke_effects/disable_nuke_effects_all_but_fog.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\killstreaks\_nuke; 2 | 3 | main() 4 | { 5 | replacefunc(maps\mp\killstreaks\_nuke::nukeVision, ::disableNukeVision); 6 | replacefunc(maps\mp\killstreaks\_nuke::nukeSlowMo, ::disableNukeSlowMo); 7 | replacefunc(maps\mp\killstreaks\_nuke::nuke_EMPJam, ::disableNukeEmp); 8 | replacefunc(maps\mp\killstreaks\_nuke::nukeEffects, ::disableNukeEffects); 9 | } 10 | 11 | disableNukeVision() 12 | { 13 | 14 | } 15 | 16 | disableNukeSlowMo() 17 | { 18 | 19 | } 20 | 21 | disableNukeEmp() 22 | { 23 | 24 | } 25 | 26 | disableNukeEffects() 27 | { 28 | level endon( "nuke_cancelled" ); 29 | setdvar( "ui_bomb_timer", 0 ); 30 | 31 | foreach ( var_1 in level.players ) 32 | { 33 | var_2 = anglestoforward( var_1.angles ); 34 | var_2 = ( var_2[0], var_2[1], 0 ); 35 | var_2 = vectornormalize( var_2 ); 36 | var_3 = 5000; 37 | var_4 = spawn( "script_model", var_1.origin + var_2 * var_3 ); 38 | var_4 setmodel( "tag_origin" ); 39 | var_4.angles = ( 0, var_1.angles[1] + 180, 90 ); 40 | var_4 thread nukeEffect( var_1 ); 41 | } 42 | } -------------------------------------------------------------------------------- /disable_nuke_effects/disable_nuke_effects_emp.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\killstreaks\_nuke; 2 | 3 | main() 4 | { 5 | replacefunc(maps\mp\killstreaks\_nuke::nuke_EMPJam, ::disableNukeEmp); 6 | } 7 | 8 | disableNukeEmp() 9 | { 10 | 11 | } -------------------------------------------------------------------------------- /disable_nuke_effects/disable_nuke_effects_slowmo.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\killstreaks\_nuke; 2 | 3 | main() 4 | { 5 | replacefunc(maps\mp\killstreaks\_nuke::nukeSlowMo, ::disableNukeSlowMo); 6 | } 7 | 8 | disableNukeSlowMo() 9 | { 10 | 11 | } -------------------------------------------------------------------------------- /disable_nuke_effects/disable_nuke_effects_vision.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\killstreaks\_nuke; 2 | 3 | main() 4 | { 5 | replacefunc(maps\mp\killstreaks\_nuke::nukeVision, ::disableNukeVision); 6 | replacefunc(maps\mp\killstreaks\_nuke::nukeEffects, ::disableNukeEffects); 7 | } 8 | 9 | disableNukeVision() 10 | { 11 | 12 | } 13 | 14 | disableNukeEffects() 15 | { 16 | level endon( "nuke_cancelled" ); 17 | setdvar( "ui_bomb_timer", 0 ); 18 | 19 | foreach ( var_1 in level.players ) 20 | { 21 | var_2 = anglestoforward( var_1.angles ); 22 | var_2 = ( var_2[0], var_2[1], 0 ); 23 | var_2 = vectornormalize( var_2 ); 24 | var_3 = 5000; 25 | var_4 = spawn( "script_model", var_1.origin + var_2 * var_3 ); 26 | var_4 setmodel( "tag_origin" ); 27 | var_4.angles = ( 0, var_1.angles[1] + 180, 90 ); 28 | var_4 thread nukeEffect( var_1 ); 29 | } 30 | } -------------------------------------------------------------------------------- /gamemodes/README.md: -------------------------------------------------------------------------------- 1 | # Gamemodes 2 | 3 | ## all_or_nothing.gsc 4 | 5 | Recreation of the Modern Warfare 3 All or Nothing gamemode based on [the wiki](https://callofduty.fandom.com/wiki/All_or_Nothing_(Game_Mode)#Call_of_Duty:_Modern_Warfare_3). 6 | The bots won't use their throwing knives often and when they do they will use preset grenade spots, they won't directly aim at a player. 7 | 8 | To enable support for Bot Warfare simply uncomment the line where it says `Uncomment if using Bot Warfare`. 9 | 10 | ## chaos.gsc 11 | 12 | A custom modded mode I created that's pretty much.. chaos. The best way to understand what it is to try it with bots. 13 | It's a mode with high jump and high speed where everyone has a weapon that shoots explosive projectiles such as AC-130, Stinger or RPG rockets and so on. 14 | Every 25 kills you get a new weapon with a new explosive to shoot. It's made so that every time you progress you get a weapon that shoots slower and has less bullets but your projecticles cause bigger explosions. 15 | Every game the weapons and explosives are randomized from the list but every player has the same progression, just like a gun game. 16 | 17 | I recommend playing this on [custom maps](https://forum.plutonium.pw/category/27/mw3-modding-releases-resources) that have no/less invisible walls. 18 | In my experience most COD 4 maps don't have a lot of invisible walls so you can jump and bunny hop everywhere on the map. 19 | You might also want to configure the script and your game further, for example by lowering the health to avoid hitmarkers. 20 | I recommend using my [jump_monitor](https://github.com/Resxt/Plutonium-IW5-Scripts/tree/main/small_scripts#jump_monitorgsc) script with this gamemode, it was made to be used with this. 21 | 22 | This was made for FFA/Deathmatch. Some modifications are necessary to get it working in other modes. 23 | Bot Warfare bots are supported but the code for it is disabled by default to avoid getting any error in case Bot Warfare isn't installed. 24 | To enable support for Bot Warfare simply uncomment the lines where it says `Uncomment if using Bot Warfare`. 25 | 26 | ## gun_game.gsc 27 | 28 | Recreation of the popular gun game mode with a good level of customization. 29 | This was made for FFA/Deathmatch. Some modifications are necessary to get it working in other modes. 30 | 31 | Bot Warfare bots are supported but the code for it is disabled by default to avoid getting any error in case Bot Warfare isn't installed. 32 | To enable support for Bot Warfare simply uncomment the lines where it says `Uncomment if using Bot Warfare`. 33 | 34 | :white_check_mark: Features available 35 | 36 | - Configure the amount of weapons per game 37 | - Configure how much chance there is weapons will have a scope attachment 38 | - Configure how much chance there is snipers and shotguns will use the default scope 39 | - Configure how much chance there is a secondary weapon will be akimbo or have a tactical knife 40 | - Configure how much chance there is weapons will have a classic attachment (silencer, heartbeat etc.) 41 | - Configure the percentage of primary weapons to have 42 | - Configure whether you only want primary weapons or secondary weapons only or both 43 | - Configure which categories you don't want (for example accept secondaries but not launchers) 44 | - Configure the uniqueness of weapons. Choose between unique weapons (cannot have the same weapon twice) or weapon + attachments combination (you can have the same weapon but a weapon cannot have the exact same attachment combination twice) or no uniqueness check at all, truly random 45 | - Configure which camos are randomized on the weapons (or have one to always have that camo) 46 | - Configure which attachments are banned globally, per weapon type or per weapon (I banned the attachments that don't exist and the silencer on shotguns by default) 47 | - Akimbo and tactical secondaries with attachments (silencer, scopes etc.) 48 | - Text to display the current player's weapon 49 | - Prevent multi kills from counting as multi kills. A double kill will only make the player go up by one weapon and his score will only go up by 50. 50 | - Play the gun game next weapon sound when the player gets the next weapon and play a sound to all players when a player reaches the last weapon 51 | - Choose which perks to give to the players 52 | - A configurable debug mode to print the array of weapons and also switch weapons when typing in the chat 53 | 54 | :no_entry_sign: Features not available/to add 55 | 56 | - Use dvars instead of GSC arrays 57 | - Configure the weight of each weapon type 58 | - Only FFA is supported. Support for some game modes like TDM and Infected could be added 59 | - These attachments aren't supported: grenade launcher, shotgun, variable scope. 60 | They weren't even tested so if you add them you will need to do some debug 61 | - The stinger isn't supported. A GSC script from another source could give support for player lock-on 62 | - There is no unexpected cases/exceptions handling. For example if you ask for 60 weapons and only want a weapon one time this will create an infinite loop because there are only 51 weapons available 63 | - Some weapons like the AC-130 could be added in a special category later 64 | 65 | ## kamikaze.gsc 66 | 67 | A custom modded mode I created that's really simple. The best way to understand what it is to try it with friends (or bots). 68 | It's a mode with high jump and high speed where everyone has a C4 detonator and needs to run close enough to other players to detonate it and get kills. 69 | Every 5 kills your explosion radius slightly increases and every 15 kills the cooldown between each detonation you can do is lowered. 70 | 71 | This mode could also work really well without high jump and high speed, it's just how I created it to make it a "modded" mode. 72 | If you play it with high jump/speed I recommend playing this on [custom maps](https://forum.plutonium.pw/category/27/mw3-modding-releases-resources) that have no/less invisible walls. 73 | In my experience most COD 4 maps don't have a lot of invisible walls so you can jump and bunny hop everywhere on the map. 74 | I recommend using my [jump_monitor](https://github.com/Resxt/Plutonium-IW5-Scripts/tree/main/small_scripts#jump_monitorgsc) script with this gamemode, it was made to be used with this. 75 | 76 | This was made for FFA/Deathmatch. Some modifications are necessary to get it working in other modes. 77 | Bot Warfare bots are supported but the code for it is disabled by default to avoid getting any error in case Bot Warfare isn't installed. 78 | To enable support for Bot Warfare simply uncomment the lines where it says `Uncomment if using Bot Warfare`. 79 | 80 | ## one_in_the_chamber.gsc 81 | 82 | Recreation of the Modern Warfare 3 One In The Chamber gamemode with infinite lives. 83 | Each game the script will randomly choose a weapon category from the 4 available and pick a random weapon from that category but you can easily change that behavior and add/remove categories and weapons. 84 | Only FFA is supported, other modes require some modifications to work properly. 85 | Also unlike the original mode this one has infinite lives so if you want limited lives you'll need to edit the script. 86 | -------------------------------------------------------------------------------- /gamemodes/all_or_nothing.gsc: -------------------------------------------------------------------------------- 1 | #include common_scripts\utility; 2 | #include maps\mp\_utility; 3 | #include maps\mp\gametypes\_class; 4 | 5 | Init() 6 | { 7 | SetGameLimits(20); 8 | 9 | SetDvar("bots_play_ads", 0); 10 | SetDvar("bots_play_camp", 0); 11 | SetDvar("bots_play_killstreak", 0); 12 | 13 | level thread OnPlayerConnect(); 14 | } 15 | 16 | OnPlayerConnect() 17 | { 18 | for(;;) 19 | { 20 | level waittill("connected", player); 21 | 22 | player thread OnPlayerSpawned(); 23 | } 24 | } 25 | 26 | OnPlayerSpawned() 27 | { 28 | self endon("disconnect"); 29 | 30 | for(;;) 31 | { 32 | self waittill("changed_kit"); 33 | 34 | self thread ReplaceKillstreaks(); 35 | self thread ReplacePerks(); 36 | self thread ReplaceWeapons("iw5_usp45_mp_tactical"); 37 | } 38 | } 39 | 40 | /* 41 | the amount of kills to win 42 | the amount of minutes until the game ends (optional) 43 | 44 | Example: 45 | SetGameLimits(20); will change the kills limit to 20 46 | SetGameLimits(40, 15); will change the kills limit to 40 and the time limit to 15 minutes 47 | */ 48 | SetGameLimits(kills_limit, time_limit) 49 | { 50 | score_multiplier = 0; 51 | 52 | switch(level.gameType) 53 | { 54 | case "dm": 55 | score_multiplier = 50; 56 | break; 57 | case "war": 58 | score_multiplier = 100; 59 | break; 60 | default: 61 | score_multiplier = 50; 62 | break; 63 | } 64 | 65 | SetDvar("scr_" + level.gameType + "_scorelimit", kills_limit * score_multiplier); 66 | SetDvar("scorelimit", kills_limit * score_multiplier); 67 | 68 | if (IsDefined(time_limit)) 69 | { 70 | SetDvar("scr_" + level.gameType + "_timelimit", time_limit); 71 | SetDvar("timelimit", time_limit); 72 | } 73 | } 74 | 75 | ReplaceWeapons(new_weapon) 76 | { 77 | self TakeAllWeapons(); 78 | self GiveWeapon(new_weapon); 79 | self GiveWeapon("throwingknife_mp"); 80 | 81 | self setweaponammoclip( new_weapon, 0 ); 82 | self setweaponammostock( new_weapon, 0 ); 83 | 84 | self SetSpawnWeapon(new_weapon); 85 | } 86 | 87 | ReplacePerks() 88 | { 89 | self ClearPerks(); 90 | 91 | self GivePerk("specialty_fastreload", 0); // Sleight of hand 92 | self GivePerk("specialty_longersprint", 0);// Extreme conditioning 93 | self GivePerk("specialty_fastmantle", 0); // Extreme condition PRO 94 | 95 | self GivePerk("specialty_hardline", 0); // Hardline 96 | 97 | self GivePerk("specialty_stalker", 0); // Stalker 98 | self GivePerk("specialty_falldamage", 0); // Dead silence PRO 99 | } 100 | 101 | ReplaceKillstreaks() 102 | { 103 | self.pers["gamemodeLoadout"] = self cloneLoadout(); 104 | self.pers["gamemodeLoadout"]["loadoutJuggernaut"] = false; 105 | 106 | self.pers["gamemodeLoadout"]["loadoutEquipment"] = "throwingknife_mp"; 107 | 108 | self.pers["gamemodeLoadout"]["loadoutStreakType"] = "streaktype_specialist"; 109 | self.pers["gamemodeLoadout"]["loadoutKillstreak1"] = "specialty_scavenger_ks"; 110 | self.pers["gamemodeLoadout"]["loadoutKillstreak2"] = "none"; 111 | self.pers["gamemodeLoadout"]["loadoutKillstreak3"] = "none"; 112 | 113 | if (self IsBot()) 114 | { 115 | //self maps\mp\bots\_bot_utility::botGiveLoadout(self.team, "gamemode", false, true); // Uncomment if using Bot Warfare 116 | } 117 | else 118 | { 119 | self maps\mp\gametypes\_class::giveLoadout(self.team, "gamemode", false, true); 120 | } 121 | 122 | maps\mp\killstreaks\_killstreaks::clearKillstreaks(); 123 | } 124 | 125 | IsBot() 126 | { 127 | return IsDefined(self.pers["isBot"]) && self.pers["isBot"]; 128 | } -------------------------------------------------------------------------------- /gamemodes/chaos.gsc: -------------------------------------------------------------------------------- 1 | /* 2 | ====================================================================== 3 | | Game: Plutonium IW5 | 4 | | Description : Chaos custom mode | 5 | | Author: Resxt | 6 | ====================================================================== 7 | | https://github.com/Resxt/Plutonium-IW5-Scripts/tree/main/gamemodes | 8 | ====================================================================== 9 | */ 10 | 11 | #include maps\mp\_utility; 12 | #include maps\mp\gametypes\_class; 13 | //#include maps\mp\bots\_bot_utility; // Uncomment if using Bot Warfare 14 | 15 | /* Entry point */ 16 | 17 | Init() 18 | { 19 | InitChaos(); 20 | } 21 | 22 | 23 | 24 | /* Init section */ 25 | 26 | InitChaos() 27 | { 28 | replacefunc(maps\mp\_utility::allowClassChoice, ::ReplaceAllowClassChoice); 29 | replacefunc(maps\mp\_utility::allowTeamChoice, ::ReplaceAllowTeamChoice); 30 | replacefunc(maps\mp\_utility::killShouldAddToKillstreak, ::ReplaceKillShouldAddToKillstreak); 31 | 32 | level.killstreakSpawnShield = 0; // Disable anti killstreak protection on player spawn 33 | level.callbackplayerdamagestub = level.callbackplayerdamage; 34 | level.callbackplayerdamage = ::ChaosDamages; // Disable direct bullet hit damage and self damage (explosions) 35 | 36 | InitConfigVariables(); 37 | InitGameVariables(); 38 | 39 | SetGameLimits(level.chaos_kills_limit, (level.chaos_kills_limit / 5)); 40 | 41 | SetDvar("player_sustainAmmo", 0); 42 | SetDvar("jump_height", 585); 43 | SetDvar("g_speed", 475); 44 | SetDvar("g_gravity", 400); 45 | SetDvar("g_playerCollision", 2); 46 | SetDvar("g_playerEjection", 2); 47 | SetDvar("jump_autoBunnyHop", 1); 48 | SetDvar("jump_disableFallDamage", 1); 49 | SetDvar("jump_slowdownEnable", 0); 50 | SetDvar("jump_spreadAdd", 0); 51 | 52 | level thread OnPlayerConnect(); 53 | } 54 | 55 | InitConfigVariables() 56 | { 57 | level.chaos_kills_limit = 125; 58 | 59 | level.chaos_config_levels[0]["weapons"] = ["iw5_cm901_mp", "iw5_cm901_mp_silencer", "iw5_mk14_mp", "iw5_mk14_mp_silencer", "iw5_ak47_mp", "iw5_ak47_mp_silencer", "iw5_ump45_mp", "iw5_ump45_mp_silencer", "iw5_mp9_mp", "iw5_mp9_mp_silencer02"]; 60 | level.chaos_config_levels[0]["bullets"] = ["ac130_40mm_mp", "ims_projectile_mp"]; 61 | level.chaos_config_levels[25]["weapons"] = ["iw5_dragunov_mp", "iw5_dragunov_mp_silencer03", "iw5_dragunov_mp_acog", "iw5_dragunov_mp_acog_silencer03", "iw5_rsass_mp", "iw5_rsass_mp_silencer03", "iw5_rsass_mp_acog", "iw5_rsass_mp_acog_silencer03", "iw5_usas12_mp", "iw5_usas12_mp_silencer03", "iw5_usas12_mp_reflex", "iw5_usas12_mp_reflex_silencer03"]; 62 | level.chaos_config_levels[25]["bullets"] = ["m320_mp", "rpg_mp", "remote_mortar_missile_mp"]; 63 | level.chaos_config_levels[50]["weapons"] = ["iw5_44magnum_mp", "iw5_usp45_mp", "iw5_deserteagle_mp", "iw5_mp412_mp", "iw5_p99_mp", "iw5_fnfiveseven_mp", "iw5_44magnum_mp_silencer02", "iw5_usp45_mp_silencer02", "iw5_deserteagle_mp_silencer02", "iw5_mp412_mp_silencer02", "iw5_p99_mp_silencer02", "iw5_fnfiveseven_mp_silencer02", "iw5_44magnum_mp_akimbo", "iw5_usp45_mp_akimbo", "iw5_deserteagle_mp_akimbo", "iw5_mp412_mp_akimbo", "iw5_p99_mp_akimbo", "iw5_fnfiveseven_mp_akimbo", "iw5_44magnum_mp_akimbo_silencer02", "iw5_usp45_mp_akimbo_silencer02", "iw5_deserteagle_mp_akimbo_silencer02", "iw5_mp412_mp_akimbo_silencer02", "iw5_p99_mp_akimbo_silencer02", "iw5_fnfiveseven_mp_akimbo_silencer02"]; 64 | level.chaos_config_levels[50]["bullets"] = ["stinger_mp"]; 65 | level.chaos_config_levels[75]["weapons"] = ["iw5_l96a1_mp", "iw5_msr_mp", "iw5_cheytac_mp", "iw5_l96a1_mp_silencer03", "iw5_msr_mp_silencer03", "iw5_cheytac_mp_silencer03", "iw5_l96a1_mp_acog", "iw5_msr_mp_acog", "iw5_cheytac_mp_acog", "iw5_l96a1_mp_acog_silencer03", "iw5_msr_mp_acog_silencer03", "iw5_cheytac_mp_acog_silencer03"]; 66 | level.chaos_config_levels[75]["bullets"] = ["ac130_105mm_mp", "javelin_mp"]; 67 | level.chaos_config_levels[100]["weapons"] = ["iw5_ksg_mp", "iw5_spas12_mp", "iw5_striker_mp", "iw5_1887_mp"]; 68 | level.chaos_config_levels[100]["bullets"] = ["uav_strike_projectile_mp"]; 69 | } 70 | 71 | InitGameVariables() 72 | { 73 | foreach (key in GetArrayKeys(level.chaos_config_levels)) 74 | { 75 | level.chaos_levels[key]["weapon"] = GetRandomElementInArray(level.chaos_config_levels[key]["weapons"]); 76 | level.chaos_levels[key]["bullet"] = GetRandomElementInArray(level.chaos_config_levels[key]["bullets"]); 77 | } 78 | } 79 | 80 | 81 | 82 | /* Player section */ 83 | 84 | OnPlayerConnect() 85 | { 86 | for(;;) 87 | { 88 | level waittill("connected", player); 89 | 90 | player.pers["chaos_level"] = 0; 91 | player.pers["last_registered_kills"] = 0; 92 | 93 | player thread OnPlayerSpawned(); 94 | player thread OnPlayerKill(); 95 | player thread OnPlayerReload(); 96 | } 97 | } 98 | 99 | OnPlayerSpawned() 100 | { 101 | self endon("disconnect"); 102 | 103 | for(;;) 104 | { 105 | self waittill("spawned_player"); 106 | 107 | self GivePlayerEquipment(); 108 | 109 | Print(self.pers["clientData"]); 110 | Print(self.pers["clientData"].permissionLevel); 111 | } 112 | } 113 | 114 | OnPlayerKill() 115 | { 116 | self endon("disconnect"); 117 | 118 | for (;;) 119 | { 120 | self waittill( "killed_enemy" ); 121 | 122 | killsForNewWeapon = self.pers["chaos_level"] + 25; 123 | 124 | if (self.pers["last_registered_kills"] < killsForNewWeapon && self.kills >= killsForNewWeapon && killsForNewWeapon != level.chaos_kills_limit) 125 | { 126 | self.pers["chaos_level"] = killsForNewWeapon; 127 | 128 | self notify("chaos_level_up"); 129 | 130 | self GivePlayerEquipment(); 131 | } 132 | } 133 | } 134 | 135 | OnPlayerReload() 136 | { 137 | level endon( "game_ended" ); 138 | self endon( "disconnect" ); 139 | 140 | for (;;) 141 | { 142 | self waittill( "reload" ); 143 | 144 | self GiveMaxAmmo(self GetCurrentWeapon()); 145 | } 146 | } 147 | 148 | ClearPlayerClass() 149 | { 150 | self.pers["gamemodeLoadout"] = self cloneLoadout(); 151 | 152 | self.pers["gamemodeLoadout"]["loadoutJuggernaut"] = false; 153 | self.pers["gamemodeLoadout"]["loadoutPrimary"] = "none"; 154 | self.pers["gamemodeLoadout"]["loadoutSecondary"] = "none"; 155 | self.pers["gamemodeLoadout"]["loadoutKillstreak1"] = "none"; 156 | self.pers["gamemodeLoadout"]["loadoutKillstreak2"] = "none"; 157 | self.pers["gamemodeLoadout"]["loadoutKillstreak3"] = "none"; 158 | self.pers["gamemodeLoadout"]["loadoutPerk1"] = "none"; 159 | self.pers["gamemodeLoadout"]["loadoutPerk2"] = "none"; 160 | self.pers["gamemodeLoadout"]["loadoutPerk3"] = "none"; 161 | 162 | if (!self IsBot()) 163 | { 164 | self maps\mp\gametypes\_class::giveLoadout(self.team, "gamemode", false, true); 165 | } 166 | else 167 | { 168 | //self botGiveLoadout(self.team, "gamemode", false, true); // Uncomment if using Bot Warfare 169 | } 170 | 171 | maps\mp\killstreaks\_killstreaks::clearKillstreaks(); 172 | } 173 | 174 | GiveChaosWeapon() 175 | { 176 | self TakeAllWeapons(); 177 | 178 | newWeapon = level.chaos_levels[self.pers["chaos_level"]]["weapon"]; 179 | 180 | self GiveWeapon(newWeapon); 181 | self SwitchToWeapon(newWeapon); 182 | self GiveMaxAmmo(newWeapon); 183 | self SetSpawnWeapon(newWeapon); 184 | 185 | self thread GiveChaosBullets(level.chaos_levels[self.pers["chaos_level"]]["bullet"]); 186 | } 187 | 188 | GiveChaosBullets(bulletType) 189 | { 190 | self endon("death"); 191 | self endon("chaos_level_up"); 192 | 193 | for(;; ) 194 | { 195 | self waittill( "weapon_fired" ); 196 | MagicBullet(bulletType, self getTagOrigin("tag_eye"), self GetCursorPos(), self ); 197 | } 198 | } 199 | GetCursorPos() 200 | { 201 | return BulletTrace( self getTagOrigin("tag_eye"), vector_scal(anglestoforward(self getPlayerAngles()),1000000), 0, self )[ "position" ]; 202 | } 203 | vector_scal(vec, scale) 204 | { 205 | return (vec[0] * scale, vec[1] * scale, vec[2] * scale); 206 | } 207 | 208 | GiveChaosPerks() 209 | { 210 | self GivePerk("specialty_longersprint", false); // Extreme conditioning 211 | self GivePerk(GetProPerkName("specialty_longersprint"), false); // Extreme conditioning PRO 212 | 213 | self GivePerk("specialty_bulletaccuracy", false); // Steady aim 214 | self GivePerk(GetProPerkName("specialty_bulletaccuracy"), false); // Steady aim PRO 215 | 216 | self GivePerk(GetProPerkName("specialty_quieter"), false); // Dead silence PRO 217 | } 218 | 219 | GivePlayerEquipment() 220 | { 221 | self ClearPlayerClass(); 222 | self DisableWeaponPickup(); 223 | 224 | self GiveChaosWeapon(); 225 | self GiveChaosPerks(); 226 | } 227 | 228 | 229 | 230 | /* Utils section */ 231 | 232 | GetRandomElementInArray(array) 233 | { 234 | return array[GetArrayKeys(array)[randomint(array.size)]]; 235 | } 236 | 237 | 238 | GetProPerkName(perkName) 239 | { 240 | return tablelookup( "mp/perktable.csv", 1, perkName, 8 ); 241 | } 242 | 243 | /* 244 | the amount of kills to win 245 | the amount of minutes until the game ends (optional) 246 | Example: 247 | SetGameLimits(20); will change the kills limit to 20 248 | SetGameLimits(40, 15); will change the kills limit to 40 and the time limit to 15 minutes 249 | */ 250 | SetGameLimits(kills_limit, time_limit) 251 | { 252 | score_multiplier = 0; 253 | 254 | switch(level.gameType) 255 | { 256 | case "dm": 257 | score_multiplier = 50; 258 | break; 259 | case "war": 260 | score_multiplier = 100; 261 | break; 262 | default: 263 | score_multiplier = 50; 264 | break; 265 | } 266 | 267 | SetDvar("scr_" + level.gameType + "_scorelimit", kills_limit * score_multiplier); 268 | SetDvar("scorelimit", kills_limit * score_multiplier); 269 | 270 | if (IsDefined(time_limit)) 271 | { 272 | SetDvar("scr_" + level.gameType + "_timelimit", time_limit); 273 | SetDvar("timelimit", time_limit); 274 | } 275 | } 276 | 277 | IsBot() 278 | { 279 | return IsDefined(self.pers["isBot"]) && self.pers["isBot"]; 280 | } 281 | 282 | 283 | 284 | /* Replaced functions section */ 285 | 286 | ReplaceAllowClassChoice() 287 | { 288 | return false; 289 | } 290 | 291 | ReplaceAllowTeamChoice() 292 | { 293 | return false; 294 | } 295 | 296 | ReplaceKillShouldAddToKillstreak() 297 | { 298 | return true; 299 | } 300 | 301 | ChaosDamages( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ) 302 | { 303 | if (isDefined(eAttacker)) 304 | { 305 | if (isDefined(eAttacker.guid) && isDefined(self.guid)) 306 | { 307 | if (eAttacker.guid == self.guid) 308 | { 309 | iDamage = 0; 310 | } 311 | else 312 | { 313 | if (sMeansOfDeath == "MOD_RIFLE_BULLET" || sMeansOfDeath == "MOD_PISTOL_BULLET") 314 | { 315 | iDamage = 0; 316 | } 317 | } 318 | } 319 | } 320 | 321 | self [[level.callbackplayerdamagestub]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ); 322 | } -------------------------------------------------------------------------------- /gamemodes/gun_game.gsc: -------------------------------------------------------------------------------- 1 | /* 2 | ====================================================================== 3 | | Game: Plutonium IW5 | 4 | | Description : Gun game recreation | 5 | | Author: Resxt | 6 | ====================================================================== 7 | | https://github.com/Resxt/Plutonium-IW5-Scripts/tree/main/gamemodes | 8 | ====================================================================== 9 | */ 10 | 11 | #include common_scripts\utility; 12 | #include maps\mp\_utility; 13 | #include maps\mp\gametypes\_class; 14 | #include maps\mp\gametypes\_hud_util; 15 | //#include maps\mp\bots\_bot_utility; // Uncomment if using Bot Warfare 16 | 17 | /* Entry point */ 18 | 19 | Init() 20 | { 21 | InitGunGame(); 22 | } 23 | 24 | 25 | 26 | /* Init section */ 27 | 28 | InitGunGame() 29 | { 30 | replacefunc(maps\mp\_utility::allowTeamChoice, ::ReplaceAllowTeamChoice); 31 | replacefunc(maps\mp\_utility::allowClassChoice, ::ReplaceAllowClassChoice); 32 | 33 | InitConfigVariables(); 34 | InitWeaponVariables(); 35 | 36 | InitCurrentGameWeapons(); 37 | SetGameLimits(0, (level.gun_game_weapons_amount / 5)); // Leave the kills limit at zero. The score will set itself in OnPlayerKill() whenever a player is at the last weapon. This is to prevent multi kills from counting as multi kills 38 | 39 | level thread OnPlayerConnect(); 40 | 41 | if (level.gun_game_debug) 42 | { 43 | level thread DebugOnPlayerSay(); 44 | 45 | DebugArray("level.gun_game_current_game_weapons", level.gun_game_current_game_weapons); 46 | } 47 | } 48 | 49 | InitConfigVariables() 50 | { 51 | level.gun_game_debug = false; 52 | level.gun_game_weapons_amount = 50; // If level.gun_game_weapons_unique_check is set to weapon then this cannot be higher than 51 (the amount of usable weapons) 53 | level.gun_game_weapons_attachment_scope_percent = 75; // The percent of chance a weapon will have a scope (max 100) 54 | level.gun_game_weapons_attachment_other_percent = 75; // The percent of chance a weapon will have an attachment other than a scope (max 100) 55 | level.gun_game_snipers_shotguns_normal_scope_percent = 90; // The percent of chance a sniper will have the default scope (max 100) 56 | level.gun_game_weapons_primary_weapons_percent = 90; // The percent of chance a random weapon will be a primary weapon. This is used when both level.gun_game_available_weapons_config arrays values aren't "none" (max 100) 57 | level.gun_game_available_weapons_config["primary_weapons"] = ["assault_rifles", "sub_machine_guns", "light_machine_guns", "sniper_rifles", "shotguns"]; // ["none"] OR array of level.gun_game_available_weapons["primary_weapons"] keys 58 | level.gun_game_available_weapons_config["secondary_weapons"] = ["machine_pistols", "handguns", "launchers"]; // ["none"] OR array of level.gun_game_available_weapons["secondary_weapons"] keys 59 | level.gun_game_weapons_unique_check = "weapon"; // weapon OR weapon_attachments OR none 60 | } 61 | 62 | InitWeaponVariables() 63 | { 64 | level.gun_game_available_weapons["primary_weapons"]["assault_rifles"] = ["iw5_m4_mp", "iw5_m16_mp", "iw5_scar_mp", "iw5_cm901_mp", "iw5_type95_mp", "iw5_g36c_mp", "iw5_acr_mp", "iw5_mk14_mp", "iw5_ak47_mp", "iw5_fad_mp"]; 65 | level.gun_game_available_weapons["primary_weapons"]["sub_machine_guns"] = ["iw5_mp5_mp", "iw5_ump45_mp", "iw5_pp90m1_mp", "iw5_p90_mp", "iw5_m9_mp", "iw5_mp7_mp", "iw5_ak74u_mp"]; 66 | level.gun_game_available_weapons["primary_weapons"]["light_machine_guns"] = ["iw5_sa80_mp", "iw5_mg36_mp", "iw5_pecheneg_mp", "iw5_mk46_mp", "iw5_m60_mp"]; 67 | level.gun_game_available_weapons["primary_weapons"]["sniper_rifles"] = ["iw5_barrett_mp", "iw5_l96a1_mp", "iw5_dragunov_mp", "iw5_as50_mp", "iw5_rsass_mp", "iw5_msr_mp", "iw5_cheytac_mp"]; 68 | level.gun_game_available_weapons["primary_weapons"]["shotguns"] = ["iw5_usas12_mp", "iw5_ksg_mp", "iw5_spas12_mp", "iw5_aa12_mp", "iw5_striker_mp", "iw5_1887_mp"]; 69 | level.gun_game_available_weapons["primary_weapons"]["riot_shield"] = ["riotshield_mp"]; 70 | 71 | level.gun_game_available_weapons["secondary_weapons"]["machine_pistols"] = ["iw5_g18_mp", "iw5_fmg9_mp", "iw5_mp9_mp", "iw5_skorpion_mp"]; 72 | level.gun_game_available_weapons["secondary_weapons"]["handguns"] = ["iw5_44magnum_mp", "iw5_usp45_mp", "iw5_deserteagle_mp", "iw5_mp412_mp", "iw5_p99_mp", "iw5_fnfiveseven_mp"]; 73 | level.gun_game_available_weapons["secondary_weapons"]["launchers"] = ["iw5_smaw_mp", "javelin_mp", "xm25_mp", "m320_mp", "rpg_mp"]; // stinger is removed. Cannot shoot at enemies (at least without a GSC script that I don't have) 74 | 75 | level.gun_game_available_attachments["weapon_assault"][0] = ["reflex", "acog", "eotech", "hybrid", "thermal"]; 76 | level.gun_game_available_attachments["weapon_assault"][1] = ["silencer", "heartbeat", "xmags"]; // gl and shotgun are removed and untested. I believe an attachment that changes the weapon's attack/fire to a generic one doesn't belong in gun game 77 | level.gun_game_available_attachments["weapon_smg"][0] = ["reflexsmg", "acogsmg", "eotechsmg", "hamrhybrid", "thermalsmg"]; 78 | level.gun_game_available_attachments["weapon_smg"][1] = ["silencer", "rof", "xmags"]; 79 | level.gun_game_available_attachments["weapon_lmg"][0] = ["reflexlmg", "acog", "eotechlmg", "thermal"]; 80 | level.gun_game_available_attachments["weapon_lmg"][1] = ["silencer", "grip", "rof", "heartbeat", "xmags"]; 81 | level.gun_game_available_attachments["weapon_sniper"][0] = ["acog", "thermal"]; // variable scope is removed and untested. Doesn't really add anything useful and would mess the percent of chance a sniper has a different scope 82 | level.gun_game_available_attachments["weapon_sniper"][1] = ["silencer03", "heartbeat", "xmags"]; 83 | level.gun_game_available_attachments["weapon_shotgun"][0] = ["reflex", "eotech"]; 84 | level.gun_game_available_attachments["weapon_shotgun"][1] = ["grip", "silencer03", "xmags"]; 85 | 86 | level.gun_game_available_attachments["weapon_machine_pistol"][0] = ["reflexsmg", "eotechsmg"]; // thanks to this you can have a scope with a silencer/akimbo/xmags attachment 87 | level.gun_game_available_attachments["weapon_machine_pistol"][1] = ["silencer02", "akimbo", "xmags"]; 88 | level.gun_game_available_attachments["weapon_pistol"][0] = ["akimbo", "tactical"]; // thanks to this you can have akimbo silencers/xmags and tactical silencers/xmags pistols 89 | level.gun_game_available_attachments["weapon_pistol"][1] = ["silencer02", "xmags"]; 90 | 91 | level.gun_game_available_camos = ["camo01", "camo02", "camo03", "camo04", "camo05", "camo06", "camo07", "camo08", "camo09", "camo10", "camo11", "camo12", "camo13"]; // camos are ordered the same way that they are in-game. camo11 is gold 92 | } 93 | 94 | InitCurrentGameWeapons() 95 | { 96 | level.gun_game_current_game_weapons = []; 97 | gunGameCurrentGameAcceptedWeapons = []; 98 | gunGameCurrentGameBaseWeapons = []; 99 | gunGameCurrentGameWeapons = []; 100 | 101 | for (i = 0; i < level.gun_game_weapons_amount; i++) 102 | { 103 | findWeapon = true; 104 | 105 | while (findWeapon) 106 | { 107 | newWeapon = GetRandomWeapon(); 108 | 109 | if (level.gun_game_weapons_unique_check == "weapon" && !ArrayContainsValue(gunGameCurrentGameBaseWeapons, GetBaseWeaponName(newWeapon))) 110 | { 111 | findWeapon = false; 112 | gunGameCurrentGameAcceptedWeapons = AddElementToArray(gunGameCurrentGameAcceptedWeapons, newWeapon); 113 | gunGameCurrentGameBaseWeapons = AddElementToArray(gunGameCurrentGameBaseWeapons, GetBaseWeaponName(newWeapon)); 114 | } 115 | else if (level.gun_game_weapons_unique_check == "weapon_attachments" && !ArrayContainsValue(gunGameCurrentGameWeapons, GetWeaponNameWithoutCamo(newWeapon))) 116 | { 117 | findWeapon = false; 118 | gunGameCurrentGameAcceptedWeapons = AddElementToArray(gunGameCurrentGameAcceptedWeapons, newWeapon); 119 | gunGameCurrentGameWeapons = AddElementToArray(gunGameCurrentGameWeapons, GetWeaponNameWithoutCamo(newWeapon)); 120 | } 121 | else if (level.gun_game_weapons_unique_check == "none") 122 | { 123 | findWeapon = false; 124 | gunGameCurrentGameAcceptedWeapons = AddElementToArray(gunGameCurrentGameAcceptedWeapons, newWeapon); 125 | } 126 | } 127 | } 128 | 129 | level.gun_game_current_game_weapons = gunGameCurrentGameAcceptedWeapons; 130 | } 131 | 132 | 133 | 134 | /* Logic section */ 135 | 136 | GetRandomWeapon() 137 | { 138 | randomWeapon = GetRandomBaseWeapon(); 139 | 140 | if (GetWeaponClass(randomWeapon) != "weapon_projectile" && randomWeapon != "riotshield_mp") 141 | { 142 | randomWeapon = randomWeapon + GetRandomAttachments(randomWeapon); 143 | } 144 | 145 | if (IsPrimaryWeapon(randomWeapon) && randomWeapon != "riotshield_mp") 146 | { 147 | randomWeapon = randomWeapon + GetRandomCamo(); 148 | } 149 | 150 | return randomWeapon; 151 | } 152 | 153 | GetRandomBaseWeapon() 154 | { 155 | weaponsFilteredByType = []; // Example: primary_weapons 156 | weaponsFilteredByCategory = []; // Example: assault_rifles 157 | randomWeapon = ""; 158 | 159 | // Array of primaries and array of secondaries 160 | if (level.gun_game_available_weapons_config["primary_weapons"][0] != "none" && level.gun_game_available_weapons_config["secondary_weapons"][0] != "none" ) 161 | { 162 | typeKey = ""; 163 | 164 | if (BooleanFromPercentage(level.gun_game_weapons_primary_weapons_percent)) 165 | { 166 | typeKey = "primary_weapons"; 167 | } 168 | else 169 | { 170 | typeKey = "secondary_weapons"; 171 | } 172 | 173 | categoryKey = GetRandomElementInArray(level.gun_game_available_weapons_config[typeKey]); 174 | 175 | weaponsFilteredByCategory = level.gun_game_available_weapons[typeKey][categoryKey]; 176 | } 177 | // Array of primaries and no secondaries 178 | else if (level.gun_game_available_weapons_config["primary_weapons"][0] != "none" && level.gun_game_available_weapons_config["secondary_weapons"][0] == "none") 179 | { 180 | typeKey = "primary_weapons"; 181 | categoryKey = GetRandomElementInArray(level.gun_game_available_weapons_config[typeKey]); 182 | 183 | weaponsFilteredByCategory = level.gun_game_available_weapons[typeKey][categoryKey]; 184 | } 185 | // No primaries and array of secondaries 186 | else if (level.gun_game_available_weapons_config["primary_weapons"][0] == "none" && level.gun_game_available_weapons_config["secondary_weapons"][0] != "none") 187 | { 188 | typeKey = "secondary_weapons"; 189 | categoryKey = GetRandomElementInArray(level.gun_game_available_weapons_config[typeKey]); 190 | 191 | weaponsFilteredByCategory = level.gun_game_available_weapons[typeKey][categoryKey]; 192 | } 193 | 194 | randomWeapon = GetRandomElementInArray(weaponsFilteredByCategory); // Example: iw5_acr_mp 195 | 196 | return randomWeapon; 197 | } 198 | 199 | GetRandomAttachments(weaponName) 200 | { 201 | weaponClass = GetWeaponClass(weaponName); 202 | scopeChancePercent = level.gun_game_weapons_attachment_scope_percent; 203 | attachments = ""; 204 | 205 | if (weaponClass == "weapon_sniper" || weaponClass == "weapon_shotgun") 206 | { 207 | scopeChancePercent = (100 - level.gun_game_snipers_shotguns_normal_scope_percent); 208 | } 209 | else if (!IsPrimaryWeapon(weaponName)) 210 | { 211 | scopeChancePercent = (scopeChancePercent / 2.5); 212 | } 213 | 214 | if (BooleanFromPercentage(scopeChancePercent)) 215 | { 216 | attachment = GetRandomElementInArray(level.gun_game_available_attachments[weaponClass][0]); 217 | 218 | if (!AttachmentIsBanned(weaponName, attachment)) 219 | { 220 | attachments = "_" + attachment; 221 | } 222 | } 223 | else 224 | { 225 | defaultScope = GetDefaultWeaponScope(weaponName); 226 | 227 | if (defaultScope != "") 228 | { 229 | attachments = "_" + defaultScope; 230 | } 231 | } 232 | 233 | if (BooleanFromPercentage(level.gun_game_weapons_attachment_other_percent)) 234 | { 235 | attachment = GetRandomElementInArray(level.gun_game_available_attachments[weaponClass][1]); 236 | 237 | if (!AttachmentIsBanned(weaponName, attachment)) 238 | { 239 | attachments = attachments + "_" + attachment; 240 | } 241 | } 242 | 243 | attachments = FixReversedAttachments(weaponName, attachments); 244 | 245 | return attachments; 246 | } 247 | 248 | GetRandomCamo() 249 | { 250 | return "_" + GetRandomElementInArray(level.gun_game_available_camos); 251 | } 252 | 253 | GiveGunGameWeapon(spawn) 254 | { 255 | self TakeAllWeapons(); 256 | 257 | newWeapon = level.gun_game_current_game_weapons[self.pers["gun_game_current_index"]]; 258 | 259 | self GiveWeapon(newWeapon); 260 | self SwitchToWeapon(newWeapon); 261 | self GiveMaxAmmo(newWeapon); 262 | 263 | if (spawn) 264 | { 265 | self SetSpawnWeapon(newWeapon); 266 | } 267 | } 268 | 269 | GiveGunGamePerks() 270 | { 271 | self GivePerk("specialty_fastreload", false); // Sleight of hand 272 | self GivePerk("specialty_longersprint", false); // Extreme conditioning 273 | self GivePerk(GetProPerkName("specialty_longersprint"), false); // Extreme conditioning PRO 274 | self GivePerk("specialty_quickdraw", false); // Quickdraw 275 | self GivePerk("specialty_bulletaccuracy", false); // Steady aim 276 | self GivePerk(GetProPerkName("specialty_bulletaccuracy"), false); // Steady aim PRO 277 | self GivePerk(GetProPerkName("specialty_quieter"), false); // Dead silence PRO 278 | } 279 | 280 | /* 281 | the amount of kills to win 282 | the amount of minutes until the game ends (optional) 283 | Example: 284 | SetGameLimits(20); will change the kills limit to 20 285 | SetGameLimits(40, 15); will change the kills limit to 40 and the time limit to 15 minutes 286 | */ 287 | SetGameLimits(kills_limit, time_limit) 288 | { 289 | score_multiplier = 0; 290 | 291 | switch(level.gameType) 292 | { 293 | case "dm": 294 | score_multiplier = 50; 295 | break; 296 | case "war": 297 | score_multiplier = 100; 298 | break; 299 | default: 300 | score_multiplier = 50; 301 | break; 302 | } 303 | 304 | SetDvar("scr_" + level.gameType + "_scorelimit", kills_limit * score_multiplier); 305 | SetDvar("scorelimit", kills_limit * score_multiplier); 306 | 307 | if (IsDefined(time_limit)) 308 | { 309 | SetDvar("scr_" + level.gameType + "_timelimit", time_limit); 310 | SetDvar("timelimit", time_limit); 311 | } 312 | } 313 | 314 | AttachmentIsBanned(weaponName, attachmentName) 315 | { 316 | if (GetBaseWeaponName(weaponName) == "iw5_ak74u_mp") 317 | { 318 | if (attachmentName == "hamrhybrid") // doesn't exist 319 | { 320 | return true; 321 | } 322 | } 323 | else if (GetWeaponClass(weaponName) == "weapon_shotgun") 324 | { 325 | if (GetBaseWeaponName(weaponName) == "iw5_1887_mp") // doesn't exist 326 | { 327 | return true; 328 | } 329 | else if (attachmentName == "silencer03") // bad/unfun 330 | { 331 | return true; 332 | } 333 | } 334 | else if (GetBaseWeaponName(weaponName) == "iw5_mp412_mp" || GetBaseWeaponName(weaponName) == "iw5_44magnum_mp" || GetBaseWeaponName(weaponName) == "iw5_deserteagle_mp") 335 | { 336 | if (attachmentName == "silencer02") // works but makes a silencer float on top of the player's on his screen 337 | { 338 | return true; 339 | } 340 | } 341 | 342 | return false; 343 | } 344 | 345 | /* 346 | In some cases certain attachments considered as primary attachments (for example scopes) should come after the other attachment, here we fix this 347 | */ 348 | FixReversedAttachments(weaponName, attachments) 349 | { 350 | reverse = false; 351 | attachmentsArray = StrTok(attachments, "_"); 352 | 353 | if (attachmentsArray.size < 2) 354 | { 355 | return attachments; 356 | } 357 | 358 | if (GetWeaponClass(weaponName) == "weapon_assault") 359 | { 360 | if (attachmentsArray[1] == "heartbeat" && attachmentsArray[0] != "eotech" && attachmentsArray[0] != "acog" && attachmentsArray[0] != "thermal") 361 | { 362 | reverse = true; 363 | } 364 | else if (attachmentsArray[0] == "thermal" && attachmentsArray[1] != "xmags") 365 | { 366 | reverse = true; 367 | } 368 | else if (attachmentsArray[0] == "hybrid" && attachmentsArray[1] != "xmags" && attachmentsArray[1] != "silencer") 369 | { 370 | reverse = true; 371 | } 372 | } 373 | else if (GetWeaponClass(weaponName) == "weapon_smg") 374 | { 375 | if (attachmentsArray[0] == "thermalsmg" && attachmentsArray[1] != "xmags") 376 | { 377 | reverse = true; 378 | } 379 | } 380 | else if (GetWeaponClass(weaponName) == "weapon_lmg") 381 | { 382 | if (attachmentsArray[1] == "grip" && attachmentsArray[0] != "acog" && attachmentsArray[0] != "eotechlmg") 383 | { 384 | reverse = true; 385 | } 386 | else if (attachmentsArray[1] == "heartbeat" && attachmentsArray[0] != "eotechlmg" && attachmentsArray[0] != "acog") 387 | { 388 | reverse = true; 389 | } 390 | else if (attachmentsArray[0] == "thermal" && attachmentsArray[1] != "xmags") 391 | { 392 | reverse = true; 393 | } 394 | } 395 | else if (GetWeaponClass(weaponName) == "weapon_sniper") 396 | { 397 | if (attachmentsArray[1] == "heartbeat" && (attachmentsArray[0] == "rsassscope" || attachmentsArray[0] == "l96a1scope" || attachmentsArray[0] == "msrscope")) 398 | { 399 | reverse = true; 400 | } 401 | else if (attachmentsArray[0] == "thermal" && (attachmentsArray[1] != "xmags" || attachmentsArray[1] == "silencer03")) 402 | { 403 | reverse = true; 404 | } 405 | } 406 | else if (GetWeaponClass(weaponName) == "weapon_shotgun") 407 | { 408 | if (attachmentsArray[1] == "grip" && attachmentsArray[0] != "eotech") 409 | { 410 | reverse = true; 411 | } 412 | } 413 | else if (GetWeaponClass(weaponName) == "weapon_machine_pistol") 414 | { 415 | if (attachmentsArray[1] == "akimbo") 416 | { 417 | reverse = true; 418 | } 419 | } 420 | else if (GetWeaponClass(weaponName) == "weapon_pistol") 421 | { 422 | if (attachmentsArray[0] == "tactical" && attachmentsArray[1] == "silencer02") 423 | { 424 | reverse = true; 425 | } 426 | } 427 | 428 | if (reverse) 429 | { 430 | return "_" + attachmentsArray[1] + "_" + attachmentsArray[0]; 431 | } 432 | else 433 | { 434 | return attachments; 435 | } 436 | } 437 | 438 | GetDefaultWeaponScope(weaponName) 439 | { 440 | switch(GetBaseWeaponName(weaponName)) 441 | { 442 | case "iw5_barrett_mp": 443 | return "barrettscope"; 444 | case "iw5_l96a1_mp": 445 | return "l96a1scope"; 446 | case "iw5_dragunov_mp": 447 | return "dragunovscope"; 448 | case "iw5_as50_mp": 449 | return "as50scope"; 450 | case "iw5_rsass_mp": 451 | return "rsassscope"; 452 | case "iw5_msr_mp": 453 | return "msrscope"; 454 | case "iw5_cheytac_mp": 455 | return "cheytacscope"; 456 | } 457 | 458 | return ""; 459 | } 460 | 461 | 462 | 463 | /* Player section */ 464 | 465 | OnPlayerConnect() 466 | { 467 | for(;;) 468 | { 469 | level waittill("connected", player); 470 | 471 | player.pers["gun_game_current_index"] = 0; 472 | player.pers["gun_game_current_weapon"] = level.gun_game_current_game_weapons[0]; 473 | player.pers["previous_score"] = 0; 474 | 475 | player thread OnPlayerSpawned(); 476 | player thread OnPlayerKill(); 477 | player thread OnPlayerReload(); 478 | 479 | if (!player IsBot()) 480 | { 481 | player thread DisplayWeaponProgression(); 482 | } 483 | } 484 | } 485 | 486 | OnPlayerSpawned() 487 | { 488 | self endon("disconnect"); 489 | 490 | for(;;) 491 | { 492 | self waittill("spawned_player"); 493 | 494 | self ClearPlayerClass(); 495 | self DisableWeaponPickup(); 496 | 497 | GiveGunGameWeapon(true); 498 | GiveGunGamePerks(); 499 | } 500 | } 501 | 502 | OnPlayerKill() 503 | { 504 | self endon("disconnect"); 505 | 506 | for (;;) 507 | { 508 | self waittill( "killed_enemy" ); 509 | 510 | self.pers["previous_score"] = (self.pers["previous_score"] + 50); // Prevent multi kills from giving score multiple times. This way our score is always equal to our current weapon index 511 | self.score = self.pers["previous_score"]; 512 | self.pers["score"] = self.pers["previous_score"]; 513 | 514 | if (self.score == (50 * level.gun_game_weapons_amount) - 50) // If we are at the last weapon 515 | { 516 | SetGameLimits(level.gun_game_weapons_amount); // Change the score limit (originally at 0 to prevent a multi kill bug) to one kill from now 517 | } 518 | 519 | self.pers["gun_game_current_index"]++; 520 | self.pers["gun_game_current_weapon"] = level.gun_game_current_game_weapons[self.pers["gun_game_current_index"]]; 521 | 522 | if (self.pers["gun_game_current_index"] < level.gun_game_weapons_amount) 523 | { 524 | GiveGunGameWeapon(false); 525 | 526 | if (self.pers["gun_game_current_index"] == (level.gun_game_weapons_amount - 1 )) // last weapon obtained 527 | { 528 | maps\mp\_utility::playsoundonplayers( "mp_enemy_obj_captured" ); 529 | } 530 | else 531 | { 532 | self playlocalsound( "mp_war_objective_taken" ); 533 | } 534 | } 535 | else 536 | { 537 | self.pers["gun_game_current_index"] = (level.gun_game_weapons_amount - 1); // Reset the index to max weapon index. This is so that we don't display Weapon: 19/18 for example 538 | } 539 | } 540 | } 541 | 542 | OnPlayerReload() 543 | { 544 | level endon( "game_ended" ); 545 | self endon( "disconnect" ); 546 | 547 | for (;;) 548 | { 549 | self waittill( "reload" ); 550 | 551 | self GiveMaxAmmo( self.pers["gun_game_current_weapon"] ); 552 | } 553 | } 554 | 555 | ClearPlayerClass() 556 | { 557 | self.pers["gamemodeLoadout"] = self cloneLoadout(); 558 | 559 | self.pers["gamemodeLoadout"]["loadoutJuggernaut"] = false; 560 | self.pers["gamemodeLoadout"]["loadoutPrimary"] = "none"; 561 | self.pers["gamemodeLoadout"]["loadoutSecondary"] = "none"; 562 | self.pers["gamemodeLoadout"]["loadoutKillstreak1"] = "none"; 563 | self.pers["gamemodeLoadout"]["loadoutKillstreak2"] = "none"; 564 | self.pers["gamemodeLoadout"]["loadoutKillstreak3"] = "none"; 565 | self.pers["gamemodeLoadout"]["loadoutPerk1"] = "none"; 566 | self.pers["gamemodeLoadout"]["loadoutPerk2"] = "none"; 567 | self.pers["gamemodeLoadout"]["loadoutPerk3"] = "none"; 568 | 569 | if (!self IsBot()) 570 | { 571 | self maps\mp\gametypes\_class::giveLoadout(self.team, "gamemode", false, true); 572 | } 573 | else 574 | { 575 | //self botGiveLoadout(self.team, "gamemode", false, true); // Uncomment if using Bot Warfare 576 | } 577 | 578 | maps\mp\killstreaks\_killstreaks::clearKillstreaks(); 579 | } 580 | 581 | 582 | 583 | /* HUD section */ 584 | 585 | DisplayWeaponProgression() 586 | { 587 | self endon( "disconnect" ); 588 | 589 | info_text = createFontString( "Objective", 0.65 ); 590 | info_text setPoint( "CENTER", "TOP", 0, 7.5 ); 591 | info_text.hideWhenInMenu = false; 592 | 593 | while(true) 594 | { 595 | if (!IsDefined(self.pers["gun_game_current_index_display"]) || self.pers["gun_game_current_index_display"] != (self.pers["gun_game_current_index"] + 1)) 596 | { 597 | self.pers["gun_game_current_index_display"] = self.pers["gun_game_current_index"] + 1; // since the index starts at 0 we add 1 to display an index that makes sense for players 598 | info_text setText("^7WEAPON: " + self.pers["gun_game_current_index_display"] + "/" + level.gun_game_weapons_amount); 599 | } 600 | 601 | wait 0.01; 602 | } 603 | } 604 | 605 | 606 | 607 | /* Utils section */ 608 | 609 | GetProPerkName(perkName) 610 | { 611 | return tablelookup( "mp/perktable.csv", 1, perkName, 8 ); 612 | } 613 | 614 | GetRandomElementInArray(array) 615 | { 616 | return array[GetArrayKeys(array)[randomint(array.size)]]; 617 | } 618 | 619 | GetRandomArrayKey(array) 620 | { 621 | return GetArrayKeys(array)[randomint(array.size)]; 622 | } 623 | 624 | GetBaseWeaponName(weaponName) 625 | { 626 | weaponCode = StrTok(weaponName, "_"); 627 | 628 | if (weaponCode.size < 3) 629 | { 630 | return weaponName; 631 | } 632 | 633 | return weaponCode[0] + "_" + weaponCode[1] + "_" + weaponCode[2]; // Example: iw5_msr_mp 634 | } 635 | 636 | GetWeaponNameWithoutCamo(weaponName) 637 | { 638 | return GetSubStr(weaponName, 0, weaponName.size - 7); // Example: iw5_acr_mp_camo01 = iw5_acr_mp 639 | } 640 | 641 | AddElementToArray(array, element) 642 | { 643 | array[array.size] = element; 644 | return array; 645 | } 646 | 647 | ArrayContainsValue(array, valueToFind) 648 | { 649 | if (array.size == 0) 650 | { 651 | return false; 652 | } 653 | 654 | foreach (value in array) 655 | { 656 | if (value == valueToFind) 657 | { 658 | return true; 659 | } 660 | } 661 | 662 | return false; 663 | } 664 | 665 | IsBot() 666 | { 667 | return IsDefined(self.pers["isBot"]) && self.pers["isBot"]; 668 | } 669 | 670 | IsPrimaryWeapon(weaponName) 671 | { 672 | if (GetWeaponClass(weaponName) == "weapon_machine_pistol" || GetWeaponClass(weaponName) == "weapon_pistol" || GetWeaponClass(weaponName) == "weapon_projectile") 673 | { 674 | return false; 675 | } 676 | 677 | return true; 678 | } 679 | 680 | /* 681 | The percent of chance that it will return true 682 | */ 683 | BooleanFromPercentage(percent) 684 | { 685 | return randomint(100) <= percent; 686 | } 687 | 688 | 689 | 690 | /* Replaced functions section */ 691 | 692 | ReplaceAllowTeamChoice() 693 | { 694 | gametype = getDvar("g_gametype"); 695 | 696 | if (gametype == "dm" || gametype == "oitc") return false; 697 | else 698 | { 699 | allowed = int( tableLookup( "mp/gametypesTable.csv", 0, level.gameType, 4 ) ); 700 | assert( isDefined( allowed ) ); 701 | 702 | return allowed; 703 | } 704 | } 705 | 706 | ReplaceAllowClassChoice() 707 | { 708 | return false; 709 | } 710 | 711 | 712 | 713 | /* Debug section */ 714 | 715 | Debug(key, value) 716 | { 717 | Print("[DEBUG] " + key + ": " + value); 718 | } 719 | 720 | DebugArray(key, array) 721 | { 722 | Print("[DEBUG] " + key); 723 | 724 | foreach (value in array) 725 | { 726 | Print(value); 727 | } 728 | } 729 | 730 | /* 731 | Go to the next weapon whenever you type something in the chat 732 | To quickly cycle through weapons it is recommend to use the bootstrapper and type `say text` 733 | Then use up arrow to quickly get the command again and press enter to run it 734 | Allows you to quickly go to the next weapon, useful to find broken weapon combinations and update FixReversedAttachments() 735 | */ 736 | DebugOnPlayerSay() 737 | { 738 | level endon( "game_ended" ); 739 | 740 | for(;;) 741 | { 742 | level waittill( "say", message, player ); 743 | 744 | if (player.pers["gun_game_current_index"] < (level.gun_game_weapons_amount - 1)) 745 | { 746 | player notify("killed_enemy"); 747 | } 748 | else 749 | { 750 | player IPrintLnBold("CANNOT GIVE WEAPON, YOU ARE AT THE MAX INDEX"); 751 | } 752 | } 753 | } -------------------------------------------------------------------------------- /gamemodes/kamikaze.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\gametypes\_hud_util; 2 | #include maps\mp\gametypes\_class; 3 | //#include maps\mp\bots\_bot_utility; // Uncomment if using Bot Warfare 4 | #include maps\mp\_utility; 5 | 6 | Init() 7 | { 8 | InitKamikazeMode(); 9 | } 10 | 11 | InitKamikazeMode() 12 | { 13 | SetGameLimits(75, 15); 14 | 15 | replacefunc(maps\mp\_utility::allowClassChoice, ::ReplaceAllowClassChoice); 16 | replacefunc(maps\mp\_utility::allowTeamChoice, ::ReplaceAllowTeamChoice); 17 | 18 | level.kamikaze_attack_detonate_interval_time = 0.75; // The time between two attacks when holding the attack button 19 | 20 | level.kamikaze_player_default_radius = 350; 21 | level.kamikaze_player_default_max_damage = 2000; 22 | level.kamikaze_player_default_min_damage = 1000; 23 | 24 | level.kamikaze_player_detonate_reduce_time = 0.375; 25 | level.kamikaze_player_increase_radius = 12.5; 26 | 27 | level.kamikaze_bonus_increase_radius_kills = 5; 28 | level.kamikaze_bonus_decrease_detonate_interval_kills = 15; 29 | 30 | SetDvar("player_sustainAmmo", 1); 31 | SetDvar("jump_height", 585); 32 | SetDvar("g_speed", 475); 33 | SetDvar("g_gravity", 400); 34 | SetDvar("g_playerCollision", 2); 35 | SetDvar("g_playerEjection", 2); 36 | SetDvar("jump_autoBunnyHop", 1); 37 | SetDvar("jump_disableFallDamage", 1); 38 | SetDvar("jump_slowdownEnable", 0); 39 | SetDvar("jump_spreadAdd", 0); 40 | 41 | level thread OnPlayerConnect(); 42 | } 43 | 44 | OnPlayerConnect() 45 | { 46 | for (;;) 47 | { 48 | level waittill("connected", player); 49 | 50 | player.pers["kamikaze_radius"] = level.kamikaze_player_default_radius; 51 | player.pers["kamikaze_max_damage"] = level.kamikaze_player_default_max_damage; 52 | player.pers["kamikaze_min_damage"] = level.kamikaze_player_default_min_damage; 53 | player.pers["kamikaze_detonate_interval_time"] = 3; 54 | player.pers["kamikaze_radius_increase_kills"] = level.kamikaze_bonus_increase_radius_kills; 55 | player.pers["kamikaze_detonate_decrease_kills"] = level.kamikaze_bonus_decrease_detonate_interval_kills; 56 | 57 | player.last_registered_kills = 0; 58 | 59 | player thread OnPlayerSpawned(); 60 | player thread OnPlayerKill(); 61 | 62 | if (!player IsBot()) 63 | { 64 | player DisplayPlayerRadius(); 65 | player DisplayPlayerDetonationInterval(); 66 | } 67 | } 68 | } 69 | 70 | OnPlayerSpawned() 71 | { 72 | self endon("disconnect"); 73 | 74 | for(;;) 75 | { 76 | self waittill("changed_kit"); 77 | 78 | self.pers["detonate_allowed"] = true; 79 | 80 | self ClearPlayerClass(); 81 | self ReplaceWeapons(); 82 | self GiveKamikazePerks(); 83 | 84 | self thread OnPlayerDetonate(); 85 | self thread OnDetonateAllowed(); 86 | self thread OnDetonateDisallowed(); 87 | } 88 | } 89 | 90 | OnPlayerDetonate() 91 | { 92 | self endon("disconnect"); 93 | self endon("death"); 94 | 95 | for(;;) 96 | { 97 | self waittill( "detonate" ); 98 | 99 | if (self.pers["detonate_allowed"]) 100 | { 101 | self DetonatePlayer(); 102 | 103 | self notify("detonate_disallowed"); 104 | } 105 | } 106 | } 107 | 108 | OnDetonateAllowed() 109 | { 110 | self endon("disconnect"); 111 | self endon("death"); 112 | 113 | for(;;) 114 | { 115 | self waittill( "detonate_allowed" ); 116 | 117 | self.pers["detonate_allowed"] = true; 118 | self playlocalsound("ammo_crate_use"); 119 | } 120 | } 121 | 122 | OnDetonateDisallowed() 123 | { 124 | self endon("disconnect"); 125 | self endon("death"); 126 | 127 | for(;;) 128 | { 129 | self waittill( "detonate_disallowed" ); 130 | 131 | self.pers["detonate_allowed"] = false; 132 | 133 | wait self.pers["kamikaze_detonate_interval_time"]; 134 | 135 | self notify("detonate_allowed"); 136 | } 137 | } 138 | 139 | OnPlayerKill() 140 | { 141 | self endon("disconnect"); 142 | 143 | for (;;) 144 | { 145 | self waittill( "killed_enemy" ); 146 | 147 | if (self.kills >= self.pers["kamikaze_radius_increase_kills"] && self.last_registered_kills < self.pers["kamikaze_radius_increase_kills"]) 148 | { 149 | self playlocalsound("copycat_steal_class"); 150 | 151 | self.pers["kamikaze_radius_increase_kills"] = self.pers["kamikaze_radius_increase_kills"] + level.kamikaze_bonus_increase_radius_kills; 152 | self.pers["kamikaze_radius"] = self.pers["kamikaze_radius"] + level.kamikaze_player_increase_radius; 153 | 154 | self.player_radius_text setValue(self.pers["kamikaze_radius"]); 155 | } 156 | 157 | if (self.kills >= self.pers["kamikaze_detonate_decrease_kills"] && self.last_registered_kills < self.pers["kamikaze_detonate_decrease_kills"]) 158 | { 159 | self playlocalsound("copycat_steal_class"); 160 | 161 | self.pers["kamikaze_detonate_decrease_kills"] = self.pers["kamikaze_detonate_decrease_kills"] + level.kamikaze_bonus_decrease_detonate_interval_kills; 162 | self.pers["kamikaze_detonate_interval_time"] = self.pers["kamikaze_detonate_interval_time"] - level.kamikaze_player_detonate_reduce_time; 163 | 164 | self.player_detonation_interval_text setValue(self.pers["kamikaze_detonate_interval_time"]); 165 | } 166 | 167 | self.last_registered_kills = self.kills; 168 | } 169 | } 170 | 171 | DetonatePlayer() 172 | { 173 | self playsound("detpack_explo_default"); 174 | playfx(level.c4death, self.origin); 175 | self radiusdamage( self.origin, self.pers["kamikaze_radius"], self.pers["kamikaze_max_damage"], self.pers["kamikaze_min_damage"], self ); 176 | } 177 | 178 | ReplaceWeapons() 179 | { 180 | self TakeAllWeapons(); 181 | 182 | newWeapon = "c4death_mp"; 183 | 184 | self GiveWeapon(newWeapon); 185 | self SwitchToWeapon(newWeapon); 186 | self SetSpawnWeapon(newWeapon); 187 | } 188 | 189 | ClearPlayerClass() 190 | { 191 | self.pers["gamemodeLoadout"] = self cloneLoadout(); 192 | 193 | self.pers["gamemodeLoadout"]["loadoutJuggernaut"] = false; 194 | self.pers["gamemodeLoadout"]["loadoutPrimary"] = "none"; 195 | self.pers["gamemodeLoadout"]["loadoutSecondary"] = "none"; 196 | self.pers["gamemodeLoadout"]["loadoutKillstreak1"] = "none"; 197 | self.pers["gamemodeLoadout"]["loadoutKillstreak2"] = "none"; 198 | self.pers["gamemodeLoadout"]["loadoutKillstreak3"] = "none"; 199 | self.pers["gamemodeLoadout"]["loadoutPerk1"] = "none"; 200 | self.pers["gamemodeLoadout"]["loadoutPerk2"] = "none"; 201 | self.pers["gamemodeLoadout"]["loadoutPerk3"] = "none"; 202 | 203 | if (!self IsBot()) 204 | { 205 | self maps\mp\gametypes\_class::giveLoadout(self.team, "gamemode", false, true); 206 | } 207 | else 208 | { 209 | //self botGiveLoadout(self.team, "gamemode", false, true); // Uncomment if using Bot Warfare 210 | } 211 | 212 | maps\mp\killstreaks\_killstreaks::clearKillstreaks(); 213 | } 214 | 215 | GiveKamikazePerks() 216 | { 217 | self GivePerk("specialty_longersprint", false); // Extreme conditioning 218 | self GivePerk(GetProPerkName("specialty_longersprint"), false); // Extreme conditioning PRO 219 | 220 | self GivePerk(GetProPerkName("specialty_bulletaccuracy"), false); // Steady aim PRO 221 | self GivePerk(GetProPerkName("specialty_quieter"), false); // Dead silence PRO 222 | } 223 | 224 | DisplayPlayerRadius() 225 | { 226 | self endon ("disconnect"); 227 | level endon("game_ended"); 228 | 229 | self.player_radius_text = createFontString( "Objective", 0.65 ); 230 | self.player_radius_text setPoint( "CENTER", "TOP", 0, 18.75 ); 231 | self.player_radius_text.label = &"^5Your explosions radius: "; 232 | self.player_radius_text.hideWhenInMenu = false; 233 | self.player_radius_text.foreground = false; 234 | 235 | if (!self IsBot()) 236 | { 237 | self.player_radius_text setValue(self.pers["kamikaze_radius"]); 238 | } 239 | } 240 | 241 | DisplayPlayerDetonationInterval() 242 | { 243 | self endon ("disconnect"); 244 | level endon("game_ended"); 245 | 246 | self.player_detonation_interval_text = createFontString( "Objective", 0.65 ); 247 | self.player_detonation_interval_text setPoint( "CENTER", "TOP", 0, 7.5 ); 248 | self.player_detonation_interval_text.label = &"^5Your detonations interval: "; 249 | self.player_detonation_interval_text.hideWhenInMenu = false; 250 | self.player_detonation_interval_text.foreground = false; 251 | 252 | if (!self IsBot()) 253 | { 254 | self.player_detonation_interval_text setValue(self.pers["kamikaze_detonate_interval_time"]); 255 | } 256 | } 257 | 258 | /* 259 | the amount of kills to win 260 | the amount of minutes until the game ends (optional) 261 | Example: 262 | SetGameLimits(20); will change the kills limit to 20 263 | SetGameLimits(40, 15); will change the kills limit to 40 and the time limit to 15 minutes 264 | */ 265 | SetGameLimits(kills_limit, time_limit) 266 | { 267 | score_multiplier = 0; 268 | 269 | switch(level.gameType) 270 | { 271 | case "dm": 272 | score_multiplier = 50; 273 | break; 274 | case "war": 275 | score_multiplier = 100; 276 | break; 277 | default: 278 | score_multiplier = 50; 279 | break; 280 | } 281 | 282 | SetDvar("scr_" + level.gameType + "_scorelimit", kills_limit * score_multiplier); 283 | SetDvar("scorelimit", kills_limit * score_multiplier); 284 | 285 | if (IsDefined(time_limit)) 286 | { 287 | SetDvar("scr_" + level.gameType + "_timelimit", time_limit); 288 | SetDvar("timelimit", time_limit); 289 | } 290 | } 291 | 292 | ReplaceAllowClassChoice() 293 | { 294 | return false; 295 | } 296 | 297 | ReplaceAllowTeamChoice() 298 | { 299 | return false; 300 | } 301 | 302 | GetProPerkName(perkName) 303 | { 304 | return tablelookup( "mp/perktable.csv", 1, perkName, 8 ); 305 | } 306 | 307 | IsBot() 308 | { 309 | return IsDefined(self.pers["isBot"]) && self.pers["isBot"]; 310 | } -------------------------------------------------------------------------------- /gamemodes/one_in_the_chamber.gsc: -------------------------------------------------------------------------------- 1 | #include common_scripts\utility; 2 | #include maps\mp\_utility; 3 | #include maps\mp\gametypes\_class; 4 | 5 | Init() 6 | { 7 | InitOneInTheChamber(); 8 | } 9 | 10 | InitOneInTheChamber() 11 | { 12 | InitWeaponVariables(); 13 | InitOneShotDamages(); 14 | 15 | randomCategoryArray = GetRandomElementInArray(level.one_in_the_chamber_available_weapons); 16 | level.one_in_the_chamber_weapon = GetRandomElementInArray(randomCategoryArray); 17 | level.one_in_the_chamber_kills = 50; 18 | level.blockWeaponDrops = true; 19 | 20 | replacefunc(maps\mp\_utility::allowTeamChoice, ::ReplaceAllowTeamChoice); 21 | replacefunc(maps\mp\_utility::allowClassChoice, ::ReplaceAllowClassChoice); 22 | 23 | SetGameLimits(level.one_in_the_chamber_kills, (level.one_in_the_chamber_kills / 5)); 24 | 25 | level thread OnPlayerConnect(); 26 | } 27 | 28 | InitWeaponVariables() 29 | { 30 | level.one_in_the_chamber_available_weapons = []; 31 | 32 | level.one_in_the_chamber_available_weapons["automatics"] = ["iw5_m4_mp", "iw5_m4_mp_silencer", "iw5_scar_mp", "iw5_scar_mp_silencer", "iw5_g36c_mp", "iw5_g36c_mp_silencer", "iw5_mk14_mp", "iw5_mk14_mp_silencer", "iw5_fad_mp", "iw5_fad_mp_silencer", "iw5_mp5_mp", "iw5_mp5_mp_silencer", "iw5_ump45_mp", "iw5_ump45_mp_silencer", "iw5_pp90m1_mp", "iw5_pp90m1_mp_silencer", "iw5_p90_mp", "iw5_p90_mp_silencer", "iw5_m9_mp", "iw5_m9_mp_silencer", "iw5_mp7_mp", "iw5_mp7_mp_silencer", "iw5_ak74u_mp", "iw5_ak74u_mp_silencer"]; 33 | level.one_in_the_chamber_available_weapons["snipers"] = ["iw5_l96a1_mp_l96a1scope", "iw5_dragunov_mp_dragunovscope", "iw5_as50_mp_as50scope", "iw5_rsass_mp_rsassscope", "iw5_msr_mp_msrscope", "iw5_cheytac_mp_cheytacscope", "iw5_l96a1_mp_l96a1scope_silencer03", "iw5_dragunov_mp_dragunovscope_silencer03", "iw5_as50_mp_as50scope_silencer03", "iw5_rsass_mp_rsassscope_silencer03", "iw5_msr_mp_msrscope_silencer03", "iw5_cheytac_mp_cheytacscope", "iw5_l96a1_mp_acog", "iw5_dragunov_mp_acog", "iw5_as50_mp_acog", "iw5_rsass_mp_acog", "iw5_msr_mp_acog", "iw5_cheytac_mp_acog", "iw5_l96a1_mp_acog_silencer03", "iw5_dragunov_mp_acog_silencer03", "iw5_as50_mp_acog_silencer03", "iw5_rsass_mp_acog_silencer03", "iw5_msr_mp_acog_silencer03", "iw5_cheytac_mp_acog_silencer03"]; 34 | level.one_in_the_chamber_available_weapons["shotguns"] = ["iw5_usas12_mp", "iw5_ksg_mp", "iw5_spas12_mp", "iw5_aa12_mp", "iw5_striker_mp", "iw5_1887_mp"]; 35 | level.one_in_the_chamber_available_weapons["pistols"] = ["iw5_44magnum_mp_tactical", "iw5_44magnum_mp_tactical", "iw5_usp45_mp_tactical", "iw5_usp45_mp_silencer02_tactical", "iw5_deserteagle_mp_tactical", "iw5_deserteagle_mp_tactical", "iw5_mp412_mp_tactical", "iw5_mp412_mp_tactical", "iw5_p99_mp_tactical", "iw5_p99_mp_silencer02_tactical", "iw5_fnfiveseven_mp_tactical", "iw5_fnfiveseven_mp_silencer02_tactical"]; 36 | } 37 | 38 | InitOneShotDamages() 39 | { 40 | level.callbackplayerdamagestub = level.callbackplayerdamage; 41 | level.callbackplayerdamage = ::OneShotDamages; 42 | } 43 | 44 | OnPlayerConnect() 45 | { 46 | for(;;) 47 | { 48 | level waittill("connected", player); 49 | 50 | player.pers["previous_score"] = 0; 51 | 52 | player thread OnPlayerSpawned(); 53 | player thread OnPlayerKill(); 54 | } 55 | } 56 | 57 | OnPlayerSpawned() 58 | { 59 | self endon("disconnect"); 60 | 61 | for(;;) 62 | { 63 | self waittill("changed_kit"); 64 | 65 | self DisableWeaponPickup(); 66 | 67 | self thread ReplaceKillstreaks(); 68 | self thread ReplacePerks(); 69 | self thread ReplaceWeapons(level.one_in_the_chamber_weapon); 70 | } 71 | } 72 | 73 | OnPlayerKill() 74 | { 75 | self endon("disconnect"); 76 | 77 | for (;;) 78 | { 79 | self waittill( "killed_enemy" ); 80 | 81 | self setweaponammoclip(level.one_in_the_chamber_weapon, self getweaponammoclip(level.one_in_the_chamber_weapon) + int((self.score - self.pers["previous_score"]) / 50)); 82 | 83 | self.pers["previous_score"] = self.score; 84 | } 85 | } 86 | 87 | /* 88 | the amount of kills to win 89 | the amount of minutes until the game ends (optional) 90 | 91 | Example: 92 | SetGameLimits(20); will change the kills limit to 20 93 | SetGameLimits(40, 15); will change the kills limit to 40 and the time limit to 15 minutes 94 | */ 95 | SetGameLimits(kills_limit, time_limit) 96 | { 97 | score_multiplier = 0; 98 | 99 | switch(level.gameType) 100 | { 101 | case "dm": 102 | score_multiplier = 50; 103 | break; 104 | case "war": 105 | score_multiplier = 100; 106 | break; 107 | default: 108 | score_multiplier = 50; 109 | break; 110 | } 111 | 112 | SetDvar("scr_" + level.gameType + "_scorelimit", kills_limit * score_multiplier); 113 | SetDvar("scorelimit", kills_limit * score_multiplier); 114 | 115 | if (IsDefined(time_limit)) 116 | { 117 | SetDvar("scr_" + level.gameType + "_timelimit", time_limit); 118 | SetDvar("timelimit", time_limit); 119 | } 120 | } 121 | 122 | ReplaceWeapons(new_weapon) 123 | { 124 | self TakeAllWeapons(); 125 | self GiveWeapon(new_weapon); 126 | 127 | self setweaponammoclip( new_weapon, 1 ); 128 | self setweaponammostock( new_weapon, 0 ); 129 | 130 | self SetSpawnWeapon(new_weapon); 131 | } 132 | 133 | ReplacePerks() 134 | { 135 | self ClearPerks(); 136 | 137 | self GivePerk("specialty_fastreload", false); // Sleight of hand 138 | self GivePerk(GetProPerkName("specialty_fastreload"), false); // Sleight of hand PRO 139 | self GivePerk("specialty_longersprint", false); // Extreme conditioning 140 | self GivePerk(GetProPerkName("specialty_longersprint"), false); // Extreme conditioning PRO 141 | 142 | self GivePerk("specialty_quickdraw", false); // Quickdraw 143 | self GivePerk(GetProPerkName("specialty_quickdraw"), false); // Quickdraw 144 | 145 | self GivePerk("specialty_bulletaccuracy", false); // Steady aim 146 | self GivePerk(GetProPerkName("specialty_bulletaccuracy"), false); // Steady aim PRO 147 | self GivePerk(GetProPerkName("specialty_quieter"), false); // Dead silence PRO 148 | 149 | self GivePerk("specialty_fastermelee", 0); 150 | } 151 | 152 | ReplaceKillstreaks() 153 | { 154 | self.pers["gamemodeLoadout"] = self cloneLoadout(); 155 | self.pers["gamemodeLoadout"]["loadoutJuggernaut"] = false; 156 | 157 | self.pers["gamemodeLoadout"]["loadoutStreakType"] = "streaktype_assault"; // don't give specialist bonus 158 | self.pers["gamemodeLoadout"]["loadoutKillstreak1"] = "none"; 159 | self.pers["gamemodeLoadout"]["loadoutKillstreak2"] = "none"; 160 | self.pers["gamemodeLoadout"]["loadoutKillstreak3"] = "none"; 161 | 162 | if (self IsBot()) 163 | { 164 | self maps\mp\bots\_bot_utility::botGiveLoadout(self.team, "gamemode", false, true); 165 | } 166 | else 167 | { 168 | self maps\mp\gametypes\_class::giveLoadout(self.team, "gamemode", false, true); 169 | } 170 | 171 | maps\mp\killstreaks\_killstreaks::clearKillstreaks(); 172 | } 173 | 174 | ReplaceAllowClassChoice() 175 | { 176 | return false; 177 | } 178 | 179 | IsBot() 180 | { 181 | return IsDefined(self.pers["isBot"]) && self.pers["isBot"]; 182 | } 183 | 184 | GetRandomElementInArray(array) 185 | { 186 | return array[GetArrayKeys(array)[randomint(array.size)]]; 187 | } 188 | 189 | GetProPerkName(perkName) 190 | { 191 | return tablelookup( "mp/perktable.csv", 1, perkName, 8 ); 192 | } 193 | 194 | OneShotDamages( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ) 195 | { 196 | if (isDefined(eAttacker)) 197 | { 198 | if (isDefined(eAttacker.guid) && isDefined(self.guid)) 199 | { 200 | if (eAttacker.guid != self.guid) 201 | { 202 | iDamage = 999; 203 | } 204 | } 205 | } 206 | 207 | self [[level.callbackplayerdamagestub]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ); 208 | } 209 | 210 | ReplaceAllowTeamChoice() 211 | { 212 | gametype = getDvar("g_gametype"); 213 | 214 | if (gametype == "dm" || gametype == "oitc") return false; 215 | else 216 | { 217 | allowed = int( tableLookup( "mp/gametypesTable.csv", 0, level.gameType, 4 ) ); 218 | assert( isDefined( allowed ) ); 219 | 220 | return allowed; 221 | } 222 | } -------------------------------------------------------------------------------- /mapvote/README.md: -------------------------------------------------------------------------------- 1 | # Mapvote 2 | 3 | A customizable mapvote script for the multiplayer mode of Modern Warfare 3. 4 | 5 | This works for both custom games and dedicated servers. 6 | 7 | This is heavily inspired by [LastDemon99's IW5 mapvote](https://github.com/LastDemon99/IW5_VoteSystem). 8 | Huge thanks to him. 9 | 10 | ![mapvote1](images/mapvote1.png) 11 | *Mouse and keyboard input. Changed settings: horizontal spacing: 100* 12 | 13 | ![mapvote2](images/mapvote2.png) 14 | *Controller input. Custom map. Changed settings: red colors, accent mode: max* 15 | 16 | ## mapvote.gsc 17 | 18 | ### Main features 19 | 20 | - It allows up to 12 elements (maps + modes) to be displayed on screen 21 | - You can configure how much maps and modes you want on screen 22 | - It will automatically adapt the amount of elements to display if you don't choose a fixed amount of maps/modes to show 23 | - It has separate map and mode choices 24 | - It supports custom maps 25 | - It supports custom display names for maps 26 | - It supports custom DSR 27 | - It supports custom gamemode names 28 | - It rotates a random map from the list when there are no votes for maps. Same applies for modes too 29 | - You can choose to rotate a random map and mode from a list you define when the human players count is between a min and max values you define (disabled by default) 30 | - Controllers are fully supported and work out of the box 31 | - It has a good level of customization 32 | - It has a debug mode to quickly preview the menu and print some values in the console 33 | 34 | ### Getting started 35 | 36 | To configure the menu before putting it on your server I recommend running it in a custom game with the `mapvote_debug` dvar set to `1`. 37 | To do that use this command in the console `set mapvote_debug 1` before running a custom game. 38 | Start a custom game and you will see the menu. 39 | You can then configure the dvars directly in your console and restart the map with `map_restart` in the console to edit the menu quickly and get your perfect setup. 40 | 41 | Note that by default the mapvote will be activated on all of your servers. 42 | If you run multiple servers and want it off on certain servers you will need to add `set mapvote_enable 0` in the server's CFG. 43 | 44 | ### Configuration 45 | 46 | Below is an example CFG showing how each dvars can be configured. 47 | The values you see are the default values that will be used if you don't set a dvar. 48 | 49 | ```c 50 | set mapvote_enable 1 51 | set mapvote_maps "Seatown,mp_seatown:Dome,mp_dome:Arkaden,mp_plaza2:Bakaara,mp_mogadishu:Resistance,mp_paris:Downturn,mp_exchange:Bootleg,mp_bootleg:Carbon,mp_carbon:Hardhat,mp_hardhat:Lockdown,mp_alpha:Village,mp_village:Fallen,mp_lambeth:Outpost,mp_radar:Interchange,mp_interchange:Underground,mp_underground:Mission,mp_bravo:Piazza,mp_italy:Liberation,mp_park:Overwatch,mp_overwatch:Black Box,mp_morningwood:Sanctuary,mp_meteora:Foundation,mp_cement:Oasis,mp_qadeem:Terminal,mp_terminal_cls:Decommission,mp_shipbreaker:Off Shore,mp_roughneck:Gulch,mp_moab:Boardwalk,mp_boardwalk:Parish,mp_nola:Favela,mp_favela:Highrise,mp_highrise:Skidrow,mp_nightshift:Nuketown,mp_nuked:Rust,mp_rust" // Default value: Every map, including DLC maps and Plutonium DLC maps. This done not include [Face Off maps](https://callofduty.fandom.com/wiki/Face_Off#Modern_Warfare_3) 52 | set mapvote_modes "Team Deathmatch,TDM_default:Domination,DOM_default" // Default value: Team Deathmatch and Domination 53 | set mapvote_additional_maps_dvars "" 54 | set mapvote_limits_maps 0 55 | set mapvote_limits_modes 0 56 | set mapvote_limits_max 12 57 | set mapvote_colors_selected "blue" 58 | set mapvote_colors_unselected "white" 59 | set mapvote_colors_timer "blue" 60 | set mapvote_colors_timer_low "red" 61 | set mapvote_colors_help_text "white" 62 | set mapvote_colors_help_accent "blue" 63 | set mapvote_colors_help_accent_mode "standard" 64 | set mapvote_sounds_menu_enabled 1 65 | set mapvote_sounds_timer_enabled 1 66 | set mapvote_vote_time 30 67 | set mapvote_blur_level 2.5 68 | set mapvote_blur_fade_in_time 2 69 | set mapvote_horizontal_spacing 75 70 | set mapvote_display_wait_time 1 71 | set mapvote_default_rotation_enable 0 72 | set mapvote_default_rotation_maps "mp_dome:mp_nuked:mp_rust" 73 | set mapvote_default_rotation_modes "TDM_default" 74 | set mapvote_default_rotation_min_players 0 75 | set mapvote_default_rotation_max_players 0 76 | ``` 77 | 78 | Here are some pre-set values if you want to quickly copy/paste something 79 | 80 | | Description | Value | 81 | |---|---| 82 | | All base game maps | "Seatown,mp_seatown:Dome,mp_dome:Arkaden,mp_plaza2:Bakaara,mp_mogadishu:Resistance,mp_paris:Downturn,mp_exchange:Bootleg,mp_bootleg:Carbon,mp_carbon:Hardhat,mp_hardhat:Lockdown,mp_alpha:Village,mp_village:Fallen,mp_lambeth:Outpost,mp_radar:Interchange,mp_interchange:Underground,mp_underground:Mission,mp_bravo" | 83 | | All DLC maps | "Piazza,mp_italy:Liberation,mp_park:Overwatch,mp_overwatch:Black Box,mp_morningwood:Sanctuary,mp_meteora:Foundation,mp_cement:Oasis,mp_qadeem:Terminal,mp_terminal_cls:Decommission,mp_shipbreaker:Off Shore,mp_roughneck:Gulch,mp_moab:Boardwalk,mp_boardwalk:Parish,mp_nola" | 84 | | All Face Off maps | "Lookout,mp_restrepo_ss:Getaway,mp_hillside_ss:Erosion,mp_courtyard_ss:Aground,mp_aground_ss:Vortex,mp_six_ss:U-Turn,mp_burn_ss:Intersection,mp_crosswalk_ss" | 85 | | All Plutonium DLC maps | "Favela,mp_favela:Highrise,mp_highrise:Skidrow,mp_nightshift:Nuketown,mp_nuked:Rust,mp_rust" | 86 | | Classic modes | "Team Deathmatch,TDM_default:Domination,DOM_default" | 87 | | Objective modes | "Demolition,DD_default:Headquaters,HQ_default:Capture the Flag,CTF_default" | 88 | | Alternative modes | "Kill Confirmed,KC_default:Team Defender,TDEF_default:Sabotage,SAB_default:Drop Zone,DZ_default" | 89 | | Party modes | "Gun Game,GG_default:One in the Chamber,OIC_default" | 90 | | Juggernaut modes | "Juggernaut,JUG_default:Team Juggernaut,TJ_default" | 91 | | FFA 24/7 | "Free for All,FFA_default" | 92 | | SND 24/7 | "Search & Destroy,SD_default" | 93 | | Infected 24/7 | "Infected,INF_default" | 94 | 95 | ### Dvars 96 | 97 | Here are the dvars you can configure: 98 | 99 | | Name | Description | Accepted values | 100 | |---|---|---| 101 | | mapvote_enable | Toggle whether the mapvote is activated or not. 0 is off and 1 is on | 0 or 1 | 102 | | mapvote_debug | Toggle whether the mapvote runs in debug mode or not. This will display the mapvote menu a few seconds after starting the game. 0 is off and 1 is on | 0 or 1 | 103 | | mapvote_maps | A list of the maps that are available for rotation | Any text followed by a comma (,) and then the map code name (mapname). Each block is separated with a colon (:). A single space `" "` is also accepted if you don't want any maps for this dvar | 104 | | mapvote_modes | A list of the modes that are available for rotation. The first parameter is how the mode will be displayed, it can be set to anything you like, the second parameter is the name of the DSR file to load | Any text followed by a comma (,) and then the cfg name. Each block is separated with a colon (:) | 105 | | mapvote_additional_maps_dvars | A list of dvar name(s) that contain additional maps, respecting the `mapvote_maps` format. See [Adding a custom map](#adding-a-custom-map) | Any valid dvar name that has a list of maps as value. Each dvar name is separated with a colon (:) | 106 | | mapvote_limits_maps | The amount of maps to display. 0 will handle it automatically | Any plain number from 0 to `mapvote_limits_max` | 107 | | mapvote_limits_modes | The amount of modes to display. 0 will handle it automatically | Any plain number from 0 to `mapvote_limits_max` | 108 | | mapvote_limits_max | The maximum amount of elements to display (maps + modes) | 2, 4, 6, 8, 10, 12 | 109 | | mapvote_colors_selected | The color of the text when hovered or selected. This is also the color of the votes count | red, green, yellow, blue, cyan, purple, white, grey, gray, black | 110 | | mapvote_colors_unselected | The color of the text when not hovered and not selected | red, green, yellow, blue, cyan, purple, white, grey, gray, black | 111 | | mapvote_colors_timer | The color of the timer as long as it has more than 5 seconds remaining | red, green, yellow, blue, cyan, purple, white, grey, gray, black | 112 | | mapvote_colors_timer_low | The color of the timer when it has 5 or less seconds remaining | red, green, yellow, blue, cyan, purple, white, grey, gray, black | 113 | | mapvote_colors_help_text | The color of the help text at the bottom explaining how to use the menu | red, green, yellow, blue, cyan, purple, white, grey, gray, black | 114 | | mapvote_colors_help_accent | The color of the accented text of the help text at the bottom | red, green, yellow, blue, cyan, purple, white, grey, gray, black | 115 | | mapvote_colors_help_accent_mode | The accenting mode for the help text. `standard` only puts the accent color on the button to press and `max` puts it on both the buttons and the action it does | standard or max | 116 | | mapvote_sounds_menu_enabled | Toggle whether the mapvote menu sounds are enabled or not. 0 is off and 1 is on | 0 or 1 | 117 | | mapvote_sounds_timer_enabled | Toggle whether the timer will start making a beeping sound every second when there's 5 or less seconds remaining to vote or not. 0 is off and 1 is on | 0 or 1 | 118 | | mapvote_vote_time | The time the vote lasts (in seconds) | Any plain number above 5 | 119 | | mapvote_blur_level | The amount of blur to put when the mapvote menu starts to show. The max recommended value is 5. 0 disables it | Any number | 120 | | mapvote_blur_fade_in_time | The time (in seconds) it takes for the blur to reach `mapvote_blur_level`. For example if you set it to 10 and `mapvote_blur_level` is 5 then it will progressively blur the screen from 0 to 5 in 10 seconds | Any number | 121 | | mapvote_horizontal_spacing | The horizontal spacing between the map/mode names on the left and the vote counts on the right. I recommend setting this value according to the longest map or mode name length so that it doesn't overlap with the vote counts | Any plain number | 122 | | mapvote_display_wait_time | Once the killcam ends, the time to wait before displaying the vote menu (in seconds) | Any number superior or equal to 0.05 | 123 | | mapvote_default_rotation_enable | Toggle whether the default rotation system is activated or not. This allows you to have one or more map(s) and mode(s) rotate by default when the human player count is between `mapvote_default_rotation_min_players` and `mapvote_default_rotation_max_players` 0 is off and 1 is on | 0 or 1 | 124 | | mapvote_default_rotation_maps | A list of the map code names that are available for default rotation | Any map code name. Each map is separated with a colon (:) | 125 | | mapvote_default_rotation_modes | A list of the DSR file names that are available for default rotation | Any DSR file name. Each DSR file name is separated with a colon (:) | 126 | | mapvote_default_rotation_min_players | The minimum amount of human players required to rotate the default rotation instead of showing the mapvote. If the human players count is smaller than this then it will display the regular mapvote rotation instead | Any plain number from 0 to 18 | 127 | | mapvote_default_rotation_max_players | The maximum amount of human players required to rotate the default rotation instead of showing the mapvote. If the human players count is higher than this then it will display the regular mapvote rotation instead | Any plain number from 0 to 18 | 128 | 129 | ### Adding a custom map 130 | 131 | **[IMPORTANT]** MW3 has a limit of `1024` characters for dvars so the value of `mapvote_maps` cannot be longer than that or it will fail to read it properly. 132 | 133 | For this reason there are ways to add a custom map to your rotation: 134 | 135 | #### Adding a custom map the classic way 136 | 137 | You can simply add your map normally to `mapvote_maps` while being sure the dvar doesn't have more than `1024` characters. 138 | So for example, if you wanted to add Scrapyard as a custom map in your rotation `"Seatown,mp_seatown:Dome,mp_dome"` would become `"Seatown,mp_seatown:Dome,mp_dome:Scrapyard,mp_boneyard"` 139 | 140 | #### Adding a custom map the advanced way 141 | 142 | On the other hand, if `mapvote_maps` is close to having more than `1024` characters or if you want to better organize your custom maps you can use the system I put in place. 143 | 144 | Simply create a dvar with any name you want, for example `mapvote_maps_mw2` and then add maps to it the same way you add maps to `mapvote_maps` and respecting the `1024` characters limit too. 145 | Finally, add the **name** of this dvar to `mapvote_additional_maps_dvars`. 146 | So in this example `mapvote_additional_maps_dvars "mapvote_maps_mw2"`. 147 | The script will then automatically read all values from `mapvote_maps` and `mapvote_maps_mw2`, all your maps will be taken into account for the randomization of available maps. 148 | 149 | You can simply repeat this process to add even more dvars in case you go up to the characters limit again or if you simply want to organize your maps dvars. 150 | For example you could create an additional dvar named `mapvote_maps_bo2` that holds some maps and then add it to the list of dvars like this `mapvote_additional_maps_dvars "mapvote_maps_mw2:mapvote_maps_bo2"`. 151 | 152 | Note that you can change the value of `mapvote_maps` to a single space `" "` if you don't want any map in this dvar. 153 | It will then only get maps from the additional dvars and will ignore the original dvar. 154 | This can be useful to organise your maps dvars. 155 | 156 | ### Notes 157 | 158 | - Capture the Flag is very buggy and will not be fixed. It pretty much breaks the entire mapvote script so I recommend to not add it. 159 | From the tests I did it seems a lot of things outside of my mapvote break it and I'm not willing to fight with so much unknown bugs coming from the outside 160 | - If right click is set to toggle ads then pressing right click will make the player go up by one every 0.25s until he right clicks again. 161 | If I didn't change it to be that way players with toggle ads would have to press right click twice to go up by one all the time. 162 | Now instead they simply right click once to start going up and right click again to stop which is a better user experience. 163 | - When there's only one map/mode, instead of showing a single vote possibility, your single map/mode will be hidden to make the user experience better but it will still always rotate to your one map/mode 164 | - If some map/mode names or vote count don't display at all then you probably have other scripts that create HUD elements and there's too much elements to display so either remove your script or lower `mapvote_limits_max` so that the mapvote will have less elements to display 165 | - When two maps/modes have the same votes, the lowest one in the list will win. In the future it would be nice to randomize between both 166 | - The game doesn't seem to have a way to display the correct key for aiming (whether you use hold to ads or toggle ads) so after trying multiple solutions I decided to simply put both keys on screen. It's not perfect but this ensures the players have all the information to use the menu properly 167 | - Once you enable your controller the game seems to never display the keyboard key again for the `Use` key (Undo). It's a pretty situational/rare bug but it would be nice to find another key or a way to somehow fix it in the future 168 | -------------------------------------------------------------------------------- /mapvote/images/mapvote1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Resxt/Plutonium-IW5-Scripts/082c3b53fadcb16b3294cf7f183db2cb8d87c45c/mapvote/images/mapvote1.png -------------------------------------------------------------------------------- /mapvote/images/mapvote2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Resxt/Plutonium-IW5-Scripts/082c3b53fadcb16b3294cf7f183db2cb8d87c45c/mapvote/images/mapvote2.png -------------------------------------------------------------------------------- /replace_weapon_on_spawn/README.md: -------------------------------------------------------------------------------- 1 | # Replace Weapon On Spawn 2 | 3 | This can easily be modified to always give a certain weapon or only give it when the player has a certain weapon etc. 4 | This is useful to add ported weapons like the Intervention to your default classes until Plutonium adds the possibility to do it directly in dsr files. 5 | 6 | ## replace_rsass_with_intervention.gsc 7 | 8 | Replace the RSASS with an Intervention (ACOG sight) 9 | 10 | Replace the RSASS silencer with an Intervention (ACOG sight + silencer) 11 | 12 | Gives a throwing knife and a tactical insertion in both cases 13 | 14 | ## replace_with_snipers.gsc 15 | 16 | Replace any weapon with a bolt action sniper with the extended mags attachment. 17 | Can be configured to only work for bots, players or both by changing `level.rws_applies_to`. 18 | As of now this removes secondary weapons and grenades but the script can easily be modified to add additional checks for these and replace/remove them only if needed. 19 | An example that shows how to only apply the replacement if the primary isn't valid can be found in `DoWeaponCheck()`. -------------------------------------------------------------------------------- /replace_weapon_on_spawn/replace_rsass_with_intervention.gsc: -------------------------------------------------------------------------------- 1 | Init() 2 | { 3 | level thread OnPlayerConnect(); 4 | } 5 | 6 | OnPlayerConnect() 7 | { 8 | for(;;) 9 | { 10 | level waittill("connected", player); 11 | player thread OnPlayerSpawned(); 12 | } 13 | } 14 | 15 | OnPlayerSpawned() 16 | { 17 | self endon("disconnect"); 18 | for(;;) 19 | { 20 | self waittill("changed_kit"); 21 | current_weapon = self GetCurrentWeapon(); 22 | self thread DoWeaponCheck(current_weapon); 23 | } 24 | } 25 | 26 | DoWeaponCheck(current_weapon) 27 | { 28 | self endon("death"); 29 | self endon("disconnect"); 30 | level endon("game_ended"); 31 | 32 | //Debug(current_weapon); 33 | 34 | if (current_weapon == "iw5_rsass_mp_rsassscope") 35 | { 36 | ReplaceWeapon("iw5_cheytac_mp_acog"); 37 | GiveLethalAndTactical(); 38 | 39 | } 40 | else if (current_weapon == "iw5_rsass_mp_rsassscope_silencer03") 41 | { 42 | ReplaceWeapon("iw5_cheytac_mp_acog_silencer03"); 43 | GiveLethalAndTactical(); 44 | } 45 | } 46 | 47 | ReplaceWeapon(new_weapon) 48 | { 49 | self TakeAllWeapons(); 50 | self GiveWeapon(new_weapon); 51 | self SetSpawnWeapon(new_weapon); // This gives the weapon without playing the animation 52 | } 53 | 54 | // TakeAllWeapons() removes lethal and tactical as well so we give default items after calling it 55 | GiveLethalAndTactical() 56 | { 57 | self GiveWeapon("throwingknife_mp"); // Found in dsr files 58 | self GiveWeapon("flare_mp"); // Tactical insertion - found in common_mp.ff 59 | } 60 | 61 | // Prints text in the bootstrapper 62 | Debug(text) 63 | { 64 | Print(text); 65 | } -------------------------------------------------------------------------------- /replace_weapon_on_spawn/replace_with_snipers.gsc: -------------------------------------------------------------------------------- 1 | #include common_scripts\utility; 2 | 3 | Init() 4 | { 5 | level.rws_available_weapons = []; 6 | level.rws_available_weapons[level.rws_available_weapons.size] = "iw5_l96a1_mp_l96a1scope_xmags"; 7 | level.rws_available_weapons[level.rws_available_weapons.size] = "iw5_msr_mp_msrscope_xmags"; 8 | level.rws_available_weapons[level.rws_available_weapons.size] = "iw5_cheytac_mp_cheytacscope_xmags"; 9 | 10 | level.rws_applies_to = 0; // 0 = bots only, 1 = players only, 2 = everyone 11 | 12 | level thread OnPlayerConnect(); 13 | } 14 | 15 | OnPlayerConnect() 16 | { 17 | for(;;) 18 | { 19 | level waittill("connected", player); 20 | 21 | if (isDefined(player.pers["isBot"])) 22 | { 23 | if (player.pers["isBot"]) 24 | { 25 | if (level.rws_applies_to == 1) { 26 | continue; // if level.rws_applies_to is set to players only and we are a bot, skip 27 | } 28 | } 29 | else { 30 | if (level.rws_applies_to == 0) { 31 | continue; // if level.rws_applies_to is set to bots only and we are a player, skip 32 | } 33 | } 34 | } 35 | else { 36 | if (level.rws_applies_to == 0) { 37 | continue; // if level.rws_applies_to is set to bots only and we are a player, skip 38 | } 39 | } 40 | 41 | player thread OnPlayerSpawned(); 42 | } 43 | } 44 | 45 | OnPlayerSpawned() 46 | { 47 | self endon("disconnect"); 48 | 49 | for(;;) 50 | { 51 | self waittill("changed_kit"); 52 | 53 | current_weapon = self GetCurrentWeapon(); 54 | 55 | self thread DoWeaponCheck(current_weapon); 56 | } 57 | } 58 | 59 | DoWeaponCheck(current_weapon) 60 | { 61 | // Uncomment this block and put all the code below (in this function) in the if condition if you don't want to change classes that already have the correct primary 62 | // Additional checks are required to check for secondary weapon lethal/tactical grenades 63 | // Thanks to TakeAllWeapons() in ReplaceWeapon() the secondary weapon and lethal/tactical grenades are removed so no check is needed 64 | 65 | /*weapon_tokens = strTok(current_weapon, "_"); 66 | 67 | if (weapon_tokens[1] != "l96a1" && weapon_tokens[1] != "msr" && weapon_tokens[1] != "cheytac") { 68 | 69 | }*/ 70 | 71 | ReplaceWeapon(random(level.rws_available_weapons)); 72 | } 73 | 74 | ReplaceWeapon(new_weapon) 75 | { 76 | self TakeAllWeapons(); 77 | self GiveWeapon(new_weapon); 78 | self SetSpawnWeapon(new_weapon); // This gives the weapon without playing the animation 79 | } -------------------------------------------------------------------------------- /small_scripts/README.md: -------------------------------------------------------------------------------- 1 | # Small scripts 2 | 3 | Simple drag and drop scripts 4 | 5 | ## anti_hardscope.gsc 6 | 7 | Prevent players from hardscoping 8 | 9 | ## autoassign_team.gsc 10 | 11 | Whenever a player connects directly autoassign him to a team, skipping the team selection menu 12 | 13 | ## change_team_names.gsc 14 | 15 | Change the team names to custom names depending on the game mode 16 | 17 | ## disable_damages.gsc 18 | 19 | Disable melee knifing damage. 20 | Also prevents players from dying to their own grenades and rockets. 21 | Note that if you shoot enough rockets (around 20/30) you can still kill yourself. 22 | This also doesn't prevent players from killing themselves when they hold a frag grenade in their hands. 23 | 24 | ## disable_nuke_killstreak.gsc 25 | 26 | Prevent players from obtaining the nuke/M.O.A.B killstreak when they have enough kills. 27 | 28 | ## display_player_stats.gsc 29 | 30 | Display the player's killstreak, total kills and deaths on top of the screen 31 |
32 | Image 33 | 34 | ![image](images/display_player_stats.png) 35 |
36 | 37 | ## get_player_guid.gsc 38 | 39 | Print the GUID of a player in the console whenever he connects and whenever he chooses/changes class. 40 | 41 | ## give_perks_on_spawn.gsc 42 | 43 | Gives perks to a player whenever he spawns if he doesn't already have them. 44 | This script has been written to give sleight of hand and quickdraw even if you have other perks like overkill (carry two primary weapons). 45 | You can find the list of perks and pro perks in [perktable.csv](https://github.com/chxseh/MW3-GSC-Dump/blob/e9445976df9f91451fa6e5dc3cb4663390aafcec/_raw-files/mp/perktable.csv) 46 | 47 | ## jump_monitor.gsc 48 | 49 | Whenever players touch the ground they have 7.5s to jump or they will explode. At 50% of this time a beeping sound starts playing. 50 | Whenever the player jumps the timer stops and is only starting again from the beginning when he touches the ground. 51 | This script is really useful if you have a high jump server and you want to make sure that players don't stay on the ground for too long and also if you have bots it ensures they don't stay on the ground most of the game to make games dynamic. 52 | 53 | Bot Warfare bots are supported but the code for it is disabled by default to avoid getting any error in case Bot Warfare isn't installed. 54 | To enable support for Bot Warfare simply uncomment the lines where it says `Uncomment if using Bot Warfare`. 55 | This will monitor bots individually and make them jump every `level.jump_monitor_bot_wait_time` second after they touch the ground. 56 | 57 | ## hardcore_tweaks.gsc 58 | 59 | The hardcore mode replaces some game functionalities like enabling friendly fire or disabling killcams. 60 | With this script you can override the tweaks the hardcore mode brings. 61 | 62 | ## kill_players_under_map.gsc 63 | 64 | This is a script that kills players when they are under the map. 65 | Some maps don't have a script to kill players under the map and they can exploit it to kill players while being under the map. 66 | Go under the map on the barrier and check the console to get the value to check. 67 | Then open the in-game console and type `mapname` to get the map name. 68 | Finally simply add a case to the `switch (map_name)` with the `mapname` value as the case and the `self.origin[2]` value as the returned value. 69 | 70 | ## kill_stuck_bots.gsc 71 | 72 | This is a temporary solution to inactive bots or bots stuck in corners on custom maps. 73 | This checks for bots kills and deaths every 30 seconds. If they didn't do any kill or didn't die in 30 seconds they're considered inactive/stuck and they're killed. 74 | Obviously a better way to do this would be checking for their positions or removing bad spawns on the map or creating waypoints for the map. 75 | This is just a quick temporary solution that works for me. 76 | 77 | ## manage_bots_fill.gsc 78 | 79 | Simple script that changes the Bot Warfare `bots_manage_fill` dvar dynamically to avoid using resource for an empty server. 80 | Whenever a player connects or disconnects the script checks the amount of human players and the value of `bots_manage_fill` and sets it accordingly. 81 | If the first player joins, it sets the dvar to the value you configured for that specific server (set in `InitServersDvar()` with the server port). 82 | If the last player leaves it sets back the dvar to 0 so that no bots will be playing, saving some resources on that server. 83 | 84 | ## remove_heavy_weapon_slow.gsc 85 | 86 | Set back your speed scale to default whenever you have an heavy weapon equipped. 87 | Whenever you have an LMG gun or heavy sniper like a Barrett your speed will be slower than with most weapons. 88 | This script makes it so that no matter the weapons you have in your class your speed will be normal/default. 89 | The script doesn't modify the player's speed, instead it modifies the speed scaling (sets it back to 1) so it's safe to use with modified `g_speed`. 90 | The speeds were tested/monitored with this [speed meter script from quaK](https://github.com/Joelrau/IW5p_DeathRun/blob/aaa9a4231d338b765d8b0fc8b06825b3a6d2a413/plugins/simplevelometer.gsc) 91 | 92 | ## show_text_on_first_spawn.gsc 93 | 94 | Display a text to a player when it's the first time he spawns in a match. 95 | This can be used to display a specific rule, a warning or just a message. 96 | 97 | ## welcome_message.gsc 98 | 99 | Display a welcome message to a player (MW2 typewriter style) when it's the first time he spawns in a match. 100 | This has an optional sound, optionally up to 3 lines of text, an optional icon and an optional glow to the text, all with support for color codes for the text. 101 | To change the icon displayed just change the value of `level.welcome_message_icon`. Most icons can be found on [this list](https://www.itsmods.com/forum/Thread-Tutorial-MW3-Cardicon-list.html). 102 | Some sounds can be found by searching the dump with certain keywords such as [playsound](https://github.com/plutoniummod/iw5-scripts/search?q=playsound) and [playlocalsound](https://github.com/plutoniummod/iw5-scripts/search?q=playlocalsound) 103 | 104 |
105 | Image 106 | 107 | ![image](images/welcome_message.png) 108 |
109 | -------------------------------------------------------------------------------- /small_scripts/anti_hardscope.gsc: -------------------------------------------------------------------------------- 1 | //#include maps\mp\bots\_bot_utility; // Uncomment if using Bot Warfare 2 | 3 | Init() 4 | { 5 | level thread OnPlayerConnect(); 6 | } 7 | 8 | OnPlayerConnect() 9 | { 10 | for(;;) 11 | { 12 | level waittill("connected", player); 13 | 14 | // Uncomment if using Bot Warfare 15 | /*if (!player IsBot()) 16 | { 17 | player thread OnPlayerSpawned(); 18 | }*/ 19 | 20 | player thread OnPlayerSpawned(); // Remove/comment if using Bot Warfare 21 | } 22 | } 23 | 24 | OnPlayerSpawned() 25 | { 26 | self endon("disconnect"); 27 | 28 | for(;;) 29 | { 30 | self waittill("spawned_player"); 31 | 32 | self.pers["allow_ads"] = true; 33 | 34 | self thread AntiHardscope(); 35 | } 36 | } 37 | 38 | AntiHardscope() 39 | { 40 | self endon("disconnect"); 41 | self endon("death"); 42 | 43 | while (true) 44 | { 45 | if (self PlayerAds() >= 0.75) 46 | { 47 | wait 0.65; 48 | 49 | if (self PlayerAds() >= 0.75) 50 | { 51 | self IPrintLn("^1Hardscoping is not allowed"); 52 | self AllowAds(false); 53 | self.pers["allow_ads"] = false; 54 | } 55 | } 56 | else if (self PlayerAds() < 0.75 && self.pers["allow_ads"] == false && self AdsButtonPressed() == false) 57 | { 58 | self.pers["allow_ads"] = true; 59 | self AllowAds(true); 60 | } 61 | 62 | wait 0.01; 63 | } 64 | } 65 | 66 | IsBot() 67 | { 68 | //return IsDefined(self.pers["isBot"]) && self.pers["isBot"]; // Uncomment if using Bot Warfare 69 | } -------------------------------------------------------------------------------- /small_scripts/autoassign_team.gsc: -------------------------------------------------------------------------------- 1 | Init() 2 | { 3 | InitTest(); 4 | } 5 | 6 | InitTest() 7 | { 8 | replacefunc(maps\mp\_utility::allowTeamChoice, ::ReplaceAllowTeamChoice); 9 | 10 | level thread OnPlayerConnect(); 11 | } 12 | 13 | OnPlayerConnect() 14 | { 15 | for(;;) 16 | { 17 | level waittill("connected", player); 18 | 19 | if (!IsDefined(player.pers["autoassign_connected"]) || !player.pers["autoassign_connected"]) 20 | { 21 | player.pers["autoassign_connected"] = true; 22 | 23 | player [[level.autoassign]](); 24 | } 25 | } 26 | } 27 | 28 | ReplaceAllowTeamChoice() 29 | { 30 | return false; 31 | } -------------------------------------------------------------------------------- /small_scripts/change_team_names.gsc: -------------------------------------------------------------------------------- 1 | Init() 2 | { 3 | switch (GetDvar("g_gametype")) 4 | { 5 | case "infect": 6 | ReplaceTeamNames("^1Infected", "^2Survivors"); 7 | break; 8 | case "dm": 9 | ReplaceTeamNames("^1Solo", ""); 10 | break; 11 | default: 12 | ReplaceTeamNames("^1Team #1", "^1Team #2"); 13 | break; 14 | } 15 | } 16 | 17 | ReplaceTeamNames(axis_name, allies_name) 18 | { 19 | SetDvar("g_TeamName_Axis", axis_name); 20 | SetDvar("g_TeamName_Allies", allies_name); 21 | } -------------------------------------------------------------------------------- /small_scripts/disable_damages.gsc: -------------------------------------------------------------------------------- 1 | Init() 2 | { 3 | level.callbackplayerdamagestub = level.callbackplayerdamage; 4 | level.callbackplayerdamage = ::DisableDamages; 5 | } 6 | 7 | DisableDamages( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ) 8 | { 9 | if (isDefined(eAttacker)) 10 | { 11 | if (isDefined(eAttacker.guid) && isDefined(self.guid)) 12 | { 13 | if (eAttacker.guid == self.guid) 14 | { 15 | // Disable explosive damage on self 16 | switch (sMeansOfDeath) 17 | { 18 | case "MOD_PROJECTILE_SPLASH": iDamage = 0; 19 | break; 20 | case "MOD_GRENADE_SPLASH": iDamage = 0; 21 | break; 22 | case "MOD_EXPLOSIVE": iDamage = 0; 23 | break; 24 | } 25 | } 26 | else 27 | { 28 | // Disable melee knifing damage 29 | if (sMeansOfDeath == "MOD_MELEE") 30 | { 31 | iDamage = 0; 32 | } 33 | } 34 | } 35 | } 36 | 37 | self [[level.callbackplayerdamagestub]]( eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset ); 38 | } -------------------------------------------------------------------------------- /small_scripts/disable_nuke_killstreak.gsc: -------------------------------------------------------------------------------- 1 | Init() 2 | { 3 | level thread OnPlayerConnect(); 4 | } 5 | 6 | OnPlayerConnect() 7 | { 8 | for(;;) 9 | { 10 | level waittill("connected", player); 11 | 12 | player thread OnPlayerSpawned(); 13 | } 14 | } 15 | 16 | OnPlayerSpawned() 17 | { 18 | self endon("disconnect"); 19 | 20 | for(;;) 21 | { 22 | self waittill("spawned_player"); 23 | 24 | self.pers["cur_kill_streak_for_nuke"] = -999; 25 | } 26 | } -------------------------------------------------------------------------------- /small_scripts/display_player_stats.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\gametypes\_hud_util; 2 | 3 | Init() 4 | { 5 | level thread OnPlayerConnected(); 6 | } 7 | 8 | OnPlayerConnected() 9 | { 10 | for(;;) 11 | { 12 | level waittill("connected", player); 13 | 14 | // Don't thread DisplayPlayerKillstreak() on bots 15 | if (isDefined(player.pers["isBot"])) 16 | { 17 | if (player.pers["isBot"]) 18 | { 19 | continue; // skip 20 | } 21 | } 22 | 23 | player thread DisplayPlayerKillstreak(); 24 | } 25 | } 26 | 27 | 28 | DisplayPlayerKillstreak() 29 | { 30 | self endon ("disconnect"); 31 | level endon("game_ended"); 32 | 33 | self.killstreak_text = createFontString( "Objective", 0.65 ); 34 | self.killstreak_text setPoint( "CENTER", "TOP", "CENTER", 7.5 ); 35 | self.killstreak_text.label = &"^1 | KILLSTREAK: "; 36 | 37 | kills_text_x = -49; 38 | kills_text_x_move = 2.5; 39 | self.kills_text = createFontString( "Objective", 0.65 ); 40 | self.kills_text setPoint( kills_text_x, "TOP", kills_text_x, 7.5 ); 41 | self.kills_text.label = &"^1KILLS: "; 42 | 43 | self.deaths_text = createFontString( "Objective", 0.65 ); 44 | self.deaths_text setPoint( 56.5, "TOP", 56.5, 7.5 ); 45 | self.deaths_text.label = &"^1 | DEATHS: "; 46 | 47 | while(true) 48 | { 49 | if(self.playerstreak != self.pers["cur_kill_streak"]) 50 | { 51 | self.playerstreak = self.pers["cur_kill_streak"]; 52 | self.killstreak_text setValue(self.pers["cur_kill_streak"]); 53 | } 54 | 55 | if (self.pers["kills"] >= 10 && self.kills_text.x == kills_text_x) 56 | { 57 | self.kills_text.x = self.kills_text.x - kills_text_x_move; 58 | } 59 | else if (self.pers["kills"] >= 100 && self.kills_text.x == kills_text_x - kills_text_x_move) 60 | { 61 | self.kills_text.x = self.kills_text.x - kills_text_x_move; 62 | } 63 | 64 | self.kills_text setValue(self.pers["kills"]); 65 | self.deaths_text setValue(self.pers["deaths"]); 66 | 67 | wait 0.01; 68 | } 69 | } -------------------------------------------------------------------------------- /small_scripts/get_player_guid.gsc: -------------------------------------------------------------------------------- 1 | Init() 2 | { 3 | level thread OnPlayerConnect(); 4 | } 5 | 6 | OnPlayerConnect() 7 | { 8 | for(;;) 9 | { 10 | level waittill("connected", player); 11 | Print(player.name + " GUID: " + player.guid); 12 | player thread OnPlayerSpawned(); 13 | } 14 | } 15 | 16 | OnPlayerSpawned() 17 | { 18 | self endon("disconnect"); 19 | for(;;) 20 | { 21 | self waittill("changed_kit"); 22 | Print(self.name + " GUID: " + self.guid); 23 | } 24 | } -------------------------------------------------------------------------------- /small_scripts/give_perks_on_spawn.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\_utility; 2 | 3 | Init() 4 | { 5 | level thread OnPlayerConnect(); 6 | } 7 | 8 | OnPlayerConnect() 9 | { 10 | for(;;) 11 | { 12 | level waittill("connected", player); 13 | 14 | player thread OnPlayerSpawned(); 15 | } 16 | } 17 | 18 | OnPlayerSpawned() 19 | { 20 | self endon("disconnect"); 21 | for(;;) 22 | { 23 | self waittill("changed_kit"); 24 | 25 | GivePerks(); 26 | } 27 | } 28 | 29 | GivePerks() 30 | { 31 | if ( !self _hasPerk( "specialty_quickdraw" )) 32 | { 33 | self givePerk( "specialty_quickdraw", false ); // Quickdraw 34 | self givePerk( "specialty_fastoffhand", false ); // Quickdraw Pro 35 | } 36 | 37 | if ( !self _hasPerk( "specialty_fastreload" )) 38 | { 39 | self givePerk( "specialty_fastreload", false ); // Sleight of hand 40 | self givePerk( "specialty_quickswap", false ); // Sleight of hand Pro 41 | } 42 | } -------------------------------------------------------------------------------- /small_scripts/hardcore_tweaks.gsc: -------------------------------------------------------------------------------- 1 | Init() 2 | { 3 | level.teamTweaks["fftype"].value = 0; // Disable friendly fire 4 | level.gameTweaks["allowkillcam"].value = 1; // Enable killcams - doesn't seem to work anymore 5 | level.killcam = true; // Enable killcams 6 | } 7 | -------------------------------------------------------------------------------- /small_scripts/images/display_player_stats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Resxt/Plutonium-IW5-Scripts/082c3b53fadcb16b3294cf7f183db2cb8d87c45c/small_scripts/images/display_player_stats.png -------------------------------------------------------------------------------- /small_scripts/images/welcome_message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Resxt/Plutonium-IW5-Scripts/082c3b53fadcb16b3294cf7f183db2cb8d87c45c/small_scripts/images/welcome_message.png -------------------------------------------------------------------------------- /small_scripts/jump_monitor.gsc: -------------------------------------------------------------------------------- 1 | //#include maps\mp\bots\_bot_utility; // Uncomment if using Bot Warfare 2 | //#include maps\mp\bots\_bot_internal; // Uncomment if using Bot Warfare 3 | #include maps\mp\gametypes\_hud_util; 4 | #include common_scripts\utility; 5 | #include maps\mp\_utility; 6 | 7 | Init() 8 | { 9 | InitJumpMonitor(); 10 | } 11 | 12 | InitJumpMonitor() 13 | { 14 | level.jump_monitor_is_monitoring = false; // don't touch, this is used to only start the timer after prematch is over 15 | level.jump_monitor_bot_wait_time = 3.25; 16 | 17 | level thread OnPlayerConnect(); 18 | level thread OnPrematchOver(); 19 | } 20 | 21 | OnPlayerConnect() 22 | { 23 | for (;;) 24 | { 25 | level waittill("connected", player); 26 | 27 | player thread OnPlayerSpawned(); 28 | } 29 | } 30 | 31 | OnPlayerSpawned() 32 | { 33 | self endon("disconnect"); 34 | 35 | for(;;) 36 | { 37 | self waittill("changed_kit"); 38 | 39 | if (!self IsBot() && level.jump_monitor_is_monitoring) 40 | { 41 | self MonitorPlayerJump(); 42 | } 43 | else if (self IsBot() && level.jump_monitor_is_monitoring) 44 | { 45 | self thread MonitorBotJump(); 46 | } 47 | } 48 | } 49 | 50 | MonitorPlayerJump() 51 | { 52 | self thread MonitorTimer(); 53 | 54 | self.pers["ground_status"] = "ground"; 55 | self notify("is_on_ground"); 56 | 57 | self thread MonitorGround(); 58 | } 59 | 60 | MonitorBotJump() 61 | { 62 | self endon("disconnect"); 63 | self endon("death"); 64 | 65 | for(;;) 66 | { 67 | wait level.jump_monitor_bot_wait_time; 68 | //self thread jump(); // Uncomment if using Bot Warfare 69 | } 70 | } 71 | 72 | MonitorTimer() 73 | { 74 | self endon("disconnect"); 75 | self endon("death"); 76 | 77 | for(;;) 78 | { 79 | groundStatus = self waittill_any_return("is_on_ground", "is_not_on_ground"); 80 | 81 | if (groundStatus == "is_on_ground") 82 | { 83 | self thread JumpTimer(); 84 | } 85 | } 86 | } 87 | 88 | MonitorGround() 89 | { 90 | self endon("disconnect"); 91 | self endon("death"); 92 | 93 | while (true) 94 | { 95 | if (self IsOnGround() && self.pers["ground_status"] != "on_ground") 96 | { 97 | self.pers["ground_status"] = "on_ground"; 98 | self notify("is_on_ground"); 99 | } 100 | else if (!self IsOnGround() && self.pers["ground_status"] != "not_on_ground") 101 | { 102 | self.pers["ground_status"] = "not_on_ground"; 103 | self notify("is_not_on_ground"); 104 | } 105 | 106 | wait 0.01; 107 | } 108 | } 109 | 110 | OnPrematchOver() 111 | { 112 | for(;;) 113 | { 114 | level waittill( "prematch_over" ); 115 | 116 | level.jump_monitor_is_monitoring = true; 117 | 118 | foreach (player in level.players) 119 | { 120 | if (!player IsBot() && IsReallyAlive(player)) 121 | { 122 | player MonitorPlayerJump(); 123 | } 124 | else if (player IsBot() && IsReallyAlive(player)) 125 | { 126 | player thread MonitorBotJump(); 127 | } 128 | } 129 | } 130 | } 131 | 132 | JumpTimer() 133 | { 134 | self endon("disconnect"); 135 | self endon("death"); 136 | self endon("is_not_on_ground"); 137 | 138 | time = 7.5; 139 | soundStartTime = (time / 2); 140 | tick = 0.25; 141 | 142 | while(time != 0) 143 | { 144 | wait tick; 145 | time -= tick; 146 | 147 | if(time <= (soundStartTime) && time != 0) 148 | { 149 | self playlocalsound("ui_mp_suitcasebomb_timer"); 150 | } 151 | } 152 | 153 | self playsound("detpack_explo_default"); 154 | 155 | playfx(level.c4death, self.origin); 156 | 157 | self suicide(); 158 | } 159 | 160 | IsBot() 161 | { 162 | return IsDefined(self.pers["isBot"]) && self.pers["isBot"]; 163 | } -------------------------------------------------------------------------------- /small_scripts/kill_players_under_map.gsc: -------------------------------------------------------------------------------- 1 | Init() 2 | { 3 | out_of_map_y = GetOutOfMapValue(GetDvar("mapname")); 4 | 5 | level thread OnPlayerConnect(out_of_map_y); 6 | } 7 | OnPlayerConnect(out_of_map_y) 8 | { 9 | for(;;) 10 | { 11 | level waittill("connected", player); 12 | 13 | player thread OnPlayerSpawned(out_of_map_y); 14 | } 15 | } 16 | 17 | OnPlayerSpawned(out_of_map_y) 18 | { 19 | level endon("game_ended"); 20 | self endon("disconnect"); 21 | 22 | for(;;) 23 | { 24 | self waittill("spawned_player"); 25 | 26 | while (true) 27 | { 28 | if (IsDefined(self.origin[2])) 29 | { 30 | Print(self.origin[2]); // Comment this line when using on your server 31 | 32 | if (self.origin[2] < out_of_map_y) 33 | { 34 | self Suicide(); 35 | } 36 | } 37 | 38 | wait 0.01; 39 | } 40 | } 41 | } 42 | 43 | GetOutOfMapValue(map_name) 44 | { 45 | switch (map_name) 46 | { 47 | case "mp_showdown_sh": 48 | return -318; 49 | 50 | case "mp_bog": 51 | return -766; 52 | 53 | default: 54 | return -999999; 55 | } 56 | } -------------------------------------------------------------------------------- /small_scripts/kill_stuck_bots.gsc: -------------------------------------------------------------------------------- 1 | Init() 2 | { 3 | level thread OnPlayerConnect(); 4 | } 5 | 6 | OnPlayerConnect() 7 | { 8 | for(;;) 9 | { 10 | level waittill("connected", player); 11 | player thread OnPlayerSpawned(); 12 | } 13 | } 14 | 15 | OnPlayerSpawned() 16 | { 17 | self endon("disconnect"); 18 | for(;;) 19 | { 20 | self waittill("spawned_player"); 21 | if (isDefined(self.pers["isBot"])) 22 | { 23 | if (self.pers["isBot"]) 24 | { 25 | self thread KillStuckBots(); 26 | } 27 | } 28 | } 29 | } 30 | 31 | KillStuckBots() 32 | { 33 | self endon ("disconnect"); 34 | level endon("game_ended"); 35 | 36 | kills_before = self.pers["cur_kill_streak"]; 37 | deaths_before = self.pers["deaths"]; 38 | 39 | wait 30; 40 | 41 | kills_now = self.pers["cur_kill_streak"]; 42 | deaths_now = self.pers["deaths"]; 43 | 44 | if (kills_now == kills_before && deaths_before == deaths_now) 45 | { 46 | self Suicide(); 47 | } 48 | } 49 | 50 | // Prints text in the bootstrapper 51 | Debug(text) 52 | { 53 | Print(text); 54 | } -------------------------------------------------------------------------------- /small_scripts/manage_bots_fill.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\bots\_bot_utility; 2 | 3 | Init() 4 | { 5 | InitManageBotsFill(); 6 | } 7 | 8 | InitManageBotsFill() 9 | { 10 | InitServersDvar(); 11 | 12 | SetDvar("bots_manage_fill_kick", 1); 13 | 14 | level thread OnPlayerConnect(); 15 | } 16 | 17 | OnPlayerConnect() 18 | { 19 | for (;;) 20 | { 21 | level waittill("connected", player); 22 | 23 | if (!player IsBot()) 24 | { 25 | TryUpdateBotsManageFill(); 26 | 27 | player thread OnPlayerDisconnect(); 28 | } 29 | } 30 | } 31 | 32 | OnPlayerDisconnect() 33 | { 34 | self waittill("disconnect"); 35 | 36 | TryUpdateBotsManageFill(); 37 | } 38 | 39 | InitServersDvar() 40 | { 41 | level.manage_bots_fill = []; 42 | 43 | level.manage_bots_fill["27017"] = "12"; 44 | } 45 | 46 | TryUpdateBotsManageFill() 47 | { 48 | wait 1; 49 | 50 | if (HasHumanPlayers()) 51 | { 52 | if (GetDvar("bots_manage_fill") != level.manage_bots_fill[GetDvar("net_port")]) 53 | { 54 | SetDvar("bots_manage_fill", level.manage_bots_fill[GetDvar("net_port")]); 55 | } 56 | } 57 | else 58 | { 59 | SetDvar("bots_manage_fill", 0); 60 | } 61 | } 62 | 63 | IsBot() 64 | { 65 | return IsDefined(self.pers["isBot"]) && self.pers["isBot"]; 66 | } 67 | 68 | HasHumanPlayers() 69 | { 70 | foreach (player in level.players) 71 | { 72 | if (!player IsBot()) 73 | { 74 | return true; 75 | } 76 | } 77 | 78 | return false; 79 | } -------------------------------------------------------------------------------- /small_scripts/remove_heavy_weapon_slow.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\_utility; 2 | 3 | Init() 4 | { 5 | InitRemoveHeavyWeaponSlow(); 6 | } 7 | 8 | InitRemoveHeavyWeaponSlow() 9 | { 10 | level thread OnPlayerConnect(); 11 | } 12 | 13 | OnPlayerConnect() 14 | { 15 | for(;;) 16 | { 17 | level waittill("connected", player); 18 | 19 | player thread OnPlayerSpawned(); 20 | } 21 | } 22 | 23 | OnPlayerSpawned() 24 | { 25 | self endon("disconnect"); 26 | 27 | for(;;) 28 | { 29 | self waittill("changed_kit"); 30 | 31 | self SetMoveSpeedScale(1); 32 | 33 | self thread OnPlayerWeaponSwitch(); 34 | } 35 | } 36 | 37 | /* 38 | The move speed scale is reset whenever we switch weapons so we need to re-apply it on weapon change 39 | */ 40 | OnPlayerWeaponSwitch() 41 | { 42 | self endon("disconnect"); 43 | self endon("death"); 44 | 45 | for (;;) 46 | { 47 | self waittill( "weapon_change", newWeapon ); 48 | 49 | wait 0.05; // For some reason this is needed otherwise when you fully stop and switch weapon it won't apply 50 | 51 | self SetMoveSpeedScale(1); 52 | } 53 | } -------------------------------------------------------------------------------- /small_scripts/show_text_on_first_spawn.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\gametypes\_hud_util; 2 | 3 | Init() 4 | { 5 | level thread OnPlayerConnected(); 6 | } 7 | 8 | OnPlayerConnected() 9 | { 10 | for(;;) 11 | { 12 | level waittill("connected", player); 13 | 14 | player thread OnPlayerSpawned(); 15 | } 16 | } 17 | 18 | OnPlayerSpawned() 19 | { 20 | self endon("disconnect"); 21 | 22 | for(;;) 23 | { 24 | self waittill("spawned_player"); 25 | 26 | // Don't show first spawn text to bots 27 | if (isDefined(self.pers["isBot"])) 28 | { 29 | if (self.pers["isBot"]) 30 | { 31 | continue; // skip 32 | } 33 | } 34 | 35 | if (!IsDefined(self.pers["saw_first_spawn_message"]) || !self.pers["saw_first_spawn_message"]) 36 | { 37 | self.pers["saw_first_spawn_message"] = true; 38 | self ShowFirstSpawnMessage(); 39 | } 40 | } 41 | } 42 | 43 | ShowFirstSpawnMessage() 44 | { 45 | first_spawn_message = "^1Read the rules by typing !rules in the chat"; 46 | 47 | self IPrintLnBold(first_spawn_message); 48 | wait 3; 49 | self IPrintLnBold(first_spawn_message); 50 | } -------------------------------------------------------------------------------- /small_scripts/welcome_message.gsc: -------------------------------------------------------------------------------- 1 | #include maps\mp\gametypes\_hud_util; 2 | 3 | Init() 4 | { 5 | InitWelcomeMessage(); 6 | } 7 | 8 | InitWelcomeMessage() 9 | { 10 | level.welcome_message_icon = "rank_prestige10"; 11 | 12 | PreCacheShader(level.welcome_message_icon); 13 | 14 | level thread OnPlayerConnected(); 15 | } 16 | 17 | OnPlayerConnected() 18 | { 19 | for(;;) 20 | { 21 | level waittill("connected", player); 22 | 23 | player thread OnPlayerSpawned(); 24 | } 25 | } 26 | 27 | OnPlayerSpawned() 28 | { 29 | self endon("disconnect"); 30 | 31 | for(;;) 32 | { 33 | self waittill("spawned_player"); 34 | 35 | // Don't show first spawn text to bots 36 | if (isDefined(self.pers["isBot"])) 37 | { 38 | if (self.pers["isBot"]) 39 | { 40 | continue; // skip 41 | } 42 | } 43 | 44 | if (!IsDefined(self.pers["saw_first_spawn_message"]) || !self.pers["saw_first_spawn_message"]) 45 | { 46 | self.pers["saw_first_spawn_message"] = true; 47 | self ShowFirstSpawnMessage(); 48 | } 49 | } 50 | } 51 | 52 | ShowFirstSpawnMessage() 53 | { 54 | notifyData = spawnstruct(); 55 | 56 | notifyData.iconName = level.welcome_message_icon; 57 | notifyData.titleText = "Welcome ^5" + self.name; // line 1 58 | notifyData.notifyText = "Enjoy your game on ^1 " + GetDvar("party_mapname"); // line 2 59 | notifyData.notifyText2 = "Join our Discord at ^5discord.gg/plutonium"; // line 3 60 | notifyData.glowColor = (0, 0, 0); // (0.3, 0.6, 0.3) is the default glow 61 | notifyData.sound = "mp_level_up"; 62 | notifyData.duration = 7; 63 | notifyData.font = "DAStacks"; 64 | notifyData.hideWhenInMenu = false; 65 | 66 | self thread maps\mp\gametypes\_hud_message::notifyMessage( notifyData ); 67 | } --------------------------------------------------------------------------------