← 모듈 공장 리스트

무작위 노예 생성0316

risum 모듈 — RISU modules[] — 기능 확장

🗒️ 제작자 게시글

자작봇원문 보기 ↗

조회 2038 · 2026-03-15

제작자 의도 — 본문 전문 (554자)
안녕하세요.
텍스트 웹게임 프리시티즈를 구현하려는 노예 경영 세계관 봇입니다.
잭오나인테일 설정도 적절히 섞어서 취향껏 만들었습니다.
상태창과 무작위 노예생성 모듈이 포함되어 있으니 같이 받아서 즐겨보세요.
해당 봇은 테스트 버전 입니다.
모든 제작은 슈바봇과 라보엔으로 했습니다.
구현하고 싶은것
1. 내부 경제 시스템
2. 구체적인 세계관 정리
다운로드 리수낼름
https://realm.risuai.net/character/bb6a5de0-d265-4ef0-858a-0e5f80768d2e
전용모듈 프로톤
https://drive.proton.me/urls/FAMMSRETXG#Qq0lTuNbNhRv
모듈 업데이트
3/16 상태창 하부에 부동산 및 건물 ui 추가 + 내 관리창 내부 기능 추가 및 대략적인 설정
봇제작 툴
슈바봇
https://arca.live/b/characterai/161042336
모듈제작 툴
라보엔
https://arca.live/b/characterai/163811916
ps. 어라 모듈 링크 잘못 걸어서 다른 모듈을 올렸네요 아이고;;
다시 올렸습니다.

정체

📚 설정·지식 자료기술분류 LORE슬롯 lore무작위 노예 생성
파싱된 모듈 전체 (66,179자)
{
 "name": "무작위 노예 생성",
 "description": "",
 "id": "968ed361-3225-4472-8a9b-12118222cca7",
 "hideIcon": false,
 "customModuleToggle": "=노예 생성기=group\nrandom-slave.mode=모드=select=끄기,메인,보조\nrandom-slave.lazy=발동=select=즉시,누르면\nrandom-slave.autoUpdate=로어북 자동 업데이트=select=누르면 동작,즉시\nrandom-slave.defaultOpen=결과창 기본 상태=select=펼쳐두기,접어두기\nrandom-slave.context=메인 모델에게 내용 숨기기=select=아니오 (기본),예\nrandom-slave.price=가격대=select=매우저렴,저렴,보통,비쌈,매우비쌈\nrandom-slave.difficulty=난이도=select=쉬움,보통,어려움\nrandom-slave.count=생성 인원수=text\nrandom-slave.moneyVar=자금 연동 변수명 (상태창 변수)=text\nrandom-slave.customReq=세부 요청사항=text\nrandom-slave.cheat=치트 (확정 특수 개체)\nrandom-slave.includeUser=로어북에 주인(user) 포함=select=포함,미포함\n=상태창 기능=divider\nrandom-slave.statusWindow=상태창 출력=select=끄기,켜기\n==groupEnd",
 "trigger": [
  {
   "comment": "",
   "type": "start",
   "conditions": [],
   "effect": [
    {
     "type": "triggerlua",
     "code": "local triggerId = ''\n\nlocal predefinedFacilities = {\n  [\"펜트하우스\"] = {\n    { id = \"ph_ai\", name = \"AI 홀로그램\", cost = 0, default = true, upgrades = {} },\n    { id = \"ph_prison\", name = \"감옥\", cost = 5000, upgrades = {} },\n    { id = \"ph_armory\", name = \"무기고 (호위)\", cost = 10000, upgrades = {} },\n    { id = \"ph_spa\", name = \"스파 (정신건강)\", cost = 8000, upgrades = {} },\n    { id = \"ph_clinic\", name = \"간이 진료소 (건강)\", cost = 7000, upgrades = {} },\n    { id = \"ph_class\", name = \"교실 (지능 및 지식)\", cost = 6000, upgrades = {} },\n    { id = \"ph_office\", name = \"노예장 휴게실 및 관리자 집무실\", cost = 15000, req = \"loyalty\", upgrades = {} }\n  },\n  [\"특수 시설\"] = {\n    { id = \"sp_brothel\", name = \"사창가\", cost = 12000, upgrades = {} },\n    { id = \"sp_farm\", name = \"우유 목장\", cost = 15000, upgrades = {\n      { id = \"up_auto_feed\", name = \"자동 먹이 배급기\", cost = 5000 },\n      { id = \"up_auto_mill\", name = \"자동 유축기\", cost = 8000 }\n    } },\n    { id = \"sp_colosseum\", name = \"콜로세움\", cost = 20000, upgrades = {} }\n  },\n  [\"주거 및 상업 시설\"] = {\n    { id = \"re_low\", name = \"저소득층 및 중산층 임대용\", cost = 5000, upgrades = {} },\n    { id = \"re_high\", name = \"고소득층 및 백만장자용 호화 인테리어\", cost = 25000, upgrades = {} }\n  },\n  [\"시장 및 오락 시설\"] = {\n    { id = \"ma_arcade\", name = \"아케이드 (최하급 노예 및 퍽돌)\", cost = 8000, upgrades = {} },\n    { id = \"ma_butcher\", name = \"정육점 (인육 가공품)\", cost = 6000, upgrades = {} },\n    { id = \"ma_boutique\", name = \"양장품점 및 옷가게\", cost = 7000, upgrades = {} },\n    { id = \"ma_pub\", name = \"우유 판매점 및 술집\", cost = 9000, upgrades = {} }\n  },\n  [\"지하 암시장 및 유지 시설\"] = {\n    { id = \"ug_merc\", name = \"계약 용병단\", cost = 15000, upgrades = {} },\n    { id = \"ug_shop\", name = \"수상한 가게\", cost = 10000, upgrades = {} },\n    { id = \"ug_cult\", name = \"종교 단체\", cost = 8000, upgrades = {} },\n    { id = \"ug_clinic\", name = \"불법 시술실\", cost = 12000, upgrades = {} },\n    { id = \"ug_drug\", name = \"마약 거래소\", cost = 20000, upgrades = {} },\n    { id = \"ug_crime\", name = \"범죄 단체\", cost = 18000, upgrades = {} },\n    { id = \"ug_maint\", name = \"콜로니 유지보수 기계실\", cost = 30000, upgrades = {} }\n  }\n}\n\nlocal function setTriggerId(tid)\n  triggerId = tid\n  if type(prelude) ~= 'nil' then return end\n  local source = getLoreBooks(triggerId, 'lightboard-prelude')\n  if not source or #source == 0 then\n    error('Failed to load lightboard-prelude.')\n  end\n  load(source[1].content, '@prelude', 't')()\nend\n\nlocal function toHex(str)\n  return (str:gsub('.', function (c)\n    return string.format('%02x', string.byte(c))\n  end))\nend\n\nlocal function fromHex(str)\n  return (str:gsub('..', function (cc)\n    return string.char(tonumber(cc, 16))\n  end))\nend\n\nlocal function getUserMoney(tid, userObj)\n  local mVar = getGlobalVar(tid, 'toggle_random-slave.moneyVar')\n  if mVar and mVar ~= \"\" then\n    local v = getChatVar(tid, mVar)\n    return tonumber(v) or 0\n  end\n  return tonumber(userObj.money) or 0\nend\n\nlocal function setUserMoney(tid, userObj, amount)\n  local mVar = getGlobalVar(tid, 'toggle_random-slave.moneyVar')\n  if mVar and mVar ~= \"\" then\n    setChatVar(tid, mVar, tostring(amount))\n  else\n    userObj.money = amount\n  end\nend\n\nlocal function numToTier5(val, t1, t2, t3, t4, t5)\n  local n = tonumber(val)\n  if not n then return tostring(val) end\n  if n <= -600 then return t1 end\n  if n <= -200 then return t2 end\n  if n <= 200 then return t3 end\n  if n <= 600 then return t4 end\n  return t5\nend\n\nlocal function displayStat(key, val)\n  if key == 'beauty' then return numToTier5(val, \"끔찍함\", \"못생김\", \"평범\", \"예쁨\", \"극상\") end\n  if key == 'sexualSkill' then return numToTier5(val, \"최하\", \"하\", \"중\", \"상\", \"최상\") end\n  if key == 'intelligence' then return numToTier5(val, \"정신이 나감\", \"멍청함\", \"평범함\", \"총명함\", \"천재\") end\n  if key == 'health' then return numToTier5(val, \"죽기직전\", \"허약함\", \"평범\", \"건강함\", \"활력이 넘침\") end\n  if key == 'combat' then return numToTier5(val, \"약골\", \"약함\", \"평범\", \"강함\", \"대장\") end\n  if key == 'loyalty' then\n    local n = tonumber(val)\n    if not n then return tostring(val or \"?\") end\n    if n <= -715 then return \"증오\" end\n    if n <= -429 then return \"반항적\" end\n    if n <= -143 then return \"저항\" end\n    if n <= 142 then return \"수동적\" end\n    if n <= 428 then return \"순응\" end\n    if n <= 714 then return \"신뢰\" end\n    return \"헌신\"\n  end\n  return tostring(val or \"?\")\nend\n\nlocal function calculateCurrentPrice(slave)\n  local ip = tonumber(slave.initial_price)\n  if not ip then ip = tonumber(string.match(tostring(slave.price or \"0\"), \"%d+\")) or 300 end\n  \n  local function getOrig(key)\n    if slave[\"orig_\" .. key] ~= nil then return tonumber(slave[\"orig_\" .. key]) or 0 end\n    return tonumber(slave[key]) or 0\n  end\n  \n  local d_be = (tonumber(slave.beauty) or 0) - getOrig(\"beauty\")\n  local d_ss = (tonumber(slave.sexualSkill) or 0) - getOrig(\"sexualSkill\")\n  local d_ly = (tonumber(slave.loyalty) or 0) - getOrig(\"loyalty\")\n  local d_hl = (tonumber(slave.health) or 0) - getOrig(\"health\")\n  local d_in = (tonumber(slave.intelligence) or 0) - getOrig(\"intelligence\")\n  local d_cb = (tonumber(slave.combat) or 0) - getOrig(\"combat\")\n\n  local delta = (d_be * 0.5) + (d_ss * 0.6) + (d_ly * 0.3) + (d_hl * 0.4) + (d_in * 0.2) + (d_cb * 0.1)\n  local cp = math.floor(ip + delta)\n  return cp > 10 and cp or 10\nend\n\nlocal function syncFacHtml(tid)\n  local facStateSuccess, facilities = pcall(getState, tid, 'rs_owned_facilities')\n  if not facStateSuccess or type(facilities) ~= 'table' then facilities = {} end\n  \n  local zones = { \"펜트하우스\", \"특수 시설\", \"주거 및 상업 시설\", \"시장 및 오락 시설\", \"지하 암시장 및 유지 시설\" }\n  local counts = { [\"펜트하우스\"] = 0, [\"특수 시설\"] = 0, [\"주거 및 상업 시설\"] = 0, [\"시장 및 오락 시설\"] = 0, [\"지하 암시장 및 유지 시설\"] = 0 }\n  \n  for _, f in ipairs(facilities) do\n     if counts[f.category] ~= nil then counts[f.category] = counts[f.category] + 1 end\n  end\n  \n  local html = '<details class=\"random-slave-fac-section\"><summary>🏢 콜로니 부동산 및 건축 현황</summary><div class=\"random-slave-fac-track\">'\n  for _, z in ipairs(zones) do\n     local statusText = counts[z] > 0 and ('시설 ' .. counts[z] .. '개') or '시설 없음'\n     html = html .. '<button type=\"button\" class=\"random-slave-fac-zone active\" style=\"outline:none; cursor:pointer; font-family:inherit; color:inherit; text-align:center;\" risu-btn=\"rs-fac-info__' .. z .. '\">'\n     html = html .. '<div class=\"random-slave-fac-zone-title\">' .. z .. '</div>'\n     html = html .. '<div class=\"random-slave-fac-zone-status\">' .. statusText .. '</div>'\n     html = html .. '</button>'\n  end\n  html = html .. '</div></details>'\n  \n  local oldHtml = getChatVar(tid, 'rs_fac_html')\n  if oldHtml ~= html then\n     setChatVar(tid, 'rs_fac_html', html)\n  end\nend\n\nlocal function syncPromptText(tid)\n  local stateSuccess, owned = pcall(getState, tid, 'rs_owned_slaves')\n  if not stateSuccess or type(owned) ~= 'table' then owned = {} end\n  \n  local fStateSucc, facilities = pcall(getState, tid, 'rs_owned_facilities')\n  if not fStateSucc or type(facilities) ~= 'table' then facilities = {} end\n\n  local uStateSucc, userObj = pcall(getState, tid, 'rs_user_data')\n  if not uStateSucc or type(userObj) ~= 'table' then userObj = {} end\n  \n  local cMoney = getUserMoney(tid, userObj)\n  \n  local pName = getPersonaName(tid)\n  if not pName or pName == \"\" then pName = userObj.name or \"주인\" end\n\n  local bg = userObj.background\n  local pDesc = getPersonaDescription(tid)\n  if (not bg or bg == \"알 수 없음\" or bg == \"\") and pDesc and pDesc ~= \"\" then\n    bg = pDesc\n  else\n    bg = bg or \"알 수 없음\"\n  end\n\n  local text = \"\"\n  text = text .. \"\\n[현재 주인(\" .. pName .. \")의 상태]\\n\"\n  text = text .. \"- 성별: \" .. (userObj.gender or \"?\") .. \", 나이: \" .. (userObj.age and tostring(userObj.age) or \"?\") .. \"\\n\"\n  text = text .. \"- 보유 자금: ₮\" .. cMoney .. \"\\n\"\n  text = text .. \"- 신체 및 외형: \" .. (userObj.appearance or \"?\") .. \" (\" .. (userObj.height or \"?\") .. \" / \" .. (userObj.weight or \"?\") .. \")\\n\"\n  text = text .. \"- 가슴: \" .. (userObj.breasts or \"?\") .. \"\\n\"\n  text = text .. \"- 성기: \" .. (userObj.genitals or \"?\") .. \"\\n\"\n  text = text .. \"- 아름다움: \" .. (userObj.beauty or \"?\") .. \", 성적기술: \" .. (userObj.sexualSkill or \"?\") .. \"\\n\"\n  text = text .. \"- 지능: \" .. (userObj.intelligence or \"?\") .. \", 건강: \" .. (userObj.health or \"?\") .. \", 전투: \" .. (userObj.combat or \"?\") .. \"\\n\"\n  text = text .. \"- 특기: \" .. (userObj.skills or \"없음\") .. \"\\n\"\n  text = text .. \"- 배경: \" .. bg .. \"\\n\"\n  text = text .. \"- 현재 상태: \" .. (userObj.status or \"특이사항 없음\") .. \"\\n\"\n\n  if #facilities > 0 then\n    text = text .. \"\\n[보유 중인 콜로니 내부 시설]\\n\"\n    for i, fac in ipairs(facilities) do\n      local ups = \"\"\n      if fac.upgradeNames and #fac.upgradeNames > 0 then\n        ups = \" (업그레이드: \" .. table.concat(fac.upgradeNames, \", \") .. \")\"\n      end\n      text = text .. \"- \" .. (fac.name or \"무명\") .. \" (구역: \" .. (fac.category or \"?\") .. \", 총 비용: ₮\" .. (fac.cost or 0) .. \")\" .. ups .. \"\\n\"\n    end\n  end\n\n  if #owned > 0 then\n    text = text .. \"\\n[소유 중인 노예 목록]\\n\"\n    for i, slave in ipairs(owned) do\n      local sName = slave.name or \"무명\"\n      if slave.isSpecial == true or slave.isSpecial == \"true\" then sName = sName .. \" ✨ (특수 개체)\" end\n      local cp = calculateCurrentPrice(slave)\n      text = text .. i .. \". \" .. sName .. \" - 예상 객단가: ₮\" .. cp .. \"\\n\"\n      text = text .. \"  성별: \" .. (slave.gender or \"?\") .. \", 나이: \" .. (slave.age and tostring(slave.age) or \"?\") .. \"\\n\"\n      text = text .. \"  신체/외형: \" .. (slave.appearance or \"?\") .. \" (\" .. (slave.height or \"?\") .. \" / \" .. (slave.weight or \"?\") .. \")\\n\"\n      text = text .. \"  아름다움:\" .. (slave.beauty or \"?\") .. \" 충성도:\" .. (slave.loyalty or \"?\") .. \" 성적기술:\" .. (slave.sexualSkill or \"?\") .. \" 순결:\" .. (slave.virginity or \"?\") .. \"\\n\"\n      text = text .. \"  건강:\" .. (slave.health or \"?\") .. \" 지능:\" .. (slave.intelligence or \"?\") .. \" 전투:\" .. (slave.combat or \"?\") .. \"\\n\"\n      text = text .. \"  역할: \" .. (slave.job or \"미지정(룰에 의한 자동 배정)\") .. \" / 상태: \" .. (slave.status or \"특이사항 없음\") .. \"\\n\"\n    end\n  end\n\n  text = text .. \"\\n[노예 기본 작업 및 역할 규칙]\\n따로 지시가 없는 노예는 다음 규칙에 따라 알아서 작업을 수행해.\\n- 일반 작업: 성적 노리게(주인에게 봉사), 하급노예(다른 노예들에게 성적 봉사), 하녀(펜트하우스 내 요리, 가사노동), 창녀(외부 매춘 활동, 효율 낮고 위험함), 교육(긍정적 특성/지능 상승, 지능이 낮으면 효율 낮음), 감금(특별한 죄나 벌받을 일 없으면 무효), 자유행동(일정 충성도/헌신도 필요, 자율 행동)\\n- 상위 노예(높은 충성도 및 헌신도 필요, 관리자 지정에 의한 관리직): 노예 감독관, 간호원장, 하녀장, 젖소관리인, 선생님, 교도관, 개인경호원, 매춘굴 마담, 노예 인사관리자, 스파 관리인, AV영상 감독\\n\"\n\n  text = text .. \"\\n[시스템 지침]\\n노예의 상태나 역할이 변했다면 'updated_owned' 배열에 반영하고, 주인의 보유 자금이 변동되었다면 JSON 최상단에 'updated_user_money': 변경된숫자 를 포함해!\"\n  \n  local oldText = getChatVar(tid, 'rs_prompt_text')\n  if oldText ~= text then\n    setChatVar(tid, 'rs_prompt_text', text)\n  end\n  \n  syncFacHtml(tid)\n  return text\nend\n\nlocal function renderSlave(slave)\n  local hexData = toHex(json.encode(slave))\n  local displayName = slave.name or \"무명\"\n  if slave.isSpecial == true or slave.isSpecial == \"true\" then displayName = displayName .. \" ✨\" end\n\n  return h.div {\n    class = \"random-slave-card\",\n    h.div { class = \"rs-header\",\n      h.span { class = \"rs-name\", displayName },\n      h.div { class = \"rs-header-right\",\n        h.span { class = \"rs-price\", slave.price or \"₮0\" },\n        h.button { class = \"rs-btn-recruit\", risu_btn = \"rs-recruit__\" .. hexData, \"영입\" }\n      }\n    },\n    h.div { class = \"rs-body\",\n      h.div { class = \"rs-row\", h.span { class = \"rs-label\", \"나이: \" }, h.span { class = \"rs-value\", slave.age and tostring(slave.age) or \"?\" } },\n      h.div { class = \"rs-row\", h.span { class = \"rs-label\", \"성별: \" }, h.span { class = \"rs-value\", slave.gender or \"?\" } },\n      h.div { class = \"rs-row\", h.span { class = \"rs-label\", \"신체: \" }, h.span { class = \"rs-value\", (slave.height or \"?\") .. \" / \" .. (slave.weight or \"?\") } },\n      h.div { class = \"rs-row\", h.span { class = \"rs-label\", \"외형: \" }, h.span { class = \"rs-value\", slave.appearance or \"?\" } },\n      h.div { class = \"rs-row\", h.span { class = \"rs-label\", \"가슴: \" }, h.span { class = \"rs-value\", slave.breasts or \"?\" } },\n      h.div { class = \"rs-row\", h.span { class = \"rs-label\", \"성기: \" }, h.span { class = \"rs-value\", slave.genitals or \"?\" } },\n      h.div { class = \"rs-row\", h.span { class = \"rs-label\", \"순결: \" }, h.span { class = \"rs-value\", slave.virginity or \"?\" } },\n      h.hr {},\n      h.div { class = \"rs-row\", h.span { class = \"rs-label\", \"아름다움: \" }, h.span { class = \"rs-value\", displayStat('beauty', slave.beauty) } },\n      h.div { class = \"rs-row\", h.span { class = \"rs-label\", \"성적 기술: \" }, h.span { class = \"rs-value\", displayStat('sexualSkill', slave.sexualSkill) } },\n      h.div { class = \"rs-row\", h.span { class = \"rs-label\", \"충성도/헌신도: \" }, h.span { class = \"rs-value\", displayStat('loyalty', slave.loyalty) } },\n      h.div { class = \"rs-row\", h.span { class = \"rs-label\", \"지능: \" }, h.span { class = \"rs-value\", displayStat('intelligence', slave.intelligence) } },\n      h.div { class = \"rs-row\", h.span { class = \"rs-label\", \"건강: \" }, h.span { class = \"rs-value\", displayStat('health', slave.health) } },\n      h.div { class = \"rs-row\", h.span { class = \"rs-label\", \"전투력: \" }, h.span { class = \"rs-value\", displayStat('combat', slave.combat) } },\n      h.hr {},\n      h.div { class = \"rs-section-title\", \"특기 및 기술\" },\n      h.div { class = \"rs-desc\", slave.skills or \"-\" },\n      h.div { class = \"rs-section-title\", \"과거 배경\" },\n      h.div { class = \"rs-desc\", slave.background or \"-\" },\n      h.div { class = \"rs-section-title\", \"현재 상태\" },\n      h.div { class = \"rs-desc\", slave.status or \"특이사항 없음\" }\n    }\n  }\nend\n\nlocal function render(tid, node)\n  local rawContent = node.content\n  if rawContent == \"\" then return \"\" end\n\n  local success, parsed = pcall(json.decode, rawContent)\n  if not success then return \"\" end\n\n  local slaves = parsed.slaves\n  if not slaves or type(slaves) ~= \"table\" then return \"\" end\n\n  local cards = {}\n  for i = 1, #slaves do table.insert(cards, renderSlave(slaves[i])) end\n\n  local defaultOpenState = getGlobalVar(tid, 'toggle_random-slave.defaultOpen')\n  local isOpen = defaultOpenState ~= '1'\n\n  return tostring(h.details {\n    class = \"random-slave-container\", open = isOpen and true or nil,\n    h.summary { class = \"rs-titlebar\", h.span { \"무작위 노예 매물\" },\n      h.div { class = \"rs-titlebar-actions\",\n        h.button { class = \"rs-btn-update\", risu_btn = \"lb-interaction__random-slave__preserve;immediate#UpdateOwned\", type = \"button\", h.span { \"✓\" } },\n        h.button { class = \"rs-btn-manage\", risu_btn = \"rs-manage-owned\", type = \"button\", \"내 관리창\" },\n        h.button['lb-reroll'] { risu_btn = 'lb-reroll__random-slave', type = 'button', h.lb_reroll_icon { closed = true } }\n      }\n    },\n    h.div { class = \"rs-cards-wrapper\", table.unpack(cards) }\n  })\nend\n\nlocal function main(tid, data)\n  if not data or data == '' then return '' end\n  local extractionSuccess, extractionResult = pcall(prelude.queryNodes, 'random-slave', data)\n  local hiddenSuccess, hiddenResult = pcall(prelude.queryNodes, 'random-slave-hidden', data)\n  \n  if hiddenSuccess and hiddenResult and #hiddenResult > 0 then\n    data = data:gsub('<random%-slave%-hidden>.-</random%-slave%-hidden>', '')\n  end\n\n  if not extractionSuccess or not extractionResult or #extractionResult == 0 then return data end\n\n  local lastResult = extractionResult[#extractionResult]\n  local output = ''\n  local lastIndex = 1\n\n  for i = 1, #extractionResult do\n    local match = extractionResult[i]\n    if match.rangeStart > lastIndex then output = output .. '\\n\\n' .. data:sub(lastIndex, match.rangeStart - 1) end\n    if i == #extractionResult then output = output .. render(tid, lastResult) end\n    lastIndex = match.rangeEnd + 1\n  end\n  return output .. data:sub(lastIndex)\nend\n\nlistenEdit('editDisplay', function(tid, data, meta)\n  setTriggerId(tid)\n  if meta and meta.index ~= nil then\n    local position = meta.index - getChatLength(tid)\n    if position < -10 then return data end\n  end\n  local success, result = pcall(main, tid, data)\n  if success then return result else return data .. '<random-slave>오류: ' .. result .. '</random-slave>' end\nend)\n\nlistenEdit('editRequest', function(tid, data, meta)\n  local includeUser = getGlobalVar(tid, 'toggle_random-slave.includeUser')\n  if includeUser ~= '1' then\n    local text = syncPromptText(tid)\n\n    local targetIdx = -1\n    for i = 1, #data do\n      if data[i].role == 'system' then targetIdx = i; break end\n    end\n    if targetIdx == -1 and #data > 0 then targetIdx = 1 end\n\n    if targetIdx ~= -1 and data[targetIdx] then\n      data[targetIdx].content = data[targetIdx].content .. \"\\n\\n\" .. text\n    elseif #data == 0 then\n      table.insert(data, 1, { role = 'system', content = text })\n    end\n  end\n  return data\nend)\n\nonButtonClick = async(function(tid, code)\n  setTriggerId(tid)\n\n  local infoPrefix = 'rs-fac-info__'\n  if string.sub(code, 1, #infoPrefix) == infoPrefix then\n    local zoneName = string.sub(code, #infoPrefix + 1)\n    local facStateSuccess, facilities = pcall(getState, tid, 'rs_owned_facilities')\n    if not facStateSuccess or type(facilities) ~= 'table' then facilities = {} end\n\n    local text = \"[ \" .. zoneName .. \" 시설 현황 ]\\n\\n\"\n    local foundCount = 0\n    for _, f in ipairs(facilities) do\n      if f.category == zoneName then\n        foundCount = foundCount + 1\n        local ups = \"\"\n        if f.upgradeNames and #f.upgradeNames > 0 then\n          ups = \"\\n  └ [업그레이드: \" .. table.concat(f.upgradeNames, \", \") .. \"]\"\n        end\n        text = text .. \"- \" .. (f.name or \"?\") .. ups .. \"\\n\"\n      end\n    end\n\n    if foundCount == 0 then\n      text = text .. \"아직 이 구역에 지어진 부속 건물이 없어!\"\n    end\n\n    alertNormal(tid, text)\n    return\n  end\n\n  if code == 'lb-interaction__random-slave__preserve;immediate#UpdateOwned' then\n    local fullChat = getFullChat(tid)\n    local lastChat = fullChat[#fullChat]\n    if lastChat and lastChat.data then\n      local extractionSuccess, extractionResult = pcall(prelude.queryNodes, 'random-slave', lastChat.data)\n      if extractionSuccess and extractionResult and #extractionResult > 0 then\n        local nodeContent = extractionResult[#extractionResult].content\n        local decSuccess, parsed = pcall(json.decode, nodeContent)\n        if decSuccess and parsed then\n          local updatedMsg = \"\"\n\n          if parsed.updated_user_money ~= nil then\n            local uStateSucc, userObj = pcall(getState, tid, 'rs_user_data')\n            if not uStateSucc or type(userObj) ~= 'table' then \n              userObj = { name = getPersonaName(tid) or \"주인\", status = \"양호\", money = 0 }\n            end\n            local oldMoney = getUserMoney(tid, userObj)\n            local newMoney = tonumber(parsed.updated_user_money) or oldMoney\n            setUserMoney(tid, userObj, newMoney)\n            setState(tid, 'rs_user_data', userObj)\n            updatedMsg = updatedMsg .. \"자금 변동: ₮\" .. oldMoney .. \" -> ₮\" .. newMoney .. \"\\n(상태창 연동 완료)\\n\\n\"\n          end\n\n          if type(parsed.updated_owned) == 'table' then\n            local stateSuccess, owned = pcall(getState, tid, 'rs_owned_slaves')\n            if stateSuccess and type(owned) == 'table' then\n              local updatedCount = 0\n              for _, uSlave in ipairs(parsed.updated_owned) do\n                for _, mySlave in ipairs(owned) do\n                  if mySlave.name == uSlave.name then\n                    for k, v in pairs(uSlave) do\n                      if k ~= \"name\" then mySlave[k] = v end\n                    end\n                    updatedCount = updatedCount + 1\n                  end\n                end\n              end\n              setState(tid, 'rs_owned_slaves', owned)\n              if updatedCount > 0 then\n                 updatedMsg = updatedMsg .. \"노예 정보 업데이트 반영 (\" .. updatedCount .. \"명)\"\n              end\n            end\n          end\n\n          if updatedMsg ~= \"\" then\n            syncPromptText(tid)\n            alertNormal(tid, updatedMsg)\n            return\n          end\n        end\n      end\n    end\n    alertNormal(tid, '적용 되었습니다!')\n  end\n\n  if code == 'rs-manage-owned' then\n    local stateSuccess, owned = pcall(getState, tid, 'rs_owned_slaves')\n    if not stateSuccess or type(owned) ~= 'table' then owned = {} end\n    \n    local uStateSucc, userObj = pcall(getState, tid, 'rs_user_data')\n    if not uStateSucc or type(userObj) ~= 'table' then \n      userObj = { name = getPersonaName(tid) or \"주인\", status = \"양호\", money = 0 }\n    end\n    \n    local cMoney = getUserMoney(tid, userObj)\n\n    local text = '[ 내 소유 노예 목록 ]\\n\\n'\n    text = text .. '(보유 자금: ₮' .. cMoney .. ')\\n\\n'\n    if #owned == 0 then text = text .. \"아직 영입한 노예가 없어!\\n\"\n    else\n      for i, slave in ipairs(owned) do\n        local sName = slave.name or \"무명\"\n        if slave.isSpecial == true or slave.isSpecial == \"true\" then sName = sName .. \" ✨\" end\n        local cp = calculateCurrentPrice(slave)\n        text = text .. i .. \". \" .. sName .. \" / \" .. (slave.gender or \"?\") .. \" / 가치: ₮\" .. cp .. \" / 역할: \" .. (slave.job or \"미지정\") .. \" / 상태: \" .. (slave.status or \"양호\") .. \"\\n\"\n      end\n    end\n    text = text .. '\\n[메뉴]\\n-2. 콜로니 부동산 시설 관리\\n-1. 주인(User) 상태 및 자금 편집\\n0. 모든 노예 삭제\\n1~' .. #owned .. '. 해당 번호 노예 관리\\n\\n확인할 번호를 입력해줘! (닫으려면 취소)'\n\n    local targetIdxStr = alertInput(tid, text):await()\n    if not targetIdxStr or targetIdxStr == '' then return end\n    local targetIdx = tonumber(targetIdxStr)\n    if not targetIdx then alertError(tid, '제대로 된 숫자를 입력해줘!') return end\n\n    if targetIdx == -2 then\n      local facStateSuccess, facilities = pcall(getState, tid, 'rs_owned_facilities')\n      if not facStateSuccess or type(facilities) ~= 'table' then facilities = {} end\n\n      local hasAI = false\n      for _, f in ipairs(facilities) do if f.id == \"ph_ai\" then hasAI = true break end end\n      if not hasAI then\n        table.insert(facilities, { id = \"ph_ai\", name = \"AI 홀로그램\", category = \"펜트하우스\", cost = 0, upgrades = {}, upgradeNames = {} })\n        setState(tid, 'rs_owned_facilities', facilities)\n      end\n\n      local menuText = '[ 콜로니 부동산 관리 ]\\n현재 자금: ₮' .. cMoney .. '\\n\\n'\n      if #facilities == 0 then\n        menuText = menuText .. \"건설된 시설이 없어!\\n\\n\"\n      else\n        for i, f in ipairs(facilities) do\n          local ups = \"\"\n          if f.upgradeNames and #f.upgradeNames > 0 then\n            ups = \" [업그레이드: \" .. table.concat(f.upgradeNames, \", \") .. \"]\"\n          end\n          menuText = menuText .. i .. \". \" .. (f.name or \"?\") .. \" (\" .. (f.category or \"?\") .. \")\" .. ups .. \"\\n\"\n        end\n        menuText = menuText .. \"\\n\"\n      end\n      menuText = menuText .. \"[ 관리 작업 선택 ]\\n1. 펜트하우스 건설\\n2. 특수 시설 건설\\n3. 주거 및 상업 시설 건설\\n4. 시장 및 오락 시설 건설\\n5. 지하 암시장 및 유지 시설 건설\\n6. 지어진 시설 업그레이드\\n7. 지어진 시설 철거\\n원하는 번호를 입력해! (돌아가려면 빈칸)\"\n\n      local action = alertInput(tid, menuText):await()\n      if not action or action == '' then return end\n      \n      if action == '7' then\n        if #facilities == 0 then alertError(tid, '철거할 시설이 없어!') return end\n        local delIdxStr = alertInput(tid, '철거할 시설의 번호를 입력해! (1~' .. #facilities .. ')'):await()\n        local delIdx = tonumber(delIdxStr)\n        if delIdx and delIdx >= 1 and delIdx <= #facilities then\n          if facilities[delIdx].id == \"ph_ai\" then alertError(tid, 'AI 홀로그램은 철거할 수 없어!') return end\n          local fName = facilities[delIdx].name\n          table.remove(facilities, delIdx)\n          setState(tid, 'rs_owned_facilities', facilities)\n          syncPromptText(tid)\n          alertNormal(tid, '[' .. fName .. '] 철거 완료!')\n        else\n          alertError(tid, '잘못된 번호야!')\n        end\n        return\n      end\n      \n      if action == '6' then\n         if #facilities == 0 then alertError(tid, '업그레이드할 시설이 없어!') return end\n         local upIdxStr = alertInput(tid, '업그레이드할 시설의 번호를 입력해! (1~' .. #facilities .. ')'):await()\n         local upIdx = tonumber(upIdxStr)\n         if upIdx and upIdx >= 1 and upIdx <= #facilities then\n            local targetFac = facilities[upIdx]\n            local pre = nil\n            for _, p in ipairs(predefinedFacilities[targetFac.category]) do\n               if p.id == targetFac.id then pre = p break end\n            end\n            if not pre or not pre.upgrades or #pre.upgrades == 0 then alertError(tid, targetFac.name .. '은(는) 가능한 업그레이드가 없어!') return end\n            \n            local availUps = {}\n            targetFac.upgrades = targetFac.upgrades or {}\n            targetFac.upgradeNames = targetFac.upgradeNames or {}\n            \n            for _, u in ipairs(pre.upgrades) do\n               local hasUp = false\n               for _, ownedUp in ipairs(targetFac.upgrades) do\n                  if ownedUp == u.id then hasUp = true break end\n               end\n               if not hasUp then table.insert(availUps, u) end\n            end\n            \n            if #availUps == 0 then alertError(tid, '이미 모든 업그레이드를 완료했어!') return end\n            \n            local uMenu = \"[\" .. targetFac.name .. \" 업그레이드 목록]\\n현재 자금: ₮\" .. cMoney .. \"\\n\"\n            for i, au in ipairs(availUps) do\n               uMenu = uMenu .. i .. \". \" .. au.name .. \" (비용: ₮\" .. au.cost .. \")\\n\"\n            end\n            uMenu = uMenu .. \"원하는 업그레이드 번호를 입력해!\"\n            local uActStr = alertInput(tid, uMenu):await()\n            local uAct = tonumber(uActStr)\n            if uAct and uAct >= 1 and uAct <= #availUps then\n               local selUp = availUps[uAct]\n               if cMoney < selUp.cost then alertError(tid, '자금이 부족해!') return end\n               local finalMoney = cMoney - selUp.cost\n               setUserMoney(tid, userObj, finalMoney)\n               setState(tid, 'rs_user_data', userObj)\n               \n               table.insert(targetFac.upgrades, selUp.id)\n               table.insert(targetFac.upgradeNames, selUp.name)\n               targetFac.cost = (targetFac.cost or 0) + selUp.cost\n               setState(tid, 'rs_owned_facilities', facilities)\n               syncPromptText(tid)\n               \n               alertNormal(tid, selUp.name .. ' 업그레이드 완료!\\n비용: -₮' .. selUp.cost .. '\\n현재 자금: ₮' .. finalMoney)\n            else\n               alertError(tid, '잘못된 번호야!')\n            end\n         else\n            alertError(tid, '잘못된 번호야!')\n         end\n         return\n      end\n\n      local cat = \"\"\n      if action == '1' then cat = \"펜트하우스\"\n      elseif action == '2' then cat = \"특수 시설\"\n      elseif action == '3' then cat = \"주거 및 상업 시설\"\n      elseif action == '4' then cat = \"시장 및 오락 시설\"\n      elseif action == '5' then cat = \"지하 암시장 및 유지 시설\"\n      else alertError(tid, '잘못된 입력이야!') return end\n      \n      local available = {}\n      for _, pre in ipairs(predefinedFacilities[cat]) do\n        local already = false\n        for _, f in ipairs(facilities) do\n          if f.id == pre.id then already = true; break end\n        end\n        if not already then table.insert(available, pre) end\n      end\n\n      if #available == 0 then alertError(tid, '이 구역에 더 지을 수 있는 시설이 없어!') return end\n\n      local bMenu = \"[\" .. cat .. \" 건설 가능 목록]\\n현재 자금: ₮\" .. cMoney .. \"\\n\"\n      for i, a in ipairs(available) do\n        bMenu = bMenu .. i .. \". \" .. a.name .. \" (비용: ₮\" .. a.cost .. \")\\n\"\n      end\n      bMenu = bMenu .. \"원하는 번호를 입력해!\"\n      \n      local bActStr = alertInput(tid, bMenu):await()\n      local bAct = tonumber(bActStr)\n      \n      if not bAct or bAct < 1 or bAct > #available then\n         if (bActStr or '') ~= '' then alertError(tid, '잘못된 번호야!') end\n         return\n      end\n      \n      local selFac = available[bAct]\n      \n      if selFac.req == \"loyalty\" then\n         local confirm = alertConfirm(tid, '이 시설은 일정 이상의 헌신도 및 충성도를 가진 노예와, 관리자의 승인이 필요해.\\n정말 건설할거야?'):await()\n         if not confirm then return end\n      end\n\n      if cMoney < selFac.cost then alertError(tid, '자금이 부족해!!') return end\n\n      local finalMoney = cMoney - selFac.cost\n      setUserMoney(tid, userObj, finalMoney)\n      setState(tid, 'rs_user_data', userObj)\n\n      table.insert(facilities, { id = selFac.id, name = selFac.name, category = cat, cost = selFac.cost, upgrades = {}, upgradeNames = {} })\n      setState(tid, 'rs_owned_facilities', facilities)\n      syncPromptText(tid)\n      \n      alertNormal(tid, cat .. ' 구역에 [' .. selFac.name .. '] 매입/건설 완료!\\n비용: -₮' .. selFac.cost .. '\\n현재 자금: ₮' .. finalMoney)\n      return\n    end\n\n    if targetIdx == -1 then\n      local action = alertInput(tid, '자금을 변경할까?\\n현재자금: ₮' .. cMoney .. '\\n\\n원하는 수치를 입력해! (닫으려면 취소)'):await()\n      if action and tonumber(action) then\n         setUserMoney(tid, userObj, tonumber(action))\n         setState(tid, 'rs_user_data', userObj)\n         syncPromptText(tid)\n         alertNormal(tid, '저장 완료! (상태창 업데이트 성공)') \n      end\n      return\n    end\n\n    if targetIdx == 0 then\n      local confirm = alertConfirm(tid, '모든 노예 기록을 삭제할까?'):await()\n      if confirm then setState(tid, 'rs_owned_slaves', {}) alertNormal(tid, '삭제 완료!') syncPromptText(tid) end\n      return\n    end\n\n    if targetIdx < 1 or targetIdx > #owned then alertError(tid, '잘못된 번호!') return end\n\n    local slave = owned[targetIdx]\n    local sName = slave.name or \"무명\"\n    local cp = calculateCurrentPrice(slave)\n\n    local menuText = '[ 관리 메뉴 - ' .. sName .. ' ]\\n1. 상세 정보 확인\\n2. 역할(Rule) 지정하기\\n3. 판매 및 방출하기 (₮' .. cp .. ' 획득)\\n4. 상태 직접 수정하기\\n원하는 작업 번호를 입력해!'\n    local action = alertInput(tid, menuText):await()\n    if action == '1' then\n      local ip = tonumber(slave.initial_price)\n      if not ip then ip = tonumber(string.match(tostring(slave.price or \"0\"), \"%d+\")) or 300 end\n      local detailText = \"[ \" .. sName .. \" 상세 정보 ]\\n\\n\"\n      detailText = detailText .. \"매입 가격: ₮\" .. ip .. \" / 예상 가격: ₮\" .. cp .. \"\\n\\n\"\n      detailText = detailText .. \"나이: \" .. (slave.age and tostring(slave.age) or \"?\") .. \" / 성별: \" .. (slave.gender or \"?\") .. \"\\n\"\n      detailText = detailText .. \"신체: \" .. (slave.height or \"?\") .. \" / \" .. (slave.weight or \"?\") .. \"\\n\"\n      detailText = detailText .. \"외형: \" .. (slave.appearance or \"?\") .. \"\\n\"\n      detailText = detailText .. \"가슴: \" .. (slave.breasts or \"?\") .. \"\\n\"\n      detailText = detailText .. \"성기: \" .. (slave.genitals or \"?\") .. \"\\n\"\n      detailText = detailText .. \"순결: \" .. (slave.virginity or \"?\") .. \"\\n\\n\"\n      detailText = detailText .. \"[ 수치 스탯 ]\\n\"\n      detailText = detailText .. \"아름다움: \" .. displayStat('beauty', slave.beauty) .. \" (\" .. (slave.beauty or \"?\") .. \")\\n\"\n      detailText = detailText .. \"성적 기술: \" .. displayStat('sexualSkill', slave.sexualSkill) .. \" (\" .. (slave.sexualSkill or \"?\") .. \")\\n\"\n      detailText = detailText .. \"충성도/헌신도: \" .. displayStat('loyalty', slave.loyalty) .. \" (\" .. (slave.loyalty or \"?\") .. \")\\n\"\n      detailText = detailText .. \"지능: \" .. displayStat('intelligence', slave.intelligence) .. \" (\" .. (slave.intelligence or \"?\") .. \")\\n\"\n      detailText = detailText .. \"건강: \" .. displayStat('health', slave.health) .. \" (\" .. (slave.health or \"?\") .. \")\\n\"\n      detailText = detailText .. \"전투력: \" .. displayStat('combat', slave.combat) .. \" (\" .. (slave.combat or \"?\") .. \")\\n\\n\"\n      detailText = detailText .. \"[ 기타 정보 ]\\n\"\n      detailText = detailText .. \"특기 및 기술: \" .. (slave.skills or \"-\") .. \"\\n\"\n      detailText = detailText .. \"과거 배경: \" .. (slave.background or \"-\") .. \"\\n\"\n      detailText = detailText .. \"현재 역할: \" .. (slave.job or \"미지정\") .. \"\\n\"\n      detailText = detailText .. \"현재 상태: \" .. (slave.status or \"특이사항 없음\")\n      alertNormal(tid, detailText)\n    elseif action == '2' then\n      local rankChoice = alertInput(tid, '[ 역할 등급 선택 ]\\n1. 일반/하위 노예 역할\\n2. 상위/관리직 노예 역할\\n\\n원하는 등급 번호를 입력해!'):await()\n      if rankChoice == '1' then\n        local lowerJobs = { \"성적 노리게\", \"하급노예\", \"하녀\", \"창녀\", \"교육\", \"감금\", \"자유행동\" }\n        local lMenu = \"[ 일반/하위 노예 역할 ]\\n\"\n        for i, job in ipairs(lowerJobs) do\n          lMenu = lMenu .. i .. \". \" .. job .. \"\\n\"\n        end\n        lMenu = lMenu .. \"원하는 역할 번호를 입력해!\"\n        local lowerActStr = alertInput(tid, lMenu):await()\n        local lowerAct = tonumber(lowerActStr)\n        if lowerAct and lowerAct >= 1 and lowerAct <= #lowerJobs then\n           slave.job = lowerJobs[lowerAct]\n           setState(tid, 'rs_owned_slaves', owned)\n           syncPromptText(tid)\n           alertNormal(tid, '역할이 [' .. slave.job .. '](으)로 지정됐어!')\n        else\n           if lowerActStr and lowerActStr ~= '' then alertError(tid, '잘못된 번호야!') end\n        end\n      elseif rankChoice == '2' then\n        local upperJobs = { \"노예 감독관\", \"간호원장\", \"하녀장\", \"젖소관리인\", \"선생님\", \"교도관\", \"개인경호원\", \"매춘굴 매니저\", \"노예 인사관리자\", \"스파 관리인\", \"AV영상 감독\" }\n        local uMenu = \"[ 상위/관리직 노예 역할 ]\\n\"\n        for i, job in ipairs(upperJobs) do\n          uMenu = uMenu .. i .. \". \" .. job .. \"\\n\"\n        end\n        uMenu = uMenu .. \"원하는 역할 번호를 입력해!\"\n        local upperActStr = alertInput(tid, uMenu):await()\n        local upperAct = tonumber(upperActStr)\n        if upperAct and upperAct >= 1 and upperAct <= #upperJobs then\n           slave.job = upperJobs[upperAct]\n           setState(tid, 'rs_owned_slaves', owned)\n           syncPromptText(tid)\n           alertNormal(tid, '역할이 [' .. slave.job .. '](으)로 지정됐어!')\n        else\n           if upperActStr and upperActStr ~= '' then alertError(tid, '잘못된 번호야!') end\n        end\n      else\n        if rankChoice and rankChoice ~= '' then alertError(tid, '잘못된 입력이야!') end\n      end\n    elseif action == '3' then\n      local confirm = alertConfirm(tid, sName .. '을(를) 방출하고 ₮' .. cp .. '을(를) 얻을까?'):await()\n      if confirm then \n        table.remove(owned, targetIdx) \n        setState(tid, 'rs_owned_slaves', owned) \n        local finalMoney = cMoney + cp\n        setUserMoney(tid, userObj, finalMoney)\n        setState(tid, 'rs_user_data', userObj)\n        syncPromptText(tid)\n        alertNormal(tid, '판매 완료!\\n(+ ₮' .. cp .. ')') \n      end\n    elseif action == '4' then\n      local val = alertInput(tid, '새 상태를 입력해!\\n기존: ' .. (slave.status or '')):await()\n      if val and val ~= '' then slave.status = val setState(tid, 'rs_owned_slaves', owned) syncPromptText(tid) end\n    end\n  end\n\n  local prefix = 'rs-recruit__'\n  if string.sub(code, 1, #prefix) == prefix then\n    local hexData = string.sub(code, #prefix + 1)\n    local success, jsonStr = pcall(fromHex, hexData)\n    if not success then return end\n    \n    local decSuccess, slave = pcall(json.decode, jsonStr)\n    if decSuccess and type(slave) == 'table' then\n      local stateSuccess, owned = pcall(getState, tid, 'rs_owned_slaves')\n      if not stateSuccess or type(owned) ~= 'table' then owned = {} end\n\n      slave.status = slave.status or '특이사항 없음'\n      slave.job = '미지정 (자동 행동)'\n      slave.initial_price = tonumber(string.match(tostring(slave.price or \"0\"), \"%d+\")) or 300\n      \n      table.insert(owned, slave)\n      setState(tid, 'rs_owned_slaves', owned)\n      \n      local uStateSucc, userObj = pcall(getState, tid, 'rs_user_data')\n      if not uStateSucc or type(userObj) ~= 'table' then userObj = { money = 0 } end\n      \n      local cMoney = getUserMoney(tid, userObj)\n      local finalMoney = cMoney - slave.initial_price\n      setUserMoney(tid, userObj, finalMoney)\n      setState(tid, 'rs_user_data', userObj)\n      syncPromptText(tid)\n      \n      alertNormal(tid, (slave.name or '무명') .. ' 영입을 완료했어!\\n비용: -₮' .. slave.initial_price)\n    end\n  end\nend)\n\nonOutput = async(function(tid)\n  local toggle_status = getGlobalVar(tid, 'toggle_random-slave.statusWindow')\n  if toggle_status ~= '1' then return end\n\n  local fullChat = getFullChat(tid)\n  if not fullChat or #fullChat == 0 then return end\n  local lastChat = fullChat[#fullChat]\n  \n  if lastChat.role == 'char' and lastChat.data then\n    local moneyLine = string.match(lastChat.data, \"MONEY[^\\n]+\") or string.match(lastChat.data, \"자금[^\\n]+\")\n    if moneyLine then\n      local moneyStr = string.match(moneyLine, \"([%d,]+)\")\n      if moneyStr then\n        local moneyVal = tonumber((string.gsub(moneyStr, \",\", \"\")))\n        if moneyVal then\n          local uStateSucc, userObj = pcall(getState, tid, 'rs_user_data')\n          if not uStateSucc or type(userObj) ~= 'table' then userObj = { money = 0 } end\n          local currentMoney = getUserMoney(tid, userObj)\n          if currentMoney ~= moneyVal then\n            setUserMoney(tid, userObj, moneyVal)\n            setState(tid, 'rs_user_data', userObj)\n            syncPromptText(tid)\n          end\n        end\n      end\n    end\n  end\nend)"
    }
   ],
   "lowLevelAccess": true
  }
 ],
 "lowLevelAccess": true,
 "lorebook": [
  {
   "key": "",
   "content": "identifier=random-slave\ncharDesc=true\nauthorsNote=true\npersonaDesc=true",
   "comment": "manifest.lb",
   "alwaysActive": false,
   "secondkey": "",
   "selective": false,
   "insertorder": 100,
   "mode": "normal",
   "bookVersion": 2,
   "useRegex": false
  },
  {
   "key": "",
   "content": "{\n  \"slaves\": [\n    {\n      \"name\": \"string\",\n      \"isSpecial\": \"boolean\",\n      \"age\": \"number\",\n      \"gender\": \"string\",\n      \"height\": \"string\",\n      \"weight\": \"string\",\n      \"appearance\": \"string\",\n      \"breasts\": \"string\",\n      \"genitals\": \"string\",\n      \"virginity\": \"string\",\n      \"beauty\": \"number\",\n      \"sexualSkill\": \"number\",\n      \"loyalty\": \"number\",\n      \"intelligence\": \"number\",\n      \"health\": \"number\",\n      \"combat\": \"number\",\n      \"skills\": \"string\",\n      \"background\": \"string\",\n      \"price\": \"string\"\n    }\n  ]\n}",
   "comment": "random-slave.lb.format",
   "alwaysActive": false,
   "secondkey": "",
   "selective": false,
   "insertorder": 100,
   "mode": "normal",
   "bookVersion": 2,
   "useRegex": false
  },
  {
   "key": "",
   "content": "# Simulation Details\n\nGenerate a list of random slaves for sale based on the generation settings.\n\n## Generation Settings\n- Target quantity: {{getglobalvar::toggle_random-slave.count}} (If this is empty or not a valid number, generate exactly 1)\n- Price Tier Index: {{getglobalvar::toggle_random-slave.price}}\n  - 0: Very Cheap (0 - 1,500 ₮, unrecyclable trash, severe flaws, lowest tier)\n  - 1: Cheap (1,500 - 15,000 ₮, simple chores, low income, low tier)\n  - 2: Normal (15,000 - 100,000 ₮, standard tasks, decent income, normal tier)\n  - 3: Expensive (100,000 - 2,000,000 ₮, fully educated, high income, high tier)\n  - 4: Very Expensive (2,000,000 - 1,000,000,000 ₮, Old World export quality, highest tier)\n  * The precise price must STRICTLY fall within the range of the selected tier constraint.\n- Difficulty Index: {{getglobalvar::toggle_random-slave.difficulty}} (0: Easy - Stats are generally better, 1: Normal - Balanced, 2: Hard - Harsher outcomes).\n- Custom Request: {{getglobalvar::toggle_random-slave.customReq}}\n- Cheat Mode Active: {{getglobalvar::toggle_random-slave.cheat}}\n\n## Parameter Rules\nThe overall quality, attributes, and precise price must scale proportionally with the Price Tier Index and Difficulty Index.\n- name, age, gender, height, weight, appearance, background: Randomly generated to fit the price and difficulty.\n- isSpecial: Boolean (true/false). Decide if this slave has a mysterious background or unique secrets. 0.1% chance normally, but if Cheat Mode Active is 1, ALWAYS set this to true.\n- breasts: Describe the size and shape of breasts, nipples, and areolas. This strongly dictates the starting sexualSkill.\n- genitals: Describe the type, size, shape, and color. This strongly dictates the starting sexualSkill.\n- virginity: Choose one of [걸레, 성경험 풍부, 평범, 순수, 처녀].\n- beauty: Number between -1000 and 1000.\n- sexualSkill: Number between -1000 and 1000. Closely correlates with breasts, genitals, and virginity.\n- loyalty: Number between -1000 and 1000.\n- intelligence: Number between -1000 and 1000.\n- health: Number between -1000 and 1000. Lower values may induce diseases or STDs.\n- combat: Number between -1000 and 1000.\n- skills: Define random specific skills, traits, or '없음'. Based on story, education, or health, this can dynamically include STDs, sexual fetishes, or behavioral traits.\n- price: Precise numeric value matching the tier range. Formatted with a ₮ sign.\n\nWhen updating owned slaves, adjust these numeric values gracefully (mostly within +/- 100 per update) based on recent story events, education, or abuse. Health drops can cause STDs, which then appear dynamically in skills.\n\n{{#when::{{getglobalvar::toggle_random-slave.autoUpdate}}::==::1}}\n## Auto Update Owned Slaves\n- You MUST ALSO output `\"updated_owned\": [...]` array if any owned slave's state has changed. Update their physical/mental state, numeric stats, diseases, or skills based on the narrative.\n{{/when}}\n\n# Example\n\n```\n<random-slave>\n{\n  \"slaves\": [\n    {\n      \"name\": \"엘라\",\n      \"isSpecial\": false,\n      \"age\": 19,\n      \"gender\": \"여성\",\n      \"height\": \"162cm\",\n      \"weight\": \"51kg\",\n      \"appearance\": \"금발의 벽안과 오똑한 코\",\n      \"breasts\": \"C컵, 옅은 분홍빛의 작고 동그란 유륜과 뾰족한 유두\",\n      \"genitals\": \"여성기, 도톰한 대음순과 연분홍빛 소음순, 앙증맞은 클리토리스\",\n      \"virginity\": \"처녀\",\n      \"beauty\": 150,\n      \"sexualSkill\": -400,\n      \"loyalty\": -50,\n      \"intelligence\": 50,\n      \"health\": 600,\n      \"combat\": -300,\n      \"skills\": \"없음\",\n      \"background\": \"가난한 농부의 딸로 태어나 빚 대신 팔려옴.\",\n      \"price\": \"₮5,000\"\n    }\n  ]{{#when::{{getglobalvar::toggle_random-slave.autoUpdate}}::==::1}},\n  \"updated_owned\": [\n    { \"name\": \"유나\", \"status\": \"가혹한 훈련으로 지침\", \"health\": -150, \"loyalty\": 200, \"skills\": \"약한 불감증, 매도 페티시\" }\n  ]{{/when}}\n}\n</random-slave>\n```\n\n- Output in JSON.\n- Wrap the output in node exactly like the example.",
   "comment": "random-slave.lb",
   "alwaysActive": false,
   "secondkey": "",
   "selective": false,
   "insertorder": 100,
   "mode": "normal",
   "bookVersion": 2,
   "useRegex": false
  },
  {
   "key": "",
   "content": "Your job is to act as a slave market system generating random slave profiles. You will follow the generation settings, especially quantity and price tier, to create plausible attributes. Output strictly in the requested structured JSON format.",
   "comment": "random-slave.lb.job",
   "alwaysActive": false,
   "secondkey": "",
   "selective": false,
   "insertorder": 100,
   "mode": "normal",
   "bookVersion": 2,
   "useRegex": false
  },
  {
   "key": "",
   "content": "local triggerId = ''\nlocal function setTriggerId(tid)\n  triggerId = tid\n  if type(prelude) ~= 'nil' then return end\n  local source = getLoreBooks(triggerId, 'lightboard-prelude')\n  if source and #source > 0 then load(source[1].content, '@prelude', 't')() end\nend\n\nlocal function main(tid, output)\n  setTriggerId(tid)\n  if not string.find(output, '<random-slave', 1, true) then return nil end\n  if not string.find(output, '</random-slave>', 1, true) then output = output .. '\\n</random-slave>' end\n\n  local node = prelude.queryNodes('random-slave', output)\n  if #node > 0 then\n    local suc, parsed = pcall(json.decode, node[1].content)\n    if suc and parsed and type(parsed.updated_owned) == 'table' then\n      local stateSuc, owned = pcall(getState, tid, 'rs_owned_slaves')\n      if stateSuc and type(owned) == 'table' then\n        local changed = false\n        for _, update in ipairs(parsed.updated_owned) do\n          for _, slave in ipairs(owned) do\n            if slave.name == update.name then\n              for k, v in pairs(update) do slave[k] = v end\n              changed = true\n            end\n          end\n        end\n        if changed then setState(tid, 'rs_owned_slaves', owned) end\n      end\n      if not parsed.slaves then\n        -- Return silent block to avoid rendering empty market panel\n        return '<random-slave-hidden></random-slave-hidden>'\n      end\n    end\n  end\n\n  return prelude.removeAllNodes(output, { 'random-slave' })\nend\nreturn main",
   "comment": "random-slave.lb.onOutput",
   "alwaysActive": false,
   "secondkey": "",
   "selective": false,
   "insertorder": 100,
   "mode": "normal",
   "bookVersion": 2,
   "useRegex": false
  },
  {
   "key": "",
   "content": "local function main(tid, output)\n  local node = prelude.queryNodes('random-slave', output)\n  if #node == 0 then return end\n  local success, content = pcall(json.decode, node[1].content)\n  if not success then error('InvalidOutput: Invalid JSON format. ' .. tostring(content)) end\n  if not content.slaves and not content.updated_owned then\n    error('InvalidOutput: Missing \"slaves\" or \"updated_owned\" array.')\n  end\nend\nreturn main",
   "comment": "random-slave.lb.onValidation",
   "alwaysActive": false,
   "secondkey": "",
   "selective": false,
   "insertorder": 100,
   "mode": "normal",
   "bookVersion": 2,
   "useRegex": false
  },
  {
   "key": "",
   "content": "Your ultimate task: Update the data according to user direction. Action specifies what to do.\n\n## UpdateOwned\n\nHow to: Analyze the narrative in the recent chat log. Focus on the currently OWNED slaves (their list is provided in the system prompt). Identify changes to their physical state, mental state, loyalty, numeric stats (-1000 to +1000), or skills/diseases. Numeric changes should be gradual (+/- 100 maximum per event unless extreme) reflecting recent events. Add STDs or fetishes to skills if appropriate based on sexual events or health drops.\n\nOutput a JSON inside `<random-slave>` tag, containing an `updated_owned` array with the modified slaves. Include only the fields that have changed, along with their name.\n\nExample:\n```\n<random-slave>\n{\n  \"updated_owned\": [\n    { \"name\": \"유나\", \"status\": \"상당한 쾌락을 배움\", \"sexualSkill\": 350, \"loyalty\": 500, \"skills\": \"개발된 몸, 복종 페티시\" }\n  ]\n}\n</random-slave>\n```",
   "comment": "random-slave.lb.interaction",
   "alwaysActive": false,
   "secondkey": "",
   "selective": false,
   "insertorder": 100,
   "mode": "normal",
   "bookVersion": 2,
   "useRegex": false
  },
  {
   "key": "",
   "content": "{{#when::keep::random-slave.statusWindow::tis::1}}\n[SYSTEM DIRECTIVE: STATUS WINDOW]\nAlways start your response with the following status block for UI compatibility. Fill in the bracketed placeholders logically based on the current situation:\n\n[STATUS]\nTIME: [YYYY]-[MM]-[DD] [HH]:00 [Weather Icon]\nLOCATION: [Current Location]\nMONEY: ₮_[Amount]\nSHARE: [Number]%\nTAX: ₮_[Amount]\nTHREAT: [Threat Level: 없음/쉬움/보통/어려움/극한/불가능]\nNAME: [Threat Name or '현재 감지된 위협 없음']\nDESC: [Detailed Situation Description]\nPOP: L:[Number][Emote] | M:[Number][Emote] | H:[Number][Emote] | E:[Number][Emote]\n{{/when}}",
   "comment": "random-slave.lb.status",
   "alwaysActive": true,
   "secondkey": "",
   "selective": false,
   "insertorder": 100,
   "mode": "normal",
   "bookVersion": 2
  },
  {
   "key": "",
   "content": "{{#when::keep::random-slave.includeUser::tisnot::1}}\n{{getvar::rs_prompt_text}}\n{{/when}}",
   "comment": "random-slave.lb.universe",
   "alwaysActive": false,
   "secondkey": "",
   "selective": false,
   "insertorder": 100,
   "mode": "normal",
   "bookVersion": 2,
   "useRegex": false
  }
 ],
 "backgroundEmbedding": "<style>\n.random-slave-container {\n  display: flex;\n  flex-direction: column;\n  gap: 10px;\n  margin: 10px 0;\n  font-family: inherit;\n}\n.random-slave-container .rs-titlebar {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  background: rgba(100, 100, 100, 0.2);\n  padding: 8px 12px;\n  font-size: 1.1em;\n  border: 1px solid rgba(150, 150, 150, 0.3);\n  border-radius: 4px;\n  cursor: pointer;\n  user-select: none;\n  list-style: none;\n}\n.random-slave-container .rs-titlebar::-webkit-details-marker {\n  display: none;\n}\n.random-slave-container .rs-titlebar-actions {\n  display: flex;\n  align-items: center;\n  gap: 10px;\n}\n.random-slave-container .rs-btn-manage {\n  background: rgba(46, 204, 113, 0.8);\n  color: white;\n  border: none;\n  padding: 4px 10px;\n  border-radius: 4px;\n  cursor: pointer;\n  font-weight: bold;\n  transition: 0.2s;\n  font-size: 0.9em;\n}\n.random-slave-container .rs-btn-manage:hover {\n  background: rgba(39, 174, 96, 1);\n}\n.random-slave-container .rs-btn-update {\n  background: rgba(46, 204, 113, 0.8);\n  color: white;\n  border: none;\n  padding: 4px 10px;\n  border-radius: 4px;\n  cursor: pointer;\n  font-weight: bold;\n  transition: 0.2s;\n  font-size: 0.9em;\n  display: flex;\n  align-items: center;\n  justify-content: center;\n  width: 26px;\n}\n.random-slave-container .rs-btn-update:hover {\n  background: rgba(39, 174, 96, 1);\n}\n.random-slave-container .rs-cards-wrapper {\n  display: flex;\n  flex-direction: column;\n  gap: 15px;\n  margin-top: 5px;\n}\n.random-slave-card {\n  border: 1px solid rgba(150, 150, 150, 0.4);\n  border-radius: 4px;\n  background: rgba(0, 0, 0, 0.1);\n  padding: 15px;\n}\n.random-slave-card .rs-header {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  border-bottom: 2px solid #e74c3c;\n  padding-bottom: 8px;\n  margin-bottom: 12px;\n}\n.random-slave-card .rs-header-right {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n}\n.random-slave-card .rs-btn-recruit {\n  background: #e74c3c;\n  color: white;\n  border: none;\n  padding: 4px 10px;\n  border-radius: 4px;\n  cursor: pointer;\n  font-weight: bold;\n  transition: 0.2s;\n  font-size: 0.9em;\n}\n.random-slave-card .rs-btn-recruit:hover {\n  background: #c0392b;\n}\n.random-slave-card .rs-name {\n  font-size: 1.2em;\n}\n.random-slave-card .rs-price {\n  background: rgba(200, 150, 50, 0.3);\n  padding: 3px 6px;\n  border-radius: 4px;\n}\n.random-slave-card .rs-body {\n  display: flex;\n  flex-direction: column;\n  gap: 5px;\n  font-size: 0.95em;\n}\n.random-slave-card .rs-row {\n  display: flex;\n}\n.random-slave-card .rs-label {\n  flex: 0 0 100px;\n  opacity: 0.8;\n}\n.random-slave-card .rs-value {\n  flex: 1;\n}\n.random-slave-card hr {\n  border: 0;\n  border-top: 1px dashed rgba(150, 150, 150, 0.4);\n  margin: 10px 0;\n}\n.random-slave-card .rs-section-title {\n  margin-bottom: 4px;\n  opacity: 0.9;\n}\n.random-slave-card .rs-desc {\n  background: rgba(100, 100, 100, 0.1);\n  padding: 8px;\n  border-radius: 4px;\n  margin-bottom: 8px;\n}\n\n/* Status Window CSS Ported from Fucking World */\n.random-slave-status-container, .random-slave-status-container * { box-sizing: border-box; }\n.random-slave-status-container {\n  --t-color: #38bdf8;\n  --t-bg: rgba(56, 189, 248, 0.05);\n  --t-hdr-bg: rgba(56, 189, 248, 0.2);\n  --t-hdr-border: rgba(56, 189, 248, 0.3);\n  --t-shadow: rgba(56, 189, 248, 0.1);\n  background: #0a0a0c;\n  border: 1px solid #1e293b;\n  border-left: 4px solid var(--t-color);\n  padding: 16px;\n  border-radius: 4px;\n  font-family: 'Courier New', Courier, monospace;\n  margin: 12px 0;\n  position: relative;\n  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.9), inset 0 0 30px var(--t-shadow);\n  overflow: hidden;\n  width: 100%;\n  color: #cbd5e1;\n  text-shadow: 0 0 2px rgba(203, 213, 225, 0.3);\n\n  /* 은은한 홀로그램 숨쉬기 효과 애니메이션 적용 */\n  animation: random-slave-holo-breathe 4s ease-in-out infinite alternate;\n}\n.random-slave-status-container.threat-없음 {\n  --t-color: #94a3b8;\n  --t-bg: rgba(148, 163, 184, 0.05);\n  --t-hdr-bg: rgba(148, 163, 184, 0.15);\n  --t-hdr-border: rgba(148, 163, 184, 0.3);\n  --t-shadow: rgba(148, 163, 184, 0.05);\n}\n.random-slave-status-container.threat-쉬움 {\n  --t-color: #4ade80;\n  --t-bg: rgba(74, 222, 128, 0.05);\n  --t-hdr-bg: rgba(74, 222, 128, 0.2);\n  --t-hdr-border: rgba(74, 222, 128, 0.3);\n  --t-shadow: rgba(74, 222, 128, 0.1);\n}\n.random-slave-status-container.threat-보통 {\n  --t-color: #fbbf24;\n  --t-bg: rgba(251, 191, 36, 0.05);\n  --t-hdr-bg: rgba(251, 191, 36, 0.2);\n  --t-hdr-border: rgba(251, 191, 36, 0.3);\n  --t-shadow: rgba(251, 191, 36, 0.1);\n}\n.random-slave-status-container.threat-어려움 {\n  --t-color: #ef4444;\n  --t-bg: rgba(239, 68, 68, 0.05);\n  --t-hdr-bg: rgba(239, 68, 68, 0.2);\n  --t-hdr-border: rgba(239, 68, 68, 0.3);\n  --t-shadow: rgba(239, 68, 68, 0.15);\n}\n.random-slave-status-container.threat-극한 {\n  --t-color: #a855f7;\n  --t-bg: rgba(168, 85, 247, 0.08);\n  --t-hdr-bg: rgba(168, 85, 247, 0.25);\n  --t-hdr-border: rgba(168, 85, 247, 0.4);\n  --t-shadow: rgba(168, 85, 247, 0.2);\n}\n.random-slave-status-container.threat-불가능 {\n  --t-color: #dc2626;\n  --t-bg: rgba(220, 38, 38, 0.12);\n  --t-hdr-bg: rgba(220, 38, 38, 0.35);\n  --t-hdr-border: rgba(220, 38, 38, 0.5);\n  --t-shadow: rgba(220, 38, 38, 0.3);\n  /* 기존에 있던 불가능 난이도의 무리한 흔들림은 약하게, 혹은 유지 가능 */\n  animation: random-slave-shake 0.3s ease-in-out infinite alternate, random-slave-holo-breathe 4s ease-in-out infinite alternate;\n}\n\n/* 스캔라인과 지직거림(jitter) 효과를 완전히 제거하고\n   대신 아주 연한 파란빛 그라데이션이 은은하게 감돌게 변경 (배경 노이즈는 부드럽게) */\n.random-slave-status-container::after {\n  content: \"\";\n  position: absolute;\n  inset: 0;\n  background: radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.02), transparent 70%);\n  pointer-events: none;\n  z-index: 10;\n}\n\n/* 새로 추가한 숨쉬기 애니메이션 (그림자/빛 번짐이 부드럽게 맥동함) */\n@keyframes random-slave-holo-breathe {\n  0% {\n    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.9), inset 0 0 10px var(--t-shadow);\n    border-color: rgba(30, 41, 59, 1);\n  }\n  100% {\n    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.9), inset 0 0 40px var(--t-shadow);\n    border-color: var(--t-color);\n  }\n}\n\n.random-slave-header {\n  font-size: 0.75rem;\n  color: #64748b;\n  margin-bottom: 16px;\n  border-bottom: 1px solid #1e293b;\n  padding-bottom: 10px;\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  flex-wrap: wrap;\n  gap: 8px;\n  text-transform: uppercase;\n  letter-spacing: 1px;\n}\n.random-slave-header-right {\n  color: #94a3b8;\n  font-weight: bold;\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  text-shadow: 0 0 4px rgba(148, 163, 184, 0.4);\n}\n.random-slave-blink {\n  animation: random-slave-blink-anim 1.2s steps(2, start) infinite;\n  color: #ef4444;\n  margin-right: 6px;\n  text-shadow: 0 0 8px #ef4444;\n}\n.random-slave-main-grid {\n  display: grid;\n  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n  gap: 20px;\n}\n.random-slave-info-column {\n  display: flex;\n  flex-direction: column;\n  gap: 10px;\n}\n.random-slave-line {\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n  border-bottom: 1px dashed rgba(100, 116, 139, 0.3);\n  padding-bottom: 6px;\n  gap: 8px;\n}\n.random-slave-label {\n  color: #64748b;\n  font-size: 0.75rem;\n  font-weight: bold;\n  letter-spacing: 0.5px;\n}\n.random-slave-value {\n  color: #f8fafc;\n  font-size: 0.9rem;\n  text-align: right;\n  word-break: break-all;\n  text-shadow: 0 0 4px rgba(248, 250, 252, 0.3);\n}\n.random-slave-currency {\n  color: #fbbf24;\n  text-shadow: 0 0 8px rgba(251, 191, 36, 0.4);\n  font-weight: bold;\n  letter-spacing: 0.5px;\n}\n.random-slave-pop-column {\n  display: grid;\n  grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));\n  gap: 10px;\n}\n.random-slave-pop-item {\n  background: rgba(15, 23, 42, 0.6);\n  padding: 10px;\n  border-radius: 4px;\n  border: 1px solid rgba(51, 65, 85, 0.5);\n  display: flex;\n  flex-direction: column;\n  gap: 6px;\n  box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.5);\n}\n.random-slave-pop-label {\n  color: #64748b;\n  font-size: 0.6rem;\n  font-weight: bold;\n  white-space: nowrap;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  text-transform: uppercase;\n  letter-spacing: 0.5px;\n}\n.random-slave-pop-value {\n  color: #e2e8f0;\n  font-size: 0.85rem;\n  font-weight: bold;\n  display: flex;\n  justify-content: space-between;\n  align-items: center;\n}\n.random-slave-pop-value span:last-child {\n  font-size: 1.1rem;\n  filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.2));\n}\n.random-slave-threat-box {\n  margin-top: 20px;\n  border-radius: 4px;\n  border: 1px solid var(--t-color);\n  background: var(--t-bg);\n  display: flex;\n  flex-direction: column;\n  box-shadow: 0 0 15px var(--t-shadow);\n}\n.random-slave-threat-header {\n  padding: 10px 14px;\n  display: flex;\n  align-items: center;\n  gap: 10px;\n  background: var(--t-hdr-bg);\n  color: var(--t-color);\n  border-bottom: 1px solid var(--t-hdr-border);\n}\n.random-slave-threat-icon {\n  font-size: 1.2rem;\n  filter: drop-shadow(0 0 6px var(--t-color));\n  animation: random-slave-pulse 2s infinite;\n}\n.random-slave-threat-level {\n  font-size: 0.8rem;\n  font-weight: bold;\n  letter-spacing: 1.5px;\n  text-transform: uppercase;\n  text-shadow: 0 0 8px var(--t-color);\n}\n.random-slave-threat-content {\n  padding: 16px;\n  display: flex;\n  flex-direction: column;\n  gap: 10px;\n}\n.random-slave-threat-title {\n  font-size: 1.05rem;\n  color: #f8fafc;\n  font-weight: bold;\n  text-shadow: 0 0 10px rgba(255, 255, 255, 0.4);\n  letter-spacing: 0.5px;\n}\n.random-slave-threat-detail {\n  font-size: 0.85rem;\n  color: #94a3b8;\n  line-height: 1.6;\n  border-left: 2px solid var(--t-hdr-border);\n  padding-left: 10px;\n}\n.random-slave-footer {\n  margin-top: 16px;\n  font-size: 0.65rem;\n  color: #475569;\n  text-align: right;\n  border-top: 1px solid rgba(255, 255, 255, 0.05);\n  padding-top: 10px;\n  letter-spacing: 1px;\n  animation: random-slave-pulse 4s infinite alternate;\n}\n@keyframes random-slave-blink-anim {\n  to { visibility: hidden; }\n}\n@keyframes random-slave-pulse {\n  0%, 100% { opacity: 1; }\n  50% { opacity: 0.6; }\n}\n@keyframes random-slave-shake {\n  0% { transform: translate(0, 0); }\n  25% { transform: translate(1px, 1px); }\n  50% { transform: translate(-1px, -1px); }\n  75% { transform: translate(1px, -1px); }\n  100% { transform: translate(-1px, 1px); }\n}\n\n/* Facility Collapse Status UI */\n.random-slave-fac-section {\n  margin-top: 15px;\n  background: rgba(15, 23, 42, 0.4);\n  border: 1px solid rgba(51, 65, 85, 0.5);\n  border-radius: 4px;\n}\n.random-slave-fac-section summary {\n  padding: 8px 12px;\n  cursor: pointer;\n  font-size: 0.8rem;\n  font-weight: bold;\n  color: #94a3b8;\n  letter-spacing: 1px;\n  user-select: none;\n  background: rgba(30, 41, 59, 0.6);\n  border-bottom: 1px solid rgba(51, 65, 85, 0.3);\n}\n.random-slave-fac-section summary:hover {\n  background: rgba(30, 41, 59, 0.8);\n  color: #f8fafc;\n}\n.random-slave-fac-track {\n  display: flex;\n  flex-direction: row;\n  overflow-x: auto;\n  gap: 15px;\n  padding: 12px;\n  scrollbar-width: thin;\n  scrollbar-color: rgba(56, 189, 248, 0.5) transparent;\n}\n.random-slave-fac-track::-webkit-scrollbar {\n  height: 6px;\n}\n.random-slave-fac-track::-webkit-scrollbar-thumb {\n  background: rgba(56, 189, 248, 0.5);\n  border-radius: 4px;\n}\n.random-slave-fac-zone {\n  display: flex;\n  flex-direction: column;\n  min-width: 120px;\n  flex: 1;\n  background: rgba(15, 23, 42, 0.8);\n  border: 1px solid rgba(100, 116, 139, 0.3);\n  border-radius: 4px;\n  padding: 10px;\n  align-items: center;\n  justify-content: center;\n  text-align: center;\n  opacity: 0.5;\n  filter: grayscale(100%);\n  transition: all 0.3s ease;\n}\n.random-slave-fac-zone.active {\n  opacity: 1;\n  filter: grayscale(0%);\n  border-color: rgba(56, 189, 248, 0.5);\n  box-shadow: inset 0 0 15px rgba(56, 189, 248, 0.1);\n}\n.random-slave-fac-zone-title {\n  font-size: 0.73rem;\n  font-weight: bold;\n  color: #cbd5e1;\n  margin-bottom: 4px;\n  word-break: keep-all;\n}\n.random-slave-fac-zone-status {\n  font-size: 0.65rem;\n  color: #64748b;\n  font-weight: bold;\n}\n.random-slave-fac-zone.active .random-slave-fac-zone-status {\n  color: #38bdf8;\n  text-shadow: 0 0 4px rgba(56, 189, 248, 0.4);\n}\n</style>",
 "regex": [
  {
   "comment": "lazy-button",
   "in": "(?:<lb-lazy id=\"random-slave\"\\s*/>)\\n?",
   "out": "{{#when::{{chat_index}}::>=::{{lastmessageid}}}}\n<button risu-btn=\"lb-reroll__random-slave\">노예 목록 생성/새로고침</button>\n{{/when}}",
   "type": "editdisplay",
   "flag": "g",
   "ableFlag": true
  },
  {
   "comment": "hide-raw",
   "in": "<random-slave(?:\\s+([^>]+))?>(?:.*?)</random-slave>\\n?",
   "out": "",
   "type": "editdisplay",
   "flag": "gs",
   "ableFlag": true
  },
  {
   "comment": "exclude-from-context",
   "in": "<random-slave(?:\\s+([^>]+))?>(?:.*?)</random-slave>\\n?",
   "out": "{{#when::{{getglobalvar::toggle_random-slave.context}}::!=::1}}{{#when::{{chat_index}}::>=::{{? {{lastmessageid}}-10}}}}\n$&\n{{/when}}{{/when}}",
   "type": "editprocess",
   "flag": "gs",
   "ableFlag": true
  },
  {
   "comment": "random-slave.statusWindow",
   "in": "(?:[a-zA-Z]*\\s*)?[\\s*_#\\\\]*\\[STATUS\\][\\s\\S]*?(?:TIME|시간).*?(\\d{4})\\D+(\\d{2})\\D+(\\d{2})\\D+(\\d{2}:\\d{2})\\s+[*_]*([^\\n]+?)[*_]*\\s+(?:LOCATION|위치).*?:\\s*[*_]*([^\\n]+?)[*_]*\\s+(?:MONEY|자금).*?:\\s*[*_]*(?:₮_?\\s*)?([\\d,]+)[*_]*\\s+(?:SHARE|지분).*?:\\s*[*_]*([\\d,.]+)[*_]*(?:%)?\\s+(?:TAX|세금).*?:\\s*[*_]*(?:₮_?\\s*)?([\\d,]+)[*_]*\\s+(?:THREAT|위협).*?:\\s*[*_]*([^\\n]+?)[*_]*\\s+(?:NAME|이름).*?:\\s*[*_]*([^\\n]+?)[*_]*\\s+(?:DESC|설명).*?:\\s*[*_]*([^\\n]+?)[*_]*\\s+(?:POP|인구).*?L.*?:\\s*[*_]*([\\d,]+)\\s*([^\\s|_*]+)?[*_]*\\s*\\|\\s*M.*?:\\s*[*_]*([\\d,]+)\\s*([^\\s|_*]+)?[*_]*\\s*\\|\\s*H.*?:\\s*[*_]*([\\d,]+)\\s*([^\\s|_*]+)?[*_]*\\s*\\|\\s*E.*?:\\s*[*_]*([\\d,]+)\\s*([^\\s_*`]+)?[*_]*",
   "out": "{{#when::keep::random-slave.statusWindow::tis::1}}\n<div class=\"random-slave-status-container threat-$10\">\n  <div class=\"random-slave-header\">\n    <span><span class=\"random-slave-blink\">●</span> DAY $1.$2.$3</span>\n    <div class=\"random-slave-header-right\">$4 $5</div>\n  </div>\n  <div class=\"random-slave-main-grid\">\n    <div class=\"random-slave-info-column\">\n      <div class=\"random-slave-line\">\n        <span class=\"random-slave-label\">LOC(지역):</span>\n        <span class=\"random-slave-value\">$6</span>\n      </div>\n      <div class=\"random-slave-line\">\n        <span class=\"random-slave-label\">MONEY(자금):</span>\n        <span class=\"random-slave-value random-slave-currency\">₮ $7</span>\n      </div>\n      <div class=\"random-slave-line\">\n        <span class=\"random-slave-label\">SHARE(지분):</span>\n        <span class=\"random-slave-value\">$8%</span>\n      </div>\n      <div class=\"random-slave-line\">\n        <span class=\"random-slave-label\">TAX(세금):</span>\n        <span class=\"random-slave-value random-slave-currency\">₮ $9</span>\n      </div>\n    </div>\n    <div class=\"random-slave-pop-column\">\n      <div class=\"random-slave-pop-item\">\n        <span class=\"random-slave-pop-label\">LOW(저소득)</span>\n        <span class=\"random-slave-pop-value\"><span>$13</span><span>$14</span></span>\n      </div>\n      <div class=\"random-slave-pop-item\">\n        <span class=\"random-slave-pop-label\">MID(중산)</span>\n        <span class=\"random-slave-pop-value\"><span>$15</span><span>$16</span></span>\n      </div>\n      <div class=\"random-slave-pop-item\">\n        <span class=\"random-slave-pop-label\">HIGH(고소득)</span>\n        <span class=\"random-slave-pop-value\"><span>$17</span><span>$18</span></span>\n      </div>\n      <div class=\"random-slave-pop-item\">\n        <span class=\"random-slave-pop-label\">ELITE(백만장자)</span>\n        <span class=\"random-slave-pop-value\"><span>$19</span><span>$20</span></span>\n      </div>\n    </div>\n  </div>\n  <div class=\"random-slave-threat-box\">\n    <div class=\"random-slave-threat-header\">\n      <span class=\"random-slave-threat-icon\">⚠️</span>\n      <span class=\"random-slave-threat-level\">THREAT LEVEL: $10</span>\n    </div>\n    <div class=\"random-slave-threat-content\">\n      <div class=\"random-slave-threat-title\">$11</div>\n      <div class=\"random-slave-threat-detail\">$12</div>\n    </div>\n  </div>\n  {{getvar::rs_fac_html}}\n  <div class=\"random-slave-footer\">DATA_ENCRYPTED_BY_KERO</div>\n</div>\n{{/when}}",
   "type": "editdisplay",
   "flag": "gimsu",
   "ableFlag": true
  }
 ],
 "assets": []
}

🔗 이것과 비슷한 인기 자산

⚔️솔렌&글레차 (1)
솔렌&글레차 — Solenne & Gletscha possesses two intelligent swords named "Solenne" and "Gletscha". They freely interact with i
👍60 ·
-🔗 空条 承太郎(TS)
(3부) 쿠죠 죠타로
👍47 ·
👩_❤️_👩앨리스
made by yurrrl
👍46 ·
♦️Hoshino Ruby
호시노 루비 모듈
👍44 ·
🐞 W2 · /city/asset