给木 26.1

《给木》

26.1 snapshot 1

警告:该版本中代码有严重漏洞:第一行显示版本不可过编译。删去即可。不做改动。

26.1 snapshot 1

#include<cstdio>
#include<random>
#include<ctime>
#include<queue>
#include<cmath>
#include<windows.h>
#include<conio.h>
using namespace std;
#define Rnd(a,b) rnd()%(b-a+1)+a
#define color(a) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a) 
void cls(){
    HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hStdOut == INVALID_HANDLE_VALUE)
        return;
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
        return;
    DWORD count;
    DWORD cellCount = csbi.dwSize.X * csbi.dwSize.Y;
    COORD homeCoords = {0, 0};
    FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count);
    FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count);
    SetConsoleCursorPosition(hStdOut, homeCoords);
}
void go_to (int x, int y){
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coordScreen = {(short)y, (short)x};
    SetConsoleCursorPosition(hConsole, coordScreen);
}
int GetDisplayWidth(const char* str) {
    int width = 0;
    int len = strlen(str);
    
    for (int i = 0; i < len; i++) {
        unsigned char c = (unsigned char)str[i];
        if (c >= 0x81 && c <= 0xFE) {
            if (i + 1 < len) {
                unsigned char c2 = (unsigned char)str[i + 1];
                if ((c2 >= 0x40 && c2 <= 0x7E) || (c2 >= 0x80 && c2 <= 0xFE)) {
                    width += 2;
                    i++;
                    continue;
                }
            }
        }
        width += 1;
    }
    
    return width;
}
struct ConsoleSize {
    int Width;   // 可见列数
    int Height;  // 可见行数
    int BufferWidth;   // 缓冲区总列数
    int BufferHeight;  // 缓冲区总行数
};
ConsoleSize GetAdvancedConsoleSize() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    ConsoleSize size = {80, 25, 80, 300}; // 默认
    
    if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
        // 可见窗口区域(用户当前看到的)
        size.Width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        size.Height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
        // 缓冲区大小(实际可绘制的范围)
        size.BufferWidth = csbi.dwSize.X;
        size.BufferHeight = csbi.dwSize.Y;
    }
    return size;
}
std::mt19937 rnd(time(NULL));

const int N = 10010;
int WEAPON_COUNT, MOB_COUNT;
int MAX_LINE = 10;

struct PLAYER {
    int att = 100;
    int choose_weapon;
    int speed = 100;
} player;

struct MOB {
    int heal;
} mobs[N];

struct WEAPON {
    int att;
} weapons[N];

bool fight (int mob) {
    int heal = mobs[mob].heal;
    int now_heal = heal;
    int round_cnt = 0;
    char output_data[N][110];

    cls();
    sprintf(output_data[0], "--- ENEMY %5d/%-5d %3d%%---", now_heal, heal, now_heal * 100 / heal);
    printf("%s\n", output_data[0]);
    while (now_heal > 0) {
        round_cnt ++;

        int wait_time = 100000 / player.speed; // 攻击速度
        int real_att = player.att + weapons[player.choose_weapon].att; // 真实伤害
        int caused = min (real_att, now_heal); // 真实造成的真实伤害
        now_heal -= caused; // 剩余血量

        Sleep (wait_time);
        sprintf(output_data[0], "--- ENEMY %5d/%-5d %3d%%---", now_heal, heal, now_heal * 100 / heal);
        sprintf(output_data[round_cnt], "%2d: You dealt %d damage to the enemy. ", round_cnt, caused);

        go_to (0, 0);
        printf("%s\n", output_data[0]);
        int line_cnt = MAX_LINE - 1;
        int start;
        if (line_cnt >= round_cnt) start = 1;
        else start = round_cnt - line_cnt + 1;
        for (int i = start; i <= round_cnt; i ++) {
            printf("%s\n", output_data[i]);
        }
    }
    return true;
}

void test_mode () {
    player.att = 50;
    player.speed = 200;
    WEAPON_COUNT = 1;
    weapons[1].att = 10;
    player.choose_weapon = 1;
    MOB_COUNT = 1;
    mobs[1].heal = 1000;
}

int main () {

    test_mode();

    fight(1);
    return 0;
}

26.1 snapshot 2

26.1 snapshot 2

/*
当前版本:26.1 snapshot 2

2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。  
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。  
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。

- 26.1
    - snapshot 1, 2026-07-12
        - 正式开服,现在十分简陋,但是能看。有了与怪物战斗能力,但是目前只有攻击力和攻击速度两个属性。
    - snapshot 2, 2026-07-12
        - 现在增加了滚动系统,控制台最多显示十行。
        - ~~为了展示滚动算法的先进性~~输出信息会额外输出回合数。
        - 修复了一个漏洞
            - 当输出行数超过控制台行数时,输出内容会错误地覆盖之前的信息。
*/
#include<cstdio>
#include<random>
#include<ctime>
#include<queue>
#include<cmath>
#include<windows.h>
#include<conio.h>
using namespace std;
#define Rnd(a,b) rnd()%(b-a+1)+a
#define color(a) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a) 
void cls(){
    HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hStdOut == INVALID_HANDLE_VALUE)
        return;
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
        return;
    DWORD count;
    DWORD cellCount = csbi.dwSize.X * csbi.dwSize.Y;
    COORD homeCoords = {0, 0};
    FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count);
    FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count);
    SetConsoleCursorPosition(hStdOut, homeCoords);
}
void go_to (int x, int y){
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coordScreen = {(short)y, (short)x};
    SetConsoleCursorPosition(hConsole, coordScreen);
}
int GetDisplayWidth(const char* str) {
    int width = 0;
    int len = strlen(str);
    
    for (int i = 0; i < len; i++) {
        unsigned char c = (unsigned char)str[i];
        if (c >= 0x81 && c <= 0xFE) {
            if (i + 1 < len) {
                unsigned char c2 = (unsigned char)str[i + 1];
                if ((c2 >= 0x40 && c2 <= 0x7E) || (c2 >= 0x80 && c2 <= 0xFE)) {
                    width += 2;
                    i++;
                    continue;
                }
            }
        }
        width += 1;
    }
    
    return width;
}
struct ConsoleSize {
    int Width;   // 可见列数
    int Height;  // 可见行数
    int BufferWidth;   // 缓冲区总列数
    int BufferHeight;  // 缓冲区总行数
};
ConsoleSize GetAdvancedConsoleSize() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    ConsoleSize size = {80, 25, 80, 300}; // 默认
    
    if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
        // 可见窗口区域(用户当前看到的)
        size.Width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        size.Height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
        // 缓冲区大小(实际可绘制的范围)
        size.BufferWidth = csbi.dwSize.X;
        size.BufferHeight = csbi.dwSize.Y;
    }
    return size;
}
std::mt19937 rnd(time(NULL));

const int N = 10010;
int WEAPON_COUNT, MOB_COUNT;
int MAX_LINE = 10;

struct PLAYER {
    int att = 100;
    int choose_weapon;
    int speed = 100;
} player;

struct MOB {
    int heal;
} mobs[N];

struct WEAPON {
    int att;
} weapons[N];

bool fight (int mob) {
    int heal = mobs[mob].heal;
    int now_heal = heal;
    int round_cnt = 0;
    char output_data[N][110];

    cls();
    sprintf(output_data[0], "--- ENEMY %5d/%-5d %3d%%---", now_heal, heal, now_heal * 100 / heal);
    printf("%s\n", output_data[0]);
    while (now_heal > 0) {
        round_cnt ++;

        int wait_time = 100000 / player.speed; // 攻击速度
        int real_att = player.att + weapons[player.choose_weapon].att; // 真实伤害
        int caused = min (real_att, now_heal); // 真实造成的真实伤害
        now_heal -= caused; // 剩余血量

        Sleep (wait_time);
        sprintf(output_data[0], "--- ENEMY %5d/%-5d %3d%%---", now_heal, heal, now_heal * 100 / heal);
        sprintf(output_data[round_cnt], "%2d: You dealt %d damage to the enemy. ", round_cnt, caused);

        go_to (0, 0);
        printf("%s\n", output_data[0]);
        int line_cnt = MAX_LINE - 1;
        int start;
        if (line_cnt >= round_cnt) start = 1;
        else start = round_cnt - line_cnt + 1;
        for (int i = start; i <= round_cnt; i ++) {
            printf("%s\n", output_data[i]);
        }
    }
    return true;
}

void test_mode () {
    player.att = 50;
    player.speed = 200;
    WEAPON_COUNT = 1;
    weapons[1].att = 10;
    player.choose_weapon = 1;
    MOB_COUNT = 1;
    mobs[1].heal = 1000;
}

int main () {

    test_mode();

    fight(1);
    return 0;
}

26.1 snapshot 3

/*
当前版本:26.1 snapshot 3

2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。  
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。  
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。

通知:后续更新日志在程序里,运行即可看到。下方变成了评论区。可以评论。记得署名

- 26.1
    - snapshot 1, 2026-07-12
		评价:有剧情吗就开服——Derekyang
    - snapshot 2, 2026-07-12
		评价:把主体做出来好吗,不要只放一个战斗模块——Derekyang
    - snapshot 3, 2026-07-13
*/
#include<cstdio>
#include<random>
#include<ctime>
#include<queue>
#include<cmath>
#include<windows.h>
#include<conio.h>
using namespace std;
#define Rnd(a,b) rnd()%(b-a+1)+a
#define color(a) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a) 
#define Key_down(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
void cls(){
    // HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    // if (hStdOut == INVALID_HANDLE_VALUE)
    //     return;
    // CONSOLE_SCREEN_BUFFER_INFO csbi;
    // if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
    //     return;
    // DWORD count;
    // DWORD cellCount = csbi.dwSize.X * csbi.dwSize.Y;
    // COORD homeCoords = {0, 0};
    // FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count);
    // FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count);
    // SetConsoleCursorPosition(hStdOut, homeCoords);
    system("cls");
}
void press_any_key_to_continue () {
	// while (_kbhit ()) {
	// 	getch();
	// } rewind (stdin);
	// while (1) if (kbhit ()) break;
	// return ;
    char c = _getch();
    return ;
} void clear_stdin(void) {
    while (_kbhit ()) {
		getch();
	} rewind (stdin);

    // int c;
    // while ((c = getchar()) != '\n' && c != EOF) {
    // }
}
void HideCursor(){
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void ShowCursor(){
	CONSOLE_CURSOR_INFO cur={1,1};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void go_to (int x, int y){
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coordScreen = {(short)y, (short)x};
    SetConsoleCursorPosition(hConsole, coordScreen);
}
int GetDisplayWidth(const char* str) {
    int width = 0;
    int len = strlen(str);
    
    for (int i = 0; i < len; i++) {
        unsigned char c = (unsigned char)str[i];
        if (c >= 0x81 && c <= 0xFE) {
            if (i + 1 < len) {
                unsigned char c2 = (unsigned char)str[i + 1];
                if ((c2 >= 0x40 && c2 <= 0x7E) || (c2 >= 0x80 && c2 <= 0xFE)) {
                    width += 2;
                    i++;
                    continue;
                }
            }
        }
        width += 1;
    }
    
    return width;
}
struct ConsoleSize {
    int Width;   // 可见列数
    int Height;  // 可见行数
    int BufferWidth;   // 缓冲区总列数
    int BufferHeight;  // 缓冲区总行数
};
ConsoleSize GetAdvancedConsoleSize() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    ConsoleSize size = {80, 25, 80, 300}; // 默认
    
    if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
        // 可见窗口区域(用户当前看到的)
        size.Width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        size.Height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
        // 缓冲区大小(实际可绘制的范围)
        size.BufferWidth = csbi.dwSize.X;
        size.BufferHeight = csbi.dwSize.Y;
    }
    return size;
}
std::mt19937 rnd(time(NULL));

char change_logs[100000] = {"\
当前版本:26.1 snapshot 3\n\
2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。\n\
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。\n\
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。\n\
\n\
开发者:jessy\n\
特邀嘉宾:DEREKYANG\n\
\n\
- 26.1\n\
    - snapshot 1, 2026-07-12\n\
        - 正式开服,现在十分简陋,但是能看。有了与怪物战斗能力,但是目前只有攻击力和攻击速度两个属性。\n\
    - snapshot 2, 2026-07-12\n\
        - 现在增加了滚动系统,控制台最多显示十行。\n\
        - ~~为了展示滚动算法的先进性~~输出信息会额外输出回合数。\n\
        - 修复了一个漏洞\n\
            - 当输出行数超过控制台行数时,输出内容会错误地覆盖之前的信息。\n\
    - snapshot 3, 2026-07-13\n\
        - 新增了主页。\n\
        - 新增了沙盒模式,玩家可以随意调控目前的战斗参数,而不是调源代码。\n\
        - 新增了更新日志。以后更新日志都会放到那里。\n\
        - 新增了查看背包功能。自己点进去看看吧。我啷个晓得嘛\n\
"};

const int N = 10010;
int WEAPON_COUNT, MOB_COUNT;
int MAX_LINE = 10;

struct PLAYER {
    int att = 100;
    int choose_weapon;
    int speed = 100;
} player;

struct MOB {
    int heal;
} mobs[N];

struct WEAPON {
    int att;
} weapons[N];

bool fight (int mob) {
    int heal = mobs[mob].heal;
    int now_heal = heal;
    int round_cnt = 0;
    char output_data[1010][110];

    cls();
    sprintf(output_data[0], "--- ENEMY %5d/%-5d %3d%%---", now_heal, heal, now_heal * 100 / heal);
    printf("%s\n", output_data[0]);
    while (now_heal > 0) {
        round_cnt ++;

        int wait_time = 100000 / player.speed; // 攻击速度
        int real_att = player.att + weapons[player.choose_weapon].att; // 真实伤害
        int caused = min (real_att, now_heal); // 真实造成的真实伤害
        now_heal -= caused; // 剩余血量

        Sleep (wait_time);
        sprintf(output_data[0], "--- ENEMY %5d/%-5d %3d%%---", now_heal, heal, now_heal * 100 / heal);
        sprintf(output_data[round_cnt], "%2d: You dealt %d damage to the enemy. ", round_cnt, caused);

        go_to (0, 0);
        printf("%s\n", output_data[0]);
        int line_cnt = MAX_LINE - 1;
        int start;
        if (line_cnt >= round_cnt) start = 1;
        else start = round_cnt - line_cnt + 1;
        for (int i = start; i <= round_cnt; i ++) {
            printf("%s\n", output_data[i]);
        }
    }
    sprintf(output_data[0], "You won the enemy. Press any key to continue.");
    go_to (0, 0);
    printf("%s\n", output_data[0]);
    int line_cnt = MAX_LINE - 1;
    int start;
    if (line_cnt >= round_cnt) start = 1;
    else start = round_cnt - line_cnt + 1;
    for (int i = start; i <= round_cnt; i ++) {
        printf("%s\n", output_data[i]);
    }

    clear_stdin();
    press_any_key_to_continue();
    return true;
}

void check_bag () {
    cls();
    printf("Stay tuned, champ.\n");
    press_any_key_to_continue();
}

void change_log () {
    cls();
    printf("%s", change_logs);
    press_any_key_to_continue();
}

void sandbox () {
    char output_data[30][110];
    int chs = 1;
    int len = 5;

    sprintf(output_data[0], "--- geimu sandbox --- (press [Enter] to change)");
    sprintf(output_data[1], "%c enemy health: %d", chs == 1 ? '>' : ' ', mobs[1].heal);
    sprintf(output_data[2], "%c player attack: %d", chs == 2 ? '>' : ' ', player.att);
    sprintf(output_data[3], "%c player attack speed: %.2lfps", chs == 3 ? '>' : ' ', player.speed / 100.0);
    sprintf(output_data[4], "%c weapon attack: %d", chs == 4 ? '>' : ' ', weapons[1].att);
    sprintf(output_data[5], "%c i'm ready.", chs == 5 ? '>' : ' ');
    cls ();
    for (int i = 0; i <= len; i ++) {
        printf("%s\n", output_data[i]);
    } while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                go_to (len + 2, 0);
                printf("input enemy health: ");
                ShowCursor();
                scanf("%d", &mobs[1].heal);
                mobs[1].heal = max (mobs[1].heal, 0);
                sprintf(output_data[1], "%c enemy health: %d", chs == 1 ? '>' : ' ', mobs[1].heal);
            } else if (chs == 2) {
                go_to (len + 2, 0);
                printf("input player attack: ");
                ShowCursor();
                scanf("%d", &player.att);
                player.att = max (player.att, 0);
                sprintf(output_data[2], "%c player attack: %d", chs == 2 ? '>' : ' ', player.att);
            } else if (chs == 3) {
                double tmp;
                go_to (len + 2, 0);
                printf("input player attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                player.speed = max (tmp, 0.0) * 100;
                sprintf(output_data[3], "%c player attack speed: %.2lfps", chs == 3 ? '>' : ' ', player.speed / 100.0);
            } else if (chs == 4) {
                go_to (len + 2, 0);
                printf("input weapon attack: ");
                ShowCursor();
                scanf("%d", &weapons[1].att);
                weapons[1].att = max(weapons[1].att, 0);
                sprintf(output_data[4], "%c weapon attack: %d", chs == 4 ? '>' : ' ', weapons[1].att);
            } else if (chs == 5) {
                fight(1);
                return ;
            } cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin(); HideCursor();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
    }
}

void home_page () {
    char output_data[30][110];
    int chs = 1;
    int len = 3;

    sprintf (output_data[0], "Welecome to the game \"geimu\"!");
    sprintf (output_data[1], "%c Check bag", chs == 1 ? '>' : ' ');
    sprintf (output_data[2], "%c Create a sandbox", chs == 2 ? '>' : ' ');
    sprintf (output_data[3], "%c Change log", chs == 3 ? '>' : ' ');
    cls ();
    printf("%s\n", output_data[0]);
    Sleep (500);
    for (int i = 1; i <= len; i ++) printf("%s\n", output_data[i]);
    clear_stdin();
    while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            cls();
            if (chs == 1) {
                check_bag ();
            } else if (chs == 2) {
                sandbox();
            } else {
                change_log ();
            }
            cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
        // Sleep (100);
    }
}

void test_mode () {
    player.att = 100;
    player.speed = 100;
    WEAPON_COUNT = 1;
    weapons[1].att = 10;
    player.choose_weapon = 1;
    MOB_COUNT = 1;
    mobs[1].heal = 1000;
}

int main () {

    test_mode();

    HideCursor();

    home_page ();

    // fight(1);
    return 0;
}

26.1 snapshot 4

注:开发者在发布前忘记修改代码开头的版本记录了。但是更新日志中更新了新版本的更新内容。不做改动。

/*
当前版本:26.1 snapshot 3

2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。  
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。  
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。

通知:后续更新日志在程序里,运行即可看到。下方变成了评论区。可以评论。记得署名

- 26.1
    - snapshot 1, 2026-07-12
		评价:有剧情吗就开服——Derekyang
    - snapshot 2, 2026-07-12
		评价:把主体做出来好吗,不要只放一个战斗模块——Derekyang
    - snapshot 3, 2026-07-13
*/
#include<cstdio>
#include<random>
#include<ctime>
#include<queue>
#include<cmath>
#include<windows.h>
#include<conio.h>
using namespace std;
#define Rnd(a,b) rnd()%(b-a+1)+a
#define color(a) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a) 
#define Key_down(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
void cls(){
    // HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    // if (hStdOut == INVALID_HANDLE_VALUE)
    //     return;
    // CONSOLE_SCREEN_BUFFER_INFO csbi;
    // if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
    //     return;
    // DWORD count;
    // DWORD cellCount = csbi.dwSize.X * csbi.dwSize.Y;
    // COORD homeCoords = {0, 0};
    // FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count);
    // FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count);
    // SetConsoleCursorPosition(hStdOut, homeCoords);
    system("cls");
}
void press_any_key_to_continue () {
	// while (_kbhit ()) {
	// 	getch();
	// } rewind (stdin);
	// while (1) if (kbhit ()) break;
	// return ;
    char c = _getch();
    return ;
} void clear_stdin(void) {
    while (_kbhit ()) {
		getch();
	} rewind (stdin);

    // int c;
    // while ((c = getchar()) != '\n' && c != EOF) {
    // }
}
void HideCursor(){
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void ShowCursor(){
	CONSOLE_CURSOR_INFO cur={1,1};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void go_to (int x, int y){
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coordScreen = {(short)y, (short)x};
    SetConsoleCursorPosition(hConsole, coordScreen);
}
int GetDisplayWidth(const char* str) {
    int width = 0;
    int len = strlen(str);
    
    for (int i = 0; i < len; i++) {
        unsigned char c = (unsigned char)str[i];
        if (c >= 0x81 && c <= 0xFE) {
            if (i + 1 < len) {
                unsigned char c2 = (unsigned char)str[i + 1];
                if ((c2 >= 0x40 && c2 <= 0x7E) || (c2 >= 0x80 && c2 <= 0xFE)) {
                    width += 2;
                    i++;
                    continue;
                }
            }
        }
        width += 1;
    }
    
    return width;
}
struct ConsoleSize {
    int Width;   // 可见列数
    int Height;  // 可见行数
    int BufferWidth;   // 缓冲区总列数
    int BufferHeight;  // 缓冲区总行数
};
ConsoleSize GetAdvancedConsoleSize() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    ConsoleSize size = {80, 25, 80, 300}; // 默认
    
    if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
        // 可见窗口区域(用户当前看到的)
        size.Width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        size.Height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
        // 缓冲区大小(实际可绘制的范围)
        size.BufferWidth = csbi.dwSize.X;
        size.BufferHeight = csbi.dwSize.Y;
    }
    return size;
}
std::mt19937 rnd(time(NULL));

char change_logs[100000] = {"\
当前版本:26.1 snapshot 3\n\
2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。\n\
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。\n\
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。\n\
\n\
开发者:jessy\n\
特邀嘉宾:DEREKYANG\n\
\n\
- 26.1\n\
    - snapshot 1, 2026-07-12\n\
        - 正式开服,现在十分简陋,但是能看。有了与怪物战斗能力,但是目前只有攻击力和攻击速度两个属性。\n\
    - snapshot 2, 2026-07-12\n\
        - 现在增加了滚动系统,控制台最多显示十行。\n\
        - ~~为了展示滚动算法的先进性~~输出信息会额外输出回合数。\n\
        - 修复了一个漏洞\n\
            - 当输出行数超过控制台行数时,输出内容会错误地覆盖之前的信息。\n\
    - snapshot 3, 2026-07-13\n\
        - 新增了主页。\n\
        - 新增了沙盒模式,玩家可以随意调控目前的战斗参数,而不是调源代码。\n\
        - 新增了更新日志。以后更新日志都会放到那里。\n\
        - 新增了查看背包功能。自己点进去看看吧。我啷个晓得嘛\n\
    - snapshot 4, 2026-07-13\n\
        - 紧急更新:修复了一个漏洞\n\
            - 当敌人生命超过int存储上限的1%时,游戏计算出错。\b\
"};

const int N = 10010;
int WEAPON_COUNT, MOB_COUNT;
int MAX_LINE = 10;

struct PLAYER {
    int att = 100;
    int choose_weapon;
    int speed = 100;
} player;

struct MOB {
    int heal;
} mobs[N];

struct WEAPON {
    int att;
} weapons[N];

bool fight (int mob) {
    int heal = mobs[mob].heal;
    int now_heal = heal;
    int round_cnt = 0;
    char output_data[1010][110];

    cls();
    sprintf(output_data[0], "--- ENEMY %5d/%-5d %3d%%---", now_heal, heal, now_heal * 100 / heal);
    printf("%s\n", output_data[0]);
    while (now_heal > 0) {
        round_cnt ++;

        int wait_time = 100000 / player.speed; // 攻击速度
        int real_att = player.att + weapons[player.choose_weapon].att; // 真实伤害
        int caused = min (real_att, now_heal); // 真实造成的真实伤害
        now_heal -= caused; // 剩余血量

        Sleep (wait_time);
        sprintf(output_data[0], "--- ENEMY %5d/%-5d %3d%%---", now_heal, heal, 1ll * now_heal * 100 / heal);
        sprintf(output_data[round_cnt], "%2d: You dealt %d damage to the enemy. ", round_cnt, caused);

        go_to (0, 0);
        printf("%s\n", output_data[0]);
        int line_cnt = MAX_LINE - 1;
        int start;
        if (line_cnt >= round_cnt) start = 1;
        else start = round_cnt - line_cnt + 1;
        for (int i = start; i <= round_cnt; i ++) {
            printf("%s\n", output_data[i]);
        }
    }
    sprintf(output_data[0], "You won the enemy. Press any key to continue.");
    go_to (0, 0);
    printf("%s\n", output_data[0]);
    int line_cnt = MAX_LINE - 1;
    int start;
    if (line_cnt >= round_cnt) start = 1;
    else start = round_cnt - line_cnt + 1;
    for (int i = start; i <= round_cnt; i ++) {
        printf("%s\n", output_data[i]);
    }

    clear_stdin();
    press_any_key_to_continue();
    return true;
}

void check_bag () {
    cls();
    printf("Stay tuned, champ.\n");
    press_any_key_to_continue();
}

void change_log () {
    cls();
    printf("%s", change_logs);
    press_any_key_to_continue();
}

void sandbox () {
    char output_data[30][110];
    int chs = 1;
    int len = 5;

    sprintf(output_data[0], "--- geimu sandbox --- (press [Enter] to change)");
    sprintf(output_data[1], "%c enemy health: %d", chs == 1 ? '>' : ' ', mobs[1].heal);
    sprintf(output_data[2], "%c player attack: %d", chs == 2 ? '>' : ' ', player.att);
    sprintf(output_data[3], "%c player attack speed: %.2lfps", chs == 3 ? '>' : ' ', player.speed / 100.0);
    sprintf(output_data[4], "%c weapon attack: %d", chs == 4 ? '>' : ' ', weapons[1].att);
    sprintf(output_data[5], "%c i'm ready.", chs == 5 ? '>' : ' ');
    cls ();
    for (int i = 0; i <= len; i ++) {
        printf("%s\n", output_data[i]);
    } while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                go_to (len + 2, 0);
                printf("input enemy health: ");
                ShowCursor();
                scanf("%d", &mobs[1].heal);
                mobs[1].heal = max (mobs[1].heal, 0);
                sprintf(output_data[1], "%c enemy health: %d", chs == 1 ? '>' : ' ', mobs[1].heal);
            } else if (chs == 2) {
                go_to (len + 2, 0);
                printf("input player attack: ");
                ShowCursor();
                scanf("%d", &player.att);
                player.att = max (player.att, 0);
                sprintf(output_data[2], "%c player attack: %d", chs == 2 ? '>' : ' ', player.att);
            } else if (chs == 3) {
                double tmp;
                go_to (len + 2, 0);
                printf("input player attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                player.speed = max (tmp, 0.0) * 100;
                sprintf(output_data[3], "%c player attack speed: %.2lfps", chs == 3 ? '>' : ' ', player.speed / 100.0);
            } else if (chs == 4) {
                go_to (len + 2, 0);
                printf("input weapon attack: ");
                ShowCursor();
                scanf("%d", &weapons[1].att);
                weapons[1].att = max(weapons[1].att, 0);
                sprintf(output_data[4], "%c weapon attack: %d", chs == 4 ? '>' : ' ', weapons[1].att);
            } else if (chs == 5) {
                fight(1);
                return ;
            } cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin(); HideCursor();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
    }
}

void home_page () {
    char output_data[30][110];
    int chs = 1;
    int len = 3;

    sprintf (output_data[0], "Welecome to the game \"geimu\"!");
    sprintf (output_data[1], "%c Check bag", chs == 1 ? '>' : ' ');
    sprintf (output_data[2], "%c Create a sandbox", chs == 2 ? '>' : ' ');
    sprintf (output_data[3], "%c Change log", chs == 3 ? '>' : ' ');
    cls ();
    printf("%s\n", output_data[0]);
    Sleep (500);
    for (int i = 1; i <= len; i ++) printf("%s\n", output_data[i]);
    clear_stdin();
    while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            cls();
            if (chs == 1) {
                check_bag ();
            } else if (chs == 2) {
                sandbox();
            } else {
                change_log ();
            }
            cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
        // Sleep (100);
    }
}

void test_mode () {
    player.att = 100;
    player.speed = 100;
    WEAPON_COUNT = 1;
    weapons[1].att = 10;
    player.choose_weapon = 1;
    MOB_COUNT = 1;
    mobs[1].heal = 1000;
}

int main () {

    test_mode();

    HideCursor();

    home_page ();

    // fight(1);
    return 0;
}

26.1 snapshot 5

/*
当前版本:26.1 snapshot 5

2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。  
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。  
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。

通知:后续更新日志在程序里,运行即可看到。下方变成了评论区。可以评论。记得署名

- 26.1
    - snapshot 1, 2026-07-12
		评价:有剧情吗就开服——Derekyang
    - snapshot 2, 2026-07-12
		评价:把主体做出来好吗,不要只放一个战斗模块——Derekyang
    - snapshot 3, 2026-07-13
*/
#include<cstdio>
#include<random>
#include<ctime>
#include<queue>
#include<cmath>
#include<windows.h>
#include<conio.h>
using namespace std;
#define Rnd(a,b) rnd()%(b-a+1)+a
#define color(a) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a) 
#define Key_down(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
void cls(){
    // HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    // if (hStdOut == INVALID_HANDLE_VALUE)
    //     return;
    // CONSOLE_SCREEN_BUFFER_INFO csbi;
    // if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
    //     return;
    // DWORD count;
    // DWORD cellCount = csbi.dwSize.X * csbi.dwSize.Y;
    // COORD homeCoords = {0, 0};
    // FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count);
    // FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count);
    // SetConsoleCursorPosition(hStdOut, homeCoords);
    system("cls");
}
void press_any_key_to_continue () {
	// while (_kbhit ()) {
	// 	getch();
	// } rewind (stdin);
	// while (1) if (kbhit ()) break;
	// return ;
    char c = _getch();
    return ;
} void clear_stdin(void) {
    while (_kbhit ()) {
		getch();
	} rewind (stdin);

    // int c;
    // while ((c = getchar()) != '\n' && c != EOF) {
    // }
}
void HideCursor(){
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void ShowCursor(){
	CONSOLE_CURSOR_INFO cur={1,1};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void go_to (int x, int y){
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coordScreen = {(short)y, (short)x};
    SetConsoleCursorPosition(hConsole, coordScreen);
}
int GetDisplayWidth(const char* str) {
    int width = 0;
    int len = strlen(str);
    
    for (int i = 0; i < len; i++) {
        unsigned char c = (unsigned char)str[i];
        if (c >= 0x81 && c <= 0xFE) {
            if (i + 1 < len) {
                unsigned char c2 = (unsigned char)str[i + 1];
                if ((c2 >= 0x40 && c2 <= 0x7E) || (c2 >= 0x80 && c2 <= 0xFE)) {
                    width += 2;
                    i++;
                    continue;
                }
            }
        }
        width += 1;
    }
    
    return width;
}
struct ConsoleSize {
    int Width;   // 可见列数
    int Height;  // 可见行数
    int BufferWidth;   // 缓冲区总列数
    int BufferHeight;  // 缓冲区总行数
};
ConsoleSize GetAdvancedConsoleSize() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    ConsoleSize size = {80, 25, 80, 300}; // 默认
    
    if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
        // 可见窗口区域(用户当前看到的)
        size.Width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        size.Height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
        // 缓冲区大小(实际可绘制的范围)
        size.BufferWidth = csbi.dwSize.X;
        size.BufferHeight = csbi.dwSize.Y;
    }
    return size;
}
std::mt19937 rnd(time(NULL));

char change_logs[100000] = {"\
当前版本:26.1 snapshot 3\n\
2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。\n\
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。\n\
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。\n\
\n\
开发者:jessy\n\
特邀嘉宾:DEREKYANG\n\
\n\
- 26.1 Sandbox Update\n\
    - snapshot 1, 2026-07-12\n\
        - 正式开服,现在十分简陋,但是能看。有了与怪物战斗能力,但是目前只有攻击力和攻击速度两个属性。\n\
    - snapshot 2, 2026-07-12\n\
        - 现在增加了滚动系统,控制台最多显示十行。\n\
        - ~~为了展示滚动算法的先进性~~输出信息会额外输出回合数。\n\
        - 修复了一个漏洞\n\
            - 当输出行数超过控制台行数时,输出内容会错误地覆盖之前的信息。\n\
    - snapshot 3, 2026-07-13\n\
        - 新增了主页。\n\
        - 新增了沙盒模式,玩家可以随意调控目前的战斗参数,而不是调源代码。\n\
        - 新增了更新日志。以后更新日志都会放到那里。\n\
        - 新增了查看背包功能。自己点进去看看吧。我啷个晓得嘛\n\
    - snapshot 4, 2026-07-13\n\
        - 紧急更新:修复了一个漏洞\n\
            - 当敌人生命超过int存储上限的1%时,游戏计算出错。\n\
    - snapshot 5, 2026-07-14\n\
        - 加入了怪物的防御,类似于护甲,真实伤害还会减去防御值。\n\
        - 修复了一个漏洞\n\
            - 战斗时不能退出。\n\
"};

const int N = 10010;
int WEAPON_COUNT, MOB_COUNT;
int MAX_LINE = 10;

struct PLAYER {
    int att = 100; // attack
    int choose_weapon;
    int speed = 100; // attack speed
} player;

struct MOB {
    int heal; // health
    int def; // defense
} mobs[N];

struct WEAPON {
    int att;
} weapons[N];

bool wait_in_fight (int wait_time) {
    const int INTERVAL = 10;
    for (int slept = 0; slept < wait_time; slept += INTERVAL) {
        Sleep(min(INTERVAL, wait_time - slept));
        if (Key_down('Q')) {
            return false;
        }
    }
    return true;
}

bool fight (int mob) {
    int heal = mobs[mob].heal;
    int now_heal = heal;
    int round_cnt = 0;
    char output_data[1010][110];

    cls();
    sprintf(output_data[0], "--- ENEMY %5d/%-5d %3d%%---", now_heal, heal, now_heal * 100 / heal);
    printf("%s\n", output_data[0]);
    while (now_heal > 0) {
        round_cnt ++;

        int wait_time = 100000 / player.speed; // 攻击速度
        int real_att = player.att + weapons[player.choose_weapon].att - mobs[mob].def; // 真实伤害
        int caused = min (max (real_att, 0), now_heal); // 真实造成的真实伤害
        now_heal -= caused; // 剩余血量

        if (! wait_in_fight(wait_time)) return false;
        sprintf(output_data[0], "--- ENEMY %5d/%-5d %3d%%---", now_heal, heal, 1ll * now_heal * 100 / heal);
        sprintf(output_data[round_cnt], "%2d: You dealt %d damage to the enemy. ", round_cnt, caused);

        go_to (0, 0);
        printf("%s\n", output_data[0]);
        int line_cnt = MAX_LINE - 1;
        int start;
        if (line_cnt >= round_cnt) start = 1;
        else start = round_cnt - line_cnt + 1;
        for (int i = start; i <= round_cnt; i ++) {
            printf("%s\n", output_data[i]);
        } if (Key_down ('Q')) {
            return false;
        }
    }
    sprintf(output_data[0], "You won the enemy. Press any key to continue.");
    go_to (0, 0);
    printf("%s\n", output_data[0]);
    int line_cnt = MAX_LINE - 1;
    int start;
    if (line_cnt >= round_cnt) start = 1;
    else start = round_cnt - line_cnt + 1;
    for (int i = start; i <= round_cnt; i ++) {
        printf("%s\n", output_data[i]);
    }

    clear_stdin();
    press_any_key_to_continue();
    return true;
}

void check_bag () {
    cls();
    printf("Stay tuned, champ.\n");
    press_any_key_to_continue();
}

void change_log () {
    cls();
    printf("%s", change_logs);
    press_any_key_to_continue();
}

void sandbox () {
    char output_data[30][110];
    int chs = 1;
    int len = 6;

    sprintf(output_data[0], "--- geimu sandbox --- (press [Enter] to change)");
    sprintf(output_data[1], "%c enemy health: %d", chs == 1 ? '>' : ' ', mobs[1].heal);
    sprintf(output_data[2], "%c enemy defense: %d", chs == 2 ? '>' : ' ', mobs[1].def);
    sprintf(output_data[3], "%c player attack: %d", chs == 3 ? '>' : ' ', player.att);
    sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
    sprintf(output_data[5], "%c weapon attack: %d", chs == 5 ? '>' : ' ', weapons[1].att);
    sprintf(output_data[6], "%c i'm ready.", chs == 6 ? '>' : ' ');
    cls ();
    for (int i = 0; i <= len; i ++) {
        printf("%s\n", output_data[i]);
    } while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                go_to (len + 2, 0);
                printf("input enemy health: ");
                ShowCursor();
                scanf("%d", &mobs[1].heal);
                mobs[1].heal = max (mobs[1].heal, 0);
                sprintf(output_data[1], "%c enemy health: %d", chs == 1 ? '>' : ' ', mobs[1].heal);
            } else if (chs == 2) {
                go_to (len + 2, 0);
                printf("input enemy defense: ");
                ShowCursor();
                scanf("%d", &mobs[1].def);
                mobs[1].def = max (mobs[1].def, 0);
                sprintf(output_data[2], "%c enemy defense: %d", chs == 2 ? '>' : ' ', mobs[1].def);
            } else if (chs == 3) {
                go_to (len + 2, 0);
                printf("input player attack: ");
                ShowCursor();
                scanf("%d", &player.att);
                player.att = max (player.att, 0);
                sprintf(output_data[3], "%c player attack: %d", chs == 3 ? '>' : ' ', player.att);
            } else if (chs == 4) {
                double tmp;
                go_to (len + 2, 0);
                printf("input player attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                player.speed = max (tmp, 0.0) * 100;
                sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
            } else if (chs == 5) {
                go_to (len + 2, 0);
                printf("input weapon attack: ");
                ShowCursor();
                scanf("%d", &weapons[1].att);
                weapons[1].att = max(weapons[1].att, 0);
                sprintf(output_data[5], "%c weapon attack: %d", chs == 5 ? '>' : ' ', weapons[1].att);
            } else if (chs == 6) {
                fight(1);
                return ;
            } cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin(); HideCursor();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
    }
}

void home_page () {
    char output_data[30][110];
    int chs = 1;
    int len = 3;

    sprintf (output_data[0], "Welecome to the game \"geimu\"!");
    sprintf (output_data[1], "%c Check bag", chs == 1 ? '>' : ' ');
    sprintf (output_data[2], "%c Create a sandbox", chs == 2 ? '>' : ' ');
    sprintf (output_data[3], "%c Change log", chs == 3 ? '>' : ' ');
    cls ();
    printf("%s\n", output_data[0]);
    Sleep (500);
    for (int i = 1; i <= len; i ++) printf("%s\n", output_data[i]);
    clear_stdin();
    while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            cls();
            if (chs == 1) {
                check_bag ();
            } else if (chs == 2) {
                sandbox();
            } else {
                change_log ();
            }
            cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
        // Sleep (100);
    }
}

void test_mode () {
    player.att = 100;
    player.speed = 100;
    WEAPON_COUNT = 1;
    weapons[1].att = 10;
    player.choose_weapon = 1;
    MOB_COUNT = 1;
    mobs[1].heal = 1000;
    mobs[1].def = 0;
}

int main () {

    test_mode();

    HideCursor();

    home_page ();

    // fight(1);
    return 0;
}

26.1 snapshot 6

/*
当前版本:26.1 snapshot 6

2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。  
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。  
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。

通知:后续更新日志在程序里,运行即可看到。下方变成了评论区。可以评论。记得署名

- 26.1
    - snapshot 1, 2026-07-12
		评价:有剧情吗就开服——Derekyang
    - snapshot 2, 2026-07-12
		评价:把主体做出来好吗,不要只放一个战斗模块——Derekyang
    - snapshot 3, 2026-07-13
*/
#include<cstdio>
#include<random>
#include<ctime>
#include<queue>
#include<cmath>
#include<windows.h>
#include<conio.h>
using namespace std;
#define Rnd(a,b) rnd()%(b-a+1)+a
#define color(a) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a) 
#define Key_down(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
void cls(){
    // HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    // if (hStdOut == INVALID_HANDLE_VALUE)
    //     return;
    // CONSOLE_SCREEN_BUFFER_INFO csbi;
    // if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
    //     return;
    // DWORD count;
    // DWORD cellCount = csbi.dwSize.X * csbi.dwSize.Y;
    // COORD homeCoords = {0, 0};
    // FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count);
    // FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count);
    // SetConsoleCursorPosition(hStdOut, homeCoords);
    system("cls");
}
void press_any_key_to_continue () {
	// while (_kbhit ()) {
	// 	getch();
	// } rewind (stdin);
	// while (1) if (kbhit ()) break;
	// return ;
    char c = _getch();
    return ;
} void clear_stdin(void) {
    while (_kbhit ()) {
		getch();
	} rewind (stdin);

    // int c;
    // while ((c = getchar()) != '\n' && c != EOF) {
    // }
}
void HideCursor(){
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void ShowCursor(){
	CONSOLE_CURSOR_INFO cur={1,1};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void go_to (int x, int y){
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coordScreen = {(short)y, (short)x};
    SetConsoleCursorPosition(hConsole, coordScreen);
}
int GetDisplayWidth(const char* str) {
    int width = 0;
    int len = strlen(str);
    
    for (int i = 0; i < len; i++) {
        unsigned char c = (unsigned char)str[i];
        if (c >= 0x81 && c <= 0xFE) {
            if (i + 1 < len) {
                unsigned char c2 = (unsigned char)str[i + 1];
                if ((c2 >= 0x40 && c2 <= 0x7E) || (c2 >= 0x80 && c2 <= 0xFE)) {
                    width += 2;
                    i++;
                    continue;
                }
            }
        }
        width += 1;
    }
    
    return width;
}
struct ConsoleSize {
    int Width;   // 可见列数
    int Height;  // 可见行数
    int BufferWidth;   // 缓冲区总列数
    int BufferHeight;  // 缓冲区总行数
};
ConsoleSize GetAdvancedConsoleSize() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    ConsoleSize size = {80, 25, 80, 300}; // 默认
    
    if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
        // 可见窗口区域(用户当前看到的)
        size.Width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        size.Height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
        // 缓冲区大小(实际可绘制的范围)
        size.BufferWidth = csbi.dwSize.X;
        size.BufferHeight = csbi.dwSize.Y;
    }
    return size;
}
std::mt19937 rnd(time(NULL));

char change_logs[100000] = {"\
当前版本:26.1 snapshot 3\n\
2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。\n\
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。\n\
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。\n\
\n\
开发者:jessy\n\
特邀嘉宾:DEREKYANG\n\
\n\
- 26.1 Sandbox Update\n\
    - snapshot 1, 2026-07-12\n\
        - 正式开服,现在十分简陋,但是能看。有了与怪物战斗能力,但是目前只有攻击力和攻击速度两个属性。\n\
    - snapshot 2, 2026-07-12\n\
        - 现在增加了滚动系统,控制台最多显示十行。\n\
        - ~~为了展示滚动算法的先进性~~输出信息会额外输出回合数。\n\
        - 修复了一个漏洞\n\
            - 当输出行数超过控制台行数时,输出内容会错误地覆盖之前的信息。\n\
    - snapshot 3, 2026-07-13\n\
        - 新增了主页。\n\
        - 新增了沙盒模式,玩家可以随意调控目前的战斗参数,而不是调源代码。\n\
        - 新增了更新日志。以后更新日志都会放到那里。\n\
        - 新增了查看背包功能。自己点进去看看吧。我啷个晓得嘛\n\
    - snapshot 4, 2026-07-13\n\
        - 紧急更新:修复了一个漏洞\n\
            - 当敌人生命超过int存储上限的1%时,游戏计算出错。\n\
    - snapshot 5, 2026-07-14\n\
        - 加入了怪物的防御,类似于护甲,真实伤害还会减去防御值。\n\
        - 修复了一个漏洞\n\
            - 战斗时不能退出。\n\
    - snapshot 6, 2026-07-14\n\
        - 加入了战斗模式暂停的功能,按空格键可以暂停。\n\
        - 删除了战斗模式暂停的功能,开发者认为这没有什么意义。\n\
        - 现在战斗记录的存储方式使用了更加先进的存储技术,用人话说就是滚动数组。\n\
        - 新增了武器的破防属性,用来削减敌人的防御值。特别地,此值可为负。\n\
        - 修复了若干个漏洞\n\
            - 回合数超过 1000 的战斗会崩溃。\n\
            - 按 Q 退出战斗后 Q 会被再次读入。\n\
"};

typedef long long ll;
const int N = 10010;
int WEAPON_COUNT, MOB_COUNT;
int MAX_LINE = 10;

struct PLAYER {
    ll att = 100; // attack
    int choose_weapon;
    int speed = 100; // attack speed
} player;

struct MOB {
    ll heal; // health
    ll def; // defense
} mobs[N];

struct WEAPON {
    ll att;
    ll anti_def;
} weapons[N];

bool wait_in_fight (int wait_time) {
    const int INTERVAL = 10;
    for (int slept = 0; slept < wait_time; slept += INTERVAL) {
        Sleep(min(INTERVAL, wait_time - slept));
        if (Key_down('Q')) {
            return false;
        }
    }
    return true;
}

bool fight (int mob) {
    ll heal = mobs[mob].heal;
    ll now_heal = heal;
    int round_cnt = 0;
    char output_data[1010][110];

    cls();
    sprintf(output_data[0], "--- ENEMY %5lld/%-5lld %3d%%---", now_heal, heal, now_heal * 100 / heal);
    printf("%s\n", output_data[0]);
    while (now_heal > 0) {
        round_cnt ++;

        int wait_time = 100000 / player.speed; // 攻击速度
        ll true_def = max (mobs[mob].def - weapons[player.choose_weapon].anti_def, 0ll);
        ll real_att = player.att + weapons[player.choose_weapon].att - true_def; // 真实伤害
        ll caused = min (max (real_att, 0ll), now_heal); // 真实造成的真实伤害
        now_heal -= caused; // 剩余血量

        if (! wait_in_fight(wait_time)) return false;
        sprintf(output_data[0], "--- ENEMY %5lld/%-5lld %3d%%---", now_heal, heal, 1ll * now_heal * 100 / heal);
        sprintf(output_data[(round_cnt - 1) % 1000 + 1], "%2d: You dealt %lld damage to the enemy. ", round_cnt, caused);

        go_to (0, 0);
        printf("%s\n", output_data[0]);
        int line_cnt = MAX_LINE - 1;
        int start;
        if (line_cnt >= round_cnt) start = 1;
        else start = round_cnt - line_cnt + 1;
        for (int i = start; i <= round_cnt; i ++) {
            printf("%s\n", output_data[(i - 1) % 1000 + 1]);
        }
    }
    sprintf(output_data[0], "You won the enemy. Press any key to continue.");
    go_to (0, 0);
    printf("%s\n", output_data[0]);
    int line_cnt = MAX_LINE - 1;
    int start;
    if (line_cnt >= round_cnt) start = 1;
    else start = round_cnt - line_cnt + 1;
    for (int i = start; i <= round_cnt; i ++) {
        printf("%s\n", output_data[i]);
    }

    clear_stdin();
    press_any_key_to_continue();
    return true;
}

void check_bag () {
    cls();
    printf("Stay tuned, champ.\n");
    press_any_key_to_continue();
}

void change_log () {
    cls();
    printf("%s", change_logs);
    press_any_key_to_continue();
}

void sandbox () {
    char output_data[30][110];
    int chs = 1;
    int len = 7;

    sprintf(output_data[0], "--- geimu sandbox --- (press [Enter] to change)");
    sprintf(output_data[1], "%c enemy health: %lld", chs == 1 ? '>' : ' ', mobs[1].heal);
    sprintf(output_data[2], "%c enemy defense: %lld", chs == 2 ? '>' : ' ', mobs[1].def);
    sprintf(output_data[3], "%c player attack: %lld", chs == 3 ? '>' : ' ', player.att);
    sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
    sprintf(output_data[5], "%c weapon attack: %lld", chs == 5 ? '>' : ' ', weapons[1].att);
    sprintf(output_data[6], "%c weapon anti_defense: %lld", chs == 6 ? '>' : ' ', weapons[1].anti_def);
    sprintf(output_data[7], "%c i'm ready.", chs == 7 ? '>' : ' ');
    cls ();
    for (int i = 0; i <= len; i ++) {
        printf("%s\n", output_data[i]);
    } while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                go_to (len + 2, 0);
                printf("input enemy health: ");
                ShowCursor();
                scanf("%lld", &mobs[1].heal);
                mobs[1].heal = max (mobs[1].heal, 0ll);
                sprintf(output_data[1], "%c enemy health: %lld", chs == 1 ? '>' : ' ', mobs[1].heal);
            } else if (chs == 2) {
                go_to (len + 2, 0);
                printf("input enemy defense: ");
                ShowCursor();
                scanf("%lld", &mobs[1].def);
                mobs[1].def = max (mobs[1].def, 0ll);
                sprintf(output_data[2], "%c enemy defense: %lld", chs == 2 ? '>' : ' ', mobs[1].def);
            } else if (chs == 3) {
                go_to (len + 2, 0);
                printf("input player attack: ");
                ShowCursor();
                scanf("%lld", &player.att);
                player.att = max (player.att, 0ll);
                sprintf(output_data[3], "%c player attack: %lld", chs == 3 ? '>' : ' ', player.att);
            } else if (chs == 4) {
                double tmp;
                go_to (len + 2, 0);
                printf("input player attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                player.speed = max (min (tmp, 100.0), 0.0) * 100;
                sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
            } else if (chs == 5) {
                go_to (len + 2, 0);
                printf("input weapon attack: ");
                ShowCursor();
                scanf("%lld", &weapons[1].att);
                weapons[1].att = max(weapons[1].att, 0ll);
                sprintf(output_data[5], "%c weapon attack: %lld", chs == 5 ? '>' : ' ', weapons[1].att);
            } else if (chs == 6) {
                go_to (len + 2, 0);
                printf("input weapon anti_defense: ");
                ShowCursor();
                scanf("%lld", &weapons[1].anti_def);
                sprintf(output_data[6], "%c weapon anti_defense: %lld", chs == 6 ? '>' : ' ', weapons[1].anti_def);
            } else if (chs == 7) {
                fight(1);
                clear_stdin();
            } cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin(); HideCursor();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
    }
}

void home_page () {
    char output_data[30][110];
    int chs = 1;
    int len = 3;

    sprintf (output_data[0], "Welecome to the game \"geimu\"!");
    sprintf (output_data[1], "%c Check bag", chs == 1 ? '>' : ' ');
    sprintf (output_data[2], "%c Create a sandbox", chs == 2 ? '>' : ' ');
    sprintf (output_data[3], "%c Change log", chs == 3 ? '>' : ' ');
    cls ();
    printf("%s\n", output_data[0]);
    Sleep (500);
    for (int i = 1; i <= len; i ++) printf("%s\n", output_data[i]);
    clear_stdin();
    while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            cls();
            if (chs == 1) {
                check_bag ();
            } else if (chs == 2) {
                sandbox();
            } else {
                change_log ();
            }
            cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
        // Sleep (100);
    }
}

void test_mode () {
    player.att = 100;
    player.speed = 100;
    WEAPON_COUNT = 1;
    weapons[1].att = 10;
    player.choose_weapon = 1;
    MOB_COUNT = 1;
    mobs[1].heal = 1000;
    mobs[1].def = 0;
}

int main () {

    test_mode();

    HideCursor();

    home_page ();

    // fight(1);
    return 0;
}

26.1 snapshot 7

/*
当前版本:26.1 snapshot 7

2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。  
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。  
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。

通知:后续更新日志在程序里,运行即可看到。下方变成了评论区。可以评论。记得署名

- 26.1
    - snapshot 1, 2026-07-12
		评价:有剧情吗就开服——Derekyang
    - snapshot 2, 2026-07-12
		评价:把主体做出来好吗,不要只放一个战斗模块——Derekyang
    - snapshot 3, 2026-07-13
*/
#include<cstdio>
#include<random>
#include<ctime>
#include<queue>
#include<cmath>
#include<windows.h>
#include<conio.h>
using namespace std;
#define Rnd(a,b) rnd()%(b-a+1)+a
#define color(a) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a) 
#define Key_down(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
void cls(){
    // HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    // if (hStdOut == INVALID_HANDLE_VALUE)
    //     return;
    // CONSOLE_SCREEN_BUFFER_INFO csbi;
    // if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
    //     return;
    // DWORD count;
    // DWORD cellCount = csbi.dwSize.X * csbi.dwSize.Y;
    // COORD homeCoords = {0, 0};
    // FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count);
    // FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count);
    // SetConsoleCursorPosition(hStdOut, homeCoords);
    system("cls");
}
void press_any_key_to_continue () {
	// while (_kbhit ()) {
	// 	getch();
	// } rewind (stdin);
	// while (1) if (kbhit ()) break;
	// return ;
    char c = _getch();
    return ;
} void clear_stdin(void) {
    while (_kbhit ()) {
		getch();
	} rewind (stdin);

    // int c;
    // while ((c = getchar()) != '\n' && c != EOF) {
    // }
}
void HideCursor(){
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void ShowCursor(){
	CONSOLE_CURSOR_INFO cur={1,1};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void go_to (int x, int y){
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coordScreen = {(short)y, (short)x};
    SetConsoleCursorPosition(hConsole, coordScreen);
}
int GetDisplayWidth(const char* str) {
    int width = 0;
    int len = strlen(str);
    
    for (int i = 0; i < len; i++) {
        unsigned char c = (unsigned char)str[i];
        if (c >= 0x81 && c <= 0xFE) {
            if (i + 1 < len) {
                unsigned char c2 = (unsigned char)str[i + 1];
                if ((c2 >= 0x40 && c2 <= 0x7E) || (c2 >= 0x80 && c2 <= 0xFE)) {
                    width += 2;
                    i++;
                    continue;
                }
            }
        }
        width += 1;
    }
    
    return width;
}
struct ConsoleSize {
    int Width;   // 可见列数
    int Height;  // 可见行数
    int BufferWidth;   // 缓冲区总列数
    int BufferHeight;  // 缓冲区总行数
};
ConsoleSize GetAdvancedConsoleSize() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    ConsoleSize size = {80, 25, 80, 300}; // 默认
    
    if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
        // 可见窗口区域(用户当前看到的)
        size.Width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        size.Height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
        // 缓冲区大小(实际可绘制的范围)
        size.BufferWidth = csbi.dwSize.X;
        size.BufferHeight = csbi.dwSize.Y;
    }
    return size;
}
std::mt19937 rnd(time(NULL));

char change_logs[100000] = {"\
当前版本:26.1 snapshot 7\n\
2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。\n\
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。\n\
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。\n\
\n\
开发者:jessy\n\
特邀嘉宾:DEREKYANG\n\
\n\
- 26.1 Sandbox Update\n\
    - snapshot 1, 2026-07-12\n\
        - 正式开服,现在十分简陋,但是能看。有了与怪物战斗能力,但是目前只有攻击力和攻击速度两个属性。\n\
    - snapshot 2, 2026-07-12\n\
        - 现在增加了滚动系统,控制台最多显示十行。\n\
        - ~~为了展示滚动算法的先进性~~输出信息会额外输出回合数。\n\
        - 修复了一个漏洞\n\
            - 当输出行数超过控制台行数时,输出内容会错误地覆盖之前的信息。\n\
    - snapshot 3, 2026-07-13\n\
        - 新增了主页。\n\
        - 新增了沙盒模式,玩家可以随意调控目前的战斗参数,而不是调源代码。\n\
        - 新增了更新日志。以后更新日志都会放到那里。\n\
        - 新增了查看背包功能。自己点进去看看吧。我啷个晓得嘛\n\
    - snapshot 4, 2026-07-13\n\
        - 紧急更新:修复了一个漏洞\n\
            - 当敌人生命超过int存储上限的1%时,游戏计算出错。\n\
    - snapshot 5, 2026-07-14\n\
        - 加入了怪物的防御,类似于护甲,真实伤害还会减去防御值。\n\
        - 修复了一个漏洞\n\
            - 战斗时不能退出。\n\
    - snapshot 6, 2026-07-14\n\
        - 加入了战斗模式暂停的功能,按空格键可以暂停。\n\
        - 删除了战斗模式暂停的功能,开发者认为这没有什么意义。\n\
        - 现在战斗记录的存储方式使用了更加先进的存储技术,用人话说就是滚动数组。\n\
        - 新增了武器的破防属性,用来削减敌人的防御值。特别地,此值可为负。\n\
        - 修复了若干个漏洞\n\
            - 回合数超过 1000 的战斗会崩溃。\n\
            - 按 Q 退出战斗后 Q 会被再次读入。\n\
    - snapshot 7, 2026-07-16\n\
        - 加入了武器的攻击速度,正负均可\n\
        - 正在设计新的存档格式,将武器、生物等数据进行软编码,预计下个快照实现,并增加一些基础的生物和武器。\n\
"};

typedef long long ll;
const int N = 10010;
int WEAPON_COUNT, MOB_COUNT;
int MAX_LINE = 10;

struct MOB {
    ll heal; // health
    ll def; // defense
} mobs[N];

struct WEAPON {
    char name[20];
    ll att;
    ll anti_def;
    int speed;
} weapons[N];

struct CHOOSEWEAPON {
    int id;
};

struct PLAYER {
    ll att = 100; // attack
    ll money;
    CHOOSEWEAPON choose_weapon;
    int speed = 100; // attack speed
    int bag_sz, bag_len = 0;
    CHOOSEWEAPON weapon_bag[1010];
} player;

bool wait_in_fight (int wait_time) {
    const int INTERVAL = 10;
    for (int slept = 0; slept < wait_time; slept += INTERVAL) {
        Sleep(min(INTERVAL, wait_time - slept));
        if (Key_down('Q')) {
            return false;
        }
    }
    return true;
}

bool fight (int mob) {
    ll heal = mobs[mob].heal;
    ll now_heal = heal;
    int round_cnt = 0;
    char output_data[1010][110];
    int real_speed = player.speed + weapons[player.choose_weapon.id].speed;
    real_speed = max (min (10000, real_speed), 10);

    cls();
    sprintf(output_data[0], "--- ENEMY %5lld/%-5lld %3d%%---", now_heal, heal, now_heal * 100 / heal);
    printf("%s\n", output_data[0]);
    while (now_heal > 0) {
        round_cnt ++;

        int wait_time = 100000 / real_speed; // 等待时间
        ll true_def = max (mobs[mob].def - weapons[player.choose_weapon.id].anti_def, 0ll); // 去除破防后的防御值
        ll real_att = player.att + weapons[player.choose_weapon.id].att - true_def; // 真实伤害
        ll caused = min (max (real_att, 0ll), now_heal); // 真实造成的真实伤害
        now_heal -= caused; // 剩余血量

        if (! wait_in_fight(wait_time)) return false;
        sprintf(output_data[0], "--- ENEMY %5lld/%-5lld %3d%%---", now_heal, heal, 1ll * now_heal * 100 / heal);
        sprintf(output_data[(round_cnt - 1) % 1000 + 1], "%2d: You dealt %lld damage to the enemy. ", round_cnt, caused);

        go_to (0, 0);
        printf("%s\n", output_data[0]);
        int line_cnt = MAX_LINE - 1;
        int start;
        if (line_cnt >= round_cnt) start = 1;
        else start = round_cnt - line_cnt + 1;
        for (int i = start; i <= round_cnt; i ++) {
            printf("%s\n", output_data[(i - 1) % 1000 + 1]);
        }
    }
    sprintf(output_data[0], "You won the enemy. Press any key to continue.");
    go_to (0, 0);
    printf("%s\n", output_data[0]);
    int line_cnt = MAX_LINE - 1;
    int start;
    if (line_cnt >= round_cnt) start = 1;
    else start = round_cnt - line_cnt + 1;
    for (int i = start; i <= round_cnt; i ++) {
        printf("%s\n", output_data[i]);
    }

    clear_stdin();
    press_any_key_to_continue();
    return true;
}

void check_bag () {
    cls();
    
    press_any_key_to_continue();
}

void change_log () {
    cls();
    printf("%s", change_logs);
    press_any_key_to_continue();
}

void sandbox () {
    char output_data[30][110];
    int chs = 1;
    int len = 8;

    sprintf(output_data[0], "--- geimu sandbox --- (press [Enter] to change)");
    sprintf(output_data[1], "%c enemy health: %lld", chs == 1 ? '>' : ' ', mobs[0].heal);
    sprintf(output_data[2], "%c enemy defense: %lld", chs == 2 ? '>' : ' ', mobs[0].def);
    sprintf(output_data[3], "%c player attack: %lld", chs == 3 ? '>' : ' ', player.att);
    sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
    sprintf(output_data[5], "%c weapon attack: %lld", chs == 5 ? '>' : ' ', weapons[0].att);
    sprintf(output_data[6], "%c weapon anti_defense: %lld", chs == 6 ? '>' : ' ', weapons[0].anti_def);
    sprintf(output_data[7], "%c weapon attack speed: %.2lfps", chs == 7 ? '>' : ' ', weapons[0].speed, player.speed / 100.0);
    sprintf(output_data[8], "%c i'm ready.", chs == 8 ? '>' : ' ');
    cls ();
    for (int i = 0; i <= len; i ++) {
        printf("%s\n", output_data[i]);
    } while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                go_to (len + 2, 0);
                printf("input enemy health: ");
                ShowCursor();
                scanf("%lld", &mobs[0].heal);
                mobs[0].heal = max (mobs[0].heal, 0ll);
                sprintf(output_data[1], "%c enemy health: %lld", chs == 1 ? '>' : ' ', mobs[0].heal);
            } else if (chs == 2) {
                go_to (len + 2, 0);
                printf("input enemy defense: ");
                ShowCursor();
                scanf("%lld", &mobs[0].def);
                mobs[0].def = max (mobs[0].def, 0ll);
                sprintf(output_data[2], "%c enemy defense: %lld", chs == 2 ? '>' : ' ', mobs[0].def);
            } else if (chs == 3) {
                go_to (len + 2, 0);
                printf("input player attack: ");
                ShowCursor();
                scanf("%lld", &player.att);
                player.att = max (player.att, 0ll);
                sprintf(output_data[3], "%c player attack: %lld", chs == 3 ? '>' : ' ', player.att);
            } else if (chs == 4) {
                double tmp;
                go_to (len + 2, 0);
                printf("input player attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                player.speed = max (min (tmp, 100.0), 0.1) * 100;
                sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
            } else if (chs == 5) {
                go_to (len + 2, 0);
                printf("input weapon attack: ");
                ShowCursor();
                scanf("%lld", &weapons[0].att);
                weapons[0].att = max(weapons[0].att, 0ll);
                sprintf(output_data[5], "%c weapon attack: %lld", chs == 5 ? '>' : ' ', weapons[0].att);
            } else if (chs == 6) {
                go_to (len + 2, 0);
                printf("input weapon anti_defense: ");
                ShowCursor();
                scanf("%lld", &weapons[0].anti_def);
                sprintf(output_data[6], "%c weapon anti_defense: %lld", chs == 6 ? '>' : ' ', weapons[0].anti_def);
            } else if (chs == 7) {
                double tmp;
                go_to (len + 2, 0);
                printf("input weapon attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                weapons[0].speed = max (min (tmp, 100.0), -100.0) * 100;
                sprintf(output_data[7], "%c weapon attack speed: %.2lfps", chs == 7 ? '>' : ' ', weapons[0].speed / 100.0);
            } else if (chs == 8) {
                fight(0);
                clear_stdin();
            } cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin(); HideCursor();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
    }
}

void home_page () {
    char output_data[30][110];
    int chs = 1;
    int len = 3;

    sprintf (output_data[0], "--- Home Page --- money: %lld", player.money);
    sprintf (output_data[1], "%c Check bag", chs == 1 ? '>' : ' ');
    sprintf (output_data[2], "%c Create a sandbox", chs == 2 ? '>' : ' ');
    sprintf (output_data[3], "%c Change log", chs == 3 ? '>' : ' ');
    cls ();
    printf("%s\n", output_data[0]);
    Sleep (500);
    for (int i = 1; i <= len; i ++) printf("%s\n", output_data[i]);
    clear_stdin();
    while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            cls();
            if (chs == 1) {
                check_bag ();
            } else if (chs == 2) {
                sandbox();
            } else {
                change_log ();
            }
            cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
        // Sleep (100);
    }
}

void init () {
    player.money = 100;
    player.att = 100;
    player.speed = 100;
    WEAPON_COUNT = 0;
    weapons[0].att = 10;
    weapons[0].anti_def = 0;
    player.choose_weapon.id = 0;
    MOB_COUNT = 0;
    mobs[0].heal = 1000;
    mobs[0].def = 0;
}

void load_game () {
    char output_data[20][50];
    char weapon_path[110] = "WEAPON.weapon";
    int chs = 1;
    int len = 3;

    sprintf (output_data[0], "请先选择读入数据的文件名。");
    sprintf (output_data[1], "武器列表:%s", chs == 1 ? '>' : ' ');
    sprintf (output_data[2], "%c Create a sandbox", chs == 2 ? '>' : ' ');
    sprintf (output_data[3], "%c Change log", chs == 3 ? '>' : ' '); 
}

int main () {

    cls();
    printf("在游玩/调试前请先更换编码方式:点击右下角'UTF-8',选择'Reopen with encoding',点击'Simplified Chinese (GBK) gbk'。若程序内中文还是无法正常显示,按Ctrl+Z。\n\
before playing/debuging, please change your encoding first: click 'UTF-8' on the right-down area, choose 'Reopen with encoding', then click 'Simplified Chinese (GBK) gbk'. If Chinese still can't show normally (that are showing like '锟斤拷'), press Ctrl + Z.\n\
press any key to continue...\n");
    press_any_key_to_continue();

    init();
    // load_game ();

    HideCursor();

    home_page ();

    // fight(1);
    return 0;
}

26.1 snapshot 8

/*
当前版本:26.1 snapshot 8

2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。  
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。  
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。

通知:后续更新日志在程序里,运行即可看到。请及时在游戏中找到更新日志以查看最新版本的更新内容。下方变成了评论区。可以评论。记得署名

- 26.1
    - snapshot 1, 2026-07-12
		评价:有剧情吗就开服——Derekyang
    - snapshot 2, 2026-07-12
		评价:把主体做出来好吗,不要只放一个战斗模块——Derekyang
    - snapshot 3, 2026-07-13
*/
#include<cstdio>
#include<random>
#include<ctime>
#include<queue>
#include<cmath>
#include<windows.h>
#include<conio.h>
using namespace std;
#define Rnd(a,b) rnd()%(b-a+1)+a
#define color(a) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a) 
#define Key_down(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
void cls(){
    // HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    // if (hStdOut == INVALID_HANDLE_VALUE)
    //     return;
    // CONSOLE_SCREEN_BUFFER_INFO csbi;
    // if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
    //     return;
    // DWORD count;
    // DWORD cellCount = csbi.dwSize.X * csbi.dwSize.Y;
    // COORD homeCoords = {0, 0};
    // FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count);
    // FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count);
    // SetConsoleCursorPosition(hStdOut, homeCoords);
    system("cls");
}
void press_any_key_to_continue () {
	// while (_kbhit ()) {
	// 	getch();
	// } rewind (stdin);
	// while (1) if (kbhit ()) break;
	// return ;
    char c = _getch();
    return ;
} void clear_stdin(void) {
    while (_kbhit ()) {
		getch();
	} rewind (stdin);

    // int c;
    // while ((c = getchar()) != '\n' && c != EOF) {
    // }
}
void HideCursor(){
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void ShowCursor(){
	CONSOLE_CURSOR_INFO cur={1,1};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void go_to (int x, int y){
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coordScreen = {(short)y, (short)x};
    SetConsoleCursorPosition(hConsole, coordScreen);
}
int GetDisplayWidth(const char* str) {
    int width = 0;
    int len = strlen(str);
    
    for (int i = 0; i < len; i++) {
        unsigned char c = (unsigned char)str[i];
        if (c >= 0x81 && c <= 0xFE) {
            if (i + 1 < len) {
                unsigned char c2 = (unsigned char)str[i + 1];
                if ((c2 >= 0x40 && c2 <= 0x7E) || (c2 >= 0x80 && c2 <= 0xFE)) {
                    width += 2;
                    i++;
                    continue;
                }
            }
        }
        width += 1;
    }
    
    return width;
}
struct ConsoleSize {
    int Width;   // 可见列数
    int Height;  // 可见行数
    int BufferWidth;   // 缓冲区总列数
    int BufferHeight;  // 缓冲区总行数
};
ConsoleSize GetAdvancedConsoleSize() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    ConsoleSize size = {80, 25, 80, 300}; // 默认
    
    if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
        // 可见窗口区域(用户当前看到的)
        size.Width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        size.Height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
        // 缓冲区大小(实际可绘制的范围)
        size.BufferWidth = csbi.dwSize.X;
        size.BufferHeight = csbi.dwSize.Y;
    }
    return size;
}
std::mt19937 rnd(time(NULL));

char change_logs[100000] = {"\
当前版本:26.1 snapshot 7\n\
2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。\n\
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。\n\
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。\n\
\n\
开发者:jessy\n\
特邀嘉宾:DEREKYANG\n\
\n\
- 26.1 Sandbox Update\n\
    - snapshot 1, 2026-07-12\n\
        - 正式开服,现在十分简陋,但是能看。有了与怪物战斗能力,但是目前只有攻击力和攻击速度两个属性。\n\
    - snapshot 2, 2026-07-12\n\
        - 现在增加了滚动系统,控制台最多显示十行。\n\
        - ~~为了展示滚动算法的先进性~~输出信息会额外输出回合数。\n\
        - 修复了一个漏洞\n\
            - 当输出行数超过控制台行数时,输出内容会错误地覆盖之前的信息。\n\
    - snapshot 3, 2026-07-13\n\
        - 新增了主页。\n\
        - 新增了沙盒模式,玩家可以随意调控目前的战斗参数,而不是调源代码。\n\
        - 新增了更新日志。以后更新日志都会放到那里。\n\
        - 新增了查看背包功能。自己点进去看看吧。我啷个晓得嘛\n\
    - snapshot 4, 2026-07-13\n\
        - 紧急更新:修复了一个漏洞\n\
            - 当敌人生命超过int存储上限的1%时,游戏计算出错。\n\
    - snapshot 5, 2026-07-14\n\
        - 加入了怪物的防御,类似于护甲,真实伤害还会减去防御值。\n\
        - 修复了一个漏洞\n\
            - 战斗时不能退出。\n\
    - snapshot 6, 2026-07-14\n\
        - 加入了战斗模式暂停的功能,按空格键可以暂停。\n\
        - 删除了战斗模式暂停的功能,开发者认为这没有什么意义。\n\
        - 现在战斗记录的存储方式使用了更加先进的存储技术,用人话说就是滚动数组。\n\
        - 新增了武器的破防属性,用来削减敌人的防御值。特别地,此值可为负。\n\
        - 修复了若干个漏洞\n\
            - 回合数超过 1000 的战斗会崩溃。\n\
            - 按 Q 退出战斗后 Q 会被再次读入。\n\
    - snapshot 7, 2026-07-16\n\
        - 加入了武器的攻击速度,正负均可\n\
        - 正在设计新的存档格式,将武器、生物等数据进行软编码,预计下个快照实现,并增加一些基础的生物和武器。\n\
    - snapshot 8, 2026-07-17\n\
        - 加入了数据格式,目前只有 .WEAPON 和 .MOB 两种,具体可见源代码底部。\n\
        - 添加了怪物以及武器的名称。在战斗中会显示怪物的名称而非之前的\"ENEMY\"。\n\
        - 更改了一个漏洞的状态\n\
            - 当怪物血量超过约 9e16 时,剩余血量百分比计算错误。漏洞状态为:不予修复。原因:就目前来看,这么高的怪物血量是不切实际的。\n\
        - 再次隆重声明:该游戏名称“给木”是作者的倾情创作,严禁丑化、扭曲本游戏名称(如称之为“旮旯给木”等)。\n\
"};

typedef long long ll;
const int N = 10010;
int WEAPON_COUNT, MOB_COUNT;
int MAX_LINE = 10;

struct MOB {
    char name[25];
    ll heal; // health
    ll def; // defense
} mobs[N];

struct WEAPON {
    char name[25];
    ll att;
    ll anti_def;
    int speed;
    int lv;
} weapons[N];

struct CHOOSEWEAPON {
    int id;
};

struct PLAYER {
    ll att = 100; // attack
    ll money;
    CHOOSEWEAPON choose_weapon;
    int speed = 100; // attack speed
    int bag_sz, bag_len = 0;
    CHOOSEWEAPON weapon_bag[1010];
} player;

bool wait_in_fight (int wait_time) {
    const int INTERVAL = 10;
    for (int slept = 0; slept < wait_time; slept += INTERVAL) {
        Sleep(min(INTERVAL, wait_time - slept));
        if (Key_down('Q')) {
            return false;
        }
    }
    return true;
}

bool fight (int mob) {
    ll heal = mobs[mob].heal;
    ll now_heal = heal;
    int round_cnt = 0;
    char output_data[1010][110];
    int real_speed = player.speed + weapons[player.choose_weapon.id].speed;
    real_speed = max (min (10000, real_speed), 10);

    cls();
    sprintf(output_data[0], "--- %s %5lld/%-5lld %3d%%---", mobs[mob].name, now_heal, heal, 1ll * now_heal * 100 / heal);
    printf("%s\n", output_data[0]);
    while (now_heal > 0) {
        round_cnt ++;

        int wait_time = 100000 / real_speed; // 等待时间
        ll true_def = max (mobs[mob].def - weapons[player.choose_weapon.id].anti_def, 0ll); // 去除破防后的防御值
        ll real_att = player.att + weapons[player.choose_weapon.id].att - true_def; // 真实伤害
        ll caused = min (max (real_att, 0ll), now_heal); // 真实造成的真实伤害
        now_heal -= caused; // 剩余血量

        if (! wait_in_fight(wait_time)) return false;
        sprintf(output_data[0], "--- %s %5lld/%-5lld %3d%%---", mobs[mob].name, now_heal, heal, 1ll * now_heal * 100 / heal);
        sprintf(output_data[(round_cnt - 1) % 1000 + 1], "%2d: You dealt %lld damage to %s. ", round_cnt, caused, mobs[mob].name);

        go_to (0, 0);
        printf("%s\n", output_data[0]);
        int line_cnt = MAX_LINE - 1;
        int start;
        if (line_cnt >= round_cnt) start = 1;
        else start = round_cnt - line_cnt + 1;
        for (int i = start; i <= round_cnt; i ++) {
            printf("%s\n", output_data[(i - 1) % 1000 + 1]);
        }
    }
    sprintf(output_data[0], "You won the enemy. Press any key to continue.");
    go_to (0, 0);
    printf("%s\n", output_data[0]);
    int line_cnt = MAX_LINE - 1;
    int start;
    if (line_cnt >= round_cnt) start = 1;
    else start = round_cnt - line_cnt + 1;
    for (int i = start; i <= round_cnt; i ++) {
        printf("%s\n", output_data[i]);
    }

    clear_stdin();
    press_any_key_to_continue();
    return true;
}

void check_bag () {
    cls();
    printf("Good thing takes time.\n");
    press_any_key_to_continue();
}

void change_log () {
    cls();
    printf("%s", change_logs);
    press_any_key_to_continue();
}

void sandbox () {
    char output_data[30][110];
    int chs = 1;
    int len = 8;

    sprintf(output_data[0], "--- geimu sandbox --- (press [Enter] to change)");
    sprintf(output_data[1], "%c enemy health: %lld", chs == 1 ? '>' : ' ', mobs[0].heal);
    sprintf(output_data[2], "%c enemy defense: %lld", chs == 2 ? '>' : ' ', mobs[0].def);
    sprintf(output_data[3], "%c player attack: %lld", chs == 3 ? '>' : ' ', player.att);
    sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
    sprintf(output_data[5], "%c weapon attack: %lld", chs == 5 ? '>' : ' ', weapons[0].att);
    sprintf(output_data[6], "%c weapon anti_defense: %lld", chs == 6 ? '>' : ' ', weapons[0].anti_def);
    sprintf(output_data[7], "%c weapon attack speed: %.2lfps", chs == 7 ? '>' : ' ', weapons[0].speed, player.speed / 100.0);
    sprintf(output_data[8], "%c i'm ready.", chs == 8 ? '>' : ' ');
    cls ();
    for (int i = 0; i <= len; i ++) {
        printf("%s\n", output_data[i]);
    } while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                go_to (len + 2, 0);
                printf("input enemy health: ");
                ShowCursor();
                scanf("%lld", &mobs[0].heal);
                mobs[0].heal = max (mobs[0].heal, 0ll);
                sprintf(output_data[1], "%c enemy health: %lld", chs == 1 ? '>' : ' ', mobs[0].heal);
            } else if (chs == 2) {
                go_to (len + 2, 0);
                printf("input enemy defense: ");
                ShowCursor();
                scanf("%lld", &mobs[0].def);
                mobs[0].def = max (mobs[0].def, 0ll);
                sprintf(output_data[2], "%c enemy defense: %lld", chs == 2 ? '>' : ' ', mobs[0].def);
            } else if (chs == 3) {
                go_to (len + 2, 0);
                printf("input player attack: ");
                ShowCursor();
                scanf("%lld", &player.att);
                player.att = max (player.att, 0ll);
                sprintf(output_data[3], "%c player attack: %lld", chs == 3 ? '>' : ' ', player.att);
            } else if (chs == 4) {
                double tmp;
                go_to (len + 2, 0);
                printf("input player attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                player.speed = max (min (tmp, 100.0), 0.1) * 100;
                sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
            } else if (chs == 5) {
                go_to (len + 2, 0);
                printf("input weapon attack: ");
                ShowCursor();
                scanf("%lld", &weapons[0].att);
                weapons[0].att = max(weapons[0].att, 0ll);
                sprintf(output_data[5], "%c weapon attack: %lld", chs == 5 ? '>' : ' ', weapons[0].att);
            } else if (chs == 6) {
                go_to (len + 2, 0);
                printf("input weapon anti_defense: ");
                ShowCursor();
                scanf("%lld", &weapons[0].anti_def);
                sprintf(output_data[6], "%c weapon anti_defense: %lld", chs == 6 ? '>' : ' ', weapons[0].anti_def);
            } else if (chs == 7) {
                double tmp;
                go_to (len + 2, 0);
                printf("input weapon attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                weapons[0].speed = max (min (tmp, 100.0), -100.0) * 100;
                sprintf(output_data[7], "%c weapon attack speed: %.2lfps", chs == 7 ? '>' : ' ', weapons[0].speed / 100.0);
            } else if (chs == 8) {
                fight(0);
                clear_stdin();
            } cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin(); HideCursor();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
    }
}

void home_page () {
    char output_data[30][110];
    int chs = 1;
    int len = 3;

    sprintf (output_data[0], "--- Home Page --- money: %lld", player.money);
    sprintf (output_data[1], "%c Check bag", chs == 1 ? '>' : ' ');
    sprintf (output_data[2], "%c Create a sandbox", chs == 2 ? '>' : ' ');
    sprintf (output_data[3], "%c Change log", chs == 3 ? '>' : ' ');
    cls ();
    printf("%s\n", output_data[0]);
    Sleep (500);
    for (int i = 1; i <= len; i ++) printf("%s\n", output_data[i]);
    clear_stdin();
    while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            cls();
            if (chs == 1) {
                check_bag ();
            } else if (chs == 2) {
                sandbox();
            } else {
                change_log ();
            }
            cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
        // Sleep (100);
    }
}

void init () {
    player.money = 100;
    player.att = 0;
    player.speed = 100;
    WEAPON_COUNT = 0;
    strcpy (weapons[0].name, "default");
    weapons[0].att = 10;
    weapons[0].anti_def = 0;
    player.choose_weapon.id = 0;
    MOB_COUNT = 0;
    strcpy (mobs[0].name, "default");
    mobs[0].heal = 1000;
    mobs[0].def = 0;
}

void load_game () {
    char output_data[20][210];
    char weapon_path[110] = "WEAPON.weapon";
    char mob_path[110] = "MOB.mob";
    int chs = 3;
    int len = 3;

    sprintf (output_data[0], "请先选择读入数据的文件名。若因读入文件填写错误而对设备造成损伤,本游戏不承担责任。若你没有游戏数据,请在源代码最底部按注释提示创建。");
    sprintf (output_data[1], "%c 武器列表:%s", chs == 1 ? '>' : ' ', weapon_path);
    sprintf (output_data[2], "%c 生物列表:%s", chs == 2 ? '>' : ' ', mob_path);
    sprintf (output_data[3], "%c 开始游戏!", chs == 3 ? '>' : ' ');
    
    cls ();
    for (int i = 0; i <= len; i ++) {
        printf("%s\n", output_data[i]);
    } while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                ShowCursor();
                go_to (len + 2, 0);
                printf("输入新的武器数据地址:");
                scanf("%s", weapon_path);
                sprintf (output_data[1], "%c 武器列表:%s", chs == 1 ? '>' : ' ', weapon_path);
            } else if (chs == 2) {
                ShowCursor();
                go_to (len + 2, 0);
                printf("输入新的生物数据地址:");
                scanf("%s", mob_path);
                sprintf (output_data[2], "%c 生物列表:%s", chs == 2 ? '>' : ' ', mob_path);
            } else if (chs == 3) {
                break;
            } cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin(); HideCursor();
        } else if (c == 'q' || c == 'Q') {
            exit(0);
        }
    }
    freopen (weapon_path, "r", stdin);
    while (1) {
        char c[25];
        int lv, att, undef, spd;
        scanf("%s", c);
        if (c[0] == '_' && c[1] == '_' && c[2] == 'E' && c[3] == 'N' && c[4] == 'D' && c[5] == '_' && c[6] == '_') {
            break;
        } scanf("%d%d%d%d", &lv, &att, &undef, &spd);
        WEAPON_COUNT ++; 
        strcpy(weapons[WEAPON_COUNT].name, c);
        weapons[WEAPON_COUNT].lv = lv;
        weapons[WEAPON_COUNT].att = att;
        weapons[WEAPON_COUNT].anti_def = undef;
        weapons[WEAPON_COUNT].speed = spd;
    } 
    fclose (stdin);
    freopen (mob_path, "r", stdin);
    while (1) {
        char c[25];
        int heal, def;
        scanf("%s", c);
        if (c[0] == '_' && c[1] == '_' && c[2] == 'E' && c[3] == 'N' && c[4] == 'D' && c[5] == '_' && c[6] == '_') {
            break;
        } scanf("%d%d", &heal, &def);
        MOB_COUNT ++; 
        strcpy(mobs[MOB_COUNT].name, c);
        mobs[MOB_COUNT].heal = heal;
        mobs[MOB_COUNT].def = def;
    } 
    fclose (stdin);
}

int main () {
    HideCursor();

    cls();
    printf("在游玩/调试前请先更换编码方式:点击右下角\"UTF-8\",选择\"reopen with encoding\",点击\"Simplified Chinese (GBK) gbk\"。若程序内中文还是无法正常显示,按Ctrl+Z。\n\
Before playing/debugging, please change the encoding method: click 'UTF-8' in the bottom right corner, select 'Reopen with encoding', and click 'Simplified Chinese (GBK) gbk'. If the Chinese text still does not display properly within the program (that are showing like '锟斤拷', press Ctrl+Z.\n\
Press any key to continue...\n");
    press_any_key_to_continue();

    init();
    load_game ();

    home_page ();
    return 0;
}

/*
创建游戏数据:

目前游戏有两个数据库,默认分别是 WEAPON.weapon 和 MOB.mob。下面是数据的官方内容。您可以在对应数据文件中修改数据来制作二创数据包。请认准官方默认数据包。

将下面内容粘贴到 WEAPON.weapon 中:

小刀 1
12 0 5
刺刀 1
10 4 0
沉重的铁斧 1
15 10 -20
__END__

将下面内容粘贴到 MOB.mob 中:

正方形
100 0
__END__

二创指引:WEAPON.weapon 的文件格式形如:
武器名称(请不要使用以__END__为开头的武器名称!) 等级
攻击 破防 攻击速度x100(为了避免精度误差)
文件末尾用__END__标识
*/

26.1 snapshot 9

/*
当前版本:26.1 snapshot 9

2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。  
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。  
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。

通知:后续更新日志在程序里,运行即可看到。请及时在游戏中找到更新日志以查看最新版本的更新内容。下方变成了评论区。可以评论。记得署名

- 26.1
    - snapshot 1, 2026-07-12
		评价:有剧情吗就开服——Derekyang
    - snapshot 2, 2026-07-12
		评价:把主体做出来好吗,不要只放一个战斗模块——Derekyang
    - snapshot 3, 2026-07-13
*/
#include<cstdio>
#include<random>
#include<ctime>
#include<queue>
#include<cmath>
#include<windows.h>
#include<conio.h>
using namespace std;
#define Rnd(a,b) rnd()%(b-a+1)+a
#define color(a) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a) 
#define Key_down(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
std::mt19937 rnd(time(NULL));
void cls(){
    if (Rnd (0, 9)) { // 降低闪屏频率
        HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
        if (hStdOut == INVALID_HANDLE_VALUE)
            return;
        CONSOLE_SCREEN_BUFFER_INFO csbi;
        if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
            return;
        DWORD count;
        DWORD cellCount = csbi.dwSize.X * csbi.dwSize.Y;
        COORD homeCoords = {0, 0};
        FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count);
        FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count);
        SetConsoleCursorPosition(hStdOut, homeCoords);
    } else
        system("cls");
}
void press_any_key_to_continue () {
	// while (_kbhit ()) {
	// 	getch();
	// } rewind (stdin);
	// while (1) if (kbhit ()) break;
	// return ;
    char c = _getch();
    return ;
} void clear_stdin(void) {
    while (_kbhit ()) {
		getch();
	} rewind (stdin);

    // int c;
    // while ((c = getchar()) != '\n' && c != EOF) {
    // }
}
void HideCursor(){
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void ShowCursor(){
	CONSOLE_CURSOR_INFO cur={1,1};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void go_to (int x, int y){
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coordScreen = {(short)y, (short)x};
    SetConsoleCursorPosition(hConsole, coordScreen);
}
int GetDisplayWidth(const char* str) {
    int width = 0;
    int len = strlen(str);
    
    for (int i = 0; i < len; i++) {
        unsigned char c = (unsigned char)str[i];
        if (c >= 0x81 && c <= 0xFE) {
            if (i + 1 < len) {
                unsigned char c2 = (unsigned char)str[i + 1];
                if ((c2 >= 0x40 && c2 <= 0x7E) || (c2 >= 0x80 && c2 <= 0xFE)) {
                    width += 2;
                    i++;
                    continue;
                }
            }
        }
        width += 1;
    }
    
    return width;
}
struct ConsoleSize {
    int Width;   // 可见列数
    int Height;  // 可见行数
    int BufferWidth;   // 缓冲区总列数
    int BufferHeight;  // 缓冲区总行数
};
ConsoleSize GetAdvancedConsoleSize() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    ConsoleSize size = {80, 25, 80, 300}; // 默认
    
    if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
        // 可见窗口区域(用户当前看到的)
        size.Width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        size.Height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
        // 缓冲区大小(实际可绘制的范围)
        size.BufferWidth = csbi.dwSize.X;
        size.BufferHeight = csbi.dwSize.Y;
    }
    return size;
}
// 计算字符串在控制台中的显示宽度(ASCII:1,GBK中文/全角:2)
int get_width(const char* str) {
    if (!str) return 0;
    int width = 0;
    while (*str) {
        unsigned char ch = static_cast<unsigned char>(*str);
        if (ch >= 0x81 && ch <= 0xFE &&
            *(str + 1) != '\0' &&
            (static_cast<unsigned char>(*(str + 1)) >= 0x40 &&
             static_cast<unsigned char>(*(str + 1)) <= 0xFE &&
             static_cast<unsigned char>(*(str + 1)) != 0x7F)) {
            width += 2;
            str += 2;
        } else {
            width += 1;
            str++;
        }
    }
    return width;
}
// 对齐字符串至指定显示宽度,返回状态码:
//  0 : 无需修改(宽度已相等)
//  1 : 补空格(原宽度 < width)
// -1 : 截断并用点填充(原宽度 > width)
int align_str(char* str, int width) {
    if (!str) return 0;
    if (width < 0) width = 0;
    int total = get_width(str);
    // 情况1:宽度相等,不做改动
    if (total == width) {
        return 0;
    }
    // 情况2:宽度足够,用空格补齐至 width 列
    if (total < width) {
        int len = strlen(str);
        int spaces = width - total;
        for (int i = 0; i < spaces; ++i) {
            str[len + i] = ' ';
        }
        str[len + spaces] = '\0';
        return 1;   // 填充空格
    }
    // 情况3:宽度不足,截断并用点填充至 width 列
    int target = width - 2;          // 至少保留2列给点(但实际可能更多)
    if (target < 0) target = 0;
    const char* p = str;
    char* write_pos = str;
    int cur_width = 0;
    // 复制尽可能多的完整字符(不拆分双字节字符)
    while (*p && cur_width < target) {
        unsigned char ch = static_cast<unsigned char>(*p);
        int char_width = 1;
        if (ch >= 0x81 && ch <= 0xFE &&
            *(p + 1) != '\0' &&
            (static_cast<unsigned char>(*(p + 1)) >= 0x40 &&
             static_cast<unsigned char>(*(p + 1)) <= 0xFE &&
             static_cast<unsigned char>(*(p + 1)) != 0x7F)) {
            char_width = 2;
        }
        if (cur_width + char_width > target) {
            break;  // 该字符放不下,停止
        }
        cur_width += char_width;
        if (char_width == 2) {
            *write_pos++ = *p++;
            *write_pos++ = *p++;
        } else {
            *write_pos++ = *p++;
        }
    }
    // 剩余宽度全部用点填充
    int dots = width - cur_width;     // 需要填充的点数
    for (int i = 0; i < dots; ++i) {
        *write_pos++ = '.';
    }
    *write_pos = '\0';
    return -1;   // 截断并填充点
}

char change_logs[100000] = {"\
当前版本:26.1 snapshot 9\n\
2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。\n\
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。\n\
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。\n\
\n\
开发者:jessy\n\
特邀嘉宾:DEREKYANG\n\
\n\
- 26.1 Sandbox Update\n\
    - snapshot 1, 2026-07-12\n\
        - 正式开服,现在十分简陋,但是能看。有了与怪物战斗能力,但是目前只有攻击力和攻击速度两个属性。\n\
    - snapshot 2, 2026-07-12\n\
        - 现在增加了滚动系统,控制台最多显示十行。\n\
        - ~~为了展示滚动算法的先进性~~输出信息会额外输出回合数。\n\
        - 修复了一个漏洞\n\
            - 当输出行数超过控制台行数时,输出内容会错误地覆盖之前的信息。\n\
    - snapshot 3, 2026-07-13\n\
        - 新增了主页。\n\
        - 新增了沙盒模式,玩家可以随意调控目前的战斗参数,而不是调源代码。\n\
        - 新增了更新日志。以后更新日志都会放到那里。\n\
        - 新增了查看背包功能。自己点进去看看吧。我啷个晓得嘛\n\
    - snapshot 4, 2026-07-13\n\
        - 紧急更新:修复了一个漏洞\n\
            - 当敌人生命超过int存储上限的1%时,游戏计算出错。\n\
    - snapshot 5, 2026-07-14\n\
        - 加入了怪物的防御,类似于护甲,真实伤害还会减去防御值。\n\
        - 修复了一个漏洞\n\
            - 战斗时不能退出。\n\
    - snapshot 6, 2026-07-14\n\
        - 加入了战斗模式暂停的功能,按空格键可以暂停。\n\
        - 删除了战斗模式暂停的功能,开发者认为这没有什么意义。\n\
        - 现在战斗记录的存储方式使用了更加先进的存储技术,用人话说就是滚动数组。\n\
        - 新增了武器的破防属性,用来削减敌人的防御值。特别地,此值可为负。\n\
        - 修复了若干个漏洞\n\
            - 回合数超过 1000 的战斗会崩溃。\n\
            - 按 Q 退出战斗后 Q 会被再次读入。\n\
    - snapshot 7, 2026-07-16\n\
        - 加入了武器的攻击速度,正负均可\n\
        - 正在设计新的存档格式,将武器、生物等数据进行软编码,预计下个快照实现,并增加一些基础的生物和武器。\n\
    - snapshot 8, 2026-07-17\n\
        - 加入了数据格式,目前只有 .WEAPON 和 .MOB 两种,具体可见源代码底部。\n\
        - 添加了怪物以及武器的名称。在战斗中会显示怪物的名称而非之前的\"ENEMY\"。\n\
        - 更改了一个漏洞的状态\n\
            - 当怪物血量超过约 9e16 时,剩余血量百分比计算错误。漏洞状态为:不予修复。原因:就目前来看,这么高的怪物血量是不切实际的。\n\
        - 再次隆重声明:该游戏名称“给木”是作者的倾情创作,严禁丑化、扭曲本游戏名称(如称之为“旮旯给木”等)。\n\
        - 重新上传,以修复严重漏洞:加载数据后标准输入流无法读取控制台的内容。\n\
    - snapshot 9, 2026-07-18\n\
        - 完善了了背包的功能,可以显示玩家的武器列表和目前装备的列表,并且可以更改,同时可以查看武器的属性。\n\
        - 后续会进行背包的优化,并且会增加背包列表的排序功能。\n\
"};

typedef long long ll;
const int N = 10010;
const int NONE = N - 9;
int WEAPON_COUNT, MOB_COUNT;
int MAX_LINE = 11;

struct MOB {
    char name[25];
    ll heal; // health
    ll def; // defense
} mobs[N];

struct WEAPON {
    char name[25];
    ll att;
    ll anti_def;
    int speed;
    int lv;
} weapons[N];

struct CHOOSEWEAPON {
    int id;
};

struct PLAYER {
    ll att = 100; // attack
    ll money;
    CHOOSEWEAPON choose_weapon;
    int speed = 100; // attack speed
    int bag_sz, weapon_bag_len = 0;
    CHOOSEWEAPON weapon_bag[1010];
} player;

bool wait_in_fight (int wait_time) {
    const int INTERVAL = 10;
    for (int slept = 0; slept < wait_time; slept += INTERVAL) {
        Sleep(min(INTERVAL, wait_time - slept));
        if (Key_down('Q')) {
            return false;
        }
    }
    return true;
}

bool fight (int mob) {
    ll heal = mobs[mob].heal;
    ll now_heal = heal;
    int round_cnt = 0;
    char output_data[1010][110];
    int real_speed = player.speed + weapons[player.choose_weapon.id].speed;
    real_speed = max (min (10000, real_speed), 10);

    cls();
    sprintf(output_data[0], "--- %s %5lld/%-5lld %3d%%---", mobs[mob].name, now_heal, heal, 1ll * now_heal * 100 / heal);
    printf("%s\n", output_data[0]);
    while (now_heal > 0) {
        round_cnt ++;

        int wait_time = 100000 / real_speed; // 等待时间
        ll true_def = max (mobs[mob].def - weapons[player.choose_weapon.id].anti_def, 0ll); // 去除破防后的防御值
        ll real_att = player.att + weapons[player.choose_weapon.id].att - true_def; // 真实伤害
        ll caused = min (max (real_att, 0ll), now_heal); // 真实造成的真实伤害
        now_heal -= caused; // 剩余血量

        if (! wait_in_fight(wait_time)) return false;
        sprintf(output_data[0], "--- %s %5lld/%-5lld %3d%%---", mobs[mob].name, now_heal, heal, 1ll * now_heal * 100 / heal);
        sprintf(output_data[(round_cnt - 1) % 1000 + 1], "%2d: You dealt %lld damage to %s. ", round_cnt, caused, mobs[mob].name);

        go_to (0, 0);
        printf("%s\n", output_data[0]);
        int line_cnt = MAX_LINE - 1;
        int start;
        if (line_cnt >= round_cnt) start = 1;
        else start = round_cnt - line_cnt + 1;
        for (int i = start; i <= round_cnt; i ++) {
            printf("%s\n", output_data[(i - 1) % 1000 + 1]);
        }
    }
    sprintf(output_data[0], "You won the enemy. Press any key to continue.");
    go_to (0, 0);
    printf("%s\n", output_data[0]);
    int line_cnt = MAX_LINE - 1;
    int start;
    if (line_cnt >= round_cnt) start = 1;
    else start = round_cnt - line_cnt + 1;
    for (int i = start; i <= round_cnt; i ++) {
        printf("%s\n", output_data[i]);
    }

    clear_stdin();
    press_any_key_to_continue();
    return true;
}

bool fight_in_sandbox () {
    int mob = 0;
    int choose_weapon = 0;
    ll heal = mobs[mob].heal;
    ll now_heal = heal;
    int round_cnt = 0;
    char output_data[1010][110];
    int real_speed = player.speed + weapons[choose_weapon].speed;
    real_speed = max (min (10000, real_speed), 10);

    cls();
    sprintf(output_data[0], "--- %s %5lld/%-5lld %3d%%---", mobs[mob].name, now_heal, heal, 1ll * now_heal * 100 / heal);
    printf("%s\n", output_data[0]);
    while (now_heal > 0) {
        round_cnt ++;

        int wait_time = 100000 / real_speed; // 等待时间
        ll true_def = max (mobs[mob].def - weapons[choose_weapon].anti_def, 0ll); // 去除破防后的防御值
        ll real_att = player.att + weapons[choose_weapon].att - true_def; // 真实伤害
        ll caused = min (max (real_att, 0ll), now_heal); // 真实造成的真实伤害
        now_heal -= caused; // 剩余血量

        if (! wait_in_fight(wait_time)) return false;
        sprintf(output_data[0], "--- %s %5lld/%-5lld %3d%%---", mobs[mob].name, now_heal, heal, 1ll * now_heal * 100 / heal);
        sprintf(output_data[(round_cnt - 1) % 1000 + 1], "%2d: You dealt %lld damage to %s. ", round_cnt, caused, mobs[mob].name);

        go_to (0, 0);
        printf("%s\n", output_data[0]);
        int line_cnt = MAX_LINE - 1;
        int start;
        if (line_cnt >= round_cnt) start = 1;
        else start = round_cnt - line_cnt + 1;
        for (int i = start; i <= round_cnt; i ++) {
            printf("%s\n", output_data[(i - 1) % 1000 + 1]);
        }
    }
    sprintf(output_data[0], "You won the enemy. Press any key to continue.");
    go_to (0, 0);
    printf("%s\n", output_data[0]);
    int line_cnt = MAX_LINE - 1;
    int start;
    if (line_cnt >= round_cnt) start = 1;
    else start = round_cnt - line_cnt + 1;
    for (int i = start; i <= round_cnt; i ++) {
        printf("%s\n", output_data[i]);
    }

    clear_stdin();
    press_any_key_to_continue();
    return true;
}

/*
/----gear----\ /-----bag------\ /---preview----\
|> WEAPON:   | |- WEAPON:     | |NAMEEEEEEEEEEE|
|AAAAAAAAAA  | |> AABBCCDDEEFF| |  MODEEEEEEEEE|
|> unequip   | |  AABBCCDDEEFF| |  MODEEEEEEEEE|
|            | |              | |  MODEEEEEEEEE|
|            | |              | |
|            | |              |
\            / |              |
               |              |
               \--------------/
*/

void show_preview_in_bag (char output_prev[30][30], int &len_prev, CHOOSEWEAPON chs_wp, bool focus) {
    int chs_wp_id = chs_wp.id;
    len_prev = 1;
    char tmp[30];
    if (focus) sprintf (output_prev[0], "/---preview----\\");
    else       sprintf (output_prev[0], "/   preview    \\");
    strcpy (tmp, weapons[chs_wp_id].name);
    align_str (tmp, 14);
    sprintf (output_prev[1], "|%s|", tmp);
    if (weapons[chs_wp_id].att != 0){
        sprintf (tmp, "%lld", weapons[chs_wp_id].att);
        align_str (tmp, 9);
        sprintf(output_prev[++ len_prev], "|att: %s|", tmp);
    } if (weapons[chs_wp_id].anti_def != 0){
        sprintf (tmp, "%lld", weapons[chs_wp_id].anti_def);
        align_str (tmp, 7);
        sprintf(output_prev[++ len_prev], "|undef: %s|", tmp);
    } if (weapons[chs_wp_id].speed != 0){
        sprintf (tmp, "%.2lf", weapons[chs_wp_id].speed / 100.0);
        align_str (tmp, 7);
        sprintf(output_prev[++ len_prev], "|speed: %s|", tmp);
    }
    if (focus) sprintf (output_prev[++ len_prev], "\\--------------/");
    else       sprintf (output_prev[++ len_prev], "\\              /");
    len_prev --;
}

void show_gear_in_bag (char output_gear[30][30], int chs_gear, bool focus) {
    char tmp[30];
    strcpy (tmp, weapons[player.choose_weapon.id].name);
    align_str (tmp, 12);
    if (focus) sprintf (output_gear[0], "/----gear----\\");
    else       sprintf (output_gear[0], "/    gear    \\");
    sprintf (output_gear[1], "|%c weapon:   |", chs_gear == 1? '>' : ' ');
    sprintf (output_gear[2], "|%s|", tmp);
    sprintf (output_gear[3], "|%c unequip   |", chs_gear == 3? '>' : ' ');
    if (focus) sprintf (output_gear[4], "\\------------/");
    else       sprintf (output_gear[4], "\\            /");
}
void show_bag_in_bag (char output_bag[30][30], char output_bag_data[1010][30], bool *valid_bag, int chs_bag, int len_bag, bool focus) {
    char tmp[30];
    if (focus) sprintf (output_bag[0],       "/-----bag------\\");
    else       sprintf (output_bag[0],       "/     bag      \\");
    if (focus) sprintf (output_bag[len_bag + 1], "\\--------------/");
    else       sprintf (output_bag[len_bag + 1], "\\              /");
    sprintf (output_bag_data[1],  "|- WEAPON:     |");
    for (int i = 1; i <= player.weapon_bag_len; i ++) {
        strcpy (tmp, weapons[player.weapon_bag[i].id].name);
        align_str (tmp, 12);
        sprintf(output_bag_data[i + 1], "|%c %s|", chs_bag == i + 1 ? '>' : ' ', tmp);
        valid_bag[i + 1] = 1;
    }
    
    int start = chs_bag - len_bag / 2, end = chs_bag + len_bag / 2;
    if (start < 1) start = 1, end = start + len_bag - 1;
    if (end > player.weapon_bag_len + 1) end = player.weapon_bag_len + 1, start = end - len_bag + 1;
    for (int i = start, j = 1; i <= end; i ++, j ++) {
        strcpy (output_bag[j], output_bag_data[i]);
    }
}

void print_in_bag (char output[30][30], int len, int start) {
    for (int i = 0; i <= len + 1; i ++) {
        go_to (i, start);
        printf("%s", output[i]);
    } 
}

void check_bag () { // 抱歉我已经尽可能的让代码不那么屎山了。
    cls();
    char output_gear[30][30];
    int chs_gear = 1;
    int len_gear = 3;
    int start_gear = 0;
    bool valid_gear[30] = {0, 1, 0, 1, 0};
    char output_bag_data[1010][30];
    char output_bag[30][30];
    bool valid_bag[1010] = {0, 0, 1};
    int chs_bag = 2;
    int len_bag = MAX_LINE - 2;
    int start_bag = 15;
    char output_prev[30][30];
    int len_prev = 1;
    int start_prev = 32;
    int chs = 2;
    char tmp[30];

    show_gear_in_bag (output_gear, chs_gear, chs == 1);
    show_bag_in_bag (output_bag, output_bag_data, valid_bag, chs_bag, len_bag, chs == 2);
    show_preview_in_bag (output_prev, len_prev, player.weapon_bag[chs_bag - 1], chs == 3);

    print_in_bag (output_gear, len_gear, start_gear);
    print_in_bag (output_bag, len_bag, start_bag);
    print_in_bag (output_prev, len_prev, start_prev);

    while (1) {
        char c = _getch();
        if (c == 'a' || c == 'A') {
            if (chs == 2) {
                sprintf(output_bag[0], "/     bag      \\");
                sprintf(output_bag[len_bag + 1], "\\              /");
                sprintf(output_gear[0], "/----gear----\\");
                sprintf(output_gear[len_gear + 1], "\\------------/");
                chs = 1;
                show_preview_in_bag (output_prev, len_prev, player.choose_weapon, chs == 3);
            } else if (chs == 1) {
                sprintf(output_gear[0], "/    gear    \\");
                sprintf(output_gear[len_gear + 1], "\\            /");
                sprintf(output_prev[0], "/---preview----\\");
                sprintf(output_prev[len_prev + 1], "\\--------------/");
                chs = 3;
            } else if (chs == 3) {
                sprintf(output_prev[0], "/   preview    \\");
                sprintf(output_prev[len_prev + 1], "\\              /");
                sprintf(output_bag[0], "/-----bag------\\");
                sprintf(output_bag[len_bag + 1], "\\--------------/");
                chs = 2;
                show_preview_in_bag (output_prev, len_prev, player.weapon_bag[chs_bag - 1], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == 'd' || c == 'D') {
            if (chs == 2) {
                sprintf(output_bag[0], "/     bag      \\");
                sprintf(output_bag[len_bag + 1], "\\              /");
                sprintf(output_prev[0], "/---preview----\\");
                sprintf(output_prev[len_prev + 1], "\\--------------/");
                chs = 3;
            } else if (chs == 1) {
                sprintf(output_gear[0], "/    gear    \\");
                sprintf(output_gear[len_gear + 1], "\\            /");
                sprintf(output_bag[0], "/-----bag------\\");
                sprintf(output_bag[len_bag + 1], "\\--------------/");
                chs = 2;
                show_preview_in_bag (output_prev, len_prev, player.weapon_bag[chs_bag - 1], chs == 3);
            } else if (chs == 3) {
                sprintf(output_prev[0], "/   preview    \\");
                sprintf(output_prev[len_prev + 1], "\\              /");
                sprintf(output_gear[0], "/----gear----\\");
                sprintf(output_gear[len_gear + 1], "\\------------/");
                chs = 1;
                show_preview_in_bag (output_prev, len_prev, player.choose_weapon, chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == 'w' || c == 'W') {
            if (chs == 1) {
                do {
                    chs_gear --;
                    chs_gear = (chs_gear - 1 + len_gear) % len_gear + 1;
                } while (! valid_gear[chs_gear]) ;
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_preview_in_bag (output_prev, len_prev, player.choose_weapon, chs == 3);
            } else if (chs == 2) {
                do {
                    chs_bag --;
                    chs_bag = (chs_bag + player.weapon_bag_len) % (player.weapon_bag_len + 1) + 1;
                } while (! valid_bag[chs_bag]) ;
                show_bag_in_bag (output_bag, output_bag_data, valid_bag, chs_bag, len_bag, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.weapon_bag[chs_bag - 1], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == 's' || c == 'S') {
            if (chs == 1) {
                do {
                    chs_gear ++;
                    chs_gear = (chs_gear - 1) % len_gear + 1;
                } while (! valid_gear[chs_gear]) ;
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_preview_in_bag (output_prev, len_prev, player.choose_weapon, chs == 3);
            } else if (chs == 2) {
                do {
                    chs_bag ++;
                    chs_bag = (chs_bag - 1) % (player.weapon_bag_len + 1) + 1;
                } while (! valid_bag[chs_bag]) ;
                show_bag_in_bag (output_bag, output_bag_data, valid_bag, chs_bag, len_bag, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.weapon_bag[chs_bag - 1], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                if (chs_gear == 3 && player.choose_weapon.id != NONE) {
                    player.weapon_bag[++ player.weapon_bag_len].id = NONE;
                    swap (player.choose_weapon, player.weapon_bag[player.weapon_bag_len]);
                }
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_bag_in_bag (output_bag, output_bag_data, valid_bag, chs_bag, len_bag, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.choose_weapon, chs == 3);
            } else if (chs == 2) {
                swap (player.choose_weapon, player.weapon_bag[chs_bag - 1]);
                if (player.weapon_bag[chs_bag - 1].id == NONE) {
                    for (int i = chs_bag; i <= player.weapon_bag_len; i ++) {
                        swap (player.weapon_bag[i - 1],player.weapon_bag[i]);
                    } player.weapon_bag_len --;
                } if (chs_bag > player.weapon_bag_len + 1) {
                    do {
                        chs_bag --;
                        chs_bag = (chs_bag + player.weapon_bag_len) % (player.weapon_bag_len + 1) + 1;
                    } while (! valid_bag[chs_bag]) ;
                }
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_bag_in_bag (output_bag, output_bag_data, valid_bag, chs_bag, len_bag, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.weapon_bag[chs_bag - 1], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        }

        else if (c == 'q' || c == 'Q') {
            return ;
        }
    }
}

void change_log () {
    cls();
    printf("%s", change_logs);
    press_any_key_to_continue();
}

void sandbox () {
    char output_data[30][110];
    int chs = 1;
    int len = 8;

    sprintf(output_data[0], "--- geimu sandbox --- (press [Enter] to change)");
    sprintf(output_data[1], "%c enemy health: %lld", chs == 1 ? '>' : ' ', mobs[0].heal);
    sprintf(output_data[2], "%c enemy defense: %lld", chs == 2 ? '>' : ' ', mobs[0].def);
    sprintf(output_data[3], "%c player attack: %lld", chs == 3 ? '>' : ' ', player.att);
    sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
    sprintf(output_data[5], "%c weapon attack: %lld", chs == 5 ? '>' : ' ', weapons[0].att);
    sprintf(output_data[6], "%c weapon anti_defense: %lld", chs == 6 ? '>' : ' ', weapons[0].anti_def);
    sprintf(output_data[7], "%c weapon attack speed: %.2lfps", chs == 7 ? '>' : ' ', weapons[0].speed, player.speed / 100.0);
    sprintf(output_data[8], "%c i'm ready.", chs == 8 ? '>' : ' ');
    cls ();
    for (int i = 0; i <= len; i ++) {
        printf("%s\n", output_data[i]);
    } while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                go_to (len + 2, 0);
                printf("input enemy health: ");
                ShowCursor();
                scanf("%lld", &mobs[0].heal);
                mobs[0].heal = max (mobs[0].heal, 0ll);
                sprintf(output_data[1], "%c enemy health: %lld", chs == 1 ? '>' : ' ', mobs[0].heal);
            } else if (chs == 2) {
                go_to (len + 2, 0);
                printf("input enemy defense: ");
                ShowCursor();
                scanf("%lld", &mobs[0].def);
                mobs[0].def = max (mobs[0].def, 0ll);
                sprintf(output_data[2], "%c enemy defense: %lld", chs == 2 ? '>' : ' ', mobs[0].def);
            } else if (chs == 3) {
                go_to (len + 2, 0);
                printf("input player attack: ");
                ShowCursor();
                scanf("%lld", &player.att);
                player.att = max (player.att, 0ll);
                sprintf(output_data[3], "%c player attack: %lld", chs == 3 ? '>' : ' ', player.att);
            } else if (chs == 4) {
                double tmp;
                go_to (len + 2, 0);
                printf("input player attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                player.speed = max (min (tmp, 100.0), 0.1) * 100;
                sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
            } else if (chs == 5) {
                go_to (len + 2, 0);
                printf("input weapon attack: ");
                ShowCursor();
                scanf("%lld", &weapons[0].att);
                weapons[0].att = max(weapons[0].att, 0ll);
                sprintf(output_data[5], "%c weapon attack: %lld", chs == 5 ? '>' : ' ', weapons[0].att);
            } else if (chs == 6) {
                go_to (len + 2, 0);
                printf("input weapon anti_defense: ");
                ShowCursor();
                scanf("%lld", &weapons[0].anti_def);
                sprintf(output_data[6], "%c weapon anti_defense: %lld", chs == 6 ? '>' : ' ', weapons[0].anti_def);
            } else if (chs == 7) {
                double tmp;
                go_to (len + 2, 0);
                printf("input weapon attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                weapons[0].speed = max (min (tmp, 100.0), -100.0) * 100;
                sprintf(output_data[7], "%c weapon attack speed: %.2lfps", chs == 7 ? '>' : ' ', weapons[0].speed / 100.0);
            } else if (chs == 8) {
                fight_in_sandbox();
                clear_stdin();
            } cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin(); HideCursor();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
    }
}

void home_page () {
    char output_data[30][110];
    int chs = 1;
    int len = 3;

    sprintf (output_data[0], "--- Home Page --- money: %lld", player.money);
    sprintf (output_data[1], "%c Check bag", chs == 1 ? '>' : ' ');
    sprintf (output_data[2], "%c Create a sandbox", chs == 2 ? '>' : ' ');
    sprintf (output_data[3], "%c Change log", chs == 3 ? '>' : ' ');
    cls ();
    printf("%s\n", output_data[0]);
    Sleep (500);
    for (int i = 1; i <= len; i ++) printf("%s\n", output_data[i]);
    clear_stdin();
    while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            cls();
            if (chs == 1) {
                check_bag ();
            } else if (chs == 2) {
                sandbox();
            } else {
                change_log ();
            }
            cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
        // Sleep (100);
    }
}

void init () {
    player.money = 100;
    player.att = 0;
    player.speed = 100;
    WEAPON_COUNT = 0;
    strcpy (weapons[0].name, "default");
    weapons[0].att = 10;
    weapons[0].anti_def = 0;
    player.choose_weapon.id = 0;
    MOB_COUNT = 0;
    strcpy (mobs[0].name, "default");
    mobs[0].heal = 1000;
    mobs[0].def = 0;
    weapons[NONE].att = weapons[NONE].anti_def = weapons[NONE].lv = weapons[NONE].speed = 0; strcpy(weapons[NONE].name, "未装备");
    player.weapon_bag_len = 15;
    player.choose_weapon.id = NONE;
    player.weapon_bag[1].id = player.weapon_bag[4].id = player.weapon_bag[7].id = player.weapon_bag[10].id = player.weapon_bag[13].id = 1;
    player.weapon_bag[2].id = player.weapon_bag[5].id = player.weapon_bag[8].id = player.weapon_bag[11].id = player.weapon_bag[14].id = 2;
    player.weapon_bag[3].id = player.weapon_bag[6].id = player.weapon_bag[9].id = player.weapon_bag[12].id = player.weapon_bag[15].id = 3;
}

void load_game () {
    char output_data[20][210];
    char weapon_path[110] = "WEAPON.weapon";
    char mob_path[110] = "MOB.mob";
    int chs = 3;
    int len = 3;

    sprintf (output_data[0], "请先选择读入数据的文件名。若因读入文件填写错误而对设备造成损伤,本游戏不承担责任。若你没有游戏数据,请在源代码最底部按注释提示创建。");
    sprintf (output_data[1], "%c 武器列表:%s", chs == 1 ? '>' : ' ', weapon_path);
    sprintf (output_data[2], "%c 生物列表:%s", chs == 2 ? '>' : ' ', mob_path);
    sprintf (output_data[3], "%c 开始游戏!", chs == 3 ? '>' : ' ');
    
    cls ();
    for (int i = 0; i <= len; i ++) {
        printf("%s\n", output_data[i]);
    } while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                ShowCursor();
                go_to (len + 2, 0);
                printf("输入新的武器数据地址:");
                scanf("%s", weapon_path);
                sprintf (output_data[1], "%c 武器列表:%s", chs == 1 ? '>' : ' ', weapon_path);
            } else if (chs == 2) {
                ShowCursor();
                go_to (len + 2, 0);
                printf("输入新的生物数据地址:");
                scanf("%s", mob_path);
                sprintf (output_data[2], "%c 生物列表:%s", chs == 2 ? '>' : ' ', mob_path);
            } else if (chs == 3) {
                break;
            } cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin(); HideCursor();
        } else if (c == 'q' || c == 'Q') {
            exit(0);
        }
    }
    freopen (weapon_path, "r", stdin);
    while (1) {
        char c[25];
        int lv, att, undef, spd;
        scanf("%s", c);
        if (c[0] == '_' && c[1] == '_' && c[2] == 'E' && c[3] == 'N' && c[4] == 'D' && c[5] == '_' && c[6] == '_') {
            break;
        } scanf("%d%d%d%d", &lv, &att, &undef, &spd);
        WEAPON_COUNT ++; 
        strcpy(weapons[WEAPON_COUNT].name, c);
        weapons[WEAPON_COUNT].lv = lv;
        weapons[WEAPON_COUNT].att = att;
        weapons[WEAPON_COUNT].anti_def = undef;
        weapons[WEAPON_COUNT].speed = spd;
    } 
    fclose (stdin);
    freopen (mob_path, "r", stdin);
    while (1) {
        char c[25];
        int heal, def;
        scanf("%s", c);
        if (c[0] == '_' && c[1] == '_' && c[2] == 'E' && c[3] == 'N' && c[4] == 'D' && c[5] == '_' && c[6] == '_') {
            break;
        } scanf("%d%d", &heal, &def);
        MOB_COUNT ++; 
        strcpy(mobs[MOB_COUNT].name, c);
        mobs[MOB_COUNT].heal = heal;
        mobs[MOB_COUNT].def = def;
    } 
    fclose (stdin);
    freopen("CON", "r", stdin);
}

int main () {
    HideCursor();

    cls();
    printf("在游玩/调试前请先更换编码方式:点击右下角\"UTF-8\",选择\"reopen with encoding\",点击\"Simplified Chinese (GBK) gbk\"。若程序内中文还是无法正常显示,按Ctrl+Z。\n\
Before playing/debugging, please change the encoding method: click 'UTF-8' in the bottom right corner, select 'Reopen with encoding', and click 'Simplified Chinese (GBK) gbk'. If the Chinese text still does not display properly within the program (that are showing like '锟斤拷', press Ctrl+Z.\n\
Press any key to continue...\n");
    press_any_key_to_continue();

    init();
    load_game ();

    home_page ();
    return 0;
}

/*
创建游戏数据:

目前游戏有两个数据库,默认分别是 WEAPON.weapon 和 MOB.mob。下面是数据的官方内容。您可以在对应数据文件中修改数据来制作二创数据包。请认准官方默认数据包。

将下面内容粘贴到 WEAPON.weapon 中:

小刀 1
12 0 5
刺刀 1
10 4 0
沉重的铁斧 1
15 10 -20
__END__

将下面内容粘贴到 MOB.mob 中:

正方形
100 0
__END__

二创指引:WEAPON.weapon 的文件格式形如:
武器名称(请不要使用以__END__为开头的武器名称!) 等级
攻击 破防 攻击速度x100(为了避免精度误差)
文件末尾用__END__标识
*/

26.1 snapshot 10

  • 更新了新的装备种类:护甲。
  • 更新了装备的属性:防御值。可以增加玩家的防御值。玩家自身的生命和防御值系统将在下个快照更新。
  • 增加了背包的排序功能。
  • 现在开发者会在博客园的随笔中事实更新最新版本,之前版本的存档也会在那里。

另:hyw
难蚌.png
这次更新开发者修改了底层逻辑,所以更新时间很长。预计下一个快照也会很慢更新。

/*
当前版本:26.1 snapshot 10

2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。  
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。  
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。

通知:后续更新日志在程序里,运行即可看到。请及时在游戏中找到更新日志以查看最新版本的更新内容。下方变成了评论区。可以评论。记得署名

- 26.1
    - snapshot 1, 2026-07-12
		评价:有剧情吗就开服——Derekyang
    - snapshot 2, 2026-07-12
		评价:把主体做出来好吗,不要只放一个战斗模块——Derekyang
    - snapshot 3, 2026-07-13
*/
#include<cstdio>
#include<random>
#include<ctime>
#include<queue>
#include<cmath>
#include<algorithm>
#include<windows.h>
#include<conio.h>
using namespace std;
#define Rnd(a,b) rnd()%(b-a+1)+a
#define color(a) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a) 
#define Key_down(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
#define fi first
#define se second
std::mt19937 rnd(time(NULL));
void cls(){
    if (Rnd (0, 9)) { // 降低闪屏频率
        HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
        if (hStdOut == INVALID_HANDLE_VALUE)
            return;
        CONSOLE_SCREEN_BUFFER_INFO csbi;
        if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
            return;
        DWORD count;
        DWORD cellCount = csbi.dwSize.X * csbi.dwSize.Y;
        COORD homeCoords = {0, 0};
        FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count);
        FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count);
        SetConsoleCursorPosition(hStdOut, homeCoords);
    } else
        system("cls");
}
void press_any_key_to_continue () {
	// while (_kbhit ()) {
	// 	getch();
	// } rewind (stdin);
	// while (1) if (kbhit ()) break;
	// return ;
    char c = _getch();
    return ;
} void clear_stdin(void) {
    while (_kbhit ()) {
		getch();
	} rewind (stdin);

    // int c;
    // while ((c = getchar()) != '\n' && c != EOF) {
    // }
}
void HideCursor(){
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void ShowCursor(){
	CONSOLE_CURSOR_INFO cur={1,1};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void go_to (int x, int y){
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coordScreen = {(short)y, (short)x};
    SetConsoleCursorPosition(hConsole, coordScreen);
}
int GetDisplayWidth(const char* str) {
    int width = 0;
    int len = strlen(str);
    
    for (int i = 0; i < len; i++) {
        unsigned char c = (unsigned char)str[i];
        if (c >= 0x81 && c <= 0xFE) {
            if (i + 1 < len) {
                unsigned char c2 = (unsigned char)str[i + 1];
                if ((c2 >= 0x40 && c2 <= 0x7E) || (c2 >= 0x80 && c2 <= 0xFE)) {
                    width += 2;
                    i++;
                    continue;
                }
            }
        }
        width += 1;
    }
    
    return width;
}
struct ConsoleSize {
    int Width;   // 可见列数
    int Height;  // 可见行数
    int BufferWidth;   // 缓冲区总列数
    int BufferHeight;  // 缓冲区总行数
};
ConsoleSize GetAdvancedConsoleSize() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    ConsoleSize size = {80, 25, 80, 300}; // 默认
    
    if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
        // 可见窗口区域(用户当前看到的)
        size.Width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        size.Height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
        // 缓冲区大小(实际可绘制的范围)
        size.BufferWidth = csbi.dwSize.X;
        size.BufferHeight = csbi.dwSize.Y;
    }
    return size;
}
// 计算字符串在控制台中的显示宽度(ASCII:1,GBK中文/全角:2)
int get_width(const char* str) {
    if (!str) return 0;
    int width = 0;
    while (*str) {
        unsigned char ch = static_cast<unsigned char>(*str);
        if (ch >= 0x81 && ch <= 0xFE &&
            *(str + 1) != '\0' &&
            (static_cast<unsigned char>(*(str + 1)) >= 0x40 &&
             static_cast<unsigned char>(*(str + 1)) <= 0xFE &&
             static_cast<unsigned char>(*(str + 1)) != 0x7F)) {
            width += 2;
            str += 2;
        } else {
            width += 1;
            str++;
        }
    }
    return width;
}
// 对齐字符串至指定显示宽度,返回状态码:
//  0 : 无需修改(宽度已相等)
//  1 : 补空格(原宽度 < width)
// -1 : 截断并用点填充(原宽度 > width)
int align_str(char* str, int width) {
    if (!str) return 0;
    if (width < 0) width = 0;
    int total = get_width(str);
    // 情况1:宽度相等,不做改动
    if (total == width) {
        return 0;
    }
    // 情况2:宽度足够,用空格补齐至 width 列
    if (total < width) {
        int len = strlen(str);
        int spaces = width - total;
        for (int i = 0; i < spaces; ++i) {
            str[len + i] = ' ';
        }
        str[len + spaces] = '\0';
        return 1;   // 填充空格
    }
    // 情况3:宽度不足,截断并用点填充至 width 列
    int target = width - 2;          // 至少保留2列给点(但实际可能更多)
    if (target < 0) target = 0;
    const char* p = str;
    char* write_pos = str;
    int cur_width = 0;
    // 复制尽可能多的完整字符(不拆分双字节字符)
    while (*p && cur_width < target) {
        unsigned char ch = static_cast<unsigned char>(*p);
        int char_width = 1;
        if (ch >= 0x81 && ch <= 0xFE &&
            *(p + 1) != '\0' &&
            (static_cast<unsigned char>(*(p + 1)) >= 0x40 &&
             static_cast<unsigned char>(*(p + 1)) <= 0xFE &&
             static_cast<unsigned char>(*(p + 1)) != 0x7F)) {
            char_width = 2;
        }
        if (cur_width + char_width > target) {
            break;  // 该字符放不下,停止
        }
        cur_width += char_width;
        if (char_width == 2) {
            *write_pos++ = *p++;
            *write_pos++ = *p++;
        } else {
            *write_pos++ = *p++;
        }
    }
    // 剩余宽度全部用点填充
    int dots = width - cur_width;     // 需要填充的点数
    for (int i = 0; i < dots; ++i) {
        *write_pos++ = '.';
    }
    *write_pos = '\0';
    return -1;   // 截断并填充点
}

char change_logs[100000] = {"\
当前版本:26.1 snapshot 10\n\
2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。\n\
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。\n\
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。\n\
\n\
开发者:jessy\n\
特邀嘉宾:DEREKYANG\n\
\n\
- 26.1 Sandbox Update\n\
    - snapshot 1, 2026-07-12\n\
        - 正式开服,现在十分简陋,但是能看。有了与怪物战斗能力,但是目前只有攻击力和攻击速度两个属性。\n\
    - snapshot 2, 2026-07-12\n\
        - 现在增加了滚动系统,控制台最多显示十行。\n\
        - ~~为了展示滚动算法的先进性~~输出信息会额外输出回合数。\n\
        - 修复了一个漏洞\n\
            - 当输出行数超过控制台行数时,输出内容会错误地覆盖之前的信息。\n\
    - snapshot 3, 2026-07-13\n\
        - 新增了主页。\n\
        - 新增了沙盒模式,玩家可以随意调控目前的战斗参数,而不是调源代码。\n\
        - 新增了更新日志。以后更新日志都会放到那里。\n\
        - 新增了查看背包功能。自己点进去看看吧。我啷个晓得嘛\n\
    - snapshot 4, 2026-07-13\n\
        - 紧急更新:修复了一个漏洞\n\
            - 当敌人生命超过int存储上限的1%时,游戏计算出错。\n\
    - snapshot 5, 2026-07-14\n\
        - 加入了怪物的防御,类似于护甲,真实伤害还会减去防御值。\n\
        - 修复了一个漏洞\n\
            - 战斗时不能退出。\n\
    - snapshot 6, 2026-07-14\n\
        - 加入了战斗模式暂停的功能,按空格键可以暂停。\n\
        - 删除了战斗模式暂停的功能,开发者认为这没有什么意义。\n\
        - 现在战斗记录的存储方式使用了更加先进的存储技术,用人话说就是滚动数组。\n\
        - 新增了武器的破防属性,用来削减敌人的防御值。特别地,此值可为负。\n\
        - 修复了若干个漏洞\n\
            - 回合数超过 1000 的战斗会崩溃。\n\
            - 按 Q 退出战斗后 Q 会被再次读入。\n\
    - snapshot 7, 2026-07-16\n\
        - 加入了武器的攻击速度,正负均可\n\
        - 正在设计新的存档格式,将武器、生物等数据进行软编码,预计下个快照实现,并增加一些基础的生物和武器。\n\
    - snapshot 8, 2026-07-17\n\
        - 加入了数据格式,目前只有 .WEAPON 和 .MOB 两种,具体可见源代码底部。\n\
        - 添加了怪物以及武器的名称。在战斗中会显示怪物的名称而非之前的\"ENEMY\"。\n\
        - 更改了一个漏洞的状态\n\
            - 当怪物血量超过约 9e16 时,剩余血量百分比计算错误。漏洞状态为:不予修复。原因:就目前来看,这么高的怪物血量是不切实际的。\n\
        - 再次隆重声明:该游戏名称“给木”是作者的倾情创作,严禁丑化、扭曲本游戏名称(如称之为“旮旯给木”等)。\n\
        - 重新上传,以修复严重漏洞:加载数据后标准输入流无法读取控制台的内容。\n\
    - snapshot 9, 2026-07-18\n\
        - 完善了了背包的功能,可以显示玩家的武器列表和目前装备的列表,并且可以更改,同时可以查看武器的属性。\n\
        - 后续会进行背包的优化,并且会增加背包列表的排序功能。\n\
    - snapshot 10, 2026-07-20\n\
        - 更新了新的装备种类:护甲。\n\
        - 更新了装备的属性:防御值。可以增加玩家的防御值。玩家自身的生命和防御值系统将在下个快照更新。\n\
        - 增加了背包的排序功能。\n\
        - 现在开发者会在博客园的随笔中事实更新最新版本,之前版本的存档也会在那里。\n\
"};

typedef long long ll;
const int N = 10010;
const int NONE = N - 9;
int WEAPON_COUNT, MOB_COUNT, ARMOR_COUNT;
int MAX_LINE = 11;

struct MOB {
    char name[25];
    ll heal; // health
    ll def; // defense
    ll anti_def; // anti_defense to player
} mobs[N];

struct EQUIP {
    char name[25];
    int lv;
    ll att;
    ll anti_def;
    ll def;
    int speed;
} equips[5][N];

struct CHOOSEEQUIP {
    int id;
    int kind;
    bool operator< (CHOOSEEQUIP &a) {
        if (id != a.id) return id < a.id;
        return kind < a.kind;
    } bool operator== (CHOOSEEQUIP &a) {
        return id == a.id && kind == a.kind;
    }
};

struct PLAYER {
    ll att = 100; // attack
    ll money;
    CHOOSEEQUIP gear[5];
    int speed = 100; // attack speed
    int bag_sz, bag_len[5] = {0};
    CHOOSEEQUIP bag[5][1010];
} player;

bool wait_in_fight (int wait_time) {
    const int INTERVAL = 10;
    for (int slept = 0; slept < wait_time; slept += INTERVAL) {
        Sleep(min(INTERVAL, wait_time - slept));
        if (Key_down('Q')) {
            return false;
        }
    }
    return true;
}

bool fight (int mob) {
    ll heal = mobs[mob].heal;
    ll now_heal = heal;
    int round_cnt = 0;
    char output_data[1010][110];
    int real_speed = player.speed + equips[1][player.gear[1].id].speed;
    real_speed = max (min (10000, real_speed), 10);

    cls();
    sprintf(output_data[0], "--- %s %5lld/%-5lld %3d%%---", mobs[mob].name, now_heal, heal, 1ll * now_heal * 100 / heal);
    printf("%s\n", output_data[0]);
    while (now_heal > 0) {
        round_cnt ++;

        int wait_time = 100000 / real_speed; // 等待时间
        ll true_def = max (mobs[mob].def - equips[1][player.gear[1].id].anti_def, 0ll); // 去除破防后的防御值
        ll real_att = player.att + equips[1][player.gear[1].id].att - true_def; // 真实伤害
        ll caused = min (max (real_att, 0ll), now_heal); // 真实造成的真实伤害
        now_heal -= caused; // 剩余血量

        if (! wait_in_fight(wait_time)) return false;
        sprintf(output_data[0], "--- %s %5lld/%-5lld %3d%%---", mobs[mob].name, now_heal, heal, 1ll * now_heal * 100 / heal);
        sprintf(output_data[(round_cnt - 1) % 1000 + 1], "%2d: You dealt %lld damage to %s. ", round_cnt, caused, mobs[mob].name);

        go_to (0, 0);
        printf("%s\n", output_data[0]);
        int line_cnt = MAX_LINE - 1;
        int start;
        if (line_cnt >= round_cnt) start = 1;
        else start = round_cnt - line_cnt + 1;
        for (int i = start; i <= round_cnt; i ++) {
            printf("%s\n", output_data[(i - 1) % 1000 + 1]);
        }
    }
    sprintf(output_data[0], "You won the enemy. Press any key to continue.");
    go_to (0, 0);
    printf("%s\n", output_data[0]);
    int line_cnt = MAX_LINE - 1;
    int start;
    if (line_cnt >= round_cnt) start = 1;
    else start = round_cnt - line_cnt + 1;
    for (int i = start; i <= round_cnt; i ++) {
        printf("%s\n", output_data[i]);
    }

    clear_stdin();
    press_any_key_to_continue();
    return true;
}

bool fight_in_sandbox (EQUIP equip) {
    int mob = 0;
    ll heal = mobs[mob].heal;
    ll now_heal = heal;
    int round_cnt = 0;
    char output_data[1010][110];
    int real_speed = player.speed + equip.speed;
    real_speed = max (min (10000, real_speed), 10);

    cls();
    sprintf(output_data[0], "--- %s %5lld/%-5lld %3d%%---", mobs[mob].name, now_heal, heal, 1ll * now_heal * 100 / heal);
    printf("%s\n", output_data[0]);
    while (now_heal > 0) {
        round_cnt ++;

        int wait_time = 100000 / real_speed; // 等待时间
        ll true_def = max (mobs[mob].def - equip.anti_def, 0ll); // 去除破防后的防御值
        ll real_att = player.att + equip.att - true_def; // 真实伤害
        ll caused = min (max (real_att, 0ll), now_heal); // 真实造成的真实伤害
        now_heal -= caused; // 剩余血量

        if (! wait_in_fight(wait_time)) return false;
        sprintf(output_data[0], "--- %s %5lld/%-5lld %3d%%---", mobs[mob].name, now_heal, heal, 1ll * now_heal * 100 / heal);
        sprintf(output_data[(round_cnt - 1) % 1000 + 1], "%2d: You dealt %lld damage to %s. ", round_cnt, caused, mobs[mob].name);

        go_to (0, 0);
        printf("%s\n", output_data[0]);
        int line_cnt = MAX_LINE - 1;
        int start;
        if (line_cnt >= round_cnt) start = 1;
        else start = round_cnt - line_cnt + 1;
        for (int i = start; i <= round_cnt; i ++) {
            printf("%s\n", output_data[(i - 1) % 1000 + 1]);
        }
    }
    sprintf(output_data[0], "You won the enemy. Press any key to continue.");
    go_to (0, 0);
    printf("%s\n", output_data[0]);
    int line_cnt = MAX_LINE - 1;
    int start;
    if (line_cnt >= round_cnt) start = 1;
    else start = round_cnt - line_cnt + 1;
    for (int i = start; i <= round_cnt; i ++) {
        printf("%s\n", output_data[i]);
    }

    clear_stdin();
    press_any_key_to_continue();
    return true;
}

/*
/----gear----\ /-----bag------\ /---preview----\
|> WEAPON:   | |- WEAPON:     | |NAMEEEEEEEEEEE|
|AAAAAAAAAA  | |> AABBCCDDEEFF| |  MODEEEEEEEEE|
|> unequip   | |  AABBCCDDEEFF| |  MODEEEEEEEEE|
|            | |              | |  MODEEEEEEEEE|
|            | |              | |
|            | |              |
\            / |              |
               |              |
               \--------------/
*/

void show_preview_in_bag (char output_prev[30][30], int &len_prev, CHOOSEEQUIP chs_eq, bool focus) {
    int chs_wp_id = chs_eq.id;
    int kd = chs_eq.kind;
    len_prev = 0;
    char tmp[30];
    if (focus) sprintf (output_prev[0], "/---preview----\\");
    else       sprintf (output_prev[0], "/   preview    \\");
    strcpy (tmp, equips[kd][chs_wp_id].name);
    align_str (tmp, 14);
    sprintf (output_prev[++ len_prev], "|%s|", tmp);
    if (kd == 1)      sprintf(output_prev[++ len_prev], "|kind: WEAPON  |");
    else if (kd == 2) sprintf(output_prev[++ len_prev], "|kind: ARMOR   |");
    sprintf(output_prev[++ len_prev], "|lvl.%-2d        |", equips[kd][chs_wp_id].lv);
    if (equips[kd][chs_wp_id].att != 0){
        sprintf (tmp, "%lld", equips[kd][chs_wp_id].att);
        align_str (tmp, 9);
        sprintf(output_prev[++ len_prev], "|att: %s|", tmp);
    } if (equips[kd][chs_wp_id].anti_def != 0){
        sprintf (tmp, "%lld", equips[kd][chs_wp_id].anti_def);
        align_str (tmp, 7);
        sprintf(output_prev[++ len_prev], "|undef: %s|", tmp);
    } if (equips[kd][chs_wp_id].speed != 0){
        sprintf (tmp, "%.2lf", equips[kd][chs_wp_id].speed / 100.0);
        align_str (tmp, 7);
        sprintf(output_prev[++ len_prev], "|speed: %s|", tmp);
    } if (equips[kd][chs_wp_id].def != 0){
        sprintf (tmp, "%lld", equips[kd][chs_wp_id].def);
        align_str (tmp, 9);
        sprintf(output_prev[++ len_prev], "|def: %s|", tmp);
    }
    if (focus) sprintf (output_prev[++ len_prev], "\\--------------/");
    else       sprintf (output_prev[++ len_prev], "\\              /");
    len_prev --;
}

void show_gear_in_bag (char output_gear[30][30], int chs_gear, bool focus) {
    char tmp[30];
    strcpy (tmp, equips[1][player.gear[1].id].name);
    align_str (tmp, 12);
    if (focus) sprintf (output_gear[0], "/----gear----\\");
    else       sprintf (output_gear[0], "/    gear    \\");
    sprintf (output_gear[1], "|%c weapon:   |", chs_gear == 1? '>' : ' ');
    sprintf (output_gear[2], "|%s|", tmp);
    sprintf (output_gear[3], "|%c unequip   |", chs_gear == 3? '>' : ' ');
    strcpy (tmp, equips[2][player.gear[2].id].name);
    align_str (tmp, 12);
    sprintf (output_gear[4], "|%c armor:    |", chs_gear == 4? '>' : ' ');
    sprintf (output_gear[5], "|%s|", tmp);
    sprintf (output_gear[6], "|%c unequip   |", chs_gear == 6? '>' : ' ');
    if (focus) sprintf (output_gear[7], "\\------------/");
    else       sprintf (output_gear[7], "\\            /");
}

void show_bag_in_bag (char output_bag[30][30], char output_bag_data[1010][30], pair<int, int> *match_bag, bool *valid_bag, int chs_bag, int len_bag, int &len_bag_data, bool focus) {
    char tmp[30];
    len_bag_data = 0;
    if (focus) sprintf (output_bag[0],       "/-----bag------\\");
    else       sprintf (output_bag[0],       "/     bag      \\");
    if (focus) sprintf (output_bag[len_bag + 1], "\\---[R] sort---/");
    else       sprintf (output_bag[len_bag + 1], "\\              /");
    sprintf (output_bag_data[++ len_bag_data],  "|- WEAPON:     |");
    match_bag[len_bag_data] = {0, NONE};
    for (int i = 1; i <= player.bag_len[1]; i ++) {
        len_bag_data ++;
        strcpy (tmp, equips[1][player.bag[1][i].id].name);
        align_str (tmp, 12);
        sprintf(output_bag_data[len_bag_data], "|%c %s|", chs_bag == len_bag_data ? '>' : ' ', tmp);
        valid_bag[len_bag_data] = 1;
        match_bag[len_bag_data] = {1, i};
    }
    sprintf (output_bag_data[++ len_bag_data],  "|- ARMOR:      |");
    match_bag[len_bag_data] = {0, NONE};
    for (int i = 1; i <= player.bag_len[2]; i ++) {
        len_bag_data ++;
        strcpy (tmp, equips[2][player.bag[2][i].id].name);
        align_str (tmp, 12);
        sprintf(output_bag_data[len_bag_data], "|%c %s|", chs_bag == len_bag_data ? '>' : ' ', tmp);
        valid_bag[len_bag_data] = 1;
        match_bag[len_bag_data] = {2, i};
    }
    
    int start = chs_bag - len_bag / 2, end = chs_bag + len_bag / 2;
    if (start < 1) start = 1, end = start + len_bag - 1;
    if (end > len_bag_data) end = len_bag_data, start = end - len_bag + 1;
    for (int i = start, j = 1; i <= end; i ++, j ++) {
        strcpy (output_bag[j], output_bag_data[i]);
    }
}

void print_in_bag (char output[30][30], int len, int start) {
    for (int i = 0; i <= len + 1; i ++) {
        go_to (i, start);
        printf("%s", output[i]);
    } 
}

void check_bag () { // 抱歉我已经尽可能的让代码不那么屎山了。
    cls();
    char output_gear[30][30];
    int chs_gear = 1;
    int len_gear = 6;
    int start_gear = 0;
    bool valid_gear[30] = {0, 1, 0, 1, 1, 0, 1};
    char output_bag_data[1010][30];
    char output_bag[30][30];
    pair <int, int> match_bag[1010];
    bool valid_bag[1010] = {0, 0, 1};
    int chs_bag = 2;
    int len_bag = MAX_LINE - 2;
    int len_bag_data;
    int start_bag = 15;
    char output_prev[30][30];
    int len_prev = 1;
    int start_prev = 32;
    int chs = 2;
    char tmp[30];

    show_gear_in_bag (output_gear, chs_gear, chs == 1);
    show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
    show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);

    print_in_bag (output_gear, len_gear, start_gear);
    print_in_bag (output_bag, len_bag, start_bag);
    print_in_bag (output_prev, len_prev, start_prev);

    while (1) {
        char c = _getch();
        if (c == 'a' || c == 'A') {
            if (chs == 2) {
                chs = 1;
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_preview_in_bag (output_prev, len_prev, player.gear[(chs_gear - 1) / 3 + 1], chs == 3);
            } else if (chs == 1) {
                chs = 3;
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_preview_in_bag (output_prev, len_prev, player.gear[(chs_gear - 1) / 3 + 1], chs == 3);
            } else if (chs == 3) {
                chs = 2;
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == 'd' || c == 'D') {
            if (chs == 2) {
                chs = 3;
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            } else if (chs == 1) {
                chs = 2;
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            } else if (chs == 3) {
                chs = 1;
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_preview_in_bag (output_prev, len_prev, player.gear[(chs_gear - 1) / 3 + 1], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == 'w' || c == 'W') {
            if (chs == 1) {
                do {
                    chs_gear --;
                    chs_gear = (chs_gear - 1 + len_gear) % len_gear + 1;
                } while (! valid_gear[chs_gear]) ;
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_preview_in_bag (output_prev, len_prev, player.gear[(chs_gear - 1) / 3 + 1], chs == 3);
            } else if (chs == 2) {
                do {
                    chs_bag --;
                    chs_bag = (chs_bag - 1 + len_bag_data) % (len_bag_data) + 1;
                } while (! valid_bag[chs_bag]) ;
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == 's' || c == 'S') {
            if (chs == 1) {
                do {
                    chs_gear ++;
                    chs_gear = (chs_gear - 1) % len_gear + 1;
                } while (! valid_gear[chs_gear]) ;
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_preview_in_bag (output_prev, len_prev, player.gear[(chs_gear - 1) / 3 + 1], chs == 3);
            } else if (chs == 2) {
                do {
                    chs_bag ++;
                    chs_bag = (chs_bag - 1) % (len_bag_data) + 1;
                } while (! valid_bag[chs_bag]) ;
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                if (chs_gear == 3 && player.gear[1].id != NONE) {
                    player.bag[1][++ player.bag_len[1]].id = NONE;
                    swap (player.gear[1], player.bag[1][player.bag_len[1]]);
                } if (chs_gear == 6 && player.gear[2].id != NONE) {
                    player.bag[2][++ player.bag_len[2]].id = NONE;
                    swap (player.gear[2], player.bag[2][player.bag_len[2]]);
                }
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.gear[(chs_gear - 1) / 3 + 1], chs == 3);
            } else if (chs == 2) {
                swap (player.gear[match_bag[chs_bag].fi], player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se]);
                if (player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se].id == NONE) {
                    for (int i = match_bag[chs_bag].se + 1; i <= player.bag_len[match_bag[chs_bag].fi]; i ++) {
                        swap (player.bag[match_bag[chs_bag].fi][i - 1],player.bag[match_bag[chs_bag].fi][i]);
                    } player.bag_len[match_bag[chs_bag].fi] --;
                } if (chs_bag > len_bag_data || ! valid_bag[chs_bag]) {
                    do {
                        chs_bag --;
                        chs_bag = (chs_bag + len_bag_data - 1) % (len_bag_data) + 1;
                    } while (! valid_bag[chs_bag]) ;
                }
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == 'r' || c == 'R') {
            if (chs == 2) {
                CHOOSEEQUIP now_eq = player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se];
                sort (player.bag[1] + 1, player.bag[1] + 1 + player.bag_len[1]);
                sort (player.bag[2] + 1, player.bag[2] + 1 + player.bag_len[2]);
                for (int i = 1; i <= player.bag_len[1]; i ++)
                    if (player.bag[1][i] == now_eq) {
                        chs_bag = i + 1;
                        break;
                    }
                for (int i = 1; i <= player.bag_len[2]; i ++)
                    if (player.bag[2][i] == now_eq) {
                        chs_bag = i + 2 + player.bag_len[1];
                        break;
                    }
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        }

        else if (c == 'q' || c == 'Q') {
            return ;
        }
    }
}

void change_log () {
    cls();
    printf("%s", change_logs);
    press_any_key_to_continue();
}

void sandbox () {
    EQUIP sandbox_equip;
    strcpy (sandbox_equip.name, "default");
    char output_data[30][110];
    int chs = 1;
    int len = 9;

    sprintf(output_data[0], "--- geimu sandbox --- (press [Enter] to change)");
    sprintf(output_data[1], "%c enemy health: %lld", chs == 1 ? '>' : ' ', mobs[0].heal);
    sprintf(output_data[2], "%c enemy defense: %lld", chs == 2 ? '>' : ' ', mobs[0].def);
    sprintf(output_data[3], "%c player attack: %lld", chs == 3 ? '>' : ' ', player.att);
    sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
    sprintf(output_data[5], "%c equip attack: %lld", chs == 5 ? '>' : ' ', sandbox_equip.att);
    sprintf(output_data[6], "%c equip anti_defense: %lld", chs == 6 ? '>' : ' ', sandbox_equip.anti_def);
    sprintf(output_data[7], "%c equip attack speed: %.2lfps", chs == 7 ? '>' : ' ', sandbox_equip.speed / 100.0);
    sprintf(output_data[8], "%c equip defense: %lld", chs == 8 ? '>' : ' ', sandbox_equip.def);
    sprintf(output_data[9], "%c i'm ready.", chs == 9 ? '>' : ' ');
    cls ();
    for (int i = 0; i <= len; i ++) {
        printf("%s\n", output_data[i]);
    } while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                go_to (len + 2, 0);
                printf("input enemy health: ");
                ShowCursor();
                scanf("%lld", &mobs[0].heal);
                mobs[0].heal = max (mobs[0].heal, 0ll);
                sprintf(output_data[1], "%c enemy health: %lld", chs == 1 ? '>' : ' ', mobs[0].heal);
            } else if (chs == 2) {
                go_to (len + 2, 0);
                printf("input enemy defense: ");
                ShowCursor();
                scanf("%lld", &mobs[0].def);
                mobs[0].def = max (mobs[0].def, 0ll);
                sprintf(output_data[2], "%c enemy defense: %lld", chs == 2 ? '>' : ' ', mobs[0].def);
            } else if (chs == 3) {
                go_to (len + 2, 0);
                printf("input player attack: ");
                ShowCursor();
                scanf("%lld", &player.att);
                player.att = max (player.att, 0ll);
                sprintf(output_data[3], "%c player attack: %lld", chs == 3 ? '>' : ' ', player.att);
            } else if (chs == 4) {
                double tmp;
                go_to (len + 2, 0);
                printf("input player attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                player.speed = max (min (tmp, 100.0), 0.1) * 100;
                sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
            } else if (chs == 5) {
                go_to (len + 2, 0);
                printf("input equip attack: ");
                ShowCursor();
                scanf("%lld", &sandbox_equip.att);
                sandbox_equip.att = max(sandbox_equip.att, 0ll);
                sprintf(output_data[5], "%c equip attack: %lld", chs == 5 ? '>' : ' ', sandbox_equip.att);
            } else if (chs == 6) {
                go_to (len + 2, 0);
                printf("input equip anti_defense: ");
                ShowCursor();
                scanf("%lld", &sandbox_equip.anti_def);
                sprintf(output_data[6], "%c equip anti_defense: %lld", chs == 6 ? '>' : ' ', sandbox_equip.anti_def);
            } else if (chs == 7) {
                double tmp;
                go_to (len + 2, 0);
                printf("input equip attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                sandbox_equip.speed = max (min (tmp, 100.0), -100.0) * 100;
                sprintf(output_data[7], "%c equip attack speed: %.2lfps", chs == 7 ? '>' : ' ', sandbox_equip.speed / 100.0);
            } else if (chs == 8) {
                go_to (len + 2, 0);
                printf("input equip defense: ");
                ShowCursor();
                scanf("%lld", &sandbox_equip.def);
                sprintf(output_data[8], "%c equip defense: %lld", chs == 6 ? '>' : ' ', sandbox_equip.def);
            }else if (chs == 9) {
                fight_in_sandbox(sandbox_equip);
                clear_stdin();
            } cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin(); HideCursor();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
    }
}

void home_page () {
    char output_data[30][110];
    int chs = 1;
    int len = 3;

    sprintf (output_data[0], "--- Home Page --- money: %lld", player.money);
    sprintf (output_data[1], "%c Check bag", chs == 1 ? '>' : ' ');
    sprintf (output_data[2], "%c Create a sandbox", chs == 2 ? '>' : ' ');
    sprintf (output_data[3], "%c Change log", chs == 3 ? '>' : ' ');
    cls ();
    printf("%s\n", output_data[0]);
    Sleep (500);
    for (int i = 1; i <= len; i ++) printf("%s\n", output_data[i]);
    clear_stdin();
    while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            cls();
            if (chs == 1) {
                check_bag ();
            } else if (chs == 2) {
                sandbox();
            } else {
                change_log ();
            }
            cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
        // Sleep (100);
    }
}

void init () {
    player.money = 100;
    player.att = 0;
    player.speed = 100;
    WEAPON_COUNT = 0;
    strcpy (equips[1][0].name, "default");
    equips[1][0].att = 10;
    equips[1][0].anti_def = 0;
    MOB_COUNT = 0;
    strcpy (mobs[0].name, "default");
    mobs[0].heal = 1000;
    mobs[0].def = 0;
    equips[1][NONE].att = equips[1][NONE].anti_def = equips[1][NONE].lv = equips[1][NONE].speed = 0; strcpy(equips[1][NONE].name, "未装备");
    equips[2][NONE].att = equips[2][NONE].anti_def = equips[2][NONE].lv = equips[2][NONE].speed = 0; strcpy(equips[2][NONE].name, "未装备");
    player.bag_len[1] = 12;
    player.bag_len[2] = 12;
    player.gear[1].kind = 1;
    player.gear[1].id = NONE;
    player.gear[2].kind = 2;
    player.gear[2].id = NONE;
    for (int i = 1; i <= 12; i ++) {
        player.bag[1][i].id = (i - 1) % 4 + 1;
        player.bag[1][i].kind = 1;
    } for (int i = 1; i <= 12; i ++) {
        player.bag[2][i].id = (i - 1) % 2 + 1;
        player.bag[2][i].kind = 2;
    }
}

void load_game () {
    char output_data[20][210];
    char weapon_path[110] = "WEAPON.equip";
    char armor_path[110] = "ARMOR.equip";
    char mob_path[110] = "MOB.mob";
    int len = 4;
    int chs = len;

    sprintf (output_data[0], "请先选择读入数据的文件名。若因读入文件填写错误而对设备造成损伤,本游戏不承担责任。若你没有游戏数据,请在源代码最底部按注释提示创建。");
    sprintf (output_data[1], "%c 武器列表:%s", chs == 1 ? '>' : ' ', weapon_path);
    sprintf (output_data[2], "%c 护甲列表:%s", chs == 2 ? '>' : ' ', weapon_path);
    sprintf (output_data[3], "%c 生物列表:%s", chs == 3 ? '>' : ' ', mob_path);
    sprintf (output_data[4], "%c 开始游戏!", chs == 4 ? '>' : ' ');
    
    cls ();
    for (int i = 0; i <= len; i ++) {
        printf("%s\n", output_data[i]);
    } while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                ShowCursor();
                go_to (len + 2, 0);
                printf("输入新的武器数据地址:");
                scanf("%s", weapon_path);
                sprintf (output_data[1], "%c 武器列表:%s", chs == 1 ? '>' : ' ', weapon_path);
            } if (chs == 2) {
                ShowCursor();
                go_to (len + 2, 0);
                printf("输入新的护甲数据地址:");
                scanf("%s", armor_path);
                sprintf (output_data[2], "%c 护甲列表:%s", chs == 2 ? '>' : ' ', armor_path);
            } else if (chs == 3) {
                ShowCursor();
                go_to (len + 2, 0);
                printf("输入新的生物数据地址:");
                scanf("%s", mob_path);
                sprintf (output_data[3], "%c 生物列表:%s", chs == 3 ? '>' : ' ', mob_path);
            } else if (chs == 4) {
                break;
            } cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin(); HideCursor();
        } else if (c == 'q' || c == 'Q') {
            exit(0);
        }
    }
    freopen (weapon_path, "r", stdin);
    while (1) {
        char c[25];
        int lv, att, undef, spd, def;
        scanf("%s", c);
        if (c[0] == '_' && c[1] == '_' && c[2] == 'E' && c[3] == 'N' && c[4] == 'D' && c[5] == '_' && c[6] == '_') {
            break;
        } scanf("%d%d%d%d%d", &lv, &att, &undef, &spd, &def);
        WEAPON_COUNT ++; 
        strcpy(equips[1][WEAPON_COUNT].name, c);
        equips[1][WEAPON_COUNT].lv = lv;
        equips[1][WEAPON_COUNT].att = att;
        equips[1][WEAPON_COUNT].anti_def = undef;
        equips[1][WEAPON_COUNT].speed = spd;
        equips[1][WEAPON_COUNT].def = def;
    } 
    fclose (stdin);
    freopen (armor_path, "r", stdin);
    while (1) {
        char c[25];
        int lv, att, undef, spd, def;
        scanf("%s", c);
        if (c[0] == '_' && c[1] == '_' && c[2] == 'E' && c[3] == 'N' && c[4] == 'D' && c[5] == '_' && c[6] == '_') {
            break;
        } scanf("%d%d%d%d%d", &lv, &att, &undef, &spd, &def);
        ARMOR_COUNT ++; 
        strcpy(equips[2][ARMOR_COUNT].name, c);
        equips[2][ARMOR_COUNT].lv = lv;
        equips[2][ARMOR_COUNT].att = att;
        equips[2][ARMOR_COUNT].anti_def = undef;
        equips[2][ARMOR_COUNT].speed = spd;
        equips[2][ARMOR_COUNT].def = def;
    } 
    fclose (stdin);
    freopen (mob_path, "r", stdin);
    while (1) {
        char c[25];
        int heal, def;
        scanf("%s", c);
        if (c[0] == '_' && c[1] == '_' && c[2] == 'E' && c[3] == 'N' && c[4] == 'D' && c[5] == '_' && c[6] == '_') {
            break;
        } scanf("%d%d", &heal, &def);
        MOB_COUNT ++; 
        strcpy(mobs[MOB_COUNT].name, c);
        mobs[MOB_COUNT].heal = heal;
        mobs[MOB_COUNT].def = def;
    } 
    fclose (stdin);
    freopen("CON", "r", stdin);
}

int main () {
    HideCursor();

    cls();
    printf("在游玩/调试前请先更换编码方式:点击右下角\"UTF-8\",选择\"reopen with encoding\",点击\"Simplified Chinese (GBK) gbk\"。若程序内中文还是无法正常显示,按Ctrl+Z。\n\
Before playing/debugging, please change the encoding method: click 'UTF-8' in the bottom right corner, select 'Reopen with encoding', and click 'Simplified Chinese (GBK) gbk'. If the Chinese text still does not display properly within the program (that are showing like '锟斤拷', press Ctrl+Z.\n\
Press any key to continue...\n");
    press_any_key_to_continue();

    init();
    load_game ();

    home_page ();
    return 0;
}

/*
创建游戏数据:

目前游戏有三个数据库,默认分别是 WEAPON.equip,ARMOR.equip 和 MOB.mob。下面是数据的官方内容。您可以在对应数据文件中修改数据来制作二创数据包。请认准官方默认数据包。

将下面内容粘贴到 WEAPON.equip 中:

小刀 1
12 0 5 0
刺刀 1
10 4 0 0
沉重的铁斧 1
15 10 -20 0
巨人的棒槌 1
25 -10 -10 0
__END__

将下面内容粘贴到 ARMOR.equip 中:

沉重的铠甲
0 0 -10 2
__END__

将下面内容粘贴到 MOB.mob 中:

正方形
100 0
__END__

二创指引:WEAPON.weapon 的文件格式形如:
武器名称(请不要使用以__END__为开头的武器名称!) 等级
攻击 破防 攻击速度x100(为了避免精度误差)
文件末尾用__END__标识
*/

26.1 snapshot 11

  • 加入了玩家的名字、血量、防御、生物的破防、攻击、攻击速度属性。更新了战斗系统,现在生物也会攻击玩家了。
  • 但是沙盒模式并没有同步更新。玩家可以通过修改源代码来测试新版本更新内容。
/*
当前版本:26.1 snapshot 11

2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。  
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。  
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。

通知:后续更新日志在程序里,运行即可看到。请及时在游戏中找到更新日志以查看最新版本的更新内容。下方变成了评论区。可以评论。记得署名

- 26.1
    - snapshot 1, 2026-07-12
		评价:有剧情吗就开服——Derekyang
    - snapshot 2, 2026-07-12
		评价:把主体做出来好吗,不要只放一个战斗模块——Derekyang
    - snapshot 3, 2026-07-13
*/
#include<cstdio>
#include<random>
#include<ctime>
#include<queue>
#include<cmath>
#include<algorithm>
#include<windows.h>
#include<conio.h>
using namespace std;
#define Rnd(a,b) rnd()%(b-a+1)+a
#define color(a) SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),a) 
#define Key_down(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
#define fi first
#define se second
std::mt19937 rnd(time(NULL));
void cls(){
    if (Rnd (0, 9)) { // 降低闪屏频率
        HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
        if (hStdOut == INVALID_HANDLE_VALUE)
            return;
        CONSOLE_SCREEN_BUFFER_INFO csbi;
        if (!GetConsoleScreenBufferInfo(hStdOut, &csbi))
            return;
        DWORD count;
        DWORD cellCount = csbi.dwSize.X * csbi.dwSize.Y;
        COORD homeCoords = {0, 0};
        FillConsoleOutputCharacter(hStdOut, ' ', cellCount, homeCoords, &count);
        FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, cellCount, homeCoords, &count);
        SetConsoleCursorPosition(hStdOut, homeCoords);
    } else
        system("cls");
}
void press_any_key_to_continue () {
	// while (_kbhit ()) {
	// 	getch();
	// } rewind (stdin);
	// while (1) if (kbhit ()) break;
	// return ;
    char c = _getch();
    return ;
} void clear_stdin(void) {
    while (_kbhit ()) {
		getch();
	} rewind (stdin);

    // int c;
    // while ((c = getchar()) != '\n' && c != EOF) {
    // }
}
void HideCursor(){
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void ShowCursor(){
	CONSOLE_CURSOR_INFO cur={1,1};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}
void go_to (int x, int y){
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD coordScreen = {(short)y, (short)x};
    SetConsoleCursorPosition(hConsole, coordScreen);
}
int GetDisplayWidth(const char* str) {
    int width = 0;
    int len = strlen(str);
    
    for (int i = 0; i < len; i++) {
        unsigned char c = (unsigned char)str[i];
        if (c >= 0x81 && c <= 0xFE) {
            if (i + 1 < len) {
                unsigned char c2 = (unsigned char)str[i + 1];
                if ((c2 >= 0x40 && c2 <= 0x7E) || (c2 >= 0x80 && c2 <= 0xFE)) {
                    width += 2;
                    i++;
                    continue;
                }
            }
        }
        width += 1;
    }
    
    return width;
}
struct ConsoleSize {
    int Width;   // 可见列数
    int Height;  // 可见行数
    int BufferWidth;   // 缓冲区总列数
    int BufferHeight;  // 缓冲区总行数
};
ConsoleSize GetAdvancedConsoleSize() {
    HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    ConsoleSize size = {80, 25, 80, 300}; // 默认
    
    if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
        // 可见窗口区域(用户当前看到的)
        size.Width = csbi.srWindow.Right - csbi.srWindow.Left + 1;
        size.Height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
        // 缓冲区大小(实际可绘制的范围)
        size.BufferWidth = csbi.dwSize.X;
        size.BufferHeight = csbi.dwSize.Y;
    }
    return size;
}
// 计算字符串在控制台中的显示宽度(ASCII:1,GBK中文/全角:2)
int get_width(const char* str) {
    if (!str) return 0;
    int width = 0;
    while (*str) {
        unsigned char ch = static_cast<unsigned char>(*str);
        if (ch >= 0x81 && ch <= 0xFE &&
            *(str + 1) != '\0' &&
            (static_cast<unsigned char>(*(str + 1)) >= 0x40 &&
             static_cast<unsigned char>(*(str + 1)) <= 0xFE &&
             static_cast<unsigned char>(*(str + 1)) != 0x7F)) {
            width += 2;
            str += 2;
        } else {
            width += 1;
            str++;
        }
    }
    return width;
}
// 对齐字符串至指定显示宽度,返回状态码:
//  0 : 无需修改(宽度已相等)
//  1 : 补空格(原宽度 < width)
// -1 : 截断并用点填充(原宽度 > width)
int align_str(char* str, int width) {
    if (!str) return 0;
    if (width < 0) width = 0;
    int total = get_width(str);
    // 情况1:宽度相等,不做改动
    if (total == width) {
        return 0;
    }
    // 情况2:宽度足够,用空格补齐至 width 列
    if (total < width) {
        int len = strlen(str);
        int spaces = width - total;
        for (int i = 0; i < spaces; ++i) {
            str[len + i] = ' ';
        }
        str[len + spaces] = '\0';
        return 1;   // 填充空格
    }
    // 情况3:宽度不足,截断并用点填充至 width 列
    int target = width - 2;          // 至少保留2列给点(但实际可能更多)
    if (target < 0) target = 0;
    const char* p = str;
    char* write_pos = str;
    int cur_width = 0;
    // 复制尽可能多的完整字符(不拆分双字节字符)
    while (*p && cur_width < target) {
        unsigned char ch = static_cast<unsigned char>(*p);
        int char_width = 1;
        if (ch >= 0x81 && ch <= 0xFE &&
            *(p + 1) != '\0' &&
            (static_cast<unsigned char>(*(p + 1)) >= 0x40 &&
             static_cast<unsigned char>(*(p + 1)) <= 0xFE &&
             static_cast<unsigned char>(*(p + 1)) != 0x7F)) {
            char_width = 2;
        }
        if (cur_width + char_width > target) {
            break;  // 该字符放不下,停止
        }
        cur_width += char_width;
        if (char_width == 2) {
            *write_pos++ = *p++;
            *write_pos++ = *p++;
        } else {
            *write_pos++ = *p++;
        }
    }
    // 剩余宽度全部用点填充
    int dots = width - cur_width;     // 需要填充的点数
    for (int i = 0; i < dots; ++i) {
        *write_pos++ = '.';
    }
    *write_pos = '\0';
    return -1;   // 截断并填充点
}

char change_logs[100000] = {"\
当前版本:26.1 snapshot 11\n\
2026-07-12 《给木》测试版正式开服!(虽然没有服)《给木》是一款最新的给木。他会不定期更新,最新版本会随时保存在note.ms/jessygeimu里。\n\
内测版提示:函数test_mode()里可以更改游戏数据,让游戏变得好玩一点。\n\
往期geimu会存放到note.ms/jessygeimuXYZ中,X表示年份,Y表示版本号,Z表示快照号,都是两位数,如note.ms/jessygeimu260101。请勿更改里面的内容。\n\
\n\
开发者:jessy\n\
特邀嘉宾:DEREKYANG\n\
\n\
- 26.1 Sandbox Update\n\
    - snapshot 1, 2026-07-12\n\
        - 正式开服,现在十分简陋,但是能看。有了与怪物战斗能力,但是目前只有攻击力和攻击速度两个属性。\n\
    - snapshot 2, 2026-07-12\n\
        - 现在增加了滚动系统,控制台最多显示十行。\n\
        - ~~为了展示滚动算法的先进性~~输出信息会额外输出回合数。\n\
        - 修复了一个漏洞\n\
            - 当输出行数超过控制台行数时,输出内容会错误地覆盖之前的信息。\n\
    - snapshot 3, 2026-07-13\n\
        - 新增了主页。\n\
        - 新增了沙盒模式,玩家可以随意调控目前的战斗参数,而不是调源代码。\n\
        - 新增了更新日志。以后更新日志都会放到那里。\n\
        - 新增了查看背包功能。自己点进去看看吧。我啷个晓得嘛\n\
    - snapshot 4, 2026-07-13\n\
        - 紧急更新:修复了一个漏洞\n\
            - 当敌人生命超过int存储上限的1%时,游戏计算出错。\n\
    - snapshot 5, 2026-07-14\n\
        - 加入了怪物的防御,类似于护甲,真实伤害还会减去防御值。\n\
        - 修复了一个漏洞\n\
            - 战斗时不能退出。\n\
    - snapshot 6, 2026-07-14\n\
        - 加入了战斗模式暂停的功能,按空格键可以暂停。\n\
        - 删除了战斗模式暂停的功能,开发者认为这没有什么意义。\n\
        - 现在战斗记录的存储方式使用了更加先进的存储技术,用人话说就是滚动数组。\n\
        - 新增了武器的破防属性,用来削减敌人的防御值。特别地,此值可为负。\n\
        - 修复了若干个漏洞\n\
            - 回合数超过 1000 的战斗会崩溃。\n\
            - 按 Q 退出战斗后 Q 会被再次读入。\n\
    - snapshot 7, 2026-07-16\n\
        - 加入了武器的攻击速度,正负均可\n\
        - 正在设计新的存档格式,将武器、生物等数据进行软编码,预计下个快照实现,并增加一些基础的生物和武器。\n\
    - snapshot 8, 2026-07-17\n\
        - 加入了数据格式,目前只有 .WEAPON 和 .MOB 两种,具体可见源代码底部。\n\
        - 添加了怪物以及武器的名称。在战斗中会显示怪物的名称而非之前的\"ENEMY\"。\n\
        - 更改了一个漏洞的状态\n\
            - 当怪物血量超过约 9e16 时,剩余血量百分比计算错误。漏洞状态为:不予修复。原因:就目前来看,这么高的怪物血量是不切实际的。\n\
        - 再次隆重声明:该游戏名称“给木”是作者的倾情创作,严禁丑化、扭曲本游戏名称(如称之为“旮旯给木”等)。\n\
        - 重新上传,以修复严重漏洞:加载数据后标准输入流无法读取控制台的内容。\n\
    - snapshot 9, 2026-07-18\n\
        - 完善了了背包的功能,可以显示玩家的武器列表和目前装备的列表,并且可以更改,同时可以查看武器的属性。\n\
        - 后续会进行背包的优化,并且会增加背包列表的排序功能。\n\
    - snapshot 10, 2026-07-20\n\
        - 更新了新的装备种类:护甲。\n\
        - 更新了装备的属性:防御值。可以增加玩家的防御值。玩家自身的生命和防御值系统将在下个快照更新。\n\
        - 增加了背包的排序功能。\n\
        - 现在开发者会在博客园的随笔中事实更新最新版本,之前版本的存档也会在那里。\n\
    - snapshot 11, 2026-07-21\n\
        - 加入了玩家的名字、血量、防御、生物的破防、攻击、攻击速度属性。更新了战斗系统,现在生物也会攻击玩家了。\n\
        - 但是沙盒模式并没有同步更新。玩家可以通过修改源代码来测试新版本更新内容。\n\
"};

typedef long long ll;
const int N = 10010;
const int NONE = N - 9;
int WEAPON_COUNT, MOB_COUNT, ARMOR_COUNT;
int MAX_LINE = 11;

struct MOB {
    char name[25];
    ll hp; // health
    ll def; // defense
    ll anti_def; // anti_defense to player
    ll att;
    int speed;
} mobs[N];

struct EQUIP {
    char name[25];
    int lv;
    ll att;
    ll anti_def;
    ll def;
    int speed;
} equips[5][N];

struct CHOOSEEQUIP {
    int id;
    int kind;
    bool operator< (CHOOSEEQUIP &a) {
        if (id != a.id) return id < a.id;
        return kind < a.kind;
    } bool operator== (CHOOSEEQUIP &a) {
        return id == a.id && kind == a.kind;
    }
};

struct PLAYER {
    char name[25] = "You";
    ll att = 100; // attack
    ll money;
    ll hp;
    ll now_hp;
    ll def;
    CHOOSEEQUIP gear[5];
    int speed = 100; // attack speed
    int bag_sz, bag_len[5] = {0};
    CHOOSEEQUIP bag[5][1010];
} player;

bool wait_in_fight (int wait_time) {
    const int INTERVAL = 10;
    for (int slept = 0; slept < wait_time; slept += INTERVAL) {
        Sleep(min(INTERVAL, wait_time - slept));
        if (Key_down('Q')) {
            return false;
        }
    }
    return true;
}

void print_in_fight (char output_data[1010][110], int startx, int starty, int round_cnt) {
    go_to (startx, starty);
    printf("%-45s", output_data[0]);
    int line_cnt = MAX_LINE - 1;
    int start;
    if (line_cnt >= round_cnt) start = 1;
    else start = round_cnt - line_cnt + 1;
    for (int i = start, j = 1; i <= round_cnt; i ++, j ++) {
        go_to (startx + j, starty);
        printf("%s", output_data[(i - 1) % 1000 + 1]);
    }   
}

bool fight (int mob) {
    ll mob_hp = mobs[mob].hp;
    ll mob_now_hp = mob_hp;
    ll player_hp = player.hp;
    ll player_now_hp = player.now_hp;
    int player_round_cnt = 0, mob_round_cnt = 0;
    char output_data_player[1010][110];
    char output_data_mob[1010][110];
    int player_real_speed = player.speed + equips[1][player.gear[1].id].speed + equips[2][player.gear[2].id].speed;
    player_real_speed = max (min (10000, player_real_speed), 10);
    int mob_real_speed = mobs[mob].speed;

    clock_t player_wait_time = CLOCKS_PER_SEC / (player_real_speed / 100.0);
    if (player_wait_time < 1) player_wait_time = 1;
    clock_t player_next_attack = clock() + player_wait_time;
    clock_t mob_wait_time = CLOCKS_PER_SEC / (mob_real_speed / 100.0);
    if (mob_wait_time < 1) mob_wait_time = 1;
    clock_t mob_next_attack = clock() + mob_wait_time;
    
    cls();
    sprintf(output_data_player[0], "--- %s%9lld/%-9lld%3d%% ---", mobs[mob].name, mob_now_hp, mob_hp, 1ll * mob_now_hp * 100 / mob_hp);
    print_in_fight (output_data_player, 0, 0, player_round_cnt);
    sprintf(output_data_mob[0], "--- %s%9lld/%-9lld%3d%% ---", player.name, player_now_hp, player_hp, 1ll * player_now_hp * 100 / player_hp);
    print_in_fight (output_data_mob, 0, 50, mob_round_cnt);
    while (mob_now_hp > 0 && player_now_hp > 0) {
        clock_t now = clock();
        
        // printf("mob_hp=%lld player_hp=%lld now=%ld next_p=%ld next_m=%ld\n", mob_now_hp, player_now_hp, now, player_next_attack, mob_next_attack);

        if (now >= player_next_attack) {
            player_round_cnt ++;

            ll mob_real_def = max (mobs[mob].def - equips[1][player.gear[1].id].anti_def, 0ll); // 去除破防后的防御值
            ll player_real_att = player.att + equips[1][player.gear[1].id].att - mob_real_def; // 真实伤害
            ll caused = min (max (player_real_att, 0ll), mob_now_hp); // 真实造成的真实伤害
            mob_now_hp -= caused; // 剩余血量

            sprintf(output_data_player[0], "--- %s%9lld/%-9lld%3d%% ---", mobs[mob].name, mob_now_hp, mob_hp, 1ll * mob_now_hp * 100 / mob_hp);
            sprintf(output_data_player[(player_round_cnt - 1) % 1000 + 1], "%2d: %s dealt %lld damage to %s. ", player_round_cnt, player.name, caused, mobs[mob].name);

            print_in_fight (output_data_player, 0, 0, player_round_cnt);
            
            // ===== 重置下次攻击时间 =====
            player_next_attack = now + player_wait_time;
        } if (now >= mob_next_attack) {
            mob_round_cnt ++;
            
            ll player_real_def = max (player.def + equips[1][player.gear[1].id].def + equips[2][player.gear[2].id].def - mobs[mob].anti_def, 0ll); // 去除破防后的防御值
            ll mob_real_att = mobs[mob].att - player_real_def; // 真实伤害
            ll caused = min (max (mob_real_att, 0ll), player_now_hp); // 真实造成的真实伤害
            player_now_hp -= caused;

            sprintf(output_data_mob[0], "--- %s%9lld/%-9lld%3d%% ---", player.name, player_now_hp, player_hp, 1ll * player_now_hp * 100 / player_hp);
            sprintf(output_data_mob[(mob_round_cnt - 1) % 1000 + 1], "%2d: %s dealt %lld damage to %s. ", mob_round_cnt, mobs[mob].name, caused, player.name);

            print_in_fight (output_data_mob, 0, 50, mob_round_cnt);
            
            mob_next_attack = now + mob_wait_time;
        }
    }
    if (player_now_hp > 0) { // player won
        sprintf(output_data_player[0], "You won %s. Press any key to continue.", mobs[mob].name);
        print_in_fight (output_data_player, 0, 0, player_round_cnt);
        
        clear_stdin();
        press_any_key_to_continue();
        return true;
    } else {
        sprintf(output_data_mob[0], "You was defeated by %s. Press any key to continue.", mobs[mob].name);
        print_in_fight (output_data_mob, 0, 50, mob_round_cnt);
        
        clear_stdin();
        press_any_key_to_continue();
        return false;
    }
}

bool fight_in_sandbox (EQUIP equip) {
    int mob = 0;
    ll hp = mobs[mob].hp;
    ll now_hp = hp;
    int round_cnt = 0;
    char output_data[1010][110];
    int real_speed = player.speed + equip.speed;
    real_speed = max (min (10000, real_speed), 10);

    cls();
    sprintf(output_data[0], "--- %s %5lld/%-5lld %3d%%---", mobs[mob].name, now_hp, hp, 1ll * now_hp * 100 / hp);
    printf("%s\n", output_data[0]);
    while (now_hp > 0) {
        round_cnt ++;

        int wait_time = 100000 / real_speed; // 等待时间
        ll true_def = max (mobs[mob].def - equip.anti_def, 0ll); // 去除破防后的防御值
        ll real_att = player.att + equip.att - true_def; // 真实伤害
        ll caused = min (max (real_att, 0ll), now_hp); // 真实造成的真实伤害
        now_hp -= caused; // 剩余血量

        if (! wait_in_fight(wait_time)) return false;
        sprintf(output_data[0], "--- %s %5lld/%-5lld %3d%%---", mobs[mob].name, now_hp, hp, 1ll * now_hp * 100 / hp);
        sprintf(output_data[(round_cnt - 1) % 1000 + 1], "%2d: You dealt %lld damage to %s. ", round_cnt, caused, mobs[mob].name);

        go_to (0, 0);
        printf("%s\n", output_data[0]);
        int line_cnt = MAX_LINE - 1;
        int start;
        if (line_cnt >= round_cnt) start = 1;
        else start = round_cnt - line_cnt + 1;
        for (int i = start; i <= round_cnt; i ++) {
            printf("%s\n", output_data[(i - 1) % 1000 + 1]);
        }
    }
    sprintf(output_data[0], "You won the enemy. Press any key to continue.");
    go_to (0, 0);
    printf("%s\n", output_data[0]);
    int line_cnt = MAX_LINE - 1;
    int start;
    if (line_cnt >= round_cnt) start = 1;
    else start = round_cnt - line_cnt + 1;
    for (int i = start; i <= round_cnt; i ++) {
        printf("%s\n", output_data[i]);
    }

    clear_stdin();
    press_any_key_to_continue();
    return true;
}

/*
/----gear----\ /-----bag------\ /---preview----\
|> WEAPON:   | |- WEAPON:     | |NAMEEEEEEEEEEE|
|AAAAAAAAAA  | |> AABBCCDDEEFF| |  MODEEEEEEEEE|
|> unequip   | |  AABBCCDDEEFF| |  MODEEEEEEEEE|
|            | |              | |  MODEEEEEEEEE|
|            | |              | |
|            | |              |
\            / |              |
               |              |
               \--------------/
*/

void show_preview_in_bag (char output_prev[30][30], int &len_prev, CHOOSEEQUIP chs_eq, bool focus) {
    int chs_wp_id = chs_eq.id;
    int kd = chs_eq.kind;
    len_prev = 0;
    char tmp[30];
    if (focus) sprintf (output_prev[0], "/---preview----\\");
    else       sprintf (output_prev[0], "/   preview    \\");
    strcpy (tmp, equips[kd][chs_wp_id].name);
    align_str (tmp, 14);
    sprintf (output_prev[++ len_prev], "|%s|", tmp);
    if (kd == 1)      sprintf(output_prev[++ len_prev], "|kind: WEAPON  |");
    else if (kd == 2) sprintf(output_prev[++ len_prev], "|kind: ARMOR   |");
    sprintf(output_prev[++ len_prev], "|lvl.%-2d        |", equips[kd][chs_wp_id].lv);
    if (equips[kd][chs_wp_id].att != 0){
        sprintf (tmp, "%lld", equips[kd][chs_wp_id].att);
        align_str (tmp, 9);
        sprintf(output_prev[++ len_prev], "|att: %s|", tmp);
    } if (equips[kd][chs_wp_id].anti_def != 0){
        sprintf (tmp, "%lld", equips[kd][chs_wp_id].anti_def);
        align_str (tmp, 7);
        sprintf(output_prev[++ len_prev], "|undef: %s|", tmp);
    } if (equips[kd][chs_wp_id].speed != 0){
        sprintf (tmp, "%.2lf", equips[kd][chs_wp_id].speed / 100.0);
        align_str (tmp, 7);
        sprintf(output_prev[++ len_prev], "|speed: %s|", tmp);
    } if (equips[kd][chs_wp_id].def != 0){
        sprintf (tmp, "%lld", equips[kd][chs_wp_id].def);
        align_str (tmp, 9);
        sprintf(output_prev[++ len_prev], "|def: %s|", tmp);
    }
    if (focus) sprintf (output_prev[++ len_prev], "\\--------------/");
    else       sprintf (output_prev[++ len_prev], "\\              /");
    len_prev --;
}

void show_gear_in_bag (char output_gear[30][30], int chs_gear, bool focus) {
    char tmp[30];
    strcpy (tmp, equips[1][player.gear[1].id].name);
    align_str (tmp, 12);
    if (focus) sprintf (output_gear[0], "/----gear----\\");
    else       sprintf (output_gear[0], "/    gear    \\");
    sprintf (output_gear[1], "|%c weapon:   |", chs_gear == 1? '>' : ' ');
    sprintf (output_gear[2], "|%s|", tmp);
    sprintf (output_gear[3], "|%c unequip   |", chs_gear == 3? '>' : ' ');
    strcpy (tmp, equips[2][player.gear[2].id].name);
    align_str (tmp, 12);
    sprintf (output_gear[4], "|%c armor:    |", chs_gear == 4? '>' : ' ');
    sprintf (output_gear[5], "|%s|", tmp);
    sprintf (output_gear[6], "|%c unequip   |", chs_gear == 6? '>' : ' ');
    if (focus) sprintf (output_gear[7], "\\------------/");
    else       sprintf (output_gear[7], "\\            /");
}

void show_bag_in_bag (char output_bag[30][30], char output_bag_data[1010][30], pair<int, int> *match_bag, bool *valid_bag, int chs_bag, int len_bag, int &len_bag_data, bool focus) {
    char tmp[30];
    len_bag_data = 0;
    if (focus) sprintf (output_bag[0],       "/-----bag------\\");
    else       sprintf (output_bag[0],       "/     bag      \\");
    if (focus) sprintf (output_bag[len_bag + 1], "\\---[R] sort---/");
    else       sprintf (output_bag[len_bag + 1], "\\              /");
    sprintf (output_bag_data[++ len_bag_data],  "|- WEAPON:     |");
    match_bag[len_bag_data] = {0, NONE};
    for (int i = 1; i <= player.bag_len[1]; i ++) {
        len_bag_data ++;
        strcpy (tmp, equips[1][player.bag[1][i].id].name);
        align_str (tmp, 12);
        sprintf(output_bag_data[len_bag_data], "|%c %s|", chs_bag == len_bag_data ? '>' : ' ', tmp);
        valid_bag[len_bag_data] = 1;
        match_bag[len_bag_data] = {1, i};
    }
    sprintf (output_bag_data[++ len_bag_data],  "|- ARMOR:      |");
    match_bag[len_bag_data] = {0, NONE};
    for (int i = 1; i <= player.bag_len[2]; i ++) {
        len_bag_data ++;
        strcpy (tmp, equips[2][player.bag[2][i].id].name);
        align_str (tmp, 12);
        sprintf(output_bag_data[len_bag_data], "|%c %s|", chs_bag == len_bag_data ? '>' : ' ', tmp);
        valid_bag[len_bag_data] = 1;
        match_bag[len_bag_data] = {2, i};
    }
    
    int start = chs_bag - len_bag / 2, end = chs_bag + len_bag / 2;
    if (start < 1) start = 1, end = start + len_bag - 1;
    if (end > len_bag_data) end = len_bag_data, start = end - len_bag + 1;
    for (int i = start, j = 1; i <= end; i ++, j ++) {
        strcpy (output_bag[j], output_bag_data[i]);
    }
}

void print_in_bag (char output[30][30], int len, int start) {
    for (int i = 0; i <= len + 1; i ++) {
        go_to (i, start);
        printf("%s", output[i]);
    } 
}

void check_bag () { // 抱歉我已经尽可能的让代码不那么屎山了。
    cls();
    char output_gear[30][30];
    int chs_gear = 1;
    int len_gear = 6;
    int start_gear = 0;
    bool valid_gear[30] = {0, 1, 0, 1, 1, 0, 1};
    char output_bag_data[1010][30];
    char output_bag[30][30];
    pair <int, int> match_bag[1010];
    bool valid_bag[1010] = {0, 0, 1};
    int chs_bag = 2;
    int len_bag = MAX_LINE - 2;
    int len_bag_data;
    int start_bag = 15;
    char output_prev[30][30];
    int len_prev = 1;
    int start_prev = 32;
    int chs = 2;
    char tmp[30];

    show_gear_in_bag (output_gear, chs_gear, chs == 1);
    show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
    show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);

    print_in_bag (output_gear, len_gear, start_gear);
    print_in_bag (output_bag, len_bag, start_bag);
    print_in_bag (output_prev, len_prev, start_prev);

    while (1) {
        char c = _getch();
        if (c == 'a' || c == 'A') {
            if (chs == 2) {
                chs = 1;
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_preview_in_bag (output_prev, len_prev, player.gear[(chs_gear - 1) / 3 + 1], chs == 3);
            } else if (chs == 1) {
                chs = 3;
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_preview_in_bag (output_prev, len_prev, player.gear[(chs_gear - 1) / 3 + 1], chs == 3);
            } else if (chs == 3) {
                chs = 2;
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == 'd' || c == 'D') {
            if (chs == 2) {
                chs = 3;
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            } else if (chs == 1) {
                chs = 2;
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            } else if (chs == 3) {
                chs = 1;
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_preview_in_bag (output_prev, len_prev, player.gear[(chs_gear - 1) / 3 + 1], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == 'w' || c == 'W') {
            if (chs == 1) {
                do {
                    chs_gear --;
                    chs_gear = (chs_gear - 1 + len_gear) % len_gear + 1;
                } while (! valid_gear[chs_gear]) ;
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_preview_in_bag (output_prev, len_prev, player.gear[(chs_gear - 1) / 3 + 1], chs == 3);
            } else if (chs == 2) {
                do {
                    chs_bag --;
                    chs_bag = (chs_bag - 1 + len_bag_data) % (len_bag_data) + 1;
                } while (! valid_bag[chs_bag]) ;
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == 's' || c == 'S') {
            if (chs == 1) {
                do {
                    chs_gear ++;
                    chs_gear = (chs_gear - 1) % len_gear + 1;
                } while (! valid_gear[chs_gear]) ;
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_preview_in_bag (output_prev, len_prev, player.gear[(chs_gear - 1) / 3 + 1], chs == 3);
            } else if (chs == 2) {
                do {
                    chs_bag ++;
                    chs_bag = (chs_bag - 1) % (len_bag_data) + 1;
                } while (! valid_bag[chs_bag]) ;
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                if (chs_gear == 3 && player.gear[1].id != NONE) {
                    player.bag[1][++ player.bag_len[1]].id = NONE;
                    swap (player.gear[1], player.bag[1][player.bag_len[1]]);
                } if (chs_gear == 6 && player.gear[2].id != NONE) {
                    player.bag[2][++ player.bag_len[2]].id = NONE;
                    swap (player.gear[2], player.bag[2][player.bag_len[2]]);
                }
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.gear[(chs_gear - 1) / 3 + 1], chs == 3);
            } else if (chs == 2) {
                swap (player.gear[match_bag[chs_bag].fi], player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se]);
                if (player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se].id == NONE) {
                    for (int i = match_bag[chs_bag].se + 1; i <= player.bag_len[match_bag[chs_bag].fi]; i ++) {
                        swap (player.bag[match_bag[chs_bag].fi][i - 1],player.bag[match_bag[chs_bag].fi][i]);
                    } player.bag_len[match_bag[chs_bag].fi] --;
                } if (chs_bag > len_bag_data || ! valid_bag[chs_bag]) {
                    do {
                        chs_bag --;
                        chs_bag = (chs_bag + len_bag_data - 1) % (len_bag_data) + 1;
                    } while (! valid_bag[chs_bag]) ;
                }
                show_gear_in_bag (output_gear, chs_gear, chs == 1);
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        } else if (c == 'r' || c == 'R') {
            if (chs == 2) {
                CHOOSEEQUIP now_eq = player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se];
                sort (player.bag[1] + 1, player.bag[1] + 1 + player.bag_len[1]);
                sort (player.bag[2] + 1, player.bag[2] + 1 + player.bag_len[2]);
                for (int i = 1; i <= player.bag_len[1]; i ++)
                    if (player.bag[1][i] == now_eq) {
                        chs_bag = i + 1;
                        break;
                    }
                for (int i = 1; i <= player.bag_len[2]; i ++)
                    if (player.bag[2][i] == now_eq) {
                        chs_bag = i + 2 + player.bag_len[1];
                        break;
                    }
                show_bag_in_bag (output_bag, output_bag_data, match_bag, valid_bag, chs_bag, len_bag, len_bag_data, chs == 2);
                show_preview_in_bag (output_prev, len_prev, player.bag[match_bag[chs_bag].fi][match_bag[chs_bag].se], chs == 3);
            }
            cls ();
            print_in_bag (output_gear, len_gear, start_gear);
            print_in_bag (output_bag, len_bag, start_bag);
            print_in_bag (output_prev, len_prev, start_prev);
        }

        else if (c == 'q' || c == 'Q') {
            return ;
        }
    }
}

void change_log () {
    cls();
    printf("%s", change_logs);
    press_any_key_to_continue();
}

void sandbox () {
    EQUIP sandbox_equip = {"default", 0, 10, 0, 0, 0};
    strcpy (sandbox_equip.name, "default");
    char output_data[30][110];
    int chs = 1;
    int len = 9;

    sprintf(output_data[0], "--- Sandbox --- (press [Enter] to change)");
    sprintf(output_data[1], "%c enemy health: %lld", chs == 1 ? '>' : ' ', mobs[0].hp);
    sprintf(output_data[2], "%c enemy defense: %lld", chs == 2 ? '>' : ' ', mobs[0].def);
    sprintf(output_data[3], "%c player attack: %lld", chs == 3 ? '>' : ' ', player.att);
    sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
    sprintf(output_data[5], "%c equip attack: %lld", chs == 5 ? '>' : ' ', sandbox_equip.att);
    sprintf(output_data[6], "%c equip anti_defense: %lld", chs == 6 ? '>' : ' ', sandbox_equip.anti_def);
    sprintf(output_data[7], "%c equip attack speed: %.2lfps", chs == 7 ? '>' : ' ', sandbox_equip.speed / 100.0);
    sprintf(output_data[8], "%c equip defense: %lld", chs == 8 ? '>' : ' ', sandbox_equip.def);
    sprintf(output_data[9], "%c i'm ready.", chs == 9 ? '>' : ' ');
    cls ();
    for (int i = 0; i <= len; i ++) {
        printf("%s\n", output_data[i]);
    } while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                go_to (len + 2, 0);
                printf("input enemy health: ");
                ShowCursor();
                scanf("%lld", &mobs[0].hp);
                mobs[0].hp = max (mobs[0].hp, 0ll);
                sprintf(output_data[1], "%c enemy health: %lld", chs == 1 ? '>' : ' ', mobs[0].hp);
            } else if (chs == 2) {
                go_to (len + 2, 0);
                printf("input enemy defense: ");
                ShowCursor();
                scanf("%lld", &mobs[0].def);
                mobs[0].def = max (mobs[0].def, 0ll);
                sprintf(output_data[2], "%c enemy defense: %lld", chs == 2 ? '>' : ' ', mobs[0].def);
            } else if (chs == 3) {
                go_to (len + 2, 0);
                printf("input player attack: ");
                ShowCursor();
                scanf("%lld", &player.att);
                player.att = max (player.att, 0ll);
                sprintf(output_data[3], "%c player attack: %lld", chs == 3 ? '>' : ' ', player.att);
            } else if (chs == 4) {
                double tmp;
                go_to (len + 2, 0);
                printf("input player attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                player.speed = max (min (tmp, 100.0), 0.1) * 100;
                sprintf(output_data[4], "%c player attack speed: %.2lfps", chs == 4 ? '>' : ' ', player.speed / 100.0);
            } else if (chs == 5) {
                go_to (len + 2, 0);
                printf("input equip attack: ");
                ShowCursor();
                scanf("%lld", &sandbox_equip.att);
                sandbox_equip.att = max(sandbox_equip.att, 0ll);
                sprintf(output_data[5], "%c equip attack: %lld", chs == 5 ? '>' : ' ', sandbox_equip.att);
            } else if (chs == 6) {
                go_to (len + 2, 0);
                printf("input equip anti_defense: ");
                ShowCursor();
                scanf("%lld", &sandbox_equip.anti_def);
                sprintf(output_data[6], "%c equip anti_defense: %lld", chs == 6 ? '>' : ' ', sandbox_equip.anti_def);
            } else if (chs == 7) {
                double tmp;
                go_to (len + 2, 0);
                printf("input equip attack speed: ");
                ShowCursor();
                scanf("%lf", &tmp);
                sandbox_equip.speed = max (min (tmp, 100.0), -100.0) * 100;
                sprintf(output_data[7], "%c equip attack speed: %.2lfps", chs == 7 ? '>' : ' ', sandbox_equip.speed / 100.0);
            } else if (chs == 8) {
                go_to (len + 2, 0);
                printf("input equip defense: ");
                ShowCursor();
                scanf("%lld", &sandbox_equip.def);
                sprintf(output_data[8], "%c equip defense: %lld", chs == 8 ? '>' : ' ', sandbox_equip.def);
            }else if (chs == 9) {
                fight_in_sandbox(sandbox_equip);
                clear_stdin();
            } cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin(); HideCursor();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
    }
}

void home_page () {
    char output_data[30][110];
    int chs = 1;
    int len = 3;

    sprintf (output_data[0], "--- Home Page --- money: %lld", player.money);
    sprintf (output_data[1], "%c Check bag", chs == 1 ? '>' : ' ');
    sprintf (output_data[2], "%c Create a sandbox", chs == 2 ? '>' : ' ');
    sprintf (output_data[3], "%c Change log", chs == 3 ? '>' : ' ');
    cls ();
    printf("%s\n", output_data[0]);
    Sleep (500);
    for (int i = 1; i <= len; i ++) printf("%s\n", output_data[i]);
    clear_stdin();
    while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            cls();
            if (chs == 1) {
                check_bag ();
            } else if (chs == 2) {
                sandbox();
            } else {
                change_log ();
            }
            cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin();
        } else if (c == 'q' || c == 'Q') {
            return ;
        }
        // Sleep (100);
    }
}

void init () {
    player.money = 100;
    player.att = 10;
    player.speed = 100;
    player.hp = player.now_hp = 200;
    WEAPON_COUNT = 0;
    strcpy (equips[1][0].name, "default");
    equips[1][0].att = 10;
    equips[1][0].anti_def = 0;
    MOB_COUNT = 0;
    strcpy (mobs[0].name, "default");
    mobs[0].hp = 1000;
    mobs[0].def = 0;
    mobs[0].att = 10;
    mobs[0].speed = 100;
    equips[1][NONE].att = equips[1][NONE].anti_def = equips[1][NONE].lv = equips[1][NONE].speed = 0; strcpy(equips[1][NONE].name, "未装备");
    equips[2][NONE].att = equips[2][NONE].anti_def = equips[2][NONE].lv = equips[2][NONE].speed = 0; strcpy(equips[2][NONE].name, "未装备");
    player.bag_len[1] = 12;
    player.bag_len[2] = 12;
    player.gear[1].kind = 1;
    player.gear[1].id = NONE;
    player.gear[2].kind = 2;
    player.gear[2].id = NONE;
    for (int i = 1; i <= 12; i ++) {
        player.bag[1][i].id = (i - 1) % 4 + 1;
        player.bag[1][i].kind = 1;
    } for (int i = 1; i <= 12; i ++) {
        player.bag[2][i].id = (i - 1) % 2 + 1;
        player.bag[2][i].kind = 2;
    }
}

void load_game () {
    char output_data[20][210];
    char weapon_path[110] = "WEAPON.equip";
    char armor_path[110] = "ARMOR.equip";
    char mob_path[110] = "MOB.mob";
    int len = 4;
    int chs = len;

    sprintf (output_data[0], "请先选择读入数据的文件名。若因读入文件填写错误而对设备造成损伤,本游戏不承担责任。若你没有游戏数据,请在源代码最底部按注释提示创建。");
    sprintf (output_data[1], "%c 武器列表:%s", chs == 1 ? '>' : ' ', weapon_path);
    sprintf (output_data[2], "%c 护甲列表:%s", chs == 2 ? '>' : ' ', weapon_path);
    sprintf (output_data[3], "%c 生物列表:%s", chs == 3 ? '>' : ' ', mob_path);
    sprintf (output_data[4], "%c 开始游戏!", chs == 4 ? '>' : ' ');
    
    cls ();
    for (int i = 0; i <= len; i ++) {
        printf("%s\n", output_data[i]);
    } while (1) {
        int c = _getch();
        if (c == 'W' || c == 'w') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs --;
            if (chs == 0) chs = len;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == 'S' || c == 's') {
            output_data[chs][0] = ' ';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
            chs ++;
            if (chs == len + 1) chs = 1;
            output_data[chs][0] = '>';
            go_to (chs, 0);
            printf("%s\n", output_data[chs]);
        } else if (c == '\n' || c == '\r') {
            if (chs == 1) {
                ShowCursor();
                go_to (len + 2, 0);
                printf("输入新的武器数据地址:");
                scanf("%s", weapon_path);
                sprintf (output_data[1], "%c 武器列表:%s", chs == 1 ? '>' : ' ', weapon_path);
            } if (chs == 2) {
                ShowCursor();
                go_to (len + 2, 0);
                printf("输入新的护甲数据地址:");
                scanf("%s", armor_path);
                sprintf (output_data[2], "%c 护甲列表:%s", chs == 2 ? '>' : ' ', armor_path);
            } else if (chs == 3) {
                ShowCursor();
                go_to (len + 2, 0);
                printf("输入新的生物数据地址:");
                scanf("%s", mob_path);
                sprintf (output_data[3], "%c 生物列表:%s", chs == 3 ? '>' : ' ', mob_path);
            } else if (chs == 4) {
                break;
            } cls(); for (int i = 0; i <= len; i ++) printf("%s\n", output_data[i]);
            clear_stdin(); HideCursor();
        } else if (c == 'q' || c == 'Q') {
            exit(0);
        }
    }
    freopen (weapon_path, "r", stdin);
    while (1) {
        char c[25];
        int lv, att, undef, spd, def;
        scanf("%s", c);
        if (c[0] == '_' && c[1] == '_' && c[2] == 'E' && c[3] == 'N' && c[4] == 'D' && c[5] == '_' && c[6] == '_') {
            break;
        } scanf("%d%d%d%d%d", &lv, &att, &undef, &spd, &def);
        WEAPON_COUNT ++; 
        strcpy(equips[1][WEAPON_COUNT].name, c);
        equips[1][WEAPON_COUNT].lv = lv;
        equips[1][WEAPON_COUNT].att = att;
        equips[1][WEAPON_COUNT].anti_def = undef;
        equips[1][WEAPON_COUNT].speed = spd;
        equips[1][WEAPON_COUNT].def = def;
    } 
    fclose (stdin);
    freopen (armor_path, "r", stdin);
    while (1) {
        char c[25];
        int lv, att, undef, spd, def;
        scanf("%s", c);
        if (c[0] == '_' && c[1] == '_' && c[2] == 'E' && c[3] == 'N' && c[4] == 'D' && c[5] == '_' && c[6] == '_') {
            break;
        } scanf("%d%d%d%d%d", &lv, &att, &undef, &spd, &def);
        ARMOR_COUNT ++; 
        strcpy(equips[2][ARMOR_COUNT].name, c);
        equips[2][ARMOR_COUNT].lv = lv;
        equips[2][ARMOR_COUNT].att = att;
        equips[2][ARMOR_COUNT].anti_def = undef;
        equips[2][ARMOR_COUNT].speed = spd;
        equips[2][ARMOR_COUNT].def = def;
    } 
    fclose (stdin);
    freopen (mob_path, "r", stdin);
    while (1) {
        char c[25];
        int hp, def, att, anti_def, spd;
        scanf("%s", c);
        if (c[0] == '_' && c[1] == '_' && c[2] == 'E' && c[3] == 'N' && c[4] == 'D' && c[5] == '_' && c[6] == '_') {
            break;
        } scanf("%d%d%d%d%d", &hp, &def, &att, &anti_def, &spd);
        MOB_COUNT ++; 
        strcpy(mobs[MOB_COUNT].name, c);
        mobs[MOB_COUNT].hp = hp;
        mobs[MOB_COUNT].def = def;
        mobs[MOB_COUNT].att = att;
        mobs[MOB_COUNT].anti_def = anti_def;
        mobs[MOB_COUNT].speed = spd;
    } 
    fclose (stdin);
    freopen("CON", "r", stdin);
}

int main () {
    HideCursor();

    cls();
    printf("在游玩/调试前请先更换编码方式:点击右下角\"UTF-8\",选择\"reopen with encoding\",点击\"Simplified Chinese (GBK) gbk\"。若程序内中文还是无法正常显示,按Ctrl+Z。\n\
Before playing/debugging, please change the encoding method: click 'UTF-8' in the bottom right corner, select 'Reopen with encoding', and click 'Simplified Chinese (GBK) gbk'. If the Chinese text still does not display properly within the program (that are showing like '锟斤拷', press Ctrl+Z.\n\
Press any key to continue...\n");
    press_any_key_to_continue();

    init();
    load_game ();

    // home_page ();
    check_bag();
    fight(1);
    return 0;
}

/*
创建游戏数据:

目前游戏有三个数据库,默认分别是 WEAPON.equip,ARMOR.equip 和 MOB.mob。下面是数据的官方内容。您可以在对应数据文件中修改数据来制作二创数据包。请认准官方默认数据包。

将下面内容粘贴到 WEAPON.equip 中:

小刀 1
12 0 10 0
刺刀 1
10 6 0 0
沉重的铁斧 1
15 10 -20 0
巨人的棒槌 1
25 -10 -10 0
__END__

将下面内容粘贴到 ARMOR.equip 中:

沉重的铠甲 1
0 0 -10 3
棉甲 1
0 0 5 1
__END__

将下面内容粘贴到 MOB.mob 中:

正方形
250 0 5 0 100 
__END__

二创指引:WEAPON.weapon 的文件格式形如:
武器名称(请不要使用以__END__为开头的武器名称!) 等级
攻击 破防 攻击速度x100(为了避免精度误差)
文件末尾用__END__标识
*/
posted on 2026-07-20 14:24  Zhaoxiyan  阅读(9)  评论(0)    收藏  举报