文字游戏
yi_hr
·
·
个人记录
#include <iostream>
#include <vector>
#include <string>
#include <map> // 用于物品栏和职业数据
#include <deque> // 用于消息日志
#include <algorithm> // 用于 min/max, find_if, random_shuffle
#include <chrono> // 用于线程暂停
#include <thread> // 用于线程暂停
#include <cstdlib> // For rand(), srand()
#include <ctime> // For time()
#include <functional> // For std::function in Upgrade struct
#include <fstream> // For file I/O (save/load)
#include <limits> // For numeric_limits in file I/O
#include <cmath> // For sqrt() and pow() in map generation
// Windows 特定头文件
#include <conio.h> // _getch() - Kept for specific "press any key" prompt, but not for general action input.
#include <windows.h> // SetConsoleCursorInfo, SetConsoleCursorPosition, SetConsoleTextAttribute, GetAsyncKeyState, COORD, SetConsoleScreenBufferSize, SetConsoleWindowInfo
// 定义快捷键宏
// getAsyncKeyState 是非阻塞的,每次循环都会检查按键状态
#define zxb(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1 : 0)
using namespace std;
// --- 控制台工具函数 ---
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); // 全局控制台句柄
void hide() {
CONSOLE_CURSOR_INFO cursor_info = {1, 0};
SetConsoleCursorInfo(hConsole, &cursor_info);
}
void gotoxy(int x, int y) {
COORD pos = {(SHORT)x, (SHORT)y};
SetConsoleCursorPosition(hConsole, pos);
}
enum Color {
black = 0, blue = 1, green = 2, cyan = 3, red = 4, magenta = 5,
yellow = 6, white = 7, gray = 8, light_blue = 9, light_green = 10,
light_cyan = 11, light_red = 12, light_magenta = 13, light_yellow = 14,
bright_white = 15
};
void set_color(int color) {
SetConsoleTextAttribute(hConsole, color);
}
// 清空指定区域
void clear_area(int x1, int y1, int x2, int y2) {
for (int y = y1; y <= y2; ++y) {
gotoxy(x1, y);
for (int x_char = x1; x_char <= x2; ++x_char) { // Iterate character by character
cout << " ";
}
}
}
// --- 游戏常量和全局变量 ---
const int MAP_COLS = 40, MAP_ROWS = 20; // 地图尺寸 MAP_COLS:宽 MAP_ROWS:高
const int UI_OFFSET_X = MAP_COLS * 2 + 4; // 侧边栏起始X坐标
const int SIDEBAR_WIDTH = 35; // 侧边栏可用的宽度 (字符数)
const int NUM_FLOORS = 6; // 总共的楼层数
// 新增:最大等级常量
const int MAX_LEVEL = 51;
// 玩家状态
int x_pos, y_pos; // 玩家在地图上的坐标,x代表行(y轴),y代表列(x轴)
int x_pos_last, y_pos_last; // 用于记录上一步的位置 (无尽模式中防卡住)
int player_class; // 1:战士 2:游侠 3:法师 4:mwh
int level = 1, experience = 0; // 等级,经验
int current_hp; // 当前生命值
int gold = 10; // 金币
int skill_cooldown = 0; // 技能冷却时间
// --- 新增:一次性物品状态 ---
bool power_potion_active = false; // 力量药水效果是否激活
bool defense_potion_active = false; // 坚韧药水效果是否激活
int have_sword = 0; // 当前装备的武器索引 (指向 all_weapons 中的一个)
int have_armor = 0; // 当前装备的防具索引 (指向 all_armors 中的一个)
int current_floor = 1; // 当前所在楼层 (1到NUM_FLOORS)
int max_unlocked_floor = 1; // 玩家能解锁的最高楼层
int game_phase = 1; // 游戏轮次
int best_phase = 1; // 最高游戏轮次记录
// --- 新增:无尽模式相关变量 ---
bool is_in_endless_mode = false; // 标记玩家是否在无尽模式中
int endless_current_floor = 1; // 无尽模式的当前层数
int endless_max_floor = 1; // 玩家达到过的最高无尽层数
// 用于从无尽模式返回
int stored_normal_floor;
int stored_normal_x, stored_normal_y;
// 无尽模式的地图和状态
vector<string> endless_map;
bool endless_boss_defeated_this_floor = false;
// --- 新增:星徽之力数据结构 ---
struct StarPower {
int id; // 唯一的ID,用于识别
string name;
string description;
};
vector<StarPower> all_star_powers; // 存储所有可用的星徽之力
int current_star_power_id = -1; // 玩家当前拥有的星徽ID,-1代表没有
// --- 妙具系统: 新增妙具数据结构 ---
struct Gadget {
int id;
string name;
string description;
int max_uses; // 每层可用的最大次数
};
vector<Gadget> all_gadgets; // 存储所有可用的妙具
int current_gadget_id = -1; // 玩家当前拥有的妙具ID,-1代表没有
int gadget_current_uses = 0; // 当前妙具的剩余使用次数
// 等级相关属性数据 (索引0不用,实际从1级开始)
// 经验需求调整,确保游戏有足够长度,现在支持到MAX_LEVEL
int XP_REQUIRED[] = {
0, 50, 120, 220, 350, 520, 750, 1000, 1300, 1700,
2200, 2800, 3500, 4300, 5200, 6200, 7325, 8600, 10050, 11700,
13575, 15700, 18090, 20755, 23700, 26935, 30475, 34330, 38515, 43045,
47935, 53200, 58855, 64915, 71395, 78310, 85675, 93505, 101815, 110620,
119935, 129775, 140155, 151090, 162595, 174685, 187375, 200680, 214615, 229195,
244435, 9999999
};
// --- 职业数据结构 ---
struct ClassStats {
string name;
string skill_name;
int skill_cooldown_base; // 技能基础冷却时间
vector<int> max_hp_per_level;
vector<int> base_attack_per_level;
vector<int> base_defense_per_level;
// 默认构造函数,用于 map 插入时初始化空向量
ClassStats() : skill_cooldown_base(0) {
max_hp_per_level.resize(MAX_LEVEL + 1); // 预留MAX_LEVEL+1个空间
base_attack_per_level.resize(MAX_LEVEL + 1);
base_defense_per_level.resize(MAX_LEVEL + 1);
}
};
map<int, ClassStats> class_definitions; // 存储所有职业的数据
// --- 物品词条(Affix)与装备数据 ---
struct Affix {
string name;
int tier; // 1:普通, 2:稀有, 3:史诗
string description; // 描述中包含具体数值
};
vector<Affix> all_affixes; // 存储所有词条模板
// Helper functions to categorize affixes (NEW)
bool is_weapon_affix_type(const Affix& affix) {
// 列出所有武器词条的名称
return (affix.name == "暴击+" || affix.name == "吸血" || affix.name == "穿甲" ||
affix.name == "破碎一击" || affix.name == "经验加成" || affix.name == "财富掠夺" ||
affix.name == "剧毒之刃" || affix.name == "致残打击");
}
bool is_armor_affix_type(const Affix& affix) {
// 列出所有护甲词条的名称
return (affix.name == "生命+" || affix.name == "韧性" || affix.name == "反伤" ||
affix.name == "再生" || affix.name == "毒抗");
}
struct Weapon {
string name;
int initial_damage; // Lv0时的基础伤害
int cost;
int level = 0; // 武器自身等级
int initial_affix_slots; // Lv0时的基础词条插槽数
vector<Affix> affixes; // 实际持有的词条
// 根据等级计算当前伤害和词条槽数
int get_current_damage() const {
return initial_damage + level * 5; // 每升一级增加5点伤害
}
int get_current_affix_slots() const {
// 固定词条武器(例如神圣之剑、混沌战斧)的词条槽数是固定的
if (name == "神圣之剑" || name == "混沌战斧") {
return initial_affix_slots;
}
return initial_affix_slots + level; // 每升一级增加1个槽位
}
// 构造函数,用于创建武器实例
Weapon(const string& n, int i_dmg, int c, int i_slots, const vector<Affix>& fixed_aff = {})
: name(n), initial_damage(i_dmg), cost(c), level(0), initial_affix_slots(i_slots) {
if (!fixed_aff.empty()) {
affixes = fixed_aff; // 对于固定词条武器,直接复制
}
}
// 默认构造函数,用于序列化/反序列化时使用,不进行自动初始化
Weapon() : name(""), initial_damage(0), cost(0), level(0), initial_affix_slots(0) {}
};
// 全局武器模板列表 (不会被存档/读档内容直接覆盖,只作为蓝本)
vector<Weapon> global_weapon_templates;
// all_weapons 现在存储的是玩家实际拥有的武器实例列表
// have_sword 索引到这个列表中的某个元素
vector<Weapon> all_weapons;
// --- 护甲数据结构 ---
struct Armor {
string name;
int initial_defense_bonus; // Lv0时的基础防御
int cost;
int level = 0; // 护甲自身等级
int initial_affix_slots; // Lv0时的基础词条插槽数
vector<Affix> affixes; // 实际持有的词条
// 根据等级计算当前防御和词条槽数
int get_current_defense() const {
return initial_defense_bonus + level * 2; // 每升一级增加2点防御
}
int get_current_affix_slots() const {
// 固定词条护甲(例如神圣之盾、混沌胸甲)的词条槽数是固定的
if (name == "神圣之盾" || name == "混沌胸甲") {
return initial_affix_slots;
}
return initial_affix_slots + level; // 每升一级增加1个槽位
}
// 构造函数,用于创建护甲实例
Armor(const string& n, int i_def, int c, int i_slots, const vector<Affix>& fixed_aff = {})
: name(n), initial_defense_bonus(i_def), cost(c), level(0), initial_affix_slots(i_slots) {
if (!fixed_aff.empty()) {
affixes = fixed_aff; // 对于固定词条护甲,直接复制
}
}
// 默认构造函数,用于序列化/反序列化时使用
Armor() : name(""), initial_defense_bonus(0), cost(0), level(0), initial_affix_slots(0) {}
};
// 全局护甲模板列表
vector<Armor> global_armor_templates;
// all_armors 存储玩家实际拥有的护甲实例列表
// have_armor 索引到这个列表中的某个元素
vector<Armor> all_armors;
// 怪物数据
enum MonsterType {
GOBLIN, SPIDER, // Floor 1
BEAST, SKELETON, // Floor 2
DEMON_GUARD, ZOMBIE, // Floor 3
SHADOW_BEAST, WIZARD_APPRENTICE, // Floor 4
ELITE_GUARD, FIRE_DEMON, // Floor 5
VOID_RAVAGER, ANCIENT_GUARDIAN, // Floor 6
BOSS_GOBLIN_KING, BOSS_MINOTAUR, BOSS_NECROMANCER, BOSS_DRAGON_SPAWN, BOSS_FINAL, BOSS_LORD_OF_CHAOS // Bosses
};
struct Monster {
string name;
int max_hp;
int attack;
int defense;
int xp_reward;
int gold_reward;
MonsterType type; // 怪物类型,用于判断特殊能力
int floor; // 怪物出现的楼层
};
vector<Monster> all_monster_templates_base; // 存储怪物原始模板数据 (未缩放)
vector<Monster> current_monster_templates; // 存储当前轮次调整后的怪物数据 (已缩放)
// 从当前怪物模板中获取特定类型的怪物
Monster get_monster_template(MonsterType type) {
for (const auto& m : current_monster_templates) {
if (m.type == type) {
return m;
}
}
return current_monster_templates[0]; // Fallback to Goblin
}
// 获取当前楼层的小怪
Monster get_random_monster_for_floor(int floor, bool is_strong = false) {
vector<Monster> available_monsters;
for (const auto& m : current_monster_templates) {
if (m.floor == floor && m.type < BOSS_GOBLIN_KING) { // 过滤掉Boss
available_monsters.push_back(m);
}
}
if (available_monsters.empty()) return current_monster_templates[0]; // Fallback to Goblin
// 对于第六层,所有小怪都应该很强,可以有逻辑偏向
if (floor == 6 && available_monsters.size() > 1 && is_strong) {
// 尝试返回第二种怪物,通常更强
return available_monsters[1];
} else if (available_monsters.size() > 1 && is_strong && rand() % 2 == 0) {
// 非第六层,但is_strong,则有50%几率返回列表中第二种怪物(如果有的话)
return available_monsters[1];
}
return available_monsters[rand() % available_monsters.size()];
}
// 物品栏 (键:物品名称,值:数量)
map<string, int> inventory;
// 消息日志
deque<string> message_log;
int g_message_log_start_y = 0; // Global variable to track where message log starts dynamically
// --- 地图数据 ---
// 原始地图模板 (用于重置)
vector<string> initial_maps[NUM_FLOORS];
// 当前地图状态 (会被修改)
vector<string> current_maps[NUM_FLOORS];
// 每层传送门进入时的默认位置 (x, y)
pair<int, int> floor_entrance_coords[NUM_FLOORS + 1] = {
{0,0}, // 占位符,索引从1开始
{1, 1}, // Floor 1 entry
{1, 1}, // Floor 2 entry
{1, 1}, // Floor 3 entry
{1, 1}, // Floor 4 entry
{1, 1}, // Floor 5 entry
{1, 1} // Floor 6 entry
};
// 追踪每层Boss是否已被击败
bool boss_defeated[NUM_FLOORS + 1];
// --- 角色强化数据 ---
struct Upgrade {
string name;
int level = 0; // 升级等级
int base_cost; // 基础费用
function<void()> apply_effect; // 升级效果
};
vector<Upgrade> upgrades;
// --- 前置声明 ---
void print_tile(char j);
void print_message_log(); // Declared to be used by add_message
void add_message(string s);
// Helper function to get combined affix descriptions (NEW)
vector<string> get_combined_affix_descriptions(const vector<Affix>& affixes);
// UI Print functions (modified to be dynamic or use new global y)
int get_total_attack(int battle_bonus_atk = 0); // 新增:计算总攻击力
int get_total_defense(int battle_bonus_def = 0); // 新增:计算总防御力
int get_total_max_hp(); // 新增:计算总生命值上限
int print_player_stats_panel_lines(int start_y_panel); // New helper for player stats
int print_equipped_items_details(int start_y_panel); // Modified signature to print both weapon and armor
int print_star_power_status(int start_y_panel); // 新增:打印星徽之力
int print_gadget_status(int start_y_panel); // --- 妙具系统: 新增前置声明 ---
void print_floor_boss_status(int start_y_panel); // New helper for floor/boss
void refresh_ui();
int print_weapon_details(const Weapon& w, int start_y, const string& prefix = ""); // Modified to return next_y
int print_armor_details(const Armor& a, int start_y, const string& prefix = ""); // New: print armor details
void check_level_up();
void start_battle(Monster monster_template);
void game_over();
void update_game_state();
void enter_shop();
void choose_class();
void load_initial_maps(); // 加载地图模板
void reset_player_progression(); // 重置玩家状态(用于游戏重开)
void reset_map_and_boss_status(); // 重置地图和Boss(用于新轮次或重开)
void reset_game_state(); // 完整的游戏重置
void enter_portal();
void initialize_class_data();
void initialize_monster_templates(); // 初始化怪物数据并根据轮次缩放
void initialize_item_templates_and_affixes(); // 初始化武器/护甲模板和词条数据 (填充 global_weapon_templates, global_armor_templates, all_affixes)
void initialize_star_powers(); // 新增:初始化星徽之力
void initialize_gadgets(); // --- 妙具系统: 新增前置声明 ---
void initialize_base_templates(); // 新增:整合所有基础模板初始化
void initialize_upgrades(); // 初始化升级系统
void enter_forging_hut(); // 锻造小屋函数
void on_final_boss_defeated(); // 最终Boss击败处理
void reroll_affixes(Weapon& w); // 武器词条重铸
void reroll_armor_affixes(Armor& a); // 护甲词条重铸
// New: Weapon Upgrade
void upgrade_weapon(int weapon_idx);
// New: Armor Upgrade
void upgrade_armor(int armor_idx);
// New: Save/Load functions
void save_game(const string& filename = "save.txt");
void load_game(const string& filename = "save.txt");
// New: Endless Mode functions
void generate_endless_map(int floor_level);
Monster get_endless_monster(int floor_level, char tile_type);
// --- 妙具系统: 更新战斗辅助函数的前置声明 ---
void perform_basic_attack(int& monster_current_hp, const Monster& monster_template, vector<string>& battle_log, bool& monster_stunned_ref,
bool& monster_poisoned_status_ref, int& monster_poison_duration_status_ref, int& monster_poison_damage_per_turn_status_ref,
bool& monster_crippled_status_ref, int& monster_cripple_duration_status_ref, int& monster_cripple_attack_reduction_ref,
float player_attack_multiplier, float monster_stat_multiplier);
void perform_skill_attack(int& monster_current_hp, const Monster& monster_template, vector<string>& battle_log, bool& monster_stunned_ref,
float player_attack_multiplier, float monster_stat_multiplier);
// --- 游戏简介函数 (New) ---
void display_game_intro() {
system("cls");
set_color(light_yellow);
gotoxy(25, 3);
cout << "--- 欢迎来到文字地牢! ---";
set_color(white);
gotoxy(10, 6);
cout << "你是一名勇敢的冒险者,踏入充满危险的地牢深处。";
gotoxy(10, 7);
cout << "这里布满了各种可怕的怪物、陷阱,但也隐藏着稀有的宝藏。";
gotoxy(10, 9);
cout << "你的目标是不断探索,击败强大的敌人,提升自身能力,";
gotoxy(10, 10);
cout << "最终征服所有楼层的挑战,并在更高的轮次中证明自己!";
set_color(light_cyan);
gotoxy(10, 12);
cout << "====== 游戏指南 ======";
set_color(white);
gotoxy(10, 14);
cout << "移动: W (上), A (左), S (下), D (右)";
gotoxy(10, 15);
cout << "战斗: 进入怪物格 ('怪'/'兽'/'王'/'英') 自动触发";
gotoxy(10, 16);
cout << "物品: H (使用生命药水), F (使用职业技能), G (使用妙具)";
gotoxy(10, 17);
cout << "特殊地点: ";
set_color(light_cyan); cout << "店"; set_color(white); cout << " (商店), ";
set_color(bright_white); cout << "锻"; set_color(white); cout << " (锻造小屋), ";
set_color(light_yellow); cout << "门"; set_color(white); cout << " (传送门)";
gotoxy(10, 18);
cout << "保存/读取: P (保存), L (读取)";
gotoxy(10, 19);
cout << "退出游戏: Esc";
set_color(light_green);
gotoxy(20, 22);
cout << "按 [空格键] 开始你的冒险...";
while (!zxb(VK_SPACE)) {
this_thread::sleep_for(chrono::milliseconds(50));
}
while (zxb(VK_SPACE)); // Debounce
system("cls"); // 清屏,准备进入职业选择界面
}
// --- 游戏功能实现 ---
// 打印单个地图图块
void print_tile(char j) {
if (j == '#') {
set_color(gray);
cout << "墙";
} else if (j == '.') {
set_color(white);
cout << ". ";
} else if (j == 'D') {
set_color(light_yellow);
cout << "门"; // 传送门
} else if (j == 'H') {
set_color(light_red);
cout << "药"; // 药水
} else if (j == 'T') {
set_color(yellow);
cout << "宝"; // 宝箱
} else if (j == 'm') {
set_color(green);
cout << "怪"; // 普通小怪
} else if (j == 'G') {
set_color(red);
cout << "兽"; // 强力小怪
} else if (j == 'S') {
set_color(light_cyan);
cout << "店"; // 商店
} else if (j == 'F') { // 新增锻造小屋
set_color(bright_white);
cout << "锻"; // 锻造小屋
} else if (j == 'B') {
set_color(light_magenta);
cout << "王"; // Boss
} else if (j == 'U') { // 新增:下一层入口
set_color(light_magenta);
cout << "往";
} else if (j == 'R') { // 新增:回归门
set_color(light_cyan);
cout << "归";
} else if (j == 'E') { // 新增:精英怪
set_color(light_magenta);
cout << "英";
} else {
cout << " "; // 未知字符或空白
}
}
// 专门用于打印消息日志 (Uses global g_message_log_start_y)
void print_message_log() {
clear_area(UI_OFFSET_X, g_message_log_start_y, UI_OFFSET_X + SIDEBAR_WIDTH, g_message_log_start_y + 9); // Max 9 messages + 1 title
set_color(light_yellow);
gotoxy(UI_OFFSET_X, g_message_log_start_y);
cout << "------ 消息日志 ------";
set_color(white);
int current_log_y = g_message_log_start_y + 1; // Messages start after title
for (const string& msg : message_log) {
gotoxy(UI_OFFSET_X, current_log_y++);
cout << msg;
}
}
// 添加消息到日志并显示
void add_message(string s) {
message_log.push_back(s);
if (message_log.size() > 9) { // 最多保留9条消息
message_log.pop_front();
}
print_message_log(); // Update the log display immediately
}
// Helper function to get combined affix descriptions (NEW)
vector<string> get_combined_affix_descriptions(const vector<Affix>& affixes) {
map<string, int> affix_counts;
for (const auto& affix : affixes) {
affix_counts[affix.name]++;
}
vector<string> combined_descriptions;
for (const auto& pair : affix_counts) {
string name = pair.first;
int count = pair.second;
string desc_line_base = ""; // This will be the base description for the affix, ignoring count for a moment
// Find the base description from all_affixes
for (const auto& original_affix : all_affixes) {
if (original_affix.name == name) {
desc_line_base = original_affix.description;
break;
}
}
string desc_line;
if (name == "暴击+") {
desc_line = "增加 " + to_string(count * 10) + "% 的暴击几率。";
} else if (name == "吸血") {
desc_line = "每次攻击造成伤害的 " + to_string(count * 10) + "% 转化为生命。";
} else if (name == "穿甲") {
desc_line = "攻击时无视敌人 " + to_string(count * 5) + " 点防御。";
} else if (name == "破碎一击") {
desc_line = "攻击时有 " + to_string(min(85, count * 15)) + "% 几率击晕敌人一回合。"; // Apply stun cap
}
else if (name == "经验加成") {
desc_line = "击败怪物时额外获得 " + to_string(count * 15) + "% 经验。";
} else if (name == "财富掠夺") {
desc_line = "击败怪物时额外获得 " + to_string(count * 15) + "% 金币。";
} else if (name == "剧毒之刃") {
desc_line = "攻击时有 " + to_string(min(100, count * 25)) + "% 几率使敌人中毒。"; // Cap at 100%
} else if (name == "致残打击") {
desc_line = "攻击时有 " + to_string(min(100, count * 20)) + "% 几率降低敌人攻击力。"; // Cap at 100%
}
else if (name == "生命+") {
desc_line = "增加生命上限 " + to_string(count * 10) + " 点。";
} else if (name == "韧性") {
desc_line = "受到伤害时有 " + to_string(min(85, count * 15)) + "% 几率减少50%伤害。"; // Cap at 85%
} else if (name == "反伤") {
desc_line = "受到伤害时反弹 " + to_string(min(85, count * 20)) + "% 伤害给攻击者。"; // Cap at 85%
} else if (name == "再生") {
desc_line = "每回合开始时回复 " + to_string(count * 5) + " 点生命值。";
} else if (name == "毒抗") {
desc_line = "减少受到的中毒伤害 " + to_string(count * 25) + "%。";
}
else {
// Fallback for any other affixes that might be added later
desc_line = name + ": " + desc_line_base;
if (count > 1) { // If multiple, indicate count
desc_line = "(x" + to_string(count) + ") " + desc_line;
}
}
combined_descriptions.push_back(desc_line);
}
return combined_descriptions;
}
// 打印地图
void print_map() {
// 使用无尽地图如果处于无尽模式
vector<string>& map_to_print = is_in_endless_mode ? endless_map : current_maps[current_floor - 1];
set_color(white);
clear_area(0, 0, MAP_COLS * 2, MAP_ROWS - 1);
for (int i = 0; i < MAP_ROWS; i++) {
string current_map_row = map_to_print[i]; // 使用正确的地图数据
gotoxy(0, i);
for (char tile : current_map_row) {
print_tile(tile);
}
}
}
// --- 新增:获取玩家总攻击力 ---
int get_total_attack(int battle_bonus_atk) { // 新增一个可选参数
int total_atk = class_definitions[player_class].base_attack_per_level[level] + all_weapons[have_sword].get_current_damage();
// 应用泰坦之力效果
if (current_star_power_id == 3) {
total_atk = static_cast<int>(total_atk * 1.10);
}
return total_atk + battle_bonus_atk; // 返回时加上战斗中的临时加成
}
// --- 新增:获取玩家总防御力 ---
int get_total_defense(int battle_bonus_def) { // 新增一个可选参数
int total_def = class_definitions[player_class].base_defense_per_level[level] + all_armors[have_armor].get_current_defense();
// 应用泰坦之力效果
if (current_star_power_id == 3) {
total_def = static_cast<int>(total_def * 1.10);
}
return total_def + battle_bonus_def; // 返回时加上战斗中的临时加成
}
// 获取玩家总生命上限(包含护甲词条)
int get_total_max_hp() {
int base_hp = class_definitions[player_class].max_hp_per_level[level];
int bonus_hp_from_affixes = 0;
for (const auto& affix : all_armors[have_armor].affixes) {
if (affix.name == "生命+") {
bonus_hp_from_affixes += 10; // 每个“生命+”词条增加10点生命
}
}
int total_hp = base_hp + bonus_hp_from_affixes;
// --- 新增:应用泰坦之力效果 ---
if (current_star_power_id == 3) {
total_hp = static_cast<int>(total_hp * 1.10);
}
// --- 结束新增 ---
return total_hp;
}
// Helper: Prints player stats, returns next Y
int print_player_stats_panel_lines(int start_y_panel) {
int current_y = start_y_panel;
set_color(white);
gotoxy(UI_OFFSET_X, current_y++);
cout << "职业: " << class_definitions[player_class].name << " (等级 " << level << ")";
gotoxy(UI_OFFSET_X, current_y++);
cout << "经验: " << experience << "/" << XP_REQUIRED[level];
gotoxy(UI_OFFSET_X, current_y++);
set_color(light_green);
cout << "生命: " << current_hp << "/" << get_total_max_hp(); // 使用新的总生命上限函数
gotoxy(UI_OFFSET_X, current_y++);
set_color(light_red);
cout << "攻击: " << get_total_attack(); // 不传入参数,显示基础攻击
set_color(white);
cout << " (" << class_definitions[player_class].base_attack_per_level[level] << "+" << all_weapons[have_sword].get_current_damage() << ")";
gotoxy(UI_OFFSET_X, current_y++);
set_color(cyan);
cout << "防御: " << get_total_defense(); // 不传入参数,显示基础防御
set_color(white);
cout << " (" << class_definitions[player_class].base_defense_per_level[level] << "+" << all_armors[have_armor].get_current_defense() << ")";
gotoxy(UI_OFFSET_X, current_y++);
cout << "金币: " << gold << " G";
// --- 修改:显示所有一次性物品 ---
clear_area(UI_OFFSET_X, current_y, UI_OFFSET_X + SIDEBAR_WIDTH, current_y + 6);
gotoxy(UI_OFFSET_X, current_y++);
cout << "生命药水: " << inventory["生命药水"] << " (非战斗按'H')";
gotoxy(UI_OFFSET_X, current_y++);
cout << "力量药水: " << inventory["力量药水"] << " (战斗中使用)";
gotoxy(UI_OFFSET_X, current_y++);
cout << "坚韧药水: " << inventory["坚韧药水"] << " (战斗中使用)";
gotoxy(UI_OFFSET_X, current_y++);
cout << "火焰炸弹: " << inventory["火焰炸弹"] << " (战斗中使用)";
gotoxy(UI_OFFSET_X, current_y++);
cout << "麻痹卷轴: " << inventory["麻痹卷轴"] << " (战斗中使用)";
gotoxy(UI_OFFSET_X, current_y++);
cout << "烟雾弹 : " << inventory["烟雾弹"] << " (战斗中使用)";
gotoxy(UI_OFFSET_X, current_y++);
cout << "技能: " << class_definitions[player_class].skill_name << " (按'F') ";
if (skill_cooldown == 0) {
set_color(light_green);
cout << "[准备就绪]";
} else {
set_color(gray);
cout << "[冷却中:" << skill_cooldown << "]";
}
set_color(white);
return current_y;
}
// Helper: Prints current floor and boss status, fixed at bottom
void print_floor_boss_status(int start_y_panel) {
if (is_in_endless_mode) {
int current_y = start_y_panel;
set_color(light_magenta);
gotoxy(UI_OFFSET_X, current_y++);
cout << "无尽模式: 第 " << endless_current_floor << " 层 (最高 " << endless_max_floor << ")";
gotoxy(UI_OFFSET_X, current_y++);
if (!endless_boss_defeated_this_floor) {
set_color(light_red);
cout << "本层守护者: 未击败 ";
} else {
set_color(light_green);
cout << "本层守护者: 已击败 ";
}
set_color(white);
return;
}
int current_y = start_y_panel;
set_color(white);
gotoxy(UI_OFFSET_X, current_y++);
cout << "当前楼层: " << current_floor << " / " << NUM_FLOORS << " (轮次: " << game_phase << ") ";
gotoxy(UI_OFFSET_X, current_y++);
if (current_floor <= NUM_FLOORS && !boss_defeated[current_floor]) {
set_color(light_red);
cout << "本层Boss: 未击败 ";
} else if (current_floor <= NUM_FLOORS && boss_defeated[current_floor]) {
set_color(light_green);
cout << "本层Boss: 已击败 ";
}
set_color(white);
}
// 打印当前装备武器和护甲的详细信息,包含词条换行 (Modified signature and logic)
int print_equipped_items_details(int start_y_panel) {
set_color(white); // Ensure color is white for this section
int current_y = start_y_panel; // Start from the passed Y
// 武器信息
gotoxy(UI_OFFSET_X, current_y++);
cout << "武器: " << all_weapons[have_sword].name << " (Lv." << all_weapons[have_sword].level << ")";
// 打印合并后的武器词条名称 (例如: [暴击+] (x2) [吸血])
map<string, int> weapon_affix_counts;
for (const auto& affix : all_weapons[have_sword].affixes) {
weapon_affix_counts[affix.name]++;
}
string current_weapon_affix_name_line = " 词条: ";
if (!weapon_affix_counts.empty()) {
for (const auto& pair : weapon_affix_counts) {
string affix_text = "[" + pair.first + "]";
if (pair.second > 1) {
affix_text += " (x" + to_string(pair.second) + ")";
}
// Check if current affix plus next would exceed sidebar width
if (current_weapon_affix_name_line.length() + affix_text.length() + 1 > SIDEBAR_WIDTH) {
gotoxy(UI_OFFSET_X, current_y++); // Increment Y for new line
cout << current_weapon_affix_name_line; // Print current accumulated line
current_weapon_affix_name_line = " " + affix_text; // Start new line with indent
} else {
current_weapon_affix_name_line += " " + affix_text; // Append to current line
}
}
gotoxy(UI_OFFSET_X, current_y++); // Print the last accumulated line of affix names
cout << current_weapon_affix_name_line;
} else {
gotoxy(UI_OFFSET_X, current_y++);
cout << current_weapon_affix_name_line << "[无]";
}
// 打印汇总后的武器词条描述
vector<string> combined_weapon_affix_descs = get_combined_affix_descriptions(all_weapons[have_sword].affixes);
if (!combined_weapon_affix_descs.empty()) {
for (const string& desc : combined_weapon_affix_descs) {
gotoxy(UI_OFFSET_X, current_y++);
cout << " - " << desc; // Indent combined descriptions
}
}
current_y++; // 武器和护甲之间的间隙
// 护甲信息
gotoxy(UI_OFFSET_X, current_y++);
cout << "防具: " << all_armors[have_armor].name << " (Lv." << all_armors[have_armor].level << ")";
// 打印合并后的护甲词条名称
map<string, int> armor_affix_counts;
for (const auto& affix : all_armors[have_armor].affixes) {
armor_affix_counts[affix.name]++;
}
string current_armor_affix_name_line = " 词条: ";
if (!armor_affix_counts.empty()) {
for (const auto& pair : armor_affix_counts) {
string affix_text = "[" + pair.first + "]";
if (pair.second > 1) {
affix_text += " (x" + to_string(pair.second) + ")";
}
if (current_armor_affix_name_line.length() + affix_text.length() + 1 > SIDEBAR_WIDTH) {
gotoxy(UI_OFFSET_X, current_y++);
cout << current_armor_affix_name_line;
current_armor_affix_name_line = " " + affix_text;
} else {
current_armor_affix_name_line += " " + affix_text;
}
}
gotoxy(UI_OFFSET_X, current_y++);
cout << current_armor_affix_name_line;
} else {
gotoxy(UI_OFFSET_X, current_y++);
cout << current_armor_affix_name_line << "[无]";
}
// 打印汇总后的护甲词条描述
vector<string> combined_armor_affix_descs = get_combined_affix_descriptions(all_armors[have_armor].affixes);
if (!combined_armor_affix_descs.empty()) {
for (const string& desc : combined_armor_affix_descs) {
gotoxy(UI_OFFSET_X, current_y++);
cout << " - " << desc;
}
}
return current_y; // Return the next available Y coordinate
}
// --- 新增:打印星徽之力状态 ---
int print_star_power_status(int start_y_panel) {
if (current_star_power_id == -1) {
return start_y_panel; // 如果没有星徽,什么也不打印,直接返回
}
int current_y = start_y_panel;
StarPower current_power;
for(const auto& sp : all_star_powers) {
if (sp.id == current_star_power_id) {
current_power = sp;
break;
}
}
set_color(light_magenta);
gotoxy(UI_OFFSET_X, current_y++);
cout << "星徽之力: [" << current_power.name << "]";
set_color(white);
gotoxy(UI_OFFSET_X, current_y++);
// 简单的换行处理
string desc = " 效果: " + current_power.description;
if (desc.length() > SIDEBAR_WIDTH) {
cout << desc.substr(0, SIDEBAR_WIDTH);
gotoxy(UI_OFFSET_X, current_y++);
cout << " " << desc.substr(SIDEBAR_WIDTH);
} else {
cout << desc;
}
return current_y + 1; // 返回下一个可用的Y坐标,留出一些间隙
}
// --- 妙具系统: 新增打印妙具状态函数 ---
int print_gadget_status(int start_y_panel) {
if (current_gadget_id == -1) {
return start_y_panel; // 如果没有妙具,不打印
}
int current_y = start_y_panel;
Gadget current_gadget;
for(const auto& g : all_gadgets) {
if (g.id == current_gadget_id) {
current_gadget = g;
break;
}
}
set_color(light_cyan); // 使用不同的颜色以区分
gotoxy(UI_OFFSET_X, current_y++);
cout << "妙具: [" << current_gadget.name << "]";
set_color(white);
gotoxy(UI_OFFSET_X, current_y++);
// 简单的换行处理
string desc = " 效果: " + current_gadget.description;
if (desc.length() > SIDEBAR_WIDTH) {
cout << desc.substr(0, SIDEBAR_WIDTH);
gotoxy(UI_OFFSET_X, current_y++);
cout << " " << desc.substr(SIDEBAR_WIDTH);
} else {
cout << desc;
}
gotoxy(UI_OFFSET_X, current_y++);
set_color(light_yellow);
cout << " 剩余次数: " << gadget_current_uses << " / " << current_gadget.max_uses << " (战斗按'G')";
return current_y + 1; // 返回下一个可用的Y坐标
}
// 打印主界面 (包含地图和状态栏)
void refresh_ui() {
print_map();
// Clear entire sidebar area for redraw, to ensure no old text lingers
clear_area(UI_OFFSET_X, 0, UI_OFFSET_X + SIDEBAR_WIDTH, MAP_ROWS + 9 + 25); // Adjusted height for more dynamic content
set_color(gray);
for (int i = 0; i < MAP_ROWS + 25; i++) { // Separator still spans map height + more
gotoxy((MAP_COLS << 1), i);
cout << "|";
}
set_color(white); // Reset color after separator
int current_sidebar_y = 1; // Start for first section content
// Section 1: Top Banner
gotoxy(UI_OFFSET_X, current_sidebar_y++);
set_color(light_yellow);
cout << "--- 文字地牢探险 ---";
set_color(white);
// Section 2: Player Stats Panel
current_sidebar_y = print_player_stats_panel_lines(current_sidebar_y); // Returns next Y
// Section 3: Equipped Items Details (dynamic height)
current_sidebar_y = print_equipped_items_details(current_sidebar_y); // Call new function
// 新增:打印星徽之力
current_sidebar_y = print_star_power_status(current_sidebar_y);
// --- 妙具系统: 调用打印函数 ---
current_sidebar_y = print_gadget_status(current_sidebar_y);
// Section 4: Message Log (fixed height, dynamic start Y)
g_message_log_start_y = current_sidebar_y; // Set global Y for message log
print_message_log(); // Call message log print (it uses g_message_log_start_y)
current_sidebar_y += 10; // Advance Y by 10 (1 for title, 9 for messages)
// Section 5: Current Floor and Boss Status (fixed height, dynamic start Y)
print_floor_boss_status(current_sidebar_y);
set_color(white); // Reset to default color at the end
}
// 打印武器详细信息 (用于商店和锻造小屋) (Modified to return next_y)
int print_weapon_details(const Weapon& w, int start_y, const string& prefix) {
// Clear a larger area sufficient for weapon details AND all affix descriptions
clear_area(4, start_y, 4 + SIDEBAR_WIDTH + 30, start_y + 25); // Extend clear area significantly
set_color(white);
int current_y_internal = start_y; // Use an internal tracker
gotoxy(4, current_y_internal++);
set_color(white);
cout << prefix << "名称: " << w.name << " (Lv." << w.level << ")";
gotoxy(4, current_y_internal++);
set_color(light_red);
cout << prefix << "伤害: " << w.get_current_damage();
gotoxy(4, current_y_internal++);
set_color(cyan);
cout << prefix << "初始词条槽位: " << w.initial_affix_slots;
gotoxy(4, current_y_internal++);
set_color(light_green);
cout << prefix << "当前词条槽位: " << w.get_current_affix_slots();
gotoxy(4, current_y_internal++);
set_color(yellow);
cout << prefix << "出售价格: " << w.cost / 2 << " G";
gotoxy(4, current_y_internal++);
set_color(white);
// 打印合并后的武器词条名称 (例如: [暴击+] (x2) [吸血])
map<string, int> affix_counts;
for (const auto& affix : w.affixes) {
affix_counts[affix.name]++;
}
string current_affix_name_line_detail = prefix + "词条: ";
if (!affix_counts.empty()) {
for (const auto& pair : affix_counts) {
string affix_text = "[" + pair.first + "]";
if (pair.second > 1) {
affix_text += " (x" + to_string(pair.second) + ")";
}
if (current_affix_name_line_detail.length() + affix_text.length() + 1 > SIDEBAR_WIDTH) {
gotoxy(4, current_y_internal++);
cout << current_affix_name_line_detail;
current_affix_name_line_detail = prefix + " " + affix_text; // 缩进新行
} else {
current_affix_name_line_detail += " " + affix_text;
}
}
gotoxy(4, current_y_internal++); // Print the last accumulated affix names line
cout << current_affix_name_line_detail;
} else {
gotoxy(4, current_y_internal++);
cout << current_affix_name_line_detail << "[无]";
}
// 打印汇总后的词条描述
vector<string> combined_affix_descs = get_combined_affix_descriptions(w.affixes);
if (!combined_affix_descs.empty()) {
for (const string& desc : combined_affix_descs) {
gotoxy(4, current_y_internal++);
cout << prefix << " - " << desc;
}
}
return current_y_internal;
}
// 打印护甲详细信息 (用于商店和锻造小屋)
int print_armor_details(const Armor& a, int start_y, const string& prefix) {
// Clear a larger area sufficient for armor details AND all affix descriptions
clear_area(4, start_y, 4 + SIDEBAR_WIDTH + 30, start_y + 25);
set_color(white);
int current_y_internal = start_y;
gotoxy(4, current_y_internal++);
set_color(white);
cout << prefix << "名称: " << a.name << " (Lv." << a.level << ")";
gotoxy(4, current_y_internal++);
set_color(cyan);
cout << prefix << "防御: " << a.get_current_defense();
gotoxy(4, current_y_internal++);
set_color(cyan);
cout << prefix << "初始词条槽位: " << a.initial_affix_slots;
gotoxy(4, current_y_internal++);
set_color(light_green);
cout << prefix << "当前词条槽位: " << a.get_current_affix_slots();
gotoxy(4, current_y_internal++);
set_color(yellow);
cout << prefix << "出售价格: " << a.cost / 2 << " G";
gotoxy(4, current_y_internal++);
set_color(white);
// 打印合并后的护甲词条名称
map<string, int> affix_counts;
for (const auto& affix : a.affixes) {
affix_counts[affix.name]++;
}
string current_affix_name_line_detail = prefix + "词条: ";
if (!affix_counts.empty()) {
for (const auto& pair : affix_counts) {
string affix_text = "[" + pair.first + "]";
if (pair.second > 1) {
affix_text += " (x" + to_string(pair.second) + ")";
}
if (current_affix_name_line_detail.length() + affix_text.length() + 1 > SIDEBAR_WIDTH) {
gotoxy(4, current_y_internal++);
cout << current_affix_name_line_detail;
current_affix_name_line_detail = prefix + " " + affix_text; // 缩进新行
} else {
current_affix_name_line_detail += " " + affix_text;
}
}
gotoxy(4, current_y_internal++); // Print the last accumulated affix names line
cout << current_affix_name_line_detail;
} else {
gotoxy(4, current_y_internal++);
cout << current_affix_name_line_detail << "[无]";
}
// 打印汇总后的词条描述
vector<string> combined_affix_descs = get_combined_affix_descriptions(a.affixes);
if (!combined_affix_descs.empty()) {
for (const string& desc : combined_affix_descs) {
gotoxy(4, current_y_internal++);
cout << prefix << " - " << desc;
}
}
return current_y_internal;
}
// 处理宝箱内容
void open_treasure_chest() {
// --- 新增:无尽模式下有几率获得星徽之力 ---
if (is_in_endless_mode && (rand() % 100 < 10)) { // 10% 的几率
int new_power_idx = rand() % all_star_powers.size();
StarPower found_power = all_star_powers[new_power_idx];
if (current_star_power_id == -1) { // 玩家没有星徽,直接获得
current_star_power_id = found_power.id;
add_message("你从宝箱中感应到一股神秘力量!");
add_message("获得了星徽之力: [" + found_power.name + "]!");
} else { // 玩家已有星徽,需要选择
// 找到当前星徽
StarPower current_power;
for(const auto& sp : all_star_powers) {
if (sp.id == current_star_power_id) {
current_power = sp;
break;
}
}
system("cls");
gotoxy(25, 2); set_color(light_magenta); cout << "--- 星徽抉择 ---";
set_color(white);
gotoxy(10, 5); cout << "你发现了一个新的星徽之力,但你只能同时拥有一个。";
gotoxy(10, 8); set_color(light_cyan); cout << "你当前拥有的星徽:";
set_color(white);
gotoxy(12, 10); cout << "名称: " << current_power.name;
gotoxy(12, 11); cout << "效果: " << current_power.description;
gotoxy(10, 14); set_color(light_yellow); cout << "新发现的星徽:";
set_color(white);
gotoxy(12, 16); cout << "名称: " << found_power.name;
gotoxy(12, 17); cout << "效果: " << found_power.description;
gotoxy(10, 20); cout << "请选择: [1] 替换为新的星徽 (" << found_power.name << ")";
gotoxy(10, 21); cout << " [2] 保留现有的星徽 (" << current_power.name << ")";
bool choice_made = false;
while (!choice_made) {
if (zxb('1')) {
add_message("你吸收了新的力量,替换了旧的星徽!");
add_message("新星徽: [" + found_power.name + "] 已激活。");
current_star_power_id = found_power.id;
choice_made = true;
while(zxb('1'));
} else if (zxb('2')) {
add_message("你决定保留现有的力量,放弃了新的星徽。");
choice_made = true;
while(zxb('2'));
}
this_thread::sleep_for(chrono::milliseconds(50));
}
system("cls");
refresh_ui();
gotoxy(y_pos << 1, x_pos); set_color(bright_white); cout << "入";
}
// 获得星徽之力后,宝箱的常规奖励不再触发
current_maps[current_floor - 1][x_pos][y_pos] = '.';
if(is_in_endless_mode) endless_map[x_pos][y_pos] = '.';
return;
}
// --- 妙具系统: 在无尽宝箱中获得妙具 ---
else if (is_in_endless_mode && (rand() % 100 < 6)) { // 6% 的几率获得妙具
int new_gadget_idx = rand() % all_gadgets.size();
Gadget found_gadget = all_gadgets[new_gadget_idx];
if (current_gadget_id == -1) { // 玩家没有妙具,直接获得
current_gadget_id = found_gadget.id;
gadget_current_uses = found_gadget.max_uses;
add_message("你从宝箱中发现一个奇妙的装置!");
add_message("获得了妙具: [" + found_gadget.name + "]!");
} else { // 玩家已有妙具,需要选择
Gadget current_gadget;
for(const auto& g : all_gadgets) {
if (g.id == current_gadget_id) {
current_gadget = g;
break;
}
}
system("cls");
gotoxy(25, 2); set_color(light_cyan); cout << "--- 妙具抉择 ---";
set_color(white);
gotoxy(10, 5); cout << "你发现了一个新的妙具,但你只能同时携带一个。";
gotoxy(10, 8); set_color(light_green); cout << "你当前携带的妙具:";
set_color(white);
gotoxy(12, 10); cout << "名称: " << current_gadget.name;
gotoxy(12, 11); cout << "效果: " << current_gadget.description;
gotoxy(12, 12); cout << "次数: " << gadget_current_uses << " / " << current_gadget.max_uses;
gotoxy(10, 15); set_color(light_yellow); cout << "新发现的妙具:";
set_color(white);
gotoxy(12, 17); cout << "名称: " << found_gadget.name;
gotoxy(12, 18); cout << "效果: " << found_gadget.description;
gotoxy(12, 19); cout << "次数: " << found_gadget.max_uses << " / " << found_gadget.max_uses;
gotoxy(10, 22); cout << "请选择: [1] 替换为新的妙具 (" << found_gadget.name << ")";
gotoxy(10, 23); cout << " [2] 保留现有的妙具 (" << current_gadget.name << ")";
bool choice_made = false;
while (!choice_made) {
if (zxb('1')) {
add_message("你装备了新的妙具,替换了旧的!");
add_message("新妙具: [" + found_gadget.name + "] 已准备就绪。");
current_gadget_id = found_gadget.id;
gadget_current_uses = found_gadget.max_uses; // 新妙具次数充满
choice_made = true;
while(zxb('1'));
} else if (zxb('2')) {
add_message("你决定保留现有的装置,放弃了新的妙具。");
choice_made = true;
while(zxb('2'));
}
this_thread::sleep_for(chrono::milliseconds(50));
}
system("cls");
refresh_ui();
gotoxy(y_pos << 1, x_pos); set_color(bright_white); cout << "入";
}
// 获得妙具后,宝箱的常规奖励不再触发
current_maps[current_floor - 1][x_pos][y_pos] = '.';
if(is_in_endless_mode) endless_map[x_pos][y_pos] = '.';
return;
}
int loot_type = rand() % 100; // 0-99
// --- 新增:无尽模式奖励调整 ---
float endless_bonus_multiplier = 1.0f;
if (is_in_endless_mode) {
endless_bonus_multiplier = 1.0f + (endless_current_floor * 0.1f);
}
// --- 结束新增 ---
if (loot_type < 30) { // 30% 几率获得金币
// --- 修改金币获取公式 ---
int amount = rand() % 20 + 10 * current_floor * game_phase;
amount = static_cast<int>(amount * endless_bonus_multiplier); // 应用无尽模式加成
gold += amount;
add_message("你打开宝箱,获得了 " + to_string(amount) + " 金币!");
} else if (loot_type < 65) { // 35% 几率获得武器或护甲
bool is_weapon = rand() % 2;
// --- 修改装备等级公式 ---
int floor_factor = is_in_endless_mode ? (endless_current_floor / 2) : current_floor;
int max_weapon_template_idx = min((int)global_weapon_templates.size() - 1, floor_factor + game_phase + 2);
max_weapon_template_idx = max(0, max_weapon_template_idx);
int max_armor_template_idx = min((int)global_armor_templates.size() - 1, floor_factor + game_phase + 2);
max_armor_template_idx = max(0, max_armor_template_idx);
if (is_weapon) {
int weapon_template_idx = rand() % (max_weapon_template_idx + 1); // 随机获得一种武器模板索引
// 创建新的武器实例,其level默认为0,affixes会在构造时根据initial_affix_slots生成
Weapon new_weapon_instance = global_weapon_templates[weapon_template_idx]; // 从模板复制
new_weapon_instance.level = rand() % 2; // 宝箱获得的武器可能是Lv0或Lv1
// 重新为这个新实例生成词条
// 对于固定词条的武器,不重新生成词条
if (!(new_weapon_instance.name == "神圣之剑" || new_weapon_instance.name == "混沌战斧")) {
new_weapon_instance.affixes.clear();
for (int i = 0; i < new_weapon_instance.get_current_affix_slots(); ++i) {
vector<Affix> pool;
for (const auto& affix_template : all_affixes) {
// 武器词条:只选择武器词条,且级别不超过武器等级+1
if (affix_template.tier <= new_weapon_instance.level + 1 &&
is_weapon_affix_type(affix_template)) {
pool.push_back(affix_template);
}
}
if (!pool.empty()) {
new_weapon_instance.affixes.push_back(pool[rand() % pool.size()]);
}
}
}
// 新增:武器选择逻辑
system("cls"); // 清屏以显示选择界面
gotoxy(25, 2);
set_color(light_yellow);
cout << "--- 发现新武器! ---";
int current_display_y = 5;
gotoxy(4, current_display_y);
set_color(light_cyan);
cout << "你当前装备的武器:";
current_display_y = print_weapon_details(all_weapons[have_sword], current_display_y + 1); // Get next Y
current_display_y++; // Add a small gap
gotoxy(4, current_display_y);
set_color(light_cyan);
cout << "你发现的新武器:";
current_display_y = print_weapon_details(new_weapon_instance, current_display_y + 1); // Get next Y
current_display_y++; // Add a small gap
set_color(white);
gotoxy(4, current_display_y++);
cout << "请选择: [1] 装备新武器 (旧武器回收 " << all_weapons[have_sword].cost / 2 << " G)";
gotoxy(4, current_display_y++);
cout << " [2] 回收新武器 (新武器回收 " << new_weapon_instance.cost / 2 << " G)";
gotoxy(4, current_display_y++);
cout << "你的选择: ";
bool choice_made = false;
while (!choice_made) {
if (zxb('1')) {
gold += all_weapons[have_sword].cost / 2; // 回收旧武器
all_weapons[have_sword] = new_weapon_instance; // 替换当前武器
add_message("你装备了 " + new_weapon_instance.name + "!旧武器已回收。");
choice_made=true;
while(zxb('1')); // Debounce
} else if (zxb('2')) {
gold += new_weapon_instance.cost / 2; // 回收新武器
add_message("你回收了 " + new_weapon_instance.name + ",获得 " + to_string(new_weapon_instance.cost / 2) + " 金币。");
choice_made=true;
while(zxb('2')); // Debounce
}
this_thread::sleep_for(chrono::milliseconds(50));
}
system("cls"); // 清屏以显示主界面
refresh_ui(); // 刷新UI以显示新武器和更新的属性
gotoxy(y_pos << 1, x_pos); // 重新绘制玩家角色在地图上
set_color(bright_white);
cout << "入";
} else { // 获得护甲
int armor_template_idx = rand() % (max_armor_template_idx + 1);
Armor new_armor_instance = global_armor_templates[armor_template_idx];
new_armor_instance.level = rand() % 2; // 宝箱护甲可能是Lv0或Lv1
// 对于固定词条的护甲,不重新生成词条
if (!(new_armor_instance.name == "神圣之盾" || new_armor_instance.name == "混沌胸甲")) {
new_armor_instance.affixes.clear();
for (int i = 0; i < new_armor_instance.get_current_affix_slots(); ++i) {
vector<Affix> pool;
for (const auto& affix_template : all_affixes) {
// 护甲词条:只选择护甲词条,且级别不超过护甲等级+1
if (affix_template.tier <= new_armor_instance.level + 1 &&
is_armor_affix_type(affix_template)) {
pool.push_back(affix_template);
}
}
if (!pool.empty()) {
new_armor_instance.affixes.push_back(pool[rand() % pool.size()]);
}
}
}
system("cls");
gotoxy(25, 2); set_color(light_yellow); cout << "--- 发现新护甲! ---";
int current_display_y = 5;
gotoxy(4, current_display_y); set_color(light_cyan); cout << "你当前装备的护甲:";
current_display_y = print_armor_details(all_armors[have_armor], current_display_y + 1);
current_display_y++;
gotoxy(4, current_display_y); set_color(light_cyan); cout << "你发现的新护甲:";
current_display_y = print_armor_details(new_armor_instance, current_display_y + 1);
current_display_y++;
set_color(white);
gotoxy(4, current_display_y++);
cout << "请选择: [1] 装备新护甲 (旧护甲回收 " << all_armors[have_armor].cost / 2 << " G)";
gotoxy(4, current_display_y++);
cout << " [2] 回收新护甲 (新护甲回收 " << new_armor_instance.cost / 2 << " G)";
gotoxy(4, current_display_y++);
cout << "你的选择: ";
bool choice_made = false;
while (!choice_made) {
if (zxb('1')) {
gold += all_armors[have_armor].cost / 2; // 回收旧护甲
all_armors[have_armor] = new_armor_instance; // 替换当前护甲
// 重要:装备新护甲后,更新当前生命值,确保不超过新的最大生命值上限
current_hp = min(current_hp, get_total_max_hp());
add_message("你装备了 " + new_armor_instance.name + "!旧护甲已回收。");
choice_made=true; while(zxb('1'));
} else if (zxb('2')) {
gold += new_armor_instance.cost / 2; // 回收新护甲
add_message("你回收了 " + new_armor_instance.name + ",获得 " + to_string(new_armor_instance.cost / 2) + " 金币。");
choice_made=true; while(zxb('2'));
}
this_thread::sleep_for(chrono::milliseconds(50));
}
system("cls"); refresh_ui(); gotoxy(y_pos << 1, x_pos); set_color(bright_white); cout << "入";
}
} else { // 35% 几率获得一次性物品
// --- 修改:随机获得一种一次性物品 ---
int item_type = rand() % 10; // 0-9
if (item_type < 4) { // 40% 概率
inventory["生命药水"]++;
add_message("你从宝箱里找到了一瓶生命药水!");
} else if (item_type < 6) { // 20% 概率
inventory["力量药水"]++;
add_message("你找到一瓶蕴含力量的药剂!");
} else if (item_type < 8) { // 20% 概率
inventory["坚韧药水"]++;
add_message("你找到一瓶能强化体魄的药剂!");
} else if (item_type == 8) { // 10% 概率
inventory["火焰炸弹"]++;
add_message("你发现了一个不稳定的火焰炸弹!");
} else { // 10% 概率,原本是麻痹卷轴
// --- 修改:检查麻痹卷轴的持有量 ---
if (inventory["麻痹卷轴"] >= 1) {
// 如果已经有了,给一个替代奖励,比如金币
int amount = rand() % 50 + 20; // 给一笔不错的金币
gold += amount;
add_message("你本该找到一张卷轴,但它化作了 " + to_string(amount) + " 金币!");
} else {
// 如果没有,正常获得
inventory["麻痹卷轴"]++;
add_message("你发现了一张古老的麻痹卷轴!");
}
}
}
}
// 检查是否升级
void check_level_up() {
while (experience >= XP_REQUIRED[level] && level < MAX_LEVEL) { // 使用 MAX_LEVEL
experience -= XP_REQUIRED[level];
level++;
add_message(">>>>> 等级提升!你现在是 " + to_string(level) + " 级!<<<<<");
add_message("生命、攻击和防御都提升了!");
current_hp = get_total_max_hp(); // 升级时生命值回满,并考虑护甲生命词条
if (skill_cooldown > 0) skill_cooldown = max(0, skill_cooldown - 1); // 升级可以减少技能冷却
}
}
// 绘制战斗界面
// --- 妙具系统: 更新战斗界面函数签名 ---
void draw_battle_screen(const Monster& monster, int monster_current_hp, const vector<string>& battle_log,
bool player_poisoned, int player_poison_duration, bool monster_stunned,
bool monster_poisoned_status, int monster_poison_duration_status,
bool monster_crippled_status, int monster_cripple_duration_status,
const string& player_buff_name, int player_buff_duration,
const string& monster_debuff_name, int monster_debuff_duration,
int player_shield_hp)
{
system("cls");
set_color(light_yellow);
gotoxy(30, 1);
cout << "--- 战 斗 中 ---";
set_color(white);
gotoxy(5, 4);
cout << "你 (等级 " << level << ")";
// --- 新增:显示药水Buff状态 ---
if (power_potion_active) {
set_color(light_red);
cout << " [力量!]";
}
if (defense_potion_active) {
set_color(light_cyan);
cout << " [坚韧!]";
}
// --- 妙具系统: 显示玩家Buff和护盾 ---
if (player_buff_name != "" && player_buff_duration > 0) {
set_color(light_yellow);
cout << " [" << player_buff_name << ":" << player_buff_duration << "]";
}
if (player_shield_hp > 0) {
set_color(cyan);
cout << " [护盾:" << player_shield_hp << "]";
}
gotoxy(5, 5);
set_color(light_green);
cout << "生命: " << current_hp << " / " << get_total_max_hp(); // 使用get_total_max_hp
if (player_poisoned && player_poison_duration > 0) {
set_color(light_magenta);
cout << " (中毒: " << player_poison_duration << " 回合)";
}
gotoxy(5, 6);
set_color(light_red);
cout << "攻击: " << get_total_attack();
gotoxy(5, 7);
set_color(cyan);
cout << "防御: " << get_total_defense();
set_color(white);
gotoxy(60, 4);
cout << monster.name;
if (monster_stunned) {
set_color(light_yellow);
cout << " (眩晕)";
}
if (monster_poisoned_status && monster_poison_duration_status > 0) { // NEW
set_color(light_magenta);
cout << " (中毒: " << monster_poison_duration_status << " 回合)";
}
if (monster_crippled_status && monster_cripple_duration_status > 0) { // NEW
set_color(light_blue);
cout << " (攻击降低: " << monster_cripple_duration_status << " 回合)";
}
// --- 妙具系统: 显示怪物Debuff ---
if (monster_debuff_name != "" && monster_debuff_duration > 0) {
set_color(gray);
cout << " (" << monster_debuff_name << ":" << monster_debuff_duration << ")";
}
set_color(white); // Reset color
gotoxy(60, 5);
set_color(light_green);
cout << "生命: " << monster_current_hp << " / " << monster.max_hp;
gotoxy(60, 6);
set_color(light_red);
cout << "攻击: " << monster.attack;
gotoxy(60, 7);
set_color(cyan);
cout << "防御: " << monster.defense;
set_color(gray);
gotoxy(0, 10);
for (int i = 0; i < 80; ++i) cout << "-";
set_color(white);
gotoxy(5, 12);
cout << "你的回合, 请选择行动:";
// --- 修改:增加新物品的使用选项 ---
gotoxy(5, 14);
cout << "[1] 普通攻击";
gotoxy(5, 15);
cout << "[2] " << class_definitions[player_class].skill_name;
if (skill_cooldown == 0) {
set_color(light_green);
cout << " [准备就绪]";
} else {
set_color(gray);
cout << " [冷却中: " << skill_cooldown << "]";
}
set_color(white);
gotoxy(5, 16);
cout << "[3] 使用生命药水 (" << inventory["生命药水"] << " 瓶)";
gotoxy(5, 17);
cout << "[4] 使用力量药水 (" << inventory["力量药水"] << " 瓶)";
gotoxy(5, 18);
cout << "[5] 使用坚韧药水 (" << inventory["坚韧药水"] << " 瓶)";
gotoxy(5, 19);
cout << "[6] 使用火焰炸弹 (" << inventory["火焰炸弹"] << " 个)";
gotoxy(5, 20);
cout << "[7] 使用麻痹卷轴 (" << inventory["麻痹卷轴"] << " 张)";
gotoxy(5, 21);
cout << "[8] 使用烟雾弹 (" << inventory["烟雾弹"] << " 个)";
// --- 妙具系统: 添加妙具使用选项 ---
gotoxy(5, 22);
if (current_gadget_id != -1 && gadget_current_uses > 0) {
Gadget current_gadget;
for(const auto& g : all_gadgets) { if (g.id == current_gadget_id) { current_gadget = g; break; } }
set_color(white);
cout << "[G] 使用妙具: " << current_gadget.name;
set_color(light_green);
cout << " [" << gadget_current_uses << "次可用]";
} else {
set_color(gray);
cout << "[G] 使用妙具 [无可用]";
}
set_color(white);
set_color(light_yellow);
gotoxy(40, 12);
cout << "--- 战斗日志 ---";
set_color(white);
for (int i = 0; i < battle_log.size(); ++i) {
gotoxy(40, 14 + i);
cout << battle_log[i];
}
}
// --- 新增:执行一次普通攻击的辅助函数 ---
// --- 妙具系统: 更新函数签名 ---
void perform_basic_attack(int& monster_current_hp, const Monster& monster_template, vector<string>& battle_log, bool& monster_stunned_ref,
bool& monster_poisoned_status_ref, int& monster_poison_duration_status_ref, int& monster_poison_damage_per_turn_status_ref,
bool& monster_crippled_status_ref, int& monster_cripple_duration_status_ref, int& monster_cripple_attack_reduction_ref,
float player_attack_multiplier, float monster_stat_multiplier)
{
int base_damage = get_total_attack();
// --- 妙具系统: 应用玩家攻击增益 ---
base_damage = static_cast<int>(base_damage * player_attack_multiplier);
// 应用力量药水效果
if (power_potion_active) {
base_damage = static_cast<int>(base_damage * 1.5);
}
// --- 妙具系统: 应用怪物防御减益 ---
int monster_effective_defense = static_cast<int>(monster_template.defense * monster_stat_multiplier);
int crit_affix_count = 0;
int lifesteal_affix_count = 0;
int armor_pierce_affix_count = 0;
int stun_affix_count = 0;
int poison_blade_affix_count = 0;
int cripple_strike_affix_count = 0;
for (const auto& affix : all_weapons[have_sword].affixes) {
if (affix.name == "暴击+") crit_affix_count++;
else if (affix.name == "吸血") lifesteal_affix_count++;
else if (affix.name == "穿甲") armor_pierce_affix_count++;
else if (affix.name == "破碎一击") stun_affix_count++;
else if (affix.name == "剧毒之刃") poison_blade_affix_count++;
else if (affix.name == "致残打击") cripple_strike_affix_count++;
}
// 应用穿甲
if (armor_pierce_affix_count > 0) {
monster_effective_defense = max(0, monster_effective_defense - (armor_pierce_affix_count * 5));
battle_log.push_back("你的武器穿透了敌人的防御 (" + to_string(armor_pierce_affix_count * 5) + ")!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
int player_damage = max(1, base_damage - monster_effective_defense);
// 应用暴击
double crit_multiplier = 2.0;
// 应用致命专注(ID:6)效果
if(current_star_power_id == 6) crit_multiplier = 2.5;
if (crit_affix_count > 0 && (rand() % 100 < crit_affix_count * 10)) {
player_damage = static_cast<int>(player_damage * crit_multiplier);
battle_log.push_back("你的武器触发了致命一击!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
monster_current_hp -= player_damage;
battle_log.push_back("你对 " + monster_template.name + " 造成 " + to_string(player_damage) + " 点伤害!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
// 应用吸血
if (lifesteal_affix_count > 0) {
int heal_amount = max(1, static_cast<int>(player_damage * (lifesteal_affix_count * 0.10f)));
current_hp = min(get_total_max_hp(), current_hp + heal_amount);
battle_log.push_back("你通过吸血恢复了 " + to_string(heal_amount) + " 点生命!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
// 应用破碎一击(眩晕)效果
if (stun_affix_count > 0) {
int total_stun_chance = min(85, stun_affix_count * 15);
if (rand() % 100 < total_stun_chance) {
monster_stunned_ref = true;
battle_log.push_back(monster_template.name + " 被破碎一击击晕了!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
}
// 应用剧毒之刃效果 (MODIFIED)
if (poison_blade_affix_count > 0) {
int total_poison_chance = min(100, poison_blade_affix_count * 25);
if (rand() % 100 < total_poison_chance) {
// 判定成功
if (!monster_poisoned_status_ref) {
// 首次施加
monster_poisoned_status_ref = true;
// 伤害仅在首次施加时计算
monster_poison_damage_per_turn_status_ref = max(1, (int)(base_damage * 0.20));
battle_log.push_back(monster_template.name + " 中毒了!");
} else {
// 刷新效果
battle_log.push_back(monster_template.name + " 的中毒效果被刷新了!");
}
// 无论首次还是刷新,都更新持续时间为最大值
monster_poison_duration_status_ref = max(monster_poison_duration_status_ref, 3);
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
}
// 应用致残打击效果 (MODIFIED)
if (cripple_strike_affix_count > 0) {
int total_cripple_chance = min(100, cripple_strike_affix_count * 20);
if (rand() % 100 < total_cripple_chance) {
// 判定成功
if (!monster_crippled_status_ref) {
// 首次施加
monster_crippled_status_ref = true;
// 攻击力削减值仅在首次施加时计算
monster_cripple_attack_reduction_ref = max(1, (int)(monster_template.attack * 0.20));
battle_log.push_back(monster_template.name + " 被致残,攻击力降低了!");
} else {
// 刷新效果
battle_log.push_back(monster_template.name + " 的致残效果被刷新了!");
}
// 无论首次还是刷新,都更新持续时间为最大值
monster_cripple_duration_status_ref = max(monster_cripple_duration_status_ref, 2);
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
}
}
// --- 新增:执行一次技能攻击的辅助函数 ---
// --- 妙具系统: 更新函数签名 ---
void perform_skill_attack(int& monster_current_hp, const Monster& monster_template, vector<string>& battle_log, bool& monster_stunned_ref,
float player_attack_multiplier, float monster_stat_multiplier)
{
float multiplier = 1.0f;
int effective_attack = get_total_attack();
// --- 妙具系统: 应用玩家攻击增益 ---
effective_attack = static_cast<int>(effective_attack * player_attack_multiplier);
// 应用力量药水效果
if (power_potion_active) {
effective_attack = static_cast<int>(effective_attack * 1.5);
}
// --- 妙具系统: 应用怪物防御减益 ---
int monster_effective_defense = static_cast<int>(monster_template.defense * monster_stat_multiplier);
int player_damage = 0;
if (player_class == 1) { // 战士:强力一击
multiplier = 1.8f;
player_damage = max(1, static_cast<int>(effective_attack * multiplier) - monster_effective_defense);
monster_current_hp -= player_damage;
battle_log.push_back("你使用了强力一击,造成 " + to_string(player_damage) + " 点暴击伤害!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
} else if (player_class == 2) { // 游侠:精准射击
multiplier = 1.2f;
player_damage = max(1, static_cast<int>(effective_attack * multiplier) - monster_effective_defense);
monster_current_hp -= player_damage;
battle_log.push_back("你施展了精准射击,造成 " + to_string(player_damage) + " 点伤害!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
if (rand() % 100 < 50) { // 50% 几率眩晕
monster_stunned_ref = true;
battle_log.push_back(monster_template.name + " 被你精准的箭矢震慑住了,无法行动!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
} else if (player_class == 3) { // 法师:火球术
multiplier = 6.5f;
player_damage = max(1, static_cast<int>(effective_attack * multiplier) - monster_effective_defense);
monster_current_hp -= player_damage;
battle_log.push_back("你施放了火球术,对 " + monster_template.name + " 造成 " + to_string(player_damage) + " 点魔法伤害!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
}
// 战斗系统
void start_battle(Monster monster_template) {
int monster_current_hp = monster_template.max_hp;
vector<string> battle_log;
bool player_poisoned = false;
int poison_duration = 0;
int poison_damage_per_turn = 0;
bool monster_stunned = false;
bool monster_poisoned_status = false;
int monster_poison_duration_status = 0;
int monster_poison_damage_per_turn_status = 0;
bool monster_crippled_status = false;
int monster_cripple_duration_status = 0;
int monster_cripple_attack_reduction = 0;
string player_buff_name = "";
int player_buff_duration = 0;
float player_attack_multiplier = 1.0f;
string monster_debuff_name = "";
int monster_debuff_duration = 0;
float monster_stat_multiplier = 1.0f;
int player_shield_hp = 0;
// --- 新增:为 mwh 技能服务的战斗内状态 ---
bool player_gets_extra_turn = false; // 用于处理 mwh 的额外回合
int mwh_battle_bonus_atk = 0; // mwh 在本场战斗中窃取到的攻击力
int mwh_battle_bonus_def = 0; // mwh 在本场战斗中窃取到的防御力
battle_log.push_back("你遭遇了 " + monster_template.name + "!");
while (current_hp > 0 && monster_current_hp > 0) {
// --- 回合开始时的状态处理 ---
player_gets_extra_turn = false; // 每回合开始时重置额外回合标记
if (player_buff_duration > 0) {
player_buff_duration--;
if (player_buff_duration == 0) {
battle_log.push_back("你的 [" + player_buff_name + "] 效果结束了!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
player_buff_name = "";
player_attack_multiplier = 1.0f;
}
}
if (monster_debuff_duration > 0) {
monster_debuff_duration--;
if (monster_debuff_duration == 0) {
battle_log.push_back(monster_template.name + " 的 [" + monster_debuff_name + "] 效果结束了!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
monster_debuff_name = "";
monster_stat_multiplier = 1.0f;
}
}
if (current_star_power_id == 2) {
int heal_amount = max(1, static_cast<int>(get_total_max_hp() * 0.15));
current_hp = min(get_total_max_hp(), current_hp + heal_amount);
battle_log.push_back("生命源泉为你回复了 " + to_string(heal_amount) + " 点生命!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
int player_regeneration_affix_count = 0;
for (const auto& affix : all_armors[have_armor].affixes) {
if (affix.name == "再生") player_regeneration_affix_count++;
}
if (player_regeneration_affix_count > 0) {
int heal_amount = player_regeneration_affix_count * 5;
current_hp = min(get_total_max_hp(), current_hp + heal_amount);
battle_log.push_back("你的再生护甲为你回复了 " + to_string(heal_amount) + " 点生命!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
if (player_poisoned && poison_duration > 0) {
int effective_poison_damage = poison_damage_per_turn;
int player_poison_resist_affix_count = 0;
for (const auto& affix : all_armors[have_armor].affixes) {
if (affix.name == "毒抗") player_poison_resist_affix_count++;
}
if (player_poison_resist_affix_count > 0) {
int reduction_percentage = player_poison_resist_affix_count * 25;
effective_poison_damage = max(0, effective_poison_damage * (100 - reduction_percentage) / 100);
}
if (effective_poison_damage > 0) {
current_hp = max(0, current_hp - effective_poison_damage);
battle_log.push_back("你因中毒受到 " + to_string(effective_poison_damage) + " 点伤害! (" + to_string(poison_duration) + " 回合剩余)");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
} else {
battle_log.push_back("你的毒抗使你免受中毒伤害!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
poison_duration--;
if (current_hp <= 0) break;
}
if (player_poisoned && poison_duration == 0) {
player_poisoned = false;
battle_log.push_back("你解除了中毒状态!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
if (monster_poisoned_status && monster_poison_duration_status > 0) {
monster_current_hp = max(0, monster_current_hp - monster_poison_damage_per_turn_status);
battle_log.push_back(monster_template.name + " 因中毒受到 " + to_string(monster_poison_damage_per_turn_status) + " 点伤害!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
monster_poison_duration_status--;
if (monster_poison_duration_status == 0) {
monster_poisoned_status = false;
battle_log.push_back(monster_template.name + " 解除了中毒状态!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
if (monster_current_hp <= 0) break;
}
if (monster_crippled_status && monster_cripple_duration_status > 0) {
monster_cripple_duration_status--;
if (monster_cripple_duration_status == 0) {
monster_crippled_status = false;
battle_log.push_back(monster_template.name + " 解除了攻击降低状态!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
}
draw_battle_screen(monster_template, monster_current_hp, battle_log, player_poisoned, poison_duration, monster_stunned,
monster_poisoned_status, monster_poison_duration_status, monster_crippled_status, monster_cripple_duration_status,
player_buff_name, player_buff_duration, monster_debuff_name, monster_debuff_duration, player_shield_hp);
bool turn_ended = false;
while (true) {
if (zxb('1')) {
auto perform_mwh_basic_attack = [&]() {
int base_damage = get_total_attack(mwh_battle_bonus_atk);
base_damage = static_cast<int>(base_damage * player_attack_multiplier);
if (power_potion_active) base_damage = static_cast<int>(base_damage * 1.5);
int monster_effective_defense = static_cast<int>(monster_template.defense * monster_stat_multiplier);
int player_damage = max(1, base_damage - monster_effective_defense);
monster_current_hp -= player_damage;
battle_log.push_back("你对 " + monster_template.name + " 造成 " + to_string(player_damage) + " 点伤害!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
};
if (player_class == 4) {
perform_mwh_basic_attack();
} else {
perform_basic_attack(monster_current_hp, monster_template, battle_log, monster_stunned,
monster_poisoned_status, monster_poison_duration_status, monster_poison_damage_per_turn_status,
monster_crippled_status, monster_cripple_duration_status, monster_cripple_attack_reduction,
player_attack_multiplier, monster_stat_multiplier);
}
if (current_star_power_id == 4 && monster_current_hp > 0 && (rand() % 100 < 20)) {
battle_log.push_back("怒意连击触发,你再次发动攻击!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
draw_battle_screen(monster_template, monster_current_hp, battle_log, player_poisoned, poison_duration, monster_stunned,
monster_poisoned_status, monster_poison_duration_status, monster_crippled_status, monster_cripple_duration_status,
player_buff_name, player_buff_duration, monster_debuff_name, monster_debuff_duration, player_shield_hp);
this_thread::sleep_for(chrono::milliseconds(800));
if (player_class == 4) perform_mwh_basic_attack();
else perform_basic_attack(monster_current_hp, monster_template, battle_log, monster_stunned,
monster_poisoned_status, monster_poison_duration_status, monster_poison_damage_per_turn_status,
monster_crippled_status, monster_cripple_duration_status, monster_cripple_attack_reduction,
player_attack_multiplier, monster_stat_multiplier);
}
turn_ended = true;
while(zxb('1'));
break;
}
if (zxb('2')) {
if (skill_cooldown > 0) {
battle_log.push_back("技能还在冷却中!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
while(zxb('2'));
} else {
if (player_class == 4) {
battle_log.push_back("你使用了 [次元断裂]!时空开始扭曲!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
bool is_boss = monster_template.type >= BOSS_GOBLIN_KING;
int hits = 3;
for (int i=0; i < hits && monster_current_hp > 0; ++i) {
if (!is_boss && (rand() % 100 < 50)) {
monster_current_hp = 0;
battle_log.push_back("次元裂缝直接吞噬了 " + monster_template.name + "!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
break;
} else {
int damage = max(1, get_total_attack(mwh_battle_bonus_atk) - monster_template.defense);
monster_current_hp -= damage;
battle_log.push_back("第 "+to_string(i+1)+"击 造成 " + to_string(damage) + " 点伤害!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
if (is_boss) {
int atk_steal = max(1, static_cast<int>(monster_template.attack * 0.1));
int def_steal = max(1, static_cast<int>(monster_template.defense * 0.1));
mwh_battle_bonus_atk += atk_steal;
mwh_battle_bonus_def += def_steal;
battle_log.push_back("你窃取了Boss " + to_string(atk_steal) + "攻击和" + to_string(def_steal) + "防御!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
}
draw_battle_screen(monster_template, monster_current_hp, battle_log, player_poisoned, poison_duration, monster_stunned, monster_poisoned_status, monster_poison_duration_status, monster_crippled_status, monster_cripple_duration_status, player_buff_name, player_buff_duration, monster_debuff_name, monster_debuff_duration, player_shield_hp);
this_thread::sleep_for(chrono::milliseconds(300));
}
battle_log.push_back("时空扭曲,你获得了额外一次行动机会!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
player_gets_extra_turn = true;
} else {
perform_skill_attack(monster_current_hp, monster_template, battle_log, monster_stunned, player_attack_multiplier, monster_stat_multiplier);
if (current_star_power_id == 5 && monster_current_hp > 0 && (rand() % 100 < 15)) {
battle_log.push_back("奥术回响触发,你再次施放技能!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
// ---- THIS IS THE CORRECTED LINE ----
draw_battle_screen(monster_template, monster_current_hp, battle_log, player_poisoned, poison_duration, monster_stunned,
monster_poisoned_status, monster_poison_duration_status, monster_crippled_status, monster_cripple_duration_status,
player_buff_name, player_buff_duration, monster_debuff_name, monster_debuff_duration, player_shield_hp);
// ---- END OF CORRECTION ----
this_thread::sleep_for(chrono::milliseconds(800));
perform_skill_attack(monster_current_hp, monster_template, battle_log, monster_stunned, player_attack_multiplier, monster_stat_multiplier);
}
}
skill_cooldown = class_definitions[player_class].skill_cooldown_base;
turn_ended = true;
while(zxb('2'));
}
if (turn_ended) break;
}
if (zxb('3')) {
if (inventory["生命药水"] > 0) {
if (current_hp == get_total_max_hp()) {
battle_log.push_back("你的生命值已满!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
} else {
int heal_amount = get_total_max_hp() / 2;
current_hp = min(get_total_max_hp(), current_hp + heal_amount);
inventory["生命药水"]--;
battle_log.push_back("你使用了药水,恢复了 " + to_string(heal_amount) + " 点生命!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
turn_ended = true;
}
} else {
battle_log.push_back("你没有生命药水了!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
while(zxb('3'));
if (turn_ended) break;
}
if (zxb('4')) {
if (power_potion_active) {
battle_log.push_back("力量药水的效果已经激活了!");
} else if (inventory["力量药水"] > 0) {
inventory["力量药水"]--;
power_potion_active = true;
battle_log.push_back("你喝下了力量药水,感觉浑身充满力量!");
} else {
battle_log.push_back("你没有力量药水了!");
}
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
while(zxb('4'));
draw_battle_screen(monster_template, monster_current_hp, battle_log, player_poisoned, poison_duration, monster_stunned,
monster_poisoned_status, monster_poison_duration_status, monster_crippled_status, monster_cripple_duration_status,
player_buff_name, player_buff_duration, monster_debuff_name, monster_debuff_duration, player_shield_hp);
}
if (zxb('5')) {
if (defense_potion_active) {
battle_log.push_back("坚韧药水的效果已经激活了!");
} else if (inventory["坚韧药水"] > 0) {
inventory["坚韧药水"]--;
defense_potion_active = true;
battle_log.push_back("你喝下了坚韧药水,感觉皮肤像岩石一样坚硬!");
} else {
battle_log.push_back("你没有坚韧药水了!");
}
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
while(zxb('5'));
draw_battle_screen(monster_template, monster_current_hp, battle_log, player_poisoned, poison_duration, monster_stunned,
monster_poisoned_status, monster_poison_duration_status, monster_crippled_status, monster_cripple_duration_status,
player_buff_name, player_buff_duration, monster_debuff_name, monster_debuff_duration, player_shield_hp);
}
if (zxb('6')) {
if (inventory["火焰炸弹"] > 0) {
inventory["火焰炸弹"]--;
float percentage = 0.15f;
if (monster_template.type >= BOSS_GOBLIN_KING || monster_template.name.find("精英") != string::npos) {
percentage = 0.05f;
}
int bomb_damage = max(1, static_cast<int>(monster_template.max_hp * percentage));
monster_current_hp -= bomb_damage;
battle_log.push_back("你扔出火焰炸弹,造成 " + to_string(bomb_damage) + " 点火焰伤害!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
turn_ended = true;
} else {
battle_log.push_back("你没有火焰炸弹了!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
while(zxb('6'));
if(turn_ended) break;
}
if (zxb('7')) {
if (inventory["麻痹卷轴"] > 0) {
inventory["麻痹卷轴"]--;
monster_stunned = true;
battle_log.push_back("卷轴爆发出强光," + monster_template.name + " 被麻痹了!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
turn_ended = true;
} else {
battle_log.push_back("你没有麻痹卷轴了!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
while(zxb('7'));
if(turn_ended) break;
}
if (zxb('8')) {
if (monster_template.type >= BOSS_GOBLIN_KING) {
battle_log.push_back("在强大的领主面前,你无处可逃!");
} else if (inventory["烟雾弹"] > 0) {
inventory["烟雾弹"]--;
add_message("你扔下烟雾弹,成功逃离了战斗!");
power_potion_active = false;
defense_potion_active = false;
system("cls");
refresh_ui();
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
return;
} else {
battle_log.push_back("你没有烟雾弹了!");
}
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
while(zxb('8'));
draw_battle_screen(monster_template, monster_current_hp, battle_log, player_poisoned, poison_duration, monster_stunned,
monster_poisoned_status, monster_poison_duration_status, monster_crippled_status, monster_cripple_duration_status,
player_buff_name, player_buff_duration, monster_debuff_name, monster_debuff_duration, player_shield_hp);
}
if (zxb('G')) {
if (current_gadget_id != -1 && gadget_current_uses > 0) {
Gadget current_gadget;
for(const auto& g : all_gadgets) { if (g.id == current_gadget_id) { current_gadget = g; break; } }
battle_log.push_back("你使用了妙具 [" + current_gadget.name + "]!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
gadget_current_uses--;
switch(current_gadget_id) {
case 101: {
int heal_amount = static_cast<int>(get_total_max_hp() * 0.35);
current_hp = min(get_total_max_hp(), current_hp + heal_amount);
battle_log.push_back("图腾发出光芒,你恢复了 " + to_string(heal_amount) + " 点生命!");
break;
}
case 102: {
int damage = static_cast<int>(get_total_max_hp() * 0.40);
monster_current_hp -= damage;
battle_log.push_back("能量脉冲对敌人造成 " + to_string(damage) + " 点真实伤害!");
break;
}
case 103: {
monster_debuff_name = "弱化";
monster_debuff_duration = 3;
monster_stat_multiplier = 0.7f;
battle_log.push_back("敌人的攻防被射线大幅削弱了!");
break;
}
case 104: {
player_buff_name = "兴奋";
player_buff_duration = 3;
player_attack_multiplier = 1.5f;
battle_log.push_back("你注射了兴奋剂,攻击力大幅提升!");
break;
}
case 105: {
if (rand() % 100 < 75) {
add_message("你使用妙具成功逃离了战斗!");
power_potion_active = false;
defense_potion_active = false;
system("cls");
refresh_ui();
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
return;
} else {
battle_log.push_back("传送被干扰,失败了!");
}
break;
}
case 106: {
int shield_amount = static_cast<int>(get_total_max_hp() * 0.25);
player_shield_hp += shield_amount;
battle_log.push_back("你获得了 " + to_string(shield_amount) + " 点护盾!");
break;
}
}
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
turn_ended = true;
} else {
battle_log.push_back("你没有可用的妙具!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
while(zxb('G'));
if(turn_ended) break;
}
this_thread::sleep_for(chrono::milliseconds(10));
}
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
if (!turn_ended) continue;
draw_battle_screen(monster_template, monster_current_hp, battle_log, player_poisoned, poison_duration, monster_stunned,
monster_poisoned_status, monster_poison_duration_status, monster_crippled_status, monster_cripple_duration_status,
player_buff_name, player_buff_duration, monster_debuff_name, monster_debuff_duration, player_shield_hp);
this_thread::sleep_for(chrono::milliseconds(1000));
// --- 怪物回合 ---
if (monster_current_hp > 0) {
if (player_gets_extra_turn) {
battle_log.push_back("由于时空扭曲," + monster_template.name + " 无法行动!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
else if (monster_stunned) {
battle_log.push_back(monster_template.name + " 处于眩晕状态,无法行动!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
monster_stunned = false;
} else {
int player_effective_defense = get_total_defense(mwh_battle_bonus_def);
int monster_actual_attack = static_cast<int>(monster_template.attack * monster_stat_multiplier);
if (monster_crippled_status && monster_cripple_duration_status > 0) {
monster_actual_attack = max(1, monster_actual_attack - monster_cripple_attack_reduction);
}
int damage_taken = max(1, monster_actual_attack - player_effective_defense);
if (current_star_power_id == 1) {
damage_taken = max(1, static_cast<int>(damage_taken * 0.85));
battle_log.push_back("神盾庇护为你抵挡了部分伤害!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
if (defense_potion_active) {
damage_taken = max(1, damage_taken / 2);
battle_log.push_back("坚韧药水的效果为你抵挡了大量伤害!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
int resilience_affix_count = 0;
int reflection_affix_count = 0;
for (const auto& affix : all_armors[have_armor].affixes) {
if (affix.name == "韧性") resilience_affix_count++;
else if (affix.name == "反伤") reflection_affix_count++;
}
if (resilience_affix_count > 0) {
int total_resilience_chance = min(85, resilience_affix_count * 15);
if (rand() % 100 < total_resilience_chance) {
damage_taken /= 2;
battle_log.push_back("你的护甲触发了韧性,伤害减少了!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
}
if (player_shield_hp > 0) {
if (damage_taken >= player_shield_hp) {
damage_taken -= player_shield_hp;
battle_log.push_back("你的护盾吸收了 " + to_string(player_shield_hp) + " 点伤害并破碎了!");
player_shield_hp = 0;
} else {
player_shield_hp -= damage_taken;
battle_log.push_back("你的护盾吸收了 " + to_string(damage_taken) + " 点伤害!");
damage_taken = 0;
}
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
if(damage_taken > 0) {
current_hp -= damage_taken;
battle_log.push_back(monster_template.name + " 对你造成了 " + to_string(damage_taken) + " 点伤害!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
if (reflection_affix_count > 0 && damage_taken > 0) {
float total_reflection_rate = reflection_affix_count * 0.20f;
int reflected_damage = max(1, static_cast<int>(damage_taken * total_reflection_rate));
monster_current_hp -= reflected_damage;
battle_log.push_back("你的护甲反弹了 " + to_string(reflected_damage) + " 点伤害给 " + monster_template.name + "!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
if ((monster_template.type == SPIDER || monster_template.type >= BOSS_GOBLIN_KING) && rand() % 3 == 0) {
if (!player_poisoned) {
player_poisoned = true;
poison_duration = rand() % 3 + 2;
poison_damage_per_turn = max(1, monster_template.attack / 5);
battle_log.push_back(monster_template.name + " 的攻击附加了剧毒!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
}
if (monster_template.type == ZOMBIE && rand() % 4 == 0) {
battle_log.push_back(monster_template.name + " 腐蚀了你的盔甲,防御降低!(暂无效果)");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
if (monster_template.type == WIZARD_APPRENTICE && rand() % 3 == 0) {
int spell_damage = max(1, static_cast<int>(monster_template.attack * 1.5) - player_effective_defense);
current_hp -= spell_damage;
battle_log.push_back(monster_template.name + " 施放了法术暴击,造成 " + to_string(spell_damage) + " 点伤害!");
if (battle_log.size() >= 5) battle_log.erase(battle_log.begin());
}
}
draw_battle_screen(monster_template, monster_current_hp, battle_log, player_poisoned, poison_duration, monster_stunned,
monster_poisoned_status, monster_poison_duration_status, monster_crippled_status, monster_cripple_duration_status,
player_buff_name, player_buff_duration, monster_debuff_name, monster_debuff_duration, player_shield_hp);
this_thread::sleep_for(chrono::milliseconds(1000));
}
if (skill_cooldown > 0) {
skill_cooldown--;
}
}
power_potion_active = false;
defense_potion_active = false;
system("cls");
if (current_hp > 0) {
set_color(light_green);
gotoxy(30, 8);
cout << "你胜利了!";
add_message("你战胜了 " + monster_template.name + "!");
int xp_bonus_affix_count = 0;
int gold_bonus_affix_count = 0;
for (const auto& affix : all_weapons[have_sword].affixes) {
if (affix.name == "经验加成") xp_bonus_affix_count++;
else if (affix.name == "财富掠夺") gold_bonus_affix_count++;
}
int final_xp_reward = monster_template.xp_reward;
int final_gold_reward = monster_template.gold_reward;
if (xp_bonus_affix_count > 0) {
final_xp_reward = (int)(final_xp_reward * (1 + xp_bonus_affix_count * 0.15));
}
if (gold_bonus_affix_count > 0) {
final_gold_reward = (int)(final_gold_reward * (1 + gold_bonus_affix_count * 0.15));
}
experience += final_xp_reward;
gold += final_gold_reward;
add_message("==========");
add_message("获得 " + to_string(final_xp_reward) + " 经验和 " + to_string(final_gold_reward) + " 金币。");
add_message("==========");
check_level_up();
if (monster_template.type >= BOSS_GOBLIN_KING) {
if (is_in_endless_mode) {
endless_boss_defeated_this_floor = true;
add_message("守护者已被击败!通往下一层的道路开启了!");
} else {
boss_defeated[current_floor] = true;
add_message(monster_template.name + " 已被击败!");
if (current_floor == NUM_FLOORS && monster_template.type == BOSS_LORD_OF_CHAOS) {
on_final_boss_defeated();
} else if (current_floor == max_unlocked_floor && max_unlocked_floor < NUM_FLOORS) {
max_unlocked_floor++;
add_message("恭喜!新的地牢区域已解锁:第 " + to_string(max_unlocked_floor) + " 层!");
}
}
}
if (!is_in_endless_mode) {
current_maps[current_floor - 1][x_pos][y_pos] = '.';
}
} else {
game_over();
return;
}
set_color(gray);
gotoxy(28, 12);
cout << "按任意键返回地图...";
while(!_kbhit()) {
this_thread::sleep_for(chrono::milliseconds(50));
}
_getch();
system("cls");
refresh_ui();
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
}
// 重置游戏状态 (用于游戏结束重新开始)
void reset_game_state() {
game_phase = 1; // 游戏轮次重置为1
endless_max_floor = 1; // 重置无尽模式进度
is_in_endless_mode = false;
initialize_monster_templates(); // 根据新的 game_phase (1) 重新初始化怪物数据
reset_player_progression(); // 重置玩家所有进度和强化
reset_map_and_boss_status(); // 重置地图和Boss(用于新轮次或重开)
}
// 游戏结束
void game_over() {
set_color(light_red);
gotoxy(30, 8);
cout << "你被击败了...";
gotoxy(30, 10);
cout << "--- GAME OVER ---";
gotoxy(0, 20);
set_color(white);
cout << "你最终到达了第 " << game_phase << " 轮挑战。最高纪录:" << best_phase << " 轮。" << endl;
cout << "无尽模式最高层数: " << endless_max_floor << " 层。" << endl;
cout << "按 'R' 重新开始,按 'Esc' 退出游戏。";
while (true) {
if (zxb('R')) { // Using VK_R
best_phase = max(best_phase, game_phase); // 记录最高(如果当前轮次是新的最高)
reset_game_state(); // 重新开始游戏状态
choose_class(); // 重新选择职业 (这将重置 class_definitions 和相关属性)
current_hp = get_total_max_hp(); // 重新设置生命值
system("cls");
refresh_ui(); // 调用新的刷新函数
x_pos = floor_entrance_coords[current_floor].first;
y_pos = floor_entrance_coords[current_floor].second;
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
while(zxb('R')); // Debounce
return;
}
if (zxb(VK_ESCAPE)) {
exit(0);
}
this_thread::sleep_for(chrono::milliseconds(50));
}
}
// 更新游戏状态 (移动后触发的事件)
void update_game_state() {
if (is_in_endless_mode) {
char current_tile = endless_map[x_pos][y_pos];
if (current_tile == 'R') { // 回归门
add_message("你离开了无尽模式。");
is_in_endless_mode = false;
// 恢复位置
current_floor = stored_normal_floor;
x_pos = stored_normal_x;
y_pos = stored_normal_y;
system("cls");
refresh_ui();
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
} else if (current_tile == 'U') { // 下一层
if (endless_boss_defeated_this_floor) {
add_message("你前往了更深的一层!");
endless_current_floor++;
if (endless_current_floor > endless_max_floor) {
endless_max_floor = endless_current_floor;
}
// --- 妙具系统: 进入下一层时重置次数 ---
if (current_gadget_id != -1) {
for (const auto& g : all_gadgets) {
if (g.id == current_gadget_id) {
gadget_current_uses = g.max_uses;
add_message("你的妙具 [" + g.name + "] 使用次数已重置!");
break;
}
}
}
generate_endless_map(endless_current_floor);
system("cls");
refresh_ui();
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
} else {
add_message("必须击败本层守护者才能前进!");
// 将玩家弹回一格,防止卡住
x_pos = x_pos_last;
y_pos = y_pos_last;
}
} else if (current_tile == 'm' || current_tile == 'G' || current_tile == 'E' || current_tile == 'B') {
Monster m = get_endless_monster(endless_current_floor, current_tile);
start_battle(m);
if (current_hp > 0) { // 如果战斗胜利
endless_map[x_pos][y_pos] = '.';
}
} else if (current_tile == 'T') {
open_treasure_chest();
endless_map[x_pos][y_pos] = '.';
} else if (current_tile == 'H') {
add_message("你捡起一瓶生命药水!");
inventory["生命药水"]++;
endless_map[x_pos][y_pos] = '.';
}
} else {
// --- 原有的 update_game_state 逻辑 ---
char current_tile = current_maps[current_floor - 1][x_pos][y_pos];
if (current_tile == 'H') {
add_message("你捡起一瓶生命药水!");
inventory["生命药水"]++;
current_maps[current_floor - 1][x_pos][y_pos] = '.';
} else if (current_tile == 'T') {
open_treasure_chest();
current_maps[current_floor - 1][x_pos][y_pos] = '.';
} else if (current_tile == 'D') {
enter_portal();
} else if (current_tile == 'S') {
enter_shop();
system("cls");
refresh_ui();
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
} else if (current_tile == 'F') {
enter_forging_hut();
system("cls");
refresh_ui();
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
}
else if (current_tile == 'm') {
Monster m = get_random_monster_for_floor(current_floor, false);
start_battle(m);
} else if (current_tile == 'G') {
Monster m = get_random_monster_for_floor(current_floor, true);
start_battle(m);
} else if (current_tile == 'B') {
Monster m;
if (current_floor == 1) m = get_monster_template(BOSS_GOBLIN_KING);
else if (current_floor == 2) m = get_monster_template(BOSS_MINOTAUR);
else if (current_floor == 3) m = get_monster_template(BOSS_NECROMANCER);
else if (current_floor == 4) m = get_monster_template(BOSS_DRAGON_SPAWN);
else if (current_floor == 5) m = get_monster_template(BOSS_FINAL);
else if (current_floor == 6) m = get_monster_template(BOSS_LORD_OF_CHAOS);
else m = get_monster_template(BOSS_GOBLIN_KING); // Fallback
if (boss_defeated[current_floor]) {
add_message("这片区域的领主已被你击败,没有敌人了。");
current_maps[current_floor - 1][x_pos][y_pos] = '.';
} else {
start_battle(m);
}
}
}
}
// 商店界面
void enter_shop() {
system("cls");
gotoxy(30, 1);
set_color(bright_white);
cout << "-----[商店]-----";
int weapon_display_limit = min((int)global_weapon_templates.size(), current_floor + game_phase + 2);
weapon_display_limit = max(1, weapon_display_limit);
int armor_display_limit = min((int)global_armor_templates.size(), current_floor + game_phase + 2);
armor_display_limit = max(1, armor_display_limit);
auto display_shop_items = [&]() {
// Clear a fixed large area for the shop items to prevent redraw issues
clear_area(0, 2, 79, MAP_ROWS + 20);
set_color(white);
gotoxy(4, 2);
cout << "武器 (拥有: " << all_weapons[have_sword].name << " Lv." << all_weapons[have_sword].level << ")";
for (int i = 0; i < weapon_display_limit; ++i) {
gotoxy(4, 3 + i);
Weapon shop_weapon_template = global_weapon_templates[i];
cout << (char)('0' + i) << " " << shop_weapon_template.name << " 伤害:" << shop_weapon_template.get_current_damage() << " 金币:" << shop_weapon_template.cost;
if (all_weapons[have_sword].name == shop_weapon_template.name) {
set_color(gray);
cout << " (已装备)";
set_color(white);
}
}
int weapon_list_end_y = 3 + weapon_display_limit;
gotoxy(4, weapon_list_end_y + 2);
cout << "护甲 (拥有: " << all_armors[have_armor].name << " Lv." << all_armors[have_armor].level << ")";
for (int i = 0; i < armor_display_limit; ++i) {
gotoxy(4, weapon_list_end_y + 3 + i);
Armor shop_armor_template = global_armor_templates[i];
cout << static_cast<char>('A' + i) << " " << shop_armor_template.name << " 防御:" << shop_armor_template.get_current_defense() << " 金币:" << shop_armor_template.cost;
if (all_armors[have_armor].name == shop_armor_template.name) {
set_color(gray);
cout << " (已装备)";
set_color(white);
}
}
int armor_list_end_y = weapon_list_end_y + 3 + armor_display_limit;
// --- 修改:增加更多物品的显示 ---
clear_area(4, armor_list_end_y + 2, 79, armor_list_end_y + 10); // 清理更大的区域
gotoxy(4, armor_list_end_y + 2);
cout << "[P] 生命药水 金币:15 (拥有: " << inventory["生命药水"] << " 瓶)";
gotoxy(4, armor_list_end_y + 3);
cout << "[O] 力量药水 金币:50 (拥有: " << inventory["力量药水"] << " 瓶)";
gotoxy(4, armor_list_end_y + 4);
cout << "[M] 坚韧药水 金币:50 (拥有: " << inventory["坚韧药水"] << " 瓶)";
gotoxy(4, armor_list_end_y + 5);
// --- 修改:更新火焰炸弹描述 ---
cout << "[R] 火焰炸弹 金币:30 (拥有: " << inventory["火焰炸弹"] << " 个) - 造成敌人最大生命值百分比伤害";
gotoxy(4, armor_list_end_y + 6);
cout << "[K] 麻痹卷轴 金币:70 (拥有: " << inventory["麻痹卷轴"] << " 张) - 使敌人眩晕";
gotoxy(4, armor_list_end_y + 7);
cout << "[L] 烟雾弹 金币:40 (拥有: " << inventory["烟雾弹"] << " 个) - 逃离战斗";
gotoxy(4, armor_list_end_y + 9);
set_color(light_yellow);
cout << "你现在有 " << gold << " 金币。";
gotoxy(4, armor_list_end_y + 11);
set_color(white);
cout << "按[Q]退出";
};
display_shop_items();
add_message("欢迎来到商店!");
while (true) {
char selected_char = 0;
for (int i = 0; i < 10; ++i) {
if (zxb('0' + i)) {
selected_char = '0' + i;
while(zxb(selected_char));
break;
}
}
if (selected_char == 0) {
for (char c = 'A'; c <= 'Z'; ++c) {
if (zxb(c)) {
selected_char = c;
while(zxb(selected_char));
break;
}
}
}
if (selected_char != 0) {
string item_name_to_confirm = "";
int item_cost_to_confirm = 0;
bool is_valid_selection = false;
bool is_weapon_purchase = false;
bool is_armor_purchase = false;
if (selected_char >= '0' && selected_char <= '9') {
int idx = selected_char - '0';
if (idx >= 0 && idx < weapon_display_limit) {
item_name_to_confirm = global_weapon_templates[idx].name;
item_cost_to_confirm = global_weapon_templates[idx].cost;
is_valid_selection = true;
is_weapon_purchase = true;
}
} else if (selected_char >= 'A' && selected_char <= 'Z') {
int idx = selected_char - 'A';
if (idx >= 0 && idx < armor_display_limit) {
item_name_to_confirm = global_armor_templates[idx].name;
item_cost_to_confirm = global_armor_templates[idx].cost;
is_valid_selection = true;
is_armor_purchase = true;
}
}
if (selected_char == 'P') { item_name_to_confirm = "生命药水"; item_cost_to_confirm = 15; is_valid_selection = true; }
else if (selected_char == 'O') { item_name_to_confirm = "力量药水"; item_cost_to_confirm = 50; is_valid_selection = true; }
else if (selected_char == 'M') { item_name_to_confirm = "坚韧药水"; item_cost_to_confirm = 50; is_valid_selection = true; }
else if (selected_char == 'R') { item_name_to_confirm = "火焰炸弹"; item_cost_to_confirm = 30; is_valid_selection = true; }
else if (selected_char == 'K') { item_name_to_confirm = "麻痹卷轴"; item_cost_to_confirm = 70; is_valid_selection = true; }
else if (selected_char == 'L') { item_name_to_confirm = "烟雾弹"; item_cost_to_confirm = 40; is_valid_selection = true; }
if (selected_char == 'Q') {
add_message("你离开了商店。");
refresh_ui();
while(zxb('Q'));
return;
}
if (is_valid_selection) {
bool confirmed = true; // 默认确认,对一次性物品生效
// 如果购买的是武器或护甲,则弹出确认窗口
if (is_weapon_purchase || is_armor_purchase) {
clear_area(30, MAP_ROWS + 10, 79, MAP_ROWS + 12);
set_color(light_yellow);
gotoxy(30, MAP_ROWS + 10);
cout << "确认购买 " << item_name_to_confirm << " (花费 " << item_cost_to_confirm << " G) 吗? [Y/N]";
confirmed = false; // 重置为需要手动确认
bool decision_made = false;
while (!decision_made) {
if (zxb('Y')) { confirmed = true; decision_made = true; while(zxb('Y')); }
else if (zxb('N')) { confirmed = false; decision_made = true; while(zxb('N')); }
this_thread::sleep_for(chrono::milliseconds(50));
}
clear_area(30, MAP_ROWS + 10, 79, MAP_ROWS + 12);
set_color(white);
}
if (!confirmed) {
add_message("取消购买。");
} else {
if (is_weapon_purchase) {
int i = selected_char - '0';
Weapon selected_template_weapon = global_weapon_templates[i];
if (gold < selected_template_weapon.cost) {
add_message("你的钱不够呦!");
} else {
system("cls");
gotoxy(25, 2); set_color(light_yellow); cout << "--- 购买新武器! ---";
int current_display_y = 5;
gotoxy(4, current_display_y); set_color(light_cyan); cout << "你当前装备的武器:";
current_display_y = print_weapon_details(all_weapons[have_sword], current_display_y + 1);
Weapon new_weapon_instance = selected_template_weapon;
new_weapon_instance.level = 0;
if (!(new_weapon_instance.name == "神圣之剑" || new_weapon_instance.name == "混沌战斧")) {
new_weapon_instance.affixes.clear();
for (int k = 0; k < new_weapon_instance.get_current_affix_slots(); ++k) {
vector<Affix> pool;
for (const auto& affix_template : all_affixes) {
if (affix_template.tier <= 1 && is_weapon_affix_type(affix_template)) {
pool.push_back(affix_template);
}
}
if (!pool.empty()) {
new_weapon_instance.affixes.push_back(pool[rand() % pool.size()]);
}
}
}
current_display_y++;
gotoxy(4, current_display_y); set_color(light_cyan); cout << "你购买的新武器:";
current_display_y = print_weapon_details(new_weapon_instance, current_display_y + 1);
current_display_y++;
set_color(white);
gotoxy(4, current_display_y++);
cout << "请选择: [1] 装备新武器 (旧武器回收 " << all_weapons[have_sword].cost / 2 << " G)";
gotoxy(4, current_display_y++);
cout << " [2] 回收新武器 (新武器回收 " << new_weapon_instance.cost / 2 << " G)";
gotoxy(4, current_display_y++);
cout << "你的选择: ";
bool choice_made = false;
while (!choice_made) {
if (zxb('1')) {
gold -= new_weapon_instance.cost;
gold += all_weapons[have_sword].cost / 2;
all_weapons[have_sword] = new_weapon_instance;
add_message("你装备了 " + new_weapon_instance.name + "!旧武器已回收。");
choice_made = true; while(zxb('1'));
} else if (zxb('2')) {
gold -= new_weapon_instance.cost;
gold += new_weapon_instance.cost / 2;
add_message("你回收了 " + new_weapon_instance.name + ",获得 " + to_string(new_weapon_instance.cost / 2) + " 金币。");
choice_made = true; while(zxb('2'));
}
this_thread::sleep_for(chrono::milliseconds(50));
}
system("cls"); refresh_ui(); gotoxy(y_pos << 1, x_pos); set_color(bright_white); cout << "入";
}
} else if (is_armor_purchase) {
int i = selected_char - 'A';
Armor selected_template_armor = global_armor_templates[i];
if (gold < selected_template_armor.cost) {
add_message("你的钱不够呦!");
} else {
system("cls");
gotoxy(25, 2); set_color(light_yellow); cout << "--- 购买新护甲! ---";
int current_display_y = 5;
gotoxy(4, current_display_y); set_color(light_cyan); cout << "你当前装备的护甲:";
current_display_y = print_armor_details(all_armors[have_armor], current_display_y + 1);
Armor new_armor_instance = selected_template_armor;
new_armor_instance.level = 0;
if (!(new_armor_instance.name == "神圣之盾" || new_armor_instance.name == "混沌胸甲")) {
new_armor_instance.affixes.clear();
for (int k = 0; k < new_armor_instance.get_current_affix_slots(); ++k) {
vector<Affix> pool;
for (const auto& affix_template : all_affixes) {
if (affix_template.tier <= 1 && is_armor_affix_type(affix_template)) {
pool.push_back(affix_template);
}
}
if (!pool.empty()) { new_armor_instance.affixes.push_back(pool[rand()%pool.size()]); }
}
}
current_display_y++;
gotoxy(4, current_display_y); set_color(light_cyan); cout << "你购买的新护甲:";
current_display_y = print_armor_details(new_armor_instance, current_display_y + 1);
current_display_y++;
set_color(white);
gotoxy(4, current_display_y++);
cout << "请选择: [1] 装备新护甲 (旧护甲回收 " << all_armors[have_armor].cost / 2 << " G)";
gotoxy(4, current_display_y++);
cout << " [2] 回收新护甲 (新护甲回收 " << new_armor_instance.cost / 2 << " G)";
gotoxy(4, current_display_y++);
cout << "你的选择: ";
bool choice_made = false;
while (!choice_made) {
if (zxb('1')) {
gold -= new_armor_instance.cost;
gold += all_armors[have_armor].cost / 2;
all_armors[have_armor] = new_armor_instance;
current_hp = min(current_hp, get_total_max_hp());
add_message("你装备了 " + new_armor_instance.name + "!旧护甲已回收。");
choice_made = true; while(zxb('1'));
} else if (zxb('2')) {
gold -= new_armor_instance.cost;
gold += new_armor_instance.cost / 2;
add_message("你回收了 " + new_armor_instance.name + ",获得 " + to_string(new_armor_instance.cost / 2) + " 金币。");
choice_made = true; while(zxb('2'));
}
this_thread::sleep_for(chrono::milliseconds(50));
}
system("cls"); refresh_ui(); gotoxy(y_pos << 1, x_pos); set_color(bright_white); cout << "入";
}
} else { // 处理所有药水和物品购买
// --- 修改:特殊处理麻痹卷轴 ---
if (item_name_to_confirm == "麻痹卷轴" && inventory["麻痹卷轴"] >= 1) {
add_message("你已经持有一个麻痹卷轴了,无法购买更多!");
} else if (gold < item_cost_to_confirm) {
add_message("你的钱不够呦!");
} else {
inventory[item_name_to_confirm]++;
gold -= item_cost_to_confirm;
add_message("恭喜获得 " + item_name_to_confirm + "×1!");
}
}
}
display_shop_items();
}
}
this_thread::sleep_for(chrono::milliseconds(50));
}
}
// 传送门界面
void enter_portal() {
system("cls");
gotoxy(30, 1);
set_color(bright_white);
cout << "-----[传送门]-----";
auto display_portal_menu = [&]() {
clear_area(0, 4, 79, MAP_ROWS + 10); // Clear enough lines for the menu
set_color(white);
gotoxy(5, 4);
cout << "选择你要前往的楼层:";
int current_y = 6;
for (int i = 1; i <= max_unlocked_floor; ++i) {
gotoxy(5, current_y++);
cout << "[" << i << "] 地牢第 " << i << " 层";
if (i == current_floor) {
set_color(light_green);
cout << " (当前)";
set_color(white);
}
}
if (current_floor < NUM_FLOORS && boss_defeated[current_floor] && current_floor + 1 > max_unlocked_floor) {
gotoxy(5, current_y++);
set_color(light_yellow);
cout << "[" << current_floor + 1 << "] 地牢第 " << current_floor + 1 << " 层 (新区域)";
set_color(white);
}
current_y++; // Add a gap
gotoxy(5, current_y++);
set_color(light_magenta);
cout << "[V] 进入无尽模式 (已达最高: " << endless_max_floor << " 层)";
set_color(white);
gotoxy(5, current_y + 2);
set_color(white);
cout << "按[Q]退出";
};
display_portal_menu();
add_message("你来到了传送门。");
while (true) {
int target_floor = 0;
bool input_received = false;
for(int i = 1; i <= 9; ++i) { // Support up to floor 9 with number keys
if (zxb('0' + i)) {
target_floor = i;
while(zxb('0' + i)); // Debounce
input_received = true;
break;
}
}
if (input_received) {
if (target_floor <= 0 || target_floor > NUM_FLOORS) { // Invalid floor number
add_message("无效的楼层选择!");
display_portal_menu();
this_thread::sleep_for(chrono::milliseconds(50));
continue;
}
if (target_floor > max_unlocked_floor) {
if (!(target_floor == max_unlocked_floor + 1 && boss_defeated[max_unlocked_floor])) {
add_message("该楼层尚未解锁!请先击败当前楼层Boss。");
display_portal_menu();
this_thread::sleep_for(chrono::milliseconds(50));
continue;
}
}
if (target_floor == current_floor) {
add_message("你已经在这一层了。");
display_portal_menu();
this_thread::sleep_for(chrono::milliseconds(50));
continue;
}
if (target_floor == current_floor + 1 && current_floor < NUM_FLOORS && !boss_defeated[current_floor]) {
add_message("你必须先击败当前楼层的Boss才能前往下一层!");
display_portal_menu();
this_thread::sleep_for(chrono::milliseconds(50));
continue;
}
add_message("你前往了地牢第 " + to_string(target_floor) + " 层。");
current_floor = target_floor;
for(int r=0; r<MAP_ROWS; ++r) {
current_maps[current_floor - 1][r] = initial_maps[current_floor - 1][r];
}
x_pos = floor_entrance_coords[current_floor].first;
y_pos = floor_entrance_coords[current_floor].second;
// --- 妙具系统: 传送后重置次数 ---
if (current_gadget_id != -1) {
for (const auto& g : all_gadgets) {
if (g.id == current_gadget_id) {
gadget_current_uses = g.max_uses;
add_message("你的妙具 [" + g.name + "] 使用次数已重置!");
break;
}
}
}
system("cls");
refresh_ui();
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
return;
}
if (zxb('V')) { // 'V' for Void/Endless
while(zxb('V'));
add_message("你踏入了无尽虚空...");
is_in_endless_mode = true;
// 储存当前位置
stored_normal_floor = current_floor;
stored_normal_x = x_pos;
stored_normal_y = y_pos;
// 从最高记录层开始
endless_current_floor = endless_max_floor;
// --- 妙具系统: 进入无尽模式时重置次数 ---
if (current_gadget_id != -1) {
for (const auto& g : all_gadgets) {
if (g.id == current_gadget_id) {
gadget_current_uses = g.max_uses;
add_message("你的妙具 [" + g.name + "] 使用次数已重置!");
break;
}
}
}
generate_endless_map(endless_current_floor); // 生成地图
system("cls");
refresh_ui();
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
return;
}
if (zxb('Q')) {
add_message("你离开了传送门。");
refresh_ui();
while(zxb('Q'));
return;
}
this_thread::sleep_for(chrono::milliseconds(50));
}
}
// 移动函数
void move_player(int dx, int dy) {
int next_x = x_pos + dx;
int next_y = y_pos + dy;
vector<string>& active_map = is_in_endless_mode ? endless_map : current_maps[current_floor - 1];
if (next_x < 0 || next_x >= MAP_ROWS || next_y < 0 || next_y >= MAP_COLS ||
active_map[next_x][next_y] == '#') {
add_message("你撞到了墙。");
return;
}
gotoxy(y_pos << 1, x_pos);
print_tile(active_map[x_pos][y_pos]);
x_pos_last = x_pos;
y_pos_last = y_pos;
x_pos = next_x;
y_pos = next_y;
update_game_state();
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
}
// 游戏初始化和职业选择
void choose_class() {
system("cls");
set_color(light_yellow);
cout << "=== 选择你的职业 ===\n\n";
set_color(white);
cout << "1. ";
set_color(light_red);
cout << class_definitions[1].name;
set_color(white);
cout << " - 攻守兼备,技能[" << class_definitions[1].skill_name << "] (对敌人造成额外伤害)。\n";
cout << "2. ";
set_color(light_blue);
cout << class_definitions[2].name;
set_color(white);
cout << " - 敏捷且箭术精湛,技能[" << class_definitions[2].skill_name << "] (对敌人造成伤害并有几率使敌人眩晕)。\n";
cout << "3. ";
set_color(light_green);
cout << class_definitions[3].name;
set_color(white);
cout << " - 脆弱但法术伤害惊人,技能[" << class_definitions[3].skill_name << "] (对敌人造成高额魔法伤害)。\n";
// 新增 mwh 选项
cout << "4. ";
set_color(light_magenta);
cout << class_definitions[4].name;
set_color(white);
cout << " - ???技能[" << class_definitions[4].skill_name << "] (撕裂次元,造成毁灭性打击并扭曲时空)。\n\n";
cout << "请输入你的选择 (1, 2, 3 或 4): ";
while (true) {
if (zxb('1')) {
player_class = 1;
while(zxb('1'));
break;
}
if (zxb('2')) {
player_class = 2;
while(zxb('2'));
break;
}
if (zxb('3')) {
player_class = 3;
while(zxb('3'));
break;
}
// 新增对 '4' 的判断
if (zxb('4')) {
player_class = 4;
while(zxb('4'));
break;
}
this_thread::sleep_for(chrono::milliseconds(10));
}
system("cls");
}
// 初始化职业数据 (模板) - 已修改以支持 MAX_LEVEL
void initialize_class_data() {
class_definitions.clear();
class_definitions[1].name = "战士";
class_definitions[1].skill_name = "强力一击";
class_definitions[1].skill_cooldown_base = 3;
int warrior_base_hp = 50; int warrior_hp_growth = 15;
int warrior_base_atk = 8; int warrior_atk_growth = 2;
int warrior_base_def = 4; int warrior_def_growth = 1;
for (int i = 1; i <= MAX_LEVEL; ++i) {
class_definitions[1].max_hp_per_level[i] = warrior_base_hp + (i - 1) * warrior_hp_growth;
class_definitions[1].base_attack_per_level[i] = warrior_base_atk + (i - 1) * warrior_atk_growth;
class_definitions[1].base_defense_per_level[i] = warrior_base_def + (i - 1) * warrior_def_growth;
}
class_definitions[2].name = "游侠";
class_definitions[2].skill_name = "精准射击";
class_definitions[2].skill_cooldown_base = 4;
int ranger_base_hp = 45; int ranger_hp_growth = 13;
int ranger_base_atk = 10; int ranger_atk_growth = 3;
int ranger_base_def = 3; int ranger_def_growth = 1;
for (int i = 1; i <= MAX_LEVEL; ++i) {
class_definitions[2].max_hp_per_level[i] = ranger_base_hp + (i - 1) * ranger_hp_growth;
class_definitions[2].base_attack_per_level[i] = ranger_base_atk + (i - 1) * ranger_atk_growth;
class_definitions[2].base_defense_per_level[i] = ranger_base_def + (i - 1) * ranger_def_growth;
}
class_definitions[3].name = "法师";
class_definitions[3].skill_name = "火球术";
class_definitions[3].skill_cooldown_base = 4;
int mage_base_hp = 40; int mage_hp_growth = 10;
int mage_base_atk = 6; int mage_atk_growth = 2;
int mage_base_def = 2; int mage_def_growth = 1;
for (int i = 1; i <= MAX_LEVEL; ++i) {
class_definitions[3].max_hp_per_level[i] = mage_base_hp + (i - 1) * mage_hp_growth;
class_definitions[3].base_attack_per_level[i] = mage_base_atk + (i - 1) * mage_atk_growth;
class_definitions[3].base_defense_per_level[i] = mage_base_def + (i - 1) * mage_def_growth;
}
// 新增:超模角色 "mwh" - 次元主宰
class_definitions[4].name = "mwh";
class_definitions[4].skill_name = "次元断裂";
class_definitions[4].skill_cooldown_base = 2; // 极短的冷却时间
int mwh_base_hp = 100; int mwh_hp_growth = 30; // 极高的生命值和成长
int mwh_base_atk = 20; int mwh_atk_growth = 5; // 极高的攻击力和成长
int mwh_base_def = 10; int mwh_def_growth = 3; // 极高的防御力和成长
for (int i = 1; i <= MAX_LEVEL; ++i) {
class_definitions[4].max_hp_per_level[i] = mwh_base_hp + (i - 1) * mwh_hp_growth;
class_definitions[4].base_attack_per_level[i] = mwh_base_atk + (i - 1) * mwh_atk_growth;
class_definitions[4].base_defense_per_level[i] = mwh_base_def + (i - 1) * mwh_def_growth;
}
}
// 初始化所有怪物模板并根据 game_phase 缩放
void initialize_monster_templates() {
all_monster_templates_base.clear();
all_monster_templates_base.push_back({"哥布林", 30, 10, 2, 15, 3, GOBLIN, 1});
all_monster_templates_base.push_back({"剧毒蜘蛛", 25, 8, 1, 12, 5, SPIDER, 1});
all_monster_templates_base.push_back({"哥布林国王", 75, 20, 8, 70, 20, BOSS_GOBLIN_KING, 1});
all_monster_templates_base.push_back({"狂暴野兽", 70, 20, 6, 40, 8, BEAST, 2});
all_monster_templates_base.push_back({"骷髅兵", 40, 15, 10, 20, 7, SKELETON, 2});
all_monster_templates_base.push_back({"牛头怪", 180, 40, 15, 180, 40, BOSS_MINOTAUR, 2});
all_monster_templates_base.push_back({"魔王守卫", 150, 35, 12, 100, 15, DEMON_GUARD, 3});
all_monster_templates_base.push_back({"腐烂僵尸", 100, 30, 10, 80, 12, ZOMBIE, 3});
all_monster_templates_base.push_back({"亡灵法师", 350, 60, 25, 300, 70, BOSS_NECROMANCER, 3});
all_monster_templates_base.push_back({"暗影兽", 200, 45, 18, 150, 25, SHADOW_BEAST, 4});
all_monster_templates_base.push_back({"学徒法师", 120, 40, 10, 120, 20, WIZARD_APPRENTICE, 4});
all_monster_templates_base.push_back({"幼龙", 500, 80, 35, 500, 120, BOSS_DRAGON_SPAWN, 4});
all_monster_templates_base.push_back({"精英守卫", 280, 55, 25, 200, 35, ELITE_GUARD, 5});
all_monster_templates_base.push_back({"烈焰恶魔", 220, 50, 20, 180, 30, FIRE_DEMON, 5});
all_monster_templates_base.push_back({"深渊领主", 800, 100, 50, 1000, 200, BOSS_FINAL, 5});
all_monster_templates_base.push_back({"虚空掠夺者", 350, 65, 30, 250, 40, VOID_RAVAGER, 6});
all_monster_templates_base.push_back({"远古守卫", 300, 60, 35, 220, 38, ANCIENT_GUARDIAN, 6});
all_monster_templates_base.push_back({"混沌之主", 1500, 180, 80, 5000, 1000, BOSS_LORD_OF_CHAOS, 6});
current_monster_templates.clear();
for (auto& m : all_monster_templates_base) {
Monster scaled_m = m;
scaled_m.max_hp = max(1, (int)(m.max_hp * (1 + 0.25 * (game_phase - 1))));
scaled_m.attack = max(1, (int)(m.attack * (1 + 0.2 * (game_phase - 1))));
scaled_m.defense = max(0, (int)(m.defense * (1 + 0.2 * (game_phase - 1))));
scaled_m.xp_reward = max(1, (int)(m.xp_reward * (1 + 0.15 * (game_phase - 1))));
scaled_m.gold_reward= max(1, (int)(m.gold_reward* (1 + 0.15 * (game_phase - 1))));
current_monster_templates.push_back(scaled_m);
}
}
// 初始化武器/护甲模板和词条 (填充 global_weapon_templates, global_armor_templates, all_affixes)
void initialize_item_templates_and_affixes() {
all_affixes.clear();
all_affixes.push_back({"暴击+", 1, "增加10%的暴击几率 (暴击造成双倍伤害)。"});
all_affixes.push_back({"吸血", 1, "每次攻击造成伤害的10%转化为生命。"});
all_affixes.push_back({"穿甲", 2, "攻击时无视敌人5点防御。"});
all_affixes.push_back({"破碎一击", 3, "攻击时有15%几率击晕敌人一回合。"});
all_affixes.push_back({"经验加成", 1, "击败怪物时额外获得15%经验。"});
all_affixes.push_back({"财富掠夺", 1, "击败怪物时额外获得15%金币。"});
all_affixes.push_back({"剧毒之刃", 2, "攻击时有25%几率使敌人中毒,持续3回合,每回合造成攻击力20%的伤害。"});
all_affixes.push_back({"致残打击", 3, "攻击时有20%几率使敌人攻击力降低20%,持续2回合。"});
all_affixes.push_back({"生命+", 1, "增加生命上限10点。"});
all_affixes.push_back({"韧性", 2, "受到伤害时有15%几率减少50%伤害。"});
all_affixes.push_back({"反伤", 3, "受到伤害时反弹20%伤害给攻击者。"});
all_affixes.push_back({"再生", 2, "每回合开始时回复5点生命值。"});
all_affixes.push_back({"毒抗", 1, "减少受到的中毒伤害25%2。"});
global_weapon_templates.clear();
global_weapon_templates.emplace_back("破旧的匕首", 2, 1, 0);
global_weapon_templates.emplace_back("崭新的匕首", 4, 5, 1);
global_weapon_templates.emplace_back("精钢长剑", 10, 30, 1);
global_weapon_templates.emplace_back("符文大剑", 20, 100, 2);
global_weapon_templates.emplace_back("黑曜石之刃", 35, 300, 2);
global_weapon_templates.emplace_back("龙骨巨剑", 55, 1000, 3);
global_weapon_templates.emplace_back("毁灭之刃", 80, 3000, 3);
global_weapon_templates.emplace_back("神圣之剑", 70, 4500, 3, vector<Affix>{
*(find_if(all_affixes.begin(), all_affixes.end(), [](const Affix& a){ return a.name == "吸血"; })),
*(find_if(all_affixes.begin(), all_affixes.end(), [](const Affix& a){ return a.name == "暴击+"; })),
*(find_if(all_affixes.begin(), all_affixes.end(), [](const Affix& a){ return a.name == "穿甲"; }))
});
global_weapon_templates.emplace_back("混沌战斧", 90, 6000, 3, vector<Affix>{
*(find_if(all_affixes.begin(), all_affixes.end(), [](const Affix& a){ return a.name == "破碎一击"; })),
*(find_if(all_affixes.begin(), all_affixes.end(), [](const Affix& a){ return a.name == "暴击+"; })),
*(find_if(all_affixes.begin(), all_affixes.end(), [](const Affix& a){ return a.name == "穿甲"; }))
});
global_armor_templates.clear();
global_armor_templates.emplace_back("布衣", 1, 1, 0);
global_armor_templates.emplace_back("皮甲", 3, 5, 1);
global_armor_templates.emplace_back("锁子甲", 6, 25, 1);
global_armor_templates.emplace_back("钢板甲", 10, 80, 2);
global_armor_templates.emplace_back("秘银胸甲", 16, 300, 2);
global_armor_templates.emplace_back("符文板甲", 25, 1200, 3);
global_armor_templates.emplace_back("巨龙鳞甲", 40, 3500, 3);
global_armor_templates.emplace_back("不朽战甲", 60, 6000, 4);
global_armor_templates.emplace_back("神圣之盾", 50, 4800, 3, vector<Affix>{
*(find_if(all_affixes.begin(), all_affixes.end(), [](const Affix& a){ return a.name == "生命+"; })),
*(find_if(all_affixes.begin(), all_affixes.end(), [](const Affix& a){ return a.name == "韧性"; })),
*(find_if(all_affixes.begin(), all_affixes.end(), [](const Affix& a){ return a.name == "反伤"; }))
});
global_armor_templates.emplace_back("混沌胸甲", 70, 6500, 4, vector<Affix>{
*(find_if(all_affixes.begin(), all_affixes.end(), [](const Affix& a){ return a.name == "生命+"; })),
*(find_if(all_affixes.begin(), all_affixes.end(), [](const Affix& a){ return a.name == "韧性"; })),
*(find_if(all_affixes.begin(), all_affixes.end(), [](const Affix& a){ return a.name == "反伤"; })),
*(find_if(all_affixes.begin(), all_affixes.end(), [](const Affix& a){ return a.name == "反伤"; }))
});
}
// --- 新增:初始化星徽之力模板 ---
void initialize_star_powers() {
all_star_powers.clear();
// ID 1: 防御型
all_star_powers.push_back({1, "神盾庇护", "受到的所有伤害降低15%。"});
// ID 2: 恢复型
all_star_powers.push_back({2, "生命源泉", "每回合开始时,恢复你15%的最大生命值。"});
// ID 3: 属性型
all_star_powers.push_back({3, "泰坦之力", "你的总攻击力、防御力和最大生命值提升10%。"});
// ID 4: 进攻型 (普攻)
all_star_powers.push_back({4, "怒意连击", "你的普通攻击有20%几率立即再次攻击一次。"});
// ID 5: 技能型
all_star_powers.push_back({5, "奥术回响", "使用技能后,有15%几率立即再次施放一次该技能。"});
// ID 6: 进攻型 (暴击)
all_star_powers.push_back({6, "致命专注", "你的暴击伤害从200%提升至250%。"});
}
// --- 妙具系统: 初始化妙具模板 ---
void initialize_gadgets() {
all_gadgets.clear();
// ID 101: 治疗型
all_gadgets.push_back({101, "治疗图腾", "立即恢复你35%的最大生命值。", 2});
// ID 102: 伤害型 - 已根据请求修改
all_gadgets.push_back({102, "能量脉冲", "对敌人造成等同于你最大生命值40%的真实伤害(无视防御)。", 2});
// ID 103: 减益型
all_gadgets.push_back({103, "弱化射线", "使敌人的攻击力和防御力降低30%,持续3回合。", 1});
// ID 104: 增益型
all_gadgets.push_back({104, "战斗兴奋剂", "你的攻击力提升50%,持续3回合。", 2});
// ID 105: 逃脱型 - 已根据请求修改
all_gadgets.push_back({105, "紧急传送", "有75%的几率立即逃离战斗。", 1});
// ID 106: 护盾型
all_gadgets.push_back({106, "能量护盾", "获得一个能吸收等同于你25%最大生命值伤害的护盾。", 2});
}
// 初始化升级系统 (模板)
void initialize_upgrades() {
upgrades.clear();
upgrades.push_back({"生命上限提升", 0, 50, [&](){
for(int i=1;i<=MAX_LEVEL;i++)
class_definitions[player_class].max_hp_per_level[i] += 10;
}});
upgrades.push_back({"基础攻击提升", 0, 75, [&](){
for(int i=1;i<=MAX_LEVEL;i++)
class_definitions[player_class].base_attack_per_level[i] += 2;
}});
upgrades.push_back({"基础防御提升", 0, 75, [&](){
for(int i=1;i<=MAX_LEVEL;i++)
class_definitions[player_class].base_defense_per_level[i] += 2;
}});
upgrades.push_back({"技能冷却缩短", 0, 100, [&](){
class_definitions[player_class].skill_cooldown_base =
max(1, class_definitions[player_class].skill_cooldown_base - 1);
}});
}
// 刷新武器词条
void reroll_affixes(Weapon& w) {
bool is_fixed_affix_weapon = (w.name == "神圣之剑" || w.name == "混沌战斧");
if (is_fixed_affix_weapon) {
add_message("这把武器的词条是固定的,无法刷新。");
return;
}
int cost = w.level * 20 + 50;
if (gold < cost) {
add_message("金币不足,无法刷新词条 (需要 " + to_string(cost) + " G)。");
return;
}
gold -= cost;
w.affixes.clear();
vector<Affix> pool;
for(auto &a: all_affixes) {
if (a.tier <= w.level + 1 && is_weapon_affix_type(a)) {
pool.push_back(a);
}
}
if (pool.empty()) {
add_message("没有可用武器词条进行刷新。");
} else {
for(int i=0;i<w.get_current_affix_slots();i++){
w.affixes.push_back(pool[rand()%pool.size()]);
}
add_message("武器词条已刷新!");
}
}
// 刷新护甲词条 (新增)
void reroll_armor_affixes(Armor& a) {
bool is_fixed_affix_armor = (a.name == "神圣之盾" || a.name == "混沌胸甲");
if (is_fixed_affix_armor) {
add_message("这件护甲的词条是固定的,无法刷新。");
return;
}
int cost = a.level * 20 + 50;
if (gold < cost) {
add_message("金币不足,无法刷新词条 (需要 " + to_string(cost) + " G)。");
return;
}
gold -= cost;
a.affixes.clear();
vector<Affix> pool;
for(auto &affix_template: all_affixes) {
if (affix_template.tier <= a.level + 1 && is_armor_affix_type(affix_template)) {
pool.push_back(affix_template);
}
}
if (pool.empty()) {
add_message("没有可用护甲词条进行刷新。");
} else {
for(int i=0;i<a.get_current_affix_slots();i++){
a.affixes.push_back(pool[rand()%pool.size()]);
}
add_message("护甲词条已刷新!");
}
}
// 升级武器函数
void upgrade_weapon(int weapon_idx) {
if (weapon_idx < 0 || weapon_idx >= all_weapons.size()) return;
Weapon& w = all_weapons[weapon_idx];
if (w.name == "神圣之剑" || w.name == "混沌战斧") {
add_message(w.name + " 是特殊武器,无法进行升级。");
return;
}
if (w.level >= level) {
add_message(w.name + " 已达到最大升级等级 (与你的角色等级相同)。");
return;
}
int upgrade_cost = (w.level + 1) * 100;
if (gold < upgrade_cost) {
add_message("金币不足,无法升级 " + w.name + " (需要 " + to_string(upgrade_cost) + " G)。");
return;
}
gold -= upgrade_cost;
w.level++;
add_message(w.name + " 升到了 Lv." + to_string(w.level) + "!");
int new_affix_slots = w.get_current_affix_slots();
if (w.affixes.size() < new_affix_slots) {
add_message("新的词条槽位已解锁!");
for (size_t i = w.affixes.size(); i < new_affix_slots; ++i) {
vector<Affix> pool;
for (const auto& affix_template : all_affixes) {
if (affix_template.tier <= w.level + 1 &&
is_weapon_affix_type(affix_template)) {
pool.push_back(affix_template);
}
}
if (!pool.empty()) {
w.affixes.push_back(pool[rand() % pool.size()]);
} else {
add_message("未能找到合适的词条填充新槽位。");
}
}
}
}
// 升级护甲函数 (新增)
void upgrade_armor(int armor_idx) {
if (armor_idx < 0 || armor_idx >= all_armors.size()) return;
Armor& a = all_armors[armor_idx];
if (a.name == "神圣之盾" || a.name == "混沌胸甲") {
add_message(a.name + " 是特殊护甲,无法进行升级。");
return;
}
if (a.level >= level) {
add_message(a.name + " 已达到最大升级等级 (与你的角色等级相同)。");
return;
}
int upgrade_cost = (a.level + 1) * 100;
if (gold < upgrade_cost) {
add_message("金币不足,无法升级 " + a.name + " (需要 " + to_string(upgrade_cost) + " G)。");
return;
}
gold -= upgrade_cost;
a.level++;
add_message(a.name + " 升到了 Lv." + to_string(a.level) + "!");
int new_affix_slots = a.get_current_affix_slots();
if (a.affixes.size() < new_affix_slots) {
add_message("新的词条槽位已解锁!");
for (size_t i = a.affixes.size(); i < new_affix_slots; ++i) {
vector<Affix> pool;
for (const auto& affix_template : all_affixes) {
if (affix_template.tier <= a.level + 1 && is_armor_affix_type(affix_template)) {
pool.push_back(affix_template);
}
}
if (!pool.empty()) {
a.affixes.push_back(pool[rand() % pool.size()]);
} else {
add_message("未能找到合适的词条填充新槽位。");
}
}
}
current_hp = min(current_hp, get_total_max_hp());
}
// 锻造小屋函数
void enter_forging_hut() {
system("cls");
gotoxy(2,2); set_color(light_yellow);
cout<<"----- 锻造小屋 -----";
set_color(white);
auto display_forging_hut_menu = [&]() {
clear_area(0, 4, 79, MAP_ROWS + 25);
set_color(white);
int current_display_y = 4;
gotoxy(2,current_display_y++); cout << "你当前职业: " << class_definitions[player_class].name;
gotoxy(2,current_display_y++); cout << "基础生命 (Lv1): " << class_definitions[player_class].max_hp_per_level[1];
gotoxy(2,current_display_y++); cout << "基础攻击 (Lv1): " << class_definitions[player_class].base_attack_per_level[1];
gotoxy(2,current_display_y++); cout << "基础防御 (Lv1): " << class_definitions[player_class].base_defense_per_level[1];
gotoxy(2,current_display_y++); cout << "技能冷却: " << class_definitions[player_class].skill_cooldown_base << " 回合";
current_display_y++;
gotoxy(2, current_display_y++); set_color(light_yellow);
cout << "--- 角色强化 ---";
set_color(white);
for(size_t i=0; i<upgrades.size(); i++){
auto &u = upgrades[i];
gotoxy(2, current_display_y++);
// START OF CHANGE
if (u.name == "技能冷却缩短" && player_class == 4) {
set_color(gray);
cout << "[" << i + 1 << "] " << u.name << " (mwh职业不可用)";
set_color(white);
} else {
cout << "[" << i + 1 << "] " << u.name << " Lv." << u.level
<< " 费用:" << (u.level + 1) * u.base_cost << " G";
}
// END OF CHANGE
}
current_display_y++;
gotoxy(2, current_display_y++); set_color(light_yellow);
cout << "--- 武器锻造 ---";
set_color(white);
Weapon& equipped_weapon = all_weapons[have_sword];
gotoxy(2, current_display_y++);
cout << "当前武器: " << equipped_weapon.name << " (Lv." << equipped_weapon.level << ")";
gotoxy(2, current_display_y++);
cout << " 伤害: " << equipped_weapon.get_current_damage();
gotoxy(2, current_display_y++);
cout << " 词条槽位: " << equipped_weapon.affixes.size() << "/" << equipped_weapon.get_current_affix_slots();
map<string, int> weapon_affix_counts_forge;
for (const auto& affix : equipped_weapon.affixes) {
weapon_affix_counts_forge[affix.name]++;
}
string current_weapon_affix_name_line_forge = " 当前词条: ";
if (!weapon_affix_counts_forge.empty()) {
for (const auto& pair : weapon_affix_counts_forge) {
string affix_text = "[" + pair.first + "]";
if (pair.second > 1) {
affix_text += " (x" + to_string(pair.second) + ")";
}
if (current_weapon_affix_name_line_forge.length() + affix_text.length() + 1 > SIDEBAR_WIDTH) {
gotoxy(2, current_display_y++);
cout << current_weapon_affix_name_line_forge;
current_weapon_affix_name_line_forge = " " + affix_text;
} else {
current_weapon_affix_name_line_forge += " " + affix_text;
}
}
gotoxy(2, current_display_y++);
cout << current_weapon_affix_name_line_forge;
} else {
gotoxy(2, current_display_y++);
cout << current_weapon_affix_name_line_forge << "[无]";
}
vector<string> combined_weapon_affix_descs_forge = get_combined_affix_descriptions(equipped_weapon.affixes);
if (!combined_weapon_affix_descs_forge.empty()) {
for (const string& desc : combined_weapon_affix_descs_forge) {
gotoxy(2, current_display_y++);
cout << " - " << desc;
}
}
current_display_y++;
gotoxy(2, current_display_y++);
if (equipped_weapon.name != "神圣之剑" && equipped_weapon.name != "混沌战斧") {
if (equipped_weapon.level < level) {
cout << "[W] 升级武器 (下一级Lv." << equipped_weapon.level + 1 << " 费用: " << (equipped_weapon.level + 1) * 100 << " G)";
} else {
cout << "[W] 升级武器 (已达最大等级 Lv." << equipped_weapon.level << ")";
}
} else {
cout << "[W] 升级武器 (特殊武器,不可升级)";
}
gotoxy(2, current_display_y++);
if (equipped_weapon.name != "神圣之剑" && equipped_weapon.name != "混沌战斧") {
cout << "[X] 刷新武器词条 (费用: " << equipped_weapon.level * 20 + 50 << " G)";
} else {
cout << "[X] 刷新武器词条 (特殊武器,不可重铸)";
}
current_display_y++;
gotoxy(2, current_display_y++); set_color(light_yellow);
cout << "--- 护甲锻造 ---";
set_color(white);
Armor& equipped_armor = all_armors[have_armor];
gotoxy(2, current_display_y++);
cout << "当前护甲: " << equipped_armor.name << " (Lv." << equipped_armor.level << ")";
gotoxy(2, current_display_y++);
cout << " 防御: " << equipped_armor.get_current_defense();
gotoxy(2, current_display_y++);
cout << " 词条槽位: " << equipped_armor.affixes.size() << "/" << equipped_armor.get_current_affix_slots();
map<string, int> armor_affix_counts_forge;
for (const auto& affix : equipped_armor.affixes) {
armor_affix_counts_forge[affix.name]++;
}
string current_armor_affix_name_line_forge = " 当前词条: ";
if (!armor_affix_counts_forge.empty()) {
for (const auto& pair : armor_affix_counts_forge) {
string affix_text = "[" + pair.first + "]";
if (pair.second > 1) {
affix_text += " (x" + to_string(pair.second) + ")";
}
if (current_armor_affix_name_line_forge.length() + affix_text.length() + 1 > SIDEBAR_WIDTH) {
gotoxy(2, current_display_y++);
cout << current_armor_affix_name_line_forge;
current_armor_affix_name_line_forge = " " + affix_text;
} else {
current_armor_affix_name_line_forge += " " + affix_text;
}
}
gotoxy(2, current_display_y++);
cout << current_armor_affix_name_line_forge;
} else {
gotoxy(2, current_display_y++);
cout << current_armor_affix_name_line_forge << "[无]";
}
vector<string> combined_armor_affix_descs_forge = get_combined_affix_descriptions(equipped_armor.affixes);
if (!combined_armor_affix_descs_forge.empty()) {
for (const string& desc : combined_armor_affix_descs_forge) {
gotoxy(2, current_display_y++);
cout << " - " << desc;
}
}
current_display_y++;
gotoxy(2, current_display_y++);
if (equipped_armor.name != "神圣之盾" && equipped_armor.name != "混沌胸甲") {
if (equipped_armor.level < level) {
cout << "[A] 升级护甲 (下一级Lv." << equipped_armor.level + 1 << " 费用: " << (equipped_armor.level + 1) * 100 << " G)";
} else {
cout << "[A] 升级护甲 (已达最大等级 Lv." << equipped_armor.level << ")";
}
} else {
cout << "[A] 升级护甲 (特殊护甲,不可升级)";
}
gotoxy(2, current_display_y++);
if (equipped_armor.name != "神圣之盾" && equipped_armor.name != "混沌胸甲") {
cout << "[Z] 刷新护甲词条 (费用: " << equipped_armor.level * 20 + 50 << " G)";
} else {
cout << "[Z] 刷新护甲词条 (特殊护甲,不可重铸)";
}
current_display_y++;
gotoxy(2, current_display_y++);
set_color(light_yellow);
cout << "你现在有 " << gold << " 金币。";
gotoxy(2, current_display_y++);
set_color(white);
cout<<"按数字购买强化,按[W]升级武器,按[X]刷新武器词条,按[A]升级护甲,按[Z]刷新护甲词条,按[Q]退出";
};
display_forging_hut_menu();
add_message("欢迎来到锻造小屋!");
while(true){
if (zxb('Q')) {
while(zxb('Q'));
break;
}
bool input_handled_in_loop = false;
for(size_t i=0; i<upgrades.size(); i++){
if (zxb('1' + i)) {
// START OF CHANGE
if (upgrades[i].name == "技能冷却缩短" && player_class == 4) {
add_message("mwh的技能冷却时间是固定的,无法强化。");
while(zxb('1' + i));
display_forging_hut_menu();
input_handled_in_loop = true;
break;
}
// END OF CHANGE
int cost = (upgrades[i].level + 1) * upgrades[i].base_cost;
if (gold < cost){
add_message("金币不足,无法升级。");
} else {
gold -= cost;
upgrades[i].level++;
initialize_class_data();
for (size_t k = 0; k < upgrades.size(); ++k) {
for (int l = 0; l < upgrades[k].level; ++l) {
upgrades[k].apply_effect();
}
}
current_hp = min(current_hp, get_total_max_hp());
add_message(upgrades[i].name + " 提升到 Lv." + to_string(upgrades[i].level));
}
while(zxb('1' + i));
display_forging_hut_menu();
input_handled_in_loop = true;
break;
}
}
if (input_handled_in_loop) {
this_thread::sleep_for(chrono::milliseconds(50));
continue;
}
if (zxb('W')) {
upgrade_weapon(have_sword);
while(zxb('W'));
display_forging_hut_menu();
}
else if (zxb('X')) {
reroll_affixes(all_weapons[have_sword]);
while(zxb('X'));
display_forging_hut_menu();
}
else if (zxb('A')) {
upgrade_armor(have_armor);
while(zxb('A'));
display_forging_hut_menu();
}
else if (zxb('Z')) {
reroll_armor_affixes(all_armors[have_armor]);
while(zxb('Z'));
display_forging_hut_menu();
}
this_thread::sleep_for(chrono::milliseconds(50));
}
system("cls");
refresh_ui();
}
// 载入初始地图
void load_initial_maps() {
const vector<string> default_map_floor1 = {
"########################################",
"#S...m.....m.......T.........#....m....#",
"#...###...###...###...###....#.........#",
"#...#...#...#...#...#...#....#....T....#",
"#...#...#...#...#...#...#....#.........#",
"#...###...###...###...###....#....m....#",
"#.......m.....H..............#.........#",
"#####...###########...#########....#####",
"#.............................#........#",
"#...G...................T.....#....H...#",
"#.............................#........#",
"#################...###########.########",
"#.........F.........#..................#",
"#...m...............#.......G..........#",
"#...................#..................#",
"#####...#############....###############",
"#.......H.............B................#",
"#......................................#",
"#T.................................#D..#",
"########################################",
};
const vector<string> default_map_floor2 = {
"########################################",
"#D.....................................#",
"#..##################################..#",
"#..#...........m..........H.........#..#",
"#..#................................#..#",
"#..#...G.......T....................#..#",
"#..#..#######.......#######.........#..#",
"#..#..#.....#.......#.....#.........#..#",
"#..#..#.....#...m...#.....#.........#..#",
"#..#..#.....#########.....#............#",
"#..# #...................#............#",
"#..# #...................#............#",
"#..# #...H...............#.......G....#",
"#..#################################...#",
"#....................................B.#",
"#...T.......m...........F..............#",
"#......................................#",
"#...G.............................S....#",
"#......................................#",
"########################################",
};
const vector<string> default_map_floor3 = {
"########################################",
"#D....................................S#",
"#....#####...#####...#####...#####.....#",
"#....#TTT#...#TTT#G..#...#...#.G.#.....#",
"#....#T.Tm...#T.TmmG.#...H...#GGGG.....#",
"#....#TTT#...#TTT#G..#...#...#.G.#.....#",
"#....#####...#####...#####...#####.....#",
"#...........F..........................#",
"##################...###################",
"#......................................#",
"#...m.............................G....#",
"#......................................#",
"#...H.......T..........................#",
"##################...###################",
"#......................................#",
"#...G................-------...m..........#",
"#...................-----............#",
"#...m.......B................----------#",
"#......................................#",
"########################################",
};
const vector<string> default_map_floor4 = {
"########################################",
"#D....T...................G............#",
"#...#####...############################",
"#...#.T.#...#..........................#",
"#...#...#...#...H...........m..........#",
"#...#...#...#..........................#",
"#...#...#...#############...############",
"#...#...#..............................#",
"#...#...#............G.................#",
"#...#...#...###########################....#",
"#...#............................#.....#",
"#...m......................G.....#...S.#",
"#.................m..............#.....#",
"###########################......#######",
"#.........F..............#.............#",
"#...H...........G........#...T.........#",
"#................--------#.............#",
"#...............B........#-------------#",
"#......................................#",
"########################################",
};
const vector<string> default_map_floor5 = {
"########################################",
"#D....m.......H.......T.......G........#",
"#...#...#...#...#...#...#...#...#......#",
"#...#...#...#...#...#...#...#...#......#",
"#...#...#...#...#...#...#...#...#......#",
"#...#...#...#...#...#...#...#...#......#",
"#...#...#...#...#...#...#...#...#......#",
"#...#...#...#...#...#...#...#...#......#",
"#...#...#...#...#...#...#...#...#......#",
"#...#...#...#...#...#...#...#...#......#",
"#...#...#...#...#...#...#...#...#......#",
"#...#...#...#...#...#...#...#...#......#",
"#...#...#...#...#...#...#...#...#......#",
"#...#...#...#...#...#...#...#...#......#",
"#...#...#...#...#...#...#...#...#......#",
"#...#...#...#...#...F...#...#...#......#",
"#...#...#...#...#.......#...#...#......#",
"#...#...#...#...#.......#...#...#......#",
"#...#...#...#...#.......#...#...#......#",
"#...#...#...#...#...B...#...#...#......#",
"########################################",
};
const vector<string> default_map_floor6 = {
"########################################",
"#D.....................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#...............mmTTTTTmm..............#",
"#...............m.GGGGG.m..............#",
"#...............T.G...G.T..............#",
"#...............T.G.B.G.T..............#",
"#...............T.G...G.T..............#",
"#...............m.GGGGG.m..............#",
"#...............mmTTTTTmm..............#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"#......................................#",
"########################################",
};
initial_maps[0] = default_map_floor1;
initial_maps[1] = default_map_floor2;
initial_maps[2] = default_map_floor3;
initial_maps[3] = default_map_floor4;
initial_maps[4] = default_map_floor5;
initial_maps[5] = default_map_floor6;
}
// 初始化所有游戏模板数据 (只调用一次,在程序启动时)
void initialize_base_templates() {
initialize_class_data();
initialize_item_templates_and_affixes();
initialize_upgrades();
load_initial_maps();
initialize_star_powers();
initialize_gadgets(); // --- 妙具系统: 调用初始化 ---
}
// 重置玩家进度相关数据 (用于游戏结束重新开始时,重置所有角色成长)
void reset_player_progression() {
level = 1;
experience = 0;
gold = 10;
skill_cooldown = 0;
max_unlocked_floor = 1;
inventory.clear();
inventory["生命药水"] = 1;
message_log.clear();
current_star_power_id = -1;
// --- 妙具系统: 重置妙具状态 ---
current_gadget_id = -1;
gadget_current_uses = 0;
initialize_class_data();
for(auto& upg : upgrades) {
upg.level = 0;
}
for (size_t k = 0; k < upgrades.size(); ++k) {
for (int l = 0; l < upgrades[k].level; ++l) {
upgrades[k].apply_effect();
}
}
all_weapons.clear();
if (!global_weapon_templates.empty()) {
Weapon initial_weapon = global_weapon_templates[0];
initial_weapon.level = 0;
initial_weapon.affixes.clear();
for (int i = 0; i < initial_weapon.get_current_affix_slots(); ++i) {
vector<Affix> pool;
for (const auto& affix_template : all_affixes) {
if (affix_template.tier <= 1 && is_weapon_affix_type(affix_template)) {
pool.push_back(affix_template);
}
}
if (!pool.empty()) {
initial_weapon.affixes.push_back(pool[rand() % pool.size()]);
}
}
all_weapons.push_back(initial_weapon);
have_sword = 0;
} else {
all_weapons.emplace_back("默认武器", 1, 0, 0);
have_sword = 0;
}
all_armors.clear();
if (!global_armor_templates.empty()) {
Armor initial_armor = global_armor_templates[0];
initial_armor.level = 0;
initial_armor.affixes.clear();
for (int i = 0; i < initial_armor.get_current_affix_slots(); ++i) {
vector<Affix> pool;
for (const auto& affix_template : all_affixes) {
if (affix_template.tier <= 1 && is_armor_affix_type(affix_template)) {
pool.push_back(affix_template);
}
}
if (!pool.empty()) {
initial_armor.affixes.push_back(pool[rand() % pool.size()]);
}
}
all_armors.push_back(initial_armor);
have_armor = 0;
} else {
all_armors.emplace_back("默认护甲", 0, 0, 0);
have_armor = 0;
}
}
// 重置地图和Boss状态 (用于新轮次或游戏重开时,重置地图布局)
void reset_map_and_boss_status() {
for(int i=0; i<NUM_FLOORS; ++i) {
current_maps[i] = initial_maps[i];
}
current_floor = 1;
x_pos = floor_entrance_coords[current_floor].first;
y_pos = floor_entrance_coords[current_floor].second;
for (int i = 1; i <= NUM_FLOORS; ++i) {
boss_defeated[i] = false;
}
}
// 击败最终Boss后的处理
void on_final_boss_defeated() {
add_message("恭喜你!你击败了混沌之主,征服了所有地牢!");
game_phase++;
best_phase = max(best_phase, game_phase);
add_message("你进入了更深层的地牢,现在是第 " + to_string(game_phase) + " 轮挑战!");
add_message("所有敌人变得更加强大了...");
initialize_monster_templates();
reset_map_and_boss_status();
system("cls");
refresh_ui();
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
this_thread::sleep_for(chrono::seconds(2));
}
// --- Save/Load Game Functions ---
void save_game(const string& filename) {
ofstream outFile(filename);
if (!outFile.is_open()) {
add_message("错误:无法保存游戏到文件 " + filename);
return;
}
outFile << player_class << endl;
outFile << level << endl;
outFile << experience << endl;
outFile << current_hp << endl;
outFile << gold << endl;
outFile << skill_cooldown << endl;
outFile << have_sword << endl;
outFile << have_armor << endl;
outFile << current_floor << endl;
outFile << max_unlocked_floor << endl;
outFile << game_phase << endl;
outFile << best_phase << endl;
outFile << endless_max_floor << endl;
outFile << current_star_power_id << endl;
// --- 妙具系统: 保存妙具状态 ---
outFile << current_gadget_id << endl;
outFile << gadget_current_uses << endl;
for (int i = 1; i <= NUM_FLOORS; ++i) {
outFile << boss_defeated[i] << " ";
}
outFile << endl;
outFile << inventory.size() << endl;
for (const auto& pair : inventory) {
outFile << pair.first << " " << pair.second << endl;
}
outFile << upgrades.size() << endl;
for (const auto& upg : upgrades) {
outFile << upg.level << " ";
}
outFile << endl;
outFile << all_weapons.size() << endl;
for (const auto& w : all_weapons) {
outFile << w.name << endl;
outFile << w.initial_damage << " " << w.cost << " " << w.initial_affix_slots << endl;
outFile << w.level << endl;
outFile << w.affixes.size() << endl;
for (const auto& affix : w.affixes) {
outFile << affix.name << endl;
}
}
outFile << all_armors.size() << endl;
for (const auto& a : all_armors) {
outFile << a.name << endl;
outFile << a.initial_defense_bonus << " " << a.cost << " " << a.initial_affix_slots << endl;
outFile << a.level << endl;
outFile << a.affixes.size() << endl;
for (const auto& affix : a.affixes) {
outFile << affix.name << endl;
}
}
for (int f = 0; f < NUM_FLOORS; ++f) {
for (int r = 0; r < MAP_ROWS; ++r) {
outFile << current_maps[f][r] << endl;
}
}
outFile.close();
add_message("游戏已成功保存到 " + filename);
}
void load_game(const string& filename) {
ifstream inFile(filename);
if (!inFile.is_open()) {
add_message("错误:无法读取存档文件 " + filename);
return;
}
// 在开始加载前,重置所有模板数据和状态,确保一个干净的环境
initialize_base_templates();
for(int f=0; f<NUM_FLOORS; ++f) {
current_maps[f].clear();
current_maps[f].resize(MAP_ROWS);
}
// --- 开始读取核心玩家数据 ---
inFile >> player_class;
inFile >> level;
inFile >> experience;
inFile >> current_hp;
inFile >> gold;
inFile >> skill_cooldown;
inFile >> have_sword;
inFile >> have_armor;
inFile >> current_floor;
inFile >> max_unlocked_floor;
inFile >> game_phase;
inFile >> best_phase;
inFile >> endless_max_floor;
inFile >> current_star_power_id;
inFile >> current_gadget_id;
inFile >> gadget_current_uses;
// 【防御性编程】检查流状态,如果前面读取失败,则停止
if (!inFile) {
add_message("错误:读取核心数据时存档文件格式损坏!");
inFile.close();
return;
}
is_in_endless_mode = false; // 总是从普通模式加载
initialize_monster_templates(); // 根据加载的 game_phase 初始化怪物
for (int i = 1; i <= NUM_FLOORS; ++i) {
inFile >> boss_defeated[i];
}
// 【关键修复 1】: 在读取完一系列 `>>` 之后,准备读取下一个逻辑块前,清除换行符。
inFile.ignore(numeric_limits<streamsize>::max(), '\n');
// --- 读取物品栏 ---
size_t inv_size;
inFile >> inv_size;
inFile.ignore(numeric_limits<streamsize>::max(), '\n'); // 清除 inv_size 后面的换行符
inventory.clear();
for (size_t i = 0; i < inv_size; ++i) {
string item_name;
int count;
inFile >> item_name >> count;
inventory[item_name] = count;
inFile.ignore(numeric_limits<streamsize>::max(), '\n'); // 清除每行物品后的换行符
}
// --- 读取角色强化 ---
size_t upg_size;
inFile >> upg_size;
initialize_upgrades(); // 确保 upgrades 向量是初始化的
for (size_t i = 0; i < upg_size; ++i) {
int loaded_level;
inFile >> loaded_level;
if (i < upgrades.size()) {
upgrades[i].level = loaded_level;
}
}
inFile.ignore(numeric_limits<streamsize>::max(), '\n'); // 清除强化等级行后的换行符
// 重新应用强化效果
initialize_class_data();
for (size_t k = 0; k < upgrades.size(); ++k) {
for (int l = 0; l < upgrades[k].level; ++l) {
upgrades[k].apply_effect();
}
}
current_hp = min(current_hp, get_total_max_hp());
// --- 读取武器列表 (最容易出错的部分) ---
size_t weapon_count;
inFile >> weapon_count;
inFile.ignore(numeric_limits<streamsize>::max(), '\n'); // 【关键修复 2】清除 weapon_count 后的换行符,为下面的 getline 做准备
all_weapons.clear();
for (size_t i = 0; i < weapon_count; ++i) {
Weapon loaded_w_instance; // 创建一个空的武器实例来填充数据
getline(inFile, loaded_w_instance.name); // 读取武器名称,这现在是安全的
inFile >> loaded_w_instance.initial_damage >> loaded_w_instance.cost >> loaded_w_instance.initial_affix_slots;
inFile.ignore(numeric_limits<streamsize>::max(), '\n'); // 【关键修复 3】清除这一行数字后的换行符
inFile >> loaded_w_instance.level;
inFile.ignore(numeric_limits<streamsize>::max(), '\n'); // 【关键修复 4】清除等级后的换行符
size_t affix_size;
inFile >> affix_size;
inFile.ignore(numeric_limits<streamsize>::max(), '\n'); // 【关键修复 5】清除词条数量后的换行符
loaded_w_instance.affixes.clear();
for (size_t j = 0; j < affix_size; ++j) {
string affix_name;
getline(inFile, affix_name); // 读取词条名称,现在是安全的
auto it = find_if(all_affixes.begin(), all_affixes.end(),
[&](const Affix& a){ return a.name == affix_name; });
if (it != all_affixes.end()) {
loaded_w_instance.affixes.push_back(*it);
} else {
add_message("警告: 武器词条 '" + affix_name + "' 未找到。");
}
}
all_weapons.push_back(loaded_w_instance);
}
// 安全检查,防止索引越界
if (all_weapons.empty()) {
all_weapons.push_back(global_weapon_templates[0]);
have_sword = 0;
} else if (have_sword >= all_weapons.size()) {
have_sword = 0;
}
// --- 读取护甲列表 (应用相同的修复逻辑) ---
size_t armor_count;
inFile >> armor_count;
inFile.ignore(numeric_limits<streamsize>::max(), '\n'); // 【关键修复 6】
all_armors.clear();
for (size_t i = 0; i < armor_count; ++i) {
Armor loaded_a_instance;
getline(inFile, loaded_a_instance.name);
inFile >> loaded_a_instance.initial_defense_bonus >> loaded_a_instance.cost >> loaded_a_instance.initial_affix_slots;
inFile.ignore(numeric_limits<streamsize>::max(), '\n'); // 【关键修复 7】
inFile >> loaded_a_instance.level;
inFile.ignore(numeric_limits<streamsize>::max(), '\n'); // 【关键修复 8】
size_t affix_size;
inFile >> affix_size;
inFile.ignore(numeric_limits<streamsize>::max(), '\n'); // 【关键修复 9】
loaded_a_instance.affixes.clear();
for (size_t j = 0; j < affix_size; ++j) {
string affix_name;
getline(inFile, affix_name);
auto it = find_if(all_affixes.begin(), all_affixes.end(),
[&](const Affix& a){ return a.name == affix_name; });
if (it != all_affixes.end()) {
loaded_a_instance.affixes.push_back(*it);
} else {
add_message("警告: 护甲词条 '" + affix_name + "' 未找到。");
}
}
all_armors.push_back(loaded_a_instance);
}
// 安全检查
if (all_armors.empty()) {
all_armors.push_back(global_armor_templates[0]);
have_armor = 0;
} else if (have_armor >= all_armors.size()) {
have_armor = 0;
}
// 【防御性编程】在读取地图前再次检查流状态
if (!inFile) {
add_message("错误:读取装备数据时存档文件格式损坏!");
inFile.close();
// 此时游戏状态可能已损坏,可以考虑触发一个安全重置
reset_game_state();
choose_class();
current_hp = get_total_max_hp();
return;
}
// --- 读取地图状态 ---
for (int f = 0; f < NUM_FLOORS; ++f) {
for (int r = 0; r < MAP_ROWS; ++r) {
// 这里之前的逻辑是正确的,因为是连续的 getline
if (!getline(inFile, current_maps[f][r])) {
// 如果在读取地图时出错,说明存档文件不完整
add_message("错误:地图数据不完整或损坏!");
inFile.close();
// 同样可以触发安全重置
reset_game_state();
choose_class();
current_hp = get_total_max_hp();
return;
}
}
}
inFile.close();
add_message("游戏存档已加载成功!");
system("cls");
refresh_ui();
// 找到玩家在当前楼层的坐标,因为存档里没有存
bool player_pos_found = false;
for(int i = 0; i < MAP_ROWS; ++i) {
for (int j = 0; j < MAP_COLS; ++j) {
// 注意:玩家的位置不会被保存在地图字符中,所以我们需要一个逻辑来恢复它。
// 最简单的假设是玩家总是在传送门处。
// 一个更稳健的方法是保存玩家坐标。但既然没存,我们先用一个回退方案。
}
}
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
}
// --- 新增:用于地图生成的辅助结构体和函数 ---
// 代表一个房间的结构体
struct Room {
int x, y, w, h;
// 获取房间中心点
pair<int, int> center() const {
return {x + h / 2, y + w / 2};
}
// 检查此房间是否与另一个房间相交(重叠)
bool intersects(const Room& other) const {
return (x <= other.x + other.h && x + h >= other.x &&
y <= other.y + other.w && y + w >= other.y);
}
};
// 在两个点之间挖掘一条水平走廊
void carve_h_corridor(vector<string>& map, int y1, int y2, int x) {
for (int y = min(y1, y2); y <= max(y1, y2); ++y) {
map[x][y] = '.';
}
}
// 在两个点之间挖掘一条垂直走廊
void carve_v_corridor(vector<string>& map, int x1, int x2, int y) {
for (int x = min(x1, x2); x <= max(x1, x2); ++x) {
map[x][y] = '.';
}
}
// --- 结束新增 ---
// --- 新增:无尽模式函数 (已改进) ---
void generate_endless_map(int floor_level) {
endless_map.assign(MAP_ROWS, string(MAP_COLS, '#')); // 用墙填充
vector<Room> rooms;
// --- 1. 随机生成不重叠的房间 ---
int max_rooms = 12; // 增加房间数量上限
int min_rooms = 7; // 增加房间数量下限
int num_rooms_to_generate = rand() % (max_rooms - min_rooms + 1) + min_rooms;
for (int i = 0; i < num_rooms_to_generate; ++i) {
int room_w = rand() % 6 + 5; // 宽 5-10
int room_h = rand() % 5 + 4; // 高 4-8
int room_x = rand() % (MAP_ROWS - room_h - 2) + 1;
int room_y = rand() % (MAP_COLS - room_w - 2) + 1;
Room new_room = {room_x, room_y, room_w, room_h};
// 检查新房间是否与已存在的房间重叠
bool failed = false;
for (const auto& other_room : rooms) {
if (new_room.intersects(other_room)) {
failed = true;
break;
}
}
if (!failed) {
// 在地图上挖掘房间
for (int rx = new_room.x; rx < new_room.x + new_room.h; ++rx) {
for (int ry = new_room.y; ry < new_room.y + new_room.w; ++ry) {
endless_map[rx][ry] = '.';
}
}
rooms.push_back(new_room);
}
}
// 如果没有成功生成任何房间,则重新生成
if (rooms.empty()) {
generate_endless_map(floor_level);
return;
}
// --- 2. 用走廊连接所有房间 ---
for (size_t i = 1; i < rooms.size(); ++i) {
auto [prev_x, prev_y] = rooms[i - 1].center();
auto [new_x, new_y] = rooms[i].center();
// 随机决定是先挖横向还是纵向走廊,使地图更多样化
if (rand() % 2 == 1) {
carve_h_corridor(endless_map, prev_y, new_y, prev_x);
carve_v_corridor(endless_map, prev_x, new_x, new_y);
} else {
carve_v_corridor(endless_map, prev_x, new_x, prev_y);
carve_h_corridor(endless_map, prev_y, new_y, new_x);
}
}
// --- 3. 放置特殊物件 (入口、出口、守护者) ---
// 找到距离最远的两个房间,作为入口和出口
int start_room_idx = 0;
int end_room_idx = 0;
float max_dist = 0.0f;
for(size_t i = 0; i < rooms.size(); ++i) {
for(size_t j = i + 1; j < rooms.size(); ++j) {
auto [x1, y1] = rooms[i].center();
auto [x2, y2] = rooms[j].center();
float dist = sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
if (dist > max_dist) {
max_dist = dist;
start_room_idx = i;
end_room_idx = j;
}
}
}
// 放置入口 (回归门) 和玩家
auto [start_x, start_y] = rooms[start_room_idx].center();
endless_map[start_x][start_y] = 'R';
x_pos = start_x;
y_pos = start_y;
// 放置出口 (下一层) 和守护者
auto [end_x, end_y] = rooms[end_room_idx].center();
endless_map[end_x][end_y] = 'U';
// 将Boss放在出口附近,但不要覆盖出口
if (endless_map[end_x - 1][end_y] == '.') endless_map[end_x - 1][end_y] = 'B';
else if (endless_map[end_x + 1][end_y] == '.') endless_map[end_x + 1][end_y] = 'B';
else if (endless_map[end_x][end_y - 1] == '.') endless_map[end_x][end_y - 1] = 'B';
else endless_map[end_x][end_y + 1] = 'B'; // Fallback
// --- 4. 在房间内散布怪物和宝藏 ---
int monster_count = 5 + floor_level / 2;
int elite_count = 1 + floor_level / 4; // 精英怪少一些
int treasure_count = 2 + floor_level / 5;
int potion_count = 1 + floor_level / 6;
// 收集所有房间内的可用地块
vector<pair<int, int>> spawn_points;
for (const auto& room : rooms) {
// 在房间内部随机选择点,避开墙壁1格
for (int rx = room.x + 1; rx < room.x + room.h - 1; ++rx) {
for (int ry = room.y + 1; ry < room.y + room.w - 1; ++ry) {
if (endless_map[rx][ry] == '.') {
spawn_points.push_back({rx, ry});
}
}
}
}
// 打乱可用点,防止物品扎堆
random_shuffle(spawn_points.begin(), spawn_points.end());
auto place_object = [&](int count, char tile) {
for (int i = 0; i < count && !spawn_points.empty(); ++i) {
auto pos = spawn_points.back();
spawn_points.pop_back();
endless_map[pos.first][pos.second] = tile;
}
};
place_object(monster_count, (rand() % 3 == 0) ? 'G' : 'm'); // 强弱小怪
place_object(elite_count, 'E');
place_object(treasure_count, 'T');
place_object(potion_count, 'H');
endless_boss_defeated_this_floor = false; // 重置Boss击败状态
}
Monster get_endless_monster(int floor_level, char tile_type) {
Monster base_monster_template;
// 从 all_monster_templates_base 获取原始数据,避免受游戏轮次缩放影响
auto find_base_template = [&](MonsterType type_to_find) {
for (const auto& m : all_monster_templates_base) {
if (m.type == type_to_find) return m;
}
return all_monster_templates_base[0]; // Fallback
};
if (tile_type == 'B') {
// 随机选一个主线Boss作为模板
int boss_type_idx = rand() % 6; // 假设有6个主线Boss
MonsterType type = static_cast<MonsterType>(BOSS_GOBLIN_KING + boss_type_idx);
base_monster_template = find_base_template(type);
} else if (tile_type == 'E') {
// 从强力小怪中选一个做精英
vector<MonsterType> elite_pool = {BEAST, SKELETON, DEMON_GUARD, SHADOW_BEAST, ELITE_GUARD, VOID_RAVAGER};
base_monster_template = find_base_template(elite_pool[rand() % elite_pool.size()]);
base_monster_template.name = "精英 " + base_monster_template.name;
} else { // 'm' or 'G'
// 从所有小怪中选
vector<MonsterType> regular_pool;
for (const auto& m_template : all_monster_templates_base) {
if (m_template.type < BOSS_GOBLIN_KING) {
regular_pool.push_back(m_template.type);
}
}
base_monster_template = find_base_template(regular_pool[rand() % regular_pool.size()]);
}
Monster scaled_monster = base_monster_template;
// 根据无尽层数进行属性缩放
float scale_factor = 1.0f + 0.3f * (floor_level - 1);
float reward_scale = 1.0f + 0.2f * (floor_level - 1);
scaled_monster.max_hp = static_cast<int>(base_monster_template.max_hp * scale_factor);
scaled_monster.attack = static_cast<int>(base_monster_template.attack * scale_factor);
scaled_monster.defense = static_cast<int>(base_monster_template.defense * scale_factor);
scaled_monster.xp_reward = static_cast<int>(base_monster_template.xp_reward * reward_scale);
scaled_monster.gold_reward = static_cast<int>(base_monster_template.gold_reward * reward_scale);
// 精英怪和Boss有额外加成
if (tile_type == 'E') {
scaled_monster.max_hp = static_cast<int>(scaled_monster.max_hp * 1.5);
scaled_monster.attack = static_cast<int>(scaled_monster.attack * 1.2);
scaled_monster.xp_reward *= 2;
scaled_monster.gold_reward *= 2;
}
if (tile_type == 'B') {
scaled_monster.max_hp = static_cast<int>(scaled_monster.max_hp * 2.5);
scaled_monster.attack = static_cast<int>(scaled_monster.attack * 1.8);
scaled_monster.xp_reward *= 5;
scaled_monster.gold_reward *= 5;
}
return scaled_monster;
}
// --- 主函数 ---
int main() {
srand(time(0));
// --- 【关键修改点 1】---
// 按照这个顺序执行,确保控制台状态稳定
// 1. 设置控制台尺寸
COORD bufferSize = {MAP_COLS * 2 + SIDEBAR_WIDTH + 5, MAP_ROWS + 10 + 25};
SMALL_RECT windowSize = {0, 0, bufferSize.X - 1, bufferSize.Y - 1};
SetConsoleScreenBufferSize(hConsole, bufferSize);
SetConsoleWindowInfo(hConsole, TRUE, &windowSize);
// 2. 立即清屏以“固化”控制台状态,防止任何后续输出引起滚动
system("cls");
// 3. 隐藏光标
hide();
// 现在可以安全地开始显示游戏内容
display_game_intro();
initialize_base_templates();
reset_game_state();
choose_class();
current_hp = get_total_max_hp();
refresh_ui();
add_message("欢迎来到文字地牢!");
add_message("W,A,S,D移动,H使用药水,F使用技能。");
add_message("P保存游戏,L读取存档,Esc退出。");
add_message("探索地图,击败怪物,寻找宝藏!");
gotoxy(y_pos << 1, x_pos);
set_color(bright_white);
cout << "入";
bool game_running = true;
while (game_running) {
if (zxb(VK_ESCAPE)) {
game_running = false;
while(zxb(VK_ESCAPE));
}
if (zxb('W')) {
move_player(-1, 0);
this_thread::sleep_for(chrono::milliseconds(20));
}
if (zxb('A') ){
move_player(0, -1);
this_thread::sleep_for(chrono::milliseconds(20));
}
if (zxb('S')) {
move_player(1, 0);
this_thread::sleep_for(chrono::milliseconds(20));
}
if (zxb('D')) {
move_player(0, 1);
this_thread::sleep_for(chrono::milliseconds(20));
}
if (zxb('H')) {
if (inventory["生命药水"] <= 0) {
add_message("你没有生命药水了。");
} else if (current_hp == get_total_max_hp()) {
add_message("你的生命值已满。");
} else {
int heal_amount = get_total_max_hp() / 2;
current_hp = min(get_total_max_hp(), current_hp + heal_amount);
inventory["生命药水"]--;
add_message("你使用了药水,恢复生命!");
refresh_ui();
}
while(zxb('H'));
}
if (zxb('P')) {
save_game("save.txt");
while(zxb('P'));
}
if (zxb('L')) {
load_game("save.txt");
while(zxb('L'));
}
this_thread::sleep_for(chrono::milliseconds(20));
}
gotoxy(0, MAP_ROWS + 15);
set_color(white);
cout << "游戏结束。再见!" << endl;
return 0;
}