A dark, mysterious five-act ARG built around hidden archives and forgotten witnesses.

Viewing files at commit a02fe2fc8753Commit detailsView latest

assets/js/state.js 177 lines · 4.7 KB · javascript
1
// Game state management system
2
3
const GameState = {
4
  // Core progression
5
  currentAct: 0,
6
  currentPage: 'landing',
7
  completedActs: new Set(),
8
  
9
  // Player inventory
10
  inventory: {
11
    items: new Map(),
12
    totalItems: 0
13
  },
14
  
15
  // Evidence collected
16
  evidence: {
17
    documents: new Map(),
18
    audioLogs: new Map(),
19
    photographs: new Map(),
20
    connections: [] // Links between evidence pieces
21
  },
22
  
23
  // Decrypted messages
24
  decrypted: new Map(),
25
  
26
  // Puzzles solved
27
  solvedPuzzles: new Set(),
28
  attemptedPuzzles: new Map(), // Track wrong answers
29
  
30
  // Discovered locations/sections
31
  unlockedSections: new Set(['landing', 'act1']),
32
  discoveredSecrets: new Set(),
33
  
34
  // Time tracking
35
  startTime: null,
36
  sessionTime: 0,
37
  
38
  // Endings discovered
39
  endingsFound: new Set(),
40
  
41
  // Initialize state from localStorage
42
  init() {
43
    const saved = localStorage.getItem('hollow-archive-state');
44
    if (saved) {
45
      try {
46
        const data = JSON.parse(saved);
47
        Object.assign(this, data);
48
        this.completedActs = new Set(data.completedActs || []);
49
        this.solvedPuzzles = new Set(data.solvedPuzzles || []);
50
        this.unlockedSections = new Set(data.unlockedSections || ['landing', 'act1']);
51
        this.discoveredSecrets = new Set(data.discoveredSecrets || []);
52
        this.endingsFound = new Set(data.endingsFound || []);
53
        this.inventory.items = new Map(data.inventory?.items || []);
54
        this.evidence.documents = new Map(data.evidence?.documents || []);
55
        this.evidence.audioLogs = new Map(data.evidence?.audioLogs || []);
56
        this.evidence.photographs = new Map(data.evidence?.photographs || []);
57
        this.decrypted = new Map(data.decrypted || []);
58
      } catch (e) {
59
        console.warn('Failed to load saved state:', e);
60
      }
61
    }
62
    this.startTime = this.startTime || Date.now();
63
  },
64
  
65
  // Save state to localStorage
66
  save() {
67
    const data = {
68
      currentAct: this.currentAct,
69
      currentPage: this.currentPage,
70
      completedActs: Array.from(this.completedActs),
71
      solvedPuzzles: Array.from(this.solvedPuzzles),
72
      unlockedSections: Array.from(this.unlockedSections),
73
      discoveredSecrets: Array.from(this.discoveredSecrets),
74
      endingsFound: Array.from(this.endingsFound),
75
      inventory: {
76
        items: Array.from(this.inventory.items),
77
        totalItems: this.inventory.totalItems
78
      },
79
      evidence: {
80
        documents: Array.from(this.evidence.documents),
81
        audioLogs: Array.from(this.evidence.audioLogs),
82
        photographs: Array.from(this.evidence.photographs),
83
        connections: this.evidence.connections
84
      },
85
      decrypted: Array.from(this.decrypted),
86
      startTime: this.startTime
87
    };
88
    localStorage.setItem('hollow-archive-state', JSON.stringify(data));
89
  },
90
  
91
  // Add item to inventory
92
  addItem(id, item) {
93
    this.inventory.items.set(id, {
94
      ...item,
95
      acquiredAt: Date.now()
96
    });
97
    this.inventory.totalItems++;
98
    this.save();
99
  },
100
  
101
  // Add evidence
102
  addEvidence(id, evidence, type = 'documents') {
103
    this.evidence[type].set(id, {
104
      ...evidence,
105
      discoveredAt: Date.now()
106
    });
107
    this.save();
108
  },
109
  
110
  // Link evidence together
111
  linkEvidence(id1, id2, description) {
112
    this.evidence.connections.push({
113
      id1, id2, description,
114
      linkedAt: Date.now()
115
    });
116
    this.save();
117
  },
118
  
119
  // Mark puzzle as solved
120
  solvePuzzle(puzzleId) {
121
    this.solvedPuzzles.add(puzzleId);
122
    this.save();
123
  },
124
  
125
  // Record wrong attempt
126
  recordAttempt(puzzleId, answer) {
127
    if (!this.attemptedPuzzles.has(puzzleId)) {
128
      this.attemptedPuzzles.set(puzzleId, []);
129
    }
130
    this.attemptedPuzzles.get(puzzleId).push({
131
      answer,
132
      timestamp: Date.now()
133
    });
134
  },
135
  
136
  // Unlock new section
137
  unlockSection(sectionId) {
138
    this.unlockedSections.add(sectionId);
139
    this.save();
140
  },
141
  
142
  // Discover secret
143
  discoverSecret(secretId) {
144
    this.discoveredSecrets.add(secretId);
145
    this.save();
146
  },
147
  
148
  // Record ending
149
  recordEnding(endingId) {
150
    this.endingsFound.add(endingId);
151
    this.save();
152
  },
153
  
154
  // Get game completion percentage
155
  getCompletion() {
156
    const maxActs = 5;
157
    const maxSecrets = 12;
158
    const maxEndings = 3;
159
    const totalMax = maxActs + maxSecrets + maxEndings;
160
    
161
    const currentTotal = this.completedActs.size + this.discoveredSecrets.size + this.endingsFound.size;
162
    return Math.round((currentTotal / totalMax) * 100);
163
  },
164
  
165
  // Reset game
166
  reset() {
167
    if (confirm('Reset all progress? This cannot be undone.')) {
168
      localStorage.removeItem('hollow-archive-state');
169
      location.reload();
170
    }
171
  }
172
};
173
174
// Initialize on load
175
document.addEventListener('DOMContentLoaded', () => {
176
  GameState.init();
177
});