import type { Location, PlayerState, CombatState, Profile, WorkbenchTab } from './types'
import { useTranslation } from 'react-i18next'
import { useAudio } from '../../contexts/AudioContext'
import Workbench from './Workbench'
import { GameTooltip } from '../common/GameTooltip'
import { getAssetPath } from '../../utils/assetPath'
import { getTranslatedText } from '../../utils/i18nUtils'
interface LocationViewProps {
location: Location
playerState: PlayerState | null
combatState: CombatState | null
message: string
locationMessages: Array<{ time: string; message: string }>
expandedCorpse: string | null
corpseDetails: any
mobileMenuOpen: string
showCraftingMenu: boolean
showRepairMenu: boolean
workbenchTab: WorkbenchTab
craftableItems: any[]
repairableItems: any[]
uncraftableItems: any[]
craftFilter: string
repairFilter: string
uncraftFilter: string
craftCategoryFilter: string
profile: Profile | null
onSetMessage: (msg: string) => void
onInitiateCombat: (npcId: number) => void
onInitiatePvP: (playerId: number) => void
onPickup: (itemId: number, quantity: number) => void
onLootCorpse: (corpseId: string) => void
onLootCorpseItem: (corpseId: string, itemIndex: number | null) => void
onSetExpandedCorpse: (corpseId: string | null) => void
onOpenCrafting?: () => void
onOpenRepair?: () => void
onCloseCrafting: () => void
onSwitchWorkbenchTab: (tab: WorkbenchTab) => void
onSetCraftFilter: (filter: string) => void
onSetRepairFilter: (filter: string) => void
onSetUncraftFilter: (filter: string) => void
onSetCraftCategoryFilter: (category: string) => void
onCraft: (itemId: number) => void
onRepair: (uniqueItemId: string, inventoryId: number) => void
onUncraft: (uniqueItemId: string, inventoryId: number) => void
}
function LocationView({
location,
message,
locationMessages,
expandedCorpse,
corpseDetails,
mobileMenuOpen,
showCraftingMenu,
showRepairMenu,
workbenchTab,
craftableItems,
repairableItems,
uncraftableItems,
craftFilter,
repairFilter,
uncraftFilter,
craftCategoryFilter,
profile,
onSetMessage,
onInitiateCombat,
onInitiatePvP,
onPickup,
onLootCorpse,
onLootCorpseItem,
onSetExpandedCorpse,
onOpenCrafting,
onOpenRepair,
onCloseCrafting,
onSwitchWorkbenchTab,
onSetCraftFilter,
onSetRepairFilter,
onSetUncraftFilter,
onSetCraftCategoryFilter,
onCraft,
onRepair,
onUncraft
}: LocationViewProps) {
const { t } = useTranslation()
const { playSfx } = useAudio()
return (
{getTranslatedText(location.name)}
{location.danger_level !== undefined && location.danger_level === 0 && (
✓ Safe
)}
{location.danger_level !== undefined && location.danger_level > 0 && (
⚠️ {location.danger_level}
)}
{location.tags && location.tags.length > 0 && (
{location.tags.map((tag: string, i: number) => {
const isClickable = tag === 'workbench' || tag === 'repair_station'
const handleClick = () => {
if (tag === 'workbench' && onOpenCrafting) onOpenCrafting()
else if (tag === 'repair_station' && onOpenRepair) onOpenRepair()
}
return (
{tag === 'workbench' && t('tags.workbench')}
{tag === 'repair_station' && t('tags.repairStation')}
{tag === 'safe_zone' && t('tags.safeZone')}
{tag === 'shop' && t('tags.shop')}
{tag === 'shelter' && t('tags.shelter')}
{tag === 'medical' && t('tags.medical')}
{tag === 'storage' && t('tags.storage')}
{tag === 'water_source' && t('tags.water')}
{tag === 'food_source' && t('tags.food')}
{tag !== 'workbench' && tag !== 'repair_station' && tag !== 'safe_zone' && tag !== 'shop' && tag !== 'shelter' && tag !== 'medical' && tag !== 'storage' && tag !== 'water_source' && tag !== 'food_source' && `🏷️ ${tag}`}
)
})}
)}
{location.image_url && (
})
(e.currentTarget.style.display = 'none')}
/>
)}
{getTranslatedText(location.description)}
{message && (
onSetMessage('')}>
{message}
)}
{locationMessages.length > 0 && (
{t('location.recentActivity')}
{locationMessages.slice(-10).reverse().map((msg, idx) => (
{msg.time}
{msg.message}
))}
)}
{/* Enemies */}
{location.npcs.filter((npc: any) => npc.type === 'enemy').length > 0 && (
{t('location.enemies')}
{location.npcs.filter((npc: any) => npc.type === 'enemy').map((enemy: any, i: number) => (
{enemy.id && (

{ e.currentTarget.style.display = 'none' }}
/>
)}
{getTranslatedText(enemy.name)}
{enemy.level &&
{t('location.level')} {enemy.level}
}
))}
)}
{/* Corpses */}
{location.corpses && location.corpses.length > 0 && (
{t('location.corpses')}
{location.corpses.map((corpse: any) => (
{corpse.emoji} {getTranslatedText(corpse.name)}
{corpse.loot_count} {t('location.items')}
{expandedCorpse === String(corpse.id) && corpseDetails && corpseDetails.loot_items && (
{t('location.lootableItems')}
{corpseDetails.loot_items.map((item: any) => (
{item.emoji} {getTranslatedText(item.item_name)}
{t('common.qty')}: {item.quantity_min}{item.quantity_min !== item.quantity_max ? `-${item.quantity_max}` : ''}
{item.required_tool && (
🔧 {getTranslatedText(item.required_tool_name)} {item.has_tool ? '✓' : '✗'}
)}
))}
)}
))}
)}
{/* Friendly NPCs */}
{location.npcs.filter((npc: any) => npc.type !== 'enemy').length > 0 && (
{t('location.npcs')}
{location.npcs.filter((npc: any) => npc.type !== 'enemy').map((npc: any, i: number) => (
🧑
{getTranslatedText(npc.name)}
{npc.level &&
{t('location.level')} {npc.level}
}
))}
)}
{/* Items on Ground */}
{location.items.length > 0 && (
{t('location.itemsOnGround')}
{location.items.map((item: any, i: number) => (
{item.image_path ? (
})
{
(e.target as HTMLImageElement).style.display = 'none';
const icon = (e.target as HTMLImageElement).nextElementSibling;
if (icon) icon.classList.remove('hidden');
}}
/>
) : null}
{item.emoji || '📦'}
{getTranslatedText(item.name) || 'Unknown Item'}
{item.quantity > 1 &&
×{item.quantity}
}
{item.description && {getTranslatedText(item.description)}
}
{item.weight !== undefined && item.weight > 0 && (
⚖️ {t('stats.weight')}: {item.weight}kg {item.quantity > 1 && `(Total: ${(item.weight * item.quantity).toFixed(2)}kg)`}
)}
{item.volume !== undefined && item.volume > 0 && (
📦 {t('stats.volume')}: {item.volume}L {item.quantity > 1 && `(Total: ${(item.volume * item.quantity).toFixed(2)}L)`}
)}
{item.hp_restore && item.hp_restore > 0 && (
❤️ {t('stats.hpRestore')}: +{item.hp_restore}
)}
{item.stamina_restore && item.stamina_restore > 0 && (
⚡ {t('stats.staminaRestore')}: +{item.stamina_restore}
)}
{item.damage_min !== undefined && item.damage_max !== undefined && (item.damage_min > 0 || item.damage_max > 0) && (
⚔️ {t('stats.damage')}: {item.damage_min}-{item.damage_max}
)}
{item.durability !== undefined && item.durability !== null && item.max_durability !== undefined && item.max_durability !== null && (
🔧 {t('stats.durability')}: {item.durability}/{item.max_durability}
)}
{item.tier !== undefined && item.tier !== null && item.tier > 0 && (
⭐ {t('stats.tier')}: {item.tier}
)}
}>
{item.quantity === 1 ? (
) : (
{item.quantity >= 5 && (
)}
{item.quantity >= 10 && (
)}
)}
))}
)}
{/* Other Players */}
{location.other_players && location.other_players.length > 0 && (
👥 Other Players
{location.other_players.map((player: any, i: number) => (
🧍
{player.name || player.username}
Lv. {player.level}
{player.level_diff !== undefined && (
{player.level_diff > 0 ? `+${player.level_diff}` : player.level_diff} levels
)}
{player.can_pvp && (
)}
{!player.can_pvp && player.level_diff !== undefined && Math.abs(player.level_diff) > 3 && (
{t('game.levelDifferenceTooHigh')}
)}
{!player.can_pvp && location.danger_level !== undefined && location.danger_level < 3 && (
{t('game.areaTooSafeForPvP')}
)}
))}
)}
{(showCraftingMenu || showRepairMenu) && (
)}
)
}
export default LocationView