extends CanvasLayer var _message_queue = [] var _font var _container var _ordered_labels = [] func _ready(): _container = VBoxContainer.new() _container.set_name("Container") _container.anchor_bottom = 1 _container.offset_left = 20.0 _container.offset_right = 1920.0 _container.offset_top = 0.0 _container.offset_bottom = -20.0 _container.alignment = BoxContainer.ALIGNMENT_END _container.mouse_filter = Control.MOUSE_FILTER_IGNORE self.add_child(_container) _font = load("res://assets/fonts/Lingo2.ttf") func _add_message(text): var new_label = RichTextLabel.new() new_label.push_font(_font) new_label.push_font_size(36) new_label.push_outline_color(Color(0, 0, 0, 1)) new_label.push_outline_size(2) new_label.append_text(text) new_label.fit_content = true _container.add_child(new_label) _ordered_labels.push_back(new_label) func showMessage(text): if _ordered_labels.size() >= 9: _message_queue.append(text) return _add_message(text) if _ordered_labels.size() > 1: return var timeout = 10.0 while !_ordered_labels.is_empty(): await get_tree().create_timer(timeout).timeout var to_remove = _ordered_labels.pop_front() var to_tween = get_tree().create_tween().bind_node(to_remove) to_tween.tween_property(to_remove, "modulate:a", 0.0, 0.5) to_tween.tween_callback(to_remove.queue_free) if !_message_queue.is_empty(): var next_msg = _message_queue.pop_front() _add_message(next_msg) if timeout > 4: timeout -= 3 /Panel.h?id=fa123398b263283d3f770c81b3324e1b8602b490'>commit diff stats
path: root/ext/wittle_generator/Panel.h
blob: 3bc23c9b45c381d9d213740d9d969bae37933804 (plain) (tree)
























































































































                                                                
                                 
                              
                                 
                              

                                           


































                                                                        

                                                   






                                                        

                                                                    

                      














                                                                              















                          







































































































































                                                                                







                                                      
                                   


                                                   
#ifndef PANEL_H_FC471D68
#define PANEL_H_FC471D68

#include <stdint.h>

#include <tuple>
#include <vector>

struct Point {
  int first;
  int second;
  Point() {
    first = 0;
    second = 0;
  };
  Point(int x, int y) {
    first = x;
    second = y;
  }
  Point operator+(const Point& p) {
    return {first + p.first, second + p.second};
  }
  Point operator*(int d) { return {first * d, second * d}; }
  Point operator/(int d) { return {first / d, second / d}; }
  bool operator==(const Point& p) const {
    return first == p.first && second == p.second;
  };
  bool operator!=(const Point& p) const {
    return first != p.first || second != p.second;
  };
  friend bool operator<(const Point& p1, const Point& p2) {
    if (p1.first == p2.first) return p1.second < p2.second;
    return p1.first < p2.first;
  };
};

class Decoration {
 public:
  enum Shape : int {
    Exit = 0x600001,
    Start = 0x600002,
    Stone = 0x100,
    Star = 0x200,
    Poly = 0x400,
    Eraser = 0x500,
    Triangle = 0x600,
    Triangle1 = 0x10600,
    Triangle2 = 0x20600,
    Triangle3 = 0x30600,
    Triangle4 = 0x40600,
    Arrow = 0x700,
    Arrow1 = 0x1700,
    Arrow2 = 0x2700,
    Arrow3 = 0x3700,
    Can_Rotate = 0x1000,
    Negative = 0x2000,
    Gap = 0x100000,
    Gap_Row = 0x300000,
    Gap_Column = 0x500000,
    Dot = 0x20,
    Dot_Row = 0x240020,
    Dot_Column = 0x440020,
    Dot_Intersection = 0x600020,
    Empty = 0xA00,
  };
  enum Color : int {
    None = 0,
    Black = 0x1,
    White = 0x2,
    Red = 0x3,  // Doesn't work sadly
    Purple = 0x4,
    Green = 0x5,
    Cyan = 0x6,
    Magenta = 0x7,
    Yellow = 0x8,
    Blue = 0x9,
    Orange = 0xA,
    X = 0xF,
  };
};

enum IntersectionFlags : int {
  ROW = 0x200000,
  COLUMN = 0x400000,
  INTERSECTION = 0x600000,
  ENDPOINT = 0x1,
  STARTPOINT = 0x2,
  OPEN = 0x3,      // Puzzle loader flag - not to be written out
  PATH = 0x4,      // Generator use only
  NO_POINT = 0x8,  // Points that nothing connects to
  GAP = 0x100000,
  DOT = 0x20,
  DOT_IS_BLUE = 0x100,
  DOT_IS_ORANGE = 0x200,
  DOT_IS_INVISIBLE = 0x1000,
  DOT_SMALL = 0x2000,
  DOT_MEDIUM = 0x4000,
  DOT_LARGE = 0x8000,
};

class Endpoint {
 public:
  enum Direction {
    NONE = 0,
    LEFT = 1,
    RIGHT = 2,
    UP = 4,
    DOWN = 8,
    UP_LEFT = 5,
    UP_RIGHT = 6,
    DOWN_LEFT = 9,
    DOWN_RIGHT = 10
  };

  Endpoint(int x, int y, Direction dir, int flags) {
    _x = x;
    _y = y;
    _dir = dir;
    _flags = flags;
  }

  int GetX() const { return _x; }
  void SetX(int x) { _x = x; }
  int GetY() const { return _y; }
  void SetY(int y) { _y = y; }
  Direction GetDir() const { return _dir; }
  int GetFlags() const { return _flags; }
  void SetDir(Direction dir) { _dir = dir; }

 private:
  int _x, _y, _flags;
  Direction _dir;
};

struct Color {
  float r;
  float g;
  float b;
  float a;
  friend bool operator<(const Color& lhs, const Color& rhs) {
    return lhs.r * 8 + lhs.g * 4 + lhs.b * 2 + lhs.a >
           rhs.r * 8 + rhs.g * 4 + rhs.b * 2 + rhs.a;
  }
};

struct SolutionPoint {
  int pointA, pointB, pointC, pointD;
  float f1x, f1y, f2x, f2y, f3x, f3y, f4x, f4y;
  int endnum;
};

class Panel {
 public:
  void SetSymbol(int x, int y, Decoration::Shape symbol,
                 Decoration::Color color);
  void SetShape(int x, int y, int shape, bool rotate, bool negative,
                Decoration::Color color);
  void ClearSymbol(int x, int y);
  void SetGridSymbol(int x, int y, Decoration::Shape symbol,
                     Decoration::Color color = Decoration::Color::None);
  void ClearGridSymbol(int x, int y);
  void Resize(int width, int height);
  void ClearStartpoints() { _startpoints.clear(); }
  void ClearExits() { _endpoints.clear(); }

  int width() const { return _width; }
  int height() const { return _height; }

  int get(int x, int y) { return _grid[x][y]; }
  void set(int x, int y, int val) { _grid[x][y] = val; }

  void SetInvisibleSymmetry(bool val) { _invisible_symmetry = val; }

  std::string Write();

  enum Style {
    SYMMETRICAL = 0x2,  // Not on the town symmetry puzzles? IDK why.
    NO_BLINK = 0x4,
    HAS_DOTS = 0x8,
    IS_2COLOR = 0x10,
    HAS_STARS = 0x40,
    HAS_TRIANGLES = 0x80,
    HAS_STONES = 0x100,
    HAS_ERASERS = 0x1000,
    HAS_SHAPERS = 0x2000,
    IS_PIVOTABLE = 0x8000,
  };

  enum Symmetry {  // NOTE - Not all of these are valid symmetries for certain
                   // puzzles
    None = 0,
    Horizontal = 1,
    Vertical = 2,
    Rotational = 3,
    RotateLeft = 4,
    RotateRight = 5,
    FlipXY = 6,
    FlipNegXY = 7,
    ParallelH = 8,
    ParallelV = 9,
    ParallelHFlip = 10,
    ParallelVFlip = 11,
    PillarParallel = 12,
    PillarHorizontal = 13,
    PillarVertical = 14,
    PillarRotational = 15,
  };
  Symmetry symmetry;

  float pathWidth;
  enum ColorMode {
    Default,
    Reset,
    Alternate,
    WriteColors,
    Treehouse,
    TreehouseAlternate
  };
  ColorMode colorMode;
  bool decorationsOnly;
  bool enableFlash;

  Point get_sym_point(int x, int y, Symmetry symmetry) {
    switch (symmetry) {
      case None:
        return Point(x, y);
      case Symmetry::Horizontal:
        return Point(x, _height - 1 - y);
      case Symmetry::Vertical:
        return Point(_width - 1 - x, y);
      case Symmetry::Rotational:
        return Point(_width - 1 - x, _height - 1 - y);
      case Symmetry::RotateLeft:
        return Point(y, _width - 1 - x);
      case Symmetry::RotateRight:
        return Point(_height - 1 - y, x);
      case Symmetry::FlipXY:
        return Point(y, x);
      case Symmetry::FlipNegXY:
        return Point(_height - 1 - y, _width - 1 - x);
      case Symmetry::ParallelH:
        return Point(x, y == _height / 2
                            ? _height / 2
                            : (y + (_height + 1) / 2) % (_height + 1));
      case Symmetry::ParallelV:
        return Point(x == _width / 2 ? _width / 2
                                     : (x + (_width + 1) / 2) % (_width + 1),
                     y);
      case Symmetry::ParallelHFlip:
        return Point(_width - 1 - x,
                     y == _height / 2
                         ? _height / 2
                         : (y + (_height + 1) / 2) % (_height + 1));
      case Symmetry::ParallelVFlip:
        return Point(x == _width / 2 ? _width / 2
                                     : (x + (_width + 1) / 2) % (_width + 1),
                     _height - 1 - y);
      case Symmetry::PillarParallel:
        return Point(x + _width / 2, y);
      case Symmetry::PillarHorizontal:
        return Point(x + _width / 2, _height - 1 - y);
      case Symmetry::PillarVertical:
        return Point(_width / 2 - x, y);
      case Symmetry::PillarRotational:
        return Point(_width / 2 - x, _height - 1 - y);
    }
    return Point(x, y);
  }

  Point get_sym_point(int x, int y) { return get_sym_point(x, y, symmetry); }
  Point get_sym_point(Point p) {
    return get_sym_point(p.first, p.second, symmetry);
  }
  Point get_sym_point(Point p, Symmetry symmetry) {
    return get_sym_point(p.first, p.second, symmetry);
  }
  Endpoint::Direction get_sym_dir(Endpoint::Direction direction,
                                  Symmetry symmetry) {
    int dirIndex;
    if (direction == Endpoint::Direction::LEFT) dirIndex = 0;
    if (direction == Endpoint::Direction::RIGHT) dirIndex = 1;
    if (direction == Endpoint::Direction::UP) dirIndex = 2;
    if (direction == Endpoint::Direction::DOWN) dirIndex = 3;
    std::vector<Endpoint::Direction> mapping;
    switch (symmetry) {
      case Symmetry::Horizontal:
        mapping = {Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT,
                   Endpoint::Direction::DOWN, Endpoint::Direction::UP};
        break;
      case Symmetry::Vertical:
        mapping = {Endpoint::Direction::RIGHT, Endpoint::Direction::LEFT,
                   Endpoint::Direction::UP, Endpoint::Direction::DOWN};
        break;
      case Symmetry::Rotational:
        mapping = {Endpoint::Direction::RIGHT, Endpoint::Direction::LEFT,
                   Endpoint::Direction::DOWN, Endpoint::Direction::UP};
        break;
      case Symmetry::RotateLeft:
        mapping = {Endpoint::Direction::DOWN, Endpoint::Direction::UP,
                   Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT};
        break;
      case Symmetry::RotateRight:
        mapping = {Endpoint::Direction::UP, Endpoint::Direction::DOWN,
                   Endpoint::Direction::RIGHT, Endpoint::Direction::LEFT};
        break;
      case Symmetry::FlipXY:
        mapping = {Endpoint::Direction::UP, Endpoint::Direction::DOWN,
                   Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT};
        break;
      case Symmetry::FlipNegXY:
        mapping = {Endpoint::Direction::DOWN, Endpoint::Direction::UP,
                   Endpoint::Direction::RIGHT, Endpoint::Direction::LEFT};
        break;
      case Symmetry::ParallelH:
        mapping = {Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT,
                   Endpoint::Direction::UP, Endpoint::Direction::DOWN};
        break;
      case Symmetry::ParallelV:
        mapping = {Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT,
                   Endpoint::Direction::UP, Endpoint::Direction::DOWN};
        break;
      case Symmetry::ParallelHFlip:
        mapping = {Endpoint::Direction::RIGHT, Endpoint::Direction::LEFT,
                   Endpoint::Direction::UP, Endpoint::Direction::DOWN};
        break;
      case Symmetry::ParallelVFlip:
        mapping = {Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT,
                   Endpoint::Direction::DOWN, Endpoint::Direction::UP};
        break;
      default:
        mapping = {Endpoint::Direction::LEFT, Endpoint::Direction::RIGHT,
                   Endpoint::Direction::UP, Endpoint::Direction::DOWN};
        break;
    }
    return mapping[dirIndex];
  }

  int get_num_grid_points() { return ((_width + 1) / 2) * ((_height + 1) / 2); }
  int get_num_grid_blocks() { return (_width / 2) * (_height / 2); }
  int get_parity() { return (get_num_grid_points() + 1) % 2; }

 private:
  int _width, _height;

  std::vector<std::vector<int>> _grid;
  std::vector<Point> _startpoints;
  std::vector<Endpoint> _endpoints;
  float minx, miny, maxx, maxy, unitWidth, unitHeight;
  int _style;
  bool _resized;
  bool _invisible_symmetry = false;
};

#endif /* end of include guard: PANEL_H_FC471D68 */