Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Frag JailBreak - Knives Shop v1.7
- Fixed:
- - v1.1-v1.6 fixes preserved
- - v1.7: Removed gravity/speed from enum and knives array.
- Removed unused plugin_natives, register_natives stubs.
- Removed duplicate is_user_connected guards.
- ShowInventory now shows HTML MOTD (not menu).
- Top Knife Leaderboard moved to main menu as separate item.
- is_user_connected guard added to all Show* functions.
- By CheezPuff (Ariel) | Discord: CheezPuff#7720
- */
- #include <amxmodx>
- #include <amxmisc>
- #include <cstrike>
- #include <fun>
- #include <hamsandwich>
- #include <fakemeta>
- #include <nvault>
- #define PLUGIN "JailBreak Knives Shop"
- #define VERSION "1.7"
- #define AUTHOR "CheezPuff"
- #define MAX_PLAYERS 32
- #define PREVIEW_TIME 5.0
- #define BASE_HEALTH 100
- #define BASE_ARMOR 0
- #define MAX_ARMOR 200
- #define TASK_PREVIEW 7000 // 7000 + id
- #define TASK_HPREGEN 8000 // 8000 + id
- enum _:eKnife {
- KNIFE_MODEL[64],
- KNIFE_NAME[32],
- KNIFE_PRICE,
- KNIFE_LEVEL_REQ,
- Float:KNIFE_CASH_BONUS,
- KNIFE_HEALTH_BONUS,
- KNIFE_ARMOR_BONUS,
- Float:KNIFE_DAMAGE_MULT,
- KNIFE_HP_REGEN,
- KNIFE_HP_REGEN_INTERVAL
- }
- // Format: model, name, price, level, cash%, hp, armor, dmg_mult, hp_regen, regen_interval
- //
- // Progression logic:
- // Knife 0 — Normal Boxer : nothing, default
- // Knife 1 — Steel Blade : basic HP + tiny DMG
- // Knife 2 — Hunter Knife : more HP + DMG, small armor
- // Knife 3 — Shadow Knife : HP + armor + DMG + cash bonus
- // Knife 4 — Blood Knife : everything from 3 + HP regen begins
- // Knife 5 — Soul Reaper : everything maxed + strong regen + cash
- // Knife 6 — Legendary Blade : VIP only — god tier
- //
- new const g_Knives[][eKnife] = {
- // model name price lvl cash% hp arm dmg regen interval
- {"models/v_knife.mdl", "Normal Boxer", 0, 0, 0.0, 0, 0, 1.0, 0, 0},
- {"models/knives/v_knife1.mdl", "Steel Blade", 10000, 3, 0.0, 15, 0, 1.15, 0, 0},
- {"models/knives/v_knife2.mdl", "Hunter Knife", 30000, 7, 0.0, 25, 15, 1.25, 0, 0},
- {"models/knives/v_knife3.mdl", "Shadow Knife", 75000, 12, 0.10, 35, 30, 1.35, 0, 0},
- {"models/knives/v_knife4.mdl", "Blood Knife", 150000, 18, 0.20, 45, 45, 1.45, 2, 5},
- {"models/knives/v_knife5.mdl", "Soul Reaper", 300000, 25, 0.30, 60, 60, 1.55, 4, 4},
- {"models/knives/v_knife6.mdl", "Legendary Blade", 750000, 35, 0.50, 80, 80, 1.75, 7, 3}
- }
- #define KNIFE_COUNT 7
- // VIP knife index — VIP players can buy this knife regardless of sequential lock
- #define VIP_KNIFE_INDEX (KNIFE_COUNT - 1) // Legendary Blade
- #define VIP_FLAG ADMIN_LEVEL_H
- // v1.2: bitmask of which knives have valid (existing) model files
- // set during plugin_precache — knives with missing models are skipped everywhere
- new g_iKnifeValid // bit N = knife N model exists and was precached
- new g_iPlayerCash[MAX_PLAYERS + 1]
- new g_iPlayerLevel[MAX_PLAYERS + 1]
- new g_iPlayerXP[MAX_PLAYERS + 1]
- new g_iPlayerEquippedKnife[MAX_PLAYERS + 1]
- new g_iPlayerOwnedKnives[MAX_PLAYERS + 1]
- new g_iPlayerPreviewingKnife[MAX_PLAYERS + 1]
- new g_iPlayerViewingKnife[MAX_PLAYERS + 1]
- new g_vault
- // -------------------------------------------------------------------------
- public plugin_precache() {
- g_iKnifeValid = 0
- for(new i = 0; i < KNIFE_COUNT; i++) {
- // Knife 0 is the default CS knife — always exists, no file check needed
- if(i == 0) {
- precache_model(g_Knives[0][KNIFE_MODEL])
- g_iKnifeValid |= (1 << 0)
- continue
- }
- // For custom knives: only precache if the file actually exists on disk
- if(file_exists(g_Knives[i][KNIFE_MODEL])) {
- precache_model(g_Knives[i][KNIFE_MODEL])
- g_iKnifeValid |= (1 << i)
- } else {
- // Log once at startup so admin knows what is missing — no crash
- log_amx("[KnifeShop] WARNING: model not found, knife disabled: %s", g_Knives[i][KNIFE_MODEL])
- }
- }
- }
- public plugin_init() {
- register_plugin(PLUGIN, VERSION, AUTHOR)
- g_vault = nvault_open("knife_shop_vault")
- if(g_vault == INVALID_HANDLE)
- set_fail_state("[KnifeShop] Failed to open vault!")
- register_clcmd("say /knife", "CmdKnifeShop")
- register_clcmd("say_team /knife", "CmdKnifeShop")
- register_concmd("amx_knivetop", "CmdKnifeTop", ADMIN_RCON, "- Show top 5 knife players")
- register_concmd("amx_knifereset", "CmdKnifeReset", ADMIN_RCON, "- Reset all player knife data")
- register_concmd("amx_givecash", "CmdGiveCash", ADMIN_RCON, "<player> <amount> - Give cash to player")
- register_concmd("amx_givelevel", "CmdGiveLevel", ADMIN_RCON, "<player> <level> - Set player level")
- register_event("DeathMsg", "EventPlayerKill", "a")
- register_event("HLTV", "EventRoundStart", "a", "1=0", "2=0")
- RegisterHam(Ham_TakeDamage, "player", "fw_TakeDamage")
- register_forward(FM_PlayerPostThink, "fw_PlayerPostThink")
- set_task(120.0, "Task_KnifeAd", _, _, _, "b")
- new statsMenuId = register_menuid("Knife Stats Menu")
- register_menucmd(statsMenuId, MENU_KEY_0, "knife_stats_menu_handler")
- }
- public plugin_end() {
- nvault_close(g_vault)
- }
- // -------------------------------------------------------------------------
- // Helper: is this knife usable (valid model + owned)
- stock bool:IsKnifeValid(knife_id) {
- return bool:(g_iKnifeValid & (1 << knife_id))
- }
- // -------------------------------------------------------------------------
- // Vault
- stock LoadPlayerData(id) {
- new authid[32]
- get_user_authid(id, authid, charsmax(authid))
- new data[128], szCash[16], szLevel[8], szXP[8], szEquipped[4], szOwned[16]
- if(nvault_get(g_vault, authid, data, charsmax(data))) {
- parse(data,
- szCash, charsmax(szCash),
- szLevel, charsmax(szLevel),
- szXP, charsmax(szXP),
- szEquipped, charsmax(szEquipped),
- szOwned, charsmax(szOwned))
- g_iPlayerCash[id] = str_to_num(szCash)
- g_iPlayerLevel[id] = str_to_num(szLevel)
- g_iPlayerXP[id] = str_to_num(szXP)
- g_iPlayerEquippedKnife[id] = str_to_num(szEquipped)
- g_iPlayerOwnedKnives[id] = str_to_num(szOwned)
- } else {
- g_iPlayerCash[id] = 0
- g_iPlayerLevel[id] = 1
- g_iPlayerXP[id] = 0
- g_iPlayerEquippedKnife[id] = 0
- g_iPlayerOwnedKnives[id] = (1 << 0)
- }
- // Safety: if the player's equipped knife has no valid model, fall back to knife 0
- if(!IsKnifeValid(g_iPlayerEquippedKnife[id]))
- g_iPlayerEquippedKnife[id] = 0
- }
- stock SavePlayerData(id) {
- new authid[32]
- get_user_authid(id, authid, charsmax(authid))
- new data[128]
- formatex(data, charsmax(data), "%d %d %d %d %d",
- g_iPlayerCash[id],
- g_iPlayerLevel[id],
- g_iPlayerXP[id],
- g_iPlayerEquippedKnife[id],
- g_iPlayerOwnedKnives[id])
- nvault_set(g_vault, authid, data)
- }
- stock bool:IsKnifeOwned(id, knife_id) {
- return bool:(g_iPlayerOwnedKnives[id] & (1 << knife_id))
- }
- stock AddOwnedKnife(id, knife_id) {
- g_iPlayerOwnedKnives[id] |= (1 << knife_id)
- }
- // -------------------------------------------------------------------------
- public client_putinserver(id) {
- LoadPlayerData(id)
- g_iPlayerPreviewingKnife[id] = -1
- g_iPlayerViewingKnife[id] = 0
- // Welcome message after 5 seconds (give time to fully connect)
- set_task(5.0, "Task_WelcomeMsg", id)
- }
- public client_disconnected(id) {
- remove_task(TASK_PREVIEW + id)
- remove_task(TASK_HPREGEN + id)
- SavePlayerData(id)
- }
- public Task_WelcomeMsg(id) {
- if(!is_user_connected(id)) return
- client_print_color(id, print_team_default, "^4[Knife Shop] ^1Welcome! Type ^3/knife ^1to open the knives shop.")
- client_print_color(id, print_team_default, "^4[Knife Shop] ^1Cash: ^3$%d ^1| Level: ^3%d ^1| Equipped: ^3%s",
- g_iPlayerCash[id], g_iPlayerLevel[id], g_Knives[g_iPlayerEquippedKnife[id]][KNIFE_NAME])
- }
- public Task_KnifeAd() {
- client_print_color(0, print_team_default, "^4[Knife Shop] ^1Want a better knife? Type ^3/knife ^1to browse and purchase!")
- }
- // -------------------------------------------------------------------------
- public fw_PlayerPostThink(id) {
- if(!is_user_alive(id)) return FMRES_IGNORED
- if(get_user_weapon(id) == CSW_KNIFE) {
- new knife_id = (g_iPlayerPreviewingKnife[id] != -1) ? g_iPlayerPreviewingKnife[id] : g_iPlayerEquippedKnife[id]
- // Only apply custom model if it was successfully precached
- if(IsKnifeValid(knife_id))
- set_pev(id, pev_viewmodel2, g_Knives[knife_id][KNIFE_MODEL])
- }
- return FMRES_IGNORED
- }
- public fw_TakeDamage(victim, inflictor, attacker, Float:damage, damage_type) {
- if(!is_user_connected(attacker) || get_user_weapon(attacker) != CSW_KNIFE)
- return HAM_IGNORED
- new knife_id = g_iPlayerEquippedKnife[attacker]
- if(!IsKnifeValid(knife_id)) return HAM_IGNORED
- // Multiply damage by knife multiplier (1.0 = no change, 1.5 = +50%)
- new Float:new_damage = damage * g_Knives[knife_id][KNIFE_DAMAGE_MULT]
- SetHamParamFloat(4, new_damage)
- return HAM_HANDLED
- }
- // -------------------------------------------------------------------------
- public EventRoundStart() {
- for(new id = 1; id <= MAX_PLAYERS; id++)
- if(is_user_connected(id) && is_user_alive(id))
- ApplyKnifeAbilities(id)
- }
- stock ApplyKnifeAbilities(id) {
- new knife_id = g_iPlayerEquippedKnife[id]
- if(!IsKnifeValid(knife_id)) knife_id = 0
- new newHealth = BASE_HEALTH + g_Knives[knife_id][KNIFE_HEALTH_BONUS]
- set_user_health(id, newHealth)
- new newArmor = BASE_ARMOR + g_Knives[knife_id][KNIFE_ARMOR_BONUS]
- if(newArmor > MAX_ARMOR) newArmor = MAX_ARMOR
- set_user_armor(id, newArmor)
- remove_task(TASK_HPREGEN + id)
- if(g_Knives[knife_id][KNIFE_HP_REGEN] > 0 && g_Knives[knife_id][KNIFE_HP_REGEN_INTERVAL] > 0)
- set_task(float(g_Knives[knife_id][KNIFE_HP_REGEN_INTERVAL]), "Task_HPRegen", TASK_HPREGEN + id, _, _, "b")
- }
- public Task_HPRegen(taskid) {
- new id = taskid - TASK_HPREGEN
- if(!is_user_connected(id) || !is_user_alive(id)) {
- remove_task(taskid)
- return
- }
- new knife_id = g_iPlayerEquippedKnife[id]
- if(!IsKnifeValid(knife_id) || g_Knives[knife_id][KNIFE_HP_REGEN] <= 0) {
- remove_task(taskid)
- return
- }
- new hp = get_user_health(id)
- new maxHp = BASE_HEALTH + g_Knives[knife_id][KNIFE_HEALTH_BONUS]
- if(hp < maxHp) {
- new newHp = hp + g_Knives[knife_id][KNIFE_HP_REGEN]
- if(newHp > maxHp) newHp = maxHp
- set_user_health(id, newHp)
- }
- }
- public EventPlayerKill() {
- new killer = read_data(1)
- new victim = read_data(2)
- if(killer == victim || !is_user_connected(killer)) return
- new xp_gain = (cs_get_user_team(victim) == CS_TEAM_CT) ? 20 : 10
- g_iPlayerCash[killer] += 100
- g_iPlayerXP[killer] += xp_gain
- client_print_color(killer, print_team_default, "^4[Knife] ^3+%d XP ^1and ^3+$100 ^1for the kill!", xp_gain)
- if(g_iPlayerXP[killer] >= g_iPlayerLevel[killer] * 100) {
- g_iPlayerXP[killer] -= g_iPlayerLevel[killer] * 100
- g_iPlayerLevel[killer]++
- new name[32]
- get_user_name(killer, name, charsmax(name))
- client_print_color(0, print_team_default, "^4[Knife] ^3%s ^1leveled up to level ^3%d^1!", name, g_iPlayerLevel[killer])
- }
- new knife_id = g_iPlayerEquippedKnife[killer]
- if(IsKnifeValid(knife_id)) {
- new Float:cash_bonus = g_Knives[knife_id][KNIFE_CASH_BONUS]
- if(cash_bonus > 0.0) {
- new bonus_cash = floatround(100.0 * cash_bonus)
- g_iPlayerCash[killer] += bonus_cash
- client_print_color(killer, print_team_default, "^4[Knife] ^3+$%d ^1knife bonus!", bonus_cash)
- }
- }
- SavePlayerData(killer)
- }
- // -------------------------------------------------------------------------
- // XP Progress bar helper — returns e.g. "[####......] 40/100"
- stock BuildXPBar(id, bar[], len) {
- new xp = g_iPlayerXP[id]
- new xpNeeded = g_iPlayerLevel[id] * 100
- new filled = (xpNeeded > 0) ? (xp * 10 / xpNeeded) : 10
- if(filled > 10) filled = 10
- new barStr[16]
- barStr[0] = '['
- for(new i = 1; i <= 10; i++)
- barStr[i] = (i <= filled) ? '#' : '.'
- barStr[11] = ']'
- barStr[12] = EOS
- formatex(bar, len, "%s %d/%d XP", barStr, xp, xpNeeded)
- }
- // -------------------------------------------------------------------------
- // Main Menu
- public CmdKnifeShop(id) {
- ShowMainMenu(id)
- return PLUGIN_HANDLED
- }
- ShowMainMenu(id) {
- if(!is_user_connected(id)) return
- new xpBar[32]
- BuildXPBar(id, xpBar, charsmax(xpBar))
- new title[160]
- formatex(title, charsmax(title),
- "\r[JailBreak] \wKnives Shop^n\wCash: \y$%d \w| Level: \y%d^n\w%s^nEquipped: \y%s",
- g_iPlayerCash[id], g_iPlayerLevel[id],
- xpBar,
- g_Knives[g_iPlayerEquippedKnife[id]][KNIFE_NAME])
- new menu = menu_create(title, "main_menu_handler")
- menu_additem(menu, "\wView Knives")
- menu_additem(menu, "\wMy Inventory \d| Top Knife Leaderboard")
- menu_additem(menu, "\wShop Information")
- menu_additem(menu, "\wPreview Knife")
- menu_setprop(menu, MPROP_EXIT, MEXIT_ALL)
- menu_display(id, menu, 0)
- }
- public main_menu_handler(id, menu, item) {
- menu_destroy(menu)
- if(item == MENU_EXIT) return PLUGIN_HANDLED
- switch(item) {
- case 0: ShowKnifesList(id)
- case 1: ShowInventoryMenu(id)
- case 2: ShowShopInfo(id)
- case 3: ShowPreviewMenu(id)
- }
- return PLUGIN_HANDLED
- }
- // -------------------------------------------------------------------------
- // Knives List — skips knives whose model is missing
- ShowKnifesList(id) {
- if(!is_user_connected(id)) return
- new title[64]
- formatex(title, charsmax(title), "\yKnives List \w| Cash: $%d | Lvl: %d",
- g_iPlayerCash[id], g_iPlayerLevel[id])
- new menu = menu_create(title, "knives_list_handler")
- for(new i = 0; i < KNIFE_COUNT; i++) {
- new item_text[96], item_info[4]
- new bool:owned = IsKnifeOwned(id, i)
- new bool:valid = IsKnifeValid(i)
- // Sequential lock: must own the previous knife first (except knife 0)
- new bool:prevOwned = (i == 0) ? true : IsKnifeOwned(id, i - 1)
- // VIP bypass for last knife
- new bool:isVIP = bool:(get_user_flags(id) & VIP_FLAG)
- if(isVIP && i == VIP_KNIFE_INDEX) prevOwned = true
- if(owned) {
- formatex(item_text, charsmax(item_text), "\y%s \d[Owned]\w | $%d | Lvl %d",
- g_Knives[i][KNIFE_NAME],
- g_Knives[i][KNIFE_PRICE],
- g_Knives[i][KNIFE_LEVEL_REQ])
- } else if(!valid) {
- // Model missing — show VIP tag if applicable
- if(isVIP && i == VIP_KNIFE_INDEX)
- formatex(item_text, charsmax(item_text), "\d%s | Model missing \y[VIP]", g_Knives[i][KNIFE_NAME])
- else
- formatex(item_text, charsmax(item_text), "\d%s | Model missing", g_Knives[i][KNIFE_NAME])
- } else if(!prevOwned) {
- formatex(item_text, charsmax(item_text), "\d%s | Buy previous first",
- g_Knives[i][KNIFE_NAME])
- } else if(g_iPlayerLevel[id] < g_Knives[i][KNIFE_LEVEL_REQ]) {
- formatex(item_text, charsmax(item_text), "\d%s | Lvl %d required",
- g_Knives[i][KNIFE_NAME], g_Knives[i][KNIFE_LEVEL_REQ])
- } else {
- // Available to buy
- if(isVIP && i == VIP_KNIFE_INDEX)
- formatex(item_text, charsmax(item_text), "\w%s | \y$%d \r[VIP KNIFE]\w | Lvl %d",
- g_Knives[i][KNIFE_NAME], g_Knives[i][KNIFE_PRICE], g_Knives[i][KNIFE_LEVEL_REQ])
- else
- formatex(item_text, charsmax(item_text), "\w%s | \y$%d\w | Lvl %d",
- g_Knives[i][KNIFE_NAME], g_Knives[i][KNIFE_PRICE], g_Knives[i][KNIFE_LEVEL_REQ])
- }
- formatex(item_info, charsmax(item_info), "%d", i)
- menu_additem(menu, item_text, item_info)
- }
- menu_setprop(menu, MPROP_EXIT, MEXIT_ALL)
- menu_display(id, menu, 0)
- }
- public knives_list_handler(id, menu, item) {
- if(item == MENU_EXIT) {
- menu_destroy(menu)
- ShowMainMenu(id)
- return PLUGIN_HANDLED
- }
- new item_info[4], dummy[64], access, callback
- menu_item_getinfo(menu, item, access, item_info, charsmax(item_info), dummy, charsmax(dummy), callback)
- menu_destroy(menu)
- new knife_id = str_to_num(item_info)
- if(knife_id < 0) {
- ShowMainMenu(id)
- return PLUGIN_HANDLED
- }
- // Sequential lock check — block entry if previous not owned
- if(knife_id > 0 && !IsKnifeOwned(id, knife_id - 1)) {
- client_print_color(id, print_team_default, "^4[Knife] ^1You must purchase ^3%s ^1first!", g_Knives[knife_id - 1][KNIFE_NAME])
- ShowKnifesList(id)
- return PLUGIN_HANDLED
- }
- // Level check
- if(g_iPlayerLevel[id] < g_Knives[knife_id][KNIFE_LEVEL_REQ]) {
- client_print_color(id, print_team_default, "^4[Knife] ^1You need level ^3%d ^1to view this knife.", g_Knives[knife_id][KNIFE_LEVEL_REQ])
- ShowKnifesList(id)
- return PLUGIN_HANDLED
- }
- ShowKnifeDetails(id, knife_id)
- return PLUGIN_HANDLED
- }
- // -------------------------------------------------------------------------
- // Knife Details
- ShowKnifeDetails(id, knife_id) {
- if(!is_user_connected(id)) return
- g_iPlayerViewingKnife[id] = knife_id
- new bool:owned = IsKnifeOwned(id, knife_id)
- new bool:valid = IsKnifeValid(knife_id)
- new bool:prevOwned = (knife_id == 0) ? true : IsKnifeOwned(id, knife_id - 1)
- new bool:levelOk = (g_iPlayerLevel[id] >= g_Knives[knife_id][KNIFE_LEVEL_REQ])
- // VIP players bypass sequential lock for the VIP knife (last knife)
- new bool:isVIP = bool:(get_user_flags(id) & VIP_FLAG)
- if(isVIP && knife_id == VIP_KNIFE_INDEX) prevOwned = true
- // Title shows knife info — no need to repeat as a menu item
- new title[160]
- if(g_Knives[knife_id][KNIFE_PRICE] == 0) {
- formatex(title, charsmax(title),
- "\r%s \d[Default Knife]^n\wNo bonuses",
- g_Knives[knife_id][KNIFE_NAME])
- } else {
- formatex(title, charsmax(title),
- "\r%s\w | \y$%d\w | Lvl %d^n\wHP: +%d | Armor: +%d | Dmg: \yx%.2f",
- g_Knives[knife_id][KNIFE_NAME],
- g_Knives[knife_id][KNIFE_PRICE],
- g_Knives[knife_id][KNIFE_LEVEL_REQ],
- g_Knives[knife_id][KNIFE_HEALTH_BONUS],
- g_Knives[knife_id][KNIFE_ARMOR_BONUS],
- g_Knives[knife_id][KNIFE_DAMAGE_MULT])
- }
- new menu = menu_create(title, "knife_details_handler")
- if(owned) {
- if(g_iPlayerEquippedKnife[id] == knife_id) {
- menu_additem(menu, "\d>> Currently Equipped", "info")
- } else if(!valid) {
- menu_additem(menu, "\dEquip (model not uploaded yet)", "locked")
- } else {
- menu_additem(menu, "\wEquip this knife", "equip")
- }
- // Show next knife info — buyable only if requirements met
- new nextId = knife_id + 1
- if(nextId < KNIFE_COUNT && !IsKnifeOwned(id, nextId)) {
- new bool:nextVIPLocked = (nextId == VIP_KNIFE_INDEX) && !(get_user_flags(id) & VIP_FLAG)
- if(!nextVIPLocked) {
- new bool:canAfford = (g_iPlayerCash[id] >= g_Knives[nextId][KNIFE_PRICE])
- new bool:hasLevel = (g_iPlayerLevel[id] >= g_Knives[nextId][KNIFE_LEVEL_REQ])
- new nextText[72]
- if(canAfford && hasLevel) {
- formatex(nextText, charsmax(nextText), "\wBuy Next: \y%s \w(\y$%d\w)", g_Knives[nextId][KNIFE_NAME], g_Knives[nextId][KNIFE_PRICE])
- menu_additem(menu, nextText, "buynext")
- } else {
- // Grayed — show what's missing, not clickable
- if(!hasLevel)
- formatex(nextText, charsmax(nextText), "\dNext: %s (Need Lvl %d)", g_Knives[nextId][KNIFE_NAME], g_Knives[nextId][KNIFE_LEVEL_REQ])
- else
- formatex(nextText, charsmax(nextText), "\dNext: %s (Need $%d)", g_Knives[nextId][KNIFE_NAME], g_Knives[nextId][KNIFE_PRICE])
- menu_additem(menu, nextText, "info", ADMIN_RCON)
- }
- }
- }
- } else if(!prevOwned) {
- new lock_text[64]
- formatex(lock_text, charsmax(lock_text), "\dBuy %s first", g_Knives[knife_id - 1][KNIFE_NAME])
- menu_additem(menu, lock_text, "locked")
- } else if(!levelOk) {
- new lock_text[48]
- formatex(lock_text, charsmax(lock_text), "\dNeed level %d to unlock", g_Knives[knife_id][KNIFE_LEVEL_REQ])
- menu_additem(menu, lock_text, "locked")
- } else if(g_iPlayerCash[id] < g_Knives[knife_id][KNIFE_PRICE]) {
- new lock_text[48]
- formatex(lock_text, charsmax(lock_text), "\dNot enough cash ($%d / $%d)", g_iPlayerCash[id], g_Knives[knife_id][KNIFE_PRICE])
- menu_additem(menu, lock_text, "locked")
- } else {
- new buy_text[40]
- formatex(buy_text, charsmax(buy_text), "\wPurchase \y$%d", g_Knives[knife_id][KNIFE_PRICE])
- menu_additem(menu, buy_text, "buy")
- }
- menu_additem(menu, "\wView Stats", "stats")
- menu_setprop(menu, MPROP_EXIT, MEXIT_ALL)
- menu_display(id, menu, 0)
- }
- public knife_details_handler(id, menu, item) {
- if(item == MENU_EXIT) {
- menu_destroy(menu)
- ShowKnifesList(id)
- return PLUGIN_HANDLED
- }
- new item_info[8], dummy[64], access, callback
- menu_item_getinfo(menu, item, access, item_info, charsmax(item_info), dummy, charsmax(dummy), callback)
- menu_destroy(menu)
- new knife_id = g_iPlayerViewingKnife[id]
- if(equal(item_info, "equip")) {
- g_iPlayerEquippedKnife[id] = knife_id
- ApplyKnifeAbilities(id)
- client_print_color(id, print_team_default, "^4[Knife] ^1Equipped: ^3%s", g_Knives[knife_id][KNIFE_NAME])
- SavePlayerData(id)
- ShowKnifeDetails(id, knife_id)
- } else if(equal(item_info, "buynext")) {
- new nextId = knife_id + 1
- if(nextId < KNIFE_COUNT && !IsKnifeOwned(id, nextId)
- && g_iPlayerCash[id] >= g_Knives[nextId][KNIFE_PRICE]
- && g_iPlayerLevel[id] >= g_Knives[nextId][KNIFE_LEVEL_REQ]) {
- g_iPlayerCash[id] -= g_Knives[nextId][KNIFE_PRICE]
- AddOwnedKnife(id, nextId)
- new buyerName[32]
- get_user_name(id, buyerName, charsmax(buyerName))
- client_print_color(0, print_team_default, "^4[Knife] ^3%s ^1purchased ^4%s^1!", buyerName, g_Knives[nextId][KNIFE_NAME])
- if(IsKnifeValid(nextId)) {
- g_iPlayerEquippedKnife[id] = nextId
- ApplyKnifeAbilities(id)
- client_print_color(id, print_team_default, "^4[Knife] ^1Purchased and equipped: ^3%s^1! Remaining: ^3$%d",
- g_Knives[nextId][KNIFE_NAME], g_iPlayerCash[id])
- } else {
- client_print_color(id, print_team_default, "^4[Knife] ^1Purchased: ^3%s^1! Remaining: ^3$%d ^1(model not uploaded yet — equip later)",
- g_Knives[nextId][KNIFE_NAME], g_iPlayerCash[id])
- }
- SavePlayerData(id)
- ShowKnifeDetails(id, nextId)
- } else {
- client_print_color(id, print_team_default, "^4[Knife] ^1Cannot buy next knife yet.")
- ShowKnifeDetails(id, knife_id)
- }
- } else if(equal(item_info, "buy")) {
- g_iPlayerCash[id] -= g_Knives[knife_id][KNIFE_PRICE]
- AddOwnedKnife(id, knife_id)
- new buyerName[32]
- get_user_name(id, buyerName, charsmax(buyerName))
- client_print_color(0, print_team_default, "^4[Knife] ^3%s ^1purchased ^4%s^1!", buyerName, g_Knives[knife_id][KNIFE_NAME])
- if(IsKnifeValid(knife_id)) {
- g_iPlayerEquippedKnife[id] = knife_id
- ApplyKnifeAbilities(id)
- client_print_color(id, print_team_default, "^4[Knife] ^1Purchased and equipped: ^3%s^1! Remaining: ^3$%d",
- g_Knives[knife_id][KNIFE_NAME], g_iPlayerCash[id])
- } else {
- client_print_color(id, print_team_default, "^4[Knife] ^1Purchased: ^3%s^1! Remaining: ^3$%d ^1(model not uploaded yet)",
- g_Knives[knife_id][KNIFE_NAME], g_iPlayerCash[id])
- }
- SavePlayerData(id)
- ShowKnifeDetails(id, knife_id)
- } else if(equal(item_info, "stats")) {
- ShowKnifeStats(id, knife_id)
- } else {
- // "locked", "info", or anything else — just re-open details
- ShowKnifeDetails(id, knife_id)
- }
- return PLUGIN_HANDLED
- }
- // -------------------------------------------------------------------------
- // Knife Stats — shown as menu text (no MOTD)
- ShowKnifeStats(id, knife_id) {
- if(!is_user_connected(id)) return
- new bool:isVIP = bool:(get_user_flags(id) & VIP_FLAG)
- new bool:vipKnife = (knife_id == VIP_KNIFE_INDEX)
- new bool:owned = IsKnifeOwned(id, knife_id)
- new bool:equipped = (g_iPlayerEquippedKnife[id] == knife_id)
- new stats[768], line[80], sl[80]
- // ── Header ──────────────────────────────────────────
- if(vipKnife && isVIP)
- formatex(stats, charsmax(stats), "\r=====[ \y%s \r]=====^n\r [ VIP EXCLUSIVE ]^n", g_Knives[knife_id][KNIFE_NAME])
- else
- formatex(stats, charsmax(stats), "\r=====[ \y%s \r]=====^n", g_Knives[knife_id][KNIFE_NAME])
- // ── Price & Status ───────────────────────────────────
- if(g_Knives[knife_id][KNIFE_PRICE] == 0) {
- add(stats, charsmax(stats), "\d Type \w: Default Knife^n")
- add(stats, charsmax(stats), "\d Price \w: \yFree^n")
- } else {
- formatex(sl, charsmax(sl), "\d Price \w: \y$%d^n", g_Knives[knife_id][KNIFE_PRICE])
- add(stats, charsmax(stats), sl)
- formatex(sl, charsmax(sl), "\d Level \w: \yLvl %d required^n", g_Knives[knife_id][KNIFE_LEVEL_REQ])
- add(stats, charsmax(stats), sl)
- }
- if(equipped)
- add(stats, charsmax(stats), "\d Status \w: \r[ Currently Equipped ]^n")
- else if(owned)
- add(stats, charsmax(stats), "\d Status \w: \y[ Owned ]^n")
- else
- add(stats, charsmax(stats), "\d Status \w: \d[ Not Owned ]^n")
- add(stats, charsmax(stats), "\d--------------------------------^n")
- // ── Combat Stats ─────────────────────────────────────
- add(stats, charsmax(stats), "\w COMBAT STATS^n")
- formatex(line, charsmax(line), "\d Health \w: \r+%d HP^n", g_Knives[knife_id][KNIFE_HEALTH_BONUS])
- add(stats, charsmax(stats), line)
- formatex(line, charsmax(line), "\d Armor \w: \r+%d^n", g_Knives[knife_id][KNIFE_ARMOR_BONUS])
- add(stats, charsmax(stats), line)
- formatex(line, charsmax(line), "\d Damage \w: \rx%.2f multiplier^n", g_Knives[knife_id][KNIFE_DAMAGE_MULT])
- add(stats, charsmax(stats), line)
- add(stats, charsmax(stats), "\d--------------------------------^n")
- // ── Passive Stats ────────────────────────────────────
- add(stats, charsmax(stats), "\w PASSIVE STATS^n")
- if(g_Knives[knife_id][KNIFE_HP_REGEN] > 0)
- formatex(line, charsmax(line), "\d HP Regen \w: \r+%d HP\w every \r%ds^n", g_Knives[knife_id][KNIFE_HP_REGEN], g_Knives[knife_id][KNIFE_HP_REGEN_INTERVAL])
- else
- copy(line, charsmax(line), "\d HP Regen \w: \d None^n")
- add(stats, charsmax(stats), line)
- if(g_Knives[knife_id][KNIFE_CASH_BONUS] > 0.0)
- formatex(line, charsmax(line), "\d Cash/Kill \w: \r+%.0f%%\w per kill^n", g_Knives[knife_id][KNIFE_CASH_BONUS] * 100.0)
- else
- copy(line, charsmax(line), "\d Cash/Kill \w: \d None^n")
- add(stats, charsmax(stats), line)
- add(stats, charsmax(stats), "\d--------------------------------^n")
- // ── Your Stats ───────────────────────────────────────
- add(stats, charsmax(stats), "\w YOUR STATS^n")
- formatex(line, charsmax(line), "\d Cash \w: \y$%d^n", g_iPlayerCash[id])
- add(stats, charsmax(stats), line)
- formatex(line, charsmax(line), "\d Level \w: \yLvl %d^n", g_iPlayerLevel[id])
- add(stats, charsmax(stats), line)
- add(stats, charsmax(stats), "\d--------------------------------^n")
- add(stats, charsmax(stats), "\r0. \wBack")
- show_menu(id, MENU_KEY_0, stats, -1, "Knife Stats Menu")
- }
- public knife_stats_menu_handler(id, key) {
- ShowKnifeDetails(id, g_iPlayerViewingKnife[id])
- return PLUGIN_HANDLED
- }
- // -------------------------------------------------------------------------
- // Preview — skips missing models
- ShowPreviewMenu(id) {
- if(!is_user_connected(id)) return
- new menu = menu_create("[JailBreak] Preview Knife", "preview_menu_handler")
- for(new i = 0; i < KNIFE_COUNT; i++) {
- new item_text[64], item_info[4]
- if(IsKnifeValid(i))
- formatex(item_text, charsmax(item_text), "%s", g_Knives[i][KNIFE_NAME])
- else
- formatex(item_text, charsmax(item_text), "\d%s (unavailable)", g_Knives[i][KNIFE_NAME])
- formatex(item_info, charsmax(item_info), "%d", i)
- menu_additem(menu, item_text, item_info)
- }
- menu_setprop(menu, MPROP_EXIT, MEXIT_ALL)
- menu_display(id, menu, 0)
- }
- public preview_menu_handler(id, menu, item) {
- if(item == MENU_EXIT) {
- menu_destroy(menu)
- ShowMainMenu(id)
- return PLUGIN_HANDLED
- }
- new item_info[4], dummy[64], access, callback
- menu_item_getinfo(menu, item, access, item_info, charsmax(item_info), dummy, charsmax(dummy), callback)
- menu_destroy(menu)
- new knife_id = str_to_num(item_info)
- if(!IsKnifeValid(knife_id)) {
- client_print_color(id, print_team_default, "^4[Knife] ^1Cannot preview ^3%s ^1- model not uploaded yet.", g_Knives[knife_id][KNIFE_NAME])
- ShowPreviewMenu(id)
- return PLUGIN_HANDLED
- }
- PreviewKnife(id, knife_id)
- return PLUGIN_HANDLED
- }
- PreviewKnife(id, knife_id) {
- remove_task(TASK_PREVIEW + id)
- g_iPlayerPreviewingKnife[id] = knife_id
- client_print(id, print_chat, "[Knife] Previewing %s for %.0f seconds.", g_Knives[knife_id][KNIFE_NAME], PREVIEW_TIME)
- set_task(PREVIEW_TIME, "EndPreview", TASK_PREVIEW + id)
- }
- public EndPreview(taskid) {
- new id = taskid - TASK_PREVIEW
- g_iPlayerPreviewingKnife[id] = -1
- if(is_user_connected(id))
- client_print(id, print_chat, "[Knife] Preview ended.")
- }
- // -------------------------------------------------------------------------
- // Inventory Menu — small selector before opening MOTD or leaderboard
- ShowInventoryMenu(id) {
- if(!is_user_connected(id)) return
- new title[64]
- formatex(title, charsmax(title), "\yMy Inventory \w| Lvl: %d | $%d",
- g_iPlayerLevel[id], g_iPlayerCash[id])
- new menu = menu_create(title, "inventory_select_handler")
- menu_additem(menu, "\wView My Knives", "inv")
- menu_additem(menu, "\wTop Knife Leaderboard", "top")
- menu_setprop(menu, MPROP_EXIT, MEXIT_ALL)
- menu_display(id, menu, 0)
- }
- public inventory_select_handler(id, menu, item) {
- if(item == MENU_EXIT) {
- menu_destroy(menu)
- ShowMainMenu(id)
- return PLUGIN_HANDLED
- }
- new item_info[4], dummy[64], access, callback
- menu_item_getinfo(menu, item, access, item_info, charsmax(item_info), dummy, charsmax(dummy), callback)
- menu_destroy(menu)
- if(equal(item_info, "inv")) ShowInventory(id)
- else if(equal(item_info, "top")) ShowTopLeaderboard(id)
- return PLUGIN_HANDLED
- }
- // -------------------------------------------------------------------------
- // Inventory — MOTD HTML
- ShowInventory(id) {
- if(!is_user_connected(id)) return
- static motd[3072], tmp[256]
- motd[0] = EOS
- tmp[0] = EOS
- new xpBar[32]
- BuildXPBar(id, xpBar, charsmax(xpBar))
- copy(motd, charsmax(motd), "<body bgcolor=#111111>")
- add(motd, charsmax(motd), "<font face=Arial size=4 color=#FFB000><b>My Inventory</b></font><br>")
- formatex(tmp, charsmax(tmp), "<font face=Arial size=2 color=#777777>Cash: <b>$%d</b> | Level: <b>%d</b> | %s</font><br><br>",
- g_iPlayerCash[id], g_iPlayerLevel[id], xpBar)
- add(motd, charsmax(motd), tmp)
- new found = 0
- for(new i = 0; i < KNIFE_COUNT; i++) {
- if(!IsKnifeOwned(id, i)) continue
- new bool:equipped = (i == g_iPlayerEquippedKnife[id])
- new bool:valid = IsKnifeValid(i)
- // Row background
- new rowBg[8]
- if(equipped) copy(rowBg, charsmax(rowBg), "#1a2a1a")
- else if(!valid) copy(rowBg, charsmax(rowBg), "#2a1a1a")
- else copy(rowBg, charsmax(rowBg), "#1a1a1a")
- formatex(tmp, charsmax(tmp), "<table bgcolor=%s width=100%%><tr>", rowBg)
- add(motd, charsmax(motd), tmp)
- // Name + equipped badge
- if(equipped) {
- formatex(tmp, charsmax(tmp), "<td width=160><font face=Arial size=3 color=#FFD700><b>%s</b></font> <font face=Arial size=2 color=#00CC44>[Equipped]</font></td>", g_Knives[i][KNIFE_NAME])
- } else if(!valid) {
- formatex(tmp, charsmax(tmp), "<td width=160><font face=Arial size=3 color=#555555>%s</font> <font face=Arial size=2 color=#FF4444>[missing]</font></td>", g_Knives[i][KNIFE_NAME])
- } else {
- formatex(tmp, charsmax(tmp), "<td width=160><font face=Arial size=3 color=#FFFFFF>%s</font></td>", g_Knives[i][KNIFE_NAME])
- }
- add(motd, charsmax(motd), tmp)
- // Stats inline
- if(g_Knives[i][KNIFE_HEALTH_BONUS] > 0 || g_Knives[i][KNIFE_ARMOR_BONUS] > 0 || g_Knives[i][KNIFE_DAMAGE_MULT] > 1.0) {
- formatex(tmp, charsmax(tmp), "<td><font face=Arial size=2 color=#AAAAAA>HP +%d | Arm +%d | Dmg x%.2f",
- g_Knives[i][KNIFE_HEALTH_BONUS], g_Knives[i][KNIFE_ARMOR_BONUS], g_Knives[i][KNIFE_DAMAGE_MULT])
- add(motd, charsmax(motd), tmp)
- if(g_Knives[i][KNIFE_HP_REGEN] > 0) {
- formatex(tmp, charsmax(tmp), " | Regen +%d/%ds", g_Knives[i][KNIFE_HP_REGEN], g_Knives[i][KNIFE_HP_REGEN_INTERVAL])
- add(motd, charsmax(motd), tmp)
- }
- add(motd, charsmax(motd), "</font></td>")
- } else {
- add(motd, charsmax(motd), "<td><font face=Arial size=2 color=#555555>No bonuses</font></td>")
- }
- add(motd, charsmax(motd), "</tr></table>")
- found++
- }
- if(!found)
- add(motd, charsmax(motd), "<font face=Arial size=3 color=#555555>No knives owned yet.</font>")
- add(motd, charsmax(motd), "<br><font face=Arial size=2 color=#555555>Click OK to close. Use /knife to equip knives.</font>")
- show_motd(id, motd, "My Inventory")
- }
- // -------------------------------------------------------------------------
- // Shop Info
- ShowShopInfo(id) {
- static info[768], tmp[128]
- info[0] = EOS
- tmp[0] = EOS
- copy(info, charsmax(info), "<body bgcolor=#111111>")
- add(info, charsmax(info), "<font color=#FFB000><b>[Frag JailBreak] Knives Shop</b></font><br><br>")
- add(info, charsmax(info), "<font color=#FFFFFF>Purchase and equip knives with unique abilities.</font><br><br>")
- add(info, charsmax(info), "<font color=#FFB000><b>How to earn cash & XP:</b></font><br>")
- add(info, charsmax(info), "<font color=#AAAAAA>- Kill enemies to earn $100 and XP per kill<br>")
- add(info, charsmax(info), "- CT kills give 20 XP, T kills give 10 XP<br>")
- add(info, charsmax(info), "- Level up to unlock stronger knives<br><br></font>")
- add(info, charsmax(info), "<font color=#FFB000><b>Knife bonuses (per equipped knife):</b></font><br>")
- add(info, charsmax(info), "<font color=#AAAAAA>- Extra health and armor each round<br>")
- add(info, charsmax(info), "- Damage bonus on knife hits<br>")
- add(info, charsmax(info), "- Cash bonus on kills<br>")
- add(info, charsmax(info), "- Gravity reduction (jump higher)<br><br></font>")
- add(info, charsmax(info), "<font color=#FFB000><b>Knife unlock order:</b></font><br>")
- new i
- for(i = 0; i < KNIFE_COUNT; i++) {
- if(g_Knives[i][KNIFE_PRICE] == 0) {
- formatex(tmp, charsmax(tmp), "<font color=#AAAAAA>%d. %s - Free (default)</font><br>",
- i + 1, g_Knives[i][KNIFE_NAME])
- } else {
- formatex(tmp, charsmax(tmp), "<font color=#AAAAAA>%d. %s - $%d | Level %d</font><br>",
- i + 1, g_Knives[i][KNIFE_NAME],
- g_Knives[i][KNIFE_PRICE],
- g_Knives[i][KNIFE_LEVEL_REQ])
- }
- add(info, charsmax(info), tmp)
- }
- add(info, charsmax(info), "<br><font color=#FFFFFF>Type <b>/knife</b> to open the shop.</font>")
- show_motd(id, info, "Shop Information")
- }
- // -------------------------------------------------------------------------
- // Top Knife Leaderboard — shows top 5 online players by most expensive knife owned
- ShowTopLeaderboard(id) {
- // Collect online players sorted by top knife price (simple insertion sort)
- new topIds[5], topPrices[5], count = 0
- for(new p = 1; p <= MAX_PLAYERS; p++) {
- if(!is_user_connected(p)) continue
- new knifeId = GetPlayerTopKnife(p)
- new knifePrice = g_Knives[knifeId][KNIFE_PRICE]
- // Insert into top 5
- if(count < 5) {
- topIds[count] = p
- topPrices[count] = knifePrice
- count++
- } else {
- // Find lowest in top5 and replace if current is higher
- new minIdx = 0
- for(new j = 1; j < 5; j++)
- if(topPrices[j] < topPrices[minIdx]) minIdx = j
- if(knifePrice > topPrices[minIdx]) {
- topIds[minIdx] = p
- topPrices[minIdx] = knifePrice
- }
- }
- }
- // Bubble sort descending
- for(new a = 0; a < count - 1; a++) {
- for(new b = a + 1; b < count; b++) {
- if(topPrices[b] > topPrices[a]) {
- new tmpId = topIds[a]; topIds[a] = topIds[b]; topIds[b] = tmpId
- new tmpPr = topPrices[a]; topPrices[a] = topPrices[b]; topPrices[b] = tmpPr
- }
- }
- }
- // static — allocated once, not on stack each call
- static motd[4096], tmp[600]
- motd[0] = EOS
- tmp[0] = EOS
- copy(motd, charsmax(motd), "<body bgcolor=#111111 style='padding:12px'>")
- add(motd, charsmax(motd), "<font face=Arial size=4 color=#FFB000><b>Top Knife Leaderboard</b></font><br>")
- add(motd, charsmax(motd), "<font face=Arial size=2 color=#777777>Online players only</font><br><br>")
- if(count == 0) {
- add(motd, charsmax(motd), "<font face=Arial size=3 color=#AAAAAA>No players online.</font>")
- } else {
- for(new i = 0; i < count; i++) {
- new p = topIds[i], name[32]
- get_user_name(p, name, charsmax(name))
- new knifeId = GetPlayerTopKnife(p)
- // Alternate row shade
- new rowColor[8]
- if(i % 2 == 0) copy(rowColor, charsmax(rowColor), "#1a1a1a")
- else copy(rowColor, charsmax(rowColor), "#222222")
- // Medal color
- new medalColor[8]
- if(i == 0) copy(medalColor, charsmax(medalColor), "#FFD700") // gold
- else if(i == 1) copy(medalColor, charsmax(medalColor), "#C0C0C0") // silver
- else if(i == 2) copy(medalColor, charsmax(medalColor), "#CD7F32") // bronze
- else copy(medalColor, charsmax(medalColor), "#888888")
- // Build row in parts — Pawn no multi-line strings
- new rowTmp[128]
- tmp[0] = EOS
- formatex(rowTmp, charsmax(rowTmp), "<table bgcolor=%s width=100%%><tr>", rowColor)
- add(tmp, charsmax(tmp), rowTmp)
- formatex(rowTmp, charsmax(rowTmp), "<td width=30><font face=Arial size=3 color=%s><b>#%d</b></font></td>", medalColor, i + 1)
- add(tmp, charsmax(tmp), rowTmp)
- formatex(rowTmp, charsmax(rowTmp), "<td width=160><font face=Arial size=3 color=#FFFFFF>%s</font></td>", name)
- add(tmp, charsmax(tmp), rowTmp)
- formatex(rowTmp, charsmax(rowTmp), "<td width=130><font face=Arial size=3 color=#FFB000>%s</font></td>", g_Knives[knifeId][KNIFE_NAME])
- add(tmp, charsmax(tmp), rowTmp)
- formatex(rowTmp, charsmax(rowTmp), "<td width=50><font face=Arial size=3 color=#AAAAAA>Lvl %d</font></td>", g_iPlayerLevel[p])
- add(tmp, charsmax(tmp), rowTmp)
- formatex(rowTmp, charsmax(rowTmp), "<td><font face=Arial size=3 color=#AAAAAA>$%d</font></td></tr></table>", g_iPlayerCash[p])
- add(tmp, charsmax(tmp), rowTmp)
- add(motd, charsmax(motd), tmp)
- }
- }
- show_motd(id, motd, "Top Knife Leaderboard")
- }
- // -------------------------------------------------------------------------
- // Admin: give cash to a player
- public CmdGiveCash(id, level, cid) {
- if(!cmd_access(id, level, cid, 3)) return PLUGIN_HANDLED
- new argName[32], argAmount[16]
- read_argv(1, argName, charsmax(argName))
- read_argv(2, argAmount, charsmax(argAmount))
- new amount = str_to_num(argAmount)
- if(amount <= 0) {
- console_print(id, "[KnifeShop] Usage: amx_givecash <player> <amount>")
- return PLUGIN_HANDLED
- }
- new target = cmd_target(id, argName, CMDTARGET_ALLOW_SELF)
- if(!target) return PLUGIN_HANDLED
- g_iPlayerCash[target] += amount
- SavePlayerData(target)
- new targetName[32], adminName[32]
- get_user_name(target, targetName, charsmax(targetName))
- get_user_name(id, adminName, charsmax(adminName))
- // Notify target
- client_print_color(target, print_team_default, "^4[Knife] ^1Admin ^3%s ^1gave you ^3$%d^1! Total: ^3$%d",
- adminName, amount, g_iPlayerCash[target])
- // Notify admin
- console_print(id, "[KnifeShop] Gave $%d to %s. New total: $%d", amount, targetName, g_iPlayerCash[target])
- // Server announcement
- client_print_color(0, print_team_default, "^4[Knife] ^3%s ^1received ^3$%d ^1cash from admin!",
- targetName, amount)
- return PLUGIN_HANDLED
- }
- // Admin: set player level
- public CmdGiveLevel(id, level, cid) {
- if(!cmd_access(id, level, cid, 3)) return PLUGIN_HANDLED
- new argName[32], argLevel[8]
- read_argv(1, argName, charsmax(argName))
- read_argv(2, argLevel, charsmax(argLevel))
- new newLevel = str_to_num(argLevel)
- if(newLevel <= 0) {
- console_print(id, "[KnifeShop] Usage: amx_givelevel <player> <level>")
- return PLUGIN_HANDLED
- }
- new target = cmd_target(id, argName, CMDTARGET_ALLOW_SELF)
- if(!target) return PLUGIN_HANDLED
- new oldLevel = g_iPlayerLevel[target]
- g_iPlayerLevel[target] = newLevel
- g_iPlayerXP[target] = 0 // reset XP bar on level change
- SavePlayerData(target)
- new targetName[32], adminName[32]
- get_user_name(target, targetName, charsmax(targetName))
- get_user_name(id, adminName, charsmax(adminName))
- // Notify target
- client_print_color(target, print_team_default, "^4[Knife] ^1Admin ^3%s ^1set your level to ^3%d",
- adminName, newLevel)
- // Notify admin
- console_print(id, "[KnifeShop] Set %s level %d -> %d", targetName, oldLevel, newLevel)
- // Server announcement
- client_print_color(0, print_team_default, "^4[Knife] ^3%s ^1was set to level ^3%d ^1by admin!",
- targetName, newLevel)
- return PLUGIN_HANDLED
- }
- // Admin command — show top leaderboard in console
- public CmdKnifeTop(id, level, cid) {
- if(!cmd_access(id, level, cid, 1)) return PLUGIN_HANDLED
- console_print(id, "--- Top Knife Leaderboard (online) ---")
- new found = 0
- // Build sorted list same as ShowTopLeaderboard
- new topIds[5], topPrices[5], count = 0
- for(new p = 1; p <= MAX_PLAYERS; p++) {
- if(!is_user_connected(p)) continue
- new knifeId = GetPlayerTopKnife(p)
- new knifePrice = g_Knives[knifeId][KNIFE_PRICE]
- if(count < 5) {
- topIds[count] = p; topPrices[count] = knifePrice; count++
- } else {
- new minIdx = 0
- for(new j = 1; j < 5; j++)
- if(topPrices[j] < topPrices[minIdx]) minIdx = j
- if(knifePrice > topPrices[minIdx]) {
- topIds[minIdx] = p; topPrices[minIdx] = knifePrice
- }
- }
- }
- for(new a = 0; a < count - 1; a++)
- for(new b = a + 1; b < count; b++)
- if(topPrices[b] > topPrices[a]) {
- new tId = topIds[a]; topIds[a] = topIds[b]; topIds[b] = tId
- new tPr = topPrices[a]; topPrices[a] = topPrices[b]; topPrices[b] = tPr
- }
- for(new i = 0; i < count; i++) {
- new p = topIds[i], name[32]
- get_user_name(p, name, charsmax(name))
- new knifeId = GetPlayerTopKnife(p)
- console_print(id, "#%d | %s | Knife: %s | Level: %d | Cash: $%d",
- i + 1, name, g_Knives[knifeId][KNIFE_NAME], g_iPlayerLevel[p], g_iPlayerCash[p])
- found++
- }
- if(!found) console_print(id, "No players online.")
- return PLUGIN_HANDLED
- }
- // Admin command — wipe all vault data and notify server
- public CmdKnifeReset(id, level, cid) {
- if(!cmd_access(id, level, cid, 1)) return PLUGIN_HANDLED
- // Reset all online players immediately
- for(new p = 1; p <= MAX_PLAYERS; p++) {
- if(!is_user_connected(p)) continue
- g_iPlayerCash[p] = 0
- g_iPlayerLevel[p] = 1
- g_iPlayerXP[p] = 0
- g_iPlayerEquippedKnife[p] = 0
- g_iPlayerOwnedKnives[p] = (1 << 0)
- SavePlayerData(p)
- client_print_color(p, print_team_default, "^4[Knife] ^1Seasonal reset! All knife data has been wiped. Start fresh!")
- }
- // Wipe the entire vault so offline players also start fresh on next connect
- nvault_prune(g_vault, 0, get_systime() + 999999999)
- new adminName[32]
- get_user_name(id, adminName, charsmax(adminName))
- log_amx("[KnifeShop] Seasonal reset performed by %s", adminName)
- console_print(id, "[KnifeShop] Seasonal reset complete. All data wiped.")
- return PLUGIN_HANDLED
- }
- // -------------------------------------------------------------------------
- stock GetPlayerTopKnife(id) {
- new top = 0
- for(new i = 0; i < KNIFE_COUNT; i++)
- if(IsKnifeOwned(id, i) && IsKnifeValid(i) && g_Knives[i][KNIFE_PRICE] > g_Knives[top][KNIFE_PRICE])
- top = i
- return top
- }
- // -------------------------------------------------------------------------
- // Natives
- public native_get_player_knife_cash(plugin_id, num_params) {
- new id = get_param(1)
- if(id < 1 || id > MAX_PLAYERS) {
- log_error(AMX_ERR_NATIVE, "Invalid player id %d", id)
- return 0
- }
- return g_iPlayerCash[id]
- }
- public native_set_player_knife_cash(plugin_id, num_params) {
- new id = get_param(1)
- new cash = get_param(2)
- if(id < 1 || id > MAX_PLAYERS) {
- log_error(AMX_ERR_NATIVE, "Invalid player id %d", id)
- return 0
- }
- g_iPlayerCash[id] = cash
- SavePlayerData(id)
- return 1
- }
- public native_get_player_knife_level(plugin_id, num_params) {
- new id = get_param(1)
- if(id < 1 || id > MAX_PLAYERS) {
- log_error(AMX_ERR_NATIVE, "Invalid player id %d", id)
- return 0
- }
- return g_iPlayerLevel[id]
- }
- public native_set_player_knife_level(plugin_id, num_params) {
- new id = get_param(1)
- new level = get_param(2)
- if(id < 1 || id > MAX_PLAYERS) {
- log_error(AMX_ERR_NATIVE, "Invalid player id %d", id)
- return 0
- }
- g_iPlayerLevel[id] = level
- SavePlayerData(id)
- return 1
- }
Comments
-
- מי שעוקב אחריי המוד רק בתהליכי בנייה כי יש בחור מתנשא
- infender חושב שהוא מתכנת על
- build shop hardcoded 1.8.3 so lets copy and paste the SAME SHIT, OFC NOT 100% SAME only half works because not have time
Add Comment
Please, Sign In to add comment