<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>忠珍諺羽卡牌遊戲</title>
<style>
body { font-family: system-ui, -apple-system, sans-serif; background: linear-gradient(135deg, #667eea, #764ba2); color: white; margin: 0; padding: 10px; }
h1, h2, h3 { text-align: center; margin: 10px 0; }
button { background: #ff6b6b; color: white; border: none; padding: 12px 24px; margin: 8px; border-radius: 12px; font-size: 16px; cursor: pointer; }
button:hover { background: #ff5252; }
button:disabled { background: #777; opacity: 0.6; cursor: not-allowed; }
.card { width: 140px; height: 200px; margin: 8px; display: inline-block; border-radius: 12px; position: relative; box-shadow: 0 4px 12px rgba(0,0,0,0.4); cursor: pointer; transition: transform 0.15s; vertical-align: top; }
.card:hover { transform: scale(1.08); }
.card img { width: 100%; height: 100%; object-fit: cover; border-radius: 12px; }
.card-info { position: absolute; bottom: 8px; left: 8px; right: 8px; background: rgba(0,0,0,0.75); padding: 6px; border-radius: 6px; font-size: 12px; text-align: center; }
.legend-name { position: absolute; top: 8px; left: 8px; background: rgba(0,0,0,0.7); padding: 4px 8px; border-radius: 6px; font-weight: bold; font-size: 13px; }
.rare-name { position: absolute; top: 8px; left: 8px; color: white; font-weight: bold; text-shadow: 1px 1px 3px black; font-size: 13px; }
.selected { border: 4px solid gold !important; box-shadow: 0 0 15px gold; }
#players { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; margin: 15px 0; }
.player { padding: 10px 20px; background: rgba(255,255,255,0.15); border-radius: 12px; min-width: 100px; text-align: center; }
#log { background: rgba(0,0,0,0.5); padding: 15px; border-radius: 12px; max-height: 250px; overflow-y: auto; font-size: 14px; margin-top: 15px; }
#admin { margin: 20px 0; background: rgba(0,0,0,0.6); padding: 15px; border-radius: 12px; }
input, select { padding: 10px; margin: 6px; border-radius: 8px; border: 1px solid #aaa; width: calc(100% - 24px); max-width: 300px; box-sizing: border-box; }
</style>
</head>
<body>
<h1>忠珍諺羽卡牌遊戲</h1>
<div id="loginScreen">
<p>點擊開始遊戲(匿名登入)</p>
<button onclick="login()">登入</button>
</div>
<div id="roleSelect" style="display:none;">
<h2>選擇你的角色(先選先得)</h2>
<div id="roleButtons"></div>
</div>
<div id="gameScreen" style="display:none;">
<h2>你的角色:<span id="currentRole"></span> | 卡片數:<span id="cardCount">0</span></h2>
<div id="players"></div>
<button id="supplyBtn" style="display:none;" onclick="requestSupply()">請求補牌(少於15張時)</button>
<div id="choiceSection" style="display:none;">
<h3>選 3 張牌(總費用 ≤15,不可連續使用上次牌)</h3>
<div id="myCards"></div>
<div id="selectedCards" style="min-height:220px;"></div>
<button id="confirmSelect" disabled onclick="confirmSelect()">確認牌序</button>
</div>
<div id="battleSection" style="display:none;">
<h3 id="roundInfo">第 1 回合</h3>
<div id="battleResult"></div>
<button id="nextRound" style="display:none;" onclick="nextRound()">下一回合</button>
</div>
<div id="log"></div>
<div id="admin">
<h3>管理員新增卡片(僅限本人)</h3>
<input id="adminPw" type="password" placeholder="輸入密碼">
<button onclick="checkAdminPw()">確認</button>
<div id="addCardForm" style="display:none;">
<select id="cardLevel"><option>普通卡</option><option>稀有卡</option><option>傳奇卡</option></select>
<select id="cardPerson"><option>JENNY</option><option>RGG</option><option>BEN</option><option>SARA</option></select>
<input id="cardDate" placeholder="日期 YYYY-MM-DD">
<select id="cardOwner"><option>JENNY</option><option>RGG</option><option>BEN</option><option>SARA</option></select>
<input id="cardImage" placeholder="圖片網址(imgur 等公開連結)">
<button onclick="addNewCard()">新增卡片</button>
</div>
</div>
</div>
<!-- Firebase SDK -->
<script src="https://www.gstatic.com/firebasejs/10.13.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.13.0/firebase-auth-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/10.13.0/firebase-database-compat.js"></script>
<script>
// === 你的 Firebase 配置 ===
const firebaseConfig = {
apiKey: "AIzaSyCSX_1dk1_t_6xg6gi5WR85bYX5S6McyQ8",
authDomain: "rjbs-card-game.firebaseapp.com",
projectId: "rjbs-card-game",
storageBucket: "rjbs-card-game.firebasestorage.app",
messagingSenderId: "120714905128",
appId: "1:120714905128:web:480526ade558e35157d71d",
measurementId: "G-HY0VXS3ESJ"
};
firebase.initializeApp(firebaseConfig);
const auth = firebase.auth();
const db = firebase.database();
// === 遊戲常數 ===
const ROLES = ['JENNY', 'RGG', 'BEN', 'SARA'];
const COUNTER = { 'JENNY':'RGG', 'RGG':'BEN', 'BEN':'SARA', 'SARA':'JENNY' };
const LEVEL_BONUS = { '普通卡':0, '稀有卡':3, '傳奇卡':5 };
const LEVEL_VALUE = { '普通卡':1, '稀有卡':2, '傳奇卡':3 };
const ADMIN_PW = 'family2026'; // ← 改成你想要的密碼
let currentUser = null;
let myRole = null;
let myCards = {};
let lastUsed = [];
let selectedIds = [];
let gameChoices = {};
let currentRound = 1;
let cardsCache = {}; // 全域快取所有角色卡片
// 登入
function login() {
auth.signInAnonymously()
.then(cred => {
currentUser = cred.user.uid;
document.getElementById('loginScreen').style.display = 'none';
document.getElementById('roleSelect').style.display = 'block';
renderRoleButtons();
listenGame();
})
.catch(err => alert('登入失敗:' + err.message));
}
// 顯示角色選擇按鈕
function renderRoleButtons() {
const container = document.getElementById('roleButtons');
container.innerHTML = '';
ROLES.forEach(role => {
const btn = document.createElement('button');
btn.textContent = role;
btn.style.background = role === 'JENNY' ? '#ff69b4' : role === 'RGG' ? '#32cd32' : role === 'BEN' ? '#4169e1' : '#ff8c00';
btn.onclick = () => selectRole(role);
container.appendChild(btn);
});
}
// 選擇角色
function selectRole(role) {
db.ref('game/players').transaction(players => {
players = players || {};
if (players[role]) return; // 已有人選
players[role] = { uid: currentUser };
return players;
}).then(result => {
if (result.committed) {
myRole = role;
document.getElementById('roleSelect').style.display = 'none';
document.getElementById('gameScreen').style.display = 'block';
document.getElementById('currentRole').textContent = role;
loadMyCards();
} else {
alert(role + ' 已被選走!');
}
});
}
// 監聽遊戲狀態
function listenGame() {
db.ref('game').on('value', snap => {
const data = snap.val() || {};
updatePlayers(data.players || {});
gameChoices = data.choices || {};
currentRound = data.round || 1;
document.getElementById('roundInfo').textContent = `第 ${currentRound} 回合`;
if (myRole && gameChoices[myRole]) {
document.getElementById('choiceSection').style.display = 'none';
} else if (Object.keys(gameChoices).length < Object.keys(data.players || {}).length) {
document.getElementById('choiceSection').style.display = 'block';
}
if (Object.keys(gameChoices).length === Object.keys(data.players || {}).length && currentRound <= 3) {
document.getElementById('battleSection').style.display = 'block';
if (currentRound > 1) playRound();
}
});
}
function updatePlayers(players) {
const container = document.getElementById('players');
container.innerHTML = '<h3>在線玩家</h3>';
ROLES.forEach(r => {
const div = document.createElement('div');
div.className = 'player';
div.innerHTML = `<strong>\( {r}</strong><br> \){players[r] ? '✅' : '❌'}`;
container.appendChild(div);
});
}
// 載入我的卡片
function loadMyCards() {
db.ref(`roles/${myRole}/cards`).on('value', snap => {
myCards = snap.val() || {};
document.getElementById('cardCount').textContent = Object.keys(myCards).length;
db.ref(`roles/${myRole}/lastUsed`).once('value').then(s => {
lastUsed = s.val() || [];
renderMyCards();
checkSupply();
});
});
}
function renderMyCards() {
const container = document.getElementById('myCards');
container.innerHTML = '';
Object.entries(myCards).forEach(([id, card]) => {
const fee = calcFee(card.date);
const points = fee + (LEVEL_BONUS[card.level] || 0);
const div = document.createElement('div');
div.className = 'card';
div.dataset.id = id;
if (lastUsed.includes(id)) div.style.opacity = '0.5';
if (card.level === '傳奇卡') {
div.innerHTML = `<img src="\( {card.image || 'https://via.placeholder.com/140x200?text=傳奇'}"><div class="legend-name"> \){card.person} ${card.date}</div>`;
} else {
div.innerHTML = `<img src="\( {card.image || 'https://via.placeholder.com/80?text=卡'}"><div class="card-info">費用: \){fee}<br>點數:\( {points}<br> \){card.person}<br>${card.level}</div>`;
if (card.level === '稀有卡') {
div.innerHTML = `<div class="rare-name">${card.person} ${card.date}</div>` + div.innerHTML;
div.style.background = 'linear-gradient(135deg, #aaa, #eee)';
}
}
div.onclick = () => toggleSelect(id);
container.appendChild(div);
});
}
function toggleSelect(id) {
if (lastUsed.includes(id)) return alert('這張上次用過,不能連續使用');
const idx = selectedIds.indexOf(id);
if (idx > -1) {
selectedIds.splice(idx, 1);
} else if (selectedIds.length < 3) {
selectedIds.push(id);
}
renderSelected();
}
function renderSelected() {
const container = document.getElementById('selectedCards');
container.innerHTML = '<h4>已選牌:</h4>';
let total = 0;
selectedIds.forEach(id => {
const card = myCards[id];
total += calcFee(card.date);
const mini = document.createElement('div');
mini.className = 'card selected';
mini.innerHTML = card.level === '傳奇卡'
? `<img src="\( {card.image}"><div class="legend-name small"> \){card.person}</div>`
: `<div class="card-info small">點數:${calcFee(card.date) + LEVEL_BONUS[card.level]}</div>`;
container.appendChild(mini);
});
container.innerHTML += `<p>總費用:${total} / 15</p>`;
document.getElementById('confirmSelect').disabled = selectedIds.length !== 3 || total > 15;
}
function confirmSelect() {
db.ref(`game/choices/${myRole}`).set(selectedIds);
alert('已送出牌序,等其他玩家...');
selectedIds = [];
renderSelected();
}
// 計算費用(年月日數字加總至個位數)
function calcFee(date) {
if (!date) return 0;
return date.replace(/-/g,'').split('').reduce((a,b)=>a+Number(b),0) % 9 || 9;
}
function checkSupply() {
const count = Object.keys(myCards).length;
document.getElementById('supplyBtn').style.display = count < 15 ? 'inline-block' : 'none';
}
function requestSupply() {
// 找牌最多的人(簡化:假設系統隨機給 5 張普通/稀有)
alert('補牌功能尚未完整實作,可請管理員手動加卡~');
// 未來可擴充:找 max cards 的角色,轉移 5 張普通/稀有
}
// 新增卡片(管理員)
function checkAdminPw() {
const pw = document.getElementById('adminPw').value;
if (pw === ADMIN_PW) {
document.getElementById('addCardForm').style.display = 'block';
} else {
alert('密碼錯誤');
}
}
function addNewCard() {
const level = document.getElementById('cardLevel').value;
const person = document.getElementById('cardPerson').value;
const date = document.getElementById('cardDate').value;
const owner = document.getElementById('cardOwner').value;
const image = document.getElementById('cardImage').value;
if (!date.match(/^\d{4}-\d{2}-\d{2}$/)) return alert('日期格式錯誤:YYYY-MM-DD');
const id = Date.now().toString();
db.ref(`roles/\( {owner}/cards/ \){id}`).set({ level, person, date, image });
alert('卡片新增成功!');
}
// 下一回合(簡化版,實際對決邏輯可再擴充)
function nextRound() {
if (currentRound < 3) {
db.ref('game').update({ round: currentRound + 1, choices: null });
} else {
alert('遊戲結束!(完整對決邏輯可再擴充)');
}
}
// 對決邏輯(目前僅 placeholder,之後可完整實作)
function playRound() {
document.getElementById('battleResult').innerHTML = '<p>對決進行中...(目前為簡化版)</p>';
// 這裡可加入完整的 resolveBattle 邏輯
}
// 初始載入角色快取(可選)
ROLES.forEach(r => {
db.ref(`roles/${r}/cards`).once('value').then(s => {
cardsCache[r] = s.val() || {};
});
});
</script>
</body>
</html>