Files

292 lines
20 KiB
JavaScript

/* ============================================================
* data.js — object catalog, careers, skills, socials, need meta
* ============================================================ */
'use strict';
/* ---------------- NEEDS ---------------- */
const NEEDS = {
hunger: { label:'Hunger', icon:'🍔', color:'#e8a33d', decay: -7 },
energy: { label:'Energy', icon:'💤', color:'#7f6fd0', decay: -4 },
bladder: { label:'Bladder', icon:'🚽', color:'#4fa3d9', decay: -6 },
hygiene: { label:'Hygiene', icon:'🚿', color:'#5ad0c8', decay: -4 },
fun: { label:'Fun', icon:'🎉', color:'#e05aa8', decay: -5 },
social: { label:'Social', icon:'💬', color:'#63c15a', decay: -5 },
comfort: { label:'Comfort', icon:'🛋️', color:'#c9a24a', decay: -5 },
room: { label:'Room', icon:'🌸', color:'#9b7fd0', decay: 0 }, // computed from environment
};
/* ---------------- SKILLS ---------------- */
const SKILLS = [
{ id:'cooking', name:'Cooking', icon:'🍳' },
{ id:'mechanical', name:'Mechanical', icon:'🔧' },
{ id:'charisma', name:'Charisma', icon:'💬' },
{ id:'body', name:'Body', icon:'💪' },
{ id:'logic', name:'Logic', icon:'🧠' },
{ id:'creativity', name:'Creativity', icon:'🎨' },
{ id:'cleaning', name:'Cleaning', icon:'🧹' },
];
/* ---------------- PERSONALITY TRAITS ---------------- */
const TRAITS = ['neat','outgoing','active','playful','nice'];
/* ---------------- CAREERS ----------------
* 10 ranks each; generated salaries; skill requirements ramp. */
function makeCareer(id, icon, title1, titles, basePay, startHour, endHour, skillKey) {
const ranks = [];
for (let i = 0; i < 10; i++) {
const req = {};
if (skillKey && i >= 1) req[skillKey] = Math.min(10, Math.ceil(i * 1.1));
if (i >= 5 && skillKey !== 'charisma') req.charisma = Math.ceil((i - 4) * 0.8);
ranks.push({
title: titles[i],
salary: Math.round(basePay * Math.pow(1.42, i)),
hours: [startHour, endHour],
offDays: (id === 'criminal') ? [2, 4] : [5, 6], // index of DAY_NAMES; criminal works weekends
req,
carpoolHour: startHour - 1,
});
}
return { id, icon, name: titles[0], trackName: title1 + ' Track', ranks };
}
const CAREERS = [
makeCareer('business', '💼', 'Business',
['Mailroom Tech','Trainee','Junior Executive','Executive','Assistant Manager','Manager','Vice President','President','CEO','Business Tycoon'],
154, 9, 16, 'charisma'),
makeCareer('culinary', '🍳', 'Culinary',
['Dish Washer','Fast Food Shift Manager','Drive-Thru Clerk','Counter Person','Waiter','Head Waiter','Sous-Chef','Executive Chef','Celebrity Chef','Five-Star Chef'],
126, 14, 21, 'cooking'),
makeCareer('science', '🔬', 'Science',
['Test Subject','Lab Assistant','Field Researcher','Science Teacher','Lab Tech','Research Assistant','Project Leader','Inventor','Scientist','Mad Scientist'],
140, 9, 15, 'logic'),
makeCareer('medicine', '🩺', 'Medicine',
['Emergency Medical Technician','Paramedic','Nurse','Orderly','Intern','Resident','General Practitioner','Specialist','Surgeon','Chief of Staff'],
168, 8, 17, 'mechanical'),
makeCareer('athletic', '🏆', 'Athletic',
['Locker Room Attendant','Team Mascot','Waterperson','Towel Boy','Equipment Manager','Team Physician','Coach','Mascot Manager','Most Valuable Player','Hall of Famer'],
132, 12, 19, 'body'),
makeCareer('criminal', '🕵️', 'Criminal',
['Con Artist','Pickpocket','Bookmaker','Cutpurse','Safecracker','Bank Robber','Cat Burglar','Safe Cracker','Getaway Driver','Crime Lord'],
150, 21, 4, 'body'),
makeCareer('military', '🎖️', 'Military',
['Recruit','Private','Corporal','Sergeant','Junior Officer','Lieutenant','Captain','Major','Colonel','Astronaut'],
155, 7, 14, 'mechanical'),
makeCareer('art', '🎭', 'Arts',
['Subway Performer','Coffee Shop Singer','Portrait Painter','Street Mime','Wedding Singer','Commercial Actor','Supporting Role','Lead Role','Famous Star','Icon'],
118, 13, 20, 'creativity'),
];
const ASPIRATIONS = {
fortune: { name:'Fortune', icon:'💰', desc:'Wants riches and promotions.' },
knowledge: { name:'Knowledge', icon:'📚', desc:'Wants maxed skills.' },
popularity: { name:'Popularity', icon:'🎊', desc:'Wants many friends.' },
family: { name:'Family', icon:'🏡', desc:'Wants a cozy home life.' },
romance: { name:'Romance', icon:'💘', desc:'Wants love and charm.' },
};
/* ---------------- WHIMS (short-term wants) ---------------- */const WHIMS = {
fortune: [
{ id:'promote', icon:'⭐', label:'Get promoted', ev:'promotion', reward:130 },
{ id:'earn', icon:'💰', label:'Earn §400 on the side', ev:'earn', amount:400, reward:80 },
{ id:'job', icon:'📋', label:'Get hired', ev:'job', reward:60 },
],
knowledge: [
{ id:'maxskill', icon:'🧠', label:'Max out a skill (10)', ev:'skill', level:10, reward:150 },
{ id:'anylevel', icon:'📈', label:'Gain any skill level', ev:'skill', reward:50 },
{ id:'chessy', icon:'♟️', label:'Play chess', ev:'social', match:'chess', reward:40 },
],
popularity: [
{ id:'friend', icon:'🤝', label:'Make a new friend', ev:'friend', reward:120 },
{ id:'mixer', icon:'💬', label:'Socialize 5 times', ev:'social', count:5, reward:70 },
{ id:'host', icon:'👋', label:'Invite a neighbor over', ev:'visitor', reward:45 },
],
family: [
{ id:'meal', icon:'🍲', label:'Cook a nice meal', ev:'meal', reward:60 },
{ id:'rested', icon:'😴', label:'Wake up fully rested', ev:'rested', reward:60 },
{ id:'tidy', icon:'✨', label:'Clean something filthy', ev:'cleaned', reward:45 },
],
romance: [
{ id:'flirt', icon:'💗', label:'Flirt with someone', ev:'social', match:'flirt', reward:85 },
{ id:'hug', icon:'🤗', label:'Share a hug', ev:'social', match:'hug', reward:50 },
{ id:'love', icon:'💞', label:'Fall in love', ev:'love', reward:200 },
],
};
/* ---------------- SOCIAL INTERACTIONS ---------------- */
const SOCIALS = [
{ id:'talk', label:'Talk', icon:'💬', str:+4, ltr:+1.5, dur:10, minRel:-100 },
{ id:'joke', label:'Joke', icon:'😄', str:+6, ltr:+2, dur:8, playfulBoost:true },
{ id:'compliment', label:'Compliment', icon:'🌹', str:+7, ltr:+2.5, dur:6, niceBoost:true },
{ id:'hug', label:'Hug', icon:'🤗', str:+9, ltr:+3.5, dur:5, minRel:25 },
{ id:'flirt', label:'Flirt', icon:'💗', str:+11, ltr:+5, dur:8, minRel:45, romanceOnly:false },
{ id:'dance', label:'Dance Together', icon:'🕺', str:+8, ltr:+3, dur:20 },
{ id:'insult', label:'Insult', icon:'😠', str:-12, ltr:-6, dur:5 },
{ id:'argue', label:'Argue', icon:'🗯️', str:-18, ltr:-9, dur:8, minRelMax:0 },
];
/* ---------------- OBJECT CATALOG ----------------
* shape keys are painted procedurally in render.js
* interactions: generic runner in ai.js — dur = minutes, fx = need points/min while using */
/* --- meals by cooking skill (needs groceries from the fridge stock) --- */
const MEALS = [
{ id:'quick', name:'Instant Noodles', skill:0, hunger:22, fun:2, emoji:'🍜' },
{ id:'spaghetti', name:'Spaghetti', skill:2, hunger:34, fun:8, emoji:'🍝' },
{ id:'roast', name:'Sunday Roast', skill:4, hunger:46, fun:16, emoji:'🍗' },
{ id:'gourmet', name:'Gourmet Lobster', skill:6, hunger:58, fun:28, emoji:'🦞' },
];
/* --- career chance cards (picked at random while at work) --- */
const CHANCE_CARDS = [
{ q:'Your boss needs someone to stay late and finish a report.',
a:[{ label:'Stay late', icon:'🌙', fx:{ perf:8, energy:-18 }, say:'💼' },
{ label:'Go home', icon:'🏠', fx:{ perf:-3 }, say:'😐' }] },
{ q:'A coworker asks you to cover their mistake in front of the client.',
a:[{ label:'Cover for them', icon:'🤝', fx:{ perf:5 }, say:'😇' },
{ label:'Tell the truth', icon:'📢', fx:{ perf:2, bonus:150 }, say:'😎' }] },
{ q:'You found a wallet in the parking lot with §200 inside.',
a:[{ label:'Return it', icon:'🙌', fx:{ perf:6 }, say:'😊' },
{ label:'Keep it', icon:'💰', fx:{ money:200, perf:-7 }, say:'🤑' }] },
{ q:'Upper management is watching today. Impress them?',
a:[{ label:'Give a bold presentation', icon:'📊', fx:{ dice:.55, win:{ perf:14 }, lose:{ perf:-10 } } },
{ label:'Keep a low profile', icon:'🙈', fx:{ perf:1 } }] },
{ q:'The office espresso machine broke. Fix it yourself?',
a:[{ label:'Fix it', icon:'🔧', fx:{ dice:.7, win:{ skill:'mechanical', amt:1, perf:4 }, lose:{ perf:-5, say:'⚡' } } },
{ label:'Drink tea instead', icon:'🍵', fx:{ fun:10 } }] },
{ q:'A rival offers you insider tips for a quick promotion.',
a:[{ label:'Take the tips', icon:'🕵️', fx:{ dice:.6, win:{ perf:12 }, lose:{ perf:-12, firedRisk:.06 } } },
{ label:'Refuse', icon:'🙅', fx:{ perf:3, say:'🙂' } }] },
{ q:'Charity gala tonight — attend or rest?',
a:[{ label:'Attend the gala', icon:'🥂', fx:{ energy:-15, perf:7, social:20 }, say:'✨' },
{ label:'Sleep early', icon:'😴', fx:{ energy:25, perf:-2 } }] },
];
const OBJECTS = {
/* --- seating --- */
chair: { id:'chair', name:'Chair', emoji:'🪑', price:85, w:1, h:1, cat:'seating', shape:'chair', rot:true, sit:true,
env:2, interactions:[{ id:'sit', label:'Sit', icon:'🛋️', dur:60, fx:{comfort:.35}, pose:'sit' }] },
stool: { id:'stool', name:'Stool', emoji:'🟫', price:50, w:1, h:1, cat:'seating', shape:'stool', rot:true, sit:true,
env:1, interactions:[{ id:'sit', label:'Sit', icon:'🛋️', dur:60, fx:{comfort:.28}, pose:'sit' }] },
sofa: { id:'sofa', name:'Sofa', emoji:'🛋️', price:450, w:1, h:3, cat:'seating', shape:'sofa', rot:true, sit:true,
env:4, comfortSeat:1, interactions:[
{ id:'sit', label:'Sit', icon:'🛋️', dur:60, fx:{comfort:.45}, pose:'sit' },
{ id:'nap', label:'Nap', icon:'💤', dur:120, fx:{energy:.22, comfort:.3}, pose:'sit' }] },
loveseat: { id:'loveseat', name:'Loveseat', emoji:'💺', price:350, w:1, h:2, cat:'seating', shape:'loveseat', rot:true, sit:true,
env:3, interactions:[{ id:'sit', label:'Sit', icon:'🛋️', dur:60, fx:{comfort:.4}, pose:'sit' }] },
/* --- tables --- */
table: { id:'table', name:'Table', emoji:'🍽️', price:250, w:1, h:1, cat:'tables', shape:'table', rot:true, env:2, eatSpot:true, interactions:[] },
coffeeTable: { id:'coffeeTable', name:'Coffee Table', emoji:'☕', price:120, w:2, h:1, cat:'tables', shape:'coffeeTable', rot:true, env:2, interactions:[] },
desk: { id:'desk', name:'Desk', emoji:'🗄️', price:180, w:2, h:1, cat:'tables', shape:'desk', rot:true, env:2, interactions:[] },
/* --- beds --- */
bedSingle: { id:'bedSingle', name:'Single Bed', emoji:'🛏️', price:400, w:1, h:2, cat:'beds', shape:'bedSingle', rot:true,
env:3, sleep:true, interactions:[
{ id:'sleep', label:'Sleep', icon:'😴', special:'sleep', pose:'lie' },
{ id:'nap', label:'Nap 2h', icon:'💤', special:'sleep', nap:true, pose:'lie' }] },
bedDouble: { id:'bedDouble', name:'Double Bed', emoji:'🛌', price:900, w:2, h:2, cat:'beds', shape:'bedDouble', rot:true,
env:5, sleep:true, love:true, interactions:[
{ id:'sleep', label:'Sleep', icon:'😴', special:'sleep', pose:'lie' },
{ id:'nap', label:'Nap 2h', icon:'💤', special:'sleep', nap:true, pose:'lie' },
{ id:'tryBaby', label:'Try for Baby', icon:'👶', special:'tryBaby', pose:'lie', dur:25 }] },
/* --- plumbing --- */
toilet: { id:'toilet', name:'Toilet', emoji:'🚽', price:300, w:1, h:1, cat:'bath', shape:'toilet', rot:true, env:-2,
interactions:[
{ id:'pee', label:'Use Toilet', icon:'🚽', dur:10, fx:{bladder:9}, pose:'sit' },
{ id:'clean',label:'Clean Toilet', icon:'🧽', special:'clean', requiresDirty:true }] },
shower: { id:'shower', name:'Shower', emoji:'🚿', price:500, w:1, h:1, cat:'bath', shape:'shower', rot:true, env:1,
interactions:[{ id:'shower', label:'Take Shower', icon:'🚿', dur:22, fx:{hygiene:4.4, fun:.15, energy:.05}, pose:'stand' }] },
bathtub:{ id:'bathtub', name:'Bathtub', emoji:'🛁', price:600, w:1, h:2, cat:'bath', shape:'bathtub', rot:true, env:3,
interactions:[{ id:'bathe', label:'Take Bath', icon:'🛁', dur:40, fx:{hygiene:2.4, comfort:.5, fun:.3}, pose:'lie' }] },
sink: { id:'sink', name:'Sink', emoji:'🚰', price:150, w:1, h:1, cat:'bath', shape:'sink', rot:true, env:1,
interactions:[{ id:'wash', label:'Wash Up', icon:'🧼', dur:5, fx:{hygiene:3.5}, pose:'stand' }] },
mirror: { id:'mirror', name:'Wall Mirror', emoji:'🪞', price:175, w:1, h:1, cat:'bath', shape:'mirror', wallObj:true, rot:true, env:2,
interactions:[{ id:'practice', label:'Practice Charisma', icon:'💬', dur:60, fx:{social:.1, fun:.08}, skill:{id:'charisma', rate:.028}, pose:'stand' }] },
/* --- kitchen --- */
fridge: { id:'fridge', name:'Fridge', emoji:'🧊', price:600, w:1, h:1, cat:'kitchen', shape:'fridge', rot:true, env:1,
interactions:[
{ id:'meal', label:'Have a Meal', icon:'🍲', special:'cookMeal', pose:'stand' },
{ id:'snack', label:'Grab a Snack', icon:'🍎', dur:8, fx:{hunger:2.6}, pose:'stand' },
{ id:'groceries', label:'Order Groceries (§60)', icon:'🛍️', special:'groceries', cost:60, pose:'stand' }] },
stove: { id:'stove', name:'Stove', emoji:'🔥', price:500, w:1, h:1, cat:'kitchen', shape:'stove', rot:true, env:1, interactions:[] },
counter:{ id:'counter', name:'Counter', emoji:'🧾', price:140, w:1, h:1, cat:'kitchen', shape:'counter', rot:true, env:1, prepTarget:true, interactions:[] },
trash: { id:'trash', name:'Trash Can', emoji:'🗑️', price:60, w:1, h:1, cat:'kitchen', shape:'trash', rot:true, env:-3,
interactions:[{ id:'empty', label:'Empty Trash', icon:'🗑️', special:'emptyTrash', requiresFull:true }] },
/* --- electronics --- */
tv: { id:'tv', name:'Television', emoji:'📺', price:800, w:2, h:1, cat:'electronics', shape:'tv', rot:true, env:3, fragile:.0035,
watchTarget:true, interactions:[{ id:'watch', label:'Watch TV', icon:'📺', dur:90, fx:{fun:.55, comfort:.06, social:.04}, pose:'sitOrStand' }] },
stereo: { id:'stereo', name:'Stereo', emoji:'🔊', price:550, w:1, h:1, cat:'electronics', shape:'stereo', rot:true, env:2, fragile:.0025,
interactions:[{ id:'dance', label:'Dance!', icon:'💃', dur:45, fx:{fun:.75, social:.05}, skill:{id:'body', rate:.006}, pose:'stand', anim:'dance' }] },
computer:{ id:'computer', name:'Computer', emoji:'🖥️', price:2100, w:1, h:1, cat:'electronics', shape:'computer', rot:true, env:2, fragile:.0018,
interactions:[
{ id:'findJob', label:'Find a Job…', icon:'📰', special:'findJob', pose:'sit' },
{ id:'games', label:'Play Games', icon:'🎮', dur:60, fx:{fun:.65}, skill:{id:'logic', rate:.008}, pose:'sit' },
{ id:'write', label:'Write Novel', icon:'✍️', special:'writeNovel', pose:'sit', dur:90 }] },
phone: { id:'phone', name:'Telephone', emoji:'☎️', price:90, w:1, h:1, cat:'electronics', shape:'phone', rot:true, env:0,
interactions:[
{ id:'chatPhone', label:'Chat With Friend', icon:'📞', dur:30, fx:{social:1.4, fun:.15}, pose:'stand' },
{ id:'invite', label:'Invite Neighbor Over', icon:'👋', special:'inviteOver', pose:'stand' },
{ id:'party', label:'Throw Party Tonight 🎉', icon:'🥳', special:'throwParty', pose:'stand' },
{ id:'orderPizza',label:'Order Pizza (§40)', icon:'🍕', special:'pizza', cost:40, pose:'stand' }] },
/* --- skill / fun objects --- */
bookshelf:{ id:'bookshelf', name:'Bookshelf', emoji:'📚', price:250, w:1, h:1, cat:'study', shape:'bookshelf', rot:true, env:3,
interactions:[
{ id:'readLogic', label:'Study Logic', icon:'🧠', dur:60, fx:{fun:.05, energy:.02}, skill:{id:'logic', rate:.03}, pose:'stand' },
{ id:'readCook', label:'Study Cooking', icon:'🍳', dur:60, fx:{fun:.08}, skill:{id:'cooking', rate:.03}, pose:'stand' },
{ id:'readMech', label:'Study Mechanical', icon:'🔧', dur:60, fx:{fun:.05}, skill:{id:'mechanical', rate:.03}, pose:'stand' },
{ id:'readFun', label:'Read for Fun', icon:'📖', dur:60, fx:{fun:.55}, pose:'stand' }] },
easel: { id:'easel', name:'Easel', emoji:'🖼️', price:350, w:1, h:1, cat:'study', shape:'easel', rot:true, env:2,
interactions:[
{ id:'paint', label:'Paint', icon:'🎨', dur:90, fx:{fun:.4, energy:-.05}, skill:{id:'creativity', rate:.033}, special:'paint', pose:'stand' }] },
treadmill:{ id:'treadmill', name:'Treadmill', emoji:'🏃', price:1200, w:1, h:1, cat:'study', shape:'treadmill', rot:true, env:1, fragile:.0022,
interactions:[{ id:'workout', label:'Work Out', icon:'💪', dur:60, fx:{fun:-.05, hygiene:-.35, energy:-.12}, skill:{id:'body', rate:.033}, pose:'stand', anim:'exercise' }] },
piano: { id:'piano', name:'Piano', emoji:'🎹', price:1300, w:2, h:1, cat:'study', shape:'piano', rot:true, env:4,
interactions:[{ id:'playPiano', label:'Play Piano', icon:'🎹', dur:60, fx:{fun:.45, social:.05}, skill:{id:'creativity', rate:.026}, pose:'sit' }] },
chessboard: { id:'chessboard', name:'Chess Table', emoji:'♟️', price:450, w:1, h:1, cat:'study', shape:'chessboard', rot:true, env:3,
interactions:[
{ id:'chess', label:'Play Chess', icon:'♟️', dur:60, fx:{fun:.4, logic:.0}, skill:{id:'logic', rate:.028}, pose:'sit' }] },
/* --- decor --- */
plant: { id:'plant', name:'Potted Plant', emoji:'🪴', price:120, w:1, h:1, cat:'decor', shape:'plant', rot:false, env:4 },
lamp: { id:'lamp', name:'Floor Lamp', emoji:'💡', price:75, w:1, h:1, cat:'decor', shape:'lamp', rot:false, env:2, light:70 },
painting:{ id:'painting', name:'Painting', emoji:'🏞️', price:200, w:1, h:1, cat:'decor', shape:'painting', wallObj:true, rot:true, env:5 },
fountain:{ id:'fountain', name:'Fountain', emoji:'⛲', price:2500, w:2, h:2, cat:'decor', shape:'fountain', rot:false, env:8, light:40 },
easel: { id:'easel', name:'Easel', emoji:'🎨', price:450, w:1, h:1, cat:'decor', shape:'easel', rot:true, env:4,
interactions:[
{ id:'paint', label:'Paint a Canvas', icon:'🖌️', special:'paint', pose:'stand', dur:90 },
{ id:'sellArt', label:'Sell Paintings', icon:'💵', special:'sellArt', pose:'stand', dur:10 }] },
gravestone:{ id:'gravestone', name:'Gravestone', emoji:'🪦', price:0, w:1, h:1, cat:'hidden', shape:'gravestone', rot:false, env:-6 },
crib: { id:'crib', name:'Crib', emoji:'🧸', price:350, w:1, h:1, cat:'kids', shape:'crib', rot:true, env:3, sleep:true,
interactions:[
{ id:'sleep', label:'Baby Nap', icon:'😴', special:'sleep', nap:true, pose:'lie', babyOnly:true }] },
toybox: { id:'toybox', name:'Toy Box', emoji:'🪀', price:180, w:1, h:1, cat:'kids', shape:'toybox', rot:false, env:4,
interactions:[{ id:'playToys', label:'Play with Toys', icon:'🧸', dur:45, fx:{fun:.7}, pose:'stand', childOnly:true }] },
};
/* ---------------- BUY CATEGORIES ---------------- */
const BUY_CATS = [
{ id:'seating', label:'Seating', icon:'🛋️' },
{ id:'tables', label:'Tables', icon:'🍽️' },
{ id:'beds', label:'Beds', icon:'🛏️' },
{ id:'bath', label:'Bathroom', icon:'🚿' },
{ id:'kitchen', label:'Kitchen', icon:'🍳' },
{ id:'electronics', label:'Electronics', icon:'📺' },
{ id:'study', label:'Skill & Fun', icon:'📚' },
{ id:'decor', label:'Decor', icon:'🪴' },
{ id:'kids', label:'Kids', icon:'🧸' },
];
/* ---------------- FLOOR STYLES & WALL STYLES ---------------- */
const FLOORS = [
{ id:'grass', c1:'#69a84f', c2:'#5f9c47', outdoor:true },
{ id:'wood', c1:'#b98a52', c2:'#a87b46' },
{ id:'tile', c1:'#dfe6ea', c2:'#cdd6dc' },
{ id:'carpet', c1:'#b0576a', c2:'#a34e60' },
{ id:'stone', c1:'#9aa2ab', c2:'#8b939c' },
{ id:'darkwood', c1:'#7a5636', c2:'#6c4a2e' },
];
const WALL_COLORS = ['#efe6d4','#d9cdb8','#bcd3e8','#d8bfcf','#c9dfc0','#e8d2a4','#b9aabf'];