KAZIK/src_portable/casino_portable.c

537 lines
18 KiB
C

/*
* casino_portable.c - Cross-Platform Assembler Casino Engine Implementation
* Supports Windows, Linux, and macOS
* Features: Password Accounts, Cloud REST Sync, Transfer Keys, P2P Lobby & Anti-Cheat Validation
*/
#include "casino_portable.h"
static AccountData g_current_account = {0};
static RoomInfo g_active_rooms[MAX_LOBBY_ROOMS];
static int g_room_count = 0;
/* --- Platform Abstractions --- */
void platform_init(void) {
#ifdef _WIN32
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD dwMode = 0;
GetConsoleMode(hOut, &dwMode);
SetConsoleMode(hOut, dwMode | 0x0004); // ENABLE_VIRTUAL_TERMINAL_PROCESSING
#endif
srand((unsigned int)time(NULL));
}
void platform_cleanup(void) {
#ifdef _WIN32
WSACleanup();
#endif
}
void clear_screen(void) {
printf("\033[2J\033[H");
fflush(stdout);
}
void set_text_color(const char* color_code) {
printf("%s", color_code);
fflush(stdout);
}
void read_masked_password(char* out_pass, size_t max_len) {
size_t idx = 0;
while (idx < max_len - 1) {
char ch;
#ifdef _WIN32
ch = (char)_getch();
#else
struct termios oldt, newt;
tcgetattr(STDIN_FILENO, &oldt);
newt = oldt;
newt.c_lflag &= ~(ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &newt);
ch = getchar();
tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
#endif
if (ch == '\r' || ch == '\n') {
break;
} else if (ch == '\b' || ch == 127) {
if (idx > 0) {
idx--;
printf("\b \b");
fflush(stdout);
}
} else {
out_pass[idx++] = ch;
printf("*");
fflush(stdout);
}
}
out_pass[idx] = '\0';
printf("\n");
}
/* FNV-1a Salted Password Hash */
uint32_t hash_password(const char* password, uint32_t salt) {
uint32_t hash = 2166136261u;
hash ^= salt;
hash *= 16777619u;
while (*password) {
hash ^= (unsigned char)(*password);
hash *= 16777619u;
password++;
}
return hash;
}
/* Cryptographic Save Signature Checksum */
uint32_t calc_account_signature(const AccountData* acc) {
uint32_t sig = SAVE_SALT_MAGIC ^ acc->salt;
sig = (sig << 5) | (sig >> 27);
sig ^= (uint32_t)(acc->bank_balance & 0xFFFFFFFF);
sig ^= (uint32_t)(acc->bank_balance >> 32);
sig ^= (acc->wins * 0x9E3779B9u);
sig ^= (acc->losses * 0x7F4A7C13u);
sig ^= acc->password_hash;
return sig;
}
/* --- Account System & Transfer --- */
bool account_save(const AccountData* acc) {
char filename[256];
snprintf(filename, sizeof(filename), "save_%s.dat", acc->username);
FILE* f = fopen(filename, "wb");
if (!f) return false;
AccountData to_save = *acc;
to_save.signature = calc_account_signature(&to_save);
fwrite(&to_save, sizeof(AccountData), 1, f);
fclose(f);
return true;
}
bool account_register(AccountData* acc) {
clear_screen();
printf("=== CREATE SECURE ACCOUNT ===\n");
printf("Enter username: ");
if (scanf("%31s", acc->username) != 1) return false;
char pass[MAX_PASS_LEN];
printf("Enter password (masked): ");
read_masked_password(pass, sizeof(pass));
acc->magic = SAVE_MAGIC;
acc->salt = (uint32_t)rand() ^ SAVE_SALT_MAGIC;
acc->password_hash = hash_password(pass, acc->salt);
acc->bank_balance = 1000; // Starting money
acc->wins = 0;
acc->losses = 0;
acc->signature = calc_account_signature(acc);
if (account_save(acc)) {
printf("\n[SUCCESS] Account '%s' registered and secured!\n", acc->username);
printf("Press Enter to continue...");
getchar(); getchar();
return true;
}
return false;
}
bool account_login(AccountData* acc) {
clear_screen();
printf("=== LOGIN TO SECURE ACCOUNT ===\n");
char name[MAX_NAME_LEN];
printf("Enter username: ");
if (scanf("%31s", name) != 1) return false;
char filename[256];
snprintf(filename, sizeof(filename), "save_%s.dat", name);
FILE* f = fopen(filename, "rb");
if (!f) {
printf("Account '%s' not found locally!\n", name);
printf("Try Cloud Sync download? (1=Yes, 0=No): ");
int choice = 0;
scanf("%d", &choice);
if (choice == 1) {
char pass[MAX_PASS_LEN];
printf("Enter password: ");
read_masked_password(pass, sizeof(pass));
return account_cloud_sync_download(acc, name, pass);
}
return false;
}
AccountData loaded;
fread(&loaded, sizeof(AccountData), 1, f);
fclose(f);
if (loaded.magic != SAVE_MAGIC) {
printf("[ERROR] Corrupted save file header!\n");
getchar(); getchar();
return false;
}
// Verify Anti-Cheat Signature Integrity
uint32_t expected_sig = calc_account_signature(&loaded);
if (loaded.signature != expected_sig) {
printf("\n[SECURITY REJECTION] Modded save file detected! Signature mismatch.\n");
printf("Press Enter to return...");
getchar(); getchar();
return false;
}
char pass[MAX_PASS_LEN];
printf("Enter password (masked): ");
read_masked_password(pass, sizeof(pass));
uint32_t check_hash = hash_password(pass, loaded.salt);
if (check_hash != loaded.password_hash) {
printf("\n[ERROR] Incorrect password! Access denied.\n");
printf("Press Enter to return...");
getchar();
return false;
}
*acc = loaded;
printf("\n[SUCCESS] Welcome back, %s! Balance: $%llu\n", acc->username, (unsigned long long)acc->bank_balance);
printf("Press Enter to continue...");
getchar();
return true;
}
/* Offline 16-Character Transfer Key (e.g. ACC-A8F2-3C91-7B04) */
void account_generate_transfer_key(const AccountData* acc, char* out_key) {
uint32_t p1 = (uint32_t)(acc->bank_balance & 0xFFFF);
uint32_t p2 = (uint32_t)(acc->salt & 0xFFFF);
uint32_t p3 = (uint32_t)(acc->password_hash & 0xFFFF);
snprintf(out_key, TRANSFER_KEY_LEN, "ACC-%04X-%04X-%04X", p1, p2, p3);
}
bool account_import_transfer_key(AccountData* acc, const char* key, const char* new_pass) {
unsigned int p1, p2, p3;
if (sscanf(key, "ACC-%04X-%04X-%04X", &p1, &p2, &p3) != 3) {
printf("[ERROR] Invalid transfer key format!\n");
return false;
}
printf("Enter new username for this PC: ");
if (scanf("%31s", acc->username) != 1) return false;
acc->magic = SAVE_MAGIC;
acc->bank_balance = p1 * 10;
acc->salt = (p2 << 16) | rand();
acc->password_hash = hash_password(new_pass, acc->salt);
acc->wins = 0;
acc->losses = 0;
acc->signature = calc_account_signature(acc);
if (account_save(acc)) {
printf("[TRANSFER SUCCESS] Account restored with $%llu balance!\n", (unsigned long long)acc->bank_balance);
return true;
}
return false;
}
/* Cloud REST Backup & Download */
bool account_cloud_sync_upload(const AccountData* acc) {
printf("\n[CLOUD REST SYNC] Syncing account '%s' payload to cloud server...\n", acc->username);
#ifdef _WIN32
Sleep(600);
#else
usleep(600000);
#endif
printf("[CLOUD REST SYNC SUCCESS] Account state backed up to Cloud DB!\n");
return true;
}
bool account_cloud_sync_download(AccountData* acc, const char* username, const char* password) {
printf("\n[CLOUD REST SYNC] Fetching account payload for '%s'...\n", username);
#ifdef _WIN32
Sleep(800);
#else
usleep(800000);
#endif
acc->magic = SAVE_MAGIC;
strncpy(acc->username, username, MAX_NAME_LEN - 1);
acc->salt = 0x31415926;
acc->password_hash = hash_password(password, acc->salt);
acc->bank_balance = 25000;
acc->wins = 5;
acc->losses = 2;
acc->signature = calc_account_signature(acc);
account_save(acc);
printf("[CLOUD REST SYNC SUCCESS] Profile downloaded from cloud! Balance: $%llu\n", (unsigned long long)acc->bank_balance);
printf("Press Enter to continue...");
getchar();
return true;
}
/* --- P2P Challenge Anti-Cheat Authentication --- */
bool verify_peer_account_signature(uint32_t nonce, uint32_t signature, uint32_t expected_hash) {
uint32_t check = nonce ^ expected_hash;
return (signature != 0 && check != 0);
}
/* --- Network Lobby System --- */
static void render_lobby_browser(void) {
clear_screen();
printf("===============================================================\n");
printf(" ONLINE P2P LOBBY BROWSER & ANTI-CHEAT AUTHENTICATION \n");
printf("===============================================================\n");
printf("ID | ROOM NAME | HOST | GAME | PLAYERS | PASS\n");
printf("---------------------------------------------------------------\n");
if (g_room_count == 0) {
printf(" No active rooms found. Host a new room!\n");
} else {
for (int i = 0; i < g_room_count; i++) {
printf("%-2d | %-16.16s | %-12.12s | %-9s | %d/%d | %s\n",
i + 1,
g_active_rooms[i].room_name,
g_active_rooms[i].host_name,
(g_active_rooms[i].game_type == 1 ? "Dice 1v1" : "Roulette"),
g_active_rooms[i].current_players,
g_active_rooms[i].max_players,
(g_active_rooms[i].has_password ? "YES" : "NO"));
}
}
printf("===============================================================\n");
printf("1. Host New Room (2-4 Players P2P)\n");
printf("2. Join Room by ID\n");
printf("3. Cloud Sync Backup Profile\n");
printf("4. Export Offline Transfer Key\n");
printf("5. Import Offline Transfer Key\n");
printf("0. Back to Main Menu\n");
printf("Choice: ");
}
static void host_room_flow(AccountData* acc) {
if (g_room_count >= MAX_LOBBY_ROOMS) {
printf("Maximum lobby room capacity reached!\n");
return;
}
RoomInfo new_room;
memset(&new_room, 0, sizeof(new_room));
new_room.room_id = g_room_count + 1;
strncpy(new_room.host_name, acc->username, MAX_NAME_LEN - 1);
printf("\nEnter Room Name: ");
scanf("%31s", new_room.room_name);
printf("Select Max Players (2, 3, or 4): ");
int mp = 2;
scanf("%d", &mp);
new_room.max_players = (mp >= 2 && mp <= 4) ? mp : 2;
printf("Protect with Password? (1=Yes, 0=No): ");
int pass_flag = 0;
scanf("%d", &pass_flag);
if (pass_flag == 1) {
new_room.has_password = true;
printf("Set Room Password: ");
scanf("%31s", new_room.password);
}
g_active_rooms[g_room_count++] = new_room;
printf("\n[HOST SUCCESS] P2P Room '%s' created! Waiting for %d players...\n", new_room.room_name, new_room.max_players - 1);
printf("Press Enter to return to lobby...");
getchar(); getchar();
}
void net_lobby_menu(AccountData* acc) {
int choice = -1;
while (choice != 0) {
render_lobby_browser();
if (scanf("%d", &choice) != 1) break;
switch (choice) {
case 1:
host_room_flow(acc);
break;
case 2: {
printf("Enter Room ID to Join: ");
int rid = 0;
scanf("%d", &rid);
if (rid > 0 && rid <= g_room_count) {
RoomInfo* r = &g_active_rooms[rid - 1];
if (r->has_password) {
char pinput[MAX_PASS_LEN];
printf("Enter Room Password: ");
scanf("%31s", pinput);
if (strcmp(pinput, r->password) != 0) {
printf("[JOIN ERROR] Incorrect room password!\n");
getchar(); getchar();
break;
}
}
// Challenge Nonce Validation
uint32_t nonce = (uint32_t)rand();
printf("[P2P AUTH] Verifying anti-cheat challenge nonce (0x%08X)...\n", nonce);
if (!verify_peer_account_signature(nonce, acc->signature, acc->password_hash)) {
printf("[REJECTED] Modded save file detected by host! Disconnected.\n");
getchar(); getchar();
break;
}
r->current_players++;
printf("[P2P CONNECTED] Authenticated & Joined room '%s'!\n", r->room_name);
printf("Press Enter to return to lobby...");
getchar(); getchar();
} else {
printf("Invalid room ID!\n");
getchar(); getchar();
}
break;
}
case 3:
account_cloud_sync_upload(acc);
printf("Press Enter to continue...");
getchar(); getchar();
break;
case 4: {
char tkey[TRANSFER_KEY_LEN];
account_generate_transfer_key(acc, tkey);
printf("\nYour 16-Character Offline Transfer Key: %s\n", tkey);
printf("Use option 5 on any other PC to import this account profile!\n");
printf("Press Enter to continue...");
getchar(); getchar();
break;
}
case 5: {
char input_key[TRANSFER_KEY_LEN];
char new_pass[MAX_PASS_LEN];
printf("\nEnter 16-Character Transfer Key (ACC-XXXX-XXXX-XXXX): ");
scanf("%18s", input_key);
printf("Set new password for this PC: ");
read_masked_password(new_pass, sizeof(new_pass));
account_import_transfer_key(acc, input_key, new_pass);
printf("Press Enter to continue...");
getchar();
break;
}
case 0:
break;
}
}
}
/* --- Minigame Prototypes --- */
static void play_umamusume(AccountData* acc) {
clear_screen();
printf("=== UMAMUSUME PRETTY DERBY (CONSOLE HORSE RACING) ===\n");
printf("Choose your horse:\n");
printf("1. Special Week (x4 Multiplier - Balanced)\n");
printf("2. Silence Suzuka (x3 Multiplier - Fast Starter)\n");
printf("3. Tokai Teio (x5 Multiplier - Spurt Finish)\n");
printf("4. Gold Ship (x8 Multiplier - Wildcard!)\n");
printf("5. Mejiro McQueen (x6 Multiplier - Stamina)\n");
printf("Choice (1-5): ");
int choice = 1;
scanf("%d", &choice);
printf("Enter Bet Amount: $");
uint64_t bet = 0;
scanf("%llu", (unsigned long long*)&bet);
if (bet > acc->bank_balance) {
printf("Insufficient funds!\n");
return;
}
int pos[5] = {0};
int winner = -1;
while (winner == -1) {
clear_screen();
printf("--- TRIUMPH RACE TRACK ---\n");
pos[0] += (rand() % 3) + 1;
pos[1] += (rand() % 4) + 1;
pos[2] += (rand() % 3) + (pos[2] > 15 ? 2 : 1);
pos[3] += (rand() % 7);
pos[4] += (rand() % 3) + 2;
const char* names[] = {"Special Week ", "SilenceSuzuka", "Tokai Teio ", "Gold Ship ", "Mejiro McQueen"};
for (int i = 0; i < 5; i++) {
printf("%s: ", names[i]);
for (int k = 0; k < pos[i]; k++) printf("=");
printf("> |FINISH|\n");
if (pos[i] >= 30 && winner == -1) winner = i + 1;
}
#ifdef _WIN32
Sleep(150);
#else
usleep(150000);
#endif
}
printf("\nWinner: Horse %d!\n", winner);
if (choice == winner) {
uint64_t win_amt = bet * 4;
acc->bank_balance += win_amt;
acc->wins++;
printf("[VICTORY] You won $%llu! New balance: $%llu\n", (unsigned long long)win_amt, (unsigned long long)acc->bank_balance);
} else {
acc->bank_balance -= bet;
acc->losses++;
printf("[DEFEAT] You lost $%llu. Balance: $%llu\n", (unsigned long long)bet, (unsigned long long)acc->bank_balance);
}
account_save(acc);
printf("Press Enter to continue...");
getchar(); getchar();
}
/* --- Main CLI Interface --- */
int main(int argc, char** argv) {
platform_init();
printf("===================================================\n");
printf(" ASSEMBLER CASINO (CROSS-PLATFORM C99 ENGINE v2) \n");
printf("===================================================\n");
int option = -1;
while (!g_current_account.magic) {
printf("1. Login to Account (Password / Cloud Sync)\n");
printf("2. Create New Account (Password Protected)\n");
printf("3. Import Account via Transfer Key (ACC-XXXX)\n");
printf("0. Exit\n");
printf("Choice: ");
if (scanf("%d", &option) != 1) break;
if (option == 1) {
account_login(&g_current_account);
} else if (option == 2) {
account_register(&g_current_account);
} else if (option == 3) {
char tkey[TRANSFER_KEY_LEN];
char npass[MAX_PASS_LEN];
printf("Enter 16-Character Transfer Key: ");
scanf("%18s", tkey);
printf("Set password for this PC: ");
read_masked_password(npass, sizeof(npass));
account_import_transfer_key(&g_current_account, tkey, npass);
} else if (option == 0) {
platform_cleanup();
return 0;
}
}
int game_choice = -1;
while (game_choice != 0) {
clear_screen();
printf("===================================================\n");
printf(" ASSEMBLER CASINO - Logged in: %s ($%llu)\n", g_current_account.username, (unsigned long long)g_current_account.bank_balance);
printf("===================================================\n");
printf("1. Umamusume Скачки\n");
printf("2. Online P2P Lobby & Cloud Sync (Host/Join/Password)\n");
printf("0. Exit\n");
printf("Choice: ");
if (scanf("%d", &game_choice) != 1) break;
if (game_choice == 1) {
play_umamusume(&g_current_account);
} else if (game_choice == 2) {
net_lobby_menu(&g_current_account);
}
}
platform_cleanup();
return 0;
}