《给木》sandbox version

《给木》 sandbox version

26.1

/*
GeiMu sandbox version 26.1
*/
#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;   // 截断并填充点
}
void putstr(string S, int wait_time = 10){
	for(int i = 0,j = S.length();i < j;i++){
		printf("%c", S[i]);
		Sleep(wait_time);
	}
	return;
}

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;
}

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;
}

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 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 ();

    sandbox();
    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-22 14:09  Zhaoxiyan  阅读(4)  评论(0)    收藏  举报