27#import "MyOpenGLView.h"
97#if OO_LOCALIZATION_TOOLS
102#include <espeak/speak_lib.h>
112#define DEMO2_VANISHING_DISTANCE 650.0
113#define DEMO2_FLY_IN_STAGE_TIME 0.4
116#define MAX_NUMBER_OF_ENTITIES 200
117#define STANDARD_STATION_ROLL 0.4
119#define LANE_WIDTH 51200.0
130 1.0f, 1.0f, 1.0f, 1.0f,
131 1.0f, -1.0f, 1.0f, 0.0f,
132 -1.0f, -1.0f, 0.0f, 0.0f,
133 -1.0f, 1.0f, 0.0f, 1.0f
154#undef CACHE_ROUTE_FROM_SYSTEM_RESULTS
164+ (instancetype) elementWithLocation:(
OOSystemID) location parent:(
OOSystemID)parent cost:(
double) cost distance:(
double) distance time:(
double) time jumps:(
int) jumps;
176+ (instancetype) elementWithLocation:(
OOSystemID) location parent:(
OOSystemID) parent cost:(
double) cost distance:(
double) distance time:(
double) time jumps:(
int) jumps
187 return [r autorelease];
200@interface Universe (OOPrivate)
202- (void) initTargetFramebufferWithViewSize:(NSSize)viewSize;
204- (void) resizeTargetFramebufferWithViewSize:(NSSize)viewSize;
208- (BOOL) doRemoveEntity:(
Entity *)entity;
211- (HPVector) fractionalPositionFrom:(HPVector)point0 to:(HPVector)point1 withFraction:(
double)routeFraction;
215- (NSString *)chooseStringForKey:(NSString *)key inDictionary:(NSDictionary *)dictionary;
217#if OO_LOCALIZATION_TOOLS
219- (void) dumpDebugGraphViz;
220- (void) dumpSystemDescriptionGraphViz;
222- (void) addNumericRefsInString:(NSString *)string toGraphViz:(NSMutableString *)graphViz fromNode:(NSString *)fromNode nodeCount:(NSUInteger)nodeCount;
232- (void) prunePreloadingPlanetMaterials;
238- (void) setFirstBeacon:(
Entity <OOBeaconEntity> *)beacon;
239- (void) setLastBeacon:(
Entity <OOBeaconEntity> *)beacon;
247- (Vector) randomPlaceWithinScannerFrom:(Vector)pos alongRoute:(Vector)route withOffset:(
double)offset;
266static GLfloat
sun_off[4] = {0.0, 0.0, 0.0, 1.0};
269#define DOCKED_AMBIENT_LEVEL 0.2f
270#define DOCKED_ILLUM_LEVEL 0.7f
277#define SUN_AMBIENT_INFLUENCE 0.75
279#define SKY_AMBIENT_ADJUSTMENT 0.0625
286- (void) setBloom: (BOOL)newBloom
293 return _currentPostFX;
296- (void) setCurrentPostFX: (
int) newCurrentPostFX
305 _colorblindMode = newCurrentPostFX;
308 _currentPostFX = newCurrentPostFX;
312- (void) terminatePostFX:(
int)postFX
314 if ([
self currentPostFX] == postFX)
316 [
self setCurrentPostFX:[
self colorblindMode]];
320- (
int) nextColorblindMode:(
int) index
328- (
int) prevColorblindMode:(
int) index
336- (
int) colorblindMode
338 return _colorblindMode;
341- (void) initTargetFramebufferWithViewSize:(NSSize)viewSize
344 OOGL(glClampColor(GL_CLAMP_VERTEX_COLOR, GL_FALSE));
345 OOGL(glClampColor(GL_CLAMP_READ_COLOR, GL_FALSE));
346 OOGL(glClampColor(GL_CLAMP_FRAGMENT_COLOR, GL_FALSE));
349 OOGL(glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &defaultDrawFBO));
351 GLint previousProgramID;
352 OOGL(glGetIntegerv(GL_CURRENT_PROGRAM, &previousProgramID));
353 GLint previousTextureID;
354 OOGL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previousTextureID));
356 OOGL(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &previousVAO));
357 GLint previousArrayBuffer;
358 OOGL(glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &previousArrayBuffer));
359 GLint previousElementBuffer;
360 OOGL(glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &previousElementBuffer));
363 OOGL(glGenFramebuffers(1, &msaaFramebufferID));
364 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, msaaFramebufferID));
367 OOGL(glGenTextures(1, &msaaTextureID));
368 OOGL(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msaaTextureID));
369 OOGL(glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA16F, (GLsizei)viewSize.width, (GLsizei)viewSize.height, GL_TRUE));
370 OOGL(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0));
371 OOGL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, msaaTextureID, 0));
374 OOGL(glGenRenderbuffers(1, &msaaDepthBufferID));
375 OOGL(glBindRenderbuffer(GL_RENDERBUFFER, msaaDepthBufferID));
376 OOGL(glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT32F, (GLsizei)viewSize.width, (GLsizei)viewSize.height));
377 OOGL(glBindRenderbuffer(GL_RENDERBUFFER, 0));
378 OOGL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, msaaDepthBufferID));
380 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
382 OOLogERR(
@"initTargetFramebufferWithViewSize.result",
@"%@",
@"***** Error: Multisample framebuffer not complete");
386 OOGL(glGenFramebuffers(1, &targetFramebufferID));
387 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, targetFramebufferID));
390 OOGL(glGenTextures(1, &targetTextureID));
391 OOGL(glBindTexture(GL_TEXTURE_2D, targetTextureID));
392 OOGL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, (GLsizei)viewSize.width, (GLsizei)viewSize.height, 0, GL_RGBA, GL_FLOAT, NULL));
393 OOGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
394 OOGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
397 OOGL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, targetTextureID, 0));
400 OOGL(glGenRenderbuffers(1, &targetDepthBufferID));
401 OOGL(glBindRenderbuffer(GL_RENDERBUFFER, targetDepthBufferID));
402 OOGL(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32F, (GLsizei)viewSize.width, (GLsizei)viewSize.height));
403 OOGL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, targetDepthBufferID));
405 GLenum attachment[1] = { GL_COLOR_ATTACHMENT0 };
406 OOGL(glDrawBuffers(1, attachment));
408 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
410 OOLogERR(
@"initTargetFramebufferWithViewSize.result",
@"%@",
@"***** Error: Framebuffer not complete");
413 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, defaultDrawFBO));
415 targetFramebufferSize = viewSize;
423 OOGL(glGenFramebuffers(1, &passthroughFramebufferID));
424 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, passthroughFramebufferID));
427 OOGL(glGenTextures(2, passthroughTextureID));
428 for (
unsigned int i = 0; i < 2; i++)
430 OOGL(glBindTexture(GL_TEXTURE_2D, passthroughTextureID[i]));
431 OOGL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, (GLsizei)viewSize.width, (GLsizei)viewSize.height, 0, GL_RGBA, GL_FLOAT, NULL));
432 OOGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
433 OOGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
436 OOGL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, GL_TEXTURE_2D, passthroughTextureID[i], 0));
439 GLenum attachments[2] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1 };
440 OOGL(glDrawBuffers(2, attachments));
442 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
444 OOLogERR(
@"initTargetFramebufferWithViewSize.result",
@"%@",
@"***** Error: Passthrough framebuffer not complete");
446 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, defaultDrawFBO));
449 OOGL(glGenFramebuffers(2, pingpongFBO));
450 OOGL(glGenTextures(2, pingpongColorbuffers));
451 for (
unsigned int i = 0; i < 2; i++)
453 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[i]));
454 OOGL(glBindTexture(GL_TEXTURE_2D, pingpongColorbuffers[i]));
455 OOGL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, (GLsizei)viewSize.width, (GLsizei)viewSize.height, 0, GL_RGBA, GL_FLOAT, NULL));
456 OOGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
457 OOGL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
460 OOGL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, pingpongColorbuffers[i], 0));
462 if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
464 OOLogERR(
@"initTargetFramebufferWithViewSize.result",
@"%@",
@"***** Error: Pingpong framebuffers not complete");
467 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, defaultDrawFBO));
481 textureProgram = [[OOShaderProgram shaderProgramWithVertexShaderName:@"oolite-texture.vertex"
482 fragmentShaderName:@"oolite-texture.fragment"
483 prefix:@"#version 330\n"
484 attributeBindings:[NSDictionary dictionary]] retain];
486 blurProgram = [[OOShaderProgram shaderProgramWithVertexShaderName:@"oolite-blur.vertex"
487 fragmentShaderName:@"oolite-blur.fragment"
488 prefix:@"#version 330\n"
489 attributeBindings:[NSDictionary dictionary]] retain];
491 finalProgram = [[OOShaderProgram shaderProgramWithVertexShaderName:@"oolite-final.vertex"
493 fragmentShaderName:[[UNIVERSE gameView] hdrOutput] ? @"oolite-final-hdr.fragment" : @"oolite-final.fragment"
495 fragmentShaderName:@"oolite-final.fragment"
497 prefix:@"#version 330\n"
498 attributeBindings:[NSDictionary dictionary]] retain];
501 OOGL(glGenVertexArrays(1, &quadTextureVAO));
502 OOGL(glGenBuffers(1, &quadTextureVBO));
503 OOGL(glGenBuffers(1, &quadTextureEBO));
505 OOGL(glBindVertexArray(quadTextureVAO));
507 OOGL(glBindBuffer(GL_ARRAY_BUFFER, quadTextureVBO));
510 OOGL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadTextureEBO));
513 OOGL(glEnableVertexAttribArray(0));
515 OOGL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 *
sizeof(
float), (
void*)0));
516 OOGL(glEnableVertexAttribArray(1));
518 OOGL(glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 *
sizeof(
float), (
void*)(2 *
sizeof(
float))));
522 OOGL(glUseProgram(previousProgramID));
523 OOGL(glBindTexture(GL_TEXTURE_2D, previousTextureID));
524 OOGL(glBindVertexArray(previousVAO));
525 OOGL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, previousElementBuffer));
526 OOGL(glBindBuffer(GL_ARRAY_BUFFER, previousArrayBuffer));
533 OOGL(glDeleteTextures(1, &msaaTextureID));
534 OOGL(glDeleteTextures(1, &targetTextureID));
535 OOGL(glDeleteTextures(2, passthroughTextureID));
536 OOGL(glDeleteTextures(2, pingpongColorbuffers));
537 OOGL(glDeleteRenderbuffers(1, &msaaDepthBufferID));
538 OOGL(glDeleteRenderbuffers(1, &targetDepthBufferID));
539 OOGL(glDeleteFramebuffers(1, &msaaFramebufferID));
540 OOGL(glDeleteFramebuffers(1, &targetFramebufferID));
541 OOGL(glDeleteFramebuffers(2, pingpongFBO));
542 OOGL(glDeleteFramebuffers(1, &passthroughFramebufferID));
543 OOGL(glDeleteVertexArrays(1, &quadTextureVAO));
544 OOGL(glDeleteBuffers(1, &quadTextureVBO));
545 OOGL(glDeleteBuffers(1, &quadTextureEBO));
546 [textureProgram release];
547 [blurProgram release];
548 [finalProgram release];
552- (void) resizeTargetFramebufferWithViewSize:(NSSize)viewSize
556 OOGL(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, msaaTextureID));
557 OOGL(glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA16F, (GLsizei)viewSize.width, (GLsizei)viewSize.height, GL_TRUE));
558 OOGL(glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0));
561 OOGL(glBindRenderbuffer(GL_RENDERBUFFER, msaaDepthBufferID));
562 OOGL(glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT32F, (GLsizei)viewSize.width, (GLsizei)viewSize.height));
563 OOGL(glBindRenderbuffer(GL_RENDERBUFFER, 0));
566 OOGL(glBindTexture(GL_TEXTURE_2D, targetTextureID));
567 OOGL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, (GLsizei)viewSize.width, (GLsizei)viewSize.height, 0, GL_RGBA, GL_FLOAT, NULL));
568 OOGL(glBindTexture(GL_TEXTURE_2D, 0));
570 for (i = 0; i < 2; i++)
572 OOGL(glBindTexture(GL_TEXTURE_2D, pingpongColorbuffers[i]));
573 OOGL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, (GLsizei)viewSize.width, (GLsizei)viewSize.height, 0, GL_RGBA, GL_FLOAT, NULL));
574 OOGL(glBindTexture(GL_TEXTURE_2D, 0));
577 for (i = 0; i < 2; i++)
579 OOGL(glBindTexture(GL_TEXTURE_2D, passthroughTextureID[i]));
580 OOGL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, (GLsizei)viewSize.width, (GLsizei)viewSize.height, 0, GL_RGBA, GL_FLOAT, NULL));
581 OOGL(glBindTexture(GL_TEXTURE_2D, 0));
585 OOGL(glBindRenderbuffer(GL_RENDERBUFFER, targetDepthBufferID));
586 OOGL(glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32F, (GLsizei)viewSize.width, (GLsizei)viewSize.height));
587 OOGL(glBindRenderbuffer(GL_RENDERBUFFER, 0));
589 targetFramebufferSize.width = viewSize.width;
590 targetFramebufferSize.height = viewSize.height;
598 OOGL(glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &previousFBO));
599 GLint previousProgramID;
600 OOGL(glGetIntegerv(GL_CURRENT_PROGRAM, &previousProgramID));
601 GLint previousTextureID;
602 OOGL(glGetIntegerv(GL_TEXTURE_BINDING_2D, &previousTextureID));
604 OOGL(glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &previousVAO));
605 GLint previousActiveTexture;
606 OOGL(glGetIntegerv(GL_ACTIVE_TEXTURE, &previousActiveTexture));
608 OOGL(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT));
610 OOGL(glDisable(GL_BLEND));
612 GLhandleARB program = [textureProgram program];
613 GLhandleARB blur = [blurProgram program];
614 GLhandleARB
final = [finalProgram program];
615 NSSize viewSize = [gameView viewSize];
616 float fboResolution[2] = {viewSize.width, viewSize.height};
618 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, passthroughFramebufferID));
619 OOGL(glClear(GL_COLOR_BUFFER_BIT));
621 OOGL(glUseProgram(program));
622 OOGL(glBindTexture(GL_TEXTURE_2D, targetTextureID));
623 OOGL(glUniform1i(glGetUniformLocation(program,
"image"), 0));
626 OOGL(glBindVertexArray(quadTextureVAO));
627 OOGL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0));
628 OOGL(glBindVertexArray(0));
630 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, defaultDrawFBO));
633 BOOL horizontal = YES, firstIteration = YES;
634 unsigned int amount = [
self bloom] ? 10 : 0;
635 OOGL(glUseProgram(blur));
636 for (
unsigned int i = 0; i < amount; i++)
638 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, pingpongFBO[horizontal]));
639 OOGL(glUniform1i(glGetUniformLocation(blur,
"horizontal"), horizontal));
640 OOGL(glActiveTexture(GL_TEXTURE0));
642 OOGL(glBindTexture(GL_TEXTURE_2D, firstIteration ? passthroughTextureID[1] : pingpongColorbuffers[!horizontal]));
643 OOGL(glUniform1i(glGetUniformLocation([blurProgram program],
"imageIn"), 0));
644 OOGL(glBindVertexArray(quadTextureVAO));
645 OOGL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0));
646 OOGL(glBindVertexArray(0));
647 horizontal = !horizontal;
650 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, defaultDrawFBO));
653 OOGL(glUseProgram(
final));
655 OOGL(glActiveTexture(GL_TEXTURE0));
656 OOGL(glBindTexture(GL_TEXTURE_2D, passthroughTextureID[0]));
657 OOGL(glUniform1i(glGetUniformLocation(
final,
"scene"), 0));
658 OOGL(glUniform1i(glGetUniformLocation(
final,
"bloom"), [
self bloom]));
659 OOGL(glUniform1f(glGetUniformLocation(
final,
"uTime"), [
self getTime]));
660 OOGL(glUniform2fv(glGetUniformLocation(
final,
"uResolution"), 1, fboResolution));
661 OOGL(glUniform1i(glGetUniformLocation(
final,
"uPostFX"), [
self currentPostFX]));
663 if([gameView hdrOutput])
665 OOGL(glUniform1f(glGetUniformLocation(
final,
"uMaxBrightness"), [gameView hdrMaxBrightness]));
666 OOGL(glUniform1f(glGetUniformLocation(
final,
"uPaperWhiteBrightness"), [gameView hdrPaperWhiteBrightness]));
670 OOGL(glActiveTexture(GL_TEXTURE1));
671 OOGL(glBindTexture(GL_TEXTURE_2D, pingpongColorbuffers[!horizontal]));
672 OOGL(glUniform1i(glGetUniformLocation(
final,
"bloomBlur"), 1));
673 OOGL(glUniform1f(glGetUniformLocation(
final,
"uSaturation"), [gameView colorSaturation]));
675 OOGL(glBindVertexArray(quadTextureVAO));
676 OOGL(glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0));
680 OOGL(glBindTexture(GL_TEXTURE_2D, 0));
683 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, previousFBO));
684 OOGL(glActiveTexture(previousActiveTexture));
685 OOGL(glBindTexture(GL_TEXTURE_2D, previousTextureID));
686 OOGL(glUseProgram(previousProgramID));
687 OOGL(glBindVertexArray(previousVAO));
688 OOGL(glEnable(GL_BLEND));
696 [NSException raise:NSInternalInconsistencyException format:@"%s: expected only one Universe to exist at a time.", __PRETTY_FUNCTION__];
702 if (
self ==
nil)
return nil;
708 NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
712 useAddOns = [[NSString alloc] initWithString:SCENARIO_OXP_DEFINITION_ALL];
714 [
self setGameView:inGameView];
717 allPlanets = [[NSMutableArray alloc] init];
718 allStations = [[NSMutableSet alloc] init];
725 [
self setDetailLevelDirectly:[prefs oo_intForKey:@"detailLevel"
728 [
self initTargetFramebufferWithViewSize:[gameView viewSize]];
735#if OOLITE_SPEECH_SYNTH
736 OOLog(
@"speech.synthesis",
@"Spoken messages are %@.", ([prefs oo_boolForKey:
@"speech_on" defaultValue:NO] ?
@"on" :
@"off"));
743 [
self loadDescriptions];
747 [
self loadScenarios];
749 autoSave = [prefs oo_boolForKey:@"autosave" defaultValue:NO];
750 wireframeGraphics = [prefs oo_boolForKey:@"wireframe-graphics" defaultValue:NO];
751 doProcedurallyTexturedPlanets = [prefs oo_boolForKey:@"procedurally-textured-planets" defaultValue:YES];
752 [inGameView
setGammaValue:[prefs oo_floatForKey:@"gamma-value" defaultValue:1.0f]];
753 [inGameView
setMsaa:[prefs oo_boolForKey:@"anti-aliasing" defaultValue:NO]];
754 OOLog(
@"MSAA.setup",
@"Multisample anti-aliasing %@requested.", [inGameView msaa] ?
@"" :
@"not ");
755 [inGameView
setFov:OOClamp_0_max_f([prefs oo_floatForKey:@"fov-value" defaultValue:57.2f], MAX_FOV_DEG)
fromFraction:NO];
758 [
self setECMVisualFXEnabled:[prefs oo_boolForKey:@"ecm-visual-fx" defaultValue:YES]];
761#if OOLITE_SPEECH_SYNTH
763 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0),
773 OOLog(
@"speech.setup.begin",
@"Starting to set up speech synthesizer.");
774 NSSpeechSynthesizer *synth = [[NSSpeechSynthesizer alloc] init];
775 OOLog(
@"speech.setup.end",
@"Finished setting up speech synthesizer.");
776 speechSynthesizer = synth;
780 espeak_Initialize(AUDIO_OUTPUT_PLAYBACK, 100, NULL, 0);
781 espeak_SetParameter(espeakPUNCTUATION, espeakPUNCT_NONE, 0);
782 espeak_SetParameter(espeakVOLUME, volume, 0);
783 espeak_voices = espeak_ListVoices(NULL);
784 for (espeak_voice_count = 0;
785 espeak_voices[espeak_voice_count];
786 ++espeak_voice_count)
796 entities = [[NSMutableArray arrayWithCapacity:MAX_NUMBER_OF_ENTITIES] retain];
806 waypoints = [[NSMutableDictionary alloc] init];
808 [
self setUpSettings];
819 [
self setUpCargoPods];
823 [
self addEntity:player];
828 [
self setUpInitialUniverse];
831 entitiesDeadThisUpdate = [[NSMutableSet alloc] init];
832 framesDoneThisUpdate = 0;
841 [
self populateNormalSpace];
845#if OO_LOCALIZATION_TOOLS
846 [
self runLocalizationTools];
848 [
self dumpDebugGraphViz];
863 [currentMessage release];
866 [message_gui release];
867 [comm_log_gui release];
871 [commodities release];
873 [_descriptions release];
874 [characters release];
875 [customSounds release];
876 [globalSettings release];
877 [systemManager release];
878 [missiontext release];
879 [equipmentData release];
880 [equipmentDataOutfitting release];
881 [demo_ships release];
883 [screenBackgrounds release];
885 [populatorSettings release];
886 [system_repopulator release];
887 [allPlanets release];
888 [allStations release];
889 [explosionSettings release];
891 [activeWormholes release];
892 [characterPool release];
893 [universeRegion release];
901 for (i = 0; i < 256; i++) [system_names[i] release];
903 [entitiesDeadThisUpdate release];
907#if OOLITE_SPEECH_SYNTH
908 [speechArray release];
910 [speechSynthesizer release];
915 [conditionScripts release];
917 [
self deleteOpenGLObjects];
923- (NSUInteger) sessionID
931 return _doingStartUp;
935- (BOOL) doProcedurallyTexturedPlanets
937 return doProcedurallyTexturedPlanets;
941- (void) setDoProcedurallyTexturedPlanets:(BOOL) value
943 doProcedurallyTexturedPlanets = !!value;
944 [[NSUserDefaults standardUserDefaults] setBool:doProcedurallyTexturedPlanets forKey:@"procedurally-textured-planets"];
948- (NSString *) useAddOns
954- (BOOL) setUseAddOns:(NSString *) newUse fromSaveGame:(BOOL) saveGame
956 return [
self setUseAddOns:newUse fromSaveGame:saveGame forceReinit:NO];
960- (BOOL) setUseAddOns:(NSString *) newUse fromSaveGame:(BOOL) saveGame forceReinit:(BOOL)force
962 if (!force && [newUse isEqualToString:useAddOns])
967 useAddOns = [newUse retain];
969 return [
self reinitAndShowDemo:!saveGame];
974- (NSUInteger) entityCount
976 return [entities count];
981- (void) debugDumpEntities
984 int show_count = n_entities;
988 OOLog(
@"universe.objectDump",
@"DEBUG: Entity Dump - [entities count] = %lu,\tn_entities = %u", [entities
count], n_entities);
991 for (i = 0; i < show_count; i++)
993 OOLog(
@"universe.objectDump",
@"Ent:%4u %@", i, [sortedEntities[i] descriptionForObjDump]);
997 if ([entities
count] != n_entities)
999 OOLog(
@"universe.objectDump",
@"entities = %@", [entities description]);
1004- (NSArray *) entityList
1006 return [NSArray arrayWithArray:entities];
1016 [
self setPauseMessageVisible:NO];
1017 NSString *pauseKey = [PLAYER keyBindingDescription2:@"key_pausebutton"];
1019 if ([player status] == STATUS_DOCKED)
1021 if ([gui setForegroundTextureKey:
@"paused_docked_overlay"])
1023 [gui drawGUI:1.0 drawCursor:NO];
1027 [
self setPauseMessageVisible:YES];
1028 [
self addMessage:OOExpandKey(@"game-paused-docked", pauseKey) forCount:1.0];
1033 if ([player guiScreen] != GUI_SCREEN_MAIN && [gui setForegroundTextureKey:
@"paused_overlay"])
1035 [gui drawGUI:1.0 drawCursor:NO];
1039 [
self setPauseMessageVisible:YES];
1040 [
self addMessage:OOExpandKey(@"game-paused", pauseKey) forCount:1.0];
1044 [[
self gameController] setGamePaused:YES];
1058 ShipScriptEvent(context, player,
"shipWillEnterWitchspace", STRING_TO_JSVAL(JS_InternString(context, [[player jumpCause] UTF8String])), INT_TO_JSVAL(dest));
1061 [
self allShipsDoScriptEvent:OOJSID("playerWillEnterWitchspace") andReactToAIMessage:@"PLAYER WITCHSPACE"];
1068 [
self removeAllEntitiesExceptPlayer];
1073 if (![wormhole withMisjump])
1076 [
self setSystemTo: dest];
1079 [
self populateNormalSpace];
1087 [
self setUpWitchspaceBetweenSystem:[wormhole
origin] andSystem:[wormhole
destination]];
1096 [UNIVERSE setSkyColorRed:0.0f
1101 [
self setWitchspaceBreakPattern:YES];
1109- (void) setUpUniverseFromStation
1119 OOSystemID sys = [
self findSystemNumberAtCoords:coords withGalaxy:[player
galaxyNumber] includingHidden:YES];
1124 if (dockedStation && !interstel)
1128 [
self setSystemTo: sys];
1130 while ([entities
count] > 2)
1132 Entity *ent = [entities objectAtIndex:index];
1133 if ((ent != player)&&(ent != dockedStation))
1137 [
self removeEntity:ent];
1147 if (dockedStation ==
nil) [
self removeAllEntitiesExceptPlayer];
1150 if (!dockedStation || !interstel)
1153 [
self populateNormalSpace];
1156 if ([dockedStation maxFlightSpeed] > 0)
1158 float d1 = [
self randomDistanceWithinScanner];
1159 HPVector pos = [UNIVERSE getWitchspaceExitPosition];
1163 if (abs((
int)d1) < 2750)
1165 d1 += ((d1 > 0.0)? 2750.0f: -2750.0f);
1174 [
self setWitchspaceBreakPattern:YES];
1182 if(!autoSaveNow) [
self setViewDirection:VIEW_FORWARD];
1186 [UNIVERSE setSkyColorRed:0.0f
1193- (void) setUpUniverseFromWitchspace
1200 if ([entities
count] == 0)
1205 [
self addEntity:player];
1211 player = [PLAYER retain];
1215 [
self populateNormalSpace];
1220 [
self setViewDirection:VIEW_FORWARD];
1222 [comm_log_gui printLongText:[NSString stringWithFormat:@"%@ %@", [
self getSystemName:systemID], [player
dial_clock_adjusted]]
1229- (void) setUpUniverseFromMisjump
1236 if ([entities
count] == 0)
1241 [
self addEntity:player];
1247 player = [PLAYER retain];
1250 [
self setUpWitchspace];
1253 [
self setAirResistanceFactor:0.0f];
1258 [
self setViewDirection:VIEW_FORWARD];
1264- (void) setUpWitchspace
1266 [
self setUpWitchspaceBetweenSystem:[PLAYER systemID] andSystem:[PLAYER nextHopTargetSystemID]];
1278 NSString* override_key = [
self keyForInterstellarOverridesForSystems:s1 :s2 inGalaxy:galaxyID];
1280 NSDictionary *systeminfo = [systemManager getPropertiesForSystemKey:override_key];
1282 [universeRegion clearSubregions];
1289 thing = [[
SkyEntity alloc] initWithColors:col1:col2 andSystemInfo: systeminfo];
1293 [
self addEntity:thing];
1299 [
self addEntity:thing];
1302 ambientLightLevel = [systeminfo oo_floatForKey:@"ambient_level" defaultValue:1.0];
1308 [
self clearSystemPopulator];
1309 NSString *populator = [systeminfo oo_stringForKey:@"populator" defaultValue:@"interstellarSpaceWillPopulate"];
1310 [system_repopulator release];
1311 system_repopulator = [[systeminfo oo_stringForKey:@"repopulator" defaultValue:@"interstellarSpaceWillRepopulate"] retain];
1313 [PLAYER doWorldScriptEvent:OOJSIDFromString(populator) inContext:context withArguments:NULL count:0 timeLimit:kOOJSLongTimeLimit];
1315 [
self populateSystemFromDictionariesWithSun:nil andPlanet:nil];
1318 NSArray *script_actions = [systeminfo oo_arrayForKey:@"script_actions"];
1319 if (script_actions !=
nil)
1321 OOStandardsDeprecated([NSString stringWithFormat:
@"The script_actions system info key is deprecated for %@.",override_key]);
1337- (OOPlanetEntity *) setUpPlanet
1340 Random_Seed systemSeed = [systemManager getRandomSeedForCurrentSystem];
1343 NSMutableDictionary *planetDict = [NSMutableDictionary dictionaryWithDictionary:[systemManager getPropertiesForCurrentSystem]];
1344 [planetDict oo_setBool:YES forKey:@"mainForLocalSystem"];
1345 OOPlanetEntity *a_planet = [[OOPlanetEntity alloc] initFromDictionary:planetDict withAtmosphere:[planetDict oo_boolForKey:@"has_atmosphere" defaultValue:YES] andSeed:systemSeed forSystem:systemID];
1347 double planet_zpos = [planetDict oo_floatForKey:@"planet_distance" defaultValue:500000];
1348 planet_zpos *= [planetDict oo_floatForKey:@"planet_distance_multiplier" defaultValue:1.0];
1350#ifdef OO_DUMP_PLANETINFO
1351 OOLog(
@"planetinfo.record",
@"planet zpos = %f",planet_zpos);
1353 [a_planet setPosition:(HPVector){ 0, 0, planet_zpos }];
1354 [a_planet setEnergy:1000000.0];
1356 if ([allPlanets
count]>0)
1358 OOPlanetEntity *tmp=[allPlanets objectAtIndex:0];
1359 [
self addEntity:a_planet];
1360 [allPlanets removeObject:a_planet];
1361 cachedPlanet=a_planet;
1362 [allPlanets replaceObjectAtIndex:0 withObject:a_planet];
1363 [
self removeEntity:(Entity *)tmp];
1367 [
self addEntity:a_planet];
1369 return [a_planet autorelease];
1381 OOPlanetEntity *a_planet;
1383 HPVector stationPos;
1388 NSDictionary *systeminfo = [systemManager getPropertiesForCurrentSystem];
1389 unsigned techlevel = [systeminfo oo_unsignedIntForKey:KEY_TECHLEVEL];
1390 NSString *stationDesc =
nil, *defaultStationDesc =
nil;
1395 Random_Seed systemSeed = [systemManager getRandomSeedForCurrentSystem];
1399 sunGoneNova = [systeminfo oo_boolForKey:@"sun_gone_nova" defaultValue:NO];
1402 [universeRegion clearSubregions];
1405 [
self setSkyColorRed:0.0f
1411#ifdef OO_DUMP_PLANETINFO
1412 OOLog(
@"planetinfo.record",
@"seed = %d %d %d %d",system_seed.c,system_seed.d,system_seed.e,system_seed.f);
1413 OOLog(
@"planetinfo.record",
@"coordinates = %d %d",system_seed.d,system_seed.b);
1415#define SPROP(PROP) OOLog(@"planetinfo.record",@#PROP " = \"%@\";",[systeminfo oo_stringForKey:@"" #PROP]);
1416#define IPROP(PROP) OOLog(@"planetinfo.record",@#PROP " = %d;",[systeminfo oo_intForKey:@#PROP]);
1417#define FPROP(PROP) OOLog(@"planetinfo.record",@#PROP " = %f;",[systeminfo oo_floatForKey:@"" #PROP]);
1422 IPROP(productivity);
1435 float h2 = h1 + 1.0 / (1.0 + (
Ranrot() % 5));
1441 thing = [[
SkyEntity alloc] initWithColors:col1:col2 andSystemInfo: systeminfo];
1443 [
self addEntity:thing];
1452 ambientLightLevel = [systeminfo oo_floatForKey:@"ambient_level" defaultValue:1.0];
1456 dict_object=[systeminfo objectForKey:@"sun_color"];
1457 if (dict_object!=
nil)
1473 [
self addEntity:thing];
1478 float defaultSunFlare =
randf()*0.1;
1479 float defaultSunHues = 0.5+
randf()*0.5;
1485 a_planet=[
self setUpPlanet];
1486 double planet_radius = [a_planet radius];
1495 double sun_distance;
1496 double sunDistanceModifier;
1497 double safeDistance;
1500 sunDistanceModifier = [systeminfo oo_nonNegativeDoubleForKey:@"sun_distance_modifier" defaultValue:0.0];
1501 if (sunDistanceModifier < 6.0)
1503 sun_distance = [systeminfo oo_nonNegativeDoubleForKey:@"sun_distance" defaultValue:(planet_radius*20)];
1505 sun_distance *= [systeminfo oo_nonNegativeDoubleForKey:@"sun_distance_multiplier" defaultValue:1];
1509 sun_distance = planet_radius * sunDistanceModifier;
1512 sun_radius = [systeminfo oo_nonNegativeDoubleForKey:@"sun_radius" defaultValue:2.5 * planet_radius];
1514 if ((sun_radius < 1000.0) || (sun_radius > sun_distance / 2 && !sunGoneNova))
1516 OOLogWARN(
@"universe.setup.badSun",
@"Sun radius of %f is not valid for this system",sun_radius);
1517 sun_radius = sun_radius < 1000.0 ? 1000.0 : (sun_distance / 2);
1519#ifdef OO_DUMP_PLANETINFO
1520 OOLog(
@"planetinfo.record",
@"sun_radius = %f",sun_radius);
1522 safeDistance=36 * sun_radius * sun_radius;
1526 HPVector sun_dir = [systeminfo oo_hpvectorForKey:@"sun_vector"];
1527 sun_distance /= 2.0;
1530 sun_distance *= 2.0;
1531 sunPos = HPvector_subtract([a_planet position],
1532 HPvector_multiply_scalar(sun_dir,sun_distance));
1536 while (HPmagnitude2(sunPos) < safeDistance);
1540 [a_planet setOrientation:quaternion_rotation_betweenHP(sun_dir,make_HPvector(1.0,0.0,0.0))];
1542#ifdef OO_DUMP_PLANETINFO
1543 OOLog(
@"planetinfo.record",
@"sun_vector = %.3f %.3f %.3f",vf.x,vf.y,vf.z);
1544 OOLog(
@"planetinfo.record",
@"sun_distance = %.0f",sun_distance);
1549 NSMutableDictionary *sun_dict = [NSMutableDictionary dictionaryWithCapacity:5];
1550 [sun_dict setObject:[NSNumber numberWithDouble:sun_radius] forKey:@"sun_radius"];
1551 dict_object=[systeminfo objectForKey: @"corona_shimmer"];
1552 if (dict_object!=
nil) [sun_dict setObject:dict_object forKey:@"corona_shimmer"];
1553 dict_object=[systeminfo objectForKey: @"corona_hues"];
1554 if (dict_object!=
nil)
1556 [sun_dict setObject:dict_object forKey:@"corona_hues"];
1560 [sun_dict setObject:[NSNumber numberWithFloat:defaultSunHues] forKey:@"corona_hues"];
1562 dict_object=[systeminfo objectForKey: @"corona_flare"];
1563 if (dict_object!=
nil)
1565 [sun_dict setObject:dict_object forKey:@"corona_flare"];
1569 [sun_dict setObject:[NSNumber numberWithFloat:defaultSunFlare] forKey:@"corona_flare"];
1571 dict_object=[systeminfo objectForKey:KEY_SUNNAME];
1572 if (dict_object!=
nil)
1574 [sun_dict setObject:dict_object forKey:KEY_SUNNAME];
1576#ifdef OO_DUMP_PLANETINFO
1577 OOLog(
@"planetinfo.record",
@"corona_flare = %f",[sun_dict oo_floatForKey:
@"corona_flare"]);
1578 OOLog(
@"planetinfo.record",
@"corona_hues = %f",[sun_dict oo_floatForKey:
@"corona_hues"]);
1579 OOLog(
@"planetinfo.record",
@"sun_color = %@",[bgcolor descriptionComponents]);
1581 a_sun = [[
OOSunEntity alloc] initSunWithColor:bgcolor andDictionary:sun_dict];
1586 [
self addEntity:a_sun];
1601 stationPos = [a_planet position];
1603 vf = [systeminfo oo_vectorForKey:@"station_vector"];
1604#ifdef OO_DUMP_PLANETINFO
1605 OOLog(
@"planetinfo.record",
@"station_vector = %.3f %.3f %.3f",vf.x,vf.y,vf.z);
1607 stationPos = HPvector_subtract(stationPos, vectorToHPVector(vector_multiply_scalar(vf, 2.0 * planet_radius)));
1611 stationDesc = [systeminfo oo_stringForKey:@"station" defaultValue:@"coriolis"];
1612#ifdef OO_DUMP_PLANETINFO
1613 OOLog(
@"planetinfo.record",
@"station = %@",stationDesc);
1616 a_station = (
StationEntity *)[
self newShipWithRole:stationDesc];
1628 if (![a_station isStation] || ![a_station validForAddToUniverse])
1630 if (a_station ==
nil)
1633 OOLog(
@"universe.setup.badStation",
@"Failed to set up a ship for role \"%@\
" as system station, trying again with \"%@\".", stationDesc, defaultStationDesc);
1637 OOLog(
@"universe.setup.badStation",
@"***** ERROR: Attempt to use non-station ship of type \"%@\
" for role \"%@\" as system station, trying again with \"%@\".", [a_station name], stationDesc, defaultStationDesc);
1639 [a_station release];
1640 stationDesc = defaultStationDesc;
1641 a_station = (
StationEntity *)[
self newShipWithRole:stationDesc];
1643 if (![a_station isStation] || ![a_station validForAddToUniverse])
1645 if (a_station ==
nil)
1647 OOLog(
@"universe.setup.badStation",
@"On retry, failed to set up a ship for role \"%@\
" as system station. Trying to fall back to built-in Coriolis station.", stationDesc);
1651 OOLog(
@"universe.setup.badStation",
@"***** ERROR: On retry, rolled non-station ship of type \"%@\
" for role \"%@\". Non-station ships should not have this role! Trying to fall back to built-in Coriolis station.", [a_station name], stationDesc);
1653 [a_station release];
1655 a_station = (
StationEntity *)[
self newShipWithName:
@"coriolis-station"];
1656 if (![a_station isStation] || ![a_station validForAddToUniverse])
1658 OOLog(
@"universe.setup.badStation",
@"%@",
@"Could not create built-in Coriolis station! Generating a stationless system.");
1664 if (a_station !=
nil)
1666 [a_station
setOrientation:quaternion_rotation_between(vf,make_vector(0.0,0.0,1.0))];
1672 [
self addEntity:a_station];
1680 cachedPlanet = a_planet;
1681 cachedStation = a_station;
1687 [
self populateSpaceFromActiveWormholes];
1691 [a_station release];
1695- (void) populateNormalSpace
1697 NSDictionary *systeminfo = [systemManager getPropertiesForCurrentSystem];
1699 BOOL sunGoneNova = [systeminfo oo_boolForKey:@"sun_gone_nova"];
1705 HPVector v0 = make_HPvector(0,0,34567.89);
1706 double min_safe_dist2 = 6000000.0 * 6000000.0;
1707 HPVector sunPos = [cachedSun position];
1708 while (HPmagnitude2(cachedSun->position) < min_safe_dist2)
1712 sunPos = HPvector_add(sunPos, v0);
1713 [cachedSun setPosition:sunPos];
1717 [
self removeEntity:cachedPlanet];
1719 [
self removeEntity:cachedStation];
1720 cachedStation =
nil;
1725 [
self clearSystemPopulator];
1727 if ([
PLAYER status] != STATUS_START_GAME)
1729 NSString *populator = [systeminfo oo_stringForKey:@"populator" defaultValue:(sunGoneNova)?@"novaSystemWillPopulate":@"systemWillPopulate"];
1730 [system_repopulator release];
1731 system_repopulator = [[systeminfo oo_stringForKey:@"repopulator" defaultValue:(sunGoneNova)?@"novaSystemWillRepopulate":@"systemWillRepopulate"] retain];
1734 [PLAYER doWorldScriptEvent:OOJSIDFromString(populator) inContext:context withArguments:NULL count:0 timeLimit:kOOJSLongTimeLimit];
1736 [
self populateSystemFromDictionariesWithSun:cachedSun andPlanet:cachedPlanet];
1742 NSArray *script_actions = [systeminfo oo_arrayForKey:@"script_actions"];
1743 if (script_actions !=
nil)
1745 OOStandardsDeprecated([NSString stringWithFormat:
@"The script_actions system info key is deprecated for %@.",[
self getSystemName:systemID]]);
1749 [PLAYER runUnsanitizedScriptActions:script_actions
1750 allowingAIMethods:NO
1751 withContextName:@"<system script_actions>"
1761- (void) clearSystemPopulator
1763 [populatorSettings release];
1764 populatorSettings = [[NSMutableDictionary alloc] initWithCapacity:128];
1768- (NSDictionary *) getPopulatorSettings
1770 return populatorSettings;
1774- (void) setPopulatorSetting:(NSString *)key to:(NSDictionary *)setting
1778 [populatorSettings removeObjectForKey:key];
1782 [populatorSettings setObject:setting forKey:key];
1787- (BOOL) deterministicPopulation
1789 return deterministic_population;
1793- (void) populateSystemFromDictionariesWithSun:(
OOSunEntity *)sun andPlanet:(OOPlanetEntity *)planet
1795 Random_Seed systemSeed = [systemManager getRandomSeedForCurrentSystem];
1796 NSArray *blocks = [populatorSettings allValues];
1797 NSEnumerator *enumerator = [[blocks sortedArrayUsingFunction:populatorPrioritySort context:nil] objectEnumerator];
1798 NSDictionary *populator =
nil;
1800 uint32_t i, locationSeed, groupCount, rndvalue;
1803 NSString *locationCode =
nil;
1805 while ((populator = [enumerator nextObject]))
1807 deterministic_population = [populator oo_boolForKey:@"deterministic" defaultValue:NO];
1811 deterministic_population = NO;
1814 locationSeed = [populator oo_unsignedIntForKey:@"locationSeed" defaultValue:0];
1815 groupCount = [populator oo_unsignedIntForKey:@"groupCount" defaultValue:1];
1817 for (i = 0; i < groupCount; i++)
1819 locationCode = [populator oo_stringForKey:@"location" defaultValue:@"COORDINATES"];
1820 if ([locationCode isEqualToString:
@"COORDINATES"])
1822 location = [populator oo_hpvectorForKey:@"coordinates" defaultValue:kZeroHPVector];
1826 if (locationSeed != 0)
1842 deterministic_population = NO;
1844 if (sun ==
nil || planet ==
nil)
1847 location = [
self locationByCode:@"WITCHPOINT" withSun:nil andPlanet:nil];
1851 location = [
self locationByCode:locationCode withSun:sun andPlanet:planet];
1853 if(locationSeed != 0)
1860 pdef = [populator objectForKey:@"callbackObj"];
1865 deterministic_population = NO;
1883- (HPVector) locationByCode:(NSString *)code withSun:(
OOSunEntity *)sun andPlanet:(OOPlanetEntity *)planet
1886 if ([code isEqualToString:
@"WITCHPOINT"] || sun ==
nil || planet ==
nil || [sun goneNova])
1893 if ([code isEqualToString:
@"LANE_WPS"])
1896 double l1 = HPmagnitude([planet position]);
1897 double l2 = HPmagnitude(HPvector_subtract([sun position],[planet position]));
1898 double l3 = HPmagnitude([sun position]);
1899 double total = l1+l2+l3;
1900 float choice =
randf();
1901 if (choice < l1/total)
1903 return [
self locationByCode:@"LANE_WP" withSun:sun andPlanet:planet];
1905 else if (choice < (l1+l2)/total)
1907 return [
self locationByCode:@"LANE_PS" withSun:sun andPlanet:planet];
1911 return [
self locationByCode:@"LANE_WS" withSun:sun andPlanet:planet];
1914 else if ([code isEqualToString:
@"LANE_WP"])
1918 else if ([code isEqualToString:
@"LANE_WS"])
1922 else if ([code isEqualToString:
@"LANE_PS"])
1926 else if ([code isEqualToString:
@"STATION_AEGIS"])
1931 }
while(HPdistance2(result,[planet position])<[planet radius]*[planet radius]*1.5);
1934 else if ([code isEqualToString:
@"PLANET_ORBIT_LOW"])
1938 else if ([code isEqualToString:
@"PLANET_ORBIT"])
1942 else if ([code isEqualToString:
@"PLANET_ORBIT_HIGH"])
1946 else if ([code isEqualToString:
@"STAR_ORBIT_LOW"])
1950 else if ([code isEqualToString:
@"STAR_ORBIT"])
1954 else if ([code isEqualToString:
@"STAR_ORBIT_HIGH"])
1958 else if ([code isEqualToString:
@"TRIANGLE"])
1971 result = HPvector_add(HPvector_multiply_scalar([planet position],r),HPvector_multiply_scalar([sun position],s));
1974 while(HPdistance2(result,[sun position]) < [sun radius]*[sun radius]*9.0 || HPdistance2(result,[planet position]) < [planet radius]*[planet radius]*9.0 || HPmagnitude2(result) <
SCANNER_MAX_RANGE2 * 9.0);
1976 else if ([code isEqualToString:
@"INNER_SYSTEM"])
1979 result =
OORandomPositionInShell([sun position],[sun radius]*3.0,HPdistance([sun position],[planet position]));
1983 }
while (HPdistance2(result,[sun position]) < [sun radius]*[sun radius]*9.0);
1985 else if ([code isEqualToString:
@"INNER_SYSTEM_OFFPLANE"])
1987 result =
OORandomPositionInShell([sun position],[sun radius]*3.0,HPdistance([sun position],[planet position]));
1989 else if ([code isEqualToString:
@"OUTER_SYSTEM"])
1991 result =
OORandomPositionInShell([sun position],HPdistance([sun position],[planet position]),HPdistance([sun position],[planet position])*10.0);
1995 else if ([code isEqualToString:
@"OUTER_SYSTEM_OFFPLANE"])
1997 result =
OORandomPositionInShell([sun position],HPdistance([sun position],[planet position]),HPdistance([sun position],[planet position])*10.0);
2009- (void) setAmbientLightLevel:(
float)newValue
2011 NSAssert(
UNIVERSE !=
nil,
@"Attempt to set ambient light level with a non yet existent universe.");
2013 ambientLightLevel = OOClamp_0_max_f(newValue, 10.0f);
2018- (float) ambientLightLevel
2020 return ambientLightLevel;
2044 GLfloat sun_pos[] = {0.0, 0.0, 0.0, 1.0};
2045 GLfloat sun_ambient[] = {0.0, 0.0, 0.0, 1.0};
2048 for (i = n_entities - 1; i > 0; i--)
2049 if ((sortedEntities[i]) && ([sortedEntities[i] isKindOfClass:[SkyEntity class]]))
2050 the_sky = (
SkyEntity*)sortedEntities[i];
2056 OOGL(glLightfv(GL_LIGHT1, GL_AMBIENT, sun_ambient));
2057 OOGL(glLightfv(GL_LIGHT1, GL_DIFFUSE, sun_diffuse));
2058 OOGL(glLightfv(GL_LIGHT1, GL_SPECULAR, sun_specular));
2066 stars_ambient[0] = 0.05; stars_ambient[1] = 0.20; stars_ambient[2] = 0.05; stars_ambient[3] = 1.0;
2067 sun_diffuse[0] = 0.85; sun_diffuse[1] = 1.0; sun_diffuse[2] = 0.85; sun_diffuse[3] = 1.0;
2068 sun_specular[0] = 0.95; sun_specular[1] = 1.0; sun_specular[2] = 0.95; sun_specular[3] = 1.0;
2069 OOGL(glLightfv(GL_LIGHT1, GL_AMBIENT, sun_ambient));
2070 OOGL(glLightfv(GL_LIGHT1, GL_DIFFUSE, sun_diffuse));
2071 OOGL(glLightfv(GL_LIGHT1, GL_SPECULAR, sun_specular));
2074 OOGL(glLightfv(GL_LIGHT1, GL_POSITION, sun_pos));
2080 [[the_sky skyColor] getRed:&r green:&g blue:&b alpha:&a];
2084 GLfloat ambient_level = [
self ambientLightLevel];
2088 stars_ambient[3] = 1.0;
2096 OOGL(glLightModelfv(GL_LIGHT_MODEL_AMBIENT, stars_ambient));
2101- (void) forceLightSwitch
2107- (void) setMainLightPosition: (Vector) sunPos
2109 main_light_position[0] = sunPos.x;
2110 main_light_position[1] = sunPos.y;
2111 main_light_position[2] = sunPos.z;
2112 main_light_position[3] = 1.0;
2116- (
ShipEntity *) addShipWithRole:(NSString *)desc launchPos:(HPVector)launchPos rfactor:(GLfloat)rfactor
2121 launchPos.x += 2 * rfactor * (
randf() - 0.5);
2122 launchPos.y += 2 * rfactor * (
randf() - 0.5);
2123 launchPos.z += 2 * rfactor * (
randf() - 0.5);
2126 ShipEntity *ship = [
self newShipWithRole:desc];
2133 if ([ship hasRole:
@"cargopod"]) [
self fillCargopodWithRandomCargo:ship];
2136 if (![ship crew] && ![ship isUnpiloted])
2137 [ship
setCrew:[NSArray arrayWithObject:
2141 if ([ship scanClass] == CLASS_NOT_SET)
2145 [
self addEntity:ship];
2153- (void) addShipWithRole:(NSString *) desc nearRouteOneAt:(
double) route_fraction
2157 Entity *theStation = [
self station];
2163 HPVector launchPos = OOHPVectorInterpolate([
self getWitchspaceExitPosition], [theStation position], route_fraction);
2165 [
self addShipWithRole:desc launchPos:launchPos rfactor:SCANNER_MAX_RANGE];
2169- (HPVector) coordinatesForPosition:(HPVector) pos withCoordinateSystem:(NSString *) system returningScalar:(GLfloat*) my_scalar
2206 NSString* l_sys = [system lowercaseString];
2207 if ([l_sys length] != 3)
2209 OOPlanetEntity* the_planet = [
self planet];
2211 if (the_planet ==
nil || the_sun ==
nil || [l_sys isEqualToString:
@"abs"])
2213 if (my_scalar) *my_scalar = 1.0;
2216 HPVector w_pos = [
self getWitchspaceExitPosition];
2217 HPVector p_pos = the_planet->
position;
2218 HPVector s_pos = the_sun->
position;
2220 const char* c_sys = [l_sys UTF8String];
2221 HPVector p0, p1, p2;
2230 p1 = p_pos; p2 = s_pos;
break;
2232 p1 = s_pos; p2 = p_pos;
break;
2242 p1 = w_pos; p2 = s_pos;
break;
2244 p1 = s_pos; p2 = w_pos;
break;
2254 p1 = w_pos; p2 = p_pos;
break;
2256 p1 = p_pos; p2 = w_pos;
break;
2264 HPVector k = HPvector_normal_or_zbasis(HPvector_subtract(p1, p0));
2265 HPVector v = HPvector_normal_or_xbasis(HPvector_subtract(p2, p0));
2267 HPVector j = HPcross_product(k, v);
2268 HPVector i = HPcross_product(j, k);
2270 GLfloat scale = 1.0;
2274 scale = [the_planet radius];
2278 scale = [the_sun
radius];
2282 scale = HPmagnitude(HPvector_subtract(p1, p0));
2296 HPVector result = p0;
2297 result.x += scale * (pos.
x * i.
x + pos.
y * j.
x + pos.z * k.
x);
2298 result.y += scale * (pos.
x * i.
y + pos.
y * j.
y + pos.z * k.
y);
2299 result.z += scale * (pos.
x * i.z + pos.
y * j.z + pos.z * k.z);
2305- (NSString *) expressPosition:(HPVector) pos inCoordinateSystem:(NSString *) system
2307 HPVector result = [
self legacyPositionFrom:pos asCoordinateSystem:system];
2308 return [NSString stringWithFormat:@"%@ %.2f %.2f %.2f", system, result.x, result.y, result.z];
2312- (HPVector) legacyPositionFrom:(HPVector) pos asCoordinateSystem:(NSString *) system
2314 NSString* l_sys = [system lowercaseString];
2315 if ([l_sys length] != 3)
2317 OOPlanetEntity* the_planet = [
self planet];
2319 if (the_planet ==
nil || the_sun ==
nil || [l_sys isEqualToString:
@"abs"])
2323 HPVector w_pos = [
self getWitchspaceExitPosition];
2324 HPVector p_pos = the_planet->
position;
2325 HPVector s_pos = the_sun->
position;
2327 const char* c_sys = [l_sys UTF8String];
2328 HPVector p0, p1, p2;
2337 p1 = p_pos; p2 = s_pos;
break;
2339 p1 = s_pos; p2 = p_pos;
break;
2349 p1 = w_pos; p2 = s_pos;
break;
2351 p1 = s_pos; p2 = w_pos;
break;
2361 p1 = w_pos; p2 = p_pos;
break;
2363 p1 = p_pos; p2 = w_pos;
break;
2371 HPVector k = HPvector_normal_or_zbasis(HPvector_subtract(p1, p0));
2372 HPVector v = HPvector_normal_or_xbasis(HPvector_subtract(p2, p0));
2374 HPVector j = HPcross_product(k, v);
2375 HPVector i = HPcross_product(j, k);
2377 GLfloat scale = 1.0;
2382 scale = 1.0f / [the_planet radius];
2387 scale = 1.0f / [the_sun
radius];
2392 scale = 1.0f / HPdistance(p1, p0);
2404 HPVector r_pos = HPvector_subtract(pos, p0);
2405 HPVector result = make_HPvector(scale * (r_pos.x * i.x + r_pos.y * i.y + r_pos.z * i.z),
2406 scale * (r_pos.x * j.x + r_pos.y * j.y + r_pos.z * j.z),
2407 scale * (r_pos.x * k.x + r_pos.y * k.y + r_pos.z * k.z) );
2413- (HPVector) coordinatesFromCoordinateSystemString:(NSString *) system_x_y_z
2416 if ([tokens
count] != 4)
2419 return make_HPvector(0,0,0);
2422 return [
self coordinatesForPosition:make_HPvector([tokens oo_floatAtIndex:1], [tokens oo_floatAtIndex:2], [tokens oo_floatAtIndex:3]) withCoordinateSystem:[tokens oo_stringAtIndex:0] returningScalar:&dummy];
2426- (BOOL) addShipWithRole:(NSString *) desc nearPosition:(HPVector) pos withCoordinateSystem:(NSString *) system
2429 GLfloat scalar = 1.0;
2430 HPVector launchPos = [
self coordinatesForPosition:pos withCoordinateSystem:system returningScalar:&scalar];
2432 GLfloat rfactor = scalar;
2438 return ([
self addShipWithRole:desc launchPos:launchPos rfactor:rfactor] !=
nil);
2442- (BOOL) addShips:(
int) howMany withRole:(NSString *) desc atPosition:(HPVector) pos withCoordinateSystem:(NSString *) system
2445 GLfloat scalar = 1.0;
2446 HPVector launchPos = [
self coordinatesForPosition:pos withCoordinateSystem:system returningScalar:&scalar];
2447 GLfloat distance_from_center = 0.0;
2448 HPVector v_from_center, ship_pos;
2449 HPVector ship_positions[howMany];
2451 int scale_up_after = 0;
2452 int current_shell = 0;
2453 GLfloat walk_factor = 2.0;
2456 ShipEntity *ship = [
self addShipWithRole:desc launchPos:launchPos rfactor:0.0];
2457 if (ship ==
nil)
return NO;
2463 int limit_count = 8;
2470 v_from_center.x += walk_factor * (
randf() - 0.5);
2471 v_from_center.y += walk_factor * (
randf() - 0.5);
2472 v_from_center.z += walk_factor * (
randf() - 0.5);
2473 }
while ((v_from_center.x == 0.0)&&(v_from_center.y == 0.0)&&(v_from_center.z == 0.0));
2474 v_from_center = HPvector_normal(v_from_center);
2476 ship_pos = make_HPvector( launchPos.x + distance_from_center * v_from_center.x,
2477 launchPos.y + distance_from_center * v_from_center.y,
2478 launchPos.z + distance_from_center * v_from_center.z);
2483 while (safe && (j >= current_shell))
2485 safe = (safe && (HPdistance2(ship_pos, ship_positions[j]) > safe_distance2));
2494 distance_from_center += sqrt(safe_distance2);
2501 [ship setScanClass:scanClass == CLASS_NOT_SET ? CLASS_NEUTRAL : scanClass];
2509 ship_positions[i] = ship_pos;
2511 if (i > scale_up_after)
2514 scale_up_after += 1 + 2 * i;
2515 distance_from_center += sqrt(safe_distance2);
2522- (BOOL) addShips:(
int) howMany withRole:(NSString *) desc nearPosition:(HPVector) pos withCoordinateSystem:(NSString *) system
2525 GLfloat scalar = 1.0;
2526 HPVector launchPos = [
self coordinatesForPosition:pos withCoordinateSystem:system returningScalar:&scalar];
2527 GLfloat rfactor = scalar;
2532 BoundingBox launch_bbox;
2533 bounding_box_reset_to_vector(&launch_bbox, make_vector(launchPos.x - rfactor, launchPos.y - rfactor, launchPos.z - rfactor));
2534 bounding_box_add_xyz(&launch_bbox, launchPos.x + rfactor, launchPos.y + rfactor, launchPos.z + rfactor);
2536 return [
self addShips: howMany withRole: desc intoBoundingBox: launch_bbox];
2540- (BOOL) addShips:(
int) howMany withRole:(NSString *) desc nearPosition:(HPVector) pos withCoordinateSystem:(NSString *) system withinRadius:(GLfloat) radius
2543 GLfloat scalar = 1.0;
2544 HPVector launchPos = [
self coordinatesForPosition:pos withCoordinateSystem:system returningScalar:&scalar];
2545 GLfloat rfactor = radius;
2548 BoundingBox launch_bbox;
2549 bounding_box_reset_to_vector(&launch_bbox, make_vector(launchPos.x - rfactor, launchPos.y - rfactor, launchPos.z - rfactor));
2550 bounding_box_add_xyz(&launch_bbox, launchPos.x + rfactor, launchPos.y + rfactor, launchPos.z + rfactor);
2552 return [
self addShips: howMany withRole: desc intoBoundingBox: launch_bbox];
2556- (BOOL) addShips:(
int) howMany withRole:(NSString *) desc intoBoundingBox:(BoundingBox) bbox
2563 int h0 = howMany / 2;
2564 int h1 = howMany - h0;
2566 GLfloat lx = bbox.max.x - bbox.min.
x;
2567 GLfloat ly = bbox.max.y - bbox.min.
y;
2568 GLfloat lz = bbox.max.z - bbox.min.z;
2569 BoundingBox bbox0 = bbox;
2570 BoundingBox bbox1 = bbox;
2571 if ((lx > lz)&&(lx > ly))
2573 bbox0.min.x += 0.5 * lx;
2574 bbox1.max.x -= 0.5 * lx;
2580 bbox0.min.y += 0.5 * ly;
2581 bbox1.max.y -= 0.5 * ly;
2585 bbox0.min.z += 0.5 * lz;
2586 bbox1.max.z -= 0.5 * lz;
2590 return ([
self addShips: h0 withRole: desc intoBoundingBox: bbox0] && [
self addShips: h1 withRole: desc intoBoundingBox: bbox1]);
2594 HPVector pos = make_HPvector(bbox.min.x, bbox.min.y, bbox.min.z);
2595 pos.x += 0.5 * (
randf() +
randf()) * (bbox.max.
x - bbox.min.
x);
2596 pos.y += 0.5 * (
randf() +
randf()) * (bbox.max.
y - bbox.min.
y);
2597 pos.z += 0.5 * (
randf() +
randf()) * (bbox.max.z - bbox.min.z);
2599 return ([
self addShipWithRole:desc launchPos:pos rfactor:0.0] !=
nil);
2603- (BOOL) spawnShip:(NSString *) shipdesc
2607 OOStandardsDeprecated([NSString stringWithFormat:
@"'spawn' via legacy script is deprecated as a way of adding ships for %@",shipdesc]);
2610 NSDictionary *shipdict =
nil;
2613 if (shipdict ==
nil)
return NO;
2615 ship = [
self newShipWithName:shipdesc];
2617 if (ship ==
nil)
return NO;
2620 NSDictionary *spawndict = [shipdict oo_dictionaryForKey:@"spawn"];
2621 HPVector pos, rpos, spos;
2622 NSString *positionString =
nil;
2625 positionString = [spawndict oo_stringForKey:@"position"];
2626 if (positionString !=
nil)
2628 if([positionString hasPrefix:
@"abs "] && ([
self planet] !=
nil || [
self sun] !=
nil))
2630 OOLogWARN(
@"script.deprecated",
@"setting %@ for %@ '%@' in 'abs' inside .plists can cause compatibility issues across Oolite versions. Use coordinates relative to main system objects instead.",
@"position",
@"entity",shipdesc);
2633 pos = [
self coordinatesFromCoordinateSystemString:positionString];
2639 OOLogERR(
@"universe.spawnShip.error",
@"***** ERROR: failed to find a spawn position for ship %@.", shipdesc);
2644 positionString = [spawndict oo_stringForKey:@"facing_position"];
2645 if (positionString !=
nil)
2647 if([positionString hasPrefix:
@"abs "] && ([
self planet] !=
nil || [
self sun] !=
nil))
2649 OOLogWARN(
@"script.deprecated",
@"setting %@ for %@ '%@' in 'abs' inside .plists can cause compatibility issues across Oolite versions. Use coordinates relative to main system objects instead.",
@"facing_position",
@"entity",shipdesc);
2654 rpos = [
self coordinatesFromCoordinateSystemString:positionString];
2655 rpos = HPvector_subtract(rpos, spos);
2659 rpos = HPvector_normal(rpos);
2668 q1 = make_quaternion(0,1,0,0);
2676 [
self addEntity:ship];
2683- (void) witchspaceShipWithPrimaryRole:(NSString *)role
2687 NSDictionary *systeminfo =
nil;
2690 systeminfo = [
self currentSystemData];
2691 government = [systeminfo oo_unsignedCharForKey:KEY_GOVERNMENT];
2693 ship = [
self newShipWithRole:role];
2696 if (ship && [ship hasRole:
@"cargopod"])
2698 [
self fillCargopodWithRandomCargo:ship];
2703 if (([ship scanClass] == CLASS_NO_DRAW)||([ship scanClass] == CLASS_NOT_SET))
2705 if ([role isEqual:
@"trader"])
2708 if ([ship hasRole:
@"sunskim-trader"] &&
randf() < 0.25)
2711 [
self makeSunSkimmer:ship andSetAI:YES];
2718 if (([ship pendingEscortCount] > 0)&&((
Ranrot() % 7) < government))
2721 [ship setPendingEscortCount:(nx > 0) ? nx : 0];
2724 if ([role isEqual:
@"pirate"])
2727 [ship
setBounty: (Ranrot() & 7) + (Ranrot() & 7) + ((randf() < 0.05)? 63 : 23)
withReason:kOOLegalStatusReasonSetup];
2729 if ([ship crew] ==
nil && ![ship isUnpiloted])
2730 [ship
setCrew:[NSArray arrayWithObject:
2743 if (entity ==
nil)
return nil;
2753 ship = [
self addShipWithRole:desc launchPos:spawn_pos rfactor:0.0];
2770 [vis setPosition:pos];
2771 [vis setOrientation:OORandomQuaternion()];
2773 success = [
self addEntity:vis];
2783- (
ShipEntity *) addShipAt:(HPVector)pos withRole:(NSString *)role withinRadius:(GLfloat)radius
2788 if (radius == NSNotFound)
2790 GLfloat scalar = 1.0;
2791 [
self coordinatesForPosition:pos withCoordinateSystem:@"abs" returningScalar:&scalar];
2793 GLfloat rfactor = scalar;
2807 ShipEntity *ship = [
self newShipWithRole:role];
2813 if ([ship hasRole:
@"cargopod"]) [
self fillCargopodWithRandomCargo:ship];
2815 if (scanClass == CLASS_NOT_SET)
2817 scanClass = CLASS_NEUTRAL;
2821 if ([ship crew] ==
nil && ![ship isUnpiloted])
2823 [ship
setCrew:[NSArray arrayWithObject:
2830 BOOL trader = [role isEqualToString:@"trader"];
2840 if (pendingEscortCount > 0)
2842 OOGovernmentID government = [[
self currentSystemData] oo_unsignedCharForKey:KEY_GOVERNMENT];
2843 if ((
Ranrot() % 7) < government)
2845 int nx = pendingEscortCount - 2 * (1 + (
Ranrot() & 3));
2846 [ship setPendingEscortCount:(nx > 0) ? nx : 0];
2854 success = [
self addEntity:ship];
2861 if ([ship hasRole:
@"sunskim-trader"] &&
randf() < 0.25)
2864 [
self makeSunSkimmer:ship andSetAI:YES];
2871 else if ([role isEqual:
@"pirate"])
2873 [ship
setBounty:(Ranrot() & 7) + (Ranrot() & 7) + ((randf() < 0.05)? 63 : 23)
withReason:kOOLegalStatusReasonSetup];
2890- (NSArray *) addShipsAt:(HPVector)pos withRole:(NSString *)role quantity:(
unsigned)count withinRadius:(GLfloat)radius asGroup:(BOOL)isGroup
2894 NSMutableArray *ships = [NSMutableArray arrayWithCapacity:count];
2905 ship = [
self addShipAt:pos withRole:role withinRadius:radius];
2909 if (isGroup) [ship
setGroup:group];
2910 [ships addObject:ship];
2914 if ([ships
count] == 0)
return nil;
2916 return [[ships copy] autorelease];
2922- (NSArray *) addShipsToRoute:(NSString *)route withRole:(NSString *)role quantity:(
unsigned)count routeFraction:(
double)routeFraction asGroup:(BOOL)isGroup
2924 NSMutableArray *ships = [NSMutableArray arrayWithCapacity:count];
2930 if ([route isEqualToString:
@"pw"] || [route isEqualToString:
@"sw"] || [route isEqualToString:
@"ps"])
2932 routeFraction = 1.0f - routeFraction;
2936 if ([route isEqualTo:
@"wp"] || [route isEqualTo:
@"pw"])
2938 point0 = [
self getWitchspaceExitPosition];
2939 entity = [
self planet];
2940 if (entity ==
nil)
return nil;
2942 radius = [entity radius];
2944 else if ([route isEqualTo:
@"ws"] || [route isEqualTo:
@"sw"])
2946 point0 = [
self getWitchspaceExitPosition];
2947 entity = [
self sun];
2948 if (entity ==
nil)
return nil;
2950 radius = [entity radius];
2952 else if ([route isEqualTo:
@"sp"] || [route isEqualTo:
@"ps"])
2954 entity = [
self sun];
2955 if (entity ==
nil)
return nil;
2957 double radius0 = [entity radius];
2959 entity = [
self planet];
2960 if (entity ==
nil)
return nil;
2962 radius = [entity radius];
2965 direction = HPvector_normal(HPvector_subtract(point0, point1));
2966 point0 = HPvector_subtract(point0, HPvector_multiply_scalar(direction, radius0 +
SCANNER_MAX_RANGE * 1.1f));
2968 else if ([route isEqualTo:
@"st"])
2970 point0 = [
self getWitchspaceExitPosition];
2971 if ([
self station] ==
nil)
return nil;
2972 point1 = [[
self station] position];
2973 radius = [[
self station] collisionRadius];
2978 direction = HPvector_normal(HPvector_subtract(point1, point0));
2979 point1 = HPvector_subtract(point1, HPvector_multiply_scalar(direction, radius +
SCANNER_MAX_RANGE * 1.1f));
2981 pos = [
self fractionalPositionFrom:point0 to:point1 withFraction:routeFraction];
2984 return [
self addShipsAt:pos withRole:role quantity:count withinRadius:(SCANNER_MAX_RANGE / 10.0f) asGroup:YES];
2990 ship = [
self addShipAt:pos withRole:role withinRadius:0];
2991 if (ship !=
nil) [ships addObject:ship];
2992 if (
count > 0) pos = [
self fractionalPositionFrom:point0 to:point1 withFraction:routeFraction];
2995 if ([ships
count] == 0)
return nil;
2998 return [[ships copy] autorelease];
3002- (BOOL) roleIsPirateVictim:(NSString *)role
3004 return [
self role:role isInCategory:@"oolite-pirate-victim"];
3008- (BOOL) role:(NSString *)role isInCategory:(NSString *)category
3010 NSSet *categoryInfo = [roleCategories objectForKey:category];
3011 if (categoryInfo ==
nil)
3015 return [categoryInfo containsObject:role];
3020- (void) forceWitchspaceEntries
3023 for (i = 0; i < n_entities; i++)
3025 if (sortedEntities[i]->isShip)
3029 if ([my_target isWormhole])
3033 else if ([[[my_ship getAI] state] isEqualToString:
@"ENTER_WORMHOLE"])
3042- (void) addWitchspaceJumpEffectForShip:(
ShipEntity *)ship
3045 if ([
PLAYER status] != STATUS_ENTERING_WITCHSPACE && [
PLAYER status] != STATUS_EXITING_WITCHSPACE)
3053- (GLfloat) safeWitchspaceExitDistance
3055 for (
unsigned i = 0; i < n_entities; i++)
3057 Entity *e2 = sortedEntities[i];
3058 if ([e2 isShip] && [(
ShipEntity*)e2 hasPrimaryRole:
@"buoy-witchpoint"])
3067- (void) setUpBreakPattern:(HPVector) pos orientation:(Quaternion) q forDocking:(BOOL) forDocking
3074 [
self setViewDirection:VIEW_FORWARD];
3086 colorDesc = [[
self globalSettings] objectForKey:@"hyperspace_tunnel_color_1"];
3087 if (colorDesc !=
nil)
3090 if (color !=
nil) col1 = color;
3091 else OOLogWARN(
@"hyperspaceTunnel.fromDict",
@"could not interpret \"%@\
" as a colour.", colorDesc);
3094 colorDesc = [[
self globalSettings] objectForKey:@"hyperspace_tunnel_color_2"];
3095 if (colorDesc !=
nil)
3098 if (color !=
nil) col2 = color;
3099 else OOLogWARN(
@"hyperspaceTunnel.fromDict",
@"could not interpret \"%@\
" as a colour.", colorDesc);
3103 GLfloat startAngle = 0;
3104 GLfloat aspectRatio = 1;
3108 NSDictionary *info = [[PLAYER dockedStation] shipInfoDictionary];
3109 sides = [info oo_unsignedIntForKey:@"tunnel_corners" defaultValue:4];
3110 startAngle = [info oo_floatForKey:@"tunnel_start_angle" defaultValue:45.0f];
3111 aspectRatio = [info oo_floatForKey:@"tunnel_aspect_ratio" defaultValue:2.67f];
3114 for (i = 1; i < 11; i++)
3123 [ring
setPosition:HPvector_add(pos, vectorToHPVector(offset))];
3126 [ring
setLifetime:i * BREAK_PATTERN_RING_SPACING];
3130 if (forDocking && ![[
PLAYER dockedStation] hasBreakPattern])
3134 else if (!forDocking && ![
self witchspaceBreakPattern])
3138 [
self addEntity:ring];
3139 breakPatternCounter++;
3144- (BOOL) witchspaceBreakPattern
3146 return _witchspaceBreakPattern;
3150- (void) setWitchspaceBreakPattern:(BOOL)newValue
3152 _witchspaceBreakPattern = !!newValue;
3156- (BOOL) dockingClearanceProtocolActive
3158 return _dockingClearanceProtocolActive;
3162- (void) setDockingClearanceProtocolActive:(BOOL)newValue
3165 NSEnumerator *statEnum = [allStations objectEnumerator];
3173 while ((station = [statEnum nextObject]))
3176 if (![[[registry shipInfoForKey:stationKey] allKeys] containsObject:
@"requires_docking_clearance"])
3182 _dockingClearanceProtocolActive = !!newValue;
3186- (void) handleGameOver
3188 if ([[
self gameController] playerFileToLoad])
3190 [[
self gameController] loadPlayerIfRequired];
3194 [
self setUseAddOns:SCENARIO_OXP_DEFINITION_ALL fromSaveGame:NO forceReinit:YES];
3199- (void) setupIntroFirstGo:(BOOL)justCobra
3203 Quaternion q2 = { 0.0f, 0.0f, 1.0f, 0.0f };
3211 [
self removeDemoShips];
3223 ship = [
self newShipWithName:PLAYER_SHIP_DESC usePlayerProxy:YES];
3229 demo_ship_index = 0;
3230 demo_ship_subindex = 0;
3234 NSArray *subList =
nil;
3235 foreach (subList, demo_ships)
3237 if ([[[subList oo_dictionaryAtIndex:0] oo_stringForKey:
kOODemoShipClass] isEqualToString:
@"ship"])
3239 demo_ship_index = [demo_ships indexOfObject:subList];
3240 NSDictionary *shipEntry =
nil;
3241 foreach (shipEntry, subList)
3243 if ([[shipEntry oo_stringForKey:
kOODemoShipKey] isEqualToString:
@"cobra3-trader"])
3245 demo_ship_subindex = [subList indexOfObject:shipEntry];
3254 if (!demo_ship) ship = [
self newShipWithName:[[[demo_ships oo_arrayAtIndex:demo_ship_index] oo_dictionaryAtIndex:demo_ship_subindex] oo_stringForKey:kOODemoShipKey] usePlayerProxy:NO];
3265 [ship
setPositionX:0.0f
y:0.0f
z:DEMO2_VANISHING_DISTANCE * ship->collision_radius * 0.01];
3278 [
self addEntity:ship];
3280 [ship
setStatus:STATUS_COCKPIT_DISPLAY];
3289 [
self setLibraryTextForDemoShip];
3292 [
self enterGUIViewModeWithMouseInteraction:NO];
3296 demo_stage_time = universal_time + 300.0;
3303 return [[demo_ships oo_arrayAtIndex:demo_ship_index] oo_dictionaryAtIndex:demo_ship_subindex];
3313 [gui setTabStops:tab_stops];
3318 NSDictionary *librarySettings = [
self demoShipData];
3322 NSString *field1 =
nil;
3323 NSString *field2 =
nil;
3324 NSString *field3 =
nil;
3325 NSString *
override =
nil;
3328 for (NSUInteger i=1;i<=26;i++)
3330 [gui setText:@"" forRow:i];
3334 override = [librarySettings oo_stringForKey:kOODemoShipClass defaultValue:@"ship"];
3338 field2 = [demo_ship shipClassName];
3341 override = [librarySettings oo_stringForKey:kOODemoShipSummary defaultValue:nil];
3342 if (
override !=
nil)
3350 [gui setArray:[NSArray arrayWithObjects:field1,field2,field3,nil] forRow:1];
3362 override = [librarySettings oo_stringForKey:kOODemoShipSpeed defaultValue:nil];
3363 if (
override !=
nil)
3365 if ([
override length] == 0)
3371 field1 = [NSString stringWithFormat:DESC(@"oolite-ship-library-speed-custom"),OOExpand(override)];
3380 override = [librarySettings oo_stringForKey:kOODemoShipTurnRate defaultValue:nil];
3381 if (
override !=
nil)
3383 if ([
override length] == 0)
3389 field2 = [NSString stringWithFormat:DESC(@"oolite-ship-library-turn-custom"),OOExpand(override)];
3398 override = [librarySettings oo_stringForKey:kOODemoShipCargo defaultValue:nil];
3399 if (
override !=
nil)
3401 if ([
override length] == 0)
3407 field3 = [NSString stringWithFormat:DESC(@"oolite-ship-library-cargo-custom"),OOExpand(override)];
3416 [gui setArray:[NSArray arrayWithObjects:field1,field2,field3,nil] forRow:3];
3419 override = [librarySettings oo_stringForKey:kOODemoShipGenerator defaultValue:nil];
3420 if (
override !=
nil)
3422 if ([
override length] == 0)
3428 field1 = [NSString stringWithFormat:DESC(@"oolite-ship-library-generator-custom"),OOExpand(override)];
3437 override = [librarySettings oo_stringForKey:kOODemoShipShields defaultValue:nil];
3438 if (
override !=
nil)
3440 if ([
override length] == 0)
3446 field2 = [NSString stringWithFormat:DESC(@"oolite-ship-library-shields-custom"),OOExpand(override)];
3455 override = [librarySettings oo_stringForKey:kOODemoShipWitchspace defaultValue:nil];
3456 if (
override !=
nil)
3458 if ([
override length] == 0)
3464 field3 = [NSString stringWithFormat:DESC(@"oolite-ship-library-witchspace-custom"),OOExpand(override)];
3473 [gui setArray:[NSArray arrayWithObjects:field1,field2,field3,nil] forRow:4];
3477 override = [librarySettings oo_stringForKey:kOODemoShipWeapons defaultValue:nil];
3478 if (
override !=
nil)
3480 if ([
override length] == 0)
3486 field1 = [NSString stringWithFormat:DESC(@"oolite-ship-library-weapons-custom"),OOExpand(override)];
3494 override = [librarySettings oo_stringForKey:kOODemoShipTurrets defaultValue:nil];
3495 if (
override !=
nil)
3497 if ([
override length] == 0)
3503 field2 = [NSString stringWithFormat:DESC(@"oolite-ship-library-turrets-custom"),OOExpand(override)];
3511 override = [librarySettings oo_stringForKey:kOODemoShipSize defaultValue:nil];
3512 if (
override !=
nil)
3514 if ([
override length] == 0)
3520 field3 = [NSString stringWithFormat:DESC(@"oolite-ship-library-size-custom"),OOExpand(override)];
3528 [gui setArray:[NSArray arrayWithObjects:field1,field2,field3,nil] forRow:5];
3531 override = [librarySettings oo_stringForKey:kOODemoShipDescription defaultValue:nil];
3532 if (
override !=
nil)
3534 [gui addLongText:OOExpand(override) startingAtRow:descRow align:GUI_ALIGN_LEFT];
3539 field1 = [NSString stringWithFormat:@"<-- %@",OOShipLibraryCategoryPlural([[[demo_ships objectAtIndex:((demo_ship_index+[demo_ships count]-1)%[demo_ships count])] objectAtIndex:0] oo_stringForKey:kOODemoShipClass])];
3541 field3 = [NSString stringWithFormat:@"%@ -->",OOShipLibraryCategoryPlural([[[demo_ships objectAtIndex:((demo_ship_index+1)%[demo_ships count])] objectAtIndex:0] oo_stringForKey:kOODemoShipClass])];
3543 [gui setArray:[NSArray arrayWithObjects:field1,field2,field3,nil] forRow:19];
3547 NSArray *subList = [demo_ships objectAtIndex:demo_ship_index];
3548 NSUInteger i,start = demo_ship_subindex - (demo_ship_subindex%5);
3549 NSUInteger end = start + 4;
3550 if (end >= [subList
count])
3552 end = [subList count] - 1;
3557 for (i = start ; i <= end ; i++)
3559 field2 = [[subList objectAtIndex:i] oo_stringForKey:kOODemoShipName];
3560 [gui setArray:[NSArray arrayWithObjects:field1,field2,field3,nil] forRow:row];
3561 if (i == demo_ship_subindex)
3575 [gui setArray:[NSArray arrayWithObjects:field1,field2,field3,nil] forRow:20];
3578 if (end < [subList
count]-1)
3580 [gui setArray:[NSArray arrayWithObjects:field1,field2,field3,nil] forRow:26];
3587- (void) selectIntro2Previous
3590 NSUInteger subcount = [[demo_ships objectAtIndex:demo_ship_index] count];
3591 demo_ship_subindex = (demo_ship_subindex + subcount - 2) % subcount;
3592 demo_stage_time = universal_time - 1.0;
3596- (void) selectIntro2PreviousCategory
3599 demo_ship_index = (demo_ship_index + [demo_ships
count] - 1) % [demo_ships
count];
3600 demo_ship_subindex = [[demo_ships objectAtIndex:demo_ship_index] count] - 1;
3601 demo_stage_time = universal_time - 1.0;
3605- (void) selectIntro2NextCategory
3608 demo_ship_index = (demo_ship_index + 1) % [demo_ships
count];
3609 demo_ship_subindex = [[demo_ships objectAtIndex:demo_ship_index] count] - 1;
3610 demo_stage_time = universal_time - 1.0;
3614- (void) selectIntro2Next
3617 demo_stage_time = universal_time - 1.0;
3627static BOOL IsFriendlyStationPredicate(
Entity *entity,
void *parameter)
3635 if (cachedSun !=
nil && cachedStation ==
nil)
3637 cachedStation = [
self findOneEntityMatchingPredicate:IsCandidateMainStationPredicate
3640 return cachedStation;
3644- (
StationEntity *) stationWithRole:(NSString *)role andPosition:(HPVector)position
3646 if ([role isEqualToString:
@""])
3651 float range = 1000000;
3653 NSArray *stations = [
self stations];
3655 foreach (station, stations)
3657 if (HPdistance2(position,[station position]) < range)
3659 if ([[station primaryRole] isEqualToString:role])
3673 return [
self findOneEntityMatchingPredicate:IsFriendlyStationPredicate parameter:ship];
3677- (OOPlanetEntity *) planet
3679 if (cachedPlanet ==
nil && [allPlanets
count] > 0)
3681 cachedPlanet = [allPlanets objectAtIndex:0];
3683 return cachedPlanet;
3689 if (cachedSun ==
nil)
3691 cachedSun = [
self findOneEntityMatchingPredicate:IsSunPredicate parameter:nil];
3697- (NSArray *) planets
3703- (NSArray *) stations
3705 return [allStations allObjects];
3709- (NSArray *) wormholes
3711 return activeWormholes;
3715- (void) unMagicMainStation
3727 if (playerStatus == STATUS_START_GAME)
return;
3731 cachedStation =
nil;
3735- (void) resetBeacons
3737 Entity <OOBeaconEntity> *beaconShip = [
self firstBeacon], *next =
nil;
3740 next = [beaconShip nextBeacon];
3741 [beaconShip setPrevBeacon:nil];
3742 [beaconShip setNextBeacon:nil];
3746 [
self setFirstBeacon:nil];
3747 [
self setLastBeacon:nil];
3751- (
Entity <OOBeaconEntity> *) firstBeacon
3753 return [_firstBeacon weakRefUnderlyingObject];
3757- (void) setFirstBeacon:(
Entity <OOBeaconEntity> *)beacon
3759 if (beacon != [
self firstBeacon])
3761 [beacon setPrevBeacon:nil];
3762 [beacon setNextBeacon:[
self firstBeacon]];
3763 [[
self firstBeacon] setPrevBeacon:beacon];
3764 [_firstBeacon release];
3765 _firstBeacon = [beacon weakRetain];
3770- (
Entity <OOBeaconEntity> *) lastBeacon
3772 return [_lastBeacon weakRefUnderlyingObject];
3776- (void) setLastBeacon:(
Entity <OOBeaconEntity> *)beacon
3778 if (beacon != [
self lastBeacon])
3780 [beacon setNextBeacon:nil];
3781 [beacon setPrevBeacon:[
self lastBeacon]];
3782 [[
self lastBeacon] setNextBeacon:beacon];
3783 [_lastBeacon release];
3784 _lastBeacon = [beacon weakRetain];
3789- (void) setNextBeacon:(
Entity <OOBeaconEntity> *) beaconShip
3791 if ([beaconShip isBeacon])
3793 [
self setLastBeacon:beaconShip];
3794 if ([
self firstBeacon] ==
nil) [
self setFirstBeacon:beaconShip];
3798 OOLog(
@"universe.beacon.error",
@"***** ERROR: Universe setNextBeacon '%@'. The ship has no beacon code set.", beaconShip);
3803- (void) clearBeacon:(
Entity <OOBeaconEntity> *) beaconShip
3805 Entity <OOBeaconEntity> *tmp =
nil;
3807 if ([beaconShip isBeacon])
3809 if ([
self firstBeacon] == beaconShip)
3811 tmp = [[beaconShip nextBeacon] nextBeacon];
3812 [
self setFirstBeacon:[beaconShip nextBeacon]];
3813 [[beaconShip prevBeacon] setNextBeacon:tmp];
3815 else if ([
self lastBeacon] == beaconShip)
3817 tmp = [[beaconShip prevBeacon] prevBeacon];
3818 [
self setLastBeacon:[beaconShip prevBeacon]];
3819 [[beaconShip nextBeacon] setPrevBeacon:tmp];
3823 [[beaconShip nextBeacon] setPrevBeacon:[beaconShip prevBeacon]];
3824 [[beaconShip prevBeacon] setNextBeacon:[beaconShip nextBeacon]];
3826 [beaconShip setBeaconCode:nil];
3831- (NSDictionary *) currentWaypoints
3837- (void) defineWaypoint:(NSDictionary *)definition forKey:(NSString *)key
3840 BOOL preserveCompass = NO;
3841 waypoint = [waypoints objectForKey:key];
3842 if (waypoint !=
nil)
3844 if ([
PLAYER compassTarget] == waypoint)
3846 preserveCompass = YES;
3848 [
self removeEntity:waypoint];
3849 [waypoints removeObjectForKey:key];
3851 if (definition !=
nil)
3854 if (waypoint !=
nil)
3856 [
self addEntity:waypoint];
3857 [waypoints setObject:waypoint forKey:key];
3858 if (preserveCompass)
3860 [PLAYER setCompassTarget:waypoint];
3861 [PLAYER setNextBeacon:waypoint];
3868- (GLfloat *) skyClearColor
3870 return skyClearColor;
3874- (void) setSkyColorRed:(GLfloat)red green:(GLfloat)green blue:(GLfloat)blue alpha:(GLfloat)alpha
3876 skyClearColor[0] = red;
3877 skyClearColor[1] = green;
3878 skyClearColor[2] = blue;
3879 skyClearColor[3] = alpha;
3880 [
self setAirResistanceFactor:alpha];
3884- (BOOL) breakPatternOver
3886 return (breakPatternCounter == 0);
3890- (BOOL) breakPatternHide
3893 return ((breakPatternCounter > 5)||(!player)||([player status] == STATUS_DOCKING));
3897#define PROFILE_SHIP_SELECTION 0
3900- (BOOL) canInstantiateShip:(NSString *)shipKey
3902 NSDictionary *shipInfo =
nil;
3903 NSArray *conditions =
nil;
3904 NSString *condition_script =
nil;
3907 condition_script = [shipInfo oo_stringForKey:@"condition_script"];
3908 if (condition_script !=
nil)
3910 OOJSScript *condScript = [
self getConditionScript:condition_script];
3911 if (condScript !=
nil)
3915 JSBool allow_instantiation;
3919 OK = [condScript
callMethod:OOJSID("allowSpawnShip")
3924 if (OK) OK = JS_ValueToBoolean(context, result, &allow_instantiation);
3928 if (OK && !allow_instantiation)
3938 conditions = [shipInfo oo_arrayForKey:@"conditions"];
3939 if (conditions ==
nil)
return YES;
3942 return [PLAYER scriptTestConditions:conditions];
3946- (NSString *) randomShipKeyForRoleRespectingConditions:(NSString *)role
3951 NSString *shipKey =
nil;
3954#if PROFILE_SHIP_SELECTION
3955 static unsigned long profTotal = 0, profSlowPath = 0;
3960 shipKey = [registry randomShipKeyForRole:role];
3961 if ([
self canInstantiateShip:shipKey])
return shipKey;
3970#if PROFILE_SHIP_SELECTION
3972 if ((profSlowPath % 10) == 0)
3974 OOLog(
@"shipRegistry.selection.profile",
@"Hit slow path in ship selection for role \"%@\
", having selected ship \"%@\". Now %lu of %lu on slow path (%f%%).", role, shipKey, profSlowPath, profTotal, ((
double)profSlowPath)/((
double)profTotal) * 100.0f);
3978 pset = [[[registry probabilitySetForRole:role] mutableCopy] autorelease];
3980 while ([pset
count] > 0)
3984 if ([
self canInstantiateShip:shipKey])
return shipKey;
3997- (
ShipEntity *) newShipWithRole:(NSString *)role
4002 NSString *shipKey =
nil;
4003 NSDictionary *shipInfo =
nil;
4004 NSString *autoAI =
nil;
4006 shipKey = [
self randomShipKeyForRoleRespectingConditions:role];
4009 ship = [
self newShipWithName:shipKey];
4012 [ship setPrimaryRole:role];
4015 if ([shipInfo oo_fuzzyBooleanForKey:
@"auto_ai" defaultValue:YES])
4018 autoAI = [
self defaultAIForRole:role];
4021 [ship setAITo:autoAI];
4024 if ([role isEqualToString:
@"pirate"]) [ship setBounty:20 + randf() * 50 withReason:kOOLegalStatusReasonSetup];
4025 if ([role isEqualToString:
@"trader"]) [ship setBounty:0 withReason:kOOLegalStatusReasonSetup];
4026 if ([role isEqualToString:
@"police"]) [ship setScanClass:CLASS_POLICE];
4027 if ([role isEqualToString:
@"interceptor"])
4029 [ship setScanClass: CLASS_POLICE];
4030 [ship setPrimaryRole:@"police"];
4033 if ([role isEqualToString:
@"thargoid"]) [ship setScanClass: CLASS_THARGOID];
4048 NSDictionary *effectDict =
nil;
4052 if (effectDict ==
nil)
return nil;
4058 @catch (NSException *exception)
4062 OOLog(
kOOLogException,
@"***** Oolite Exception : '%@' in [Universe newVisualEffectWithName: %@ ] *****", [exception reason], effectKey);
4064 else @throw exception;
4073- (
ShipEntity *) newSubentityWithName:(NSString *)shipKey andScaleFactor:(
float)scale
4075 return [
self newShipWithName:shipKey usePlayerProxy:NO isSubentity:YES andScaleFactor:scale];
4079- (
ShipEntity *) newShipWithName:(NSString *)shipKey usePlayerProxy:(BOOL)usePlayerProxy
4081 return [
self newShipWithName:shipKey usePlayerProxy:usePlayerProxy isSubentity:NO];
4084- (
ShipEntity *) newShipWithName:(NSString *)shipKey usePlayerProxy:(BOOL)usePlayerProxy isSubentity:(BOOL)isSubentity
4086 return [
self newShipWithName:shipKey usePlayerProxy:usePlayerProxy isSubentity:isSubentity andScaleFactor:1.0f];
4089- (
ShipEntity *) newShipWithName:(NSString *)shipKey usePlayerProxy:(BOOL)usePlayerProxy isSubentity:(BOOL)isSubentity andScaleFactor:(
float)scale
4093 NSDictionary *shipDict =
nil;
4097 if (shipDict ==
nil)
return nil;
4099 volatile Class shipClass =
nil;
4106 shipClass = [
self shipClassForShipDictionary:shipDict];
4107 if (usePlayerProxy && shipClass == [
ShipEntity class])
4117 NSMutableDictionary *mShipDict = [shipDict mutableCopy];
4118 [mShipDict setObject:[NSNumber numberWithFloat:scale] forKey:@"model_scale_factor"];
4119 shipDict = [NSDictionary dictionaryWithDictionary:mShipDict];
4120 [mShipDict release];
4122 ship = [[shipClass alloc] initWithKey:shipKey definition:shipDict];
4124 @catch (NSException *exception)
4128 OOLog(
kOOLogException,
@"***** Oolite Exception : '%@' in [Universe newShipWithName: %@ ] *****", [exception reason], shipKey);
4130 else @throw exception;
4143- (
DockEntity *) newDockWithName:(NSString *)shipDataKey andScaleFactor:(
float)scale
4147 NSDictionary *shipDict =
nil;
4151 if (shipDict ==
nil)
return nil;
4157 NSMutableDictionary *mShipDict = [shipDict mutableCopy];
4158 [mShipDict setObject:[NSNumber numberWithFloat:scale] forKey:@"model_scale_factor"];
4159 shipDict = [NSDictionary dictionaryWithDictionary:mShipDict];
4160 [mShipDict release];
4162 dock = [[
DockEntity alloc] initWithKey:shipDataKey definition:shipDict];
4164 @catch (NSException *exception)
4168 OOLog(
kOOLogException,
@"***** Oolite Exception : '%@' in [Universe newDockWithName: %@ ] *****", [exception reason], shipDataKey);
4170 else @throw exception;
4175 if ([dock hasRole:shipDataKey]) [dock
setPrimaryRole:shipDataKey];
4183- (
ShipEntity *) newShipWithName:(NSString *)shipKey
4185 return [
self newShipWithName:shipKey usePlayerProxy:NO];
4189- (Class) shipClassForShipDictionary:(NSDictionary *)dict
4193 if (dict ==
nil)
return Nil;
4195 BOOL isStation = NO;
4196 NSString *shipRoles = [dict oo_stringForKey:@"roles"];
4198 if (shipRoles !=
nil)
4200 isStation = [shipRoles rangeOfString:@"station"].location != NSNotFound ||
4201 [shipRoles rangeOfString:@"carrier"].location != NSNotFound;
4205 isStation = [dict oo_boolForKey:@"isCarrier" defaultValue:isStation];
4206 isStation = [dict oo_boolForKey:@"is_carrier" defaultValue:isStation];
4215- (NSString *)defaultAIForRole:(NSString *)role
4217 return [autoAIMap oo_stringForKey:role];
4232 foreach (itemData, equipmentData)
4234 NSString *itemType = [itemData oo_stringAtIndex:EQUIPMENT_KEY_INDEX];
4236 if ([itemType isEqual:eq_key])
4238 return [itemData oo_unsignedLongLongAtIndex:EQUIPMENT_PRICE_INDEX];
4254 if ([cargoObj isTemplateCargoPod])
4256 return [UNIVERSE cargoPodFromTemplate:cargoObj];
4270 OOCargoQuantity co_amount = [UNIVERSE getRandomAmountOfCommodity:co_type];
4273 container = [UNIVERSE newShipWithRole:co_type];
4275 if (container ==
nil)
4277 container = [UNIVERSE newShipWithRole:@"cargopod"];
4280 return [container autorelease];
4284- (NSArray *) getContainersOfGoods:(
OOCargoQuantity)how_many scarce:(BOOL)scarce legal:(BOOL)legal
4290 NSMutableArray *accumulator = [NSMutableArray arrayWithCapacity:how_many];
4291 NSUInteger i=0, commodityCount = [commodityMarket count];
4295 NSArray *goodsKeys = [commodityMarket goods];
4296 NSString *goodsKey =
nil;
4298 foreach (goodsKey, goodsKeys)
4303 if (q < 64) q = 64 - q;
4308 if (legal && [commodityMarket exportLegalityForGood:goodsKey] > 0)
4314 quantities[i++] = q;
4315 total_quantity += q;
4318 for (i = 0; i < how_many; i++)
4320 NSUInteger co_type = 0;
4325 qr = 1+(
Ranrot() % total_quantity);
4329 NSAssert((NSUInteger)co_type < commodityCount,
@"Commodity type index out of range.");
4330 qr -= quantities[co_type++];
4335 ShipEntity *container = [cargoPods objectForKey:[goodsKeys oo_stringAtIndex:co_type]];
4337 if (container !=
nil)
4339 [accumulator addObject:container];
4343 OOLog(
@"universe.createContainer.failed",
@"***** ERROR: failed to find a container to fill with %@ (%ld).", [goodsKeys oo_stringAtIndex:co_type], co_type);
4347 return [NSArray arrayWithArray:accumulator];
4353 NSMutableArray *accumulator = [NSMutableArray arrayWithCapacity:how_much];
4354 if (![commodities goodDefined:commodity_name])
4356 return [NSArray array];
4359 ShipEntity *container = [cargoPods objectForKey:commodity_name];
4360 while (how_much > 0)
4364 [accumulator addObject:container];
4368 OOLog(
@"universe.createContainer.failed",
@"***** ERROR: failed to find a container to fill with %@", commodity_name);
4373 return [NSArray arrayWithArray:accumulator];
4377- (void) fillCargopodWithRandomCargo:(
ShipEntity *)cargopod
4379 if (cargopod ==
nil || ![cargopod hasRole:
@"cargopod"] || [cargopod cargoType] ==
CARGO_SCRIPTED_ITEM)
return;
4381 if ([cargopod commodityType] ==
nil || ![cargopod commodityAmount])
4383 NSString *aCommodity = [
self getRandomCommodity];
4384 OOCargoQuantity aQuantity = [
self getRandomAmountOfCommodity:aCommodity];
4390- (NSString *) getRandomCommodity
4392 return [commodities getRandomCommodity];
4400 if (co_type ==
nil) {
4404 units = [commodities massUnitForGood:co_type];
4414 OOLog(
@"universe.commodityAmount.warning",
@"Commodity %@ has an unrecognised mass unit, assuming tonnes",co_type);
4421 return [commodityMarket definitionForGood:type];
4427 return [commodityMarket nameForGood:co_type];
4434 NSString *unitDesc =
nil, *typeDesc =
nil;
4435 NSDictionary *commodity = [
self commodityDataForType:co_type];
4437 if (commodity ==
nil)
return @"";
4439 units = [commodityMarket massUnitForGood:co_type];
4445 unitDesc =
DESC(
@"cargo-kilogram");
4448 unitDesc =
DESC(
@"cargo-gram");
4452 unitDesc =
DESC(
@"cargo-ton");
4461 unitDesc =
DESC(
@"cargo-kilograms");
4464 unitDesc =
DESC(
@"cargo-grams");
4468 unitDesc =
DESC(
@"cargo-tons");
4473 typeDesc = [commodityMarket nameForGood:co_type];
4475 return [NSString stringWithFormat:@"%d %@ %@",co_amount, unitDesc, typeDesc];
4483 gameView = [view retain];
4495 return [[
self gameView] gameController];
4499- (NSDictionary *) gameSettings
4502 NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:11];
4504 NSMutableDictionary *result = [NSMutableDictionary dictionaryWithCapacity:10];
4507 [result oo_setInteger:[PLAYER isSpeechOn] forKey:@"speechOn"];
4508 [result oo_setBool:autoSave forKey:@"autosave"];
4509 [result oo_setBool:wireframeGraphics forKey:@"wireframeGraphics"];
4510 [result oo_setBool:doProcedurallyTexturedPlanets forKey:@"procedurallyTexturedPlanets"];
4512 [result oo_setFloat:[gameView gammaValue] forKey:@"gammaValue"];
4515 [result oo_setFloat:[gameView fov:NO] forKey:@"fovValue"];
4518 if ([gameView hdrOutput])
4520 [result oo_setFloat:[gameView hdrMaxBrightness] forKey:@"hdr-max-brightness"];
4521 [result oo_setFloat:[gameView hdrPaperWhiteBrightness] forKey:@"hdr-paperwhite-brightness"];
4525 [result setObject:OOStringFromGraphicsDetail([
self detailLevel]) forKey:@"detailLevel"];
4527 NSString *desc =
@"UNDEFINED";
4534 [result setObject:desc forKey:@"musicMode"];
4536 NSDictionary *gameWindow = [NSDictionary dictionaryWithObjectsAndKeys:
4537 [NSNumber numberWithFloat:[gameView viewSize].width], @"width",
4538 [NSNumber numberWithFloat:[gameView viewSize].height], @"height",
4539 [NSNumber numberWithBool:[[
self gameController] inFullScreenMode]], @"fullScreen",
4541 [result setObject:gameWindow forKey:@"gameWindow"];
4543 [result setObject:[PLAYER keyConfig] forKey:@"keyConfig"];
4545 return [[result copy] autorelease];
4549- (void) useGUILightSource:(BOOL)GUILight
4553 if (![
self useShaders])
4557 OOGL(glEnable(GL_LIGHT0));
4558 OOGL(glDisable(GL_LIGHT1));
4562 OOGL(glEnable(GL_LIGHT1));
4563 OOGL(glDisable(GL_LIGHT0));
4572 else OOGL(glEnable(GL_LIGHT1));
4579- (void) lightForEntity:(BOOL)isLit
4583 if ([
self useShaders])
4587 OOGL(glLightfv(GL_LIGHT1, GL_DIFFUSE, sun_diffuse));
4588 OOGL(glLightfv(GL_LIGHT1, GL_SPECULAR, sun_specular));
4600 if (isLit)
OOGL(glEnable(GL_LIGHT1));
4601 else OOGL(glDisable(GL_LIGHT1));
4606 OOGL(glEnable(GL_LIGHT0));
4622 { 1.0f, 0.0f, 0.0f, 0.0f },
4623 { 0.0f, 1.0f, 0.0f, 0.0f },
4624 { 0.0f, 0.0f, 1.0f, 0.0f },
4625 { 0.0f, 0.0f, 0.0f, 1.0f }
4629 {-1.0f, 0.0f, 0.0f, 0.0f },
4630 { 0.0f, 1.0f, 0.0f, 0.0f },
4631 { 0.0f, 0.0f, -1.0f, 0.0f },
4632 { 0.0f, 0.0f, 0.0f, 1.0f }
4636 { 0.0f, 0.0f, -1.0f, 0.0f },
4637 { 0.0f, 1.0f, 0.0f, 0.0f },
4638 { 1.0f, 0.0f, 0.0f, 0.0f },
4639 { 0.0f, 0.0f, 0.0f, 1.0f }
4643 { 0.0f, 0.0f, 1.0f, 0.0f },
4644 { 0.0f, 1.0f, 0.0f, 0.0f },
4645 {-1.0f, 0.0f, 0.0f, 0.0f },
4646 { 0.0f, 0.0f, 0.0f, 1.0f }
4650- (void) getActiveViewMatrix:(OOMatrix *)outMatrix forwardVector:(Vector *)outForward upVector:(Vector *)outUp
4652 assert(outMatrix != NULL && outForward != NULL && outUp != NULL);
4656 switch (viewDirection)
4670 case VIEW_STARBOARD:
4685 case VIEW_GUI_DISPLAY:
4686 case VIEW_BREAK_PATTERN:
4696- (OOMatrix) activeViewMatrix
4701 [
self getActiveViewMatrix:&m forwardVector:&f upVector:&u];
4711- (void) defineFrustum
4719 frustum[0][0] = clip.m[0][3] - clip.m[0][0];
4720 frustum[0][1] = clip.m[1][3] - clip.m[1][0];
4721 frustum[0][2] = clip.m[2][3] - clip.m[2][0];
4722 frustum[0][3] = clip.m[3][3] - clip.m[3][0];
4725 rt = 1.0f / sqrt(frustum[0][0] * frustum[0][0] + frustum[0][1] * frustum[0][1] + frustum[0][2] * frustum[0][2]);
4726 frustum[0][0] *= rt;
4727 frustum[0][1] *= rt;
4728 frustum[0][2] *= rt;
4729 frustum[0][3] *= rt;
4732 frustum[1][0] = clip.m[0][3] + clip.m[0][0];
4733 frustum[1][1] = clip.m[1][3] + clip.m[1][0];
4734 frustum[1][2] = clip.m[2][3] + clip.m[2][0];
4735 frustum[1][3] = clip.m[3][3] + clip.m[3][0];
4738 rt = 1.0f / sqrt(frustum[1][0] * frustum[1][0] + frustum[1][1] * frustum[1][1] + frustum[1][2] * frustum[1][2]);
4739 frustum[1][0] *= rt;
4740 frustum[1][1] *= rt;
4741 frustum[1][2] *= rt;
4742 frustum[1][3] *= rt;
4745 frustum[2][0] = clip.m[0][3] + clip.m[0][1];
4746 frustum[2][1] = clip.m[1][3] + clip.m[1][1];
4747 frustum[2][2] = clip.m[2][3] + clip.m[2][1];
4748 frustum[2][3] = clip.m[3][3] + clip.m[3][1];
4751 rt = 1.0 / sqrt(frustum[2][0] * frustum[2][0] + frustum[2][1] * frustum[2][1] + frustum[2][2] * frustum[2][2]);
4752 frustum[2][0] *= rt;
4753 frustum[2][1] *= rt;
4754 frustum[2][2] *= rt;
4755 frustum[2][3] *= rt;
4758 frustum[3][0] = clip.m[0][3] - clip.m[0][1];
4759 frustum[3][1] = clip.m[1][3] - clip.m[1][1];
4760 frustum[3][2] = clip.m[2][3] - clip.m[2][1];
4761 frustum[3][3] = clip.m[3][3] - clip.m[3][1];
4764 rt = 1.0 / sqrt(frustum[3][0] * frustum[3][0] + frustum[3][1] * frustum[3][1] + frustum[3][2] * frustum[3][2]);
4765 frustum[3][0] *= rt;
4766 frustum[3][1] *= rt;
4767 frustum[3][2] *= rt;
4768 frustum[3][3] *= rt;
4771 frustum[4][0] = clip.m[0][3] - clip.m[0][2];
4772 frustum[4][1] = clip.m[1][3] - clip.m[1][2];
4773 frustum[4][2] = clip.m[2][3] - clip.m[2][2];
4774 frustum[4][3] = clip.m[3][3] - clip.m[3][2];
4777 rt = sqrt(frustum[4][0] * frustum[4][0] + frustum[4][1] * frustum[4][1] + frustum[4][2] * frustum[4][2]);
4778 frustum[4][0] *= rt;
4779 frustum[4][1] *= rt;
4780 frustum[4][2] *= rt;
4781 frustum[4][3] *= rt;
4784 frustum[5][0] = clip.m[0][3] + clip.m[0][2];
4785 frustum[5][1] = clip.m[1][3] + clip.m[1][2];
4786 frustum[5][2] = clip.m[2][3] + clip.m[2][2];
4787 frustum[5][3] = clip.m[3][3] + clip.m[3][2];
4790 rt = sqrt(frustum[5][0] * frustum[5][0] + frustum[5][1] * frustum[5][1] + frustum[5][2] * frustum[5][2]);
4791 frustum[5][0] *= rt;
4792 frustum[5][1] *= rt;
4793 frustum[5][2] *= rt;
4794 frustum[5][3] *= rt;
4798- (BOOL) viewFrustumIntersectsSphereAt:(Vector)position withRadius:(GLfloat)radius
4802 for (p = 0; p < 6; p++)
4804 if (frustum[p][0] * position.x + frustum[p][1] * position.y + frustum[p][2] * position.z + frustum[p][3] <= -radius)
4813- (void) drawUniverse
4815 int currentPostFX = [
self currentPostFX];
4817 NSSize viewSize = [gameView viewSize];
4818 OOLog(
@"universe.profile.draw",
@"%@",
@"Begin draw");
4822 if ((
int)targetFramebufferSize.width != (
int)viewSize.width || (
int)targetFramebufferSize.height != (
int)viewSize.height)
4824 [
self resizeTargetFramebufferWithViewSize:viewSize];
4827 if([
self useShaders])
4829 if ([gameView msaa])
4831 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, msaaFramebufferID));
4835 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, targetFramebufferID));
4842 int i, v_status, vdist;
4843 Vector view_dir, view_up;
4844 OOMatrix view_matrix;
4845 int ent_count = n_entities;
4846 Entity *my_entities[ent_count];
4852 float aspect = viewSize.height/viewSize.width;
4854 if (!displayGUI && wasDisplayGUI)
4857 if (cachedSun) [UNIVERSE setMainLightPosition:HPVectorToVector([cachedSun position])];
4858 else [UNIVERSE setMainLightPosition:kZeroVector];
4860 wasDisplayGUI = displayGUI;
4862 for (i = 0; i < ent_count; i++)
4869 Entity *e = sortedEntities[i];
4872 my_entities[draw_count++] = [[e retain] autorelease];
4876 v_status = [player
status];
4882 OOGL(glClear(GL_COLOR_BUFFER_BIT));
4886 OOGL(glClearColor(skyClearColor[0], skyClearColor[1], skyClearColor[2], skyClearColor[3]));
4890 OOGL(glClearColor(0.0, 0.0, 0.0, 0.0));
4894 [gui drawGUIBackground];
4898 BOOL fogging, bpHide = [
self breakPatternHide];
4900 for (vdist=0;vdist<=1;vdist++)
4904 float ratio = (displayGUI ? 0.5 : [gameView fov:YES]) * nearPlane;
4907 if ((displayGUI && 4*aspect >= 3) || (!displayGUI && 4*aspect <= 3))
4909 OOGLFrustum(-ratio, ratio, -aspect*ratio, aspect*ratio, nearPlane, farPlane);
4913 OOGLFrustum(-3*ratio/aspect/4, 3*ratio/aspect/4, -3*ratio/4, 3*ratio/4, nearPlane, farPlane);
4916 [
self getActiveViewMatrix:&view_matrix forwardVector:&view_dir upVector:&view_up];
4948 OOGL(glClear(GL_DEPTH_BUFFER_BIT));
4953 flipMatrix.m[2][2] = -1;
4959 if (
EXPECT(!displayGUI || demoShipMode))
4961 if (
EXPECT(!demoShipMode))
4967 OOGL(glLightModelfv(GL_LIGHT_MODEL_AMBIENT, stars_ambient));
4971 [
self setMainLightPosition:[cachedSun cameraRelativePosition]];
4976 [
self setMainLightPosition:HPVectorToVector(HPvector_flip([PLAYER viewpointPosition]))];
4978 OOGL(glLightfv(GL_LIGHT1, GL_POSITION, main_light_position));
4984 OOGL(glLightfv(GL_LIGHT0, GL_POSITION, main_light_position));
4986 OOGL(glLightfv(GL_LIGHT1, GL_POSITION, main_light_position));
4990 OOGL([
self useGUILightSource:demoShipMode]);
4995 int furthest = draw_count - 1;
4997 BOOL inAtmosphere = airResistanceFactor > 0.01;
4998 GLfloat fogFactor = 0.5 / airResistanceFactor;
4999 double fog_scale, half_scale;
5000 GLfloat flat_ambdiff[4] = {1.0, 1.0, 1.0, 1.0};
5001 GLfloat mat_no[4] = {0.0, 0.0, 0.0, 1.0};
5004 OOGL(glHint(GL_FOG_HINT, [
self reducedDetail] ? GL_FASTEST : GL_NICEST));
5006 [
self defineFrustum];
5010 OOLog(
@"universe.profile.draw",
@"%@",
@"Begin opaque pass");
5014 for (i = furthest; i >= nearest; i--)
5016 drawthing = my_entities[i];
5020 if (vdist == 1 && [drawthing cameraRangeFront] > farPlane*1.5)
continue;
5021 if (vdist == 0 && [drawthing cameraRangeBack] < nearPlane)
continue;
5024 if (!((d_status == STATUS_COCKPIT_DISPLAY) ^ demoShipMode))
5028 OOGL(glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, flat_ambdiff));
5029 OOGL(glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, mat_no));
5032 if (
EXPECT(drawthing != player))
5055 half_scale = fog_scale * 0.50;
5056 OOGL(glEnable(GL_FOG));
5057 OOGL(glFogi(GL_FOG_MODE, GL_LINEAR));
5058 OOGL(glFogfv(GL_FOG_COLOR, skyClearColor));
5059 OOGL(glFogf(GL_FOG_START, half_scale));
5060 OOGL(glFogf(GL_FOG_END, fog_scale));
5061 fog_blend = OOClamp_0_1_f((magnitude([drawthing cameraRelativePosition]) - half_scale)/half_scale);
5065 [
self lightForEntity:demoShipMode || drawthing->isSunlit];
5076 OOGL(glDisable(GL_FOG));
5081 if (!((d_status == STATUS_COCKPIT_DISPLAY) ^ demoShipMode))
5084 if (
EXPECT(drawthing != player))
5107 half_scale = fog_scale * 0.50;
5108 OOGL(glEnable(GL_FOG));
5109 OOGL(glFogi(GL_FOG_MODE, GL_LINEAR));
5110 OOGL(glFogfv(GL_FOG_COLOR, skyClearColor));
5111 OOGL(glFogf(GL_FOG_START, half_scale));
5112 OOGL(glFogf(GL_FOG_END, fog_scale));
5113 fog_blend = OOClamp_0_1_f((magnitude([drawthing cameraRelativePosition]) - half_scale)/half_scale);
5124 OOGL(glDisable(GL_FOG));
5141 if (!bpHide && cachedSun)
5143 [cachedSun drawDirectVisionSunGlare];
5144 [cachedSun drawStarGlare];
5149 if (hudSeparateRenderPass)
5154 [
self prepareToRenderIntoDefaultFramebuffer];
5155 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, defaultDrawFBO));
5157 OOLog(
@"universe.profile.secondPassDraw",
@"%@",
@"Begin second pass draw");
5158 [
self drawTargetTextureIntoDefaultFramebuffer];
5159 OOCheckOpenGLErrors(
@"Universe after drawing from custom framebuffer to screen framebuffer");
5160 OOLog(
@"universe.profile.secondPassDraw",
@"%@",
@"End second pass drawing");
5162 OOLog(
@"universe.profile.drawHUD",
@"%@",
@"Begin HUD drawing");
5167 OOLog(
@"universe.profile.draw",
@"%@",
@"Begin HUD");
5169 GLfloat lineWidth = [gameView viewSize].width / 1024.0;
5170 if (lineWidth < 1.0) lineWidth = 1.0;
5171 if (lineWidth > 1.5) lineWidth = 1.5;
5178 if ([theHUD deferredHudName] !=
nil)
5182 [deferredName release];
5183 theHUD = [player
hud];
5187 static float sPrevHudAlpha = -1.0f;
5188 if ([theHUD isHidden])
5190 if (sPrevHudAlpha < 0.0f)
5196 else if (sPrevHudAlpha >= 0.0f)
5199 sPrevHudAlpha = -1.0f;
5204 case STATUS_ESCAPE_SEQUENCE:
5205 case STATUS_START_GAME:
5209 switch ([player guiScreen])
5223#if (defined (SNAPSHOT_BUILD) && defined (OOLITE_SNAPSHOT_VERSION))
5224 [
self drawWatermarkString:@"Development version " @OOLITE_SNAPSHOT_VERSION];
5227 OOLog(
@"universe.profile.drawHUD",
@"%@",
@"End HUD drawing");
5236 if (![[
self gameController] isGamePaused])
5238 framesDoneThisUpdate++;
5241 @catch (NSException *exception)
5245 if ([[exception name] hasPrefix:
@"Oolite"])
5247 [
self handleOoliteException:exception];
5251 OOLog(
kOOLogException,
@"***** Exception: %@ : %@ *****",[exception name], [exception reason]);
5257 OOLog(
@"universe.profile.draw",
@"%@",
@"End drawing");
5260 if(!hudSeparateRenderPass)
5262 if([
self useShaders])
5264 [
self prepareToRenderIntoDefaultFramebuffer];
5265 OOGL(glBindFramebuffer(GL_FRAMEBUFFER, defaultDrawFBO));
5267 OOLog(
@"universe.profile.secondPassDraw",
@"%@",
@"Begin second pass draw");
5268 [
self drawTargetTextureIntoDefaultFramebuffer];
5269 OOLog(
@"universe.profile.secondPassDraw",
@"%@",
@"End second pass drawing");
5277 NSSize viewSize = [gameView viewSize];
5278 if([
self useShaders])
5280 if ([gameView msaa])
5283 OOGL(glBindFramebuffer(GL_READ_FRAMEBUFFER, msaaFramebufferID));
5284 OOGL(glBindFramebuffer(GL_DRAW_FRAMEBUFFER, targetFramebufferID));
5285 OOGL(glBlitFramebuffer(0, 0, (GLint)viewSize.width, (GLint)viewSize.height, 0, 0, (GLint)viewSize.width, (GLint)viewSize.height, GL_COLOR_BUFFER_BIT, GL_NEAREST));
5291- (
int) framesDoneThisUpdate
5293 return framesDoneThisUpdate;
5297- (void) resetFramesDoneThisUpdate
5299 framesDoneThisUpdate = 0;
5303- (OOMatrix) viewMatrix
5313 OOGL(glDisable(GL_TEXTURE_2D));
5315 float overallAlpha = [[PLAYER hud] overallAlpha];
5320 cursor_row = [gui drawGUI:1.0 drawCursor:YES];
5324 [gui drawGUI:1.0 drawCursor:NO];
5328 [message_gui drawGUI:[message_gui alpha] * overallAlpha drawCursor:NO];
5329 [comm_log_gui drawGUI:[comm_log_gui alpha] * overallAlpha drawCursor:NO];
5335- (void) drawWatermarkString:(NSString *) watermarkString
5337 NSSize watermarkStringSize =
OORectFromString(watermarkString, 0.0f, 0.0f, NSMakeSize(10, 10)).size;
5339 OOGL(glColor4f(0.0, 1.0, 0.0, 1.0));
5353 OOLog(
@"universe.badUID",
@"Attempt to retrieve entity for out-of-range UID %u. (This is an internal programming error, please report it.)", u_id);
5357 if ((u_id ==
NO_TARGET)||(!entity_for_uid[u_id]))
5360 Entity *ent = entity_for_uid[u_id];
5366 if ([ent status] == STATUS_DEAD || [ent status] == STATUS_DOCKED)
5377 NSCParameterAssert(uni != NULL);
5390 while ((n--)&&(checkEnt))
5393 checkEnt = checkEnt->
x_next;
5395 if ((checkEnt)||(n > 0))
5403 while ((n--)&&(checkEnt)) checkEnt = checkEnt->
x_previous;
5404 if ((checkEnt)||(n > 0))
5415 checkEnt = checkEnt->
x_next;
5423 while ((n--)&&(checkEnt))
5426 checkEnt = checkEnt->
y_next;
5428 if ((checkEnt)||(n > 0))
5436 while ((n--)&&(checkEnt)) checkEnt = checkEnt->
y_previous;
5437 if ((checkEnt)||(n > 0))
5448 checkEnt = checkEnt->
y_next;
5456 while ((n--)&&(checkEnt))
5459 checkEnt = checkEnt->
z_next;
5461 if ((checkEnt)||(n > 0))
5469 while ((n--)&&(checkEnt)) checkEnt = checkEnt->
z_previous;
5470 if ((checkEnt)||(n > 0))
5477 NSCAssert(checkEnt !=
nil,
@"Expected z-list to be non-empty.");
5482 checkEnt = checkEnt->
z_next;
5492 NSArray *allEntities = uni->
entities;
5498 foreach (ent, allEntities)
5514- (BOOL) addEntity:(
Entity *) entity
5522 if (![entity validForAddToUniverse])
return NO;
5525 if ([entities containsObject:entity])
5531 OOLog(
@"universe.addEntity.failed",
@"***** Universe cannot addEntity:%@ -- Universe is full (%d entities out of %d)", entity, n_entities,
UNIVERSE_MAX_ENTITIES);
5538 if (![entity isEffect])
5541 while (entity_for_uid[next_universal_id] !=
nil)
5543 next_universal_id++;
5551 OOLog(
@"universe.addEntity.failed",
@"***** Universe cannot addEntity:%@ -- Could not find free slot for entity.", entity);
5555 [entity setUniversalID:next_universal_id];
5556 entity_for_uid[next_universal_id] = entity;
5557 if ([entity isShip])
5562 [
self setNextBeacon:se];
5569 double stationRoll = 0.0;
5573 if (definedRoll !=
nil)
5579 stationRoll = [[
self currentSystemData] oo_doubleForKey:@"station_roll" defaultValue:STANDARD_STATION_ROLL];
5592 if ([se status] != STATUS_COCKPIT_DISPLAY)
5600 [entity setUniversalID:NO_TARGET];
5601 if ([entity isVisualEffect])
5606 [
self setNextBeacon:ve];
5609 else if ([entity isWaypoint])
5614 [
self setNextBeacon:wp];
5624 [entities addObject:entity];
5625 [entity wasAddedToUniverse];
5628 HPVector entity_pos = entity->position;
5629 HPVector delta = HPvector_between(entity_pos,
PLAYER->position);
5630 double z_distance = HPmagnitude2(delta);
5631 entity->zero_distance = z_distance;
5632 unsigned index = n_entities;
5633 sortedEntities[index] = entity;
5634 entity->zero_index = index;
5635 while ((index > 0)&&(z_distance < sortedEntities[index - 1]->zero_distance))
5637 sortedEntities[index] = sortedEntities[index - 1];
5638 sortedEntities[index]->zero_index = index;
5640 sortedEntities[index] = entity;
5641 entity->zero_index = index;
5648 [entity addToLinkedLists];
5649 if ([entity canCollide])
5651 doLinkedListMaintenanceThisUpdate = YES;
5654 if ([entity isWormhole])
5656 [activeWormholes addObject:entity];
5658 else if ([entity isPlanet])
5660 [allPlanets addObject:entity];
5662 else if ([entity isShip])
5666 if ([entity isStation])
5668 [allStations addObject:entity];
5678- (BOOL) removeEntity:(
Entity *) entity
5680 if (entity !=
nil && ![entity isPlayer])
5686 [entitiesDeadThisUpdate addObject:entity];
5687 if ([entity isStation])
5689 [allStations removeObject:entity];
5690 if ([
PLAYER getTargetDockStation] == entity)
5692 [PLAYER setDockingClearanceStatus:DOCKING_CLEARANCE_STATUS_NONE];
5695 return [
self doRemoveEntity:entity];
5701- (void) ensureEntityReallyRemoved:(
Entity *)entity
5705 OOLog(
@"universe.unremovedEntity",
@"Entity %@ dealloced without being removed from universe! (This is an internal programming error, please report it.)", entity);
5706 [
self doRemoveEntity:entity];
5711- (void) removeAllEntitiesExceptPlayer
5713 BOOL updating = no_update;
5717 Entity* p0 = [entities objectAtIndex:0];
5726 NSMutableArray *savedWormholes = [activeWormholes mutableCopy];
5728 while ([entities
count] > 1)
5730 Entity* ent = [entities objectAtIndex:1];
5733 if (
EXPECT(![ent isVisualEffect]))
5735 [
self removeEntity:ent];
5744 [activeWormholes release];
5745 activeWormholes = savedWormholes;
5752 cachedStation =
nil;
5753 [closeSystems release];
5756 [
self resetBeacons];
5757 [waypoints removeAllObjects];
5759 no_update = updating;
5763- (void) removeDemoShips
5766 int ent_count = n_entities;
5770 for (i = 0; i < ent_count; i++)
5772 ent = sortedEntities[i];
5773 if ([ent status] == STATUS_COCKPIT_DISPLAY && ![ent isPlayer])
5775 [
self removeEntity:ent];
5783- (
ShipEntity *) makeDemoShipWithRole:(NSString *)role spinning:(BOOL)spinning
5787 [
self removeDemoShips];
5789 [PLAYER setShowDemoShips: YES];
5790 Quaternion q2 = { (GLfloat)
M_SQRT1_2, (GLfloat)
M_SQRT1_2, (GLfloat)0.0, (GLfloat)0.0 };
5792 ShipEntity *ship = [
self newShipWithRole:role];
5802 [UNIVERSE addEntity:ship];
5812 [ship
setStatus:STATUS_COCKPIT_DISPLAY];
5819 return [ship autorelease];
5823- (BOOL) isVectorClearFromEntity:(
Entity *) e1 toDistance:(
double)dist fromPoint:(HPVector) p2
5831 v1.x -= p1.
x; v1.y -= p1.
y; v1.z -= p1.z;
5833 double nearest = sqrt(v1.x*v1.x + v1.y*v1.y + v1.z*v1.z) - dist;
5839 int ent_count = n_entities;
5840 Entity* my_entities[ent_count];
5841 for (i = 0; i < ent_count; i++)
5842 my_entities[i] = [sortedEntities[i] retain];
5844 if (v1.x || v1.y || v1.z)
5845 f1 = HPvector_normal(v1);
5847 f1 = make_HPvector(0, 0, 1);
5849 for (i = 0; i < ent_count ; i++)
5851 Entity *e2 = my_entities[i];
5852 if ((e2 != e1)&&([e2 canCollide]))
5855 epos.x -= p1.
x; epos.y -= p1.
y; epos.z -= p1.z;
5857 double d_forward = HPdot_product(epos,f1);
5859 if ((d_forward > 0)&&(d_forward < nearest))
5863 p0.x += d_forward * f1.
x; p0.y += d_forward * f1.
y; p0.z += d_forward * f1.z;
5866 p0.x -= epos.
x; p0.y -= epos.
y; p0.z -= epos.z;
5868 double dist2 = p0.x * p0.x + p0.
y * p0.
y + p0.z * p0.z;
5871 for (i = 0; i < ent_count; i++)
5872 [my_entities[i] release];
5878 for (i = 0; i < ent_count; i++)
5879 [my_entities[i] release];
5884- (
Entity*) hazardOnRouteFromEntity:(
Entity *) e1 toDistance:(
double)dist fromPoint:(HPVector) p2
5892 v1.x -= p1.
x; v1.y -= p1.
y; v1.z -= p1.z;
5894 double nearest = HPmagnitude(v1) - dist;
5901 int ent_count = n_entities;
5902 Entity* my_entities[ent_count];
5903 for (i = 0; i < ent_count; i++)
5904 my_entities[i] = [sortedEntities[i] retain];
5906 if (v1.x || v1.y || v1.z)
5907 f1 = HPvector_normal(v1);
5909 f1 = make_HPvector(0, 0, 1);
5911 for (i = 0; (i < ent_count) && (!result) ; i++)
5913 Entity *e2 = my_entities[i];
5914 if ((e2 != e1)&&([e2 canCollide]))
5917 epos.x -= p1.
x; epos.y -= p1.
y; epos.z -= p1.z;
5919 double d_forward = HPdot_product(epos,f1);
5921 if ((d_forward > 0)&&(d_forward < nearest))
5925 p0.x += d_forward * f1.
x; p0.y += d_forward * f1.
y; p0.z += d_forward * f1.z;
5928 p0.x -= epos.
x; p0.y -= epos.
y; p0.z -= epos.z;
5930 double dist2 = HPmagnitude2(p0);
5936 for (i = 0; i < ent_count; i++)
5937 [my_entities[i] release];
5942- (HPVector) getSafeVectorFromEntity:(
Entity *) e1 toDistance:(
double)dist fromPoint:(HPVector) p2
5953 HPVector result = p2;
5955 int ent_count = n_entities;
5956 Entity* my_entities[ent_count];
5957 for (i = 0; i < ent_count; i++)
5958 my_entities[i] = [sortedEntities[i] retain];
5961 v1.x -= p1.
x; v1.y -= p1.
y; v1.z -= p1.z;
5963 double nearest = sqrt(v1.x*v1.x + v1.y*v1.y + v1.z*v1.z) - dist;
5965 if (v1.x || v1.y || v1.z)
5966 f1 = HPvector_normal(v1);
5968 f1 = make_HPvector(0, 0, 1);
5970 for (i = 0; i < ent_count; i++)
5972 Entity *e2 = my_entities[i];
5973 if ((e2 != e1)&&([e2 canCollide]))
5976 epos.x -= p1.
x; epos.y -= p1.
y; epos.z -= p1.z;
5977 double d_forward = HPdot_product(epos,f1);
5978 if ((d_forward > 0)&&(d_forward < nearest))
5983 p0.x += d_forward * f1.
x; p0.y += d_forward * f1.
y; p0.z += d_forward * f1.z;
5987 p0.x -= epos.
x; p0.y -= epos.
y; p0.z -= epos.z;
5990 double dist2 = p0.x * p0.x + p0.
y * p0.
y + p0.z * p0.z;
5995 nearest = d_forward;
6001 result.x += ((
int)(
Ranrot() % 1024) - 512)/512.0;
6002 result.y += ((
int)(
Ranrot() % 1024) - 512)/512.0;
6003 result.z += ((
int)(
Ranrot() % 1024) - 512)/512.0;
6006 HPVector nearest_point = p1;
6007 nearest_point.x += d_forward * f1.
x; nearest_point.y += d_forward * f1.
y; nearest_point.z += d_forward * f1.z;
6010 HPVector outward = nearest_point;
6011 outward.x -= result.
x; outward.y -= result.
y; outward.z -= result.z;
6012 if (outward.x||outward.y||outward.z)
6013 outward = HPvector_normal(outward);
6018 HPVector backward = p1;
6019 backward.x -= result.
x; backward.y -= result.
y; backward.z -= result.z;
6020 if (backward.x||backward.y||backward.z)
6021 backward = HPvector_normal(backward);
6026 HPVector dd = result;
6027 dd.x -= p1.
x; dd.y -= p1.
y; dd.z -= p1.z;
6028 double current_distance = HPmagnitude(dd);
6031 if (current_distance < cr * 1.25)
6032 current_distance = cr * 1.25;
6033 if (current_distance > cr * 5.0)
6034 current_distance = cr * 5.0;
6038 result.x += 0.25 * (outward.
x * current_distance) + 0.75 * (backward.
x * current_distance);
6039 result.y += 0.25 * (outward.
y * current_distance) + 0.75 * (backward.
y * current_distance);
6040 result.z += 0.25 * (outward.z * current_distance) + 0.75 * (backward.z * current_distance);
6046 for (i = 0; i < ent_count; i++)
6047 [my_entities[i] release];
6052- (
ShipEntity*) addWreckageFrom:(
ShipEntity *)ship withRole:(NSString *)wreckRole at:(HPVector)rpos scale:(GLfloat)scale lifetime:(GLfloat)lifetime
6054 ShipEntity* wreck = [UNIVERSE newShipWithRole:wreckRole];
6058 GLfloat expected_mass = 0.1f * [ship
mass] * (0.75 + 0.5 *
randf());
6059 GLfloat wreck_mass = [wreck
mass];
6060 GLfloat scale_factor = powf(expected_mass / wreck_mass, 0.33333333f) * scale;
6076 [UNIVERSE addEntity:wreck];
6086- (void) addLaserHitEffectsAt:(HPVector)pos against:(
ShipEntity *)target damage:(
float)damage color:(
OOColor *)color
6089 if ([target showDamage] && [target energy] < [target maxEnergy]/2)
6091 NSString *key = (
randf() < 0.5) ?
@"oolite-hull-spark" :
@"oolite-hull-spark-b";
6092 NSDictionary *settings = [UNIVERSE explosionSetting:key];
6095 [
self addEntity: burst];
6096 if ([target energy] *
randf() < damage)
6098 ShipEntity *wreck = [
self addWreckageFrom:target withRole:@"oolite-wreckage-chunk" at:pos scale:0.05 lifetime:(125.0+(randf()*200.0))];
6101 Vector direction = HPVectorToVector(HPvector_normal(HPvector_subtract(pos,[target position])));
6102 [wreck
setVelocity:vector_add([wreck
velocity],vector_multiply_scalar(direction,10+20*randf()))];
6113- (
ShipEntity *) firstShipHitByLaserFromShip:(
ShipEntity *)srcEntity inDirection:(
OOWeaponFacing)direction offset:(Vector)offset gettingRangeFound:(GLfloat *)range_ptr
6115 if (srcEntity ==
nil)
return nil;
6119 HPVector p0 = [srcEntity
position];
6127 HPVector midfrontplane = make_HPvector(0.5 * (bbox.max.x + bbox.min.x), 0.5 * (bbox.max.y + bbox.min.y), bbox.max.z);
6130 if ([parent isPlayer]) q1.w = -q1.w;
6135 int ent_count = n_entities;
6139 for (i = 0; i < ent_count; i++)
6141 Entity* ent = sortedEntities[i];
6142 if (ent != srcEntity && ent != parent && [ent isShip] && [ent canCollide])
6173 HPVector p1 = HPvector_add(p0, vectorToHPVector(vector_multiply_scalar(f1, nearest)));
6175 for (i = 0; i < ship_count; i++)
6181 Vector rpos = HPVectorToVector(HPvector_subtract(e2->
position, p0));
6182 Vector v_off = make_vector(dot_product(rpos, r1), dot_product(rpos, u1), dot_product(rpos, f1));
6183 if (v_off.z > 0.0 && v_off.z < nearest + cr &&
6184 v_off.x < cr && v_off.x > -cr && v_off.y < cr && v_off.y > -cr &&
6185 v_off.x * v_off.x + v_off.y * v_off.y < cr * cr)
6188 GLfloat hit = [(
ShipEntity *)
e2 doesHitLine:p0 :p1 :&entHit];
6190 if (hit > 0.0 && hit < nearest)
6192 if ([entHit isSubEntity])
6194 hit_subentity = entHit;
6198 p1 = HPvector_add(p0, vectorToHPVector(vector_multiply_scalar(f1, nearest)));
6208 if (range_ptr != NULL)
6210 *range_ptr = nearest;
6214 for (i = 0; i < ship_count; i++) [my_entities[i] release];
6220- (
Entity *) firstEntityTargetedByPlayer
6225 nearest2 *= nearest2;
6227 int ent_count = n_entities;
6229 Entity *my_entities[ent_count];
6231 for (i = 0; i < ent_count; i++)
6233 if (([sortedEntities[i] isShip] && ![sortedEntities[i] isPlayer]) || [sortedEntities[i] isWormhole])
6235 my_entities[ship_count++] = [sortedEntities[i] retain];
6247 switch (viewDirection)
6255 case VIEW_STARBOARD :
6263 for (i = 0; i < ship_count; i++)
6265 Entity *e2 = my_entities[i];
6266 if ([e2 canCollide] && [e2 scanClass] != CLASS_NO_DRAW)
6268 Vector rp = HPVectorToVector(HPvector_subtract([e2 position], p1));
6270 if (dist2 < nearest2)
6273 if (df > 0.0 && df * df < nearest2)
6278 if (du * du + dr * dr < cr * cr)
6288 if (hit_entity !=
nil && [hit_entity isShip])
6291 if ([ship isJammingScanning] && ![player hasMilitaryScannerFilter])
6297 for (i = 0; i < ship_count; i++)
6299 [my_entities[i] release];
6306- (
Entity *) firstEntityTargetedByPlayerPrecisely
6312 switch (viewDirection)
6329 case VIEW_STARBOARD:
6340 return [
self firstShipHitByLaserFromShip:PLAYER inDirection:targetFacing offset:laserPortOffset gettingRangeFound:NULL];
6344- (NSArray *) entitiesWithinRange:(
double)range ofEntity:(
Entity *)entity
6346 if (entity ==
nil)
return nil;
6348 return [
self findShipsMatchingPredicate:YESPredicate
6355- (unsigned) countShipsWithRole:(NSString *)role inRange:(
double)range ofEntity:(
Entity *)entity
6357 return [
self countShipsMatchingPredicate:HasRolePredicate
6364- (unsigned) countShipsWithRole:(NSString *)role
6366 return [
self countShipsWithRole:role inRange:-1 ofEntity:nil];
6370- (unsigned) countShipsWithPrimaryRole:(NSString *)role inRange:(
double)range ofEntity:(
Entity *)entity
6372 return [
self countShipsMatchingPredicate:HasPrimaryRolePredicate
6379- (unsigned) countShipsWithScanClass:(
OOScanClass)scanClass inRange:(
double)range ofEntity:(
Entity *)entity
6381 return [
self countShipsMatchingPredicate:HasScanClassPredicate
6382 parameter:[NSNumber numberWithInt:scanClass]
6388- (unsigned) countShipsWithPrimaryRole:(NSString *)role
6390 return [
self countShipsWithPrimaryRole:role inRange:-1 ofEntity:nil];
6395 parameter:(
void *)parameter
6396 inRange:(
double)range
6399 unsigned i, found = 0;
6401 double distance, cr;
6408 for (i = 0; i < n_entities; i++)
6410 Entity *e2 = sortedEntities[i];
6411 if (e2 != e1 && predicate(e2, parameter))
6413 if (range < 0) distance = -1;
6416 cr = range + e2->collision_radius;
6417 distance = HPdistance2(e2->
position, p1) - cr * cr;
6431 parameter:(
void *)parameter
6432 inRange:(
double)range
6433 ofEntity:(
Entity *)entity
6435 if (predicate != NULL)
6440 predicate, parameter
6443 return [
self countEntitiesMatchingPredicate:ANDPredicate
6450 return [
self countEntitiesMatchingPredicate:IsShipPredicate
6460 if (range < 0)
return YES;
6462 return HPdistance2(e2->
position,p1) < cr * cr;
6469 parameter:(
void *)parameter
6470 inRange:(
double)range
6477 NSMutableArray *result =
nil;
6483 result = [NSMutableArray arrayWithCapacity:n_entities];
6488 for (i = 0; i < n_entities; i++)
6490 Entity *e2 = sortedEntities[i];
6494 predicate(e2, parameter))
6496 [result addObject:e2];
6509 parameter:(
void *)parameter
6518 for (i = 0; i < n_entities; i++)
6520 candidate = sortedEntities[i];
6521 if (predicate(candidate, parameter))
return candidate;
6531 parameter:(
void *)parameter
6532 inRange:(
double)range
6533 ofEntity:(
Entity *)entity
6535 if (predicate != NULL)
6540 predicate, parameter
6543 return [
self findEntitiesMatchingPredicate:ANDPredicate
6550 return [
self findEntitiesMatchingPredicate:IsShipPredicate
6559 parameter:(
void *)parameter
6560 inRange:(
double)range
6561 ofEntity:(
Entity *)entity
6563 if (predicate != NULL)
6568 predicate, parameter
6571 return [
self findEntitiesMatchingPredicate:ANDPredicate
6578 return [
self findEntitiesMatchingPredicate:IsVisualEffectPredicate
6587 parameter:(
void *)parameter
6588 relativeToEntity:(
Entity *)entity
6592 float rangeSq = INFINITY;
6600 for (i = 0; i < n_entities; i++)
6602 Entity *e2 = sortedEntities[i];
6603 float distanceToReferenceEntitySquared = (float)HPdistance2(p1, [e2 position]);
6606 distanceToReferenceEntitySquared < rangeSq &&
6607 predicate(e2, parameter))
6610 rangeSq = distanceToReferenceEntitySquared;
6614 return [[result retain] autorelease];
6619 parameter:(
void *)parameter
6620 relativeToEntity:(
Entity *)entity
6622 if (predicate != NULL)
6627 predicate, parameter
6630 return [
self nearestEntityMatchingPredicate:ANDPredicate
6632 relativeToEntity:entity];
6636 return [
self nearestEntityMatchingPredicate:IsShipPredicate
6638 relativeToEntity:entity];
6645 return universal_time;
6655- (void) findCollisionsAndShadows
6659 [universeRegion clearEntityList];
6661 for (i = 0; i < n_entities; i++)
6663 [universeRegion checkEntity:sortedEntities[i]];
6666 if (![[
self gameController] isGamePaused])
6668 [universeRegion findCollisions];
6672 [universeRegion findShadowedEntities];
6676- (NSString*) collisionDescription
6678 if (universeRegion !=
nil)
return [universeRegion collisionDescription];
6683- (void) dumpCollisions
6685 dumpCollisionInfo = YES;
6691 return viewDirection;
6695- (void) setViewDirection:(
OOViewID) vd
6698 BOOL guiSelected = NO;
6700 if ((viewDirection == vd) && (vd != VIEW_CUSTOM) && (!displayGUI))
6706 ms =
DESC(
@"forward-view-string");
6710 ms =
DESC(
@"aft-view-string");
6714 ms =
DESC(
@"port-view-string");
6717 case VIEW_STARBOARD:
6718 ms =
DESC(
@"starboard-view-string");
6722 ms = [PLAYER customViewDescription];
6725 case VIEW_GUI_DISPLAY:
6726 [
self setDisplayText:YES];
6727 [
self setMainLightPosition:(Vector){ DEMO_LIGHT_POSITION }];
6738 [[
self gameController] setMouseInteractionModeForUIWithMouseInteraction:NO];
6743 [[
self gameController] setMouseInteractionModeForFlight];
6746 if (viewDirection != vd || viewDirection == VIEW_CUSTOM)
6748 #if (ALLOW_CUSTOM_VIEWS_WHILE_PAUSED)
6749 BOOL gamePaused = [[
self gameController] isGamePaused];
6751 BOOL gamePaused = NO;
6756 if (ms && !gamePaused)
6758 [
self addMessage:ms forCount:3];
6760 else if (gamePaused)
6762 [message_gui clear];
6768- (void) enterGUIViewModeWithMouseInteraction:(BOOL)mouseInteraction
6770 [
self setViewDirection:VIEW_GUI_DISPLAY];
6771 [[
self gameController] setMouseInteractionModeForUIWithMouseInteraction:mouseInteraction];
6775- (NSString *) soundNameForCustomSoundKey:(NSString *)key
6777 NSString *result =
nil;
6778 NSMutableSet *seen =
nil;
6779 id object = [customSounds objectForKey:key];
6781 if ([
object isKindOfClass:[NSArray
class]] && [
object count] > 0)
6783 key = [object oo_stringAtIndex:Ranrot() % [object count]];
6794 seen = [NSMutableSet set];
6796 if (
object ==
nil || ([result hasPrefix:
@"["] && [result hasSuffix:
@"]"]))
6800 [seen addObject:result];
6801 object = [customSounds objectForKey:result];
6802 if( [
object isKindOfClass:[NSArray
class]] && [
object count] > 0)
6804 result = [object oo_stringAtIndex:Ranrot() % [object count]];
6805 if ([key hasPrefix:
@"["] && [key hasSuffix:
@"]"]) key=result;
6809 if ([
object isKindOfClass:[NSString
class]])
6814 if (result ==
nil || ![result hasPrefix:
@"["] || ![result hasSuffix:
@"]"])
break;
6815 if ([seen containsObject:result])
6817 OOLogERR(
@"sound.customSounds.recursion",
@"recursion in customsounds.plist for '%@' (at '%@'), no sound will be played.", key, result);
6824 if (result ==
nil) result =
@"__oolite-no-sound";
6828 if ([result isEqualToString:
@"__oolite-no-sound"])
6830 OOLog(
@"sound.customSounds",
@"Could not resolve sound name in customsounds.plist for '%@', no sound will be played.", key);
6837- (NSDictionary *) screenTextureDescriptorForKey:(NSString *)key
6839 id value = [screenBackgrounds objectForKey:key];
6840 while ([value isKindOfClass:[NSArray
class]]) value = [value objectAtIndex:
Ranrot() % [value
count]];
6842 if ([value isKindOfClass:[NSString
class]]) value = [NSDictionary dictionaryWithObject:value forKey:
@"name"];
6843 else if (![value isKindOfClass:[NSDictionary
class]]) value =
nil;
6846 if (![[
self gui] preloadGUITexture:value]) value =
nil;
6852- (void) setScreenTextureDescriptorForKey:(NSString *)key descriptor:(NSDictionary *)desc
6854 NSMutableDictionary *sbCopy = [screenBackgrounds mutableCopy];
6857 [sbCopy removeObjectForKey:key];
6861 [sbCopy setObject:desc forKey:key];
6863 [screenBackgrounds release];
6864 screenBackgrounds = [sbCopy copy];
6869- (void) clearPreviousMessage
6871 if (currentMessage) [currentMessage release];
6872 currentMessage =
nil;
6876- (void) setMessageGuiBackgroundColor:(
OOColor *)some_color
6878 [message_gui setBackgroundColor:some_color];
6882- (void) displayMessage:(NSString *) text forCount:(
OOTimeDelta)count
6884 if (![currentMessage isEqual:text] || universal_time >= messageRepeatTime)
6886 if (currentMessage) [currentMessage release];
6887 currentMessage = [text retain];
6888 messageRepeatTime=universal_time + 6.0;
6889 [
self showGUIMessage:text withScroll:YES andColor:[message_gui textColor] overDuration:count];
6894- (void) displayCountdownMessage:(NSString *) text forCount:(
OOTimeDelta)count
6896 if (![currentMessage isEqual:text] && universal_time >= countdown_messageRepeatTime)
6898 if (currentMessage) [currentMessage release];
6899 currentMessage = [text retain];
6900 countdown_messageRepeatTime=universal_time +
count;
6901 [
self showGUIMessage:text withScroll:NO andColor:[message_gui textColor] overDuration:count];
6906- (void) addDelayedMessage:(NSString *)text forCount:(
OOTimeDelta)count afterDelay:(
double)delay
6908 NSMutableDictionary *msgDict = [NSMutableDictionary dictionaryWithCapacity:2];
6909 [msgDict setObject:text forKey:@"message"];
6910 [msgDict setObject:[NSNumber numberWithDouble:count] forKey:@"duration"];
6911 [
self performSelector:@selector(addDelayedMessage:) withObject:msgDict afterDelay:delay];
6915- (void) addDelayedMessage:(NSDictionary *) textdict
6917 NSString *msg =
nil;
6920 msg = [textdict oo_stringForKey:@"message"];
6921 if (msg ==
nil)
return;
6922 msg_duration = [textdict oo_nonNegativeDoubleForKey:@"duration" defaultValue:3.0];
6924 [
self addMessage:msg forCount:msg_duration];
6928- (void) addMessage:(NSString *)text forCount:(
OOTimeDelta)count
6930 [
self addMessage:text forCount:count forceDisplay:NO];
6934- (void) speakWithSubstitutions:(NSString *)text
6936#if OOLITE_SPEECH_SYNTH
6942 NSString *systemSaid =
nil;
6943 NSString *h_systemSaid =
nil;
6945 NSString *systemName = [
self getSystemName:systemID];
6947 systemSaid = systemName;
6949 NSString *h_systemName = [
self getSystemName:[player
targetSystemID]];
6950 h_systemSaid = h_systemName;
6952 NSString *spokenText = text;
6953 if (speechArray !=
nil)
6955 NSEnumerator *speechEnumerator =
nil;
6956 NSArray *thePair =
nil;
6958 for (speechEnumerator = [speechArray objectEnumerator]; (thePair = [speechEnumerator nextObject]); )
6960 NSString *original_phrase = [thePair oo_stringAtIndex:0];
6962 NSUInteger replacementIndex;
6964 replacementIndex = 1;
6966 replacementIndex = [thePair count] > 2 ? 2 : 1;
6969 NSString *replacement_phrase = [thePair oo_stringAtIndex:replacementIndex];
6970 if (![replacement_phrase isEqualToString:
@"_"])
6972 spokenText = [spokenText stringByReplacingOccurrencesOfString:original_phrase withString:replacement_phrase];
6975 spokenText = [spokenText stringByReplacingOccurrencesOfString:systemName withString:systemSaid];
6976 spokenText = [spokenText stringByReplacingOccurrencesOfString:h_systemName withString:h_systemSaid];
6978 [
self stopSpeaking];
6979 [
self startSpeakingString:spokenText];
6985- (void) addMessage:(NSString *) text forCount:(
OOTimeDelta) count forceDisplay:(BOOL) forceDisplay
6987 if (![currentMessage isEqual:text] || forceDisplay || universal_time >= messageRepeatTime)
6991 [
self speakWithSubstitutions:text];
6994 [
self showGUIMessage:text withScroll:YES andColor:[message_gui textColor] overDuration:count];
6996 [PLAYER doScriptEvent:OOJSID("consoleMessageReceived") withArgument:text];
6998 [currentMessage release];
6999 currentMessage = [text retain];
7000 messageRepeatTime=universal_time + 6.0;
7005- (void) addCommsMessage:(NSString *)text forCount:(
OOTimeDelta)count
7007 [
self addCommsMessage:text forCount:count andShowComms:_autoCommLog logOnly:NO];
7011- (void) addCommsMessage:(NSString *)text forCount:(
OOTimeDelta)count andShowComms:(BOOL)showComms logOnly:(BOOL)logOnly
7013 if ([
PLAYER showDemoShips])
return;
7015 NSString *expandedMessage =
OOExpand(text);
7017 if (![currentMessage isEqualToString:expandedMessage] || universal_time >= messageRepeatTime)
7026 NSString *format =
OOExpandKey(
@"speech-synthesis-incoming-message-@");
7027 [
self speakWithSubstitutions:[NSString stringWithFormat:format, expandedMessage]];
7030 [
self showGUIMessage:expandedMessage withScroll:YES andColor:[message_gui textCommsColor] overDuration:count];
7032 [currentMessage release];
7033 currentMessage = [expandedMessage retain];
7034 messageRepeatTime=universal_time + 6.0;
7037 [comm_log_gui printLongText:expandedMessage align:GUI_ALIGN_LEFT color:nil fadeTime:0.0 key:nil addToArray:[player
commLog]];
7039 if (showComms) [
self showCommsLog:6.0];
7046 [comm_log_gui setAlpha:1.0];
7047 if (![
self permanentCommLog]) [comm_log_gui fadeOutFromTime:[
self getTime] overDuration:how_long];
7051- (void) showGUIMessage:(NSString *)text withScroll:(BOOL)scroll andColor:(
OOColor *)selectedColor overDuration:(
OOTimeDelta)how_long
7055 [message_gui printLongText:text align:GUI_ALIGN_CENTER color:selectedColor fadeTime:how_long key:nil addToArray:nil];
7059 [message_gui printLineNoScroll:text align:GUI_ALIGN_CENTER color:selectedColor fadeTime:how_long key:nil addToArray:nil];
7061 [message_gui setAlpha:1.0f];
7065- (void) repopulateSystem
7072 [PLAYER doWorldScriptEvent:OOJSIDFromString(system_repopulator) inContext:context withArguments:NULL count:0 timeLimit:kOOJSLongTimeLimit];
7080 volatile OOTimeDelta delta_t = inDeltaT * [
self timeAccelerationFactor];
7081 NSUInteger sessionID = _sessionID;
7082 OOLog(
@"universe.profile.update",
@"%@",
@"Begin update");
7085 next_repopulation -= delta_t;
7086 if (next_repopulation < 0)
7088 [
self repopulateSystem];
7091 unsigned i, ent_count = n_entities;
7092 Entity *my_entities[ent_count];
7094 [
self verifyEntitySessionIDs];
7097 for (i = 0; i < ent_count; i++)
7099 my_entities[i] = [sortedEntities[i] retain];
7102 NSString *
volatile update_stage =
@"initialisation";
7104 id volatile update_stage_param =
nil;
7111 skyClearColor[0] = 0.0;
7112 skyClearColor[1] = 0.0;
7113 skyClearColor[2] = 0.0;
7114 skyClearColor[3] = 0.0;
7116 time_delta = delta_t;
7117 universal_time += delta_t;
7119 if (
EXPECT_NOT([player showDemoShips] && [player guiScreen] == GUI_SCREEN_SHIPLIBRARY))
7121 update_stage =
@"demo management";
7123 if (universal_time >= demo_stage_time)
7135 [demo_ship setPosition:[demo_ship destination]];
7137 demo_stage_time = universal_time + 300.0;
7141 [demo_ship setVelocity:vel];
7143 demo_stage_time = universal_time + 0.25;
7147 [
self removeEntity:demo_ship];
7154 demo_ship_subindex = (demo_ship_subindex + 1) % [[demo_ships objectAtIndex:demo_ship_index] count];
7155 demo_ship = [
self newShipWithName:[[
self demoShipData] oo_stringForKey:kOODemoShipKey] usePlayerProxy:NO];
7157 if (demo_ship !=
nil)
7159 [demo_ship removeEquipmentItem:@"EQ_SHIELD_BOOSTER"];
7160 [demo_ship removeEquipmentItem:@"EQ_SHIELD_ENHANCER"];
7162 [demo_ship switchAITo:@"nullAI.plist"];
7163 [demo_ship setOrientation:q2];
7164 [demo_ship setScanClass: CLASS_NO_DRAW];
7165 [demo_ship setStatus: STATUS_COCKPIT_DISPLAY];
7166 [demo_ship setDemoShip: 1.0f];
7167 [demo_ship setDemoStartTime: universal_time];
7168 if ([
self addEntity:demo_ship])
7170 [demo_ship release];
7171 [demo_ship setStatus:STATUS_COCKPIT_DISPLAY];
7173 [demo_ship setPositionX:0.0f y:0.0f z:demo_start_z];
7174 [demo_ship setDestination: make_HPvector(0.0f, 0.0f, demo_start_z * 0.01f)];
7175 [demo_ship setVelocity:kZeroVector];
7176 [demo_ship setScanClass: CLASS_NO_DRAW];
7179 [
self setLibraryTextForDemoShip];
7182 demo_start_time=universal_time;
7197 [demo_ship setPositionX:0.0f y:[demo_ship destination].y * delta z:demo_start_z + ([demo_ship destination].z - demo_start_z) * delta ];
7201 update_stage =
@"update:entity";
7202 NSMutableSet *zombies =
nil;
7203 OOLog(
@"universe.profile.update",
@"%@", update_stage);
7204 for (i = 0; i < ent_count; i++)
7206 Entity *thing = my_entities[i];
7208 update_stage_param = thing;
7209 update_stage =
@"update:entity [%@]";
7212 if (
EXPECT_NOT([thing status] == STATUS_DEAD && ![entitiesDeadThisUpdate containsObject:thing] && ![thing isPlayer]))
7214 if (zombies ==
nil) zombies = [NSMutableSet set];
7215 [zombies addObject:thing];
7227 update_stage =
@"update:list maintenance [%@]";
7234 while (index > 0 && z_distance < sortedEntities[index - 1]->zero_distance)
7236 sortedEntities[index] = sortedEntities[index - 1];
7237 sortedEntities[index - 1] = thing;
7239 sortedEntities[index]->zero_index = index;
7247 update_stage =
@"update:think [%@]";
7253 if ((universal_time > thinkTime)||(thinkTime == 0.0))
7262 update_stage_param =
nil;
7267 update_stage =
@"shootin' zombies";
7268 NSEnumerator *zombieEnum =
nil;
7270 for (zombieEnum = [zombies objectEnumerator]; (zombie = [zombieEnum nextObject]); )
7272 OOLogERR(
@"universe.zombie",
@"Found dead entity %@ in active entity list, removing. This is an internal error, please report it.", zombie);
7273 [
self removeEntity:zombie];
7278 update_stage =
@"updating linked lists";
7279 OOLog(
@"universe.profile.update",
@"%@", update_stage);
7280 for (i = 0; i < ent_count; i++)
7287 update_stage =
@"collision and shadow detection";
7288 OOLog(
@"universe.profile.update",
@"%@", update_stage);
7289 [
self filterSortedLists];
7290 [
self findCollisionsAndShadows];
7294 if (doLinkedListMaintenanceThisUpdate)
7297 doLinkedListMaintenanceThisUpdate = NO;
7300 @catch (NSException *exception)
7302 if ([[exception name] hasPrefix:
@"Oolite"])
7304 [
self handleOoliteException:exception];
7309 if (update_stage_param !=
nil) update_stage = [NSString stringWithFormat:update_stage, update_stage_param];
7311 OOLog(
kOOLogException,
@"***** Exception during [%@] in [Universe update:] : %@ : %@ *****", update_stage, [exception name], [exception reason]);
7317 update_stage =
@"clean up";
7318 OOLog(
@"universe.profile.update",
@"%@", update_stage);
7319 for (i = 0; i < ent_count; i++)
7321 [my_entities[i] release];
7331 update_stage =
@"JS Garbage Collection";
7332 OOLog(
@"universe.profile.update",
@"%@", update_stage);
7335 uint32 gcbytes1 = JS_GetGCParameter(JS_GetRuntime(context),JSGC_BYTES);
7341 uint32 gcbytes2 = JS_GetGCParameter(JS_GetRuntime(context),JSGC_BYTES);
7343 if (gcbytes2 < gcbytes1)
7345 OOLog(
@"universe.profile.jsgc",
@"Unplanned JS Garbage Collection from %d to %d",gcbytes1,gcbytes2);
7354 if ([
PLAYER status] == STATUS_DEAD) [PLAYER update:delta_t];
7357 [entitiesDeadThisUpdate autorelease];
7358 entitiesDeadThisUpdate =
nil;
7359 entitiesDeadThisUpdate = [[NSMutableSet alloc] initWithCapacity:n_entities];
7362 [
self prunePreloadingPlanetMaterials];
7365 OOLog(
@"universe.profile.update",
@"%@",
@"Update complete");
7370- (double) timeAccelerationFactor
7372 return timeAccelerationFactor;
7376- (void) setTimeAccelerationFactor:(
double)newTimeAccelerationFactor
7382 timeAccelerationFactor = newTimeAccelerationFactor;
7385- (double) timeAccelerationFactor
7391- (void) setTimeAccelerationFactor:(
double)newTimeAccelerationFactor
7397- (BOOL) ECMVisualFXEnabled
7399 return ECMVisualFXEnabled;
7403- (void) setECMVisualFXEnabled:(BOOL)isEnabled
7405 ECMVisualFXEnabled = isEnabled;
7409- (void) filterSortedLists
7419 Entity *e0, *next, *prev;
7420 OOHPScalar start, finish, next_start, next_finish, prev_start, prev_finish;
7443 start = e0->
position.z - 2.0f * e0->collision_radius;
7444 finish = start + 4.0f * e0->collision_radius;
7450 next_start = next->
position.z - 2.0f * next->collision_radius;
7451 if (next_start < finish)
7454 while ((next)&&(next_start < finish))
7457 next_finish = next_start + 4.0f * next->collision_radius;
7458 if (next_finish > finish)
7459 finish = next_finish;
7465 next_start = next->
position.z - 2.0f * next->collision_radius;
7487 start = e0->
position.z + 2.0f * e0->collision_radius;
7488 finish = start - 4.0f * e0->collision_radius;
7494 prev_start = prev->
position.z + 2.0f * prev->collision_radius;
7495 if (prev_start > finish)
7498 while ((prev)&&(prev_start > finish))
7501 prev_finish = prev_start - 4.0f * prev->collision_radius;
7502 if (prev_finish < finish)
7503 finish = prev_finish;
7509 prev_start = prev->
position.z + 2.0f * prev->collision_radius;
7533 start = e0->
position.y - 2.0f * e0->collision_radius;
7534 finish = start + 4.0f * e0->collision_radius;
7541 next_start = next->
position.y - 2.0f * next->collision_radius;
7542 if (next_start < finish)
7545 while ((next)&&(next_start < finish))
7548 next_finish = next_start + 4.0f * next->collision_radius;
7549 if (next_finish > finish)
7550 finish = next_finish;
7556 next_start = next->
position.y - 2.0f * next->collision_radius;
7578 start = e0->
position.y + 2.0f * e0->collision_radius;
7579 finish = start - 4.0f * e0->collision_radius;
7585 prev_start = prev->
position.y + 2.0f * prev->collision_radius;
7586 if (prev_start > finish)
7589 while ((prev)&&(prev_start > finish))
7592 prev_finish = prev_start - 4.0f * prev->collision_radius;
7593 if (prev_finish < finish)
7594 finish = prev_finish;
7600 prev_start = prev->
position.y + 2.0f * prev->collision_radius;
7624 start = e0->
position.x - 2.0f * e0->collision_radius;
7625 finish = start + 4.0f * e0->collision_radius;
7631 next_start = next->
position.x - 2.0f * next->collision_radius;
7632 if (next_start < finish)
7635 while ((next)&&(next_start < finish))
7638 next_finish = next_start + 4.0f * next->collision_radius;
7639 if (next_finish > finish)
7640 finish = next_finish;
7646 next_start = next->
position.x - 2.0f * next->collision_radius;
7668 start = e0->
position.x + 2.0f * e0->collision_radius;
7669 finish = start - 4.0f * e0->collision_radius;
7675 prev_start = prev->
position.x + 2.0f * prev->collision_radius;
7676 if (prev_start > finish)
7679 while ((prev)&&(prev_start > finish))
7682 prev_finish = prev_start - 4.0f * prev->collision_radius;
7683 if (prev_finish < finish)
7684 finish = prev_finish;
7690 prev_start = prev->
position.x + 2.0f * prev->collision_radius;
7714 start = e0->
position.y - 2.0f * e0->collision_radius;
7715 finish = start + 4.0f * e0->collision_radius;
7721 next_start = next->
position.y - 2.0f * next->collision_radius;
7722 if (next_start < finish)
7725 while ((next)&&(next_start < finish))
7728 next_finish = next_start + 4.0f * next->collision_radius;
7729 if (next_finish > finish)
7730 finish = next_finish;
7736 next_start = next->
position.y - 2.0f * next->collision_radius;
7757 start = e0->
position.y + 2.0f * e0->collision_radius;
7758 finish = start - 4.0f * e0->collision_radius;
7764 prev_start = prev->
position.y + 2.0f * prev->collision_radius;
7765 if (prev_start > finish)
7768 while ((prev)&&(prev_start > finish))
7771 prev_finish = prev_start - 4.0f * prev->collision_radius;
7772 if (prev_finish < finish)
7773 finish = prev_finish;
7779 prev_start = prev->
position.y + 2.0f * prev->collision_radius;
7803 start = e0->
position.z - 2.0f * e0->collision_radius;
7804 finish = start + 4.0f * e0->collision_radius;
7810 next_start = next->
position.z - 2.0f * next->collision_radius;
7811 if (next_start < finish)
7814 while ((next)&&(next_start < finish))
7819 next_finish = next_start + 4.0f * next->collision_radius;
7820 if (next_finish > finish)
7821 finish = next_finish;
7827 next_start = next->
position.z - 2.0f * next->collision_radius;
7849 start = e0->
position.z + 2.0f * e0->collision_radius;
7850 finish = start - 4.0f * e0->collision_radius;
7856 prev_start = prev->
position.z + 2.0f * prev->collision_radius;
7857 if (prev_start > finish)
7860 while ((prev)&&(prev_start > finish))
7885 OOLog(
@"general.error.inconsistentState",
@"Unexpected state in collision chain builder prev=%@, prev->c=%@, e0=%@, e0->c=%@",prev,prev->
collision_chain,e0,e0->
collision_chain);
7890 prev_finish = prev_start - 4.0f * prev->collision_radius;
7891 if (prev_finish < finish)
7892 finish = prev_finish;
7898 prev_start = prev->
position.z + 2.0f * prev->collision_radius;
7924 [
self setGalaxyTo:g andReinit:NO];
7928- (void) setGalaxyTo:(
OOGalaxyID) g andReinit:(BOOL) forced
7931 NSAutoreleasePool *pool =
nil;
7933 if (galaxyID != g || forced) {
7937 pool = [[NSAutoreleasePool alloc] init];
7939 for (i = 0; i < 256; i++)
7941 if (system_names[i])
7943 [system_names[i] release];
7945 system_names[i] = [[systemManager getProperty:@"name" forSystem:i inGalaxy:g] retain];
7955 NSDictionary *systemData;
7958 NSString *scriptName;
7965 systemData = [
self generateSystemData:targetSystemID];
7966 economy = [systemData oo_unsignedCharForKey:KEY_ECONOMY];
7967 scriptName = [systemData oo_stringForKey:@"market_script" defaultValue:nil];
7970 commodityMarket = [[commodities generateMarketForSystemWithEconomy:economy andScript:scriptName] retain];
7980- (NSDictionary *) descriptions
7982 if (_descriptions ==
nil)
7987 stringByAppendingPathComponent:@"Config"]
7988 stringByAppendingPathComponent:@"descriptions.plist"]];
7990 [
self verifyDescriptions];
7992 return _descriptions;
7996static void VerifyDesc(NSString *key,
id desc);
8001 if ([desc rangeOfString:
@"%n"].location != NSNotFound)
8003 OOLog(
@"descriptions.verify.percentN",
@"***** FATAL: descriptions.plist entry \"%@\
" contains the dangerous control sequence %%n.", key);
8012 foreach (subDesc, desc)
8014 VerifyDesc(key, subDesc);
8019static void VerifyDesc(NSString *key,
id desc)
8021 if ([desc isKindOfClass:[NSString
class]])
8023 VerifyDescString(key, desc);
8025 else if ([desc isKindOfClass:[NSArray
class]])
8027 VerifyDescArray(key, desc);
8029 else if ([desc isKindOfClass:[NSNumber
class]])
8035 OOLogERR(
@"descriptions.verify.badType",
@"***** FATAL: descriptions.plist entry for \"%@\
" is neither a string nor an array.", key);
8053 NSString *key =
nil;
8054 if (_descriptions ==
nil)
8056 OOLog(
@"descriptions.verify",
@"%@",
@"***** FATAL: Tried to verify descriptions, but descriptions was nil - unable to load any descriptions.plist file.");
8061 VerifyDesc(key, [_descriptions objectForKey:key]);
8068 [_descriptions autorelease];
8070 [
self verifyDescriptions];
8074- (NSDictionary *) explosionSetting:(NSString *)explosion
8076 return [explosionSettings oo_dictionaryForKey:explosion defaultValue:nil];
8080- (NSArray *) scenarios
8088 [_scenarios autorelease];
8093- (NSDictionary *) characters
8099- (NSDictionary *) missiontext
8105- (NSString *)descriptionForKey:(NSString *)key
8107 return [
self chooseStringForKey:key inDictionary:[
self descriptions]];
8111- (NSString *)descriptionForArrayKey:(NSString *)key index:(
unsigned)index
8113 NSArray *array = [[
self descriptions] oo_arrayForKey:key];
8114 if ([array
count] <= index)
return nil;
8115 return [array objectAtIndex:index];
8119- (BOOL) descriptionBooleanForKey:(NSString *)key
8121 return [[
self descriptions] oo_boolForKey:key];
8127 return systemManager;
8133 return [NSString stringWithFormat:@"%d %d", g, s];
8139 return [NSString stringWithFormat:@"interstellar: %d %d %d", g, s1, s2];
8143- (NSDictionary *) generateSystemData:(
OOSystemID) s
8145 return [
self generateSystemData:s useCache:YES];
8150- (NSDictionary *) generateSystemData:(
OOSystemID) s useCache:(BOOL) useCache
8157 NSString *systemKey = [NSString stringWithFormat:@"%u %u",[PLAYER galaxyNumber],s];
8159 return [systemManager getPropertiesForSystemKey:systemKey];
8165- (NSDictionary *) currentSystemData
8169 if (![
self inInterstellarSpace])
8171 return [
self generateSystemData:systemID];
8175 static NSDictionary *interstellarDict =
nil;
8176 if (interstellarDict ==
nil)
8178 NSString *interstellarName =
DESC(
@"interstellar-space");
8179 NSString *notApplicable =
DESC(
@"not-applicable");
8180 NSNumber *minusOne = [NSNumber numberWithInt:-1];
8181 NSNumber *zero = [NSNumber numberWithInt:0];
8182 interstellarDict = [[NSDictionary alloc] initWithObjectsAndKeys:
8183 interstellarName, KEY_NAME,
8184 minusOne, KEY_GOVERNMENT,
8185 minusOne, KEY_ECONOMY,
8186 minusOne, KEY_TECHLEVEL,
8187 zero, KEY_POPULATION,
8188 zero, KEY_PRODUCTIVITY,
8190 notApplicable, KEY_INHABITANTS,
8191 notApplicable, KEY_DESCRIPTION,
8195 return interstellarDict;
8202- (BOOL) inInterstellarSpace
8204 return [
self sun] ==
nil;
8212- (void) setSystemDataKey:(NSString *)key value:(NSObject *)object fromManifest:(NSString *)manifest
8214 [
self setSystemDataForGalaxy:galaxyID planet:systemID key:key value:object fromManifest:manifest forLayer:OO_LAYER_OXP_DYNAMIC];
8218- (void) setSystemDataForGalaxy:(
OOGalaxyID)gnum planet:(
OOSystemID)pnum key:(NSString *)key value:(
id)object fromManifest:(NSString *)manifest forLayer:(
OOSystemLayer)layer
8220 static BOOL sysdataLocked = NO;
8223 OOLogERR(
@"script.error",
@"%@",
@"System properties cannot be set during 'systemInformationChanged' events to avoid infinite loops.");
8227 BOOL sameGalaxy = (gnum == [PLAYER currentGalaxyID]);
8228 BOOL sameSystem = (sameGalaxy && pnum == [
self currentSystemID]);
8231 if ([key isEqualToString:
KEY_RADIUS] && sameGalaxy && sameSystem)
8233 OOLogERR(
@"script.error",
@"System property '%@' cannot be set while in the system.",key);
8237 if ([key isEqualToString:
@"coordinates"])
8239 OOLogERR(
@"script.error",
@"System property '%@' cannot be set.",key);
8244 NSString *overrideKey = [NSString stringWithFormat:@"%u %u", gnum, pnum];
8245 NSDictionary *sysInfo =
nil;
8248 [gui refreshStarChart];
8250 if (
object !=
nil) {
8252 if ([key isEqualToString:
KEY_NAME])
8254 object=(id)[[(NSString *)
object lowercaseString] capitalizedString];
8257 if (system_names[pnum]) [system_names[pnum] release];
8258 system_names[pnum] = [(NSString *)object retain];
8261 else if ([key isEqualToString:
@"sun_radius"])
8263 if ([
object doubleValue] < 1000.0 || [
object doubleValue] > 10000000.0 )
8265 object = ([object doubleValue] < 1000.0 ? (id)
@"1000.0" : (id)
@"10000000.0");
8268 else if ([key hasPrefix:
@"corona_"])
8270 object = (id)[NSString stringWithFormat:
@"%f",OOClamp_0_1_f([object floatValue])];
8274 [systemManager setProperty:key forSystemKey:overrideKey andLayer:layer toValue:object fromManifest:manifest];
8280 sysInfo = [systemManager getPropertiesForCurrentSystem];
8290 [[
self station] setEquivalentTechLevel:[object intValue]];
8291 [[
self station] setLocalShipyard:[
self shipsForSaleForSystem:systemID
8292 withTL:[object intValue] atTime:[PLAYER clockTime]]];
8295 else if ([key isEqualToString:
@"sun_color"] || [key isEqualToString:
@"star_count_multiplier"] ||
8296 [key isEqualToString:
@"nebula_count_multiplier"] || [key hasPrefix:
@"sky_"])
8301 for (i = n_entities - 1; i > 0; i--)
8302 if ((sortedEntities[i]) && ([sortedEntities[i] isKindOfClass:[SkyEntity class]]))
8303 the_sky = (
SkyEntity*)sortedEntities[i];
8309 if ([key isEqualToString:
@"sun_color"])
8318 for (i = n_entities - 1; i > 0; i--)
8319 if ((sortedEntities[i]) && ([sortedEntities[i] isKindOfClass:[DustEntity class]]))
8320 [(
DustEntity*)sortedEntities[i] setDustColor:[color blendedColorWithFraction:0.5 ofColor:[OOColor whiteColor]]];
8324 else if (the_sun !=
nil && ([key hasPrefix:
@"sun_"] || [key hasPrefix:
@"corona_"]))
8328 else if ([key isEqualToString:
@"texture"])
8330 [[
self planet] setUpPlanetFromTexture:(NSString *)object];
8332 else if ([key isEqualToString:
@"texture_hsb_color"])
8334 [[
self planet] setUpPlanetFromTexture: [[
self planet] textureFileName]];
8336 else if ([key isEqualToString:
@"air_color"])
8340 else if ([key isEqualToString:
@"illumination_color"])
8344 else if ([key isEqualToString:
@"air_color_mix_ratio"])
8346 [[
self planet] setAirColorMixRatio:[sysInfo oo_floatForKey:key]];
8350 sysdataLocked = YES;
8351 [PLAYER doScriptEvent:OOJSID("systemInformationChanged") withArguments:[NSArray arrayWithObjects:[NSNumber numberWithInt:gnum],[NSNumber numberWithInt:pnum],key,object,nil]];
8359 NSString *systemKey = [
self keyForPlanetOverridesForSystem:pnum inGalaxy:gnum];
8360 return [systemManager getPropertiesForSystemKey:systemKey];
8366 return [[
self generateSystemDataForGalaxy:gnum planet:pnum] allKeys];
8373 return [systemManager getProperty:key forSystem:pnum inGalaxy:gnum];
8379 return [
self getSystemName:sys forGalaxy:galaxyID];
8385 return [systemManager getProperty:@"name" forSystem:sys inGalaxy:gnum];
8391 return [[systemManager getProperty:@"government" forSystem:sys inGalaxy:galaxyID] unsignedCharValue];
8395- (NSString *) getSystemInhabitants:(
OOSystemID) sys
8397 return [
self getSystemInhabitants:sys plural:YES];
8401- (NSString *) getSystemInhabitants:(
OOSystemID) sys plural:(BOOL)plural
8403 NSString *ret =
nil;
8406 ret = [systemManager getProperty:KEY_INHABITANT forSystem:sys inGalaxy:galaxyID];
8414 return [systemManager getProperty:KEY_INHABITANTS forSystem:sys inGalaxy:galaxyID];
8419- (NSPoint) coordinatesForSystem:(
OOSystemID)s
8421 return [systemManager getCoordinatesForSystem:s inGalaxy:galaxyID];
8425- (
OOSystemID) findSystemFromName:(NSString *) sysName
8427 if (sysName ==
nil)
return -1;
8429 NSString *system_name =
nil;
8430 NSString *match = [sysName lowercaseString];
8432 for (i = 0; i < 256; i++)
8434 system_name = [system_names[i] lowercaseString];
8435 if ([system_name isEqualToString:match])
8446 OOLog(
@"deprecated.function",
@"%@",
@"findSystemAtCoords");
8447 return [
self findSystemNumberAtCoords:coords withGalaxy:g includingHidden:YES];
8451- (NSMutableArray *) nearbyDestinationsWithinRange:(
double)range
8453 NSMutableArray *result = [NSMutableArray arrayWithCapacity:16];
8456 NSPoint here = [PLAYER galaxy_coordinates];
8458 for (
unsigned short i = 0; i < 256; i++)
8460 NSPoint there = [
self coordinatesForSystem:i];
8462 if (dist <= range && (i != systemID || [
self inInterstellarSpace]))
8464 [result addObject: [NSDictionary dictionaryWithObjectsAndKeys:
8465 [NSNumber numberWithDouble:dist], @"distance",
8466 [NSNumber numberWithInt:i], @"sysID",
8467 [[
self generateSystemData:i] oo_stringForKey:@"sun_gone_nova" defaultValue:@"0"], @"nova",
8481 double min_dist = 10000.0;
8484 BOOL connected[256];
8485 for (i = 0; i < 256; i++)
8488 for (n = 0; n < 3; n++)
8490 for (i = 0; i < 256; i++)
8492 NSPoint ipos = [systemManager getCoordinatesForSystem:i inGalaxy:g];
8493 for (j = 0; j < 256; j++)
8495 NSPoint jpos = [systemManager getCoordinatesForSystem:j inGalaxy:g];
8499 connected[j] |= connected[i];
8500 connected[i] |= connected[j];
8506 for (i = 0; i < 256; i++)
8508 NSPoint ipos = [systemManager getCoordinatesForSystem:i inGalaxy:g];
8510 if ((connected[i])&&(distance < min_dist)&&(distance != 0.0))
8512 min_dist = distance;
8528 double min_dist = 10000.0;
8531 BOOL connected[256];
8532 for (i = 0; i < 256; i++)
8535 for (n = 0; n < 3; n++)
8537 for (i = 0; i < 256; i++)
8539 NSPoint ipos = [systemManager getCoordinatesForSystem:i inGalaxy:g];
8540 for (j = 0; j < 256; j++)
8542 NSPoint jpos = [systemManager getCoordinatesForSystem:j inGalaxy:g];
8546 connected[j] |= connected[i];
8547 connected[i] |= connected[j];
8553 for (i = 0; i < 256; i++)
8555 NSPoint ipos = [systemManager getCoordinatesForSystem:i inGalaxy:g];
8557 if ((connected[i])&&(distance < min_dist))
8559 min_dist = distance;
8568- (
OOSystemID) findSystemNumberAtCoords:(NSPoint) coords withGalaxy:(
OOGalaxyID)g includingHidden:(BOOL)hidden
8577 unsigned distance, dx, dy;
8579 unsigned min_dist = 10000;
8581 for (i = 0; i < 256; i++)
8584 NSDictionary *systemInfo = [systemManager getPropertiesForSystem:i inGalaxy:g];
8585 NSInteger concealment = [systemInfo oo_intForKey:@"concealment" defaultValue:OO_SYSTEMCONCEALMENT_NONE];
8591 NSPoint ipos = [systemManager getCoordinatesForSystem:i inGalaxy:g];
8592 dx =
ABS(coords.x - ipos.x);
8593 dy =
ABS(coords.y - ipos.y);
8595 if (dx > dy) distance = (dx + dx + dy) / 2;
8596 else distance = (dx + dy + dy) / 2;
8598 if (distance < min_dist)
8600 min_dist = distance;
8604 if ((distance == min_dist)&&(coords.y > ipos.y))
8609 else if ((distance == min_dist)&&(coords.y == ipos.y)&&(i==[
PLAYER targetSystemID]))
8618- (NSPoint) findSystemCoordinatesWithPrefix:(NSString *) p_fix
8620 return [
self findSystemCoordinatesWithPrefix:p_fix exactMatch:NO];
8624- (NSPoint) findSystemCoordinatesWithPrefix:(NSString *) p_fix exactMatch:(BOOL) exactMatch
8626 NSString *system_name =
nil;
8627 NSPoint system_coords = NSMakePoint(-1.0,-1.0);
8630 for (i = 0; i < 256; i++)
8632 system_found[i] = NO;
8633 system_name = [system_names[i] lowercaseString];
8634 if ((exactMatch && [system_name isEqualToString:p_fix]) || (!exactMatch && [system_name hasPrefix:p_fix]))
8637 NSDictionary *systemInfo = [systemManager getPropertiesForSystem:i inGalaxy:galaxyID];
8638 NSInteger concealment = [systemInfo oo_intForKey:@"concealment" defaultValue:OO_SYSTEMCONCEALMENT_NONE];
8644 system_found[i] = YES;
8647 system_coords = [systemManager getCoordinatesForSystem:i inGalaxy:galaxyID];
8652 return system_coords;
8656- (BOOL*) systemsFound
8658 return (BOOL*)system_found;
8662- (NSString*)systemNameIndex:(
OOSystemID)index
8664 return system_names[index & 255];
8681 if (start == -1 || goal == -1)
return nil;
8683#ifdef CACHE_ROUTE_FROM_SYSTEM_RESULTS
8685 static NSDictionary *c_route =
nil;
8689 if (c_route !=
nil && c_start == start && c_goal == goal && c_optimizeBy == optimizeBy)
8698 if (start > 255 || goal > 255)
return nil;
8700 NSArray *neighbours[256];
8701 BOOL concealed[256];
8702 for (i = 0; i < 256; i++)
8704 NSDictionary *systemInfo = [systemManager getPropertiesForSystem:i inGalaxy:galaxyID];
8705 NSInteger concealment = [systemInfo oo_intForKey:@"concealment" defaultValue:OO_SYSTEMCONCEALMENT_NONE];
8708 neighbours[i] = [NSArray array];
8713 neighbours[i] = [
self neighboursToSystem:i];
8720 double maxCost = optimizeBy ==
OPTIMIZED_BY_TIME ? 256 * (7 * 7) : 256 * (7 * 256 + 7);
8722 NSMutableArray *curr = [NSMutableArray arrayWithCapacity:256];
8725 NSMutableArray *next = [NSMutableArray arrayWithCapacity:256];
8726 while ([curr
count] != 0)
8728 for (i = 0; i < [curr count]; i++) {
8730 NSArray *ns = neighbours[[elemI
location]];
8731 for (j = 0; j < [ns count]; j++)
8741 NSPoint cpos = [systemManager getCoordinatesForSystem:c inGalaxy:galaxyID];
8742 NSPoint npos = [systemManager getCoordinatesForSystem:n inGalaxy:galaxyID];
8745 double lastTime = lastDistance * lastDistance;
8747 double distance = [ce
distance] + lastDistance;
8748 double time = [ce
time] + lastTime;
8750 int jumps = [ce
jumps] + 1;
8752 if (cost < maxCost && (cheapest[n] ==
nil || [cheapest[n] cost] > cost)) {
8757 if (n == goal && cost < maxCost)
8762 [curr setArray:next];
8763 [next removeAllObjects];
8767 if (!cheapest[goal])
return nil;
8769 NSMutableArray *route = [NSMutableArray arrayWithCapacity:256];
8773 [route insertObject:[NSNumber numberWithInt:[e
location]] atIndex:0];
8774 if ([e parent] == -1)
break;
8775 e = cheapest[[e
parent]];
8778#ifdef CACHE_ROUTE_FROM_SYSTEM_RESULTS
8781 c_optimizeBy = optimizeBy;
8783 c_route = [[NSDictionary alloc] initWithObjectsAndKeys: route, @"route", [NSNumber numberWithDouble:[cheapest[goal]
distance]], @"distance", nil];
8787 return [NSDictionary dictionaryWithObjectsAndKeys:
8789 [NSNumber numberWithDouble:[cheapest[goal]
distance]], @"distance",
8790 [NSNumber numberWithDouble:[cheapest[goal]
time]], @"time",
8791 [NSNumber numberWithInt:[cheapest[goal]
jumps]], @"jumps",
8797- (NSArray *) neighboursToSystem: (
OOSystemID) s
8799 if (s == systemID && closeSystems !=
nil)
8801 return closeSystems;
8803 NSArray *neighbours = [systemManager getNeighbourIDsForSystem:s inGalaxy:galaxyID];
8807 [closeSystems release];
8808 closeSystems = [neighbours copy];
8809 return closeSystems;
8843- (void) preloadPlanetTexturesForSystem:(
OOSystemID)s
8847 [
self prunePreloadingPlanetMaterials];
8849 if ([_preloadingPlanetMaterials
count] < 3)
8851 if (_preloadingPlanetMaterials ==
nil) _preloadingPlanetMaterials = [[NSMutableArray alloc] initWithCapacity:4];
8853 OOPlanetEntity *planet = [[OOPlanetEntity alloc] initAsMainPlanetForSystem:s];
8859 if (![surface isFinishedLoading])
8861 [_preloadingPlanetMaterials addObject:surface];
8865 OOMaterial *atmo = [planet atmosphereMaterial];
8866 if (atmo !=
nil) [_preloadingPlanetMaterials addObject:atmo];
8876- (NSDictionary *) globalSettings
8878 return globalSettings;
8882- (NSArray *) equipmentData
8884 return equipmentData;
8888- (NSArray *) equipmentDataOutfitting
8890 return equipmentDataOutfitting;
8896 return commodityMarket;
8900- (NSString *) timeDescription:(
double) interval
8902 double r_time = interval;
8903 NSString* result =
@"";
8907 int days = floor(r_time / 86400);
8908 r_time -= 86400 * days;
8909 result = [NSString stringWithFormat:@"%@ %d day%@", result, days, (days > 1) ? @"s" : @""];
8913 int hours = floor(r_time / 3600);
8914 r_time -= 3600 * hours;
8915 result = [NSString stringWithFormat:@"%@ %d hour%@", result, hours, (hours > 1) ? @"s" : @""];
8919 int mins = floor(r_time / 60);
8920 r_time -= 60 * mins;
8921 result = [NSString stringWithFormat:@"%@ %d minute%@", result, mins, (mins > 1) ? @"s" : @""];
8925 int secs = floor(r_time);
8926 result = [NSString stringWithFormat:@"%@ %d second%@", result, secs, (secs > 1) ? @"s" : @""];
8928 return [result stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
8932- (NSString *) shortTimeDescription:(
double) interval
8934 double r_time = interval;
8935 NSString* result =
@"";
8938 if (interval <= 0.0)
8939 return DESC(
@"contracts-no-time");
8943 int days = floor(r_time / 86400);
8944 r_time -= 86400 * days;
8945 result = [NSString stringWithFormat:@"%@ %d %@", result, days, DESC_PLURAL(@"contracts-day-word", days)];
8950 int hours = floor(r_time / 3600);
8951 r_time -= 3600 * hours;
8952 result = [NSString stringWithFormat:@"%@ %d %@", result, hours, DESC_PLURAL(@"contracts-hour-word", hours)];
8955 if (parts < 2 && r_time > 60)
8957 int mins = floor(r_time / 60);
8958 r_time -= 60 * mins;
8959 result = [NSString stringWithFormat:@"%@ %d %@", result, mins, DESC_PLURAL(@"contracts-minute-word", mins)];
8962 if (parts < 2 && r_time > 0)
8964 int secs = floor(r_time);
8965 result = [NSString stringWithFormat:@"%@ %d %@", result, secs, DESC_PLURAL(@"contracts-second-word", secs)];
8967 return [result stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
8971- (void) makeSunSkimmer:(
ShipEntity *) ship andSetAI:(BOOL)setAI
8973 if (setAI) [ship switchAITo:
@"oolite-traderAI.js"];
8977 if ([ship heatInsulation] < minInsulation) [ship setHeatInsulation:minInsulation];
8983 Random_Seed ret = [systemManager getRandomSeedForCurrentSystem];
8999- (void) loadStationMarkets:(NSArray *)marketData
9001 if (marketData ==
nil)
9006 NSArray *stations = [
self stations];
9008 NSDictionary *savedMarket =
nil;
9010 foreach (savedMarket, marketData)
9012 HPVector pos = [savedMarket oo_hpvectorForKey:@"position"];
9013 foreach (station, stations)
9016 if ([station allowsSaving] && station != [
UNIVERSE station])
9019 if (HPdistance2(pos,[station position]) < 1000000)
9021 [station setLocalMarket:[savedMarket oo_arrayForKey:@"market"]];
9031- (NSArray *) getStationMarkets
9033 NSMutableArray *markets = [[NSMutableArray alloc] init];
9034 NSArray *stations = [
self stations];
9037 NSMutableDictionary *savedMarket =
nil;
9041 foreach (station, stations)
9044 if ([station allowsSaving] && station != [
UNIVERSE station])
9046 stationMarket = [station localMarket];
9047 if (stationMarket !=
nil)
9049 savedMarket = [NSMutableDictionary dictionaryWithCapacity:2];
9051 [savedMarket setObject:ArrayFromHPVector([station position]) forKey:@"position"];
9052 [markets addObject:savedMarket];
9057 return [markets autorelease];
9066 NSMutableDictionary *resultDictionary = [NSMutableDictionary dictionary];
9068 float tech_price_boost = (ship_seed.
a + ship_seed.b) / 256.0;
9074 for (i = 0; i < 256; i++)
9076 long long reference_time = 0x1000000 * floor(current_time / 0x1000000);
9078 long long c_time = ship_seed.
a * 0x10000 + ship_seed.b * 0x100 + ship_seed.c;
9079 double ship_sold_time = reference_time + c_time;
9081 if (ship_sold_time < 0)
9082 ship_sold_time += 0x1000000;
9084 double days_until_sale = (ship_sold_time - current_time) / 86400.0;
9086 NSMutableArray *keysForShips = [NSMutableArray arrayWithArray:[registry
playerShipKeys]];
9088 for (si = 0; si < [keysForShips count]; si++)
9091 NSString *key = [keysForShips oo_stringAtIndex:si];
9093 NSArray *conditions = [dict oo_arrayForKey:@"conditions"];
9095 if (![player scriptTestConditions:conditions])
9097 [keysForShips removeObjectAtIndex:si--];
9099 NSString *condition_script = [dict oo_stringForKey:@"condition_script"];
9100 if (condition_script !=
nil)
9102 OOJSScript *condScript = [
self getConditionScript:condition_script];
9103 if (condScript !=
nil)
9107 JSBool allow_purchase;
9111 OK = [condScript
callMethod:OOJSID("allowOfferShip")
9116 if (OK) OK = JS_ValueToBoolean(context, result, &allow_purchase);
9120 if (OK && !allow_purchase)
9125 [keysForShips removeObjectAtIndex:si--];
9132 NSDictionary *systemInfo = [
self generateSystemData:s];
9134 if (specialTL != NSNotFound)
9137 techlevel = specialTL;
9142 techlevel = [systemInfo oo_unsignedIntForKey:KEY_TECHLEVEL];
9144 unsigned ship_index = (ship_seed.
d * 0x100 + ship_seed.e) % [keysForShips
count];
9145 NSString *ship_key = [keysForShips oo_stringAtIndex:ship_index];
9147 OOTechLevelID ship_techlevel = [ship_info oo_intForKey:KEY_TECHLEVEL];
9149 double chance = 1.0 - pow(1.0 - [ship_info oo_doubleForKey:KEY_CHANCE], MAX((
OOTechLevelID)1, techlevel - ship_techlevel));
9152 int superRand1 = ship_seed.
a * 0x10000 + ship_seed.c * 0x100 + ship_seed.e;
9153 uint32_t superRand2 = ship_seed.
b * 0x10000 + ship_seed.d * 0x100 + ship_seed.f;
9158 if ((days_until_sale > 0.0) && (days_until_sale < 30.0) && (ship_techlevel <= techlevel) && (
randf() < chance) && (shipBaseDict !=
nil))
9160 NSMutableDictionary* shipDict = [NSMutableDictionary dictionaryWithDictionary:shipBaseDict];
9161 NSMutableString* shortShipDescription = [NSMutableString stringWithCapacity:256];
9162 NSString *shipName = [shipDict oo_stringForKey:@"display_name" defaultValue:[shipDict oo_stringForKey:KEY_NAME]];
9165 NSMutableArray* extras = [NSMutableArray arrayWithArray:[[ship_info oo_dictionaryForKey:KEY_STANDARD_EQUIPMENT] oo_arrayForKey:KEY_EQUIPMENT_EXTRAS]];
9166 NSString* fwdWeaponString = [[ship_info oo_dictionaryForKey:KEY_STANDARD_EQUIPMENT] oo_stringForKey:KEY_EQUIPMENT_FORWARD_WEAPON];
9167 NSString* aftWeaponString = [[ship_info oo_dictionaryForKey:KEY_STANDARD_EQUIPMENT] oo_stringForKey:KEY_EQUIPMENT_AFT_WEAPON];
9169 NSMutableArray* options = [NSMutableArray arrayWithArray:[ship_info oo_arrayForKey:KEY_OPTIONAL_EQUIPMENT]];
9170 OOCargoQuantity maxCargo = [shipDict oo_unsignedIntForKey:@"max_cargo"];
9176 [shortShipDescription appendFormat:@"%@:", shipName];
9184 if (fwdWeapon && fwdWeaponString) [shipDict setObject:fwdWeaponString forKey:KEY_EQUIPMENT_FORWARD_WEAPON];
9185 if (aftWeapon && aftWeaponString) [shipDict setObject:aftWeaponString forKey:KEY_EQUIPMENT_AFT_WEAPON];
9187 int passengerBerthCount = 0;
9188 BOOL customised = NO;
9189 BOOL weaponCustomized = NO;
9191 NSString *fwdWeaponDesc =
nil;
9193 NSString *shortExtrasKey =
@"shipyard-first-extra";
9198 while ((
randf() < chance) && ([options
count]))
9201 int optionIndex =
Ranrot() % [options count];
9202 NSString *equipmentKey = [options oo_stringAtIndex:optionIndex];
9209 NSString *eqShortDesc = [item
name];
9211 if ([item techLevel] > techlevel)
9214 eqTechLevel =
MIN(eqTechLevel, 15U);
9217 if (
randf() * (eqTechLevel - techlevel) < 1.0)
9220 eqPrice *= (tech_price_boost + eqTechLevel - techlevel) * 90 / 100;
9226 if ([item incompatibleEquipment] !=
nil && extras !=
nil)
9228 NSEnumerator *keyEnum =
nil;
9230 BOOL incompatible = NO;
9232 for (keyEnum = [[item incompatibleEquipment] objectEnumerator]; (key = [keyEnum nextObject]); )
9234 if ([extras containsObject:key])
9236 [options removeObject:equipmentKey];
9241 if (incompatible)
break;
9244 for (keyEnum = [[item incompatibleEquipment] objectEnumerator]; (key = [keyEnum nextObject]); )
9246 if ([options containsObject:key])
9248 [options removeObject:key];
9255 if (condition_script !=
nil)
9257 OOJSScript *condScript = [
self getConditionScript:condition_script];
9258 if (condScript !=
nil)
9262 JSBool allow_addition;
9266 OK = [condScript
callMethod:OOJSID("allowAwardEquipment")
9271 if (OK) OK = JS_ValueToBoolean(JScontext, result, &allow_addition);
9275 if (OK && !allow_addition)
9286 if ([item requiresEquipment] !=
nil && extras !=
nil)
9288 NSEnumerator *keyEnum =
nil;
9292 for (keyEnum = [[item requiresEquipment] objectEnumerator]; (key = [keyEnum nextObject]); )
9294 if (![extras containsObject:key])
9302 if ([item requiresAnyEquipment] !=
nil && extras !=
nil)
9304 NSEnumerator *keyEnum =
nil;
9308 for (keyEnum = [[item requiresAnyEquipment] objectEnumerator]; (key = [keyEnum nextObject]); )
9310 if ([extras containsObject:key])
9320 if ([equipmentKey isEqualTo:
@"EQ_NAVAL_ENERGY_UNIT"])
9322 if ([extras containsObject:
@"EQ_ENERGY_UNIT"])
9324 [options removeObject:equipmentKey];
9329 if ([equipmentKey hasPrefix:
@"EQ_WEAPON"])
9333 if (availableFacings &
WEAPON_FACING_FORWARD && [new_weapon weaponThreatAssessment] > [fwdWeapon weaponThreatAssessment])
9336 price -= [
self getEquipmentPriceForKey:fwdWeaponString] * 90 / 1000;
9338 fwdWeaponString = equipmentKey;
9339 fwdWeapon = new_weapon;
9340 [shipDict setObject:fwdWeaponString forKey:KEY_EQUIPMENT_FORWARD_WEAPON];
9341 weaponCustomized = YES;
9342 fwdWeaponDesc = eqShortDesc;
9347 if (availableFacings &
WEAPON_FACING_AFT && (
isWeaponNone(aftWeapon) || [new_weapon weaponThreatAssessment] > [aftWeapon weaponThreatAssessment]))
9349 price -= [
self getEquipmentPriceForKey:aftWeaponString] * 90 / 1000;
9351 aftWeaponString = equipmentKey;
9352 aftWeapon = new_weapon;
9353 [shipDict setObject:aftWeaponString forKey:KEY_EQUIPMENT_AFT_WEAPON];
9357 [options removeObject:equipmentKey];
9364 if ([equipmentKey isEqualToString:
@"EQ_PASSENGER_BERTH"])
9370 [extras addObject:equipmentKey];
9371 passengerBerthCount++;
9377 [options removeObject:equipmentKey];
9383 [extras addObject:equipmentKey];
9384 if ([item isVisible])
9386 NSString *item = eqShortDesc;
9387 [shortShipDescription appendString:OOExpandKey(shortExtrasKey, item)];
9388 shortExtrasKey =
@"shipyard-additional-extra";
9391 [options removeObject:equipmentKey];
9397 [options removeObject:equipmentKey];
9402 BOOL lowercaseIgnore = [[
self descriptions] oo_boolForKey:@"lowercase_ignore"];
9404 if (passengerBerthCount)
9406 NSString* npb = (passengerBerthCount > 1)? [NSString stringWithFormat:
@"%d ", passengerBerthCount] : (id)
@"";
9407 NSString* ppb =
DESC_PLURAL(
@"passenger-berth", passengerBerthCount);
9408 NSString* extraPassengerBerthsDescription = [NSString stringWithFormat:DESC(@"extra-@-@-(passenger-berths)"), npb, ppb];
9409 NSString *item = extraPassengerBerthsDescription;
9410 [shortShipDescription appendString:OOExpandKey(shortExtrasKey, item)];
9411 shortExtrasKey =
@"shipyard-additional-extra";
9416 [shortShipDescription appendString:OOExpandKey(@"shipyard-standard-customer-model")];
9419 if (weaponCustomized)
9421 NSString *weapon = (lowercaseIgnore ? fwdWeaponDesc : [fwdWeaponDesc lowercaseString]);
9422 [shortShipDescription appendString:OOExpandKey(@"shipyard-forward-weapon-upgraded", weapon)];
9424 if (price > base_price)
9426 price = base_price +
cunningFee(price - base_price, 0.05);
9429 [shortShipDescription appendString:OOExpandKey(@"shipyard-price", price)];
9431 NSString *shipID = [NSString stringWithFormat:@"%06x-%06x", superRand1, superRand2];
9435 NSDictionary *ship_info_dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
9436 shipID, SHIPYARD_KEY_ID,
9437 ship_key, SHIPYARD_KEY_SHIPDATA_KEY,
9438 shipDict, SHIPYARD_KEY_SHIP,
9439 shortShipDescription, KEY_SHORT_DESCRIPTION,
9440 [NSNumber numberWithUnsignedLongLong:price], SHIPYARD_KEY_PRICE,
9441 extras, KEY_EQUIPMENT_EXTRAS,
9442 [NSNumber numberWithUnsignedShort:personality], SHIPYARD_KEY_PERSONALITY,
9445 [resultDictionary setObject:ship_info_dictionary forKey:shipID];
9455 NSMutableArray *resultArray = [[[resultDictionary allValues] mutableCopy] autorelease];
9456 [resultArray sortUsingFunction:compareName context:NULL];
9461 while (i < [resultArray
count])
9463 if (
compareName([resultArray objectAtIndex:i - 1], [resultArray objectAtIndex:i],
nil) == NSOrderedSame )
9465 [resultArray removeObjectAtIndex: i];
9475 return [NSArray arrayWithArray:resultArray];
9481 NSDictionary *ship1 = [(NSDictionary *)dict1 oo_dictionaryForKey:SHIPYARD_KEY_SHIP];
9482 NSDictionary *ship2 = [(NSDictionary *)dict2 oo_dictionaryForKey:SHIPYARD_KEY_SHIP];
9483 NSString *name1 = [ship1 oo_stringForKey:KEY_NAME];
9484 NSString *name2 = [ship2 oo_stringForKey:KEY_NAME];
9486 NSComparisonResult result = [[name1 lowercaseString] compare:[name2 lowercaseString]];
9487 if (result != NSOrderedSame)
9496 NSNumber *price1 = [(NSDictionary *)dict1 objectForKey:SHIPYARD_KEY_PRICE];
9497 NSNumber *price2 = [(NSDictionary *)dict2 objectForKey:SHIPYARD_KEY_PRICE];
9499 return [price1 compare:price2];
9507 NSString *ship_desc = [dict oo_stringForKey:@"ship_desc"];
9511 if (shipyard_info ==
nil)
9513 OOLogERR(
@"universe.tradeInValueForCommanderDictionary.valueCalculationError",
9514 @"Shipyard dictionary entry for ship %@ required for trade in value calculation, but does not exist. Setting ship value to 0.", ship_desc);
9518 base_price = [shipyard_info oo_unsignedLongLongForKey:SHIPYARD_KEY_PRICE defaultValue:0ULL];
9521 if(base_price == 0ULL)
return base_price;
9529 unsigned ship_missiles = [dict oo_unsignedIntForKey:@"missiles"];
9530 unsigned ship_max_passengers = [dict oo_unsignedIntForKey:@"max_passengers"];
9531 NSMutableArray *ship_extra_equipment = [NSMutableArray arrayWithArray:[[dict oo_dictionaryForKey:@"extra_equipment"] allKeys]];
9533 NSDictionary *basic_info = [shipyard_info oo_dictionaryForKey:KEY_STANDARD_EQUIPMENT];
9534 unsigned base_missiles = [basic_info oo_unsignedIntForKey:KEY_EQUIPMENT_MISSILES];
9535 OOCreditsQuantity base_missiles_value = base_missiles * [UNIVERSE getEquipmentPriceForKey:@"EQ_MISSILE"] / 10;
9536 NSString *base_weapon_key = [basic_info oo_stringForKey:KEY_EQUIPMENT_FORWARD_WEAPON];
9537 OOCreditsQuantity base_weapons_value = [UNIVERSE getEquipmentPriceForKey:base_weapon_key] / 10;
9538 NSMutableArray *base_extra_equipment = [NSMutableArray arrayWithArray:[basic_info oo_arrayForKey:KEY_EQUIPMENT_EXTRAS]];
9539 NSString *weapon_key =
nil;
9542 base_weapon_key = [basic_info oo_stringForKey:KEY_EQUIPMENT_AFT_WEAPON defaultValue:nil];
9543 if (base_weapon_key !=
nil)
9544 base_weapons_value += [
UNIVERSE getEquipmentPriceForKey:base_weapon_key] / 10;
9551 NSArray *missileRoles = [dict oo_arrayForKey:@"missile_roles"];
9552 if (missileRoles !=
nil)
9555 for (i = 0; i < ship_missiles; i++)
9557 NSString *missile_desc = [missileRoles oo_stringAtIndex:i];
9558 if (missile_desc !=
nil && ![missile_desc isEqualToString:
@"NONE"])
9560 ship_missiles_value += [
UNIVERSE getEquipmentPriceForKey:missile_desc] / 10;
9565 ship_missiles_value = ship_missiles * [UNIVERSE getEquipmentPriceForKey:@"EQ_MISSILE"] / 10;
9568 long long extra_equipment_value = ship_max_passengers * [UNIVERSE getEquipmentPriceForKey:@"EQ_PASSENGER_BERTH"]/10;
9571 extra_equipment_value += ship_missiles_value - base_missiles_value;
9574 if (ship_fwd_weapon)
9577 ship_main_weapons_value = [UNIVERSE getEquipmentPriceForKey:weapon_key] / 10;
9579 if (ship_aft_weapon)
9582 if (base_weapon_key !=
nil)
9584 ship_main_weapons_value += [
UNIVERSE getEquipmentPriceForKey:weapon_key] / 10;
9588 ship_other_weapons_value += [
UNIVERSE getEquipmentPriceForKey:weapon_key] / 10;
9591 if (ship_port_weapon)
9594 ship_other_weapons_value += [
UNIVERSE getEquipmentPriceForKey:weapon_key] / 10;
9596 if (ship_starboard_weapon)
9599 ship_other_weapons_value += [
UNIVERSE getEquipmentPriceForKey:weapon_key] / 10;
9603 extra_equipment_value += ship_other_weapons_value;
9604 extra_equipment_value += ship_main_weapons_value - base_weapons_value;
9607 NSString *eq_key =
nil;
9611 for (i = [base_extra_equipment
count]-1; i > 0;i--)
9613 eq_key = [base_extra_equipment oo_stringAtIndex:i];
9614 if ([base_extra_equipment indexOfObject:eq_key inRange:NSMakeRange(0, i-1)] != NSNotFound)
9615 [base_extra_equipment removeObjectAtIndex:i];
9619 for (i = [base_extra_equipment
count]-1; i >= 0; i--)
9621 eq_key = [base_extra_equipment oo_stringAtIndex:i];
9622 if ([ship_extra_equipment containsObject:eq_key])
9623 [ship_extra_equipment removeObject:eq_key];
9625 extra_equipment_value -= ([
UNIVERSE getEquipmentPriceForKey:eq_key] / 10);
9631 for (i = [ship_extra_equipment
count]-1; i >= 0; i--)
9633 eq_key = [ship_extra_equipment oo_stringAtIndex:i];
9635 if ([item isPortableBetweenShips]) [ship_extra_equipment removeObjectAtIndex:i];
9639 for (i = [ship_extra_equipment
count]-1; i >= 0; i--)
9640 extra_equipment_value += ([
UNIVERSE getEquipmentPriceForKey:[ship_extra_equipment oo_stringAtIndex:i]] / 10);
9643 extra_equipment_value *= extra_equipment_value < 0 ? 1.4 : 0.9;
9647 if ((
long long)scrap_value > (
long long)base_price + extra_equipment_value)
return scrap_value;
9649 return base_price + extra_equipment_value;
9653- (NSString *) brochureDescriptionWithDictionary:(NSDictionary *)dict standardEquipment:(NSArray *)extras optionalEquipment:(NSArray *)options
9655 NSMutableArray *mut_extras = [NSMutableArray arrayWithArray:extras];
9656 NSString *allOptions = [options componentsJoinedByString:@" "];
9658 NSMutableString *desc = [NSMutableString stringWithFormat:@"The %@.", [dict oo_stringForKey: KEY_NAME]];
9664 OOCargoQuantity extra_cargo = [dict oo_unsignedIntForKey:@"extra_cargo" defaultValue:15];
9665 [desc appendFormat:@" Cargo capacity %dt", max_cargo];
9666 BOOL canExpand = ([allOptions rangeOfString:@"EQ_CARGO_BAY"].location != NSNotFound);
9668 [desc appendFormat:@" (expandable to %dt at most starports)", max_cargo + extra_cargo];
9669 [desc appendString:@"."];
9673 float top_speed = [dict oo_intForKey:@"max_flight_speed"];
9674 [desc appendFormat:@" Top speed %.3fLS.", 0.001 * top_speed];
9677 if ([mut_extras
count])
9679 unsigned n_berths = 0;
9681 for (i = 0; i < [mut_extras count]; i++)
9683 NSString* item_key = [mut_extras oo_stringAtIndex:i];
9684 if ([item_key isEqual:
@"EQ_PASSENGER_BERTH"])
9687 [mut_extras removeObjectAtIndex:i--];
9693 [desc appendString:@" Includes luxury accomodation for a single passenger."];
9695 [desc appendFormat:@" Includes luxury accomodation for %d passengers.", n_berths];
9700 if ([mut_extras
count])
9702 [desc appendString:@"\nComes with"];
9704 for (i = 0; i < [mut_extras count]; i++)
9706 NSString* item_key = [mut_extras oo_stringAtIndex:i];
9707 NSString* item_desc =
nil;
9708 for (j = 0; ((j < [equipmentData count])&&(!item_desc)) ; j++)
9710 NSString *eq_type = [[equipmentData oo_arrayAtIndex:j] oo_stringAtIndex:EQUIPMENT_KEY_INDEX];
9711 if ([eq_type isEqual:item_key])
9716 switch ([mut_extras
count] - i)
9719 [desc appendFormat:@" %@ fitted as standard.", item_desc];
9722 [desc appendFormat:@" %@ and", item_desc];
9725 [desc appendFormat:@" %@,", item_desc];
9733 if ([options
count])
9735 [desc appendString:@"\nCan additionally be outfitted with"];
9737 for (i = 0; i < [options count]; i++)
9739 NSString* item_key = [options oo_stringAtIndex:i];
9740 NSString* item_desc =
nil;
9741 for (j = 0; ((j < [equipmentData count])&&(!item_desc)) ; j++)
9743 NSString *eq_type = [[equipmentData oo_arrayAtIndex:j] oo_stringAtIndex:EQUIPMENT_KEY_INDEX];
9744 if ([eq_type isEqual:item_key])
9749 switch ([options
count] - i)
9752 [desc appendFormat:@" %@ at suitably equipped starports.", item_desc];
9755 [desc appendFormat:@" %@ and/or", item_desc];
9758 [desc appendFormat:@" %@,", item_desc];
9769- (HPVector) getWitchspaceExitPosition
9775- (Quaternion) getWitchspaceExitRotation
9778 Quaternion q_result;
9788 quaternion_normalize(&q_result);
9794- (HPVector) getSunSkimStartPositionForShip:(
ShipEntity*) ship
9810 v1.x -= v0.
x; v1.y -= v0.
y; v1.z -= v0.z;
9811 if (v1.x||v1.y||v1.z)
9812 v1 = HPvector_normal(v1);
9816 v1.x *= radius; v1.y *= radius; v1.z *= radius;
9817 v1.x += v0.
x; v1.y += v0.
y; v1.z += v0.z;
9823- (HPVector) getSunSkimEndPositionForShip:(
ShipEntity*) ship
9839 v1.x -= v0.
x; v1.y -= v0.
y; v1.z -= v0.z;
9840 if (v1.x||v1.y||v1.z)
9841 v1 = HPvector_normal(v1);
9845 if (v2.x||v2.y||v2.z)
9846 v2 = HPvector_normal(v2);
9849 HPVector v3 = HPcross_product(v1, v2);
9850 if (v3.x||v3.y||v3.z)
9851 v3 = HPvector_normal(v3);
9855 v1.x *= radius; v1.y *= radius; v1.z *= radius;
9856 v1.x += v0.
x; v1.y += v0.
y; v1.z += v0.z;
9857 v1.x += 15000 * v3.
x; v1.y += 15000 * v3.
y; v1.z += 15000 * v3.z;
9858 v1.x -= v0.
x; v1.y -= v0.
y; v1.z -= v0.z;
9859 if (v1.x||v1.y||v1.z)
9860 v1 = HPvector_normal(v1);
9863 v1.x *= radius; v1.y *= radius; v1.z *= radius;
9864 v1.x += v0.
x; v1.y += v0.
y; v1.z += v0.z;
9870- (NSArray *) listBeaconsWithCode:(NSString *)code
9872 NSMutableArray *result = [NSMutableArray array];
9873 Entity <OOBeaconEntity> *beacon = [
self firstBeacon];
9875 while (beacon !=
nil)
9877 NSString *beaconCode = [beacon beaconCode];
9878 if ([beaconCode rangeOfString:code options: NSCaseInsensitiveSearch].location != NSNotFound)
9880 [result addObject:beacon];
9882 beacon = [beacon nextBeacon];
9885 return [result sortedArrayUsingSelector:@selector(compareBeaconCodeWith:)];
9889- (void) allShipsDoScriptEvent:(jsid)event andReactToAIMessage:(NSString *)message
9892 int ent_count = n_entities;
9895 for (i = 0; i < ent_count; i++)
9897 if (sortedEntities[i]->isShip)
9903 for (i = 0; i < ship_count; i++)
9907 if (message !=
nil) [[se getAI] reactToMessage:message context:
@"global message"];
9922 return comm_log_gui;
9935 [message_gui clear];
9936 [comm_log_gui clear];
9937 [comm_log_gui printLongText:DESC(@"communications-log-string")
9938 align:GUI_ALIGN_CENTER color:[
OOColor yellowColor] fadeTime:0 key:nil addToArray:nil];
9942- (void) resetCommsLogColor
9948- (void) setDisplayText:(BOOL) value
9950 displayGUI = !!value;
9960- (void) setDisplayFPS:(BOOL) value
9962 displayFPS = !!value;
9972- (void) setAutoSave:(BOOL) value
9975 [[NSUserDefaults standardUserDefaults] setBool:autoSave forKey:@"autosave"];
9985- (void) setAutoSaveNow:(BOOL) value
9987 autoSaveNow = !!value;
9997- (void) setWireframeGraphics:(BOOL) value
9999 wireframeGraphics = !!value;
10000 [[NSUserDefaults standardUserDefaults] setBool:wireframeGraphics forKey:@"wireframe-graphics"];
10004- (BOOL) wireframeGraphics
10006 return wireframeGraphics;
10010- (BOOL) reducedDetail
10031 detailLevel = value;
10038 [
self setDetailLevelDirectly:value];
10039 [[NSUserDefaults standardUserDefaults] setInteger:detailLevel forKey:@"detailLevel"];
10042 if (old != detailLevel)
10052 return detailLevel;
10062- (void) handleOoliteException:(NSException *)exception
10064 if (exception !=
nil)
10069 [player
setStatus:STATUS_HANDLING_ERROR];
10071 OOLog(
kOOLogException,
@"***** Handling Fatal : %@ : %@ *****",[exception name], [exception reason]);
10072 NSString* exception_msg = [NSString stringWithFormat:@"Exception : %@ : %@ Please take a screenshot and/or press esc or Q to quit.", [exception name], [exception reason]];
10073 [
self addMessage:exception_msg forCount:30.0];
10074 [[
self gameController] setGamePaused:YES];
10078 OOLog(
kOOLogException,
@"***** Handling Non-fatal : %@ : %@ *****",[exception name], [exception reason]);
10084- (GLfloat)airResistanceFactor
10086 return airResistanceFactor;
10090- (void) setAirResistanceFactor:(GLfloat)newFactor
10092 airResistanceFactor = OOClamp_0_1_f(newFactor);
10099- (void) startSpeakingString:(NSString *) text
10101 [speechSynthesizer startSpeakingString:[NSString stringWithFormat:@"[[volm %.3f]]%@", 0.3333333f * [
OOSound masterVolume], text]];
10105- (void) stopSpeaking
10107 if ([speechSynthesizer respondsToSelector:
@selector(stopSpeakingAtBoundary:)])
10109 [speechSynthesizer stopSpeakingAtBoundary:NSSpeechWordBoundary];
10113 [speechSynthesizer stopSpeaking];
10120 return [speechSynthesizer isSpeaking];
10125- (void) startSpeakingString:(NSString *) text
10127 NSData *utf8 = [text dataUsingEncoding:NSUTF8StringEncoding];
10131 const char *stringToSay = [text UTF8String];
10132 espeak_Synth(stringToSay, strlen(stringToSay) + 1 , 0, POS_CHARACTER, 0, espeakCHARS_UTF8 | espeakPHONEMES | espeakENDPAUSE, NULL, NULL);
10137- (void) stopSpeaking
10145 return espeak_IsPlaying();
10149- (NSString *) voiceName:(
unsigned int) index
10151 if (index >= espeak_voice_count)
10153 return [NSString stringWithCString: espeak_voices[index]->name];
10157- (
unsigned int) voiceNumber:(NSString *) name
10162 const char *
const label = [name UTF8String];
10166 unsigned int index = -1;
10167 while (espeak_voices[++index] && strcmp (espeak_voices[index]->name, label))
10169 return (index < espeak_voice_count) ? index : UINT_MAX;
10173- (
unsigned int) nextVoice:(
unsigned int) index
10175 if (++index >= espeak_voice_count)
10181- (
unsigned int) prevVoice:(
unsigned int) index
10183 if (--index >= espeak_voice_count)
10184 index = espeak_voice_count - 1;
10189- (
unsigned int) setVoice:(
unsigned int) index withGenderM:(BOOL) isMale
10191 if (index == UINT_MAX)
10192 index = [
self voiceNumber:DESC(@"espeak-default-voice")];
10194 if (index < espeak_voice_count)
10196 espeak_VOICE voice = { espeak_voices[index]->name, NULL, NULL, isMale ? 1 : 2 };
10197 espeak_SetVoiceByProperties (&voice);
10205- (void) startSpeakingString:(NSString *) text {}
10207- (void) stopSpeaking {}
10216- (BOOL) pauseMessageVisible
10218 return _pauseMessage;
10222- (void) setPauseMessageVisible:(BOOL)value
10224 _pauseMessage = value;
10228- (BOOL) permanentMessageLog
10230 return _permanentMessageLog;
10234- (void) setPermanentMessageLog:(BOOL)value
10236 _permanentMessageLog = value;
10240- (BOOL) autoMessageLogBg
10242 return _autoMessageLogBg;
10246- (void) setAutoMessageLogBg:(BOOL)value
10248 _autoMessageLogBg = !!value;
10252- (BOOL) permanentCommLog
10254 return _permanentCommLog;
10258- (void) setPermanentCommLog:(BOOL)value
10260 _permanentCommLog = value;
10264- (void) setAutoCommLog:(BOOL)value
10266 _autoCommLog = value;
10270- (BOOL) blockJSPlayerShipProps
10276- (void) setBlockJSPlayerShipProps:(BOOL)value
10289- (void) setUpSettings
10291 [
self resetBeacons];
10293 next_universal_id = 100;
10294 memset(entity_for_uid, 0,
sizeof entity_for_uid);
10296 [
self setMainLightPosition:kZeroVector];
10303 [message_gui autorelease];
10305 initWithPixelSize:NSMakeSize(480, 160)
10312 [comm_log_gui autorelease];
10314 initWithPixelSize:NSMakeSize(360, 120)
10325 [
self setTimeAccelerationFactor:TIME_ACCELERATION_FACTOR_DEFAULT];
10327 universal_time = 0.0;
10328 messageRepeatTime = 0.0;
10329 countdown_messageRepeatTime = 0.0;
10331#if OOLITE_SPEECH_SYNTH
10332 [speechArray autorelease];
10336 [commodities autorelease];
10340 [
self loadDescriptions];
10342 [characters autorelease];
10345 [customSounds autorelease];
10348 [globalSettings autorelease];
10352 [systemManager autorelease];
10355 [screenBackgrounds autorelease];
10359 [roleCategories autorelease];
10362 [autoAIMap autorelease];
10365 [equipmentData autorelease];
10366 [equipmentDataOutfitting autorelease];
10368 equipmentData = [[equipmentTemp sortedArrayUsingFunction:equipmentSort context:NULL] retain];
10369 equipmentDataOutfitting = [[equipmentTemp sortedArrayUsingFunction:equipmentSortOutfitting context:NULL] retain];
10373 [explosionSettings autorelease];
10381 NSMutableDictionary *tmp = [[NSMutableDictionary alloc] initWithCapacity:[commodities count]];
10383 foreach (type, [commodities goods])
10385 ShipEntity *container = [
self newShipWithRole:@"oolite-template-cargopod"];
10388 [tmp setObject:container forKey:type];
10389 [container release];
10391 [cargoPods release];
10392 cargoPods = [[NSDictionary alloc] initWithDictionary:tmp];
10399 NSMutableArray *badEntities =
nil;
10403 for (i = 0; i < n_entities; i++)
10405 entity = sortedEntities[i];
10406 if ([entity sessionID] != _sessionID)
10408 OOLogERR(
@"universe.sessionIDs.verify.failed",
@"Invalid entity %@ (came from session %lu, current session is %lu).", [entity shortDescription], [entity sessionID], _sessionID);
10409 if (badEntities ==
nil) badEntities = [NSMutableArray array];
10410 [badEntities addObject:entity];
10414 foreach (entity, badEntities)
10416 [
self removeEntity:entity];
10423- (BOOL) reinitAndShowDemo:(BOOL) showDemo
10427 assert(player !=
nil);
10438 [
self removeAllEntitiesExceptPlayer];
10451 [[
self gameController] setGamePaused:NO];
10452 [[
self gameController] setMouseInteractionModeForUIWithMouseInteraction:NO];
10453 [PLAYER setSpeed:0.0];
10455 [
self loadDescriptions];
10456 [
self loadScenarios];
10458 [missiontext autorelease];
10464 [demo_ships release];
10466 demo_ship_index = 0;
10467 demo_ship_subindex = 0;
10470 breakPatternCounter = 0;
10473 cachedPlanet =
nil;
10474 cachedStation =
nil;
10476 [
self setUpSettings];
10481 [
self setUpCargoPods];
10483 if (![player setUpAndConfirmOK:YES])
10492 [
self addEntity:player];
10494 [[
self gameController] setPlayerFileToLoad:nil];
10496 [
self setUpInitialUniverse];
10499 [[
self station] initialiseLocalMarket];
10522 [
self populateNormalSpace];
10533 [
self verifyEntitySessionIDs];
10545 if (activeWormholes) [activeWormholes autorelease];
10546 activeWormholes = [[NSMutableArray arrayWithCapacity:16] retain];
10547 if (characterPool) [characterPool autorelease];
10548 characterPool = [[NSMutableArray arrayWithCapacity:256] retain];
10552 [
self setGalaxyTo: [player
galaxyNumber] andReinit:YES];
10564 [
self setDockingClearanceProtocolActive:
10565 [[
self currentSystemData] oo_boolForKey:@"stations_require_docking_clearance" defaultValue:YES]];
10567 [
self enterGUIViewModeWithMouseInteraction:NO];
10579- (Vector) randomPlaceWithinScannerFrom:(Vector)pos alongRoute:(Vector)route withOffset:(
double)offset
10581 pos.x +=
offset * route.
x + [
self randomDistanceWithinScanner];
10582 pos.y +=
offset * route.
y + [
self randomDistanceWithinScanner];
10583 pos.z +=
offset * route.z + [
self randomDistanceWithinScanner];
10589- (HPVector) fractionalPositionFrom:(HPVector)point0 to:(HPVector)point1 withFraction:(
double)routeFraction
10591 if (routeFraction == NSNotFound) routeFraction =
randf();
10593 point1 = OOHPVectorInterpolate(point0, point1, routeFraction);
10603- (BOOL)doRemoveEntity:(
Entity *)entity
10606 if ([entity canCollide])
10608 doLinkedListMaintenanceThisUpdate = YES;
10616 entity_for_uid[old_id] =
nil;
10626 if (sortedEntities[index] != entity)
10628 OOLog(
kOOLogInconsistentState,
@"DEBUG: Universe removeEntity:%@ ENTITY IS NOT IN THE RIGHT PLACE IN THE ZERO_DISTANCE SORTED LIST -- FIXING...", entity);
10631 for (i = 0; (i < n_entities)&&(index == -1); i++)
10632 if (sortedEntities[i] == entity)
10635 OOLog(
kOOLogInconsistentState,
@"DEBUG: Universe removeEntity:%@ ENTITY IS NOT IN THE ZERO_DISTANCE SORTED LIST -- CONTINUING...", entity);
10639 while ((
unsigned)index < n_entities)
10641 while (((
unsigned)index + n < n_entities)&&(sortedEntities[index + n] == entity))
10660 sortedEntities[index] = sortedEntities[index + n];
10661 if (sortedEntities[index])
10668 OOLog(
kOOLogInconsistentState,
@"DEBUG: Universe removeEntity: REMOVED %d EXTRA COPIES OF %@ FROM THE ZERO_DISTANCE SORTED LIST", n - 1, entity);
10672 sortedEntities[n_entities] =
nil;
10679 if ([entities containsObject:entity])
10682 if ([entity isBreakPattern] && ![entity isVisualEffect])
10684 breakPatternCounter--;
10687 if ([entity isShip])
10690 [
self clearBeacon:se];
10692 if ([entity isWaypoint])
10695 [
self clearBeacon:wp];
10697 if ([entity isVisualEffect])
10700 [
self clearBeacon:ve];
10703 if ([entity isWormhole])
10705 [activeWormholes removeObject:entity];
10707 else if ([entity isPlanet])
10709 [allPlanets removeObject:entity];
10712 [entities removeObject:entity];
10720static void PreloadOneSound(NSString *soundName)
10722 if (![soundName hasPrefix:
@"["] && ![soundName hasSuffix:
@"]"])
10729- (void) preloadSounds
10732 NSString *key =
nil;
10735 id object = [customSounds objectForKey:key];
10736 if([
object isKindOfClass:[NSString
class]])
10738 PreloadOneSound(
object);
10740 else if([
object isKindOfClass:[NSArray
class]] && [
object count] > 0)
10742 NSString *soundName =
nil;
10743 foreach (soundName,
object)
10745 if ([soundName isKindOfClass:[NSString
class]])
10747 PreloadOneSound(soundName);
10754 PreloadOneSound(
@"afterburner1.ogg");
10760 NSAutoreleasePool *pool =
nil;
10762 while ([activeWormholes
count])
10764 pool = [[NSAutoreleasePool alloc] init];
10770 if (![whole isScanned] &&
10771 NSEqualPoints([
PLAYER galaxy_coordinates], [whole destinationCoordinates]) )
10776 [activeWormholes removeObjectAtIndex:0];
10778 @catch (NSException *exception)
10780 OOLog(
kOOLogException,
@"Squashing exception during wormhole unpickling (%@: %@).", [exception name], [exception reason]);
10787- (NSString *)chooseStringForKey:(NSString *)key inDictionary:(NSDictionary *)dictionary
10789 id object = [dictionary objectForKey:key];
10790 if ([
object isKindOfClass:[NSString
class]])
return object;
10791 else if ([
object isKindOfClass:[NSArray
class]] && [
object count] > 0)
return [object oo_stringAtIndex:Ranrot() % [object count]];
10796#if OO_LOCALIZATION_TOOLS
10799- (void) dumpDebugGraphViz
10801 if ([[NSUserDefaults standardUserDefaults] boolForKey:
@"universe-dump-debug-graphviz"])
10803 [
self dumpSystemDescriptionGraphViz];
10808- (void) dumpSystemDescriptionGraphViz
10810 NSMutableString *graphViz =
nil;
10811 NSArray *systemDescriptions =
nil;
10812 NSArray *thisDesc =
nil;
10813 NSUInteger i,
count, j, subCount;
10814 NSString *descLine =
nil;
10815 NSArray *curses =
nil;
10816 NSString *label =
nil;
10817 NSDictionary *keyMap =
nil;
10823 graphViz = [NSMutableString stringWithString:
10824 @"// System description grammar:\n\n"
10825 "digraph system_descriptions\n"
10827 "\tgraph [charset=\"UTF-8\", label=\"System description grammar\", labelloc=t, labeljust=l rankdir=LR compound=true nodesep=0.02 ranksep=1.5 concentrate=true fontname=Helvetica]\n"
10828 "\tedge [arrowhead=dot]\n"
10829 "\tnode [shape=none height=0.2 width=3 fontname=Helvetica]\n\t\n"];
10831 systemDescriptions = [[
self descriptions] oo_arrayForKey:@"system_description"];
10832 count = [systemDescriptions count];
10835 descLine =
DESC(
@"system-description-string");
10837 [graphViz appendFormat:@"\tsystem_description_string [label=\"%@\" shape=ellipse]\n", EscapedGraphVizString(label)];
10838 [
self addNumericRefsInString:descLine
10839 toGraphViz:graphViz
10840 fromNode:@"system_description_string"
10842 [graphViz appendString:@"\t\n"];
10845 [graphViz appendString:
10846 @"\tpercent_I [label=\"%I\\nInhabitants\" shape=diamond]\n"
10847 "\tpercent_H [label=\"%H\\nSystem name\" shape=diamond]\n"
10848 "\tpercent_RN [label=\"%R/%N\\nRandom name\" shape=diamond]\n"
10849 "\tpercent_J [label=\"%J\\nNumbered system name\" shape=diamond]\n"
10850 "\tpercent_G [label=\"%G\\nNumbered system name in chart number\" shape=diamond]\n\t\n"];
10853 [graphViz appendString:@"\tsubgraph cluster_thargoid_curses\n\t{\n\t\tlabel = \"Thargoid curses\"\n"];
10854 curses = [[
self descriptions] oo_arrayForKey:@"thargoid_curses"];
10855 subCount = [curses count];
10856 for (j = 0; j < subCount; ++j)
10859 [graphViz appendFormat:@"\t\tthargoid_curse_%lu [label=\"%@\"]\n", j, EscapedGraphVizString(label)];
10861 [graphViz appendString:@"\t}\n"];
10862 for (j = 0; j < subCount; ++j)
10864 [
self addNumericRefsInString:[curses oo_stringAtIndex:j]
10865 toGraphViz:graphViz
10866 fromNode:[NSString stringWithFormat:@"thargoid_curse_%lu", j]
10869 [graphViz appendString:@"\t\n"];
10873 for (i = 0; i <
count; ++i)
10876 label = [keyMap objectForKey:[NSString stringWithFormat:@"%lu", i]];
10877 if (label ==
nil) label = [NSString stringWithFormat:
@"[%lu]", i];
10878 else label = [NSString stringWithFormat:@"[%lu] (%@)", i, label];
10880 [graphViz appendFormat:@"\tsubgraph cluster_%lu\n\t{\n\t\tlabel=\"%@\"\n", i, EscapedGraphVizString(label)];
10882 thisDesc = [systemDescriptions oo_arrayAtIndex:i];
10883 subCount = [thisDesc count];
10884 for (j = 0; j < subCount; ++j)
10887 [graphViz appendFormat:@"\t\tn%lu_%lu [label=\"\\\"%@\\\"\"]\n", i, j, EscapedGraphVizString(label)];
10890 [graphViz appendString:@"\t}\n"];
10892 [graphViz appendString:@"\t\n"];
10895 for (i = 0; i !=
count; ++i)
10897 thisDesc = [systemDescriptions oo_arrayAtIndex:i];
10898 subCount = [thisDesc count];
10899 for (j = 0; j != subCount; ++j)
10901 descLine = [thisDesc oo_stringAtIndex:j];
10902 [
self addNumericRefsInString:descLine
10903 toGraphViz:graphViz
10904 fromNode:[NSString stringWithFormat:@"n%lu_%lu", i, j]
10910 [graphViz appendString:@"\t}\n"];
10916- (void) addNumericRefsInString:(NSString *)string toGraphViz:(NSMutableString *)graphViz fromNode:(NSString *)fromNode nodeCount:(NSUInteger)nodeCount
10918 NSString *index =
nil;
10919 NSInteger start, end;
10920 NSRange remaining, subRange;
10923 remaining = NSMakeRange(0, [
string length]);
10927 subRange = [string rangeOfString:@"[" options:NSLiteralSearch range:remaining];
10928 if (subRange.location == NSNotFound)
break;
10929 start = subRange.location + subRange.length;
10930 remaining.length -= start - remaining.location;
10931 remaining.location = start;
10933 subRange = [string rangeOfString:@"]" options:NSLiteralSearch range:remaining];
10934 if (subRange.location == NSNotFound)
break;
10935 end = subRange.location;
10936 remaining.length -= end - remaining.location;
10937 remaining.location = end;
10939 index = [string substringWithRange:NSMakeRange(start, end - start)];
10940 i = [index intValue];
10943 [graphViz appendFormat:@"\t%@ -> n%u_0 [color=\"%f,0.75,0.8\" lhead=cluster_%u]\n", fromNode, i, ((float)(i * 511 % nodeCount)) / ((float)nodeCount), i];
10946 if ([
string rangeOfString:
@"%I"].location != NSNotFound)
10948 [graphViz appendFormat:@"\t%@ -> percent_I [color=\"0,0,0.25\"]\n", fromNode];
10950 if ([
string rangeOfString:
@"%H"].location != NSNotFound)
10952 [graphViz appendFormat:@"\t%@ -> percent_H [color=\"0,0,0.45\"]\n", fromNode];
10954 if ([
string rangeOfString:
@"%R"].location != NSNotFound || [
string rangeOfString:
@"%N"].location != NSNotFound)
10956 [graphViz appendFormat:@"\t%@ -> percent_RN [color=\"0,0,0.65\"]\n", fromNode];
10960 if ([
string rangeOfString:
@"%J"].location != NSNotFound)
10962 [graphViz appendFormat:@"\t%@ -> percent_J [color=\"0,0,0.75\"]\n", fromNode];
10965 if ([
string rangeOfString:
@"%G"].location != NSNotFound)
10967 [graphViz appendFormat:@"\t%@ -> percent_G [color=\"0,0,0.85\"]\n", fromNode];
10975 NSArray *arguments =
nil;
10976 NSEnumerator *argEnum =
nil;
10977 NSString *arg =
nil;
10978 BOOL compileSysDesc = NO, exportSysDesc = NO, xml = NO;
10980 arguments = [[NSProcessInfo processInfo] arguments];
10982 for (argEnum = [arguments objectEnumerator]; (arg = [argEnum nextObject]); )
10984 if ([arg isEqual:
@"--compile-sysdesc"]) compileSysDesc = YES;
10985 else if ([arg isEqual:
@"--export-sysdesc"]) exportSysDesc = YES;
10986 else if ([arg isEqual:
@"--xml"]) xml = YES;
10987 else if ([arg isEqual:
@"--openstep"]) xml = NO;
10998- (void) prunePreloadingPlanetMaterials
11002 NSUInteger i = [_preloadingPlanetMaterials count];
11005 if ([[_preloadingPlanetMaterials objectAtIndex:i] isFinishedLoading])
11007 [_preloadingPlanetMaterials removeObjectAtIndex:i];
11015- (void) loadConditionScripts
11017 [conditionScripts autorelease];
11018 conditionScripts = [[NSMutableDictionary alloc] init];
11028- (void) addConditionScripts:(NSEnumerator *)scripts
11030 NSString *scriptname =
nil;
11031 while ((scriptname = [scripts nextObject]))
11033 if ([conditionScripts objectForKey:scriptname] ==
nil)
11038 [conditionScripts setObject:script forKey:scriptname];
11045- (
OOJSScript*) getConditionScript:(NSString *)scriptname
11047 return [conditionScripts objectForKey:scriptname];
11053@implementation OOSound (OOCustomSounds)
11055+ (id) soundWithCustomSoundKey:(NSString *)key
11057 NSString *fileName = [UNIVERSE soundNameForCustomSoundKey:key];
11058 if (fileName ==
nil)
return nil;
11063- (id) initWithCustomSoundKey:(NSString *)key
11072@implementation OOSoundSource (OOCustomSounds)
11074+ (id) sourceWithCustomSoundKey:(NSString *)key
11076 return [[[
self alloc] initWithCustomSoundKey:key] autorelease];
11080- (id) initWithCustomSoundKey:(NSString *)key
11083 if (theSound !=
nil)
11085 self = [
self initWithSound:theSound];
11096- (void) playCustomSoundWithKey:(NSString *)key
11099 if (theSound !=
nil) [
self playSound:theSound];
11106 NSDictionary *one = (NSDictionary *)a;
11107 NSDictionary *two = (NSDictionary *)b;
11108 int pri_one = [one oo_intForKey:@"priority" defaultValue:100];
11109 int pri_two = [two oo_intForKey:@"priority" defaultValue:100];
11110 if (pri_one < pri_two)
return NSOrderedAscending;
11111 if (pri_one > pri_two)
return NSOrderedDescending;
11112 return NSOrderedSame;
11118 NSArray *one = (NSArray *)a;
11119 NSArray *two = (NSArray *)b;
11123 OOCreditsQuantity comp1 = [[one oo_dictionaryAtIndex:EQUIPMENT_EXTRA_INFO_INDEX] oo_unsignedLongLongForKey:@"sort_order" defaultValue:1000];
11124 OOCreditsQuantity comp2 = [[two oo_dictionaryAtIndex:EQUIPMENT_EXTRA_INFO_INDEX] oo_unsignedLongLongForKey:@"sort_order" defaultValue:1000];
11125 if (comp1 < comp2)
return NSOrderedAscending;
11126 if (comp1 > comp2)
return NSOrderedDescending;
11128 comp1 = [one oo_unsignedLongLongAtIndex:EQUIPMENT_TECH_LEVEL_INDEX];
11129 comp2 = [two oo_unsignedLongLongAtIndex:EQUIPMENT_TECH_LEVEL_INDEX];
11130 if (comp1 < comp2)
return NSOrderedAscending;
11131 if (comp1 > comp2)
return NSOrderedDescending;
11133 comp1 = [one oo_unsignedLongLongAtIndex:EQUIPMENT_PRICE_INDEX];
11134 comp2 = [two oo_unsignedLongLongAtIndex:EQUIPMENT_PRICE_INDEX];
11135 if (comp1 < comp2)
return NSOrderedAscending;
11136 if (comp1 > comp2)
return NSOrderedDescending;
11138 return NSOrderedSame;
11144 NSArray *one = (NSArray *)a;
11145 NSArray *two = (NSArray *)b;
11149 OOCreditsQuantity comp1 = [[one oo_dictionaryAtIndex:EQUIPMENT_EXTRA_INFO_INDEX] oo_unsignedLongLongForKey:@"purchase_sort_order" defaultValue:[[one oo_dictionaryAtIndex:EQUIPMENT_EXTRA_INFO_INDEX] oo_unsignedLongLongForKey:@"sort_order" defaultValue:1000]];
11150 OOCreditsQuantity comp2 = [[two oo_dictionaryAtIndex:EQUIPMENT_EXTRA_INFO_INDEX] oo_unsignedLongLongForKey:@"purchase_sort_order" defaultValue:[[two oo_dictionaryAtIndex:EQUIPMENT_EXTRA_INFO_INDEX] oo_unsignedLongLongForKey:@"sort_order" defaultValue:1000]];
11151 if (comp1 < comp2)
return NSOrderedAscending;
11152 if (comp1 > comp2)
return NSOrderedDescending;
11154 comp1 = [one oo_unsignedLongLongAtIndex:EQUIPMENT_TECH_LEVEL_INDEX];
11155 comp2 = [two oo_unsignedLongLongAtIndex:EQUIPMENT_TECH_LEVEL_INDEX];
11156 if (comp1 < comp2)
return NSOrderedAscending;
11157 if (comp1 > comp2)
return NSOrderedDescending;
11159 comp1 = [one oo_unsignedLongLongAtIndex:EQUIPMENT_PRICE_INDEX];
11160 comp2 = [two oo_unsignedLongLongAtIndex:EQUIPMENT_PRICE_INDEX];
11161 if (comp1 < comp2)
return NSOrderedAscending;
11162 if (comp1 > comp2)
return NSOrderedDescending;
11164 return NSOrderedSame;
11170 NSString *result = [UNIVERSE descriptionForKey:key];
11171 if (result ==
nil) result = key;
11179 NSArray *conditions = [[UNIVERSE descriptions] oo_arrayForKey:@"plural-rules"];
11182 NSString *tmp = [UNIVERSE descriptionForKey:key];
11185 static NSMutableSet *warned =
nil;
11187 if (![warned containsObject:tmp])
11189 OOLogWARN(
@"localization.plurals",
@"'%@' found in descriptions.plist, should be '%@%%0'. Localization data needs updating.",key,key);
11190 if (warned ==
nil) warned = [[NSMutableSet alloc] init];
11191 [warned addObject:tmp];
11195 if (conditions ==
nil)
11205 for (index = i = 0; i < [conditions count]; ++index, ++i)
11207 const char *cond = [[conditions oo_stringAtIndex:i] UTF8String];
11211 long int input =
count;
11214 while (isspace (*cond))
11219 while (isspace (*cond))
11222 char command = *cond++;
11234 long int param = strtol(cond, (
char **)&cond, 10);
11249 if (flag ^ (input == param))
11253 if (flag ^ (input != param))
11258 if (flag ^ (input < param))
11262 if (flag ^ (input > param))
#define INTERMEDIATE_CLEAR_DEPTH
#define SCANNER_MAX_RANGE
#define SCANNER_MAX_RANGE2
#define OO_DEBUG_POP_PROGRESS()
#define OO_DEBUG_PROGRESS(...)
#define OO_DEBUG_PUSH_PROGRESS(...)
OOGUITabStop OOGUITabSettings[GUI_MAX_COLUMNS]
#define MAIN_GUI_PIXEL_WIDTH
#define MAIN_GUI_PIXEL_HEIGHT
NSRect OORectFromString(NSString *text, GLfloat x, GLfloat y, NSSize siz)
void OODrawString(NSString *text, GLfloat x, GLfloat y, GLfloat z, NSSize siz)
@ kOOBreakPatternMaxSides
#define BREAK_PATTERN_RING_SPEED
#define BREAK_PATTERN_RING_SPACING
NSInteger OOComparisonResult
#define foreachkey(VAR, DICT)
NSString * OOStringFromGraphicsDetail(OOGraphicsDetail detail)
void CompileSystemDescriptions(BOOL asXML)
void ExportSystemDescriptions(BOOL asXML)
NSString * OOStringifySystemDescriptionLine(NSString *line, NSDictionary *indicesToKeys, BOOL useFallback)
void OOStandardsDeprecated(NSString *message)
BOOL OOEnforceStandards(void)
void OOInitDebugSupport(void)
BOOL IsShipPredicate(Entity *entity, void *parameter)
BOOL IsVisualEffectPredicate(Entity *entity, void *parameter)
BOOL YESPredicate(Entity *entity, void *parameter)
HPVector OOHPVectorRandomRadial(OOHPScalar maxLength)
HPVector OOProjectHPVectorToPlane(HPVector point, HPVector plane, HPVector normal)
HPVector OORandomPositionInShell(HPVector centre, OOHPScalar inner, OOHPScalar outer)
const HPVector kZeroHPVector
HPVector OOHPVectorRandomSpatial(OOHPScalar maxLength)
const HPVector kBasisZHPVector
HPVector OORandomPositionInCylinder(HPVector centre1, OOHPScalar exclusion1, HPVector centre2, OOHPScalar exclusion2, OOHPScalar radius)
#define OOJS_PROFILE_EXIT
#define OOJS_PROFILE_ENTER
void OOJSPauseTimeLimiter(void)
OOINLINE jsval OOJSValueFromNativeObject(JSContext *context, id object)
OOINLINE JSContext * OOJSAcquireContext(void)
OOINLINE void OOJSRelinquishContext(JSContext *context)
void OOJSResumeTimeLimiter(void)
#define OOLogWARN(class, format,...)
#define OOLogERR(class, format,...)
NSString *const kOOLogException
NSString *const kOOLogInconsistentState
BOOL OOLogWillDisplayMessagesInClass(NSString *inMessageClass)
#define OOLogOutdentIf(class)
#define OOLog(class, format,...)
NSString *const kOOLogParameterError
#define OOLogIndentIf(class)
OOMatrix OOMatrixMultiply(OOMatrix a, OOMatrix b)
const OOMatrix kIdentityMatrix
Vector OOVectorMultiplyMatrix(Vector v, OOMatrix m)
@ MOUSE_MODE_UI_SCREEN_WITH_INTERACTION
void OOGLLoadModelView(OOMatrix matrix)
void OOGLLookAt(Vector eye, Vector center, Vector up)
OOMatrix OOGLGetModelView(void)
void OOGLPushModelView(void)
void OOGLResetModelView(void)
void OOGLTranslateModelView(Vector vector)
void OOGLFrustum(double left, double right, double bottom, double top, double near, double far)
void OOGLMultModelView(OOMatrix matrix)
OOMatrix OOGLGetModelViewProjection(void)
OOMatrix OOGLPopModelView(void)
void OOGLResetProjection(void)
#define OOVerifyOpenGLState()
BOOL OOCheckOpenGLErrors(NSString *format,...)
void GLScaledLineWidth(GLfloat width)
#define OOSetOpenGLState(STATE)
Vector vector_forward_from_quaternion(Quaternion quat)
void basis_vectors_from_quaternion(Quaternion quat, Vector *outRight, Vector *outUp, Vector *outForward)
void quaternion_set_random(Quaternion *quat)
const Quaternion kIdentityQuaternion
Quaternion quaternion_rotation_between(Vector v0, Vector v1)
void quaternion_rotate_about_y(Quaternion *quat, OOScalar angle)
void quaternion_rotate_about_axis(Quaternion *quat, Vector axis, OOScalar angle)
NSString * OOShipLibraryCategorySingular(NSString *category)
NSString * OOShipLibraryWitchspace(ShipEntity *demo_ship)
NSString * OOShipLibraryTurrets(ShipEntity *demo_ship)
NSString * OOShipLibraryShields(ShipEntity *demo_ship)
NSString * OOShipLibraryCargo(ShipEntity *demo_ship)
NSString * OOShipLibraryCategoryPlural(NSString *category)
static NSString *const kOODemoShipClass
NSString * OOShipLibraryGenerator(ShipEntity *demo_ship)
static NSString *const kOODemoShipShipData
NSString * OOShipLibrarySize(ShipEntity *demo_ship)
NSString * OOShipLibrarySpeed(ShipEntity *demo_ship)
static NSString *const kOODemoShipKey
NSString * OOShipLibraryWeapons(ShipEntity *demo_ship)
NSString * OOShipLibraryTurnRate(ShipEntity *demo_ship)
#define OOExpandKey(key,...)
#define OOExpand(string,...)
NSMutableArray * ScanTokensFromString(NSString *values)
@ OO_SYSTEMCONCEALMENT_NOTHING
@ OO_SYSTEMCONCEALMENT_NONAME
uint8_t OOWeaponFacingSet
NSString * OOCommodityType
uint64_t OOCreditsQuantity
#define VALID_WEAPON_FACINGS
@ WEAPON_FACING_STARBOARD
const Vector kBasisYVector
const Vector kBasisZVector
const Vector kBasisXVector
BOOL isWeaponNone(OOWeaponType weapon)
#define ENTITY_PERSONALITY_MAX
NSString * OOEquipmentIdentifierFromWeaponType(OOWeaponType weapon) CONST_FUNC
OOWeaponType OOWeaponTypeFromEquipmentIdentifierSloppy(NSString *string) PURE_FUNC
#define ShipScriptEvent(context, ship, event,...)
#define SUN_SKIM_RADIUS_FACTOR
#define TIME_ACCELERATION_FACTOR_DEFAULT
#define PASSENGER_BERTH_SPACE
#define MIN_DISTANCE_TO_BUOY
#define DEMO_LIGHT_POSITION
#define DESC_PLURAL(key, count)
#define OOLITE_EXCEPTION_FATAL
@ EQUIPMENT_SHORT_DESC_INDEX
#define TIME_ACCELERATION_FACTOR_MAX
NSString * OOLookUpDescriptionPRIV(NSString *key)
#define SAFE_ADDITION_FACTOR2
@ OO_POSTFX_COLORBLINDNESS_TRITAN
NSString * OOLookUpPluralDescriptionPRIV(NSString *key, NSInteger count)
NSComparisonResult populatorPrioritySort(id a, id b, void *context)
NSComparisonResult equipmentSortOutfitting(id a, id b, void *context)
NSComparisonResult equipmentSort(id a, id b, void *context)
#define SYSTEM_REPOPULATION_INTERVAL
#define OOLITE_EXCEPTION_DATA_NOT_FOUND
BOOL(* EntityFilterPredicate)(Entity *entity, void *parameter)
#define DOCKED_ILLUM_LEVEL
const GLfloat framebufferQuadVertices[]
static const OOMatrix fwd_matrix
#define SKY_AMBIENT_ADJUSTMENT
static GLfloat docked_light_specular[4]
static NSString *const kOOLogUniversePopulateWitchspace
static const OOMatrix port_matrix
Universe * gSharedUniverse
static const OOMatrix starboard_matrix
#define SUN_AMBIENT_INFLUENCE
static BOOL MaintainLinkedLists(Universe *uni)
static OOComparisonResult compareName(id dict1, id dict2, void *context)
static BOOL demo_light_on
static const OOMatrix aft_matrix
static NSString *const kOOLogEntityVerificationRebuild
static BOOL object_light_on
Entity * gOOJSPlayerIfStale
static GLfloat docked_light_ambient[4]
#define DEMO2_FLY_IN_STAGE_TIME
static NSString *const kOOLogEntityVerificationError
static GLfloat sun_off[4]
static NSString *const kOOLogUniversePopulateError
#define DEMO2_VANISHING_DISTANCE
const GLuint framebufferQuadIndices[]
static GLfloat docked_light_diffuse[4]
static GLfloat demo_light_position[4]
#define DOCKED_AMBIENT_LEVEL
OOINLINE BOOL EntityInRange(HPVector p1, Entity *e2, float range)
static OOComparisonResult comparePrice(id dict1, id dict2, void *context)
NSDictionary * demoShipData()
void deleteOpenGLObjects()
void drawTargetTextureIntoDefaultFramebuffer()
void verifyEntitySessionIDs()
void setLibraryTextForDemoShip()
void prepareToRenderIntoDefaultFramebuffer()
void verifyDescriptions()
void setUpInitialUniverse()
float randomDistanceWithinScanner()
void populateSpaceFromActiveWormholes()
void setGuiToIntroFirstGo:(BOOL justCobra)
void runLocalizationTools()
void setNextThinkTime:(OOTimeAbsolute ntt)
void setOwner:(ShipEntity *ship)
OOTimeDelta thinkTimeInterval
void setState:(NSString *stateName)
OOTimeAbsolute nextThinkTime
unsigned isImmuneToBreakPatternHide
void setAtmosphereFogging:(OOColor *fogging)
void removeFromLinkedLists()
void drawImmediate:translucent:(bool immediate,[translucent] bool translucent)
void setUniversalID:(OOUniversalID uid)
OOUniversalID universalID
void setThrowSparks:(BOOL value)
void setVelocity:(Vector vel)
void updateCameraRelativePosition()
void setOrientation:(Quaternion quat)
void update:(OOTimeDelta delta_t)
unsigned collisionTestFilter
GLfloat collisionRadius()
void wasRemovedFromUniverse()
void setScanClass:(OOScanClass sClass)
void setPositionX:y:z:(OOHPScalar x,[y] OOHPScalar y,[z] OOHPScalar z)
HPVector absolutePositionForSubentityOffset:(HPVector offset)
void setEnergy:(GLfloat amount)
Quaternion normalOrientation()
ShipEntity * parentEntity()
unsigned isExplicitlyNotMainStation
void setStatus:(OOEntityStatus stat)
void setPosition:(HPVector posn)
GameController * sharedController()
void logProgress:(NSString *message)
void setLineWidth:(GLfloat value)
NSString * deferredHudName
void setOverallAlpha:(GLfloat newAlphaValue)
void setFov:fromFraction:(float value,[fromFraction] BOOL fromFraction)
void setGammaValue:(float value)
void setMsaa:(BOOL newMsaa)
void completePendingTasks()
OOAsyncWorkManager * sharedAsyncWorkManager()
void setInnerColor:outerColor:(OOColor *color1,[outerColor] OOColor *color2)
void setLifetime:(double lifetime)
instancetype breakPatternWithPolygonSides:startAngle:aspectRatio:(NSUInteger sides,[startAngle] float startAngleDegrees,[aspectRatio] float aspectRatio)
void setObject:forKey:inCache:(id inElement,[forKey] NSString *inKey,[inCache] NSString *inCacheKey)
id objectForKey:inCache:(NSString *inKey,[inCache] NSString *inCacheKey)
OOCacheManager * sharedCache()
OOCharacter * randomCharacterWithRole:andOriginalSystem:(NSString *c_role,[andOriginalSystem] OOSystemID s)
OOColor * colorWithRed:green:blue:alpha:(float red,[green] float green,[blue] float blue,[alpha] float alpha)
OOColor * brightColorWithDescription:(id description)
OOColor * colorWithDescription:(id description)
OOColor * colorWithHue:saturation:brightness:alpha:(float hue,[saturation] float saturation,[brightness] float brightness,[alpha] float alpha)
OOColor * blendedColorWithFraction:ofColor:(float fraction,[ofColor] OOColor *color)
NSArray * saveStationAmounts()
NSString * conditionScript()
OOTechLevelID techLevel()
OOEquipmentType * equipmentTypeWithIdentifier:(NSString *identifier)
OOCreditsQuantity price()
instancetype explosionCloudFromEntity:withSettings:(Entity *entity,[withSettings] NSDictionary *settings)
instancetype laserFlashWithPosition:velocity:color:(HPVector position,[velocity] Vector vel,[color] OOColor *color)
void resetGraphicsState()
OOGraphicsResetManager * sharedManager()
void runCallback:(HPVector location)
BOOL callMethod:inContext:withArguments:count:result:(jsid methodID,[inContext] JSContext *context,[withArguments] jsval *argv,[count] intN argc,[result] jsval *outResult)
OOJavaScriptEngine * sharedEngine()
void garbageCollectionOpportunity:(BOOL force)
void removeObject:(id object)
OOOpenGLExtensionManager * sharedManager()
OOGraphicsDetail defaultDetailLevel()
instancetype shrinkingRingFromEntity:(Entity *sourceEntity)
instancetype ringFromEntity:(Entity *sourceEntity)
id jsScriptFromFileNamed:properties:(NSString *fileName,[properties] NSDictionary *properties)
instancetype groupWithName:(NSString *name)
NSDictionary * shipyardInfoForKey:(NSString *key)
NSArray * playerShipKeys()
NSString * randomShipKeyForRole:(NSString *role)
OOShipRegistry * sharedRegistry()
NSDictionary * shipInfoForKey:(NSString *key)
NSDictionary * effectInfoForKey:(NSString *key)
id soundWithCustomSoundKey:(NSString *key)
void setRadius:andCorona:(GLfloat rad,[andCorona] GLfloat corona)
BOOL changeSunProperty:withDictionary:(NSString *key,[withDictionary] NSDictionary *dict)
void setPosition:(HPVector posn)
void getSpecularComponents:(GLfloat[4] components)
void getDiffuseComponents:(GLfloat[4] components)
BOOL setSunColor:(OOColor *sun_color)
instancetype waypointWithDictionary:(NSDictionary *info)
void setBounty:withReason:(OOCreditsQuantity amount, [withReason] OOLegalStatusReason reason)
void setSystemID:(OOSystemID sid)
void setGuiToStatusScreen()
void setRandom_factor:(int rf)
Vector weaponViewOffset()
OOGalaxyID galaxyNumber()
void setWormhole:(WormholeEntity *newWormhole)
BOOL setUpShipFromDictionary:(NSDictionary *shipDict)
StationEntity * dockedStation()
void setShowDemoShips:(BOOL value)
Quaternion normalOrientation()
BOOL switchHudTo:(NSString *hudFileName)
void addScannedWormhole:(WormholeEntity *wormhole)
void addToAdjustTime:(double seconds)
NSPoint galaxy_coordinates
OOSystemID currentSystemID()
void setGalaxyCoordinates:(NSPoint newPosition)
void runUnsanitizedScriptActions:allowingAIMethods:withContextName:forTarget:(NSArray *unsanitizedActions,[allowingAIMethods] BOOL allowAIMethods,[withContextName] NSString *contextName,[forTarget] ShipEntity *target)
void setJumpCause:(NSString *value)
void setDockedAtMainStation()
void setPreviousSystemID:(OOSystemID sid)
OOMatrix customViewMatrix
Vector customViewUpVector
Vector customViewForwardVector
NSString * dial_clock_adjusted()
BOOL doWorldEventUntilMissionScreen:(jsid message)
PlayerEntity * sharedPlayer()
OOSystemID targetSystemID()
OOSound * ooSoundNamed:inFolder:(NSString *fileName,[inFolder] NSString *folderName)
NSDictionary * dictionaryFromFilesNamed:inFolder:andMerge:(NSString *fileName,[inFolder] NSString *folderName,[andMerge] BOOL mergeFiles)
NSArray * arrayFromFilesNamed:inFolder:andMerge:(NSString *fileName,[inFolder] NSString *folderName,[andMerge] BOOL mergeFiles)
BOOL writeDiagnosticData:toFileNamed:(NSData *data,[toFileNamed] NSString *name)
OOSystemDescriptionManager * systemDescriptionManager()
void setUseAddOns:(NSString *useAddOns)
NSDictionary * roleCategoriesDictionary()
NSDictionary * dictionaryFromFilesNamed:inFolder:mergeMode:cache:(NSString *fileName,[inFolder] NSString *folderName,[mergeMode] OOResourceMergeMode mergeMode,[cache] BOOL useCache)
instancetype elementWithLocation:parent:cost:distance:time:jumps:(OOSystemID location,[parent] OOSystemID parent,[cost] double cost,[distance] double distance,[time] double time,[jumps] int jumps)
void setDemoStartTime:(OOTimeAbsolute time)
void setIsWreckage:(BOOL isw)
void setBounty:withReason:(OOCreditsQuantity amount,[withReason] OOLegalStatusReason reason)
NSDictionary * shipInfoDictionary()
void removeEquipmentItem:(NSString *equipmentKey)
void setFuel:(OOFuelQuantity amount)
void rescaleBy:writeToCache:(GLfloat factor, [writeToCache] BOOL writeToCache)
void setStatus:(OOEntityStatus stat)
void setCargoFlag:(OOCargoFlag flag)
BOOL witchspaceLeavingEffects()
void setRoll:(double amount)
void setDestination:(HPVector dest)
void setGroup:(OOShipGroup *group)
void setSubEntityTakingDamage:(ShipEntity *sub)
void doScriptEvent:(jsid message)
NSArray * portWeaponOffset
void setPrimaryRole:(NSString *role)
NSArray * starboardWeaponOffset
void setHeatInsulation:(GLfloat value)
void setPitch:(double amount)
void enterTargetWormhole()
NSArray * aftWeaponOffset
NSArray * forwardWeaponOffset
void setPendingEscortCount:(uint8_t count)
uint8_t pendingEscortCount()
void setTemperature:(GLfloat value)
void setCrew:(NSArray *crewArray)
void setDemoShip:(OOScalar demoRate)
void doScriptEvent:withArgument:(jsid message,[withArgument] id argument)
void switchAITo:(NSString *aiString)
void setCommodity:andAmount:(OOCommodityType co_type,[andAmount] OOCargoQuantity co_amount)
OOCommodityType commodityType()
BOOL changeProperty:withDictionary:(NSString *key,[withDictionary] NSDictionary *dict)
void setAllowsFastDocking:(BOOL newValue)
void setRequiresDockingClearance:(BOOL newValue)
void setEquivalentTechLevel:(OOTechLevelID value)
unsigned interstellarUndockingAllowed
void setAllegiance:(NSString *newAllegiance)
static OOComparisonResult compareName(id dict1, id dict2, void *context)
static void VerifyDescArray(NSString *key, NSArray *desc)
static void VerifyDescString(NSString *key, NSString *desc)
static BOOL IsCandidateMainStationPredicate(Entity *entity, void *parameter)
NSMutableArray * entities
NSPoint destinationCoordinates()
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
RANROTSeed RanrotSeedFromRandomSeed(Random_Seed seed)
RANROTSeed RANROTGetFullSeed(void)
void ranrot_srand(uint32_t seed)
void OOInitReallyRandom(uint64_t seed)
void RANROTSetFullSeed(RANROTSeed seed)
unsigned RanrotWithSeed(RANROTSeed *ioSeed)
double cunningFee(double value, double precision)
void seed_for_planet_description(Random_Seed s_seed)
RANROTSeed MakeRanrotSeed(uint32_t seed)
void rotate_seed(Random_Seed *seed_ptr)
OOINLINE double distanceBetweenPlanetPositions(int x1, int y1, int x2, int y2) INLINE_CONST_FUNC