- gf25036 的博客
《章鱼&游戏之遗忘深渊 · 记忆追寻》cpp
- @ 2026-4-16 14:44:53
c++版的
需要Easy x库
#include <graphics.h>
#include <conio.h>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <algorithm>
#include <random>
#include <ctime>
using namespace std;
// ==================== 颜色定义 ====================
#define COLOR_BG 0x221C0A
#define COLOR_PANEL 0x2D2B1A
#define COLOR_BTN 0x4A5D3E
#define COLOR_BTN_HOVER 0x6B8C5A
#define COLOR_TEXT 0xEFE8C9
#define COLOR_HP 0xFF6B6B
#define COLOR_ENERGY 0xFFD93B
#define COLOR_CRYSTAL 0x6BCBFF
#define COLOR_BATTLE 0xFF8C42
#define COLOR_SKILL1 0x8B5A2B
#define COLOR_SKILL2 0x2B6B8B
#define COLOR_SKILL3 0x2B8B5A
#define COLOR_SKILL_ULT 0x8B2B6B
// ==================== 游戏数据 ====================
struct GameData {
string currentLocation = "回廊大厅";
int lampEnergy = 12;
int maxLamp = 12;
int hp = 36;
int maxHp = 36;
set<string> crystals;
vector<string> inventory;
bool inBattle = false;
int bossHp = 56;
int bossMaxHp = 56;
bool gameOver = false;
bool escaped = false;
bool ironShield = false;
vector<tuple<string, string, bool>> items = {
{"赤炎灵晶", "演武厅", false}, {"霜月灵晶", "书阁", false},
{"苍翠灵晶", "幽暗牢房", false}, {"紫霄灵晶", "星语祭坛", false},
{"曜金灵晶", "灵晶矿脉", false}, {"断刃匕首", "回廊大厅", false},
{"流光磨刀石", "演武厅", false}, {"灵灯余烬", "书阁", false},
{"残破卷轴", "星语祭坛", false}, {"魂晶碎块", "菌菇洞穴", false}
};
vector<string> locations = {"回廊大厅", "演武厅", "书阁", "幽暗牢房",
"星语祭坛", "菌菇洞穴", "灵晶矿脉", "玄光出口"};
map<string, vector<string>> exits = {
{"回廊大厅", {"演武厅", "书阁", "幽暗牢房"}},
{"演武厅", {"回廊大厅", "星语祭坛"}},
{"书阁", {"回廊大厅", "菌菇洞穴"}},
{"幽暗牢房", {"回廊大厅", "灵晶矿脉"}},
{"星语祭坛", {"演武厅"}},
{"菌菇洞穴", {"书阁", "玄光出口"}},
{"灵晶矿脉", {"幽暗牢房"}},
{"玄光出口", {"菌菇洞穴"}}
};
map<string, vector<string>> npcs = {
{"菌菇洞穴", {"黄炎硕"}}, {"星语祭坛", {"坤哥"}}, {"灵晶矿脉", {"章鱼"}}
};
map<string, vector<string>> npcDialogs = {
{"黄炎硕", {"白切鸡背叛了五灵!", "用魂晶碎块换情报。"}},
{"坤哥", {"集齐五晶才能对抗白切鸡。", "卷轴记载了五灵归一斩。"}},
{"章鱼", {"小黄,白切鸡就在出口等你。", "战斗时用大招可以重创他。"}}
};
map<string, string> npcSpecial = {
{"黄炎硕", "魂晶碎块"}, {"坤哥", "残破卷轴"}
};
};
GameData game;
mt19937 rng(time(0));
// 按钮结构
struct Button {
int x, y, w, h;
string text;
int color;
int hoverColor;
bool enabled;
function<void()> onClick;
void draw() {
if (!enabled) {
setfillcolor(0x333333);
} else {
int mx = getmousex(), my = getmousey();
if (mx >= x && mx <= x + w && my >= y && my <= y + h) {
setfillcolor(hoverColor);
} else {
setfillcolor(color);
}
}
solidroundrect(x, y, x + w, y + h, 10, 10);
setcolor(COLOR_TEXT);
setbkmode(TRANSPARENT);
settextstyle(18, 0, _T("微软雅黑"));
int tw = textwidth(text.c_str());
outtextxy(x + (w - tw) / 2, y + (h - 20) / 2, text.c_str());
}
bool isHover() {
int mx = getmousex(), my = getmousey();
return enabled && mx >= x && mx <= x + w && my >= y && my <= y + h;
}
};
vector<Button> mapButtons;
vector<Button> skillButtons;
Button takeBtn, combineBtn, resetBtn, talkBtn;
// 日志系统
vector<pair<string, int>> logs;
void addLog(const string& msg, int color = COLOR_TEXT) {
logs.insert(logs.begin(), {msg, color});
if (logs.size() > 20) logs.pop_back();
}
// ==================== 游戏逻辑 ====================
void refreshUI() {
// 重新创建地图按钮
mapButtons.clear();
int bx = 30, by = 200;
for (int i = 0; i < game.locations.size(); i++) {
string loc = game.locations[i];
bool canGo = false;
for (const auto& e : game.exits[game.currentLocation]) {
if (e == loc) canGo = true;
}
Button btn;
btn.x = bx + (i % 4) * 110;
btn.y = by + (i / 4) * 55;
btn.w = 100;
btn.h = 45;
btn.text = (loc == game.currentLocation) ? loc + " ?" : loc;
btn.color = (loc == game.currentLocation) ? COLOR_SKILL_ULT : COLOR_BTN;
btn.hoverColor = COLOR_BTN_HOVER;
btn.enabled = canGo && !game.inBattle && !game.gameOver;
btn.onClick = [loc]() {
if (game.lampEnergy <= 0) {
addLog("灵灯能量耗尽!", COLOR_BATTLE);
return;
}
game.lampEnergy--;
game.currentLocation = loc;
addLog("?? 来到 " + loc);
// 自动拾取灵晶(简化)
for (auto& item : game.items) {
if (get<1>(item) == loc && !get<2>(item) && get<0>(item).find("灵晶") != string::npos) {
get<2>(item) = true;
game.inventory.push_back(get<0>(item));
game.crystals.insert(get<0>(item));
addLog("?? 获得 " + get<0>(item) + "! (" + to_string(game.crystals.size()) + "/5)", COLOR_CRYSTAL);
}
}
if (loc == "玄光出口" && game.crystals.size() >= 5 && !game.inBattle) {
game.inBattle = true;
game.bossHp = game.bossMaxHp;
addLog("?? 白切鸡挡住了去路!战斗开始!", COLOR_BATTLE);
}
refreshUI();
};
mapButtons.push_back(btn);
}
// 技能按钮
skillButtons.clear();
const char* skillNames[] = {"?? 崩拳", "?? 疾风连打", "??? 铁壁", "?? 五灵归一斩"};
int skillColors[] = {COLOR_SKILL1, COLOR_SKILL2, COLOR_SKILL3, COLOR_SKILL_ULT};
for (int i = 0; i < 4; i++) {
Button btn;
btn.x = 30 + i * 110;
btn.y = 520;
btn.w = 100;
btn.h = 45;
btn.text = skillNames[i];
btn.color = skillColors[i];
btn.hoverColor = COLOR_BTN_HOVER;
btn.enabled = game.inBattle && !game.gameOver;
btn.onClick = [i]() {
if (!game.inBattle) return;
int cost = (i == 3) ? 2 : 1;
if (game.lampEnergy < cost) {
addLog("灵灯不足!", COLOR_BATTLE);
return;
}
game.lampEnergy -= cost;
if (i == 2) { // 铁壁
int heal = 12;
game.hp = min(game.maxHp, game.hp + heal);
game.ironShield = true;
addLog("??? 铁壁恢复 " + to_string(heal) + " 生命!");
} else {
uniform_int_distribution<int> dmgDist((i == 0) ? 12 : (i == 1) ? 18 : 30,
(i == 0) ? 18 : (i == 1) ? 28 : 48);
int damage = dmgDist(rng);
uniform_int_distribution<int> critDist(1, 100);
if (critDist(rng) <= 20) {
damage = damage * 1.5;
addLog("? 暴击!");
}
if (i == 1 && critDist(rng) <= 25) {
damage += damage * 0.5;
addLog("?? 连击触发!");
}
game.bossHp -= damage;
addLog("? 使用" + string((i == 0) ? "崩拳" : (i == 1) ? "疾风连打" : "五灵归一斩") +
" 造成 " + to_string(damage) + " 伤害!");
}
if (game.bossHp <= 0) {
addLog("?? 击败白切鸡!逃离深渊!", COLOR_CRYSTAL);
game.inBattle = false;
game.escaped = true;
game.gameOver = true;
refreshUI();
return;
}
// 敌人反击
uniform_int_distribution<int> bossDist(7, 15);
int bossDmg = bossDist(rng);
if (i == 3) bossDmg = max(4, bossDmg - 5);
if (game.ironShield) {
bossDmg /= 2;
addLog("??? 铁壁减伤!");
game.ironShield = false;
}
game.hp -= bossDmg;
addLog("?? 白切鸡反击造成 " + to_string(bossDmg) + " 伤害!", COLOR_BATTLE);
if (game.hp <= 0) {
addLog("?? 小黄被击败了...", COLOR_BATTLE);
game.gameOver = true;
}
refreshUI();
};
skillButtons.push_back(btn);
}
// 操作按钮
takeBtn = {30, 580, 110, 40, "?? 拾取", COLOR_BTN, COLOR_BTN_HOVER,
!game.inBattle && !game.gameOver, []() {
for (auto& item : game.items) {
if (get<1>(item) == game.currentLocation && !get<2>(item)) {
get<2>(item) = true;
game.inventory.push_back(get<0>(item));
if (get<0>(item).find("灵晶") != string::npos) {
game.crystals.insert(get<0>(item));
addLog("?? 获得 " + get<0>(item) + "! (" + to_string(game.crystals.size()) + "/5)", COLOR_CRYSTAL);
} else {
addLog("? 获得 " + get<0>(item));
}
refreshUI();
return;
}
}
addLog("这里没有可拾取的物品");
}};
combineBtn = {150, 580, 110, 40, "?? 合成", COLOR_BTN, COLOR_BTN_HOVER,
!game.inBattle && !game.gameOver, []() {
auto hasDagger = find(game.inventory.begin(), game.inventory.end(), "断刃匕首") != game.inventory.end();
auto hasStone = find(game.inventory.begin(), game.inventory.end(), "流光磨刀石") != game.inventory.end();
if (hasDagger && hasStone) {
game.inventory.erase(find(game.inventory.begin(), game.inventory.end(), "断刃匕首"));
game.inventory.erase(find(game.inventory.begin(), game.inventory.end(), "流光磨刀石"));
game.inventory.push_back("破晓短刃");
addLog("?? 合成成功!获得破晓短刃!");
} else {
addLog("需要断刃匕首和流光磨刀石");
}
refreshUI();
}};
resetBtn = {270, 580, 110, 40, "?? 重置", COLOR_BTN, COLOR_BTN_HOVER, true, []() {
game = GameData();
addLog("?? 游戏已重置!");
refreshUI();
}};
talkBtn = {390, 580, 110, 40, "?? 对话", COLOR_BTN, COLOR_BTN_HOVER,
!game.inBattle && !game.gameOver, []() {
if (game.npcs.count(game.currentLocation)) {
string npc = game.npcs[game.currentLocation][0];
// 检查特殊物品
if (game.npcSpecial.count(npc)) {
auto it = find(game.inventory.begin(), game.inventory.end(), game.npcSpecial[npc]);
if (it != game.inventory.end()) {
game.inventory.erase(it);
addLog("?? " + npc + ": \"获得战斗增益!\"");
refreshUI();
return;
}
}
vector<string> dialogs = game.npcDialogs[npc];
addLog("?? " + npc + ": \"" + dialogs[rand() % dialogs.size()] + "\"");
} else {
addLog("这里没有人可以对话");
}
}};
}
// ==================== 绘图函数 ====================
void draw() {
cleardevice();
// 背景
setfillcolor(COLOR_BG);
solidrectangle(0, 0, 800, 700);
// 标题
setcolor(COLOR_CRYSTAL);
settextstyle(28, 0, _T("微软雅黑"));
outtextxy(200, 15, _T("?? 遗忘深渊 · 小黄 VS 白切鸡 ??"));
// 状态栏
setfillcolor(COLOR_PANEL);
solidroundrect(20, 60, 780, 120, 15, 15);
char status[256];
sprintf(status, "?? 小黄 %d/%d ?? 灵灯 %d/%d ?? 灵晶 %d/5 ?? %s",
game.hp, game.maxHp, game.lampEnergy, game.maxLamp,
(int)game.crystals.size(), game.currentLocation.c_str());
setcolor(COLOR_TEXT);
settextstyle(20, 0, _T("微软雅黑"));
outtextxy(40, 85, status);
// 血量条
setfillcolor(0x442222);
solidrectangle(40, 115, 40 + 200, 130);
setfillcolor(COLOR_HP);
solidrectangle(40, 115, 40 + 200 * game.hp / game.maxHp, 130);
// 灵灯条
setfillcolor(0x443300);
solidrectangle(260, 115, 260 + 150, 130);
setfillcolor(COLOR_ENERGY);
solidrectangle(260, 115, 260 + 150 * game.lampEnergy / game.maxLamp, 130);
// 地图区域标题
setcolor(COLOR_TEXT);
settextstyle(16, 0, _T("微软雅黑"));
outtextxy(30, 165, _T("??? 深渊地图 (点击移动)"));
// 绘制地图按钮
for (auto& btn : mapButtons) btn.draw();
// 背包区域
setfillcolor(COLOR_PANEL);
solidroundrect(30, 430, 400, 510, 10, 10);
outtextxy(35, 440, _T("?? 背包"));
int iy = 465;
for (const auto& item : game.inventory) {
setcolor(COLOR_CRYSTAL);
outtextxy(40, iy, item.c_str());
iy += 22;
}
// NPC区域
solidroundrect(410, 430, 780, 510, 10, 10);
outtextxy(415, 440, _T("?? 角色"));
iy = 465;
if (game.npcs.count(game.currentLocation)) {
for (const auto& npc : game.npcs[game.currentLocation]) {
setcolor(COLOR_SKILL2);
outtextxy(420, iy, npc.c_str());
iy += 22;
}
} else {
setcolor(0x888888);
outtextxy(420, 465, _T("无人在此"));
}
// 技能区域
if (game.inBattle) {
setfillcolor(COLOR_BATTLE);
solidroundrect(20, 510, 780, 560, 10, 10);
setcolor(COLOR_TEXT);
char bossHpStr[100];
sprintf(bossHpStr, "?? 白切鸡 HP: %d/%d", game.bossHp, game.bossMaxHp);
outtextxy(30, 522, bossHpStr);
}
for (auto& btn : skillButtons) btn.draw();
takeBtn.draw();
combineBtn.draw();
resetBtn.draw();
talkBtn.draw();
// 日志区域
solidroundrect(20, 635, 780, 690, 10, 10);
int ly = 645;
for (int i = 0; i < min((int)logs.size(), 6); i++) {
setcolor(logs[i].second);
outtextxy(30, ly, logs[i].first.c_str());
ly += 22;
}
// 胜利/失败提示
if (game.gameOver) {
if (game.escaped) {
setcolor(COLOR_CRYSTAL);
settextstyle(36, 0, _T("微软雅黑"));
outtextxy(250, 300, _T("?? 胜利!逃离深渊! ??"));
} else if (game.hp <= 0) {
setcolor(COLOR_BATTLE);
settextstyle(36, 0, _T("微软雅黑"));
outtextxy(250, 300, _T("?? 游戏结束 ??"));
}
}
}
// ==================== 主函数 ====================
int main() {
initgraph(800, 700);
setbkcolor(COLOR_BG);
srand(time(0));
addLog("?? 小黄 VS 白切鸡 - 点击式游戏");
addLog("?? 目标:集齐5枚灵晶,前往玄光出口决战!");
addLog("?? 点击地图移动,点击技能战斗");
refreshUI();
ExMessage msg;
while (true) {
draw();
if (peekmessage(&msg, EM_MOUSE)) {
if (msg.message == WM_LBUTTONDOWN) {
// 检查所有按钮
for (auto& btn : mapButtons) {
if (btn.isHover() && btn.enabled) btn.onClick();
}
for (auto& btn : skillButtons) {
if (btn.isHover() && btn.enabled) btn.onClick();
}
if (takeBtn.isHover() && takeBtn.enabled) takeBtn.onClick();
if (combineBtn.isHover() && combineBtn.enabled) combineBtn.onClick();
if (resetBtn.isHover() && resetBtn.enabled) resetBtn.onClick();
if (talkBtn.isHover() && talkBtn.enabled) talkBtn.onClick();
}
}
Sleep(16);
}
closegraph();
return 0;
}