1 /*KJL***************************************************
2 * lighting.c - a lighting interface for simple effects *
3 ***************************************************KJL*/
4
5 #include "3dc.h"
6
7 #include "inline.h"
8 #include "module.h"
9 #include "stratdef.h"
10 #include "gamedef.h"
11 #include "bh_types.h"
12 #include "bh_weap.h"
13
14 #include "lighting.h"
15 #include "particle.h"
16 #include "dynamics.h"
17 #define UseLocalAssert Yes
18 #include "ourasert.h"
19
20 static VECTORCH RotatingLightPosition;
21 extern int CloakingPhase;
22 extern int NormalFrameTime;
23 extern VIEWDESCRIPTORBLOCK *Global_VDB_Ptr;
24 extern int LightScale;
25
AddLightingEffectToObject(DISPLAYBLOCK * objectPtr,enum LIGHTING_EFFECTS_ID lfxID)26 void AddLightingEffectToObject(DISPLAYBLOCK *objectPtr, enum LIGHTING_EFFECTS_ID lfxID)
27 {
28 LIGHTBLOCK *lightPtr;
29
30 lightPtr = AddLightBlock(objectPtr, NULL);
31
32 if (!lightPtr) return;
33
34 switch(lfxID)
35 {
36 case LFX_EXPLOSION:
37 {
38 /* brightness */
39 lightPtr->LightBright = ONE_FIXED*4;
40 /* flags */
41 lightPtr->LightFlags = LFlag_Omni;
42 /* lightblock light type */
43 lightPtr->LightType = LightType_PerVertex;
44 /* range */
45 lightPtr->LightRange = EXPLOSION_LIGHT_RANGE;
46
47 lightPtr->RedScale=255*256;
48 lightPtr->GreenScale=120*256;
49 lightPtr->BlueScale=0;
50
51 break;
52 }
53 case LFX_BIGEXPLOSION:
54 {
55 /* brightness */
56 lightPtr->LightBright = ONE_FIXED << 2;
57 /* flags */
58 lightPtr->LightFlags = LFlag_Omni;
59 /* lightblock light type */
60 lightPtr->LightType = LightType_PerVertex;
61 /* range */
62 lightPtr->LightRange = EXPLOSION_LIGHT_RANGE;
63
64 lightPtr->RedScale=255*256;
65 lightPtr->GreenScale=120*256;
66 lightPtr->BlueScale=0;
67
68 break;
69 }
70
71 case LFX_MUZZLEFLASH:
72 {
73 /* brightness */
74 lightPtr->LightBright = 65536 - (FastRandom()&32767);
75 /* flags */
76 lightPtr->LightFlags = LFlag_Omni|LFlag_Deallocate;
77 /* lightblock light type */
78 lightPtr->LightType = LightType_PerVertex;
79 /* range */
80 #if 0
81 lightPtr->LightRange = 5000; /* ? */
82
83 lightPtr->RedScale=255*256;
84 lightPtr->GreenScale=192*256;
85 lightPtr->BlueScale=128*256;
86 #else
87 lightPtr->LightRange = 10000; /* ? */
88 lightPtr->RedScale=255*256;
89 lightPtr->GreenScale=230*256;
90 lightPtr->BlueScale=200*256;
91 #endif
92
93 break;
94 }
95 case LFX_PARTICLECANNON:
96 {
97 /* brightness */
98 lightPtr->LightBright = 65536 - (FastRandom()&32767);
99 /* flags */
100 lightPtr->LightFlags = LFlag_Omni|LFlag_Deallocate;
101 /* lightblock light type */
102 lightPtr->LightType = LightType_PerVertex;
103 /* range */
104 lightPtr->LightRange = 10000; /* ? */
105
106 lightPtr->RedScale=255*256;
107 lightPtr->GreenScale=32*256;
108 lightPtr->BlueScale=0;
109 break;
110 }
111 case LFX_ROCKETJET:
112 {
113 /* brightness */
114 lightPtr->LightBright = ONE_FIXED*3/4;
115 /* flags */
116 lightPtr->LightFlags = LFlag_Omni|LFlag_CosAtten;
117 /* lightblock light type */
118 lightPtr->LightType = LightType_PerVertex;
119 /* range */
120 lightPtr->LightRange = 5000; /* ? */
121
122 lightPtr->RedScale=255*256;
123 lightPtr->GreenScale=255*256;
124 lightPtr->BlueScale=128*256;
125
126 break;
127 }
128 case LFX_FLARE:
129 {
130 /* brightness */
131 lightPtr->LightBright = 0;
132 /* flags */
133 lightPtr->LightFlags = LFlag_Omni;
134 /* lightblock light type */
135 lightPtr->LightType = LightType_PerVertex;
136 /* range */
137 lightPtr->LightRange = 10000; /* ? */
138
139 lightPtr->RedScale=255*256;
140 lightPtr->GreenScale=200*256;
141 lightPtr->BlueScale=255*256;
142
143 break;
144 }
145 case LFX_XENO_FIRING:
146 {
147 /* brightness */
148 lightPtr->LightBright = 226100;
149 /* flags */
150 lightPtr->LightFlags = LFlag_Omni|LFlag_Deallocate;
151 /* lightblock light type */
152 lightPtr->LightType = LightType_PerVertex;
153 /* range */
154 lightPtr->LightRange = 5000; /* ? */
155
156 lightPtr->RedScale=255*256;
157 lightPtr->GreenScale=64*256;
158 lightPtr->BlueScale=255*256;
159
160 break;
161 }
162 case LFX_PLASMA_BOLT:
163 {
164 /* brightness */
165 lightPtr->LightBright = ONE_FIXED/4;
166 /* flags */
167 lightPtr->LightFlags = LFlag_Omni|LFlag_CosAtten;
168 /* lightblock light type */
169 lightPtr->LightType = LightType_PerVertex;
170 /* range */
171 lightPtr->LightRange = 10000;
172
173 lightPtr->RedScale=200*256;
174 lightPtr->GreenScale=255*256;
175 lightPtr->BlueScale=255*256;
176
177 break;
178 }
179 case LFX_OBJECTONFIRE:
180 {
181 /* brightness */
182 lightPtr->LightBright = 16484 - (FastRandom()&4095);
183 /* flags */
184 lightPtr->LightFlags = LFlag_Omni|LFlag_Deallocate|LFlag_Thermal;
185 /* lightblock light type */
186 lightPtr->LightType = LightType_PerVertex;
187 /* range */
188 lightPtr->LightRange = 10000;
189 lightPtr->RedScale=255*256;
190 lightPtr->GreenScale=110*256;
191 lightPtr->BlueScale=50*256;
192
193 break;
194 }
195 case LFX_SPEARGUNBOLT:
196 {
197 /* Just an experiment. */
198 /* brightness */
199 lightPtr->LightBright = ONE_FIXED/4;
200 /* flags */
201 lightPtr->LightFlags = LFlag_Omni|LFlag_CosAtten;
202 /* lightblock light type */
203 lightPtr->LightType = LightType_PerVertex;
204 /* range */
205 lightPtr->LightRange = 10000;
206
207 lightPtr->RedScale=255*256;
208 lightPtr->GreenScale=255*256;
209 lightPtr->BlueScale=255*256;
210
211 break;
212 }
213 }
214 }
215
216
217
LightBlockDeallocation(void)218 void LightBlockDeallocation(void)
219 {
220 extern int NumActiveBlocks;
221 extern DISPLAYBLOCK *ActiveBlockList[];
222 int numblocks = NumActiveBlocks;
223
224 while(numblocks)
225 {
226 DISPLAYBLOCK *dptr = ActiveBlockList[--numblocks];
227
228 int numlights = dptr->ObNumLights;
229 while(numlights)
230 {
231 LIGHTBLOCK *lightPtr = dptr->ObLights[--numlights];
232 if(lightPtr->LightFlags & LFlag_Deallocate)
233 DeleteLightBlock(lightPtr, dptr);
234 }
235 }
236
237 }
238
239 /*KJL******************************
240 * *
241 * LIGHT ELEMENT CODE *
242 * *
243 ******************************KJL*/
244 #define MAX_NO_OF_LIGHTELEMENTS 500
245 LIGHTELEMENT LightElementStorage[MAX_NO_OF_LIGHTELEMENTS];
246 int NumActiveLightElements;
247
InitialiseLightElementSystem(void)248 void InitialiseLightElementSystem(void)
249 {
250 NumActiveLightElements = 0;
251 }
252
AllocateLightElement(void)253 static LIGHTELEMENT* AllocateLightElement(void)
254 {
255 LIGHTELEMENT *lightElementPtr = 0; /* Default to null ptr */
256
257 if (NumActiveLightElements != MAX_NO_OF_LIGHTELEMENTS)
258 {
259 lightElementPtr = &LightElementStorage[NumActiveLightElements];
260 NumActiveLightElements++;
261 }
262 else
263 {
264 /* unable to allocate a lightElement */
265 }
266
267 return lightElementPtr;
268 }
DeallocateLightElement(LIGHTELEMENT * lightElementPtr)269 static void DeallocateLightElement(LIGHTELEMENT *lightElementPtr)
270 {
271 /* is pointer within array? */
272 LOCALASSERT(lightElementPtr>=LightElementStorage);
273 LOCALASSERT(lightElementPtr<=&LightElementStorage[MAX_NO_OF_LIGHTELEMENTS-1]);
274
275 NumActiveLightElements--;
276 *lightElementPtr = LightElementStorage[NumActiveLightElements];
277 }
278
279
MakeLightElement(VECTORCH * positionPtr,enum LIGHTELEMENT_BEHAVIOUR_ID behaviourID)280 void MakeLightElement(VECTORCH *positionPtr, enum LIGHTELEMENT_BEHAVIOUR_ID behaviourID)
281 {
282 LIGHTELEMENT *lightElementPtr = AllocateLightElement();
283 LIGHTBLOCK *lightPtr = &(lightElementPtr->LightBlock);
284
285 /* if we failed to make an element, get the hell out of here */
286 if (!lightElementPtr) return;
287
288 lightElementPtr->BehaviourID = behaviourID;
289 lightElementPtr->LightBlock.LightWorld = *positionPtr;
290 lightElementPtr->LifeTime=ONE_FIXED;
291
292 switch (behaviourID)
293 {
294 case LIGHTELEMENT_ROTATING:
295 {
296 RotatingLightPosition = *positionPtr;
297 break;
298 }
299 case LIGHTELEMENT_ALIEN_TEETH:
300 {
301 lightPtr->LightBright = ONE_FIXED/2;
302 /* flags */
303 lightPtr->LightFlags = LFlag_Omni;
304 /* lightblock light type */
305 lightPtr->LightType = LightType_PerVertex;
306 /* range */
307 lightPtr->LightRange = 200;
308
309 lightPtr->RedScale= ONE_FIXED;
310 lightPtr->GreenScale= ONE_FIXED;
311 lightPtr->BlueScale= ONE_FIXED;
312
313 {
314 VECTORCH position;
315 position.vx = MUL_FIXED(200,GetSin((CloakingPhase)&4095));
316 position.vy = MUL_FIXED(200,GetCos((CloakingPhase)&4095));
317 position.vz = 80+MUL_FIXED(50,GetCos((CloakingPhase/2)&4095));
318 {
319 MATRIXCH myMat = Global_VDB_Ptr->VDB_Mat;
320 TransposeMatrixCH(&myMat);
321 RotateVector(&(position), &(myMat));
322 position.vx += Global_VDB_Ptr->VDB_World.vx;
323 position.vy += Global_VDB_Ptr->VDB_World.vy;
324 position.vz += Global_VDB_Ptr->VDB_World.vz;
325 }
326 lightElementPtr->LightBlock.LightWorld = position;
327 }
328 lightElementPtr->LifeTime = 0;
329 break;
330 }
331 case LIGHTELEMENT_ALIEN_TEETH2:
332 {
333 lightPtr->LightBright = ONE_FIXED/2;
334 /* flags */
335 lightPtr->LightFlags = LFlag_Omni;
336 /* lightblock light type */
337 lightPtr->LightType = LightType_PerVertex;
338 /* range */
339 lightPtr->LightRange = 200;
340
341 lightPtr->RedScale= ONE_FIXED;
342 lightPtr->GreenScale= ONE_FIXED;
343 lightPtr->BlueScale= ONE_FIXED;
344
345 {
346 VECTORCH position;
347 position.vx = MUL_FIXED(200,GetSin((CloakingPhase/3+2048)&4095));
348 position.vy = MUL_FIXED(200,GetCos((CloakingPhase/3+2048)&4095));
349 position.vz = 80+MUL_FIXED(50,GetCos((CloakingPhase/2+2048)&4095));
350 {
351 MATRIXCH myMat = Global_VDB_Ptr->VDB_Mat;
352 TransposeMatrixCH(&myMat);
353 RotateVector(&(position), &(myMat));
354 position.vx += Global_VDB_Ptr->VDB_World.vx;
355 position.vy += Global_VDB_Ptr->VDB_World.vy;
356 position.vz += Global_VDB_Ptr->VDB_World.vz;
357 }
358 lightElementPtr->LightBlock.LightWorld = position;
359 }
360 lightElementPtr->LifeTime = 0;
361 break;
362 }
363 default: ;
364 }
365 }
366
367
HandleLightElementSystem(void)368 void HandleLightElementSystem(void)
369 {
370 int i = NumActiveLightElements;
371 LIGHTELEMENT *lightElementPtr = LightElementStorage;
372
373 while(i--)
374 {
375 LIGHTBLOCK *lightPtr = &(lightElementPtr->LightBlock);
376
377 switch(lightElementPtr->BehaviourID)
378 {
379 case LIGHTELEMENT_MOLTENMETAL:
380 {
381
382 lightPtr->LightBright = ONE_FIXED/4;
383 /* flags */
384 lightPtr->LightFlags = LFlag_Omni;
385 /* lightblock light type */
386 lightPtr->LightType = LightType_PerVertex;
387 /* range */
388 lightPtr->LightRange = EXPLOSION_LIGHT_RANGE;
389
390 lightPtr->RedScale= 255*256;
391 lightPtr->GreenScale= 120*256;
392 lightPtr->BlueScale= 0;
393
394 break;
395 }
396 case LIGHTELEMENT_PLASMACASTERHIT:
397 {
398 /* flags */
399 lightPtr->LightFlags = LFlag_Omni;
400 /* lightblock light type */
401 lightPtr->LightType = LightType_PerVertex;
402 /* range */
403 lightPtr->LightRange = EXPLOSION_LIGHT_RANGE;
404
405 if (lightElementPtr->LifeTime==ONE_FIXED)
406 {
407 lightPtr->LightBright = ONE_FIXED*4;
408
409 lightPtr->RedScale= 0*256;
410 lightPtr->GreenScale= 255*256;
411 lightPtr->BlueScale= 255*256;
412 }
413 else
414 {
415 lightPtr->LightBright = lightElementPtr->LifeTime/2;
416 lightPtr->LightRange = 1+MUL_FIXED(EXPLOSION_LIGHT_RANGE,lightElementPtr->LifeTime);
417
418 lightPtr->RedScale= 255*256;
419 lightPtr->GreenScale= 120*256;
420 lightPtr->BlueScale= 0*256;
421 }
422
423 lightElementPtr->LifeTime-=NormalFrameTime*4;
424
425 break;
426 }case LIGHTELEMENT_FROMFMV:
427 {
428 extern int FmvColourRed;
429 extern int FmvColourGreen;
430 extern int FmvColourBlue;
431
432 lightPtr->LightBright = ONE_FIXED*4;
433 /* flags */
434 lightPtr->LightFlags = LFlag_Omni;
435 /* lightblock light type */
436 lightPtr->LightType = LightType_PerVertex;
437 /* range */
438 lightPtr->LightRange = 15000;
439
440 lightPtr->RedScale= FmvColourRed;
441 lightPtr->GreenScale= FmvColourGreen;
442 lightPtr->BlueScale= FmvColourBlue;
443
444 break;
445 }
446 case LIGHTELEMENT_EXPLOSION:
447 {
448
449 /* flags */
450 lightPtr->LightFlags = LFlag_Omni;
451 /* lightblock light type */
452 lightPtr->LightType = LightType_PerVertex;
453
454 lightPtr->RedScale=255*256;
455 lightPtr->GreenScale=120*256;
456 lightPtr->BlueScale=0;
457 {
458 int scale = lightElementPtr->LifeTime*4;
459
460 if (scale < ONE_FIXED)
461 {
462 lightPtr->LightRange = 1+MUL_FIXED(EXPLOSION_LIGHT_RANGE,scale);
463 lightPtr->LightBright = scale*8;
464 }
465 else
466 {
467 lightPtr->LightRange = EXPLOSION_LIGHT_RANGE;
468 lightPtr->LightBright = ONE_FIXED*8;
469 }
470 }
471
472
473 {
474 PLAYER_STATUS *playerStatusPtr= (PLAYER_STATUS *) (Player->ObStrategyBlock->SBdataptr);
475
476 if (playerStatusPtr->IsAlive)
477 {
478 VECTORCH d = lightElementPtr->LightBlock.LightWorld;
479 int m;
480 d.vx -= Global_VDB_Ptr->VDB_World.vx;
481 d.vy -= Global_VDB_Ptr->VDB_World.vy;
482 d.vz -= Global_VDB_Ptr->VDB_World.vz;
483 m = Approximate3dMagnitude(&d);
484
485 if (m<ONE_FIXED)
486 {
487 int maxTilt = MUL_FIXED((ONE_FIXED-m)>>9,lightElementPtr->LifeTime);
488 int halfTilt = maxTilt/2;
489 if (maxTilt)
490 {
491 HeadOrientation.EulerX = (FastRandom()%maxTilt)-halfTilt;
492 HeadOrientation.EulerY = (FastRandom()%maxTilt)-halfTilt;
493 HeadOrientation.EulerZ = (FastRandom()%maxTilt)-halfTilt;
494
495 if (HeadOrientation.EulerX < 0) HeadOrientation.EulerX += 4096;
496 if (HeadOrientation.EulerY < 0) HeadOrientation.EulerY += 4096;
497 if (HeadOrientation.EulerZ < 0) HeadOrientation.EulerZ += 4096;
498 }
499 }
500 }
501 }
502 lightElementPtr->LifeTime-=NormalFrameTime;
503 break;
504 }
505 case LIGHTELEMENT_ELECTRICAL_EXPLOSION:
506 {
507 int scale = ONE_FIXED*5/4-lightElementPtr->LifeTime;
508
509 /* flags */
510 lightPtr->LightFlags = LFlag_Omni|LFlag_Electrical;
511 /* lightblock light type */
512 lightPtr->LightType = LightType_PerVertex;
513
514 if (scale>65536) scale = 65536;
515 scale = ONE_FIXED - scale;
516
517 lightPtr->RedScale= scale;
518 lightPtr->GreenScale=ONE_FIXED;
519 lightPtr->BlueScale=ONE_FIXED;
520 lightPtr->LightRange = EXPLOSION_LIGHT_RANGE;// 1+MUL_FIXED(EXPLOSION_LIGHT_RANGE,scale);
521 lightPtr->LightBright = scale*16;
522
523 lightElementPtr->LifeTime-=NormalFrameTime;
524 break;
525 }
526 case LIGHTELEMENT_ELECTRICAL_SPARKS:
527 {
528 int scale = lightElementPtr->LifeTime;
529
530 /* flags */
531 lightPtr->LightFlags = LFlag_Omni|LFlag_Electrical;
532 /* lightblock light type */
533 lightPtr->LightType = LightType_PerVertex;
534
535 if (scale == ONE_FIXED)
536 {
537 lightPtr->RedScale=ONE_FIXED;
538 lightPtr->GreenScale=ONE_FIXED;
539 lightPtr->BlueScale=ONE_FIXED;
540 }
541 else
542 {
543 lightPtr->RedScale= 0;
544 lightPtr->GreenScale= scale/2;
545 lightPtr->BlueScale= scale;
546 }
547 lightPtr->LightRange = 4000;// 1+MUL_FIXED(EXPLOSION_LIGHT_RANGE,scale);
548 lightPtr->LightBright = scale;
549
550 lightElementPtr->LifeTime-=NormalFrameTime*2;
551 break;
552 }
553
554 case LIGHTELEMENT_ROTATING:
555 {
556
557 lightPtr->LightBright = ONE_FIXED/2;
558 /* flags */
559 lightPtr->LightFlags = LFlag_Omni;
560 /* lightblock light type */
561 lightPtr->LightType = LightType_PerVertex;
562 /* range */
563 lightPtr->LightRange = 10000;
564
565 lightPtr->RedScale= ONE_FIXED;
566 lightPtr->GreenScale= ONE_FIXED;
567 lightPtr->BlueScale= ONE_FIXED;
568
569 lightElementPtr->LightBlock.LightWorld = Player->ObWorld;//RotatingLightPosition;
570 // lightElementPtr->LightBlock.LightWorld.vx += MUL_FIXED(2000,GetCos((CloakingPhase/2)&4095));
571 lightElementPtr->LightBlock.LightWorld.vy -= 2200;
572 // lightElementPtr->LightBlock.LightWorld.vz += MUL_FIXED(2000,GetSin((CloakingPhase/2)&4095));
573 #if 0
574 {
575
576 VECTORCH zero = {0,0,0};
577 MakeParticle(&(lightElementPtr->LightBlock.LightWorld),&zero,PARTICLE_SPARK);
578 }
579 #endif
580 break;
581 }
582 case LIGHTELEMENT_ALIEN_TEETH:
583 case LIGHTELEMENT_ALIEN_TEETH2:
584 {
585 break;
586 }
587
588 case LIGHTELEMENT_PARGEN_FLAME :
589 {
590 if(lightElementPtr->LifeTime == ONE_FIXED)
591 {
592 lightElementPtr->LifeTime = 1;
593
594 /* flags */
595 lightPtr->LightFlags = LFlag_Omni;
596 /* lightblock light type */
597 lightPtr->LightType = LightType_PerVertex;
598
599 //lightPtr->RedScale= 255*256;
600 //lightPtr->GreenScale= 120*256;
601 lightPtr->RedScale= 255*(200+(CloakingPhase%56));
602 lightPtr->GreenScale= 120*(200+((CloakingPhase/8)%56));
603 lightPtr->BlueScale= 0;
604
605 lightPtr->LightRange = 6000;
606 lightPtr->LightBright = ONE_FIXED;
607
608 }
609 else
610 {
611 lightElementPtr->LifeTime = 0;
612 }
613 }
614 break;
615
616 default:
617 break;
618 }
619
620 lightPtr->BrightnessOverRange = DIV_FIXED(MUL_FIXED(lightPtr->LightBright,LightScale),lightPtr->LightRange);
621
622 if (lightElementPtr->LifeTime<=0)
623 {
624 DeallocateLightElement(lightElementPtr);
625 }
626 else
627 {
628 lightElementPtr++;
629 }
630 }
631 }
632
633
634 /*--------------------------**
635 ** Load/Save Light Elements **
636 **--------------------------*/
637 #include "savegame.h"
638
639 typedef struct light_element_save_block_header
640 {
641 SAVE_BLOCK_HEADER header;
642
643 int NumActiveLightElements;
644
645 //followed by array of light elements
646 }LIGHT_ELEMENT_SAVE_BLOCK_HEADER;
647
Load_LightElements(SAVE_BLOCK_HEADER * header)648 void Load_LightElements(SAVE_BLOCK_HEADER* header)
649 {
650 int i;
651 LIGHT_ELEMENT_SAVE_BLOCK_HEADER* block = (LIGHT_ELEMENT_SAVE_BLOCK_HEADER*) header;
652 LIGHTELEMENT* saved_light_element = (LIGHTELEMENT*) (block+1);
653 int expected_size;
654
655 //make sure the block is the correct size
656 expected_size = sizeof(*block);
657 expected_size += sizeof(LIGHTELEMENT) * block->NumActiveLightElements;
658 if(header->size != expected_size) return;
659
660
661 for(i=0;i<block->NumActiveLightElements;i++)
662 {
663 LIGHTELEMENT* light_element = AllocateLightElement();
664 if(light_element)
665 {
666 *light_element = *saved_light_element++;
667 }
668 }
669
670 }
671
Save_LightElements()672 void Save_LightElements()
673 {
674 LIGHT_ELEMENT_SAVE_BLOCK_HEADER* block;
675 int i;
676
677 if(!NumActiveLightElements) return;
678
679 //get memory for header
680 GET_SAVE_BLOCK_POINTER(block);
681
682 //fill in header
683 block->header.type = SaveBlock_LightElements;
684 block->header.size = sizeof(*block) + NumActiveLightElements * sizeof(LIGHTELEMENT);
685
686 block->NumActiveLightElements = NumActiveLightElements;
687
688
689 //now save the light elements
690 for(i=0;i<NumActiveLightElements;i++)
691 {
692 LIGHTELEMENT* light = GET_SAVE_BLOCK_POINTER(light);
693 *light = LightElementStorage[i];
694 }
695
696 }
697