⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 battle.cpp

📁 Visual C++角色扮演游戏程序设计(附带CD源代码)作者: (日)坂本千寻 译者:博硕文化
💻 CPP
📖 第 1 页 / 共 4 页
字号:
{
	NumberView = 1;
	CPoint view = AttackFrom->GetDrawPos();
	view.x += (AttackFrom->GetSize().cx - 32) / 2;
	view.y -= 12;
	Number[0].Set(&PopupParts, view, CPoint(0, 32), CSize(32, 9), 0);
	RedrawSprite(Number);

	AttackAnimeCount = 0;
	status = STATUS_ANIME;
	Parent->SetTimer(TIMER_LEVELUP_ID, TIMER_LEVELUP_TIME);

	// 播放音效
	Parent->StartWave(LEVELUP_WAVE);
}

// 战斗结束

void CBattleAction::BattleEnd(bool iswin)
{
	// 结束所有动作
	status = STATUS_BATTLE_END;

	// 将胜负结果储存到变量
	Parent->SetValue("battle", iswin? 1: 0);

	// 先把人物的状态储存回去
	for (list<CCharacter>::iterator p = player_list.begin(); p != player_list.end(); ++p) {
		Parent->GetParam().SetStatus(p->status.name, &p->status);
	}

	// 把显示中的内容储存到“背景”,以便移往事件
	BackLayer->Copy(ViewImage);
	Parent->Invalidate();

	// CBattleAction作废
	Parent->ScriptDone();
}

// 魔法

void CBattleAction::Magic(CCharacter *from, CCharacter *to, bool player)
{
	// 删除光标
	SetCursor(CPoint(-1, -1));

	// 清除显示范围
	ClearDistCursor();
	CPoint pos = from->GetMapPoint();
	map_data[pos.y][pos.x].type &= ~ATTACKDIST;
	map_data[pos.y][pos.x].attack_dist = 0;

	CSize diff = from->GetMapPoint() - to->GetMapPoint();

	// 调整人物角色的方向
	if (abs(diff.cx) > abs(diff.cy)) {
		if (diff.cx < 0) {
			from->SetDirection(CCharacter::RIGHT);
			to->SetDirection(CCharacter::LEFT);
		}
		else {
			from->SetDirection(CCharacter::LEFT);
			to->SetDirection(CCharacter::RIGHT);
		}
	}
	else {
		if (diff.cy < 0) {
			from->SetDirection(CCharacter::DOWN);
			to->SetDirection(CCharacter::UP);
		}
		else {
			from->SetDirection(CCharacter::UP);
			to->SetDirection(CCharacter::DOWN);
		}
	}
	RedrawSprite(from);
	RedrawSprite(to);

	// 攻击动画开始
	AttackFrom = from;
	AttackTo = to;
	AttackPlayerToEnemy = player;
	AttackAnimeCount = 0;
	AttackAnimeState = 0;

	status = STATUS_ANIME;
	Parent->SetTimer(TIMER_MAGIC_ID, TIMER_MAGIC_TIME);

	// 播放效果音
	switch (magic_param.id) {
	  case MAGIC_HEAL:			// 恢复
		Parent->StartWave(HEAL_WAVE);
		break;

	  case MAGIC_FIREBALL:		// Fire ball
		Parent->StartWave(FIREBALL_WAVE);
		break;
	}
}

// 魔法动作(Heal)

bool CBattleAction::MagicHeal()
{
	switch (AttackAnimeState) {
	  case 0:		// 第1阶段  魔法发动
		if (AttackFrom->MagicAnime(AttackAnimeCount++)) {
			AttackAnimeCount = 0;
			AttackAnimeState++;

			MagicSprite[0].Set(&HealImage, CPoint(0, 0), CPoint(0, 0),
				CSize(HealImage.Width() / 7, HealImage.Height() / 2), 10);	// 前
			MagicSprite[1].Set(&HealImage, CPoint(0, 0), CPoint(0, HealImage.Height() / 2),
				CSize(HealImage.Width() / 7, HealImage.Height() / 2), -10);	// 后傠
			MagicSprite[0].SetMapPoint(AttackTo->GetMapPoint());
			MagicSprite[1].SetMapPoint(AttackTo->GetMapPoint());
			AddSprite(MagicSprite);
			AddSprite(MagicSprite + 1);
		}
		RedrawSprite(AttackFrom);
		break;

	  case 1:		// 第2阶段  效果发挥
		if (AttackAnimeCount < 7) {
			MagicSprite[0].SetSrcPos(
				MagicSprite[0].GetSize().cx * AttackAnimeCount,
				MagicSprite[0].GetSrcPos().y);
			MagicSprite[1].SetSrcPos(
				MagicSprite[1].GetSize().cx * AttackAnimeCount,
				MagicSprite[1].GetSrcPos().y);
			RedrawSprite(MagicSprite);
			RedrawSprite(MagicSprite + 1);
			AttackAnimeCount++;
		}
		else {
			AttackFrom->NormalStatus();
			RedrawSprite(AttackFrom);
			RemoveSprite(MagicSprite);
			RemoveSprite(MagicSprite + 1);
			HealPhase2();
			return true;
		}
	}
	return false;
}

// 第2阶段的魔法恢复/补血

void CBattleAction::HealPhase2()
{
	// 判断魔法
	// debug用,追踪变量
	TRACE("攻方参数:[%s]\n", AttackFrom->status.name);
	TRACE(" 攻击力 : %4d\n", AttackFrom->status.attack_power);
	TRACE(" 防御力 : %4d\n", AttackFrom->status.defence_power);
	TRACE(" 剩余HP : %4d\n", AttackFrom->status.hit_point);
	TRACE("守方参数:[%s]\n", AttackTo->status.name);
	TRACE(" 攻击力 : %4d\n", AttackTo->status.attack_power);
	TRACE(" 防御力 : %4d\n", AttackTo->status.defence_power);
	TRACE(" 剩余HP : %4d\n", AttackTo->status.hit_point);

	TRACE("使用魔法 id    : %d\n", magic_param.id);
	TRACE("         type  : %d\n", magic_param.type);
	TRACE("         dist  : %d\n", magic_param.dist);
	TRACE("         power : %d\n", magic_param.power);
	TRACE("         use_mp: %d\n", magic_param.use_mp);

	// MP的消耗
	AttackFrom->status.magic_point -= magic_param.use_mp;

	// 损伤的显示
	char heal[8];
	NumberView = sprintf(heal, "%d", magic_param.power);
	CPoint view = AttackTo->GetDrawPos();
	view.x += (AttackTo->GetSize().cx - NumberView * 8) / 2;
	view.y -= 12;
	for (int i=0; i<NumberView; i++) {
		heal[i] -= '0';
		Number[i].Set(&PopupParts, view, CPoint(heal[i] * 8, 10), CSize(8, 10), 0);
		view.x += 8;
		RedrawSprite(Number + i);
	}

	AttackTo->status.hit_point += magic_param.power;
	if (AttackTo->status.hit_point > AttackTo->status.max_hit_point)
		AttackTo->status.hit_point = AttackTo->status.max_hit_point;

	TRACE(" 剩余HP : %4d\n", AttackTo->status.hit_point);

	// 经验值的计算
	AttackFrom->status.experience += 10;

	// 开始显示恢复量
	AttackAnimeCount = 0;
	status = STATUS_ANIME;
	Parent->SetTimer(TIMER_NUMBER_ID, TIMER_NUMBER_TIME);
}

// 魔法动作(FireBall)

bool CBattleAction::MagicFireBall()
{
	switch (AttackAnimeState) {
	  case 0:		//第1阶段  魔法发动
		if (AttackFrom->MagicAnime(AttackAnimeCount++)) {
			AttackAnimeCount = 0;
			AttackAnimeState++;

			MagicSprite[0].SetFireBall(&FireBallImage, AttackFrom);
			AddSprite(MagicSprite);
		}
		RedrawSprite(AttackFrom);
		break;

	  case 1:		// 第2阶段  火焰的移动
		{
			RemoveSprite(MagicSprite);
			if (MagicSprite[0].MoveFireBall(AttackFrom, AttackTo, AttackAnimeCount)) {
				AddSprite(MagicSprite);
				AttackAnimeCount++;
			}
			else {
				AttackAnimeCount = 0;
				AttackAnimeState++;
				MagicSprite[0].Set(&Explosion, CPoint(0, 0), CPoint(0, 0),
					CSize(Explosion.Width() / 11, Explosion.Height()), 10);
				MagicSprite[0].SetMapPoint(AttackTo->GetMapPoint());
				AddSprite(MagicSprite);
			}
		}
		break;

	  case 2:		// 第3阶段  爆炸
		if (AttackAnimeCount < 11) {
			MagicSprite[0].SetSrcPos(
				MagicSprite[0].GetSize().cx * AttackAnimeCount,
				MagicSprite[0].GetSrcPos().y);
			RedrawSprite(MagicSprite);
			AttackAnimeCount++;
		}
		else {
			AttackFrom->NormalStatus();
			RemoveSprite(MagicSprite);
			RedrawSprite(AttackFrom);
			FireBallPhase2();
			return true;
		}
	}
	return false;
}

// 第2阶段的攻击魔法

void CBattleAction::FireBallPhase2()
{
	// 判断魔法
	// debug用,追踪变量
	TRACE("攻方参数:[%s]\n", AttackFrom->status.name);
	TRACE(" 攻击力 : %4d\n", AttackFrom->status.attack_power);
	TRACE(" 防御力 : %4d\n", AttackFrom->status.defence_power);
	TRACE(" 剩余HP : %4d\n", AttackFrom->status.hit_point);
	TRACE("守方参数:[%s]\n", AttackTo->status.name);
	TRACE(" 攻击力 : %4d\n", AttackTo->status.attack_power);
	TRACE(" 防御力 : %4d\n", AttackTo->status.defence_power);
	TRACE(" 剩余HP : %4d\n", AttackTo->status.hit_point);

	TRACE("使用魔法 id    : %d\n", magic_param.id);
	TRACE("         type  : %d\n", magic_param.type);
	TRACE("         dist  : %d\n", magic_param.dist);
	TRACE("         power : %d\n", magic_param.power);
	TRACE("         use_mp: %d\n", magic_param.use_mp);

	// MP的消耗
	AttackFrom->status.magic_point -= magic_param.use_mp;
	int ap = magic_param.power;
	int dp = AttackTo->status.resistance == 0? 1: AttackTo->status.resistance;
	int attack = ap * ap / dp;
	if (attack <= 0)	// 破坏力至少1点
		attack = 1;

	// 损伤的显示
	char damage[8];
	NumberView = sprintf(damage, "%d", attack);
	CPoint view = AttackTo->GetDrawPos();
	view.x += (AttackTo->GetSize().cx - NumberView * 8) / 2;
	view.y -= 12;
	for (int i=0; i<NumberView; i++) {
		damage[i] -= '0';
		Number[i].Set(&PopupParts, view, CPoint(damage[i] * 8, 0), CSize(8, 10), 0);
		view.x += 8;
		RedrawSprite(Number + i);
	}

	if (attack > AttackTo->status.hit_point)
		attack = AttackTo->status.hit_point;

	TRACE(" 损伤 : %4d\n", attack);

	AttackTo->status.hit_point -= attack;

	TRACE(" 剩余HP : %4d\n", AttackTo->status.hit_point);

	// 计算经验值
	// 每次攻击就有基本 10 point,若被打败倒地则+20 point
	// 如果有等级差距时
	// 攻方等级 > 守方等级  减低所获得的经验值
	// 攻方等级 < 守方等级  提高所获得的经验值
	int experience = 10;
	if (AttackTo->status.hit_point == 0)
		experience += 20;
	int level_diff = AttackFrom->status.level - AttackTo->status.level;
	if (level_diff > 0) {	// 攻击较弱的对手
		experience >>= level_diff;
	}
	else if (level_diff) {
		experience <<= -level_diff;
	}

	TRACE(" 经验值 = %d + %d = %d\n",
		AttackFrom->status.experience, experience,
		AttackFrom->status.experience + experience);

	AttackFrom->status.experience += experience;

	// 开始显示损伤
	AttackAnimeCount = 0;
	status = STATUS_ANIME;
	Parent->SetTimer(TIMER_NUMBER_ID, TIMER_NUMBER_TIME);
}

// 搜寻攻击范围(敌方移动使用)

void CBattleAction::FindAttackCalc(int x, int y, int dist)
{
	map_data[y][x].type |= ATTACKDIST;
	map_data[y][x].attack_dist = dist;
	if (dist == 0)
		return;
	if (y > MapRect.top && map_data[y - 1][x].ChkAttack(dist))
		FindAttackCalc(x, y - 1, dist - 1);
	if (y < MapRect.bottom - 1 && map_data[y + 1][x].ChkAttack(dist))
		FindAttackCalc(x, y + 1, dist - 1);
	if (x > MapRect.left && map_data[y][x - 1].ChkAttack(dist))
		FindAttackCalc(x - 1, y, dist - 1);
	if (x < MapRect.right - 1 && map_data[y][x + 1].ChkAttack(dist))
		FindAttackCalc(x + 1, y, dist - 1);
}

// 敌军人物的移动

void CBattleAction::MoveEnemy()
{
	TRACE("[%s]的移动\n", enemy_ptr->status.name);
	enemy_ptr->move_done = true;			// 已移动
	attack_target = 0;						// 清除攻击对象

	// 当作直接攻击设定参数
	magic_attack = false;
	int attack_dist = enemy_ptr->status.attack_dist;

	// 判断如果还有攻击魔法,则可使用
	int magic_id = enemy_ptr->status.FindMagic(MAGIC_FIREBALL);
	if (magic_id >= 0 && enemy_ptr->IsMagicOk(magic_id)) {
		magic_attack = true;
		magic_param = enemy_ptr->GetMagicParam(magic_id);
		attack_dist = magic_param.dist;
	}

	CPoint mp = enemy_ptr->GetMapPoint();
	FindDist(mp.x, mp.y, enemy_ptr->status.move_dist);
	Parent->UpdateWindow();

	// 为了让后面的处理好做,让目前位置也包含到移动范围之内
	map_data[mp.y][mp.x].type |= MOVEDIST;
	map_data[mp.y][mp.x].move_dist = enemy_ptr->status.move_dist;

	int eval_point = INT_MIN;			// 评分点数
	CPoint move = mp;					// 移动位置

	for (list<CCharacter>::iterator p = player_list.begin(); p != player_list.end(); p++) {
		CPoint pos = p->GetMapPoint();
		FindAttackCalc(pos.x, pos.y, attack_dist);
		map_data[pos.y][pos.x].type &= ~ATTACKDIST;

		CRect rect(pos.x, pos.y, pos.x + 1, pos.y + 1);
		rect.InflateRect(attack_dist, attack_dist);
		rect &= MapRect;

		for (int y=rect.top; y<rect.bottom; y++) {
			for (int x=rect.left; x<rect.right; x++) {
				// 判断是否有可移动、可攻击的位置
				if (map_data[y][x].ChkType(ATTACKDIST | MOVEDIST)) {
					// 评分标准为:
					// 1. 移动距离越少越好
					// 2. 攻击距离越远越好
					// 3. 对方的HP越小越好
					// 4. 对方的攻击力越高越好
					// 依此原则计分
					int point = (attack_dist - map_data[y][x].attack_dist) * 20
						+ map_data[y][x].move_dist * 50
						- p->status.hit_point * 5
						+ p->status.attack_power;

					// 若得分较高,则更新
					if (eval_point < point) {
						eval_point = point;		// 新的得分
						attack_target = &*p;	// 设定攻击目标
						move.x = x;				// 新的移动
						move.y = y;
					}
				}
				// 清除作业区域
				map_data[y][x].attack_dist = 0;
				map_data[y][x].type &= ~ATTACKDIST;
			}
		}
	}

	if (attack_target == 0) {		// 无法移动到可攻击的位置
		CRect rect(mp.x, mp.y, mp.x + 1, mp.y + 1);
		rect.InflateRect(enemy_ptr->status.move_dist, enemy_ptr->status.move_dist);
		rect &= MapRect;

		eval_point = INT_MAX;		// 清除得分

		for (list<CCharacter>::iterator p = player_list.begin(); p != player_list.end(); p++) {
			CPoint pos = p->GetMapPoint();
			for (int y=rect.top; y<rect.bottom; y++) {
				for (int x=rect.left; x<rect.right; x++) {
					if (map_data[y][x].ChkType(MOVEDIST)) {
						int dist = abs(x - pos.x) + abs(y - pos.y);
						if (eval_point > dist) {
							eval_point = dist;
							move.x = x;
							move.y = y;
						}
					}
				}
			}
		}
	}

	// 清除目前位置中的移动范围旗标
	map_data[mp.y][mp.x].type &= ~MOVEDIST;
	map_data[mp.y][mp.x].move_dist = 0;

	::Sleep(70);				// 等待直到出现移动范围的显示

	if (mp == move) {			// 不移动
		ClearDistCursor();
	}
	else {
		MovePlayer(&*enemy_ptr, move);
	}
}

// 敌军人物的攻击

void CBattleAction::AttackEnemy()
{
	TRACE("[%s]的攻击\n", enemy_ptr->status.name);
	enemy_ptr->attack_done = true;	// 已攻击

	if (attack_target) {
		CPoint mp = enemy_ptr->GetMapPoint();

		if (magic_attack) {	// 魔法攻击
			FindAttack(mp.x, mp.y, magic_param.dist);
			Parent->UpdateWindow();
			Sleep(100);
			Magic(&*enemy_ptr, attack_target, false);
		}
		else {				// 直接攻击
			FindAttack(mp.x, mp.y, enemy_ptr->status.attack_dist);
			Parent->UpdateWindow();
			Sleep(100);
			Attack(&*enemy_ptr, attack_target, false);
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -