#pragma once
#include <memory>
#include <vector>
#include <string>
#include <list>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include "GameInput.h"
#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 RGBA(r,g,b,a) ((DWORD)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)|(((DWORD)(BYTE)(a))<<24)))
//实体旗
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 lr = false;//左右面对方向
	bool text = false;//绘制文本（用于菜单）
	bool save = false;//该实体数据通过游戏记录加载进行保存读取
	bool simpAni = false;//使用0号动画 实体ID作为png文件
};

//实体加载结构
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;//属性旗
};
constexpr float ts = 0x200;//一个方格边缘的大小
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 PlayerUIData;
//游戏功能函数
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, SDL_GameControllerButtonBind* 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, SDL_GameControllerButtonBind* 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所有手柄按键设置
	InputSetting_Keyboard* (*GetInputSetting_Player1Keyboard)() = nullptr;//取玩家1按键设置
	InputSetting_Joystick* (*GetInputSetting_Player1Joystick)() = nullptr;//取玩家1手柄设置
	InputSetting_Keyboard* (*GetInputSetting_Player2Keyboard)() = nullptr;//取玩家2按键设置
	InputSetting_Joystick* (*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;//存档取房间名
	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;
	PlayerUIData* (*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();
	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;//染色
	GameInput input;//游戏操作输入
	GameInput 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;
};

//动作实体
class ActionEntity :
	public Entity
{
public:
	int action_timecounter = 0;//动画计时器
	int action_timecounter_max = INT_MAX;//动画计时器最大值
	//攻击僵直
	int atkFeedBack = 0;
	bool InAction();
	void CopyFrom(std::shared_ptr<Entity>& another) override;//让自己获得另一个和自己同类型实体一模一样的属性
};
class EntityState;
class EntitySkillState;
//玩家角色实体
class MyCharEntity :
	public ActionEntity
{
public:
	MyCharEntity();
	void SetState(std::wstring stateName, int lr) override;
	void LoadSaveData() override;//加载保存数据
	void WriteSaveData() override;//写入保存数据
	void ImmUpdate() override;//立即更新某些处理
	void CopyFrom(std::shared_ptr<Entity>& another) override;//让自己获得另一个和自己同类型实体一模一样的属性
	void KeepInMap();//防止掉到地图外面
	virtual void SetPhysice(bool bInWater);//设置地面物理或水中物理
	virtual void ChangeState(int stateID);//启用状态函数
	virtual bool CheckCrush(std::wstring* pCrushEvent = nullptr);//检查被压扁
	//动画机
	int stateID = 0;
	//状态表
	std::vector<EntityState*> stateList;//状态表
	virtual void AddState(EntityState* state);
	//事件调查
	bool faceToBack = false;//面向背后
	//技能绑定
	virtual void SetSkillBindIndex(EntitySkillState* skillState, int skillIndex);//把技能绑定到目标下标
	virtual void SetSkillBindAdd(EntitySkillState* skillState);//自动寻找一个技能空位绑定
	virtual void RemoveSkillBind(EntitySkillState* skillStat);//解绑一个技能
	//技能模块
	EntitySkillState* lastSkill = nullptr;
	//技能表
	std::vector<EntitySkillState*> skillList;//技能表
	virtual void AddSkill(EntitySkillState* skillState);
	std::wstring uiName;
	std::wstring saveName;
	//投掷物品
	int throwItem = 0;
	int throwItem_max = 0;
	int throwItem_type = 0;
	std::vector<int> throwItemOther;//额外的投掷物品
	virtual void UpdateUI();
	//其他
	std::wstring lastAI_followTarget;
	float levelResetPos_x = 0;
	float levelResetPos_y = 0;
};

//UI
struct PlayerUIData
{
	std::wstring uiName;//使用的UI
	int face = 0;//显示的UI面孔下标
	int Hp = 50;
	int HpMax = 50;
	int HpBar_flash_counter = 0;//生命条闪烁时间
	int Mp = 50;
	int MpMax = 50;
	int MpBar_flash_counter = 0;//魔法条闪烁时间
	int o2 = 0;//氧气值
	bool o2_show = false;//显示氧气值
	bool o2_effect = false;//产生气泡效果
	int SkillArr[6] = { -1 ,-1,-1 ,-1 ,-1 ,-1 };
	float SkillCDArr[6] = { 1,1,1,1,1,1 };
	bool SkillDisable[6] = { false ,false ,false ,false ,false ,false };
	std::wstring SkillName[6];//在物品栏中的技能显示函数
	std::wstring SkillCheckName[6];//在物品栏中的技能说明函数
	bool SwapOp = false;//交换技能位置
	int SwapSrc = -1, SwapDst = -1;//交换技能位置的下标
	std::vector<int> throwItem;//投掷物列表（0不使用，x表示投掷物品的id，-x表示空的投掷物品id）
	std::vector<bool> appearEffect;
	std::vector<int> appearEffect_counter;//投掷物品出现效果
	std::vector<bool> disappearEffect;
	std::vector<int> disappearEffect_counter;//投掷物品消失效果
	//技能子菜单
	bool bShowChildMenu = false;//显示技能子菜单
	int SkillArr_ChildMenu[6] = { -1 ,-1,-1 ,-1 ,-1 ,-1 };
	float SkillCDArr_ChildMenu[6] = { 1,1,1,1,1,1 };
	bool SkillDisable_ChildMenu[6] = { false ,false ,false ,false ,false ,false };
};

struct MyRect
{
	float left = 0, right = 0, top = 0, bottom = 0, z = 1;
};

struct MapLayer
{
	bool visible = true;//是否可见
	std::wstring layerName;//图层名
	//地形组
	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;
};