Editor: remove tiles from painted zones, scrollable zone list
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a8d1c4d6ea
commit
c11d281281
20 files changed
+92
-3
No files matched your search
@@ -95,7 +95,7 @@ The map in the game's 3D view; tool bar on the left, options on top.
|
||||
| Towers | arrow, cannon, magic, rune forge tower; the dungeon's or the knights', level 1–3 |
|
||||
| Traps | the seven traps and three doors, armed |
|
||||
| Forts | a knight fortress (with or without a shard), rival masters (Mossgrim, Lady Nightwell, rival 3); level = strength |
|
||||
| Zones | trigger zones: rectangle, circle (drag from the middle), painted tiles (paint onto the selected tiles zone), line (drag from start to end); name, rename, delete |
|
||||
| Zones | trigger zones: rectangle, circle (drag from the middle), painted tiles (paint onto the selected tiles zone; *Remove tiles* takes them out again), line (drag from start to end); name, rename, delete (the "x"); the list scrolls with the wheel |
|
||||
| Erase | removes units, towers, traps and doors on a tile |
|
||||
|
||||
Options: brush size 1–5, rectangle, fill (connected area of the same ground), mirror (left/right,
|
||||
|
||||
@@ -1205,6 +1205,7 @@ ed.level = Úroveň
|
||||
ed.zone_shape = Tvar nové zóny
|
||||
ed.zone_new_name = Název nové zóny
|
||||
ed.zones = Zóny
|
||||
ed.zone_erase = Odebrat pole
|
||||
ed.shape.rect = Obdélník
|
||||
ed.shape.circle = Kruh
|
||||
ed.shape.tiles = Políčka
|
||||
|
||||
@@ -1204,6 +1204,7 @@ ed.level = Niveau
|
||||
ed.zone_shape = Form på ny zone
|
||||
ed.zone_new_name = Navn på ny zone
|
||||
ed.zones = Zoner
|
||||
ed.zone_erase = Fjern felter
|
||||
ed.shape.rect = Rektangel
|
||||
ed.shape.circle = Cirkel
|
||||
ed.shape.tiles = Felter
|
||||
|
||||
@@ -1204,6 +1204,7 @@ ed.level = Stufe
|
||||
ed.zone_shape = Form einer neuen Zone
|
||||
ed.zone_new_name = Name einer neuen Zone
|
||||
ed.zones = Zonen
|
||||
ed.zone_erase = Kacheln entfernen
|
||||
ed.shape.rect = Rechteck
|
||||
ed.shape.circle = Kreis
|
||||
ed.shape.tiles = Kacheln
|
||||
|
||||
@@ -1205,6 +1205,7 @@ ed.level = Επίπεδο
|
||||
ed.zone_shape = Σχήμα νέας ζώνης
|
||||
ed.zone_new_name = Όνομα νέας ζώνης
|
||||
ed.zones = Ζώνες
|
||||
ed.zone_erase = Αφαίρεση πλακιδίων
|
||||
ed.shape.rect = Ορθογώνιο
|
||||
ed.shape.circle = Κύκλος
|
||||
ed.shape.tiles = Πλακίδια
|
||||
|
||||
@@ -1205,6 +1205,7 @@ ed.level = Level
|
||||
ed.zone_shape = Shape of a new zone
|
||||
ed.zone_new_name = Name of a new zone
|
||||
ed.zones = Zones
|
||||
ed.zone_erase = Remove tiles
|
||||
ed.shape.rect = Rectangle
|
||||
ed.shape.circle = Circle
|
||||
ed.shape.tiles = Tiles
|
||||
|
||||
@@ -1197,6 +1197,7 @@ ed.level = Nivel
|
||||
ed.zone_shape = Forma de la nueva zona
|
||||
ed.zone_new_name = Nombre de la nueva zona
|
||||
ed.zones = Zonas
|
||||
ed.zone_erase = Quitar casillas
|
||||
ed.shape.rect = Rectángulo
|
||||
ed.shape.circle = Círculo
|
||||
ed.shape.tiles = Casillas
|
||||
|
||||
@@ -1205,6 +1205,7 @@ ed.level = Taso
|
||||
ed.zone_shape = Uuden alueen muoto
|
||||
ed.zone_new_name = Uuden alueen nimi
|
||||
ed.zones = Alueet
|
||||
ed.zone_erase = Poista ruutuja
|
||||
ed.shape.rect = Suorakulmio
|
||||
ed.shape.circle = Ympyrä
|
||||
ed.shape.tiles = Ruudut
|
||||
|
||||
@@ -1205,6 +1205,7 @@ ed.level = Razina
|
||||
ed.zone_shape = Oblik nove zone
|
||||
ed.zone_new_name = Ime nove zone
|
||||
ed.zones = Zone
|
||||
ed.zone_erase = Ukloni polja
|
||||
ed.shape.rect = Pravokutnik
|
||||
ed.shape.circle = Krug
|
||||
ed.shape.tiles = Polja
|
||||
|
||||
@@ -1205,6 +1205,7 @@ ed.level = Szint
|
||||
ed.zone_shape = Új zóna alakja
|
||||
ed.zone_new_name = Új zóna neve
|
||||
ed.zones = Zónák
|
||||
ed.zone_erase = Mezők törlése
|
||||
ed.shape.rect = Téglalap
|
||||
ed.shape.circle = Kör
|
||||
ed.shape.tiles = Mezők
|
||||
|
||||
@@ -1197,6 +1197,7 @@ ed.level = Livello
|
||||
ed.zone_shape = Forma della nuova zona
|
||||
ed.zone_new_name = Nome della nuova zona
|
||||
ed.zones = Zone
|
||||
ed.zone_erase = Togli caselle
|
||||
ed.shape.rect = Rettangolo
|
||||
ed.shape.circle = Cerchio
|
||||
ed.shape.tiles = Caselle
|
||||
|
||||
@@ -1205,6 +1205,7 @@ ed.level = Niveau
|
||||
ed.zone_shape = Vorm van een nieuwe zone
|
||||
ed.zone_new_name = Naam van een nieuwe zone
|
||||
ed.zones = Zones
|
||||
ed.zone_erase = Tegels weghalen
|
||||
ed.shape.rect = Rechthoek
|
||||
ed.shape.circle = Cirkel
|
||||
ed.shape.tiles = Vakken
|
||||
|
||||
@@ -1204,6 +1204,7 @@ ed.level = Nivå
|
||||
ed.zone_shape = Form på ny sone
|
||||
ed.zone_new_name = Navn på ny sone
|
||||
ed.zones = Soner
|
||||
ed.zone_erase = Fjern ruter
|
||||
ed.shape.rect = Rektangel
|
||||
ed.shape.circle = Sirkel
|
||||
ed.shape.tiles = Ruter
|
||||
|
||||
@@ -1205,6 +1205,7 @@ ed.level = Nível
|
||||
ed.zone_shape = Forma da nova zona
|
||||
ed.zone_new_name = Nome da nova zona
|
||||
ed.zones = Zonas
|
||||
ed.zone_erase = Remover casas
|
||||
ed.shape.rect = Retângulo
|
||||
ed.shape.circle = Círculo
|
||||
ed.shape.tiles = Casas
|
||||
|
||||
@@ -1205,6 +1205,7 @@ ed.level = Nivel
|
||||
ed.zone_shape = Forma unei zone noi
|
||||
ed.zone_new_name = Numele unei zone noi
|
||||
ed.zones = Zone
|
||||
ed.zone_erase = Scoate pătrate
|
||||
ed.shape.rect = Dreptunghi
|
||||
ed.shape.circle = Cerc
|
||||
ed.shape.tiles = Dale
|
||||
|
||||
@@ -1197,6 +1197,7 @@ ed.level = Уровень
|
||||
ed.zone_shape = Форма новой зоны
|
||||
ed.zone_new_name = Имя новой зоны
|
||||
ed.zones = Зоны
|
||||
ed.zone_erase = Убрать клетки
|
||||
ed.shape.rect = Прямоугольник
|
||||
ed.shape.circle = Круг
|
||||
ed.shape.tiles = Клетки
|
||||
|
||||
@@ -1205,6 +1205,7 @@ ed.level = Úroveň
|
||||
ed.zone_shape = Tvar novej zóny
|
||||
ed.zone_new_name = Názov novej zóny
|
||||
ed.zones = Zóny
|
||||
ed.zone_erase = Odobrať polia
|
||||
ed.shape.rect = Obdĺžnik
|
||||
ed.shape.circle = Kruh
|
||||
ed.shape.tiles = Políčka
|
||||
|
||||
@@ -1205,6 +1205,7 @@ ed.level = Ниво
|
||||
ed.zone_shape = Облик нове зоне
|
||||
ed.zone_new_name = Име нове зоне
|
||||
ed.zones = Зоне
|
||||
ed.zone_erase = Уклони поља
|
||||
ed.shape.rect = Правоугаоник
|
||||
ed.shape.circle = Круг
|
||||
ed.shape.tiles = Поља
|
||||
|
||||
@@ -1205,6 +1205,7 @@ ed.level = Nivå
|
||||
ed.zone_shape = Form på ny zon
|
||||
ed.zone_new_name = Namn på ny zon
|
||||
ed.zones = Zoner
|
||||
ed.zone_erase = Ta bort rutor
|
||||
ed.shape.rect = Rektangel
|
||||
ed.shape.circle = Cirkel
|
||||
ed.shape.tiles = Rutor
|
||||
|
||||
+73
-2
@@ -61,6 +61,8 @@ pub struct MapEdit {
|
||||
zone: usize, // selected zone
|
||||
zone_shape: usize, // shape for a new zone
|
||||
zone_name: String,
|
||||
zone_erase: bool, // painting a tiles zone takes tiles out of it again
|
||||
zone_scroll: usize, // first zone shown in the list (usize::MAX: scroll to the end)
|
||||
last_mouse: Option<Vec2>,
|
||||
}
|
||||
|
||||
@@ -117,6 +119,8 @@ impl MapEdit {
|
||||
zone: 0,
|
||||
zone_shape: 0,
|
||||
zone_name: String::new(),
|
||||
zone_erase: false,
|
||||
zone_scroll: 0,
|
||||
last_mouse: None,
|
||||
}
|
||||
}
|
||||
@@ -460,9 +464,18 @@ impl MapEdit {
|
||||
}
|
||||
m.zones.push(z);
|
||||
self.zone = m.zones.len() - 1;
|
||||
self.zone_scroll = usize::MAX;
|
||||
self.zone_name.clear();
|
||||
}
|
||||
|
||||
// the brush takes tiles out of the selected tiles zone
|
||||
fn erase_zone_tiles(&mut self, m: &mut MissionDoc, x: i32, y: i32) {
|
||||
let targets = self.targets(x, y);
|
||||
if let Some(t) = m.zones.get_mut(self.zone).filter(|z| z.shape == "tiles").and_then(|z| z.tiles.as_mut()) {
|
||||
t.retain(|p| !targets.contains(p));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame(&mut self, im: &mut Im, gfx: &Gfx, r3d: &mut R3d, dt: f32, now: f64, m: &mut MissionDoc) -> MapResult {
|
||||
let (cssx, cssy) = mouse_position();
|
||||
let bar_w = CW() * 30.0;
|
||||
@@ -547,6 +560,15 @@ impl MapEdit {
|
||||
}
|
||||
im.pressed = false;
|
||||
}
|
||||
// a tiles zone is painted (or erased) all along the drag
|
||||
let tiles_zone = self.cat == Cat::Zones && ZONE_SHAPES[self.zone_shape] == "tiles";
|
||||
if tiles_zone && im.down && self.drag.is_some() {
|
||||
if self.zone_erase {
|
||||
self.erase_zone_tiles(m, x, y);
|
||||
} else {
|
||||
self.draw_zone(m, x, y, x, y);
|
||||
}
|
||||
}
|
||||
if self.stroke && im.down {
|
||||
for (tx, ty) in self.targets(x, y) {
|
||||
self.paint_tile(tx, ty);
|
||||
@@ -555,7 +577,11 @@ impl MapEdit {
|
||||
if im.released {
|
||||
if let Some((sx, sy)) = self.drag {
|
||||
if self.cat == Cat::Zones {
|
||||
self.draw_zone(m, sx, sy, x, y);
|
||||
if ZONE_SHAPES[self.zone_shape] == "tiles" && self.zone_erase {
|
||||
self.erase_zone_tiles(m, x, y);
|
||||
} else {
|
||||
self.draw_zone(m, sx, sy, x, y);
|
||||
}
|
||||
} else {
|
||||
for (tx, ty) in self.targets(x, y) {
|
||||
self.paint_tile(tx, ty);
|
||||
@@ -738,7 +764,24 @@ impl MapEdit {
|
||||
label(gfx, x, y, &tr("ed.zones"), FRAME_HI);
|
||||
y += CH() * 1.4;
|
||||
let mut remove = None;
|
||||
for k in 0..m.zones.len() {
|
||||
// the list scrolls (wheel over it) when there are more zones than room
|
||||
let row = CH() * 1.7;
|
||||
let room = (((h - CH() * 3.0 - y) / row).floor() as usize).max(1);
|
||||
let over_list = im.mx < bar_w && im.my >= y && im.my < y + room as f32 * row;
|
||||
if over_list && im.wheel != 0.0 {
|
||||
self.zone_scroll = if im.wheel > 0.0 { self.zone_scroll.min(m.zones.len()).saturating_sub(1) } else { self.zone_scroll.saturating_add(1) };
|
||||
}
|
||||
let max_scroll = m.zones.len().saturating_sub(room);
|
||||
if self.zone_scroll == usize::MAX {
|
||||
// a new zone: show it
|
||||
self.zone_scroll = self.zone.saturating_sub(room - 1);
|
||||
}
|
||||
self.zone_scroll = self.zone_scroll.min(max_scroll);
|
||||
if self.zone_scroll > 0 || max_scroll > 0 {
|
||||
let more = format!("{}-{} / {}", self.zone_scroll + 1, (self.zone_scroll + room).min(m.zones.len()), m.zones.len());
|
||||
gfx.text(&more, x + fw - gfx.measure(&more, SMALL()), y - CH() * 1.3, SMALL(), DIM);
|
||||
}
|
||||
for k in self.zone_scroll..m.zones.len() {
|
||||
if y > h - CH() * 3.0 {
|
||||
break;
|
||||
}
|
||||
@@ -778,6 +821,10 @@ impl MapEdit {
|
||||
}
|
||||
bx += gfx.measure(&tr("ed.fill"), S()) + CW() * 4.0;
|
||||
}
|
||||
if self.cat == Cat::Zones && ZONE_SHAPES[self.zone_shape] == "tiles" {
|
||||
im.toggle(gfx, bx, by + CH() * 0.15, &tr("ed.zone_erase"), &mut self.zone_erase);
|
||||
bx += gfx.measure(&tr("ed.zone_erase"), S()) + CW() * 4.0;
|
||||
}
|
||||
let mirrors: Vec<String> = (0..4).map(|k| tr(&format!("ed.mirror{}", k))).collect();
|
||||
if let Some(c) = im.dropdown(gfx, id("mirror", 0), Rect::new(bx, by, CW() * 23.0, CH() * 1.7), &mirrors[self.mirror as usize], &mirrors) {
|
||||
self.mirror = c as u8;
|
||||
@@ -799,3 +846,27 @@ impl MapEdit {
|
||||
done
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn tiles_of_a_painted_zone_can_be_taken_out_again() {
|
||||
let mut ed = MapEdit::new(Game::new(3, 64, 64));
|
||||
let mut m = MissionDoc::default();
|
||||
ed.zone_shape = ZONE_SHAPES.iter().position(|s| *s == "tiles").unwrap();
|
||||
ed.brush = 2;
|
||||
ed.draw_zone(&mut m, 10, 10, 10, 10);
|
||||
ed.draw_zone(&mut m, 14, 10, 14, 10);
|
||||
assert_eq!(m.zones.len(), 1, "painting goes on in the selected tiles zone");
|
||||
let n = m.zones[0].tiles.as_ref().unwrap().len();
|
||||
assert!(n >= 2);
|
||||
ed.erase_zone_tiles(&mut m, 10, 10);
|
||||
let t = m.zones[0].tiles.as_ref().unwrap();
|
||||
assert!(!t.contains(&(10, 10)) && t.contains(&(14, 10)));
|
||||
assert!(t.len() < n);
|
||||
// a new zone scrolls the list to it
|
||||
assert_eq!(ed.zone_scroll, usize::MAX);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user