use crate::*;
impl TileFlags {
pub fn flip_x(&mut self) {
match self.contains(TileFlags::ROTATE) {
false => self.toggle(TileFlags::FLIP_X),
true => self.toggle(TileFlags::FLIP_Y),
}
}
pub fn flip_y(&mut self) {
match self.contains(TileFlags::ROTATE) {
false => self.toggle(TileFlags::FLIP_Y),
true => self.toggle(TileFlags::FLIP_X),
}
}
pub fn rotate_cw(&mut self) {
if self.contains(TileFlags::ROTATE) {
self.toggle(TileFlags::FLIP_Y | TileFlags::FLIP_X);
}
self.toggle(TileFlags::ROTATE);
}
pub fn rotate_ccw(&mut self) {
if !self.contains(TileFlags::ROTATE) {
self.toggle(TileFlags::FLIP_Y | TileFlags::FLIP_X);
}
self.toggle(TileFlags::ROTATE);
}
pub fn flip_x_physics(&mut self) {
if self.contains(TileFlags::ROTATE) {
self.toggle(TileFlags::FLIP_Y | TileFlags::FLIP_X);
}
}
pub fn flip_y_physics(&mut self) {
if !self.contains(TileFlags::ROTATE) {
self.toggle(TileFlags::FLIP_Y | TileFlags::FLIP_X);
}
}
}
trait TilePrivate {
fn mirror_id(id: u8) -> u8 {
id
}
fn directional_physics_tile(_id: u8) -> bool {
false
}
}
impl TilePrivate for Tile {}
fn mirror_lasers(mut id: u8) -> u8 {
if (203..=205).contains(&id) {
id += (206 - id) * 2;
} else if (207..=209).contains(&id) {
id -= (id - 206) * 2;
}
id
}
impl TilePrivate for GameTile {
fn mirror_id(id: u8) -> u8 {
mirror_lasers(id)
}
fn directional_physics_tile(id: u8) -> bool {
matches!(id, 60 | 61 | 64 | 65 | 67 | 224 | 225)
}
}
impl TilePrivate for Tele {}
impl TilePrivate for Switch {
fn mirror_id(id: u8) -> u8 {
mirror_lasers(id)
}
fn directional_physics_tile(id: u8) -> bool {
matches!(id, 224 | 225)
}
}
impl TilePrivate for Tune {}
pub trait TileFlips: AnyTile {
fn flip_x(&mut self);
fn flip_y(&mut self);
fn rotate_cw(&mut self);
fn rotate_ccw(&mut self);
}
impl<T: AnyTile + TilePrivate> TileFlips for T {
fn flip_x(&mut self) {
let id = self.id();
if let Some(flags) = self.flags_mut() {
if T::directional_physics_tile(id) {
flags.flip_x_physics();
} else {
flags.flip_x();
}
*self.id_mut() = T::mirror_id(*self.id_mut());
}
}
fn flip_y(&mut self) {
let id = self.id();
if let Some(flags) = self.flags_mut() {
if T::directional_physics_tile(id) {
flags.flip_y_physics();
} else {
flags.flip_y();
}
*self.id_mut() = T::mirror_id(*self.id_mut());
}
}
fn rotate_cw(&mut self) {
if let Some(flags) = self.flags_mut() {
flags.rotate_cw();
}
}
fn rotate_ccw(&mut self) {
if let Some(flags) = self.flags_mut() {
flags.rotate_ccw();
}
}
}
impl TileFlips for Speedup {
fn flip_x(&mut self) {
let mut angle = i16::from(self.angle);
angle = 180 - angle;
if angle < 0 {
angle += 360;
}
self.angle = angle.into();
}
fn flip_y(&mut self) {
let mut angle = i16::from(self.angle);
angle = 180 - angle;
angle *= -1;
angle = 180 - angle;
angle %= 360;
self.angle = angle.into();
}
fn rotate_cw(&mut self) {
let mut angle = i16::from(self.angle);
angle += 90;
angle %= 360;
self.angle = angle.into();
}
fn rotate_ccw(&mut self) {
let mut angle = i16::from(self.angle);
angle += 270;
angle %= 360;
self.angle = angle.into();
}
}
pub trait EditTile {
fn tile(_tile: &mut Tile) {}
fn game_tile(_tile: &mut GameTile) {}
fn tele(_tele: &mut Tele) {}
fn speedup(_speedup: &mut Speedup) {}
fn switch(_switch: &mut Switch) {}
fn tune(_tune: &mut Tune) {}
}
fn edit_tilemap<T: TilemapLayer, F: Fn(&mut T::TileType)>(layer: &mut T, f: F) {
layer.tiles_mut().unwrap_mut().iter_mut().for_each(f)
}
impl TwMap {
pub fn edit_tiles<T: EditTile>(&mut self) {
for group in &mut self.groups {
for layer in &mut group.layers {
match layer {
Layer::Game(l) => edit_tilemap(l, T::game_tile),
Layer::Tiles(l) => edit_tilemap(l, T::tile),
Layer::Front(l) => edit_tilemap(l, T::game_tile),
Layer::Tele(l) => edit_tilemap(l, T::tele),
Layer::Speedup(l) => edit_tilemap(l, T::speedup),
Layer::Switch(l) => edit_tilemap(l, T::switch),
Layer::Tune(l) => edit_tilemap(l, T::tune),
Layer::Quads(_) | Layer::Sounds(_) | Layer::Invalid(_) => {}
}
}
}
}
}
pub struct ZeroUnusedParts;
impl TileFlags {
fn clear_unused(&mut self) -> bool {
let cleared = *self & TileFlags::all();
let changed = cleared != *self;
*self = cleared;
changed
}
fn clear_unused_and_opaque(&mut self) -> bool {
let cleared = *self & (TileFlags::all() - TileFlags::OPAQUE);
let changed = cleared != *self;
*self = cleared;
changed
}
}
impl EditTile for ZeroUnusedParts {
fn tile(tile: &mut Tile) {
tile.flags.clear_unused();
tile.unused = 0;
tile.skip = 0;
}
fn game_tile(tile: &mut GameTile) {
tile.flags.clear_unused_and_opaque();
tile.unused = 0;
tile.skip = 0;
}
fn speedup(speedup: &mut Speedup) {
speedup.unused_padding = 0;
}
fn switch(switch: &mut Switch) {
switch.flags.clear_unused_and_opaque();
}
}
fn zero_air_tile<T: AnyTile>(tile: &mut T) {
if tile.id() == 0 {
*tile = T::default()
}
}
pub struct ZeroAir;
impl EditTile for ZeroAir {
fn tile(tile: &mut Tile) {
zero_air_tile(tile)
}
fn game_tile(tile: &mut GameTile) {
zero_air_tile(tile)
}
fn tele(tele: &mut Tele) {
zero_air_tile(tele)
}
fn speedup(speedup: &mut Speedup) {
zero_air_tile(speedup)
}
fn switch(switch: &mut Switch) {
zero_air_tile(switch)
}
fn tune(tune: &mut Tune) {
zero_air_tile(tune)
}
}
fn reset_unnecessary_rotation<T: TilePrivate + AnyTile>(tile: &mut T) {
if !T::directional_physics_tile(tile.id()) {
if let Some(flags) = tile.flags_mut() {
flags.remove(TileFlags::ROTATE | TileFlags::FLIP_X | TileFlags::FLIP_Y);
}
}
}
pub struct DDNetNormalizePhysicsRotation;
impl EditTile for DDNetNormalizePhysicsRotation {
fn game_tile(tile: &mut GameTile) {
reset_unnecessary_rotation(tile);
}
fn tele(tele: &mut Tele) {
reset_unnecessary_rotation(tele);
}
fn switch(switch: &mut Switch) {
reset_unnecessary_rotation(switch);
}
fn tune(tune: &mut Tune) {
reset_unnecessary_rotation(tune);
}
}
fn fix_broken_physics_rotation<T: TilePrivate + AnyTile>(tile: &mut T) {
if T::directional_physics_tile(tile.id()) {
let Some(flags) = tile.flags_mut() else {
return;
};
if flags.contains(TileFlags::FLIP_X) ^ flags.contains(TileFlags::FLIP_Y) {
if flags.contains(TileFlags::ROTATE) {
flags.insert(TileFlags::FLIP_X | TileFlags::FLIP_Y);
} else {
flags.remove(TileFlags::FLIP_X | TileFlags::FLIP_Y);
}
}
}
}
pub struct DDNetFixPhysicsRotation;
impl EditTile for DDNetFixPhysicsRotation {
fn game_tile(tile: &mut GameTile) {
fix_broken_physics_rotation(tile);
}
fn tele(tele: &mut Tele) {
fix_broken_physics_rotation(tele);
}
fn switch(switch: &mut Switch) {
fix_broken_physics_rotation(switch);
}
fn tune(tune: &mut Tune) {
fix_broken_physics_rotation(tune);
}
}
pub struct DDNetMigrateSpeedup;
impl EditTile for DDNetMigrateSpeedup {
fn speedup(speedup: &mut Speedup) {
if speedup.id == 28 {
speedup.id = 29;
if (1..5).contains(&speedup.max_speed) {
speedup.max_speed = 5;
}
}
}
}