• ★「C++游戏」BattleOfPhantom:大乱斗游戏升级版


    (原创)
    目前正在不断更新!

    ★ 一款超级有趣的大乱斗游戏,包含多种游戏模式,支持双人联机。
    离线情况下也可以与多个(或一群)机器玩家进行疯狂的对战
    直接上图
    幻影之战标题画面

    使用C++ with EGE图形库编写
    有一定数量的BUG,请谅解。

    双人离线模式下的一张截图
    [ 双人离线的一张截图 ]

    操作说明

    A,W,S,D | 主玩家移动
    1/2/3/4 | 主玩家选择武器或道具
    J | 主玩家向面前方向攻击
    Backspace | 主玩家删除当前武器或道具(注意:装备是靠刷新更好的,不能删)
    鼠标左键 | 向鼠标方向攻击(非常方便),将被识别成八个方向之一(双人离线为了平等不能使用)

    ↑←↓→ | 双人离线时玩家2的移动
    小键盘1/2/3/4 | 双人离线时玩家2选择武器或道具
    小键盘5 | 双人离线时玩家2向面前方向攻击
    Delete | 双人离线时玩家2删除当前武器或道具

    F2 | 立即窗口截图,存入Screenshots文件夹中
    Esc | 退出战斗

    基本玩法

    比如说人机离线对战模式(是可以使用鼠标攻击的),
    开局就先随机获得两把武器,两个道具,没有装备。
    你可以通过右侧的对方方位与距离锁定敌人的位置进行有效攻击。
    机器玩家的算法还说得过去,有时真难弄死它。
    人机对战的一张截图
    [↑ 人机对战的一张截图 ]
    普通模式下一般都是300滴血,只有比较容易死的模式会1000血甚至5000血。(自己探索)
    有些武器带效果的,要注意防护与使用:
    效果数据
    有些剑是带剑气的;
    有些弹药是会反弹/爆炸/分裂/追踪(分为3种等级)/穿墙的。
    实体属性(局部)
    武器千奇百怪,战斗场面琳琅满目:
    混战模式的一张截图
    [↑ 混战模式的一张截图 ——那个血量不是正常的血量,请忽视 ]
    群殴模式是很难挺过去的,你可以尝试一下!!
    群殴模式的一张截图
    群殴模式会给你1000血加上长时间的矫捷效果与永久的穿人特权。就算这样也能死得很惨。
    诀窍是不断逃跑,让他们自己误伤。逃跑的时候注意安全。

    • 离线团战的话一定要把对方所有人消灭,但自己死了就算失败了。
    • 作为红队头领,一定要学会保护自己!
      离线团战的一张截图
      右侧将会有两队活人数数据。

    最后关于联机:

    • 在线模式下服务端开启后,客户端依次输入服务端IP地址和端口号即可
      (若无外网则必须同一局域网下)
      配置外网时映射的IP需要是服务端开启后显示的IP(也就是服务端电脑第一个能用的IP)
      服务端

    • 端口号一律填8888.
      使用外网时,在输入IP地址界面不得输入域名。
      客户端输入的端口号是映射后的端口号(一般是五位数而不是8888)
      需要使用IP地址。获取其IP地址可以通过ping命令获得:
      Win+R打开运行,输入cmd
      ping命令获取外网IP地址

    • 联机的时候经常会崩溃,应该是这个TCP连接太差劲的缘故,也么有办法,因此我尽量减少机器玩家的数量。凑合着玩吧。不要使用频率极高的武器,因为更容易致使崩溃。

    这款游戏已经写了一年左右了,祝愿大家玩得愉快
    源码真的很长(快一万行了)真的想要的话(也不给 XD )
    无源码的游戏链接: https://download.csdn.net/download/cjz2005/86287023

    ★★★

    为了造福广大苍生,我决定放一点源码给大家看看!
    这是机器玩家的AI算法,原创,还行,有兴趣的同志可以好好研究一下。

    //Dir Modes
    #define DIR_NONE 0x00
    #define DIR_4 0x01
    #define DIR_8 0x02
    
    //AI Modes
    #define AAM_STILL 0		//静止
    #define AAM_WANDER 1	//多逛
    #define AAM_CHASE 2		//多追
    #define AAM_FLEE 3		//多逃
    
    //Constants
    #define AA_CHANGE_MODE_RATE 25			//模式更改机率
    #define AA_CHANGE_MODE_MIN_T 1000*6	//模式更改最小周期
    #define AA_CHANGE_WEAPON_RATE 32			//武器切换概率
    #define AA_CHANGE_WEAPON_MIN_T 1000*8	//武器切换最小周期
    #define AA_LEVEL_UP_T 1000*43		//等级提升周期
    #define AA_DRINK_POTION_RATE 8		//喝药水概率
    #define AA_DODGE_BASE_RATE 13	//基础闪避概率
    #define AA_DODGE_RATE_MAX 60	//闪避概率最大值
    #define AA_DODGE_UP_RATIO 0.5	//闪避提升率
    #define AA_DODGE_T 1000*0.9		//闪避周期
    #define AA_EXTRA_DODGE_RATE_T 1000*65	//闪避概率微调周期
    #define AA_CHANGE_TARGET_MIN_T 11000	//目标切换最小周期 
    #define AA_CHANGE_TARGET_RATE 8		//目标切换概率 
    #define AA_REVENGE_RATE 40		//复仇概率
    
    class AIControl {	//AI控制玩家算法
    public:
    	bool enabled;	//是否启用 
    	
    	int my_index;		//附着玩家下标 
    	int target_index;	//目标玩家下标(可变) 
    	int team_index;		//队伍下标
    	
    	clock_t lastModeChanged;	//上一次切换模式 
    	clock_t lastWeaponChanged;	//上一次切换武器 
    	clock_t lastChangeTarget;	//上一次切换攻击目标 
    	clock_t lastUp;				
    	clock_t lastDodge;			//上一次闪避 
    	clock_t lastExtraRateChanged;	//上一次改变额外躲闪率 
    	int extraDodgeRate;		//额外躲闪率 
    	int mode;		//AI模式 
    	int xp;		//经验值
    	BYTE extraMode;		//作弊额外模式 
    	float adjust;
    	const vector<int> mode_prob = { 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3 };	//带比重
    	const vector<int> curw_prob = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 3 };	//带比重
    
    	AIControl()
    	{
    		target_index = 0;	//默认主角为目标
    		team_index = 0;
    		adjust = 0;
    		enabled = false;
    		Init();
    	}
    	void Init()	//initialize
    	{
    		my_index = 1;	//
    		target_index = 0;	//默认主角为目标
    		extraDodgeRate = 0;
    		extraMode = AAE_NONE;
    		mode = AAM_CHASE;
    		lastModeChanged = clock() + 5000;
    		lastWeaponChanged = clock();
    		lastExtraRateChanged = clock();
    		lastChangeTarget = clock();
    		lastUp = clock();
    		lastDodge = clock();
    		xp = 0;
    		adjust = (GetPlayerCount() * 5 + 10101 + RandomRange(0, 100, true, false)) % 100 / 100.0;
    	}
    	void Close()	//关闭 
    	{
    		enabled = false;
    		mode = AAM_STILL;
    		xp = 0;
    		target_index = 0;
    	}
    	void Update()	//更新
    	{
    		if (!enabled || !IsPlayerAlive(my_index))	//未启用状态或死亡状态直接退出 
    			return;
    
    		CheckLevelUp();
    		int r;
    		//离线模式下,玩家2成为AI玩家
    		//在线模式下,自己成为AI玩家(自动攻击)
    		r = RandomRange(0, 100, true, false);	//percent
    		if (r > 100 - AA_CHANGE_MODE_RATE - adjust*6 && (clock() - lastModeChanged > AA_CHANGE_MODE_MIN_T))
    		{
    			mode = mode_prob.at(RandomRange(0, mode_prob.size() - 1, true, true));
    			lastModeChanged = clock();
    		}
    		if (clock() - lastExtraRateChanged > AA_EXTRA_DODGE_RATE_T)
    		{
    			extraDodgeRate = Varience(0, 5+adjust*6);
    			lastExtraRateChanged = clock();
    		}
    		Move();		//根据模式进行移动
    		if (clock() - lastDodge > AA_DODGE_T + adjust * 3)
    		{
    			TryToDodge();	//checking inside
    		}
    		if (g_bIdt != IDT_OFFLINE)
    		{
    			if(GetDirMode(GetPlayerCurWeapon(my_index)) == DIR_8)
    				GetPlayerFace(my_index) = FaceDir8(target_index);
    			else
    				GetPlayerFace(my_index) = FaceDir4(target_index);
    		}
    		
    #ifndef AI_CONCENTRATE
    		if(g_mode != 0 && g_mode != 1 && g_mode != 2 	//就两个玩家时无需切换 
    			&& g_mode != 3	//离线群殴始终只有一个目标
    		&& (!IsPlayerAlive(target_index)	//目标死了就赶紧换目标 没有CD和概率要求
    			|| (
    		RandomRange(0,100,true,false) < AA_CHANGE_TARGET_RATE + adjust * 9	//还有概率 
    		&& clock() - lastChangeTarget >= AA_CHANGE_TARGET_MIN_T)))
    		{	//切换目标 
    			int new_target_index = this->target_index;
    			int min_dist = 9999;
    			for(int i = 0; i < GetPlayerCount(); ++i)
    			{
    				if (!IsPlayerAlive(i) || i == my_index)
    					continue;
    				if ((g_mode == 5 || g_mode == 9)
    					&& GetPlayerTeam(i) == team_index)
    				{	//团战时 放过队友
    					continue;
    				}
    				if ((g_mode == 6 || g_mode == 7) && i != 0 && i != 1)
    					continue;	//在线群殴只能以人为目标
    				auto _dist = Distance(GetX(),GetY(),GetPlayerX(i),GetPlayerY(i));
    				if(_dist < min_dist)
    				{
    					new_target_index = i;
    					min_dist = _dist;
    				}
    			}
    			this->target_index = new_target_index;
    			/*if(mode != AAM_CHASE && RandomRange(0,100,true,false) < AA_CHANGE_MODE_RATE + adjust * 8)
    			{	//追赶加强
    				this->mode = AAM_CHASE;
    			}*/
    		}
    #endif
    		if (RandomRange(0, 100, true, false) < 20 + adjust * 10)
    			this->mode = AAM_CHASE;
    		Attack();	//根据模式进行攻击
    	}
    	void CheckLevelUp()
    	{
    		if (clock() - lastUp > AA_LEVEL_UP_T)
    		{
    			int upv = 1;	//升级默认1级
    			if (GetPlayerHp(my_index) > 1 && GetPlayerHp(target_index) > GetPlayerHp(my_index) * 1.8)
    				upv = 2;	//当血量差得太远的时候,升级加速
    			xp += upv; 
    			lastUp = clock();
    		}
    	}
    	void OnHurt(int hurt_by)	//受伤时调用
    	{
    		if(!enabled)
    		    return;
    		lastUp += 1000 * RandomRange(0,3,true,true);	//经验有增长的趋势
    		if(mode == AAM_STILL || mode == AAM_WANDER)		//迅速进入正常状态
    			lastModeChanged += 1000 * 4 + adjust * 100;
    		if (PlayerHasAffect(my_index,3) || PlayerHasAffect(my_index,7) || PlayerHasAffect(my_index,11) || PlayerHasAffect(my_index,12))
    		{
    			extraDodgeRate += RandomRange(5, 9 + adjust * 2, true, false);	//躲闪率微调
    		}
    		else {
    			extraDodgeRate += RandomRange(4, 7 + adjust * 2, true, false);	//躲闪率微调
    		}
    
    		if (hurt_by != my_index && hurt_by != target_index	//非我非你
    			&& (g_mode == 5 || g_mode == 9) || (GetPlayerTeam(hurt_by) != team_index)	//异队
    			&& g_mode != 3 //离线群殴没有复仇;在线群殴还是有复仇的
    			)
    		{
    			if (RandomRange(0, 100, true, false) < AA_REVENGE_RATE)
    			{	//复仇
    				target_index = hurt_by;
    			}
    		}
    	}
    	DIR FaceDir8(int i) const
    	{
    		POINT et{GetPlayerX(i),GetPlayerY(i)};
    		if (IsOuttaField(POINT2(et.x, et.y)))
    			return 0;
    		int x = GetX();
    		int y = GetY();
    		int ex = GetPlayerX(target_index); 
    		int ey = GetPlayerY(target_index); 
    		if (x < ex)
    		{
    			if (y > ey)	return RIGHTUP;
    			else if (y < ey)	return RIGHTDOWN;
    			else	return RIGHT;
    		}
    		else if (x > ex)
    		{
    			if (y > ey)	return LEFTUP;
    			else if (y < ey)	return LEFTDOWN;
    			else	return LEFT;
    		}
    		else {
    			if (y > ey)	return UP;
    			else	return DOWN;
    		}
    	}
    	DIR FaceDir4(int i) const
    	{
    		POINT et{GetPlayerX(i),GetPlayerY(i)};
    		if (IsOuttaField(POINT2(et.x, et.y)))
    			return 0;
    		int x = GetX();
    		int y = GetY();
    		int ex = GetPlayerX(target_index); 
    		int ey = GetPlayerY(target_index); 
    		if (ex > x)
    		{
    			if (ey > y)
    				return (abs(ex - x) > abs(ey - y) ? (RandomRange(1, 10) > 7 ? RIGHT : DOWN) : (RandomRange(1, 10) > 7 ? DOWN : RIGHT));
    			else if (ey < y)
    				return (abs(ex - x) > abs(ey - y) ? (RandomRange(1, 10) > 7 ? RIGHT : UP) : (RandomRange(1, 10) > 7 ? UP : RIGHT));
    			else
    				return RIGHT;
    		}
    		else if (ex < x)
    		{
    			if (ey > y)
    				return (abs(ex - x) > abs(ey - y) ? (RandomRange(1, 10) > 7 ? LEFT : DOWN) : (RandomRange(1, 10) > 7 ? DOWN : LEFT));
    			else if (ey < y)
    				return (abs(ex - x) > abs(ey - y) ? (RandomRange(1, 10) > 7 ? LEFT : UP) : (RandomRange(1, 10) > 7 ? UP : LEFT));
    			else
    				return LEFT;
    		}
    		else {
    			if (ey > y)
    				return DOWN;
    			else
    				return UP;
    		}
    	}
    	UINT GetI() const {			//获取下标
    		/*if (enabled == false)
    			return 2;	//无
    		else if (g_bIdt == IDT_OFFLINE)
    			return 1;
    		else
    			return g_p_i;*/
    		return my_index;
    	}
    	UINT GetOppoI() const {
    		return target_index;	
    	}
    	int GetX() const
    	{
    		return GetPlayerX(GetI());
    	}
    	int GetY() const
    	{
    		return GetPlayerY(GetI());
    	}
    	void _Tag(string text) const
    	{
    		setcolor(WHITE);
    		setbkmode(OPAQUE);
    		setfont(20, 0, "微软雅黑");
    		xyprintf(20, 500, "TAG:%s", text.c_str());
    	}
    	void Move()
    	{
    		EXCEPTION_L
    		//debug _Tag("Move");
    
    		/*if (mode == AAM_STILL)
    		{
    			return;
    		}
    		else */
    		if (mode == AAM_WANDER)
    		{
    			if (!PlayerTimeToMove(my_index))
    				return;
    			DIR dir;
    			int x, y;
    		_retry:
    			dir = 2 * RandomRange(1, 4, true, true) - 1;
    			x = GetX();
    			y = GetY();
    			if (PlayerHasAffect(GetI(), 12))
    				dir = OppoDir(dir);
    			DirOffsetPos(x, y, dir, "AIControl::Move");
    			if (IsOuttaField(POINT2(x,y)) || 
    				IsBarrier(bk(x, y, "AIControl::Move")))
    			{
    				goto _retry;
    			}
    			//Move
    			GetPlayerX(my_index) = x;
    			GetPlayerY(my_index) = y;
    			bool sendMsg = (g_bIdt != IDT_OFFLINE);
    			if (sendMsg)
    				SendTCP(UM_SETPOS, x, y, GetI());
    //			p[GetI()].lastMove = clock();
    			LastMove(my_index);
    		}
    		else if (mode == AAM_CHASE || mode == AAM_FLEE 
    			|| mode == AAM_STILL)
    		{
    			if (!PlayerTimeToMove(my_index))
    				return;
    			int x = GetX();
    			int y = GetY();
    			int ex = GetPlayerX(target_index);
    			int ey = GetPlayerY(target_index);
    			DIR xd, yd;
    
    			if (ex > x)
    				xd = RIGHT;
    			else if (ex < x)
    				xd = LEFT;
    			else
    				xd = 0;
    			if (ey > y)
    				yd = DOWN;
    			else if (ey < y)
    				yd = UP;
    			else
    				yd = 0;
    
    			int r = RandomRange(0, 1, true, true);
    			DIR dir;	//final dir
    			if (xd == RIGHT)
    			{
    				if (yd == 0)
    					dir = RIGHT;
    				else {
    					dir = (r ? RIGHT : yd);
    				}
    			}
    			else if (xd == LEFT)
    			{
    				if (yd == 0)
    					dir = LEFT;
    				else {
    					dir = (r ? LEFT : yd);
    				}
    			}
    			else {
    				dir = yd;
    			}
    			if (mode == AAM_FLEE)	//相反逃离
    				dir = OppoDir(dir);
    			if (PlayerHasAffect(GetI(), 12))
    				dir = OppoDir(dir);	//混沌效果 直接再反
    			
    			//Move(CHASE)
    			DirOffsetPos(x, y, dir,"AIControl::Move");
    			if (!IsOuttaField(POINT2(x, y)) &&
    				!IsBarrier(bk(x,y,"AIControl::Move")) && 
    				//!(x == ex && y == ey)	&&	//不能与对方重叠
    				!HasPlayerTouch(my_index,dir)	//不能与别的玩家重叠
    				)	
    			{
    				if (mode != AAM_STILL)
    				{
    					bool sendMsg = (g_bIdt != IDT_OFFLINE);
    					GetPlayerX(my_index) = x;
    					GetPlayerY(my_index) = y;
    					if (sendMsg)
    						SendTCP(UM_SETPOS, x, y, GetI());
    				}
    				GetPlayerFace(my_index) = dir;
    //				p[GetI()].lastMove = clock();
    				LastMove(my_index);
    				//return;
    			}else
    				LastMove(my_index);
    		}
    		else {
    
    		}
    
    		EXCEPTION_R_TITLED("BOP AIControl::Move EXCEPTION")
    	}
    	DIR GetComingDir(const Entity& et) const
    	{
    		if (IsOuttaField(POINT2(et.x, et.y)))
    			return 0;
    		int x = GetX();
    		int y = GetY();
    		int ex = GetPlayerX(target_index);
    		int ey = GetPlayerY(target_index);
    		DIR eface = et.face;
    		if (eface == RIGHT && y == ey && x > ex)
    			return LEFT;
    		else if (eface == LEFT && y == ey && x < ex)
    			return RIGHT;
    		else if (eface == DOWN && x == ex && y > ey)
    			return UP;
    		else if (eface == UP && x == ex && y < ey)
    			return DOWN;
    		else if (eface == LEFTDOWN && (x - ex < 0) && (x - ex) / float(y - ey) == -1.0f)
    			return RIGHTUP;
    		else if (eface == LEFTUP && (x - ex < 0) && (x - ex) / float(y - ey) == 1.0f)
    			return RIGHTDOWN;
    		else if (eface == RIGHTDOWN && (x - ex > 0) && (x - ex) / float(y - ey) == 1.0f)
    			return LEFTUP;
    		else if (eface == RIGHTUP && (x - ex > 0) && (x - ex) / float(y - ey) == -1.0f)
    			return LEFTDOWN;
    		else
    			return 0;
    	}
    	void TryToDodge()
    	{	//尝试躲闪 
    		if (entities.empty())
    			return;
    
    		int x = GetX();
    		int y = GetY();
    		int dp;
    		int r;
    		dp = Varience(AA_DODGE_BASE_RATE,4)	//基础也在变动
    			+ xp * AA_DODGE_UP_RATIO 
    			+ adjust * 3
    			+ extraDodgeRate;
    		//各种效果对其的影响
    		if (PlayerHasAffect(my_index, 6))
    			dp -= 4;
    		if (PlayerHasAffect(my_index, 7))
    			dp -= 3;
    		if (PlayerHasAffect(my_index, 9))
    			dp -= 6;
    		if (PlayerHasAffect(my_index, 11))
    			dp -= 10;
    		else if (PlayerHasAffect(my_index, 12))
    			dp -= 9;
    		if (PlayerHasAffect(my_index, 1))
    			dp -= 2;
    		if (PlayerHasAffect(my_index, 14))
    			dp -= 8;	//隐身的时候得削弱一下,否则太难玩了
    
    		ClampA(dp, AA_DODGE_BASE_RATE-5, AA_DODGE_RATE_MAX);	//限制
    
    		if (PlayerHasAffect(my_index, 4))	//矫捷
    			dp += 3 + adjust * 1;
    
    		  //debug _Tag(ToString(dp));
    
    		for (int i = 0; i < entities.size(); i++)
    		{
    			double dist = Distance(x, y, entities.at(i).x, entities.at(i).y);
    			DIR aimdir=0;
    			if (aimdir = GetComingDir(entities.at(i)))
    			{
    				int dextra_rate = 0;	//根据距离决定的 额外 补充/扣除 概率
    				if (dist < 2.1f)
    					dextra_rate = 4;
    				else if (dist < 4.4f)
    					dextra_rate = 0;
    				else if (dist < 6.3f)
    					dextra_rate = -4;
    				else if (dist < 10.5f)
    					dextra_rate = -8;
    				else {
    					dextra_rate = -16;
    				}
    
    				r = RandomRange(0, 100, true, false);
    				if (r < dp + dextra_rate)
    				{
    					Dodge(aimdir);	//尽力闪避
    				}
    				//continue;
    				break;
    			}
    		}//end of for
    	}
    	bool FaceBarrier(int _x, int _y, DIR face)
    	{
    		int nx = _x, ny = _y;
    		DirOffsetPos(nx, ny, face, "FaceBarrier");
    		if (IsBarrier(bk(nx, ny, string(__func__))) || IsOuttaField(POINT2(nx, ny)))
    			return true;
    		return false;
    	}
    	bool Dodge(DIR aimdir)
    	{	//调用此函数时,必须尽力闪避
    		if (aimdir == 0)
    			return false;
    		if (PlayerHasAffect(my_index, 2) || PlayerHasAffect(my_index, 10))	//不能动的效果一定要中止,否则会被视为作弊
    			return false;
    		const vector<DIR> _choices{1,3,5,7};	//四向
    		vector<DIR> choices{};
    		DIR oppdir = 0;	//最终选择
    		for (int i = 0; i < _choices.size(); i++)
    		{
    			if (_choices.at(i) != aimdir && _choices.at(i) != OppoDir(aimdir))
    			{
    				choices.push_back(_choices.at(i));
    			}
    			else if (_choices.at(i) == OppoDir(aimdir))
    			{
    				oppdir = _choices.at(i);
    			}
    		}
    		if (oppdir != 0)
    		{
    			choices.push_back(oppdir);	//最后选择
    		}
    		bool sendMsg = (g_bIdt != IDT_OFFLINE);
    		for (int k = 0; k < choices.size(); k++)
    		{
    			if (!HasPlayerTouch(GetI(),choices.at(k))		//不碰玩家
    			&&  !FaceBarrier(GetX(),GetY(),choices.at(k))	//不碰壁,不出图
    				)
    			{
    				int x = GetX(), y = GetY();
    				DirOffsetPos(x, y, choices.at(k), "Dodge");
    				SetPlayerPos(GetI(), x, y);		//闪避
    				if (sendMsg)
    					SendTCP(UM_SETPOS, x, y, GetI());
    				return true;					//成功
    			}
    		}
    		return false;	//闪避失败
    	}
    #define AA_CANREACH_RANGE_MAX 30
    	bool CanReach(int x, int y, DIR face, int ex, int ey) const
    	{	//能否打得到
    		if (face == 0)
    			return false;
    		int _x = x, _y = y;
    		int i = 0;
    		if (face == RIGHT || face == LEFT)
    		{
    			if (y != ey)
    				return false;
    			while (!IsOuttaField(POINT2(_x, _y)) && !IsBarrier(bk(_x, _y, "AIControl::CanReach")) && i < AA_CANREACH_RANGE_MAX)
    			{
    				if (_x == ex && _y == ey)
    					return true;
    				DirOffsetPos(_x, _y, face, "AIControl::CanReach");
    				i++;
    				//DebugLog(ToString(i),false);
    			}
    			return false;
    		}else if (face == DOWN || face == UP)
    		{
    			if (x != ex)
    				return false;
    			while (!IsOuttaField(POINT2(_x, _y)) && !IsBarrier(bk(_x, _y, "AIControl::CanReach")) && i < AA_CANREACH_RANGE_MAX)
    			{
    				if (_x == ex && _y == ey)
    					return true;
    				DirOffsetPos(_x, _y, face, "AIControl::CanReach");
    				i++;
    				//DebugLog(ToString(i), false);
    			}
    			return false;
    		}
    		else {
    			if (x == ex || y == ey)
    				return false;
    			while (!IsOuttaField(POINT2(_x, _y)) && !IsBarrier(bk(_x, _y, "AIControl::CanReach")) && i < AA_CANREACH_RANGE_MAX)
    			{
    				if (_x == ex && _y == ey)
    					return true;
    				DirOffsetPos(_x, _y, face, "AIControl::CanReach");
    				i++;
    				//DebugLog(ToString(i), false);
    			}
    			return false;
    		}
    	}
    	double GetTargetDistance()	const
    	{	//获取目标距离 
    		return Distance(GetPlayerX(my_index),GetPlayerY(my_index),GetPlayerX(target_index),GetPlayerY(target_index));
    	}
    	void Attack()
    	{
    		EXCEPTION_L
    		//_Tag("Attack");
    
    		int r = RandomRange(0, 100, true, false);
    		if (r > 100 - AA_CHANGE_WEAPON_RATE && (clock() - lastWeaponChanged) > AA_CHANGE_WEAPON_MIN_T)
    		{
    			do {
    				GetPlayerCurWeaponIndex(my_index) = curw_prob.at(RandomRange(0, curw_prob.size() - 1, true, true));
    			} while (GetPlayerCurWeaponIndex(my_index) == 0);	//不能选空的格子
    
    			lastWeaponChanged = clock();
    		}
    //		double distance = GetOppoDistance();
    		double distance = GetTargetDistance();
    		UINT type = GetItemType(GetPlayerCurWeapon(my_index));
    		int x = GetX();
    		int y = GetY();
    		int ex = GetPlayerX(target_index);
    		int ey = GetPlayerY(target_index);
    
    		DIR face = GetPlayerFace(my_index);
    		UINT ptype;
    		ITEM_ID id = GetPlayerCurWeapon(my_index);
    
    		if(type == ITT_PROP)
    			ptype = GetItemPropType(GetPlayerCurWeapon(my_index));
    		if (type == ITT_BOW || type == ITT_GUN
    			|| (type == ITT_PROP && ptype == ITPT_THROWABLE))	//远程武器
    		{
    			bool reach = CanReach(x, y, face, ex, ey);
    			r = RandomRange(0, 100, true, false);
    
    			int blind_prob = 10;
    			if (mode == AAM_FLEE)
    				blind_prob = 2;
    			else if (type == ITT_PROP && ptype == ITPT_THROWABLE)
    				blind_prob = 1;
    			else
    				blind_prob = 11;
    			if(reach && r > (mode == AAM_CHASE ? 49 : 62) || r < blind_prob)
    //				p[GetI()].TryToAttack(GetI(), (g_bIdt != IDT_OFFLINE));	//checking is inside
    				PlayerTryToAttack(my_index, (g_bIdt != IDT_OFFLINE));	//checking is inside
    		}
    		else if (type == ITT_CLOSE_WEAPON)	//近战武器
    		{	
    			bool reach = distance < 3.3;
    			r = RandomRange(0, 100, true, false);
    			if(reach && r > (mode == AAM_CHASE ? 43 : 45) || r > (mode == AAM_FLEE ? 86 : 97))
    				PlayerTryToAttack(my_index, (g_bIdt != IDT_OFFLINE));	//checking is inside
    		}
    		else if (type == ITT_PROP)	//道具
    		{
    			if (ptype == ITPT_PUT)	//放置类
    			{
    				if (id == 33)	//地雷
    				{
    					int prob = 5;
    					if (distance < 6.0)
    					{
    						if (mode == AAM_FLEE)
    						{	//逃亡中布地雷对方很容易中招
    							prob = 40;
    						}
    						else if (mode == AAM_CHASE)
    						{	//追的时候就不一定了
    							prob = 12;
    						}
    						else if (mode == AAM_STILL)
    						{	//判断对手是否朝自己方向来
    							bool come = false;
    							int delta_x, delta_y;
    							DIR eface = GetPlayerFace(target_index);
    							delta_x = ex - x;
    							delta_y = ey - y;
    							if (delta_x > 0 && eface == LEFT
    								|| delta_x < 0 && eface == RIGHT
    								|| delta_y > 0 && eface == UP
    								|| delta_y < 0 && eface == DOWN)
    								come = true;
    							prob = (come?76:33);
    							
    						}
    					}
    					else {
    						prob = 11;
    					}
    					r = RandomRange(0, 100, true, false);
    					if (r < prob)
    					{	//布地雷
    						PlayerTryToAttack(my_index, (g_bIdt != IDT_OFFLINE));	//checking is inside
    					}
    				}
    				else {
    					//other PUTs...
    				}
    			}
    			else if (ptype == ITPT_POTION)	//药水类,好的药水
    			{
    				r = RandomRange(0, 100, true, false);
    				float t = AA_DRINK_POTION_RATE;	//概率
    				if (id >= 71 && id <= 73)
    				{
    					if (GetPlayerHp(my_index) < GetPlayerMaxHp(my_index) * 0.10)
    						t *= 5.0;
    					else if (GetPlayerHp(my_index) < GetPlayerMaxHp(my_index) * 0.25)
    						t *= 3.0;
    					else if (GetPlayerHp(my_index) < GetPlayerMaxHp(my_index) * 0.45)
    						t *= 1.6;
    				}
    				if (r < t)
    				{	//喝药水
    //					p[GetI()].TryToAttack(GetI(), (g_bIdt != IDT_OFFLINE));
    					PlayerTryToAttack(my_index, (g_bIdt != IDT_OFFLINE));
    				}
    			}
    			else {
    				//other ITPTs...
    			}
    		}
    		else {
    			return;
    		}
    
    		EXCEPTION_R_TITLED("BOP AIControl::Attack EXCEPTION")
    	}
    };
    //AIControl g_aic;
    AIControl& GetPlayerAI(int index);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344
    • 345
    • 346
    • 347
    • 348
    • 349
    • 350
    • 351
    • 352
    • 353
    • 354
    • 355
    • 356
    • 357
    • 358
    • 359
    • 360
    • 361
    • 362
    • 363
    • 364
    • 365
    • 366
    • 367
    • 368
    • 369
    • 370
    • 371
    • 372
    • 373
    • 374
    • 375
    • 376
    • 377
    • 378
    • 379
    • 380
    • 381
    • 382
    • 383
    • 384
    • 385
    • 386
    • 387
    • 388
    • 389
    • 390
    • 391
    • 392
    • 393
    • 394
    • 395
    • 396
    • 397
    • 398
    • 399
    • 400
    • 401
    • 402
    • 403
    • 404
    • 405
    • 406
    • 407
    • 408
    • 409
    • 410
    • 411
    • 412
    • 413
    • 414
    • 415
    • 416
    • 417
    • 418
    • 419
    • 420
    • 421
    • 422
    • 423
    • 424
    • 425
    • 426
    • 427
    • 428
    • 429
    • 430
    • 431
    • 432
    • 433
    • 434
    • 435
    • 436
    • 437
    • 438
    • 439
    • 440
    • 441
    • 442
    • 443
    • 444
    • 445
    • 446
    • 447
    • 448
    • 449
    • 450
    • 451
    • 452
    • 453
    • 454
    • 455
    • 456
    • 457
    • 458
    • 459
    • 460
    • 461
    • 462
    • 463
    • 464
    • 465
    • 466
    • 467
    • 468
    • 469
    • 470
    • 471
    • 472
    • 473
    • 474
    • 475
    • 476
    • 477
    • 478
    • 479
    • 480
    • 481
    • 482
    • 483
    • 484
    • 485
    • 486
    • 487
    • 488
    • 489
    • 490
    • 491
    • 492
    • 493
    • 494
    • 495
    • 496
    • 497
    • 498
    • 499
    • 500
    • 501
    • 502
    • 503
    • 504
    • 505
    • 506
    • 507
    • 508
    • 509
    • 510
    • 511
    • 512
    • 513
    • 514
    • 515
    • 516
    • 517
    • 518
    • 519
    • 520
    • 521
    • 522
    • 523
    • 524
    • 525
    • 526
    • 527
    • 528
    • 529
    • 530
    • 531
    • 532
    • 533
    • 534
    • 535
    • 536
    • 537
    • 538
    • 539
    • 540
    • 541
    • 542
    • 543
    • 544
    • 545
    • 546
    • 547
    • 548
    • 549
    • 550
    • 551
    • 552
    • 553
    • 554
    • 555
    • 556
    • 557
    • 558
    • 559
    • 560
    • 561
    • 562
    • 563
    • 564
    • 565
    • 566
    • 567
    • 568
    • 569
    • 570
    • 571
    • 572
    • 573
    • 574
    • 575
    • 576
    • 577
    • 578
    • 579
    • 580
    • 581
    • 582
    • 583
    • 584
    • 585
    • 586
    • 587
    • 588
    • 589
    • 590
    • 591
    • 592
    • 593
    • 594
    • 595
    • 596
    • 597
    • 598
    • 599
    • 600
    • 601
    • 602
    • 603
    • 604
    • 605
    • 606
    • 607
    • 608
    • 609
    • 610
    • 611
    • 612
    • 613
    • 614
    • 615
    • 616
    • 617
    • 618
    • 619
    • 620
    • 621
    • 622
    • 623
    • 624
    • 625
    • 626
    • 627
    • 628
    • 629
    • 630
    • 631
    • 632
    • 633
    • 634
    • 635
    • 636
    • 637
    • 638
    • 639
    • 640
    • 641
    • 642
    • 643
    • 644
    • 645
    • 646
    • 647
    • 648
    • 649
    • 650
    • 651
    • 652
    • 653
    • 654
    • 655
    • 656
    • 657
    • 658
    • 659
    • 660
    • 661
    • 662
    • 663
    • 664
    • 665
    • 666
    • 667
    • 668
    • 669
    • 670
    • 671
    • 672
    • 673
    • 674
    • 675
    • 676
    • 677
    • 678
    • 679
    • 680
    • 681
    • 682
    • 683
    • 684
    • 685
    • 686
    • 687
    • 688
    • 689
    • 690
    • 691
    • 692
    • 693
    • 694
    • 695
    • 696
    • 697
    • 698
    • 699
    • 700
    • 701
    • 702
    • 703
    • 704
    • 705
    • 706
    • 707
    • 708
    • 709
    • 710
    • 711
    • 712
    • 713
    • 714
    • 715
    • 716

    大致就包括自动移动、攻击、躲闪、喝药、埋地雷等,特别是那个躲闪很有意思,经验值越高躲闪越容易成功。
    以后打算搞个游击模式算法。。等更新吧

    下载: https://download.csdn.net/download/cjz2005/86287023

    喜欢的朋友别忘了点赞关注!!

  • 相关阅读:
    微分的定义和介绍习题
    SAM-DETR源码讲解
    【个人博客公网访问】使用Cpolar+Emlog在Ubuntu上轻松搭建个人博客公网访问
    32、学习 Java 中的注解(参照官方教程)
    [深入研究4G/5G/6G专题-55]: L3信令控制-4-软件功能与流程的切分-CU网元的信令
    上位机工作感想-从C#到Qt的转变-2
    KNN算法实现
    金融数学方法:有限差分法
    数论div2训练题解
    Python伪随机数模块random
  • 原文地址:https://blog.csdn.net/cjz2005/article/details/126138900