Added conditions.

This commit is contained in:
2026-04-26 10:37:25 -04:00
parent 451151628c
commit 33c93ab86b
+97 -1
View File
@@ -50,6 +50,24 @@ const DEFAULT_INIT_MOD = 0;
const MONSTER_DEFAULT_INIT_MOD = 2;
const ROLL_DISPLAY_DURATION = 5000;
const CONDITIONS = [
{ id: 'blinded', label: 'Blinded', emoji: '🙈' },
{ id: 'charmed', label: 'Charmed', emoji: '💘' },
{ id: 'deafened', label: 'Deafened', emoji: '🔇' },
{ id: 'exhaustion', label: 'Exhaustion', emoji: '😴' },
{ id: 'frightened', label: 'Frightened', emoji: '😱' },
{ id: 'grappled', label: 'Grappled', emoji: '🤜' },
{ id: 'incapacitated', label: 'Incapacitated', emoji: '💫' },
{ id: 'invisible', label: 'Invisible', emoji: '👻' },
{ id: 'paralyzed', label: 'Paralyzed', emoji: '⚡' },
{ id: 'petrified', label: 'Petrified', emoji: '🗿' },
{ id: 'poisoned', label: 'Poisoned', emoji: '🤢' },
{ id: 'prone', label: 'Prone', emoji: '⬇️' },
{ id: 'restrained', label: 'Restrained', emoji: '🕸️' },
{ id: 'stunned', label: 'Stunned', emoji: '💥' },
{ id: 'unconscious', label: 'Unconscious', emoji: '💤' },
];
// ============================================================================
// FIREBASE CONFIGURATION
// ============================================================================
@@ -769,6 +787,7 @@ function ParticipantManager({ encounter, encounterPath, campaignCharacters }) {
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
const [itemToDelete, setItemToDelete] = useState(null);
const [lastRollDetails, setLastRollDetails] = useState(null);
const [openConditionsId, setOpenConditionsId] = useState(null);
const participants = encounter.participants || [];
@@ -1057,6 +1076,23 @@ function ParticipantManager({ encounter, encounterPath, campaignCharacters }) {
}
};
const toggleCondition = async (participantId, conditionId) => {
if (!db) return;
const updatedParticipants = participants.map(p => {
if (p.id !== participantId) return p;
const current = p.conditions || [];
const next = current.includes(conditionId)
? current.filter(c => c !== conditionId)
: [...current, conditionId];
return { ...p, conditions: next };
});
try {
await updateDoc(doc(db, encounterPath), { participants: updatedParticipants });
} catch (err) {
console.error("Error updating conditions:", err);
}
};
const handleDragStart = (e, id) => {
setDraggedItemId(id);
e.dataTransfer.effectAllowed = 'move';
@@ -1329,6 +1365,47 @@ function ParticipantManager({ encounter, encounterPath, campaignCharacters }) {
))}
</div>
)}
{/* Active condition badges */}
{(p.conditions || []).length > 0 && (
<div className="mt-1 flex flex-wrap gap-1">
{(p.conditions || []).map(cId => {
const cond = CONDITIONS.find(c => c.id === cId);
return cond ? (
<span
key={cId}
className="inline-flex items-center gap-0.5 px-1.5 py-0.5 rounded-full bg-purple-900 border border-purple-600 text-xs text-purple-200 cursor-pointer hover:bg-purple-800"
title={`Remove ${cond.label}`}
onClick={() => toggleCondition(p.id, cId)}
>
{cond.emoji} {cond.label}
</span>
) : null;
})}
</div>
)}
{/* Expandable conditions picker */}
{openConditionsId === p.id && (
<div className="mt-2 p-2 bg-stone-900 rounded-md border border-stone-600">
<p className="text-xs text-stone-400 mb-1 font-medium">Toggle Conditions</p>
<div className="flex flex-wrap gap-1">
{CONDITIONS.map(cond => {
const active = (p.conditions || []).includes(cond.id);
return (
<button
key={cond.id}
onClick={() => toggleCondition(p.id, cond.id)}
className={`px-2 py-1 rounded text-xs transition-colors ${active ? 'bg-purple-700 border border-purple-400 text-white' : 'bg-stone-700 border border-stone-500 text-stone-300 hover:bg-stone-600'}`}
title={cond.label}
>
{cond.emoji} {cond.label}
</button>
);
})}
</div>
</div>
)}
</div>
</div>
@@ -1370,6 +1447,13 @@ function ParticipantManager({ encounter, encounterPath, campaignCharacters }) {
{p.isActive ? <UserCheck size={18} /> : <UserX size={18} />}
</button>
)}
<button
onClick={() => setOpenConditionsId(openConditionsId === p.id ? null : p.id)}
className={`p-1 rounded transition-colors bg-stone-700 hover:bg-stone-600 ${openConditionsId === p.id || (p.conditions || []).length > 0 ? 'text-purple-400 hover:text-purple-300' : 'text-stone-400 hover:text-stone-300'}`}
title="Conditions"
>
<span className="text-base leading-none"></span>
</button>
<button
onClick={() => setEditingParticipant(p)}
className="p-1 rounded transition-colors text-yellow-400 hover:text-yellow-300 bg-stone-700 hover:bg-stone-600"
@@ -2308,7 +2392,19 @@ function DisplayView() {
</div>
{p.conditions?.length > 0 && (
<p className="text-sm text-yellow-300 mt-2">Conditions: {p.conditions.join(', ')}</p>
<div className="flex flex-wrap gap-1 mt-2">
{p.conditions.map(cId => {
const cond = CONDITIONS.find(c => c.id === cId);
return cond ? (
<span
key={cId}
className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-purple-900 border border-purple-500 text-xs md:text-sm text-purple-200 font-medium"
>
{cond.emoji} {cond.label}
</span>
) : null;
})}
</div>
)}
{!p.isActive && !isDead && (