#pragma once
#include "global.h"
#include <memory>
#include <unordered_set>
/*--------------------四叉树部分----------------------*/
class Entity;
template<typename T>
class Rect;
struct GetRectEntity
{
	Rect<float>& operator()(Entity*) const;
};
template<typename T, typename GetRect, typename Equal>
class Quadtree;
/*---------------------Entity头-----------------------*/
//自定义消息
#define MYDXLIST_SELCHANGED WM_USER + 100
#define MYPICBUTTON_LBUTTONDOWN WM_USER + 101
#define MYPICBUTTON_LBUTTONUP WM_USER + 102
struct MyRGBA
{
	UINT8 r;
	UINT8 g;
	UINT8 b;
	UINT8 a;
	void Set(DWORD c);
	DWORD Get();
};

struct MyTextureAndSRV
{
	ID3D11Texture2D* pTexture = nullptr;
	ID3D11ShaderResourceView* pSRV = nullptr;
};

//设定实现表
struct MyLabelXML
{
	CString name;
};

struct MyCalendarClickZone
{
	MyRect rect;
	int month;
	int day;
	bool diary = false;
};

struct MyCharacterInfo
{
	int id = -1;//主键id
	CString facePng;//头像图片
	int lifeType;//生命类型 0生物 1精灵
	CString image;//印象
	CString name;//名字
	CString mcpos;//角色定位
	CString mcChar;//角色性格
	int gender;//性别 0无 1雌 2雄
	CString ideal;//理想
	CString labelXML;//xml标签
};

struct MyWorldSet
{
	CString name;
	CString info;
	std::unordered_map<std::wstring, MyLabelXML> labelMap;//地点设定实现表
};

struct MyView;
struct MyViewDrawFor
{
	void Init(MyView* view);
	MyView* view = nullptr;
	//绘制for变量
	int draw_xMax, draw_yMax;
	int count_h;
	float rc_draw_x, rc_draw_y, rc_draw_w, rc_draw_h;
	int _x, _y;
	//绘制循环
	void DrawForYBegin(int** outY = nullptr);
	bool DrawForY();
	void DrawForYInc();
	void DrawForXBegin(int** outX = nullptr);
	bool DrawForX(MyRect* outRect = nullptr);
	void DrawForXInc();
};

//网格编辑器视图
struct MyView
{
	void Init(CDialog* dlg, MyDX11Renderer* pRenderer);
	void Reset();
	CDialog* dlg = nullptr;
	MyDX11Renderer* pRenderer = nullptr;//渲染器
	float scale = 4;//编辑器视图缩放程度
	float offX = 0, offY = 0;//相机坐标
	float window_w = 0, window_h = 0;//目标窗口大小
	float grid_w = 16, grid_h = 16;//网格大小
	int count_w = 16, count_max = 32;//绘制数量
	//显示拖拽
	bool moveMode = false;//是否处于拖拽状态
	CPoint moveStartPos;//光标拖拽的起始坐标
	float offX_start = 0, offY_start = 0;//光标拖拽的起始原点坐标
	//光标
	int cursorX = 0, cursorY = 0;//当前的光标位置
	int cursorW = 1, cursorH = 1;//当前光标的大小
	int cursorX_selected = 0, cursorY_selected = 0;//当前的光标位置
	int cursorW_selected = 1, cursorH_selected = 1;//光标大小
	int cursorX_last = 0, cursorY_last = 0;
	bool selecting = false;//正在选择中
	bool drawSelectedCursor = true;//绘制选择光标
	bool allowSelectOut = false;//允许绘制到界外
	//框选
	void BeginSelect(CPoint pt);
	void Select(CPoint pt);
	void EndSelect();
	//绘制功能
	void DrawTransparentBk(DWORD c1 = RGBA(0x80, 0x80, 0x80, 0xff), DWORD c2 = RGBA(0xc0, 0xc0, 0xc0, 0xff));//绘制透明背景
	void DrawBorderLine(bool center = false);//绘制边界线
	void DrawGrid(DWORD c = RGBA(0xff, 0, 0xff, 0xff));//绘制网格
	void DrawCursor();//绘制光标
	//窗口编辑绑定
	void WindowBind_OnRButtonDown(CPoint point);
	void WindowBind_OnRButtonUp();
	void SetScrollBar();
	//以下函数如果返回为真，需要【重新绘制】
	bool WindowBind_OnMouseMove(CPoint point);
	bool WindowBind_OnMouseWheel(short zDelta, CPoint pt);
	bool WindowBind_OnVScroll(UINT nSBCode, UINT nPos);
	bool WindowBind_OnHScroll(UINT nSBCode, UINT nPos);
};


struct MyUndoRedoDataOp
{
	void* (*NewData)() = nullptr;
	void* (*NewCopyOfData)(void*) = nullptr;
	void (*ReleaseData)(void*) = nullptr;
};

struct MyUndoRedo
{
	MyUndoRedo() = default;
	MyUndoRedo(const MyUndoRedo& src);//对象实例复制
	MyUndoRedo& operator=(const MyUndoRedo& src);//对象实例复制
	~MyUndoRedo();
	bool canStep = false;
	int maxSize = 10;//撤销次数上限
	std::unordered_map<std::string, MyUndoRedoDataOp> dataOpMap;//数据类型表
	std::unordered_map<std::string, void*> step;//步
	std::unordered_map<std::string, std::list<void*>> redo;
	std::unordered_map<std::string, std::list<void*>> undo;
	std::list<std::string> dataTypeList_redo;//重做操作顺序表
	std::list<std::string> dataTypeList_undo;//撤销操作顺序表
	void AddDataType(const char* dataTypeName, MyUndoRedoDataOp op);
	void BeginStep(const char* dataTypeName);
	void EndStep();//结尾要调用UpdateUndoRedoMenuState();
	void Undo();
	void Redo();
	bool UndoEmpty();
	bool RedoEmpty();
	void Clear();
	void ClearUndoRedo();
	void* GetStep(const char* dataTypeName);
};

//动画帧
struct MyAniFrame
{
	int id = 0;//动画pid
	float offx = 0;
	float offy = 0;
};
bool operator ==(const MyAniFrame& l, const MyAniFrame& r);

//动画层
struct MyAniLayer
{
	std::vector<MyAniFrame> rcList;
};
bool operator ==(const MyAniLayer& l, const MyAniLayer& r);

#define CANIEDITOR_DATATYPE_ANI_STR "std::vector<MyAniLayer>"
#define CANIEDITOR_DATATYPE_ANI std::vector<MyAniLayer>
//动画
struct MyAniSet
{
	MyAniSet();
	int playSpeed = 6;//播放速度
	bool loop = false;//循环播放
	int texture_up = 16;
	int texture_down = 16;
	int texture_left = 16;
	int texture_right = 16;
	MyUndoRedo undoRedo;//撤销重做表
	CANIEDITOR_DATATYPE_ANI* GetStep();
};
bool operator ==(const MyAniSet& l, const MyAniSet& r);

//实体旗
struct EntityFlag
{
	//触发器
	bool tCheck = false;//调查时触发事件
	bool tTouch = false;//接触实体时触发事件
	bool tDeath = false;//死亡时触发事件
	bool tCrush = false;//被移动平台压扁时触发事件
	bool tHurt = false;//该实体受伤时触发事件
	bool tDamage = false;//该实体造成伤害时触发事件
	//地图载入
	bool fShow = false;//当id设立时在地图载入时出现
	bool fHide = false;//当id设立时在地图载入时消失
	//快进旗
	bool skShow = false;//当sk设立时在地图载入时出现
	bool skHide = false;//当sk设立时在地图载入时消失
	//游戏难度
	bool d0Show = false;//当游戏难度设为0时出现
	bool d0Hide = false;//当游戏难度设为0时消失
	bool d1Show = false;//当游戏难度设为1时出现
	bool d1Hide = false;//当游戏难度设为1时消失
	//其他选项
	bool lr = false;//左右面对方向
	bool text = false;//绘制文本（用于菜单）
	bool save = false;//该实体数据通过游戏记录加载进行保存读取
	bool simpAni = false;//使用0号动画 实体ID作为png文件
};
bool operator ==(const EntityFlag& l, const EntityFlag& r);

//实体加载结构
struct EntityLoad
{
	std::wstring name;//实体名
	int x = 0, y = 0;//坐标
	std::wstring eid;//实体号
	std::wstring eventName;//事件函数名
	std::wstring arg;//特殊作用参数
	std::wstring arg2;//特殊作用参数
	std::wstring arg3;//特殊作用参数
	EntityFlag flag;//属性旗
};
bool operator ==(const EntityLoad& l, const EntityLoad& r);

#define CMAPEDITOR_DATATYPE_PXM_STR "std::unordered_map<LONG,LONG>"
#define CMAPEDITOR_DATATYPE_PXM std::unordered_map<LONG,LONG>
#define CMAPEDITOR_DATATYPE_PXE_STR "std::unordered_map<int,EntityLoad>"
#define CMAPEDITOR_DATATYPE_PXE std::unordered_map<int,EntityLoad>
#define CPXAEDITOR_DATATYPE_PXA_STR "std::unordered_map<LONG, int>"
#define CPXAEDITOR_DATATYPE_PXA std::unordered_map<LONG, int>

class Entity;
struct MapLayer;
//矩形状态
struct CbRect
{
	//选项
	bool enableCbRect = false;//启用碰撞框运算（接触墙体会得到接触墙的类型）
	bool enableSoild = false;//启用墙体排挤（接触墙体，墙体会把该物体排开）
	bool enableSelfSoild = false;//启用自身墙体（会把玩家实体排开）
	bool enableMovePlatform = false;//空中平台特性（会把其他实体排开）
	bool enableWaterSpace = false;//赋予其他物体在水中特性
	bool ignoreMovePlatform = false;//忽略移动平台
	bool breakStarBlock = false;//破坏星星砖
	//实体碰撞框范围
	float left = 8;
	float top = 8;
	float right = 8;
	float bottom = 8;
	//是否碰到墙体地形
	bool cbLeft = 0;
	bool cbTop = 0;
	bool cbRight = 0;
	bool cbBottom = 0;
	//碰到的墙体地形类型
	int pxaLeft = 0;
	int pxaTop = 0;
	int pxaRight = 0;
	int pxaBottom = 0;
	//是否站在斜坡上
	bool onSlopeL = false;//左斜坡
	bool onSlopeLSide = false;//附近有左斜坡
	bool onSlopeR = false;//右斜坡
	bool onSlopeRSide = false;//附近有右斜坡
	//是否接触到陷阱
	bool onTrap = false;
	//接触的移动平台
	std::weak_ptr<Entity> movingPlatformLeft;
	std::weak_ptr<Entity> movingPlatformTop;
	std::weak_ptr<Entity> movingPlatformRight;
	std::weak_ptr<Entity> movingPlatformBottom;
	//水中
	bool inWater = false;
	bool waterBlock = false;//不能进水
	bool fullWaterBlock = false;//满水碰撞（与水的碰撞运算扩大到16x16）
	//风中
	bool inWind = false;
	int windDir = 0;//风的方向789、456、123
	//岩浆中
	bool inLava = false;
	int lavaDmg = 127;//岩浆的伤害
	//其他
	DWORD roomColor = UINT_MAX;
	std::vector<LONG>* pxmArr = nullptr;
	std::vector<int>* pxaArr = nullptr;
	std::map<LONG, LONG>* updatedPxmArr = nullptr;
	int pxmArr_w = 0;
	int pxaArr_w = 0;
	void (*Collision)(std::weak_ptr<Entity> e, std::vector<LONG>* pxmArr, std::vector<int>* pxaArr, std::map<LONG, LONG>* updatedPxmArr, int pxmArr_w, int pxaArr_w) = nullptr;
	SDL_FRect qtRect;
};

//动画播放机
struct Animation
{
	std::wstring png;//动画文件名
	std::wstring sprite_index;//动画名
	int image_index = 0;//帧下标
	float image_counter = 0;
	float image_counter_speed = 1.0f;//动画速度
	std::set<int> hideLayerList;//隐藏的图层号列表
};

//着色器
struct EntityShader
{
	bool usingShader = false;//是否启用着色器
	std::wstring ps;//像素着色器名
	std::wstring vs;//顶点着色器名
	std::vector<float> args;//传进着色器的参数列表
};
//发光实体
struct EntityLight
{
	bool usingLight = false;//是否是发光实体
	void* layer = nullptr;//地图图层
};

struct EntityLayer
{
	std::list<std::shared_ptr<Entity>> Ls;//实体
	std::list<std::shared_ptr<Entity>> Am;//玩家的抛射物
	std::list<std::shared_ptr<Entity>> Pe;//粒子效果物体
	std::vector<std::shared_ptr<Entity>> addList;//待添加实体
	std::unordered_set<Entity*> treeCheck;
	Quadtree <Entity*, GetRectEntity, std::equal_to<Entity*>>* quadTree = nullptr;
	virtual ~EntityLayer();
};

//路径向量
struct PathCell
{
	float vec1_x;//初向量
	float vec1_y;
	float dis;
};

//完成的寻路网格
struct PathGrid
{
	std::vector<PathCell> vecMap;//向量图
	void* mapLayer = nullptr;
};

//游戏功能函数
struct GameFunc
{
	void (*PlaySound)(const wchar_t* soundName) = nullptr;//播放wav声音
	int (*PlayLoopSound)(const wchar_t* soundName) = nullptr;//播放循环声音
	void (*StopLoopSound)(int channelID) = nullptr;//停止循环声音
	bool (*GetFullScreen)() = nullptr;//是否全屏
	void (*SetFullScreen)(bool bFullScreen) = nullptr;//设置显示全屏
	bool (*GetShowDebug)() = nullptr;//是否显示调试信息
	void (*SetShowDebug)(bool bShowDebug) = nullptr;//设置显示调试信息
	void (*EnlargeWindow)() = nullptr;//放大窗口
	void (*ReduceWindow)() = nullptr;//缩小窗口
	int (*GetMusicVolume)() = nullptr;//取音乐音量[0-10]
	void (*SetMusicVolume)(int vol) = nullptr;//设置音乐音量
	int (*GetSoundVolume)() = nullptr;//取音效音量[0-10]
	void (*SetSoundVolume)(int vol) = nullptr;//设置音效音量
	void (*OpenGameController)() = nullptr;//重新打开所有链接的手柄设备
	void (*GetScanCodeName)(std::vector<wchar_t>* outName, SDL_Scancode key) = nullptr;//取键盘扫描码名
	void (*GetGameControllerKeyName)(std::vector<wchar_t>* outName, void* keyBind) = nullptr;//取手柄键绑定名
	void (*GetGameControllerName)(std::vector<wchar_t>* outName, SDL_GameController* pGameController) = nullptr;//取手柄设备名
	void (*ResetKeyboard)() = nullptr;//重置键盘状态
	bool (*GetAnyKeyPress)(SDL_Scancode* outKey) = nullptr;//取键盘上任意按键
	bool (*GetAnyGameControllerKeyPress)(SDL_GameController* pGameController, void* keyBind) = nullptr;//取手柄上任意按键
	bool (*GetKey)(SDL_Scancode key) = nullptr;//取键盘扫描码是否按下
	void (*ResetKeySetting_Player1Keyboard)() = nullptr;//重置玩家1所有键盘按键设置
	void (*ResetKeySetting_Player1Joystick)() = nullptr;//重置玩家1所有手柄按键设置
	void (*ResetKeySetting_Player2Keyboard)() = nullptr;//重置玩家2所有键盘按键设置
	void (*ResetKeySetting_Player2Joystick)() = nullptr;//重置玩家2所有手柄按键设置
	void* (*GetInputSetting_Player1Keyboard)() = nullptr;//取玩家1按键设置
	void* (*GetInputSetting_Player1Joystick)() = nullptr;//取玩家1手柄设置
	void* (*GetInputSetting_Player2Keyboard)() = nullptr;//取玩家2按键设置
	void* (*GetInputSetting_Player2Joystick)() = nullptr;//取玩家2手柄设置
	SDL_GameController* (*GetGameControllerFromIndex)(int index) = nullptr;//从连接下标取手柄设备
	int (*GetPlayer1ControllerType)() = nullptr;//取玩家1控制器类型
	int (*GetPlayer2ControllerType)() = nullptr;//取玩家2控制器类型
	void (*SetPlayer1ControllerType)(int type) = nullptr;//设置玩家1控制器类型
	void (*SetPlayer2ControllerType)(int type) = nullptr;//设置玩家2控制器类型
	void (*LoadConfig)() = nullptr;//载入游戏选项配置
	void (*SaveConfig)() = nullptr;//保存游戏选项配置
	void* entityRes = nullptr;//实体资源管理器指针
	std::weak_ptr<Entity> (*GetMyChar_Player1)(void* entityRes) = nullptr;//取玩家1实体
	std::weak_ptr<Entity> (*GetMyChar_Player1_menuKeyboard)(void* entityRes) = nullptr;//取玩家1的菜单键盘实体
	std::weak_ptr<Entity> (*GetMyChar_Player2)(void* entityRes) = nullptr;//取玩家2实体
	std::weak_ptr<Entity> (*GetMyChar_Player2_menuKeyboard)(void* entityRes) = nullptr;//取玩家2的菜单键盘实体
	std::unordered_map<MapLayer*, EntityLayer>* (*GetLoadedEntity)(void* entityRes) = nullptr;//取当前房间所有的实体
	void (*GetDisplayInfo)(void* entityRes, float* outWindow_w, float* outWindow_h, float* outScale, float* outOffX, float* outOffY) = nullptr;//取显示信息
	void (*GetMousePos)(void* entityRes, float* pX, float* pY) = nullptr;//取鼠标光标对应的实体位置
	bool (*InScreen)(void* entityRes, float x, float y) = nullptr;//该坐标是否在屏幕显示范围内
	void (*GridTouch)(void* entityRes, std::weak_ptr<Entity> e, EntityLayer* targetLayer) = nullptr;//取与这个实体框接触的所有实体
	void* gameMap = nullptr;//游戏地图指针
	MapLayer* (*GetMapLayer)(void* gameMap, const wchar_t* layerName);//取地图图层
	void* mapSizeGetter = nullptr;
	void (*GetMapSize)(void* mapSizeGetter, int* outMapW, int* outMapH) = nullptr;//取房间尺寸
	void (*SetNewNameOption)(const wchar_t* gameName, int playerNum, int difficulty) = nullptr;//设置新游戏参数
	void (*SetSaveName)(const wchar_t* saveName) = nullptr;//设置当前存档文件名
	void (*DelSave)(const wchar_t* saveName) = nullptr;//删除存档
	void (*SaveNameGetRoomName)(std::wstring* outRoomName, const wchar_t* saveName) = nullptr;//存档取房间名
	int (*SaveNameGetGameDifficulty)(const wchar_t* saveName) = nullptr;//存档取游戏难度
	void (*WriteData)(const wchar_t* eid, const wchar_t* field, const wchar_t* value) = nullptr;//写入数据
	const wchar_t* (*ReadData)(const wchar_t* eid, const wchar_t* field, const wchar_t* defaultVal) = nullptr;//读取数据
	void (*SetPauseMenuBackGame)(bool bBack) = nullptr;//暂停菜单返回游戏
	void (*SetPauseMenuBackTitle)(bool bBack) = nullptr;//暂停菜单返回标题画面
	void* dmgNum = nullptr;//伤害数字指针
	void (*SetDmgNum)(void* dmgNum, int val, float x, float y, int style, std::weak_ptr<Entity> e) = nullptr;//设置一个伤害数值显示
	std::shared_ptr<Entity> (*GameCreateEntity)(const wchar_t* name) = nullptr;//创建一个实体在内存中（可以来自其他dll）
	void (*SetEntity)(std::shared_ptr<Entity> parent, std::shared_ptr<Entity> newE) = nullptr;//放置一个实体
	void* gameScript = nullptr;//游戏脚本指针
	void (*StartEvent)(void* gameScript, const wchar_t* eventName, const wchar_t* triggerType) = nullptr;//启动事件
	bool (*IsLockKeyboard)(void* gameScript) = nullptr;//键盘是否锁定
	bool (*ScriptIsRunning)(void* gameScript) = nullptr;//是否正在运行事件
	void* gameUI = nullptr;
	void* (*GetPlayerUIData)(void* gameUI, int playerIndex) = nullptr;//取玩家UI显示数据
	void (*StopMusic)() = nullptr;//立即停止音乐
	void (*ScreenShot)() = nullptr;//取截图
	void (*QuitGame)() = nullptr;//退出游戏
	const wchar_t* (*GetLanguage)() = nullptr;//取游戏的语言设置
	void (*SetLanguage)(const wchar_t* lang) = nullptr;//设置语言
	void (*GetAllLanguage)(std::vector<std::wstring>* languageList) = nullptr;//取所有的语言
	void (*ReloadLanguage)() = nullptr;//生效语言设置
	void (*SetLastPlaySlot)(int slotPage, int index) = nullptr;//设置最后游玩的存档位置
	void (*GetLastPlaySlot)(int* outSlotPage, int* outIndex) = nullptr;//取最后游玩的存档位置
	std::set<std::wstring>* flagSet = nullptr;//游戏旗
	std::set<std::wstring>* skipSet = nullptr;//快进旗
	PathCell* (*GetPath)(std::weak_ptr<Entity> e, float dstX, float dstY, float srcX, float srcY) = nullptr;//取寻路网格
	bool (*LineTest)(std::weak_ptr<Entity> e, float srcX, float srcY, float dstX, float dstY) = nullptr;//直线测试
	void* game = nullptr;
	void (*SetMyChar_Player1)(void* game, std::weak_ptr<Entity> e) = nullptr;//设置玩家1的控制实体
	void (*SetMyChar_Player2)(void* game, std::weak_ptr<Entity> e) = nullptr;//设置玩家2的控制实体
	void (*SetGlobalEntity)(void* game, std::shared_ptr<Entity> we, const wchar_t* globalEntityID) = nullptr;//将实体设置到全局运行
	std::weak_ptr<Entity> (*GetGlobalEntity)(void* game, const wchar_t* globalEntityID) = nullptr;//取出全局实体指针
	std::unordered_map<std::wstring, std::weak_ptr<Entity>>* (*GetGlobalEntityTable)(void* game) = nullptr;//取全局实体指针表
	int (*GetPlayerIndex)(void* game, std::weak_ptr<Entity> e) = nullptr;//取当前实体的玩家下标
	std::weak_ptr<Entity> (*GetPlayerDistance)(void* game, float x, float y) = nullptr;//取离该点最近的玩家
	std::weak_ptr<Entity>(*GetPlayerDistanceLR)(void* game, float x, float y, int lr) = nullptr;//取离该点一侧最近的玩家
	std::weak_ptr<Entity>(*GetPlayerDistanceWithLineTest)(void* game, float x, float y) = nullptr;//取离该点最近的可以直接射击的玩家
	std::weak_ptr<Entity>(*GetPlayerDistanceLRWithLineTest)(void* game, float x, float y, int lr) = nullptr;//取离该点一侧最近的可以直接射击的玩家
	void (*SetQuake)(void* game, int times, int mode) = nullptr;//mode:0小抖动、1大抖动
	void (*SetLocalCamera)(void* game, std::weak_ptr<Entity> e, float focusTimes) = nullptr;//设置局部相机
	void (*UnsetLocalCamera)(void* game, std::weak_ptr<Entity> e) = nullptr;//取消该单位的聚焦
	bool (*InBossFight)(void* game) = nullptr;//是否在Boss战中
	std::weak_ptr<Entity>(*GetCheckEventPlayer)(void* game) = nullptr;//取最后一次正在调查事件的玩家
	int (*PlayerHaveItem)(void* game, const wchar_t* regID) = nullptr;//返回玩家拥有某物品的数量
	int (*PlayerAddItem)(void* game, const wchar_t* regID, int num) = nullptr;//添加物品，返回该物品总数量
	int (*PlayerDeleteItem)(void* game, const wchar_t* regID, int num) = nullptr;//移除物品（-1为移除全部）,返回剩余数量
	int* pGameOption_playerNum = nullptr;
	int* pGameOption_difficulty = nullptr;
	void (*DecodeRecord)(const wchar_t* recordStr, const void** outInputArr, size_t* outDataSize) = nullptr;//解码操作记录
	void* slotDrawer = nullptr;
	void (*SlotPageEnableDraw)(void* slotDrawer, bool bEnable) = nullptr;//启用存档页绘制
	void (*SlotPageDrawClear)(void* slotDrawer) = nullptr;//清除存档页绘制列表
	void (*SlotPageAddDraw)(void* slotDrawer, const wchar_t* saveName, std::weak_ptr<Entity> player1Icon, std::weak_ptr<Entity> player2Icon) = nullptr;//添加要绘制的玩家存档信息到绘制列表
	void (*SlotPageReset)(void* slotDrawer) = nullptr;//重置存档页绘制器
	void* gameFlash = nullptr;
	void (*SetScreenFlash)(void* gameFlash, int times) = nullptr;//设置屏幕闪烁
};

struct PenVertex
{
	float x = 0, y = 0;//顶点
	DWORD c = 0xffffffff;//颜色
};

//游戏对象抽象类
class Entity
	: public std::enable_shared_from_this<Entity>
{
public:
	Entity() = default;
	Entity(int type);
	virtual ~Entity() = default;
	//函数
	virtual void Init(std::weak_ptr<Entity> self);//初始化
	virtual void Step();
	virtual void SetState(int stateID, int lr);
	virtual void SetState(std::wstring stateName, int lr);
	virtual void DeltaTime(float deltaTime);//绘制更新
	virtual void Collision();//执行碰撞
	virtual void ClearCollisionResult();//清除上一次的碰撞结果
	virtual void BeginMovingPlatform();//跟上移动平台（在处理所有速度之前调用）
	virtual void EndMovingPlatform();//跟上移动平台（在处理所有速度之后调用）
	virtual void LoadSaveData();//加载保存数据
	virtual void WriteSaveData();//写入保存数据
	virtual bool Touch(std::weak_ptr<Entity> e);//功能函数
	virtual bool DeathByMovingPlatform();//检测被移动平台压死
	virtual bool Pathfinding(float targetX, float targetY, float* outDirX, float* outDirY);//寻路（只适用于体积16x16和以下小的飞行物）
	virtual int GetMapPxa(int x, int y);//取地图上某地形的pxa值
	virtual float GetShootingAngle();//取射击角
	virtual void KeepOnSlopes();//保持在斜坡上
	virtual void GetCameraPos(float* outX, float* outY);//取相机输出坐标
	virtual void ImmUpdate();//立即更新某些处理
	virtual void KeepInMap();//水平方向防止掉到地图外面
	virtual bool IsOutOfMap(int r = 8);//是否在地图之外
	virtual void GetIcon(std::wstring& png, std::wstring& sprite_index, int& image_index, std::set<int>& hideLayerList);//取这个实体的图像
	virtual void Wind();//受风的影响
	virtual void Destroy();//删除这个实体
	virtual void CopyFrom(std::shared_ptr<Entity>& another);//让自己获得另一个和自己同类型实体一模一样的属性
	virtual void GetAnimateOffset(float& outDx, float& outDy);//取动画偏移
	//游戏程序初始化赋值变量\函数
	GameFunc* gameFunc = nullptr;
	//成员
	float x = 0, y = 0;//坐标
	float draw_x = 0, draw_y = 0;//绘制坐标（用于Lerp绘制）
	float last_x = 0, last_y = 0;//绘制坐标（用于Lerp绘制）
	float vx = 0, vy = 0;//速度
	int lr = 0, ud = 0;//方向
	bool initCheck = false;//强制Init检查，如果为false进入运行会弹窗提示
	bool speedDir = false;//物理物体不使用方向变量，而使用速度值来作为方向，该变量影响一些格挡技能的判定
	bool noDir = false;//无方向（全方向）方向性防御不可阻挡（比如尖刺）
	//实体碰撞框
	CbRect cbRect;
	//显示图像
	Animation ani;
	//是否正在使用
	bool inUsing = true;
	//隐藏
	bool hide = false;//隐藏会停止实体运行 动画也会中断播放
	bool drawBeforeOtherEntity = false;//在其他实体绘制之前绘制
	bool drawAfterPlayer = false;//是否显示在玩家之上
	bool topDraw = false;//是否顶级绘制（绘制在fade之上）
	//载入属性
	EntityLoad el;
	//初始化变量
	int type = 0;//0实体 1玩家 2弹药 3粒子
	//其他
	DWORD color = 0xffffffff;//染色
	DWORD input;//游戏操作输入
	DWORD inputLock;//锁住的游戏操作输入
	bool enableAI = false;//启用AI控制
	std::weak_ptr<Entity> ai;//AI对象
	std::wstring aiName;//适用的AI对象名
	float axis[19];//摇杆幅度 如果该操作有的话
	//土狼时间
	int coyote_counter = 0;
	int coyote_max = 3;
	//是否是可拾取物品
	bool isItem = false;
	//正在调查事件（玩家）
	bool inCheckingEvent = false;
	bool faceToBackEnd = false;//事件结束信号
	bool blockJump = false;//阻止事件结束或者意外操作玩家起跳
	bool initCollision = true;//第一次载入时先执行碰撞
	//数值
	int hp = 0;//生命值
	int hp_max = 0;//生命最大值
	int dropExp = 0;//掉落的经验
	//经验
	int mp = 0;
	int mp_max = 0;
	//其他
	bool ignoreTrap = false;//无视陷阱
	int ignoreTrap_counter = 0;//无视陷阱时间
	int shock_counter = 0;//晃动时间（只是图像绘制晃动）
	//攻击
	std::map<Entity*, int> damaged;//这个Entity*变量禁止读取
	bool attackState = true;//是否启用攻击状态（抛射物实体用）
	int attackState_reset_counter_max = -1;//攻击状态失效后，再启动攻击状态的时间， -1为永不重置
	int attackState_reset_counter = -1;
	int damaged_counter = 0;//已攻击的次数
	int damaged_limit = 0;//攻击次数上限 0无限
	int damage_reset_counter = -1;//攻击目标后，再次刷新攻击的帧时间， -1为永不重置
	std::weak_ptr<Entity> attackParent;//产生攻击抛射物的父实体
	bool isTrap = false;//是陷阱实体（陷阱实体会尝试攻击陷阱以外所有实体）
	virtual bool Hurt(std::weak_ptr<Entity> src, int getDamage, float angle, bool bTakedown, int elemType, float shockForce, float heavy, int* outRealDamage);
	virtual void Attack(std::weak_ptr<Entity> dst, int* outDamage, float* outAngle, bool* outTakedown, int* outElemType, float* outShockForce, float* outHeavy);
	virtual void Feedback(std::weak_ptr<Entity> target);
	virtual void AttackEffectObject(std::weak_ptr<Entity> target, float centerX, float centerY, int realDamage);//攻击后产生的效果物体
	virtual void AddDamagedEntity(Entity* e);//外部对damaged的变量写入
	//抓取
	virtual std::weak_ptr<Entity> BeginCaught(std::weak_ptr<Entity> e);//开始被某单位抓取（切换到被抓取状态）返回真正的捕获对象
	virtual void EndCaught(std::weak_ptr<Entity> e);//被某单位抓取结束(退出被抓取状态）
	float caughtDifficulty = 0;//抓取该单位的难度（一些可以直接抓取该单位的技能判定用，0非常简单，0.5普通，1极难）
	bool ignoreCaught = false;//无视抓取
	int ignoreCaught_counter = 0;//无视抓取时间
	//接触
	std::vector<std::weak_ptr<Entity>> touchList;//接触实体列表
	virtual void GridTouch(EntityLayer* targetLayer = nullptr);//更新接触实体列表
	virtual void AddTouchList(std::weak_ptr<Entity> e);//外部对touchList的变量写入
	//物品
	virtual bool Item(std::weak_ptr<Entity> src);//打开isItem=true才能使用，作为可拾取物品被实体（一般是玩家）接触后调用，返回能被该目标拾取
	virtual void Gain(std::weak_ptr<Entity> item);//实体（一般是玩家）拾取到物品后调用
	//其他一些消息
	virtual void ReloadLanguage();//游戏重新载入了语言
	//层级 实体所在层
	MapLayer* mapLayer = nullptr;
	EntityLayer* entityLayer = nullptr;
	//自定义绘制
	std::vector<PenVertex> lineList;
	virtual int AddLine(std::vector<PenVertex>& lineList, int index, float x1, float y1, DWORD c1, float x2, float y2, DWORD c2);
	virtual int AddRect(std::vector<PenVertex>& lineList, int index, float left, float top, float right, float bottom,
		DWORD c_lu, DWORD c_ru, DWORD c_ld, DWORD c_rd);
	virtual int AddArc(std::vector<PenVertex>& lineList, int index, float r, float startAngle, float endAngle, DWORD c_start, DWORD c_end);
	std::vector<PenVertex> fillList;
	virtual int AddFillRect(std::vector<PenVertex>& fillList, int index, float left, float top, float right, float bottom,
		DWORD c_lu, DWORD c_ru, DWORD c_ld, DWORD c_rd);
	virtual int AddFillLine(std::vector<PenVertex>& fillList, int index, float x1, float y1, DWORD c1, float x2, float y2, DWORD c2, float width);
	virtual int AddFillFadeCircle(std::vector<PenVertex>& fillList, int index, float radius, float featherSize, DWORD c);
	virtual int AddFillFadeRect(std::vector<PenVertex>& fillList, int index, float left, float top, float right, float bottom, float featherSize,
		DWORD c_lu, DWORD c_ru, DWORD c_ld, DWORD c_rd);
	//着色器
	EntityShader shader;
	//发光实体
	EntityLight light;
	//全局实体ID
	std::wstring globalEntityID;
	//保存一份自身的弱引用
	std::weak_ptr<Entity> self;
};

struct MapLayer
{
	bool visible = true;//是否可见
	std::wstring tempLayerName;//临时变量图层名
	//地形组
	std::wstring pxaName;//使用的地形组名
	//图层类型
	int layerType = 0;
	//图层属性
	float offx = 0.0f;//图层x偏移
	float offy = 0.0f;//图层y偏移
	float myFar = 0;//影响显示跟随移动
	//循环背景层属性
	bool loopH = false;
	bool loopV = false;
	float speedH = 0;
	float speedV = 0;
	//通用
	float order = 100.0f;
	int jumpFrame = 0;//载入这张地图后，会先将实体层跳跃这个帧数后再运行
	//光层
	float dayLight = 1.0f;//天光
	float tinyHSV[3];//细微HSV调整
	float lightConst = 1.0f;//收到来自其他层的光线影响比例【0-1】
	//颜色调整
	DWORD color;//rgba染色
	//绘制剪切区域
	bool enableClipZone = false;
	MyRect clipZone;
};
//地图图层
struct MyMapLayer : 
	public MapLayer
{
	//编辑器属性
	int nextPxeID = 0;
	int selected_entity = -1;//已选择的实体
	//实体运行的地图缓存
	std::vector<LONG> pxmArr;//数组版的pxm数据
	std::map<LONG, LONG> updatedPxmArr;//更新的pxm
	int pxmArr_w = 0;
	int pxmArr_h = 0;
	void UpdatePxmArr(int pxaArr_w);//把step_pxm的数据更新到pxmArr中
	//帧数跳跃
	int jumpFrame_counter = 0;
	//撤销重做表
	MyUndoRedo undoRedo;
	CMAPEDITOR_DATATYPE_PXM* GetPxmStep();
	CMAPEDITOR_DATATYPE_PXE* GetPxeStep();
	bool operator <(const MyMapLayer& r) const;
};
bool operator ==(const MyMapLayer& l, const MyMapLayer& r);

//地图
struct MyMapSet
{
	std::wstring mapName;//地图显示名
	int mapW, mapH;//地图尺寸
	std::unordered_map<std::wstring, MyMapLayer> layerList;//图层列表
};
bool operator ==(const MyMapSet& l, const MyMapSet& r);
CString StrAddLr(CString text);//给文本补齐回车符 XML解析文本会吃\r符

struct PxaData
{
	CPXAEDITOR_DATATYPE_PXA pxa;
	int tileW;
	int tileH;
	//实体运行的地图缓存
	std::vector<int> pxaArr;
	int pxaArr_w = 0;
	int pxaArr_h = 0;
	void UpdatePxaArr();//pxa的数据更新到pxaArr中
};