code:
#include "OREMath/Size.hpp"
#include <algorithm>
#include <cinttypes>

void Size::transpose() { std::swap(mWidth, mHeight); }

void Size::scale(const Size& size, const AspectRatioMode mode) {
  if (mode == AspectRatioMode::Ignore || mWidth == 0 || mHeight == 0) {
    mWidth = size.mWidth;
    mHeight = size.height();
    return;
  }

  const uint64_t rw = size.mHeight * mWidth / mHeight;

  if ((mode == AspectRatioMode::Keep && rw <= size.mWidth) || (mode == AspectRatioMode::KeepByExpanding && rw >= size.mWidth)) {
    mWidth = rw;
    mHeight = size.mHeight;
  } else {
    mWidth = size.mWidth;
    mHeight = static_cast<uint64_t>(size.mWidth) * static_cast<uint64_t>(mHeight) / static_cast<uint64_t>(mWidth);
  }
}

void SizeF::transpose() { std::swap(mWidth, mHeight); }

void SizeF::scale(const SizeF& size, const AspectRatioMode mode) {
  if (mode == AspectRatioMode::Ignore || ::isNull(mWidth) || ::isNull(mHeight)) {
    mWidth = size.mWidth;
    mHeight = size.height();
    return;
  }

  const double rw = size.mHeight * mWidth / mHeight;

  if ((mode == AspectRatioMode::Keep && rw <= size.mWidth) || (mode == AspectRatioMode::KeepByExpanding && rw >= size.mWidth)) {
    mWidth = rw;
    mHeight = size.mHeight;
  } else {
    mWidth = size.mWidth;
    mHeight = size.mWidth * mHeight / mWidth;
  }
}


code:
#pragma once
#include "imgui.h"
#include "OREMath/MathGlobals.hpp"

class Size {
public:
  Size() = default;
  Size(const int width, const int height)
  : mWidth(width)
  , mHeight(height) {}
  explicit Size(const ImVec2& size)
  : mWidth(size.x)
  , mHeight(size.y) {}

  explicit operator ImVec2() const { return ImVec2{static_cast<float>(mWidth), static_cast<float>(mHeight)}; }

  void transpose();

  bool isNull() const { return mWidth == 0 && mHeight == 0; }
  bool isEmpty() const { return mWidth < 1 || mHeight < 1; }
  bool isValid() const { return mWidth >= 0 && mHeight >= 0; }

  int width() const { return mWidth; }
  int& rwidth() { return mWidth; }
  void setWidth(const int width) { mWidth = width; }

  int height() const { return mHeight; }
  int& rheight() { return mHeight; }
  void setHeight(const int height) { mHeight = height; }

  void scale(const int w, const int h, const AspectRatioMode mode) { scale(Size{w, h}, mode); }
  void scale(const Size& size, AspectRatioMode mode);

  Size& operator+=(const Size& s) {
    mWidth += s.mWidth;
    mHeight += s.mHeight;
    return *this;
  }
  Size& operator-=(const Size& s) {
    mWidth -= s.mWidth;
    mHeight -= s.mHeight;
    return *this;
  }

  Size& operator*=(const Size& s) {
    mWidth *= s.mWidth;
    mHeight *= s.mHeight;
    return *this;
  }

  bool operator==(const Size& rhs) const { return mWidth == rhs.mWidth && mHeight == rhs.mHeight; }
  bool operator!=(const Size& rhs) const { return mWidth != rhs.mWidth || mHeight != rhs.mHeight; }

  friend inline Size operator+(const Size&, const Size&);
  friend inline Size operator-(const Size&, const Size&);
  friend inline Size operator*(const Size&, float);
  friend inline Size operator*(float, const Size&);
  friend inline Size operator/(const Size&, float);

private:
  int mWidth{-1};
  int mHeight{-1};
};

Size operator+(const Size& lhs, const Size& rhs) { return Size{lhs.mWidth + rhs.mWidth, lhs.mHeight + rhs.mHeight}; }
Size operator-(const Size& lhs, const Size& rhs) { return Size{lhs.mWidth - rhs.mWidth, lhs.mHeight - rhs.mHeight}; }
Size operator*(const Size& lhs, const float rhs) { return Size{static_cast<int>(lhs.mWidth * rhs), static_cast<int>(lhs.mHeight * rhs)}; }

Size operator/(const Size& lhs, const float rhs) { return Size{static_cast<int>(lhs.mWidth / rhs), static_cast<int>(lhs.mHeight / rhs)}; }

class SizeF {
public:
  SizeF() = default;
  SizeF(const float width, const float height)
  : mWidth(width)
  , mHeight(height) {}
  explicit SizeF(const ImVec2& size)
  : mWidth(size.x)
  , mHeight(size.y) {}
  explicit operator ImVec2() const { return ImVec2{mWidth, mHeight}; }

  void transpose();

  bool isNull() const { return mWidth == 0 && mHeight == 0; }
  bool isEmpty() const { return mWidth < 1 || mHeight < 1; }
  bool isValid() const { return mWidth >= 0 && mHeight >= 0; }

  float width() const { return mWidth; }
  float& rwidth() { return mWidth; }
  void setWidth(const int width) { mWidth = width; }

  float height() const { return mHeight; }
  float& rheight() { return mHeight; }
  void setHeight(const int height) { mHeight = height; }

  void scale(const float w, const float h, const AspectRatioMode mode) { scale(SizeF{w, h}, mode); }
  void scale(const SizeF& size, AspectRatioMode mode);

  SizeF& operator+=(const SizeF& s) {
    mWidth += s.mWidth;
    mHeight += s.mHeight;
    return *this;
  }
  SizeF& operator-=(const SizeF& s) {
    mWidth -= s.mWidth;
    mHeight -= s.mHeight;
    return *this;
  }

  SizeF& operator*=(const SizeF& s) {
    mWidth *= s.mWidth;
    mHeight *= s.mHeight;
    return *this;
  }

  friend bool operator==(const SizeF& lhs, const SizeF& rhs);
  friend bool operator!=(const SizeF& lhs, const SizeF& rhs);

  friend inline SizeF operator+(const SizeF&, const SizeF&);
  friend inline SizeF operator-(const SizeF&, const SizeF&);
  friend inline SizeF operator*(const SizeF&, float);
  friend inline SizeF operator*(float, const SizeF&);
  friend inline SizeF operator/(const SizeF&, float);

private:
  float mWidth{-1};
  float mHeight{-1};
};

inline bool operator==(const SizeF& lhs, const SizeF& rhs) { return lhs.mWidth == rhs.mWidth && lhs.mHeight == rhs.mHeight; }

inline bool operator!=(const SizeF& lhs, const SizeF& rhs) { return lhs.mWidth != rhs.mWidth || lhs.mHeight != rhs.mHeight; }

SizeF operator+(const SizeF& lhs, const SizeF& rhs) { return SizeF{lhs.mWidth + rhs.mWidth, lhs.mHeight + rhs.mHeight}; }
SizeF operator-(const SizeF& lhs, const SizeF& rhs) { return SizeF{lhs.mWidth - rhs.mWidth, lhs.mHeight - rhs.mHeight}; }
SizeF operator*(const SizeF& lhs, const float rhs) { return SizeF{lhs.mWidth * rhs, lhs.mHeight * rhs}; }
SizeF operator*(const float lhs, const SizeF& rhs) { return SizeF{lhs * rhs.mWidth, lhs * rhs.mHeight}; }

SizeF operator/(const SizeF& lhs, const float rhs) { return SizeF{lhs.mWidth / rhs, lhs.mHeight / rhs}; }

repo_name: Antidote/openrpgeditor

license: mit


code:
#include "Vector2D.hpp"

#include "Vector3D.hpp"
#include "Vector4D.hpp"

Vector2D::Vector2D(const Vector3D& vector)
: m_x(vector.m_x)
, m_y(vector.m_y) {}
Vector2D::Vector2D(const Vector4D& vector)
: m_x(vector.m_x)
, m_y(vector.m_y) {}

float Vector2D::length() const { return sqrtf(m_x * m_x + m_y * m_y); }

float Vector2D::lengthSquared() const { return m_x * m_x + m_y * m_y; }

Vector2D Vector2D::normalized() const {
  const double len = static_cast<double>(m_x) * static_cast<double>(m_x) + static_cast<double>(m_y) * static_cast<double>(m_y);
  if (fuzzyIsNull(len - 1.0f)) {
    return *this;
  }
  if (!fuzzyIsNull(len)) {
    return *this / std::sqrt(len);
  }
  return {};
}

void Vector2D::normalize() {
  double len = static_cast<double>(m_x) * static_cast<double>(m_x) + static_cast<double>(m_y) * static_cast<double>(m_y);
  if (fuzzyIsNull(len - 1.0f) || fuzzyIsNull(len)) {
    return;
  }

  len = std::sqrt(len);

  m_x /= len;
  m_y /= len;
}

float Vector2D::dotProduct(const Vector2D& v1, const Vector2D& v2) { return v1.m_x * v2.m_x + v1.m_y * v2.m_y; }

Vector3D Vector2D::toVector3D() const { return {m_x, m_y, 0.0f}; }


code:
#pragma once

#include "Point.hpp"

class Vector3D;
class Vector4D;
class Vector2D {
public:
  Vector2D();
  Vector2D(const float xpos, const float ypos)
  : m_x(xpos)
  , m_y(ypos) {}
  explicit Vector2D(const Point& point);
  explicit Vector2D(const PointF& point);
  explicit Vector2D(const Vector3D& vector);
  explicit Vector2D(const Vector4D& vector);

  [[nodiscard]] bool isNull() const { return ::isNull(m_x) && ::isNull(m_y); }

  [[nodiscard]] float x() const { return m_x; }
  [[nodiscard]] float y() const { return m_y; }
  void setX(const float x) { m_x = x; }
  void setY(const float y) { m_y = y; }
  [[nodiscard]] float length() const;
  [[nodiscard]] float lengthSquared() const;

  [[nodiscard]] Vector2D normalized() const;
  void normalize();

  Vector2D& operator+=(const Vector2D& vector) {
    m_x += vector.m_x;
    m_y += vector.m_y;
    return *this;
  }
  Vector2D& operator-=(const Vector2D& vector) {
    m_x -= vector.m_x;
    m_y -= vector.m_y;
    return *this;
  }
  Vector2D& operator*=(float factor) {
    m_x *= factor;
    m_y *= factor;
    return *this;
  }
  Vector2D& operator*=(const Vector2D& vector) {
    m_x *= vector.m_x;
    m_y *= vector.m_y;
    return *this;
  }
  Vector2D& operator/=(float divisor) {
    m_x /= divisor;
    m_y /= divisor;
    return *this;
  }

  static float dotProduct(const Vector2D& v1, const Vector2D& v2);

  friend inline bool operator==(const Vector2D& v1, const Vector2D& v2);
  friend inline bool operator!=(const Vector2D& v1, const Vector2D& v2);
  friend inline Vector2D operator+(const Vector2D& v1, const Vector2D& v2);
  friend inline Vector2D operator-(const Vector2D& v1, const Vector2D& v2);
  friend inline Vector2D operator*(float factor, const Vector2D& vector);
  friend inline Vector2D operator*(const Vector2D& vector, float factor);
  friend inline Vector2D operator*(const Vector2D& v1, const Vector2D& v2);
  friend inline Vector2D operator-(const Vector2D& vector);
  friend inline Vector2D operator/(const Vector2D& vector, float divisor);

  friend inline bool fuzzyCompare(const Vector2D& v1, const Vector2D& v2);

  [[nodiscard]] Vector3D toVector3D() const;
  [[nodiscard]] Vector4D toVector4D() const;

  [[nodiscard]] Point toPoint() const { return {oRound(m_x), oRound(m_y)}; }
  [[nodiscard]] PointF toPointF() const { return {m_x, m_y}; }

private:
  float m_x;
  float m_y;

  friend class Vector3D;
  friend class Vector4D;
};

inline bool operator==(const Vector2D& v1, const Vector2D& v2) { return v1.m_x == v2.m_x && v1.m_y == v2.m_y; }

inline bool operator!=(const Vector2D& v1, const Vector2D& v2) { return v1.m_x != v2.m_x || v1.m_y != v2.m_y; }

inline Vector2D operator+(const Vector2D& v1, const Vector2D& v2) { return {v1.m_x + v2.m_x, v1.m_y + v2.m_y}; }

inline Vector2D operator-(const Vector2D& v1, const Vector2D& v2) { return {v1.m_x - v2.m_x, v1.m_y - v2.m_y}; }

inline Vector2D operator*(const float factor, const Vector2D& vector) { return {vector.m_x * factor, vector.m_y * factor}; }

inline Vector2D operator*(const Vector2D& vector, const float factor) { return {vector.m_x * factor, vector.m_y * factor}; }

inline Vector2D operator*(const Vector2D& v1, const Vector2D& v2) { return {v1.m_x * v2.m_x, v1.m_y * v2.m_y}; }

inline Vector2D operator-(const Vector2D& vector) { return {-vector.m_x, -vector.m_y}; }

inline Vector2D operator/(const Vector2D& vector, const float divisor) { return Vector2D(vector.m_x / divisor, vector.m_y / divisor); }

inline bool fuzzyCompare(const Vector2D& v1, const Vector2D& v2) { return fuzzyCompare(v1.m_x, v2.m_x) && fuzzyCompare(v1.m_y, v2.m_y); }


code:
#include "Vector3D.hpp"

#include "Vector2D.hpp"
#include "Vector4D.hpp"

Vector3D::Vector3D(const Vector2D& vector)
: m_x(vector.m_x)
, m_y(vector.m_y)
, m_z(0.f) {}
Vector3D::Vector3D(const Vector2D& vector, const float zpos)
: m_x(vector.m_x)
, m_y(vector.m_y)
, m_z(zpos) {}

Vector3D::Vector3D(const Vector4D& vector)
: m_x(vector.m_x)
, m_y(vector.m_y)
, m_z(vector.m_z) {}

Vector3D Vector3D::normalized() const {
  double len = static_cast<double>(m_x) * static_cast<double>(m_x) + static_cast<double>(m_y) * static_cast<double>(m_y) + static_cast<double>(m_z) * static_cast<double>(m_z);
  if (fuzzyIsNull(len - 1.0f))
    return *this;
  if (!fuzzyIsNull(len)) {
    return *this / std::sqrt(len);
  }

  return {};
}

void Vector3D::normalize() {
  double len = static_cast<double>(m_x) * static_cast<double>(m_x) + static_cast<double>(m_y) * static_cast<double>(m_y) + static_cast<double>(m_z) * static_cast<double>(m_z);
  if (fuzzyIsNull(len - 1.0f) || fuzzyIsNull(len)) {
    return;
  }

  len = std::sqrt(len);

  m_x /= len;
  m_y /= len;
  m_z /= len;
}

float Vector3D::dotProduct(const Vector3D& v1, const Vector3D& v2) { return v1.m_x * v2.m_x + v1.m_y * v2.m_y + v1.m_z * v2.m_z; }

Vector3D Vector3D::crossProduct(const Vector3D& v1, const Vector3D& v2) { return {v1.m_y * v2.m_z - v1.m_z * v2.m_y, v1.m_z * v2.m_x - v1.m_x * v2.m_z, v1.m_x * v2.m_y - v1.m_y * v2.m_x}; }

Vector3D Vector3D::normal(const Vector3D& v1, const Vector3D& v2) { return crossProduct(v1, v2).normalized(); }

Vector3D Vector3D::normal(const Vector3D& v1, const Vector3D& v2, const Vector3D& v3) { return crossProduct((v2 - v1), (v3 - v1)).normalized(); }

float Vector3D::distanceToPlane(const Vector3D& plane, const Vector3D& normal) const { return dotProduct(*this - plane, normal); }

float Vector3D::distanceToPlane(const Vector3D& plane1, const Vector3D& plane2, const Vector3D& plane3) const {
  const Vector3D n = normal(plane2 - plane1, plane3 - plane1);
  return dotProduct(*this - plane1, n);
}
float Vector3D::distanceToLine(const Vector3D& point, const Vector3D& direction) const {
  if (direction.isNull())
    return (*this - point).length();
  const Vector3D p = point + dotProduct(*this - point, direction) * direction;
  return (*this - p).length();
}

Vector2D Vector3D::toVector2D() const { return {m_x, m_y}; }
Vector4D Vector3D::toVector4D() const { return {m_x, m_y, m_z, 0.0f}; }


code:
#pragma once

#include "Point.hpp"

class Matrix4x4;
class Vector2D;
class Vector4D;
class Vector3D {
public:
  Vector3D();
  Vector3D(const float xpos, const float ypos, float zpos)
  : m_x(xpos)
  , m_y(ypos)
  , m_z(zpos) {}
  explicit Vector3D(const Point& point)
  : m_x(static_cast<float>(point.x()))
  , m_y(static_cast<float>(point.y()))
  , m_z(0.f) {}
  explicit Vector3D(const PointF& point)
  : m_x(point.x())
  , m_y(point.y())
  , m_z(0.f) {}
  explicit Vector3D(const Vector2D& vector);
  Vector3D(const Vector2D& vector, float zpos);
  explicit Vector3D(const Vector4D& vector);

  [[nodiscard]] bool isNull() const { return ::isNull(m_x) && ::isNull(m_y) && ::isNull(m_z); }

  [[nodiscard]] float x() const { return m_x; }
  [[nodiscard]] float y() const { return m_y; }
  [[nodiscard]] float z() const { return m_z; }
  void setX(const float x) { m_x = x; }
  void setY(const float y) { m_y = y; }
  void setZ(const float z) { m_z = z; }
  [[nodiscard]] float length() const;
  [[nodiscard]] float lengthSquared() const;

  [[nodiscard]] Vector3D normalized() const;
  void normalize();

  Vector3D& operator+=(const Vector3D& vector) {
    m_x += vector.m_x;
    m_y += vector.m_y;
    m_z += vector.m_z;
    return *this;
  }
  Vector3D& operator-=(const Vector3D& vector) {
    m_x -= vector.m_x;
    m_y -= vector.m_y;
    m_z -= vector.m_z;
    return *this;
  }
  Vector3D& operator*=(const float factor) {
    m_x *= factor;
    m_y *= factor;
    m_z *= factor;
    return *this;
  }
  Vector3D& operator*=(const Vector3D& vector) {
    m_x *= vector.m_x;
    m_y *= vector.m_y;
    m_z *= vector.m_z;
    return *this;
  }
  Vector3D& operator/=(const float divisor) {
    m_x /= divisor;
    m_y /= divisor;
    m_z /= divisor;
    return *this;
  }

  static float dotProduct(const Vector3D& v1, const Vector3D& v2);
  static Vector3D crossProduct(const Vector3D& v1, const Vector3D& v2);
  static Vector3D normal(const Vector3D& v1, const Vector3D& v2);
  static Vector3D normal(const Vector3D& v1, const Vector3D& v2, const Vector3D& v3);

  [[nodiscard]] float distanceToPlane(const Vector3D& plane, const Vector3D& normal) const;
  [[nodiscard]] float distanceToPlane(const Vector3D& plane1, const Vector3D& plane2, const Vector3D& plane3) const;
  [[nodiscard]] float distanceToLine(const Vector3D& point, const Vector3D& direction) const;

  friend inline bool operator==(const Vector3D& v1, const Vector3D& v2);
  friend inline bool operator!=(const Vector3D& v1, const Vector3D& v2);
  friend inline Vector3D operator+(const Vector3D& v1, const Vector3D& v2);
  friend inline Vector3D operator-(const Vector3D& v1, const Vector3D& v2);
  friend inline Vector3D operator*(float factor, const Vector3D& vector);
  friend inline Vector3D operator*(const Vector3D& vector, float factor);
  friend inline Vector3D operator*(const Vector3D& v1, const Vector3D& v2);
  friend inline Vector3D operator-(const Vector3D& vector);
  friend inline Vector3D operator/(const Vector3D& vector, float divisor);

  friend inline bool fuzzyCompare(const Vector3D& v1, const Vector3D& v2);

  [[nodiscard]] Vector2D toVector2D() const;
  [[nodiscard]] Vector4D toVector4D() const;

  [[nodiscard]] Point toPoint() const;
  [[nodiscard]] PointF toPointF() const;

private:
  float m_x;
  float m_y;
  float m_z;

  friend class Vector2D;
  friend class Vector4D;

  friend inline Vector3D operator*(const Vector3D& vector, const Matrix4x4& matrix);
  friend inline Vector3D operator*(const Matrix4x4& matrix, const Vector3D& vector);
};

inline bool operator==(const Vector3D& v1, const Vector3D& v2) { return v1.m_x == v2.m_x && v1.m_y == v2.m_y && v1.m_z == v2.m_z; }

inline bool operator!=(const Vector3D& v1, const Vector3D& v2) { return v1.m_x != v2.m_x || v1.m_y != v2.m_y || v1.m_z != v2.m_z; }

inline Vector3D operator+(const Vector3D& v1, const Vector3D& v2) { return {v1.m_x + v2.m_x, v1.m_y + v2.m_y, v1.m_z + v2.m_z}; }

inline Vector3D operator-(const Vector3D& v1, const Vector3D& v2) { return {v1.m_x - v2.m_x, v1.m_y - v2.m_y, v1.m_z - v2.m_z}; }

inline Vector3D operator*(const Vector3D& vector, const float factor) { return {factor * vector.m_x, factor * vector.m_y, factor * vector.m_z}; }
inline Vector3D operator*(const float factor, const Vector3D& vector) { return {factor * vector.m_x, factor * vector.m_y, factor * vector.m_z}; }
inline Vector3D operator*(const Vector3D& v1, const Vector3D& v2) { return {v1.m_x * v2.m_x, v1.m_y * v2.m_y, v1.m_z * v2.m_z}; }

inline Vector3D operator-(const Vector3D& vector) { return {-vector.m_x, -vector.m_y, -vector.m_z}; }
inline Vector3D operator/(const Vector3D& vector, const float divisor) { return {vector.m_x / divisor, vector.m_y / divisor, vector.m_z / divisor}; }

inline bool fuzzyCompare(const Vector3D& v1, const Vector3D& v2) { return fuzzyCompare(v1.m_x, v2.m_x) && fuzzyCompare(v1.m_y, v2.m_y) && fuzzyCompare(v1.m_z, v2.m_z); }


code:
#include "Vector4D.hpp"

#include "Vector2D.hpp"
#include "Vector3D.hpp"

#include <cmath>

Vector4D::Vector4D(const Vector2D& vector)
: m_x(vector.m_x)
, m_y(vector.m_y)
, m_z(0.f)
, m_w(0.f) {}
Vector4D::Vector4D(const Vector2D& vector, const float zpos, const float wpos)
: m_x(vector.m_x)
, m_y(vector.m_y)
, m_z(zpos)
, m_w(wpos) {}

Vector4D::Vector4D(const Vector3D& vector)
: m_x(vector.m_x)
, m_y(vector.m_y)
, m_z(0.f)
, m_w(0.f) {}
Vector4D::Vector4D(const Vector3D& vector, const float wpos)
: m_x(vector.m_x)
, m_y(vector.m_y)
, m_z(vector.m_z)
, m_w(wpos) {}

float Vector4D::length() const { return sqrtf(m_x * m_x + m_y * m_y + m_z * m_z); }

float Vector4D::lengthSquared() const { return m_x * m_x + m_y * m_y + m_z * m_z; }

Vector4D Vector4D::normalized() const {
  const double len = static_cast<double>(m_x) * static_cast<double>(m_x) + static_cast<double>(m_y) * static_cast<double>(m_y) + static_cast<double>(m_z) * static_cast<double>(m_z) +
                     static_cast<double>(m_w) * static_cast<double>(m_w);
  if (fuzzyIsNull(len - 1.0f))
    return *this;
  if (!fuzzyIsNull(len))
    return *this / sqrtf(len);
  return {};
}

void Vector4D::normalize() {
  double len = static_cast<double>(m_x) * static_cast<double>(m_x) + static_cast<double>(m_y) * static_cast<double>(m_y) + static_cast<double>(m_z) * static_cast<double>(m_z) +
               static_cast<double>(m_w) * static_cast<double>(m_w);
  if (fuzzyIsNull(len - 1.0f) || fuzzyIsNull(len)) {
    return;
  }

  len = sqrtf(len);

  m_x /= len;
  m_y /= len;
  m_z /= len;
  m_w /= len;
}

float Vector4D::dotProduct(const Vector4D& v1, const Vector4D& v2) { return v1.m_x * v2.m_x + v1.m_y * v2.m_y + v1.m_z * v2.m_z + v1.m_w * v2.m_w; }

Vector2D Vector4D::toVector2D() const { return {m_x, m_y}; }

Vector2D Vector4D::toVector2DAffine() const {
  if (::isNull(m_w)) {
    return {};
  }
  return {m_x / m_w, m_y / m_w};
}

Vector3D Vector4D::toVector3D() const { return {m_x, m_y, m_z}; }

Vector3D Vector4D::toVector3DAffine() const {
  if (::isNull(m_w)) {
    return {};
  }
  return {m_x / m_w, m_y / m_w, m_z / m_w};
}


code:
#pragma once
#include "MathGlobals.hpp"
#include "Point.hpp"

class Matrix4x4;

class Vector2D;
class Vector3D;

class Vector4D {
public:
  Vector4D()
  : m_x(0.f)
  , m_y(0.f)
  , m_z(0.f)
  , m_w(0.f) {}
  Vector4D(float xpos, float ypos, float zpos, float wpos)
  : m_x(xpos)
  , m_y(ypos)
  , m_z(zpos)
  , m_w(wpos) {}
  explicit Vector4D(const Point& point)
  : m_x(static_cast<float>(point.x()))
  , m_y(static_cast<float>(point.y()))
  , m_z(0.f)
  , m_w(0.f) {}
  explicit Vector4D(const PointF& point)
  : m_x(point.x())
  , m_y(point.y())
  , m_z(0.f)
  , m_w(0.f) {}

  explicit Vector4D(const Vector2D& vector);
  Vector4D(const Vector2D& vector, float m_zos, float m_wos);

  explicit Vector4D(const Vector3D& vector);
  Vector4D(const Vector3D& vector, float m_wos);

  [[nodiscard]] bool isNull() const { return ::isNull(m_x) && ::isNull(m_y) && ::isNull(m_z) && ::isNull(m_w); }

  [[nodiscard]] float x() const { return m_x; }
  [[nodiscard]] float y() const { return m_y; }
  [[nodiscard]] float z() const { return m_z; }
  [[nodiscard]] float w() const { return m_w; }

  void setX(const float aX) { m_x = aX; }
  void setY(const float aY) { m_y = aY; }
  void setZ(const float aZ) { m_z = aZ; }
  void setW(const float aW) { m_w = aW; }

  [[nodiscard]] float length() const;
  [[nodiscard]] float lengthSquared() const;

  [[nodiscard]] Vector4D normalized() const;
  void normalize();

  Vector4D& operator+=(const Vector4D& vector) {
    m_x += vector.m_x;
    m_y += vector.m_y;
    m_z += vector.m_z;
    m_w += vector.m_w;
    return *this;
  }
  Vector4D& operator-=(const Vector4D& vector) {
    m_x -= vector.m_x;
    m_y -= vector.m_y;
    m_z -= vector.m_z;
    m_w -= vector.m_w;
    return *this;
  }
  Vector4D& operator*=(const float factor) {
    m_x *= factor;
    m_y *= factor;
    m_z *= factor;
    m_w *= factor;
    return *this;
  }
  Vector4D& operator*=(const Vector4D& vector) {
    m_x *= vector.m_x;
    m_y *= vector.m_y;
    m_z *= vector.m_z;
    m_w *= vector.m_w;
    return *this;
  }
  Vector4D& operator/=(float divisor) {
    m_x /= divisor;
    m_y /= divisor;
    m_z /= divisor;
    m_w /= divisor;
    return *this;
  }

  static float dotProduct(const Vector4D& v1, const Vector4D& v2);

  friend inline bool operator==(const Vector4D& v1, const Vector4D& v2);
  friend inline bool operator!=(const Vector4D& v1, const Vector4D& v2);
  friend inline Vector4D operator+(const Vector4D& v1, const Vector4D& v2);
  friend inline Vector4D operator-(const Vector4D& v1, const Vector4D& v2);
  friend inline Vector4D operator*(float factor, const Vector4D& vector);
  friend inline Vector4D operator*(const Vector4D& vector, float factor);
  friend inline Vector4D operator*(const Vector4D& v1, const Vector4D& v2);
  friend inline Vector4D operator-(const Vector4D& vector);
  friend inline Vector4D operator/(const Vector4D& vector, float divisor);

  friend inline bool fuzzyCompare(const Vector4D& v1, const Vector4D& v2);

  [[nodiscard]] Vector2D toVector2D() const;
  [[nodiscard]] Vector2D toVector2DAffine() const;

  [[nodiscard]] Vector3D toVector3D() const;
  [[nodiscard]] Vector3D toVector3DAffine() const;

  [[nodiscard]] Point toPoint() const { return {oRound(m_x), oRound(m_y)}; }

  [[nodiscard]] PointF toPointF() const { return {m_x, m_y}; }

#ifdef IMGUI_VERSION
  explicit operator ImVec4() const { return {m_x, m_y, m_z, m_w}; }
#endif

private:
  float m_x;
  float m_y;
  float m_z;
  float m_w;

  friend class Vector2D;
  friend class Vector3D;
  friend Vector4D operator*(const Vector4D& vector, const Matrix4x4& matrix);
  friend Vector4D operator*(const Matrix4x4& matrix, const Vector4D& vector);
};

inline bool operator==(const Vector4D& v1, const Vector4D& v2) { return v1.m_x == v2.m_x && v1.m_y == v2.m_y && v1.m_z == v2.m_z && v1.m_w == v2.m_w; }

inline bool operator!=(const Vector4D& v1, const Vector4D& v2) { return v1.m_x != v2.m_x || v1.m_y != v2.m_y || v1.m_z != v2.m_z || v1.m_w != v2.m_w; }

inline Vector4D operator+(const Vector4D& v1, const Vector4D& v2) { return {v1.m_x + v2.m_x, v1.m_y + v2.m_y, v1.m_z + v2.m_z, v1.m_w + v2.m_w}; }

inline Vector4D operator-(const Vector4D& v1, const Vector4D& v2) { return {v1.m_x - v2.m_x, v1.m_y - v2.m_y, v1.m_z - v2.m_z, v1.m_w - v2.m_w}; }

inline Vector4D operator*(float factor, const Vector4D& vector) { return {vector.m_x * factor, vector.m_y * factor, vector.m_z * factor, vector.m_w * factor}; }

inline Vector4D operator*(const Vector4D& vector, const float factor) { return {vector.m_x * factor, vector.m_y * factor, vector.m_z * factor, vector.m_w * factor}; }

inline Vector4D operator*(const Vector4D& v1, const Vector4D& v2) { return {v1.m_x * v2.m_x, v1.m_y * v2.m_y, v1.m_z * v2.m_z, v1.m_w * v2.m_w}; }

inline Vector4D operator-(const Vector4D& vector) { return {-vector.m_x, -vector.m_y, -vector.m_z, -vector.m_w}; }

inline Vector4D operator/(const Vector4D& vector, float divisor) { return {vector.m_x / divisor, vector.m_y / divisor, vector.m_z / divisor, vector.m_w / divisor}; }

inline bool fuzzyCompare(const Vector4D& v1, const Vector4D& v2) {
  return fuzzyCompare(v1.m_x, v2.m_x) && fuzzyCompare(v1.m_y, v2.m_y) && fuzzyCompare(v1.m_z, v2.m_z) && fuzzyCompare(v1.m_w, v2.m_w);
}


code:
#include "Core/Resources.hpp"

#include <SDL3/SDL.h>

#include <filesystem>
#include <string_view>

#include "Core/Debug/Instrumentor.hpp"

namespace App {

std::filesystem::path Resources::resource_path(const std::filesystem::path& file_path) {
  const char* base_path = SDL_GetBasePath();
  std::filesystem::path path{base_path};
  path /= "../share" / file_path;
  return path;
}

std::filesystem::path Resources::font_path(const std::string_view& font_file) { return resource_path("fonts") / font_file; }
std::filesystem::path Resources::image_path(const std::string_view& image_file) { return resource_path("images") / image_file; }

} // namespace App


code:
#include "Core/Resources.hpp"

#include <SDL3/SDL.h>

#include <filesystem>
#include <string>
#include <string_view>

#include "Core/Debug/Instrumentor.hpp"

namespace App {

std::filesystem::path Resources::resource_path(const std::filesystem::path& file_path) {
  const char* base_path = SDL_GetBasePath();
  std::filesystem::path font_path{base_path};
  font_path /= file_path;
  return font_path;
}

std::filesystem::path Resources::font_path(const std::string_view& font_file) { return resource_path("fonts") / font_file; }
std::filesystem::path Resources::image_path(const std::string_view& image_file) { return resource_path("images") / image_file; }

} // namespace App


code:
#include "Core/Resources.hpp"

#include <SDL3/SDL.h>

#include <filesystem>
#include <string>
#include <string_view>

#include "Core/Debug/Instrumentor.hpp"

namespace App {

std::filesystem::path Resources::resource_path(const std::filesystem::path& file_path) {
  const char* base_path = SDL_GetBasePath();
  std::filesystem::path font_path{base_path};
  font_path /= "../share" / file_path;
  return font_path;
}

std::filesystem::path Resources::font_path(const std::string_view& font_file) { return resource_path("fonts") / font_file; }
std::filesystem::path Resources::image_path(const std::string_view& image_file) { return resource_path("images") / image_file; }

} // namespace App


code:
# Test cases

add_executable(ResourcesTest $<TARGET_OBJECTS:TestRunner> Resources.spec.cpp)
add_test(NAME ResourcesTest COMMAND ResourcesTest)
target_link_libraries(ResourcesTest PRIVATE doctest Core)


code:
#include <doctest/doctest.h>
#include <string>

// NOLINTBEGIN(misc-use-anonymous-namespace, cppcoreguidelines-avoid-do-while, cert-err33-c)

TEST_SUITE("Core::Resources") {
  TEST_CASE("Example") {
    const std::string input{"A"};
    CHECK_EQ(input, "A");
  }
}

// NOLINTEND(misc-use-anonymous-namespace, cppcoreguidelines-avoid-do-while, cert-err33-c)


code:
# Assets for all platforms
set(SHARED_STATIC_ASSETS ${PROJECT_SOURCE_DIR}/src/assets/fonts/MPLUSRounded1c-Medium.ttf)
set(SHARED_STATIC_ASSETS ${PROJECT_SOURCE_DIR}/src/assets/fonts/NotoSansSinhala-Medium.ttf)
set(SHARED_STATIC_ASSETS ${PROJECT_SOURCE_DIR}/src/assets/fonts/JetBrainsMono-Medium.ttf)
set(SHARED_STATIC_ASSETS ${PROJECT_SOURCE_DIR}/src/assets/fonts/mplus-1m-regular.ttf)
set(SHARED_STATIC_ASSETS ${PROJECT_SOURCE_DIR}/src/assets/images/tilemarkers_64x80.png)

# Platform specific static assets
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
    target_sources(${NAME} PUBLIC
            ${SHARED_STATIC_ASSETS}
            ${PROJECT_SOURCE_DIR}/src/assets/icons/icon.ico
            ${PROJECT_SOURCE_DIR}/src/openrpgeditor/Manifests/app.rc
            ${PROJECT_SOURCE_DIR}/src/openrpgeditor/Manifests/App.manifest)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
    set(MACOSX_STATIC_ASSETS
            ${SHARED_STATIC_ASSETS}
            ${PROJECT_SOURCE_DIR}/src/assets/icons/icon.icns)
    target_sources(${NAME} PUBLIC ${MACOSX_STATIC_ASSETS})
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
    target_sources(${NAME} PRIVATE ${SHARED_STATIC_ASSETS})
endif ()


code:
# General target installation settings
install(TARGETS ${NAME}
        BUNDLE DESTINATION .
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})

# Settings for packaging per platform
if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
  include(${PROJECT_SOURCE_DIR}/src/openrpgeditor/cmake/packaging/Windows.cmake)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux")
  include(${PROJECT_SOURCE_DIR}/src/openrpgeditor/cmake/packaging/Linux.cmake)
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
  include(${PROJECT_SOURCE_DIR}/src/openrpgeditor/cmake/packaging/Darwin.cmake)
endif ()


code:
# Get dynamic SDL2 lib into Frameworks folder in app bundle.
# For development:
add_custom_command(TARGET ${NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
        $<TARGET_FILE:SDL3::SDL3>
        $<TARGET_FILE_DIR:${NAME}>/../Frameworks/$<TARGET_FILE_NAME:SDL3::SDL3>)

# For distribution without XCode:
if (NOT "${CMAKE_GENERATOR}" STREQUAL "Xcode")
    install(FILES $<TARGET_FILE:SDL3::SDL3> DESTINATION $<TARGET_FILE_DIR:${NAME}>/../Frameworks/)
endif ()

# macOS package settings
string(TIMESTAMP CURR_YEAR "%Y")
set_target_properties(${NAME} PROPERTIES
        XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
        MACOSX_BUNDLE_BUNDLE_VERSION "${BUILD_VERSION}"
        MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}"
        MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Manifests/Info.plist"
        MACOSX_BUNDLE_GUI_IDENTIFIER "${PROJECT_COMPANY_NAMESPACE}.${CMAKE_PROJECT_NAME}"
        MACOSX_BUNDLE_COPYRIGHT "(c) ${CURR_YEAR} ${PROJECT_COMPANY_NAME}"
        INSTALL_RPATH @executable_path/../Frameworks
        RESOURCE "${MACOSX_STATIC_ASSETS}")


code:
# Copy .so files on Linux to the target App build folder.
# For development:
add_custom_command(TARGET ${NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
        $<TARGET_FILE:SDL3::SDL3>
        $<TARGET_FILE_DIR:${NAME}>)

# For distribution:
install(FILES $<TARGET_FILE:SDL3::SDL3>
        DESTINATION ${CMAKE_INSTALL_BINDIR}
        RENAME ${NAME}_$<TARGET_FILE_NAME:SDL3::SDL3>)

# Copy assets into app bundle
# For development:
add_custom_command(TARGET ${NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_directory
        ${PROJECT_SOURCE_DIR}/src/assets
        $<TARGET_FILE_DIR:${NAME}>/../share)

# For distribution:
install(DIRECTORY ${PROJECT_SOURCE_DIR}/src/assets/ DESTINATION ${CMAKE_INSTALL_DATADIR})

# Linux app icon setup
configure_file(
        ${PROJECT_SOURCE_DIR}/src/openrpgeditor/Manifests/App.desktop.in
        ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.desktop
        @ONLY)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${NAME}.desktop
        DESTINATION share/applications)
install(FILES ${PROJECT_SOURCE_DIR}/src/assets/icons/BaseAppIcon.png
        DESTINATION share/pixmaps
        RENAME ${NAME}_icon.png)


code:
# Use main entry for Windows GUI app.
if (MINGW)
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-subsystem,windows")
    # Static link MinGW standard libraries
    set(CMAKE_CXX_STANDARD_LIBRARIES
            "-static-libgcc -static-libstdc++ -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive")
else ()
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /subsystem:windows /entry:mainCRTStartup")
endif ()

# Copy .dll files on Windows to the target App build folder.
# For development:
add_custom_command(TARGET ${NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
        $<TARGET_FILE:SDL3::SDL3>
        $<TARGET_FILE_DIR:${NAME}>)

install(FILES $<TARGET_FILE:SDL3::SDL3> DESTINATION ${CMAKE_INSTALL_BINDIR})

# For distribution:
# Copy OpenAL DLL to output directory
add_custom_command(TARGET ${NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_if_different
        ${SFML_SOURCE_DIR}/extlibs/bin/x64/openal32.dll
        $<TARGET_FILE_DIR:${NAME}>
)
install(FILES ${SFML_SOURCE_DIR}/extlibs/bin/x64/openal32.dll DESTINATION ${CMAKE_INSTALL_BINDIR})

# Copy assets into app bundle
# For development:
add_custom_command(TARGET ${NAME} POST_BUILD
        COMMAND ${CMAKE_COMMAND} -E copy_directory
        ${PROJECT_SOURCE_DIR}/src/assets
        $<TARGET_FILE_DIR:${NAME}>/../share)

# For distribution:
install(DIRECTORY ${PROJECT_SOURCE_DIR}/src/assets/ DESTINATION ${CMAKE_INSTALL_DATADIR})


code:
#!/bin/bash

for i in {1..24} ;
do
    width=$(expr $i \* 64)
    height=$(expr $i \* 80)
    physicalWidth==$(inkscape -W "assets/images/tilemarkers.svg")
    dpi=$(expr $width \/ physicalWidth)
    filepath="assets/images/tilemarkers_${width}x${height}.png"
    echo "Rendering ${filepath}"
    inkscape -d $dpi "assets/images/tilemarkers.svg" -o $filepath
done


code:
set(NAME "TestRunner")

add_library(${NAME} OBJECT ${PROJECT_SOURCE_DIR}/src/tests/TestRunner.cpp)
target_compile_features(${NAME} PRIVATE cxx_std_20)
target_link_libraries(${NAME} PUBLIC doctest)


code:
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include <doctest/doctest.h>


code:
include(FetchContent)

# Dependencies

FetchContent_Declare(
        fmt
        GIT_REPOSITORY "https://github.com/fmtlib/fmt.git"
        GIT_TAG 10.2.1)

FetchContent_Declare(
        imgui
        #GIT_REPOSITORY "https://github.com/ocornut/imgui.git"
        GIT_REPOSITORY "https://github.com/Antidote/imgui"
        #GIT_TAG docking # Branch: docking
        GIT_TAG docking-layout
)

#FetchContent_Declare(
#        ImGuiFileDialog
#        GIT_REPOSITORY "https://github.com/aiekick/ImGuiFileDialog.git"
#        GIT_TAG v0.6.7
#)

FetchContent_Declare(
        clip
        GIT_REPOSITORY "https://github.com/dacap/clip.git"
        GIT_TAG main
)

FetchContent_Declare(
        implot
        GIT_REPOSITORY "https://github.com/epezent/implot.git"
        GIT_TAG master
)

FetchContent_Declare(
        SDL3
        GIT_REPOSITORY "https://github.com/libsdl-org/SDL.git"
        GIT_TAG release-3.2.12)

FetchContent_Declare(
        SDL3_image
        GIT_REPOSITORY https://github.com/libsdl-org/SDL_image
        GIT_TAG release-3.2.x)

FetchContent_Declare(
        spdlog
        GIT_REPOSITORY "https://github.com/gabime/spdlog.git"
        GIT_TAG v1.15.2)

FetchContent_Declare(json
        GIT_REPOSITORY "https://github.com/nlohmann/json.git"
)

FetchContent_Declare(magic_enum
        GIT_REPOSITORY "https://github.com/Neargye/magic_enum.git")

FetchContent_Declare(
        SFML
        GIT_REPOSITORY https://github.com/SFML/SFML.git
        GIT_TAG 2.6.2)
FetchContent_MakeAvailable(
        SFML
)

if (NOT TARGET freetype)
    FetchContent_Declare(freetype2
            GIT_REPOSITORY "https://github.com/freetype/freetype"
            GIT_TAG VER-2-13-3
    )
    FetchContent_MakeAvailable(
            freetype2
    )
endif ()

FetchContent_Declare(curl
        GIT_REPOSITORY "https://github.com/curl/curl.git"
        GIT_TAG curl-8_10_1
)

FetchContent_Declare(cpuid
        GIT_REPOSITORY "https://github.com/anrieff/libcpuid.git"
        GIT_TAG v0.7.0
)

FetchContent_Declare(athena
        GIT_REPOSITORY "https://github.com/libAthena/athena.git"
        GIT_TAG master
)

FetchContent_Declare(liblcf
        GIT_REPOSITORY "https://github.com/EasyRPG/liblcf.git"
)

FetchContent_Declare(moloader
        GIT_REPOSITORY "https://github.com/Antidote/moloader.git"
        GIT_TAG main
)
# Settings

# For SDL2 to be able to override options
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)

set(BUILD_STATIC_LIBRARIES ON)
set(BUILD_SHARED_LIBRARIES OFF)
set(BUILD_CURL_EXE OFF)
set(DOCTEST_NO_INSTALL ON)
set(FMT_INSTALL OFF)
set(FMT_STATIC ON)
set(SDL3_DISABLE_SDL2MAIN ON)
set(SDL_STATIC_ENABLED_BY_DEFAULT OFF)
set(BUILD_SHARED_LIBS OFF)
set(SPDLOG_FMT_EXTERNAL ON)
set(SPDLOG_BUILD_SHARED OFF)
set(SPDLOG_ENABLE_PCH ON)
set(SDLIMAGE_VENDORED OFF)
set(LIBLCF_WITH_XML OFF)
set(JSON_ImplicitConversions OFF)
set(LIBLCF_WITH_INI OFF)
if (APPLE)
    set(LIBLCF_WITH_ICU OFF)
endif ()
# Populate

FetchContent_MakeAvailable(
        fmt
        SDL3
        SDL3_image
        spdlog
        json
        magic_enum
        clip
        curl
        liblcf
        imgui
        implot
        cpuid
        athena
        moloader
)

add_subdirectory(imgui-setup)

#target_include_directories(ImGuiFileDialog PRIVATE ${imgui_SOURCE_DIR})
#target_compile_definitions(ImGuiFileDialog PRIVATE USE_THUMBNAILS DONT_DEFINE_AGAIN__STB_IMAGE_IMPLEMENTATION)
#target_compile_options(ImGuiFileDialog PRIVATE "-Wno-deprecated-enum-enum-conversion")


code:
project(imgui-setup LANGUAGES CXX C)

set(CMAKE_CXX_STANDARD 20)
set(CMAKE_C_STANDARD 17)

add_library(imgui-setup STATIC
        ${implot_SOURCE_DIR}/implot.h ${implot_SOURCE_DIR}/implot.cpp
        ${implot_SOURCE_DIR}/implot_demo.cpp
        ${implot_SOURCE_DIR}/implot_internal.h ${implot_SOURCE_DIR}/implot_items.cpp
        ${imgui_SOURCE_DIR}/imgui.cpp ${imgui_SOURCE_DIR}/imgui.h
        ${imgui_SOURCE_DIR}/imgui_stacklayout.cpp ${imgui_SOURCE_DIR}/imgui_stacklayout.h
        ${imgui_SOURCE_DIR}/imgui_stacklayout_internal.h
        ${imgui_SOURCE_DIR}/imconfig.h ${imgui_SOURCE_DIR}/imgui_demo.cpp
        ${imgui_SOURCE_DIR}/imgui_draw.cpp ${imgui_SOURCE_DIR}/imgui_internal.h
        ${imgui_SOURCE_DIR}/imgui_tables.cpp ${imgui_SOURCE_DIR}/imgui_widgets.cpp
        ${imgui_SOURCE_DIR}/imstb_rectpack.h ${imgui_SOURCE_DIR}/imstb_textedit.h
        ${imgui_SOURCE_DIR}/imstb_truetype.h
        ${imgui_SOURCE_DIR}/misc/cpp/imgui_stdlib.h ${imgui_SOURCE_DIR}/misc/cpp/imgui_stdlib.cpp
        ${imgui_SOURCE_DIR}/misc/freetype/imgui_freetype.h ${imgui_SOURCE_DIR}/misc/freetype/imgui_freetype.cpp
        ${imgui_SOURCE_DIR}/backends/imgui_impl_sdl3.h ${imgui_SOURCE_DIR}/backends/imgui_impl_sdl3.cpp
        ${imgui_SOURCE_DIR}/backends/imgui_impl_sdlrenderer3.h ${imgui_SOURCE_DIR}/backends/imgui_impl_sdlrenderer3.cpp
)

target_include_directories(imgui-setup PUBLIC ${imgui_SOURCE_DIR} ${implot_SOURCE_DIR} "${freetype2_SOURCE_DIR}/include")
target_compile_features(imgui-setup PRIVATE cxx_std_20)
target_compile_definitions(imgui-setup PUBLIC IMGUI_HAS_STACK_LAYOUT IMGUI_DEFINE_MATH_OPERATORS IMGUI_ENABLE_FREETYPE)
target_link_libraries(imgui-setup PUBLIC SDL3::SDL3 freetype)


code:
// dear imgui: Renderer Backend for SDL_Renderer for SDL2
// (Requires: SDL 2.0.17+)

// Note how SDL_Renderer is an _optional_ component of SDL2.
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
// If your application will want to render any non trivial amount of graphics other than UI,
// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and
// it might be difficult to step out of those boundaries.

// Implemented features:
//  [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
//  [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
// Missing features:
//  [ ] Renderer: Multi-viewport support (multiple windows).

// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ                  https://dearimgui.com/faq
// - Getting Started      https://dearimgui.com/getting-started
// - Documentation        https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp

// CHANGELOG
//  2024-05-14: *BREAKING CHANGE* ImGui_ImplSDLRenderer3_RenderDrawData() requires SDL_Renderer* passed as parameter.
//  2023-05-30: Renamed imgui_impl_sdlrenderer.h/.cpp to imgui_impl_sdlrenderer2.h/.cpp to accommodate for upcoming SDL3.
//  2022-10-11: Using 'nullptr' instead of 'NULL' as per our switch to C++11.
//  2021-12-21: Update SDL_RenderGeometryRaw() format to work with SDL 2.0.19.
//  2021-12-03: Added support for large mesh (64K+ vertices), enable ImGuiBackendFlags_RendererHasVtxOffset flag.
//  2021-10-06: Backup and restore modified ClipRect/Viewport.
//  2021-09-21: Initial version.

#include "imgui.h"
#ifndef IMGUI_DISABLE
#include "imgui_impl_sdlrenderer2.h"
#include <stdint.h>     // intptr_t

// Clang warnings with -Weverything
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-conversion"    // warning: implicit conversion changes signedness
#endif

// SDL
#include <SDL.h>
#if !SDL_VERSION_ATLEAST(2,0,17)
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function
#endif

// SDL_Renderer data
struct ImGui_ImplSDLRenderer2_Data
{
    SDL_Renderer*   Renderer;       // Main viewport's renderer
    SDL_Texture*    FontTexture;
    ImGui_ImplSDLRenderer2_Data()   { memset((void*)this, 0, sizeof(*this)); }
};

// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
static ImGui_ImplSDLRenderer2_Data* ImGui_ImplSDLRenderer2_GetBackendData()
{
    return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}

// Functions
bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer)
{
    ImGuiIO& io = ImGui::GetIO();
    IMGUI_CHECKVERSION();
    IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
    IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!");

    // Setup backend capabilities flags
    ImGui_ImplSDLRenderer2_Data* bd = IM_NEW(ImGui_ImplSDLRenderer2_Data)();
    io.BackendRendererUserData = (void*)bd;
    io.BackendRendererName = "imgui_impl_sdlrenderer2";
    io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;  // We can honor the ImDrawCmd::VtxOffset field, allowing for large meshes.

    bd->Renderer = renderer;

    return true;
}

void ImGui_ImplSDLRenderer2_Shutdown()
{
    ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
    IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
    ImGuiIO& io = ImGui::GetIO();

    ImGui_ImplSDLRenderer2_DestroyDeviceObjects();

    io.BackendRendererName = nullptr;
    io.BackendRendererUserData = nullptr;
    io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset;
    IM_DELETE(bd);
}

static void ImGui_ImplSDLRenderer2_SetupRenderState(SDL_Renderer* renderer)
{
	// Clear out any viewports and cliprect set by the user
    // FIXME: Technically speaking there are lots of other things we could backup/setup/restore during our render process.
	SDL_RenderSetViewport(renderer, nullptr);
	SDL_RenderSetClipRect(renderer, nullptr);
}

void ImGui_ImplSDLRenderer2_NewFrame()
{
    ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
    IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLRenderer2_Init()?");

    if (!bd->FontTexture)
        ImGui_ImplSDLRenderer2_CreateDeviceObjects();
}

void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer)
{
	// If there's a scale factor set by the user, use that instead
    // If the user has specified a scale factor to SDL_Renderer already via SDL_RenderSetScale(), SDL will scale whatever we pass
    // to SDL_RenderGeometryRaw() by that scale factor. In that case we don't want to be also scaling it ourselves here.
    float rsx = 1.0f;
	float rsy = 1.0f;
	SDL_RenderGetScale(renderer, &rsx, &rsy);
    ImVec2 render_scale;
	render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f;
	render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f;

	// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
	int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x);
	int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y);
	if (fb_width == 0 || fb_height == 0)
		return;

    // Backup SDL_Renderer state that will be modified to restore it afterwards
    struct BackupSDLRendererState
    {
        SDL_Rect    Viewport;
        bool        ClipEnabled;
        SDL_Rect    ClipRect;
    };
    BackupSDLRendererState old = {};
    old.ClipEnabled = SDL_RenderIsClipEnabled(renderer) == SDL_TRUE;
    SDL_RenderGetViewport(renderer, &old.Viewport);
    SDL_RenderGetClipRect(renderer, &old.ClipRect);

	// Will project scissor/clipping rectangles into framebuffer space
	ImVec2 clip_off = draw_data->DisplayPos;         // (0,0) unless using multi-viewports
	ImVec2 clip_scale = render_scale;

    // Render command lists
    ImGui_ImplSDLRenderer2_SetupRenderState(renderer);
    for (int n = 0; n < draw_data->CmdListsCount; n++)
    {
        const ImDrawList* cmd_list = draw_data->CmdLists[n];
        const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data;
        const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data;

        for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
        {
            const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
            if (pcmd->UserCallback)
            {
                // User callback, registered via ImDrawList::AddCallback()
                // (ImDrawCallback_ResetRenderState is a special callback value used by the user to request the renderer to reset render state.)
                if (pcmd->UserCallback == ImDrawCallback_ResetRenderState)
                    ImGui_ImplSDLRenderer2_SetupRenderState(renderer);
                else
                    pcmd->UserCallback(cmd_list, pcmd);
            }
            else
            {
                // Project scissor/clipping rectangles into framebuffer space
                ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
                ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
                if (clip_min.x < 0.0f) { clip_min.x = 0.0f; }
                if (clip_min.y < 0.0f) { clip_min.y = 0.0f; }
                if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; }
                if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; }
                if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
                    continue;

                SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) };
                SDL_RenderSetClipRect(renderer, &r);

                const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, pos));
                const float* uv = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, uv));
#if SDL_VERSION_ATLEAST(2,0,19)
                const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.19+
#else
                const int* color = (const int*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); // SDL 2.0.17 and 2.0.18
#endif

                // Bind texture, Draw
				SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID();
                SDL_RenderGeometryRaw(renderer, tex,
                    xy, (int)sizeof(ImDrawVert),
                    color, (int)sizeof(ImDrawVert),
                    uv, (int)sizeof(ImDrawVert),
                    cmd_list->VtxBuffer.Size - pcmd->VtxOffset,
                    idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx));
            }
        }
    }

    // Restore modified SDL_Renderer state
    SDL_RenderSetViewport(renderer, &old.Viewport);
    SDL_RenderSetClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr);
}

// Called by Init/NewFrame/Shutdown
bool ImGui_ImplSDLRenderer2_CreateFontsTexture()
{
    ImGuiIO& io = ImGui::GetIO();
    ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();

    // Build texture atlas
    unsigned char* pixels;
    int width, height;
    io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);   // Load as RGBA 32-bit (75% of the memory is wasted, but default font is so small) because it is more likely to be compatible with user's existing shaders. If your ImTextureId represent a higher-level concept than just a GL texture id, consider calling GetTexDataAsAlpha8() instead to save on GPU memory.

    // Upload texture to graphics system
    // (Bilinear sampling is required by default. Set 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines' or 'style.AntiAliasedLinesUseTex = false' to allow point/nearest sampling)
    bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height);
    if (bd->FontTexture == nullptr)
    {
        SDL_Log("error creating texture");
        return false;
    }
    SDL_UpdateTexture(bd->FontTexture, nullptr, pixels, 4 * width);
    SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND);
    SDL_SetTextureScaleMode(bd->FontTexture, SDL_ScaleModeLinear);

    // Store our identifier
    io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture);

    return true;
}

void ImGui_ImplSDLRenderer2_DestroyFontsTexture()
{
    ImGuiIO& io = ImGui::GetIO();
    ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData();
    if (bd->FontTexture)
    {
        io.Fonts->SetTexID(0);
        SDL_DestroyTexture(bd->FontTexture);
        bd->FontTexture = nullptr;
    }
}

bool ImGui_ImplSDLRenderer2_CreateDeviceObjects()
{
    return ImGui_ImplSDLRenderer2_CreateFontsTexture();
}

void ImGui_ImplSDLRenderer2_DestroyDeviceObjects()
{
    ImGui_ImplSDLRenderer2_DestroyFontsTexture();
}

//-----------------------------------------------------------------------------

#if defined(__clang__)
#pragma clang diagnostic pop
#endif

#endif // #ifndef IMGUI_DISABLE


code:
// dear imgui: Renderer Backend for SDL_Renderer for SDL2
// (Requires: SDL 2.0.17+)

// Note how SDL_Renderer is an _optional_ component of SDL2.
// For a multi-platform app consider using e.g. SDL+DirectX on Windows and SDL+OpenGL on Linux/OSX.
// If your application will want to render any non trivial amount of graphics other than UI,
// please be aware that SDL_Renderer currently offers a limited graphic API to the end-user and
// it might be difficult to step out of those boundaries.

// Implemented features:
//  [X] Renderer: User texture binding. Use 'SDL_Texture*' as ImTextureID. Read the FAQ about ImTextureID!
//  [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
// Missing features:
//  [ ] Renderer: Multi-viewport support (multiple windows).

// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.
// Learn about Dear ImGui:
// - FAQ                  https://dearimgui.com/faq
// - Getting Started      https://dearimgui.com/getting-started
// - Documentation        https://dearimgui.com/docs (same as your local docs/ folder).
// - Introduction, links and more at the top of imgui.cpp

#pragma once
#ifndef IMGUI_DISABLE
#include "imgui.h"      // IMGUI_IMPL_API

struct SDL_Renderer;

IMGUI_IMPL_API bool     ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer);
IMGUI_IMPL_API void     ImGui_ImplSDLRenderer2_Shutdown();
IMGUI_IMPL_API void     ImGui_ImplSDLRenderer2_NewFrame();
IMGUI_IMPL_API void     ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer);

// Called by Init/NewFrame/Shutdown
IMGUI_IMPL_API bool     ImGui_ImplSDLRenderer2_CreateFontsTexture();
IMGUI_IMPL_API void     ImGui_ImplSDLRenderer2_DestroyFontsTexture();
IMGUI_IMPL_API bool     ImGui_ImplSDLRenderer2_CreateDeviceObjects();
IMGUI_IMPL_API void     ImGui_ImplSDLRenderer2_DestroyDeviceObjects();

#endif // #ifndef IMGUI_DISABLE


code:
### Pepper Mackin On A Girl

### Report Began On March 23rd, 2018

### Incident began roughly around April-May 2016
How It Began
------
According to sources by Fraggin, Pepper tried to go for a chick who just broke up with her boyfriend.
The girl decided to engage in a relationship with Pepper, likely due to mental stress and a sudden complete lapse of judgement,
giving Pepper a slight confidence boost. However within a day, she realized this was a terrible mistake and consulted to Fraggin about her problems.
This would lead to a very interesting situation.

Things Get Spicy
------
The girl told Fraggin about her problems, to which Fraggin advised her to let him down gently.
She did, however Pepper did not relent. While they became sort of friends afterwards, Pepper decided to continue with
lewd comments with her within games such as League Of Legends.

The Three Way
------
Eventually Pepper was desperate enough to ask for Fraggin for the three way and Fraggin reluctantly accepted due to the girl
being interested in this (mainly due to her attraction to Fraggin).
So maybe, Fraggin & Pepper were cucking each other?

Towards The End
------
After a week, the girl got back with her ex and Pepper seethed in rage towards the ex and Fraggin due to believing he helped set up
the downfall of the one day relationship with the girl. Pepper never forgave Fraggin.

repo_name: totsuya/The

path: After Action Reports/Pepper Crush On Girl In Facebook 2016.md


code: Dedicated non-canon stories of the b7 lore

path: Non-canon B7 Stories/non-canon.md


code:
# Patrick Hocke Profiling

### **DATE OF CREATION**: April 3rd, 2018

## Basic Information
  **Name**: Patrick Hocke

  **Age**: 22 (possibly 23?)

  **Last Known Location** Pennsylvania, USA

  **Physical Description**: Chubby, overweight Caucasian man, stated to have unnaturally kind eyes.

  Missing two fingers on his left hand (middle and ring finger)

  **Mental Status**: Self-describes as nervous wreck, likely has a autism disorder of some kind?

  Is believed to be generally non-violent though it is unknown what will happen if he reached a mental breaking point.

  **Sexual Orientation**: ???

## Known Aliases
1. AnonymousPepper (on most forums)
2. AP#9786 (On Discord)
3. JustMonikammmmmmmmmm (Fanfiction.net)
4. (Tinder) TO BE FOUND

# Pepper Profile

Patrick Hocke, otherwise known to "friends" as AnonymousPepper is a Caucasian man living in Pennsylvania state of the United States of America.
He is believed to live with his grandmother and generally is to believed to have a less than amicable relationship with most of his family members including his
father and mother.

Not much is known about his youth, though as he grew into adolescence found a gaming forum called "Gamefaqs", centered around providing assistance & discussion of
video games. However, the forum also have several sub-forums, one of them known as Current Events, otherwise referred to as "CE". Despite it's name, many things other than actual news is discussion on this sub-forum such as socially awkward incel complaining and general shitposting.

His general posting style is seems to mainly focused on politics or ramblings about his daily life. Unfortunately, the Gamefaqs Archive, a tool that would have been very useful in tracking old Pepper posts has gone down and thus the exact known quantity of his posts are gone forever.

As time passed, CE was developing a TF2 team, Pepper met a group that would change his life and scar him forever: B7.

At the time, Pepper was a avid Team Fortress 2 player, a popular and well-known game created by Valve. It is a a first person shooter with emphasis on classes that synergize with each other and counter other classes. The game was a few years old at this point but still have a very strong and active player base at the time and several tournaments were being done. One of them being the United Gaming League, an organization that hosts several tournaments for a few games. A team was being made in CE to participate in the UGC's highlander tournament seasons, which is a 9v9 mode with one of every class on each team. Pepper opted to join the new team as a Medic, an extremely core and important role. This was turned out to be a very terrible mistake for him.

The team was named B7 or alternatively 'ToU Violation' in reference to Gamefaqs Terms of Use. The moderators were known to be fairly strict with the rules

path: Pepper Dossier/Pepper Profile.MD


code:
# The Pepper Archive

This is a archive of notable incidents of B7 (and mainly Pepper).

This is a preservation effort to reduce the chances of B7 lore being lost amongst the abyss of the internet.

I will be your curator (tots) and will be working hard (not really) to add more files and data as time goes on.

Please enjoy.

autism

Also we're looking for collaborators, you only need to have knowledge of git terminal

thank

**DISCLAIMER: DO NOT USE THIS TO HARASS ANYONE IN ANY WAY** (he is meant for observing)

# How the Pepper Files works

The Pepper files is a collection of known events about Pepper and as such, we try and organize folders so it's easy to find what you're looking for.

The type of files are:

**After Action Reports**: Focused on the various shenanigans Pepper finds himself caught up with, these are reports focusing on the actual events Pepper participates in. While these events can be referenced in other files within the Pepper Files, their main focused should be self contained.

**Evidence**: Snapshots of actual proof of conversation is stored here or other images of evidence available to us. This term is broad, but basically anything that helps prove that the various events we report on actually _happened_.

**Pepper Dossier**: The actual profiling of Pepper is stored here. This stores the various unedited pictures we have of Pepper and documents that profile him. While various events can be referenced in the Pepper dossier, they should not receive too much focus, as those events are referenced in greater detail in After Action Reports.

**Typed or Recorded Convos**: .txt versions of various conversation and any recorded conversations are stored here. This generally collaborates with the Evidence folder.


code:
FRAGGIN-TOTS DISCUSSION
MARCH 23 2018
SOURCE: DISCORD DM

Fraggin - Today at 10:37 PM
Basically, him and I were hanging out with these mutual league friends, and this one girl broke up with her boyfriend. Pepper, being the suave man that he was, swooped in and started "courting" this lady. She and I were really close, and after a couple days of being with Pepper, she came crying to me, telling me how much of a mistake it was, and that she actually really liked me, and apparently did since we started talking. After her breakup though, she was so down and sad about the whole thing, that when Pepper swooped in with his cheeto dust covered fedora tipping antics, she sorta went with it because she felt like she needed to be with someone at the time. Like I said, she literally came crying her eyes out to me, telling me how much she messed up and how she felt like it was a big mistake.
Then, it continues.
[10:37 PM] totsuya: w o w
[10:38 PM] totsuya: btw i deleted your post to hide from pepper
[10:38 PM] totsuya: i'm storing up my pepper lore energy
[10:40 PM] Fraggin: I tell her to let him down easy, and she tries, but he wouldn't stop making these incredibly awkward, cringy sexual remarks during games with her. Then she finally let him have it. She didn't want me or Pepper, and she just wanted time to herself. Which is all fine of course. Then Pepper makes these really weird, depressed, sad facebook posts that he makes so only she can see, probably to get sympathy and try to force her back with him out of guilt.
[10:40 PM] Fraggin: Hold on, I'll see if I can find the screencaps she took.
[10:40 PM] totsuya: oh fuck we have evidence
[10:40 PM] totsuya: aaaaaaaaaaaaaaa
[10:45 PM] Fraggin: Alright, hold on. I think I'm close to getting it.
[10:50 PM] Fraggin: Okay, found them.
[10:51 PM] Fraggin: Now, I would have for sure kept this hidden and safe because Pepper is a friend-o, BUT considering he kinda said he hates me or something, I guess that means I wouldn't need to feel much remorse. :stuck_out_tongue:
[10:51 PM] totsuya: wowowowowow
[10:51 PM] Fraggin: TIME TO DUNK ON HIM GUD
(Fraggin commences image dumb, images can be files via images/FacebookPepper folder)
[10:52 PM] totsuya: WOW
[10:54 PM] totsuya: so when was this
[10:54 PM] totsuya: looks like april right
[10:54 PM] totsuya: last year
[10:55 PM] Fraggin: It was actually in about 2016 I believe.
[10:55 PM] Fraggin: So it's a bit old.
[10:55 PM] totsuya: whatever that's fine
[10:55 PM] totsuya: i need to archive this in my Pepper Files folder
[10:55 PM] Fraggin: Can say it's from 2017 if it fits better with the lore though
[10:56 PM] Fraggin: Now remember, he made those facebook psts so only SHE could see them. No one else. Makes it even more amusing.
[11:01 PM] totsuya: imagine pepper telling you needs you badly
[11:02 PM] Fraggin: And then to continue with the story, eventually, I don't remember how it came up, but because she was still kinda into me, Pepper proposed we get into a three way relationship. Which she was very ecstatic about. Me not so much, because I wouldn't want to be that close to Pepper ever, but I decided to roll with it, more to keep her from having to be possibly just stuck with Pepper.
[11:02 PM] totsuya: wait
[11:02 PM] totsuya: so does that mean
[11:02 PM] totsuya: pepper let himself get cucked
[11:02 PM] totsuya: aaaaaaaaaaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[11:07 PM] Fraggin: Eventually she decided to get back with her ex, which devastated Pepper, but I was actually quite for it. Pepper HATED him for such a long time. Pepper hated this man, presumably, for "stealing his girl". When me and her former ex, once again boyfriend talked, I even told him that I was happy it was him, because at least it wasn't Pepper (and trust me, she was miserable when she was with Pepper, for like, 3 days. Which is how long their relationship lasted by the way) And he told me that if she wasn't back with him, he'd rather she be with me instead of Pepper.
[11:07 PM] totsuya: WOWOOWOWOW
[11:10 PM] Fraggin: So that my dear Tots, is the saga of Peppers love.
[11:10 PM] Fraggin: And yes, he basically let himself get cucked.
[11:13 PM] totsuya: damn i can't tell if this is is heavier than the legendary box of roses incident
[11:16 PM] Fraggin: Random bit of side lore, he got into a relationship with another girl from that discord not long after. It lasted maybe a few days to a week at most, and whenever she gets tipsy, Pepper will ask her to play league and make her use a valentine heart profile picture with him so they can match, and he can pretend.
[11:16 PM] totsuya: >pretend
[11:16 PM] Fraggin: Yeah, I suppose he still liked to pretend they're in a relationship when she's tipsy...
[11:17 PM] Fraggin: Even though she has a boyfriend.
[11:17 PM] Fraggin: One that she posts about on facebook fairly regularly in fact.

path: Typed Or Recorded Convos/Fraggin-Tots.txt


code:
# Ignore all files
*.*

# File Types
!*.mps
!*.dat
!*.json
!*.txt
!*.project
!*.js
!*.zip
!*.7z
!*.csv
!*.ain
!*.fnl
!*.ks
!*.tjs
!*.yaml
!*.rb
!*.rvdata2

# Other Needed Files
!.gitignore
!README.md
!patch-config.txt
!GameUpdate*
!patch*
!Game.dat
!bsxx.dat*
!game.ini

# Ignore
previous_patch_sha.txt
kabe3_save.dat
kabe3_system.dat
psbpack.dat
Save*
cg.dat
scene.dat
BSXScript_*

# Images
!/www/img/battlecommands/*
!cos_01rose.rpgmvp
!cos_02sea.rpgmvp
!dokonero_00omakase.rpgmvp
!dokonero_01tekoki.rpgmvp
!dokonero_02shita.rpgmvp
!dokonero_03pechi.rpgmvp
!dokonero_04umanori.rpgmvp
!dokonero_05pantsu.rpgmvp
!dokonero_06back.rpgmvp
!dokonero_07fera.rpgmvp
!dokonero_08paizuri.rpgmvp
!eat_cho_01.rpgmvp
!eat_cho_02.rpgmvp
!idouma_1minami.rpgmvp
!idouma_2nanto.rpgmvp
!idouma_3nansei.rpgmvp
!idouma_4hokuto.rpgmvp
!idouma_5kita.rpgmvp
!idouma_6hokusei.rpgmvp
!map_n2_01.rpgmvp
!map_n2_02.rpgmvp
!map_n2_03.rpgmvp
!map_n2_04.rpgmvp
!map_n_01.rpgmvp
!map_n_02.rpgmvp
!map_n_03.rpgmvp
!map_n_04.rpgmvp
!map_n_05.rpgmvp
!map_n_06.rpgmvp
!map_n_07.rpgmvp
!map_n_08.rpgmvp
!map_n_09.rpgmvp
!map_n_10.rpgmvp
!map_n_11.rpgmvp
!map_n_12.rpgmvp
!map_n_13.rpgmvp
!map_n_14.rpgmvp
!map_n_15.rpgmvp
!map_n_16.rpgmvp
!map_n_17.rpgmvp
!map_n_18.rpgmvp
!map_n_19.rpgmvp
!map_n_20.rpgmvp
!map_n_20_2.rpgmvp
!map_n_21.rpgmvp
!map_n_22.rpgmvp
!map_n_23.rpgmvp
!map_n_24.rpgmvp
!map_n_25.rpgmvp
!map_n_26.rpgmvp
!map_n_27.rpgmvp
!map_n_28.rpgmvp
!map_n_mo.rpgmvp
!map_town1a_01.rpgmvp
!map_town1a_02.rpgmvp
!map_town1a_03.rpgmvp
!map_town1a_04.rpgmvp
!map_town1b_01.rpgmvp
!map_town1b_02.rpgmvp
!map_town1b_03.rpgmvp
!map_town1b_04.rpgmvp
!map_town1b_05.rpgmvp
!map_town1c_01.rpgmvp
!map_town1c_02.rpgmvp
!map_town1c_03.rpgmvp
!map_town1d_01.rpgmvp
!map_town1d_02.rpgmvp
!map_town1e_01.rpgmvp
!map_town1e_02.rpgmvp
!map_town1f_01.rpgmvp
!map_town1f_02.rpgmvp
!map_town1f_03.rpgmvp
!map_town1_yado.rpgmvp
!map_town2_01.rpgmvp
!map_town3_01.rpgmvp
!map_town4_01.rpgmvp
!map_town4_02.rpgmvp
!map_town5_01.rpgmvp
!map_town6_01.rpgmvp
!map_town6_02.rpgmvp
!map_town6_03.rpgmvp
!map_town7_01.rpgmvp
!map_town8_01.rpgmvp
!map_town8_02.rpgmvp
!map_town8_03.rpgmvp
!map_x_field_00_town.rpgmvp
!map_x_field_01_elf_01.rpgmvp
!map_x_field_01_elf_02.rpgmvp
!map_x_field_01_elf_03.rpgmvp
!map_x_field_02_pamara_01.rpgmvp
!map_x_field_02_pamara_b01.rpgmvp
!map_x_field_02_pamara_b02.rpgmvp
!map_x_field_03_02mizu.rpgmvp
!map_x_field_03_03cazz.rpgmvp
!map_x_field_03_sicchityuo.rpgmvp
!map_x_field_04_grud_02tyu.rpgmvp
!map_x_field_04_grud_mura.rpgmvp
!map_x_field_04_grud_shinden.rpgmvp
!map_x_field_05_beir.rpgmvp
!map_x_field_06_aonagi.rpgmvp
!map_x_field_06_regnas_mura.rpgmvp
!map_x_field_07_demon.rpgmvp
!map_x_field_07_kaido_1.rpgmvp
!map_x_field_07_makutsu.rpgmvp
!map_x_field_07_makutsu2.rpgmvp
!map_x_field_x_tabi.rpgmvp
!menu_config.rpgmvp
!menu_equip.rpgmvp
!menu_exit.rpgmvp
!menu_item.rpgmvp
!menu_quest.rpgmvp
!menu_save.rpgmvp
!menu_save_load.rpgmvp
!menu_save_save.rpgmvp
!menu_skill.rpgmvp
!menu_skin.rpgmvp
!menu_state.rpgmvp
!menu_story.rpgmvp
!quest_clear_03.rpgmvp
!shop_cho_dogu.rpgmvp
!shop_cho_shokuzai.rpgmvp
!shop_cho_sobi.rpgmvp
!smi_cho1_01.rpgmvp
!smi_cho1_02.rpgmvp
!smi_cho1_03.rpgmvp
!smi_cho1_03b.rpgmvp
!smi_cho1_04.rpgmvp
!smi_cho1_04b.rpgmvp
!uma_cho1_01.rpgmvp
!uma_cho1_02.rpgmvp
!LayoutCommand.rpgmvp
!LayoutSlot.rpgmvp
!Com_0.rpgmvp
!Com_1.rpgmvp
!Com_2.rpgmvp
!Com_3.rpgmvp
!Layout.rpgmvp
!02_cutin_08mune.rpgmvp
!boutou_tero.rpgmvp
!costume_buck.rpgmvp
!cos_01rose.rpgmvp
!cos_02sea.rpgmvp
!cos_03maid.rpgmvp
!cos_04dre.rpgmvp
!cos_05chao.rpgmvp
!cos_06vis.rpgmvp
!cos_07chami.rpgmvp
!cos_08elf.rpgmvp
!cos_09naked.rpgmvp
!dokodemo_nero.rpgmvp
!eat_layout1.rpgmvp
!ero_gauge03.rpgmvp
!ero_gauge03_2.rpgmvp
!ero_HBS01_slimeMizu.rpgmvp
!ero_HBS01_slimeMizu_02_midori.rpgmvp
!ero_HBS02_hibuname_mata.rpgmvp
!ero_HBS03b_kage_01.rpgmvp
!ero_HBS03_tsuta_01_kusa.rpgmvp
!ero_HBS03_tsuta_02_jimen.rpgmvp
!ero_HBS04_kiss_01.rpgmvp
!ero_HBS05_tasoku_01_jimen.rpgmvp
!ero_HBS06_01_munemomi.rpgmvp
!ero_HBS07_saimin_01_kahun_konran.rpgmvp
!ero_HBS08_marunomi_01_mizu.rpgmvp
!ero_HBS09_mizuzeme_01.rpgmvp
!ero_HBS10_tanedukepresu_01.rpgmvp
!ero_HBS11_zenshin_01_gobu.rpgmvp
!ero_ono_01.rpgmvp
!ero_ono_02.rpgmvp
!ero_ono_03.rpgmvp
!ero_ono_04.rpgmvp
!ero_ono_05.rpgmvp
!ero_ono_06.rpgmvp
!ero_ono_07.rpgmvp
!ero_ono_08.rpgmvp
!EVE_00_tuto_03.rpgmvp
!EVE_00_tuto_05.rpgmvp
!EVE_00_tuto_06.rpgmvp
!EVE_00_tuto_07.rpgmvp
!EVE_00_tuto_A_01.rpgmvp
!EVE_00_tuto_A_02.rpgmvp
!EVE_00_tuto_A_03.rpgmvp
!EVE_99_config_01.rpgmvp
!EVE_99_hoho01_01.rpgmvp
!field_name_01.rpgmvp
!field_name_02.rpgmvp
!field_name_03.rpgmvp
!field_name_04.rpgmvp
!field_name_05.rpgmvp
!field_name_06.rpgmvp
!field_name_07.rpgmvp
!field_name_08.rpgmvp
!field_name_09.rpgmvp
!field_name_10.rpgmvp
!field_name_11.rpgmvp
!field_name_12.rpgmvp
!field_name_13.rpgmvp
!field_name_14.rpgmvp
!field_name_15.rpgmvp
!field_name_16.rpgmvp
!field_name_17.rpgmvp
!field_name_18.rpgmvp
!field_name_19.rpgmvp
!field_name_20.rpgmvp
!field_name_20_2.rpgmvp
!field_name_21.rpgmvp
!field_name_22.rpgmvp
!field_name_23.rpgmvp
!field_name_24.rpgmvp
!field_name_25.rpgmvp
!field_name_26.rpgmvp
!field_name_27.rpgmvp
!field_name_28.rpgmvp
!field_name_29.rpgmvp
!foodstuff_menu.rpgmvp
!Lose_001_moji.rpgmvp
!Lose_002_moji.rpgmvp
!Lose_003_moji.rpgmvp
!map_town1a_01.rpgmvp
!map_town1a_02.rpgmvp
!map_town1a_03.rpgmvp
!map_town1a_04.rpgmvp
!map_town1b_01.rpgmvp
!map_town1b_02.rpgmvp
!map_town1b_03.rpgmvp
!map_town1b_04.rpgmvp
!map_town1b_05.rpgmvp
!menu_hai_com.rpgmvp
!menu_hai_com01.rpgmvp
!menu_hai_com02.rpgmvp
!menu_hai_com03.rpgmvp
!menu_hai_com04.rpgmvp
!menu_hai_com05_1.rpgmvp
!menu_hai_com05_2.rpgmvp
!menu_hai_com06.rpgmvp
!menu_hai_com07.rpgmvp
!menu_hai_com08.rpgmvp
!menu_hai_com08_2.rpgmvp
!menu_hai_com13.rpgmvp
!menu_hai_right.rpgmvp
!menu_next.rpgmvp
!quest_clear_02.rpgmvp
!secretprofile_back_01.rpgmvp
!secretprofile_back_02.rpgmvp
!secretprofile_back_03.rpgmvp
!shop_layout1.rpgmvp
!shop_layout2.rpgmvp
!smi_kyokakanryo_1.rpgmvp
!smi_kyo_sentaku_A01.rpgmvp
!smi_kyo_sentaku_B01_2.rpgmvp
!smi_kyo_sentaku_B02_2.rpgmvp
!smi_kyo_sentaku_B03_2.rpgmvp
!smi_kyo_sentaku_B04_2.rpgmvp
!smi_kyo_sentaku_C01_2.rpgmvp
!smi_kyo_sentaku_C02_2.rpgmvp
!smi_kyo_sentaku_C03_2.rpgmvp
!smi_kyo_sentaku_C04_2.rpgmvp
!smi_kyo_sentaku_C05_2.rpgmvp
!smi_kyo_sentaku_C06_2.rpgmvp
!smi_kyo_sentaku_C07_2.rpgmvp
!smi_kyo_sentaku_C08_2.rpgmvp
!smi_kyo_sentaku_D01_2.rpgmvp
!smi_kyo_sentaku_D02_2.rpgmvp
!smi_kyo_sentaku_D03_2.rpgmvp
!smi_kyo_sentaku_D04_2.rpgmvp
!smi_kyo_sentaku_D05_2.rpgmvp
!smi_kyo_sentaku_D06_2.rpgmvp
!smi_kyo_sentaku_D07_2.rpgmvp
!smi_kyo_sentaku_D08_2.rpgmvp
!smi_nerokyo_001.rpgmvp
!smi_nerokyo_002.rpgmvp
!smi_nerokyo_003.rpgmvp
!smi_nerokyo_004.rpgmvp
!smi_nerokyo_005.rpgmvp
!smi_rayout1.rpgmvp
!title_chapter_0.rpgmvp
!title_chapter_1.rpgmvp
!title_chapter_10.rpgmvp
!title_chapter_11.rpgmvp
!title_chapter_12.rpgmvp
!title_chapter_13.rpgmvp
!title_chapter_14.rpgmvp
!title_chapter_2.rpgmvp
!title_chapter_3.rpgmvp
!title_chapter_4.rpgmvp
!title_chapter_5.rpgmvp
!title_chapter_6.rpgmvp
!title_chapter_7.rpgmvp
!title_chapter_8.rpgmvp
!title_chapter_9.rpgmvp
!title_subti_0.rpgmvp
!title_subti_1.rpgmvp
!title_subti_10.rpgmvp
!title_subti_11.rpgmvp
!title_subti_12.rpgmvp
!title_subti_13.rpgmvp
!title_subti_2.rpgmvp
!title_subti_3.rpgmvp
!title_subti_4.rpgmvp
!title_subti_5.rpgmvp
!title_subti_6.rpgmvp
!title_subti_7.rpgmvp
!title_subti_8.rpgmvp
!title_subti_9.rpgmvp
!UI2_HOHOA01wo.rpgmvp
!UI2_HOHOA02ma.rpgmvp
!UI2_HOHOA03kyo.rpgmvp
!UI2_HOHOA04uma.rpgmvp
!UI2_HOHOA04uma2.rpgmvp
!UI2_HOHOA05nero.rpgmvp
!uma_rayout1.rpgmvp
!win_moji_1.rpgmvp
!win_moji_2.rpgmvp
!win_moji_3.rpgmvp
!worldmap_kangokumap.rpgmvp
!Title.rpgmvp

repo_name: dazed/translations

path: .gitignore

license: unknown


code:
@echo off
setlocal

REM Copy GAMEUPDATE.bat to a new file
copy patch.bat patch2.bat

REM Run the new file
call patch2.bat

REM Delete the new file
del patch2.bat

endlocal
@echo on


code:
#!/bin/bash

# Enable error handling
set -e

# Copy patch.bat to a new file
cp patch.sh patch2.sh

# Run the new file
bash patch2.sh

# Delete the new file
rm patch2.sh


code:
# Apply Patch
1. Click Code
2. Click Download ZIP
3. Extract to game folder and Replace All.

## Future Patching
1. Run GAMEUPDATE.bat to auto patch.

# Troubleshooting
**GAMEUPDATE.bat doesn't update and closes immediately**
1. Make sure your path doesn't contain any Japanese characters or lots of whitespace.
2. Make sure you actually have permissions in the folder

For WOLF RPG games, if you downloaded the game off of DLSite, you will need to do some extra steps to patch it. This is because there is a "master" file called Data.wolf that will take priority over the english patch files. You will need this file to be a folder before patching will work.

# Wolf Games
1) Download the latest UberWolf.exe release from the following link:
https://github.com/Sinflower/UberWolf/releases
2) Drag Data.wolf onto UberWolf.exe. This will create a new folder called data.wolf~
3) Rename the new data.wolf~ folder to Data
4) Delete the Data.wolf file
5) Delete previous_patch_sha.txt (this will exist if you ran GameUpdate.bat previously)
6) Run GameUpdate.bat

# Edit/Contribute
TLDR 3 steps.

    Fork the repository.
    Make the changes.
    Submit a merge request.

If everything looks good and doesn't break things I'll merge it in.

Longer Version:

# Required Software:
* [VSCode](https://code.visualstudio.com/) Make sure you check all the boxes for context menus.
* [Git](https://git-scm.com/downloads) (Use the default for everything. Just keep clicking Next)

# Guide to contributing

### 1. Fork the Repository
- Go to the repository you want to fork.
- Click the "Fork" button.

### 2. Clone Your Fork
- Clone your forked repository to your local machine.
    ```sh
    git clone https://gitgud.io/YOUR_USERNAME/REPO_NAME.git
    ```

### 3. Make Your Changes (In VSCode)
- Edit the files locally on your new branch using VSCode.
- Add and commit your changes.
    ```sh
    git add .
    git commit -m "Description of your changes"
    ```

### 4. Push Your Changes
- Push your changes to your fork on GitGud.io.
    ```sh
    git push origin your-feature-branch
    ```

### 5. Create a Merge Request
- Go to your fork on GitGud.io.
- Click on "Merge Requests" in the sidebar.
- Click the "New merge request" button.
- Select the branch you made changes to and the target project (the original repo).
- Provide a title and description for your merge request and submit it.

---

## Example

Assuming you want to fork a repository named `example-project`:

### 1. Fork the Repo
- Navigate to `https://gitgud.io/original_user/example-project` and click "Fork".

### 2. Clone Your Fork
    ```sh
    git clone https://gitgud.io/YOUR_USERNAME/example-project.git
    ```

### 3. Make Changes and Commit
    ```sh
    # Make changes to the files
    git add .
    git commit -m "Add new feature to example project"
    ```

### 4. Push Changes
    ```sh
    git push origin add-new-feature
    ```

### 5. Create a Merge Request
- Go to `https://gitgud.io/YOUR_USERNAME/example-project/merge_requests` and click on "New merge request".
- Choose the source branch `add-new-feature` and target branch (default: `main` or `master`).
- Fill in the details and submit the merge request.


code:
������������������������������������������������������������������������

�@�@�@�����������_�l���X�q�iver 2.03�j

������������������������������������������������������������������������

���̓x�́A�u�����������_�l���X�q�v�����w������
���ɂ��肪�Ƃ��������܂��B

����ReadMe������t�H���_���́uGame.exe�v���N�����邱�Ƃ�
�Q�[�����X�^�[�g���܂��B

�s���@�\�ύX�ɂ��Ă͓�������Ă���u�X�V�����v��
���m�F���������B

���̌��ł���̈��p��

�����̌��ł̃Z�[�u�f�[�^�������p���Ńv���C���\�ł��B
�̌��ő��́uwww�v�t�H���_���ɂ���usave�v�t�H���_��
���i�ő��́uwww�v�t�H���_���Ɉړ������邱�ƂŁA�Z�[�u�f�[�^��
�����p���Ńv���C���邱�Ƃ��o���܂��B

�ړ��̍ۂ�A��������̕s�����������ꍇ���������܂��̂�
���炩���߃o�b�N�A�b�v���������ŃZ�[�u�f�[�^�ڍs�����肢���܂��B

���⑫����

(ver1.03�ǋL)
�E���b�Z�[�W�\�����i�ʏ��b�A�g�V�[���̃e�L�X�g�\�����j��
�uCtrl�v�L�[�������ƃ��b�Z�[�W�E�B���h�E���\���ɂ��邱�Ƃ��o���܂��B
�ēx�L�[�������ƍĂѕ\������܂��B

�E�̌��ł��烌�x���A�b�v�ɕK�v�Ȍo���l�ʂ̒��߂��s���Ă���܂��B
�X�e�[�^�X�m�F���Ɍo���l���}�C�i�X�ɂȂ��Ă���ꍇ���������܂����A
�o���l���擾�����ۂɐ���Ȓl�ɏC������܂��̂ł����S���������B

���z��s����������܂�����A
MOON KNIGHT SPARKLE��Ci-en�̂ق��ɂ��A��������ƍK���ł��B
https://ci-en.dlsite.com/creator/3934

MOON KNIGHT SPARKLE
����

������������������������������������������������������������������������
--�摜�f��--

�҂ۂ�q�� �l
https://pipoya.net/sozai/assets/fog/fog-image/

--�X�N���v�g--

Yanfly �l
http://www.yanfly.moe/wiki/Category:Yanfly_Engine_Plugins

����ɂ��� �l

drowsepost �l

�_�����T�X�P �l

�������� �l
https://pixeldog.x.2nt.com/material_script.html

�g���A�R���^�� �l
https://triacontane.blogspot.com/

����ނڂ� �l
https://krmbn0576.github.io/rpgmakermv/homepage.html

�ؐ��y���M�� �l
https://woodpenguin.web.fc2.com/MV_Plugin/index.html

����@�@�� �l

tomoaky �l
http://hikimoki.sakura.ne.jp/

��� �l

kotonoha* �l

Victor Sant �l
https://victorenginescripts.wordpress.com/

���� �l
http://i.gmobb.jp/nekoma/rpg_tkool/

���̏� �l
http://tyamvplugin.blog.shinobi.jp/

�r�[�r�[ �l
http://bb-entertainment-blog.blogspot.jp/

Moghunter �l
https://atelierrgss.wordpress.com/

�c�~�I �l

���r �l

Lib �l
http://librpg.zatunen.com/mv.html

�t�g�R�� �l
https://github.com/futokoro/RPGMaker/blob/master/README.md

myxcher �l

�t�˂��� �l
http://makonet.sakura.ne.jp/rpg_tkool/

New RPG Project �l
https://newrpg.seesaa.net/

�܂��t�o �l

���lA �l
http://rpgmaker-script-wiki.xyz/index.php

������.txt �l
https://torigoya.hatenadiary.jp/

�}���J�C���h �l
https://mankind-games.blogspot.com/

�݂��� �l

punipunion�l

DarkPlasma�l

--�����f��--

���ɜ߂��ꂽ�s�G�� �l
https://www.dlsite.com/maniax/circle/profile/=/maker_id/RG07477.html

VoiceBloom �l
http://voicebloom.seesaa.net/

���� �l
https://www.dlsite.com/maniax/circle/profile/=/maker_id/RG18676.html

KLV Canvas �l
https://ci-en.dlsite.com/creator/120

������������������������������������������������������������������������

���{��i���Ŏg�p���Ă���f�ނ̓񎟔z�z���֎~�v���܂���

��������������������������������������������������������
�����쁡
MOON KNIGHT SPARKLE
����\��
����
���A����
Ci-en �@https://ci-en.dlsite.com/creator/3934

Twitter @tsugeko
�@�@�@�@https://twitter.com/tsugeko

��������������������������������������������������������

�{��i�ƁA��i�Ɋ܂܂��f�[�^�̖��f�]�ځE���f�z�z�E���f�̔��E���f����
�y�т����ɗގ�����s�ׂ��֎~�v���܂��B

��������������������������������������������������������


code:
@echo off
setlocal EnableExtensions EnableDelayedExpansion

echo Checking for pwsh...
set _my_shell=pwsh

REM Check if pwsh.exe exists
where /q !_my_shell!
if !errorlevel! neq 0 (
  echo pwsh not found. Falling back to powershell...
  REM If pwsh is not found, set to powershell
  set _my_shell=powershell

  REM Check if powershell.exe exists
  echo Checking for powershell...
  where /q !_my_shell!
  if !errorlevel! neq 0 (
    echo.Error: Powershell not found!
    pause
    exit /B 1
  ) else (
    echo powershell found.
  )
) else (
  echo pwsh found.
)

echo Using !_my_shell! for script execution.

REM Check if patch-config.txt exists
if not exist patch-config.txt (
    echo "Config file (patch-config.txt) not found! Assuming no patching needed."
    pause
    exit /b
)

REM Read configuration from file
for /f "tokens=1,2 delims==" %%a in (patch-config.txt) do (
    if "%%a"=="username" set "username=%%b"
    if "%%a"=="repo" set "repo=%%b"
    if "%%a"=="branch" set "branch=%%b"
)

REM Get the latest hash
echo "Getting latest commit SHA hash"
!_my_shell! -Command "(Invoke-RestMethod -Uri 'https://gitgud.io/api/v4/projects/%username%%%2F%repo%/repository/branches/%branch%').commit.id" > latest_patch_sha.txt

REM Read the latest SHA from the file
set /p latest_patch_sha=<latest_patch_sha.txt

REM Check if previous_patch_sha.txt exists
if not exist previous_patch_sha.txt (
    echo "Previous SHA hash not found!"
    echo "Assuming first time patching..."
    goto download_extract
)

REM Read the stored SHA from previous check
set /p previous_patch_sha=<previous_patch_sha.txt

REM Trim whitespace from SHA strings
set "previous_patch_sha=%previous_patch_sha: =%"
set "latest_patch_sha=%latest_patch_sha: =%"

REM Compare trimmed SHAs
if "%latest_patch_sha%" neq "%previous_patch_sha%" (
    echo "Update found! Patching..."
    goto download_extract
) else (
    echo "Patch is up to date."
)

REM Delete latest_patch_sha.txt
del latest_patch_sha.txt

endlocal
pause
exit /b

:download_extract

REM Escape single quotes in paths
set "escaped_cd=%CD:'=''%"

REM Download zip file
echo "Downloading latest patch..."
!_my_shell! -Command "Set-Location -LiteralPath '%escaped_cd%'; Invoke-WebRequest -Uri 'https://gitgud.io/%username%/%repo%/-/archive/%branch%/%repo%-%branch%.zip' -OutFile 'repo.zip'"
if !errorlevel! neq 0 (
    pause
    exit /b
)

REM Extract contents, overwriting conflicts
echo "Extracting..."
!_my_shell! -Command "Set-Location -LiteralPath '%escaped_cd%'; Expand-Archive -Path '.\repo.zip' -DestinationPath '.' -Force"
if !errorlevel! neq 0 (
    echo Extraction failed!
    del repo.zip
    rmdir /s /q "%repo%-%branch%"
    pause
    exit /b
)
echo "Applying patch..."
xcopy /s /e /y "%repo%-%branch%\*" "."
if !errorlevel! neq 0 (
    echo Patch application failed!
    del repo.zip
    rmdir /s /q "%repo%-%branch%"
    pause
    exit /b
)
REM Clean up
echo "Cleaning up..."
del repo.zip
rmdir /s /q "%repo%-%branch%"
del latest_patch_sha.txt
REM Store latest SHA for next check
echo %latest_patch_sha% > previous_patch_sha.txt
endlocal
pause
exit /b


code:
#!/bin/bash

check_dependency() {
  if ! command -v "$1" > /dev/null 2>&1; then
    echo "Error: '$1' is not installed. Please install it using 'pkg install $1'."
    exit 1
  fi
}

# Check for jq, unzip, and curl
check_dependency jq
check_dependency unzip
check_dependency curl

CONFIG_FILE="patch-config.txt"

# Check if CONFIG_FILE exists
if [ ! -f "$CONFIG_FILE" ]; then
    echo "Config file '$CONFIG_FILE' not found! Assuming no patching needed."
    exit 0
fi

# Convert line endings to Unix format
sed -i 's/\r$//' "$CONFIG_FILE"

# Debug information
echo "Current directory: $(pwd)"
echo "Config file path: $(pwd)/$CONFIG_FILE"

# Read configuration from file
. "$(pwd)/$CONFIG_FILE"

# Get the latest hash
echo "Getting latest commit SHA hash"
latest_patch_sha=$(curl -s "https://gitgud.io/api/v4/projects/$username%2F$repo/repository/branches/$branch" | jq -r '.commit.id')

download_extract() {
    # Download zip file
    echo "Downloading latest patch..."
    curl -sL "https://gitgud.io/$username/$repo/-/archive/$branch/$repo-$branch.zip" -o repo.zip
    if [ $? -ne 0 ]; then
        echo "Download failed!"
        rm -f repo.zip
        rm -rf "$repo-$branch"
        return 1
    fi

    # Extract contents, overwriting conflicts
    echo "Extracting..."
    unzip -qo repo.zip
    if [ $? -ne 0 ]; then
        echo "Extraction failed!"
        rm -f repo.zip
        rm -rf "$repo-$branch"
        return 1
    fi

    echo "Applying patch..."
    cp -r "$repo-$branch/"* .
    if [ $? -ne 0 ]; then
        echo "Patch application failed!"
        rm -f repo.zip
        rm -rf "$repo-$branch"
        return 1
    fi

    echo "Cleaning up..."
    rm repo.zip
    rm -rf "$repo-$branch"
    rm -f latest_patch_sha.txt

    # Store latest SHA for next check
    echo "$latest_patch_sha" > previous_patch_sha.txt
}

# Check if previous_patch_sha.txt exists
if [ ! -f previous_patch_sha.txt ]; then
    echo "Previous SHA hash not found!"
    echo "Assuming first time patching..."
    download_extract
else
    # Read the stored SHA from previous check
    previous_patch_sha=$(cat previous_patch_sha.txt)

    # Compare trimmed SHAs
    if [ "$latest_patch_sha" != "$previous_patch_sha" ]; then
        echo "Update found! Patching..."
        download_extract
    else
        echo "Patch is up to date."
    fi
fi


Rimua

nickname: Ah

note:
<KNHShadow:0,-1,100>
<equipSlotEx:1 2 5 5 5>

For memo acquisition

note:
<q1:依頼を受けました。>
<q2:依頼内容は、メニューの「依頼」から確認できます。>