Files
npc-config-app/src/components/NPCBasicSettings.tsx
2025-08-11 21:32:22 +02:00

199 lines
7.7 KiB
TypeScript

import React from 'react';
import type { NPCConfiguration, NPCHitboxValue } from '../types/npc';
interface NPCBasicSettingsProps {
config: NPCConfiguration;
onChange: (config: NPCConfiguration) => void;
}
export const NPCBasicSettings: React.FC<NPCBasicSettingsProps> = ({ config, onChange }) => {
const handleChange = (field: keyof NPCConfiguration, value: any) => {
onChange({ ...config, [field]: value });
};
const handleHitboxChange = (hitbox: NPCHitboxValue) => {
handleChange('hitbox', hitbox);
};
const handleNamesChange = (names: string) => {
handleChange('names', names.split(',').map(name => name.trim()).filter(name => name));
};
const handleAspectsChange = (aspects: string) => {
handleChange('aspects', aspects ? aspects.split(',').map(aspect => aspect.trim()).filter(aspect => aspect) : undefined);
};
return (
<div className="space-y-6">
<h2 className="text-xl font-semibold text-gray-900">Basic Settings</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium text-gray-700">Resource Identifier</label>
<input
type="text"
value={config.resourceIdentifier}
onChange={(e) => handleChange('resourceIdentifier', e.target.value)}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
placeholder="cobblemon:npc_name"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Names (comma-separated)</label>
<input
type="text"
value={config.names.join(', ')}
onChange={(e) => handleNamesChange(e.target.value)}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
placeholder="NPC Name 1, NPC Name 2"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Hitbox</label>
<div className="mt-1 space-y-2">
<label className="inline-flex items-center">
<input
type="radio"
checked={config.hitbox === "player"}
onChange={() => handleHitboxChange("player")}
className="form-radio"
/>
<span className="ml-2">Player (default)</span>
</label>
<div className="space-y-1">
<label className="inline-flex items-center">
<input
type="radio"
checked={typeof config.hitbox === "object"}
onChange={() => handleHitboxChange({ width: 0.6, height: 1.8 })}
className="form-radio"
/>
<span className="ml-2">Custom</span>
</label>
{typeof config.hitbox === "object" && (
<div className="ml-6 grid grid-cols-2 gap-2">
<div>
<label className="block text-xs text-gray-600">Width</label>
<input
type="number"
step="0.1"
value={config.hitbox.width}
onChange={(e) => handleHitboxChange({
width: parseFloat(e.target.value),
height: typeof config.hitbox === "object" ? config.hitbox.height : 1.8
})}
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm"
/>
</div>
<div>
<label className="block text-xs text-gray-600">Height</label>
<input
type="number"
step="0.1"
value={config.hitbox.height}
onChange={(e) => handleHitboxChange({
width: typeof config.hitbox === "object" ? config.hitbox.width : 0.6,
height: parseFloat(e.target.value)
})}
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 text-sm"
/>
</div>
</div>
)}
</div>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Model Scale</label>
<input
type="number"
step="0.01"
value={config.modelScale || 0.9375}
onChange={(e) => handleChange('modelScale', parseFloat(e.target.value))}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700">Aspects (comma-separated)</label>
<input
type="text"
value={config.aspects?.join(', ') || ''}
onChange={(e) => handleAspectsChange(e.target.value)}
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500"
placeholder="aspect1, aspect2"
/>
</div>
</div>
<div className="space-y-3">
<h3 className="text-lg font-medium text-gray-900">Behavior Settings</h3>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
<label className="inline-flex items-center">
<input
type="checkbox"
checked={config.isInvulnerable || false}
onChange={(e) => handleChange('isInvulnerable', e.target.checked)}
className="form-checkbox"
/>
<span className="ml-2">Invulnerable</span>
</label>
<label className="inline-flex items-center">
<input
type="checkbox"
checked={!(config.canDespawn ?? true)}
onChange={(e) => handleChange('canDespawn', !e.target.checked)}
className="form-checkbox"
/>
<span className="ml-2">Persistent</span>
</label>
<label className="inline-flex items-center">
<input
type="checkbox"
checked={config.isMovable ?? true}
onChange={(e) => handleChange('isMovable', e.target.checked)}
className="form-checkbox"
/>
<span className="ml-2">Movable</span>
</label>
<label className="inline-flex items-center">
<input
type="checkbox"
checked={config.isLeashable || false}
onChange={(e) => handleChange('isLeashable', e.target.checked)}
className="form-checkbox"
/>
<span className="ml-2">Leashable</span>
</label>
<label className="inline-flex items-center">
<input
type="checkbox"
checked={config.allowProjectileHits ?? true}
onChange={(e) => handleChange('allowProjectileHits', e.target.checked)}
className="form-checkbox"
/>
<span className="ml-2">Projectile Hits</span>
</label>
<label className="inline-flex items-center">
<input
type="checkbox"
checked={config.hideNameTag || false}
onChange={(e) => handleChange('hideNameTag', e.target.checked)}
className="form-checkbox"
/>
<span className="ml-2">Hide Name Tag</span>
</label>
</div>
</div>
</div>
);
};