디스코드 미니게임 상점이 명령어마다 초기화되는 문제 해결법

Q&A 아카이브2026년 9월 3일·메시지 77

원본 디스코드 대화 기록 (77개 메시지)

질문자08. 04. PM 01:03

상점이 12시간마다 초기화되는 기능을 만들고싶은데 자꾸 명령어 입력할때마다 바껴버립니다.코딩은 Acode앱으로 하고있어요

용감한 올빼미08. 04. PM 01:06

어떤게 바뀌어요?

용감한 올빼미08. 04. PM 01:07

언어는 어떤거 쓰시나요

용감한 올빼미08. 04. PM 01:07

@유저

질문자08. 04. PM 01:16

코드를 차라리 보내드릴게요

질문자08. 04. PM 01:18

const fs = require("fs");

const { Client, GatewayIntentBits, REST, Routes, SlashCommandBuilder } = require("discord.js");

const express = require("express");

process.on("unhandledRejection", console.error); process.on("uncaughtException", console.error);

// 플레이어 저장 공간 const players = new Map();

// ===================== // 🛒 상점 시스템 // =====================

const swords = {

// 일반 "나무 검": { grade: "일반", power: 50, price: 10 },

"훈련용 검": { grade: "일반", power: 100, price: 25 },

"낡은 돌 검": { grade: "일반", power: 150, price: 40 },

// 고급 "녹슨 철 검": { grade: "고급", power: 250, price: 50 },

"철검": { grade: "고급", power: 400, price: 100 },

"강철 검": { grade: "고급", power: 600, price: 300 },

// 희귀 "빙결의 검": { grade: "희귀", power: 1000, price: 1000 },

"붉은 달의 검": { grade: "희귀", power: 1500, price: 3000 },

"심해의 검": { grade: "희귀", power: 2200, price: 7000 },

// 영웅 "용기사의 검": { grade: "영웅", power: 3000, price: 10000 },

"화염의 검": { grade: "영웅", power: 4500, price: 30000 },

"폭풍의 검": { grade: "영웅", power: 6000, price: 70000 },

// 전설 "태양의 성검": { grade: "전설", power: 10000, price: 100000 },

"황혼의 검": { grade: "전설", power: 15000, price: 300000 },

"천뢰의 검": { grade: "전설", power: 22000, price: 700000 },

// 신화 "창세의 검": { grade: "신화", power: 30000, price: 1000000 },

"신의 검": { grade: "신화", power: 50000, price: 3000000 },

"종말의 검": { grade: "신화", power: 70000, price: 7000000 },

// 초월 "「무명의 검」": { grade: "초월", power: 100000, price: 10000000 },

"「공허의 검」": { grade: "초월",

질문자08. 04. PM 01:18

power: 250000, price: 20000000 },

"「운명의 검」": { grade: "초월", power: 400000, price: 30000000 },

"「세계수의 검」": { grade: "초월", power: 650000, price: 50000000 },

"「시공의 검」": { grade: "초월", power: 999999, price: 100000000 }

};

// ===================== // 🎲 일일 상점 등급 확률 // =====================

const gradeChance = [ { grade: "일반", chance: 55 },

{ grade: "고급", chance: 25 },

{ grade: "희귀", chance: 12 },

{ grade: "영웅", chance: 5 },

{ grade: "전설", chance: 2 },

{ grade: "신화", chance: 0.9 },

{ grade: "초월", chance: 0.1 } ];

// ===================== // 📅 일일 상점 데이터 // =====================

let dailyShop = []; let lastShopUpdate = 0;

const SHOP_RESET_TIME = 12 * 60 * 60 * 1000;

const shopFile = "./shop.json"; loadShop();

function loadShop() {

if (fs.existsSync(shopFile)) {

const data = JSON.parse(
  fs.readFileSync(shopFile)
);

dailyShop = data.dailyShop || [];
lastShopUpdate = data.lastShopUpdate || 0;

console.log("상점 데이터 불러오기 완료");

}

}

function saveShop() {

fs.writeFileSync( shopFile, JSON.stringify({ dailyShop, lastShopUpdate }, null, 2) );

}

function updateDailyShop() {

const now = Date.now();

if (now - lastShopUpdate < SHOP_RESET_TIME) { return; }

dailyShop = [];

while (dailyShop.length < 3) {

// 등급 뽑기
const roll = Math.random() * 100;

let total = 0;
let selectedGrade = "";

for (const grade of gradeChance) {

  total += grade.chance;

  if (roll <= total) {
    selectedGrade =
질문자08. 04. PM 01:18

grade.grade; break; }

}

// 해당 등급 검 목록
const candidates = Object.entries(swords)
  .filter(([name, data]) => data.grade === selectedGrade);


if (candidates.length > 0) {

  const item = candidates[
    Math.floor(Math.random() * candidates.length)
  ];

  // 중복 방지
  if (!dailyShop.some(x => x[0] === item[0])) {
    dailyShop.push(item);
  }

}

}

lastShopUpdate = now; saveShop(); }

// Render용 웹 서버 const app = express();

app.get("/", (req, res) => { res.send("Bot is running!"); });

app.listen(process.env.PORT || 3000, () => { console.log("웹 서버 실행됨"); });

// 디스코드 봇 설정 const client = new Client({ intents: [GatewayIntentBits.Guilds] });

// Render 환경 변수 const token = process.env.TOKEN;

// Discord Developer Portal → General Information → Application ID const clientId = "1533924586989686784";

// 명령어 목록 const commands = [ new SlashCommandBuilder() .setName("가입") .setDescription("검 키우기에 가입합니다.") .toJSON(),

new SlashCommandBuilder() .setName("프로필") .setDescription("내 프로필을 확인합니다.") .toJSON(),

new SlashCommandBuilder() .setName("상점") .setDescription("검 상점을 확인합니다.") .toJSON(),

new SlashCommandBuilder() .setName("구매") .setDescription("검을 구매합니다.") .addIntegerOption(option => option .setName("번호") .setDescription("상점에 표시된 검 번호") .setRequired(true) ) .toJSON() ];

const rest = new REST({ version: "10" }).setToken(token);

질문자08. 04. PM 01:18

}

players.set(userId, {
  id: userId,
  name: interaction.user.username,
질문자08. 04. PM 01:18

level:0, exp: 0,

  gold: 1000000000,

  sword: {
    name: "나무 몽둥이",
    grade: "일반",
    enhance: 1,
    power: 3
  },

  pvp: {
    win: 0,
    lose: 0
  }
});


await interaction.reply(

`⚔️ 검 키우기 가입 완료!

플레이어: ${interaction.user.username}

🪵 장착: 나무 몽둥이 ⚪ 등급: 일반 💰 보유 골드: 1000000000` ); return; }

// 구매 if (interaction.commandName === "구매") {

const userId = interaction.user.id;

if (!players.has(userId)) { return interaction.reply("먼저 /가입 해주세요!"); return; }

updateDailyShop();