Files
2026-05-06 20:18:40 +00:00

355 lines
21 KiB
HTML

<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>เลือกตัวละคร — Game</title>
<link rel="stylesheet" href="css/style.css">
<style>
.char-upload { margin: 1.5rem 0; padding: 1rem; background: #24283b; border-radius: 8px; max-width: 100%; }
.char-upload h2 { margin: 0 0 0.75rem 0; font-size: 1rem; color: #7aa2f7; }
.char-upload-grid { display: grid; gap: 0.75rem; margin: 0.75rem 0; }
/* Simple upload: 2x2 grid กระชับ ไม่ยาว */
.char-upload-simple .char-upload-grid {
grid-template-columns: repeat(2, 1fr);
max-width: 420px;
}
@media (min-width: 520px) {
.char-upload-simple .char-upload-grid {
grid-template-columns: repeat(4, 1fr);
max-width: 520px;
}
}
/* Advanced layered: 2 คอลัมน์บนมือถือ, 4 คอลัมน์จอใหญ่ พร้อม scroll ถ้าจำเป็น */
#char-upload-advanced .char-upload-grid {
grid-template-columns: repeat(2, 1fr);
max-width: 100%;
}
#char-upload-advanced .char-upload-cell { font-size: 0.8rem; }
#char-upload-advanced .char-upload-cell strong { display: block; margin-top: 0.4rem; color: #7aa2f7; font-size: 0.75rem; }
#char-upload-advanced .char-upload-cell strong:first-of-type { margin-top: 0; }
#char-upload-advanced .char-upload-cell label { font-size: 0.75rem; margin-bottom: 0.15rem; }
#char-upload-advanced .char-upload-cell input[type="file"] { font-size: 0.7rem; padding: 0.2rem 0.4rem; }
@media (min-width: 900px) {
#char-upload-advanced .char-upload-grid {
grid-template-columns: repeat(4, 1fr);
}
}
.char-upload-cell { text-align: center; min-width: 0; }
.char-upload-cell label { display: block; font-size: 0.85rem; color: #a9b1d6; margin-bottom: 0.25rem; }
.char-upload-cell input[type="file"] { font-size: 0.8rem; max-width: 100%; }
.char-layer-seq-strip {
display: flex; flex-wrap: wrap; gap: 3px; margin: 0.2rem 0 0.35rem; max-width: 100%; justify-content: center;
min-height: 0;
}
.char-layer-seq-strip img {
width: 28px; height: 28px; object-fit: contain; background: #1a1b26; border-radius: 3px; border: 1px solid rgba(122,162,247,0.25);
}
.char-upload-cell .preview { width: 56px; height: 56px; margin: 0.25rem auto; background: #1a1b26; border-radius: 6px; object-fit: contain; display: block; }
.char-upload-actions { margin-top: 1rem; display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.character-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 1rem; margin: 1rem 0; }
.character-item { text-align: center; cursor: pointer; padding: 0.5rem; border-radius: 8px; border: 2px solid transparent; transition: border-color 0.2s, background 0.2s; }
.character-item:hover { background: rgba(122,162,247,0.15); border-color: #7aa2f7; }
.character-item.selected { border-color: #9ece6a; background: rgba(158,206,106,0.2); }
.character-item .previews { display: flex; flex-wrap: wrap; justify-content: center; gap: 2px; margin-bottom: 0.25rem; }
.character-item .previews img { width: 36px; height: 36px; object-fit: contain; background: #24283b; border-radius: 4px; }
.character-item .name { font-size: 0.85rem; color: #a9b1d6; }
.character-actions { display: flex; justify-content: center; gap: 0.4rem; margin-top: 0.35rem; flex-wrap: wrap; }
.character-actions button { font-size: 0.75rem; padding: 0.25rem 0.5rem; }
.char-edit-btn { background: #565f89; color: #c0caf5; }
.char-edit-btn:hover { background: #7aa2f7; color: #1a1b26; }
.char-delete-btn { background: #414868; color: #a9b1d6; }
.char-delete-btn:hover { background: #f7768e; color: #1a1b26; }
/* idle ฝังในแบบเลเยอร์ — แยกโซนสีม่วง */
.char-layer-global-tabs {
display: flex;
flex-wrap: wrap;
gap: 0.35rem;
margin: 0.75rem 0 1rem;
padding: 0.35rem;
background: rgba(26, 27, 38, 0.65);
border-radius: 10px;
border: 1px solid rgba(122, 162, 247, 0.25);
}
.char-layer-global-tabs .char-mode-tab {
flex: 1 1 auto;
min-width: 120px;
padding: 0.45rem 0.75rem;
font-size: 0.88rem;
border: 1px solid transparent;
border-radius: 8px;
background: transparent;
color: #a9b1d6;
cursor: pointer;
font-family: inherit;
}
.char-layer-global-tabs .char-mode-tab:hover {
color: #c0caf5;
background: rgba(122, 162, 247, 0.12);
}
.char-layer-global-tabs .char-mode-tab.is-active {
background: #414868;
color: #c0caf5;
border-color: rgba(187, 154, 247, 0.45);
box-shadow: 0 0 0 1px rgba(122, 162, 247, 0.2);
}
#char-upload-advanced .char-layer-panel-stack { min-height: 0; }
#char-upload-advanced[data-adv-layer-mode="move"] .char-layer-panel--idle { display: none !important; }
#char-upload-advanced[data-adv-layer-mode="idle"] .char-layer-panel--move { display: none !important; }
#char-upload-advanced .char-layer-panel--move,
#char-upload-advanced .char-layer-panel--idle {
text-align: left;
}
#char-upload-advanced .char-panel-subtle {
margin: 0 0 0.4rem 0;
font-size: 0.78rem;
color: #bb9af7;
line-height: 1.35;
}
#char-upload-advanced .preview-idle-inline {
margin-top: 0.35rem;
}
/* ฝังใน Admin (iframe): ลดหัวข้อ/ลิงก์นำทาง */
html.character-embed-admin .character-page-links,
html.character-embed-admin body > .container > h1:first-of-type,
html.character-embed-admin .version-tag {
display: none !important;
}
html.character-embed-admin body {
overflow-x: hidden;
}
html.character-embed-admin .container {
padding-top: 0.35rem;
padding-bottom: 1.5rem;
}
</style>
</head>
<body>
<script>
(function () {
try {
var q = new URLSearchParams(location.search);
if (q.get('embed') === '1' || q.get('from') === 'admin') {
document.documentElement.classList.add('character-embed-admin');
document.body.classList.add('character-embed-admin');
}
} catch (e) {}
})();
</script>
<div class="container">
<h1>ตัวละคร (4 ทิศ)</h1>
<p class="character-page-links"><a href="index.html">กลับหน้าหลัก</a> · <a href="lobby.html">ล็อบบี้</a></p>
<section class="char-upload char-upload-simple">
<h2>อัปโหลดตัวละคร (บน · ล่าง · ซ้าย · ขวา)</h2>
<p class="legend">เลือกรูปทั้ง 4 ทิศ แล้วใส่ชื่อ (ไม่บังคับ) กดอัปโหลด · รูป <strong>ยืนเฉย (idle)</strong> แยกเลเยอร์ต่อทิศอยู่ในตาราง <strong>แบบเลเยอร์</strong> ด้านล่าง</p>
<div class="char-upload-grid">
<div class="char-upload-cell">
<label>บน (up) <small>เลือกได้หลายเฟรม</small></label>
<input type="file" id="file-up" accept="image/*" multiple>
<img id="preview-up" class="preview" alt="">
</div>
<div class="char-upload-cell">
<label>ล่าง (down) <small>เลือกได้หลายเฟรม</small></label>
<input type="file" id="file-down" accept="image/*" multiple>
<img id="preview-down" class="preview" alt="">
</div>
<div class="char-upload-cell">
<label>ซ้าย (left) <small>เลือกได้หลายเฟรม</small></label>
<input type="file" id="file-left" accept="image/*" multiple>
<img id="preview-left" class="preview" alt="">
</div>
<div class="char-upload-cell">
<label>ขวา (right) <small>เลือกได้หลายเฟรม</small></label>
<input type="file" id="file-right" accept="image/*" multiple>
<img id="preview-right" class="preview" alt="">
</div>
</div>
<div class="char-upload-actions">
<label>ชื่อตัวละคร <input type="text" id="char-name" placeholder="เช่น mychar"></label>
<button type="button" id="btn-upload">อัปโหลด</button>
</div>
<p id="upload-status" style="margin-top:0.5rem;font-size:0.9rem;color:#a9b1d6;"></p>
</section>
<section class="char-upload" id="char-upload-advanced" data-adv-layer-mode="move">
<h2>อัปโหลดตัวละครแบบเลเยอร์ (Shadow / Body / Hair / Head / Face)</h2>
<p class="legend">สำหรับผู้สร้างสกิน: แยกไฟล์ตามเลเยอร์ + ทิศ · ใช้เมนูด้านล่างสลับระหว่าง <strong>เดิน</strong> กับ <strong>ยืนเฉย (idle)</strong> — ถ้าไม่ใส่ idle เกมจะใช้เฟรมเดินเมื่อยืนนิ่ง</p>
<div class="char-layer-global-tabs" id="char-layer-global-tabs" role="tablist" aria-label="โหมดเลเยอร์เดินและยืนเฉย">
<button type="button" class="char-mode-tab is-active" role="tab" aria-selected="true" data-adv-mode="move">เดิน (Move)</button>
<button type="button" class="char-mode-tab" role="tab" aria-selected="false" data-adv-mode="idle">ยืนเฉย (Idle)</button>
</div>
<div class="char-upload-grid">
<div class="char-upload-cell">
<label>บน (up)</label>
<div class="char-layer-panel-stack">
<div class="char-layer-panel char-layer-panel--move">
<strong>Shadow</strong>
<label>Shadow <input type="file" id="layer-up-shadow" accept="image/*" multiple></label>
<strong>Body</strong>
<label>Color <input type="file" id="layer-up-bodyColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-up-bodyStroke" accept="image/*" multiple></label>
<strong>Hair</strong>
<label>Color <input type="file" id="layer-up-hairColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-up-hairStroke" accept="image/*" multiple></label>
<strong>Head</strong>
<label>Color <input type="file" id="layer-up-headColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-up-headStroke" accept="image/*" multiple></label>
<strong>Face</strong>
<label>Face <input type="file" id="layer-up-face" accept="image/*" multiple></label>
<img id="preview-up-layer" class="preview" alt="">
</div>
<div class="char-layer-panel char-layer-panel--idle">
<p class="char-panel-subtle">เลเยอร์ยืนเฉย (idle) ทิศบน — โครงเดียวกับเดิน</p>
<strong>Shadow</strong>
<label>Shadow <input type="file" id="layer-idle-up-shadow" accept="image/*" multiple></label>
<strong>Body</strong>
<label>Color <input type="file" id="layer-idle-up-bodyColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-idle-up-bodyStroke" accept="image/*" multiple></label>
<strong>Hair</strong>
<label>Color <input type="file" id="layer-idle-up-hairColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-idle-up-hairStroke" accept="image/*" multiple></label>
<strong>Head</strong>
<label>Color <input type="file" id="layer-idle-up-headColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-idle-up-headStroke" accept="image/*" multiple></label>
<strong>Face</strong>
<label>Face <input type="file" id="layer-idle-up-face" accept="image/*" multiple></label>
<img id="preview-idle-layer-up" class="preview preview-idle-inline" alt="">
</div>
</div>
</div>
<div class="char-upload-cell">
<label>ล่าง (down)</label>
<div class="char-layer-panel-stack">
<div class="char-layer-panel char-layer-panel--move">
<strong>Shadow</strong>
<label>Shadow <input type="file" id="layer-down-shadow" accept="image/*" multiple></label>
<strong>Body</strong>
<label>Color <input type="file" id="layer-down-bodyColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-down-bodyStroke" accept="image/*" multiple></label>
<strong>Hair</strong>
<label>Color <input type="file" id="layer-down-hairColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-down-hairStroke" accept="image/*" multiple></label>
<strong>Head</strong>
<label>Color <input type="file" id="layer-down-headColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-down-headStroke" accept="image/*" multiple></label>
<strong>Face</strong>
<label>Face <input type="file" id="layer-down-face" accept="image/*" multiple></label>
<img id="preview-down-layer" class="preview" alt="">
</div>
<div class="char-layer-panel char-layer-panel--idle">
<p class="char-panel-subtle">เลเยอร์ยืนเฉย (idle) ทิศล่าง</p>
<strong>Shadow</strong>
<label>Shadow <input type="file" id="layer-idle-down-shadow" accept="image/*" multiple></label>
<strong>Body</strong>
<label>Color <input type="file" id="layer-idle-down-bodyColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-idle-down-bodyStroke" accept="image/*" multiple></label>
<strong>Hair</strong>
<label>Color <input type="file" id="layer-idle-down-hairColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-idle-down-hairStroke" accept="image/*" multiple></label>
<strong>Head</strong>
<label>Color <input type="file" id="layer-idle-down-headColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-idle-down-headStroke" accept="image/*" multiple></label>
<strong>Face</strong>
<label>Face <input type="file" id="layer-idle-down-face" accept="image/*" multiple></label>
<img id="preview-idle-layer-down" class="preview preview-idle-inline" alt="">
</div>
</div>
</div>
<div class="char-upload-cell">
<label>ซ้าย (left)</label>
<div class="char-layer-panel-stack">
<div class="char-layer-panel char-layer-panel--move">
<strong>Shadow</strong>
<label>Shadow <input type="file" id="layer-left-shadow" accept="image/*" multiple></label>
<strong>Body</strong>
<label>Color <input type="file" id="layer-left-bodyColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-left-bodyStroke" accept="image/*" multiple></label>
<strong>Hair</strong>
<label>Color <input type="file" id="layer-left-hairColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-left-hairStroke" accept="image/*" multiple></label>
<strong>Head</strong>
<label>Color <input type="file" id="layer-left-headColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-left-headStroke" accept="image/*" multiple></label>
<strong>Face</strong>
<label>Face <input type="file" id="layer-left-face" accept="image/*" multiple></label>
<img id="preview-left-layer" class="preview" alt="">
</div>
<div class="char-layer-panel char-layer-panel--idle">
<p class="char-panel-subtle">เลเยอร์ยืนเฉย (idle) ทิศซ้าย</p>
<strong>Shadow</strong>
<label>Shadow <input type="file" id="layer-idle-left-shadow" accept="image/*" multiple></label>
<strong>Body</strong>
<label>Color <input type="file" id="layer-idle-left-bodyColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-idle-left-bodyStroke" accept="image/*" multiple></label>
<strong>Hair</strong>
<label>Color <input type="file" id="layer-idle-left-hairColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-idle-left-hairStroke" accept="image/*" multiple></label>
<strong>Head</strong>
<label>Color <input type="file" id="layer-idle-left-headColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-idle-left-headStroke" accept="image/*" multiple></label>
<strong>Face</strong>
<label>Face <input type="file" id="layer-idle-left-face" accept="image/*" multiple></label>
<img id="preview-idle-layer-left" class="preview preview-idle-inline" alt="">
</div>
</div>
</div>
<div class="char-upload-cell">
<label>ขวา (right)</label>
<div class="char-layer-panel-stack">
<div class="char-layer-panel char-layer-panel--move">
<strong>Shadow</strong>
<label>Shadow <input type="file" id="layer-right-shadow" accept="image/*" multiple></label>
<strong>Body</strong>
<label>Color <input type="file" id="layer-right-bodyColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-right-bodyStroke" accept="image/*" multiple></label>
<strong>Hair</strong>
<label>Color <input type="file" id="layer-right-hairColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-right-hairStroke" accept="image/*" multiple></label>
<strong>Head</strong>
<label>Color <input type="file" id="layer-right-headColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-right-headStroke" accept="image/*" multiple></label>
<strong>Face</strong>
<label>Face <input type="file" id="layer-right-face" accept="image/*" multiple></label>
<img id="preview-right-layer" class="preview" alt="">
</div>
<div class="char-layer-panel char-layer-panel--idle">
<p class="char-panel-subtle">เลเยอร์ยืนเฉย (idle) ทิศขวา</p>
<strong>Shadow</strong>
<label>Shadow <input type="file" id="layer-idle-right-shadow" accept="image/*" multiple></label>
<strong>Body</strong>
<label>Color <input type="file" id="layer-idle-right-bodyColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-idle-right-bodyStroke" accept="image/*" multiple></label>
<strong>Hair</strong>
<label>Color <input type="file" id="layer-idle-right-hairColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-idle-right-hairStroke" accept="image/*" multiple></label>
<strong>Head</strong>
<label>Color <input type="file" id="layer-idle-right-headColor" accept="image/*" multiple></label>
<label>Stroke <input type="file" id="layer-idle-right-headStroke" accept="image/*" multiple></label>
<strong>Face</strong>
<label>Face <input type="file" id="layer-idle-right-face" accept="image/*" multiple></label>
<img id="preview-idle-layer-right" class="preview preview-idle-inline" alt="">
</div>
</div>
</div>
</div>
<div class="char-upload-actions">
<p class="legend">ใช้ "ชื่อตัวละคร" ช่องเดียวกับด้านบน</p>
<button type="button" id="btn-upload-layered">อัปโหลดแบบเลเยอร์</button>
</div>
</section>
<h2>เลือกตัวละครที่ใช้ในเกม</h2>
<p class="legend">คลิกเลือก — ตัวนี้จะแสดงเมื่อเข้าโถงรอและเล่นเกม (เปลี่ยนทิศตามการเดิน)</p>
<p id="char-status">โหลดรายการตัวละคร...</p>
<div class="character-grid" id="character-grid"></div>
<p id="char-hint" style="display:none; color: #a9b1d6;">ยังไม่มีตัวละคร — อัปโหลดด้านบน</p>
</div>
<script src="js/version.js?v=0.0112"></script>
<script src="js/character.js?v=0.021"></script>
<div class="version-tag">v —</div>
</body>
</html>