about summary refs log tree commit diff stats
path: root/data/maps/the_symbolic/doors.txtpb
blob: 5a443e7044a2b2bced4d178e71d67ca07d8f2979 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
doors {
  name: "White Door"
  type: EVENT
  #receivers: "Components/Doors/Door18"
  panels { room: "White Room" name: "WRITE" }
}
doors {
  name: "Black Door"
  type: EVENT
  #receivers: "Components/Doors/Door19"
  panels { room: "Black Room" name: "HERE" }
}
doors {
  name: "Red Door"
  type: EVENT
  #receivers: "Components/Doors/Door20"
  panels { room: "Red Room" name: "SYNONYM" }
}
doors {
  name: "Blue Door"
  type: EVENT
  #receivers: "Components/Doors/Door21"
  panels { room: "Blue Room" name: "DEPLETE" }
}
doors {
  name: "Green Door"
  type: EVENT
  #receivers: "Components/Doors/Door22"
  panels { room: "Green Room" name: "INERT" }
}
doors {
  name: "Yellow Door"
  type: EVENT
  #receivers: "Components/Doors/Door23"
  panels { room: "Yellow Room" name: "WHOLE" }
}
doors {
  name: "Purple Door"
  type: EVENT
  #receivers: "Components/Doors/Door24"
  panels { room: "Purple Room" name: "TIME" }
}
doors {
  name: "Orange Door"
  type: EVENT
  #receivers: "Components/Doors/Door25"
  panels { room: "Orange Room" name: "YOUNG" }
}
doors {
  name: "Tutorial Door"
  type: ITEM_ONLY
  receivers: "Components/Doors/Door"
  panels { room: "Tutorial" name: "<- (1)" }
  panels { room: "Tutorial" name: "<- (2)" }
  panels { room: "Tutorial" name: "<- (3)" }
}
doors {
  name: "Tutorial Panels"
  type: LOCATION_ONLY
  panels { room: "Tutorial" name: "SAY" }
  panels { room: "Tutorial" name: "HIGH" }
  panels { room: "Tutorial" name: "<- (1)" }
  panels { room: "Tutorial" name: "<- (2)" }
  panels { room: "Tutorial" name: "<- (3)" }
  panels { room: "Tutorial" name: "THIS" }
  panels { room: "Tutorial" name: "WRITE" }
  panels { room: "Tutorial" name: "TYPE" }
  panels { room: "Tutorial" name: "SAME" }
  location_room: "Tutorial"
}
doors {
  name: "Main Area Entrance"
  type: EVENT
  panels { room: "Red Blue Room" name: "RIGHTWARD" answer: "word" }
  panels { room: "Red Blue Room" name: "TYPEWRITING" answer: "writing" }
}
doors {
  name: "Whirred Room Entrance"
  type: EVENT
  panels { room: "Red Blue Room" name: "RIGHTWARD" answer: "whirred" }
}
doors {
  name: "Whirred Room Panels"
  type: LOCATION_ONLY
  panels { room: "Whirred Room" name: "TAIPEI" }
  panels { room: "Whirred Room" name: "NAYSAYER" }
  panels { room: "Whirred Room" name: "NAY" }
  panels { room: "Whirred Room" name: "INDEX (1)" }
  panels { room: "Whirred Room" name: "INDEX (2)" }
  location_room: "Whirred Room"
}
doors {
  name: "Poetry Room Entrance"
  type: EVENT
  panels { room: "Red Blue Room" name: "TYPEWRITING" answer: "poetry" }
}
doors {
  name: "Poetry Room Door 1"
  type: EVENT
  panels { room: "Poetry Room 1" name: "ABSORBED" answer: "bed" }
  panels { room: "Poetry Room 1" name: "PRIMORDIAL" answer: "prim" }
  # It has to be the middle two strips of the door.
}
doors {
  name: "Poetry Room Door 2"
  type: EVENT
  panels { room: "Poetry Room 2" name: "NOT THERE" }
}
doors {
  name: "Poetry Room Left"
  type: EVENT
  panels { room: "Poetry Room 3" name: "NOT PRETTY" answer: "ugly" }
}
doors {
  name: "Poetry Room Right"
  type: EVENT
  panels { room: "Poetry Room 3" name: "NOT PRETTY" answer: "prey" }
}
doors {
  name: "Poetry Room Left Left"
  type: EVENT
  panels { room: "Poetry Room Left" name: "NOT TRUE" answer: "false" }
}
doors {
  name: "Poetry Room Left Right"
  type: EVENT
  panels { room: "Poetry Room Left" name: "NOT TRUE" answer: "rue" }
}
doors {
  name: "Poetry Room Right Left"
  type: EVENT
  panels { room: "Poetry Room Right" name: "NOT BETTER" answer: "worse" }
}
doors {
  name: "Poetry Room Right Right"
  type: EVENT
  panels { room: "Poetry Room Right" name: "NOT BETTER" answer: "beer" }
}
doors {
  name: "Poetry Room Panels"
  type: LOCATION_ONLY
  panels { room: "Poetry Room 1" name: "ABSORBED" }
  panels { room: "Poetry Room 1" name: "PRIMORDIAL" }
  panels { room: "Poetry Room 2" name: "NOT" }
  panels { room: "Poetry Room 2" name: "THERE" }
  panels { room: "Poetry Room 2" name: "NOT THERE" }
  panels { room: "Poetry Room 3" name: "NOT" }
  panels { room: "Poetry Room 3" name: "PRETTY" }
  panels { room: "Poetry Room 3" name: "NOT PRETTY" }
  panels { room: "Poetry Room Left" name: "NOT" }
  panels { room: "Poetry Room Left" name: "TRUE" }
  panels { room: "Poetry Room Left" name: "NOT TRUE" }
  panels { room: "Poetry Room Left Left" name: "NOT (1)" }
  panels { room: "Poetry Room Left Left" name: "NOT (2)" }
  panels { room: "Poetry Room Left Left" name: "LEFT" }
  panels { room: "Poetry Room Left Left" name: "NOT NOT LEFT" }
  panels { room: "Poetry Room Left Right" name: "NOT (1)" }
  panels { room: "Poetry Room Left Right" name: "NOT (2)" }
  panels { room: "Poetry Room Left Right" name: "MISS" }
  panels { room: "Poetry Room Left Right" name: "NOT NOT MISS" }
  panels { room: "Poetry Room Right" name: "NOT" }
  panels { room: "Poetry Room Right" name: "BETTER" }
  panels { room: "Poetry Room Right" name: "NOT BETTER" }
  panels { room: "Poetry Room Right Left" name: "NOT (1)" }
  panels { room: "Poetry Room Right Left" name: "NOT (2)" }
  panels { room: "Poetry Room Right Left" name: "TABLET" }
  panels { room: "Poetry Room Right Left" name: "NOT NOT TABLET" }
  panels { room: "Poetry Room Right Right" name: "NOT (1)" }
  panels { room: "Poetry Room Right Right" name: "NOT (2)" }
  panels { room: "Poetry Room Right Right" name: "NOT (3)" }
  panels { room: "Poetry Room Right Right" name: "NOT NOT NOT" }
  location_room: "Poetry Room Right Right"
}
doors {
  name: "Main Area First Row"
  type: LOCATION_ONLY
  panels { room: "Main Area" name: "JUSTICE" }
  panels { room: "Main Area" name: "NOTICE (1)" }
  panels { room: "Main Area" name: "NOTICE (2)" }
  panels { room: "Main Area" name: "NOTICE (3)" }
  panels { room: "Main Area" name: "UNABLE (1)" }
  panels { room: "Main Area" name: "UNABLE (2)" }
  location_room: "Main Area"
}
doors {
  name: "Main Area Second Row"
  type: LOCATION_ONLY
  panels { room: "Main Area" name: "LINEARLY" }
  panels { room: "Main Area" name: "SADDLED" }
  panels { room: "Main Area" name: "PADDING" }
  panels { room: "Main Area" name: "BRINGING" }
  panels { room: "Main Area" name: "THOUSANDS" }
  panels { room: "Main Area" name: "REINDICT" }
  panels { room: "Main Area" name: "LINEAGE" }
  panels { room: "Main Area" name: "TINCTURE" }
  panels { room: "Main Area" name: "IMMATURE" }
  panels { room: "Main Area" name: "THING" }
  location_room: "Main Area"
}
doors {
  name: "Main Area Third Row"
  type: LOCATION_ONLY
  panels { room: "Main Area" name: "SOME" }
  panels { room: "Main Area" name: "HALFTIME (1)" }
  panels { room: "Main Area" name: "HALFTIME (2)" }
  panels { room: "Main Area" name: "QUARTERBACK" }
  panels { room: "Main Area" name: "NORTHERN" }
  panels { room: "Main Area" name: "INMATE" }
  panels { room: "Main Area" name: "NOTCHES" }
  panels { room: "Main Area" name: "VIOLET (1)" }
  panels { room: "Main Area" name: "VIOLET (2)" }
  panels { room: "Main Area" name: "NONSENSE" }
  panels { room: "Main Area" name: "DISTANT" }
  panels { room: "Main Area" name: "TIGHT (1)" }
  panels { room: "Main Area" name: "TIGHT (2)" }
  panels { room: "Main Area" name: "DISCARD" }
  panels { room: "Main Area" name: "PASSPORT" }
  panels { room: "Main Area" name: "PORT" }
  panels { room: "Main Area" name: "STORMS" }
  panels { room: "Main Area" name: "MS" }
  location_room: "Main Area"
}
doors {
  name: "Main Area Fourth Row"
  type: LOCATION_ONLY
  panels { room: "Main Area" name: "SOUNDBITE" }
  panels { room: "Main Area" name: "BORED" }
  panels { room: "Main Area" name: "VOCALIZE" }
  panels { room: "Main Area" name: "VOICEMAIL" }
  panels { room: "Main Area" name: "MIXTURE" }
  panels { room: "Main Area" name: "PEAT" }
  panels { room: "Main Area" name: "SHUFFLEBOARD" }
  panels { room: "Main Area" name: "BLENDING" }
  panels { room: "Main Area" name: "FLIPPER" }
  panels { room: "Main Area" name: "PANT" }
  panels { room: "Main Area" name: "BACKFIRES" }
  panels { room: "Main Area" name: "DRAW" }
  panels { room: "Main Area" name: "OLDTIMER" }
  panels { room: "Main Area" name: "EMULATE" }
  panels { room: "Main Area" name: "CHICKEN" }
  panels { room: "Main Area" name: "PLUMAGED" }
  panels { room: "Main Area" name: "BOY (1)" }
  panels { room: "Main Area" name: "BOY (2)" }
  location_room: "Main Area"
}
doors {
  name: "Main Area Fifth Row"
  type: LOCATION_ONLY
  panels { room: "Main Area" name: "SAGE" }
  panels { room: "Main Area" name: "LIKEABLE" }
  panels { room: "Main Area" name: "MEANINGFULLY" }
  panels { room: "Main Area" name: "MORE" }
  panels { room: "Main Area" name: "MOUTHPIECE" }
  panels { room: "Main Area" name: "RAMPART" }
  panels { room: "Main Area" name: "INJURY" }
  panels { room: "Main Area" name: "NUMERATOR" }
  panels { room: "Main Area" name: "TYPEWRITING" }
  panels { room: "Main Area" name: "WHIRRED" }
  panels { room: "Main Area" name: "BOOMBOX" }
  panels { room: "Main Area" name: "STEREO" }
  panels { room: "Main Area" name: "KINDRED" }
  panels { room: "Main Area" name: "GEM" }
  panels { room: "Main Area" name: "GEIGER" }
  panels { room: "Main Area" name: "COUNTER" }
  panels { room: "Main Area" name: "HORSEMAN" }
  panels { room: "Main Area" name: "RATHER" }
  panels { room: "Main Area" name: "DEAR" }
  panels { room: "Main Area" name: "COWBOY" }
  panels { room: "Main Area" name: "HEIFER" }
  panels { room: "Main Area" name: "ANYMORE" }
  panels { room: "Main Area" name: "LIKE" }
  panels { room: "Main Area" name: "NEEDLESS" }
  panels { room: "Main Area" name: "RESTLESS" }
  location_room: "Main Area"
}
doors {
  name: "Main Area Exit"
  type: EVENT
  panels { room: "Main Area" name: "JUSTICE" }
  panels { room: "Main Area" name: "NOTICE (1)" }
  panels { room: "Main Area" name: "NOTICE (2)" }
  panels { room: "Main Area" name: "NOTICE (3)" }
  panels { room: "Main Area" name: "UNABLE (1)" }
  panels { room: "Main Area" name: "UNABLE (2)" }
  panels { room: "Main Area" name: "LINEARLY" }
  panels { room: "Main Area" name: "SADDLED" }
  panels { room: "Main Area" name: "PADDING" }
  panels { room: "Main Area" name: "BRINGING" }
  panels { room: "Main Area" name: "THOUSANDS" }
  panels { room: "Main Area" name: "REINDICT" }
  panels { room: "Main Area" name: "LINEAGE" }
  panels { room: "Main Area" name: "TINCTURE" }
  panels { room: "Main Area" name: "IMMATURE" }
  panels { room: "Main Area" name: "THING" }
  panels { room: "Main Area" name: "SOME" }
  panels { room: "Main Area" name: "HALFTIME (1)" }
  panels { room: "Main Area" name: "HALFTIME (2)" }
  panels { room: "Main Area" name: "QUARTERBACK" }
  panels { room: "Main Area" name: "NORTHERN" }
  panels { room: "Main Area" name: "INMATE" }
  panels { room: "Main Area" name: "NOTCHES" }
  panels { room: "Main Area" name: "VIOLET (1)" }
  panels { room: "Main Area" name: "VIOLET (2)" }
  panels { room: "Main Area" name: "NONSENSE" }
  panels { room: "Main Area" name: "DISTANT" }
  panels { room: "Main Area" name: "TIGHT (1)" }
  panels { room: "Main Area" name: "TIGHT (2)" }
  panels { room: "Main Area" name: "DISCARD" }
  panels { room: "Main Area" name: "PASSPORT" }
  panels { room: "Main Area" name: "PORT" }
  panels { room: "Main Area" name: "STORMS" }
  panels { room: "Main Area" name: "MS" }
  panels { room: "Main Area" name: "SOUNDBITE" }
  panels { room: "Main Area" name: "BORED" }
  panels { room: "Main Area" name: "VOCALIZE" }
  panels { room: "Main Area" name: "VOICEMAIL" }
  panels { room: "Main Area" name: "MIXTURE" }
  panels { room: "Main Area" name: "PEAT" }
  panels { room: "Main Area" name: "SHUFFLEBOARD" }
  panels { room: "Main Area" name: "BLENDING" }
  panels { room: "Main Area" name: "FLIPPER" }
  panels { room: "Main Area" name: "PANT" }
  panels { room: "Main Area" name: "BACKFIRES" }
  panels { room: "Main Area" name: "DRAW" }
  panels { room: "Main Area" name: "OLDTIMER" }
  panels { room: "Main Area" name: "EMULATE" }
  panels { room: "Main Area" name: "CHICKEN" }
  panels { room: "Main Area" name: "PLUMAGED" }
  panels { room: "Main Area" name: "BOY (1)" }
  panels { room: "Main Area" name: "BOY (2)" }
  panels { room: "Main Area" name: "SAGE" }
  panels { room: "Main Area" name: "LIKEABLE" }
  panels { room: "Main Area" name: "MEANINGFULLY" }
  panels { room: "Main Area" name: "MORE" }
  panels { room: "Main Area" name: "MOUTHPIECE" }
  panels { room: "Main Area" name: "RAMPART" }
  panels { room: "Main Area" name: "INJURY" }
  panels { room: "Main Area" name: "NUMERATOR" }
  panels { room: "Main Area" name: "TYPEWRITING" }
  panels { room: "Main Area" name: "WHIRRED" }
  panels { room: "Main Area" name: "BOOMBOX" }
  panels { room: "Main Area" name: "STEREO" }
  panels { room: "Main Area" name: "KINDRED" }
  panels { room: "Main Area" name: "GEM" }
  panels { room: "Main Area" name: "GEIGER" }
  panels { room: "Main Area" name: "COUNTER" }
  panels { room: "Main Area" name: "HORSEMAN" }
  panels { room: "Main Area" name: "RATHER" }
  panels { room: "Main Area" name: "DEAR" }
  panels { room: "Main Area" name: "COWBOY" }
  panels { room: "Main Area" name: "HEIFER" }
  panels { room: "Main Area" name: "ANYMORE" }
  panels { room: "Main Area" name: "LIKE" }
  panels { room: "Main Area" name: "NEEDLESS" }
  panels { room: "Main Area" name: "RESTLESS" }
}
doors {
  name: "Mastery"
  type: EVENT
  panels { room: "Last Room" name: "BLEAT" }
  panels { room: "Last Room" name: "JARGON" }
  panels { room: "Last Room" name: "JARGON BLEAT" }
  panels { room: "Last Room" name: "BRAG" }
}
// http://love2d.org/ // // // Radius mode support, from 71 squared // http://particledesigner.71squared.com/ // // IMPORTANT: Particle Designer is supported by cocos2d, but // 'Radius Mode' in Particle Designer uses a fixed emit rate of 30 hz. Since that can't be guarateed in cocos2d, // cocos2d uses a another approach, but the results are almost identical. // // opengl #import "Platforms/CCGL.h" // cocos2d #import "ccConfig.h" #if CC_ENABLE_PROFILERS #import "Support/CCProfiling.h" #endif #import "CCParticleSystem.h" #import "CCTextureCache.h" #import "ccMacros.h" // support #import "Support/OpenGL_Internal.h" #import "Support/CGPointExtension.h" #import "Support/base64.h" #import "Support/ZipUtils.h" #import "Support/CCFileUtils.h" @implementation CCParticleSystem @synthesize active, duration; @synthesize sourcePosition, posVar; @synthesize particleCount; @synthesize life, lifeVar; @synthesize angle, angleVar; @synthesize startColor, startColorVar, endColor, endColorVar; @synthesize startSpin, startSpinVar, endSpin, endSpinVar; @synthesize emissionRate; @synthesize totalParticles; @synthesize startSize, startSizeVar; @synthesize endSize, endSizeVar; @synthesize blendFunc = blendFunc_; @synthesize positionType = positionType_; @synthesize autoRemoveOnFinish = autoRemoveOnFinish_; @synthesize emitterMode = emitterMode_; +(id) particleWithFile:(NSString*) plistFile { return [[[self alloc] initWithFile:plistFile] autorelease]; } -(id) init { NSAssert(NO, @"CCParticleSystem: Init not supported."); [self release]; return nil; } -(id) initWithFile:(NSString *)plistFile { NSString *path = [CCFileUtils fullPathFromRelativePath:plistFile]; NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:path]; NSAssert( dict != nil, @"Particles: file not found"); return [self initWithDictionary:dict]; } -(id) initWithDictionary:(NSDictionary *)dictionary { NSUInteger maxParticles = [[dictionary valueForKey:@"maxParticles"] intValue]; // self, not super if ((self=[self initWithTotalParticles:maxParticles] ) ) { // angle angle = [[dictionary valueForKey:@"angle"] floatValue]; angleVar = [[dictionary valueForKey:@"angleVariance"] floatValue]; // duration duration = [[dictionary valueForKey:@"duration"] floatValue]; // blend function blendFunc_.src = [[dictionary valueForKey:@"blendFuncSource"] intValue]; blendFunc_.dst = [[dictionary valueForKey:@"blendFuncDestination"] intValue]; // color float r,g,b,a; r = [[dictionary valueForKey:@"startColorRed"] floatValue]; g = [[dictionary valueForKey:@"startColorGreen"] floatValue]; b = [[dictionary valueForKey:@"startColorBlue"] floatValue]; a = [[dictionary valueForKey:@"startColorAlpha"] floatValue]; startColor = (ccColor4F) {r,g,b,a}; r = [[dictionary valueForKey:@"startColorVarianceRed"] floatValue]; g = [[dictionary valueForKey:@"startColorVarianceGreen"] floatValue]; b = [[dictionary valueForKey:@"startColorVarianceBlue"] floatValue]; a = [[dictionary valueForKey:@"startColorVarianceAlpha"] floatValue]; startColorVar = (ccColor4F) {r,g,b,a}; r = [[dictionary valueForKey:@"finishColorRed"] floatValue]; g = [[dictionary valueForKey:@"finishColorGreen"] floatValue]; b = [[dictionary valueForKey:@"finishColorBlue"] floatValue]; a = [[dictionary valueForKey:@"finishColorAlpha"] floatValue]; endColor = (ccColor4F) {r,g,b,a}; r = [[dictionary valueForKey:@"finishColorVarianceRed"] floatValue]; g = [[dictionary valueForKey:@"finishColorVarianceGreen"] floatValue]; b = [[dictionary valueForKey:@"finishColorVarianceBlue"] floatValue]; a = [[dictionary valueForKey:@"finishColorVarianceAlpha"] floatValue]; endColorVar = (ccColor4F) {r,g,b,a}; // particle size startSize = [[dictionary valueForKey:@"startParticleSize"] floatValue]; startSizeVar = [[dictionary valueForKey:@"startParticleSizeVariance"] floatValue]; endSize = [[dictionary valueForKey:@"finishParticleSize"] floatValue]; endSizeVar = [[dictionary valueForKey:@"finishParticleSizeVariance"] floatValue]; // position float x = [[dictionary valueForKey:@"sourcePositionx"] floatValue]; float y = [[dictionary valueForKey:@"sourcePositiony"] floatValue]; self.position = ccp(x,y); posVar.x = [[dictionary valueForKey:@"sourcePositionVariancex"] floatValue]; posVar.y = [[dictionary valueForKey:@"sourcePositionVariancey"] floatValue]; // Spinning startSpin = [[dictionary valueForKey:@"rotationStart"] floatValue]; startSpinVar = [[dictionary valueForKey:@"rotationStartVariance"] floatValue]; endSpin = [[dictionary valueForKey:@"rotationEnd"] floatValue]; endSpinVar = [[dictionary valueForKey:@"rotationEndVariance"] floatValue]; emitterMode_ = [[dictionary valueForKey:@"emitterType"] intValue]; // Mode A: Gravity + tangential accel + radial accel if( emitterMode_ == kCCParticleModeGravity ) { // gravity mode.A.gravity.x = [[dictionary valueForKey:@"gravityx"] floatValue]; mode.A.gravity.y = [[dictionary valueForKey:@"gravityy"] floatValue]; // // speed mode.A.speed = [[dictionary valueForKey:@"speed"] floatValue]; mode.A.speedVar = [[dictionary valueForKey:@"speedVariance"] floatValue]; // radial acceleration NSString *tmp = [dictionary valueForKey:@"radialAcceleration"]; mode.A.radialAccel = tmp ? [tmp floatValue] : 0; tmp = [dictionary valueForKey:@"radialAccelVariance"]; mode.A.radialAccelVar = tmp ? [tmp floatValue] : 0; // tangential acceleration tmp = [dictionary valueForKey:@"tangentialAcceleration"]; mode.A.tangentialAccel = tmp ? [tmp floatValue] : 0; tmp = [dictionary valueForKey:@"tangentialAccelVariance"]; mode.A.tangentialAccelVar = tmp ? [tmp floatValue] : 0; } // or Mode B: radius movement else if( emitterMode_ == kCCParticleModeRadius ) { float maxRadius = [[dictionary valueForKey:@"maxRadius"] floatValue]; float maxRadiusVar = [[dictionary valueForKey:@"maxRadiusVariance"] floatValue]; float minRadius = [[dictionary valueForKey:@"minRadius"] floatValue]; mode.B.startRadius = maxRadius; mode.B.startRadiusVar = maxRadiusVar; mode.B.endRadius = minRadius; mode.B.endRadiusVar = 0; mode.B.rotatePerSecond = [[dictionary valueForKey:@"rotatePerSecond"] floatValue]; mode.B.rotatePerSecondVar = [[dictionary valueForKey:@"rotatePerSecondVariance"] floatValue]; } else { NSAssert( NO, @"Invalid emitterType in config file"); } // life span life = [[dictionary valueForKey:@"particleLifespan"] floatValue]; lifeVar = [[dictionary valueForKey:@"particleLifespanVariance"] floatValue]; // emission Rate emissionRate = totalParticles/life; // texture // Try to get the texture from the cache NSString *textureName = [dictionary valueForKey:@"textureFileName"]; CCTexture2D *tex = [[CCTextureCache sharedTextureCache] addImage:textureName]; if( tex ) self.texture = tex; else { NSString *textureData = [dictionary valueForKey:@"textureImageData"]; NSAssert( textureData, @"CCParticleSystem: Couldn't load texture"); // if it fails, try to get it from the base64-gzipped data unsigned char *buffer = NULL; int len = base64Decode((unsigned char*)[textureData UTF8String], (unsigned int)[textureData length], &buffer); NSAssert( buffer != NULL, @"CCParticleSystem: error decoding textureImageData"); unsigned char *deflated = NULL; NSUInteger deflatedLen = ccInflateMemory(buffer, len, &deflated); free( buffer ); NSAssert( deflated != NULL, @"CCParticleSystem: error ungzipping textureImageData"); NSData *data = [[NSData alloc] initWithBytes:deflated length:deflatedLen]; #ifdef __IPHONE_OS_VERSION_MAX_ALLOWED UIImage *image = [[UIImage alloc] initWithData:data]; #elif defined(__MAC_OS_X_VERSION_MAX_ALLOWED) NSBitmapImageRep *image = [[NSBitmapImageRep alloc] initWithData:data]; #endif free(deflated); deflated = NULL; self.texture = [[CCTextureCache sharedTextureCache] addCGImage:[image CGImage] forKey:textureName]; [data release]; [image release]; } NSAssert( [self texture] != NULL, @"CCParticleSystem: error loading the texture"); } return self; } -(id) initWithTotalParticles:(NSUInteger) numberOfParticles { if( (self=[super init]) ) { totalParticles = numberOfParticles; particles = calloc( totalParticles, sizeof(tCCParticle) ); if( ! particles ) { NSLog(@"Particle system: not enough memory"); [self release]; return nil; } // default, active active = YES; // default blend function blendFunc_ = (ccBlendFunc) { CC_BLEND_SRC, CC_BLEND_DST }; // default movement type; positionType_ = kCCPositionTypeFree; // by default be in mode A: emitterMode_ = kCCParticleModeGravity; // default: modulate // XXX: not used // colorModulate = YES; autoRemoveOnFinish_ = NO; // profiling #if CC_ENABLE_PROFILERS _profilingTimer = [[CCProfiler timerWithName:@"particle system" andInstance:self] retain]; #endif // Optimization: compile udpateParticle method updateParticleSel = @selector(updateQuadWithParticle:newPosition:); updateParticleImp = (CC_UPDATE_PARTICLE_IMP) [self methodForSelector:updateParticleSel]; // udpate after action in run! [self scheduleUpdateWithPriority:1]; } return self; } -(void) dealloc { free( particles ); [texture_ release]; // profiling #if CC_ENABLE_PROFILERS [CCProfiler releaseTimer:_profilingTimer]; #endif [super dealloc]; } -(BOOL) addParticle { if( [self isFull] ) return NO; tCCParticle * particle = &particles[ particleCount ]; [self initParticle: particle]; particleCount++; return YES; } -(void) initParticle: (tCCParticle*) particle { // timeToLive // no negative life. prevent division by 0 particle->timeToLive = life + lifeVar * CCRANDOM_MINUS1_1(); particle->timeToLive = MAX(0, particle->timeToLive); // position particle->pos.x = sourcePosition.x + posVar.x * CCRANDOM_MINUS1_1(); particle->pos.x *= CC_CONTENT_SCALE_FACTOR(); particle->pos.y = sourcePosition.y + posVar.y * CCRANDOM_MINUS1_1(); particle->pos.y *= CC_CONTENT_SCALE_FACTOR(); // Color ccColor4F start; start.r = clampf( startColor.r + startColorVar.r * CCRANDOM_MINUS1_1(), 0, 1); start.g = clampf( startColor.g + startColorVar.g * CCRANDOM_MINUS1_1(), 0, 1); start.b = clampf( startColor.b + startColorVar.b * CCRANDOM_MINUS1_1(), 0, 1); start.a = clampf( startColor.a + startColorVar.a * CCRANDOM_MINUS1_1(), 0, 1); ccColor4F end; end.r = clampf( endColor.r + endColorVar.r * CCRANDOM_MINUS1_1(), 0, 1); end.g = clampf( endColor.g + endColorVar.g * CCRANDOM_MINUS1_1(), 0, 1); end.b = clampf( endColor.b + endColorVar.b * CCRANDOM_MINUS1_1(), 0, 1); end.a = clampf( endColor.a + endColorVar.a * CCRANDOM_MINUS1_1(), 0, 1); particle->color = start; particle->deltaColor.r = (end.r - start.r) / particle->timeToLive; particle->deltaColor.g = (end.g - start.g) / particle->timeToLive; particle->deltaColor.b = (end.b - start.b) / particle->timeToLive; particle->deltaColor.a = (end.a - start.a) / particle->timeToLive; // size float startS = startSize + startSizeVar * CCRANDOM_MINUS1_1(); startS = MAX(0, startS); // No negative value startS *= CC_CONTENT_SCALE_FACTOR(); particle->size = startS; if( endSize == kCCParticleStartSizeEqualToEndSize ) particle->deltaSize = 0; else { float endS = endSize + endSizeVar * CCRANDOM_MINUS1_1(); endS = MAX(0, endS); // No negative values endS *= CC_CONTENT_SCALE_FACTOR(); particle->deltaSize = (endS - startS) / particle->timeToLive; } // rotation float startA = startSpin + startSpinVar * CCRANDOM_MINUS1_1(); float endA = endSpin + endSpinVar * CCRANDOM_MINUS1_1(); particle->rotation = startA; particle->deltaRotation = (endA - startA) / particle->timeToLive; // position if( positionType_ == kCCPositionTypeFree ) { CGPoint p = [self convertToWorldSpace:CGPointZero]; particle->startPos = ccpMult( p, CC_CONTENT_SCALE_FACTOR() ); } else if( positionType_ == kCCPositionTypeRelative ) { particle->startPos = ccpMult( position_, CC_CONTENT_SCALE_FACTOR() ); } // direction float a = CC_DEGREES_TO_RADIANS( angle + angleVar * CCRANDOM_MINUS1_1() ); // Mode Gravity: A if( emitterMode_ == kCCParticleModeGravity ) { CGPoint v = {cosf( a ), sinf( a )}; float s = mode.A.speed + mode.A.speedVar * CCRANDOM_MINUS1_1(); s *= CC_CONTENT_SCALE_FACTOR(); // direction particle->mode.A.dir = ccpMult( v, s ); // radial accel particle->mode.A.radialAccel = mode.A.radialAccel + mode.A.radialAccelVar * CCRANDOM_MINUS1_1(); particle->mode.A.radialAccel *= CC_CONTENT_SCALE_FACTOR(); // tangential accel particle->mode.A.tangentialAccel = mode.A.tangentialAccel + mode.A.tangentialAccelVar * CCRANDOM_MINUS1_1(); particle->mode.A.tangentialAccel *= CC_CONTENT_SCALE_FACTOR(); } // Mode Radius: B else { // Set the default diameter of the particle from the source position float startRadius = mode.B.startRadius + mode.B.startRadiusVar * CCRANDOM_MINUS1_1(); float endRadius = mode.B.endRadius + mode.B.endRadiusVar * CCRANDOM_MINUS1_1(); startRadius *= CC_CONTENT_SCALE_FACTOR(); endRadius *= CC_CONTENT_SCALE_FACTOR(); particle->mode.B.radius = startRadius; if( mode.B.endRadius == kCCParticleStartRadiusEqualToEndRadius ) particle->mode.B.deltaRadius = 0; else particle->mode.B.deltaRadius = (endRadius - startRadius) / particle->timeToLive; particle->mode.B.angle = a; particle->mode.B.degreesPerSecond = CC_DEGREES_TO_RADIANS(mode.B.rotatePerSecond + mode.B.rotatePerSecondVar * CCRANDOM_MINUS1_1()); } } -(void) stopSystem { active = NO; elapsed = duration; emitCounter = 0; } -(void) resetSystem { active = YES; elapsed = 0; for(particleIdx = 0; particleIdx < particleCount; ++particleIdx) { tCCParticle *p = &particles[particleIdx]; p->timeToLive = 0; } } -(BOOL) isFull { return (particleCount == totalParticles); } #pragma mark ParticleSystem - MainLoop -(void) update: (ccTime) dt { if( active && emissionRate ) { float rate = 1.0f / emissionRate; emitCounter += dt; while( particleCount < totalParticles && emitCounter > rate ) { [self addParticle]; emitCounter -= rate; } elapsed += dt; if(duration != -1 && duration < elapsed) [self stopSystem]; } particleIdx = 0; #if CC_ENABLE_PROFILERS CCProfilingBeginTimingBlock(_profilingTimer); #endif CGPoint currentPosition = CGPointZero; if( positionType_ == kCCPositionTypeFree ) { currentPosition = [self convertToWorldSpace:CGPointZero]; currentPosition.x *= CC_CONTENT_SCALE_FACTOR(); currentPosition.y *= CC_CONTENT_SCALE_FACTOR(); } else if( positionType_ == kCCPositionTypeRelative ) { currentPosition = position_; currentPosition.x *= CC_CONTENT_SCALE_FACTOR(); currentPosition.y *= CC_CONTENT_SCALE_FACTOR(); } while( particleIdx < particleCount ) { tCCParticle *p = &particles[particleIdx]; // life p->timeToLive -= dt; if( p->timeToLive > 0 ) { // Mode A: gravity, direction, tangential accel & radial accel if( emitterMode_ == kCCParticleModeGravity ) { CGPoint tmp, radial, tangential; radial = CGPointZero; // radial acceleration if(p->pos.x || p->pos.y) radial = ccpNormalize(p->pos); tangential = radial; radial = ccpMult(radial, p->mode.A.radialAccel); // tangential acceleration float newy = tangential.x; tangential.x = -tangential.y; tangential.y = newy; tangential = ccpMult(tangential, p->mode.A.tangentialAccel); // (gravity + radial + tangential) * dt tmp = ccpAdd( ccpAdd( radial, tangential), mode.A.gravity); tmp = ccpMult( tmp, dt); p->mode.A.dir = ccpAdd( p->mode.A.dir, tmp); tmp = ccpMult(p->mode.A.dir, dt); p->pos = ccpAdd( p->pos, tmp ); } // Mode B: radius movement else { // Update the angle and radius of the particle. p->mode.B.angle += p->mode.B.degreesPerSecond * dt; p->mode.B.radius += p->mode.B.deltaRadius * dt; p->pos.x = - cosf(p->mode.B.angle) * p->mode.B.radius; p->pos.y = - sinf(p->mode.B.angle) * p->mode.B.radius; } // color p->color.r += (p->deltaColor.r * dt); p->color.g += (p->deltaColor.g * dt); p->color.b += (p->deltaColor.b * dt); p->color.a += (p->deltaColor.a * dt); // size p->size += (p->deltaSize * dt); p->size = MAX( 0, p->size ); // angle p->rotation += (p->deltaRotation * dt); // // update values in quad // CGPoint newPos; if( positionType_ == kCCPositionTypeFree || positionType_ == kCCPositionTypeRelative ) { CGPoint diff = ccpSub( currentPosition, p->startPos ); newPos = ccpSub(p->pos, diff); } else newPos = p->pos; updateParticleImp(self, updateParticleSel, p, newPos); // update particle counter particleIdx++; } else { // life < 0 if( particleIdx != particleCount-1 ) particles[particleIdx] = particles[particleCount-1]; particleCount--; if( particleCount == 0 && autoRemoveOnFinish_ ) { [self unscheduleUpdate]; [parent_ removeChild:self cleanup:YES]; return; } } } #if CC_ENABLE_PROFILERS CCProfilingEndTimingBlock(_profilingTimer); #endif #ifdef CC_USES_VBO [self postStep]; #endif } -(void) updateQuadWithParticle:(tCCParticle*)particle newPosition:(CGPoint)pos; { // should be overriden } -(void) postStep { // should be overriden } #pragma mark ParticleSystem - CCTexture protocol -(void) setTexture:(CCTexture2D*) texture { [texture_ release]; texture_ = [texture retain]; // If the new texture has No premultiplied alpha, AND the blendFunc hasn't been changed, then update it if( texture_ && ! [texture hasPremultipliedAlpha] && ( blendFunc_.src == CC_BLEND_SRC && blendFunc_.dst == CC_BLEND_DST ) ) { blendFunc_.src = GL_SRC_ALPHA; blendFunc_.dst = GL_ONE_MINUS_SRC_ALPHA; } } -(CCTexture2D*) texture { return texture_; } #pragma mark ParticleSystem - Additive Blending -(void) setBlendAdditive:(BOOL)additive { if( additive ) { blendFunc_.src = GL_SRC_ALPHA; blendFunc_.dst = GL_ONE; } else { if( texture_ && ! [texture_ hasPremultipliedAlpha] ) { blendFunc_.src = GL_SRC_ALPHA; blendFunc_.dst = GL_ONE_MINUS_SRC_ALPHA; } else { blendFunc_.src = CC_BLEND_SRC; blendFunc_.dst = CC_BLEND_DST; } } } -(BOOL) blendAdditive { return( blendFunc_.src == GL_SRC_ALPHA && blendFunc_.dst == GL_ONE); } #pragma mark ParticleSystem - Properties of Gravity Mode -(void) setTangentialAccel:(float)t { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); mode.A.tangentialAccel = t; } -(float) tangentialAccel { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); return mode.A.tangentialAccel; } -(void) setTangentialAccelVar:(float)t { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); mode.A.tangentialAccelVar = t; } -(float) tangentialAccelVar { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); return mode.A.tangentialAccelVar; } -(void) setRadialAccel:(float)t { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); mode.A.radialAccel = t; } -(float) radialAccel { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); return mode.A.radialAccel; } -(void) setRadialAccelVar:(float)t { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); mode.A.radialAccelVar = t; } -(float) radialAccelVar { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); return mode.A.radialAccelVar; } -(void) setGravity:(CGPoint)g { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); mode.A.gravity = g; } -(CGPoint) gravity { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); return mode.A.gravity; } -(void) setSpeed:(float)speed { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); mode.A.speed = speed; } -(float) speed { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); return mode.A.speed; } -(void) setSpeedVar:(float)speedVar { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); mode.A.speedVar = speedVar; } -(float) speedVar { NSAssert( emitterMode_ == kCCParticleModeGravity, @"Particle Mode should be Gravity"); return mode.A.speedVar; } #pragma mark ParticleSystem - Properties of Radius Mode -(void) setStartRadius:(float)startRadius { NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); mode.B.startRadius = startRadius; } -(float) startRadius { NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); return mode.B.startRadius; } -(void) setStartRadiusVar:(float)startRadiusVar { NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); mode.B.startRadiusVar = startRadiusVar; } -(float) startRadiusVar { NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); return mode.B.startRadiusVar; } -(void) setEndRadius:(float)endRadius { NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); mode.B.endRadius = endRadius; } -(float) endRadius { NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); return mode.B.endRadius; } -(void) setEndRadiusVar:(float)endRadiusVar { NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); mode.B.endRadiusVar = endRadiusVar; } -(float) endRadiusVar { NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); return mode.B.endRadiusVar; } -(void) setRotatePerSecond:(float)degrees { NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); mode.B.rotatePerSecond = degrees; } -(float) rotatePerSecond { NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); return mode.B.rotatePerSecond; } -(void) setRotatePerSecondVar:(float)degrees { NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); mode.B.rotatePerSecondVar = degrees; } -(float) rotatePerSecondVar { NSAssert( emitterMode_ == kCCParticleModeRadius, @"Particle Mode should be Radius"); return mode.B.rotatePerSecondVar; } @end