/* Ski2 Shop by Seta00
*
* This code is released under the GPLv3 License:
* http://www.gnu.org/licenses/gpl-3.0.html
*
* This plugin enables gameplay funcionalities to
* the surf_ski_2 map.
*
* When the player enters the Mario room, a menu
* is displayed with the Ski 2 Shop Items.
*
* All item costs are changeable by cvar, changes
* are applied on round start.
*
* Items description:
*
* - Get Out Of Jail ($1500) - One shot
*
* Inspired by the "Get Out Of Jail Free Card"
* from GTA2, this item removes you from the
* jail as soon as you enter it.
*
* Note: Users with the Eye of the Spy can see
* you entering the jail, but not leaving it.
* You can use this to attract enemies to the
* jail area.
*
* - Health Reload ($7500) - One shot
*
* Reloads your HP to 100. Useful but expensive.
*
* Note: Be careful, two Health Reloads and you
* are left with ~1000 in your pocket.
*
* - Extra Amor ($2500) - 3 rounds
*
* Sets your maximum armor to 150.
*
* Note: If you are already wearing armor, it gets
* filled to 100 AP.
*
* - M3 and M4 ($5000) - 3 rounds
*
* The second most expensive item in the shop, it's
* a really god choice in surf_ski_2. Remember, if
* you die with this item, you have to reach the
* Mario room to get a new M3 and M4.
*
* - Eye of the Spy ($1000) - 5 rounds
*
* An item for the strategists. It warns you every
* time someone enters the jail.
*
* - Save ($2500) - One shot
*
* Saves your current items. When you reconnect, items
* are automatically restored.
*
* Plugin Thread: http://forums.alliedmods.net/showthread.php?p=1092198
*
* Thanks to xPaw for his surf_ski_2 rules watcher plugin.
* Thanks to Arkshine for pointing me the message issue and by doing so allowed me to remove fakemeta dependency.
* Thanks for ConnorMcLeod for reviving this trash from the deeper layer of hell. NOT!
*/
#include <amxmodx>
#include <engine>
#include <nvault>
#include <cstrike>
#include <fun>
#include <hamsandwich>
#define PLUGIN "Ski2 Shop"
#define AUTHOR "Seta00"
#define VERSION "1.7.1"
#pragma semicolon 1
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// ENUMERATIONS / TYPEs
enum __cvar_t {
cvName[50],
cvValue[10],
cvPtr
};
enum __duration_t {
duration,
lostMlStr[50]
};
enum {
GET_OUT_OF_JAIL, // FREE_CARD
HEALTH_RELOAD,
EXTRA_ARMOR,
M3_AND_M4,
EYE_OF_THE_SPY,
SAVE,
LAST_ITEM
};
enum {
JAIL,
MARIOROOM,
LAST_ZONE
};
enum Color {
NORMAL = 1, // clients scr_concolor cvar color
GREEN, // Green Color
TEAM_COLOR, // Red, grey, blue
GREY, // grey
RED, // Red
BLUE, // Blue
};
enum {
M3,
M4
};
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// GLOBAL VARS
new const Classname[] = "trigger_ski2_shop";
new UserItems[33], UserIPs[33][15], UserRoundStart[33][LAST_ITEM], M3AndM4[33][2], RoundCount, MaxPlayers;
new Float:LastTouch[33][LAST_ZONE];
new bool:IsOnMario[33], bool:IsOnJail[33];
new const CVARS[][__cvar_t] = {
{"ss_getoutofjail_price", "1500", 0},
{"ss_getoutofjail_duration", "-1", 0},
{"ss_healthreload_price", "7500", 0},
{"ss_healthreload_duration", "-1", 0},
{"ss_extraarmor_price", "2500", 0},
{"ss_extraarmor_duration", "3", 0},
{"ss_m3andm4_price", "5000", 0},
{"ss_m3andm4_duration", "3", 0},
{"ss_eyeofthespy_price", "750", 0},
{"ss_eyeofthespy_duration", "5", 0},
{"ss_save_price", "2500", 0},
{"ss_save_duration", "-1", 0},
{"ss_version", VERSION, 0} // always the last one
};
new COST[LAST_ITEM] = {
1500,
7500,
2500,
5000,
750,
2500
};
new DURATION[LAST_ITEM][__duration_t] = {
{-1, "LOST_GET_OUT_OF_JAIL"},
{-1, ""},
{3, "LOST_EXTRA_ARMOR"},
{3, "LOST_M3_AND_M4"},
{5, "LOST_EYE_OF_THE_SPY"},
{-1, ""}
};
new TeamName[][] = {
"",
"TERRORIST",
"CT",
"SPECTATOR"
};
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// MACROS
#define HAS_GET_OUT_OF_JAIL(%1) (UserItems[%1] & (1 << GET_OUT_OF_JAIL))
#define HAS_HEALTH_RELOAD(%1) (UserItems[%1] & (1 << HEALTH_RELOAD))
#define HAS_EXTRA_ARMOR(%1) (UserItems[%1] & (1 << EXTRA_ARMOR))
#define HAS_M3_AND_M4(%1) (UserItems[%1] & (1 << M3_AND_M4))
#define HAS_EYE_OF_THE_SPY(%1) (UserItems[%1] & (1 << EYE_OF_THE_SPY))
#define HAS_SAVE(%1) (UserItems[%1] & (1 << SAVE))
#define SET_GET_OUT_OF_JAIL(%1,%2) (UserItems[%1] |= (_:%2 << GET_OUT_OF_JAIL))
#define SET_HEALTH_RELOAD(%1,%2) (UserItems[%1] |= (_:%2 << HEALTH_RELOAD))
#define SET_EXTRA_ARMOR(%1,%2) (UserItems[%1] |= (_:%2 << EXTRA_ARMOR))
#define SET_M3_AND_M4(%1,%2) (UserItems[%1] |= (_:%2 << M3_AND_M4))
#define SET_EYE_OF_THE_SPY(%1,%2) (UserItems[%1] |= (_:%2 << EYE_OF_THE_SPY))
#define SET_SAVE(%1,%2) (UserItems[%1] |= (_:%2 << SAVE))
#define MAX_MENU_ITEMS 7
#define ML(%1) formatex(menuStr, charsmax(menuStr), "%L", id, %1)
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
public plugin_init() {
register_plugin(PLUGIN, VERSION, AUTHOR);
register_dictionary("ski2_shop.txt");
new mapname[11];
get_mapname(mapname, charsmax(mapname));
if (equali(mapname, "surf_ski_2")) {
CreateTrigger(JAIL, Float:{-579.0, 2983.0, 586.0}, Float:{-309.0, 3288.0, 796.0});
CreateTrigger(MARIOROOM, Float:{2735.0, 193.0, -2361.0}, Float:{3709.0, 1180.0, -2087.0});
register_touch(Classname, "player", "EnteredSpecialZone");
RegisterHam(Ham_Spawn, "player", "FwdPlayerSpawn", 1);
register_event("HLTV", "NewRound", "a", "1=0", "2=0");
register_event("ItemPickup", "OnItemPickup", "be");
register_clcmd("say /menu", "ShowShopMenu");
register_clcmd("say_team /menu", "ShowShopMenu");
register_clcmd("shop_menu", "ShowShopMenu");
for (new i = 0; i < sizeof(CVARS)-1; ++i) {
CVARS[i][cvPtr] = register_cvar(CVARS[i][cvName], CVARS[i][cvValue]);
}
// version cvar
register_cvar(CVARS[sizeof(CVARS)-1][cvName], CVARS[sizeof(CVARS)-1][cvValue], FCVAR_SERVER|FCVAR_SPONLY);
CacheCvars();
MaxPlayers = get_maxplayers();
}
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// FORWARDS
public client_connect(id) {
get_user_ip(id, UserIPs[id], 15, 1);
if (LoadUserItems(id) == -1) {
UserItems[id] = 0;
}
}
public client_disconnect(id) {
if (HAS_SAVE(id))
SaveUserItems(id);
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// EVENTS / TOUCHS / HAMS
public NewRound() {
RoundCount++;
CacheCvars();
new players[32], num, i;
get_players(players, num, "ch");
for (new k = 0; k < num; ++k) {
i = players[k];
for (new j = 0; j < sizeof(UserItems[]); ++j) {
if (DURATION[j][duration] == -1) break;
if (~UserItems[i] & (1 << j)) break;
if (RoundCount == UserRoundStart[i][j] + DURATION[j][duration]) {
UserItems[i] &= ~(1 << j);
client_print(i, print_chat, "%L", i, DURATION[j][lostMlStr]);
}
}
}
}
public OnItemPickup(player) {
if (!HAS_EXTRA_ARMOR(player))
return;
new itemName[17];
read_data(1, itemName, charsmax(itemName));
if (!(equal(itemName, "item_kevlar") || equal(itemName, "item_assaultsuit"))) {
return;
}
entity_set_float(player, EV_FL_armorvalue, 150.0);
return;
}
// used xPaw idea for avoiding multiple touchs
public EnteredSpecialZone(entity, id) {
static Float:gametime;
gametime = get_gametime();
static location;
location = entity_get_int(entity, EV_INT_iuser1);
if( gametime > (LastTouch[id][location] + 1.2)) {
LastTouch[id][location] = gametime;
if(location)
IsOnJail[id] = false;
else
IsOnMario[id] = false;
} else if (LastTouch[id][location] < gametime) {
switch (location) {
case MARIOROOM: {
if (!IsOnMario[id]) {
IsOnMario[id] = true;
client_print(id, print_chat, "%L", id, "MENU_ADVERTISING");
ShowShopMenu(id);
if (HAS_M3_AND_M4(id)) {
if (M3AndM4[id][M3] <= 0) {
M3AndM4[id][M3] = give_item(id, "weapon_m3");
cs_set_user_bpammo(id, CSW_M3, 32);
}
if (M3AndM4[id][M4] <= 0) {
M3AndM4[id][M3] = give_item(id, "weapon_m4a1");
cs_set_user_bpammo(id, CSW_M4A1, 90);
}
}
}
}
case JAIL:{
if (!IsOnJail[id]) {
IsOnJail[id] = true;
if (HAS_GET_OUT_OF_JAIL(id)) {
client_print(id, print_chat, "%L", id, "LOST_GET_OUT_OF_JAIL");
entity_set_vector(id, EV_VEC_angles, Float:{0.0, 270.0, 0.0});
entity_set_int(id, EV_INT_fixangle, 1);
entity_set_origin(id, Float:{-405.0, 2900.0,720.0});
SET_GET_OUT_OF_JAIL(id, false);
}
AnnounceJailEnter(id);
}
}
}
LastTouch[id][location] = gametime + 1.0;
}
}
public FwdPlayerSpawn(id) {
if(!is_user_alive(id))
return HAM_IGNORED;
for (new i = 0; i < sizeof(LastTouch[]); ++i) {
LastTouch[id][i] = 0.0;
}
IsOnMario[id] = false;
IsOnJail[id] = false;
if (!HAS_M3_AND_M4(id)) {
if (M3AndM4[id][M3] > 0)
remove_entity(M3AndM4[id][M3]);
if (M3AndM4[id][M4] > 0)
remove_entity(M3AndM4[id][M4]);
}
if (!HAS_EXTRA_ARMOR(id) && get_user_armor(id) > 100) {
new CsArmorType:armorType;
cs_get_user_armor(id, armorType);
cs_set_user_armor(id, 100, armorType);
}
return HAM_HANDLED;
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// COMMANDS
public ShowShopMenu(id) {
if (!IsOnMario[id]) {
client_print(id, print_chat, "%L", id, "NOT_ON_MARIO");
return PLUGIN_HANDLED;
}
new menuStr[50]; // used by macro, do NOT rename or delete
ML("MENU_TITLE");
new menu = menu_create(menuStr, "ShopMenuHandler");
new const mlPrefix[] = "MENU_ITEM_";
new mlKey[12], nbToStr[2];
for(new i = 1; i <= MAX_MENU_ITEMS; ++i) {
copy(mlKey, charsmax(mlKey), mlPrefix);
num_to_str(i, nbToStr, charsmax(nbToStr));
add(mlKey, charsmax(mlKey), nbToStr);
ML(mlKey);
menu_additem(menu, menuStr, nbToStr);
}
menu_setprop(menu, MPROP_EXIT, 0);
menu_display(id, menu);
return PLUGIN_HANDLED;
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS
public ShopMenuHandler(id, menu, item) {
if (item == MENU_EXIT) {
menu_destroy(menu);
return;
}
new data[3], name[64], access, callback;
menu_item_getinfo(menu, item, access, data, charsmax(data), name, charsmax(name), callback);
new key = str_to_num(data);
new cost;
cost = COST[key-1];
if (UserItems[id] & (1 << key-1)) {
client_print(id, print_chat, "%L", id, "CANT_BUY_ITEM");
return;
}
switch (key) {
case 1: { // Get Out of Jail
if(CheckAndSubtractUserMoney(id, cost)) {
SET_GET_OUT_OF_JAIL(id, true);
client_print(id, print_chat, "%L", id, "GET_OUT_OF_JAIL");
}
}
case 2: { // Health Reload
if (CheckAndSubtractUserMoney(id, cost)) {
set_user_health(id, 100);
client_print(id, print_chat, "%L", id, "HEALTH_RELOAD");
}
}
case 3: { // Extra Armor
if (CheckAndSubtractUserMoney(id, cost)) {
SET_EXTRA_ARMOR(id, true);
new CsArmorType:armorType;
cs_get_user_armor(id, armorType);
if (armorType != CS_ARMOR_NONE)
cs_set_user_armor(id, 150, armorType);
UserRoundStart[id][EXTRA_ARMOR] = RoundCount;
client_print(id, print_chat, "%L", id, "EXTRA_ARMOR");
}
}
case 4: { // M3 and M4
if (CheckAndSubtractUserMoney(id, cost)) {
SET_M3_AND_M4(id, true);
if ((M3AndM4[id][M3] = give_item(id, "weapon_m3"))) {
cs_set_user_bpammo(id, CSW_M3, 32);
}
if ((M3AndM4[id][M4] = give_item(id, "weapon_m4a1"))) {
cs_set_user_bpammo(id, CSW_M4A1, 90);
}
UserRoundStart[id][M3_AND_M4] = RoundCount;
client_print(id, print_chat, "%L", id, "M3_AND_M4");
}
}
case 5: { // Eye of the Spy
if (CheckAndSubtractUserMoney(id, cost)) {
SET_EYE_OF_THE_SPY(id, true);
UserRoundStart[id][EYE_OF_THE_SPY] = RoundCount;
client_print(id, print_chat, "%L", id, "EYE_OF_THE_SPY");
}
}
case 6: { // Save
if (CheckAndSubtractUserMoney(id, cost)) {
SaveUserItems(id);
client_print(id, print_chat, "%L", id, "SAVE");
}
}
}
menu_destroy(menu);
return;
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// PRIVATE FUNCTIONS
AnnounceJailEnter(id) {
for (new i = 1; i < MaxPlayers; i++) {
if (i == id) continue;
if (HAS_EYE_OF_THE_SPY(i)) {
new name[32];
get_user_name(id, name, charsmax(name));
ColorChat(i, (cs_get_user_team(id) == CS_TEAM_CT ? BLUE : RED), "%L", id, "PLAYER_ON_JAIL", name);
}
}
}
CheckAndSubtractUserMoney(id, money) {
new m = cs_get_user_money(id);
if (m < money) {
client_print(id, print_center, "%L", id, "NOT_ENOUGH_MONEY");
return 0;
}
cs_set_user_money(id, m-money);
return 1;
}
SaveUserItems(id) {
new vault = nvault_open("ski_2_shop");
new value[100], i, tmpStr[10];
format(value, charsmax(value), "%d", UserItems[id]);
add(value, charsmax(value), "#");
for (i = 0; i < sizeof(UserRoundStart[]); ++i) {
num_to_str(UserRoundStart[id][i], tmpStr, charsmax(tmpStr));
add(value, charsmax(value), tmpStr);
if (i < sizeof(UserRoundStart[])-1) add(value, charsmax(value), "-");
}
nvault_set(vault, UserIPs[id], value);
nvault_close(vault);
return 0;
}
LoadUserItems(id) {
new vault = nvault_open("ski_2_shop");
new value[100], timestamp, i, j, tmpStr[30], tmpStr2[30];
if (!nvault_lookup(vault, UserIPs[id], value, charsmax(value), timestamp))
return -1;
strtok(value, tmpStr, charsmax(tmpStr), tmpStr2, charsmax(tmpStr2), '#');
UserItems[id] = str_to_num(tmpStr);
for (i += 2; i < strlen(value); ++i) {
strtok(value[i], tmpStr, charsmax(tmpStr), tmpStr2, charsmax(tmpStr2), '-');
UserRoundStart[id][j] = str_to_num(tmpStr);
i += strlen(tmpStr)+2;
}
nvault_remove(vault, UserIPs[id]);
nvault_close(vault);
return 0;
}
// took from surf_ski_2 ruleswatcher by xPaw
CreateTrigger( iType, Float:flMins[ 3 ], Float:flMaxs[ 3 ] ) {
new iEntity = create_entity( "info_target" );
if( !is_valid_ent( iEntity ) ) {
return 0;
}
entity_set_string( iEntity, EV_SZ_classname, Classname );
entity_set_int( iEntity, EV_INT_iuser1, iType );
entity_set_int( iEntity, EV_INT_movetype, MOVETYPE_FLY );
entity_set_int( iEntity, EV_INT_solid, SOLID_TRIGGER );
entity_set_size( iEntity, flMins, flMaxs );
return iEntity;
}
CacheCvars() {
for (new i = 0; i < (sizeof(CVARS)-1)/2; i++) {
COST[i] = get_pcvar_num(CVARS[i][cvPtr]);
DURATION[i][duration] = get_pcvar_num(CVARS[i+1][cvPtr]);
}
}
/////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
// COLORCHAT FUNCTIONS
ColorChat(id, Color:type, const msg[], {Float,Sql,Result,_}:...) {
if( !get_playersnum() ) return;
new message[256];
switch(type) {
case NORMAL: { // clients scr_concolor cvar color
message[0] = 0x01;
}
case GREEN: { // Green
message[0] = 0x04;
}
default: {// White, Red, Blue
message[0] = 0x03;
}
}
vformat(message[1], 251, msg, 4);
// Make sure message is not longer than 192 character. Will crash the server.
message[192] = '^0';
new team, ColorChange, index, MSG_Type;
if(id) {
MSG_Type = MSG_ONE;
index = id;
} else {
index = FindPlayer();
MSG_Type = MSG_ALL;
}
team = get_user_team(index);
ColorChange = ColorSelection(index, MSG_Type, type);
ShowColorMessage(index, MSG_Type, message);
if(ColorChange) {
Team_Info(index, MSG_Type, TeamName[team]);
}
}
ShowColorMessage(id, type, message[]) {
static bool:saytext_used;
static get_user_msgid_saytext;
if(!saytext_used)
{
get_user_msgid_saytext = get_user_msgid("SayText");
saytext_used = true;
}
message_begin(type, get_user_msgid_saytext, _, id);
write_byte(id);
write_string(message);
message_end();
}
Team_Info(id, type, team[]) {
static bool:teaminfo_used;
static get_user_msgid_teaminfo;
if(!teaminfo_used) {
get_user_msgid_teaminfo = get_user_msgid("TeamInfo");
teaminfo_used = true;
}
message_begin(type, get_user_msgid_teaminfo, _, id);
write_byte(id);
write_string(team);
message_end();
return 1;
}
ColorSelection(index, type, Color:Type) {
switch(Type) {
case RED: {
return Team_Info(index, type, TeamName[1]);
}
case BLUE: {
return Team_Info(index, type, TeamName[2]);
}
case GREY: {
return Team_Info(index, type, TeamName[0]);
}
}
return 0;
}
FindPlayer() {
new i = -1;
while(i <= get_maxplayers()) {
if(is_user_connected(++i))
return i;
}
return -1;
}