Code:
#include <amxmodx>
#include <fakemeta>
#include <engine>
#include <cstrike>
#include <hamsandwich>
/*
* The includes depends on what natives, forwards, stocks, et.c. we require.
* Here's a list of the natives and forwards from each library that we're using:
*
* amxmodx:
* forwards:
* plugin_init()
* client_disconnect(id)
*
* natives:
* register_plugin()
* register_cvar(const name[], const string[], flags = 0, Float:fvalue = 0.0)
* get_user_msgid(const name[])
* is_user_alive(index)
* get_user_aiming(index, &id, &body, dist=9999)
* get_pcvar_num(pcvar)
* set_task(Float:time, const function[], id = 0, const parameter[]=, len = 0, const flags[]=, repeat = 0)
* remove_task(id = 0, outside = 0)
* client_print(index, type, const message[], any:...)
* get_user_name(index, name[], len)
* message_begin(dest, msg_type, const origin[3] = {0, 0, 0}, player = 0)
* write_short(x)
* message_end()
*
* fakemeta:
* natives:
* register_forward(_forwardType, const _function[], _post=0)
*
* engine:
* natives:
* get_user_button(id)
* get_user_oldbutton(id)
*
* cstrike:
* natives:
* cs_get_user_team(index, &{CsInternalModel, _:model = CS_DONTCHANGE})
* cs_get_user_money(index)
* cs_set_user_money(index, money, flash = 1)
*
* hamsandwich:
* natives:
* RegisterHam(Ham:function, const EntityClass[], const Callback[], Post=0)
*
*/
new gTarget[33]; // Storing of the player target being aimed at.
new gTargetOf[33]; // Storing of the player aiming at the target.
new gpcvarTime, gpcvarRange, gpcvarMessage; // Cvar pointers, efficient usage of cvars. More memory, less CPU. ( = faster )
new gMsgIDBarTime; // Storing of the message id for BarTime.
public plugin_init() { // This is called around when the plugin starts. It is generally used to setup everything.
register_plugin("Pickpocket", "1.0", "[ --{-@ ]"); // Register the plugin. So it looks nice in the lists and so you have your name somewhere. There's no other purpose to this.
register_forward(FM_CmdStart, "fwd_CmdStart"); // This is a hook that will call once every server frame. We will use it to monitor the change of buttons used.
gpcvarTime = register_cvar("pickpocket_time", "3"); // This is the cvar for chosing time before the money is transfered. Please replace "whatever_time" with something suitable.
gpcvarRange = register_cvar("pickpocket_range", "300"); // This is the cvar to determine the range of the pickpocketing.
gpcvarMessage = register_cvar("pickpocket_message", "1") // This is the cvar that decides if a message is displayed to the person being pocket picked. 0 = nothing, 1 = a general message, 2 = message with a name.
gMsgIDBarTime = get_user_msgid("BarTime"); // We need this message id to call the correct message later.
RegisterHam(Ham_Killed, "player", "fwd_HamKilled"); // This is a hook that will call whenever a player is killed. We use it to remove any existing tasks related to that player.
}
public fwd_CmdStart(id, uc_handle, seed) { // This function is called on every server frame. I've already explained this, pay attention!
if ( ! is_user_alive(id) ) // No need doing anything if the user isn't alive.
return; // Exit the function completely. Don't continue beyond this point.
static xButtons, xOldbuttons; // We need to store some buttons.
xButtons = get_user_button(id); // This will return a bitsum of all the buttons currently pressed.
xOldbuttons = get_user_oldbutton(id); // This will do the same as buttons but with the key difference that it will be "delayed" one frame.
/* The combination of both functions above makes it possible to see if the key pressed is "new" or "old"
* by checking if a button exists in the new but not the old and vice versa.
*/
if ( xButtons & IN_USE && ! ( xOldbuttons & IN_USE ) ) { // This will be true on the first frame after E is pressed down, only called once per key press.
get_user_aiming(id, gTarget[id], gTarget[0], get_pcvar_num(gpcvarRange)); // This will give us the target that the player is currently aiming at within the set range of the cvar.
if ( // We need to abort if...
! gTarget[id] || // The player is not aiming at anything OR
! is_user_alive(gTarget[id]) || // The player is not aiming at an alive player OR
gTargetOf[gTarget[id]] || // The target is currently being stolen from already OR
cs_get_user_team(id) != cs_get_user_team(gTarget[id]) // The two players are not on the same team
) {
gTarget[id] = 0; // While writing this explanation I realize this is probably useless. I will leave it just in case.
return; // Exit the function completely. Don't continue beyond this point.
}
new moneyThief = cs_get_user_money(id); // How much money does the thief have. We can only have so much.
if ( moneyThief >= 16000 ) { // If the user already have full money we can't add anything.
client_print(id, print_chat, "You already have enough money. Greedy bastard!") // Send the message to tell them so.
gTarget[id] = 0; // While writing this explanation I realize this is probably useless. I will leave it just in case.
return; // Exit the function completely. Don't continue beyond this point.
}
new moneyTarget = cs_get_user_money(gTarget[id]); // How much money does the target have to steal.
if ( ! moneyTarget ) { // The poor target is emptied out. No need continuing from here.
client_print(id, print_chat, "The target has no money to steal.") // Send the message to tell them so.
gTarget[id] = 0; // While writing this explanation I realize this is probably useless. I will leave it just in case.
return; // Exit the function completely. Don't continue beyond this point.
}
gTargetOf[gTarget[id]] = id; // We made it here. And we will claim the target as ours. Nobody else will be able to steal from it while we're doing it.
static xTaskTime; // More variables... gotta have them.
xTaskTime = get_pcvar_num(gpcvarTime); // This will return the time set by the cvar "whatever_time".
BarTime(id, xTaskTime); // This will call the stock BarTime(), seen below, with the second parameter being the time that the bar should fill in.
set_task(float(xTaskTime), "task_StealMoney", id); // This will call the function "task_StealMoney" after set amount of time.
switch ( get_pcvar_num(gpcvarMessage) ) { // This will decide if and how the target will be notified. A switch is used instead of an if/else statement when there are multiple options.
case 1 : // General message.
client_print(gTarget[id], print_chat, "Someone is trying to pick your pockets!"); // Display the message to the target.
case 2 : { // Detailed message.
static xName[32]; // Gotta store the player name in a string. That's why we create this variable.
get_user_name(id, xName, charsmax(xName)); // Also need to retrieve the name.
client_print(gTarget[id], print_chat, "%s is trying to pick your pockets!", xName); // Display the message to the target.
}
}
}
else if ( ! ( xButtons & IN_USE ) && xOldbuttons & IN_USE ) { // This will be true when they key is released since it no longer exists in "new" buttons but still exists in old.
if ( ! gTarget[id] ) // If the player has no target, why bother doing anything.
return; // Exit the function completely. Don't continue beyond this point.
gTargetOf[gTarget[id]] = 0; // Free the target from our hold, others will be able to steal from it again.
gTarget[id] = 0; // I don't think this is neccessary... Again, just in case.
BarTime(id); // Again, calling the stock BarTime(), seen below. However with no time, removing the bar completely.
remove_task(id); // Stop the stealing of money before it's too late.
}
else if ( gTargetOf[id] && xButtons ) { // This will check if the player is a target and if it is using buttons, which will reset all the timers of the players trying to steal it.
static xTaskTime; // Variables, variables, variables...
xTaskTime = get_pcvar_num(gpcvarTime); // Again, returning the time set by the cvar. Previously mentioned.
remove_task(gTargetOf[id]); // Remove the task, otherwise we end up with two tasks.
set_task(float(xTaskTime), "task_StealMoney", id); // Start a new task from the beginning for the player stealing money.
BarTime(gTargetOf[id], xTaskTime); // Again, calling the stock BarTime(), seen below. restarting the progress by setting the time to 3 (or whatever the cvar is set to) again.
}
}
public task_StealMoney(id) { // This task will be called when the timer runs out and we actually succeed in stealing the money. We just need to do some math first.
new moneyTarget = cs_get_user_money(gTarget[id]); // How much money does the target have to steal.
new moneyThief = cs_get_user_money(id); // How much money does the thief have. We can only have so much.
new amount; // This will later be set to the amount that is being transfered between the two.
if ( moneyThief + moneyTarget > 16000 ) // If all the money from both players won't fit in the receivers wallet we have to make some adjustments...
amount = 16000 - moneyThief; // The amount will be set to as much as the thief can hold, excluding his own money.
else // However, if both players money will fit in the receivers wallet.
amount = moneyTarget; // Take everything.
cs_set_user_money(id, moneyThief + amount); // Add the decided amount to the receiving player...
cs_set_user_money(gTarget[id], moneyTarget - amount); // ... and remove it from the target.
switch ( get_pcvar_num(gpcvarMessage) ) { // Again, do we tell someone when they were robbed by someone and how do we do it.
case 1 : // General message.
client_print(gTarget[id], print_chat, "Someone stole $%d from you!", amount); // Display the message to the target.
case 2 : { // Detailed message.
static xName[32]; // Gotta store the player name in a string. That's why we create this variable.
get_user_name(id, xName, charsmax(xName)); // Also need to retrieve the name.
client_print(gTarget[id], print_chat, "%s stole $%d from you!", xName, amount); // Display the message to the target.
}
}
gTargetOf[gTarget[id]] = 0; // We're done now. We have to free this person so others may be able to steal from the target again.
gTarget[id] = 0; // I don't think this is neccessary... Again, just in case.
}
public client_disconnect(id) { // This is called when a players leaves the game.
if ( gTargetOf[id] ) { // If this player is a target, we have to remove the bar and the task from the thief. Otherwise we will run into problems.
BarTime(gTargetOf[id]); // Again, calling the stock BarTime(), seen below. With no time, removing the bar completely.
remove_task(gTargetOf[id]); // Remove the money stealing task.
}
gTarget[id] = 0; // I don't think this is neccessary... Again, just in case.
gTargetOf[id] = 0; // If this player was stealing money from someone, free that target.
remove_task(id); // Gotta remove eventual tasks as well. Bad things await those calling functions on players that has left. Probably runtime errors.
}
public fwd_HamKilled(victim, attacker, shouldgib) // This forward is called when a player is killed.
client_disconnect(victim); // We do the same thing as if that person has left. Free them from all responsability and anyone related to that person. Instead of writing the same code twice, we just call client_disconnect().
BarTime(id, time = 0) { // This is a stock. A custom function created within this code to avoid writing those 3 lines of code for every position needed. Instead we just write BarTime(id, time...). Simple.
message_begin(MSG_ONE_UNRELIABLE, gMsgIDBarTime, { 0, 0, 0 }, id); // Begin the message, mostly sending dummy variables. This will start the loading bar.
write_short(time); // A short is 2 bytes which allows values between -32 768 and 32 767. 1 short (2 bytes) is 16 bits. For example, the number 3 will look like this: 00000000 00000011
message_end(); // We have to end the message. Otherwise probably error. Don't even try.
}
// Snipp, snapp, snut. Så var sagan slut.
Be nicer to eachother.
I have nobody to test it with. You have to test it yourself.