├── preview.jpg ├── images ├── job.png ├── prison.png ├── options │ ├── cv.png │ ├── cars.png │ ├── love.png │ ├── health.png │ ├── skills.png │ ├── criminal.png │ ├── education.png │ ├── emigrate.png │ ├── free-time.png │ ├── identity.png │ ├── inventory.png │ ├── sexuality.png │ ├── shopping.png │ ├── drivelicense.png │ ├── real-estate.png │ ├── university.png │ ├── plasticSurgery.png │ └── criminal-record.png ├── relations.png └── shop │ ├── bass.png │ ├── knife.png │ ├── piano.png │ ├── rpg.png │ ├── guitar.png │ ├── handgun.png │ ├── laptop.png │ ├── shotgun.png │ ├── violin.png │ └── smartphone.png ├── README.md ├── js ├── worldEvents.js ├── interface.js ├── events.js ├── items.js ├── main.js ├── characters.js ├── careers.js ├── libs.js ├── countriesData.js └── menu.js ├── index.html └── styles.css /preview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/preview.jpg -------------------------------------------------------------------------------- /images/job.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/job.png -------------------------------------------------------------------------------- /images/prison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/prison.png -------------------------------------------------------------------------------- /images/options/cv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/cv.png -------------------------------------------------------------------------------- /images/relations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/relations.png -------------------------------------------------------------------------------- /images/shop/bass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/shop/bass.png -------------------------------------------------------------------------------- /images/shop/knife.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/shop/knife.png -------------------------------------------------------------------------------- /images/shop/piano.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/shop/piano.png -------------------------------------------------------------------------------- /images/shop/rpg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/shop/rpg.png -------------------------------------------------------------------------------- /images/options/cars.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/cars.png -------------------------------------------------------------------------------- /images/options/love.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/love.png -------------------------------------------------------------------------------- /images/shop/guitar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/shop/guitar.png -------------------------------------------------------------------------------- /images/shop/handgun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/shop/handgun.png -------------------------------------------------------------------------------- /images/shop/laptop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/shop/laptop.png -------------------------------------------------------------------------------- /images/shop/shotgun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/shop/shotgun.png -------------------------------------------------------------------------------- /images/shop/violin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/shop/violin.png -------------------------------------------------------------------------------- /images/options/health.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/health.png -------------------------------------------------------------------------------- /images/options/skills.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/skills.png -------------------------------------------------------------------------------- /images/shop/smartphone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/shop/smartphone.png -------------------------------------------------------------------------------- /images/options/criminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/criminal.png -------------------------------------------------------------------------------- /images/options/education.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/education.png -------------------------------------------------------------------------------- /images/options/emigrate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/emigrate.png -------------------------------------------------------------------------------- /images/options/free-time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/free-time.png -------------------------------------------------------------------------------- /images/options/identity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/identity.png -------------------------------------------------------------------------------- /images/options/inventory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/inventory.png -------------------------------------------------------------------------------- /images/options/sexuality.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/sexuality.png -------------------------------------------------------------------------------- /images/options/shopping.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/shopping.png -------------------------------------------------------------------------------- /images/options/drivelicense.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/drivelicense.png -------------------------------------------------------------------------------- /images/options/real-estate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/real-estate.png -------------------------------------------------------------------------------- /images/options/university.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/university.png -------------------------------------------------------------------------------- /images/options/plasticSurgery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/plasticSurgery.png -------------------------------------------------------------------------------- /images/options/criminal-record.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robert1811/life-simulator/HEAD/images/options/criminal-record.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Life simulator 2 | This is a vanillaJS life simulator heavily inspired in games like bitlife, instlife and altlife. You can work, interact with your relatives, get a job and university career, improve your skills, buy stuff and **kill**. 3 | 4 | ## About the project 5 | Its not finished yet, I will be constantly updating this, bringing new content, bug fixes and UI improvements 6 | 7 | ![alt text](https://github.com/robert1811/life-simulator/blob/main/preview.jpg?raw=true) 8 | 9 | ## To add 10 | - Military career 11 | - Continue as child after dying 12 | - More shops, jobs, university careers, properties and cars 13 | - Diseases 14 | - More prison actions 15 | - Commercial properties 16 | - More laws 17 | - Taxes 18 | - Writing career 19 | - More social interactions 20 | -------------------------------------------------------------------------------- /js/worldEvents.js: -------------------------------------------------------------------------------- 1 | const worldEvents = {} 2 | 3 | // they display eventually and dont affect any character 4 | 5 | worldEvents.randomWar = () => { 6 | let i = Math.floor(Math.random() * countriesData.length); 7 | let j = Math.floor(Math.random() * countriesData.length); 8 | if(i === j){ 9 | j--; 10 | if(j === -1) j = 2; 11 | }; 12 | 13 | const casusBellis = ['because they have chemical weapons', 'due to their human rights violations', 'they have stolen their land', 'because they want to overthrow their dictatorship', 'in order to restore their democracy']; 14 | const randomCasusBellis = Math.floor(Math.random() * casusBellis.length); 15 | 16 | return `${countriesData[i].country} has declared war on ${countriesData[j].country} ${casusBellis[randomCasusBellis]}` 17 | 18 | } 19 | 20 | worldEvents.randomAsteroid = () =>{ 21 | let i = Math.floor(Math.random() * countriesData.length); 22 | let casualties = Math.floor(Math.random() * 5000); 23 | 24 | return `An asteroid crashed in ${countriesData[i].country}, ${casualties} people died`; 25 | } 26 | 27 | worldEvents.randomTerroristAttack = () => { 28 | let i = Math.floor(Math.random() * countriesData.length); 29 | let casualties = Math.floor(Math.random() * 120); 30 | let injuried = Math.floor(Math.random() * 150) 31 | 32 | return `Terrorist attack in ${countriesData[i].country}, ${casualties} deaths and ${injuried} injuried` 33 | } 34 | 35 | const worldEventsMethodArr = Object.entries(worldEvents); 36 | const worldEventsAmount = worldEventsMethodArr.length; 37 | 38 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Quicklife 11 | 12 | 13 | 14 |
15 |

Create your character

16 |
17 | 18 | 19 |
20 |
21 | 22 | 29 |
30 | 31 |
32 | 38 |
39 |
40 | 48 |
49 |
50 |
51 | Childhood 52 |
53 |
54 |
55 |
56 |
57 |
58 | 59 |
60 |
61 | 62 |

Relationships

63 |
64 |
65 | 66 |

Profile

67 |
68 |
69 | 70 |
71 |
72 | 73 |

Career

74 |
75 |
76 | 77 |
78 |
79 | 80 |

Activities

81 |
82 |
83 |
84 |
85 | 86 | 87 | 91 |
92 | 93 |
94 |
95 |
96 |

You have died!

97 |
98 |
99 | 100 |
101 |
102 |
103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /js/interface.js: -------------------------------------------------------------------------------- 1 | const ageButton = document.getElementById('age-btn'); 2 | 3 | let modalBackground = document.getElementById('modal-background'); 4 | let eventBox = document.getElementById('event-box'); 5 | let eventTitle = document.getElementById('event-title'); 6 | let eventBody = document.getElementById('event-body') 7 | let options = document.getElementsByClassName('option') 8 | 9 | let textContainer = document.getElementById('text-container'); 10 | 11 | let year = Math.round(Math.random() * 20) + 2000; 12 | 13 | 14 | //this is when you customize your character 15 | const displayCustomization = () => { 16 | const characterScreen = document.getElementById('create-character-screen'); 17 | characterScreen.innerHTML = ` 18 |

Customize your character

19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 34 | 35 | 36 | 39 | 40 | 41 | 42 | 43 |
44 | ` 45 | //these two prevent typing white spaces in the inputs 46 | const inputName = document.getElementById('name'); 47 | inputName.addEventListener('input', e => { 48 | e.target.value = e.target.value = e.target.value.replace(/\W|\d/, '') 49 | }) 50 | 51 | const inputSurname = document.getElementById('surname'); 52 | inputSurname.addEventListener('input', e => { 53 | e.target.value = e.target.value = e.target.value.replace(/\W|\d/, '') 54 | }) 55 | } 56 | 57 | //called after dying 58 | const newLife = () => { 59 | const deathScreen = document.getElementById('death-screen'); 60 | const characterScreen = document.getElementById('create-character-screen') 61 | textContainer.innerHTML = '' 62 | 63 | deathScreen.style.display = 'none' 64 | characterScreen.style.display = 'block' 65 | } 66 | 67 | //im gonna move this somewhere else 68 | const deathScreen = () => { 69 | const ageBtnContainer = document.getElementById('age-btn-container'); 70 | ageBtnContainer.innerHTML = ` 71 | 72 | ` 73 | 74 | const obituaryContainer = document.getElementById('obituary-container'); 75 | 76 | const siblingLength = player.relationships.siblings.length; 77 | const dadName = player.relationships.parents[0].fullName 78 | const momName = player.relationships.parents[1].fullName 79 | const pronoun = player.gender === 'male' ? 'He' : 'She' 80 | 81 | obituaryContainer.innerHTML = ` 82 |

${player.fullName} was born in ${player.birthplace} at year ${year - player.age}. ${pronoun} was son of ${dadName} and ${momName}${siblingLength !== 0 ? `, ${player.gender === 'male' ? 'brother' : 'sister'} of ${siblingLength} ${siblingLength > 1 ? 'persons' : 'person'}.` : '.'}


83 | ` 84 | 85 | if (player.cv.length !== 0) { 86 | obituaryContainer.innerHTML += `

He worked as:

87 | ${cvListifier(player)}
88 | ` 89 | } else obituaryContainer.innerHTML += `

${pronoun} never got a job.


` 90 | 91 | obituaryContainer.innerHTML += `

${pronoun} left this world with ${moneyFormat(player.money.total)} $ on his bank account. ${player.inventory.houses.length !== 0 ? `${pronoun} had ${player.inventory.houses.length} properties.` : `${pronoun} was homeless.`}


` 92 | 93 | obituaryContainer.innerHTML += ` 94 |

Criminal record:

95 |
99 | ` 100 | 101 | obituaryContainer.innerHTML += ` 102 |

${pronoun} passed away at age of ${player.age} ${player.deathCause} in ${player.location}

103 | ` 104 | 105 | document.getElementById('death-screen').style.display = 'block' 106 | } 107 | 108 | const annualChanges = () => { 109 | year++; 110 | for (let person of characters) { 111 | if (person.alive) person.age++; 112 | pregnancyHandler(person) 113 | } 114 | 115 | textContainer.innerHTML += ` 116 |

${year} - ${player.age} years old

117 | ` 118 | 119 | //death possibility 120 | for (let person of characters) { 121 | randomDeath(person) 122 | } 123 | 124 | // shows if player is in the stage of childhood, adulthood or elderhood 125 | lifeStageDisplayer() 126 | 127 | //this is for events such as first words and university 128 | specificEvents() 129 | 130 | //random messages 131 | if (Math.floor(Math.random() * 10) === 5) 132 | textContainer.innerHTML += `

${worldEventsMethodArr[Math.floor(Math.random() * worldEventsAmount)][1]()}

` 133 | 134 | player.money.total += player.money.income - player.money.expenses 135 | 136 | // job related stats 137 | if (player.job !== 'none') { 138 | const random = Math.round(Math.random()) 139 | if (random === 0) 140 | player.job.performance += Math.floor(Math.random() * 5) 141 | else 142 | player.job.performance -= Math.floor(Math.random() * 5) 143 | } 144 | 145 | // for university 146 | studyingProcess(textContainer) 147 | if(player.job != 'none') player.job.buff(player) 148 | if(player.currentCareer.studying) player.currentCareer.buff(player); 149 | statsChanges() 150 | statsBuffer() 151 | statsLimit(player) 152 | handleStatBars(player, true); 153 | skillLeveler() 154 | 155 | //scroll handling 156 | scrolldown(textContainer) 157 | 158 | //displaying flow of money 159 | moneyViewer() 160 | 161 | resetAvaibleActions() 162 | 163 | randomizeHouseStats() 164 | prisonHandler(player) 165 | eventsHandler() 166 | } 167 | 168 | const closeMenu = document.getElementById('close-menu'); 169 | closeMenu.addEventListener('click', e => { 170 | menuTemplate.style.display = 'none' 171 | }) -------------------------------------------------------------------------------- /js/events.js: -------------------------------------------------------------------------------- 1 | //random events 2 | const childhoodEvents = [ 3 | { 4 | display() { 5 | createStoryEvent({ 6 | title: 'Happy Birthday!', 7 | body(id) { 8 | return ` 9 |

What are you going to do?

10 |
Invite friends
11 |
Only invite family
12 |
Dont celebrate
13 | ` 14 | } 15 | }) 16 | }, 17 | celebrate(id, guests) { 18 | player.stats.happiness += 5 + Math.floor(Math.random() * 10) 19 | statsLimit(player) 20 | closeStoryEvent(id) 21 | textContainer.innerHTML += ` 22 |

I celebrated my birthday

23 |

I invited my ${guests}

24 | ` 25 | scrolldown(textContainer) 26 | } 27 | }, 28 | { 29 | display() { 30 | const person = new Person(undefined, undefined, player.age, player.gender == 'male' ? 'female' : 'male') 31 | const appearance = person.stats.appearance 32 | const { fullName, gender, age } = person 33 | const pronoun = gender === 'male' ? 'him' : 'her' 34 | createStoryEvent({ 35 | title: 'Kiss', 36 | body(id) { 37 | return ` 38 |

Name: ${fullName}

39 |

Gender: ${gender}

40 |

Age: ${age}

41 |

Appearance:

42 |
43 |
44 |
45 |
46 |

You got the oportunity to kiss ${pronoun}. Would you like to do it?

47 |
Kiss ${pronoun}
48 |
Close
49 | ` 50 | } 51 | }) 52 | }, 53 | kiss(id, pronoun) { 54 | const appearance = player.stats.appearance 55 | const enjoyment = appearance + Math.floor(Math.random() * (100 - appearance)) 56 | 57 | modifyStoryEvent({ 58 | id, 59 | title: 'Kiss', 60 | body(id){ return ` 61 |

You kissed ${pronoun}.

62 |

${pronoun == 'him' ? 'His' : 'Her'} enjoyment.

63 |
64 |
65 |
66 |
67 |
Close
68 | ` 69 | } 70 | }) 71 | } 72 | } 73 | ] 74 | 75 | const adulthoodEvents = [ 76 | { 77 | display() { 78 | const places = ['a hospital', 'the zoo', 'a store'] 79 | const random = Math.floor(Math.random() * places.length) 80 | const place = places[random] 81 | createStoryEvent({ 82 | title: 'Provide directions', 83 | body(id) { 84 | return ` 85 |

Someone asked you for the direction of ${place}.

86 |
87 |
Correct directions
88 |
Incorrect directions
89 |
Ignore
90 | ` 91 | } 92 | }) 93 | } 94 | } 95 | ] 96 | 97 | const elderhoodEvents = [ 98 | 99 | ] 100 | 101 | const prisonEvents = [ 102 | { 103 | display() { 104 | const insults = ['baby', 'idiot', 'dumbass', 'faggot', 'retard', 'fatty'] 105 | const insult = insults[Math.floor(Math.random() * insults.length)] 106 | textContainer.innerHTML += '

I got insulted by inmates

' 107 | 108 | createStoryEvent({ 109 | title: `The inmates called you ${insult}`, 110 | body(id) { 111 | return ` 112 |
Argue
113 |
Do nothing
114 | ` 115 | } 116 | }) 117 | }, 118 | argue(id) { 119 | textContainer.innerHTML += `

I insulted them

` 120 | scrolldown(textContainer) 121 | 122 | closeStoryEvent(id) 123 | } 124 | } 125 | ] 126 | 127 | const jobEvents = [ 128 | { 129 | display() { 130 | textContainer.innerHTML += ` 131 |

We have a job meeting

132 | ` 133 | scrolldown(textContainer) 134 | createStoryEvent({ 135 | title: 'Job Meeting', 136 | body(id) { 137 | return ` 138 |

You have a meeting in your job, what are you going to do?

139 |
Dont say a word
140 |
Propose a revolutionary idea
141 | `} 142 | }) 143 | }, 144 | dontSpeak(id) { 145 | textContainer.innerHTML += ` 146 |

I said nothing in that meeting

147 | ` 148 | closeStoryEvent(id) 149 | scrolldown(textContainer) 150 | }, 151 | proposeIdea(id) { 152 | const smartness = player.stats.smartness; 153 | const random = Math.floor(Math.random() * 50) + 50 154 | 155 | if (random <= smartness) { 156 | textContainer.innerHTML += ` 157 |

They congratulated me

158 | ` 159 | closeStoryEvent(id) 160 | } else 161 | textContainer.innerHTML += ` 162 |

They told me to shut up

163 | ` 164 | closeStoryEvent(id) 165 | scrolldown(textContainer) 166 | } 167 | } 168 | ] 169 | 170 | const obligatoryEvents = { 171 | firstWords: { 172 | display() { 173 | createStoryEvent({ 174 | title: 'Your first words', 175 | body(id) { 176 | return ` 177 |
Hungry
178 |
Water
179 |
Mom
180 |
Dad
181 | ` 182 | } 183 | }) 184 | }, 185 | speak(words, id) { 186 | closeStoryEvent(id) 187 | textContainer.innerHTML += ` 188 |

My first words were "${words}"

189 | ` 190 | } 191 | } 192 | } 193 | 194 | const eventsHandler = () => { 195 | if (!player.alive || player.age < 4) return 196 | 197 | const displayHandler = (events, probability) => { 198 | const random = Math.floor(Math.random() * 100) 199 | const eventIndex = Math.floor(Math.random() * events.length) 200 | if (random + 5 <= probability) { 201 | events[eventIndex].display() 202 | } 203 | } 204 | 205 | if (player.prison.jailed) return displayHandler(prisonEvents, 10) 206 | 207 | if (player.job != 'none') displayHandler(jobEvents, 8) 208 | 209 | if (player.lifeStage === 'childhood') displayHandler(childhoodEvents, 20) 210 | 211 | else if (player.lifeStage === 'adulthood') displayHandler(adulthoodEvents, 8) 212 | } -------------------------------------------------------------------------------- /js/items.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const items = { 4 | weapons: [ 5 | { 6 | label: 'Knife', 7 | price: 5000, 8 | successChance: 35, 9 | image: 'knife.png', 10 | type: 'weapons', 11 | index: 0 12 | }, 13 | { 14 | label: 'Handgun', 15 | price: 32000, 16 | successChance: 55, 17 | image: 'handgun.png', 18 | type: 'weapons', 19 | index: 1 20 | }, 21 | { 22 | label: 'Shotgun', 23 | price: 50000, 24 | successChance: 75, 25 | image: 'shotgun.png', 26 | type: 'weapons', 27 | index: 2 28 | }, 29 | { 30 | label: 'RPG', 31 | price: 150000, 32 | successChance: 86, 33 | image: 'rpg.png', 34 | type: 'weapons', 35 | index: 3 36 | } 37 | ], 38 | instruments: [ 39 | { 40 | label: 'Piano', 41 | price: 16000, 42 | image: 'piano.png', 43 | type: 'instruments', 44 | index: 0 45 | }, 46 | { 47 | label: 'Guitar', 48 | price: 5000, 49 | image: 'guitar.png', 50 | type: 'instruments', 51 | index: 1 52 | }, 53 | { 54 | label: 'Violin', 55 | price: 5000, 56 | image: 'violin.png', 57 | type: 'instruments', 58 | index: 2 59 | }, 60 | { 61 | label: 'Bass', 62 | price: 4800, 63 | image: 'bass.png', 64 | type: 'instruments', 65 | index: 3 66 | }, 67 | { 68 | label: 'Flute', 69 | price: 5, 70 | image: 'flute.png', 71 | type: 'instruments', 72 | index: 4 73 | } 74 | ], 75 | electronics : [ 76 | { 77 | label: 'Smartphone', 78 | price: 6000, 79 | image: 'smartphone.png', 80 | type: 'electronics', 81 | index: 0 82 | }, 83 | { 84 | label: 'Laptop', 85 | price: 12000, 86 | image: 'laptop.png', 87 | type: 'electronics', 88 | index: 1 89 | } 90 | ], 91 | fastFood: [ 92 | { 93 | label: 'Hamburguer', 94 | price: 35, 95 | image: 'hamburguer.png', 96 | type: 'fastFood', 97 | index: 0, 98 | statChanges: { 99 | health: -1, 100 | happiness: 5, 101 | fitness: -1 102 | } 103 | }, 104 | { 105 | label: 'Pizza', 106 | price: 50, 107 | image: 'pizza.png', 108 | type: 'fastFood', 109 | index: 1, 110 | statChanges: { 111 | health: -1, 112 | happiness: 7, 113 | fitness: -1 114 | } 115 | }, 116 | { 117 | label: 'Hot dogs', 118 | price: 30, 119 | image:'hot_dog.png', 120 | type: 'fastFood', 121 | index: 2, 122 | statChanges: { 123 | health: -1, 124 | happiness: 3, 125 | fitness: -1 126 | } 127 | } 128 | ], 129 | vegetables: [ 130 | { 131 | label: 'Potato', 132 | price: 10, 133 | image: 'potato.png', 134 | type: 'vegetables', 135 | index: 0, 136 | statChanges: { 137 | health: 2 138 | } 139 | }, 140 | { 141 | label: 'Carrot', 142 | price: 50, 143 | image: 'carrot.png', 144 | type: 'vegetables', 145 | index: 1, 146 | statChanges: { 147 | health: 5 148 | } 149 | }, 150 | { 151 | label: 'Broccoli', 152 | price: 80, 153 | image: 'broccoli.png', 154 | type: 'vegetables', 155 | index: 2, 156 | statChanges: { 157 | health: 7 158 | } 159 | } 160 | ], 161 | desserts: [ 162 | { 163 | label: 'Cotton candy', 164 | price: 15, 165 | image: 'cotton_candy.png', 166 | index: 0, 167 | type: 'desserts', 168 | statChanges: { 169 | happiness: 3, 170 | health: -1 171 | } 172 | }, 173 | { 174 | label: 'Ice cream', 175 | price: 15, 176 | image: 'ice_cream.png', 177 | index: 1, 178 | type: 'desserts', 179 | statChanges: { 180 | happiness: 5 181 | } 182 | }, 183 | { 184 | label: 'Chocolate bar', 185 | price: 15, 186 | image: 'chocolate.png', 187 | index: 2, 188 | type: 'desserts', 189 | statChanges: { 190 | happiness: 4, 191 | fitness: -1 192 | } 193 | } 194 | ], 195 | alcoholic: [ 196 | { 197 | label: 'Wine', 198 | price: 60, 199 | image: 'wine.png', 200 | index: 0, 201 | type: 'alcoholic', 202 | statChanges: { 203 | happiness: 12, 204 | health: -8 205 | } 206 | }, 207 | { 208 | label: 'Beer', 209 | price: 25, 210 | image: 'beer.png', 211 | index: 1, 212 | type: 'alcoholic', 213 | statChanges: { 214 | happiness: 10, 215 | health: -8 216 | } 217 | }, 218 | { 219 | label: 'Vodka', 220 | price: 50, 221 | image: 'vodka.png', 222 | index: 2, 223 | type: 'alcoholic', 224 | statChanges: { 225 | happiness: 11, 226 | health: -7 227 | } 228 | } 229 | ], 230 | nonAlcoholic: [ 231 | { 232 | label: 'Orange juice', 233 | price: 15, 234 | image: 'orange_juice.png', 235 | index: 0, 236 | type: 'nonAlcoholic', 237 | statChanges: { 238 | happiness: 4 239 | } 240 | }, 241 | { 242 | label: 'Milk', 243 | price: 5, 244 | image: 'milk.png', 245 | index: 1, 246 | type: 'nonAlcoholic', 247 | statChanges: { 248 | happiness: 2 249 | } 250 | } 251 | ] 252 | } 253 | 254 | const assets = { 255 | houses: [ 256 | { 257 | label: 'Modern House', 258 | age: Math.floor(Math.random() * 10), 259 | condition: Math.floor(Math.random() * 100), 260 | price: 510000 261 | }, 262 | { 263 | label: 'House boat', 264 | age: Math.floor(Math.random() * 120), 265 | condition: Math.floor(Math.random() * 100), 266 | price: 60000 267 | }, 268 | { 269 | label: 'Tiny apartment', 270 | age: Math.floor(Math.random() * 100), 271 | condition: Math.floor(Math.random() * 100), 272 | price: 75000 273 | }, 274 | { 275 | label: 'Big Mansion', 276 | age: Math.floor(Math.random() * 100), 277 | condition: Math.floor(Math.random() * 100), 278 | price: 2000000 279 | } 280 | ], 281 | cars: [ 282 | { 283 | label: 'Alpine A110', 284 | price: 107000, 285 | }, { 286 | label: 'Aiways U5', 287 | price: 42690 288 | }, { 289 | label: 'Bolt 550S', 290 | price: 124000 291 | }, { 292 | label: 'Onyx Zeal', 293 | price: 113000 294 | }, { 295 | label: 'FRX Catalyst', 296 | price: 58000 297 | }, { 298 | label: 'Shelly Behemot GT', 299 | price: 56000 300 | }, { 301 | label: 'EOS Nimbus', 302 | price: 54000 303 | }, { 304 | label: 'Ranger Expedition', 305 | price: 26000 306 | }, { 307 | label: 'Ranger Radiance', 308 | price: 35000 309 | } 310 | ] 311 | } 312 | 313 | const randomizeHouseStats = () => { 314 | for(let house of assets.houses){ 315 | house.age = Math.floor(Math.floor(Math.random() * 120)); 316 | house.condition = Math.floor(Math.floor(Math.random() * 100)); 317 | } 318 | // for(let car of assets.cars){ 319 | // console.log(car) 320 | // } 321 | } 322 | -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | let characters = []; 4 | 5 | class Person { 6 | constructor(name, surname, age, gender, nationality, money, location) { 7 | this.gender = gender || genderRandomizer() 8 | this.nationality = nationality || countryRandomizer(); 9 | this.language = languageQuery(this.nationality) 10 | this.name = name || nameRandomizer(this.language, this.gender); 11 | this.surname = surname || surnameRandomizer(this.language); 12 | this.age = age || 0; 13 | this.money.total = money ? money : 0; 14 | this.location = location || birthplaceQuery(this.nationality) 15 | this.birthplace = this.location 16 | this.driverLicense = this.age > 18 ? true : false; 17 | } 18 | 19 | inventory = { weapons: [], instruments: [], electronics: [], houses: [], cars: []}; 20 | 21 | sexuality = 'heterosexual' 22 | 23 | stats = { 24 | health: randomStat(70, 30), 25 | happiness: randomStat(0, 100), 26 | smartness: randomStat(0, 100), 27 | fitness: randomStat(0, 35), 28 | appearance: randomStat(0, 100) 29 | } 30 | 31 | relationships = { 32 | parents: [], 33 | siblings: [], 34 | partner: [], 35 | friends: [], 36 | offspring: [] 37 | } 38 | alive = true; 39 | career = {}; 40 | currentCareer = {studying: false} 41 | 42 | skills = { 43 | programming: { 44 | level: 0, 45 | xp: 0, 46 | xpNeeded: 50, 47 | }, 48 | handiness: { 49 | level: 0, 50 | xp: 0, 51 | xpNeeded: 50, 52 | }, 53 | writing: { 54 | level: 0, 55 | xp: 0, 56 | xpNeeded: 50, 57 | }, 58 | art: { 59 | level: 0, 60 | xp: 0, 61 | xpNeeded: 50, 62 | }, 63 | music: { 64 | level: 0, 65 | xp: 0, 66 | xpNeeded: 50 67 | } 68 | } 69 | 70 | //activities which you pay for increasing skills and stats 71 | freetime = { 72 | isReading: false, 73 | isTakingMusicLessons: false, 74 | isAttendingParties: false, 75 | goesToGym: false 76 | } 77 | 78 | job = 'none'; 79 | 80 | //in cv goes your employment history 81 | cv = []; 82 | 83 | money = { 84 | expenses: 0, 85 | income: 0, 86 | total: 0 87 | } 88 | 89 | get fullName() { 90 | return `${this.name} ${this.surname}` 91 | } 92 | 93 | //this is used when you want to access to certain character by using this index with the characters array 94 | characterIndex = characters.length 95 | 96 | criminalRecord = { 97 | yearsInPrison: 0, 98 | murderAttempts: 0, 99 | murder: 0, 100 | prisonEscapes: 0 101 | } 102 | 103 | prison = { 104 | yearsLeft: 0, 105 | sentenceTime: 0, 106 | jailed: false 107 | } 108 | 109 | // this limits your actions per year 110 | actions = { 111 | programming: 0, 112 | writing: 0, 113 | workHarder: 0, 114 | music: 0, 115 | meanActions: 0, 116 | friendlyActions: 0, 117 | romanticActions: 0, 118 | askPromotion: 0 119 | } 120 | 121 | socialMedia = { 122 | youtube: { 123 | created: false, 124 | created_at: null, 125 | username: null, 126 | videos: [], 127 | subscribers: 0 128 | }, 129 | instagram: { 130 | created: false, 131 | created_at: null, 132 | username: null, 133 | posts: [], 134 | followers: 0 135 | } 136 | } 137 | } 138 | 139 | const createFamily = (player) => { 140 | const parentsAge = () => { 141 | let age = Math.floor(Math.random() * 40) + player.age; 142 | if (age - player.age < 18) age = age + 18 + player.age; 143 | return age; 144 | } 145 | 146 | 147 | let dad = new Person(undefined, player.surname, parentsAge(), 'male', player.nationality); 148 | dad.stats.relationWithPlayer = Math.floor(Math.random() * 100); 149 | characters.push(dad); 150 | 151 | let mom = new Person(undefined, undefined, dad.age + Math.floor(Math.random() * 10), 'female', player.nationality); 152 | mom.stats.relationWithPlayer = Math.floor(Math.random() * 100); 153 | characters.push(mom) 154 | 155 | dad.relationships.partner.push(mom); 156 | mom.relationships.partner.push(dad); 157 | 158 | player.relationships.parents.push(dad); 159 | player.relationships.parents.push(mom) 160 | 161 | let siblingsAmount = Math.floor(Math.random() * 3); 162 | 163 | while (siblingsAmount > 0) { 164 | let randomAge = Math.floor(Math.random() * 5); 165 | let sibling = new Person(undefined, player.surname, randomAge, undefined, player.nationality); 166 | sibling.stats.relationWithPlayer = Math.floor(Math.random() * 100); 167 | characters.push(sibling); 168 | player.relationships.siblings.push(sibling); 169 | siblingsAmount--; 170 | } 171 | } 172 | 173 | const firstMessage = () => { 174 | textContainer.innerHTML = ` 175 |

${year} - ${player.age === 0 ? 'birth' : `${player.age} years old`}

176 |

My name is ${player.fullName}

177 |

I was born ${player.gender} in ${player.location} on year ${year}

178 |

My father is ${player.relationships.parents[0].fullName}, he works as a ${player.relationships.parents[0].job.label.toLowerCase()}

179 |

My mother is ${player.relationships.parents[1].fullName}, she works as a ${player.relationships.parents[1].job.label.toLowerCase()}

180 | ` 181 | } 182 | 183 | let player; 184 | 185 | const interfaceLoading = () => { 186 | handleStatBars(player, true); 187 | lifeStageDisplayer() 188 | moneyViewer() 189 | jobAssigner(characters) 190 | firstMessage() 191 | const menu = document.getElementById('create-character-screen') 192 | menu.style.display = 'none' 193 | menu.innerHTML = ` 194 |

Choose how will you create your character

195 |
196 | 197 | 198 |
199 | ` 200 | const bars = document.getElementsByClassName('bar-progress'); 201 | for (let bar of bars) { 202 | bar.style.animationName = 'animation-bar'; 203 | bar.style.transition = 'all ease 0.3s' 204 | } 205 | } 206 | 207 | //sets jobs for npcs 208 | const jobAssigner = (characters) => { 209 | const findJob = (person) => { 210 | let randomIndex = Math.floor(Math.random() * jobs.length) 211 | const job = jobs[randomIndex] 212 | person.job = job 213 | person.money.income = job.salary 214 | requirementsFiller(job, person) 215 | } 216 | if (characters.characterIndex === player.characterIndex) return 217 | if (Array.isArray(characters)) for (let person of characters) { 218 | if (person.age > 17 && person.job === 'none' && person.characterIndex !== player.characterIndex) 219 | findJob(person) 220 | } 221 | else { 222 | let person = characters; 223 | if (person.age > 17 && person.job && person.job === 'none') 224 | findJob(person) 225 | } 226 | } 227 | 228 | const assignNPCEducation = (characters) => { 229 | for(let person of characters){ 230 | if(person.age >= 3 && person.age < 6){ 231 | person.currentEducation = 'preschool' 232 | } else if(person.age >= 6 && person.age < 12){ 233 | person.currentEducation = 'elementary' 234 | } else if(person.age >= 12 && person.age < 18){ 235 | person.currentEducation = 'highschool' 236 | } else if(person.age >= 18){ 237 | person.currentEducation = 'none' 238 | person.career['education'] = {name: 'Highschool'} 239 | } 240 | } 241 | } 242 | 243 | const randomCharacter = () => { 244 | player = new Person(); 245 | characters.push(player) 246 | createFamily(player) 247 | interfaceLoading() 248 | assignNPCEducation(characters) 249 | } 250 | 251 | const customCharacter = () => { 252 | const inputName = document.getElementById('name'); 253 | const inputSurname = document.getElementById('surname'); 254 | const inputAge = document.getElementById('age') 255 | const selectGender = document.getElementById('gender'); 256 | const selectNationality = document.getElementById('nationality'); 257 | const inputMoney = document.getElementById('money'); 258 | 259 | const name = inputName.value.trim() !== '' ? inputName.value.trim() : undefined; 260 | const surname = inputSurname.value.trim() !== '' ? inputSurname.value.trim() : undefined; 261 | const age = inputAge.value >= 0 ? parseInt(inputAge.value) : 0; 262 | const gender = selectGender.value || undefined; 263 | const nationality = selectNationality.value || undefined; 264 | const money = parseInt(inputMoney.value) || undefined; 265 | 266 | player = new Person(name !== undefined ? capitalize(name) : name, name !== undefined ? capitalize(surname) : name, age, gender, nationality, money); 267 | characters.push(player); 268 | createFamily(player); 269 | interfaceLoading() 270 | assignNPCEducation(characters) 271 | } -------------------------------------------------------------------------------- /js/characters.js: -------------------------------------------------------------------------------- 1 | //here I handle every stat change in the characters 2 | 3 | const studyingProcess = (textbox) => { 4 | let currentEducation = player.currentEducation; 5 | let currentCareer = player.currentCareer 6 | let yearsStudied; 7 | let duration; 8 | 9 | if(currentCareer) { 10 | duration = currentCareer.duration; 11 | yearsStudied = currentCareer.yearsStudied; 12 | } 13 | 14 | if(currentCareer && currentEducation === 'university' && yearsStudied !== duration){ 15 | player.currentCareer.yearsStudied++; 16 | } else if(currentCareer && currentEducation === 'university' && yearsStudied === duration){ 17 | player.career[player.currentCareer.label] = player.currentCareer; 18 | if(player.currentCareer.paidBy === 'myself') player.money.expenses -= 6000 19 | player.currentCareer = {studying: false}; 20 | player.currentEducation = 'none'; 21 | textbox.innerHTML += `

I finished my career

` 22 | } 23 | } 24 | 25 | const statsLimit = (person) => { 26 | let stats = person.stats; 27 | for(let stat of Object.entries(stats)){ 28 | if(stat[1] < 0) person.stats[stat[0]] = 0 29 | else if (stat[1] > 100) person.stats[stat[0]] = 100 30 | } 31 | if(person.job !== 'none') 32 | if(person.job.performance > 100) 33 | person.job.performance = 100 34 | else if (person.job.performance < 0) 35 | person.job.performance = 0 36 | 37 | } 38 | 39 | const statsBuffer = () => { 40 | if(player.freetime.isReading){ 41 | if(player.money.total > 0){ 42 | player.stats.smartness += 3; 43 | } 44 | else { 45 | player.freetime.isReading = false 46 | player.money.expenses -= 200 47 | } 48 | 49 | } 50 | if(player.freetime.isAttendingParties){ 51 | if(player.money.total > 0) player.stats.happiness += 5 52 | else { 53 | player.freetime.isAttendingParties = false 54 | player.money.expenses -= 500 55 | } 56 | } 57 | if(player.freetime.isTakingMusicLessons){ 58 | if(player.money.total > 0) player.skills.music.xp += 25; 59 | else { 60 | player.freetime.isTakingMusicLessons = false 61 | player.money.expenses -= 2000 62 | } 63 | } 64 | if(player.freetime.goesToGym){ 65 | if(player.money.total > 0) { 66 | player.stats.health++; 67 | player.stats.fitness += 6; 68 | } else { 69 | player.freetime.goesToGym = false 70 | player.money.expenses -= 1800 71 | } 72 | } else player.stats.fitness--; 73 | 74 | 75 | } 76 | 77 | const specificEvents = () => { 78 | switch (player.age) { 79 | case 1: 80 | obligatoryEvents.firstWords.display() 81 | break; 82 | case 3: 83 | player.currentEducation = 'preschool' 84 | textContainer.innerHTML += `

I started prescholar

` 85 | break; 86 | 87 | case 6: 88 | player.currentEducation = 'elementary' 89 | textContainer.innerHTML += `

I started elementary school

` 90 | break; 91 | 92 | case 12: 93 | player.currentEducation = 'highschool' 94 | textContainer.innerHTML += `

I started highschool

` 95 | break; 96 | 97 | case 18: 98 | player.career['education'] = {name: 'Highschool'} 99 | windows.university.display() 100 | } 101 | } 102 | 103 | const careerPreviewer = () => { 104 | let string = ''; 105 | let object = {education: '
  • No education received yet
  • ', degrees: '

    No degrees yet

    '} 106 | for(let obj of Object.entries(player.career)){ 107 | if(obj[0] !== 'education'){ 108 | string = string.concat(`
  • ${obj[1].name}
  • `) 109 | } 110 | else object.education = 'Highschool' 111 | } 112 | if(string !== '') 113 | object.degrees = string; 114 | return object 115 | 116 | } 117 | 118 | const skillLeveler = () => { 119 | const levelChanger = (skill, newXpNeeded) =>{ 120 | player.skills[skill[0]].level++; 121 | player.skills[skill[0]].xp = player.skills[skill[0]].xp - player.skills[skill[0]].xpNeeded; 122 | player.skills[skill[0]].xpNeeded = newXpNeeded 123 | } 124 | 125 | let skills = player.skills; 126 | for(let skill of Object.entries(skills)){ 127 | let xp = skills[skill[0]].xp; 128 | let level = skills[skill[0]].level 129 | let xpNeeded = skills[skill[0]].xpNeeded 130 | 131 | if(level === 0 && xp >= xpNeeded){ 132 | levelChanger(skill, 50) 133 | } else if(level === 1 && xp >= xpNeeded){ 134 | levelChanger(skill, 100) 135 | } else if(level === 2 && xp >= xpNeeded){ 136 | levelChanger(skill, 250) 137 | } else if(level === 3 && xp >= xpNeeded){ 138 | levelChanger(skill, 450) 139 | } else if(level === 4 && xp >= xpNeeded){ 140 | levelChanger(skill, 600) 141 | } else if(level === 5 && xp >= xpNeeded){ 142 | levelChanger(skill, 800) 143 | } else if(level === 6 && xp >= xpNeeded){ 144 | levelChanger(skill, 1200) 145 | } else if(level === 7 && xp >= xpNeeded){ 146 | levelChanger(skill, 3000) 147 | } else if(level === 8 && xp >= xpNeeded){ 148 | levelChanger(skill, 6000) 149 | } else if(level === 9 && xp >= xpNeeded){ 150 | levelChanger(skill, 6000) 151 | } 152 | } 153 | } 154 | 155 | const randomDeath = (person) => { 156 | const randomNum = Math.floor(Math.random() * person.age) 157 | const deathCause = [`has died while ${person.gender == 'male' ? 'he' : 'she'} was sleeping`] 158 | const randomReason = deathCause[Math.floor(Math.random() * deathCause.length)] 159 | 160 | if(person.age > 70 && person.stats.health < randomNum && person.alive){ 161 | death(person, randomReason) 162 | } 163 | } 164 | 165 | const death = (person, reason) => { 166 | person.alive = false; 167 | textContainer.innerHTML += `

    ${person.fullName} ${reason} at age of ${person.age}

    ` 168 | 169 | person.deathCause = reason; 170 | 171 | if(person.job !== 'none'){ 172 | person.job.until = year; 173 | person.cv.push(person.job) 174 | person.job = 'none' 175 | } 176 | 177 | if(person.characterIndex === player.characterIndex){ 178 | const ageBtnContainer = document.getElementById('age-btn-container'); 179 | ageBtnContainer.innerHTML = ` 180 | 181 | ` 182 | } 183 | } 184 | 185 | const prisonHandler = (person) => { 186 | if(!person.prison.jailed) return 187 | 188 | person.prison.yearsLeft--; 189 | person.criminalRecord.yearsInPrison++; 190 | 191 | if(person.prison.yearsLeft === 0){ 192 | person.prison.jailed = false 193 | person.prison.sentenceTime = 0; 194 | leftBtnContainer.innerHTML = '' 195 | textContainer.innerHTML += `

    I got out of prison

    ` 196 | } 197 | } 198 | 199 | const jobPerformanceHandler = () => { 200 | if(player.job === 'none') return 201 | 202 | const performance = player.job.performance 203 | const random = Math.round(Math.random() * 10) 204 | if(performance <= 10 && random === 2){ 205 | player.job.until = year 206 | player.cv.push(player.job) 207 | player.job = 'none' 208 | } else if(performance >= 75 && random === 5){ 209 | 210 | } 211 | } 212 | 213 | const resetAvaibleActions = () => { 214 | for(let action of Object.entries(player.actions)){ 215 | player.actions[action[0]] = 0 216 | } 217 | } 218 | 219 | const arrest = (min, max, person) => { 220 | person.prison.sentenceTime = min + Math.floor(Math.random() * max) 221 | person.prison.yearsLeft = person.prison.sentenceTime 222 | person.prison.jailed = true; 223 | 224 | leftBtnContainer.innerHTML = ` 225 | 228 |

    Prison

    229 | ` 230 | if(player.job !== 'none') { 231 | player.job === 'none'; 232 | textContainer.innerHTML += `

    I lost my job

    ` 233 | } 234 | } 235 | 236 | const arrestByMurder = (person) => { 237 | arrest(8, 17, person) 238 | } 239 | 240 | const arrestByStealingCar = (person) => { 241 | arrest(1, 3, person) 242 | } 243 | 244 | const pregnancyHandler = (person) => { 245 | if(!person.pregnant) return 246 | 247 | person.pregnant = false; 248 | const partner = person.relationships.partner[0] 249 | const possibleGenders = ['male', 'female'] 250 | const gender = possibleGenders[Math.round(Math.random())] 251 | 252 | if(person.characterIndex == player.characterIndex || person.characterIndex == player.characterIndex.relationships.partner[0]){ 253 | const pronoun = gender === 'male' ? 'him' : 'her' 254 | modalBackground.style.display = 'flex' 255 | eventTitle.innerText = `Its a ${gender == 'male' ? 'boy' : 'girl'}` 256 | eventBody.innerHTML = ` 257 |

    How will you call ${pronoun}

    258 | 259 |
    Name ${pronoun}
    260 |
    Random
    261 | ` 262 | return 263 | } 264 | const nationality = nationalityQuery(person.location) 265 | const offspring = new Person(undefined, partner != undefined ? partner.surname : person.surname, 0, gender, nationality) 266 | person.relationships.offspring.push(offspring) 267 | offspring.relationships.parents.push(person) 268 | if(partner != undefined){ 269 | partner.relationships.offspring.push(offspring) 270 | offspring.relationships.parents.push(partner) 271 | } 272 | 273 | characters.push(offspring) 274 | } 275 | 276 | const statsChanges = () => { 277 | const stats = Object.entries(player.stats) 278 | for(let stat of stats) { 279 | // if its true buffes the stat 280 | if(Math.floor(Math.random() * 2) === 1){ 281 | player.stats[stat[0]] += Math.floor(Math.random() * 5) 282 | } else { 283 | player.stats[stat[0]] -= Math.floor(Math.random() * 5) 284 | } 285 | } 286 | } -------------------------------------------------------------------------------- /js/careers.js: -------------------------------------------------------------------------------- 1 | const childhoodEducation = { 2 | preschool: { 3 | label:'Preschool', 4 | since: 3, 5 | until: 5, 6 | }, 7 | elementary: { 8 | label: 'Elementary school', 9 | since: 5, 10 | } 11 | } 12 | 13 | const universityCareers = { 14 | medic: { 15 | label: 'medic', 16 | name: 'Medic', 17 | duration: 4, 18 | buff(player) { 19 | player.stats.smartness += Math.floor(Math.random() * 5) 20 | } 21 | }, 22 | computerScience: { 23 | label: 'computerScience', 24 | name: 'Computer science', 25 | duration: 4, 26 | buff(player) { 27 | player.stats.smartness += Math.floor(Math.random() * 5) 28 | player.skills.programming.xp += 50 + Math.floor(Math.random() * 20) 29 | } 30 | }, 31 | biology: { 32 | label: 'biology', 33 | name: 'Biology', 34 | duration: 4, 35 | buff(player) { 36 | player.stats.smartness += Math.floor(Math.random() * 5) 37 | } 38 | }, 39 | chemistry: { 40 | label: 'chemistry', 41 | name: 'Chemistry', 42 | duration: 4, 43 | buff(player) { 44 | player.stats.smartness += Math.floor(Math.random() * 5) 45 | } 46 | }, 47 | history : { 48 | label: 'history', 49 | name: 'History', 50 | duration: 4, 51 | buff(player) { 52 | player.stats.smartness += Math.floor(Math.random() * 5) 53 | } 54 | }, 55 | politicalScience: { 56 | label: 'politicalScience', 57 | name: 'Political science', 58 | duration: 4, 59 | buff(player) { 60 | player.stats.smartness += Math.floor(Math.random() * 5) 61 | } 62 | }, 63 | math: { 64 | label: 'math', 65 | name: 'Math', 66 | duration: 4, 67 | buff(player) { 68 | player.stats.smartness += Math.floor(Math.random() * 5) 69 | } 70 | }, 71 | 72 | 73 | } 74 | 75 | const jobs = [ 76 | { 77 | label: 'Jr App Developer', 78 | requirements: { 79 | education: 'computerScience', 80 | programming: 3 81 | }, 82 | salary: 55000, 83 | field: 'technology', 84 | promotion: 'App Developer', 85 | buff(player){ 86 | player.skills.programming.xp += 5 + Math.floor(Math.random() * 20); 87 | } 88 | }, { 89 | label: 'App Developer', 90 | requirements: { 91 | education: 'computerScience', 92 | programming: 5 93 | }, 94 | salary: 75000, 95 | field: 'technology', 96 | promotion: 'Sr App Developer', 97 | buff(player){ 98 | player.skills.programming.xp += 5 + Math.floor(Math.random() * 20); 99 | } 100 | }, { 101 | label: 'Sr App Developer', 102 | requirements: { 103 | education: 'computerScience', 104 | programming: 8 105 | }, 106 | salary: 100000, 107 | field: 'technology', 108 | promotion: 'none', 109 | buff(player){ 110 | player.skills.programming.xp += 5 + Math.floor(Math.random() * 20); 111 | } 112 | }, { 113 | label: 'Supermarket cashier', 114 | requirements: { 115 | minAge: 16 116 | }, 117 | salary: 25000, 118 | field: '', 119 | promotion: 'none', 120 | buff(player){ 121 | return 122 | } 123 | },{ 124 | label: 'Janitor', 125 | requirements: { 126 | minAge: 16 127 | }, 128 | salary: 18000, 129 | field: '', 130 | promotion: 'none', 131 | buff(player){ 132 | player.skills.handiness.xp += 5 + Math.floor(Math.random() * 20); 133 | } 134 | }, { 135 | label: 'History teacher', 136 | requirements: { 137 | minAge: 20, 138 | education: 'history' 139 | }, 140 | salary: 50000, 141 | field: 'history', 142 | promotion: 'none', 143 | buff(player){ 144 | return 145 | } 146 | },{ 147 | label: 'Math teacher', 148 | requirements: { 149 | minAge: 20, 150 | education: 'math' 151 | }, 152 | salary: 50000, 153 | field: 'math', 154 | promotion: 'none', 155 | buff(player){ 156 | return 157 | } 158 | },{ 159 | label: 'Gym trainer', 160 | requirements: { 161 | minAge: 18, 162 | fitness: 70 163 | }, 164 | salary: 36000, 165 | field: 'fitness', 166 | promotion: 'none', 167 | buff(player){ 168 | return 169 | } 170 | }, { 171 | label: 'Chemistry teacher', 172 | requirements: { 173 | minAge: 20, 174 | education: 'chemistry' 175 | }, 176 | salary: 50000, 177 | field: 'chemistry', 178 | promotion: 'none', 179 | buff(player){ 180 | return 181 | } 182 | }, { 183 | label: 'Biology teacher', 184 | requirements: { 185 | minAge: 20, 186 | education: 'biology' 187 | }, 188 | salary: 50000, 189 | field: 'biology', 190 | promotion: 'none', 191 | buff(player){ 192 | return 193 | } 194 | }, { 195 | label: 'Jr Web developer', 196 | requirements: { 197 | minAge: 18, 198 | education: 'computerScience', 199 | programming: 2 200 | }, 201 | salary: 52000, 202 | field: 'technology', 203 | promotion: 'Web developer', 204 | buff(player){ 205 | player.skills.programming.xp += 5 + Math.floor(Math.random() * 20); 206 | } 207 | }, { 208 | label: 'Web developer', 209 | requirements: { 210 | education: 'computerScience', 211 | programming: 4 212 | }, 213 | salary: 65000, 214 | field: 'technology', 215 | promotion: 'Sr Web developer', 216 | buff(player){ 217 | player.skills.programming.xp += 5 + Math.floor(Math.random() * 20); 218 | } 219 | }, { 220 | label: 'Sr Web developer', 221 | requirements: { 222 | education: 'computerScience', 223 | programming: 7 224 | }, 225 | salary: 80000, 226 | field: 'technology', 227 | promotion: 'none', 228 | buff(player){ 229 | player.skills.programming.xp += 5 + Math.floor(Math.random() * 20); 230 | } 231 | }, { 232 | label: 'Truck driver', 233 | requirements: { 234 | driverLicense: true 235 | }, 236 | salary: 40000, 237 | field: 'transport', 238 | promotion: 'none', 239 | buff(player){ 240 | return 241 | } 242 | }, { 243 | label: 'Taxi driver', 244 | requirements: { 245 | driverLicense: true 246 | }, 247 | salary: 48000, 248 | field: 'transport', 249 | promotion: 'none', 250 | buff(player){ 251 | return 252 | } 253 | }, { 254 | label: 'Music teacher', 255 | requirements: { 256 | education: 'music', 257 | music: 2 258 | }, 259 | salary: 50000, 260 | field: 'music', 261 | promotion: 'none', 262 | buff(player){ 263 | player.skills.music.xp += 5 + Math.floor(Math.random() * 20); 264 | } 265 | }, { 266 | label: 'Pianist', 267 | requirements: { 268 | education: 'music', 269 | music: 4 270 | }, 271 | salary: 55000, 272 | field: 'music', 273 | promotion: 'none', 274 | buff(player){ 275 | player.skills.music.xp += 5 + Math.floor(Math.random() * 20); 276 | } 277 | }, { 278 | label: 'Guru', 279 | requirements: { 280 | happiness: 100, 281 | health: 100, 282 | minAge: 18, 283 | criminalRecord: 'clean' 284 | }, 285 | salary: 78000, 286 | promotion: 'none', 287 | buff(player){ 288 | return 289 | } 290 | }, 291 | { 292 | label: 'Apprentice carpenter', 293 | requirements: { 294 | minAge: 18, 295 | handiness: 5, 296 | fitness: 70 297 | }, 298 | salary: 41000, 299 | field: 'construction', 300 | promotion: 'none', 301 | buff(player){ 302 | player.skills.handiness.xp += 5 + Math.floor(Math.random() * 20); 303 | } 304 | }, 305 | { 306 | label: 'Apprentice construction worker', 307 | requirements: { 308 | handiness: 5, 309 | minAge: 18 310 | }, 311 | salary: 30000, 312 | field: 'construction', 313 | promotion: 'Construction worker', 314 | buff(player){ 315 | player.skills.handiness.xp += 5 + Math.floor(Math.random() * 20); 316 | } 317 | }, 318 | { 319 | label: 'Construction worker', 320 | requirements: { 321 | handiness: 8, 322 | minAge: 18 323 | }, 324 | salary: 40000, 325 | field: 'construction', 326 | promotion: 'none', 327 | buff(player){ 328 | player.skills.handiness.xp += 5 + Math.floor(Math.random() * 20); 329 | } 330 | }, 331 | { 332 | label: 'Police officer', 333 | requirements: { 334 | fitness: 85, 335 | minAge: 25, 336 | criminalRecord: 'clean' 337 | }, 338 | salary: 55000, 339 | field: 'lawEnforcement', 340 | promotion: 'none', 341 | buff(player){ 342 | return 343 | } 344 | }, 345 | { 346 | label: 'Barber', 347 | requirements: { 348 | handiness: 3, 349 | minAge: 18, 350 | criminalRecord: 'clean' 351 | }, 352 | salary: 24000, 353 | field: 'smallBussiness', 354 | promotion: 'none', 355 | buff(player){ 356 | return 357 | } 358 | }, 359 | { 360 | label: 'Apprentice pediatrician', 361 | requirements: { 362 | education: 'medic', 363 | minAge: 20, 364 | }, 365 | salary: 50000, 366 | field: 'medicine', 367 | promotion: 'Pediatrician', 368 | buff(player){ 369 | return 370 | } 371 | }, 372 | { 373 | label:'Pediatrician', 374 | requirements: { 375 | education: 'medic', 376 | minAge: 20, 377 | handiness: 3 378 | }, 379 | salary: 75000, 380 | field: 'medicine', 381 | promotion: 'none', 382 | buff(player){ 383 | return 384 | } 385 | } 386 | ]; -------------------------------------------------------------------------------- /js/libs.js: -------------------------------------------------------------------------------- 1 | let leftBtnContainer = document.getElementById('left-btn-container') 2 | 3 | let menuTemplate = document.getElementById('menu-template'); 4 | let menuBody = document.getElementById('menu-body'); 5 | let menuTitle = document.getElementById('menu-title'); 6 | let eventContainer = document.getElementById('event-container') 7 | 8 | const randomStat = (min, max) => { 9 | return min + Math.floor(Math.random() * max); 10 | } 11 | 12 | const genderRandomizer = () => { 13 | const index = Math.round(Math.random()); 14 | const genders = ['male', 'female']; 15 | return genders[index] 16 | } 17 | 18 | const countryRandomizer = () => { 19 | const data = countriesData[Math.round(Math.random() * countriesData.length)]; 20 | return data.nationality; 21 | } 22 | 23 | const languageQuery = (nationality) => { 24 | for(let country of countriesData){ 25 | if(country.nationality == nationality) return country.language; 26 | } 27 | } 28 | const birthplaceQuery = (nationality) => { 29 | for(let country of countriesData){ 30 | if(country.nationality == nationality) return country.country; 31 | } 32 | } 33 | 34 | const nationalityQuery = (location) => { 35 | for(let country of countriesData){ 36 | if(country.country == location) return country.nationality 37 | } 38 | } 39 | 40 | const countryQuery = (countryName) => { 41 | for(let country of countriesData){ 42 | if(country.country === countryName) return country 43 | } 44 | } 45 | 46 | const nameRandomizer = (languaje, gender) => { 47 | const nameEntries = Object.entries(names); 48 | let matchingList; 49 | for(let list of nameEntries){ 50 | if(list[0] === languaje) matchingList = list[1]; 51 | } 52 | return matchingList[gender][Math.floor(Math.random() * matchingList[gender].length)] 53 | } 54 | 55 | const surnameRandomizer = (languaje) => { 56 | const nameEntries = Object.entries(surnames); 57 | let matchingList; 58 | for(let list of nameEntries){ 59 | if(list[0] === languaje) { 60 | matchingList = list[1]; 61 | } 62 | } 63 | const surname = matchingList[Math.floor(Math.random() * matchingList.length )] 64 | console.log(surname) 65 | return surname 66 | } 67 | 68 | const countriesList = () => { 69 | let string = ''; 70 | for(let country of countriesData){ 71 | if(country.country !== player.location) 72 | string = string.concat(``) 73 | } 74 | return string; 75 | } 76 | 77 | const nationalityList = () => { 78 | let string = ''; 79 | for(let country of countriesData){ 80 | string = string.concat(``) 81 | } 82 | return string; 83 | } 84 | 85 | //displays items including houses and cars 86 | const itemListifier = (obj, property, objName) => { 87 | let string = ''; 88 | let index = 0; 89 | let collection = obj[property] 90 | if(objName === 'items') 91 | for(let element of obj[property]) { 92 | string = string.concat(`
  • ${element.label} (${moneyFormat(element.price)} $)
  • `) 93 | index++; 94 | } 95 | else if(objName === 'assets'){ 96 | for(let element of collection.sort((a, b) => b.price - a.price)) { 97 | string = string.concat(`
    ${element.label} (${moneyFormat(element.price)} $)
    `) 99 | index++; 100 | } 101 | return string 102 | } 103 | return string 104 | } 105 | 106 | const ownedAssets = (type) =>{ 107 | let string = ''; 108 | for(let asset of player.inventory[type]){ 109 | string = string.concat(`
    110 | ${asset.label} 111 |
    `) 112 | } return string 113 | 114 | } 115 | 116 | const capitalize = (word) =>{ 117 | let newWord = [] 118 | for(let i = 0; i < word.length; i++){ 119 | if(i === 0) newWord.push(word.split('')[i].toUpperCase()) 120 | else newWord.push(word.split('')[i]) 121 | } return newWord = newWord.join('') 122 | } 123 | 124 | const relationShipListifier = (category) => { 125 | const title = capitalize(category) 126 | 127 | const relations = player.relationships[category] 128 | let string = `

    ${title}:

    `; 129 | let index = 0; 130 | //these bars depend on windows.handleRelationBars() 131 | if(relations.length !== 0) for(let relation of relations){ 132 | string = string.concat(` 133 |
    135 |

    ${relation.fullName} ${!relation.alive ? '(Dead)' : ''}

    136 |
    137 |
    Opinion about you
    138 | ${category === 'partner' ? ` 139 |
    Love
    140 | ` : ''} 141 |
    142 |
    143 | `) 144 | index++; 145 | } else string = '' 146 | return `
    ${string}
    ` 147 | } 148 | 149 | const statbarColorer = () => { 150 | let progressBars = document.getElementsByClassName('bar-progress'); 151 | for (let progressBar of progressBars) { 152 | let percentage = parseInt(progressBar.style.width.split('%')[0]); 153 | if (percentage > 55) progressBar.style.backgroundColor = 'rgb(47, 151, 73)' 154 | else if (percentage > 25) progressBar.style.backgroundColor = 'rgb(196, 221, 105)' 155 | else progressBar.style.backgroundColor = 'rgb(185, 61, 61)' 156 | } 157 | } 158 | 159 | const handleStatBars = (person, isPlayer) => { 160 | const stats = ['health', 'happiness', 'smartness', 'appearance', 'fitness']; 161 | const windowStat = ['relationWithPlayer', 'health', 'happiness', 'smartness', 'appearance', 'fitness'] 162 | 163 | if(isPlayer) for (let stat of stats) { 164 | document.getElementById(`${stat}-bar`).style.width = `${person.stats[stat]}%` 165 | } 166 | else for(let stat of windowStat){ 167 | document.getElementById(`window-${stat}-bar`).style.width = `${person.stats[stat]}%` 168 | } 169 | statbarColorer() 170 | } 171 | 172 | const skillListifier = (player) => { 173 | let skills = player.skills; 174 | let defaultString = 'You do not have any skill' 175 | let string = ''; 176 | for(let skill of Object.entries(skills)){ 177 | if(skill[1].level !== 0 || skill[1].level === 0 && 178 | skill[1].xp !== 0){ 179 | string = string.concat(` 180 |
  • 181 |

    ${capitalize(skill[0])}

    182 |

    Level: ${skill[1].level}

    183 |

  • 184 | `) 185 | } 186 | } if(string === '') return defaultString 187 | return `` 188 | } 189 | 190 | const moneyFormat = (money) => { 191 | money = money.toString() 192 | let parsedMoney = [] 193 | let amountOfNumbers = 0; 194 | 195 | for(let i = money.length - 1; i >= 0; i--){ 196 | parsedMoney.unshift(money[i]) 197 | amountOfNumbers++; 198 | 199 | if(amountOfNumbers === 3){ 200 | parsedMoney.unshift('.') 201 | amountOfNumbers = 0 202 | } 203 | } 204 | if(parsedMoney[0] == '-' && parsedMoney[1] == '.') { 205 | parsedMoney.splice(1, 1) 206 | return parsedMoney.join('') 207 | } else if(parsedMoney[0] !== '.') return parsedMoney.join('') 208 | return parsedMoney.join('').slice(1) 209 | } 210 | 211 | const cvListifier = (player) =>{ 212 | if(player.cv.length === 0) return `

    You do not have job history

    ` 213 | 214 | let string = ''; 215 | for(let job of player.cv){ 216 | string = string.concat(` 217 |
  • 218 | ${job.label} (${job.since} - ${job.until}) 219 |
  • 220 | `) 221 | return `` 222 | } 223 | 224 | } 225 | 226 | const lifeStageDisplayer = () => { 227 | let headContainer = document.getElementById('head-container'); 228 | if (player.age < 18) { 229 | headContainer.innerText = 'Childhood'; 230 | player.lifeStage = 'childhood'; 231 | } else if (player.age < 60) { 232 | headContainer.innerText = 'Adulthood'; 233 | player.lifeStage = 'adulthood' 234 | } 235 | else { 236 | headContainer.innerText = 'Elderhood'; 237 | player.lifeStage = 'elderhood' 238 | } 239 | } 240 | 241 | //reverts camelCase 242 | const uncamelCaser = (string) => { 243 | if(typeof string !== 'string') return string 244 | 245 | let arr = [] 246 | for(let i = 0; i < string.length; i++){ 247 | if(string[i] === string[i].toUpperCase()){ 248 | arr.push(' ') 249 | arr.push(string[i].toLowerCase()) 250 | } else { 251 | arr.push(string[i]) 252 | } 253 | } 254 | return capitalize(arr.join('').trim()) 255 | } 256 | 257 | const jobRequirementsListifier = (index) => { 258 | const jobRequirements = jobs[index].requirements 259 | let string = ''; 260 | for(let requirement of Object.entries(jobRequirements)){ 261 | let reqName = requirement[0] 262 | if(requirement[0] === 'minAge') 263 | reqName = 'Minimal age' 264 | string = string.concat(` 265 |
  • ${capitalize(uncamelCaser(reqName))}: ${uncamelCaser(requirement[1])}
  • 266 | `) 267 | } 268 | return string 269 | } 270 | 271 | // its used when you want to give the needed stats to any npc for its job 272 | const requirementsFiller = (obj, person) =>{ 273 | const statsList = ['programming', 'handiness', 'writing', 'art', 'music'] 274 | const requirements = obj.requirements 275 | person.career.education = {name: 'Highschool'} 276 | for(let req of Object.entries(requirements)){ 277 | if(statsList.includes(req[0])) 278 | person.skills[req[0]].level = req[1] 279 | 280 | if(req[0] === 'education') 281 | person.career[req[1]] = universityCareers[req[1]] 282 | 283 | if(req[0] === 'driverLicense') 284 | person.driverLicense = true 285 | } 286 | } 287 | 288 | const numAbbreviation = (money) => { 289 | const array = moneyFormat(money).split('.') 290 | const size = array.length 291 | const handler = (letter) => { 292 | console.log(parseInt(array[1][0]) !== 0) 293 | if(parseInt(array[1][0]) !== 0) 294 | return `${array[0]}.${array[1][0]}${letter}` 295 | else 296 | return array[0] + letter 297 | } 298 | if(size === 2) return handler('K') 299 | else if(size === 3) return handler('M') 300 | else if(size === 4) return handler('B') 301 | } 302 | 303 | const moneyViewer = () => { 304 | const totalMoney = document.getElementById('total-money'); 305 | totalMoney.innerText = `${moneyFormat(player.money.total)} $`; 306 | 307 | const balance = document.getElementById('balance'); 308 | if(player.money.income - player.money.expenses > 0) 309 | balance.innerHTML = `+${numAbbreviation(player.money.income - player.money.expenses)} $` 310 | else if(player.money.income - player.money.expenses < 0) 311 | balance.innerHTML = `${numAbbreviation(player.money.income - player.money.expenses)} $` 312 | else if(player.money.income - player.money.expenses === 0) 313 | balance.innerText = '' 314 | } 315 | 316 | const createChild = (personIndex, gender) => { 317 | const person = characters[personIndex] 318 | const partner = person.relationships.partner[0] 319 | const name = document.getElementById('name-field').value; 320 | const surname = partner.surname 321 | const nationality = nationalityQuery(person.location) 322 | const offspring = new Person(name, partner != undefined ? surname : person.surname, 0, gender, nationality) 323 | offspring.stats.relationWithPlayer = 50 + Math.floor(Math.random() * 50) 324 | 325 | characters.push(offspring) 326 | person.relationships.offspring.push(offspring) 327 | offspring.relationships.parents.push(person) 328 | if(partner != undefined){ 329 | partner.relationships.offspring.push(offspring) 330 | offspring.relationships.parents.push(partner) 331 | } 332 | 333 | textContainer.innerHTML += ` 334 |

    My ${gender === 'male' ? 'son' : 'daughter'} has born. ${gender === 'male' ? 'His' : 'Her'} name is ${offspring.name}

    335 | ` 336 | closeEvent(); 337 | } 338 | 339 | const randomNameForChildren = (personIndex) => { 340 | const person = characters[personIndex] 341 | const gender = person.gender; 342 | const array = names[person.language][gender] 343 | const random = Math.floor(Math.random() * array.length) 344 | document.getElementById('name-field').value = array[random] 345 | } 346 | 347 | const closeEvent = () => { 348 | eventTitle.innerText = ''; 349 | eventBody.innerHTML = ''; 350 | eventContainer.style.display = 'none' 351 | modalBackground.style.display = 'none'; 352 | } 353 | 354 | const showEvent = ({title, body}) => { 355 | eventTitle.innerText = title 356 | eventBody.innerHTML = body 357 | eventContainer.style.display = 'block' 358 | modalBackground.style.display = 'flex' 359 | } 360 | 361 | // used for story events 362 | const createStoryEvent = ({title, body}) => { 363 | const eventsContainer = document.getElementById("events-container") 364 | const index = eventsContainer.children.length 365 | eventsContainer.innerHTML += ` 366 | 378 | ` 379 | } 380 | 381 | const modifyStoryEvent = ({title, body, id}) => { 382 | const eventTitle = document.getElementById(`event-${id}-title`) 383 | const eventBody = document.getElementById(`event-${id}-body`) 384 | 385 | eventTitle.innerText = title 386 | eventBody.innerHTML = body(id) 387 | } 388 | 389 | const closeStoryEvent = (id) => { 390 | document.getElementById(`event-${id}`).remove() 391 | } 392 | 393 | // this function will replace the statbarColorer 394 | const barColor = (percentage) => { 395 | if(percentage > 55) return `rgb(47, 151, 73)` 396 | else if (percentage > 25) return `rgb(196, 221, 105)` 397 | else return `rgb(185, 61, 61)` 398 | } 399 | 400 | const scrolldown = (element) => { 401 | element.scrollTop = element.scrollHeight; 402 | } -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | :root{ 2 | --purple-text: #8b6ddd; 3 | --yellow-text: #fcd34d; 4 | --gray-line: rgb(68, 65, 87); 5 | --background-color: rgb(42 42 44); 6 | --option-background: rgb(87, 87, 87); 7 | --disabled-option-background: rgb(70, 70, 70); 8 | } 9 | 10 | .clear{ 11 | clear: both; 12 | } 13 | 14 | #text-container p { 15 | margin-top: 2px; 16 | } 17 | 18 | *{ 19 | padding: 0; 20 | margin: 0; 21 | font-family: sans-serif; 22 | } 23 | 24 | 25 | body{ 26 | background-color: var(--background-color); 27 | color: white; 28 | } 29 | 30 | hr { 31 | border-color: #696969; 32 | } 33 | 34 | .modal{ 35 | position: fixed; 36 | top: 0; 37 | left: 0; 38 | z-index: 10; 39 | width: 100%; 40 | height: 100%; 41 | background-color: rgba(0, 0, 0, 0.3); 42 | transition: all ease 0.5s; 43 | display: none; 44 | align-items: center; 45 | justify-content: center; 46 | 47 | } 48 | 49 | .flex { 50 | display: flex !important; 51 | } 52 | 53 | .event-container{ 54 | background-color: #3b3b3b; 55 | color: white; 56 | width: 300px; 57 | border-radius: 10px; 58 | max-height: 800px; 59 | z-index: 5; 60 | animation-name: event-popup; 61 | animation-duration: 0.2s; 62 | } 63 | 64 | .event-container p { 65 | line-height: 20px; 66 | } 67 | 68 | @keyframes event-popup { 69 | from { 70 | width: 0; 71 | height: 0; 72 | } 73 | to { 74 | width: 300px; 75 | height: min-content; 76 | } 77 | } 78 | 79 | .event-title{ 80 | text-align: center; 81 | padding: 10px; 82 | } 83 | 84 | .event-body{ 85 | padding: 15px; 86 | display: flex; 87 | flex-direction: column; 88 | justify-content: center; 89 | } 90 | 91 | .option{ 92 | cursor: pointer; 93 | font-size: 1.2em; 94 | padding: 5px; 95 | border: 2px solid var(--gray-line); 96 | background-color: var(--option-background); 97 | border-radius: 5px; 98 | width: 170px; 99 | height: 40px; 100 | display: flex; 101 | justify-content: center; 102 | align-items: center; 103 | margin: 5px auto; 104 | position: relative; 105 | } 106 | 107 | 108 | .yellow { 109 | color: #bece63 110 | } 111 | 112 | #navbar{ 113 | background-color: rgb(56, 56, 56); 114 | width: 100%; 115 | min-height: 50px; 116 | display: flex; 117 | flex-direction: row; 118 | align-items: center; 119 | position: fixed; 120 | } 121 | 122 | #money-container{ 123 | margin: 0 auto; 124 | padding: 5px; 125 | cursor: pointer; 126 | border-radius: 10px; 127 | min-width: 60px; 128 | transition: all ease 0.3s; 129 | } 130 | 131 | #money-container:hover { 132 | background-color: #303030; 133 | } 134 | 135 | .row{ 136 | display: flex; 137 | flex-direction: row; 138 | align-items: center; 139 | position: relative; 140 | } 141 | 142 | .row:nth-child(2){ 143 | margin-top: 5px; 144 | min-height: 50px; 145 | width: 100%; 146 | display: flex; 147 | justify-content: space-between; 148 | } 149 | 150 | .btn{ 151 | color: #48c267; 152 | padding: 15px; 153 | border-radius: 50%; 154 | font-size: 1.1em; 155 | border: 2px solid var(--gray-line); 156 | background-color: #2c2428; 157 | cursor: pointer; 158 | } 159 | 160 | #age-btn{ 161 | margin: 0 auto; 162 | color: #48c267; 163 | padding: 20px 50px; 164 | border-radius: 5%; 165 | font-size: 1.1em; 166 | border: 2px solid var(--gray-line); 167 | background-color: #2c2428; 168 | cursor: pointer; 169 | 170 | } 171 | 172 | #activities-btn{ 173 | float: right; 174 | color: #48c267; 175 | padding: 20px 20px; 176 | border-radius: 50%; 177 | font-size: 1.1em; 178 | border: 2px solid var(--gray-line); 179 | background-color: #2c2428; 180 | cursor: pointer; 181 | } 182 | 183 | #stats-list{ 184 | clear: both; 185 | height: min-content; 186 | display: block; 187 | display: flex; 188 | flex-direction: column; 189 | align-items: center; 190 | border: 2px solid var(--gray-line); 191 | border-radius: 2%; 192 | padding: 5px; 193 | background-color: #2c2428; 194 | } 195 | 196 | #stats-list li{ 197 | text-align: right; 198 | display: flex; 199 | flex-direction: row; 200 | margin: 2px; 201 | float: right; 202 | width: 100%; 203 | justify-content: end; 204 | } 205 | 206 | #stats-list ul { 207 | margin: 0 auto; 208 | } 209 | 210 | .bar{ 211 | margin-left: 5px; 212 | background-color: rgb(68, 65, 87); 213 | width: 250px; 214 | } 215 | 216 | .bar-progress{ 217 | height: 100%; 218 | animation-duration: 0.4s; 219 | } 220 | 221 | @keyframes animation-bar { 222 | from { 223 | width: 0; 224 | } 225 | } 226 | 227 | .bar-percentage{ 228 | float: right; 229 | 230 | } 231 | 232 | #tale-container{ 233 | margin: 10px auto; 234 | width: 365px; 235 | border: 2px solid rgb(68, 65, 87); 236 | border-radius: 2%; 237 | background-color: #2c2428; 238 | } 239 | 240 | #text-container{ 241 | overflow-y: auto; 242 | height: calc(100vh - 500px); 243 | padding: 15px; 244 | } 245 | 246 | *::-webkit-scrollbar { 247 | background-color: #303030; 248 | width: 15px; 249 | } 250 | 251 | *::-webkit-scrollbar-thumb { 252 | background-color: #505050; 253 | border-radius: 15px; 254 | } 255 | 256 | #head-container{ 257 | padding: 15px; 258 | text-align: center; 259 | border-bottom: 2px solid rgb(68, 65, 87);; 260 | } 261 | 262 | main{ 263 | padding-top: 65px; 264 | } 265 | 266 | #menu-template{ 267 | background-color: rgb(41, 41, 41); 268 | position: fixed; 269 | left: 0; 270 | bottom: 0; 271 | width: 100%; 272 | height: 100%; 273 | display: none; 274 | animation-name: menu-popup; 275 | animation-duration: 0.3s; 276 | padding: 0; 277 | } 278 | 279 | @keyframes menu-popup { 280 | from{ 281 | bottom: -100%; 282 | } 283 | to{ 284 | bottom: 0; 285 | } 286 | } 287 | 288 | #menu-template ul:not(#inventory-container) { 289 | display: flex; 290 | flex-direction: column; 291 | justify-content: center; 292 | align-items: center; 293 | min-height: 70vh; 294 | } 295 | 296 | #menu-template li:not(.item-container){ 297 | list-style: none; 298 | width: 300px; 299 | display: flex; 300 | justify-content: left; 301 | color: white; 302 | text-decoration: none; 303 | } 304 | 305 | #menu-template h2{ 306 | font-size: 1.6em; 307 | text-align: center; 308 | } 309 | 310 | #menu-template img:not(.item-preview){ 311 | width: 60px; 312 | height: 50px; 313 | margin-right: 5px; 314 | float: left; 315 | } 316 | 317 | .menu-header{ 318 | display: flex; 319 | flex-direction: row; 320 | padding: 5px; 321 | margin-top: 15px; 322 | } 323 | 324 | .menu-header h2 { 325 | margin: 0 auto; 326 | text-align: center; 327 | } 328 | 329 | .menu-header button { 330 | float: right; 331 | margin-right: 15px; 332 | } 333 | 334 | a{ 335 | text-decoration: none; 336 | color: white; 337 | } 338 | 339 | #close-menu{ 340 | background: none; 341 | border: none; 342 | font-size: 1.5em; 343 | cursor: pointer; 344 | color: #ffff; 345 | position: absolute; 346 | right: 15px; 347 | } 348 | 349 | #control-container{ 350 | margin: 0 auto; 351 | width: 360px; 352 | } 353 | 354 | hr{ 355 | margin-bottom: 10px; 356 | } 357 | 358 | #stats-container{ 359 | display: flex; 360 | justify-content: center; 361 | } 362 | 363 | select{ 364 | margin: 0 auto; 365 | width: 80%; 366 | padding: 15px ; 367 | background-color:rgb(56, 56, 56); 368 | color: white; 369 | font-size: 20px; 370 | border-radius: 15px; 371 | } 372 | 373 | #menu-template select{ 374 | margin: 0 auto; 375 | width: 324px; 376 | padding: 15px ; 377 | background-color:rgb(56, 56, 56); 378 | color: white; 379 | font-size: 20px; 380 | border: none; 381 | border-radius: 15px; 382 | } 383 | 384 | #menu-template #select-container{ 385 | display: flex; 386 | justify-content: center; 387 | margin-top: 30px; 388 | width: 100%; 389 | } 390 | 391 | .switch{ 392 | width: 20px; 393 | height: 20px; 394 | border-radius: 50%; 395 | background-color: #bece63; 396 | } 397 | 398 | .switch-background{ 399 | background-color: rgb(109, 33, 105); 400 | width: 50px; 401 | height: 20px; 402 | padding: 1px; 403 | border-radius: 100%; 404 | margin-right: 15px; 405 | } 406 | 407 | li{ 408 | list-style: none; 409 | } 410 | 411 | .relationship-container{ 412 | margin: 0 auto; 413 | margin-bottom: 5px; 414 | background-color: #7b4891; 415 | padding: 10px 20px; 416 | border: 2px solid #693b7c; 417 | border-radius: 5px; 418 | cursor: pointer; 419 | } 420 | 421 | .relationship-container p{ 422 | display: flex; 423 | flex-direction: column; 424 | justify-content: right; 425 | } 426 | 427 | .relation-background{ 428 | margin-left: 5px; 429 | background-color: rgb(89, 56, 121); 430 | width: 235px; 431 | height: 15px; 432 | } 433 | 434 | .relation{ 435 | height: 100%; 436 | } 437 | 438 | .opinion-data-wrapper{ 439 | display: flex; 440 | flex-direction: column; 441 | } 442 | 443 | .window-bar{ 444 | width: 250px; 445 | height: 15px; 446 | background-color: #303030; 447 | } 448 | 449 | .event-container hr{ 450 | animation-name: loading-hr; 451 | animation-duration: 0.5s; 452 | margin: 0 auto; 453 | } 454 | 455 | #event-container { 456 | display: none; 457 | } 458 | 459 | @keyframes loading-hr{ 460 | from{ 461 | width: 0; 462 | } to{ 463 | width: 100%; 464 | } 465 | } 466 | 467 | .disabled{ 468 | background-color: var(--disabled-option-background); 469 | color: #969696 !important; 470 | cursor: not-allowed; 471 | } 472 | 473 | #job-wrapper{ 474 | width: 350px; 475 | margin: 0 auto; 476 | } 477 | 478 | #jobs-container{ 479 | height: 80vh; 480 | border: 2px solid #636363; 481 | margin: 0 auto; 482 | padding: 0 ; 483 | align-items: flex-start !important; 484 | justify-content: flex-start !important; 485 | overflow-y: auto; 486 | } 487 | 488 | .cell{ 489 | height: 2em; 490 | background-color: #303030; 491 | border-bottom: 1px solid #636363; 492 | padding: 10px; 493 | cursor: pointer; 494 | } 495 | 496 | .cell:hover{ 497 | background-color: #4d4d4d; 498 | } 499 | 500 | .column{ 501 | display: flex; 502 | flex-direction: column; 503 | } 504 | 505 | .switch-container{ 506 | position: absolute; 507 | right: 5px; 508 | } 509 | 510 | .green{ 511 | color: #15c53b; 512 | } 513 | 514 | 515 | .item-container{ 516 | background-color: #303030; 517 | width: 120px !important; 518 | height: 150px; 519 | margin: 15px; 520 | cursor: pointer; 521 | } 522 | 523 | .item-container figcaption{ 524 | text-align: center; 525 | } 526 | 527 | #inventory-container{ 528 | display: flex; 529 | flex-direction: row !important; 530 | justify-content: center; 531 | align-items: baseline !important; 532 | flex-wrap: wrap; 533 | padding: 15px; 534 | 535 | } 536 | 537 | .item-preview{ 538 | width: 120px; 539 | height: 80%; 540 | } 541 | 542 | #no-items{ 543 | text-align: center; 544 | font-size: 30px; 545 | display: flex; 546 | justify-content: center; 547 | align-items: center; 548 | min-height: calc(100vh - 150px); 549 | } 550 | 551 | #money-container{ 552 | text-align: center; 553 | } 554 | 555 | #relation-button{ 556 | display: flex; 557 | justify-content: center; 558 | align-items: center; 559 | margin: 0 auto; 560 | } 561 | 562 | .button-container{ 563 | text-align: center; 564 | font-size: 15px; 565 | } 566 | 567 | #relationship-container{ 568 | margin: 0 auto; 569 | } 570 | 571 | #cell-container{ 572 | height: 80vh; 573 | border: 2px solid #636363; 574 | margin: 0 auto; 575 | padding: 0 ; 576 | align-items: flex-start !important; 577 | justify-content: flex-start !important; 578 | overflow-y: auto; 579 | position: relative; 580 | } 581 | 582 | .tab{ 583 | padding: 5px; 584 | background-color: #3b3b3b; 585 | border: 2px solid #636363; 586 | border-bottom: none; 587 | width: 45%; 588 | border-top-left-radius: 5px; 589 | border-top-right-radius: 5px; 590 | z-index: 100; 591 | text-align: center; 592 | cursor: pointer; 593 | } 594 | 595 | .tab:hover{ 596 | background-color: #4d4d4d; 597 | } 598 | 599 | .active{ 600 | background-color: #4d4d4d; 601 | } 602 | 603 | .assetsContainer{ 604 | width: 350px; 605 | margin: 0 auto; 606 | } 607 | 608 | #assets-header{ 609 | display: flex; 610 | flex-direction: row; 611 | justify-content: space-between; 612 | } 613 | 614 | #death-screen{ 615 | position: fixed; 616 | left: 0; 617 | top: 0; 618 | width: 100%; 619 | height: 100%; 620 | background-color: #3b3b3b; 621 | display: none; 622 | } 623 | #death-screen-body{ 624 | margin: 0 auto; 625 | width: 350px; 626 | } 627 | 628 | #death-screen button{ 629 | margin: 0 auto; 630 | padding: 5px 15px; 631 | font-size: 20px; 632 | 633 | } 634 | 635 | #death-screen-title{ 636 | text-align: center; 637 | padding: 5px; 638 | } 639 | 640 | #obituary-container{ 641 | padding: 15px; 642 | margin: 0 auto; 643 | border: 2px solid #636363; 644 | border-radius: 15px; 645 | overflow-y: auto; 646 | height: 80vh; 647 | margin-bottom: 15px; 648 | } 649 | 650 | .relationships-container{ 651 | width: 360px; 652 | margin: 0 auto; 653 | } 654 | 655 | .relationships-container h3{ 656 | font-size: 1.5em; 657 | } 658 | 659 | #create-character-screen{ 660 | position: fixed; 661 | top: 0; 662 | left: 0; 663 | width: 100vw; 664 | height: 100vh; 665 | z-index: 10; 666 | background-color: rgba(27, 27, 27, 0.904); 667 | } 668 | 669 | #create-character-screen h1{ 670 | width: 350px; 671 | text-align: center; 672 | margin: 0 auto; 673 | color: var(--yellow-text); 674 | margin-top: 15px; 675 | font-size: 32px; 676 | } 677 | 678 | .create-btn{ 679 | padding: 10px 30px; 680 | width: 340px; 681 | font-size: 25px; 682 | margin: 15px auto; 683 | cursor: pointer; 684 | background-color: black; 685 | border: 2px solid var(--purple-text); 686 | color: var(--purple-text); 687 | transition: ease 0.5s; 688 | border-radius: 15px; 689 | } 690 | 691 | .create-btn:hover{ 692 | border: 2px solid #c373e6; 693 | color: #c373e6; 694 | } 695 | 696 | #buttons-container{ 697 | display: flex; 698 | flex-direction: column; 699 | width: 350px; 700 | margin: 30px auto; 701 | } 702 | 703 | #create-character-screen input, .event-body input{ 704 | padding: 5px; 705 | border-radius: 5px; 706 | background-color: #303030; 707 | border: none; 708 | color: #ffff; 709 | font-size: 20px; 710 | } 711 | 712 | #create-character-screen select{ 713 | width: 350px; 714 | padding: 5px; 715 | font-size: 15px; 716 | border-radius: 5px; 717 | border: none; 718 | background-color: #303030; 719 | color: #ffff; 720 | font-size: 20px; 721 | } 722 | 723 | .input-group{ 724 | width: 350px; 725 | margin: 0 auto; 726 | display: flex; 727 | flex-direction: column; 728 | } 729 | 730 | .input-group label{ 731 | margin-top: 15px; 732 | font-size: 25px; 733 | color: rgb(211, 211, 211); 734 | } 735 | 736 | #skills-icon{ 737 | width: 50px !important; 738 | } 739 | 740 | .btn img{ 741 | width: 30px; 742 | height: 30px; 743 | } 744 | 745 | .rectangular-btn{ 746 | margin: 0 auto; 747 | color: #48c267; 748 | width: 150px; 749 | height: 60px; 750 | border-radius: 5%; 751 | font-size: 1.1em; 752 | border: 2px solid var(--gray-line); 753 | background-color: var(--background-color); 754 | cursor: pointer; 755 | } 756 | .bar-container { 757 | width: 100%; 758 | } 759 | 760 | #profile-container{ 761 | position: absolute; 762 | right: 0; 763 | } 764 | 765 | #left-btn-container{ 766 | position: absolute; 767 | left: 0; 768 | } 769 | 770 | #general-container{ 771 | margin: 0 auto; 772 | width: 360px; 773 | } 774 | 775 | .green{ 776 | color: #15c53b; 777 | } 778 | 779 | .red{ 780 | color: #df3b3b; 781 | } 782 | 783 | #modal-background select { 784 | padding: 5px !important; 785 | } -------------------------------------------------------------------------------- /js/countriesData.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const countriesData = [ 4 | { 5 | country: 'United States', nationality: 'american', language: 'english', laws: { 6 | abort: true, 7 | gay_weddings: true, 8 | banned_youtube: false, 9 | banned_instagram: false 10 | } 11 | }, 12 | { 13 | country: 'Canada', nationality: 'canadian', language: 'english', laws: { 14 | abort: true, 15 | gay_weddings: true, 16 | banned_youtube: false, 17 | banned_instagram: false 18 | } 19 | }, 20 | { 21 | country: 'Mexico', nationality: 'mexican', language: 'spanish', laws: { 22 | abort: false, 23 | gay_weddings: true, 24 | banned_youtube: false, 25 | banned_instagram: false 26 | } 27 | }, 28 | { 29 | country: 'Guatemala', nationality: 'guatemalan', language: 'spanish', laws: { 30 | abort: false, 31 | gay_weddings: false, 32 | banned_youtube: false, 33 | banned_instagram: false 34 | } 35 | }, 36 | { 37 | country: 'Belice', nationality: 'belizean', language: 'english', laws: { 38 | abort: false, 39 | gay_weddings: false, 40 | banned_youtube: false, 41 | banned_instagram: false 42 | } 43 | }, 44 | { 45 | country: 'Honduras', nationality: 'honduran', language: 'spanish', laws: { 46 | abort: false, 47 | gay_weddings: false, 48 | banned_youtube: false, 49 | banned_instagram: false 50 | } 51 | }, 52 | { 53 | country: 'Nicaragua', nationality: 'nicaraguan', language: 'spanish', laws: { 54 | abort: false, 55 | gay_weddings: false, 56 | banned_youtube: false, 57 | banned_instagram: false 58 | } 59 | }, 60 | { 61 | country: 'Costa Rica', nationality: 'costa rican', language: 'spanish', laws: { 62 | abort: false, 63 | gay_weddings: true, 64 | banned_youtube: false, 65 | banned_instagram: false 66 | } 67 | }, 68 | { 69 | country: 'Panama', nationality: 'panamanian', language: 'spanish', laws: { 70 | abort: false, 71 | gay_weddings: false, 72 | banned_youtube: false, 73 | banned_instagram: false 74 | } 75 | }, 76 | { 77 | country: 'Colombia', nationality: 'colombian', language: 'spanish', laws: { 78 | abort: true, 79 | gay_weddings: true, 80 | banned_youtube: false, 81 | banned_instagram: false 82 | } 83 | }, 84 | { 85 | country: 'Venezuela', nationality: 'venezuelan', language: 'spanish', laws: { 86 | abort: false, 87 | gay_weddings: false, 88 | banned_youtube: false, 89 | banned_instagram: false 90 | } 91 | }, 92 | { 93 | country: 'Brazil', nationality: 'brazilian', language: 'portuguese', laws: { 94 | abort: false, 95 | gay_weddings: true, 96 | banned_youtube: false, 97 | banned_instagram: false 98 | } 99 | }, 100 | { 101 | country: 'Ecuador', nationality: 'ecuadorian', language: 'spanish', laws: { 102 | abort: false, 103 | gay_weddings: true, 104 | banned_youtube: false, 105 | banned_instagram: false 106 | } 107 | }, 108 | { 109 | country: 'Peru', nationality: 'peruvian', language: 'spanish', laws: { 110 | abort: false, 111 | gay_weddings: false, 112 | banned_youtube: false, 113 | banned_instagram: false 114 | } 115 | }, 116 | { 117 | country: 'Chile', nationality: 'chilean', language: 'spanish', laws: { 118 | abort: false, 119 | gay_weddings: true, 120 | banned_youtube: false, 121 | banned_instagram: false 122 | } 123 | }, 124 | { 125 | country: 'Bolivia', nationality: 'bolivian', language: 'spanish', laws: { 126 | abort: false, 127 | gay_weddings: false, 128 | banned_youtube: false, 129 | banned_instagram: false 130 | } 131 | }, 132 | { 133 | country: 'Paraguay', nationality: 'paraguayan', language: 'spanish', laws: { 134 | abort: false, 135 | gay_weddings: false, 136 | banned_youtube: false, 137 | banned_instagram: false 138 | } 139 | }, 140 | { 141 | country: 'Argentina', nationality: 'argentinean', language: 'spanish', laws: { 142 | abort: true, 143 | gay_weddings: true, 144 | banned_youtube: false, 145 | banned_instagram: false 146 | } 147 | }, 148 | { 149 | country: 'Uruguay', nationality: 'uruguayan', language: 'spanish', laws: { 150 | abort: true, 151 | gay_weddings: true, 152 | banned_youtube: false, 153 | banned_instagram: false 154 | } 155 | }, 156 | { 157 | country: 'Cuba', nationality: 'cuban', language: 'spanish', laws: { 158 | abort: true, 159 | gay_weddings: false, 160 | banned_youtube: false, 161 | banned_instagram: false 162 | } 163 | }, 164 | { 165 | country: 'Portugal', nationality: 'portuguese', language: 'portuguese', laws: { 166 | abort: true, 167 | gay_weddings: false, 168 | banned_youtube: false, 169 | banned_instagram: false 170 | } 171 | }, 172 | { 173 | country: 'Spain', nationality: 'spaniard', language: 'spanish', laws: { 174 | abort: true, 175 | gay_weddings: true, 176 | banned_youtube: false, 177 | banned_instagram: false 178 | } 179 | }, 180 | { 181 | country: 'France', nationality: 'french', language: 'french', laws: { 182 | abort: true, 183 | gay_weddings: true, 184 | banned_youtube: false, 185 | banned_instagram: false 186 | } 187 | }, 188 | { 189 | country: 'Germany', nationality: 'german', language: 'german', laws: { 190 | abort: true, 191 | gay_weddings: true, 192 | banned_youtube: false, 193 | banned_instagram: false 194 | } 195 | }, 196 | { 197 | country: 'Italy', nationality: 'italian', language: 'italian', laws: { 198 | abort: false, 199 | gay_weddings: false, 200 | banned_youtube: false, 201 | banned_instagram: false 202 | } 203 | }, 204 | { 205 | country: 'United Kingdom', nationality: 'british', language: 'english', laws: { 206 | abort: false, 207 | gay_weddings: true, 208 | banned_youtube: false, 209 | banned_instagram: false 210 | } 211 | }, 212 | { 213 | country: 'Ireland', nationality: 'irish', language: 'irish', laws: { 214 | abort: true, 215 | gay_weddings: true, 216 | banned_youtube: false, 217 | banned_instagram: false 218 | } 219 | }, 220 | { 221 | country: 'Ukraine', nationality: 'ukrainian', language: 'ukrainian', laws: { 222 | abort: true, 223 | gay_weddings: false, 224 | banned_youtube: false, 225 | banned_instagram: false 226 | } 227 | }, 228 | { 229 | country: 'Russia', nationality: 'russian', language: 'russian', laws: { 230 | abort: true, 231 | gay_weddings: false, 232 | banned_youtube: false, 233 | banned_instagram: false 234 | } 235 | }, 236 | { 237 | country: 'Sweeden', nationality: 'sweedish', language: 'sweedish', laws: { 238 | abort: true, 239 | gay_weddings: true, 240 | banned_youtube: false, 241 | banned_instagram: false 242 | } 243 | }, 244 | { 245 | country: 'Finland', nationality: 'finnish', language: 'finnish', laws: { 246 | abort: false, 247 | gay_weddings: true, 248 | banned_youtube: false, 249 | banned_instagram: false 250 | } 251 | }, 252 | { 253 | country: 'China', nationality: 'chinese', language: 'chinese', laws: { 254 | abort: true, 255 | gay_weddings: false, 256 | banned_youtube: true, 257 | banned_instagram: true 258 | } 259 | }, 260 | { 261 | country: 'Taiwan', nationality: 'taiwanese', language: 'chinese', laws: { 262 | abort: false, 263 | gay_weddings: true, 264 | banned_youtube: false, 265 | banned_instagram: false 266 | } 267 | }, 268 | { 269 | country: 'Japan', nationality: 'japanese', language: 'japanese', laws: { 270 | abort: false, 271 | gay_weddings: false, 272 | banned_youtube: false, 273 | banned_instagram: false 274 | } 275 | }, 276 | { 277 | country: 'South Korea', nationality: 'south korean', language: 'korean', laws: { 278 | abort: true, 279 | gay_weddings: false, 280 | banned_youtube: false, 281 | banned_instagram: false 282 | } 283 | }, 284 | { 285 | country: 'North Korea', nationality: 'north korean', language: 'korean', laws: { 286 | abort: false, 287 | gay_weddings: false, 288 | banned_youtube: true, 289 | banned_instagram: true 290 | } 291 | }, 292 | { 293 | country: 'India', nationality: 'indian', language: 'hindi', laws: { 294 | abort: false, 295 | gay_weddings: false, 296 | banned_youtube: false, 297 | banned_instagram: false 298 | } 299 | }, 300 | { 301 | country: 'Saudi Arabia', nationality: 'arab', language: 'arab', laws: { 302 | abort: false, 303 | gay_weddings: false, 304 | banned_youtube: false, 305 | banned_instagram: false 306 | } 307 | }, 308 | { 309 | country: 'Syria', nationality: 'syrian', language: 'arab', laws: { 310 | abort: false, 311 | gay_weddings: false, 312 | banned_youtube: false, 313 | banned_instagram: false 314 | } 315 | }, 316 | { 317 | country: 'Iraq', nationality: 'iraqi', language: 'arab', laws: { 318 | abort: false, 319 | gay_weddings: false, 320 | banned_youtube: false, 321 | banned_instagram: false 322 | } 323 | }, 324 | { 325 | country: 'Israel', nationality: 'israeli', language: 'hebrew', laws: { 326 | abort: false, 327 | gay_weddings: false, 328 | banned_youtube: false, 329 | banned_instagram: false 330 | } 331 | }, 332 | { 333 | country: 'Egypt', nationality: 'egyptian', language: 'arab', laws: { 334 | abort: false, 335 | gay_weddings: false, 336 | banned_youtube: false, 337 | banned_instagram: false 338 | } 339 | }, 340 | { 341 | country: 'Libya', nationality: 'libyan', language: 'arab', laws: { 342 | abort: false, 343 | gay_weddings: false, 344 | banned_youtube: false, 345 | banned_instagram: false 346 | } 347 | }, 348 | { 349 | country: 'Morocco', nationality: 'moroccan', language: 'arab', laws: { 350 | abort: false, 351 | gay_weddings: false, 352 | banned_youtube: false, 353 | banned_instagram: false 354 | } 355 | }, 356 | { 357 | country: 'Algeria', nationality: 'algerian', language: 'arab', laws: { 358 | abort: false, 359 | gay_weddings: false, 360 | banned_youtube: false, 361 | banned_instagram: false 362 | } 363 | }, 364 | { 365 | country: 'Turkey', nationality: 'turkish', language: 'turkish', laws: { 366 | abort: true, 367 | gay_weddings: false, 368 | banned_youtube: true, 369 | banned_instagram: false 370 | } 371 | }, 372 | { 373 | country: 'Armenia', nationality: 'armenian', language: 'armenian', laws: { 374 | abort: false, 375 | gay_weddings: false, 376 | banned_youtube: false, 377 | banned_instagram: false 378 | } 379 | }, 380 | { 381 | country: 'South Africa', nationality: 'south africam', language: 'english', laws: { 382 | abort: true, 383 | gay_weddings: true, 384 | banned_youtube: false, 385 | banned_instagram: false 386 | } 387 | }, 388 | { 389 | country: 'Australia', nationality: 'australian', language: 'english', laws: { 390 | abort: true, 391 | gay_weddings: true, 392 | banned_youtube: false, 393 | banned_instagram: false 394 | } 395 | } 396 | ]; 397 | 398 | const names = { 399 | spanish: { 400 | male: ['Abraham', 'Adolfo', 'Adrian', 'Alejandro', 'Alejandro', 'Alexander', 'Andres', 'Armando', 'Arturo', 'Benjamin', 'Carlos', 'Daniel', 'David', 'Edixon', 'Eduardo', 'Edward', 'Emanuel', 'Emiliano', 'Enmanuel', 'Ernesto', 'Felix', 'Francisco', 'Franco', 'Genaro', 'Geronimo', 'Humberto', 'Ignacio', 'Jesús', 'Josue', 'José', 'Julian', 'Lautaro', 'Lucas', 'Matias', 'Mauricio', 'Miguel', 'Omar', 'Pedro', 'Rigoberto', 'Roberto', 'Rodolfo', 'Rodrigo', 'Santiago', 'Saul', 'Thiago'], 401 | female: ['Juana', 'Sofia', 'Ariana', 'Victoria', 'Arianna', 'Daniela', 'Hilda', 'Carmen', 'Sara', 'Maria', 'Valentina', 'Aleina', 'Jimena', 'Valeria', 'Aura', 'Juliana', 'Alejandra', 'Francisca', 'Yazmina', 'Carolina', 'Julieta', 'Juliana'] 402 | }, 403 | english: { 404 | male: ['Thomas', 'Edward', 'Charles', 'Robert', 'Joseph', 'Daniel', 'Mathew', 'John', 'Benjamin', 'Humbert', 'Andrew', 'Adolf', 'Saul', 'James', 'Tyler'], 405 | female: ['Sophie', 'Victoria', 'Sara', 'Olivia', 'Amelia', 'Emily', 'Emma', 'Enid'] 406 | }, 407 | portuguese: { 408 | male: ['Joao', 'Alexander', 'Aleixo', 'Abrahao', 'Roberto', 'Jesus', 'Donato', 'Mateus', 'Marcelo'], 409 | female: ['Ana', 'Maria', 'Rosa', 'Isabel'] 410 | }, 411 | french: { 412 | male: ['Jean', 'Paul', 'Adrien', 'Oliver'], 413 | female: ['Paulette', 'Lucie', 'Nadine'] 414 | }, 415 | arab: { 416 | male: ['Abdul', 'Ibrahim', 'Osama', 'Abdel', 'Hassan'], 417 | female: ['Abir', 'Abla', 'Amira', 'Badra'] 418 | }, 419 | hebrew: { 420 | male: ['Aaron', 'Abner', 'Asaf'], 421 | female: ['Ada', 'Ana', 'Daniela', 'Ariel'] 422 | }, 423 | japanese: { 424 | male: ['Akira', 'Kuta', 'Hiroshi', 'Kousei', 'Tenma'], 425 | female: ['Aiko', 'Aoi', 'Hana', 'Akira', 'Tsubaki', 'Chihiro'] 426 | }, 427 | korean: { 428 | male: ['Kim', 'Yejun', 'SeoJoon', 'Jiho'], 429 | female: ['Suni', 'Yon', 'Mi-Suk'] 430 | }, 431 | turkish: { 432 | male: ['Adem', 'Acar', 'Kadir'], 433 | female: ['Adalet', 'Asya', 'Ayla', 'Damla'] 434 | }, 435 | hindi: { 436 | male: ['Brahma', 'Madhur', 'Ranjit', 'Apu'], 437 | female: ['Uma', 'Denali', 'Indira'] 438 | }, 439 | german: { 440 | male: ['Hans', 'Heinrich', 'Joseph', 'Adolf', 'Erich', 'Paul', 'Ernst', 'Gunter', 'Friedrich', 'Arthur', 'Otto', 'Johan', ''], 441 | female: ['Erika', 'Frida', 'Annelies', 'Matilde', 'Anna', 'Nina', 'Berta', 'Emilia'] 442 | }, 443 | italian: { 444 | male: ['Giuseppe', 'Luigi', 'Victor', 'Mario', 'Roberto', 'Benito', 'Giorno'], 445 | female: ['Emma', 'Beatrice', 'Sofia', 'Alice'] 446 | }, 447 | russian: { 448 | male: ['Vladimir', 'Aleksander', 'Ivan', 'Igor', 'Pyotr'], 449 | female: ['Natasha', 'Dasha', 'Irina', 'Tasya', 'Zaria', 'Karenina'] 450 | }, 451 | sweedish: { 452 | male: ['Acke', 'Aleksander'], 453 | female: ['Ottilia', 'Ellie', 'Aischa'] 454 | }, 455 | finnish: { 456 | male: ['Onni', 'Eetu', 'Elias', 'Aleksi'], 457 | female: ['Sofia', 'Lia', 'Lily'] 458 | }, 459 | irish: { 460 | male: ['Brian', 'Aidan'], 461 | female: ['Brianna', 'Adara'] 462 | }, 463 | armenian: { 464 | male: ['Davit', 'Narek', 'Tigran', 'Alex'], 465 | female: ['Maria', 'Yeva', 'Nare'] 466 | }, 467 | ukrainian: { 468 | male: ['Volodimir', 'Bohdan', 'Anton', 'Anatoliy', 'Borys', 'Gleb', 'Georgiy', 'Ivan'], 469 | female: ['Nataliya', 'Natalka', 'Oleksandra', 'Mariya'] 470 | }, 471 | chinese: { 472 | male: ['Bao', 'Da', 'Jin', 'Hong'], 473 | female: ['Xiang', 'Shui', 'Yun'] 474 | } 475 | } 476 | 477 | const surnames = { 478 | spanish: ['Gonzales', 'Gonzalez', 'Jimenez', 'Chavez', 'Andreone', 'Arevalo', 'Acosta', 'Rodriguez', 'Gomez', 'Oviedo', 'Hernandez', 'Paredes', 'Torres', 'Valenzuela', 'Nuñez', 'Muñoz', 'Andrade', 'Enrique', 'Coronado', 'Preciado', 'Pineda', 'Moreyra'], 479 | english: ['Johnson', 'Adamson', 'Jobs', 'Gates', 'Bush', 'Adams'], 480 | portuguese: ['Freitas', 'De Sousa', 'Aveiro', 'Silva'], 481 | french: ['Lamont', 'Martin', 'Bernard'], 482 | arab: ['Ahmad', 'Abadi', 'Ayad', 'Ramaiti'], 483 | hebrew: ['Friedman', 'Bernstein', 'Lewin'], 484 | japanese: ['Tanaka', 'Sato', 'Yamamoto'], 485 | korean: ['Kim', 'Lee', 'Choi'], 486 | turkish: ['Kaya', 'Aydin', 'Demir'], 487 | hindi: ['Kumar', 'Devi', 'Singh', 'Ram'], 488 | german: ['Schmid', 'Schneider', 'Ehrmantraut', 'Weber'], 489 | italian: ['Vecchio', 'Giordano', 'Giovanna'], 490 | russian: ['Gorbachov', 'Ivanovich', 'Petrikov', 'Ivanov', 'Ivanova', 'Petrov', 'Petrova', 'Magomedov', 'Kuznetsov'], 491 | sweedish: ['Johansson', 'Andersson', 'Karlsson'], 492 | finnish: ['Koskinen', 'Heikkinen', 'Korhonen'], 493 | irish: ['Murphy', 'McCarthy', 'Doyle'], 494 | armenian: ['Grigoryan', 'Sargsyan', 'Harutyunyan'], 495 | ukrainian: ['Bondarenko', 'Kovalenko', 'Boiko', 'Tkachenko', 'Kravchenko', 'Kovalchuk'], 496 | } 497 | 498 | const popularYoutubers = [ 499 | { user: 'Sr Bestia', subscribers: 190000000 }, 500 | { user: 'Piudipai', subscribers: 111000000 }, 501 | { user: 'ORichMC', subscribers: 10000000 }, 502 | { user: 'BBE', subscribers: 92000000 }, 503 | { user: 'Piernafloo', subscribers: 52000000 }, 504 | { user: 'PlayGeorge', subscribers: 90000000 }, 505 | { user: 'Rincon de Jose', subscribers: 46000000 }, 506 | { user: 'Fast', subscribers: 58200000 } 507 | ] -------------------------------------------------------------------------------- /js/menu.js: -------------------------------------------------------------------------------- 1 | const weaponOptions = itemListifier(items, 'weapons', 'items'); 2 | const instrumentOptions = itemListifier(items, 'instruments', 'items'); 3 | const electronicOptions = itemListifier(items, 'electronics', 'items'); 4 | const housesOptions = itemListifier(assets, 'houses', 'assets'); 5 | const carsOptions = itemListifier(assets, 'cars', 'assets'); 6 | 7 | 8 | const menu = { 9 | activities() { 10 | if (player.prison.jailed) return; 11 | 12 | menuTemplate.style.display = 'block'; 13 | menuTitle.innerText = 'Activities' 14 | menuBody.innerHTML = ` 15 | 51 | ` 52 | }, 53 | criminal() { 54 | if (player.age < 14) return 55 | 56 | menuTemplate.style.display = 'block' 57 | menuTitle.innerText = 'Criminal' 58 | menuBody.innerHTML = ` 59 | 70 | ` 71 | }, 72 | freetime() { 73 | menuTemplate.style.display = 'block'; 74 | menuTitle.innerText = 'Free time' 75 | menuBody.innerHTML = ` 76 | 145 | ` 146 | }, 147 | cars() { 148 | if (player.age < 18) return; 149 | 150 | menuTemplate.style.display = 'block'; 151 | menuTitle.innerText = 'Cars'; 152 | menuBody.innerHTML = ` 153 |
    154 |
    155 |
    156 | Owned 157 |
    158 |
    159 | Market 160 |
    161 |
    162 |
    163 | ${carsOptions} 164 |
    165 |
    ` 166 | }, 167 | realEstate() { 168 | if (player.age < 16) return; 169 | 170 | menuTemplate.style.display = 'block'; 171 | menuTitle.innerText = 'Real Estate'; 172 | menuBody.innerHTML = ` 173 |
    174 |
    175 |
    176 | Owned 177 |
    178 |
    179 | Market 180 |
    181 |
    182 |
    183 | ${housesOptions} 184 |
    185 |
    ` 186 | }, 187 | assetsHandler(data) { 188 | const ids = { 189 | ownedTab: 'marketTab', 190 | marketTab: 'ownedTab' 191 | } 192 | const thisId = data.id; 193 | const cellContainer = document.getElementById('cell-container') 194 | const type = data.getAttribute('data-type') 195 | 196 | if (!data.classList.value.includes('active')) { 197 | document.getElementById(ids[thisId]).classList.remove('active'); 198 | data.classList.add('active') 199 | if (thisId === 'marketTab') { 200 | if (type === 'houses') 201 | cellContainer.innerHTML = housesOptions 202 | else 203 | cellContainer.innerHTML = carsOptions 204 | } 205 | else cellContainer.innerHTML = ownedAssets(type) 206 | } 207 | }, 208 | shopping() { 209 | if (player.age < 14) return 210 | 211 | menuTemplate.style.display = 'block'; 212 | menuTitle.innerText = 'Shopping' 213 | menuBody.innerHTML = ` 214 | 220 | ` 221 | }, 222 | foodAndDrinks: { 223 | display() { 224 | menuTitle.innerText = 'Food and drinks' 225 | menuBody.innerHTML = ` 226 | 230 | ` 231 | }, 232 | food: { 233 | display() { 234 | menuTitle.innerText = 'Food' 235 | menuBody.innerHTML = ` 236 | 241 | ` 242 | }, 243 | fastFood() { 244 | menuTitle.innerText = 'Fast food' 245 | menuBody.innerHTML = ` 246 | 249 | ` 250 | }, 251 | dessert() { 252 | menuTitle.innerText = 'Fast food' 253 | menuBody.innerHTML = ` 254 | 257 | ` 258 | }, 259 | vegetables() { 260 | menuTitle.innerText = 'Fast food' 261 | menuBody.innerHTML = ` 262 | 265 | ` 266 | } 267 | 268 | }, 269 | drinks: { 270 | display() { 271 | menuTitle.innerText = 'Drinks' 272 | menuBody.innerHTML = ` 273 | 277 | ` 278 | }, 279 | alcoholic() { 280 | menuTitle.innerText = 'Alcoholic' 281 | menuBody.innerHTML = ` 282 | 285 | ` 286 | }, 287 | nonAlcoholic() { 288 | menuTitle.innerText = 'Non alcoholic' 289 | menuBody.innerHTML = ` 290 | 293 | ` 294 | } 295 | } 296 | }, 297 | emigrate() { 298 | if (player.age < 18) return 299 | menuTemplate.style.display = 'block'; 300 | menuTitle.innerText = 'Emigrate' 301 | menuBody.innerHTML = ` 302 |
    303 | 306 |
    307 | 311 | 312 | ` 313 | }, 314 | job() { 315 | if (player.prison.jailed) return; 316 | 317 | let string = ''; 318 | let index = 0; 319 | for (let job of jobs) { 320 | if (job.label !== player.job.label) 321 | string = string.concat(`
    ${job.label}
    `) 322 | index++; 323 | } 324 | 325 | menuTemplate.style.display = 'block' 326 | menuTitle.innerText = 'Jobs' 327 | menuBody.innerHTML = ` 328 |
    329 |
    330 | ${string} 331 |
    332 |
    333 | ${player.job !== 'none' ? ` 334 |
    ${player.job.label}
    335 | ` : ''} 336 |
    337 |
    338 | ` 339 | }, 340 | weapons() { 341 | menuTemplate.style.display = 'block'; 342 | menuTitle.innerText = 'Weapons' 343 | menuBody.innerHTML = ` 344 | 347 | ` 348 | }, 349 | instruments() { 350 | menuTemplate.style.display = 'block'; 351 | menuTitle.innerText = 'Instruments' 352 | menuBody.innerHTML = ` 353 | 356 | ` 357 | }, 358 | electronics() { 359 | menuTemplate.style.display = 'block'; 360 | menuTitle.innerText = 'Electronics' 361 | menuBody.innerHTML = ` 362 | 365 | ` 366 | }, 367 | profile() { 368 | menuTemplate.style.display = 'block'; 369 | menuTitle.innerText = 'Profile' 370 | menuBody.innerHTML = ` 371 | 397 | ` 398 | }, 399 | relationships() { 400 | menuTemplate.style.display = 'block' 401 | menuTitle.innerText = 'Relationships' 402 | menuBody.innerHTML = ` 403 | ${relationShipListifier('parents')} 404 | ${relationShipListifier('siblings')} 405 | ${relationShipListifier('friends')} 406 | ${relationShipListifier('partner')} 407 | ${player.relationships.exPartners != null ? relationShipListifier('exPartners') : ''} 408 | ${relationShipListifier('offspring')} 409 | ` 410 | windows.handleRelationBars() 411 | }, 412 | inventory() { 413 | menuTitle.innerText = 'Inventory' 414 | 415 | let inventoryArr = []; 416 | for (let object of Object.entries(player.inventory)) { 417 | if (object[1].length !== 0 && object[0] !== 'cars' && object[0] !== 'houses') 418 | inventoryArr.push(...object[1]) 419 | } 420 | let string = ''; 421 | if (inventoryArr.length !== 0) for (let item of inventoryArr) { 422 | string = string.concat(` 423 |
  • 425 | 426 |
    ${item.label}
    427 |
  • 428 | `) 429 | } 430 | 431 | if (string !== '') 432 | menuBody.innerHTML = ``; 433 | else menuBody.innerHTML = ` 434 |
    435 |

    No items owned yet

    436 |
    437 | ` 438 | 439 | menuTemplate.style.display = 'block'; 440 | }, 441 | } 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | const windows = { 450 | suicide: { 451 | display() { 452 | if (player.age < 5) return 453 | 454 | showEvent({ 455 | title: 'Suicide', 456 | body: ` 457 |

    Are you sure you want to do this

    458 |
    Yes
    459 |
    No
    460 | ` 461 | }) 462 | }, 463 | confirmation() { 464 | closeEvent() 465 | death(player, 'commited suicide') 466 | menuTemplate.style.display = 'none' 467 | } 468 | }, 469 | criminal: { 470 | stealCar: { 471 | display() { 472 | const cars = assets.cars 473 | const random = Math.floor(Math.random() * cars.length) 474 | const car = cars[random] 475 | 476 | showEvent({ 477 | title: 'Steal car', 478 | body: ` 479 |

    You found a ${car.label}, would you steal it?

    480 |
    Yes
    481 |
    No
    482 | ` 483 | }) 484 | }, 485 | steal(carName) { 486 | let car 487 | const cars = assets.cars 488 | for (let i = 0; i < assets.cars.length; i++) { 489 | if (carName === cars[i].label) { 490 | car = structuredClone(cars[i]) 491 | car.stolen = true 492 | break 493 | } 494 | } 495 | const random = Math.floor(Math.random() * 100) 496 | menuTemplate.style.display = 'none' 497 | if (random >= 30) { 498 | car.inventoryIndex = player.inventory.cars.length 499 | player.inventory.cars.push(car) 500 | eventBody.innerHTML = ` 501 |

    You stole this car succesfully

    502 |
    Close
    503 | ` 504 | textContainer.innerHTML += `

    I stole a ${carName.toLowerCase()}

    ` 505 | } else { 506 | eventBody.innerHTML = ` 507 |

    You got arrested

    508 |
    Close
    509 | ` 510 | arrestByStealingCar(player) 511 | textContainer.innerHTML += `

    I tried to steal a ${carName.toLowerCase()}

    ` 512 | textContainer.innerHTML += `

    I got arrested for ${player.prison.sentenceTime} years

    ` 513 | } 514 | }, 515 | }, 516 | murder: { 517 | display() { 518 | const events = [{ 519 | message: 'A beggar asked for your charity', 520 | target: 'beggar', 521 | gender: 'male' 522 | }, { 523 | message: 'A prostitute offers you her services', 524 | target: 'prostitute', 525 | gender: 'female' 526 | }] 527 | const random = Math.floor(Math.random() * events.length) 528 | const pronoun = events[random].gender === "male" ? 'him' : 'her' 529 | const victim = events[random].target 530 | 531 | showEvent({ 532 | title: 'Murder', 533 | body: ` 534 |

    ${events[random].message}

    535 |

    Murder method:

    536 | 540 | ` 541 | }) 542 | 543 | const methodSelector = document.getElementById('method-selector') 544 | let method = methodSelector.value 545 | methodSelector.onselect = (e => { 546 | method = e.target.value 547 | }) 548 | eventBody.innerHTML += ` 549 |
    kill
    550 |
    Close
    551 | ` 552 | }, 553 | kill(victim) { 554 | const random = Math.floor(Math.random() * 100) 555 | menuTemplate.style.display = 'none' 556 | 557 | if (random > 30) { 558 | player.criminalRecord.murder++ 559 | textContainer.innerHTML += ` 560 |

    I killed a ${victim}

    561 | ` 562 | const probabilityOfArrest = Math.floor(Math.random() * 100) 563 | if (probabilityOfArrest > 60) { 564 | eventBody.innerHTML = ` 565 |

    You got caught by the police, you are arrested

    566 |
    Close
    567 | ` 568 | arrestByMurder(player) 569 | textContainer.innerHTML += ` 570 |

    The police caught me

    571 |

    I have been arrested for ${player.prison.sentenceTime} years

    572 | ` 573 | } else { 574 | eventBody.innerHTML = ` 575 |

    You killed the ${victim} succesfully

    576 |
    Close
    577 | ` 578 | } 579 | 580 | } else { 581 | player.criminalRecord.murderAttempts++ 582 | arrestByMurder(player) 583 | eventBody.innerHTML = ` 584 |

    Your murder attempt failed, you got denounced

    585 |
    Close
    586 | ` 587 | textContainer.innerHTML += ` 588 |

    My murder attempt failed

    589 |

    I got denounced

    590 |

    I have been arrested for ${player.prison.sentenceTime} years

    591 | ` 592 | } 593 | }, 594 | }, 595 | robbery() { 596 | showEvent({ 597 | title: 'Robbery', 598 | body: ` 599 |
    Close
    600 | ` 601 | }) 602 | }, 603 | }, 604 | plasticSurgeries: { 605 | display() { 606 | if (player.age < 17) return 607 | 608 | showEvent({ 609 | title: 'Plastic surgeries', 610 | body: ` 611 |

    Fix your insecurities today

    612 |
    613 | Nose job 614 |
    615 |
    616 | Face lift 617 |
    618 |
    619 | Lip Augmentation 620 |
    621 | ${player.gender === 'male' ? `` : ` 622 |
    623 | Breast augmentation 624 |
    625 | `} 626 |
    627 | Eyelid Lift 628 |
    629 |
    630 | Hair transplantation 631 |
    632 |
    Do nothing
    633 | ` 634 | }) 635 | }, 636 | beautyBuff(price, operation) { 637 | if (player.money.total < price) 638 | return eventBody.innerHTML = ` 639 |

    You cant afford this

    640 |
    Close
    641 | ` 642 | const buff = 12 + Math.floor(Math.random() * 12) 643 | player.stats.appearance += buff 644 | statsLimit(player) 645 | eventBody.innerHTML = ` 646 |

    +${buff} appearance

    647 |
    Close
    648 | ` 649 | menuTemplate.style.display = 'none' 650 | textContainer.innerHTML += ` 651 |

    I paid for a ${operation}

    652 | ` 653 | handleStatBars(player, true) 654 | }, 655 | options(price, operation) { 656 | return ` 657 |

    Price: ${moneyFormat(price)} $

    658 |
    Pay
    659 |
    Close
    660 | ` 661 | }, 662 | noseJob(price) { 663 | const options = this.options(price, 'nose job') 664 | eventTitle.innerText = 'Nose job' 665 | eventBody.innerHTML = options 666 | }, 667 | faceLift(price) { 668 | const options = this.options(price, 'face lift') 669 | eventTitle.innerText = 'Face lift' 670 | eventBody.innerHTML = options 671 | }, 672 | lipAugmentation(price) { 673 | const options = this.options(price, 'lip augmentation') 674 | eventTitle.innerText = 'Lip augmentation' 675 | eventBody.innerHTML = options 676 | }, 677 | breastAugmentation(price) { 678 | const options = this.options(price, 'breast augmentation') 679 | eventTitle.innerText = 'Breast augmentation' 680 | eventBody.innerHTML = options 681 | }, 682 | eyelidLift(price) { 683 | const options = this.options(price, 'eyelid lift') 684 | eventTitle.innerText = 'Eyelid lift' 685 | eventBody.innerHTML = options 686 | }, 687 | hairTransplantation(price) { 688 | const options = this.options(price, 'hair transplantation') 689 | eventTitle.innerText = 'Hair transplantation' 690 | eventBody.innerHTML = options 691 | } 692 | }, 693 | playerData: { 694 | moneyDashboard() { 695 | showEvent({ 696 | title: 'Money', 697 | body: ` 698 |

    Total money: ${moneyFormat(player.money.total)} $

    699 |

    Income: ${moneyFormat(player.money.income)} $

    700 |

    Expenses: ${moneyFormat(player.money.expenses)} $

    701 |

    Balance: ${moneyFormat(player.money.income - player.money.expenses)} $

    702 |
    Close
    703 | ` 704 | }) 705 | }, 706 | identity() { 707 | showEvent({ 708 | title: 'Identity', 709 | body: ` 710 |

    Full name: ${player.fullName}

    711 |

    Gender: ${player.gender}

    712 |

    Age: ${player.age}

    713 |

    Nationality: ${player.nationality}

    714 |

    Location: ${player.location}

    715 |

    Sexuality: ${player.sexuality}

    716 |
    Close
    717 | ` 718 | }) 719 | }, 720 | education() { 721 | showEvent({ 722 | title: 'Education', 723 | body: ` 724 |

    Education:

    725 |

    ${careerPreviewer().education}

    726 |

    Degrees:

    727 | 730 |
    Close
    731 | ` 732 | }) 733 | }, 734 | skills() { 735 | showEvent({ 736 | title: 'Skills', 737 | body: ` 738 | ${skillListifier(player)} 739 |
    Close
    740 | ` 741 | }) 742 | }, cv() { 743 | showEvent({ 744 | title: 'Curriculum Vitae', 745 | body: ` 746 |

    Jobs

    747 | ${cvListifier(player)} 748 |
    Close
    749 | ` 750 | }) 751 | }, 752 | criminalRecord() { 753 | const { yearsInPrison, murderAttempts, murder, prisonEscapes } = player.criminalRecord 754 | 755 | showEvent({ 756 | title: 'Criminal Record', 757 | body: ` 758 |

    Years arrested: ${yearsInPrison === 0 ? 'none' : yearsInPrison + ' years'}

    759 |

    Murder attempts: ${murderAttempts === 0 ? 'none' : murderAttempts}

    760 |

    Murder: ${murder === 0 ? 'none' : murder}

    761 |

    Prison escapes: ${prisonEscapes === 0 ? 'none' : prisonEscapes}

    762 |
    Close
    763 | ` 764 | }) 765 | }, 766 | }, 767 | items: { 768 | buyWindow(e) { 769 | // objname could be items of assets (car or real estate) 770 | const objName = e.getAttribute('data-objname'); 771 | const property = e.getAttribute('data-property'); 772 | const index = e.getAttribute('data-index'); 773 | 774 | if (property === 'cars') { 775 | return windows.driverLicense.display() 776 | } 777 | 778 | let obj; 779 | 780 | if (objName === 'items') obj = items[property][index] 781 | else obj = assets[property][index]; 782 | 783 | showEvent({ 784 | title: `Buy ${obj.label}`, 785 | body: ` 786 |

    Price: ${moneyFormat(obj.price)} $

    787 |
    Buy it
    788 |
    Cancel
    789 | ` 790 | }) 791 | }, 792 | sell(data) { 793 | const index = data.getAttribute('data-item').split('-')[1] 794 | const type = data.getAttribute('data-item').split('-')[0] 795 | const item = player.inventory[type][index]; 796 | const price = item.price; 797 | 798 | eventBody.innerHTML = ` 799 |

    Are you sure you want to sell this?

    800 |

    Price: ${moneyFormat(price)} $

    801 |
    Sell
    802 |
    No
    803 | ` 804 | 805 | }, confirmSell(data) { 806 | const price = data.getAttribute('data-price'); 807 | let index = data.getAttribute('data-index'); 808 | const type = data.getAttribute('data-type') 809 | closeEvent() 810 | menuTemplate.style.display = 'none' 811 | textContainer.innerHTML += `

    I sold an item for ${moneyFormat(price)}$

    ` 812 | 813 | player.inventory[type].splice(parseInt(index), 1) 814 | 815 | let i = 0 816 | for (let item of player.inventory[type]) { 817 | item.inventoryIndex = i; 818 | i++ 819 | } 820 | 821 | player.money.total += parseInt(price) 822 | moneyViewer() 823 | }, 824 | useItem(data) { 825 | const type = data.getAttribute('data-type') 826 | const index = data.getAttribute('data-index') 827 | const object = player.inventory[type][index] 828 | 829 | if (type === 'weapons') { 830 | showEvent({ 831 | title: object.label, 832 | body: ` 833 | 839 | ` 840 | }) 841 | } else if (type === 'instruments') { 842 | showEvent({ 843 | title: object.label, 844 | body: ` 845 | ${player.actions.music < 3 ? ` 846 |
    Play
    847 | ` : ''} 848 |
    Sell
    849 |
    Close
    850 | ` 851 | }) 852 | } else if (['fastFood', 'desserts', 'vegetables'].includes(type)) { 853 | showEvent({ 854 | title: object.label, 855 | body: ` 856 |
    Eat
    857 |
    Sell
    858 |
    Close
    859 | ` 860 | }) 861 | } else if (['alcoholic', 'nonAlcoholic'].includes(type)) { 862 | showEvent({ 863 | title: object.label, 864 | body: ` 865 |
    Drink
    866 |
    Sell
    867 |
    Close
    868 | ` 869 | }) 870 | } 871 | 872 | if (object.label === 'Laptop' || object.label === 'PC') { 873 | showEvent({ 874 | title: object.label, 875 | body: ` 876 | ${player.actions.programming < 3 ? ` 877 |
    Practice programming
    878 | ` : ''} 879 | ${player.actions.writing < 3 ? ` 880 |
    Practice writing
    881 | ` : ''} 882 |
    Play videogames
    883 |
    Sell
    884 |
    Do nothing
    885 | ` 886 | }) 887 | } 888 | else if (object.label === 'Smartphone') { 889 | showEvent({ 890 | title: object.label, 891 | body: ` 892 |
    Social Media
    893 |
    Watch video
    894 |
    Sell
    895 |
    Close
    896 | ` 897 | }) 898 | } 899 | }, 900 | buy(objName, property, index) { 901 | let obj; 902 | if (objName === 'items') obj = items[property][index] 903 | else obj = assets[property][index]; 904 | 905 | if (property === 'houses') obj.location = player.location 906 | let newObj = structuredClone(obj); 907 | 908 | if (player.money.total >= newObj.price) { 909 | player.money.total -= newObj.price; 910 | try { 911 | newObj.inventoryIndex = player.inventory[property].length; 912 | } catch (err) { 913 | newObj.inventoryIndex = 0 914 | player.inventory[property] = [] 915 | } 916 | 917 | player.inventory[property].push(newObj); 918 | textContainer.innerHTML += `

    I bought a ${newObj.label}

    `; 919 | closeEvent() 920 | document.getElementById(`${property}-${index}`).remove() 921 | moneyViewer() 922 | 923 | } else { 924 | eventTitle.innerText = 'Cant afford this' 925 | eventBody.innerHTML = `
    ...
    `; 926 | } 927 | }, 928 | consume(data, kind) { 929 | const type = data.getAttribute('data-item').split('-')[0] 930 | const index = data.getAttribute('data-item').split('-')[1] 931 | const item = player.inventory[type][index] 932 | const statChanges = item.statChanges 933 | for (let stat of Object.entries(statChanges)) { 934 | player.stats[stat[0]] += stat[1] 935 | statsLimit(player) 936 | } 937 | handleStatBars(player, true) 938 | eventBody.innerHTML = ` 939 |

    You ${kind === 'food' ? 'ate' : 'drank'} a ${item.label.toLowerCase()}

    940 |
    Close
    941 | ` 942 | player.inventory[type].splice(index, 1) 943 | menu.inventory() 944 | }, 945 | playInstrument(data) { 946 | player.actions.music++ 947 | player.skills.music.xp += 25; 948 | 949 | eventBody.innerHTML = ` 950 |

    +25 music skill earned!

    951 |
    Close
    952 | ` 953 | skillLeveler() 954 | }, 955 | weapon: { 956 | selectVictim(data) { 957 | let weaponIndex = data.getAttribute('data-weapon') 958 | 959 | let options = '' 960 | //one because player is 0, this may cause problems later if I decide to implement generations 961 | let index = 1; 962 | 963 | for (let person of characters) { 964 | if (person.fullName !== player.fullName && person.alive) { 965 | person.index = index 966 | options = options.concat(` 967 |
    ${person.fullName}
    968 | `) 969 | index++; 970 | } 971 | } 972 | 973 | options = options.concat(`
    Random beggar
    `) 974 | 975 | eventBody.innerHTML = ` 976 | ${options} 977 |
    Not a good idea
    978 | ` 979 | }, 980 | kill(data) { 981 | const victimIndex = data.getAttribute('data-person') 982 | const victim = characters[victimIndex] 983 | const weaponIndex = data.getAttribute('data-weapon') 984 | const weapon = player.inventory.weapons[weaponIndex] 985 | const efficiency = weapon.successChance; 986 | const randomNum = Math.floor(Math.random() * 100); 987 | 988 | if (randomNum < efficiency) { 989 | let name; 990 | if (victim != undefined) { 991 | victim.alive = false 992 | name = victim.fullName 993 | player.criminalRecord.murder++; 994 | } else name = 'someone' 995 | eventBody.innerHTML = ` 996 |

    Success

    997 |

    You have commited murder succesfully

    998 |
    Okay
    999 | ` 1000 | textContainer.innerHTML += ` 1001 |

    I killed ${name}

    1002 | ` 1003 | } else { 1004 | eventBody.innerHTML = ` 1005 |

    Oh no!

    1006 |

    Your assasination attemp failed! you got arrested

    1007 |
    ...
    1008 | ` 1009 | menuTemplate.style.display = 'none'; 1010 | 1011 | player.criminalRecord.murderAttempts++; 1012 | arrestByMurder(player) 1013 | 1014 | textContainer.innerHTML += ` 1015 |

    My assasination attempt failed, I got denounced

    1016 |

    I have been arrested for ${player.prison.sentenceTime} years 1017 |

    1018 | ` 1019 | 1020 | } 1021 | }, 1022 | }, 1023 | computer: { 1024 | practiceWriting() { 1025 | player.actions.writing++ 1026 | player.skills.writing.xp += 25; 1027 | eventBody.innerHTML = ` 1028 |

    +25 writing skill earned!

    1029 |
    Close
    1030 | ` 1031 | textContainer.innerHTML += ` 1032 |

    I practiced writing

    1033 | ` 1034 | skillLeveler() 1035 | }, 1036 | practiceProgramming() { 1037 | player.actions.programming++ 1038 | player.skills.programming.xp += 25; 1039 | eventBody.innerHTML = ` 1040 |

    +25 programming skill earned!

    1041 |
    Close
    1042 | ` 1043 | textContainer.innerHTML += ` 1044 |

    I practiced programming

    1045 | ` 1046 | skillLeveler() 1047 | }, 1048 | playVideogames() { 1049 | const videogames = ['Among sus', 'Minekampf', 'Call of Honor', 'The Binding of Ray', 'Hollow Warrior', 'Raymonds Mod', 'Hearts of Steel IV', 'Asia Universallis IV', 'Fall-in: New Ohio'] 1050 | player.stats.happiness += 5; 1051 | 1052 | const gamePlayed = videogames[Math.floor(Math.random() * videogames.length)] 1053 | 1054 | eventBody.innerHTML = ` 1055 |

    You played ${gamePlayed}

    1056 |

    +5 happiness

    1057 |
    Close
    1058 | ` 1059 | textContainer.innerHTML += `

    I played ${gamePlayed}

    ` 1060 | } 1061 | }, 1062 | smartphone: { 1063 | watchVideo() { 1064 | const location = countryQuery(player.location) 1065 | if (location.laws.banned_youtube) { 1066 | return eventBody.innerHTML = ` 1067 |

    Youtube is not available in your country

    1068 |
    Close
    1069 | ` 1070 | } 1071 | 1072 | 1073 | const randomIndex = Math.floor(Math.random() * popularYoutubers.length) 1074 | const randomUser = popularYoutubers[randomIndex].user 1075 | closeEvent() 1076 | menuTemplate.style.display = 'none' 1077 | textContainer.innerHTML += ` 1078 |

    I watched a video of ${randomUser}

    1079 | ` 1080 | player.stats.happiness += Math.round(Math.random() * 10) 1081 | handleStatBars(player, true) 1082 | }, 1083 | }, 1084 | ownedAssetWindow(data) { 1085 | const type = data.getAttribute('data-type') 1086 | const index = data.getAttribute('data-index'); 1087 | const asset = player.inventory[type][index] 1088 | const canThrowParty = asset.location === player.location ? true : false 1089 | 1090 | modalBackground.style.display = 'flex' 1091 | eventTitle.innerText = asset.label 1092 | if (type === 'houses') 1093 | eventBody.innerHTML = ` 1094 |

    Age: ${asset.age}

    1095 |

    Value: ${moneyFormat(asset.price)} $

    1096 |

    Condition: ${asset.condition}

    1097 |

    Location: ${asset.location}

    1098 |
    1099 | 1100 | ${canThrowParty ? ` 1101 |
    Throw a party
    1102 | ` : ''} 1103 |
    Sell
    1104 |
    Close
    1105 | ` 1106 | else eventBody.innerHTML = ` 1107 |

    Value: ${moneyFormat(asset.price)}

    1108 | ${player.driverLicense ? ` 1109 |
    Drive
    1110 | ` : ''} 1111 |
    Sell
    1112 |
    Close
    1113 | ` 1114 | }, 1115 | }, 1116 | socialMedia: { 1117 | createAccount(socialMedia) { 1118 | const username = document.getElementById('username-field').value.trim() 1119 | player.socialMedia[socialMedia].created = true; 1120 | player.socialMedia[socialMedia].username = username; 1121 | player.socialMedia[socialMedia].created_at = year 1122 | 1123 | textContainer.innerHTML += ` 1124 |

    I created a ${socialMedia} account called ${username}

    1125 | ` 1126 | closeEvent() 1127 | menuTemplate.style.display = 'none' 1128 | }, 1129 | display() { 1130 | const laws = countryQuery(player.location).laws 1131 | 1132 | eventTitle.innerText = 'Social media' 1133 | eventBody.innerHTML = ` 1134 |
    Youtube
    1135 |
    Instagram
    1136 |
    Close
    1137 | ` 1138 | }, 1139 | youtube: { 1140 | display() { 1141 | if (!player.socialMedia.youtube.created) { 1142 | return eventBody.innerHTML = ` 1143 |

    You dont have an account yet

    1144 | 1145 |
    Create account
    1146 |
    Close
    1147 | ` 1148 | } 1149 | const stats = player.socialMedia.youtube 1150 | eventBody.innerHTML = ` 1151 |

    Username: ${stats.username}

    1152 |

    Subscribers: ${stats.subscribers}

    1153 |

    Creation year: ${stats.created_at}

    1154 |
    Record a video
    1155 |
    Browse my videos
    1156 |
    Ranking
    1157 |
    Close
    1158 | ` 1159 | }, 1160 | recordVideo: { 1161 | display() { 1162 | modalBackground.style.display = 'flex' 1163 | eventBody.innerHTML = ` 1164 |

    Thematic:

    1165 | 1171 |

    Title:

    1172 | 1173 |
    Select
    1174 |
    Cancel
    1175 | ` 1176 | 1177 | }, 1178 | record() { 1179 | const title = document.getElementById('title-field').value.trim() 1180 | const thematic = document.getElementById('thematic-selector').value 1181 | 1182 | if (title === '') return windows.socialMedia.youtube.recordVideo.display(); 1183 | const subscribers = player.socialMedia.youtube.subscribers 1184 | const views = Math.floor(Math.random() * (subscribers / 5) + 5 + subscribers) 1185 | const likes = Math.floor(Math.random() * (views / 5)) 1186 | const newSubs = Math.floor(views / 4) 1187 | 1188 | player.socialMedia.youtube.subscribers += newSubs 1189 | player.socialMedia.youtube.videos.push({ 1190 | title, 1191 | thematic, 1192 | views, 1193 | likes, 1194 | id: player.socialMedia.youtube.videos.length 1195 | }) 1196 | eventBody.innerHTML = ` 1197 |

    Video uploaded

    1198 |

    Views: ${views}

    1199 |

    Likes: ${likes}

    1200 |

    New subscribers: ${newSubs}

    1201 |
    Close
    1202 | ` 1203 | 1204 | } 1205 | }, 1206 | browseVideos() { 1207 | const videos = player.socialMedia.youtube.videos; 1208 | let list = '' 1209 | if (videos.length !== 0) 1210 | for (let video of videos) { 1211 | list = list.concat(` 1212 |
    1213 |

    ${video.title}

    1214 |

    ID: ${video.id}

    1215 |

    Thematic: ${video.thematic}

    1216 |

    Views: ${video.views}

    1217 |

    Likes: ${video.likes}

    1218 |
    1219 | `) 1220 | } 1221 | else list = '

    No videos yet

    ' 1222 | 1223 | eventBody.innerHTML = ` 1224 | ${list} 1225 |
    Close
    1226 | ` 1227 | }, 1228 | ranking() { 1229 | 1230 | }, 1231 | 1232 | }, 1233 | instagram: { 1234 | display() { 1235 | const isBanned = countryQuery(player.location).laws.banned_instagram 1236 | 1237 | if (isBanned) 1238 | return eventBody.innerHTML = ` 1239 |

    Youtube is banned in your country

    1240 |
    Close
    1241 | ` 1242 | if (!player.socialMedia.instagram.created) { 1243 | return eventBody.innerHTML = ` 1244 |

    You dont have an account yet

    1245 | 1246 |
    Create account
    1247 |
    Close
    1248 | ` 1249 | } 1250 | 1251 | const stats = player.socialMedia.instagram 1252 | eventBody.innerHTML = ` 1253 |

    Username: ${stats.username}

    1254 |

    Followers: ${stats.followers}

    1255 |

    Creation year: ${stats.created_at}

    1256 |
    Post a photo
    1257 |
    Browse posts
    1258 |
    Ranking
    1259 |
    Close
    1260 | ` 1261 | }, 1262 | photo: { 1263 | display() { 1264 | eventBody.innerHTML = ` 1265 |

    Title

    1266 | 1267 |
    Upload
    1268 |
    Close
    1269 | ` 1270 | }, 1271 | upload() { 1272 | const description = document.getElementById('description-field').value.trim() 1273 | 1274 | const followers = player.socialMedia.instagram.followers 1275 | const newFollowers = Math.round(Math.random() * 3 / followers != 0 ? followers : 2) + player.stats.appearance 1276 | const likes = Math.round(Math.random() * (followers * (player.stats.appearance / 100))) 1277 | 1278 | player.socialMedia.instagram.posts.push({ 1279 | description, 1280 | likes, 1281 | id: player.socialMedia.instagram.posts.length 1282 | }) 1283 | player.socialMedia.instagram.followers += newFollowers 1284 | windows.socialMedia.instagram.display() 1285 | } 1286 | }, 1287 | browsePosts() { 1288 | let str = '' 1289 | const posts = player.socialMedia.instagram.posts 1290 | posts.map(post => str = str.concat(` 1291 |

    ${post.description}

    1292 |

    ID: ${post.id}

    1293 |

    ${post.likes} likes

    1294 | `)) 1295 | if (str === '') str = '

    No posts yet

    ' 1296 | 1297 | eventBody.innerHTML = ` 1298 | ${str} 1299 |
    Close
    1300 | ` 1301 | } 1302 | } 1303 | }, 1304 | relations: { 1305 | display(target) { 1306 | let personID = target.getAttribute('data-id').split('-')[1] 1307 | let personCategory = target.getAttribute('data-id').split('-')[0] 1308 | const person = player.relationships[personCategory][parseInt(personID)]; 1309 | const characterIndex = person.characterIndex 1310 | const possibleRelationships = { 1311 | offspring: person.gender === 'male' ? 'son' : 'daughter', 1312 | parents: person.gender === 'male' ? 'father' : 'mother', 1313 | partner: person.gender === 'male' ? 'boyfriend' : 'girlfriend', 1314 | siblings: person.gender === 'male' ? 'brother' : 'sister', 1315 | friends: 'friend', 1316 | exPartner: `ex-${person.gender === 'male' ? 'boyfried' : 'girlfriend'}` 1317 | } 1318 | const relationship = possibleRelationships[personCategory] 1319 | 1320 | modalBackground.style.display = 'flex'; 1321 | 1322 | showEvent({ 1323 | title: `${person.fullName} ${!person.alive ? '(dead)' : ''}`, 1324 | body: ` 1325 |

    Relationship: ${relationship}

    1326 |

    Age: ${person.age}

    1327 | ${person.age >= 16 ? ` 1328 |

    Occupation: ${person.job !== 'none' ? person.job.label : 'unemployed'}

    1329 | ${person.job !== 'none' ? `

    Salary: ${moneyFormat(person.job.salary)} $

    ` : ''}

    1330 | ` : ''} 1331 |

    Location: ${person.location}

    1332 |

    Nationality: ${person.nationality}

    1333 | 1345 | 1346 | ${!player.prison.jailed && person.alive ? ` 1347 |
    Friendly
    1348 | 1349 |
    Mean
    1350 | 1351 | ${personCategory === 'partner' ? ` 1352 |
    Romantic
    1353 | ` : ''} 1354 | ` : ''} 1355 | 1356 |
    Close
    1357 | ` 1358 | }) 1359 | handleStatBars(person, false) 1360 | }, 1361 | friendlyOptions(data) { 1362 | const index = data.getAttribute('data-index'); 1363 | 1364 | eventBody.innerHTML = ` 1365 |
    Spend time together
    1366 |
    Close
    1367 | ` 1368 | }, 1369 | meanOptions(data) { 1370 | const index = data.getAttribute('data-index'); 1371 | const person = characters[index] 1372 | 1373 | eventBody.innerHTML = ` 1374 |
    Insult
    1375 |
    Yell
    1376 | ${player.age > 14 ? `
    Assault
    ` 1377 | : ''} 1378 | ${person.relationships.partner[0].characterIndex === player.characterIndex ? ` 1379 |
    ${person.married ? 'Divorce' : 'Break up'}
    1380 | ` : ''} 1381 |
    Close
    1382 | ` 1383 | }, 1384 | romanticOptions(data) { 1385 | const partner = player.relationships.partner[0] 1386 | const gayWeddings = countryQuery(player.location).laws.gay_weddings; 1387 | let canMarry = true 1388 | if (partner.gender == player.gender && !gayWeddings) 1389 | canMarry = false 1390 | 1391 | eventBody.innerHTML = ` 1392 | ${canMarry ? ` 1393 |
    Propose marriage
    1394 | ` : ''} 1395 |
    Flirt
    1396 |
    Cuddle
    1397 |
    Sex with protection
    1398 |
    Sex without protection
    1399 |
    Close
    1400 | ` 1401 | }, 1402 | friendly: { 1403 | spendTime(data) { 1404 | if (player.actions.friendlyActions >= 3) return 1405 | 1406 | player.actions.friendlyActions++ 1407 | const index = data.getAttribute('data-index'); 1408 | let person = characters[index]; 1409 | 1410 | person.stats.relationWithPlayer += 8; 1411 | 1412 | eventBody.innerHTML = ` 1413 |

    We spent time together

    1414 |

    +8 relationship

    1415 |
    Close
    1416 | ` 1417 | windows.handleRelationBars() 1418 | textContainer.innerHTML += `

    I spent time with ${person.fullName}

    ` 1419 | } 1420 | }, 1421 | mean: { 1422 | yell(data) { 1423 | if (player.actions.meanActions >= 3) return 1424 | 1425 | player.actions.meanActions++ 1426 | const index = data.getAttribute('data-index'); 1427 | let person = characters[index] 1428 | const isPartner = person.relationships.partner[0].characterIndex === player.characterIndex ? true : false; 1429 | 1430 | person.stats.relationWithPlayer -= 10 1431 | 1432 | if (isPartner) 1433 | person.stats.loveToPartner -= 20 1434 | statsLimit(person) 1435 | 1436 | eventBody.innerHTML = ` 1437 |

    You yelled at ${person.gender === 'male' ? 'him' : 'her'}

    1438 |

    -10 relationship

    1439 | ${isPartner ? '

    -20 love

    ' : ''} 1440 |
    Close
    1441 | ` 1442 | textContainer.innerHTML += `

    You yelled at ${person.fullName}

    ` 1443 | 1444 | 1445 | menu.relationships() 1446 | }, 1447 | insult(data) { 1448 | if (player.actions.meanActions >= 3) return 1449 | 1450 | player.actions.meanActions++ 1451 | const index = data.getAttribute('data-index'); 1452 | let person = characters[index] 1453 | const isPartner = person.relationships.partner[0].characterIndex === player.characterIndex ? true : false; 1454 | 1455 | person.stats.relationWithPlayer -= 8 1456 | 1457 | if (isPartner) 1458 | person.stats.loveToPartner -= 30 1459 | 1460 | eventBody.innerHTML = ` 1461 |

    You insulted ${person.gender === 'male' ? 'him' : 'her'}

    1462 |

    -8 relationship

    1463 | ${isPartner ? '

    -30 love

    ' : ''} 1464 |
    Close
    1465 | ` 1466 | textContainer.innerHTML += `

    You insulted ${person.fullName}

    ` 1467 | statsLimit(person) 1468 | 1469 | menu.relationships() 1470 | }, 1471 | assault(data) { 1472 | if (player.actions.meanActions >= 3) return 1473 | 1474 | const index = data.getAttribute('data-index'); 1475 | 1476 | alert('not implemented yet') 1477 | } 1478 | }, 1479 | romance: { 1480 | partner() { 1481 | return player.relationships.partner[0] 1482 | }, 1483 | break() { 1484 | const exPartner = this.partner(); 1485 | exPartner.stats.relationWithPlayer -= 20 + Math.floor(Math.random() * 60) 1486 | exPartner.stats.loveToPartner = 0; 1487 | statsLimit(exPartner); 1488 | 1489 | exPartner.relationships.exPartners = []; 1490 | exPartner.relationships.exPartners.push(player); 1491 | exPartner.relationships.partner.pop(); 1492 | 1493 | player.relationships.exPartners = [] 1494 | player.relationships.exPartners.push(exPartner) 1495 | player.relationships.partner.pop(); 1496 | 1497 | eventBody.innerHTML = ` 1498 |

    You broke up with you ex

    1499 |
    Nothing to miss, right?
    1500 | ` 1501 | 1502 | menu.relationships() 1503 | }, 1504 | proposeMarriage() { 1505 | player.actions.romanticActions++ 1506 | const partner = this.partner(); 1507 | const pronoun = partner.gender === 'male' ? 'He' : 'She'; 1508 | if (partner.stats.loveToPartner >= 60) { 1509 | partner.married = true; 1510 | eventBody.innerHTML = ` 1511 |

    ${pronoun} has accepted your marriage offer, now you are married

    1512 |
    Close
    1513 | ` 1514 | } else { 1515 | eventBody.innerHTML = ` 1516 |

    ${pronoun} has rejected your marriage offer

    1517 |
    Close
    1518 | ` 1519 | menu.relationships() 1520 | } 1521 | }, 1522 | cuddle() { 1523 | player.actions.romanticActions++ 1524 | const partner = this.partner(); 1525 | const pronoun = partner.gender === 'male' ? 'him' : 'her'; 1526 | partner.stats.loveToPartner += 15; 1527 | statsLimit(partner) 1528 | eventBody.innerHTML = ` 1529 |

    You cuddled with ${pronoun}

    1530 |
    Close
    1531 | ` 1532 | menu.relationships() 1533 | 1534 | }, 1535 | flirt() { 1536 | player.actions.romanticActions++ 1537 | const partner = this.partner(); 1538 | const pronoun = partner.gender === 'male' ? 'him' : 'her'; 1539 | partner.stats.loveToPartner += 10; 1540 | statsLimit(partner) 1541 | eventBody.innerHTML = ` 1542 |

    You flirted with ${pronoun}

    1543 |
    Close
    1544 | ` 1545 | menu.relationships() 1546 | }, 1547 | sex(useProtection) { 1548 | const enjoyment = Math.floor(Math.random() * 100); 1549 | const partner = this.partner(); 1550 | partner.stats.loveToPartner = Math.floor(enjoyment / 10) 1551 | 1552 | const pronoun = partner.gender === 'male' ? 'His' : 'Her'; 1553 | let color = '' 1554 | let colors = { 1555 | green: 'rgb(47, 151, 73)', 1556 | yellow: 'rgb(196, 221, 105)', 1557 | red: 'rgb(185, 61, 61)' 1558 | } 1559 | if (enjoyment > 55) color = colors.green 1560 | else if (enjoyment > 25) color = colors.yellow 1561 | else color = colors.red 1562 | 1563 | eventBody.innerHTML = ` 1564 |

    ${pronoun} enjoyment

    1565 |
    1566 |
    1567 |

    1568 | ${useProtection ? ` 1569 |
    Close
    1570 | ` : ''} 1571 | ` 1572 | if (!useProtection) { 1573 | const abort = countryQuery(player.location).laws.abort 1574 | console.log(abort) 1575 | if (player.gender == 'male' && partner.gender == 'female' || player.gender == 'female' && partner.gender == 'male') { 1576 | if (player.gender == 'female') 1577 | player.pregnant = true 1578 | else partner.pregnant = true 1579 | 1580 | eventBody.innerHTML += ` 1581 |

    ${player.pregnant ? 'You are' : 'She is'} pregnant

    1582 | ${abort ? ` 1583 |
    Abort
    1584 | ` : ''} 1585 |
    Abandon
    1586 |
    Keep it
    1587 | ` 1588 | textContainer.innerHTML += ` 1589 |

    ${player.pregnant ? 'I am pregnant' : 'My partner is pregnant'}

    1590 | ` 1591 | } 1592 | } 1593 | }, 1594 | abort() { 1595 | const partner = player.relationships.partner[0] 1596 | if (player.pregnant) player.pregnant = false 1597 | else partner.pregnant = false 1598 | eventBody.innerHTML = ` 1599 |

    We decided to abort it

    1600 |
    Close
    1601 | ` 1602 | } 1603 | } 1604 | }, 1605 | sexuality: { 1606 | display() { 1607 | if (player.age < 15) return 1608 | 1609 | showEvent({ 1610 | title: 'Sexuality', 1611 | body: ` 1612 |

    Choose your sexual orientation

    1613 |

    You are currently ${player.sexuality}

    1614 |
    Heterosexual
    1615 |
    Homosexual
    1616 |
    Bisexual
    1617 | ` 1618 | }) 1619 | }, 1620 | choose(sexuality) { 1621 | player.sexuality = sexuality; 1622 | closeEvent(); 1623 | menuTemplate.style.display = 'none' 1624 | textContainer.innerHTML += `

    I am ${sexuality} now

    ` 1625 | } 1626 | }, 1627 | driverLicense: { 1628 | display() { 1629 | if (player.age < 18) return; 1630 | 1631 | modalBackground.style.display = 'flex'; 1632 | eventTitle.innerText = 'Driver license' 1633 | eventBody.innerHTML = ` 1634 | ${player.driverLicense ? '

    You already have a driver license

    ' : '

    You dont have a driver license

    '} 1635 | ` 1636 | eventBody.innerHTML += ` 1637 | ${!player.driverLicense ? ` 1638 |
    Take test
    1639 |
    Close
    1640 | ` : '
    Close
    '} 1641 | ` 1642 | }, 1643 | test() { 1644 | const random = Math.floor(Math.random() * 3) 1645 | if (random === 2) { 1646 | player.driverLicense = true 1647 | eventBody.innerHTML = `

    Congratulations, you approved the driver test

    1648 |
    Close
    1649 | ` 1650 | textContainer.innerHTML += `

    I approved the driver test succesfully

    ` 1651 | } else { 1652 | eventBody.innerHTML = `

    You failed the driver test, good luck the next time

    1653 |
    Close
    1654 | ` 1655 | textContainer.innerHTML += `

    I failed the driver test

    ` 1656 | } 1657 | }, 1658 | 1659 | }, 1660 | prison: { 1661 | display() { 1662 | showEvent({ 1663 | title: 'Prison', 1664 | body: ` 1665 |

    Years left: ${player.prison.yearsLeft} years

    1666 |

    Sentence: ${player.prison.sentenceTime} years

    1667 |
    Attempt to escape
    1668 |
    Lift
    1669 |
    Close
    1670 | ` 1671 | }) 1672 | }, 1673 | attempToEscape() { 1674 | const random = Math.floor(Math.random() * 100); 1675 | if (random <= 10) { 1676 | player.prison.jailed = false; 1677 | player.criminalRecord.prisonEscapes++; 1678 | eventBody.innerHTML = ` 1679 |

    You escaped from prison

    1680 | ` 1681 | textContainer.innerHTML += ` 1682 |

    I escaped from prison

    1683 | ` 1684 | 1685 | } else { 1686 | player.prison.yearsLeft += 2; 1687 | player.prison.sentenceTime += 2 1688 | eventBody.innerHTML = ` 1689 |

    Your escape attempt failed

    1690 |

    +2 years of prison

    1691 |
    ...
    1692 | ` 1693 | textContainer.innerHTML += ` 1694 |

    My escape attempt failed

    1695 | ` 1696 | } 1697 | }, 1698 | lift() { 1699 | player.stats.fitness += 5; 1700 | statsLimit(player); 1701 | 1702 | eventBody.innerHTML = ` 1703 |

    You lifted

    1704 |

    +5 fitness

    1705 |
    Close
    1706 | ` 1707 | textContainer.innerHTML += ` 1708 |

    I lifted

    1709 | ` 1710 | } 1711 | }, 1712 | love: { 1713 | findLove() { 1714 | if (player.age < 14) return; 1715 | 1716 | if (player.relationships.partner.length !== 0) { 1717 | showEvent({ 1718 | title: 'Are you sure?', 1719 | body: ` 1720 |

    This means breaking up with your current partner

    1721 |
    Break up
    1722 |
    I changed my mind
    1723 | ` 1724 | }) 1725 | return 1726 | } 1727 | 1728 | const targetGender = { 1729 | heterosexual: player.gender === 'male' ? 'female' : 'male', 1730 | homosexual: player.gender, 1731 | bisexual: undefined 1732 | } 1733 | 1734 | let possiblePartner = new Person(undefined, undefined, player.age, targetGender[player.sexuality], undefined, 0, player.location) 1735 | if (possiblePartner.gender === player.gender) 1736 | possiblePartner.sexuality = 'homosexual' 1737 | if (possiblePartner.age >= 18) 1738 | jobAssigner(possiblePartner); 1739 | 1740 | characters.push(possiblePartner) 1741 | 1742 | showEvent({ 1743 | title: 'Find a partner', 1744 | body: ` 1745 |

    Name: ${possiblePartner.fullName}

    1746 |

    Gender: ${capitalize(possiblePartner.gender)}

    1747 |

    Age: ${possiblePartner.age}

    1748 |

    Job: ${possiblePartner.job !== 'none' ? possiblePartner.job.label : 'unemployed'}

    1749 | ${possiblePartner.job !== 'none' ? `

    Salary: ${moneyFormat(possiblePartner.job.salary)} $

    ` : ''} 1750 | 1757 |
    Try it
    1758 |
    Close
    1759 | ` 1760 | }) 1761 | statbarColorer() 1762 | }, 1763 | tryPartner() { 1764 | let possiblePartner = characters.at(-1) 1765 | 1766 | const random = Math.floor(Math.random() * 100); 1767 | const appearance = player.stats.appearance; 1768 | 1769 | const pronoun = possiblePartner.gender === 'male' ? 'He' : 'She'; 1770 | 1771 | if (random + appearance > 100) { 1772 | possiblePartner.stats.relationWithPlayer = 50 + Math.floor(Math.random() * 50) 1773 | possiblePartner.stats.loveToPartner = 25 + Math.floor(Math.random() * 25) 1774 | 1775 | possiblePartner.relationships.partner.push(player) 1776 | 1777 | player.relationships.partner.push(possiblePartner) 1778 | eventBody.innerHTML = ` 1779 |

    ${pronoun} is your partner now

    1780 |
    Close
    1781 | ` 1782 | } else { 1783 | eventBody.innerHTML = ` 1784 |

    ${pronoun} has rejected you

    1785 |
    Close
    1786 | ` 1787 | characters.pop() 1788 | } 1789 | }, 1790 | dontTryPartner() { 1791 | closeEvent() 1792 | characters.pop() 1793 | }, 1794 | }, 1795 | university: { 1796 | display() { 1797 | if (player.age < 17) return 1798 | 1799 | if (player.currentEducation === 'university') { 1800 | return showEvent({ 1801 | title: 'University', 1802 | body: ` 1803 |

    You are already studying in the university

    1804 |
    Close
    1805 | ` 1806 | }) 1807 | } 1808 | 1809 | const dad = player.relationships.parents[0]; 1810 | const mom = player.relationships.parents[1]; 1811 | 1812 | showEvent({ 1813 | title: 'Are you going to university?', 1814 | body: ` 1815 |
    Ask my parents to pay it
    1816 |
    Ask for a student loan
    1817 |
    Pay it by myself
    1818 |
    Nevermind
    1819 | ` 1820 | }) 1821 | }, 1822 | dontGo() { 1823 | closeEvent() 1824 | textContainer.innerHTML += `

    Im not going to the university

    ` 1825 | }, 1826 | chooseCareer(payer, paidBy) { 1827 | eventTitle.innerText = 'Choose your career'; 1828 | eventBody.innerHTML = ` 1829 | 1838 |
    Study
    1839 |
    I changed my mind
    1840 | ` 1841 | for (let option of document.getElementsByClassName('option')) { 1842 | option.addEventListener('click', e => { 1843 | const decision = e.target.getAttribute('data-label') 1844 | if (decision === 'yes') { 1845 | const chosenCareer = document.getElementById('career-selector').value 1846 | player.currentCareer = Object.assign({ studying: true }, universityCareers[chosenCareer]); 1847 | player.currentCareer.paidBy = paidBy; 1848 | player.currentEducation = 'university'; 1849 | player.currentCareer.yearsStudied = 0 1850 | if (!payer) { 1851 | // add loan later 1852 | return closeEvent() 1853 | } 1854 | if (payer.characterIndex === player.characterIndex) { 1855 | payer.money.expenses += 6000 1856 | } 1857 | player.currentCareer.yearsStudied = 0; 1858 | closeEvent(); 1859 | } else { 1860 | closeEvent(); 1861 | } 1862 | }) 1863 | } 1864 | }, 1865 | payByMyself() { 1866 | if (player.money.income >= 6000 || player.money.total >= 6000 * 5) { 1867 | windows.university.chooseCareer(player, 'myself'); 1868 | } else { 1869 | textContainer.innerHTML += `

    I dont have enough money

    ` 1870 | let btn = document.getElementById('player-pay-university') 1871 | btn.remove() 1872 | } 1873 | }, 1874 | paidByParents() { 1875 | const dad = player.relationships.parents[0]; 1876 | const mom = player.relationships.parents[1]; 1877 | 1878 | if (dad.alive || mom.alive) 1879 | textContainer.innerHTML += `

    I asked my parents to pay

    ` 1880 | 1881 | if (dad.alive && dad.money.income - dad.money.expenses >= 6000 || 1882 | mom.alive && mom.money.income - mom.money.expenses >= 6000) { 1883 | textContainer.innerHTML += `

    My parents accepted

    ` 1884 | windows.university.chooseCareer(dad.alive && dad.money.income - dad.money.expenses >= 6000 ? dad : mom, 'parents'); 1885 | } else { 1886 | textContainer.innerHTML += `

    My parents rejected

    ` 1887 | let btn = document.getElementById('parents-pay-university') 1888 | btn.remove() 1889 | } 1890 | 1891 | }, 1892 | loan() { 1893 | textContainer.innerHTML += `

    I applied for a loan

    ` 1894 | windows.university.chooseCareer(undefined, 'loan'); 1895 | } 1896 | 1897 | }, 1898 | emigrate() { 1899 | const chosenCountry = document.getElementById('country-chooser').value 1900 | if (player.age >= 18) { 1901 | player.location = chosenCountry; 1902 | textContainer.innerHTML += ` 1903 |

    I emigrated to ${player.location}

    1904 | ${player.job !== 'none' ? ` 1905 |

    I quit my job

    ` : ''} 1906 | `; 1907 | player.job.until = year; 1908 | player.money.income -= player.job.salary; 1909 | moneyViewer() 1910 | player.cv.push(player.job) 1911 | player.job = 'none' 1912 | menuTemplate.style.display = 'none'; 1913 | 1914 | 1915 | } else if (player.age < 18) { 1916 | showEvent({ 1917 | title: 'You cant emigrate', 1918 | body: ` 1919 |
    Ok
    1920 | ` 1921 | }) 1922 | textContainer.innerHTML += 'I cant emigrate' 1923 | menuTemplate.style.display = 'none'; 1924 | } 1925 | }, 1926 | job: { 1927 | jobWindow(e) { 1928 | if (player.job !== 'none') { 1929 | showEvent({ 1930 | title: 'You already have a job', 1931 | body: ` 1932 |

    Will you quit?

    1933 |
    Quit
    1934 |
    Keep my job
    1935 | ` 1936 | }) 1937 | } 1938 | 1939 | const index = e.getAttribute('data-index'); 1940 | const job = jobs[index]; 1941 | 1942 | showEvent({ 1943 | title: `Get a job as ${job.label}`, 1944 | body: ` 1945 |

    Anual salary: ${moneyFormat(job.salary)}$


    1946 |

    Requirements:

    1947 | 1950 | 1951 |
    Apply
    1952 |
    Uh, nevermind
    1953 | ` 1954 | }) 1955 | }, 1956 | apply(index) { 1957 | const job = Object.assign({}, jobs[index]); 1958 | const requirements = job.requirements 1959 | let requirementsCompleted = 0; 1960 | for (let requirement of Object.entries(requirements)) { 1961 | const skillVerifier = () => { 1962 | const skills = ['programming', 'music', 'handiness', 'writing', 'art'] 1963 | if (skills.includes(requirement[0])) 1964 | if (player.skills[requirement[0]].level >= requirement[1]) 1965 | requirementsCompleted++; 1966 | } 1967 | const statVerifier = () => { 1968 | stats = ['health', 'happiness', 'smartness', 'fitness', 'appearance'] 1969 | if (stats.includes(requirement[0])) 1970 | if (player.stats[requirement[0]] >= requirement[1]) 1971 | requirementsCompleted++; 1972 | } 1973 | if (requirement[0] === 'criminalRecord') { 1974 | const values = Object.entries(player.criminalRecord) 1975 | let count = values.length 1976 | for (let value of values) { 1977 | if (value[1] === 0) count-- 1978 | } 1979 | if (count === 0) requirementsCompleted++ 1980 | } 1981 | if (requirement[0] === 'education' && Object.entries(player.career).length > 0 1982 | && player.career[requirement[1]] != undefined) 1983 | if (player.career[requirement[1]].label === requirement[1]) requirementsCompleted++; 1984 | 1985 | skillVerifier() 1986 | statVerifier() 1987 | 1988 | if (requirement[0] === 'minAge' && player.age >= requirement[1]) 1989 | requirementsCompleted++ 1990 | } 1991 | 1992 | if (Object.entries(requirements).length === requirementsCompleted) { 1993 | player.money.income += job.salary; 1994 | player.job = job; 1995 | player.job.since = year; 1996 | player.job.performance = Math.floor(Math.random() * 50) + 25 1997 | eventTitle.innerText = 'Applied succesfuly!' 1998 | eventBody.innerHTML = `
    Nice
    `; 1999 | textContainer.innerHTML += `

    I got a job as ${job.label}

    ` 2000 | menu.job() 2001 | moneyViewer() 2002 | } else { 2003 | eventTitle.innerText = 'You did not get an interview' 2004 | eventBody.innerHTML = `
    ...
    `; 2005 | } 2006 | }, 2007 | confirmLeave() { 2008 | eventBody.innerHTML = ` 2009 |

    Are you sure you want to leave?

    2010 |
    Yes
    2011 |
    No
    2012 | 2013 | ` 2014 | }, 2015 | leave() { 2016 | player.job.until = year; 2017 | player.cv.push(player.job); 2018 | player.job = 'none' 2019 | eventBody.innerHTML = ` 2020 |

    You resigned succesfully

    2021 |
    Good
    2022 | ` 2023 | menu.job() 2024 | }, 2025 | workHarder() { 2026 | closeEvent() 2027 | menuTemplate.style.display = 'none' 2028 | textContainer.innerHTML += ` 2029 |

    I worked harder at my job

    2030 | ` 2031 | player.job.performance += Math.floor(Math.random() * 10) 2032 | player.stats.happiness -= 5 2033 | player.stats.health -= 2 2034 | player.actions.workHarder++; 2035 | statsLimit(player) 2036 | }, 2037 | askPromotion() { 2038 | player.actions.performance++ 2039 | modalBackground.style.display = 'flex' 2040 | eventTitle.innerText = 'Promotion' 2041 | if (player.job.performance >= 70) 2042 | for (let job of jobs) { 2043 | if (job.label === player.job.promotion) { 2044 | player.job.until = year 2045 | player.cv.push(player.job) 2046 | 2047 | player.job = structuredClone(job) 2048 | player.job.since = year 2049 | 2050 | eventBody.innerHTML = ` 2051 |

    Your promotion request has been accepted

    2052 |
    Close
    2053 | ` 2054 | menu.job() 2055 | break; 2056 | } 2057 | } 2058 | else { 2059 | eventBody.innerHTML = ` 2060 |

    Your promotion request has been rejected

    2061 |
    Close
    2062 | ` 2063 | } 2064 | }, 2065 | currentJob() { 2066 | showEvent({ 2067 | title: 'Current Job', 2068 | body: ` 2069 |

    Current job: ${player.job.label}

    2070 |

    Salary: ${moneyFormat(player.job.salary)} $

    2071 |

    Next position: TO DO

    2072 |

    Years working: ${year - player.job.since}

    2073 |

    Performance: ${player.job.performance}/100

    2074 |
    2075 |
    2076 |
    2077 | 2088 | ` 2089 | }) 2090 | }, 2091 | }, 2092 | freetime: { 2093 | handleSwitch(option) { 2094 | const notEnoughMoney = () => { 2095 | showEvent({ 2096 | title: 'Freetime', 2097 | body: ` 2098 |

    You do not have enough money

    2099 |
    Close
    2100 | ` 2101 | }) 2102 | } 2103 | let freetime = player.freetime; 2104 | let button = document.getElementById(`freetime-${option}`) 2105 | switch (option) { 2106 | case 'reading': 2107 | if (player.age < 8) return 2108 | if (player.money.total < 200) return notEnoughMoney() 2109 | freetime.isReading ? freetime.isReading = false : freetime.isReading = true; 2110 | freetime.isReading ? button.style.float = 'right' : button.style.float = 'left' 2111 | freetime.isReading ? player.money.expenses += 200 : player.money.expenses -= 200 2112 | break; 2113 | case 'parties': 2114 | if (player.age < 2) return 2115 | if (player.money.total < 500) return notEnoughMoney() 2116 | freetime.isAttendingParties ? freetime.isAttendingParties = false : freetime.isAttendingParties = true; 2117 | freetime.isAttendingParties ? button.style.float = 'right' : button.style.float = 'left' 2118 | freetime.isAttendingParties ? player.money.expenses += 500 : player.money.expenses -= 500 2119 | break; 2120 | case 'musicLessons': 2121 | if (player.age < 7) return 2122 | if (player.money.total < 2000) return notEnoughMoney() 2123 | freetime.isTakingMusicLessons ? freetime.isTakingMusicLessons = false : freetime.isTakingMusicLessons = true; 2124 | freetime.isTakingMusicLessons ? button.style.float = 'right' : button.style.float = 'left' 2125 | freetime.isTakingMusicLessons ? player.money.expenses += 2000 : player.money.expenses -= 2000 2126 | break; 2127 | case 'gym': 2128 | if (player.age < 16) return 2129 | if (player.money.total < 1800) return notEnoughMoney() 2130 | freetime.goesToGym ? freetime.goesToGym = false : freetime.goesToGym = true; 2131 | freetime.goesToGym ? button.style.float = 'right' : button.style.float = 'left' 2132 | freetime.goesToGym ? player.money.expenses += 1800 : player.money.expenses -= 1800 2133 | break; 2134 | default: 2135 | break; 2136 | } 2137 | moneyViewer() 2138 | }, 2139 | cinema: { 2140 | display() { 2141 | if (player.age < 12) return 2142 | 2143 | showEvent({ 2144 | title: 'Cinema', 2145 | body: ` 2146 |

    Price: 400$

    2147 |
    Pay
    2148 |
    Cancel
    2149 | ` 2150 | }) 2151 | }, 2152 | pay(money) { 2153 | if (player.money.total >= money) { 2154 | player.money.total -= money; 2155 | player.stats.happiness += 3; 2156 | eventTitle.innerText = 'Cinema'; 2157 | eventBody.innerHTML = ` 2158 |

    You went to the cinema

    2159 |
    Nice
    2160 | `; 2161 | textContainer.innerHTML += `

    I watched a movie at a cinema

    ` 2162 | moneyViewer() 2163 | } else { 2164 | eventTitle.innerText = 'Cinema'; 2165 | eventBody.innerHTML = ` 2166 |

    You do not have enough money

    2167 |
    ...
    2168 | `; 2169 | } 2170 | } 2171 | }, 2172 | restaurant: { 2173 | display() { 2174 | if (player.age < 12) return 2175 | 2176 | showEvent({ 2177 | title: 'Restaurant', 2178 | body: ` 2179 |

    This would cost 250$

    2180 |
    Pay
    2181 |
    Leave
    2182 | ` 2183 | }) 2184 | }, 2185 | pay(money) { 2186 | if (player.money.total >= money) { 2187 | player.money.total -= money; 2188 | player.stats.happiness += 3; 2189 | showEvent({ 2190 | title: "Restaurant", 2191 | body: ` 2192 |

    You paid the restaurant

    2193 |
    Nice
    2194 | ` 2195 | }) 2196 | textContainer.innerHTML += `

    I went to a restaurant

    ` 2197 | moneyViewer() 2198 | } else { 2199 | showEvent({ 2200 | title: "Restaurant", 2201 | body: ` 2202 |

    You do not have enough money

    2203 |
    ...
    2204 | ` 2205 | }) 2206 | } 2207 | } 2208 | }, 2209 | goClubbing: { 2210 | display() { 2211 | if (player.age < 18) return 2212 | 2213 | modalBackground.style.display = 'flex' 2214 | eventTitle.innerText = 'Go clubbing' 2215 | const possibilities = Math.round(Math.random() * 3) 2216 | 2217 | player.stats.happiness += Math.floor(Math.random() * 5) 2218 | statsLimit(player) 2219 | textContainer.innerHTML += ` 2220 |

    I went clubbing

    2221 | ` 2222 | handleStatBars(player, true) 2223 | if (possibilities <= 1) 2224 | showEvent({ 2225 | title: "Go clubbing", 2226 | body: ` 2227 |

    You had fun at the club

    2228 |
    Close
    2229 | ` 2230 | }) 2231 | else if (possibilities === 2) { 2232 | const drinks = items.alcoholic 2233 | // const drinks = ['beer', 'wine', 'vodka'] 2234 | const random = Math.floor(Math.random() * drinks.length) 2235 | const drink = drinks[random].label.toLowerCase() 2236 | showEvent({ 2237 | title: "Go clubbing", 2238 | body: ` 2239 |

    You have been offered a ${drink}

    2240 |
    Accept
    2241 | 2242 |
    Refuse
    2243 | ` 2244 | }) 2245 | textContainer.innerHTML += `

    I have been offered a ${drink}

    ` 2246 | } 2247 | else if (possibilities === 3) { 2248 | const drugs = [ 2249 | { 2250 | name: 'LSD', 2251 | damage: 5 2252 | }, 2253 | { 2254 | name: 'weed', 2255 | damage: 3 2256 | }, 2257 | { 2258 | name: 'heroin', 2259 | damage: 12 2260 | }, 2261 | { 2262 | name: 'cocaine', 2263 | damage: 10 2264 | } 2265 | ]; 2266 | const random = Math.floor(Math.random() * drugs.length) 2267 | const drug = drugs[random] 2268 | 2269 | textContainer.innerHTML += `

    I have been offered ${drug.name}

    ` 2270 | showEvent({ 2271 | title: "Go clubbing", 2272 | body: ` 2273 |

    You have been offered ${drug.name}

    2274 |
    Accept
    2275 |
    Refuse
    2276 | ` 2277 | }) 2278 | } 2279 | }, 2280 | acceptDrink(drink) { 2281 | menuTemplate.style.display = 'none' 2282 | eventBody.innerHTML = ` 2283 |

    You accepted the ${drink}

    2284 |
    Close
    2285 | ` 2286 | textContainer.innerHTML += `

    I accepted the ${drink}

    ` 2287 | const random = Math.floor(Math.random() * 8) 2288 | player.stats.health -= random 2289 | statsLimit(player) 2290 | handleStatBars(player, true) 2291 | }, 2292 | acceptDrug(damage) { 2293 | menuTemplate.style.display = 'none' 2294 | closeEvent() 2295 | player.stats.health -= damage 2296 | statsLimit(player) 2297 | textContainer.innerHTML += `

    I accepted

    ` 2298 | handleStatBars(player, true) 2299 | }, 2300 | decline() { 2301 | menuTemplate.style.display = 'none' 2302 | closeEvent() 2303 | textContainer.innerHTML += ` 2304 |

    I declined

    2305 | ` 2306 | } 2307 | }, 2308 | }, 2309 | handleRelationBars() { 2310 | let progressBars = document.getElementsByClassName('relation'); 2311 | for (let element of Object.entries(progressBars)) { 2312 | let index = parseInt(element[1].id.split('-')[1]) 2313 | let category = element[1].id.split('-')[0] 2314 | let opinion = player.relationships[category][index].stats.relationWithPlayer; 2315 | element[1].style.width = `${opinion}%` 2316 | } 2317 | 2318 | for (let progressBar of progressBars) { 2319 | let percentage = parseInt(progressBar.style.width.split('%')[0]); 2320 | if (percentage > 55) progressBar.style.backgroundColor = 'rgb(47, 151, 73)' 2321 | else if (percentage > 25) progressBar.style.backgroundColor = 'rgb(196, 221, 105)' 2322 | else progressBar.style.backgroundColor = 'rgb(185, 61, 61)' 2323 | } 2324 | }, 2325 | throwParty() { 2326 | player.stats.happiness += 10; 2327 | eventBody.innerHTML = ` 2328 |

    You threw an amazing party

    2329 |
    2330 |
    Close
    2331 | ` 2332 | textContainer.innerHTML += `

    I organized a party at home

    ` 2333 | statsLimit(player) 2334 | menuTemplate.style.display = 'none' 2335 | handleStatBars(player, true) 2336 | }, 2337 | } --------------------------------------------------------------------------------