Implement WeaponHandler class to streamline weapon and knife selection logic in index.php, enhancing maintainability and clarity. Refactor weapon update handling to utilize the new class, improving organization and reducing code duplication. Update CSS for improved button styles and layout consistency.

This commit is contained in:
Bram Suurd
2025-06-30 00:56:18 +02:00
parent cc5da9eabb
commit 0d7077063f
4 changed files with 930 additions and 946 deletions

View File

@@ -1,16 +1,15 @@
<?php
define('SKIN_LANGUAGE', 'skins_en');
define('DB_HOST', 'localhost');
define('DB_HOST', '10.0.0.24');
define('DB_PORT', '3306');
define('DB_NAME', '');
define('DB_USER', '');
define('DB_PASS', '');
define('DB_NAME', 'weaponskins_database');
define('DB_USER', 'root');
define('DB_PASS', 'DoOctwqOnohFSMvxLDGhGMaLGMJXjTSZBwROQeQcvFyfhkqEZHTEWMvQprOZLVco');
define('WEB_STYLE_DARK', true);
define('STEAM_API_KEY', '');
define('STEAM_DOMAIN_NAME', '');
define('STEAM_LOGOUT_PAGE', '');
define('STEAM_LOGIN_PAGE', '');
define('STEAM_API_KEY', 'D4EA0D36F688221050E06AF062B5EA48');
define('STEAM_DOMAIN_NAME', 'http://10.0.0.254');
define('STEAM_LOGOUT_PAGE', 'index.php');
define('STEAM_LOGIN_PAGE', 'index.php');

View File

@@ -0,0 +1,304 @@
<?php
require_once 'utils.php';
require_once 'database.php';
class WeaponHandler
{
private $db;
private $steamid;
public function __construct($steamid)
{
$this->db = new DataBase();
$this->steamid = $steamid;
}
public function handleWeaponUpdate($postData): bool
{
if (!isset($postData['forma'])) {
return false;
}
$formaParts = explode("-", $postData['forma']);
if ($formaParts[0] === "knife") {
return $this->handleKnifeSelection($formaParts[1]);
} else {
return $this->handleWeaponSkin($formaParts, $postData);
}
}
private function handleKnifeSelection($knifeId): bool
{
$knifes = UtilsClass::getKnifeTypes();
if (!isset($knifes[$knifeId])) {
return false;
}
$knifeData = $knifes[$knifeId];
// Clear existing knife data
$this->clearKnifeData();
// Set new knife selection (insert for both teams separately)
$this->db->query(
"INSERT INTO `wp_player_knife` (`steamid`, `knife`, `weapon_team`) VALUES (:steamid, :knife, 2)",
["steamid" => $this->steamid, "knife" => $knifeData['weapon_name']]
);
$this->db->query(
"INSERT INTO `wp_player_knife` (`steamid`, `knife`, `weapon_team`) VALUES (:steamid, :knife, 3)",
["steamid" => $this->steamid, "knife" => $knifeData['weapon_name']]
);
return true;
}
private function handleWeaponSkin($formaParts, $postData): bool
{
$defindex = $formaParts[0];
$paintId = $formaParts[1];
$skins = UtilsClass::skinsFromJson();
if (!isset($skins[$defindex][$paintId]) ||
!isset($postData['wear']) ||
!isset($postData['seed'])) {
return false;
}
$wear = $this->validateWear($postData['wear']);
$seed = $this->validateSeed($postData['seed']);
if ($wear === false || $seed === false) {
return false;
}
// Handle knife skins
if (UtilsClass::isKnifeDefindex($defindex)) {
$this->handleKnifeSkin($defindex, $paintId, $wear, $seed);
} else {
$this->handleRegularWeaponSkin($defindex, $paintId, $wear, $seed);
}
return true;
}
private function handleKnifeSkin($defindex, $paintId, $wear, $seed): void
{
$knifeMapping = UtilsClass::getKnifeMapping();
// Clear existing knife data
$this->clearKnifeData();
// Clear other knife skins
$knifeDefindexes = UtilsClass::getKnifeDefindexes();
foreach ($knifeDefindexes as $knifeDefindex) {
if ($knifeDefindex != $defindex) {
$this->db->query(
"DELETE FROM `wp_player_skins` WHERE `steamid` = :steamid AND `weapon_defindex` = :weapon_defindex",
["steamid" => $this->steamid, "weapon_defindex" => $knifeDefindex]
);
}
}
// Set knife type in wp_player_knife table
if (isset($knifeMapping[$defindex])) {
$this->db->query(
"INSERT INTO `wp_player_knife` (`steamid`, `knife`, `weapon_team`) VALUES (:steamid, :knife, 2)",
["steamid" => $this->steamid, "knife" => $knifeMapping[$defindex]]
);
$this->db->query(
"INSERT INTO `wp_player_knife` (`steamid`, `knife`, `weapon_team`) VALUES (:steamid, :knife, 3)",
["steamid" => $this->steamid, "knife" => $knifeMapping[$defindex]]
);
}
// Set knife skin
$this->upsertWeaponSkin($defindex, $paintId, $wear, $seed);
}
private function handleRegularWeaponSkin($defindex, $paintId, $wear, $seed): void
{
$this->upsertWeaponSkin($defindex, $paintId, $wear, $seed);
}
private function upsertWeaponSkin($defindex, $paintId, $wear, $seed): void
{
$selectedSkins = $this->getSelectedSkins();
if (array_key_exists($defindex, $selectedSkins)) {
// Update existing
$this->db->query(
"UPDATE wp_player_skins SET weapon_paint_id = :weapon_paint_id, weapon_wear = :weapon_wear, weapon_seed = :weapon_seed WHERE steamid = :steamid AND weapon_defindex = :weapon_defindex",
[
"weapon_paint_id" => $paintId,
"weapon_wear" => $wear,
"weapon_seed" => $seed,
"steamid" => $this->steamid,
"weapon_defindex" => $defindex
]
);
} else {
// Insert new for both teams
$this->db->query(
"INSERT INTO wp_player_skins (`steamid`, `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`, `weapon_team`) VALUES (:steamid, :weapon_defindex, :weapon_paint_id, :weapon_wear, :weapon_seed, 2)",
[
"steamid" => $this->steamid,
"weapon_defindex" => $defindex,
"weapon_paint_id" => $paintId,
"weapon_wear" => $wear,
"weapon_seed" => $seed
]
);
$this->db->query(
"INSERT INTO wp_player_skins (`steamid`, `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`, `weapon_team`) VALUES (:steamid, :weapon_defindex, :weapon_paint_id, :weapon_wear, :weapon_seed, 3)",
[
"steamid" => $this->steamid,
"weapon_defindex" => $defindex,
"weapon_paint_id" => $paintId,
"weapon_wear" => $wear,
"weapon_seed" => $seed
]
);
}
}
private function clearKnifeData(): void
{
$knifeDefindexes = UtilsClass::getKnifeDefindexes();
// Clear knife skins
foreach ($knifeDefindexes as $knifeDefindex) {
$this->db->query(
"DELETE FROM `wp_player_skins` WHERE `steamid` = :steamid AND `weapon_defindex` = :weapon_defindex",
["steamid" => $this->steamid, "weapon_defindex" => $knifeDefindex]
);
}
// Clear basic knife selection
$this->db->query(
"DELETE FROM `wp_player_knife` WHERE `steamid` = :steamid",
["steamid" => $this->steamid]
);
}
private function validateWear($wear)
{
$wear = floatval($wear);
return ($wear >= 0.00 && $wear <= 1.00) ? $wear : false;
}
private function validateSeed($seed)
{
$seed = intval($seed);
return ($seed >= 0) ? $seed : false;
}
public function getSelectedSkins(): array
{
$query = $this->db->select(
"SELECT `weapon_defindex`, MAX(`weapon_paint_id`) AS `weapon_paint_id`, MAX(`weapon_wear`) AS `weapon_wear`, MAX(`weapon_seed`) AS `weapon_seed`
FROM `wp_player_skins`
WHERE `steamid` = :steamid
GROUP BY `weapon_defindex`, `steamid`",
["steamid" => $this->steamid]
);
return UtilsClass::getSelectedSkins($query ?: []);
}
public function getSelectedKnife(): array
{
return $this->db->select(
"SELECT * FROM `wp_player_knife` WHERE `steamid` = :steamid LIMIT 1",
["steamid" => $this->steamid]
) ?: [];
}
public function getLoadoutData(): array
{
$weapons = UtilsClass::getWeaponsFromArray();
$knifes = UtilsClass::getKnifeTypes();
$selectedSkins = $this->getSelectedSkins();
$selectedKnife = $this->getSelectedKnife();
return [
'weapons' => $weapons,
'knifes' => $knifes,
'selectedSkins' => $selectedSkins,
'selectedKnife' => $selectedKnife,
'displayKnife' => $this->getDisplayKnife($selectedSkins, $selectedKnife, $knifes)
];
}
private function getDisplayKnife($selectedSkins, $selectedKnife, $knifes): array
{
$skins = UtilsClass::skinsFromJson();
// Check for knife skin first
foreach ($selectedSkins as $defindex => $selectedSkin) {
if (UtilsClass::isKnifeDefindex($defindex) && isset($skins[$defindex][$selectedSkin['weapon_paint_id']])) {
return [
'data' => $skins[$defindex][$selectedSkin['weapon_paint_id']],
'source' => 'skin'
];
}
}
// Check for basic knife selection
if (!empty($selectedKnife)) {
foreach ($knifes as $knife) {
if ($selectedKnife[0]['knife'] === $knife['weapon_name']) {
return [
'data' => $knife,
'source' => 'basic'
];
}
}
}
// Default knife
return [
'data' => $knifes[0] ?? null,
'source' => 'default'
];
}
public function getOrganizedWeapons(): array
{
$weapons = UtilsClass::getWeaponsFromArray();
$knifes = UtilsClass::getKnifeTypes();
$categories = UtilsClass::getWeaponCategories();
$organized = [
'Knives' => [],
'Gloves' => []
];
// Add weapon categories
foreach ($categories as $categoryName => $weaponIds) {
$organized[$categoryName] = [];
foreach ($weaponIds as $weaponId) {
if (isset($weapons[$weaponId])) {
$organized[$categoryName][$weaponId] = $weapons[$weaponId];
}
}
}
// Add knives (exclude default)
foreach ($knifes as $knifeId => $knife) {
if ($knifeId !== 0) {
$organized['Knives'][$knifeId] = $knife;
}
}
// Remove empty categories
return array_filter($organized, function($category) {
return !empty($category);
});
}
}

View File

@@ -3,120 +3,25 @@ require_once 'class/config.php';
require_once 'class/database.php';
require_once 'steamauth/steamauth.php';
require_once 'class/utils.php';
require_once 'class/weapon_handler.php';
$db = new DataBase();
if (isset($_SESSION['steamid'])) {
$steamid = $_SESSION['steamid'];
// Fetch Steam user information
require_once 'steamauth/userInfo.php';
$weapons = UtilsClass::getWeaponsFromArray();
$skins = UtilsClass::skinsFromJson();
$querySelected = $db->select("
SELECT `weapon_defindex`, MAX(`weapon_paint_id`) AS `weapon_paint_id`, MAX(`weapon_wear`) AS `weapon_wear`, MAX(`weapon_seed`) AS `weapon_seed`
FROM `wp_player_skins`
WHERE `steamid` = :steamid
GROUP BY `weapon_defindex`, `steamid`
", ["steamid" => $steamid]);
$selectedSkins = UtilsClass::getSelectedSkins($querySelected);
$selectedKnife = $db->select("SELECT * FROM `wp_player_knife` WHERE `wp_player_knife`.`steamid` = :steamid LIMIT 1", ["steamid" => $steamid]);
$knifes = UtilsClass::getKnifeTypes();
if (isset($_POST['forma'])) {
$ex = explode("-", $_POST['forma']);
if ($ex[0] == "knife") {
// Handle knife selection - use the knife key directly
if (isset($knifes[$ex[1]])) {
$knifeData = $knifes[$ex[1]];
// Clear any existing knife skins first
$db->query("DELETE FROM `wp_player_skins` WHERE `steamid` = :steamid AND `weapon_defindex` IN (500, 503, 505, 506, 507, 508, 509, 512, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 525, 526)", ["steamid" => $steamid]);
// Clear any existing basic knife selection first
$db->query("DELETE FROM `wp_player_knife` WHERE `steamid` = :steamid", ["steamid" => $steamid]);
// Set the new basic knife selection
$db->query("INSERT INTO `wp_player_knife` (`steamid`, `knife`, `weapon_team`) VALUES(:steamid, :knife, 2)", ["steamid" => $steamid, "knife" => $knifeData['weapon_name']]);
$db->query("INSERT INTO `wp_player_knife` (`steamid`, `knife`, `weapon_team`) VALUES(:steamid, :knife, 3)", ["steamid" => $steamid, "knife" => $knifeData['weapon_name']]);
}
} else {
if (array_key_exists($ex[1], $skins[$ex[0]]) && isset($_POST['wear']) && $_POST['wear'] >= 0.00 && $_POST['wear'] <= 1.00 && isset($_POST['seed'])) {
$wear = floatval($_POST['wear']);
$seed = intval($_POST['seed']);
// If this is a knife skin, automatically equip the corresponding knife type
if (in_array($ex[0], [500, 503, 505, 506, 507, 508, 509, 512, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 525, 526])) {
// Map defindex to knife weapon_name
$knifeMapping = [
500 => 'weapon_bayonet',
503 => 'weapon_knife_css',
505 => 'weapon_knife_flip',
506 => 'weapon_knife_gut',
507 => 'weapon_knife_karambit',
508 => 'weapon_knife_m9_bayonet',
509 => 'weapon_knife_tactical',
512 => 'weapon_knife_falchion',
514 => 'weapon_knife_survival_bowie',
515 => 'weapon_knife_butterfly',
516 => 'weapon_knife_push',
517 => 'weapon_knife_cord',
518 => 'weapon_knife_canis',
519 => 'weapon_knife_ursus',
520 => 'weapon_knife_gypsy_jackknife',
521 => 'weapon_knife_outdoor',
522 => 'weapon_knife_stiletto',
523 => 'weapon_knife_widowmaker',
525 => 'weapon_knife_skeleton',
526 => 'weapon_knife_css'
];
// Clear any existing basic knife selection
$db->query("DELETE FROM `wp_player_knife` WHERE `steamid` = :steamid", ["steamid" => $steamid]);
// Clear ALL other knife skins (to handle switching between knife types)
$db->query("DELETE FROM `wp_player_skins` WHERE `steamid` = :steamid AND `weapon_defindex` IN (500, 503, 505, 506, 507, 508, 509, 512, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 525, 526) AND `weapon_defindex` != :current_defindex", ["steamid" => $steamid, "current_defindex" => $ex[0]]);
// Set the corresponding knife type in wp_player_knife table
if (isset($knifeMapping[$ex[0]])) {
$knifeWeaponName = $knifeMapping[$ex[0]];
$db->query("INSERT INTO `wp_player_knife` (`steamid`, `knife`, `weapon_team`) VALUES(:steamid, :knife, 2)", ["steamid" => $steamid, "knife" => $knifeWeaponName]);
$db->query("INSERT INTO `wp_player_knife` (`steamid`, `knife`, `weapon_team`) VALUES(:steamid, :knife, 3)", ["steamid" => $steamid, "knife" => $knifeWeaponName]);
}
}
if (array_key_exists($ex[0], $selectedSkins)) {
$db->query("UPDATE wp_player_skins SET weapon_paint_id = :weapon_paint_id, weapon_wear = :weapon_wear, weapon_seed = :weapon_seed WHERE steamid = :steamid AND weapon_defindex = :weapon_defindex", ["steamid" => $steamid, "weapon_defindex" => $ex[0], "weapon_paint_id" => $ex[1], "weapon_wear" => $wear, "weapon_seed" => $seed]);
} else {
$db->query("INSERT INTO wp_player_skins (`steamid`, `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`, `weapon_team`) VALUES (:steamid, :weapon_defindex, :weapon_paint_id, :weapon_wear, :weapon_seed, 2)", ["steamid" => $steamid, "weapon_defindex" => $ex[0], "weapon_paint_id" => $ex[1], "weapon_wear" => $wear, "weapon_seed" => $seed]);
$db->query("INSERT INTO wp_player_skins (`steamid`, `weapon_defindex`, `weapon_paint_id`, `weapon_wear`, `weapon_seed`, `weapon_team`) VALUES (:steamid, :weapon_defindex, :weapon_paint_id, :weapon_wear, :weapon_seed, 3)", ["steamid" => $steamid, "weapon_defindex" => $ex[0], "weapon_paint_id" => $ex[1], "weapon_wear" => $wear, "weapon_seed" => $seed]);
}
}
}
// Handle weapon updates
if (isset($_SESSION['steamid']) && isset($_POST['forma'])) {
$weaponHandler = new WeaponHandler($_SESSION['steamid']);
if ($weaponHandler->handleWeaponUpdate($_POST)) {
header("Location: {$_SERVER['PHP_SELF']}");
exit;
}
}
// Organize weapons by categories
$weaponCategories = [
'Knives' => [],
'Gloves' => [],
'Rifles' => [7, 8, 10, 13, 16, 60, 39, 40, 38],
'Pistols' => [1, 2, 3, 4, 30, 32, 36, 61, 63, 64],
'SMGs' => [17, 19, 24, 26, 33, 34],
'Shotguns' => [25, 27, 29, 35],
'Snipers' => [9, 11, 38],
'Machine Guns' => [14, 28],
'Grenades' => [43, 44, 45, 46, 47, 48]
];
// Add knives to categories
foreach ($knifes as $knifeKey => $knife) {
if ($knifeKey != 0) {
$weaponCategories['Knives'][$knifeKey] = $knife;
}
}
// Get loadout data for logged in users
$loadoutData = null;
$weaponCategories = [];
if (isset($_SESSION['steamid'])) {
require_once 'steamauth/userInfo.php';
$weaponHandler = new WeaponHandler($_SESSION['steamid']);
$loadoutData = $weaponHandler->getLoadoutData();
$weaponCategories = $weaponHandler->getOrganizedWeapons();
}
?>
@@ -148,7 +53,7 @@ if (isset($_SESSION['steamid'])) {
<h1>CS2 Weapon Paints</h1>
</div>
<div class="header-right">
<span class="user-info">Welcome, <?php echo $_SESSION['steam_personaname'] ?? 'Player'; ?></span>
<span class="user-info">Welcome, <?php echo htmlspecialchars($_SESSION['steam_personaname'] ?? 'Player'); ?></span>
<a href="<?php echo $_SERVER['PHP_SELF']; ?>?logout" class="logout-btn">Logout</a>
</div>
</header>
@@ -164,66 +69,39 @@ if (isset($_SESSION['steamid'])) {
</div>
<nav class="sidebar-nav">
<?php foreach ($weaponCategories as $categoryName => $categoryWeapons): ?>
<?php
// Count weapons in this category
$weaponCount = 0;
if ($categoryName == 'Knives') {
$weaponCount = count($knifes) - 1; // Exclude default knife
} else {
foreach ($categoryWeapons as $weaponDefindex) {
if (isset($weapons[$weaponDefindex])) {
$weaponCount++;
}
}
}
// Skip categories with 0 items
if ($weaponCount == 0) {
continue;
}
?>
<?php if (empty($categoryWeapons)) continue; ?>
<div class="nav-category">
<div class="nav-item category-header" data-category="<?php echo strtolower($categoryName); ?>" onclick="toggleCategory('<?php echo strtolower($categoryName); ?>')">
<span class="nav-icon">
<?php echo $categoryName == 'Knives' ? '🗡️' : ($categoryName == 'Gloves' ? '🧤' : ($categoryName == 'Rifles' ? '🔫' : ($categoryName == 'Pistols' ? '🔫' : ($categoryName == 'SMGs' ? '🔫' : ($categoryName == 'Shotguns' ? '🔫' : ($categoryName == 'Snipers' ? '🎯' : ($categoryName == 'Machine Guns' ? '⚡' : '💣'))))))); ?>
</span>
<span class="nav-icon"><?php echo getCategoryIcon($categoryName); ?></span>
<div class="nav-content">
<span class="nav-text"><?php echo $categoryName; ?></span>
<span class="nav-count"><?php echo $weaponCount; ?></span>
<span class="nav-count"><?php echo count($categoryWeapons); ?></span>
</div>
<span class="nav-arrow">▶</span>
</div>
<div class="weapon-list" data-category="<?php echo strtolower($categoryName); ?>">
<?php if ($categoryName == 'Knives'): ?>
<?php foreach ($knifes as $knifeKey => $knife): ?>
<?php if ($knifeKey != 0): ?>
<div class="weapon-container">
<div class="weapon-item" onclick="toggleKnifeSkins(<?php echo $knifeKey; ?>)">
<img src="<?php echo $knife['image_url']; ?>" alt="<?php echo $knife['paint_name']; ?>" class="weapon-icon">
<span class="weapon-name"><?php echo $knife['paint_name']; ?></span>
<span class="weapon-arrow">▶</span>
</div>
<div class="weapon-skins-grid" data-weapon="knife-<?php echo $knifeKey; ?>">
<!-- Knife skins will be populated by JavaScript -->
</div>
<?php if ($categoryName === 'Knives'): ?>
<?php foreach ($categoryWeapons as $knifeId => $knife): ?>
<div class="weapon-container">
<div class="weapon-item" onclick="toggleKnifeSkins(<?php echo $knifeId; ?>)">
<img src="<?php echo htmlspecialchars($knife['image_url']); ?>" alt="<?php echo htmlspecialchars($knife['paint_name']); ?>" class="weapon-icon">
<span class="weapon-name"><?php echo htmlspecialchars($knife['paint_name']); ?></span>
<span class="weapon-arrow">▶</span>
</div>
<?php endif; ?>
<div class="weapon-skins-grid" data-weapon="knife-<?php echo $knifeId; ?>"></div>
</div>
<?php endforeach; ?>
<?php else: ?>
<?php foreach ($categoryWeapons as $weaponDefindex): ?>
<?php if (isset($weapons[$weaponDefindex])): ?>
<div class="weapon-container">
<div class="weapon-item" onclick="toggleWeaponSkins(<?php echo $weaponDefindex; ?>)">
<img src="<?php echo $weapons[$weaponDefindex]['image_url']; ?>" alt="<?php echo $weapons[$weaponDefindex]['paint_name']; ?>" class="weapon-icon">
<span class="weapon-name"><?php echo ucfirst(strtolower(str_replace('weapon_', '', $weapons[$weaponDefindex]['weapon_name']))); ?></span>
<span class="weapon-arrow">▶</span>
</div>
<div class="weapon-skins-grid" data-weapon="<?php echo $weaponDefindex; ?>">
<!-- Skins will be populated by JavaScript -->
</div>
<?php foreach ($categoryWeapons as $weaponId => $weapon): ?>
<div class="weapon-container">
<div class="weapon-item" onclick="toggleWeaponSkins(<?php echo $weaponId; ?>)">
<img src="<?php echo htmlspecialchars($weapon['image_url']); ?>" alt="<?php echo htmlspecialchars($weapon['paint_name']); ?>" class="weapon-icon">
<span class="weapon-name"><?php echo htmlspecialchars(ucfirst(strtolower(str_replace('weapon_', '', $weapon['weapon_name'])))); ?></span>
<span class="weapon-arrow">▶</span>
</div>
<?php endif; ?>
<div class="weapon-skins-grid" data-weapon="<?php echo $weaponId; ?>"></div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
@@ -240,121 +118,62 @@ if (isset($_SESSION['steamid'])) {
</div>
<div class="loadout-grid">
<!-- Knife - Show the currently equipped knife (either basic knife or knife skin) -->
<?php
$displayKnife = null;
$displayKnifeSkin = null;
$knifeSource = '';
// Debug: Show what's in selectedKnife
// echo "<!-- Debug: selectedKnife = " . print_r($selectedKnife, true) . " -->";
// Check if there's a knife skin equipped (from selectedSkins for knife defindexes)
foreach ($selectedSkins as $defindex => $selectedSkin) {
if (in_array($defindex, [500, 503, 505, 506, 507, 508, 509, 512, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 525, 526])) {
if (isset($skins[$defindex][$selectedSkin['weapon_paint_id']])) {
$displayKnifeSkin = $skins[$defindex][$selectedSkin['weapon_paint_id']];
$knifeSource = 'skin';
break; // Use the first knife skin found
}
}
}
// If no knife skin, check for basic knife selection
if (!$displayKnifeSkin && $selectedKnife != null && !empty($selectedKnife)) {
foreach ($knifes as $knifeKey => $knife) {
if ($selectedKnife[0]['knife'] == $knife['weapon_name']) {
$displayKnife = $knife;
$knifeSource = 'basic';
break;
}
}
}
// If no knife selected at all, show default knife
if (!$displayKnifeSkin && !$displayKnife && isset($knifes[0])) {
$displayKnife = $knifes[0]; // Default knife
$knifeSource = 'default';
}
<?php
$displayKnife = $loadoutData['displayKnife'];
$knifeEquipped = ($displayKnife['source'] === 'skin') ? 'true' : 'false';
?>
<!-- Always show a knife (either selected or default) -->
<?php if ($displayKnifeSkin || $displayKnife): ?>
<div class="loadout-item" data-weapon-type="knife" data-equipped="<?php echo $knifeEquipped; ?>">
<div class="item-image-container">
<img src="<?php echo htmlspecialchars($displayKnife['data']['image_url']); ?>"
alt="<?php echo htmlspecialchars($displayKnife['data']['paint_name']); ?>"
class="item-image">
<div class="item-overlay">
<button class="customize-btn" onclick="openCustomizeModal('knife', 0)">Customize</button>
</div>
</div>
<div class="item-info">
<div class="item-category">Knife</div>
<div class="item-name"><?php echo htmlspecialchars($displayKnife['data']['paint_name']); ?></div>
</div>
</div>
<?php foreach ($loadoutData['weapons'] as $defindex => $weapon): ?>
<?php if (UtilsClass::isKnifeWeapon($weapon)) continue; ?>
<?php
// Set equipped status for knife - only true if it's a custom skin
$knifeEquipped = ($knifeSource == 'skin') ? 'true' : 'false';
$hasCustomSkin = array_key_exists($defindex, $loadoutData['selectedSkins']);
$isEquipped = $hasCustomSkin ? 'true' : 'false';
?>
<div class="loadout-item" data-weapon-type="knife" data-equipped="<?php echo $knifeEquipped; ?>">
<div class="loadout-item" data-weapon-id="<?php echo $defindex; ?>" data-equipped="<?php echo $isEquipped; ?>">
<div class="item-image-container">
<?php if ($knifeSource == 'skin'): ?>
<img src="<?php echo $displayKnifeSkin['image_url']; ?>" alt="<?php echo $displayKnifeSkin['paint_name']; ?>" class="item-image">
<?php if ($hasCustomSkin): ?>
<?php
$skins = UtilsClass::skinsFromJson();
$selectedSkin = $skins[$defindex][$loadoutData['selectedSkins'][$defindex]['weapon_paint_id']];
?>
<img src="<?php echo htmlspecialchars($selectedSkin['image_url']); ?>"
alt="<?php echo htmlspecialchars($selectedSkin['paint_name']); ?>"
class="item-image">
<div class="item-overlay">
<button class="customize-btn" onclick="openCustomizeModal('weapon', <?php echo $defindex; ?>)">Customize</button>
</div>
<?php else: ?>
<img src="<?php echo $displayKnife['image_url']; ?>" alt="<?php echo $displayKnife['paint_name']; ?>" class="item-image">
<img src="<?php echo htmlspecialchars($weapon['image_url']); ?>"
alt="<?php echo htmlspecialchars($weapon['paint_name']); ?>"
class="item-image">
<?php endif; ?>
<div class="item-overlay">
<button class="customize-btn" onclick="openCustomizeModal('knife', 0)">Customize</button>
</div>
</div>
<div class="item-info">
<div class="item-category">Knife</div>
<div class="item-category"><?php echo htmlspecialchars(ucfirst(strtolower(str_replace('weapon_', '', $weapon['weapon_name'])))); ?></div>
<div class="item-name">
<?php if ($knifeSource == 'skin'): ?>
<?php echo $displayKnifeSkin['paint_name']; ?>
<?php if ($hasCustomSkin): ?>
<?php echo htmlspecialchars($selectedSkin['paint_name']); ?>
<?php else: ?>
<?php echo $displayKnife['paint_name']; ?>
<?php echo htmlspecialchars($weapon['paint_name']); ?>
<?php endif; ?>
</div>
</div>
</div>
<?php endif; ?>
<!-- Show all weapons (exclude knives) - either with custom skin or default -->
<?php foreach ($weapons as $defindex => $weapon): ?>
<?php
// Skip ALL knives - comprehensive check
$isKnifeWeapon = in_array($defindex, [500, 503, 505, 506, 507, 508, 509, 512, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 525, 526]);
$isDefaultKnife = ($weapon['weapon_name'] == 'weapon_knife');
$isKnifeVariant = (strpos($weapon['weapon_name'], 'knife') !== false);
$isKnifePaint = (strpos($weapon['paint_name'], '★') !== false); // Knife skins have ★ in name
// Skip ANY knife-related weapon
if ($isKnifeWeapon || $isDefaultKnife || $isKnifeVariant || $isKnifePaint) {
continue;
}
?>
<?php
$hasCustomSkin = array_key_exists($defindex, $selectedSkins);
$isEquipped = $hasCustomSkin ? 'true' : 'false';
?>
<div class="loadout-item" data-weapon-id="<?php echo $defindex; ?>" data-equipped="<?php echo $isEquipped; ?>">
<div class="item-image-container">
<?php if ($hasCustomSkin): ?>
<!-- Show custom skin -->
<img src="<?php echo $skins[$defindex][$selectedSkins[$defindex]['weapon_paint_id']]['image_url']; ?>"
alt="<?php echo $skins[$defindex][$selectedSkins[$defindex]['weapon_paint_id']]['paint_name']; ?>"
class="item-image">
<div class="item-overlay">
<button class="customize-btn" onclick="openCustomizeModal('weapon', <?php echo $defindex; ?>)">Customize</button>
</div>
<?php else: ?>
<!-- Show default weapon -->
<img src="<?php echo $weapon['image_url']; ?>"
alt="<?php echo $weapon['paint_name']; ?>"
class="item-image">
<!-- No overlay button for default weapons -->
<?php endif; ?>
</div>
<div class="item-info">
<div class="item-category"><?php echo ucfirst(strtolower(str_replace('weapon_', '', $weapon['weapon_name']))); ?></div>
<div class="item-name">
<?php if ($hasCustomSkin): ?>
<?php echo $skins[$defindex][$selectedSkins[$defindex]['weapon_paint_id']]['paint_name']; ?>
<?php else: ?>
<?php echo $weapon['paint_name']; ?>
<?php endif; ?>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
</main>
@@ -411,335 +230,311 @@ if (isset($_SESSION['steamid'])) {
</div>
<script>
// Store weapon and skin data for JavaScript
const weaponsData = <?php echo json_encode($weapons); ?>;
const skinsData = <?php echo json_encode($skins); ?>;
const selectedSkinsData = <?php echo json_encode($selectedSkins); ?>;
const knivesData = <?php echo json_encode($knifes); ?>;
const weaponCategories = <?php echo json_encode($weaponCategories); ?>;
// Optimized JavaScript with embedded data (restored functionality)
const weaponsData = <?php echo json_encode($loadoutData['weapons']); ?>;
const skinsData = <?php echo json_encode(UtilsClass::skinsFromJson()); ?>;
const selectedSkinsData = <?php echo json_encode($loadoutData['selectedSkins']); ?>;
const knivesData = <?php echo json_encode($loadoutData['knifes']); ?>;
const WeaponApp = {
init() {
this.bindEvents();
},
function toggleCategory(category) {
const categoryHeader = document.querySelector(`.category-header[data-category="${category}"]`);
const weaponList = document.querySelector(`.weapon-list[data-category="${category}"]`);
const arrow = categoryHeader.querySelector('.nav-arrow');
// Toggle the weapon list
if (weaponList.classList.contains('expanded')) {
// Collapse
weaponList.classList.remove('expanded');
arrow.textContent = '▶';
categoryHeader.classList.remove('active');
} else {
// Collapse all other categories first
document.querySelectorAll('.weapon-list').forEach(list => {
list.classList.remove('expanded');
});
document.querySelectorAll('.category-header').forEach(header => {
header.classList.remove('active');
header.querySelector('.nav-arrow').textContent = '▶';
});
// Expand this category
weaponList.classList.add('expanded');
arrow.textContent = '▼';
categoryHeader.classList.add('active');
}
}
function equipKnife(knifeId) {
// Create form and submit
const form = document.createElement('form');
form.method = 'POST';
form.style.display = 'none';
const formaInput = document.createElement('input');
formaInput.name = 'forma';
formaInput.value = `knife-${knifeId}`;
form.appendChild(formaInput);
document.body.appendChild(form);
form.submit();
}
function searchWeapons(query) {
if (!query.trim()) {
// Reset search - show all categories and hide all weapon lists
document.querySelectorAll('.nav-category').forEach(category => {
category.style.display = 'block';
});
document.querySelectorAll('.weapon-list').forEach(list => {
list.classList.remove('expanded');
});
document.querySelectorAll('.category-header').forEach(header => {
header.classList.remove('active');
header.querySelector('.nav-arrow').textContent = '▶';
});
return;
}
const searchTerm = query.toLowerCase();
// Search through categories and weapons
document.querySelectorAll('.nav-category').forEach(category => {
const categoryName = category.querySelector('.nav-text').textContent.toLowerCase();
const weaponItems = category.querySelectorAll('.weapon-item');
let categoryMatches = categoryName.includes(searchTerm);
let hasMatchingWeapons = false;
// Check if any weapons in this category match
weaponItems.forEach(weaponItem => {
const weaponName = weaponItem.querySelector('.weapon-name').textContent.toLowerCase();
const matches = weaponName.includes(searchTerm);
if (matches) {
hasMatchingWeapons = true;
weaponItem.style.display = 'flex';
} else {
weaponItem.style.display = 'none';
bindEvents() {
document.addEventListener('click', (e) => {
if (e.target.id === 'customizeModal') {
this.closeCustomizeModal();
}
});
},
// Show/hide category based on matches
if (categoryMatches || hasMatchingWeapons) {
category.style.display = 'block';
if (hasMatchingWeapons) {
// Expand the category to show matching weapons
toggleCategory(category) {
const categoryHeader = document.querySelector(`.category-header[data-category="${category}"]`);
const weaponList = document.querySelector(`.weapon-list[data-category="${category}"]`);
const arrow = categoryHeader.querySelector('.nav-arrow');
if (weaponList.classList.contains('expanded')) {
weaponList.classList.remove('expanded');
arrow.textContent = '▶';
categoryHeader.classList.remove('active');
} else {
// Collapse other categories
document.querySelectorAll('.weapon-list').forEach(list => list.classList.remove('expanded'));
document.querySelectorAll('.category-header').forEach(header => {
header.classList.remove('active');
header.querySelector('.nav-arrow').textContent = '▶';
});
weaponList.classList.add('expanded');
arrow.textContent = '▼';
categoryHeader.classList.add('active');
}
},
searchWeapons(query) {
const searchTerm = query.toLowerCase().trim();
if (!searchTerm) {
document.querySelectorAll('.nav-category').forEach(category => category.style.display = 'block');
document.querySelectorAll('.weapon-list').forEach(list => list.classList.remove('expanded'));
document.querySelectorAll('.category-header').forEach(header => {
header.classList.remove('active');
header.querySelector('.nav-arrow').textContent = '▶';
});
return;
}
document.querySelectorAll('.nav-category').forEach(category => {
const categoryName = category.querySelector('.nav-text').textContent.toLowerCase();
const weaponItems = category.querySelectorAll('.weapon-item');
let hasMatches = categoryName.includes(searchTerm);
weaponItems.forEach(item => {
const weaponName = item.querySelector('.weapon-name').textContent.toLowerCase();
const matches = weaponName.includes(searchTerm);
item.style.display = matches ? 'flex' : 'none';
if (matches) hasMatches = true;
});
category.style.display = hasMatches ? 'block' : 'none';
if (hasMatches) {
const weaponList = category.querySelector('.weapon-list');
const header = category.querySelector('.category-header');
weaponList.classList.add('expanded');
header.classList.add('active');
header.querySelector('.nav-arrow').textContent = '▼';
}
} else {
category.style.display = 'none';
});
},
toggleWeaponSkins(weaponId) {
const weaponItem = event.target.closest('.weapon-item');
const skinGrid = weaponItem.parentNode.querySelector('.weapon-skins-grid');
if (!skinsData[weaponId]) return;
if (skinGrid.classList.contains('expanded')) {
skinGrid.classList.remove('expanded');
weaponItem.classList.remove('expanded');
return;
}
});
}
function toggleWeaponSkins(weaponId) {
const weaponItem = event.target.closest('.weapon-item');
const skinGrid = weaponItem.parentNode.querySelector('.weapon-skins-grid');
// Collapse others
document.querySelectorAll('.weapon-skins-grid').forEach(grid => grid.classList.remove('expanded'));
document.querySelectorAll('.weapon-item').forEach(item => item.classList.remove('expanded'));
if (!skinsData[weaponId]) return;
// Toggle the weapon item and skin grid
if (skinGrid.classList.contains('expanded')) {
// Collapse
skinGrid.classList.remove('expanded');
weaponItem.classList.remove('expanded');
} else {
// Collapse all other weapon skin grids first
document.querySelectorAll('.weapon-skins-grid').forEach(grid => {
grid.classList.remove('expanded');
});
document.querySelectorAll('.weapon-item').forEach(item => {
item.classList.remove('expanded');
});
// Expand this weapon's skin grid
populateWeaponSkins(weaponId, skinGrid);
this.populateWeaponSkins(weaponId, skinGrid);
skinGrid.classList.add('expanded');
weaponItem.classList.add('expanded');
}
}
},
function populateWeaponSkins(weaponId, skinGrid) {
// Create skins container
const skinsContainer = document.createElement('div');
skinsContainer.className = 'skins-container';
// Clear previous content
skinGrid.innerHTML = '';
// Populate skins in 3-column grid
Object.entries(skinsData[weaponId]).forEach(([paintId, skin]) => {
const skinOption = document.createElement('div');
skinOption.className = 'skin-option';
// Check if this skin is currently equipped
if (selectedSkinsData[weaponId] && selectedSkinsData[weaponId].weapon_paint_id == paintId) {
skinOption.classList.add('active');
toggleKnifeSkins(knifeType) {
const weaponItem = event.target.closest('.weapon-item');
const skinGrid = weaponItem.parentNode.querySelector('.weapon-skins-grid');
if (skinGrid.classList.contains('expanded')) {
skinGrid.classList.remove('expanded');
weaponItem.classList.remove('expanded');
return;
}
skinOption.onclick = () => equipSkin(weaponId, paintId);
skinOption.innerHTML = `
<img src="${skin.image_url}" alt="${skin.paint_name}">
<div class="skin-option-name">${skin.paint_name.replace(/.*\| /, '')}</div>
`;
skinsContainer.appendChild(skinOption);
});
skinGrid.appendChild(skinsContainer);
}
function toggleKnifeSkins(knifeType) {
const weaponItem = event.target.closest('.weapon-item');
const skinGrid = weaponItem.parentNode.querySelector('.weapon-skins-grid');
// Collapse others
document.querySelectorAll('.weapon-skins-grid').forEach(grid => grid.classList.remove('expanded'));
document.querySelectorAll('.weapon-item').forEach(item => item.classList.remove('expanded'));
// Toggle the weapon item and skin grid
if (skinGrid.classList.contains('expanded')) {
// Collapse
skinGrid.classList.remove('expanded');
weaponItem.classList.remove('expanded');
} else {
// Collapse all other weapon skin grids first
document.querySelectorAll('.weapon-skins-grid').forEach(grid => {
grid.classList.remove('expanded');
});
document.querySelectorAll('.weapon-item').forEach(item => {
item.classList.remove('expanded');
});
// Expand this knife type's skin grid
populateKnifeTypeSkins(knifeType, skinGrid);
this.populateKnifeTypeSkins(knifeType, skinGrid);
skinGrid.classList.add('expanded');
weaponItem.classList.add('expanded');
}
}
},
function populateKnifeTypeSkins(knifeType, skinGrid) {
// Create skins container
const skinsContainer = document.createElement('div');
skinsContainer.className = 'skins-container';
// Clear previous content
skinGrid.innerHTML = '';
// ALWAYS show the basic knife option first
const knife = knivesData[knifeType];
if (knife) {
const basicKnifeOption = document.createElement('div');
basicKnifeOption.className = 'skin-option';
populateWeaponSkins(weaponId, skinGrid) {
const skinsContainer = document.createElement('div');
skinsContainer.className = 'skins-container';
// Check if basic knife is currently selected (no knife skins equipped for this type)
if (!selectedSkinsData[knifeType]) {
basicKnifeOption.classList.add('active');
}
skinGrid.innerHTML = '';
basicKnifeOption.onclick = () => equipKnife(knifeType);
basicKnifeOption.innerHTML = `
<img src="${knife.image_url}" alt="${knife.paint_name}">
<div class="skin-option-name">Default</div>
`;
skinsContainer.appendChild(basicKnifeOption);
}
// Then show knife skins if available
if (skinsData[knifeType]) {
// This knife type has multiple skins
Object.entries(skinsData[knifeType]).forEach(([paintId, skin]) => {
// Skip the default skin (paint ID 0) since we already show it as "Default" option above
if (paintId == '0') {
return;
}
Object.entries(skinsData[weaponId]).forEach(([paintId, skin]) => {
const skinOption = document.createElement('div');
skinOption.className = 'skin-option';
// Check if this skin is currently equipped
if (selectedSkinsData[knifeType] && selectedSkinsData[knifeType].weapon_paint_id == paintId) {
if (selectedSkinsData[weaponId] && selectedSkinsData[weaponId].weapon_paint_id == paintId) {
skinOption.classList.add('active');
}
skinOption.onclick = () => equipSkin(knifeType, paintId);
skinOption.onclick = () => this.equipSkin(weaponId, paintId);
skinOption.innerHTML = `
<img src="${skin.image_url}" alt="${skin.paint_name}">
<img src="${skin.image_url}" alt="${skin.paint_name}" loading="lazy">
<div class="skin-option-name">${skin.paint_name.replace(/.*\| /, '')}</div>
`;
skinsContainer.appendChild(skinOption);
});
}
skinGrid.appendChild(skinsContainer);
}
function equipSkin(weaponId, paintId) {
// Create form and submit
const form = document.createElement('form');
form.method = 'POST';
form.style.display = 'none';
const formaInput = document.createElement('input');
formaInput.name = 'forma';
formaInput.value = `${weaponId}-${paintId}`;
const wearInput = document.createElement('input');
wearInput.name = 'wear';
wearInput.value = '0.00';
const seedInput = document.createElement('input');
seedInput.name = 'seed';
seedInput.value = '0';
form.appendChild(formaInput);
form.appendChild(wearInput);
form.appendChild(seedInput);
document.body.appendChild(form);
form.submit();
}
function openCustomizeModal(type, weaponId) {
const modal = document.getElementById('customizeModal');
const title = document.getElementById('modalTitle');
const form = document.getElementById('customizeForm');
const weaponIdInput = document.getElementById('customizeWeaponId');
const wearSelect = document.getElementById('wearSelect');
const wearInput = document.getElementById('wearInput');
const seedInput = document.getElementById('seedInput');
if (type === 'knife') {
title.textContent = 'Customize Knife';
weaponIdInput.value = 'knife-0';
} else {
title.textContent = `Customize ${weaponsData[weaponId].weapon_name.replace('weapon_', '').toUpperCase()}`;
weaponIdInput.value = `${weaponId}-${selectedSkinsData[weaponId]?.weapon_paint_id || 0}`;
// Set current values
if (selectedSkinsData[weaponId]) {
wearInput.value = selectedSkinsData[weaponId].weapon_wear;
seedInput.value = selectedSkinsData[weaponId].weapon_seed;
skinGrid.appendChild(skinsContainer);
},
populateKnifeTypeSkins(knifeType, skinGrid) {
const skinsContainer = document.createElement('div');
skinsContainer.className = 'skins-container';
skinGrid.innerHTML = '';
// ALWAYS show the basic knife option first
const knife = knivesData[knifeType];
if (knife) {
const basicKnifeOption = document.createElement('div');
basicKnifeOption.className = 'skin-option';
// Set wear select based on value
const wear = parseFloat(selectedSkinsData[weaponId].weapon_wear);
if (wear <= 0.00) wearSelect.value = "0.00";
else if (wear <= 0.07) wearSelect.value = "0.07";
else if (wear <= 0.15) wearSelect.value = "0.15";
else if (wear <= 0.38) wearSelect.value = "0.38";
else wearSelect.value = "0.45";
// Check if basic knife is currently selected (no knife skins equipped for this type)
if (!selectedSkinsData[knifeType]) {
basicKnifeOption.classList.add('active');
}
basicKnifeOption.onclick = () => this.equipKnife(knifeType);
basicKnifeOption.innerHTML = `
<img src="${knife.image_url}" alt="${knife.paint_name}" loading="lazy">
<div class="skin-option-name">Default</div>
`;
skinsContainer.appendChild(basicKnifeOption);
}
// Then show knife skins if available
if (skinsData[knifeType]) {
Object.entries(skinsData[knifeType]).forEach(([paintId, skin]) => {
// Skip the default skin (paint ID 0) since we already show it as "Default" option above
if (paintId == '0') {
return;
}
const skinOption = document.createElement('div');
skinOption.className = 'skin-option';
// Check if this skin is currently equipped
if (selectedSkinsData[knifeType] && selectedSkinsData[knifeType].weapon_paint_id == paintId) {
skinOption.classList.add('active');
}
skinOption.onclick = () => this.equipSkin(knifeType, paintId);
skinOption.innerHTML = `
<img src="${skin.image_url}" alt="${skin.paint_name}" loading="lazy">
<div class="skin-option-name">${skin.paint_name.replace(/.*\| /, '')}</div>
`;
skinsContainer.appendChild(skinOption);
});
}
skinGrid.appendChild(skinsContainer);
},
equipSkin(weaponId, paintId) {
this.submitForm(`${weaponId}-${paintId}`, { wear: '0.00', seed: '0' });
},
equipKnife(knifeId) {
this.submitForm(`knife-${knifeId}`);
},
submitForm(forma, additionalData = {}) {
const form = document.createElement('form');
form.method = 'POST';
form.style.display = 'none';
const formaInput = document.createElement('input');
formaInput.name = 'forma';
formaInput.value = forma;
form.appendChild(formaInput);
Object.entries(additionalData).forEach(([name, value]) => {
const input = document.createElement('input');
input.name = name;
input.value = value;
form.appendChild(input);
});
document.body.appendChild(form);
form.submit();
},
openCustomizeModal(type, weaponId) {
const modal = document.getElementById('customizeModal');
const title = document.getElementById('modalTitle');
const weaponIdInput = document.getElementById('customizeWeaponId');
const wearSelect = document.getElementById('wearSelect');
const wearInput = document.getElementById('wearInput');
const seedInput = document.getElementById('seedInput');
if (type === 'knife') {
title.textContent = 'Customize Knife';
weaponIdInput.value = 'knife-0';
} else {
const weaponName = weaponsData[weaponId] ? weaponsData[weaponId].weapon_name.replace('weapon_', '').toUpperCase() : 'Weapon';
title.textContent = `Customize ${weaponName}`;
weaponIdInput.value = `${weaponId}-${selectedSkinsData[weaponId]?.weapon_paint_id || 0}`;
if (selectedSkinsData[weaponId]) {
const wear = parseFloat(selectedSkinsData[weaponId].weapon_wear);
wearInput.value = selectedSkinsData[weaponId].weapon_wear;
seedInput.value = selectedSkinsData[weaponId].weapon_seed;
// Set wear select
if (wear <= 0.00) wearSelect.value = "0.00";
else if (wear <= 0.07) wearSelect.value = "0.07";
else if (wear <= 0.15) wearSelect.value = "0.15";
else if (wear <= 0.38) wearSelect.value = "0.38";
else wearSelect.value = "0.45";
}
}
modal.classList.remove('hidden');
},
closeCustomizeModal() {
document.getElementById('customizeModal').classList.add('hidden');
},
updateWearValue(selectedValue) {
document.getElementById('wearInput').value = selectedValue;
}
};
modal.classList.remove('hidden');
}
// Global functions for onclick handlers
const toggleCategory = (category) => WeaponApp.toggleCategory(category);
const searchWeapons = (query) => WeaponApp.searchWeapons(query);
const toggleWeaponSkins = (weaponId) => WeaponApp.toggleWeaponSkins(weaponId);
const toggleKnifeSkins = (knifeType) => WeaponApp.toggleKnifeSkins(knifeType);
const openCustomizeModal = (type, weaponId) => WeaponApp.openCustomizeModal(type, weaponId);
const closeCustomizeModal = () => WeaponApp.closeCustomizeModal();
const updateWearValue = (value) => WeaponApp.updateWearValue(value);
function closeCustomizeModal() {
document.getElementById('customizeModal').classList.add('hidden');
}
function updateWearValue(selectedValue) {
document.getElementById('wearInput').value = selectedValue;
}
// Close modals when clicking outside
document.addEventListener('click', function(e) {
const modal = document.getElementById('customizeModal');
if (e.target === modal) {
closeCustomizeModal();
}
});
// Initialize app
WeaponApp.init();
</script>
<?php endif; ?>
</body>
</html>
<?php
// Helper function for category icons
function getCategoryIcon($categoryName) {
$icons = [
'Knives' => '🗡️',
'Gloves' => '🧤',
'Rifles' => '🔫',
'Pistols' => '🔫',
'SMGs' => '🔫',
'Shotguns' => '🔫',
'Snipers' => '🎯',
'Machine Guns' => '⚡',
'Grenades' => '💣'
];
return $icons[$categoryName] ?? '🔫';
}
?>

View File

@@ -1,11 +1,14 @@
/* Reset and base styles */
* {
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
/* Colors */
--bg-primary: #1a1a1a;
--bg-secondary: #2a2a2a;
--bg-tertiary: #3a3a3a;
@@ -19,10 +22,16 @@
--accent-blue-hover: #357abd;
--accent-orange: #ff6b35;
--accent-green: #4caf50;
/* Shadows and Effects */
--shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
--shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.4);
--border-radius: 8px;
--transition: all 0.2s ease;
/* Layout */
--sidebar-width: 320px;
--header-height: 70px;
}
body {
@@ -33,6 +42,68 @@ body {
line-height: 1.6;
}
/* Common button styles */
.btn,
button {
border: none;
border-radius: var(--border-radius);
cursor: pointer;
font-weight: 600;
transition: var(--transition);
text-transform: uppercase;
letter-spacing: 0.5px;
font-size: 0.9rem;
padding: 0.75rem 1.5rem;
}
.btn-primary,
.customize-btn,
.equip-btn {
background: var(--accent-blue);
color: white;
}
.btn-primary:hover,
.customize-btn:hover,
.equip-btn:hover {
background: var(--accent-blue-hover);
transform: translateY(-1px);
}
.btn-secondary {
background: var(--bg-tertiary);
color: var(--text-secondary);
border: 1px solid var(--border-color);
}
.btn-secondary:hover {
background: var(--bg-hover);
color: var(--text-primary);
}
.equip-btn {
background: var(--accent-green);
}
.equip-btn:hover {
background: #45a049;
}
.logout-btn {
background: var(--accent-orange);
color: white;
text-decoration: none;
padding: 0.5rem 1rem;
border-radius: var(--border-radius);
transition: var(--transition);
font-weight: 500;
}
.logout-btn:hover {
background: #e55a2b;
text-decoration: none;
}
/* Login Page */
.login-container {
display: flex;
@@ -81,6 +152,7 @@ body {
justify-content: space-between;
align-items: center;
box-shadow: var(--shadow);
height: var(--header-height);
}
.header-left h1 {
@@ -100,22 +172,6 @@ body {
font-size: 0.9rem;
}
.logout-btn {
background: var(--accent-orange);
color: white;
text-decoration: none;
padding: 0.5rem 1rem;
border-radius: var(--border-radius);
transition: var(--transition);
font-weight: 500;
}
.logout-btn:hover {
background: #e55a2b;
color: white;
text-decoration: none;
}
.app-main {
display: flex;
flex: 1;
@@ -125,13 +181,11 @@ body {
/* Sidebar */
.sidebar {
width: 320px;
width: var(--sidebar-width);
background: var(--bg-secondary);
border-right: 1px solid var(--border-color);
display: flex;
flex-direction: column;
position: relative;
align-self: stretch;
overflow: hidden;
}
@@ -177,8 +231,10 @@ body {
padding: 1rem 0;
overflow-y: auto;
overflow-x: hidden;
scrollbar-width: thin;
}
/* Navigation Items */
.nav-item {
display: flex;
align-items: center;
@@ -188,11 +244,7 @@ body {
border-left: 3px solid transparent;
}
.nav-item:hover {
background: var(--bg-hover);
border-left-color: var(--accent-blue);
}
.nav-item:hover,
.nav-item.active {
background: var(--bg-hover);
border-left-color: var(--accent-blue);
@@ -240,6 +292,117 @@ body {
margin-left: 0.5rem;
}
/* Weapon Lists */
.nav-category {
margin-bottom: 0.5rem;
}
.weapon-list {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
background: rgba(0, 0, 0, 0.1);
}
.weapon-list.expanded {
max-height: none;
}
.weapon-container:last-child {
border-bottom: none;
}
.weapon-item {
display: flex;
align-items: center;
padding: 0.75rem 2rem;
cursor: pointer;
transition: var(--transition);
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.weapon-item:hover,
.weapon-item.expanded {
background: var(--bg-hover);
}
.weapon-icon {
width: 32px;
height: 20px;
object-fit: contain;
margin-right: 0.75rem;
border-radius: 4px;
}
.weapon-name {
flex: 1;
font-size: 0.85rem;
color: var(--text-secondary);
}
.weapon-arrow {
color: var(--text-muted);
font-size: 0.7rem;
transition: var(--transition);
}
.weapon-item.expanded .weapon-arrow {
transform: rotate(90deg);
}
.weapon-skins-grid {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
background: var(--bg-primary);
}
.weapon-skins-grid.expanded {
max-height: none;
padding: 1rem;
}
.skins-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 0.5rem;
}
.skin-option {
background: var(--bg-secondary);
border-radius: var(--border-radius);
border: 1px solid var(--border-color);
overflow: hidden;
cursor: pointer;
transition: var(--transition);
text-align: center;
padding: 0.5rem;
}
.skin-option:hover {
transform: translateY(-2px);
border-color: var(--accent-blue);
}
.skin-option.active {
border-color: var(--accent-green);
box-shadow: 0 0 8px rgba(76, 175, 80, 0.3);
}
.skin-option img {
width: 100%;
height: 60px;
object-fit: contain;
margin-bottom: 0.25rem;
border-radius: 4px;
}
.skin-option-name {
font-size: 0.7rem;
color: var(--text-secondary);
line-height: 1.2;
}
/* Main Content */
.main-content {
flex: 1;
@@ -279,6 +442,7 @@ body {
overflow: hidden;
transition: all 0.3s ease;
position: relative;
animation: fadeInUp 0.3s ease;
}
.loadout-item:hover {
@@ -287,6 +451,14 @@ body {
border-color: var(--accent-blue);
}
.loadout-item[data-equipped="true"] {
border-color: var(--accent-green);
}
.loadout-item[data-equipped="true"] .item-category {
color: var(--accent-green);
}
.item-image-container {
position: relative;
aspect-ratio: 16/10;
@@ -322,35 +494,6 @@ body {
opacity: 1;
}
.customize-btn,
.equip-btn {
background: var(--accent-blue);
color: white;
border: none;
padding: 0.75rem 1.5rem;
border-radius: var(--border-radius);
cursor: pointer;
font-weight: 600;
transition: var(--transition);
text-transform: uppercase;
letter-spacing: 0.5px;
font-size: 0.9rem;
}
.customize-btn:hover,
.equip-btn:hover {
background: var(--accent-blue-hover);
transform: translateY(-1px);
}
.equip-btn {
background: var(--accent-green);
}
.equip-btn:hover {
background: #45a049;
}
.item-info {
padding: 1rem;
}
@@ -403,8 +546,7 @@ body {
text-decoration: underline;
}
/* Overlays and Modals */
.overlay,
/* Modals */
.modal {
position: fixed;
top: 0;
@@ -420,13 +562,11 @@ body {
transition: var(--transition);
}
.overlay.hidden,
.modal.hidden {
opacity: 0;
pointer-events: none;
}
.overlay-content,
.modal-content {
background: var(--bg-card);
border-radius: var(--border-radius);
@@ -437,20 +577,9 @@ body {
overflow: hidden;
display: flex;
flex-direction: column;
}
.overlay-content {
width: 1400px;
height: 800px;
max-height: 95vh;
max-width: 98vw;
}
.modal-content {
width: 500px;
}
.overlay-header,
.modal-header {
padding: 1.5rem;
border-bottom: 1px solid var(--border-color);
@@ -460,7 +589,6 @@ body {
background: var(--bg-secondary);
}
.overlay-header h3,
.modal-header h3 {
color: var(--text-primary);
font-size: 1.4rem;
@@ -483,58 +611,13 @@ body {
color: var(--text-primary);
}
/* Skin Grid */
.skin-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
padding: 1.5rem;
overflow-y: auto;
flex: 1;
}
.skin-item {
background: var(--bg-secondary);
border-radius: var(--border-radius);
border: 1px solid var(--border-color);
overflow: hidden;
cursor: pointer;
transition: var(--transition);
}
.skin-item:hover {
transform: translateY(-2px);
box-shadow: var(--shadow);
border-color: var(--accent-blue);
}
.skin-item .skin-image {
width: 100%;
height: 280px;
object-fit: contain;
background: linear-gradient(145deg, #333, #222);
padding: 1rem;
display: block;
box-sizing: border-box;
}
.skin-name {
padding: 0.75rem;
color: var(--text-primary);
font-weight: 500;
font-size: 0.9rem;
text-align: center;
border-top: 1px solid var(--border-color);
}
/* Modal Body */
.modal-body {
padding: 1.5rem;
}
.customize-grid {
display: grid;
gap: 1.5rem;
gap: 1rem;
}
.customize-section {
@@ -553,12 +636,12 @@ body {
.customize-section select,
.customize-section input {
background: var(--bg-secondary);
background: var(--bg-tertiary);
border: 1px solid var(--border-color);
border-radius: var(--border-radius);
padding: 0.75rem;
color: var(--text-primary);
font-size: 1rem;
font-size: 0.9rem;
transition: var(--transition);
}
@@ -570,127 +653,15 @@ body {
}
.modal-footer {
display: flex;
justify-content: flex-end;
gap: 1rem;
padding: 1.5rem;
padding: 1rem 1.5rem;
border-top: 1px solid var(--border-color);
display: flex;
gap: 1rem;
justify-content: flex-end;
background: var(--bg-secondary);
}
.btn {
padding: 0.75rem 1.5rem;
border: none;
border-radius: var(--border-radius);
cursor: pointer;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
transition: var(--transition);
font-size: 0.9rem;
}
.btn-primary {
background: var(--accent-blue);
color: white;
}
.btn-primary:hover {
background: var(--accent-blue-hover);
}
.btn-secondary {
background: var(--bg-tertiary);
color: var(--text-primary);
border: 1px solid var(--border-color);
}
.btn-secondary:hover {
background: var(--bg-hover);
}
/* Responsive Design */
@media (max-width: 768px) {
.app-main {
flex-direction: column;
}
.sidebar {
width: 100%;
height: auto;
}
.main-content {
padding: 1rem;
}
.loadout-grid {
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 1rem;
}
.overlay-content {
width: 95vw;
height: 80vh;
}
.modal-content {
width: 95vw;
}
.app-header {
flex-direction: column;
gap: 1rem;
text-align: center;
}
.header-right {
flex-direction: column;
gap: 0.5rem;
}
}
@media (max-width: 480px) {
.loadout-grid {
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
}
.skin-grid {
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
}
.main-content {
padding: 0.5rem;
}
.loadout-header h2 {
font-size: 1.5rem;
}
}
/* Scrollbar Styling */
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: var(--bg-secondary);
}
::-webkit-scrollbar-thumb {
background: var(--bg-tertiary);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--bg-hover);
}
/* Animation for loadout items */
.loadout-item {
animation: fadeInUp 0.3s ease forwards;
}
/* Animations */
@keyframes fadeInUp {
from {
opacity: 0;
@@ -702,178 +673,93 @@ body {
}
}
/* Special styling for equipped items */
.loadout-item[data-equipped="true"] {
border-color: var(--accent-green);
/* Smooth scrolling */
html {
scroll-behavior: smooth;
}
.loadout-item[data-equipped="true"] .item-category {
color: var(--accent-green);
/* Scrollbars */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
/* Empty Loadout Message */
.empty-loadout {
grid-column: 1 / -1;
display: flex;
justify-content: center;
align-items: center;
min-height: 200px;
background: var(--bg-card);
border-radius: var(--border-radius);
border: 2px dashed var(--border-color);
}
.empty-message {
text-align: center;
color: var(--text-secondary);
}
.empty-message h3 {
font-size: 1.5rem;
margin-bottom: 0.5rem;
color: var(--text-primary);
}
.empty-message p {
font-size: 1rem;
color: var(--text-muted);
}
/* Sidebar Weapon Lists */
.nav-category {
margin-bottom: 0.5rem;
}
.category-header {
margin-bottom: 0 !important;
}
.weapon-list {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
::-webkit-scrollbar-track {
background: var(--bg-tertiary);
border-left: 3px solid var(--accent-blue);
margin-left: 1rem;
}
.weapon-list.expanded {
max-height: 2000px;
padding: 0.5rem 0;
}
.weapon-container {
border-bottom: 1px solid var(--border-color);
}
.weapon-container:last-child {
border-bottom: none;
}
.weapon-item {
display: flex;
align-items: center;
padding: 0.75rem 1rem;
cursor: pointer;
transition: var(--transition);
position: relative;
}
.weapon-item:hover {
background: var(--bg-hover);
padding-left: 1.25rem;
}
.weapon-item.expanded {
background: var(--bg-hover);
border-bottom: 1px solid var(--border-color);
}
.weapon-icon {
width: 48px;
height: 32px;
object-fit: contain;
margin-right: 0.75rem;
background: linear-gradient(145deg, #333, #222);
border-radius: 4px;
padding: 4px;
}
.weapon-name {
color: var(--text-primary);
font-size: 0.85rem;
font-weight: 500;
flex: 1;
::-webkit-scrollbar-thumb {
background: var(--border-color);
border-radius: 4px;
transition: background 0.2s ease;
}
.weapon-arrow {
color: var(--text-muted);
font-size: 0.7rem;
transition: var(--transition);
margin-left: 0.5rem;
::-webkit-scrollbar-thumb:hover {
background: var(--text-muted);
}
.weapon-item.expanded .weapon-arrow {
transform: rotate(90deg);
color: var(--accent-blue);
}
.weapon-skins-grid {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease;
background: var(--bg-primary);
padding: 0;
}
.weapon-skins-grid.expanded {
max-height: 2000px;
padding: 1rem;
}
.skins-container {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 0.5rem;
}
.skin-option {
background: var(--bg-secondary);
border-radius: var(--border-radius);
border: 1px solid var(--border-color);
overflow: hidden;
cursor: pointer;
transition: var(--transition);
aspect-ratio: 16/10;
}
.skin-option:hover {
border-color: var(--accent-blue);
transform: scale(1.02);
}
.skin-option.active {
border-color: var(--accent-green);
box-shadow: 0 0 0 2px rgba(76, 175, 80, 0.3);
}
.skin-option img {
width: 100%;
height: 100%;
object-fit: contain;
background: linear-gradient(145deg, #333, #222);
padding: 4px;
box-sizing: border-box;
}
.skin-option-name {
padding: 0.25rem;
font-size: 0.7rem;
color: var(--text-secondary);
text-align: center;
::-webkit-scrollbar-corner {
background: var(--bg-tertiary);
border-top: 1px solid var(--border-color);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Firefox scrollbar styling */
.sidebar-nav,
.weapon-skins-grid,
.skins-container {
scrollbar-width: thin;
scrollbar-color: var(--border-color) var(--bg-tertiary);
}
/* Responsive Design */
@media (max-width: 1024px) {
.app-main {
flex-direction: column;
}
.sidebar {
width: 100%;
max-height: 400px;
}
.main-content {
padding: 1rem;
}
.loadout-grid {
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
}
}
@media (max-width: 768px) {
.app-header {
padding: 1rem;
flex-direction: column;
gap: 1rem;
height: auto;
}
.header-right {
width: 100%;
justify-content: center;
}
.modal-content {
width: 90%;
margin: 1rem;
}
.loadout-header h2 {
font-size: 1.5rem;
}
}
@media (max-width: 480px) {
.loadout-grid {
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
}
.main-content {
padding: 0.5rem;
}
}