Add some more complex tiles to the palette; add ,/. shortcuts
This commit is contained in:
parent
c4bb1f3df1
commit
f462ae3394
@ -85,6 +85,82 @@ class HintTileEditor extends TileEditorOverlay {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DirectionalBlockTileEditor extends TileEditorOverlay {
|
||||||
|
constructor(conductor) {
|
||||||
|
super(conductor);
|
||||||
|
|
||||||
|
let svg_icons = [];
|
||||||
|
for (let center of [[16, 0], [16, 16], [0, 16], [0, 0]]) {
|
||||||
|
let symbol = mk_svg('svg', {viewBox: '0 0 16 16'},
|
||||||
|
mk_svg('circle', {cx: center[0], cy: center[1], r: 3}),
|
||||||
|
mk_svg('circle', {cx: center[0], cy: center[1], r: 13}),
|
||||||
|
);
|
||||||
|
svg_icons.push(symbol);
|
||||||
|
}
|
||||||
|
svg_icons.push(mk_svg('svg', {viewBox: '0 0 16 16'},
|
||||||
|
mk_svg('rect', {x: -2, y: 3, width: 20, height: 10}),
|
||||||
|
));
|
||||||
|
svg_icons.push(mk_svg('svg', {viewBox: '0 0 16 16'},
|
||||||
|
mk_svg('rect', {x: 3, y: -2, width: 10, height: 20}),
|
||||||
|
));
|
||||||
|
|
||||||
|
this.root.append(mk('h3', "Arrows"));
|
||||||
|
let arrow_list = mk('ol.editor-directional-block-tile-arrows.editor-tile-editor-svg-parts');
|
||||||
|
// Arrange the arrows in a grid
|
||||||
|
for (let [direction, icon] of [
|
||||||
|
[null, mk_svg('path', {d: 'M 8,16 v -8 h 8'})],
|
||||||
|
['north', mk_svg('path', {d: 'M 0,12 h 16 l -8,-8 z'})],
|
||||||
|
[null, mk_svg('path', {d: 'M 0,8 h 8 v 8'})],
|
||||||
|
['west', mk_svg('path', {d: 'M 12,16 v -16 l -8,8 z'})],
|
||||||
|
[null, null],
|
||||||
|
['east', mk_svg('path', {d: 'M 4,0 v 16 l 8,-8 z'})],
|
||||||
|
[null, mk_svg('path', {d: 'M 16,8 h -8 v -8'})],
|
||||||
|
['south', mk_svg('path', {d: 'M 16,4 h -16 l 8,8 z'})],
|
||||||
|
[null, mk_svg('path', {d: 'M 8,0 v 8 h -8'})],
|
||||||
|
]) {
|
||||||
|
let li = mk('li');
|
||||||
|
let svg;
|
||||||
|
if (icon) {
|
||||||
|
svg = mk_svg('svg', {viewBox: '0 0 16 16'}, icon);
|
||||||
|
}
|
||||||
|
if (direction === null) {
|
||||||
|
if (svg) {
|
||||||
|
li.append(svg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let input = mk('input', {type: 'checkbox', name: 'direction', value: direction});
|
||||||
|
li.append(mk('label', input, svg));
|
||||||
|
}
|
||||||
|
arrow_list.append(li);
|
||||||
|
}
|
||||||
|
arrow_list.addEventListener('change', ev => {
|
||||||
|
if (! this.tile)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ev.target.checked) {
|
||||||
|
this.tile.arrows.add(ev.target.value);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.tile.arrows.delete(ev.target.value);
|
||||||
|
}
|
||||||
|
this.editor.mark_tile_dirty(this.tile);
|
||||||
|
});
|
||||||
|
this.root.append(arrow_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
edit_tile(tile) {
|
||||||
|
super.edit_tile(tile);
|
||||||
|
|
||||||
|
for (let input of this.root.elements['direction']) {
|
||||||
|
input.checked = tile.arrows.has(input.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static configure_tile_defaults(tile) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class RailroadTileEditor extends TileEditorOverlay {
|
class RailroadTileEditor extends TileEditorOverlay {
|
||||||
constructor(conductor) {
|
constructor(conductor) {
|
||||||
super(conductor);
|
super(conductor);
|
||||||
@ -105,7 +181,7 @@ class RailroadTileEditor extends TileEditorOverlay {
|
|||||||
));
|
));
|
||||||
|
|
||||||
this.root.append(mk('h3', "Tracks"));
|
this.root.append(mk('h3', "Tracks"));
|
||||||
let track_list = mk('ul.editor-railroad-tile-tracks');
|
let track_list = mk('ul.editor-railroad-tile-tracks.editor-tile-editor-svg-parts');
|
||||||
// Shown as two rows, this puts the straight parts first and the rest in a circle
|
// Shown as two rows, this puts the straight parts first and the rest in a circle
|
||||||
let track_order = [4, 1, 2, 5, 0, 3];
|
let track_order = [4, 1, 2, 5, 0, 3];
|
||||||
for (let i of track_order) {
|
for (let i of track_order) {
|
||||||
@ -168,6 +244,7 @@ class RailroadTileEditor extends TileEditorOverlay {
|
|||||||
export const TILES_WITH_PROPS = {
|
export const TILES_WITH_PROPS = {
|
||||||
floor_letter: LetterTileEditor,
|
floor_letter: LetterTileEditor,
|
||||||
hint: HintTileEditor,
|
hint: HintTileEditor,
|
||||||
|
directional_block: DirectionalBlockTileEditor,
|
||||||
railroad: RailroadTileEditor,
|
railroad: RailroadTileEditor,
|
||||||
// TODO various wireable tiles
|
// TODO various wireable tiles
|
||||||
// TODO initial value of counter
|
// TODO initial value of counter
|
||||||
|
|||||||
@ -612,36 +612,21 @@ class AdjustOperation extends MouseOperation {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (let tile of cell) {
|
// FIXME implement shift to always target floor, or maybe start from bottom
|
||||||
// Rotate railroads, which are a bit complicated
|
for (let i = cell.length - 1; i >= 0; i--) {
|
||||||
if (tile.type.name === 'railroad') {
|
let tile = cell[i];
|
||||||
let new_tracks = 0;
|
|
||||||
let rotated_tracks = [1, 2, 3, 0, 5, 4];
|
|
||||||
for (let [i, new_bit] of rotated_tracks.entries()) {
|
|
||||||
if (tile.tracks & (1 << i)) {
|
|
||||||
new_tracks |= (1 << new_bit);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tile.tracks = new_tracks;
|
|
||||||
|
|
||||||
if (tile.switch_track !== null) {
|
if (this.editor.rotate_tile_right(tile)) {
|
||||||
tile.switch_track = rotated_tracks[tile.switch_track];
|
this.editor.mark_tile_dirty(tile);
|
||||||
}
|
break;
|
||||||
tile.entered_direction = DIRECTIONS[tile.entered_direction].right;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO also directional blocks
|
|
||||||
|
|
||||||
// Toggle tiles that go in obvious pairs
|
// Toggle tiles that go in obvious pairs
|
||||||
let other = ADJUST_TOGGLES_CW[tile.type.name];
|
let other = ADJUST_TOGGLES_CW[tile.type.name];
|
||||||
if (other) {
|
if (other) {
|
||||||
tile.type = TILE_TYPES[other];
|
tile.type = TILE_TYPES[other];
|
||||||
continue;
|
this.editor.mark_tile_dirty(tile);
|
||||||
}
|
break;
|
||||||
|
|
||||||
// Rotate actors
|
|
||||||
if (TILE_TYPES[tile.type.name].is_actor) {
|
|
||||||
tile.direction = DIRECTIONS[tile.direction ?? 'south'].right;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -839,6 +824,7 @@ const EDITOR_TOOLS = {
|
|||||||
icon: 'icons/tool-pencil.png',
|
icon: 'icons/tool-pencil.png',
|
||||||
name: "Pencil",
|
name: "Pencil",
|
||||||
desc: "Place, erase, and select tiles.\nLeft click: draw\nRight click: erase\nShift: Replace all layers\nCtrl-click: eyedrop",
|
desc: "Place, erase, and select tiles.\nLeft click: draw\nRight click: erase\nShift: Replace all layers\nCtrl-click: eyedrop",
|
||||||
|
uses_palette: true,
|
||||||
op1: PencilOperation,
|
op1: PencilOperation,
|
||||||
//op2: EraseOperation,
|
//op2: EraseOperation,
|
||||||
//hover: show current selection under cursor
|
//hover: show current selection under cursor
|
||||||
@ -848,18 +834,21 @@ const EDITOR_TOOLS = {
|
|||||||
icon: 'icons/tool-line.png',
|
icon: 'icons/tool-line.png',
|
||||||
name: "Line",
|
name: "Line",
|
||||||
desc: "Draw straight lines",
|
desc: "Draw straight lines",
|
||||||
|
uses_palette: true,
|
||||||
},
|
},
|
||||||
box: {
|
box: {
|
||||||
// TODO not implemented
|
// TODO not implemented
|
||||||
icon: 'icons/tool-box.png',
|
icon: 'icons/tool-box.png',
|
||||||
name: "Box",
|
name: "Box",
|
||||||
desc: "Fill a rectangular area with tiles",
|
desc: "Fill a rectangular area with tiles",
|
||||||
|
uses_palette: true,
|
||||||
},
|
},
|
||||||
fill: {
|
fill: {
|
||||||
// TODO not implemented
|
// TODO not implemented
|
||||||
icon: 'icons/tool-fill.png',
|
icon: 'icons/tool-fill.png',
|
||||||
name: "Fill",
|
name: "Fill",
|
||||||
desc: "Flood-fill an area with tiles",
|
desc: "Flood-fill an area with tiles",
|
||||||
|
uses_palette: true,
|
||||||
},
|
},
|
||||||
'force-floors': {
|
'force-floors': {
|
||||||
icon: 'icons/tool-force-floors.png',
|
icon: 'icons/tool-force-floors.png',
|
||||||
@ -941,8 +930,8 @@ const EDITOR_PALETTE = [{
|
|||||||
|
|
||||||
'door_blue', 'door_red', 'door_yellow', 'door_green',
|
'door_blue', 'door_red', 'door_yellow', 'door_green',
|
||||||
'water', 'turtle', 'fire',
|
'water', 'turtle', 'fire',
|
||||||
'ice', 'ice_nw', 'ice_ne', 'ice_sw', 'ice_se',
|
'ice', 'ice_nw', // 'ice_ne', 'ice_sw', 'ice_se',
|
||||||
'force_floor_n', 'force_floor_s', 'force_floor_w', 'force_floor_e', 'force_floor_all',
|
'force_floor_n', /* 'force_floor_s', 'force_floor_w', 'force_floor_e', */ 'force_floor_all',
|
||||||
],
|
],
|
||||||
}, {
|
}, {
|
||||||
title: "Items",
|
title: "Items",
|
||||||
@ -980,39 +969,193 @@ const EDITOR_PALETTE = [{
|
|||||||
tiles: [
|
tiles: [
|
||||||
'dirt_block',
|
'dirt_block',
|
||||||
'ice_block',
|
'ice_block',
|
||||||
/*
|
'directional_block/0',
|
||||||
* FIXME this won't work for all kinds of reasons
|
'directional_block/1',
|
||||||
{ name: 'directional_block', arrows: new Set },
|
'directional_block/2a',
|
||||||
{ name: 'directional_block', arrows: new Set(['north']) },
|
'directional_block/2o',
|
||||||
{ name: 'directional_block', arrows: new Set(['north', 'east']) },
|
'directional_block/3',
|
||||||
{ name: 'directional_block', arrows: new Set(['north', 'south']) },
|
'directional_block/4',
|
||||||
{ name: 'directional_block', arrows: new Set(['north', 'east', 'south']) },
|
|
||||||
{ name: 'directional_block', arrows: new Set(['north', 'east', 'south', 'west']) },
|
|
||||||
*/
|
|
||||||
'bomb',
|
|
||||||
'button_gray',
|
|
||||||
'button_green',
|
|
||||||
'green_floor',
|
'green_floor',
|
||||||
'green_wall',
|
'green_wall',
|
||||||
'green_chip',
|
'green_chip',
|
||||||
'green_bomb',
|
'green_bomb',
|
||||||
'button_yellow',
|
'button_green',
|
||||||
'button_blue',
|
'button_blue',
|
||||||
|
'button_yellow',
|
||||||
|
'bomb',
|
||||||
|
|
||||||
'button_red', 'cloner',
|
'button_red', 'cloner',
|
||||||
'button_brown', 'trap',
|
'button_brown', 'trap',
|
||||||
'button_orange', 'flame_jet_off', 'flame_jet_on',
|
'button_orange', 'flame_jet_off', 'flame_jet_on',
|
||||||
'button_pink',
|
'transmogrifier',
|
||||||
'button_black',
|
|
||||||
'purple_floor',
|
|
||||||
'purple_wall',
|
|
||||||
'teleport_blue',
|
'teleport_blue',
|
||||||
'teleport_red',
|
'teleport_red',
|
||||||
'teleport_green',
|
'teleport_green',
|
||||||
'teleport_yellow',
|
'teleport_yellow',
|
||||||
'transmogrifier',
|
'railroad/straight',
|
||||||
|
'railroad/curve',
|
||||||
|
'railroad/switch',
|
||||||
|
],
|
||||||
|
// TODO missing:
|
||||||
|
// - wires, wire tunnels probably a dedicated tool, placing tunnels like a tile makes no sense
|
||||||
|
// - stopwatches normal tiles
|
||||||
|
// - swivel special rotate logic, like ice corners
|
||||||
|
// - canopy normal tile; layering problem
|
||||||
|
// - thin walls special rotate logic, like force floors; layering problem
|
||||||
|
// TODO should tiles that respond to wiring and/or gray buttons be highlighted, highlightable?
|
||||||
|
}, {
|
||||||
|
title: "Logic",
|
||||||
|
tiles: [
|
||||||
|
'logic_gate/not',
|
||||||
|
'logic_gate/and',
|
||||||
|
'logic_gate/or',
|
||||||
|
'logic_gate/xor',
|
||||||
|
'logic_gate/nand',
|
||||||
|
'logic_gate/latch-cw',
|
||||||
|
'logic_gate/latch-ccw',
|
||||||
|
'logic_gate/counter',
|
||||||
|
'button_pink',
|
||||||
|
'button_black',
|
||||||
|
'purple_floor',
|
||||||
|
'purple_wall',
|
||||||
|
'button_gray',
|
||||||
],
|
],
|
||||||
}];
|
}];
|
||||||
|
|
||||||
|
const SPECIAL_PALETTE_ENTRIES = {
|
||||||
|
'directional_block/0': { name: 'directional_block', arrows: new Set },
|
||||||
|
'directional_block/1': { name: 'directional_block', arrows: new Set(['north']) },
|
||||||
|
'directional_block/2a': { name: 'directional_block', arrows: new Set(['north', 'east']) },
|
||||||
|
'directional_block/2o': { name: 'directional_block', arrows: new Set(['north', 'south']) },
|
||||||
|
'directional_block/3': { name: 'directional_block', arrows: new Set(['north', 'east', 'south']) },
|
||||||
|
'directional_block/4': { name: 'directional_block', arrows: new Set(['north', 'east', 'south', 'west']) },
|
||||||
|
// FIXME these should be additive/subtractive, but a track picked up from the level should replace
|
||||||
|
'railroad/straight': { name: 'railroad', tracks: 1 << 5, track_switch: null, entered_direction: 'north' },
|
||||||
|
'railroad/curve': { name: 'railroad', tracks: 1 << 0, track_switch: null, entered_direction: 'north' },
|
||||||
|
'railroad/switch': { name: 'railroad', tracks: 0, track_switch: 0, entered_direction: 'north' },
|
||||||
|
'logic_gate/not': { name: 'logic_gate', direction: 'north', gate_type: 'not' },
|
||||||
|
'logic_gate/and': { name: 'logic_gate', direction: 'north', gate_type: 'and' },
|
||||||
|
'logic_gate/or': { name: 'logic_gate', direction: 'north', gate_type: 'or' },
|
||||||
|
'logic_gate/xor': { name: 'logic_gate', direction: 'north', gate_type: 'xor' },
|
||||||
|
'logic_gate/nand': { name: 'logic_gate', direction: 'north', gate_type: 'nand' },
|
||||||
|
'logic_gate/latch-cw': { name: 'logic_gate', direction: 'north', gate_type: 'latch-cw' },
|
||||||
|
'logic_gate/latch-ccw': { name: 'logic_gate', direction: 'north', gate_type: 'latch-ccw' },
|
||||||
|
'logic_gate/counter': { name: 'logic_gate', direction: 'north', gate_type: 'counter' },
|
||||||
|
};
|
||||||
|
const _RAILROAD_ROTATED_LEFT = [3, 0, 1, 2, 5, 4];
|
||||||
|
const _RAILROAD_ROTATED_RIGHT = [1, 2, 3, 0, 5, 4];
|
||||||
|
const SPECIAL_PALETTE_BEHAVIOR = {
|
||||||
|
directional_block: {
|
||||||
|
pick_palette_entry(tile) {
|
||||||
|
if (tile.arrows.size === 2) {
|
||||||
|
let [a, b] = tile.arrows.keys();
|
||||||
|
if (a === DIRECTIONS[b].opposite) {
|
||||||
|
return 'directional_block/2o';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'directional_block/2a';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return `directional_block/${tile.arrows.size}`;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rotate_left(tile) {
|
||||||
|
tile.arrows = new Set(Array.from(tile.arrows, arrow => DIRECTIONS[arrow].left));
|
||||||
|
},
|
||||||
|
rotate_right(tile) {
|
||||||
|
tile.arrows = new Set(Array.from(tile.arrows, arrow => DIRECTIONS[arrow].right));
|
||||||
|
},
|
||||||
|
},
|
||||||
|
logic_gate: {
|
||||||
|
pick_palette_entry(tile) {
|
||||||
|
return `logic_gate/${tile.gate_type}`;
|
||||||
|
},
|
||||||
|
rotate_left(tile) {
|
||||||
|
if (tile.gate_type !== 'counter') {
|
||||||
|
tile.direction = DIRECTIONS[tile.direction].left;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rotate_right(tile) {
|
||||||
|
if (tile.gate_type !== 'counter') {
|
||||||
|
tile.direction = DIRECTIONS[tile.direction].right;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
railroad: {
|
||||||
|
pick_palette_entry(tile) {
|
||||||
|
// This is a little fuzzy, since railroads are compound, but we just go with the first
|
||||||
|
// one that matches and fall back to the switch if it's empty
|
||||||
|
if (tile.tracks & 0x30) {
|
||||||
|
return 'railroad/straight';
|
||||||
|
}
|
||||||
|
if (tile.tracks) {
|
||||||
|
return 'railroad/curve';
|
||||||
|
}
|
||||||
|
return 'railroad/switch';
|
||||||
|
},
|
||||||
|
rotate_left(tile) {
|
||||||
|
let new_tracks = 0;
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
if (tile.tracks & (1 << i)) {
|
||||||
|
new_tracks |= 1 << _RAILROAD_ROTATED_LEFT[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tile.tracks = new_tracks;
|
||||||
|
|
||||||
|
if (tile.track_switch !== null) {
|
||||||
|
tile.track_switch = _RAILROAD_ROTATED_LEFT[tile.track_switch];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tile.entered_direction) {
|
||||||
|
tile.entered_direction = DIRECTIONS[tile.entered_direction].left;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
rotate_right(tile) {
|
||||||
|
let new_tracks = 0;
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
if (tile.tracks & (1 << i)) {
|
||||||
|
new_tracks |= 1 << _RAILROAD_ROTATED_RIGHT[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tile.tracks = new_tracks;
|
||||||
|
|
||||||
|
if (tile.track_switch !== null) {
|
||||||
|
tile.track_switch = _RAILROAD_ROTATED_RIGHT[tile.track_switch];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tile.entered_direction) {
|
||||||
|
tile.entered_direction = DIRECTIONS[tile.entered_direction].right;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
// Fill in some special behavior that boils down to rotating tiles which happen to be encoded as
|
||||||
|
// different tile types
|
||||||
|
for (let cycle of [
|
||||||
|
['force_floor_n', 'force_floor_e', 'force_floor_s', 'force_floor_w'],
|
||||||
|
['ice_nw', 'ice_ne', 'ice_se', 'ice_sw'],
|
||||||
|
['swivel_nw', 'swivel_ne', 'swivel_se', 'swivel_sw'],
|
||||||
|
]) {
|
||||||
|
for (let [i, name] of cycle.entries()) {
|
||||||
|
let left = cycle[(i - 1 + cycle.length) % cycle.length];
|
||||||
|
let right = cycle[(i + 1) % cycle.length];
|
||||||
|
SPECIAL_PALETTE_BEHAVIOR[name] = {
|
||||||
|
pick_palette_entry(tile) {
|
||||||
|
return name;
|
||||||
|
},
|
||||||
|
rotate_left(tile) {
|
||||||
|
tile.type = TILE_TYPES[left];
|
||||||
|
},
|
||||||
|
rotate_right(tile) {
|
||||||
|
tile.type = TILE_TYPES[right];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export class Editor extends PrimaryView {
|
export class Editor extends PrimaryView {
|
||||||
constructor(conductor) {
|
constructor(conductor) {
|
||||||
@ -1047,6 +1190,28 @@ export class Editor extends PrimaryView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
|
// Keyboard shortcuts
|
||||||
|
window.addEventListener('keydown', ev => {
|
||||||
|
if (! this.active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ev.key === ',') {
|
||||||
|
if (ev.shiftKey) {
|
||||||
|
this.rotate_palette_left();
|
||||||
|
}
|
||||||
|
else if (this.palette_selection) {
|
||||||
|
this.rotate_tile_left(this.palette_selection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ev.key === '.') {
|
||||||
|
if (ev.shiftKey) {
|
||||||
|
this.rotate_palette_right();
|
||||||
|
}
|
||||||
|
else if (this.palette_selection) {
|
||||||
|
this.rotate_tile_right(this.palette_selection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
// Level canvas and mouse handling
|
// Level canvas and mouse handling
|
||||||
this.mouse_op = null;
|
this.mouse_op = null;
|
||||||
this.viewport_el.addEventListener('mousedown', ev => {
|
this.viewport_el.addEventListener('mousedown', ev => {
|
||||||
@ -1234,11 +1399,18 @@ export class Editor extends PrimaryView {
|
|||||||
for (let sectiondef of EDITOR_PALETTE) {
|
for (let sectiondef of EDITOR_PALETTE) {
|
||||||
let section_el = mk('section');
|
let section_el = mk('section');
|
||||||
palette_el.append(mk('h2', sectiondef.title), section_el);
|
palette_el.append(mk('h2', sectiondef.title), section_el);
|
||||||
for (let name of sectiondef.tiles) {
|
for (let key of sectiondef.tiles) {
|
||||||
let entry = this.renderer.create_tile_type_canvas(name);
|
let entry;
|
||||||
entry.setAttribute('data-tile-name', name);
|
if (SPECIAL_PALETTE_ENTRIES[key]) {
|
||||||
|
let tile = SPECIAL_PALETTE_ENTRIES[key];
|
||||||
|
entry = this.renderer.create_tile_type_canvas(tile.name, tile);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
entry = this.renderer.create_tile_type_canvas(key);
|
||||||
|
}
|
||||||
|
entry.setAttribute('data-palette-key', key);
|
||||||
entry.classList = 'palette-entry';
|
entry.classList = 'palette-entry';
|
||||||
this.palette[name] = entry;
|
this.palette[key] = entry;
|
||||||
section_el.append(entry);
|
section_el.append(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1247,7 +1419,18 @@ export class Editor extends PrimaryView {
|
|||||||
if (! entry)
|
if (! entry)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.select_palette(entry.getAttribute('data-tile-name'));
|
let key = entry.getAttribute('data-palette-key');
|
||||||
|
if (SPECIAL_PALETTE_ENTRIES[key]) {
|
||||||
|
// Tile with preconfigured stuff on it
|
||||||
|
let tile = Object.assign({}, SPECIAL_PALETTE_ENTRIES[key]);
|
||||||
|
tile.type = TILE_TYPES[tile.name];
|
||||||
|
delete tile.name;
|
||||||
|
this.select_palette(tile);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Regular tile name
|
||||||
|
this.select_palette(key);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
this.palette_selection = null;
|
this.palette_selection = null;
|
||||||
this.select_palette('floor');
|
this.select_palette('floor');
|
||||||
@ -1479,10 +1662,8 @@ export class Editor extends PrimaryView {
|
|||||||
let name, tile;
|
let name, tile;
|
||||||
if (typeof name_or_tile === 'string') {
|
if (typeof name_or_tile === 'string') {
|
||||||
name = name_or_tile;
|
name = name_or_tile;
|
||||||
if (this.palette_selection && name === this.palette_selection.type.name)
|
|
||||||
return;
|
|
||||||
|
|
||||||
tile = { type: TILE_TYPES[name] };
|
tile = { type: TILE_TYPES[name] };
|
||||||
|
|
||||||
if (tile.type.is_actor) {
|
if (tile.type.is_actor) {
|
||||||
tile.direction = 'south';
|
tile.direction = 'south';
|
||||||
}
|
}
|
||||||
@ -1495,26 +1676,63 @@ export class Editor extends PrimaryView {
|
|||||||
name = tile.type.name;
|
name = tile.type.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.palette_selection) {
|
// Deselect any previous selection
|
||||||
let entry = this.palette[this.palette_selection.type.name];
|
if (this.palette_selection_el) {
|
||||||
if (entry) {
|
this.palette_selection_el.classList.remove('--selected');
|
||||||
entry.classList.remove('--selected');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store the tile
|
||||||
this.palette_selection = tile;
|
this.palette_selection = tile;
|
||||||
if (this.palette[name]) {
|
|
||||||
this.palette[name].classList.add('--selected');
|
// Select it in the palette, if possible
|
||||||
|
let key = name;
|
||||||
|
if (SPECIAL_PALETTE_BEHAVIOR[name]) {
|
||||||
|
key = SPECIAL_PALETTE_BEHAVIOR[name].pick_palette_entry(tile);
|
||||||
|
}
|
||||||
|
this.palette_selection_el = this.palette[key] ?? null;
|
||||||
|
if (this.palette_selection_el) {
|
||||||
|
this.palette_selection_el.classList.add('--selected');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.mark_tile_dirty(tile);
|
this.mark_tile_dirty(tile);
|
||||||
|
|
||||||
// Some tools obviously don't work with a palette selection, in which case changing tiles
|
// Some tools obviously don't work with a palette selection, in which case changing tiles
|
||||||
// should default you back to the pencil
|
// should default you back to the pencil
|
||||||
if (this.current_tool === 'adjust') {
|
if (! EDITOR_TOOLS[this.current_tool].uses_palette) {
|
||||||
this.select_tool('pencil');
|
this.select_tool('pencil');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rotate_tile_left(tile) {
|
||||||
|
if (SPECIAL_PALETTE_BEHAVIOR[tile.type.name]) {
|
||||||
|
SPECIAL_PALETTE_BEHAVIOR[tile.type.name].rotate_left(tile);
|
||||||
|
}
|
||||||
|
else if (TILE_TYPES[tile.type.name].is_actor) {
|
||||||
|
tile.direction = DIRECTIONS[tile.direction ?? 'south'].left;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mark_tile_dirty(tile);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
rotate_tile_right(tile) {
|
||||||
|
if (SPECIAL_PALETTE_BEHAVIOR[tile.type.name]) {
|
||||||
|
SPECIAL_PALETTE_BEHAVIOR[tile.type.name].rotate_right(tile);
|
||||||
|
}
|
||||||
|
else if (TILE_TYPES[tile.type.name].is_actor) {
|
||||||
|
tile.direction = DIRECTIONS[tile.direction ?? 'south'].right;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mark_tile_dirty(tile);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
rotate_palette_left() {
|
rotate_palette_left() {
|
||||||
this.palette_rotation_index += 1;
|
this.palette_rotation_index += 1;
|
||||||
this.palette_rotation_index %= 4;
|
this.palette_rotation_index %= 4;
|
||||||
|
|||||||
@ -391,6 +391,7 @@ const TILE_TYPES = {
|
|||||||
],
|
],
|
||||||
populate_defaults(me) {
|
populate_defaults(me) {
|
||||||
me.tracks = 0; // bitmask of bits 0-5, corresponding to track order above
|
me.tracks = 0; // bitmask of bits 0-5, corresponding to track order above
|
||||||
|
// FIXME it's possible to have a switch but no tracks...
|
||||||
me.track_switch = null; // null, or 0-5 indicating the active switched track
|
me.track_switch = null; // null, or 0-5 indicating the active switched track
|
||||||
// If there's already an actor on us, it's treated as though it entered the tile moving
|
// If there's already an actor on us, it's treated as though it entered the tile moving
|
||||||
// in this direction, which is given in the save file and defaults to zero i.e. north
|
// in this direction, which is given in the save file and defaults to zero i.e. north
|
||||||
|
|||||||
76
style.css
76
style.css
@ -1196,6 +1196,57 @@ main.--has-demo .demo-controls {
|
|||||||
box-shadow: 0 0 0 1px black, 0 0 0 3px white;
|
box-shadow: 0 0 0 1px black, 0 0 0 3px white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.editor-level-browser {
|
||||||
|
display: grid;
|
||||||
|
grid: auto-flow auto / repeat(auto-fill, minmax(13em, 1fr)); /* 12em preview wdith + padding */
|
||||||
|
gap: 0.5em;
|
||||||
|
width: 70vw;
|
||||||
|
/* seems to go into the parent's right padding fsr, i guess because the scrollbar is there */
|
||||||
|
margin-right: 1em;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
.editor-level-browser li {
|
||||||
|
display: grid;
|
||||||
|
grid:
|
||||||
|
"preview preview"
|
||||||
|
"number title"
|
||||||
|
/ min-content 1fr
|
||||||
|
;
|
||||||
|
gap: 0.25em;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
.editor-level-browser li:hover {
|
||||||
|
background: hsl(225, 60%, 85%);
|
||||||
|
}
|
||||||
|
.editor-level-browser li > .-preview {
|
||||||
|
grid-area: preview;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 12em;
|
||||||
|
height: 12em;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
.editor-level-browser li > .-preview:empty::before {
|
||||||
|
content: '···';
|
||||||
|
display: block;
|
||||||
|
font-size: 5em;
|
||||||
|
color: #c0c0c0;
|
||||||
|
}
|
||||||
|
.editor-level-browser li > .-preview canvas {
|
||||||
|
display: block;
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
.editor-level-browser li > .-number {
|
||||||
|
grid-area: number;
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
.editor-level-browser li > .-title {
|
||||||
|
grid-area: title;
|
||||||
|
align-self: center;
|
||||||
|
}
|
||||||
|
|
||||||
/* Mini editors for specific tiles with complex properties */
|
/* Mini editors for specific tiles with complex properties */
|
||||||
/* FIXME should this stuff be on an overlay container class? */
|
/* FIXME should this stuff be on an overlay container class? */
|
||||||
form.editor-popup-tile-editor {
|
form.editor-popup-tile-editor {
|
||||||
@ -1271,25 +1322,32 @@ textarea.editor-hint-tile-text {
|
|||||||
border: none;
|
border: none;
|
||||||
font-family: serif;
|
font-family: serif;
|
||||||
}
|
}
|
||||||
/* Railroad tracks are... complicated */
|
/* Class for a list that uses hidden inputs with svg icons, shared by directional blocks and
|
||||||
ul.editor-railroad-tile-tracks {
|
* railroad tracks */
|
||||||
display: grid;
|
.editor-tile-editor-svg-parts input {
|
||||||
grid: auto-flow 3em / repeat(3, 3em);
|
|
||||||
gap: 0.25em;
|
|
||||||
}
|
|
||||||
ul.editor-railroad-tile-tracks input {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
ul.editor-railroad-tile-tracks svg {
|
.editor-tile-editor-svg-parts svg {
|
||||||
display: block;
|
display: block;
|
||||||
width: 3em;
|
width: 3em;
|
||||||
fill: none;
|
fill: none;
|
||||||
stroke: #c0c0c0;
|
stroke: #c0c0c0;
|
||||||
stroke-width: 2;
|
stroke-width: 2;
|
||||||
}
|
}
|
||||||
ul.editor-railroad-tile-tracks input:checked + svg {
|
.editor-tile-editor-svg-parts input:checked + svg {
|
||||||
stroke: hsl(225, 90%, 50%);
|
stroke: hsl(225, 90%, 50%);
|
||||||
}
|
}
|
||||||
|
/* Directional blocks have arrows */
|
||||||
|
ol.editor-directional-block-tile-arrows {
|
||||||
|
display: grid;
|
||||||
|
grid: auto-flow 3em / repeat(3, 3em);
|
||||||
|
}
|
||||||
|
/* Railroad tracks are... complicated */
|
||||||
|
ul.editor-railroad-tile-tracks {
|
||||||
|
display: grid;
|
||||||
|
grid: auto-flow 3em / repeat(3, 3em);
|
||||||
|
gap: 0.25em;
|
||||||
|
}
|
||||||
ul.editor-railroad-tile-tracks.--switch input:checked + svg {
|
ul.editor-railroad-tile-tracks.--switch input:checked + svg {
|
||||||
stroke: hsl(15, 90%, 50%);
|
stroke: hsl(15, 90%, 50%);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user