roy / index.html
kimhyunwoo's picture
Update index.html
9815e43 verified
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>🚀 로이: 잘 살아낸 인생 v2.1</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css">
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #0a192f;
color: #ccd6f6;
margin: 0;
padding: 20px 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
min-height: 100vh;
overflow-x: hidden;
}
#game-container {
background-color: #112240;
border: 2px solid #64ffda;
border-radius: 10px;
padding: 25px;
width: 90%;
max-width: 800px;
box-shadow: 0 0 25px rgba(100, 255, 218, 0.4);
text-align: center;
margin-top: 20px;
}
h1 {
color: #64ffda;
font-size: 2.2em;
margin-bottom: 25px;
letter-spacing: 1px;
}
h1 i { margin-right: 10px; }
#stats-display {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
gap: 12px;
margin-bottom: 25px;
padding: 15px;
background-color: #0a192f;
border-radius: 8px;
}
.stat {
font-size: 1em;
padding: 10px;
border-radius: 5px;
background-color: #172a45;
transition: transform 0.2s ease-out, background-color 0.2s;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
text-align: center;
}
.stat i {
margin-bottom: 5px;
color: #64ffda;
font-size: 1.3em;
}
.stat span { display: block; }
.stat strong {
color: #e6f1ff;
font-weight: 600;
}
.stat-changed {
transform: scale(1.05);
background-color: #2a3f5e;
}
#event-text {
font-size: 1.2em;
margin-bottom: 30px;
line-height: 1.7;
min-height: 70px;
background-color: #0a192f;
padding: 20px;
border-radius: 8px;
border-left: 5px solid #64ffda;
text-align: left;
}
#choices-container { margin-bottom: 20px; }
#choices-container button {
background-color: #64ffda;
color: #0a192f;
border: none;
padding: 14px 22px;
margin: 8px;
border-radius: 5px;
cursor: pointer;
font-size: 1em;
transition: background-color 0.3s, transform 0.2s, box-shadow 0.2s;
font-weight: bold;
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}
#choices-container button:hover {
background-color: #52cca8;
transform: translateY(-3px);
box-shadow: 0 4px 8px rgba(0,0,0,0.3);
}
#choices-container button:active {
transform: translateY(0px);
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
}
#start-screen, #end-screen {
display: flex;
flex-direction: column;
align-items: center;
}
#start-screen button, #end-screen button, #save-button {
background-color: #64ffda;
color: #0a192f;
border: none;
padding: 12px 25px;
margin-top: 15px;
border-radius: 5px;
cursor: pointer;
font-size: 1.1em;
font-weight: bold;
transition: background-color 0.3s;
}
#start-screen button:hover, #end-screen button:hover, #save-button:hover {
background-color: #52cca8;
}
#start-screen p { margin-bottom: 20px; font-size: 1.1em; line-height: 1.6; }
#life-summary {
text-align: left;
margin-top: 15px;
margin-bottom: 20px;
padding: 15px;
background-color: #0a192f;
border-radius: 8px;
max-height: 280px;
overflow-y: auto;
border: 1px solid #233554;
font-size: 0.95em;
}
#life-summary p {
margin: 8px 0;
line-height: 1.6;
padding-bottom: 8px;
border-bottom: 1px dashed #233554;
}
#life-summary p:last-child { border-bottom: none; }
#life-summary strong { color: #64ffda; }
#life-summary small { color: #8892b0; }
.hidden { display: none !important; }
#age-bar-container {
width: 100%;
background-color: #233554;
border-radius: 8px;
margin-bottom: 25px;
height: 25px;
overflow: hidden;
box-shadow: inset 0 1px 3px rgba(0,0,0,0.3);
}
#age-bar {
width: 0%;
height: 100%;
background: linear-gradient(90deg, #64ffda, #78ffd6);
transition: width 0.5s ease-in-out;
text-align: center;
line-height: 25px;
color: #0a192f;
font-size: 0.9em;
font-weight: bold;
}
.modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgba(0,0,0,0.7);
justify-content: center;
align-items: center;
backdrop-filter: blur(3px);
}
.modal-content {
background-color: #112240;
margin: auto;
padding: 30px;
border: 1px solid #64ffda;
border-radius: 10px;
width: 80%;
max-width: 500px;
text-align: center;
box-shadow: 0 5px 15px rgba(100, 255, 218, 0.3);
color: #ccd6f6;
animation: modalAppear 0.3s ease-out;
}
@keyframes modalAppear {
from { opacity: 0; transform: scale(0.9); }
to { opacity: 1; transform: scale(1); }
}
.modal-content h3 { color: #64ffda; margin-top: 0; font-size: 1.5em;}
.modal-content p { font-size: 1.1em; line-height: 1.6; margin-bottom: 20px;}
.modal-close-button {
background-color: #64ffda;
color: #0a192f;
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
font-weight: bold;
font-size: 1em;
margin-top: 10px;
}
.modal-close-button:hover { background-color: #52cca8; }
#achievements-log-container {
margin-top: 20px;
padding: 15px;
background-color: #0a192f;
border-radius: 8px;
border: 1px solid #233554;
width: 100%;
box-sizing: border-box;
}
#achievements-log-container h3 { color: #64ffda; margin-bottom: 10px; font-size: 1.3em;}
#achievements-log-list p {
font-size: 0.95em;
margin: 8px 0;
line-height: 1.5;
color: #a8b2d1;
padding-left: 25px;
position: relative;
}
#achievements-log-list p i {
color: #64ffda;
position: absolute;
left: 0;
top: 4px;
}
#save-button i { margin-right: 8px; }
</style>
</head>
<body>
<div id="game-container">
<h1><i class="fas fa-user-astronaut"></i> 로이: 잘 살아낸 인생 v2.1</h1>
<div id="start-screen">
<p>인생은 선택의 연속입니다. 🎢<br>당신의 로이는 어떤 삶을 살게 될까요?<br>더욱 풍부해진 기능과 함께 새로운 인생을 시작해보세요! 🚀</p>
<button id="start-button"><i class="fas fa-play-circle"></i> 새 인생 시작하기</button>
<button id="load-button" class="hidden"><i class="fas fa-redo-alt"></i> 이어하기</button>
</div>
<div id="game-content" class="hidden">
<div id="stats-display">
<div class="stat" id="age-stat-container"><i class="fas fa-birthday-cake"></i><span>나이: <strong id="age-stat">0</strong></span></div>
<div class="stat" id="health-stat-container"><i class="fas fa-heartbeat"></i><span>건강: <strong id="health-stat">100</strong></span></div>
<div class="stat" id="happiness-stat-container"><i class="fas fa-smile-beam"></i><span>행복: <strong id="happiness-stat">50</strong></span></div>
<div class="stat" id="intelligence-stat-container"><i class="fas fa-brain"></i><span>지능: <strong id="intelligence-stat">10</strong></span></div>
<div class="stat" id="wealth-stat-container"><i class="fas fa-coins"></i><span>재산: <strong id="wealth-stat">0</strong></span></div>
<div class="stat hidden" id="spouse-relationship-stat-container"><i class="fas fa-users"></i><span>관계: <strong id="spouse-relationship-stat">0</strong></span></div>
</div>
<div id="age-bar-container">
<div id="age-bar"></div>
</div>
<div id="event-text"></div>
<div id="choices-container"></div>
<button id="save-button"><i class="fas fa-save"></i> 현재 인생 저장</button>
</div>
<div id="end-screen" class="hidden">
<h2 id="end-title">🏁 게임 오버 🏁</h2>
<p id="end-message"></p>
<h3><i class="fas fa-scroll"></i> 나의 인생 요약:</h3>
<div id="life-summary"></div>
<div id="achievements-log-container">
<h3><i class="fas fa-trophy"></i> 달성한 업적:</h3>
<div id="achievements-log-list"></div>
</div>
<button id="restart-button"><i class="fas fa-sync-alt"></i> 다시 플레이하기</button>
</div>
</div>
<div id="achievement-modal" class="modal">
<div class="modal-content">
<h3><i class="fas fa-award"></i> 업적 달성!</h3>
<p id="achievement-modal-text"></p>
<button class="modal-close-button">확인 👍</button>
</div>
</div>
<script>
const GAME_SAVE_KEY = 'royGameSaveData_v2.1';
const gameData = {
stats: {
age: 0, health: 100, happiness: 50, intelligence: 10, wealth: 0, relationshipWithSpouse: 0,
},
lifeLog: [], maxAge: 100,
flags: {
isMarried: false, hasChildren: 0, marriageDuration: 0, isDINK: false, ownsHouse: false, hasMortgage: false,
employed: false, isManager: false, hasDegree: false, childTraits: [], careerPath: null, retired: false,
hasDated: false, traveledWorld: false, inRelationship: false,
},
currentEventId: null,
achievements: {
firstSteps: { name: "첫 걸음마 👶", description: "인생의 첫 발을 내딛다!", achieved: false, condition: (s, f, le, ceid) => s.age >= 1 && ceid === 'toddler_first_steps'},
firstLove: { name: "첫사랑 💕", description: "풋풋한 첫사랑을 경험하다.", achieved: false, condition: (s, f) => f.hasDated },
graduation: { name: "학사모를 쓰다 🎓", description: "대학교를 졸업하다.", achieved: false, condition: (s, f) => f.hasDegree && s.age >= 22 && s.age <= 28 },
millionaire: { name: "백만장자 💰", description: "순자산 1000 달성!", achieved: false, condition: (s, f) => s.wealth >= 1000 },
happyMarriage: { name: "행복한 결혼 생활 💑", description: "배우자와의 관계 80 이상으로 10년 유지", achieved: false, condition: (s,f) => f.isMarried && s.relationshipWithSpouse >= 80 && f.marriageDuration >= 10},
proudParent: { name: "자랑스러운 부모 👨‍👩‍👧‍👦", description: "자녀를 훌륭히 키워내다.", achieved: false, condition: (s, f, le) => f.hasChildren > 0 && le.some(e => e.event && e.event.includes("자녀가 명문대에 합격")) },
ceo: { name: "회사의 정점 CEO 👔", description: "회사의 CEO가 되다.", achieved: false, condition: (s, f) => f.careerPath === 'ceo' },
globetrotter: { name: "세계 일주 여행가 ✈️", description: "세계 일주를 경험하다.", achieved: false, condition: (s, f) => f.traveledWorld },
goldenAge: { name: "황금빛 노년 🌟", description: "80세 이상 행복도 70 이상으로 생존", achieved: false, condition: (s, f) => s.age >= 80 && s.happiness >= 70 },
perfectLife: { name: "완벽한 인생 ✨", description: "모든 스탯(관계 제외) 80 이상으로 90세 생존", achieved: false, condition: (s,f) => s.age >=90 && s.health >=80 && s.happiness >= 80 && s.intelligence >=80 && s.wealth >=80},
carpetSalesmanLegacy: { name: "전설의 카펫 판매왕 👑", description: "카펫 판매로 대성공하다.", achieved: false, condition: (s,f) => f.careerPath === 'carpet_sales_tycoon'}
},
events: []
};
let currentStats = {};
let currentFlags = {};
let lifeEventsLog = [];
let currentAchievements = {};
const startScreen = document.getElementById('start-screen');
const gameContent = document.getElementById('game-content');
const endScreen = document.getElementById('end-screen');
const ageStatDisplay = document.getElementById('age-stat');
const healthStatDisplay = document.getElementById('health-stat');
const happinessStatDisplay = document.getElementById('happiness-stat');
const intelligenceStatDisplay = document.getElementById('intelligence-stat');
const wealthStatDisplay = document.getElementById('wealth-stat');
const spouseRelationshipStatDisplay = document.getElementById('spouse-relationship-stat');
const spouseRelationshipContainer = document.getElementById('spouse-relationship-stat-container');
const eventTextDisplay = document.getElementById('event-text');
const choicesContainer = document.getElementById('choices-container');
const endTitleDisplay = document.getElementById('end-title');
const endMessageDisplay = document.getElementById('end-message');
const lifeSummaryDisplay = document.getElementById('life-summary');
const achievementsLogList = document.getElementById('achievements-log-list');
const ageBar = document.getElementById('age-bar');
const saveButton = document.getElementById('save-button');
const loadButton = document.getElementById('load-button');
const achievementModal = document.getElementById('achievement-modal');
const achievementModalText = document.getElementById('achievement-modal-text');
const achievementModalCloseButton = achievementModal.querySelector('.modal-close-button');
document.getElementById('start-button').addEventListener('click', () => startGame(false));
loadButton.addEventListener('click', () => startGame(true));
document.getElementById('restart-button').addEventListener('click', () => startGame(false));
saveButton.addEventListener('click', saveGame);
achievementModalCloseButton.addEventListener('click', () => achievementModal.style.display = 'none');
function initGameDataEvents() {
gameData.events = [
{ id: 'birth', text: "당신은 태어났습니다! 🍼 세상에 온 것을 환영해요. 무엇을 먼저 해볼까요?", ageMin: 0, ageMax: 0, choices: [ { text: "응애! 울기 😭", effects: { happiness: -2, health: +1 }, nextEvent: 'infant_cry', ageUp: 1 }, { text: "가만히 있기 🤔", effects: { intelligence: +1 }, nextEvent: 'infant_observe', ageUp: 1 } ] },
{ id: 'infant_cry', text: "크게 울자 부모님이 달려와 안아줍니다. 약간의 안정감을 느낍니다. 🤱", ageMin: 1, ageMax: 2, choices: [ { text: "계속 울기 😫", effects: { happiness: +5, health: -1 }, nextEvent: 'toddler_first_steps', ageUp: 1 }, { text: "웃어보기 😊", effects: { happiness: +10, intelligence: +1 }, nextEvent: 'toddler_first_words', ageUp: 1 } ] },
{ id: 'infant_observe', text: "주변을 조용히 관찰합니다. 세상은 신기한 것들로 가득 차 있습니다. 👀", ageMin: 1, ageMax: 2, choices: [ { text: "손 뻗어보기 🖐️", effects: { intelligence: +2 }, nextEvent: 'toddler_first_steps', ageUp: 1 }, { text: "옹알이 하기 👶💬", effects: { happiness: +3, intelligence: +1 }, nextEvent: 'toddler_first_words', ageUp: 1 } ] },
{ id: 'toddler_first_steps', text: "비틀거리며 첫 걸음을 뗍니다! 세상이 더 넓어 보입니다. 🚶‍♂️", ageMin: 1, ageMax: 3, choices: [ { text: "넘어져도 계속 걷기 💪", effects: { health: -2, happiness: +5, intelligence: +1 }, nextEvent: 'child_play', ageUp: 2 }, { text: "기어다니기 Crawl", effects: { health: +1, happiness: -1 }, nextEvent: 'child_shy', ageUp: 2 } ] },
{ id: 'toddler_first_words', text: "첫 단어를 말했습니다! '엄마' 혹은 '아빠'였을까요? 부모님이 기뻐합니다. 🗣️", ageMin: 1, ageMax: 3, choices: [ { text: "계속 말 연습하기 📚", effects: { intelligence: +3, happiness: +5 }, nextEvent: 'child_read', ageUp: 2 }, { text: "그림 그리기 🎨", effects: { intelligence: +2, happiness: +3 }, nextEvent: 'child_art', ageUp: 2 } ] },
{ id: 'child_play', text: "동네 아이들과 뛰어놉니다. 약간의 찰과상을 입었지만 즐겁습니다. 🏃‍♀️💨", ageMin: 3, ageMax: 6, choices: [ { text: "리더가 되어 놀이 주도 👑", effects: { happiness: +10, intelligence: +2 }, nextEvent: 'school_entry', ageUp: 3 }, { text: "조용히 따라다니기 😶", effects: { happiness: +3, intelligence: +1 }, nextEvent: 'school_entry_quiet', ageUp: 3 } ] },
{ id: 'child_shy', text: "혼자 노는 것을 더 좋아합니다. 상상력이 풍부해집니다. 🧸💭", ageMin: 3, ageMax: 6, choices: [ { text: "책 읽기 📖", effects: { intelligence: +5, happiness: +3 }, nextEvent: 'school_entry_quiet', ageUp: 3 }, { text: "장난감 가지고 놀기 🤖", effects: { happiness: +5 }, nextEvent: 'school_entry', ageUp: 3 } ] },
{ id: 'child_read', text: "부모님이 읽어주는 동화책에 푹 빠졌습니다. 글자를 배우고 싶어집니다. fairytale", ageMin: 3, ageMax: 6, choices: [ { text: "스스로 읽기 도전 🧐", effects: { intelligence: +7, happiness: +3 }, nextEvent: 'school_entry_smart', ageUp: 3 }, { text: "그림만 보기 🖼️", effects: { happiness: +2 }, nextEvent: 'school_entry', ageUp: 3 } ] },
{ id: 'child_art', text: "그림 그리는 것이 즐겁습니다. 벽에 낙서를 해서 혼나기도 합니다. 🖍️💥", ageMin: 3, ageMax: 6, choices: [ { text: "미술 학원 보내달라 조르기 🙏", effects: { intelligence: +3, happiness: +5, wealth: -5 }, nextEvent: 'school_entry_creative', ageUp: 3 }, { text: "숨어서 계속 그리기 🤫", effects: { intelligence: +1, happiness: +2 }, nextEvent: 'school_entry', ageUp: 3 } ] },
{ id: 'school_entry', text: "드디어 학교에 입학합니다! 🎒 새로운 친구들과 선생님을 만납니다.", ageMin: 6, ageMax: 8, choices: [ { text: "공부 열심히 하기 🤓", effects: { intelligence: +5, happiness: -2 }, nextEvent: 'elem_study', ageUp: 3 }, { text: "친구 사귀기에 집중 🤝", effects: { happiness: +5, intelligence: -1 }, nextEvent: 'elem_social', ageUp: 3 } ] },
{ id: 'school_entry_quiet', text: "조용히 학교 생활을 시작합니다. 아직은 모든 것이 낯섭니다. 😟", ageMin: 6, ageMax: 8, choices: [ { text: "도서관에서 책 읽기 📚", effects: { intelligence: +6, happiness: +2 }, nextEvent: 'elem_study_hard', ageUp: 3 }, { text: "먼저 말 걸어보기 👋", effects: { happiness: +4, intelligence: +1 }, nextEvent: 'elem_social', ageUp: 3 } ] },
{ id: 'school_entry_smart', text: "학교 공부가 생각보다 쉽습니다. 선생님의 칭찬을 받습니다. 🌟", ageMin: 6, ageMax: 8, choices: [ { text: "더 어려운 문제에 도전 🧠", effects: { intelligence: +8, happiness: +1 }, nextEvent: 'elem_gifted', ageUp: 3 }, { text: "친구들에게 알려주기 🧑‍🏫", effects: { intelligence: +3, happiness: +5 }, nextEvent: 'elem_popular_smart', ageUp: 3 } ] },
{ id: 'school_entry_creative', text: "미술 시간에 두각을 나타냅니다. 창의력이 넘칩니다. 🎨✨", ageMin: 6, ageMax: 8, choices: [ { text: "미술 대회 참가 🏆", effects: { intelligence: +2, happiness: +7, wealth: +10 }, nextEvent: 'elem_art_focus', ageUp: 3 }, { text: "다른 과목도 열심히 💯", effects: { intelligence: +3, happiness: +3 }, nextEvent: 'elem_study', ageUp: 3 } ] },
{ id: 'elem_study', text: "초등학교 시절, 공부에 매진합니다. 성적이 오릅니다. 📈", ageMin: 9, ageMax: 12, choices: [ { text: "과학 경시대회 참가 🔬", effects: { intelligence: +10, happiness: -2, wealth: (s) => s.intelligence > 40 ? 20 : 0 }, nextEvent: 'middle_school_science', ageUp: 3 }, { text: "반장 선거 출마 🙋‍♂️", effects: { intelligence: +3, happiness: +5 }, nextEvent: 'middle_school_leader', ageUp: 3 } ] },
{ id: 'elem_social', text: "친구들과 즐거운 초등학교 시절을 보냅니다. 인기가 많습니다. 🎉", ageMin: 9, ageMax: 12, choices: [ { text: "스포츠 클럽 가입 ⚽", effects: { health: +10, happiness: +7, intelligence: -1 }, nextEvent: 'middle_school_athlete', ageUp: 3 }, { text: "학예회 사회 보기 🎤", effects: { happiness: +8, intelligence: +2 }, nextEvent: 'middle_school_popular', ageUp: 3 } ] },
{ id: 'elem_study_hard', text: "혼자 공부하는 시간이 많습니다. 깊이 있는 지식을 쌓습니다. 🧑‍💻", ageMin: 9, ageMax: 12, choices: [ { text: "영재 교육원 시험 📝", effects: { intelligence: +15, happiness: (s) => s.intelligence > 50 ? 10 : -5 }, nextEvent: (s) => s.intelligence > 50 ? 'elem_gifted_path' : 'middle_school_normal', ageUp: 3 }, { text: "프로그래밍 독학 💻", effects: { intelligence: +12, happiness: +3 }, nextEvent: 'middle_school_tech', ageUp: 3 } ] },
{ id: 'elem_gifted', text: "영재로 판명되어 특별 교육을 받게 됩니다. 주변의 기대가 큽니다. ✨", ageMin: 9, ageMax: 12, choices: [ { text: "기대에 부응하기 위해 노력 😥", effects: { intelligence: +10, happiness: -5, health: -3 }, nextEvent: 'middle_school_stress', ageUp: 3 }, { text: "평범하게 지내려 노력 😊", effects: { intelligence: +2, happiness: +5 }, nextEvent: 'middle_school_normal', ageUp: 3 } ] },
{ id: 'elem_popular_smart', text: "똑똑하면서 인기도 많아 즐거운 학교 생활을 보냅니다. 😎", ageMin: 9, ageMax: 12, choices: [ { text: "학생회 활동 🏛️", effects: { intelligence: +5, happiness: +8 }, nextEvent: 'middle_school_leader', ageUp: 3 }, { text: "다양한 분야에 관심 🤔", effects: { intelligence: +4, happiness: +4 }, nextEvent: 'middle_school_versatile', ageUp: 3 } ] },
{ id: 'elem_art_focus', text: "예술가의 길을 꿈꾸며 미술에 전념합니다. 각종 대회에서 상을 받습니다. 🥇", ageMin: 9, ageMax: 12, choices: [ { text: "예술 중학교 진학 준비 🎨🏫", effects: { intelligence: +2, happiness: +10, wealth: -10 }, nextEvent: 'middle_school_art_special', ageUp: 3 }, { text: "취미로만 남기기 😕", effects: { happiness: -3 }, nextEvent: 'middle_school_normal', ageUp: 3 } ] },
{ id: 'elem_gifted_path', text: "영재 교육원을 수료하고 명문 중학교에 진학합니다. 🚀", ageMin: 12, ageMax: 13, choices: [{ text: "계속 학업에 정진 📚", effects: { intelligence: +10 }, nextEvent: 'high_school_elite', ageUp: 3 }]},
{ id: 'middle_school_science', text: "중학교에서 과학에 더욱 흥미를 느낍니다. 과학 동아리 활동이 즐겁습니다. 🧪", ageMin: 12, ageMax: 15, choices: [ { text: "과학고 진학 준비 🧬", effects: { intelligence: +15, happiness: -5, health: -2 }, nextEvent: 'high_school_science_prep', ageUp: 3 }, { text: "다른 분야도 탐색 🧭", effects: { intelligence: +5, happiness: +3 }, nextEvent: 'high_school_normal', ageUp: 3 } ] },
{ id: 'middle_school_leader', text: "학생회장으로 활동하며 리더십을 키웁니다. 바쁘지만 보람찹니다. 🌟", ageMin: 12, ageMax: 15, choices: [ { text: "정치에 관심 갖기 🗳️", effects: { intelligence: +7, happiness: +5 }, nextEvent: 'high_school_politics', ageUp: 3 }, { text: "공부에 집중하기 📖", effects: { intelligence: +8, happiness: -2 }, nextEvent: 'high_school_study', ageUp: 3 } ] },
{ id: 'middle_school_athlete', text: "운동부에서 활약하며 건강한 중학교 시절을 보냅니다. 체력이 크게 향상됩니다. 🏋️‍♂️", ageMin: 12, ageMax: 15, choices: [ { text: "체육고 진학 고려 🏅", effects: { health: +15, happiness: +8, intelligence: -5 }, nextEvent: 'high_school_athlete_track', ageUp: 3 }, { text: "운동은 취미로 😌", effects: { health: +5, happiness: +3 }, nextEvent: 'high_school_normal', ageUp: 3 } ] },
{ id: 'middle_school_popular', text: "사교성이 좋아 친구가 많습니다. 첫사랑을 경험할 수도? 🥰", ageMin: 12, ageMax: 15, choices: [ { text: "이성친구 사귀기 💌", effects: { happiness: +15, intelligence: -3, health: -1 }, nextEvent: 'high_school_romance', ageUp: 3, setFlag: { hasDated: true } }, { text: "공부에 집중 📚", effects: { intelligence: +5, happiness: -5 }, nextEvent: 'high_school_study', ageUp: 3 } ] },
{ id: 'middle_school_tech', text: "컴퓨터와 프로그래밍에 푹 빠져 지냅니다. 작은 게임을 만들기도 합니다. 🎮🕹️", ageMin: 12, ageMax: 15, choices: [ { text: "IT 특성화고 진학 💻🏫", effects: { intelligence: +15, happiness: +5, wealth: -5 }, nextEvent: 'high_school_tech_focus', ageUp: 3 }, { text: "다른 공부도 병행 📑", effects: { intelligence: +7, happiness: +2 }, nextEvent: 'high_school_normal', ageUp: 3 } ] },
{ id: 'middle_school_stress', text: "과도한 학업 스트레스로 건강이 조금 나빠집니다. 하지만 지식은 쌓입니다. 🤯", ageMin: 12, ageMax: 15, choices: [ { text: "상담 받기 🛋️", effects: { health: +5, happiness: +10, intelligence: -2 }, nextEvent: 'high_school_balanced', ageUp: 3 }, { text: "더욱 공부에 매진 😵", effects: { intelligence: +10, health: -8, happiness: -10 }, nextEvent: 'high_school_burnout_risk', ageUp: 3 } ] },
{ id: 'middle_school_normal', text: "평범하지만 무난한 중학교 생활을 보냅니다. 🙂", ageMin: 12, ageMax: 15, choices: [ { text: "인문계 고등학교 진학 🏫", effects: { intelligence: +3 }, nextEvent: 'high_school_normal', ageUp: 3 }, { text: "실업계 고등학교 진학 🛠️", effects: { intelligence: -2, wealth: +5 }, nextEvent: 'high_school_vocational', ageUp: 3 } ] },
{ id: 'middle_school_versatile', text: "다방면에 재능을 보이며 즐거운 학창시절을 보냅니다. 🥳", ageMin: 12, ageMax: 15, choices: [ { text: "가장 흥미로운 분야 선택 👍", effects: { intelligence: +5, happiness: +5 }, nextEvent: 'high_school_normal', ageUp: 3 }, { text: "모든 것을 조금씩 🤏", effects: { intelligence: +2, happiness: +2 }, nextEvent: 'high_school_jack_of_all_trades', ageUp: 3 } ] },
{ id: 'middle_school_art_special', text: "예술 중학교에서 재능을 갈고 닦습니다. 경쟁이 치열합니다. 🎭", ageMin: 12, ageMax: 15, choices: [ { text: "예술고등학교 진학 🎨🎓", effects: { happiness: +10, intelligence: +3, wealth: -10 }, nextEvent: 'high_school_art_elite', ageUp: 3 }, { text: "일반고로 전환 🤔", effects: { happiness: -5, intelligence: +2 }, nextEvent: 'high_school_normal', ageUp: 3 } ] },
{ id: 'high_school_elite', text: "명문고에서 최상위권 성적을 유지합니다. SKY 대학이 눈앞입니다. 🌟", ageMin: 15, ageMax: 18, choices: [{ text: "의대 목표 🩺", effects: { intelligence: +10, health: -5 }, nextEvent: 'uni_medical', ageUp: 4, setFlag: {hasDegree:false} }, { text: "공대 목표 ⚙️", effects: { intelligence: +10 }, nextEvent: 'uni_engineering_top', ageUp: 4, setFlag: {hasDegree:false} }] },
{ id: 'high_school_science_prep', text: "과학고 진학에 성공! 심도있는 과학 공부를 합니다. 🔬📚", ageMin: 15, ageMax: 18, choices: [{ text: "KAIST/POSTECH 목표 🚀", effects: { intelligence: +15, happiness: +5 }, nextEvent: 'uni_science_top', ageUp: 4, setFlag: {hasDegree:false} }, { text: "해외 유학 준비 ✈️🌍", effects: { intelligence: +10, wealth: -30, happiness: +10 }, nextEvent: 'study_abroad_prep', ageUp: 4, setFlag: {hasDegree:false} }] },
{ id: 'high_school_politics', text: "모의 UN 등 정치/사회 활동에 적극 참여합니다. 변호사나 정치인을 꿈꿉니다. 🏛️📢", ageMin: 15, ageMax: 18, choices: [{ text: "법대/정치외교학과 목표 ⚖️", effects: { intelligence: +8, happiness: +5 }, nextEvent: 'uni_law_politics', ageUp: 4, setFlag: {hasDegree:false} }, { text: "NGO 활동 시작 ❤️‍🩹", effects: { happiness: +10, wealth: -5 }, nextEvent: 'activist_path', ageUp: 4 }] },
{ id: 'high_school_athlete_track', text: "체육고에서 유망주로 주목받습니다. 국가대표를 꿈꿉니다. 🏆🇰🇷", ageMin: 15, ageMax: 18, choices: [{ text: "프로 선수 도전 🌟", effects: { health: +20, happiness: +10, intelligence: -10, wealth: +50 }, nextEvent: (s) => s.health > 70 ? 'pro_athlete_career' : 'athlete_injury', ageUp: 4 }, { text: "체육 교육과 진학 🧑‍🏫", effects: { health: +10, intelligence: +3 }, nextEvent: 'uni_physical_ed', ageUp: 4, setFlag: {hasDegree:false} }] },
{ id: 'high_school_romance', text: "풋풋한 연애와 함께 고등학교 시절을 보냅니다. 때로는 공부에 방해가 되기도 합니다. 🥰💔", ageMin: 15, ageMax: 18, choices: [{ text: "연애와 학업 병행 💑📚", effects: { happiness: +10, intelligence: -2 }, nextEvent: 'uni_normal', ageUp: 4, setFlag: {hasDegree:false} }, { text: "이별 후 학업 집중 💔➡️💪", effects: { happiness: -10, intelligence: +8 }, nextEvent: 'uni_study_focused', ageUp: 4, setFlag: {hasDegree:false} }] },
{ id: 'high_school_tech_focus', text: "IT 특성화고에서 실력을 키워 각종 대회에서 입상합니다. 일찍부터 스카웃 제의가 오기도 합니다. 💻🏆", ageMin: 15, ageMax: 18, choices: [{ text: "바로 취업 (스타트업) 🚀🏢", effects: { intelligence: +5, wealth: +30, happiness: +10 }, nextEvent: 'work_startup_young', ageUp: 4, setFlag: { employed: true } }, { text: "컴퓨터 공학과 진학 🎓💻", effects: { intelligence: +10 }, nextEvent: 'uni_computer_science', ageUp: 4, setFlag: {hasDegree:false} }] },
{ id: 'high_school_balanced', text: "상담을 통해 스트레스를 극복하고, 학업과 생활의 균형을 찾습니다. ⚖️😊", ageMin: 15, ageMax: 18, choices: [{ text: "원하는 대학에 진학 🎉", effects: { intelligence: +5, happiness: +8 }, nextEvent: 'uni_normal', ageUp: 4, setFlag: {hasDegree:false} }, { text: "갭이어 갖기 🌍🎒", effects: { happiness: +15, intelligence: -2, wealth: -10 }, nextEvent: 'gap_year', ageUp: 1 }] },
{ id: 'high_school_burnout_risk', text: "번아웃 직전입니다. 대학 입시가 코앞인데, 몸과 마음이 지쳐갑니다. 😫🔥", ageMin: 15, ageMax: 18, condition: (s) => s.health < 30 || s.happiness < 20, choices: [ { text: "억지로 수능 응시 억지로...", effects: { health: -10, happiness: -10, intelligence: (s) => s.intelligence > 60 ? -10 : -5 }, nextEvent: 'uni_struggle', ageUp: 4, setFlag: {hasDegree:false} }, { text: "휴식 후 재수 결심 🛌➡️📚", effects: { health: +15, happiness: +5, wealth: -15 }, nextEvent: 'prepare_retake_exam', ageUp: 1 } ] },
{ id: 'high_school_normal', text: "일반 인문계 고등학교에서 평범한 학창시절을 보냅니다. 수능을 준비합니다. 📚✏️", ageMin: 15, ageMax: 18, choices: [{ text: "열심히 수능 공부 🔥", effects: { intelligence: +7, happiness: -3 }, nextEvent: 'uni_normal', ageUp: 4, setFlag: {hasDegree:false} }, { text: "아르바이트와 병행 💰📚", effects: { intelligence: -2, wealth: +20, happiness: +2 }, nextEvent: 'uni_part_time_student', ageUp: 4, setFlag: {hasDegree:false} }] },
{ id: 'high_school_vocational', text: "실업계 고등학교에서 기술을 배웁니다. 졸업 후 바로 취업할 생각입니다. 🛠️🧑‍🏭", ageMin: 15, ageMax: 18, choices: [{ text: "자격증 취득에 집중 📜", effects: { intelligence: +3, wealth: +5 }, nextEvent: 'work_skilled_labor', ageUp: 4, setFlag: { employed: true } }, { text: "전문대학 진학 🏢", effects: { intelligence: +2 }, nextEvent: 'community_college', ageUp: 2, setFlag: {hasDegree:false} }] },
{ id: 'high_school_jack_of_all_trades', text: "다양한 분야에 관심은 많지만, 깊이가 부족한 것 같아 고민입니다. 🤔🤷", ageMin: 15, ageMax: 18, choices: [{ text: "가장 자신있는 분야 선택 👍", effects: { intelligence: +3, happiness: +3 }, nextEvent: 'uni_normal', ageUp: 4, setFlag: {hasDegree:false} }, { text: "자유전공 학부 진학 🌐", effects: { intelligence: +2, happiness: +2 }, nextEvent: 'uni_liberal_arts', ageUp: 4, setFlag: {hasDegree:false} }] },
{ id: 'high_school_art_elite', text: "예술고에서 뛰어난 재능을 선보입니다. 국내 최고 예술대학을 목표로 합니다. 🎨🌟", ageMin: 15, ageMax: 18, choices: [{ text: "명문 예술대학 진학 🎓🎭", effects: { happiness: +15, intelligence: +5, wealth: -20 }, nextEvent: 'uni_art_top', ageUp: 4, setFlag: {hasDegree:false} }, { text: "해외 예술학교 유학 ✈️🎨", effects: { happiness: +10, intelligence: +7, wealth: -50 }, nextEvent: 'study_abroad_art', ageUp: 4, setFlag: {hasDegree:false} }] },
{ id: 'high_school_study', text: "친구들과의 관계보다는 학업에 집중하여 성적을 올립니다. 📚🔝", ageMin: 15, ageMax: 18, choices: [{ text: "상위권 대학 진학 🥇", effects: { intelligence: +10 }, nextEvent: 'uni_good_grades', ageUp: 4, setFlag: {hasDegree:false} }, {text: "적당한 대학 진학 👍", effects: { intelligence: +5 }, nextEvent: 'uni_normal', ageUp: 4, setFlag: {hasDegree:false}}]},
{ id: 'uni_medical', text: "치열한 경쟁을 뚫고 의대에 합격했습니다! 🩺 그러나 공부는 이제 시작입니다. 💀", ageMin: 19, ageMax: 26, choices: [{ text: "예과 마치고 본과 진입 💉", effects: { intelligence: +20, health: -10, happiness: -5 }, nextEvent: 'medical_resident', ageUp: 6, setFlag:{hasDegree:true} }, { text: "너무 힘들어 중퇴 🏳️", effects: { intelligence: -5, happiness: -20, health: +5 }, nextEvent: 'career_change_early', ageUp: 1 }] },
{ id: 'uni_engineering_top', text: "최고 공대에 진학하여 첨단 기술을 배웁니다. 미래가 밝아 보입니다. 💡🤖", ageMin: 19, ageMax: 23, choices: [{ text: "대기업 R&D 취업 🏢🔬", effects: { intelligence: +10, wealth: +70, happiness: +5 }, nextEvent: 'work_large_corp_rnd', ageUp: 1, setFlag: { employed: true, hasDegree:true } }, { text: "대학원 진학 🧑‍🔬", effects: { intelligence: +15, wealth: -10 }, nextEvent: 'graduate_school_eng', ageUp: 2, setFlag:{hasDegree:true} }] },
{ id: 'uni_science_top', text: "KAIST/POSTECH에서 과학자의 꿈을 키웁니다. 밤샘 연구는 기본입니다. 🧪🌌", ageMin: 19, ageMax: 23, choices: [{ text: "국책 연구소 취업 🇰🇷🔬", effects: { intelligence: +10, wealth: +60, happiness: +3 }, nextEvent: 'work_national_lab', ageUp: 1, setFlag: { employed: true, hasDegree:true } }, { text: "유학 후 교수 도전 ✈️🧑‍🏫", effects: { intelligence: +15, wealth: -40 }, nextEvent: 'study_abroad_phd', ageUp: 3, setFlag:{hasDegree:true} }] },
{ id: 'study_abroad_prep', text: "해외 명문대 합격! ✈️ 새로운 환경에서 공부하게 됩니다. 🌐", ageMin: 19, ageMax: 23, choices: [{ text: "열심히 공부해 장학금 받기 💰🎓", effects: { intelligence: +10, wealth: +20, happiness: +5 }, nextEvent: 'work_international_corp', ageUp: 1, setFlag: { employed: true, hasDegree:true } }, { text: "문화 체험에 집중 🥳🎭", effects: { intelligence: +3, happiness: +15, wealth: -10 }, nextEvent: 'travel_lover_career', ageUp: 1, setFlag:{hasDegree:true, traveledWorld: true} }] },
{ id: 'uni_law_politics', text: "법대/정치외교학과에서 사회 정의와 국가 운영을 배웁니다. ⚖️🏛️", ageMin: 19, ageMax: 23, choices: [{ text: "로스쿨 진학/행정고시 준비 📚⏳", effects: { intelligence: +15, happiness: -8, health: -5 }, nextEvent: 'prepare_bar_exam', ageUp: 3, setFlag: {hasDegree:true, isLawyerPath: true} }, { text: "시민단체 활동 ❤️‍🩹🌍", effects: { intelligence: +5, happiness: +10, wealth: -5 }, nextEvent: 'ngo_staff', ageUp: 1, setFlag: { employed: true, hasDegree:true } }] },
{ id: 'activist_path', text: "NGO에서 열정적으로 활동하며 사회 변화를 위해 노력합니다. 🔥🌍", ageMin: 19, ageMax: 23, choices: [{ text: "국제 구호 활동 참가 ✈️🤝", effects: { happiness: +20, health: -5, wealth: -10 }, nextEvent: 'international_aid_worker', ageUp: 2 }, { text: "국내 정책 개선 운동 📢🇰🇷", effects: { intelligence: +5, happiness: +10 }, nextEvent: 'policy_advocate', ageUp: 1 }] },
{ id: 'pro_athlete_career', text: "프로 선수로 데뷔! 뛰어난 활약을 펼칩니다. 🌟🥇", ageMin: 19, ageMax: 30, choices: [{ text: "전성기를 누리다 ✨", effects: { health: -10, happiness: +20, wealth: +200 }, nextEvent: 'athlete_peak', ageUp: 5 }, { text: "부상으로 은퇴 위기 🤕", effects: { health: -30, happiness: -15, wealth: +50 }, nextEvent: 'athlete_injury_serious', ageUp: 1 }] },
{ id: 'athlete_injury', text: "아, 이런! 경기 중 부상을 당했습니다. 😫 선수 생활에 지장이 있을까요?", ageMin: 19, ageMax: 23, choices: [{ text: "재활에 힘쓰다 💪", effects: { health: +10, happiness: -5}, nextEvent: 'pro_athlete_career', ageUp: 1}, { text: "다른 길을 찾다 🤔", effects: {health: -5, happiness: -10}, nextEvent: 'career_change_early', ageUp:1}]},
{ id: 'uni_physical_ed', text: "체육 교육과에서 교사의 꿈을 키웁니다. 🧑‍🏫⚽", ageMin: 19, ageMax: 23, choices: [{ text: "임용고시 합격 후 교사로 👨‍🏫", effects: { intelligence: +5, wealth: +40, happiness: +10 }, nextEvent: 'work_teacher', ageUp: 1, setFlag: { employed: true, hasDegree:true } }, { text: "스포츠센터 강사 🏋️‍♀️", effects: { health: +5, wealth: +30, happiness: +5 }, nextEvent: 'work_fitness_instructor', ageUp: 1, setFlag: { employed: true, hasDegree:true } }] },
{ id: 'uni_normal', text: "평범한 대학 생활. 캠퍼스의 낭만과 학점 관리에 힘씁니다. 🌸📚", ageMin: 19, ageMax: 23, choices: [{ text: "대기업 공채 도전 🏢💼", effects: { intelligence: +5, wealth: (s) => s.intelligence > 60 ? 60: 40, happiness: (s) => s.intelligence > 60 ? 5 : 0 }, nextEvent: 'work_large_corp_general', ageUp: 1, setFlag: { employed: true, hasDegree:true } }, { text: "중소기업 취업 👨‍💼", effects: { intelligence: +2, wealth: +35, happiness: +3 }, nextEvent: 'work_smb', ageUp: 1, setFlag: { employed: true, hasDegree:true } }, { text: "공무원 시험 준비 公务员", effects: { intelligence: +3, wealth: -5, happiness: -5 }, nextEvent: 'prepare_civil_service_exam', ageUp: 2, setFlag:{hasDegree:true} }] },
{ id: 'uni_study_focused', text: "과거의 아픔을 딛고 학업에만 매진하여 우수한 성적으로 졸업합니다. 🎓✨", ageMin: 19, ageMax: 23, choices: [{ text: "좋은 조건으로 회사 입사 💼🌟", effects: { intelligence: +5, wealth: +65, happiness: +5 }, nextEvent: 'work_good_company', ageUp: 1, setFlag: { employed: true, hasDegree:true } }, {text: "대학원 진학 🧑‍🎓", effects: { intelligence: +10, wealth: -10}, nextEvent: 'graduate_school_humanities', ageUp: 2, setFlag:{hasDegree:true}}]},
{ id: 'work_startup_young', text: "젊은 나이에 스타트업에 합류하여 열정적으로 일합니다. 회사가 빠르게 성장합니다. 🚀📈", ageMin: 19, ageMax: 28, choices: [{ text: "스톡옵션 대박! 💰🎉", effects: { wealth: +300, happiness: +20 }, nextEvent: 'work_startup_success', ageUp: 3 }, { text: "회사 매각 후 새 도전 🔄️", effects: { wealth: +150, happiness: +10 }, nextEvent: 'entrepreneur_serial', ageUp: 2 }, { text: "회사가 망했어요... 📉😭", effects: { wealth: -20, happiness: -15 }, nextEvent: 'career_crisis_mid', ageUp: 1 }] },
{ id: 'uni_computer_science', text: "컴퓨터 공학과에서 최신 IT 기술을 배우며 프로젝트를 진행합니다. 💻🌐", ageMin: 19, ageMax: 23, choices: [{ text: "IT 대기업 취업 🏢🖱️", effects: { intelligence: +8, wealth: +70, happiness: +8 }, nextEvent: 'work_it_major', ageUp: 1, setFlag: { employed: true, hasDegree:true } }, { text: "친구와 스타트업 창업 🤝🚀", effects: { intelligence: +5, wealth: -20, happiness: +15 }, nextEvent: 'entrepreneur_first_try', ageUp: 1, setFlag:{hasDegree:true} }] },
{ id: 'gap_year', text: "1년간의 갭이어. 여행을 다니거나 하고 싶던 일들을 합니다. ✈️🧘", ageMin: 18, ageMax: 20, choices: [{ text: "세계 일주 🌍✨", effects: { happiness: +30, intelligence: +5, wealth: -20, health: +5 }, nextEvent: 'back_to_study_or_work', ageUp: 1, setFlag: {traveledWorld: true} }, { text: "다양한 아르바이트 🛠️💰", effects: { happiness: +10, wealth: +15 }, nextEvent: 'back_to_study_or_work', ageUp: 1 }] },
{ id: 'uni_struggle', text: "겨우 대학에 입학했지만, 학업에 흥미를 느끼지 못하고 방황합니다. 😟🌀", ageMin: 19, ageMax: 23, choices: [{ text: "자퇴하고 기술 배우기 🛠️", effects: { intelligence: -5, happiness: +10, wealth: +5 }, nextEvent: 'learn_trade_skill', ageUp: 2 }, { text: "억지로 졸업하고 취업 😫➡️💼", effects: { intelligence: -2, happiness: -10, wealth: +30 }, nextEvent: 'work_unhappy', ageUp: 1, setFlag: { employed: true, hasDegree:true } }] },
{ id: 'prepare_retake_exam', text: "재수를 결심하고 1년간 열심히 공부합니다. 📚💪", ageMin: 19, ageMax: 20, choices: [{ text: "수능 대박! 원하는 대학 진학 🎉🎓", effects: { intelligence: +10, happiness: +15 }, nextEvent: 'uni_good_grades', ageUp: 4, setFlag: {hasDegree:false} }, { text: "결과가 비슷... 다른 길 모색 🤔", effects: { intelligence: +2, happiness: -10 }, nextEvent: 'career_change_early', ageUp: 1 }] },
{ id: 'uni_part_time_student', text: "학업과 아르바이트를 병행하느라 바쁜 대학 생활을 보냅니다. 🏃‍♂️💨", ageMin: 19, ageMax: 23, choices: [{ text: "졸업 후 바로 취업 🎓➡️💼", effects: { wealth: +40, happiness: +2 }, nextEvent: 'work_smb', ageUp: 1, setFlag: { employed: true, hasDegree:true } }, { text: "모은 돈으로 창업 도전 💰➡️🚀", effects: { wealth: -10, happiness: +10 }, nextEvent: 'entrepreneur_small_shop', ageUp: 1, setFlag:{hasDegree:true} }] },
{ id: 'work_skilled_labor', text: "고등학교에서 배운 기술로 일찍 사회생활을 시작합니다. 안정적인 수입이 있습니다. 🛠️💰", ageMin: 19, ageMax: 28, choices: [{ text: "기술 명장 도전 🌟", effects: { intelligence: +5, wealth: +20, happiness: +10 }, nextEvent: 'master_craftsman', ageUp: 5 }, { text: "개인 사업 시작 🏢", effects: { wealth: -10, happiness: +5 }, nextEvent: 'self_employed_skilled', ageUp: 2 }] },
{ id: 'community_college', text: "전문대학에서 실용적인 기술을 배웁니다. 🧑‍🔧📚", ageMin: 19, ageMax: 21, choices: [{ text: "대기업 생산직 취업 🏭💼", effects: { wealth: +50, happiness: +3 }, nextEvent: 'work_factory_large', ageUp: 1, setFlag: { employed: true, hasDegree:true } }, { text: "4년제 대학 편입 🎓➡️🎓", effects: { intelligence: +5, wealth: -15 }, nextEvent: 'uni_transfer_student', ageUp: 2, setFlag:{hasDegree:false} }] },
{ id: 'uni_liberal_arts', text: "자유전공 학부에서 다양한 학문을 접하며 진로를 탐색합니다. 🌐🧭", ageMin: 19, ageMax: 23, choices: [{ text: "언론/방송계 진출 🎤📰", effects: { intelligence: +7, happiness: +8, wealth: +45 }, nextEvent: 'work_media', ageUp: 1, setFlag: { employed: true, hasDegree:true } }, { text: "대학원 진학(인문학) 📚🏛️", effects: { intelligence: +10, wealth: -15, happiness: +3 }, nextEvent: 'graduate_school_humanities', ageUp: 2, setFlag:{hasDegree:true} }] },
{ id: 'uni_art_top', text: "국내 최고 예술대학에서 실력을 인정받으며 졸업합니다. 🎨🎓✨", ageMin: 19, ageMax: 23, choices: [{ text: "유명 작가 어시스턴트 🧑‍🎨🤝", effects: { intelligence: +5, wealth: +30, happiness: +10 }, nextEvent: 'work_artist_assistant', ageUp: 1, setFlag: { employed: true, hasDegree:true } }, { text: "독립 아티스트로 활동 시작 🎨🚀", effects: { wealth: -5, happiness: +15 }, nextEvent: 'freelance_artist', ageUp: 1, setFlag:{hasDegree:true} }] },
{ id: 'study_abroad_art', text: "해외 예술학교에서 자유로운 분위기 속에 창작 활동을 합니다. 🎨🌍", ageMin: 19, ageMax: 24, choices: [{ text: "졸업 후 현지에서 활동 🖼️💼", effects: { intelligence: +8, wealth: +35, happiness: +12 }, nextEvent: 'work_artist_abroad', ageUp: 2, setFlag: { employed: true, hasDegree:true } }, { text: "귀국하여 작품 활동 🇰🇷🎨", effects: { intelligence: +5, wealth: +20, happiness: +8 }, nextEvent: 'work_artist_korea', ageUp: 1, setFlag: { employed: true, hasDegree:true } }] },
{ id: 'uni_good_grades', text: "좋은 성적으로 대학을 졸업하고 사회에 첫 발을 내딛습니다. 🎓💼🚀", ageMin: 19, ageMax: 23, choices: [{ text: "유망 중견기업 입사 🏢👍", effects: { wealth: +55, happiness: +7 }, nextEvent: 'work_mid_size_corp', ageUp: 1, setFlag: { employed: true, hasDegree:true }}, { text: "외국계 기업 도전 🌐💼", effects: { intelligence: +3, wealth: +65, happiness: +5 }, nextEvent: 'work_foreign_company', ageUp: 1, setFlag: { employed: true, hasDegree:true }}]},
{ id: 'back_to_study_or_work', text: "갭이어/여행에서 돌아왔습니다. 이제 무엇을 할까요? 🤔", ageMin: 19, ageMax: 22, choices: [ { text: "대학에 복학/진학한다 📚", effects: { intelligence: +2, happiness: +3 }, nextEvent: 'uni_normal', ageUp: 4, setFlag: {hasDegree:false} }, { text: "바로 취업 준비를 한다 💼", effects: { wealth: +5 }, nextEvent: 'job_search_after_gap', ageUp: 1 } ] },
{ id: 'job_search_after_gap', text: "취업 시장에 뛰어들었습니다. 어떤 분야에 도전할까요? 🧐", ageMin: 20, ageMax: 23, choices: [ { text: "IT/기술 분야 💻", effects: { intelligence: +3, wealth: (s) => s.intelligence > 40 ? 40 : 25 }, nextEvent: 'work_smb', ageUp: 1, setFlag: {employed: true}}, { text: "서비스/영업 분야 🗣️", effects: { happiness: +5, wealth: (s) => s.happiness > 50 ? 35 : 20}, nextEvent: 'work_sales_customer_service', ageUp: 1, setFlag: {employed: true}}, { text: "일단 아무거나! 🙏", effects: { wealth: +15, happiness: -3}, nextEvent: 'odd_jobs_phase', ageUp: 1, setFlag: {employed: true}} ] },
{ id: 'generic_early_career', text: "사회 초년생으로 열심히 일하며 경력을 쌓아갑니다. 💼📈", ageMin: 23, ageMax: 35, condition: (s, f) => f.employed && !f.isMarried, choices: [ { text: "업무 능력 향상에 집중 🚀", effects: { intelligence: +5, wealth: +15, happiness: -2 }, nextEvent: 'promotion_chance', ageUp: 3 }, { text: "동료들과의 관계 증진 🍻", effects: { happiness: +10, wealth: +5 }, nextEvent: 'office_social_life', ageUp: 3 }, { text: "소개팅 하기 🥰", effects: { happiness: +5 }, nextEvent: 'dating_life', ageUp: 1 }, { text: "결혼 정보 회사 가입 💍", effects: { wealth: -5, happiness: +2 }, nextEvent: 'arranged_marriage_path', ageUp: 1} ] },
{ id: 'dating_life', text: "소개팅에서 마음에 드는 사람을 만났습니다. 💖", ageMin: 23, ageMax: 40, condition: (s,f) => !f.isMarried && !f.inRelationship, choices: [ { text: "연애 시작! 💑", effects: { happiness: +20, relationshipWithSpouse: +10 }, nextEvent: 'relationship_develop', ageUp: 1, setFlag: { inRelationship: true, hasDated: true } }, { text: "친구로 지내기 🤝", effects: { happiness: +5 }, nextEventRandom: true, ageUp: 1 } ] },
{ id: 'relationship_develop', text: "연인과의 관계가 깊어집니다. 결혼을 생각하게 됩니다. 💍🤔", ageMin: 24, ageMax: 45, condition: (s,f) => f.inRelationship && !f.isMarried, choices: [ { text: "프로포즈 하기/받기! 💌", effects: { happiness: +30, wealth: -10, relationshipWithSpouse: +20 }, nextEvent: 'marriage_decision', ageUp: 1 }, { text: "아직은 때가 아닌 듯 ⏳", effects: { happiness: -5, relationshipWithSpouse: -5 }, nextEvent: 'relationship_stagnate', ageUp: 2 } ] },
{ id: 'marriage_decision', text: "결혼을 결정했습니다! 🎉 결혼 준비로 바빠집니다. 💒", ageMin: 25, ageMax: 48, choices: [ { text: "성대한 결혼식 올리기 🎊", effects: { happiness: +20, wealth: -50, relationshipWithSpouse: +15 }, nextEvent: 'married_life_start', ageUp: 1, setFlag: { isMarried: true, inRelationship: false, marriageDuration: 1 } }, { text: "소박한 결혼식 올리기 🥂", effects: { happiness: +15, wealth: -20, relationshipWithSpouse: +10 }, nextEvent: 'married_life_start', ageUp: 1, setFlag: { isMarried: true, inRelationship: false, marriageDuration: 1 } } ] },
{ id: 'married_life_start', text: "행복한 결혼 생활 시작! 🏡 배우자와 함께 미래를 계획합니다. 💖", ageMin: 26, ageMax: 50, condition: (s, f) => f.isMarried && f.hasChildren === 0, onLoad: (s,f) => { spouseRelationshipContainer.classList.remove('hidden'); }, choices: [ { text: "아이 갖기 계획 👶🍼", effects: { happiness: +15, relationshipWithSpouse: +10 }, nextEvent: 'try_for_baby', ageUp: 1 }, { text: "딩크족으로 살기 ✈️🥂", effects: { happiness: +10, wealth: +10, relationshipWithSpouse: +5 }, nextEvent: 'dink_life', ageUp: 5, setFlag: { isDINK: true } }, { text: "주택 구매 알아보기 🏠🔑", effects: { wealth: -5 }, nextEvent: 'buy_house_decision', ageUp: 1} ] },
{ id: 'try_for_baby', text: "아이를 갖기 위해 노력합니다. 곧 좋은 소식이 있을까요? 🙏", ageMin: 27, ageMax: 45, condition: (s,f) => f.isMarried && !f.isDINK && s.health > 40, choices: [ { text: "아이가 생겼다! 🎉👶", effects: { happiness: +30, health: -5, wealth: -20, relationshipWithSpouse: +15 }, nextEvent: 'parenting_first_child', ageUp: 1, setFlagFunction: (s,f) => { f.hasChildren++; f.childTraits.push({ name: `${f.hasChildren}째`, age: 0, intelligence: Math.floor(Math.random() * 5) + 8, educationSet: false}); } }, { text: "아직 소식이 없다... 😔", effects: { happiness: -10, relationshipWithSpouse: -5 }, nextEvent: (s) => s.age > 38 ? 'fertility_issues' : 'try_for_baby_again', ageUp: 1 } ] },
{ id: 'try_for_baby_again', text: "다시 아이를 갖기 위해 노력합니다. 이번엔 꼭! 🙏🙏🙏", ageMin: 28, ageMax: 45, condition: (s,f) => f.isMarried && !f.isDINK && s.health > 35 && f.hasChildren < 3, choices: [ { text: "드디어 아이가! 🥳👶", effects: { happiness: +25, health: -5, wealth: -20, relationshipWithSpouse: +10 }, nextEvent: 'parenting_first_child', ageUp: 1, setFlagFunction: (s,f) => { f.hasChildren++; f.childTraits.push({ name: `${f.hasChildren}째`, age: 0, intelligence: Math.floor(Math.random() * 5) + 7, educationSet: false}); } }, { text: "이번에도... 😭", effects: { happiness: -15, relationshipWithSpouse: -8 }, nextEvent: (s) => s.age > 42 ? 'accept_childless_or_adopt' : 'fertility_issues', ageUp: 1 } ] },
{ id: 'accept_childless_or_adopt', text: "계속 아이가 생기지 않아 고민입니다. 😔", ageMin: 35, ageMax: 50, condition: (s,f) => f.isMarried && !f.isDINK && f.hasChildren === 0, choices: [ { text: "아이 없이 살기로 한다. 😢", effects: { happiness: -10, relationshipWithSpouse: +5 }, nextEvent: 'dink_life', ageUp: 3, setFlag: { isDINK: true } }, { text: "입양을 고려해본다. ❤️", effects: { happiness: +20, wealth: -25, relationshipWithSpouse: +15 }, nextEvent: 'adoption_process', ageUp: 2 } ] },
{ id: 'adoption_process', text: "입양 절차를 밟기 시작했습니다. 새로운 가족을 맞이할 준비. 🤗", ageMin: 37, ageMax: 52, choices: [ { text: "드디어 아이를 입양했다! 🎉👨‍👩‍👧", effects: { happiness: +35, wealth: -10, relationshipWithSpouse: +20 }, nextEvent: 'parenting_first_child', ageUp: 1, setFlagFunction: (s,f) => { f.hasChildren++; f.childTraits.push({ name: `${f.hasChildren}째 (입양)`, age: Math.floor(Math.random()*3)+1, intelligence: Math.floor(Math.random() * 6) + 10, educationSet: false}); } }, { text: "입양 절차가 너무 복잡해... 😥", effects: { happiness: -10, wealth: -5 }, nextEvent: 'generic_mid_life', ageUp: 2 } ] },
{ id: 'parenting_first_child', text: () => `${currentFlags.childTraits[0]?.name || '아이'}가 태어났습니다! 🍼 육아는 힘들지만 행복합니다. 🥰`, ageMin: 28, ageMax: 55, condition: (s,f) => f.hasChildren > 0, choices: [ { text: "육아에 전념 🤱", effects: { happiness: +20, wealth: -15, intelligence: -2, relationshipWithSpouse: (s,f) => f.isMarried ? 5 : 0 }, nextEvent: 'child_grows_up', ageUp: 5 }, { text: "맞벌이하며 아이 키우기 💼👶", effects: { happiness: +10, wealth: +5, health: -5, relationshipWithSpouse: (s,f) => f.isMarried ? 3 : 0 }, nextEvent: 'child_grows_up_working_parent', ageUp: 5 } ] },
{ id: 'buy_house_decision', text: "내 집 마련의 꿈! 🏠 어떤 집을 살까요?", ageMin: 28, ageMax: 60, condition: (s, f) => !f.ownsHouse && s.wealth > 30, choices: [ { text: "대출 받아 아파트 구매 🏢🔑", effects: { wealth: (s) => s.wealth > 100 ? -50 : -30, happiness: +20, relationshipWithSpouse: (s,f) => f.isMarried ? 5 : 0 }, nextEvent: 'settled_down', ageUp: 1, setFlag: { ownsHouse: true, hasMortgage: true } }, { text: "전세로 좀 더 살기 🛋️", effects: { happiness: +5 }, nextEvent: 'generic_mid_life', ageUp: 2 }, { text: "아직은 시기상조 🤔", effects: {}, nextEvent: 'generic_mid_life', ageUp: 1} ] },
{ id: 'promotion_chance', text: "회사에서 승진 기회가 왔습니다! 🚀🎉", ageMin: 26, ageMax: 50, condition: (s,f) => f.employed, choices: [ { text: "승진 수락 (책임감 증가) 👔", effects: { wealth: +30, intelligence: +5, happiness: (s) => s.intelligence > 70 ? 10 : 0, health: -3 }, nextEvent: 'work_managerial_role', ageUp: 1, setFlag: { isManager: true } }, { text: "현재 위치에 만족 😊", effects: { happiness: +5 }, nextEvent: 'work_stable_employee', ageUp: 3 } ] },
{ id: 'office_social_life', text: "동료들과 회식/모임에 자주 참여하며 즐거운 시간을 보냅니다. 🍻🥳", ageMin: 24, ageMax: 40, choices: [ { text: "사내 인싸 등극! 😎", effects: { happiness: +10, wealth: +5, health: -2 }, nextEventRandom: true, ageUp: 2 }, { text: "적당히 어울리기 👍", effects: { happiness: +5 }, nextEventRandom: true, ageUp: 2 } ] },
{ id: 'relationship_stagnate', text: "연인과의 관계가 예전같지 않습니다. 권태기일까요? 💔", ageMin: 26, ageMax: 45, condition: (s,f) => f.inRelationship && !f.isMarried, choices: [ { text: "관계를 개선하려 노력한다 ❤️‍🩹", effects: { happiness: (s,f) => Math.random() > 0.5 ? 10 : -5, relationshipWithSpouse: (s,f) => Math.random() > 0.5 ? 15 : -10 }, nextEvent: 'relationship_develop', ageUp: 1 }, { text: "이별을 결심한다 👋", effects: { happiness: -15, relationshipWithSpouse: 0 }, nextEvent: 'break_up', ageUp: 1, setFlag: {inRelationship: false, relationshipWithSpouse:0 }} ] },
{ id: 'break_up', text: "슬프지만 연인과 헤어졌습니다. 새로운 시작을 준비해야 합니다. 😢➡️🌅", ageMin: 26, ageMax: 48, choices: [ { text: "일에 집중하며 잊는다 💼", effects: { intelligence: +3, wealth: +5, happiness: -5 }, nextEventRandom: true, ageUp: 2 }, { text: "친구들과 시간을 보낸다 🧑‍🤝‍🧑", effects: { happiness: +10, health: +2 }, nextEventRandom: true, ageUp: 2 }, { text: "새로운 사람을 찾아본다 🥰", effects: { happiness: +5 }, nextEvent: 'dating_life', ageUp: 1} ] },
{ id: 'marriage_conflict', text: () => `배우자와 사소한 일로 다퉜습니다. 😠 (${currentFlags.marriageDuration}년차 부부의 위기?)`, ageMin: 30, ageMax: 60, condition: (s, f) => f.isMarried && Math.random() < 0.2, choices: [ { text: "먼저 사과하고 대화로 푼다 🙏", effects: { happiness: +5, relationshipWithSpouse: +15 }, nextEventRandom: true, ageUp: 0 }, { text: "자존심 세우며 버틴다 😤", effects: { happiness: -5, relationshipWithSpouse: -10 }, nextEventRandom: true, ageUp: 0 }, { text: "각자의 시간을 갖는다 ⏳", effects: { relationshipWithSpouse: -5 }, nextEventRandom: true, ageUp: 0 } ] },
{ id: 'generic_mid_life', text: "중년의 삶. 경력은 안정되었지만, 때로는 새로운 자극이 필요합니다. 🤔", ageMin: 40, ageMax: 55, condition: (s, f) => f.employed || f.isMarried, onLoad: (s,f) => { if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + (s.age - (f.lastAgeUpdate || s.age)); f.lastAgeUpdate = s.age; }, choices: [ { text: "새로운 취미 시작 🎨🎸", effects: { happiness: +15, health: +5 }, nextEvent: 'midlife_hobby', ageUp: 3 }, { text: "건강 검진 받기 🩺", effects: { health: (s) => s.health > 60 ? 5 : -5 }, nextEvent: 'health_checkup_result', ageUp: 1 }, { text: "이직 고려 🔄️", condition: (s,f) => f.employed, effects: { happiness: -5 }, nextEvent: 'career_change_mid', ageUp: 1 }, { text: "자녀 학자금 마련 💰🎓", condition: (s,f) => f.hasChildren > 0 && f.childTraits.some(c => c.age >= 15 && c.age <=20), effects: { wealth: -20, happiness: +5 }, nextEvent: 'child_enters_college', ageUp: 2} ] },
{ id: 'child_grows_up', text: () => `${currentFlags.childTraits[0]?.name || '아이'}가 무럭무럭 자라 초등학교에 입학합니다. 🎒🥳`, ageMin: 33, ageMax: 60, condition: (s,f) => f.hasChildren > 0 && f.childTraits[0]?.age < 7, onLoad: (s,f) => { f.childTraits.forEach(c => c.age = (c.age||0) + 5); if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 5; }, choices: [ { text: "학부모 모임 참여 🧑‍🏫🤝", effects: { happiness: +5, intelligence: +1 }, nextEvent: 'child_teenager', ageUp: 5 }, { text: "아이 교육에 투자 📚💰", effects: { wealth: -30, intelligence: (s,f,c) => { if(f.childTraits[0]) f.childTraits[0].intelligence = (f.childTraits[0].intelligence || 10) + 5; return 0; }, happiness: +3 }, nextEvent: 'child_teenager', ageUp: 5} ] },
{ id: 'child_grows_up_working_parent', text: () => `바쁜 와중에도 ${currentFlags.childTraits[0]?.name || '아이'}는 잘 자라 초등학교에 입학합니다. 🥳🏫`, ageMin: 33, ageMax: 60, condition: (s,f) => f.hasChildren > 0 && f.childTraits[0]?.age < 7, onLoad: (s,f) => { f.childTraits.forEach(c => c.age = (c.age||0) + 5); if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 5; }, choices: [ { text: "주말엔 아이와 시간 보내기 👨‍👩‍👧‍👦❤️", effects: { happiness: +10, health: -2, relationshipWithSpouse: (s,f) => f.isMarried ? 3 : 0 }, nextEvent: 'child_teenager', ageUp: 5 }, { text: "아이 학원 보내기 📖✍️", effects: { wealth: -25, intelligence: (s,f,c) => { if(f.childTraits[0]) f.childTraits[0].intelligence = (f.childTraits[0].intelligence || 10) + 3; return 0; }, happiness: +1 }, nextEvent: 'child_teenager', ageUp: 5} ] },
{ id: 'child_teenager', text: () => `${currentFlags.childTraits[0]?.name || '아이'}가 질풍노도의 시기, 십대가 되었습니다. 🌪️ 가끔 반항도 합니다. 😒`, ageMin: 38, ageMax: 65, condition: (s,f) => f.hasChildren > 0 && f.childTraits[0]?.age >= 12 && f.childTraits[0]?.age < 18, onLoad: (s,f) => { f.childTraits.forEach(c => c.age = (c.age||0) + 5); if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 5;}, choices: [ { text: "대화로 풀어나가기 🗣️❤️", effects: { happiness: +10, intelligence: +2, relationshipWithSpouse: (s,f) => f.isMarried ? 5 : 0 }, nextEvent: 'child_enters_college', ageUp: 5 }, { text: "엄격하게 훈육하기 😠", effects: { happiness: -5, intelligence: -1, health: -2, relationshipWithSpouse: (s,f) => f.isMarried ? -3 : 0 }, nextEvent: 'child_college_issues', ageUp: 5 } ] },
{ id: 'child_enters_college', text: () => `${currentFlags.childTraits[0]?.name || '아이'}${ (currentFlags.childTraits[0]?.intelligence > 15 ? '명문' : '') }대학에 합격했습니다! 🎉 자랑스럽지만 학비 부담이... 💸 독립할 때가 된 걸까요?`, ageMin: 43, ageMax: 70, condition: (s,f) => f.hasChildren > 0 && f.childTraits[0]?.age >= 18, onLoad: (s,f) => { f.childTraits.forEach(c => c.age = (c.age||0) + 4); if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 4;}, choices: [ { text: "학비 전액 지원 💰🎓", effects: { wealth: -80, happiness: +15, relationshipWithSpouse: (s,f) => f.isMarried ? 5 : 0 }, nextEvent: 'child_graduates_college', ageUp: 4 }, { text: "일부 지원 및 독립 격려 👍🏠", effects: { wealth: -40, happiness: +10, relationshipWithSpouse: (s,f) => f.isMarried ? 3 : 0 }, nextEvent: 'child_graduates_college_independent', ageUp: 4 } ] },
{ id: 'child_college_issues', text: () => `${currentFlags.childTraits[0]?.name || '아이'}가 대학 생활에 어려움을 겪는 듯 합니다. 😥`, ageMin: 43, ageMax: 70, condition: (s,f) => f.hasChildren > 0 && f.childTraits[0]?.age >= 18, onLoad: (s,f) => { f.childTraits.forEach(c => c.age = (c.age||0) + 4); if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 4;}, choices: [ { text: "따뜻하게 격려하고 지원한다 ❤️", effects: { wealth: -10, happiness: +10, intelligence: (s,f,c) => { if(f.childTraits[0]) f.childTraits[0].intelligence = (f.childTraits[0].intelligence || 10) + 1; return 0; } }, nextEvent: 'child_graduates_college', ageUp: 4 }, { text: "스스로 해결하도록 둔다 🤔", effects: { happiness: -5, intelligence: (s,f,c) => { if(f.childTraits[0]) f.childTraits[0].intelligence = (f.childTraits[0].intelligence || 10) -1; return 0; } }, nextEvent: 'child_graduates_college_independent', ageUp: 4 } ] },
{ id: 'child_graduates_college', text: () => `${currentFlags.childTraits[0]?.name || '아이'}가 대학을 졸업하고 사회에 첫 발을 내딛습니다! 🎓🎉 뿌듯합니다.`, ageMin: 47, ageMax: 74, condition: (s,f) => f.hasChildren > 0 && f.childTraits[0]?.age >= 22, onLoad: (s,f) => { f.childTraits.shift(); if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 2;}, choices: [ { text: "취업 축하 선물 🎁", effects: { wealth: -20, happiness: +10 }, nextEventRandom: true, ageUp: 2 }, { text: "독립 자금 지원 💰🏠", effects: { wealth: -50, happiness: +5 }, nextEventRandom: true, ageUp: 2 } ] },
{ id: 'child_graduates_college_independent', text: () => `${currentFlags.childTraits[0]?.name || '아이'}가 독립적으로 대학을 졸업하고 사회생활을 시작합니다. 대견합니다. 👍`, ageMin: 47, ageMax: 74, condition: (s,f) => f.hasChildren > 0 && f.childTraits[0]?.age >= 22, onLoad: (s,f) => { f.childTraits.shift(); if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 2;}, choices: [ { text: "따뜻한 격려의 말 ❤️", effects: { happiness: +10 }, nextEventRandom: true, ageUp: 2 }, { text: "가끔 용돈 주기 💵", effects: { wealth: -10, happiness: +5 }, nextEventRandom: true, ageUp: 2 } ] },
{ id: 'health_checkup_result', text: "건강검진 결과, 약간의 관리가 필요하다는 진단을 받았습니다. 🩺😟", ageMin: 41, ageMax: 65, choices: [ { text: "운동 시작 및 식단 관리 🥗🏃‍♂️", effects: { health: +15, happiness: +5 }, nextEvent: 'midlife_health_improve', ageUp: 3 }, { text: "무시하고 평소처럼 생활 🍔🍟", effects: { health: -10, happiness: -3 }, nextEvent: 'midlife_health_decline', ageUp: 3 } ] },
{ id: 'midlife_hobby', text: "새로운 취미로 삶의 활력을 찾았습니다! 😊", ageMin: 43, ageMax: 58, choices: [ { text: "취미 동호회 활동 🤝", effects: { happiness: +10, health: +2 }, nextEventRandom: true, ageUp: 2 }, { text: "전문가 수준으로 발전 🌟", effects: { happiness: +5, intelligence: +3 }, nextEventRandom: true, ageUp: 2 } ] },
{ id: 'midlife_health_improve', text: "건강 관리를 시작하니 몸이 가뿐해졌습니다! 💪✨", ageMin: 44, ageMax: 68, choices: [ { text: "꾸준히 유지하기 👍", effects: { health: +5, happiness: +3 }, nextEventRandom: true, ageUp: 3 }, { text: "마라톤 도전! 🏃‍♀️🏅", effects: { health: +10, happiness: +8, wealth: -5 }, nextEventRandom: true, ageUp: 3} ] },
{ id: 'midlife_health_decline', text: "건강 관리를 소홀히 했더니 여기저기 쑤시기 시작합니다... 😥", ageMin: 44, ageMax: 68, choices: [ { text: "이제라도 관리 시작 😟", effects: { health: +5, happiness: -2 }, nextEvent: 'midlife_health_improve', ageUp: 2 }, { text: "어쩔 수 없지... 🤷", effects: { health: -8, happiness: -5 }, nextEventRandom: true, ageUp: 2, checkHealthDeath: true} ] },
{ id: 'career_change_mid', text: "중년에 이직을 결심했습니다. 새로운 도전! 🔥", ageMin: 40, ageMax: 55, condition: (s,f) => f.employed, choices: [ { text: "연봉 높은 곳으로 💰", effects: { wealth: +30, happiness: -3, intelligence: +2 }, nextEvent: 'work_new_company_mid', ageUp: 2, setFlag:{isManager: false} }, { text: "워라밸 좋은 곳으로 ⚖️", effects: { wealth: -10, happiness: +15, health: +5 }, nextEvent: 'work_new_company_mid_워라밸', ageUp: 2, setFlag:{isManager: false} }, { text: "아예 다른 분야로! 🚀", effects: { wealth: -20, happiness: +10, intelligence: +5 }, nextEvent: 'career_pivot_mid', ageUp: 3, setFlag:{isManager: false} } ] },
{ id: 'retirement_decision', text: "정년퇴직의 시간이 다가옵니다. ⏳ 은퇴 후 무엇을 할까요?", ageMin: 58, ageMax: 70, condition: (s,f) => f.employed && !f.retired, choices: [ { text: "은퇴 후 여가 즐기기 ✈️🎣", effects: { happiness: +20, health: +5, wealth: (s) => s.wealth > 300 ? -10 : -20 }, nextEvent: 'retired_life_leisure', ageUp: 5, setFlag: { retired: true, employed: false } }, { text: "소일거리 찾기 (자문 등) 🧑‍🏫💼", effects: { happiness: +10, wealth: +15 }, nextEvent: 'retired_life_working', ageUp: 5, setFlag: { retired: true, employed: true } }, { text: "귀농/귀촌 생활 🧑‍🌾🏞️", effects: { happiness: +15, health: +10, wealth: -50 }, nextEvent: 'retired_life_country', ageUp: 5, setFlag: { retired: true, employed: false } } ] },
{ id: 'grand_children_news', text: "자녀에게서 손주가 태어났다는 기쁜 소식을 듣습니다! 🥳👶🎉", ageMin: 50, ageMax: 80, condition: (s,f) => f.hasChildren > 0 && f.childTraits.length === 0 && Math.random() < 0.3, onLoad: (s,f) => { if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 3;}, choices: [ { text: "손주 돌보미 자처 🥰", effects: { happiness: +25, health: -5, wealth: -10, relationshipWithSpouse: (s,f) => f.isMarried ? 5 : 0 }, nextEvent: 'grandparent_life', ageUp: 3 }, { text: "가끔 보며 용돈 주기 💰🎁", effects: { happiness: +15, wealth: -5, relationshipWithSpouse: (s,f) => f.isMarried ? 3 : 0 }, nextEvent: 'enjoy_grandkids_occasionally', ageUp: 3 } ] },
{ id: 'late_life_health_issue', text: "나이가 들면서 건강이 예전 같지 않습니다. 병원 방문이 잦아집니다. 😥🏥", ageMin: 70, ageMax: 90, onLoad: (s,f) => { if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 3;}, choices: [ { text: "꾸준히 건강 관리 💪", effects: { health: +5, happiness: +2 }, nextEvent: 'peaceful_old_age', ageUp: 3 }, { text: "마음 편히 지내기 😌", effects: { health: -5, happiness: +5 }, nextEvent: 'declining_health_old_age', ageUp: 3, checkHealthDeath: true } ] },
{ id: 'spouse_illness', text: "배우자가 건강 문제로 힘들어합니다. 😢 간병이 필요합니다.", ageMin: 65, ageMax: 85, condition: (s,f) => f.isMarried && s.relationshipWithSpouse > 30, onLoad: (s,f) => { f.marriageDuration = (f.marriageDuration || 0) + 2;}, choices: [ { text: "정성껏 간병한다 ❤️‍🩹", effects: { happiness: -10, health: -8, wealth: -15, relationshipWithSpouse: +20 }, nextEvent: 'spouse_recovery_or_loss', ageUp: 2 }, { text: "전문 간병인 고용 🧑‍⚕️💰", effects: { happiness: -5, wealth: -30, relationshipWithSpouse: +5 }, nextEvent: 'spouse_recovery_or_loss', ageUp: 2 } ] },
{ id: 'spouse_recovery_or_loss', text: "배우자의 건강이 어떻게 될까요?", ageMin: 67, ageMax: 87, condition: (s,f) => f.isMarried, onLoad: (s,f) => { f.marriageDuration = (f.marriageDuration || 0) + (currentStats.age - (f.lastAgeUpdateForSpouse || s.age)); f.lastAgeUpdateForSpouse = s.age;}, choices: [ { text: "배우자가 건강을 회복했다! 🎉", effects: { happiness: +20, health: +5, relationshipWithSpouse: +15 }, nextEventRandom: true, ageUp: 0, condition: (s,f) => Math.random() > 0.4 }, { text: "배우자가 세상을 떠났다... 💔", effects: { happiness: -30, health: -10 }, nextEvent: 'widowed_life', ageUp: 0, setFlag: {isMarried: false, relationshipWithSpouse: 0}, condition: (s,f) => Math.random() <= 0.4 } ] },
{ id: 'widowed_life', text: "배우자를 먼저 떠나보내고 홀로 남았습니다. 깊은 슬픔에 잠깁니다. 😔", ageMin: 67, ageMax: 90, choices: [ { text: "추억을 되새기며 살아간다... 🖼️", effects: { happiness: -10, health: -5 }, nextEventRandom: true, ageUp: 3 }, { text: "새로운 활동으로 슬픔을 극복한다 💪", effects: { happiness: +5 }, nextEventRandom: true, ageUp: 3 }, { text: "자녀/손주에게 의지한다 👨‍👩‍👧‍👦", condition: (s,f) => f.hasChildren > 0 || f.grandChildren > 0, effects: { happiness: +10, wealth: -5 }, nextEventRandom: true, ageUp: 3} ] },
{ id: 'reflect_on_life', text: "황혼기에 접어들어 지나온 삶을 되돌아봅니다. 많은 일들이 있었습니다. 🤔🌅", ageMin: 80, ageMax: 95, onLoad: (s,f) => { if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 2;}, choices: [ { text: "만족스러운 삶이었다 😊✨", effects: { happiness: (s) => s.happiness > 60 ? 20 : 5 }, nextEvent: 'final_years', ageUp: 2 }, { text: "후회가 남는 부분도 있다 😟", effects: { happiness: (s) => s.happiness < 40 ? -10 : -2 }, nextEvent: 'final_years_regret', ageUp: 2 } ] },
{ id: 'retired_life_leisure', text: "은퇴 후 여행, 취미 생활 등 여유로운 시간을 보냅니다. 悠々自適! 🏖️", ageMin: 63, ageMax: 80, condition: (s,f) => f.retired, onLoad: (s,f) => { if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 5;}, choices: [{ text: "매일이 즐겁다! 😄", effects: { happiness: +10, health: +3 }, nextEventRandom: true, ageUp: 5 }] },
{ id: 'retired_life_working', text: "은퇴 후에도 자문 등으로 소소하게 일을 계속합니다. 아직 젊다! 💪", ageMin: 63, ageMax: 80, condition: (s,f) => f.retired && f.employed, onLoad: (s,f) => { if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 5;}, choices: [{ text: "보람찬 노년! 👍", effects: { happiness: +8, wealth: +10, intelligence: +1 }, nextEventRandom: true, ageUp: 5 }] },
{ id: 'retired_life_country', text: "귀농/귀촌하여 자연과 함께 평화로운 노년을 보냅니다. 🌳🏞️", ageMin: 63, ageMax: 80, condition: (s,f) => f.retired, onLoad: (s,f) => { if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 5;}, choices: [{ text: "공기가 맑다! 😊", effects: { happiness: +10, health: +8 }, nextEventRandom: true, ageUp: 5 }] },
{ id: 'grandparent_life', text: "손주들을 돌보며 제2의 육아를 경험합니다. 힘들지만 귀엽네요! 🥰👶", ageMin: 53, ageMax: 83, condition: (s,f) => f.hasChildren > 0 || f.grandChildren > 0, onLoad: (s,f) => { if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 3; f.grandChildren = (f.grandChildren || 0) +1;}, choices: [{ text: "손주 재롱에 시간 가는 줄 모른다 😄", effects: { happiness: +15, health: -3 }, nextEventRandom: true, ageUp: 3 }] },
{ id: 'enjoy_grandkids_occasionally', text: "가끔 손주들을 만나 즐거운 시간을 보냅니다. 용돈 주는 재미! 🎁💰", ageMin: 53, ageMax: 83, condition: (s,f) => f.hasChildren > 0 || f.grandChildren > 0, onLoad: (s,f) => { if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 3; f.grandChildren = (f.grandChildren || 0) +1;}, choices: [{ text: "귀여운 것들! 🥰", effects: { happiness: +10, wealth: -3 }, nextEventRandom: true, ageUp: 3 }] },
{ id: 'peaceful_old_age', text: "마음의 평화를 찾고, 건강도 그럭저럭 유지하며 노년을 보냅니다. 🍵😌", ageMin: 73, ageMax: 93, onLoad: (s,f) => { if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 3;}, choices: [{ text: "하루하루가 감사하다 🙏", effects: { happiness: +5, health: +2 }, nextEventRandom: true, ageUp: 3 }] },
{ id: 'declining_health_old_age', text: "몸이 점점 약해지는 것을 느낍니다. 그래도 긍정적으로! 💪😊", ageMin: 73, ageMax: 93, onLoad: (s,f) => { if(f.isMarried) f.marriageDuration = (f.marriageDuration || 0) + 3;}, choices: [{ text: "버텨보자! 😤", effects: { health: -3, happiness: +3 }, nextEventRandom: true, ageUp: 3, checkHealthDeath: true }] },
{ id: 'random_lottery_win_small', text: "길에서 긁은 복권이 소소하게 당첨되었습니다! 🥳 ($50)", isRandomEvent: true, probability: 0.02, choices: [ { text: "꽁돈이다! 🤩", effects: { wealth: +50, happiness: +10 }, nextEventRandom: true, ageUp: 0 } ] },
{ id: 'random_lottery_win_big', text: "세상에! 복권 1등에 당첨되었습니다! 💰💰💰 ($500)", isRandomEvent: true, probability: 0.005, condition: (s,f) => s.age > 25, choices: [ { text: "인생 역전! 🚀", effects: { wealth: +500, happiness: +50, health: +5 }, nextEventRandom: true, ageUp: 0 } ] },
{ id: 'random_minor_illness', text: "가벼운 감기에 걸려 며칠 고생했습니다. 🤧", isRandomEvent: true, probability: 0.05, condition: (s,f) => s.health > 20, choices: [ { text: "푹 쉬어야지... 🛌", effects: { health: -10, happiness: -5 }, nextEventRandom: true, ageUp: 0 } ] },
{ id: 'random_find_money', text: "길에서 $20짜리 지폐를 주웠습니다! 횡재! 💵", isRandomEvent: true, probability: 0.03, choices: [ { text: "오늘 운수대통! 😄", effects: { wealth: +20, happiness: +5 }, nextEventRandom: true, ageUp: 0 } ] },
{ id: 'random_petty_theft', text: "이런! 소매치기를 당해 지갑을 잃어버렸습니다... 😩 ($ -30)", isRandomEvent: true, probability: 0.015, condition: (s,f) => s.wealth >= 30, choices: [ { text: "액땜했다 치자... 😭", effects: { wealth: -30, happiness: -10 }, nextEventRandom: true, ageUp: 0 } ] },
{ id: 'random_unexpected_bonus', text: "회사에서 예상치 못한 보너스를 받았습니다! 🎉 ($ +100)", isRandomEvent: true, probability: 0.01, condition: (s,f) => f.employed, choices: [ { text: "사장님 최고! 👍", effects: { wealth: +100, happiness: +15 }, nextEventRandom: true, ageUp: 0 } ] },
{ id: 'random_stock_market_crash', text: "주식 시장이 폭락하여 투자금의 일부를 잃었습니다... 📉😭 (재산의 10% 감소)", isRandomEvent: true, probability: 0.01, condition: (s,f) => s.wealth > 100 && f.investedInStocks, choices: [ { text: "존버는 승리한다...? 😥", effects: { wealth: (s) => -Math.floor(s.wealth * 0.1), happiness: -10 }, nextEventRandom: true, ageUp: 0 } ] },
{ id: 'random_meet_old_friend', text: "길에서 우연히 오랜 친구를 만났습니다! 반가운 마음에 회포를 풀었습니다. 🧑‍🤝‍🧑", isRandomEvent: true, probability: 0.04, choices: [ { text: "즐거운 시간! 😊", effects: { happiness: +15, health: +2 }, nextEventRandom: true, ageUp: 0 } ] },
{ id: 'random_natural_disaster_minor', text: "가벼운 지진/태풍으로 인해 집에 약간의 피해가 발생했습니다. 수리비가... ($ -50) 🏠💥", isRandomEvent: true, probability: 0.008, condition: (s,f) => f.ownsHouse, choices: [ { text: "보험 처리해야 하나... 😟", effects: { wealth: -50, happiness: -5 }, nextEventRandom: true, ageUp: 0 } ] },
{ id: 'start_carpet_sales', text: "딱히 할 일이 없어... 동네 카펫 가게에서 판매원으로 일하기 시작합니다. '어서오세요, 고객님! 어떤 카펫을 찾으시나요?' 🧶", ageMin: 18, ageMax: 30, condition: (s,f) => !f.employed && s.intelligence < 50 && !f.hasDegree, choices: [ { text: "열심히 팔아보자! 💪", effects: { wealth: +10, happiness: +3, intelligence: +1 }, nextEvent: 'carpet_sales_grind', ageUp: 2, setFlag: { employed: true, careerPath: 'carpet_salesman' } } ] },
{ id: 'carpet_sales_grind', text: "카펫 판매에 점차 익숙해집니다. 생각보다 적성에 맞는 것 같기도? 🧐", ageMin: 20, ageMax: 40, condition: (s,f) => f.careerPath === 'carpet_salesman', choices: [ { text: "더 많은 고객 유치 🗣️", effects: { wealth: +15, happiness: +5, intelligence: +2 }, nextEvent: (s) => s.intelligence > 30 && s.wealth > 50 ? 'carpet_sales_promotion' : 'carpet_sales_grind', ageUp: 3 }, { text: "그냥저냥 시간 때우기 ⏳", effects: { wealth: +5, happiness: -2 }, nextEvent: 'career_crisis_mid', ageUp: 3 } ] },
{ id: 'carpet_sales_promotion', text: "뛰어난 판매 실적을 인정받아 매니저로 승진했습니다! 이제 카펫 제국을 건설할 시간인가? 👑", ageMin: 25, ageMax: 50, condition: (s,f) => f.careerPath === 'carpet_salesman' && s.intelligence > 30, choices: [ { text: "사업 확장! 🚀", effects: { wealth: +50, intelligence: +5, happiness: +10 }, nextEvent: 'carpet_empire_building', ageUp: 5, setFlag: { careerPath: 'carpet_manager', isManager: true } }, { text: "이 정도면 만족. 😌", effects: { wealth: +20 }, nextEvent: 'work_stable_employee', ageUp: 5 } ] },
{ id: 'carpet_empire_building', text: "당신의 카펫 가게는 전국적인 체인으로 성장했습니다! '카펫왕 로이'라는 별명까지 얻었군요. 💸", ageMin: 30, ageMax: 60, condition: (s,f) => f.careerPath === 'carpet_manager' && s.wealth > 200, choices: [ { text: "카펫으로 세계 정복! 🌍", effects: { wealth: +200, happiness: +20, intelligence: +3 }, nextEvent: 'carpet_sales_tycoon_achieved', ageUp: 5, setFlag: { careerPath: 'carpet_sales_tycoon'} }, { text: "이제 은퇴할까... 🏖️", effects: { wealth: +50, happiness: +10 }, nextEvent: 'retirement_decision', ageUp: 3, setFlag:{retired:true, employed: false}} ] },
{ id: 'carpet_sales_tycoon_achieved', text: "당신은 전설적인 카펫 판매 거물이 되었습니다! 융단 위를 나는 기분입니다. 🥳 이제 당신의 이름은 역사에 길이 남을 것입니다.", ageMin: 35, ageMax: 70, isEndingSegment: true, choices: [ { text: "계속 사업 운영하기 📈", effects: { wealth: +50, happiness: +5 }, nextEventRandom: true, ageUp: 5 }, { text: "자선 사업에 힘쓰기 🙏", effects: { wealth: -100, happiness: +30 }, nextEvent: 'philanthropist_life', ageUp: 5 } ] },
{ id: 'philanthropist_life', text: "카펫으로 번 돈을 사회에 환원하며 존경받는 자선사업가로 살아갑니다. ❤️🌍", ageMin: 40, ageMax: 80, choices: [{ text: "세상이 조금 더 따뜻해졌기를... 😊", effects: {happiness: +20, health: +5}, nextEventRandom: true, ageUp: 5}] },
{ id: 'final_years', text: "평화로운 마지막 날들을 보냅니다. 가족과 친구들이 곁에 있습니다. 😊🌅", ageMin: 82, ageMax: 98, choices: [{ text: "조용히 눈을 감다... 🌙", effects: {}, nextEvent: 'death_peaceful', ageUp: 1 }] },
{ id: 'final_years_regret', text: "후회와 아쉬움 속에서 마지막 날들을 보냅니다. 😟", ageMin: 82, ageMax: 98, choices: [{ text: "쓸쓸히 눈을 감다... 🍂", effects: { happiness: -10 }, nextEvent: 'death_lonely', ageUp: 1 }] },
{ id: 'death_peaceful', text: "당신은 평화롭게 잠들었습니다. 🌙 많은 이들이 당신을 기억할 것입니다.", isEnding: true, message: (s) => `향년 ${s.age}세. 당신은 행복 ${s.happiness}, 건강 ${s.health}, 지능 ${s.intelligence}, 재산 ${s.wealth}을 남기고 평화롭게 생을 마감했습니다. 정말 잘 살아낸 인생이었습니다! 🎉` },
{ id: 'death_lonely', text: "당신은 외롭게 생을 마감했습니다. 😥", isEnding: true, message: (s) => `향년 ${s.age}세. 당신은 행복 ${s.happiness}, 건강 ${s.health}, 지능 ${s.intelligence}, 재산 ${s.wealth}을 남기고 다소 쓸쓸하게 생을 마감했습니다. 다음 생에는 더 많은 연결을 만들어보세요. 🔗` },
{ id: 'death_health', text: "건강 악화로 인해 더 이상 버티지 못하고 눈을 감습니다. 💔", isEnding: true, message: (s) => `향년 ${s.age}세. 건강을 더 챙겼더라면... 💊 당신은 행복 ${s.happiness}, 지능 ${s.intelligence}, 재산 ${s.wealth}을 남기고 병상에서 생을 마감했습니다.` },
{ id: 'death_accident', text: "불의의 사고로 갑작스럽게 세상을 떠났습니다. 💥", isEnding: true, message: (s) => `향년 ${s.age}세. 예상치 못한 사고였습니다. ⚡ 당신은 행복 ${s.happiness}, 건강 ${s.health}, 지능 ${s.intelligence}, 재산 ${s.wealth}을 남기고 갑작스럽게 생을 마감했습니다.` },
{ id: 'death_wealth_extreme_poverty', text: "극심한 가난과 빚에 시달리다 생을 마감합니다. 📉", isEnding: true, condition: (s, f) => s.wealth < -200 && s.age > 50, message: (s) => `향년 ${s.age}세. 재정 관리에 실패하여 힘겨운 말년을 보냈습니다. 💸 다음 생에는 더 현명한 재테크를...` },
{ id: 'death_broken_heart', text: "깊은 슬픔과 외로움 속에서 심장이 멈췄습니다. 💔", isEnding: true, condition: (s, f) => s.happiness < -30 && s.age > 40 && !f.isMarried && f.hasChildren === 0, message: (s) => `향년 ${s.age}세. 마음의 상처가 너무 컸습니다. 😢 행복을 찾는 여정은 쉽지 않았군요.` }
];
}
initGameDataEvents();
function startGame(loadSave) {
if (loadSave && localStorage.getItem(GAME_SAVE_KEY)) {
const savedData = JSON.parse(localStorage.getItem(GAME_SAVE_KEY));
currentStats = savedData.stats;
currentFlags = savedData.flags;
lifeEventsLog = savedData.lifeLog;
currentAchievements = savedData.achievements;
gameData.currentEventId = savedData.currentEventId;
} else {
currentStats = JSON.parse(JSON.stringify(gameData.stats));
currentFlags = JSON.parse(JSON.stringify(gameData.flags));
lifeEventsLog = [];
currentAchievements = JSON.parse(JSON.stringify(gameData.achievements));
Object.keys(currentAchievements).forEach(key => currentAchievements[key].achieved = false);
gameData.currentEventId = 'birth';
}
startScreen.classList.add('hidden');
endScreen.classList.add('hidden');
gameContent.classList.remove('hidden');
if (currentFlags.isMarried || currentStats.relationshipWithSpouse !== 0) {
spouseRelationshipContainer.classList.remove('hidden');
} else {
spouseRelationshipContainer.classList.add('hidden');
}
updateStatsDisplay();
checkAllAchievements();
loadEvent(gameData.currentEventId || 'birth');
}
function saveGame() {
const saveData = {
stats: currentStats, flags: currentFlags, lifeLog: lifeEventsLog,
achievements: currentAchievements, currentEventId: gameData.currentEventId
};
localStorage.setItem(GAME_SAVE_KEY, JSON.stringify(saveData));
alert("💾 인생이 저장되었습니다!");
}
function checkLoadButtonVisibility() {
if (localStorage.getItem(GAME_SAVE_KEY)) {
loadButton.classList.remove('hidden');
} else {
loadButton.classList.add('hidden');
}
}
checkLoadButtonVisibility();
function updateStatsDisplay() {
const statsToUpdate = {
'age-stat': currentStats.age, 'health-stat': Math.max(0, currentStats.health),
'happiness-stat': currentStats.happiness, 'intelligence-stat': currentStats.intelligence,
'wealth-stat': currentStats.wealth, 'spouse-relationship-stat': currentStats.relationshipWithSpouse
};
for (const id in statsToUpdate) {
const el = document.getElementById(id);
if (el) {
const strongEl = el.parentElement.querySelector('strong') || el;
const oldValue = parseInt(strongEl.textContent);
if (oldValue !== statsToUpdate[id]) {
const statContainer = el.closest('.stat');
if (statContainer) {
statContainer.classList.add('stat-changed');
setTimeout(() => statContainer.classList.remove('stat-changed'), 500);
}
}
strongEl.textContent = statsToUpdate[id];
}
}
if (currentFlags.isMarried || currentStats.relationshipWithSpouse !== 0) {
spouseRelationshipContainer.classList.remove('hidden');
} else {
spouseRelationshipContainer.classList.add('hidden');
}
const agePercentage = Math.min(100, (currentStats.age / gameData.maxAge) * 100);
ageBar.style.width = agePercentage + '%';
ageBar.textContent = currentStats.age > 0 ? `${currentStats.age}세` : "";
}
function applyEffects(effects) {
for (const stat in effects) {
if (typeof effects[stat] === 'function') {
currentStats[stat] += effects[stat](currentStats, currentFlags, {});
} else { currentStats[stat] += effects[stat]; }
}
currentStats.health = Math.min(100, Math.max(0, currentStats.health));
currentStats.happiness = Math.min(100, Math.max(-50, currentStats.happiness));
currentStats.intelligence = Math.max(0, currentStats.intelligence);
currentStats.wealth = Math.max(-1000, currentStats.wealth);
if (currentFlags.isMarried || currentFlags.inRelationship) { // 연애 중이거나 결혼했을 때만 관계도 업데이트
currentStats.relationshipWithSpouse = Math.min(100, Math.max(-50, currentStats.relationshipWithSpouse));
}
}
function setEventFlags(flagsToSet) {
if (flagsToSet) {
for (const flag in flagsToSet) { currentFlags[flag] = flagsToSet[flag]; }
}
}
function applySetFlagFunction(setFlagFunction) {
if (setFlagFunction && typeof setFlagFunction === 'function') {
setFlagFunction(currentStats, currentFlags);
}
}
function loadEvent(eventId) {
let event = gameData.events.find(e => e.id === eventId);
if (!event) {
event = findRandomAvailableEvent();
if (!event) {
console.error("No valid event found, defaulting to death_accident."); // Added for debugging
loadEvent('death_accident');
return;
}
eventId = event.id;
}
gameData.currentEventId = eventId;
if (typeof event.onLoad === 'function') { event.onLoad(currentStats, currentFlags); }
eventTextDisplay.textContent = typeof event.text === 'function' ? event.text(currentStats, currentFlags) : event.text;
if (lifeEventsLog.length === 0 || lifeEventsLog[lifeEventsLog.length -1].event !== eventTextDisplay.textContent) {
lifeEventsLog.push({age: currentStats.age, event: eventTextDisplay.textContent, choice: null });
}
choicesContainer.innerHTML = '';
let choicesAvailable = false;
// MODIFIED PART: Check if event.choices exists and is an array before iterating
if (event.choices && Array.isArray(event.choices)) {
event.choices.forEach((choice, index) => {
if (choice.condition && !choice.condition(currentStats, currentFlags)) { return; }
const button = document.createElement('button');
button.innerHTML = typeof choice.text === 'function' ? choice.text(currentStats, currentFlags) : choice.text;
button.addEventListener('click', () => processChoice(choice));
choicesContainer.appendChild(button);
choicesAvailable = true;
});
}
updateStatsDisplay();
checkAllAchievements();
if (event.isEnding) {
endGame(event);
} else if (!choicesAvailable && !event.isEndingSegment) { // isEndingSegment events might have choices but lead to ending
// If it's not an ending event and no choices were rendered (e.g., all conditions false, or empty choices array)
// This indicates a potential dead-end in the game logic for this event.
console.warn(`Event "${eventId}" is non-ending but rendered no choices. Attempting to auto-advance.`);
lifeEventsLog.push({age: currentStats.age, event: `(시스템: '${eventId}' 이벤트에서 선택지가 없어 자동으로 진행합니다.)`, choice: "자동 진행"});
currentStats.age += 1; // Slightly advance age to help break potential loops
const nextEventAfterStuck = findRandomAvailableEvent();
if (nextEventAfterStuck) {
loadEvent(nextEventAfterStuck.id);
} else {
loadEvent('death_accident'); // Fallback if still no event can be found
}
}
}
function processChoice(choice) {
if (choice.effects) { applyEffects(choice.effects); }
if (choice.setFlag) { setEventFlags(choice.setFlag); }
if (choice.setFlagFunction) { applySetFlagFunction(choice.setFlagFunction); }
if(lifeEventsLog.length > 0 && lifeEventsLog[lifeEventsLog.length-1].choice === null) {
lifeEventsLog[lifeEventsLog.length -1].choice = typeof choice.text === 'function' ? choice.text(currentStats, currentFlags) : choice.text;
}
if (choice.outcomeMessage) {
const outcome = typeof choice.outcomeMessage === 'function' ? choice.outcomeMessage(currentStats, currentFlags) : choice.outcomeMessage;
lifeEventsLog.push({age: currentStats.age, event: outcome, choice: "결과"});
}
const ageIncrement = choice.ageUp !== undefined ? choice.ageUp : Math.floor(Math.random() * 2) + 1;
if (ageIncrement > 0) {
currentStats.age += ageIncrement;
if (currentFlags.isMarried) { currentFlags.marriageDuration = (currentFlags.marriageDuration || 0) + ageIncrement; }
if (currentFlags.childTraits && currentFlags.childTraits.length > 0) {
currentFlags.childTraits.forEach(child => { child.age = (child.age || 0) + ageIncrement; });
}
}
updateStatsDisplay(); // Update stats after age increment and effects
// Check for game-ending conditions first
if (choice.checkHealthDeath && currentStats.health <= 0) { loadEvent('death_health'); return; }
if (currentStats.health <= 0) { loadEvent('death_health'); return; } // General health check
if (currentStats.age >= gameData.maxAge) {
if (currentStats.happiness > 70 && currentStats.health > 50) loadEvent('death_peaceful');
else if (currentStats.happiness < 20 && currentStats.health < 30) loadEvent('death_lonely');
else loadEvent('reflect_on_life'); // reflect_on_life has choices leading to final ending
return;
}
const povertyEnding = gameData.events.find(e => e.id === 'death_wealth_extreme_poverty');
if (povertyEnding && povertyEnding.condition && povertyEnding.condition(currentStats, currentFlags)) { loadEvent('death_wealth_extreme_poverty'); return; }
const brokenHeartEnding = gameData.events.find(e => e.id === 'death_broken_heart');
if (brokenHeartEnding && brokenHeartEnding.condition && brokenHeartEnding.condition(currentStats, currentFlags)) { loadEvent('death_broken_heart'); return; }
// Determine next event
let nextEventId;
if (typeof choice.nextEvent === 'function') { nextEventId = choice.nextEvent(currentStats, currentFlags); }
else { nextEventId = choice.nextEvent; }
if (choice.nextEventRandom) {
const randomEv = findRandomAvailableEvent(true);
nextEventId = randomEv ? randomEv.id : null;
}
if (nextEventId) {
loadEvent(nextEventId);
} else {
const randomEvent = findRandomAvailableEvent();
if (randomEvent) {
loadEvent(randomEvent.id);
} else {
// Fallback logic if no specific next event and no random event found
console.warn("No specific or random event found, attempting fallback progression.");
if(currentStats.age > 75 && gameData.currentEventId !== 'reflect_on_life') loadEvent('reflect_on_life');
else if(currentStats.age > 58 && !currentFlags.retired && currentFlags.employed && gameData.currentEventId !== 'retirement_decision') loadEvent('retirement_decision');
else if(currentStats.age > 40 && gameData.currentEventId !== 'generic_mid_life' && (currentFlags.employed || currentFlags.isMarried)) loadEvent('generic_mid_life');
else if(currentStats.age > 23 && currentFlags.employed && !currentFlags.isMarried && gameData.currentEventId !== 'generic_early_career') loadEvent('generic_early_career');
else {
currentStats.age +=1;
const finalAttemptEvent = findRandomAvailableEvent();
loadEvent(finalAttemptEvent ? finalAttemptEvent.id : 'death_accident');
}
}
}
}
function findRandomAvailableEvent(isStrictlyRandom = false) {
let potentialEvents = gameData.events.filter(event => {
if (event.isEnding && !event.isEndingSegment) return false; // Allow ending segments that might have choices
if (event.id === gameData.currentEventId && !event.isRandomEvent) return false;
const ageOk = (!event.ageMin || currentStats.age >= event.ageMin) && (!event.ageMax || currentStats.age <= event.ageMax);
const conditionOk = !event.condition || event.condition(currentStats, currentFlags);
let flagDependencyOk = true;
if (event.requiresFlag) { for (const flag in event.requiresFlag) { if (currentFlags[flag] !== event.requiresFlag[flag]) { flagDependencyOk = false; break; } } }
if (event.avoidsFlag) { for (const flag in event.avoidsFlag) { if (currentFlags[flag] === event.avoidsFlag[flag]) { flagDependencyOk = false; break; } } }
if (isStrictlyRandom) return event.isRandomEvent && ageOk && conditionOk && flagDependencyOk;
return ageOk && conditionOk && flagDependencyOk;
});
let randomEventsWithProbability = potentialEvents.filter(e => e.isRandomEvent && Math.random() < (e.probability || 0.05));
if (randomEventsWithProbability.length > 0) { return randomEventsWithProbability[Math.floor(Math.random() * randomEventsWithProbability.length)]; }
if (!isStrictlyRandom) {
let generalEvents = potentialEvents.filter(e => !e.isRandomEvent && !e.isEndingSegment); // Prefer non-ending general events
if (generalEvents.length === 0) { // If no general non-ending, consider ending segments too
generalEvents = potentialEvents.filter(e => !e.isRandomEvent);
}
if (generalEvents.length > 0) { return generalEvents[Math.floor(Math.random() * generalEvents.length)]; }
}
let fallbackRandomEvents = potentialEvents.filter(e => e.isRandomEvent);
if (fallbackRandomEvents.length > 0) { return fallbackRandomEvents[Math.floor(Math.random() * fallbackRandomEvents.length)]; }
return null;
}
function checkAllAchievements() {
for (const key in currentAchievements) {
const achievement = currentAchievements[key];
if (!achievement.achieved && achievement.condition(currentStats, currentFlags, lifeEventsLog, gameData.currentEventId)) {
achievement.achieved = true;
showAchievementModal(achievement.name, achievement.description);
}
}
}
function showAchievementModal(name, description) {
achievementModalText.innerHTML = `<strong>${name}</strong><br>${description}`;
achievementModal.style.display = 'flex';
}
function endGame(endingEvent) {
gameContent.classList.add('hidden');
endScreen.classList.remove('hidden');
endTitleDisplay.textContent = typeof endingEvent.text === 'function' ? endingEvent.text(currentStats, currentFlags) : endingEvent.text;
if (typeof endingEvent.message === 'function') { endMessageDisplay.textContent = endingEvent.message(currentStats); }
else { endMessageDisplay.textContent = endingEvent.message || "당신의 인생이 끝났습니다."; }
lifeSummaryDisplay.innerHTML = '';
lifeEventsLog.forEach(logEntry => {
const p = document.createElement('p');
let entryText = `<strong>[${logEntry.age}세]</strong> ${logEntry.event}`;
if(logEntry.choice && logEntry.choice !== "결과" && logEntry.choice !== "자동 진행") { entryText += ` <small>(선택: ${logEntry.choice})</small>`; }
p.innerHTML = entryText;
lifeSummaryDisplay.appendChild(p);
});
achievementsLogList.innerHTML = '';
let achievedCount = 0;
for (const key in currentAchievements) {
if (currentAchievements[key].achieved) {
achievedCount++;
const p = document.createElement('p');
p.innerHTML = `<i class="fas fa-trophy"></i> <strong>${currentAchievements[key].name}:</strong> ${currentAchievements[key].description}`;
achievementsLogList.appendChild(p);
}
}
if (achievedCount === 0) { achievementsLogList.innerHTML = '<p><i class="fas fa-ghost"></i> 달성한 업적이 없습니다...</p>'; }
}
</script>
</body>
</html>