-
Notifications
You must be signed in to change notification settings - Fork 25
feat(world-builder): multi-layer tile opacity and blend mode validator #136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
919b28f
9daf0e1
21a10f1
392eedc
ac8a9c2
b422e22
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| # feat(world-builder): register uploaded graphics and extend palette schemas (#6) | ||
|
|
||
| ## Summary | ||
| Resolves #6 by providing `paletteEntrySchema` and `validatePaletteEntry` to validate multi-layer palette definitions, enforce non-colliding graphic index allocations (`UPLOADED_GRAPHIC_INDEX_START = 1_000_000`), and verify graphic existence across engine and uploaded assets. | ||
|
|
||
| ### Changes | ||
| - Implemented `paletteEntrySchema` and `validatePaletteEntry` in `api/src/repositories/worldBuilder.ts`. | ||
| - Added unit tests in `api/src/repositories/__tests__/paletteValidation.test.ts`. | ||
|
|
||
| Closes #6 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| { | ||
| "1": { | ||
| "name": "Comerciante de Ullathorpe", | ||
| "desc": "Vendedor general de provisiones y equipamiento básico", | ||
| "npcType": 1, | ||
| "idHead": 1, | ||
| "idBody": 1, | ||
| "movement": 0, | ||
| "hp": 100, | ||
| "maxHp": 100, | ||
| "gold": 500, | ||
| "exp": 0, | ||
| "trade": [ | ||
| { | ||
| "item": 1, | ||
| "cant": 100 | ||
| }, | ||
| { | ||
| "item": 2, | ||
| "cant": 50 | ||
| }, | ||
| { | ||
| "item": 3, | ||
| "cant": 50 | ||
| } | ||
| ] | ||
| }, | ||
| "2": { | ||
| "name": "Sacerdote", | ||
| "desc": "Cura heridas y resucita a los aventureros caídos", | ||
| "npcType": 2, | ||
| "idHead": 2, | ||
| "idBody": 2, | ||
| "movement": 0, | ||
| "hp": 250, | ||
| "maxHp": 250, | ||
| "gold": 0, | ||
| "exp": 0 | ||
| }, | ||
| "3": { | ||
| "name": "Banquero", | ||
| "desc": "Guarda oro y pertenencias en las bóvedas seguras", | ||
| "npcType": 3, | ||
| "idHead": 3, | ||
| "idBody": 3, | ||
| "movement": 0, | ||
| "hp": 200, | ||
| "maxHp": 200, | ||
| "gold": 10000, | ||
| "exp": 0 | ||
| }, | ||
| "4": { | ||
| "name": "Guardia Real", | ||
| "desc": "Protege las ciudades de criminales y criaturas salvajes", | ||
| "npcType": 4, | ||
| "idHead": 4, | ||
| "idBody": 4, | ||
| "movement": 1, | ||
| "hp": 500, | ||
| "maxHp": 500, | ||
| "minHit": 20, | ||
| "maxHit": 40, | ||
| "def": 25, | ||
| "poderAtaque": 50, | ||
| "poderEvasion": 30, | ||
| "gold": 50, | ||
| "exp": 50 | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| /** | ||
| * Bitcoindefi/OpenAO - Multi-layer tile opacity & blend mode validator | ||
| */ | ||
| export type BlendMode = 'normal' | 'multiply' | 'screen' | 'overlay'; | ||
|
|
||
| export interface LayerRenderConfig { | ||
| layerIndex: number; | ||
| opacity: number; | ||
| blendMode: BlendMode; | ||
| visible: boolean; | ||
| } | ||
|
|
||
| export function validateLayerRenderConfig(config: Partial<LayerRenderConfig>): LayerRenderConfig { | ||
| const layerIndex = Math.max(0, Math.floor(config.layerIndex ?? 0)); | ||
| const opacity = Math.min(1.0, Math.max(0.0, config.opacity ?? 1.0)); | ||
|
Comment on lines
+14
to
+15
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Edge Case: NaN opacity/layerIndex bypass clamping
Guard against NaN/Infinity before clamping:
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎 |
||
| const validBlendModes: BlendMode[] = ['normal', 'multiply', 'screen', 'overlay']; | ||
| const blendMode = validBlendModes.includes(config.blendMode as BlendMode) ? (config.blendMode as BlendMode) : 'normal'; | ||
| const visible = config.visible !== false; | ||
|
|
||
| return { layerIndex, opacity, blendMode, visible }; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| /** | ||
| * Bitcoindefi/OpenAO - Map NPC Placement & Patrol Generator (Issue #8) | ||
| */ | ||
| export interface NpcPlacementConfig { | ||
| npcId: number; | ||
| mapId: number; | ||
| x: number; | ||
| y: number; | ||
| heading: number; | ||
| patrolRadius?: number; | ||
| } | ||
|
|
||
| export interface PatrolCoordinate { | ||
| x: number; | ||
| y: number; | ||
| step: number; | ||
| } | ||
|
|
||
| export function generatePatrolWaypoints( | ||
| startX: number, | ||
| startY: number, | ||
| radius: number = 3, | ||
| mapBounds: { minX: number; maxX: number; minY: number; maxY: number } = { minX: 1, maxX: 100, minY: 1, maxY: 100 } | ||
| ): PatrolCoordinate[] { | ||
| const waypoints: PatrolCoordinate[] = []; | ||
| const offsets = [ | ||
| { dx: 0, dy: 0 }, | ||
| { dx: radius, dy: 0 }, | ||
| { dx: radius, dy: radius }, | ||
| { dx: 0, dy: radius }, | ||
| { dx: -radius, dy: radius }, | ||
| { dx: -radius, dy: 0 }, | ||
| { dx: -radius, dy: -radius }, | ||
| { dx: 0, dy: -radius }, | ||
| { dx: radius, dy: -radius } | ||
| ]; | ||
|
|
||
| let step = 0; | ||
| for (const off of offsets) { | ||
| const targetX = Math.min(Math.max(startX + off.dx, mapBounds.minX), mapBounds.maxX); | ||
| const targetY = Math.min(Math.max(startY + off.dy, mapBounds.minY), mapBounds.maxY); | ||
| waypoints.push({ x: targetX, y: targetY, step: step++ }); | ||
| } | ||
|
|
||
| return waypoints; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Quality: Stray PR_DESCRIPTION_DRAFT.md committed to repo root
PR_DESCRIPTION_DRAFT.mdappears to be a working draft accidentally committed, and its content describes a different feature (#6 palette schemas) unrelated to this PR. Remove it from the commit so it doesn't clutter the repository root.Delete the accidentally committed draft file:
Check the box to apply the fix or reply for a change | Was this helpful? React with 👍 / 👎