wip repl
This commit is contained in:
parent
e862b02019
commit
e49fbede9a
21 changed files with 1280 additions and 148 deletions
21
tools/aseprite/package.sh
Executable file
21
tools/aseprite/package.sh
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
EXTENSION_NAME="tile-props"
|
||||
SOURCE_DIR="$(cd "$(dirname "$0")" && pwd)/$EXTENSION_NAME"
|
||||
ZIP_FILE="$(cd "$(dirname "$0")" && pwd)/${EXTENSION_NAME}.aseprite-extension"
|
||||
|
||||
echo "Creating extension package: ${EXTENSION_NAME}.aseprite-extension"
|
||||
cd "$(dirname "$SOURCE_DIR")"
|
||||
rm -f "$ZIP_FILE"
|
||||
zip -q -r "$ZIP_FILE" "$EXTENSION_NAME"
|
||||
|
||||
echo "✓ Extension package created: $ZIP_FILE"
|
||||
echo ""
|
||||
echo "To install in Aseprite:"
|
||||
echo "1. Open Aseprite"
|
||||
echo "2. Go to Edit → Preferences → Extensions"
|
||||
echo "3. Click 'Add Extension'"
|
||||
echo "4. Select: $ZIP_FILE"
|
||||
echo "5. Restart Aseprite"
|
||||
41
tools/aseprite/tile-props/README.md
Normal file
41
tools/aseprite/tile-props/README.md
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# pxl8 Tile Properties Extension
|
||||
|
||||
Aseprite extension for editing custom tile properties that are exported to pxl8 engine.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Copy this directory to your Aseprite extensions folder:
|
||||
- **Windows**: `%APPDATA%\Aseprite\extensions\tile-properties`
|
||||
- **macOS**: `~/Library/Application Support/Aseprite/extensions/tile-properties`
|
||||
- **Linux**: `~/.config/aseprite/extensions/tile-properties`
|
||||
|
||||
2. Restart Aseprite
|
||||
|
||||
## Usage
|
||||
|
||||
1. Open a tilemap sprite in Aseprite (File → New → Tilemap)
|
||||
2. Create your tileset with tiles
|
||||
3. Select a tile in the Tileset panel
|
||||
4. Go to **Edit → Edit Tile Properties** (menu will be enabled when a tile is selected)
|
||||
5. Add/edit custom properties:
|
||||
- **Name**: Property key (e.g., `solid`, `terrain`, `move_cost`)
|
||||
- **Type**: `boolean`, `number`, or `string`
|
||||
- **Value**: The property value
|
||||
6. Click **Apply** to save
|
||||
|
||||
## Example Properties
|
||||
|
||||
For a grass tile in a tactical RPG:
|
||||
- `solid` (boolean): `false`
|
||||
- `terrain` (string): `grass`
|
||||
- `move_cost` (number): `1`
|
||||
- `defense_bonus` (number): `0`
|
||||
|
||||
For a wall tile:
|
||||
- `solid` (boolean): `true`
|
||||
- `terrain` (string): `wall`
|
||||
- `blocks_sight` (boolean): `true`
|
||||
|
||||
## How It Works
|
||||
|
||||
Properties are saved directly into the Aseprite file using the tile properties API. When pxl8 loads the tilemap, these properties are automatically extracted and made available in your Fennel/Lua code via `pxl8.tilemap_get_tile_data()`.
|
||||
283
tools/aseprite/tile-props/main.lua
Normal file
283
tools/aseprite/tile-props/main.lua
Normal file
|
|
@ -0,0 +1,283 @@
|
|||
-- pxl8 tile properties editor
|
||||
-- provides a ui for editing custom properties of tilemap tiles
|
||||
|
||||
local DEBUG = false
|
||||
|
||||
local function log(msg)
|
||||
if DEBUG then
|
||||
print("[tile-properties] " .. msg)
|
||||
end
|
||||
end
|
||||
|
||||
local function getSelectedTile()
|
||||
log("getSelectedTile() called")
|
||||
|
||||
if not app then
|
||||
log("ERROR: app is nil!")
|
||||
return nil
|
||||
end
|
||||
|
||||
local sprite = app.sprite
|
||||
log("sprite: " .. tostring(sprite))
|
||||
if not sprite then
|
||||
log("No sprite selected")
|
||||
return nil
|
||||
end
|
||||
|
||||
local layer = app.layer
|
||||
log("layer: " .. tostring(layer))
|
||||
if not layer or not layer.isTilemap then
|
||||
log("Layer is not a tilemap")
|
||||
return nil
|
||||
end
|
||||
|
||||
local tileset = layer.tileset
|
||||
log("tileset: " .. tostring(tileset))
|
||||
if not tileset then
|
||||
log("No tileset in layer")
|
||||
return nil
|
||||
end
|
||||
|
||||
local tileIndex = app.fgTile
|
||||
log("tileIndex: " .. tostring(tileIndex))
|
||||
if not tileIndex or tileIndex < 0 then
|
||||
log("Invalid tile index")
|
||||
return nil
|
||||
end
|
||||
|
||||
log("Selected tile: tileset=" .. tostring(tileset) .. ", index=" .. tostring(tileIndex))
|
||||
return tileset, tileIndex
|
||||
end
|
||||
|
||||
local function getTileProperties(tileset, tileIndex)
|
||||
log("getTileProperties() called for tile index: " .. tostring(tileIndex))
|
||||
|
||||
local tile = tileset:tile(tileIndex)
|
||||
if not tile then
|
||||
log("Could not get tile object")
|
||||
return {}
|
||||
end
|
||||
|
||||
if not tile.properties then
|
||||
log("Tile has no properties")
|
||||
return {}
|
||||
end
|
||||
|
||||
local props = {}
|
||||
for key, value in pairs(tile.properties) do
|
||||
local propType = "string"
|
||||
if type(value) == "boolean" then
|
||||
propType = "boolean"
|
||||
elseif type(value) == "number" then
|
||||
propType = "number"
|
||||
end
|
||||
|
||||
table.insert(props, {
|
||||
key = key,
|
||||
type = propType,
|
||||
value = value
|
||||
})
|
||||
end
|
||||
|
||||
log("Found " .. #props .. " properties")
|
||||
return props
|
||||
end
|
||||
|
||||
local function setTileProperties(tileset, tileIndex, props)
|
||||
log("setTileProperties() called for tile index: " .. tostring(tileIndex))
|
||||
|
||||
local tile = tileset:tile(tileIndex)
|
||||
if not tile then
|
||||
log("Could not get tile object")
|
||||
return
|
||||
end
|
||||
|
||||
tile.properties = {}
|
||||
local count = 0
|
||||
for _, prop in ipairs(props) do
|
||||
if prop.key and prop.key ~= "" then
|
||||
local value = prop.value
|
||||
if prop.type == "boolean" then
|
||||
value = (value == true or value == "true")
|
||||
elseif prop.type == "number" then
|
||||
value = tonumber(value) or 0
|
||||
end
|
||||
tile.properties[prop.key] = value
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
log("Set " .. count .. " properties")
|
||||
end
|
||||
|
||||
local function showPropertyEditor(existingProps)
|
||||
log("showPropertyEditor() called")
|
||||
|
||||
local tileset, tileIndex = getSelectedTile()
|
||||
|
||||
if not tileset then
|
||||
log("No tileset selected, showing alert")
|
||||
app.alert("Please select a tile in the tileset")
|
||||
return
|
||||
end
|
||||
|
||||
log("Getting properties for tile")
|
||||
local properties = existingProps or getTileProperties(tileset, tileIndex)
|
||||
|
||||
local dlg = Dialog("Tile Properties - Tile #" .. tileIndex)
|
||||
|
||||
dlg:label{ text="Properties:" }
|
||||
|
||||
for i, prop in ipairs(properties) do
|
||||
dlg:separator()
|
||||
dlg:entry{
|
||||
id = "key_" .. i,
|
||||
label = "Name:",
|
||||
text = prop.key
|
||||
}
|
||||
dlg:combobox{
|
||||
id = "type_" .. i,
|
||||
label = "Type:",
|
||||
option = prop.type,
|
||||
options = { "boolean", "number", "string" },
|
||||
onchange = function()
|
||||
-- Save all current field values and apply type conversions
|
||||
for j = 1, #properties do
|
||||
properties[j].key = dlg.data["key_" .. j] or properties[j].key
|
||||
local newType = dlg.data["type_" .. j] or properties[j].type
|
||||
local oldType = properties[j].type
|
||||
|
||||
-- Apply default values when type changes
|
||||
if newType ~= oldType then
|
||||
if newType == "boolean" then
|
||||
properties[j].value = false
|
||||
elseif newType == "number" then
|
||||
properties[j].value = 0
|
||||
else -- string
|
||||
properties[j].value = ""
|
||||
end
|
||||
else
|
||||
properties[j].value = dlg.data["value_" .. j] or properties[j].value
|
||||
end
|
||||
|
||||
properties[j].type = newType
|
||||
end
|
||||
dlg:close()
|
||||
showPropertyEditor(properties)
|
||||
end
|
||||
}
|
||||
|
||||
if prop.type == "boolean" then
|
||||
dlg:check{
|
||||
id = "value_" .. i,
|
||||
text = "",
|
||||
selected = prop.value
|
||||
}
|
||||
elseif prop.type == "number" then
|
||||
dlg:number{
|
||||
id = "value_" .. i,
|
||||
label = "Value:",
|
||||
text = tostring(prop.value),
|
||||
decimals = 0
|
||||
}
|
||||
else
|
||||
dlg:entry{
|
||||
id = "value_" .. i,
|
||||
label = "Value:",
|
||||
text = tostring(prop.value)
|
||||
}
|
||||
end
|
||||
|
||||
dlg:button{
|
||||
id = "delete_" .. i,
|
||||
text = "Delete",
|
||||
onclick = function()
|
||||
-- Save current field values before deleting
|
||||
for j = 1, #properties do
|
||||
properties[j].key = dlg.data["key_" .. j] or properties[j].key
|
||||
properties[j].type = dlg.data["type_" .. j] or properties[j].type
|
||||
properties[j].value = dlg.data["value_" .. j] or properties[j].value
|
||||
end
|
||||
table.remove(properties, i)
|
||||
dlg:close()
|
||||
showPropertyEditor(properties)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
dlg:separator()
|
||||
dlg:button{
|
||||
text = "Add Property",
|
||||
onclick = function()
|
||||
-- Save current field values before adding new property
|
||||
for i = 1, #properties do
|
||||
properties[i].key = dlg.data["key_" .. i] or properties[i].key
|
||||
properties[i].type = dlg.data["type_" .. i] or properties[i].type
|
||||
properties[i].value = dlg.data["value_" .. i] or properties[i].value
|
||||
end
|
||||
table.insert(properties, {
|
||||
key = "",
|
||||
type = "string",
|
||||
value = ""
|
||||
})
|
||||
dlg:close()
|
||||
showPropertyEditor(properties)
|
||||
end
|
||||
}
|
||||
|
||||
dlg:separator()
|
||||
dlg:button{
|
||||
text = "Apply",
|
||||
onclick = function()
|
||||
local newProps = {}
|
||||
for i = 1, #properties do
|
||||
local key = dlg.data["key_" .. i]
|
||||
local propType = dlg.data["type_" .. i]
|
||||
local value = dlg.data["value_" .. i]
|
||||
|
||||
if key and key ~= "" then
|
||||
table.insert(newProps, {
|
||||
key = key,
|
||||
type = propType,
|
||||
value = value
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
setTileProperties(tileset, tileIndex, newProps)
|
||||
dlg:close()
|
||||
end
|
||||
}
|
||||
|
||||
dlg:button{ text = "Cancel" }
|
||||
|
||||
dlg:show()
|
||||
end
|
||||
|
||||
function init(plugin)
|
||||
log("=== PLUGIN INIT START ===")
|
||||
|
||||
if not plugin then
|
||||
print("[tile-properties] ERROR: plugin is nil!")
|
||||
return
|
||||
end
|
||||
|
||||
-- Register in Sprite menu
|
||||
plugin:newCommand{
|
||||
id = "TilePropertiesEditor",
|
||||
title = "Tile Properties",
|
||||
group = "sprite_properties",
|
||||
onenabled = function()
|
||||
local tileset, tileIndex = getSelectedTile()
|
||||
return tileset ~= nil and tileIndex ~= nil
|
||||
end,
|
||||
onclick = showPropertyEditor
|
||||
}
|
||||
|
||||
log("Command registered in Sprite menu")
|
||||
|
||||
log("=== PLUGIN INIT COMPLETE ===")
|
||||
end
|
||||
|
||||
function exit(plugin)
|
||||
log("=== PLUGIN EXIT ===")
|
||||
end
|
||||
17
tools/aseprite/tile-props/package.json
Normal file
17
tools/aseprite/tile-props/package.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "tile-props",
|
||||
"displayName": "pxl8 tile props",
|
||||
"description": "Edit custom properties for tilemap tiles",
|
||||
"version": "1.0.0",
|
||||
"author": {
|
||||
"name": "pxl8.org"
|
||||
},
|
||||
"categories": ["Scripts"],
|
||||
"contributes": {
|
||||
"scripts": [
|
||||
{
|
||||
"path": "./main.lua"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue