Oolite 1.91.0.7645-241119-222d325
Loading...
Searching...
No Matches
OOPlanetEntity.m
Go to the documentation of this file.
1/*
2
3OOPlanetEntity.m
4
5Oolite
6Copyright (C) 2004-2013 Giles C Williams and contributors
7
8This program is free software; you can redistribute it and/or
9modify it under the terms of the GNU General Public License
10as published by the Free Software Foundation; either version 2
11of the License, or (at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21MA 02110-1301, USA.
22
23*/
24
25#import "OOPlanetEntity.h"
26
27#if NEW_PLANETS
28
29#define NEW_ATMOSPHERE 1
30
31#import "OOPlanetDrawable.h"
32
33#import "AI.h"
34#import "Universe.h"
35#import "ShipEntity.h"
36#import "PlayerEntity.h"
37#import "ShipEntityAI.h"
38#import "OOCharacter.h"
39
40#import "OOMaths.h"
41#import "ResourceManager.h"
42#import "OOStringParsing.h"
45
49#import "OOShaderMaterial.h"
52#import "OOStringExpander.h"
54
55
56#define OO_TERMINATOR_THRESHOLD_VECTOR_DEFAULT (make_vector(0.105, 0.18, 0.28)) // used to be (0.1, 0.105, 0.12);
57
58
59@interface OOPlanetEntity (Private) <OOGraphicsResetClient>
60
61- (void) setUpTerrainParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo;
62- (void) setUpLandParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo;
63- (void) setUpAtmosphereParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo;
64- (void) setUpColorParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo isAtmosphere:(BOOL)isAtmosphere;
65- (void) setUpTypeParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo;
66
67@end
68
69
70@implementation OOPlanetEntity
71
72// this is exclusively called to initialise the main planet.
73- (id) initAsMainPlanetForSystem:(OOSystemID)s
74{
75 NSMutableDictionary *planetInfo = [[UNIVERSE generateSystemData:s] mutableCopy];
76 [planetInfo autorelease];
77
78 [planetInfo oo_setBool:YES forKey:@"mainForLocalSystem"];
79 if (s != [PLAYER systemID])
80 {
81 [planetInfo oo_setBool:YES forKey:@"isMiniature"];
82 }
83 return [self initFromDictionary:planetInfo withAtmosphere:[planetInfo oo_boolForKey:@"has_atmosphere" defaultValue:YES] andSeed:[[UNIVERSE systemManager] getRandomSeedForSystem:s inGalaxy:[PLAYER galaxyNumber]] forSystem:s];
84}
85
86
87static const double kMesosphere = 10.0 * ATMOSPHERE_DEPTH; // atmosphere effect starts at 10x the height of the clouds
88
89
90- (id) initFromDictionary:(NSDictionary *)dict withAtmosphere:(BOOL)atmosphere andSeed:(Random_Seed)seed forSystem:(OOSystemID)systemID
91{
92 if (dict == nil) dict = [NSDictionary dictionary];
93 RANROTSeed savedRanrotSeed = RANROTGetFullSeed();
94
95 self = [self init];
96 if (self == nil) return nil;
97
98 scanClass = CLASS_NO_DRAW;
99
100 NSMutableDictionary *planetInfo = [[UNIVERSE generateSystemData:systemID] mutableCopy];
101 [planetInfo autorelease];
102
103 [self setUpTypeParametersWithSourceInfo:dict targetInfo:planetInfo];
104
105 [self setUpTerrainParametersWithSourceInfo:dict targetInfo:planetInfo];
106
107
108 // Load random seed override.
109 NSString *seedStr = [dict oo_stringForKey:@"seed"];
110 if (seedStr != nil)
111 {
112 Random_Seed overrideSeed = RandomSeedFromString(seedStr);
113 if (!is_nil_seed(overrideSeed)) seed = overrideSeed;
114 else OOLogERR(@"planet.fromDict", @"could not interpret \"%@\" as planet seed, using default.", seedStr);
115 }
116
117 // Generate various planet info.
119
120 _name = nil;
121 [self setName:OOExpand([dict oo_stringForKey:KEY_PLANETNAME defaultValue:[planetInfo oo_stringForKey:KEY_PLANETNAME defaultValue:@"%H"]])];
122
123 int radius_km = [dict oo_intForKey:KEY_RADIUS defaultValue:[planetInfo oo_intForKey:KEY_RADIUS]];
124 collision_radius = radius_km * 10.0; // Scale down by a factor of 100
125 OOTechLevelID techLevel = [dict oo_intForKey:KEY_TECHLEVEL defaultValue:[planetInfo oo_intForKey:KEY_TECHLEVEL]];
126
127 if (techLevel > 14) techLevel = 14;
128 _shuttlesOnGround = 1 + techLevel / 2;
129 _shuttleLaunchInterval = 3600.0 / (double)_shuttlesOnGround; // All are launched in one hour.
130 _lastLaunchTime = [UNIVERSE getTime] + 30.0 - _shuttleLaunchInterval; // launch 30s after player enters universe.
131 // make delay > 0 to allow scripts adding a station nearby.
132
133 int percent_land = [planetInfo oo_intForKey:@"percent_land" defaultValue:24 + (gen_rnd_number() % 48)];
134 [planetInfo setObject:[NSNumber numberWithFloat:0.01 * percent_land] forKey:@"land_fraction"];
135
136 int percent_ice = [planetInfo oo_intForKey:@"percent_ice" defaultValue:5];
137 [planetInfo setObject:[NSNumber numberWithFloat:0.01 * percent_ice] forKey:@"polar_fraction"];
138
139
140 RNG_Seed savedRndSeed = currentRandomSeed();
141
142 _planetDrawable = [[OOPlanetDrawable alloc] init];
143
144 _terminatorThresholdVector = [planetInfo oo_vectorForKey:@"terminator_threshold_vector" defaultValue:OO_TERMINATOR_THRESHOLD_VECTOR_DEFAULT];
145
146 // Load material parameters, including atmosphere.
147 RANROTSeed planetNoiseSeed = RANROTGetFullSeed();
148 [planetInfo setObject:[NSValue valueWithBytes:&planetNoiseSeed objCType:@encode(RANROTSeed)] forKey:@"noise_map_seed"];
149 [self setUpLandParametersWithSourceInfo:dict targetInfo:planetInfo];
150
151 _airColor = nil; // default to no air
152 _airColorMixRatio = 0.5f;
153 _airDensity = 0.75f;
154
155 _illuminationColor = [[planetInfo objectForKey:@"illumination_color"] retain];
156
157#if NEW_ATMOSPHERE
158 if (atmosphere)
159 {
160 // shader atmosphere always has a radius of collision_radius + ATMOSPHERE_DEPTH. For texture atmosphere, we need to check
161 // if a shader atmosphere is also used. If yes, set its radius to just cover the planet so that it doesn't conflict with
162 // the shader atmosphere at the planet edges. If no shader atmosphere is used, then set it to the standard radius
163 double atmosphereRadius = [UNIVERSE detailLevel] >= DETAIL_LEVEL_SHADERS ? collision_radius : collision_radius + ATMOSPHERE_DEPTH;
164 _atmosphereDrawable = [[OOPlanetDrawable atmosphereWithRadius:atmosphereRadius] retain];
165 _atmosphereShaderDrawable = [[OOPlanetDrawable atmosphereWithRadius:collision_radius + ATMOSPHERE_DEPTH] retain];
166
167 // convert the atmosphere settings to generic 'material parameters'
168 percent_land = 100 - [dict oo_intForKey:@"percent_cloud" defaultValue:100 - (3 + (gen_rnd_number() & 31)+(gen_rnd_number() & 31))];
169 [planetInfo setObject:[NSNumber numberWithFloat:0.01 * percent_land] forKey:@"cloud_fraction"];
170 [self setUpAtmosphereParametersWithSourceInfo:dict targetInfo:planetInfo];
171 // planetInfo now contains a valid air_color
172 _airColor = [[planetInfo objectForKey:@"air_color"] retain];
173 _airColorMixRatio = [planetInfo oo_floatForKey:@"air_color_mix_ratio"];
174
175 _airDensity = OOClamp_0_1_f([planetInfo oo_floatForKey:@"air_density"]);
176 // OOLog (@"planet.debug",@" translated air colour:%@ cloud colour:%@ polar cloud color:%@", [_airColor rgbaDescription],[(OOColor *)[planetInfo objectForKey:@"cloud_color"] rgbaDescription],[(OOColor *)[planetInfo objectForKey:@"polar_cloud_color"] rgbaDescription]);
177
178 _materialParameters = [planetInfo dictionaryWithValuesForKeys:[NSArray arrayWithObjects:@"cloud_fraction", @"air_color", @"air_color_mix_ratio", @"air_density", @"cloud_color", @"polar_cloud_color", @"cloud_alpha", @"land_fraction", @"land_color", @"sea_color", @"polar_land_color", @"polar_sea_color", @"noise_map_seed", @"economy", @"polar_fraction", @"isMiniature", @"perlin_3d", @"terminator_threshold_vector", nil]];
179 }
180 else
181#else
182 // NEW_ATMOSPHERE is 0? still differentiate between normal planets and moons.
183 if (atmosphere)
184 {
185 _atmosphereDrawable = [[OOPlanetDrawable atmosphereWithRadius:collision_radius + ATMOSPHERE_DEPTH] retain];
186 _airColor = [[OOColor colorWithRed:0.8f green:0.8f blue:0.9f alpha:1.0f] retain];
187 }
188 if (YES) // create _materialParameters when NEW_ATMOSPHERE is set to 0
189#endif
190 {
191 _materialParameters = [planetInfo dictionaryWithValuesForKeys:[NSArray arrayWithObjects:@"land_fraction", @"land_color", @"sea_color", @"polar_land_color", @"polar_sea_color", @"noise_map_seed", @"economy", @"polar_fraction", @"isMiniature", @"perlin_3d", @"terminator_threshold_vector", @"illumination_color", nil]];
192 }
193 [_materialParameters retain];
194
195 _mesopause2 = (atmosphere) ? (kMesosphere + collision_radius) * (kMesosphere + collision_radius) : 0.0;
196
197 _normSpecMapName = [[dict oo_stringForKey:@"texture_normspec"] retain]; // must be set up before _textureName
198
199 _textureName = [[dict oo_stringForKey:@"texture"] retain];
200 [self setUpPlanetFromTexture:_textureName];
201 [_planetDrawable setRadius:collision_radius];
202
203 // Orientation should be handled by the code that calls this planetEntity. Starting with a default value anyway.
204 orientation = (Quaternion){ M_SQRT1_2, M_SQRT1_2, 0, 0 };
205 _atmosphereOrientation = kIdentityQuaternion;
206 _rotationAxis = vector_up_from_quaternion(orientation);
207
208 // set speed of rotation.
209 if ([dict objectForKey:@"rotational_velocity"])
210 {
211 _rotationalVelocity = [dict oo_floatForKey:@"rotational_velocity" defaultValue:0.01f * randf()]; // 0.0 .. 0.01 avr 0.005
212 }
213 else
214 {
215 _rotationalVelocity = [planetInfo oo_floatForKey:@"rotation_speed" defaultValue:0.005f * randf()]; // 0.0 .. 0.005 avr 0.0025
216 _rotationalVelocity *= [planetInfo oo_floatForKey:@"rotation_speed_factor" defaultValue:1.0f];
217 }
218
219 _atmosphereRotationalVelocity = [dict oo_floatForKey:@"atmosphere_rotational_velocity" defaultValue:0.01f * randf()];
220
221 // set energy
222 energy = collision_radius * 1000.0f;
223
224 setRandomSeed(savedRndSeed);
225 RANROTSetFullSeed(savedRanrotSeed);
226
227 // rotate planet based on current time, needs to be done here - backported from PlanetEntity.
228 int deltaT = floor(fmod([PLAYER clockTimeAdjusted], 86400));
229 quaternion_rotate_about_axis(&orientation, _rotationAxis, _rotationalVelocity * deltaT);
230 quaternion_rotate_about_axis(&_atmosphereOrientation, kBasisYVector, _atmosphereRotationalVelocity * deltaT);
231
232
233#ifdef OO_DUMP_PLANETINFO
234#define CPROP(PROP) OOLog(@"planetinfo.record",@#PROP " = %@;",[(OOColor *)[planetInfo objectForKey:@#PROP] descriptionComponents]);
235#define FPROP(PROP) OOLog(@"planetinfo.record",@#PROP " = %f;",[planetInfo oo_floatForKey:@"" #PROP]);
236 CPROP(air_color);
237 CPROP(illumination_color);
238 FPROP(air_color_mix_ratio);
239 FPROP(cloud_alpha);
240 CPROP(cloud_color);
241 FPROP(cloud_fraction);
242 CPROP(land_color);
243 FPROP(land_fraction);
244 CPROP(polar_cloud_color);
245 CPROP(polar_land_color);
246 CPROP(polar_sea_color);
247 CPROP(sea_color);
248 OOLog(@"planetinfo.record",@"rotation_speed = %f",_rotationalVelocity);
249#endif
250
251 [self setStatus:STATUS_ACTIVE];
252
254
255 return self;
256}
257
258
259static Vector RandomHSBColor(void)
260{
261 return (Vector)
262 {
263 gen_rnd_number() / 256.0,
264 gen_rnd_number() / 256.0,
265 0.5 + gen_rnd_number() / 512.0
266 };
267}
268
269
270static Vector LighterHSBColor(Vector c)
271{
272 return (Vector)
273 {
274 c.x,
275 c.y * 0.25f,
276 1.0f - (c.z * 0.1f)
277 };
278}
279
280
281static Vector HSBColorWithColor(OOColor *color)
282{
284 return (Vector){ c.h/360, c.s, c.b };
285}
286
287
288static OOColor *ColorWithHSBColor(Vector c)
289{
290 return [OOColor colorWithHue:c.x saturation:c.y brightness:c.z alpha:1.0];
291}
292
293
294- (void) setUpTypeParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo
295{
296 [targetInfo oo_setBool:[sourceInfo oo_boolForKey:@"mainForLocalSystem"] forKey:@"mainForLocalSystem"];
297 [targetInfo oo_setBool:[sourceInfo oo_boolForKey:@"isMiniature"] forKey:@"isMiniature"];
298
299}
300
301
302- (void) setUpTerrainParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo
303{
304 NSArray *keys = [NSArray arrayWithObjects:@"atmosphere_rotational_velocity",@"rotational_velocity",@"cloud_alpha",@"has_atmosphere",@"percent_cloud",@"percent_ice",@"percent_land",@"radius",@"seed",nil];
305 NSString *key = nil;
306 foreach (key, keys) {
307 id sval = [sourceInfo objectForKey:key];
308 if (sval != nil) {
309 [targetInfo setObject:sval forKey:key];
310 }
311 }
312
313}
314
315
316- (void) setUpLandParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo
317{
318 [self setUpColorParametersWithSourceInfo:sourceInfo targetInfo:targetInfo isAtmosphere:NO];
319}
320
321
322- (void) setUpAtmosphereParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo
323{
324 [self setUpColorParametersWithSourceInfo:sourceInfo targetInfo:targetInfo isAtmosphere:YES];
325}
326
327
328- (void) setUpColorParametersWithSourceInfo:(NSDictionary *)sourceInfo targetInfo:(NSMutableDictionary *)targetInfo isAtmosphere:(BOOL)isAtmosphere
329{
330 // Stir the PRNG fourteen times for backwards compatibility.
331 unsigned i;
332 for (i = 0; i < 14; i++)
333 {
335 }
336
337 Vector landHSB, seaHSB, landPolarHSB, seaPolarHSB, illumHSB;
338 Vector terminatorThreshold;
339 OOColor *color;
340
341 landHSB = RandomHSBColor();
342
343 if (!isAtmosphere)
344 {
345 do
346 {
347 seaHSB = RandomHSBColor();
348 }
349 while (dot_product(landHSB, seaHSB) > .80f); // make sure land and sea colors differ significantly
350
351 // saturation bias - avoids really grey oceans
352 if (seaHSB.y < 0.22f) seaHSB.y = seaHSB.y * 0.3f + 0.2f;
353 // brightness bias - avoids really bright landmasses
354 if (landHSB.z > 0.66f) landHSB.z = 0.66f;
355
356 // planetinfo.plist overrides
357 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"land_color"]];
358 if (color != nil) landHSB = HSBColorWithColor(color);
359 else ScanVectorFromString([sourceInfo oo_stringForKey:@"land_hsb_color"], &landHSB);
360
361 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"sea_color"]];
362 if (color != nil) seaHSB = HSBColorWithColor(color);
363 else ScanVectorFromString([sourceInfo oo_stringForKey:@"sea_hsb_color"], &seaHSB);
364
365 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"illumination_color"]];
366 if (color != nil) illumHSB = HSBColorWithColor(color);
367 else
368 {
369 NSString *illumHSBColorString = [sourceInfo oo_stringForKey:@"illumination_hsb_color"];
370 if (illumHSBColorString) ScanVectorFromString(illumHSBColorString, &illumHSB);
371 else illumHSB = HSBColorWithColor([OOColor colorWithRed:0.8f green:0.8f blue:0.4f alpha:1.0f]);
372 }
373
374 // polar areas are brighter but have less colour (closer to white)
375 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"polar_land_color"]];
376 if (color != nil)
377 {
378 landPolarHSB = HSBColorWithColor(color);
379 }
380 else
381 {
382 landPolarHSB = LighterHSBColor(landHSB);
383 }
384
385 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"polar_sea_color"]];
386 if (color != nil)
387 {
388 seaPolarHSB = HSBColorWithColor(color);
389 }
390 else
391 {
392 seaPolarHSB = LighterHSBColor(seaHSB);
393 }
394
395 [targetInfo setObject:ColorWithHSBColor(landHSB) forKey:@"land_color"];
396 [targetInfo setObject:ColorWithHSBColor(seaHSB) forKey:@"sea_color"];
397 [targetInfo setObject:ColorWithHSBColor(landPolarHSB) forKey:@"polar_land_color"];
398 [targetInfo setObject:ColorWithHSBColor(seaPolarHSB) forKey:@"polar_sea_color"];
399 [targetInfo setObject:ColorWithHSBColor(illumHSB) forKey:@"illumination_color"];
400 }
401 else
402 {
403 landHSB = RandomHSBColor(); // NB: randomcolor is called twice to make the cloud colour similar to the old one.
404
405 // add a cloud_color tinge to sky blue({0.66, 0.3, 1}).
406 seaHSB = vector_add(landHSB,((Vector){1.333, 0.6, 2})); // 1 part cloud, 2 parts sky blue
407 scale_vector(&seaHSB, 0.333);
408
409 float cloudAlpha = OOClamp_0_1_f([sourceInfo oo_floatForKey:@"cloud_alpha" defaultValue:1.0f]);
410 [targetInfo setObject:[NSNumber numberWithFloat:cloudAlpha] forKey:@"cloud_alpha"];
411
412 // planetinfo overrides
413 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"air_color"]];
414 if (color != nil) seaHSB = HSBColorWithColor(color);
415
416 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"cloud_color"]];
417 if (color != nil) landHSB = HSBColorWithColor(color);
418
419 // polar areas: brighter, less saturation
420 landPolarHSB = vector_add(landHSB,LighterHSBColor(landHSB));
421 scale_vector(&landPolarHSB, 0.5);
422
423 color = [OOColor colorWithDescription:[sourceInfo objectForKey:@"polar_cloud_color"]];
424 if (color != nil) landPolarHSB = HSBColorWithColor(color);
425
426 [targetInfo setObject:ColorWithHSBColor(seaHSB) forKey:@"air_color"];
427 [targetInfo setObject:ColorWithHSBColor(landHSB) forKey:@"cloud_color"];
428 [targetInfo setObject:ColorWithHSBColor(landPolarHSB) forKey:@"polar_cloud_color"];
429 [targetInfo setObject:[NSNumber numberWithFloat:[sourceInfo oo_floatForKey:@"air_color_mix_ratio"]] forKey:@"air_color_mix_ratio"];
430 }
431 terminatorThreshold = [sourceInfo oo_vectorForKey:@"terminator_threshold_vector" defaultValue:OO_TERMINATOR_THRESHOLD_VECTOR_DEFAULT];
432 [targetInfo setObject:[NSString stringWithFormat:@"%f %f %f", terminatorThreshold.x, terminatorThreshold.y, terminatorThreshold.z] forKey:@"terminator_threshold_vector"];
433}
434
435
436- (id) initAsMiniatureVersionOfPlanet:(OOPlanetEntity *)planet
437{
438 // Nasty, nasty. I'd really prefer to have a separate entity class for this.
439 if (planet == nil)
440 {
441 [self release];
442 return nil;
443 }
444
445 self = [self init];
446 if (self == nil) return nil;
447
448 scanClass = CLASS_NO_DRAW;
449 [self setStatus:STATUS_COCKPIT_DISPLAY];
450
451 collision_radius = planet->collision_radius * PLANET_MINIATURE_FACTOR;
452 orientation = planet->orientation;
453 _rotationAxis = planet->_rotationAxis;
454 _atmosphereOrientation = planet->_atmosphereOrientation;
455 _rotationalVelocity = 0.04;
456
457 _terminatorThresholdVector = planet->_terminatorThresholdVector;
458
459 _miniature = YES;
460
461 _planetDrawable = [planet->_planetDrawable copy];
462 [_planetDrawable setRadius:collision_radius];
463
464 // FIXME: in old planet code, atmosphere (if textured) is set to 0.6 alpha.
465 _atmosphereDrawable = [planet->_atmosphereDrawable copy];
466 _atmosphereShaderDrawable = [planet->_atmosphereShaderDrawable copy];
467 [_atmosphereDrawable setRadius:collision_radius + ATMOSPHERE_DEPTH * PLANET_MINIATURE_FACTOR * 2.0]; //not to scale: invisible otherwise
468 if (_atmosphereShaderDrawable) [_atmosphereShaderDrawable setRadius:collision_radius + ATMOSPHERE_DEPTH * PLANET_MINIATURE_FACTOR * 2.0];
469
470 [_planetDrawable setLevelOfDetail:0.8f];
471 [_atmosphereDrawable setLevelOfDetail:0.8f];
472 if (_atmosphereShaderDrawable) [_atmosphereShaderDrawable setLevelOfDetail:0.8f];
473
474 return self;
475}
476
477
478- (void) dealloc
479{
480 DESTROY(_name);
481 DESTROY(_planetDrawable);
482 DESTROY(_atmosphereDrawable);
483 DESTROY(_atmosphereShaderDrawable);
484 DESTROY(_airColor);
485 DESTROY(_illuminationColor);
486 DESTROY(_materialParameters);
487 DESTROY(_textureName);
488 DESTROY(_normSpecMapName);
489
491
492 [super dealloc];
493}
494
495
496- (NSString*) descriptionComponents
497{
498 return [NSString stringWithFormat:@"position: %@ radius: %g m", HPVectorDescription([self position]), [self radius]];
499}
500
501
502- (void) setOrientation:(Quaternion) quat
503{
504 [super setOrientation: quat];
505 _rotationAxis = vector_up_from_quaternion(quat);
506}
507
508
509- (double) radius
510{
511 return collision_radius;
512}
513
514
515- (OOStellarBodyType) planetType
516{
517 if (_miniature) return STELLAR_TYPE_MINIATURE;
518 if (_atmosphereDrawable != nil) return STELLAR_TYPE_NORMAL_PLANET;
519 return STELLAR_TYPE_MOON;
520}
521
522
523- (instancetype) miniatureVersion
524{
525 return [[[[self class] alloc] initAsMiniatureVersionOfPlanet:self] autorelease];
526}
527
528
529- (void) update:(OOTimeDelta) delta_t
530{
531 [super update:delta_t];
532
533 if (EXPECT(!_miniature))
534 {
535 BOOL canDrawShaderAtmosphere = _atmosphereShaderDrawable && [UNIVERSE detailLevel] >= DETAIL_LEVEL_SHADERS;
536 if (EXPECT_NOT(_atmosphereDrawable && cam_zero_distance < _mesopause2))
537 {
538 NSAssert(_airColor != nil, @"Expected a non-nil air colour for normal planet. Exiting.");
539 double alt = (sqrt(cam_zero_distance) - collision_radius) / kMesosphere; // the viewpoint altitude
540 double trueAlt = (sqrt(zero_distance) - collision_radius) / kMesosphere; // the actual ship altitude
541 // if at long distance external view, rotating the camera could potentially end up with it being
542 // at negative altitude. Since we know we are already inside the atmosphere at this point, just make sure
543 // that altitude is kept to a minimum positive value to avoid sudden black skies
544 if (alt <= 0.0) alt = 1e-4;
545 if (EXPECT_NOT(alt > 0 && alt <= 1.0)) // ensure aleph is clamped between 0 and 1
546 {
547 double aleph = 1.0 - alt;
548 double aleph2 = aleph * aleph;
549
550 // night sky, reddish flash on entering the atmosphere, low light pollution otherwhise
551 OOColor *mixColor = [OOColor colorWithRed:(EXPECT_NOT(alt > 0.98) ? 30.0f : 0.1f)
552 green:0.1f
553 blue:0.1f
554 alpha:aleph];
555
556 // occlusion rate: .9 is 18 degrees after the terminus, where twilight ends.
557 // 1 is the terminus, 1.033 is 6 degrees before the terminus, where the sky begins to redden
558 double rate = ([PLAYER occlusionLevel] - 0.97)/0.06; // from 0.97 to 1.03
559
560 if (EXPECT(rate <= 1.0 && rate > 0.0))
561 {
562 mixColor = [mixColor blendedColorWithFraction:rate ofColor:_airColor];
563 // TODO: properly calculated pink sky - needs to depend on sun's angular size,
564 // and its angular height on the horizon.
565 /*
566 rate -= 0.7;
567 if (rate >= 0.0) // pink sky!
568 {
569 rate = 0.5 - (fabs(rate - 0.15) / 0.3); // at most a 50% blend!
570 mixColor = [mixColor blendedColorWithFraction:rate ofColor:[OOColor colorWithRed:0.6
571 green:0.1
572 blue:0.0
573 alpha:aleph]];
574 }
575 */
576 }
577 else
578 {
579 if (PLAYER->isSunlit && _airColor != nil) mixColor = _airColor;
580 }
581 [UNIVERSE setSkyColorRed:[mixColor redComponent] * aleph2
582 green:[mixColor greenComponent] * aleph2
583 blue:[mixColor blueComponent] * aleph
584 alpha:aleph];
585 double atmosphereRadius = canDrawShaderAtmosphere ? collision_radius : collision_radius + (ATMOSPHERE_DEPTH * alt);
586 [_atmosphereDrawable setRadius:atmosphereRadius];
587 if (_atmosphereShaderDrawable) [_atmosphereShaderDrawable setRadius:collision_radius + (ATMOSPHERE_DEPTH * alt)];
588 // apply air resistance for the ship, not the camera. Although setSkyColorRed
589 // has already set the air resistance to aleph, override it immediately
590 [UNIVERSE setAirResistanceFactor:OOClamp_0_1_f(1.0 - trueAlt)];
591 }
592 }
593 else
594 {
595 if (EXPECT_NOT([_atmosphereDrawable radius] < collision_radius + ATMOSPHERE_DEPTH))
596 {
597 [_atmosphereDrawable setRadius:collision_radius + ATMOSPHERE_DEPTH];
598 if (_atmosphereShaderDrawable) [_atmosphereShaderDrawable setRadius:collision_radius + ATMOSPHERE_DEPTH];
599 }
600 if (canDrawShaderAtmosphere && [_atmosphereDrawable radius] != collision_radius)
601 {
602 // if shader atmo is in use, force texture atmo radius to just collision_radius for cosmetic purposes
603 [_atmosphereDrawable setRadius:collision_radius];
604 }
605 if ([PLAYER findNearestPlanet] == self) // ensure no problems in case of more than one planets
606 {
607 [UNIVERSE setAirResistanceFactor:0.0f]; // out of atmosphere - no air friction
608 }
609 }
610
611 double time = [UNIVERSE getTime];
612
613 if (_shuttlesOnGround > 0 && time > _lastLaunchTime + _shuttleLaunchInterval) [self launchShuttle];
614 }
615
616 quaternion_rotate_about_axis(&orientation, _rotationAxis, _rotationalVelocity * delta_t);
617 // atmosphere orientation is relative to the orientation of the planet
618 quaternion_rotate_about_axis(&_atmosphereOrientation, kBasisYVector, _atmosphereRotationalVelocity * delta_t);
619
620 [self orientationChanged];
621
622 // FIXME: update atmosphere rotation
623}
624
625
626- (BOOL) isFinishedLoading
627{
628 OOMaterial *material = [self material];
629 if (material != nil && ![material isFinishedLoading]) return NO;
630 material = [self atmosphereMaterial];
631 if (material != nil && ![material isFinishedLoading]) return NO;
632 material = [self atmosphereShaderMaterial];
633 if (material != nil && ![material isFinishedLoading]) return NO;
634 return YES;
635}
636
637
638- (void) drawImmediate:(bool)immediate translucent:(bool)translucent
639{
640 BOOL canDrawShaderAtmosphere = _atmosphereShaderDrawable && [UNIVERSE detailLevel] >= DETAIL_LEVEL_SHADERS;
641
642 if ([UNIVERSE breakPatternHide]) return; // DON'T DRAW
643 if (_miniature && ![self isFinishedLoading]) return; // For responsiveness, don't block to draw as miniature.
644
645 // too far away to be drawn
646 if (magnitude(cameraRelativePosition) > [self radius]*3000) {
647 return;
648 }
649 if (![UNIVERSE viewFrustumIntersectsSphereAt:cameraRelativePosition withRadius:([self radius] + ATMOSPHERE_DEPTH)])
650 {
651 // Don't draw
652 return;
653 }
654
655 if ([UNIVERSE wireframeGraphics]) OOGLWireframeModeOn();
656
657 if (!_miniature)
658 {
659 [_planetDrawable calculateLevelOfDetailForViewDistance:cam_zero_distance];
660 [_atmosphereDrawable setLevelOfDetail:[_planetDrawable levelOfDetail]];
661 if (canDrawShaderAtmosphere) [_atmosphereShaderDrawable setLevelOfDetail:[_planetDrawable levelOfDetail]];
662 }
663
664 // 500km squared
665 // if (magnitude2(cameraRelativePosition) > 250000000000.0)
666 /* Temporarily for 1.82 make this branch unconditional. There's an
667 * odd change in appearance when crossing this boundary, which can
668 * be quite noticeable. There don't appear to be close-range
669 * problems with doing it this way all the time, though it's not
670 * ideal. - CIM */
671 {
672 /* at this distance the atmosphere is too close to the planet
673 * for a 24-bit depth buffer to reliably distinguish the two,
674 * so cheat and draw the atmosphere on the opaque pass: it's
675 * far enough away that painter's algorithm should do fine */
676 [_planetDrawable renderOpaqueParts];
677 if (_atmosphereDrawable != nil)
678 {
680 OOGLMultModelView(OOMatrixForQuaternionRotation(_atmosphereOrientation));
681 [_atmosphereDrawable renderTranslucentPartsOnOpaquePass];
682 if (canDrawShaderAtmosphere) [_atmosphereShaderDrawable renderTranslucentPartsOnOpaquePass];
684 }
685 }
686#if OOLITE_HAVE_FIXED_THE_ABOVE_DESCRIBED_BUG_WHICH_WE_HAVENT
687 else
688 {
689 /* At close range we can do this properly and draw the
690 * atmosphere on the transparent pass */
691 if (translucent)
692 {
693 if (_atmosphereDrawable != nil)
694 {
696 OOGLMultModelView(OOMatrixForQuaternionRotation(_atmosphereOrientation));
697 [_atmosphereDrawable renderTranslucentParts];
698 if (canDrawShaderAtmosphere) [_atmosphereShaderDrawable renderTranslucentParts];
700 }
701 }
702 else
703 {
704 [_planetDrawable renderOpaqueParts];
705 }
706 }
707#endif
708
709 if ([UNIVERSE wireframeGraphics]) OOGLWireframeModeOff();
710}
711
712
713- (BOOL) checkCloseCollisionWith:(Entity *)other
714{
715 if (!other)
716 return NO;
717 if (other->isShip)
718 {
719 ShipEntity *ship = (ShipEntity *)other;
720 if ([ship behaviour] == BEHAVIOUR_LAND_ON_PLANET)
721 {
722 return NO;
723 }
724 }
725
726 return YES;
727}
728
729
730- (BOOL) planetHasStation
731{
732 // find the nearest station...
733 ShipEntity *station = nil;
734 station = [UNIVERSE nearestShipMatchingPredicate:IsStationPredicate
735 parameter:nil
736 relativeToEntity:self];
737
738 if (station && HPdistance([station position], position) < 4 * collision_radius) // there is a station in range.
739 {
740 return YES;
741 }
742 return NO;
743}
744
745
746- (void) launchShuttle
747{
748 if (_shuttlesOnGround == 0)
749 {
750 return;
751 }
752 if ([PLAYER status] == STATUS_START_GAME)
753 {
754 // don't launch if game not started
755 return;
756 }
757 if (self != [UNIVERSE planet] && ![self planetHasStation])
758 {
759 // don't launch shuttles when no station is nearby.
760 _shuttlesOnGround = 0;
761 return;
762 }
763
764 Quaternion q1;
766 float start_distance = collision_radius + 125.0f;
767 HPVector launch_pos = HPvector_add(position, vectorToHPVector(vector_multiply_scalar(vector_forward_from_quaternion(q1), start_distance)));
768
769 ShipEntity *shuttle_ship = [UNIVERSE newShipWithRole:@"shuttle"]; // retain count = 1
770 if (shuttle_ship)
771 {
772 if ([[shuttle_ship crew] count] == 0)
773 {
774 [shuttle_ship setSingleCrewWithRole:@"trader"];
775 }
776
777 [shuttle_ship setPosition:launch_pos];
778 [shuttle_ship setOrientation:q1];
779
780 [shuttle_ship setScanClass: CLASS_NEUTRAL];
781 [shuttle_ship setCargoFlag:CARGO_FLAG_FULL_PLENTIFUL];
782 [shuttle_ship switchAITo:@"oolite-shuttleAI.js"];
783 [UNIVERSE addEntity:shuttle_ship]; // STATUS_IN_FLIGHT, AI state GLOBAL
784 _shuttlesOnGround--;
785 _lastLaunchTime = [UNIVERSE getTime];
786
787 [shuttle_ship release];
788 }
789}
790
791
792- (void) welcomeShuttle:(ShipEntity *)shuttle
793{
794 _shuttlesOnGround++;
795}
796
797
798- (BOOL) isPlanet
799{
800 return YES;
801}
802
803
804- (BOOL) isVisible
805{
806 return YES;
807}
808
809
810- (double) rotationalVelocity
811{
812 return _rotationalVelocity;
813}
814
815
816- (void) setRotationalVelocity:(double) v
817{
818 if ([self hasAtmosphere])
819 {
820 // FIXME: change atmosphere rotation speed proportionally
821 }
822 _rotationalVelocity = v;
823}
824
825
826// this method is visible to shader bindings, hence it returns vector
827- (Vector) airColorAsVector
828{
829 float r, g, b, a;
830 [_airColor getRed:&r green:&g blue:&b alpha:&a];
831 return make_vector(r, g, b); // don't care about a
832}
833
834
835- (OOColor *) airColor
836{
837 return _airColor;
838}
839
840
841- (void) setAirColor:(OOColor *) newColor
842{
843 if (newColor)
844 {
845 [_airColor release];
846 _airColor = [newColor retain];
847 }
848}
849
850
851// this method is visible to shader bindings, hence it returns vector
852- (Vector) illuminationColorAsVector
853{
854 float r, g, b, a;
855 [_illuminationColor getRed:&r green:&g blue:&b alpha:&a];
856 return make_vector(r, g, b); // don't care about a
857}
858
859
860- (OOColor *) illuminationColor
861{
862 return _illuminationColor;
863}
864
865
866- (void) setIlluminationColor:(OOColor *) newColor
867{
868 if (newColor)
869 {
870 [_illuminationColor release];
871 _illuminationColor = [newColor retain];
872 }
873}
874
875
876// visible to shader bindings
877- (float) airColorMixRatio
878{
879 return _airColorMixRatio;
880}
881
882
883- (void) setAirColorMixRatio:(float) newRatio
884{
885 _airColorMixRatio = OOClamp_0_1_f(newRatio);
886}
887
888
889// visible to shader bindings
890- (float) airDensity
891{
892 return _airDensity;
893}
894
895
896- (void) setAirDensity: (float)newDensity
897{
898 _airDensity = OOClamp_0_1_f(newDensity);
899}
900
901
902- (void) setTerminatorThresholdVector:(Vector) newTerminatorThresholdVector
903{
904 _terminatorThresholdVector.x = newTerminatorThresholdVector.x;
905 _terminatorThresholdVector.y = newTerminatorThresholdVector.y;
906 _terminatorThresholdVector.z = newTerminatorThresholdVector.z;
907}
908
909
910- (Vector) terminatorThresholdVector
911{
912 return _terminatorThresholdVector;
913}
914
915
916- (BOOL) hasAtmosphere
917{
918 return _atmosphereDrawable != nil;
919}
920
921
922// FIXME: need material model.
923- (NSString *) textureFileName
924{
925 return [_planetDrawable textureName];
926}
927
928
929- (void)resetGraphicsState
930{
931 // reset the texture if graphics mode changes
932 [self setUpPlanetFromTexture:_textureName];
933}
934
935
936- (void) setTextureFileName:(NSString *)textureName
937{
938 BOOL isMoon = _atmosphereDrawable == nil;
939
940 OOTexture *diffuseMap = nil;
941 OOTexture *normalMap = nil;
942 NSDictionary *macros = nil;
943 NSDictionary *materialDefaults = [ResourceManager materialDefaults];
944
945#if OO_SHADERS
946 OOGraphicsDetail detailLevel = [UNIVERSE detailLevel];
947 BOOL shadersOn = detailLevel >= DETAIL_LEVEL_SHADERS;
948#else
949 const BOOL shadersOn = NO;
950#endif
951
952 if (textureName != nil)
953 {
954 NSDictionary *spec = [NSDictionary dictionaryWithObjectsAndKeys:textureName, @"name", @"yes", @"repeat_s", @"linear", @"min_filter", @"yes", @"cube_map", nil];
955 diffuseMap = [OOTexture textureWithConfiguration:spec];
956 if (diffuseMap == nil) return; // OOTexture will have logged a file-not-found warning.
957 if (shadersOn)
958 {
959 [diffuseMap ensureFinishedLoading]; // only know if it is a cube map if it's loaded
960 if ([diffuseMap isCubeMap])
961 {
962 macros = [materialDefaults oo_dictionaryForKey:isMoon ? @"moon-customized-cubemap-macros" : @"planet-customized-cubemap-macros"];
963 }
964 else
965 {
966 macros = [materialDefaults oo_dictionaryForKey:isMoon ? @"moon-customized-macros" : @"planet-customized-macros"];
967 }
968 }
969 else textureName = @"dynamic";
970
971 // let's try giving some love to normalMap too
972 if (_normSpecMapName)
973 {
974 NSDictionary *nspec = [NSDictionary dictionaryWithObjectsAndKeys:_normSpecMapName, @"name", @"yes", @"repeat_s", @"linear", @"min_filter", @"yes", @"cube_map", nil];
975 normalMap = [OOTexture textureWithConfiguration:nspec];
976 if (normalMap != nil) // OOTexture will have logged a file-not-found warning.
977 {
978 if (shadersOn)
979 {
980 [normalMap ensureFinishedLoading]; // only know if it is a cube map if it's loaded
981 if ([normalMap isCubeMap])
982 {
983 macros = [materialDefaults oo_dictionaryForKey:isMoon ? @"moon-customized-cubemap-normspec-macros" : @"planet-customized-cubemap-normspec-macros"];
984 }
985 else
986 {
987 macros = [materialDefaults oo_dictionaryForKey:isMoon ? @"moon-customized-normspec-macros" : @"planet-customized-normspec-macros"];
988 }
989 }
990 }
991 }
992 }
993 else
994 {
995 [OOPlanetTextureGenerator generatePlanetTexture:&diffuseMap
996 secondaryTexture:(detailLevel >= DETAIL_LEVEL_SHADERS) ? &normalMap : NULL
997 withInfo:_materialParameters];
998
999 if (shadersOn)
1000 {
1001 macros = [materialDefaults oo_dictionaryForKey:isMoon ? @"moon-dynamic-macros" : @"planet-dynamic-macros"];
1002 }
1003 textureName = @"dynamic";
1004 }
1005
1006 /* Generate atmosphere texture */
1007 if (!isMoon)
1008 {
1009 if (shadersOn)
1010 {
1011 NSMutableDictionary *aConfig = [[[materialDefaults oo_dictionaryForKey:@"atmosphere-material"] mutableCopy] autorelease];
1012 [aConfig setObject:[NSArray arrayWithObjects:diffuseMap, normalMap, nil] forKey:@"_oo_texture_objects"];
1013
1014 NSDictionary *amacros = [materialDefaults oo_dictionaryForKey:@"atmosphere-dynamic-macros"];
1015
1016 OOMaterial *dynamicShaderMaterial = [OOShaderMaterial shaderMaterialWithName:@"dynamic"
1017 configuration:aConfig
1018 macros:amacros
1019 bindingTarget:self];
1020
1021 if (dynamicShaderMaterial == nil)
1022 {
1023 DESTROY(_atmosphereShaderDrawable);
1024 }
1025 else
1026 {
1027 [_atmosphereShaderDrawable setMaterial:dynamicShaderMaterial];
1028 }
1029 }
1030
1031 OOLog(@"texture.planet.generate",@"Preparing atmosphere for planet %@",self);
1032 /* Generate a standalone atmosphere texture */
1033 OOTexture *atmosphere = nil;
1035 withInfo:_materialParameters];
1036
1037 OOLog(@"texture.planet.generate",@"Planet %@ has atmosphere %@",self,atmosphere);
1038
1039 OOSingleTextureMaterial *dynamicMaterial = [[OOSingleTextureMaterial alloc] initWithName:@"dynamic" texture:atmosphere configuration:nil];
1040 [_atmosphereDrawable setMaterial:dynamicMaterial];
1041 [dynamicMaterial release];
1042 }
1043
1044 OOMaterial *material = nil;
1045
1046#if OO_SHADERS
1047 if (shadersOn)
1048 {
1049 NSMutableDictionary *config = [[[materialDefaults oo_dictionaryForKey:@"planet-material"] mutableCopy] autorelease];
1050 [config setObject:[NSArray arrayWithObjects:diffuseMap, normalMap, nil] forKey:@"_oo_texture_objects"];
1051
1052 material = [OOShaderMaterial shaderMaterialWithName:textureName
1053 configuration:config
1054 macros:macros
1055 bindingTarget:self];
1056 }
1057#endif
1058 if (material == nil)
1059 {
1060 material = [[OOSingleTextureMaterial alloc] initWithName:textureName texture:diffuseMap configuration:nil];
1061 [material autorelease];
1062 }
1063 [_planetDrawable setMaterial:material];
1064}
1065
1066
1067- (BOOL) setUpPlanetFromTexture:(NSString *)textureName
1068{
1069 [self setTextureFileName:textureName];
1070 return YES;
1071}
1072
1073
1074- (OOMaterial *) material
1075{
1076 return [_planetDrawable material];
1077}
1078
1079
1080- (OOMaterial *) atmosphereMaterial
1081{
1082 return [_atmosphereDrawable material];
1083}
1084
1085
1086- (OOMaterial *) atmosphereShaderMaterial
1087{
1088 if(!_atmosphereShaderDrawable) return nil;
1089 return [_atmosphereShaderDrawable material];
1090}
1091
1092
1093- (NSString *) name
1094{
1095 return _name;
1096}
1097
1098
1099- (void) setName:(NSString *)name
1100{
1101 [_name release];
1102 _name = [name retain];
1103}
1104
1105@end
1106
1107#endif // NEW_PLANETS
#define DESTROY(x)
Definition OOCocoa.h:77
#define EXPECT_NOT(x)
#define EXPECT(x)
#define OOLogERR(class, format,...)
Definition OOLogging.h:112
#define OOLog(class, format,...)
Definition OOLogging.h:88
#define M_SQRT1_2
Definition OOMaths.h:94
OOMatrix OOMatrixForQuaternionRotation(Quaternion orientation)
Definition OOMatrix.m:65
void OOGLPushModelView(void)
void OOGLMultModelView(OOMatrix matrix)
OOMatrix OOGLPopModelView(void)
void OOGLWireframeModeOn(void)
Definition OOOpenGL.m:87
void OOGLWireframeModeOff(void)
Definition OOOpenGL.m:103
unsigned count
return nil
Vector vector_up_from_quaternion(Quaternion quat)
Vector vector_forward_from_quaternion(Quaternion quat)
void quaternion_set_random(Quaternion *quat)
const Quaternion kIdentityQuaternion
void quaternion_rotate_about_axis(Quaternion *quat, Vector axis, OOScalar angle)
#define PLANET_MINIATURE_FACTOR
#define ATMOSPHERE_DEPTH
OOStellarBodyType
@ STELLAR_TYPE_MOON
@ STELLAR_TYPE_MINIATURE
@ STELLAR_TYPE_NORMAL_PLANET
Random_Seed RandomSeedFromString(NSString *abcdefString)
BOOL ScanVectorFromString(NSString *xyzString, Vector *outVector)
OOGraphicsDetail
Definition OOTypes.h:243
@ DETAIL_LEVEL_SHADERS
Definition OOTypes.h:246
NSUInteger OOTechLevelID
Definition OOTypes.h:204
int16_t OOSystemID
Definition OOTypes.h:211
double OOTimeDelta
Definition OOTypes.h:224
const Vector kBasisYVector
Definition OOVector.m:30
#define PLAYER
#define UNIVERSE
Definition Universe.h:833
void setOrientation:(Quaternion quat)
Definition Entity.m:725
unsigned isShip
Definition Entity.h:91
void setScanClass:(OOScanClass sClass)
Definition Entity.m:799
void setPosition:(HPVector posn)
Definition Entity.m:647
OOColor * colorWithRed:green:blue:alpha:(float red,[green] float green,[blue] float blue,[alpha] float alpha)
Definition OOColor.m:95
float blueComponent()
Definition OOColor.m:362
OOColor * colorWithDescription:(id description)
Definition OOColor.m:127
OOColor * colorWithHue:saturation:brightness:alpha:(float hue,[saturation] float saturation,[brightness] float brightness,[alpha] float alpha)
Definition OOColor.m:87
float redComponent()
Definition OOColor.m:350
OOHSBAComponents hsbaComponents()
Definition OOColor.m:474
OOColor * blendedColorWithFraction:ofColor:(float fraction,[ofColor] OOColor *color)
Definition OOColor.m:328
float greenComponent()
Definition OOColor.m:356
void registerClient:(id< OOGraphicsResetClient > client)
void unregisterClient:(id< OOGraphicsResetClient > client)
OOGraphicsResetManager * sharedManager()
instancetype atmosphereWithRadius:(float radius)
BOOL generateAtmosphereTexture:withInfo:(OOTexture **texture,[withInfo] NSDictionary *planetInfo)
void ensureFinishedLoading()
Definition OOTexture.m:289
id textureWithConfiguration:(id configuration)
Definition OOTexture.m:192
NSDictionary * materialDefaults()
void setCargoFlag:(OOCargoFlag flag)
void setSingleCrewWithRole:(NSString *crewRole)
void switchAITo:(NSString *aiString)
RANROTSeed RANROTGetFullSeed(void)
void setRandomSeed(RNG_Seed a_seed)
RNG_Seed currentRandomSeed(void)
void RANROTSetFullSeed(RANROTSeed seed)
int gen_rnd_number(void)
void seed_for_planet_description(Random_Seed s_seed)
OOINLINE int is_nil_seed(Random_Seed a_seed) INLINE_CONST_FUNC