ok
This commit is contained in:
454
DEBUG_TOTAL_RECOVERY/NPCPrivacySystem.js
Normal file
454
DEBUG_TOTAL_RECOVERY/NPCPrivacySystem.js
Normal file
@@ -0,0 +1,454 @@
|
||||
/**
|
||||
* NPC PRIVACY & HOME DECORATION SYSTEM
|
||||
* Part of: Game Systems Expansion
|
||||
* Created: January 4, 2026
|
||||
*
|
||||
* Features:
|
||||
* - Hobby-based automatic interior generation
|
||||
* - Door lock system (heart-based access)
|
||||
* - NPC home visit mechanics
|
||||
* - Relationship effects from visits
|
||||
* - Privacy violations & consequences
|
||||
*/
|
||||
|
||||
class NPCPrivacySystem {
|
||||
constructor(game) {
|
||||
this.game = game;
|
||||
this.player = game.player;
|
||||
|
||||
// Privacy settings
|
||||
this.privacyLevels = {
|
||||
PUBLIC: 0, // Anyone can enter (living room, kitchen)
|
||||
FRIENDLY: 3, // 3+ hearts required
|
||||
PRIVATE: 5, // 5+ hearts required (bedroom)
|
||||
INTIMATE: 8, // 8+ hearts required (special rooms)
|
||||
LOCKED: 10 // 10 hearts or marriage required
|
||||
};
|
||||
|
||||
// Visit tracking
|
||||
this.visitHistory = {};
|
||||
this.lastVisitTimes = {};
|
||||
|
||||
// NPC home decorations (generated based on hobby)
|
||||
this.npcHomes = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate NPC home interior based on hobby
|
||||
*/
|
||||
generateNPCHome(npcId) {
|
||||
const npc = this.game.npcs.get(npcId);
|
||||
if (!npc) return null;
|
||||
|
||||
const hobby = npc.hobby;
|
||||
|
||||
// Base home structure
|
||||
const home = {
|
||||
npcId: npcId,
|
||||
rooms: {
|
||||
living_room: {
|
||||
name: 'Living Room',
|
||||
privacyLevel: this.privacyLevels.PUBLIC,
|
||||
objects: this.generateLivingRoomObjects(hobby)
|
||||
},
|
||||
kitchen: {
|
||||
name: 'Kitchen',
|
||||
privacyLevel: this.privacyLevels.PUBLIC,
|
||||
objects: this.generateKitchenObjects(hobby)
|
||||
},
|
||||
bedroom: {
|
||||
name: 'Bedroom',
|
||||
privacyLevel: this.privacyLevels.PRIVATE,
|
||||
objects: this.generateBedroomObjects(hobby)
|
||||
},
|
||||
hobby_room: {
|
||||
name: this.getHobbyRoomName(hobby),
|
||||
privacyLevel: this.privacyLevels.FRIENDLY,
|
||||
objects: this.generateHobbyRoomObjects(hobby)
|
||||
}
|
||||
},
|
||||
visitCount: 0,
|
||||
lastVisit: null
|
||||
};
|
||||
|
||||
// Store home
|
||||
this.npcHomes[npcId] = home;
|
||||
|
||||
return home;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate living room objects
|
||||
*/
|
||||
generateLivingRoomObjects(hobby) {
|
||||
const base = [
|
||||
'interior_table_small',
|
||||
'interior_bookshelf',
|
||||
'interior_gothic_lantern'
|
||||
];
|
||||
|
||||
// Hobby-specific additions
|
||||
const hobbyAdditions = {
|
||||
fishing: ['mounted_fish', 'fishing_net'],
|
||||
farming: ['grain_sack', 'tool_rack'],
|
||||
cooking: ['recipe_shelf'],
|
||||
reading: ['bookshelf', 'reading_chair'],
|
||||
music: ['guitar_stand', 'music_sheets'],
|
||||
crafting: ['crafting_workshop']
|
||||
};
|
||||
|
||||
return [...base, ...(hobbyAdditions[hobby] || [])];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate kitchen objects
|
||||
*/
|
||||
generateKitchenObjects(hobby) {
|
||||
const base = [
|
||||
'interior_kitchen_stove',
|
||||
'interior_kitchen_counter'
|
||||
];
|
||||
|
||||
if (hobby === 'cooking') {
|
||||
base.push(
|
||||
'interior_kitchen_fridge',
|
||||
'interior_kitchen_sink',
|
||||
'interior_recipe_shelf'
|
||||
);
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate bedroom objects
|
||||
*/
|
||||
generateBedroomObjects(hobby) {
|
||||
const base = [
|
||||
'interior_bed_wooden',
|
||||
'interior_wardrobe',
|
||||
'interior_chest_locked'
|
||||
];
|
||||
|
||||
// Personal items based on hobby
|
||||
const hobbyItems = {
|
||||
zombie_worker: ['brain_jar', 'work_uniform'],
|
||||
baker: ['flour_workspace', 'dough_tools'],
|
||||
barber: ['dreadlock_kit', 'styling_tools'],
|
||||
fisherman: ['tackle_box', 'fish_collection']
|
||||
};
|
||||
|
||||
return [...base, ...(hobbyItems[hobby] || [])];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate hobby room objects
|
||||
*/
|
||||
generateHobbyRoomObjects(hobby) {
|
||||
const hobbyRooms = {
|
||||
fishing: [
|
||||
'fishing_rod_rack',
|
||||
'bait_storage',
|
||||
'fish_tank',
|
||||
'mounted_trophy_fish'
|
||||
],
|
||||
zombie_worker: [
|
||||
'brain_jar',
|
||||
'work_bench',
|
||||
'tool_storage',
|
||||
'miner_equipment'
|
||||
],
|
||||
baker: [
|
||||
'flour_workspace',
|
||||
'mixing_bowls',
|
||||
'bread_storage',
|
||||
'recipe_collection'
|
||||
],
|
||||
alchemy: [
|
||||
'interior_alchemy_bottle',
|
||||
'interior_brewing_cauldron',
|
||||
'interior_chemistry_set',
|
||||
'interior_potion_shelf'
|
||||
],
|
||||
crafting: [
|
||||
'interior_crafting_workshop',
|
||||
'interior_tool_rack',
|
||||
'material_storage',
|
||||
'blueprint_table'
|
||||
],
|
||||
reading: [
|
||||
'interior_bookshelf',
|
||||
'reading_chair',
|
||||
'ancient_manuscripts',
|
||||
'writing_desk'
|
||||
]
|
||||
};
|
||||
|
||||
return hobbyRooms[hobby] || ['generic_workspace'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get hobby room name
|
||||
*/
|
||||
getHobbyRoomName(hobby) {
|
||||
const names = {
|
||||
fishing: 'Fishing Den',
|
||||
zombie_worker: 'Worker\'s Quarters',
|
||||
baker: 'Baking Workshop',
|
||||
alchemy: 'Alchemy Lab',
|
||||
crafting: 'Craft Room',
|
||||
reading: 'Library',
|
||||
music: 'Music Studio',
|
||||
farming: 'Storage Shed'
|
||||
};
|
||||
|
||||
return names[hobby] || 'Hobby Room';
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to enter NPC room
|
||||
*/
|
||||
attemptEntry(npcId, roomId) {
|
||||
const npc = this.game.npcs.get(npcId);
|
||||
if (!npc) {
|
||||
return { success: false, message: 'NPC not found!' };
|
||||
}
|
||||
|
||||
// Generate home if doesn't exist
|
||||
if (!this.npcHomes[npcId]) {
|
||||
this.generateNPCHome(npcId);
|
||||
}
|
||||
|
||||
const home = this.npcHomes[npcId];
|
||||
const room = home.rooms[roomId];
|
||||
|
||||
if (!room) {
|
||||
return { success: false, message: 'Room not found!' };
|
||||
}
|
||||
|
||||
// Check privacy level
|
||||
const playerHearts = this.player.getRelationshipHearts(npcId);
|
||||
const requiredHearts = room.privacyLevel;
|
||||
|
||||
if (playerHearts < requiredHearts) {
|
||||
// Privacy violation!
|
||||
return this.handlePrivacyViolation(npcId, roomId, requiredHearts);
|
||||
}
|
||||
|
||||
// Allowed entry
|
||||
return this.handleSuccessfulEntry(npcId, roomId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle privacy violation
|
||||
*/
|
||||
handlePrivacyViolation(npcId, roomId, requiredHearts) {
|
||||
const npc = this.game.npcs.get(npcId);
|
||||
|
||||
// Relationship penalty
|
||||
const penalty = (requiredHearts - this.player.getRelationshipHearts(npcId)) * 20;
|
||||
npc.addRelationshipPoints(-penalty);
|
||||
|
||||
// NPC reaction
|
||||
const reactions = [
|
||||
"Hey! That's private!",
|
||||
"What are you doing in my room?!",
|
||||
"Get out! This is MY space!",
|
||||
"I can't believe you just walked in here...",
|
||||
"Privacy, please!"
|
||||
];
|
||||
|
||||
const reaction = Phaser.Utils.Array.GetRandom(reactions);
|
||||
|
||||
this.game.showDialogue(npc.name, reaction, {
|
||||
mood: 'angry',
|
||||
animation: 'shocked'
|
||||
});
|
||||
|
||||
this.game.showMessage(
|
||||
`${npc.name} is upset! -${penalty} relationship points`
|
||||
);
|
||||
|
||||
// Player gets kicked out
|
||||
this.game.player.teleportToLocation('outside_' + npcId + '_home');
|
||||
|
||||
return {
|
||||
success: false,
|
||||
privacyViolation: true,
|
||||
penalty: penalty,
|
||||
requiredHearts: requiredHearts,
|
||||
currentHearts: this.player.getRelationshipHearts(npcId)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle successful entry
|
||||
*/
|
||||
handleSuccessfulEntry(npcId, roomId) {
|
||||
const npc = this.game.npcs.get(npcId);
|
||||
const home = this.npcHomes[npcId];
|
||||
|
||||
// Track visit
|
||||
if (!this.visitHistory[npcId]) {
|
||||
this.visitHistory[npcId] = [];
|
||||
}
|
||||
|
||||
const visit = {
|
||||
roomId: roomId,
|
||||
timestamp: this.game.time.currentTime,
|
||||
timeOfDay: this.game.time.getTimeOfDay()
|
||||
};
|
||||
|
||||
this.visitHistory[npcId].push(visit);
|
||||
this.lastVisitTimes[npcId] = this.game.time.currentTime;
|
||||
|
||||
home.visitCount++;
|
||||
home.lastVisit = this.game.time.currentTime;
|
||||
|
||||
// Relationship effects based on visit
|
||||
this.applyVisitEffects(npcId, roomId, visit);
|
||||
|
||||
// Enter room scene
|
||||
this.game.scene.start('NPCRoomScene', {
|
||||
npcId: npcId,
|
||||
roomId: roomId,
|
||||
room: home.rooms[roomId]
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
room: home.rooms[roomId],
|
||||
npc: npc
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply relationship effects from visit
|
||||
*/
|
||||
applyVisitEffects(npcId, roomId, visit) {
|
||||
const npc = this.game.npcs.get(npcId);
|
||||
const timeOfDay = visit.timeOfDay;
|
||||
|
||||
// Visit frequency check
|
||||
const recentVisits = this.visitHistory[npcId].filter(v => {
|
||||
const hoursSince = (this.game.time.currentTime - v.timestamp) / 3600;
|
||||
return hoursSince < 24; // Last 24 hours
|
||||
});
|
||||
|
||||
if (recentVisits.length > 3) {
|
||||
// Visiting TOO much = annoying
|
||||
npc.addRelationshipPoints(-10);
|
||||
this.game.showMessage(
|
||||
`${npc.name} seems a bit annoyed by frequent visits...`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Time of day effects
|
||||
if (timeOfDay === 'night' && roomId === 'bedroom') {
|
||||
// Visiting bedroom at night = awkward
|
||||
npc.addRelationshipPoints(-5);
|
||||
this.game.showDialogue(
|
||||
npc.name,
|
||||
"It's quite late... Is everything okay?",
|
||||
{ mood: 'concerned' }
|
||||
);
|
||||
} else if (timeOfDay === 'morning' && roomId === 'kitchen') {
|
||||
// Morning kitchen visit = breakfast together!
|
||||
npc.addRelationshipPoints(5);
|
||||
this.game.showDialogue(
|
||||
npc.name,
|
||||
"Good morning! Care to join me for breakfast?",
|
||||
{ mood: 'happy' }
|
||||
);
|
||||
} else if (roomId === 'hobby_room') {
|
||||
// Showing interest in hobby = bonus points!
|
||||
npc.addRelationshipPoints(10);
|
||||
this.game.showDialogue(
|
||||
npc.name,
|
||||
"I'm glad you're interested in my hobby!",
|
||||
{ mood: 'excited' }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get visit statistics for NPC
|
||||
*/
|
||||
getVisitStats(npcId) {
|
||||
const visits = this.visitHistory[npcId] || [];
|
||||
|
||||
// Count visits per room
|
||||
const roomCounts = {};
|
||||
visits.forEach(visit => {
|
||||
roomCounts[visit.roomId] = (roomCounts[visit.roomId] || 0) + 1;
|
||||
});
|
||||
|
||||
// Average visits per day
|
||||
const daysSinceFirstVisit = visits.length > 0
|
||||
? (this.game.time.currentTime - visits[0].timestamp) / 86400
|
||||
: 0;
|
||||
|
||||
const avgVisitsPerDay = daysSinceFirstVisit > 0
|
||||
? visits.length / daysSinceFirstVisit
|
||||
: 0;
|
||||
|
||||
return {
|
||||
totalVisits: visits.length,
|
||||
roomCounts: roomCounts,
|
||||
avgVisitsPerDay: avgVisitsPerDay,
|
||||
lastVisit: this.lastVisitTimes[npcId],
|
||||
favoriteRoom: Object.keys(roomCounts).reduce((a, b) =>
|
||||
roomCounts[a] > roomCounts[b] ? a : b, null)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if player can access special room
|
||||
*/
|
||||
canAccessSpecialRoom(npcId, roomId) {
|
||||
const npc = this.game.npcs.get(npcId);
|
||||
if (!npc) return false;
|
||||
|
||||
const home = this.npcHomes[npcId];
|
||||
if (!home) return false;
|
||||
|
||||
const room = home.rooms[roomId];
|
||||
if (!room) return false;
|
||||
|
||||
const playerHearts = this.player.getRelationshipHearts(npcId);
|
||||
|
||||
// Special case: marriage allows LOCKED access
|
||||
if (room.privacyLevel === this.privacyLevels.LOCKED) {
|
||||
return this.player.spouse === npcId;
|
||||
}
|
||||
|
||||
return playerHearts >= room.privacyLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get NPC home UI data
|
||||
*/
|
||||
getNPCHomeUIData(npcId) {
|
||||
if (!this.npcHomes[npcId]) {
|
||||
this.generateNPCHome(npcId);
|
||||
}
|
||||
|
||||
const home = this.npcHomes[npcId];
|
||||
const npc = this.game.npcs.get(npcId);
|
||||
|
||||
return {
|
||||
npc: npc,
|
||||
home: home,
|
||||
accessibleRooms: Object.keys(home.rooms).filter(roomId =>
|
||||
this.canAccessSpecialRoom(npcId, roomId)
|
||||
),
|
||||
lockedRooms: Object.keys(home.rooms).filter(roomId =>
|
||||
!this.canAccessSpecialRoom(npcId, roomId)
|
||||
),
|
||||
visitStats: this.getVisitStats(npcId)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user