JavaScript · 8181 bytes Raw Blame History
1 // Item catalog for dougk shop
2 // Defines all purchasable outfits and buildings
3
4 import * as THREE from 'three'
5
6 // Outfit types
7 export const OUTFIT_TYPES = {
8 COLOR_BODY: 'color_body',
9 COLOR_ACCENT: 'color_accent',
10 ACCESSORY_HEAD: 'accessory_head',
11 ACCESSORY_FACE: 'accessory_face',
12 ACCESSORY_HELD: 'accessory_held'
13 }
14
15 // Character IDs
16 export const CHARACTERS = {
17 DOUG: 'doug',
18 DONNY: 'donny',
19 OLLIE: 'ollie'
20 }
21
22 // Outfit definitions
23 export const OUTFITS = {
24 // Doug outfits - starter tier (cheap)
25 doug_mint: {
26 id: 'doug_mint',
27 name: 'Mint Fresh',
28 character: CHARACTERS.DOUG,
29 type: OUTFIT_TYPES.COLOR_BODY,
30 price: 5,
31 colors: { body: 0x98fb98, highlight: 0xb0ffb0 }
32 },
33 doug_bubblegum: {
34 id: 'doug_bubblegum',
35 name: 'Bubblegum',
36 character: CHARACTERS.DOUG,
37 type: OUTFIT_TYPES.COLOR_BODY,
38 price: 5,
39 colors: { body: 0xffb6c1, highlight: 0xffd1dc }
40 },
41 // Doug outfits - mid tier
42 doug_golden: {
43 id: 'doug_golden',
44 name: 'Golden Glow',
45 character: CHARACTERS.DOUG,
46 type: OUTFIT_TYPES.COLOR_BODY,
47 price: 12,
48 colors: { body: 0xffd700, highlight: 0xffec8b }
49 },
50 doug_sunset: {
51 id: 'doug_sunset',
52 name: 'Sunset Orange',
53 character: CHARACTERS.DOUG,
54 type: OUTFIT_TYPES.COLOR_BODY,
55 price: 12,
56 colors: { body: 0xff6b35, highlight: 0xffa07a }
57 },
58 doug_tophat: {
59 id: 'doug_tophat',
60 name: 'Top Hat',
61 character: CHARACTERS.DOUG,
62 type: OUTFIT_TYPES.ACCESSORY_HEAD,
63 price: 25,
64 meshFactory: (gradientMap) => {
65 const group = new THREE.Group()
66 const material = new THREE.MeshToonMaterial({ color: 0x1a1a1a, gradientMap })
67
68 // Hat brim
69 const brimGeom = new THREE.CylinderGeometry(0.25, 0.25, 0.03, 12)
70 const brim = new THREE.Mesh(brimGeom, material)
71 group.add(brim)
72
73 // Hat top
74 const topGeom = new THREE.CylinderGeometry(0.15, 0.15, 0.25, 12)
75 const top = new THREE.Mesh(topGeom, material)
76 top.position.y = 0.14
77 group.add(top)
78
79 // Hat band
80 const bandMat = new THREE.MeshToonMaterial({ color: 0x8b0000, gradientMap })
81 const bandGeom = new THREE.CylinderGeometry(0.155, 0.155, 0.04, 12)
82 const band = new THREE.Mesh(bandGeom, bandMat)
83 band.position.y = 0.04
84 group.add(band)
85
86 return group
87 }
88 },
89 doug_shades: {
90 id: 'doug_shades',
91 name: 'Cool Shades',
92 character: CHARACTERS.DOUG,
93 type: OUTFIT_TYPES.ACCESSORY_FACE,
94 price: 20,
95 meshFactory: (gradientMap) => {
96 const group = new THREE.Group()
97 const frameMat = new THREE.MeshToonMaterial({ color: 0x1a1a1a, gradientMap })
98 const lensMat = new THREE.MeshBasicMaterial({ color: 0x222222, transparent: true, opacity: 0.7 })
99
100 // Left lens
101 const lensGeom = new THREE.CircleGeometry(0.08, 8)
102 const leftLens = new THREE.Mesh(lensGeom, lensMat)
103 leftLens.position.set(-0.1, 0, 0.01)
104 group.add(leftLens)
105
106 // Right lens
107 const rightLens = new THREE.Mesh(lensGeom, lensMat)
108 rightLens.position.set(0.1, 0, 0.01)
109 group.add(rightLens)
110
111 // Bridge
112 const bridgeGeom = new THREE.BoxGeometry(0.06, 0.02, 0.02)
113 const bridge = new THREE.Mesh(bridgeGeom, frameMat)
114 group.add(bridge)
115
116 // Frames
117 const frameGeom = new THREE.TorusGeometry(0.08, 0.01, 4, 12)
118 const leftFrame = new THREE.Mesh(frameGeom, frameMat)
119 leftFrame.position.set(-0.1, 0, 0)
120 group.add(leftFrame)
121
122 const rightFrame = new THREE.Mesh(frameGeom, frameMat)
123 rightFrame.position.set(0.1, 0, 0)
124 group.add(rightFrame)
125
126 return group
127 }
128 },
129
130 // Donny outfits - starter tier
131 donny_seafoam: {
132 id: 'donny_seafoam',
133 name: 'Seafoam',
134 character: CHARACTERS.DONNY,
135 type: OUTFIT_TYPES.COLOR_BODY,
136 price: 8,
137 colors: { body: 0x5f9ea0, belly: 0x98d8d8 }
138 },
139 // Donny outfits - mid tier
140 donny_royal: {
141 id: 'donny_royal',
142 name: 'Royal Purple',
143 character: CHARACTERS.DONNY,
144 type: OUTFIT_TYPES.COLOR_BODY,
145 price: 15,
146 colors: { body: 0x6b3fa0, belly: 0x9b7bc0 }
147 },
148 donny_arctic: {
149 id: 'donny_arctic',
150 name: 'Arctic White',
151 character: CHARACTERS.DONNY,
152 type: OUTFIT_TYPES.COLOR_BODY,
153 price: 18,
154 colors: { body: 0xe8e8e8, belly: 0xffffff }
155 },
156 donny_ruby_monocle: {
157 id: 'donny_ruby_monocle',
158 name: 'Ruby Monocle',
159 character: CHARACTERS.DONNY,
160 type: OUTFIT_TYPES.ACCESSORY_FACE,
161 price: 25,
162 colors: { rim: 0xb22222, glass: 0xff6666 }
163 },
164 donny_bowler: {
165 id: 'donny_bowler',
166 name: 'Bowler Hat',
167 character: CHARACTERS.DONNY,
168 type: OUTFIT_TYPES.ACCESSORY_HEAD,
169 price: 25,
170 meshFactory: (gradientMap) => {
171 const group = new THREE.Group()
172 const material = new THREE.MeshToonMaterial({ color: 0x2f2f2f, gradientMap })
173
174 // Hat dome
175 const domeGeom = new THREE.SphereGeometry(0.15, 12, 8, 0, Math.PI * 2, 0, Math.PI / 2)
176 const dome = new THREE.Mesh(domeGeom, material)
177 group.add(dome)
178
179 // Hat brim
180 const brimGeom = new THREE.CylinderGeometry(0.22, 0.22, 0.025, 12)
181 const brim = new THREE.Mesh(brimGeom, material)
182 brim.position.y = -0.01
183 group.add(brim)
184
185 return group
186 }
187 },
188
189 // Ollie outfits
190 ollie_coral: {
191 id: 'ollie_coral',
192 name: 'Coral Pink',
193 character: CHARACTERS.OLLIE,
194 type: OUTFIT_TYPES.COLOR_BODY,
195 price: 20,
196 colors: { body: 0xff7f7f, belly: 0xffb3b3, suckers: 0xffcccc }
197 },
198 ollie_deepsea: {
199 id: 'ollie_deepsea',
200 name: 'Deep Sea Blue',
201 character: CHARACTERS.OLLIE,
202 type: OUTFIT_TYPES.COLOR_BODY,
203 price: 20,
204 colors: { body: 0x1e3a5f, belly: 0x4a6fa5, suckers: 0x6b8cae }
205 },
206 ollie_golden_mag: {
207 id: 'ollie_golden_mag',
208 name: 'Golden Magnifier',
209 character: CHARACTERS.OLLIE,
210 type: OUTFIT_TYPES.ACCESSORY_HELD,
211 price: 30,
212 colors: { rim: 0xffd700, glass: 0xffffcc }
213 },
214 ollie_detective: {
215 id: 'ollie_detective',
216 name: 'Detective Cap',
217 character: CHARACTERS.OLLIE,
218 type: OUTFIT_TYPES.ACCESSORY_HEAD,
219 price: 25,
220 meshFactory: (gradientMap) => {
221 const group = new THREE.Group()
222 const material = new THREE.MeshToonMaterial({ color: 0x8b4513, gradientMap })
223
224 // Cap body
225 const capGeom = new THREE.SphereGeometry(0.18, 8, 6, 0, Math.PI * 2, 0, Math.PI / 2)
226 const cap = new THREE.Mesh(capGeom, material)
227 cap.scale.y = 0.5
228 group.add(cap)
229
230 // Front brim
231 const brimGeom = new THREE.CylinderGeometry(0.12, 0.15, 0.02, 8, 1, false, -Math.PI/3, Math.PI * 2/3)
232 const brim = new THREE.Mesh(brimGeom, material)
233 brim.position.set(0.12, -0.02, 0)
234 brim.rotation.z = -0.3
235 group.add(brim)
236
237 return group
238 }
239 }
240 }
241
242 // Building definitions
243 export const BUILDINGS = {
244 dock_wooden: {
245 id: 'dock_wooden',
246 buildingType: 'dock_wooden',
247 name: 'Wooden Dock',
248 price: 40,
249 zoneType: 'waterEdge',
250 forbiddenRadius: 0.8
251 },
252 fishing_hut: {
253 id: 'fishing_hut',
254 buildingType: 'fishing_hut',
255 name: 'Fishing Hut',
256 price: 50,
257 zoneType: 'waterEdge',
258 forbiddenRadius: 0.9
259 },
260 lighthouse: {
261 id: 'lighthouse',
262 buildingType: 'lighthouse',
263 name: 'Mini Lighthouse',
264 price: 50,
265 zoneType: 'shore',
266 forbiddenRadius: 0.5
267 },
268 reeds: {
269 id: 'reeds',
270 buildingType: 'reeds',
271 name: 'Reed Cluster',
272 price: 25,
273 zoneType: 'water',
274 forbiddenRadius: 0.4
275 },
276 fence: {
277 id: 'fence',
278 buildingType: 'fence',
279 name: 'Fence Segment',
280 price: 25,
281 zoneType: 'shore',
282 forbiddenRadius: 0.3
283 },
284 onion_house: {
285 id: 'onion_house',
286 buildingType: 'onion_house',
287 name: 'Onion House',
288 price: 45,
289 zoneType: 'shore',
290 forbiddenRadius: 0.6
291 }
292 }
293
294 // Get all outfits for a character
295 export function getOutfitsForCharacter(character) {
296 return Object.values(OUTFITS).filter(o => o.character === character)
297 }
298
299 // Get all buildings
300 export function getAllBuildings() {
301 return Object.values(BUILDINGS)
302 }
303
304 // Get item by ID (outfit or building)
305 export function getItem(itemId) {
306 return OUTFITS[itemId] || BUILDINGS[itemId] || null
307 }